From 9cf69447f48f82601d375ddc38f07116d8dd1914 Mon Sep 17 00:00:00 2001 From: Gerry Shaw Date: Tue, 6 Nov 2018 21:21:41 +0700 Subject: [PATCH 01/61] Do not assume project in current directory (#3131) Correctly prints `cd path/to/project` when project is created in a nested directory. --- installer/lib/mix/tasks/phx.new.ex | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/installer/lib/mix/tasks/phx.new.ex b/installer/lib/mix/tasks/phx.new.ex index a69b202e27..1eca2415e7 100644 --- a/installer/lib/mix/tasks/phx.new.ex +++ b/installer/lib/mix/tasks/phx.new.ex @@ -136,25 +136,25 @@ defmodule Mix.Tasks.Phx.New do defp prompt_to_install_deps(%Project{} = project, generator) do install? = Mix.shell.yes?("\nFetch and install dependencies?") + cd_step = ["$ cd #{relative_app_path(project.project_path)}"] + maybe_cd(project.project_path, fn -> - mix_pending = - install_mix(install?) + mix_step = install_mix(install?) compile = - case mix_pending do + case mix_step do [] -> Task.async(fn -> rebar_available?() && cmd("mix deps.compile") end) _ -> Task.async(fn -> :ok end) end - webpack_pending = install_webpack(install?, project) + webpack_step = install_webpack(install?, project) Task.await(compile, :infinity) if Project.webpack?(project) and !System.find_executable("npm") do print_webpack_info(project, generator) end - pending = mix_pending ++ (webpack_pending || []) - print_missing_commands(pending, project.project_path) + print_missing_steps(cd_step ++ mix_step ++ webpack_step) if Project.ecto?(project) do print_ecto_info(project, generator) @@ -208,16 +208,7 @@ defmodule Mix.Tasks.Phx.New do """ end - defp print_missing_commands([], path) do - Mix.shell.info """ - - We are all set! Go into your application by running: - - $ cd #{relative_app_path(path)} - """ - end - defp print_missing_commands(commands, path) do - steps = ["$ cd #{relative_app_path(path)}" | commands] + defp print_missing_steps(steps) do Mix.shell.info """ We are almost there! The following steps are missing: From bf1872be3ebbd4721f4fbc0c899044846517f3ee Mon Sep 17 00:00:00 2001 From: Jeff Kreeftmeijer Date: Tue, 6 Nov 2018 15:22:10 +0100 Subject: [PATCH 02/61] Remove extra newline in generated context test cases (#3129) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, context tests generated by running the html generator (`mix phx.gen.context Accounts User users name:string`), produce a test with an extra line with some trailing whitespace (illustrated with dots here): test "update_user/2 with valid data updates the user" do user = user_fixture() assert {:ok, %User{} = user} = Accounts.update_user(user, @update_attrs) ······ assert user.name == "some updated name" end This patch removes both newlines from the template, resulting in a generated test like this: test "update_user/2 with valid data updates the user" do user = user_fixture() assert {:ok, %User{} = user} = Accounts.update_user(user, @update_attrs) assert user.name == "some updated name" end --- priv/templates/phx.gen.context/test_cases.exs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/priv/templates/phx.gen.context/test_cases.exs b/priv/templates/phx.gen.context/test_cases.exs index e83b1252fb..92f73323f4 100644 --- a/priv/templates/phx.gen.context/test_cases.exs +++ b/priv/templates/phx.gen.context/test_cases.exs @@ -36,9 +36,7 @@ test "update_<%= schema.singular %>/2 with valid data updates the <%= schema.singular %>" do <%= schema.singular %> = <%= schema.singular %>_fixture() - assert {:ok, %<%= inspect schema.alias %>{} = <%= schema.singular %>} = <%= inspect context.alias %>.update_<%= schema.singular %>(<%= schema.singular %>, @update_attrs) - - <%= for {field, value} <- schema.params.update do %> + assert {:ok, %<%= inspect schema.alias %>{} = <%= schema.singular %>} = <%= inspect context.alias %>.update_<%= schema.singular %>(<%= schema.singular %>, @update_attrs)<%= for {field, value} <- schema.params.update do %> assert <%= schema.singular %>.<%= field %> == <%= Mix.Phoenix.Schema.value(schema, field, value) %><% end %> end From d747637a099ada25bc62a2105cd155fcbafe5cdf Mon Sep 17 00:00:00 2001 From: Tan Jay Jun Date: Tue, 6 Nov 2018 22:23:04 +0800 Subject: [PATCH 03/61] Document Phoenix.Channel callbacks (#3130) --- lib/phoenix/channel.ex | 64 +++++++++++++++++++++++++++++++++++------- 1 file changed, 54 insertions(+), 10 deletions(-) diff --git a/lib/phoenix/channel.ex b/lib/phoenix/channel.ex index 6e528f1f5e..312296134d 100644 --- a/lib/phoenix/channel.ex +++ b/lib/phoenix/channel.ex @@ -20,12 +20,12 @@ defmodule Phoenix.Channel do matched in your channels' `join/3` callback to pluck out the scoped pattern: # handles the special `"lobby"` subtopic - def join("room:lobby", _auth_message, socket) do + def join("room:lobby", _payload, socket) do {:ok, socket} end # handles any other subtopic as the room ID, for example `"room:12"`, `"room:34"` - def join("room:" <> room_id, auth_message, socket) do + def join("room:" <> room_id, _payload, socket) do {:ok, socket} end @@ -243,8 +243,8 @@ defmodule Phoenix.Channel do simply relay the `%Phoenix.Socket.Broadcast{}` event and payload: alias Phoenix.Socket.Broadcast - def handle_info(%Broadcast{topic: _, event: ev, payload: payload}, socket) do - push(socket, ev, payload) + def handle_info(%Broadcast{topic: _, event: event, payload: payload}, socket) do + push(socket, event, payload) {:noreply, socket} end @@ -267,31 +267,74 @@ defmodule Phoenix.Channel do @type socket_ref :: {transport_pid :: Pid, serializer :: module, topic :: binary, ref :: binary, join_ref :: binary} - @callback join(topic :: binary, auth_msg :: map, Socket.t) :: + @doc """ + Handle channel joins by `topic`. + + To authorize a socket, return `{:ok, socket}` or `{:ok, reply, socket}`. To + refuse authorization, return `{:error, reason}`. + + ## Example + + def join("room:lobby", payload, socket) do + if authorized?(payload) do + {:ok, socket} + else + {:error, %{reason: "unauthorized"}} + end + end + + """ + @callback join(topic :: binary, payload :: map, socket :: Socket.t) :: {:ok, Socket.t} | - {:ok, map, Socket.t} | - {:error, map} + {:ok, reply :: map, Socket.t} | + {:error, reason :: map} + + @doc """ + Handle incoming `event`s. + + ## Example - @callback handle_in(event :: String.t, msg :: map, Socket.t) :: + def handle_in("ping", payload, socket) do + {:reply, {:ok, payload}, socket} + end + + """ + @callback handle_in(event :: String.t, payload :: map, socket :: Socket.t) :: {:noreply, Socket.t} | {:noreply, Socket.t, timeout | :hibernate} | {:reply, reply, Socket.t} | {:stop, reason :: term, Socket.t} | {:stop, reason :: term, reply, Socket.t} - @callback handle_out(event :: String.t, msg :: map, Socket.t) :: + @doc """ + Intercepts outgoing `event`s. + + See `intercept/1`. + """ + @callback handle_out(event :: String.t, payload :: map, socket :: Socket.t) :: {:noreply, Socket.t} | {:noreply, Socket.t, timeout | :hibernate} | {:stop, reason :: term, Socket.t} - @callback handle_info(term, Socket.t) :: + @doc """ + Handle regular Elixir process messages. + + See `GenServer.handle_info/2`. + """ + @callback handle_info(msg :: term, socket :: Socket.t) :: {:noreply, Socket.t} | {:stop, reason :: term, Socket.t} + @doc false @callback code_change(old_vsn, Socket.t, extra :: term) :: {:ok, Socket.t} | {:error, reason :: term} when old_vsn: term | {:down, term} + @doc """ + Invoked when the channel process is about to exit. + + See `GenServer.terminate/2`. + """ @callback terminate(reason :: :normal | :shutdown | {:shutdown, :left | :closed | term}, Socket.t) :: term @@ -348,6 +391,7 @@ defmodule Phoenix.Channel do `handle_out/3` callbacks must return one of: {:noreply, Socket.t} | + {:noreply, Socket.t, timeout | :hibernate} | {:stop, reason :: term, Socket.t} """ From 3b6bc3868162fb39570fe1beb2d45a117983af61 Mon Sep 17 00:00:00 2001 From: Stephen Bussey Date: Wed, 7 Nov 2018 13:01:39 -0500 Subject: [PATCH 04/61] Allow channels to immediately reconnect when the socket does (#3141) The timer state must be known in order to know if the channel was attempting to rejoin or not. It is not correct to start a channel rejoin timer if it was not previously running. --- assets/js/phoenix.js | 27 +++++++++++++++++++++++++-- assets/test/socket_test.js | 19 +++++++++++++++++++ 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/assets/js/phoenix.js b/assets/js/phoenix.js index 9f56a052d2..78149265a9 100644 --- a/assets/js/phoenix.js +++ b/assets/js/phoenix.js @@ -838,6 +838,7 @@ export class Socket { this.flushSendBuffer() this.reconnectTimer.reset() this.resetHeartbeat() + this.resetChannelTimers() this.stateChangeCallbacks.open.forEach( callback => callback() ) } @@ -986,6 +987,15 @@ export class Socket { } }) } + + /** + * @private + */ + resetChannelTimers() { + this.channels.forEach(channel => { + channel.rejoinTimer.restart() + }) + } } @@ -1346,18 +1356,31 @@ class Timer { reset(){ this.tries = 0 - clearTimeout(this.timer) + this.clearTimer() + } + + restart(){ + const processing = this.timer !== null + this.reset() + if (processing){ + this.scheduleTimeout() + } } /** * Cancels any previous scheduleTimeout and schedules callback */ scheduleTimeout(){ - clearTimeout(this.timer) + this.clearTimer() this.timer = setTimeout(() => { this.tries = this.tries + 1 this.callback() }, this.timerCalc(this.tries + 1)) } + + clearTimer() { + clearTimeout(this.timer) + this.timer = null + } } diff --git a/assets/test/socket_test.js b/assets/test/socket_test.js index 4790db7759..fe38507b5d 100644 --- a/assets/test/socket_test.js +++ b/assets/test/socket_test.js @@ -605,6 +605,25 @@ describe("onConnOpen", () => { assert.ok(spy.calledOnce) }) + it("resets all channel timers and schedules a timeout if the timer was in progress", () => { + const channel = socket.channel("topic", {}) + const channel2 = socket.channel("topic2", {}) + + channel.rejoinTimer.tries = 1 + channel2.rejoinTimer.tries = 2 + channel2.rejoinTimer.scheduleTimeout() + + assert.equal(channel.rejoinTimer.timer, null) + assert.notEqual(channel2.rejoinTimer.timer, null) + + socket.onConnOpen() + + assert.equal(channel.rejoinTimer.tries, 0) + assert.equal(channel2.rejoinTimer.tries, 0) + assert.equal(channel.rejoinTimer.timer, null) + assert.notEqual(channel2.rejoinTimer.timer, null) + }) + it("triggers onOpen callback", () => { const spy = sinon.spy() From ddb9f7d07e4d02105098838ebcd0f87792ccc676 Mon Sep 17 00:00:00 2001 From: Tan Jay Jun Date: Thu, 8 Nov 2018 02:03:39 +0800 Subject: [PATCH 05/61] Document Phoenix.Presence callbacks (#3132) --- lib/phoenix/presence.ex | 124 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 114 insertions(+), 10 deletions(-) diff --git a/lib/phoenix/presence.ex b/lib/phoenix/presence.ex index b50a3ee1c7..3b041a97b1 100644 --- a/lib/phoenix/presence.ex +++ b/lib/phoenix/presence.ex @@ -82,15 +82,15 @@ defmodule Phoenix.Presence do including the `:metas` key, but can extend the map of information to include any additional information. For example: - def fetch(_topic, entries) do + def fetch(_topic, presences) do query = from u in User, - where: u.id in ^Map.keys(entries), + where: u.id in ^Map.keys(presences), select: {u.id, u} - users = query |> Repo.all |> Enum.into(%{}) + users = query |> Repo.all() |> Enum.into(%{}) - for {key, %{metas: metas}} <- entries, into: %{} do + for {key, %{metas: metas}} <- presences, into: %{} do {key, %{metas: metas, user: users[key]}} end end @@ -107,16 +107,120 @@ defmodule Phoenix.Presence do @type presence :: %{key: String.t, meta: map()} @type topic :: String.t - @callback start_link(Keyword.t) :: {:ok, pid()} | {:error, reason :: term()} | :ignore + @doc false + @callback start_link(Keyword.t) :: + {:ok, pid()} | + {:error, reason :: term()} | + :ignore + + @doc false @callback init(Keyword.t) :: {:ok, state :: term} | {:error, reason :: term} - @callback track(Phoenix.Socket.t, key :: String.t, meta :: map()) :: {:ok, binary()} | {:error, reason :: term()} - @callback track(pid, topic, key :: String.t, meta :: map()) :: {:ok, binary()} | {:error, reason :: term()} - @callback untrack(Phoenix.Socket.t, key :: String.t) :: :ok + + @doc """ + Track a channel's process as a presence. + + Tracked presences are grouped by `key`, cast as a string. For example, to + group each user's channels together, use user IDs as keys. Each presence can + be associated with a map of metadata to store small, emphemeral state, such as + a user's online status. To store detailed information, see `fetch/2`. + + ## Example + + alias MyApp.Presence + def handle_info(:after_join, socket) do + {:ok, _} = Presence.track(socket, socket.assigns.user_id, %{ + online_at: inspect(System.system_time(:second)) + }) + {:noreply, socket} + end + + """ + @callback track(socket :: Phoenix.Socket.t, key :: String.t, meta :: map()) :: + {:ok, ref :: binary()} | + {:error, reason :: term()} + + @doc """ + Track an arbitary process as a presence. + + Same with `track/3`, except track any process by `topic` and `key`. + """ + @callback track(pid, topic, key :: String.t, meta :: map()) :: + {:ok, ref :: binary()} | + {:error, reason :: term()} + + @doc """ + Stop tracking a channel's process. + """ + @callback untrack(socket :: Phoenix.Socket.t, key :: String.t) :: :ok + + @doc """ + Stop tracking a process. + """ @callback untrack(pid, topic, key :: String.t) :: :ok - @callback update(Phoenix.Socket.t, key :: String.t, meta :: map() | (map() -> map())) :: {:ok, binary()} | {:error, reason :: term()} - @callback update(pid, topic, key :: String.t, meta :: map() | (map() -> map())) :: {:ok, binary()} | {:error, reason :: term()} + + @doc """ + Update a channel presence's metadata. + + Replace a presence's metadata by passing a new map or a function that takes + the current map and returns a new one. + """ + @callback update(socket :: Phoenix.Socket.t, key :: String.t, meta :: map() | (map() -> map())) :: + {:ok, ref :: binary()} | + {:error, reason :: term()} + + @doc """ + Update a process presence's metadata. + + Same as `update/3`, but with an arbitary process. + """ + @callback update(pid, topic, key :: String.t, meta :: map() | (map() -> map())) :: + {:ok, ref :: binary()} | + {:error, reason :: term()} + + @doc """ + Extend presence information with additional data. + + When `list/1` is used to list all presences of the given `topic`, this + callback is triggered once to modify the result before it is broadcasted to + all channel subscribers. This avoids N query problems and provides a single + place to extend presence metadata. You must return a map of data matching the + original result, including the `:metas` key, but can extend the map to include + any additional information. + + The default implementation simply passes `presences` through unchanged. + + ## Example + + def fetch(_topic, presences) do + query = + from u in User, + where: u.id in ^Map.keys(presences), + select: {u.id, u} + + users = query |> Repo.all() |> Enum.into(%{}) + for {key, %{metas: metas}} <- presences, into: %{} do + {key, %{metas: metas, user: users[key]}} + end + end + + """ @callback fetch(topic, presences) :: presences + + @doc """ + Returns presences for a channel. + + Calls `list/2` with presence module. + """ + @callback list(socket :: Phoenix.Socket.t) :: presences + + @doc """ + Returns presences for a topic. + + Calls `list/2` with presence module. + """ @callback list(topic) :: presences + + @doc false @callback handle_diff(%{topic => {joins :: presences, leaves :: presences}}, state :: term) :: {:ok, state :: term} defmacro __using__(opts) do From 8720941870d7c3362ef10e42c6e65ae0886d59e4 Mon Sep 17 00:00:00 2001 From: Chris McCord Date: Wed, 7 Nov 2018 13:13:45 -0500 Subject: [PATCH 06/61] Update compiled assets --- assets/package-lock.json | 3054 ++++++++++----------- installer/templates/phx_assets/phoenix.js | 2 +- priv/static/phoenix.js | 2 +- 3 files changed, 1529 insertions(+), 1529 deletions(-) diff --git a/assets/package-lock.json b/assets/package-lock.json index 23932262a2..7f2e3a81fa 100644 --- a/assets/package-lock.json +++ b/assets/package-lock.json @@ -10,7 +10,7 @@ "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", "dev": true, "requires": { - "@babel/highlight": "^7.0.0" + "@babel/highlight": "7.0.0" } }, "@babel/core": { @@ -19,20 +19,20 @@ "integrity": "sha512-IFeSSnjXdhDaoysIlev//UzHZbdEmm7D0EIH2qtse9xK7mXEZQpYjs2P00XlP1qYsYvid79p+Zgg6tz1mp6iVw==", "dev": true, "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.1.2", - "@babel/helpers": "^7.1.2", - "@babel/parser": "^7.1.2", - "@babel/template": "^7.1.2", - "@babel/traverse": "^7.1.0", - "@babel/types": "^7.1.2", - "convert-source-map": "^1.1.0", - "debug": "^3.1.0", - "json5": "^0.5.0", - "lodash": "^4.17.10", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" + "@babel/code-frame": "7.0.0", + "@babel/generator": "7.1.2", + "@babel/helpers": "7.1.2", + "@babel/parser": "7.1.2", + "@babel/template": "7.1.2", + "@babel/traverse": "7.1.0", + "@babel/types": "7.1.2", + "convert-source-map": "1.6.0", + "debug": "3.2.5", + "json5": "0.5.1", + "lodash": "4.17.11", + "resolve": "1.8.1", + "semver": "5.5.1", + "source-map": "0.5.7" }, "dependencies": { "debug": { @@ -41,7 +41,7 @@ "integrity": "sha512-D61LaDQPQkxJ5AUM2mbSJRbPkNs/TmdmOeLAi1hgDkpDfIfetSrjmWhccwtuResSwMbACjx/xXQofvM9CE/aeg==", "dev": true, "requires": { - "ms": "^2.1.1" + "ms": "2.1.1" } }, "ms": { @@ -58,11 +58,11 @@ "integrity": "sha512-70A9HWLS/1RHk3Ck8tNHKxOoKQuSKocYgwDN85Pyl/RBduss6AKxUR7RIZ/lzduQMSYfWEM4DDBu6A+XGbkFig==", "dev": true, "requires": { - "@babel/types": "^7.1.2", - "jsesc": "^2.5.1", - "lodash": "^4.17.10", - "source-map": "^0.5.0", - "trim-right": "^1.0.1" + "@babel/types": "7.1.2", + "jsesc": "2.5.1", + "lodash": "4.17.11", + "source-map": "0.5.7", + "trim-right": "1.0.1" }, "dependencies": { "jsesc": { @@ -79,7 +79,7 @@ "integrity": "sha512-3UYcJUj9kvSLbLbUIfQTqzcy5VX7GRZ/CCDrnOaZorFFM01aXp1+GJwuFGV4NDDoAS+mOUyHcO6UD/RfqOks3Q==", "dev": true, "requires": { - "@babel/types": "^7.0.0" + "@babel/types": "7.1.2" } }, "@babel/helper-builder-binary-assignment-operator-visitor": { @@ -88,8 +88,8 @@ "integrity": "sha512-qNSR4jrmJ8M1VMM9tibvyRAHXQs2PmaksQF7c1CGJNipfe3D8p+wgNwgso/P2A2r2mdgBWAXljNWR0QRZAMW8w==", "dev": true, "requires": { - "@babel/helper-explode-assignable-expression": "^7.1.0", - "@babel/types": "^7.0.0" + "@babel/helper-explode-assignable-expression": "7.1.0", + "@babel/types": "7.1.2" } }, "@babel/helper-builder-react-jsx": { @@ -98,8 +98,8 @@ "integrity": "sha512-ebJ2JM6NAKW0fQEqN8hOLxK84RbRz9OkUhGS/Xd5u56ejMfVbayJ4+LykERZCOUM6faa6Fp3SZNX3fcT16MKHw==", "dev": true, "requires": { - "@babel/types": "^7.0.0", - "esutils": "^2.0.0" + "@babel/types": "7.1.2", + "esutils": "2.0.2" } }, "@babel/helper-call-delegate": { @@ -108,9 +108,9 @@ "integrity": "sha512-YEtYZrw3GUK6emQHKthltKNZwszBcHK58Ygcis+gVUrF4/FmTVr5CCqQNSfmvg2y+YDEANyYoaLz/SHsnusCwQ==", "dev": true, "requires": { - "@babel/helper-hoist-variables": "^7.0.0", - "@babel/traverse": "^7.1.0", - "@babel/types": "^7.0.0" + "@babel/helper-hoist-variables": "7.0.0", + "@babel/traverse": "7.1.0", + "@babel/types": "7.1.2" } }, "@babel/helper-define-map": { @@ -119,9 +119,9 @@ "integrity": "sha512-yPPcW8dc3gZLN+U1mhYV91QU3n5uTbx7DUdf8NnPbjS0RMwBuHi9Xt2MUgppmNz7CJxTBWsGczTiEp1CSOTPRg==", "dev": true, "requires": { - "@babel/helper-function-name": "^7.1.0", - "@babel/types": "^7.0.0", - "lodash": "^4.17.10" + "@babel/helper-function-name": "7.1.0", + "@babel/types": "7.1.2", + "lodash": "4.17.11" } }, "@babel/helper-explode-assignable-expression": { @@ -130,8 +130,8 @@ "integrity": "sha512-NRQpfHrJ1msCHtKjbzs9YcMmJZOg6mQMmGRB+hbamEdG5PNpaSm95275VD92DvJKuyl0s2sFiDmMZ+EnnvufqA==", "dev": true, "requires": { - "@babel/traverse": "^7.1.0", - "@babel/types": "^7.0.0" + "@babel/traverse": "7.1.0", + "@babel/types": "7.1.2" } }, "@babel/helper-function-name": { @@ -140,9 +140,9 @@ "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", "dev": true, "requires": { - "@babel/helper-get-function-arity": "^7.0.0", - "@babel/template": "^7.1.0", - "@babel/types": "^7.0.0" + "@babel/helper-get-function-arity": "7.0.0", + "@babel/template": "7.1.2", + "@babel/types": "7.1.2" } }, "@babel/helper-get-function-arity": { @@ -151,7 +151,7 @@ "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", "dev": true, "requires": { - "@babel/types": "^7.0.0" + "@babel/types": "7.1.2" } }, "@babel/helper-hoist-variables": { @@ -160,7 +160,7 @@ "integrity": "sha512-Ggv5sldXUeSKsuzLkddtyhyHe2YantsxWKNi7A+7LeD12ExRDWTRk29JCXpaHPAbMaIPZSil7n+lq78WY2VY7w==", "dev": true, "requires": { - "@babel/types": "^7.0.0" + "@babel/types": "7.1.2" } }, "@babel/helper-member-expression-to-functions": { @@ -169,7 +169,7 @@ "integrity": "sha512-avo+lm/QmZlv27Zsi0xEor2fKcqWG56D5ae9dzklpIaY7cQMK5N8VSpaNVPPagiqmy7LrEjK1IWdGMOqPu5csg==", "dev": true, "requires": { - "@babel/types": "^7.0.0" + "@babel/types": "7.1.2" } }, "@babel/helper-module-imports": { @@ -178,7 +178,7 @@ "integrity": "sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A==", "dev": true, "requires": { - "@babel/types": "^7.0.0" + "@babel/types": "7.1.2" } }, "@babel/helper-module-transforms": { @@ -187,12 +187,12 @@ "integrity": "sha512-0JZRd2yhawo79Rcm4w0LwSMILFmFXjugG3yqf+P/UsKsRS1mJCmMwwlHDlMg7Avr9LrvSpp4ZSULO9r8jpCzcw==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/helper-simple-access": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.0.0", - "@babel/template": "^7.1.0", - "@babel/types": "^7.0.0", - "lodash": "^4.17.10" + "@babel/helper-module-imports": "7.0.0", + "@babel/helper-simple-access": "7.1.0", + "@babel/helper-split-export-declaration": "7.0.0", + "@babel/template": "7.1.2", + "@babel/types": "7.1.2", + "lodash": "4.17.11" } }, "@babel/helper-optimise-call-expression": { @@ -201,7 +201,7 @@ "integrity": "sha512-u8nd9NQePYNQV8iPWu/pLLYBqZBa4ZaY1YWRFMuxrid94wKI1QNt67NEZ7GAe5Kc/0LLScbim05xZFWkAdrj9g==", "dev": true, "requires": { - "@babel/types": "^7.0.0" + "@babel/types": "7.1.2" } }, "@babel/helper-plugin-utils": { @@ -216,7 +216,7 @@ "integrity": "sha512-TR0/N0NDCcUIUEbqV6dCO+LptmmSQFQ7q70lfcEB4URsjD0E1HzicrwUH+ap6BAQ2jhCX9Q4UqZy4wilujWlkg==", "dev": true, "requires": { - "lodash": "^4.17.10" + "lodash": "4.17.11" } }, "@babel/helper-remap-async-to-generator": { @@ -225,11 +225,11 @@ "integrity": "sha512-3fOK0L+Fdlg8S5al8u/hWE6vhufGSn0bN09xm2LXMy//REAF8kDCrYoOBKYmA8m5Nom+sV9LyLCwrFynA8/slg==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.0.0", - "@babel/helper-wrap-function": "^7.1.0", - "@babel/template": "^7.1.0", - "@babel/traverse": "^7.1.0", - "@babel/types": "^7.0.0" + "@babel/helper-annotate-as-pure": "7.0.0", + "@babel/helper-wrap-function": "7.1.0", + "@babel/template": "7.1.2", + "@babel/traverse": "7.1.0", + "@babel/types": "7.1.2" } }, "@babel/helper-replace-supers": { @@ -238,10 +238,10 @@ "integrity": "sha512-BvcDWYZRWVuDeXTYZWxekQNO5D4kO55aArwZOTFXw6rlLQA8ZaDicJR1sO47h+HrnCiDFiww0fSPV0d713KBGQ==", "dev": true, "requires": { - "@babel/helper-member-expression-to-functions": "^7.0.0", - "@babel/helper-optimise-call-expression": "^7.0.0", - "@babel/traverse": "^7.1.0", - "@babel/types": "^7.0.0" + "@babel/helper-member-expression-to-functions": "7.0.0", + "@babel/helper-optimise-call-expression": "7.0.0", + "@babel/traverse": "7.1.0", + "@babel/types": "7.1.2" } }, "@babel/helper-simple-access": { @@ -250,8 +250,8 @@ "integrity": "sha512-Vk+78hNjRbsiu49zAPALxTb+JUQCz1aolpd8osOF16BGnLtseD21nbHgLPGUwrXEurZgiCOUmvs3ExTu4F5x6w==", "dev": true, "requires": { - "@babel/template": "^7.1.0", - "@babel/types": "^7.0.0" + "@babel/template": "7.1.2", + "@babel/types": "7.1.2" } }, "@babel/helper-split-export-declaration": { @@ -260,7 +260,7 @@ "integrity": "sha512-MXkOJqva62dfC0w85mEf/LucPPS/1+04nmmRMPEBUB++hiiThQ2zPtX/mEWQ3mtzCEjIJvPY8nuwxXtQeQwUag==", "dev": true, "requires": { - "@babel/types": "^7.0.0" + "@babel/types": "7.1.2" } }, "@babel/helper-wrap-function": { @@ -269,10 +269,10 @@ "integrity": "sha512-R6HU3dete+rwsdAfrOzTlE9Mcpk4RjU3aX3gi9grtmugQY0u79X7eogUvfXA5sI81Mfq1cn6AgxihfN33STjJA==", "dev": true, "requires": { - "@babel/helper-function-name": "^7.1.0", - "@babel/template": "^7.1.0", - "@babel/traverse": "^7.1.0", - "@babel/types": "^7.0.0" + "@babel/helper-function-name": "7.1.0", + "@babel/template": "7.1.2", + "@babel/traverse": "7.1.0", + "@babel/types": "7.1.2" } }, "@babel/helpers": { @@ -281,9 +281,9 @@ "integrity": "sha512-Myc3pUE8eswD73aWcartxB16K6CGmHDv9KxOmD2CeOs/FaEAQodr3VYGmlvOmog60vNQ2w8QbatuahepZwrHiA==", "dev": true, "requires": { - "@babel/template": "^7.1.2", - "@babel/traverse": "^7.1.0", - "@babel/types": "^7.1.2" + "@babel/template": "7.1.2", + "@babel/traverse": "7.1.0", + "@babel/types": "7.1.2" } }, "@babel/highlight": { @@ -292,9 +292,9 @@ "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", "dev": true, "requires": { - "chalk": "^2.0.0", - "esutils": "^2.0.2", - "js-tokens": "^4.0.0" + "chalk": "2.4.1", + "esutils": "2.0.2", + "js-tokens": "4.0.0" }, "dependencies": { "ansi-styles": { @@ -303,7 +303,7 @@ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { - "color-convert": "^1.9.0" + "color-convert": "1.9.3" } }, "chalk": { @@ -312,9 +312,9 @@ "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", "dev": true, "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" } }, "js-tokens": { @@ -329,7 +329,7 @@ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -346,9 +346,9 @@ "integrity": "sha512-Fq803F3Jcxo20MXUSDdmZZXrPe6BWyGcWBPPNB/M7WaUYESKDeKMOGIxEzQOjGSmW/NWb6UaPZrtTB2ekhB/ew==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-remap-async-to-generator": "^7.1.0", - "@babel/plugin-syntax-async-generators": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0", + "@babel/helper-remap-async-to-generator": "7.1.0", + "@babel/plugin-syntax-async-generators": "7.0.0" } }, "@babel/plugin-proposal-class-properties": { @@ -357,12 +357,12 @@ "integrity": "sha512-/PCJWN+CKt5v1xcGn4vnuu13QDoV+P7NcICP44BoonAJoPSGwVkgrXihFIQGiEjjPlUDBIw1cM7wYFLARS2/hw==", "dev": true, "requires": { - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-member-expression-to-functions": "^7.0.0", - "@babel/helper-optimise-call-expression": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-replace-supers": "^7.1.0", - "@babel/plugin-syntax-class-properties": "^7.0.0" + "@babel/helper-function-name": "7.1.0", + "@babel/helper-member-expression-to-functions": "7.0.0", + "@babel/helper-optimise-call-expression": "7.0.0", + "@babel/helper-plugin-utils": "7.0.0", + "@babel/helper-replace-supers": "7.1.0", + "@babel/plugin-syntax-class-properties": "7.0.0" } }, "@babel/plugin-proposal-decorators": { @@ -371,10 +371,10 @@ "integrity": "sha512-YooynBO6PmBgHvAd0fl5e5Tq/a0pEC6RqF62ouafme8FzdIVH41Mz/u1dn8fFVm4jzEJ+g/MsOxouwybJPuP8Q==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-replace-supers": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.0.0", - "@babel/plugin-syntax-decorators": "^7.1.0" + "@babel/helper-plugin-utils": "7.0.0", + "@babel/helper-replace-supers": "7.1.0", + "@babel/helper-split-export-declaration": "7.0.0", + "@babel/plugin-syntax-decorators": "7.1.0" } }, "@babel/plugin-proposal-do-expressions": { @@ -383,8 +383,8 @@ "integrity": "sha512-fIXsLAsQ5gVhQF44wZ9Yc3EBxaCHzeNjd8z9ivEzKOQyv5VoU1YJQ3AZa0VJgQMX5k/cbXJpNwp2mtg7iSdiGg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-do-expressions": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0", + "@babel/plugin-syntax-do-expressions": "7.0.0" } }, "@babel/plugin-proposal-export-default-from": { @@ -393,8 +393,8 @@ "integrity": "sha512-cWhkx6SyjZ4caFOanoPmDNgQCuYYTmou4QXy886JsyLTw/vhWQbop2gLKsWyyswrJkKTB7fSNxVYbP/oEsoySA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-export-default-from": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0", + "@babel/plugin-syntax-export-default-from": "7.0.0" } }, "@babel/plugin-proposal-export-namespace-from": { @@ -403,8 +403,8 @@ "integrity": "sha512-UZuK8lkobh3570vCu0sxDQn+ZlCV6CVLlXe+nNohvPr6/zI5I+j4Ir2fTTCG0ayBQanym0N+29K5+v4c8SATaQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-export-namespace-from": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0", + "@babel/plugin-syntax-export-namespace-from": "7.0.0" } }, "@babel/plugin-proposal-function-bind": { @@ -413,8 +413,8 @@ "integrity": "sha512-CNLspFXoquetQqPTFRedMvF7VYpsY2IecFu7Gcb86w+70lXojIKHhX1QFt5dhyk5n4MsjKrdXlGipbCFqD0Xeg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-function-bind": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0", + "@babel/plugin-syntax-function-bind": "7.0.0" } }, "@babel/plugin-proposal-function-sent": { @@ -423,9 +423,9 @@ "integrity": "sha512-yciM4dketj0pjd1enirzfVWclzSCzjOljHx8E4DJUBq/q65CuaKsX2zhpdImzcn6TtFupzdcuchbqN00IEKDAA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-wrap-function": "^7.1.0", - "@babel/plugin-syntax-function-sent": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0", + "@babel/helper-wrap-function": "7.1.0", + "@babel/plugin-syntax-function-sent": "7.0.0" } }, "@babel/plugin-proposal-json-strings": { @@ -434,8 +434,8 @@ "integrity": "sha512-kfVdUkIAGJIVmHmtS/40i/fg/AGnw/rsZBCaapY5yjeO5RA9m165Xbw9KMOu2nqXP5dTFjEjHdfNdoVcHv133Q==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-json-strings": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0", + "@babel/plugin-syntax-json-strings": "7.0.0" } }, "@babel/plugin-proposal-logical-assignment-operators": { @@ -444,8 +444,8 @@ "integrity": "sha512-06osaVN0bKEIXvzScf6qPpbDUEP4sixqVdjwpSPPwEtMyDC+x8PDvcJCww6p6TDOTIHnuUx2Afmguf/RypKDIw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-logical-assignment-operators": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0", + "@babel/plugin-syntax-logical-assignment-operators": "7.0.0" } }, "@babel/plugin-proposal-nullish-coalescing-operator": { @@ -454,8 +454,8 @@ "integrity": "sha512-QIN3UFo1ul4ruAsjIqK43PeXedo1qY74zeGrODJl1KfCGeMc6qJC4rb5Ylml/smzxibqsDeVZGH+TmWHCldRQQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0", + "@babel/plugin-syntax-nullish-coalescing-operator": "7.0.0" } }, "@babel/plugin-proposal-numeric-separator": { @@ -464,8 +464,8 @@ "integrity": "sha512-m4iDNpbBv2rTxxgViAeaqLOStc2wrlVAC5ifp6pjBPG29F56LdlPgf5CQYzj99y3kYeKqsyf/dcMx/r+QfwMZg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-numeric-separator": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0", + "@babel/plugin-syntax-numeric-separator": "7.0.0" } }, "@babel/plugin-proposal-object-rest-spread": { @@ -474,8 +474,8 @@ "integrity": "sha512-14fhfoPcNu7itSen7Py1iGN0gEm87hX/B+8nZPqkdmANyyYWYMY2pjA3r8WXbWVKMzfnSNS0xY8GVS0IjXi/iw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-object-rest-spread": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0", + "@babel/plugin-syntax-object-rest-spread": "7.0.0" } }, "@babel/plugin-proposal-optional-catch-binding": { @@ -484,8 +484,8 @@ "integrity": "sha512-JPqAvLG1s13B/AuoBjdBYvn38RqW6n1TzrQO839/sIpqLpbnXKacsAgpZHzLD83Sm8SDXMkkrAvEnJ25+0yIpw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-optional-catch-binding": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0", + "@babel/plugin-syntax-optional-catch-binding": "7.0.0" } }, "@babel/plugin-proposal-optional-chaining": { @@ -494,8 +494,8 @@ "integrity": "sha512-7x8HLa71OzNiofbQUVakS0Kmg++6a+cXNfS7QKHbbv03SuSaumJyaWsfNgw+T7aqrJlqurYpZqrkPgXu0iZK0w==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-optional-chaining": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0", + "@babel/plugin-syntax-optional-chaining": "7.0.0" } }, "@babel/plugin-proposal-pipeline-operator": { @@ -504,8 +504,8 @@ "integrity": "sha512-MN189PDyTMoor/YFh9dk6HpSZLMGHCXRdAhgmzshwcalbgYh5Mkn7Ib17lOo6fmLwHdyQ4GR4yagizfeR2LwQQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-pipeline-operator": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0", + "@babel/plugin-syntax-pipeline-operator": "7.0.0" } }, "@babel/plugin-proposal-throw-expressions": { @@ -514,8 +514,8 @@ "integrity": "sha512-CA2EUiwnbXrsdV4hy3jYghm91WaL7zL7xYfu628dyItRr6gylbRxshghGEK/Hhm//rR58N3PBmEeuYqSW57IUQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-throw-expressions": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0", + "@babel/plugin-syntax-throw-expressions": "7.0.0" } }, "@babel/plugin-proposal-unicode-property-regex": { @@ -524,9 +524,9 @@ "integrity": "sha512-tM3icA6GhC3ch2SkmSxv7J/hCWKISzwycub6eGsDrFDgukD4dZ/I+x81XgW0YslS6mzNuQ1Cbzh5osjIMgepPQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-regex": "^7.0.0", - "regexpu-core": "^4.2.0" + "@babel/helper-plugin-utils": "7.0.0", + "@babel/helper-regex": "7.0.0", + "regexpu-core": "4.2.0" }, "dependencies": { "jsesc": { @@ -541,12 +541,12 @@ "integrity": "sha512-Z835VSnJJ46CNBttalHD/dB+Sj2ezmY6Xp38npwU87peK6mqOzOpV8eYktdkLTEkzzD+JsTcxd84ozd8I14+rw==", "dev": true, "requires": { - "regenerate": "^1.4.0", - "regenerate-unicode-properties": "^7.0.0", - "regjsgen": "^0.4.0", - "regjsparser": "^0.3.0", - "unicode-match-property-ecmascript": "^1.0.4", - "unicode-match-property-value-ecmascript": "^1.0.2" + "regenerate": "1.4.0", + "regenerate-unicode-properties": "7.0.0", + "regjsgen": "0.4.0", + "regjsparser": "0.3.0", + "unicode-match-property-ecmascript": "1.0.4", + "unicode-match-property-value-ecmascript": "1.0.2" } }, "regjsgen": { @@ -561,7 +561,7 @@ "integrity": "sha512-zza72oZBBHzt64G7DxdqrOo/30bhHkwMUoT0WqfGu98XLd7N+1tsy5MJ96Bk4MD0y74n629RhmrGW6XlnLLwCA==", "dev": true, "requires": { - "jsesc": "~0.5.0" + "jsesc": "0.5.0" } } } @@ -572,7 +572,7 @@ "integrity": "sha512-im7ged00ddGKAjcZgewXmp1vxSZQQywuQXe2B1A7kajjZmDeY/ekMPmWr9zJgveSaQH0k7BcGrojQhcK06l0zA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-syntax-class-properties": { @@ -581,7 +581,7 @@ "integrity": "sha512-cR12g0Qzn4sgkjrbrzWy2GE7m9vMl/sFkqZ3gIpAQdrvPDnLM8180i+ANDFIXfjHo9aqp0ccJlQ0QNZcFUbf9w==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-syntax-decorators": { @@ -590,7 +590,7 @@ "integrity": "sha512-uQvRSbgQ0nQg3jsmIixXXDCgSpkBolJ9X7NYThMKCcjvE8dN2uWJUzTUNNAeuKOjARTd+wUQV0ztXpgunZYKzQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-syntax-do-expressions": { @@ -599,7 +599,7 @@ "integrity": "sha512-ZN5MO2WuYfznTK0/TRlF9qG+pBGV/bY5CRO9/a00XEGvaU31JAewRbYaZrySDw6kwSdtPG76yk9jZdPrEC3jWg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-syntax-dynamic-import": { @@ -608,7 +608,7 @@ "integrity": "sha512-Gt9xNyRrCHCiyX/ZxDGOcBnlJl0I3IWicpZRC4CdC0P5a/I07Ya2OAMEBU+J7GmRFVmIetqEYRko6QYRuKOESw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-syntax-export-default-from": { @@ -617,7 +617,7 @@ "integrity": "sha512-HNnjg/fFFbnuLAqr/Ocp1Y3GB4AjmXcu1xxn3ql3bS2kGrB/qi+Povshb8i3hOkE5jNozzh8r/0/lq1w8oOWbQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-syntax-export-namespace-from": { @@ -626,7 +626,7 @@ "integrity": "sha512-l314XT1eMa0MWboSmG4BdKukHfSpSpQRenUoZmEpL6hqc5nc1/ddpLETjPB77gZE1dZ9qxy5D3U3UUjjcX2d4g==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-syntax-flow": { @@ -635,7 +635,7 @@ "integrity": "sha512-zGcuZWiWWDa5qTZ6iAnpG0fnX/GOu49pGR5PFvkQ9GmKNaSphXQnlNXh/LG20sqWtNrx/eB6krzfEzcwvUyeFA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-syntax-function-bind": { @@ -644,7 +644,7 @@ "integrity": "sha512-dGxXCBMhRgdoJdTDouuC5sTRqZihfm4bKTWCJOXpTknZnmb1AozdvoNQA8V1WCccwk0IGKr0LaCbsQDQNp48JA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-syntax-function-sent": { @@ -653,7 +653,7 @@ "integrity": "sha512-j+D8C+clbieA+1UFlRzMkVozWNLB94TCJsUUE7OCyKBRM329ZZXnFPjgm0em5ddLsKV9DNpdtaOZsNZ1J7gHyA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-syntax-import-meta": { @@ -662,7 +662,7 @@ "integrity": "sha512-FEoGvhXVAiWzpDjyZIlBGzKyNk/lnRPy7aPke3PjVkiAY0QFsvFfkjUg5diRwVfowBA8SJqvFt0ZoXNSjl70hQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-syntax-json-strings": { @@ -671,7 +671,7 @@ "integrity": "sha512-UlSfNydC+XLj4bw7ijpldc1uZ/HB84vw+U6BTuqMdIEmz/LDe63w/GHtpQMdXWdqQZFeAI9PjnHe/vDhwirhKA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-syntax-jsx": { @@ -680,7 +680,7 @@ "integrity": "sha512-PdmL2AoPsCLWxhIr3kG2+F9v4WH06Q3z+NoGVpQgnUNGcagXHq5sB3OXxkSahKq9TLdNMN/AJzFYSOo8UKDMHg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-syntax-logical-assignment-operators": { @@ -689,7 +689,7 @@ "integrity": "sha512-eOcVPYWpdReMfxHZIBRjC5wlB8iU7kM6eQyst0kK6SwUPmpYNKyB4rJdf0HTeUEOSRqdlH6uMiLAzReA0qDGLQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-syntax-nullish-coalescing-operator": { @@ -698,7 +698,7 @@ "integrity": "sha512-oAJmMsAvTSIk9y0sZdU2S/nY44PEUuHN7EzNDMgbuR4e/OwyfR9lSmoBJBZ2lslFZIqhksrTt4i+av7uKfNYDw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-syntax-numeric-separator": { @@ -707,7 +707,7 @@ "integrity": "sha512-t9RMUPWsFXVeUZxEOhIDkVqYLi1sWOTjxFBAp8wJtaARilvkGlEQvSObd2W5YKicDktINI9XmdV0sB2FZaLOpw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-syntax-object-rest-spread": { @@ -716,7 +716,7 @@ "integrity": "sha512-5A0n4p6bIiVe5OvQPxBnesezsgFJdHhSs3uFSvaPdMqtsovajLZ+G2vZyvNe10EzJBWWo3AcHGKhAFUxqwp2dw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-syntax-optional-catch-binding": { @@ -725,7 +725,7 @@ "integrity": "sha512-Wc+HVvwjcq5qBg1w5RG9o9RVzmCaAg/Vp0erHCKpAYV8La6I94o4GQAmFYNmkzoMO6gzoOSulpKeSSz6mPEoZw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-syntax-optional-chaining": { @@ -734,7 +734,7 @@ "integrity": "sha512-QXedQsZf8yua1nNrXSePT0TsGSQH9A1iK08m9dhCMdZeJaaxYcQfXdgHWVV6Cp7WE/afPVvSKIsAHK5wP+yxDA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-syntax-pipeline-operator": { @@ -743,7 +743,7 @@ "integrity": "sha512-McK1JV4klGq2r0UZ1SLE2u+u37ElArBcPMGl6JizdgEXD3ttp0dpOB5ZpqpeRHkIgnl46th64UHrFDteQ4P5aw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-syntax-throw-expressions": { @@ -752,7 +752,7 @@ "integrity": "sha512-/5uORdWlPta/ALhI5zKtm0Y9vAYOa7HJMML0OnCGk9XZA4hpGjb0Xjt/OVDCJVawC/4FrlAGCHOaj9BtWeVDvg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-transform-arrow-functions": { @@ -761,7 +761,7 @@ "integrity": "sha512-2EZDBl1WIO/q4DIkIp4s86sdp4ZifL51MoIviLY/gG/mLSuOIEg7J8o6mhbxOTvUJkaN50n+8u41FVsr5KLy/w==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-transform-async-to-generator": { @@ -770,9 +770,9 @@ "integrity": "sha512-rNmcmoQ78IrvNCIt/R9U+cixUHeYAzgusTFgIAv+wQb9HJU4szhpDD6e5GCACmj/JP5KxuCwM96bX3L9v4ZN/g==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-remap-async-to-generator": "^7.1.0" + "@babel/helper-module-imports": "7.0.0", + "@babel/helper-plugin-utils": "7.0.0", + "@babel/helper-remap-async-to-generator": "7.1.0" } }, "@babel/plugin-transform-block-scoped-functions": { @@ -781,7 +781,7 @@ "integrity": "sha512-AOBiyUp7vYTqz2Jibe1UaAWL0Hl9JUXEgjFvvvcSc9MVDItv46ViXFw2F7SVt1B5k+KWjl44eeXOAk3UDEaJjQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-transform-block-scoping": { @@ -790,8 +790,8 @@ "integrity": "sha512-GWEMCrmHQcYWISilUrk9GDqH4enf3UmhOEbNbNrlNAX1ssH3MsS1xLOS6rdjRVPgA7XXVPn87tRkdTEoA/dxEg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "lodash": "^4.17.10" + "@babel/helper-plugin-utils": "7.0.0", + "lodash": "4.17.11" } }, "@babel/plugin-transform-classes": { @@ -800,14 +800,14 @@ "integrity": "sha512-rNaqoD+4OCBZjM7VaskladgqnZ1LO6o2UxuWSDzljzW21pN1KXkB7BstAVweZdxQkHAujps5QMNOTWesBciKFg==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.0.0", - "@babel/helper-define-map": "^7.1.0", - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-optimise-call-expression": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-replace-supers": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.0.0", - "globals": "^11.1.0" + "@babel/helper-annotate-as-pure": "7.0.0", + "@babel/helper-define-map": "7.1.0", + "@babel/helper-function-name": "7.1.0", + "@babel/helper-optimise-call-expression": "7.0.0", + "@babel/helper-plugin-utils": "7.0.0", + "@babel/helper-replace-supers": "7.1.0", + "@babel/helper-split-export-declaration": "7.0.0", + "globals": "11.8.0" }, "dependencies": { "globals": { @@ -824,7 +824,7 @@ "integrity": "sha512-ubouZdChNAv4AAWAgU7QKbB93NU5sHwInEWfp+/OzJKA02E6Woh9RVoX4sZrbRwtybky/d7baTUqwFx+HgbvMA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-transform-destructuring": { @@ -833,7 +833,7 @@ "integrity": "sha512-cvToXvp/OsYxtEn57XJu9BvsGSEYjAh9UeUuXpoi7x6QHB7YdWyQ4lRU/q0Fu1IJNT0o0u4FQ1DMQBzJ8/8vZg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-transform-dotall-regex": { @@ -842,9 +842,9 @@ "integrity": "sha512-00THs8eJxOJUFVx1w8i1MBF4XH4PsAjKjQ1eqN/uCH3YKwP21GCKfrn6YZFZswbOk9+0cw1zGQPHVc1KBlSxig==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-regex": "^7.0.0", - "regexpu-core": "^4.1.3" + "@babel/helper-plugin-utils": "7.0.0", + "@babel/helper-regex": "7.0.0", + "regexpu-core": "4.2.0" }, "dependencies": { "jsesc": { @@ -859,12 +859,12 @@ "integrity": "sha512-Z835VSnJJ46CNBttalHD/dB+Sj2ezmY6Xp38npwU87peK6mqOzOpV8eYktdkLTEkzzD+JsTcxd84ozd8I14+rw==", "dev": true, "requires": { - "regenerate": "^1.4.0", - "regenerate-unicode-properties": "^7.0.0", - "regjsgen": "^0.4.0", - "regjsparser": "^0.3.0", - "unicode-match-property-ecmascript": "^1.0.4", - "unicode-match-property-value-ecmascript": "^1.0.2" + "regenerate": "1.4.0", + "regenerate-unicode-properties": "7.0.0", + "regjsgen": "0.4.0", + "regjsparser": "0.3.0", + "unicode-match-property-ecmascript": "1.0.4", + "unicode-match-property-value-ecmascript": "1.0.2" } }, "regjsgen": { @@ -879,7 +879,7 @@ "integrity": "sha512-zza72oZBBHzt64G7DxdqrOo/30bhHkwMUoT0WqfGu98XLd7N+1tsy5MJ96Bk4MD0y74n629RhmrGW6XlnLLwCA==", "dev": true, "requires": { - "jsesc": "~0.5.0" + "jsesc": "0.5.0" } } } @@ -890,7 +890,7 @@ "integrity": "sha512-w2vfPkMqRkdxx+C71ATLJG30PpwtTpW7DDdLqYt2acXU7YjztzeWW2Jk1T6hKqCLYCcEA5UQM/+xTAm+QCSnuQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-transform-exponentiation-operator": { @@ -899,8 +899,8 @@ "integrity": "sha512-uZt9kD1Pp/JubkukOGQml9tqAeI8NkE98oZnHZ2qHRElmeKCodbTZgOEUtujSCSLhHSBWbzNiFSDIMC4/RBTLQ==", "dev": true, "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.1.0", - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-builder-binary-assignment-operator-visitor": "7.1.0", + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-transform-flow-strip-types": { @@ -909,8 +909,8 @@ "integrity": "sha512-WhXUNb4It5a19RsgKKbQPrjmy4yWOY1KynpEbNw7bnd1QTcrT/EIl3MJvnGgpgvrKyKbqX7nUNOJfkpLOnoDKA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-flow": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0", + "@babel/plugin-syntax-flow": "7.0.0" } }, "@babel/plugin-transform-for-of": { @@ -919,7 +919,7 @@ "integrity": "sha512-TlxKecN20X2tt2UEr2LNE6aqA0oPeMT1Y3cgz8k4Dn1j5ObT8M3nl9aA37LLklx0PBZKETC9ZAf9n/6SujTuXA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-transform-function-name": { @@ -928,8 +928,8 @@ "integrity": "sha512-VxOa1TMlFMtqPW2IDYZQaHsFrq/dDoIjgN098NowhexhZcz3UGlvPgZXuE1jEvNygyWyxRacqDpCZt+par1FNg==", "dev": true, "requires": { - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-function-name": "7.1.0", + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-transform-literals": { @@ -938,7 +938,7 @@ "integrity": "sha512-1NTDBWkeNXgpUcyoVFxbr9hS57EpZYXpje92zv0SUzjdu3enaRwF/l3cmyRnXLtIdyJASyiS6PtybK+CgKf7jA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-transform-modules-amd": { @@ -947,8 +947,8 @@ "integrity": "sha512-wt8P+xQ85rrnGNr2x1iV3DW32W8zrB6ctuBkYBbf5/ZzJY99Ob4MFgsZDFgczNU76iy9PWsy4EuxOliDjdKw6A==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.1.0", - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-module-transforms": "7.1.0", + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-transform-modules-commonjs": { @@ -957,9 +957,9 @@ "integrity": "sha512-wtNwtMjn1XGwM0AXPspQgvmE6msSJP15CX2RVfpTSTNPLhKhaOjaIfBaVfj4iUZ/VrFSodcFedwtPg/NxwQlPA==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.1.0", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-simple-access": "^7.1.0" + "@babel/helper-module-transforms": "7.1.0", + "@babel/helper-plugin-utils": "7.0.0", + "@babel/helper-simple-access": "7.1.0" } }, "@babel/plugin-transform-modules-systemjs": { @@ -968,8 +968,8 @@ "integrity": "sha512-8EDKMAsitLkiF/D4Zhe9CHEE2XLh4bfLbb9/Zf3FgXYQOZyZYyg7EAel/aT2A7bHv62jwHf09q2KU/oEexr83g==", "dev": true, "requires": { - "@babel/helper-hoist-variables": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-hoist-variables": "7.0.0", + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-transform-modules-umd": { @@ -978,8 +978,8 @@ "integrity": "sha512-enrRtn5TfRhMmbRwm7F8qOj0qEYByqUvTttPEGimcBH4CJHphjyK1Vg7sdU7JjeEmgSpM890IT/efS2nMHwYig==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.1.0", - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-module-transforms": "7.1.0", + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-transform-new-target": { @@ -988,7 +988,7 @@ "integrity": "sha512-yin069FYjah+LbqfGeTfzIBODex/e++Yfa0rH0fpfam9uTbuEeEOx5GLGr210ggOV77mVRNoeqSYqeuaqSzVSw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-transform-object-super": { @@ -997,8 +997,8 @@ "integrity": "sha512-/O02Je1CRTSk2SSJaq0xjwQ8hG4zhZGNjE8psTsSNPXyLRCODv7/PBozqT5AmQMzp7MI3ndvMhGdqp9c96tTEw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-replace-supers": "^7.1.0" + "@babel/helper-plugin-utils": "7.0.0", + "@babel/helper-replace-supers": "7.1.0" } }, "@babel/plugin-transform-parameters": { @@ -1007,9 +1007,9 @@ "integrity": "sha512-vHV7oxkEJ8IHxTfRr3hNGzV446GAb+0hgbA7o/0Jd76s+YzccdWuTU296FOCOl/xweU4t/Ya4g41yWz80RFCRw==", "dev": true, "requires": { - "@babel/helper-call-delegate": "^7.1.0", - "@babel/helper-get-function-arity": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-call-delegate": "7.1.0", + "@babel/helper-get-function-arity": "7.0.0", + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-transform-react-display-name": { @@ -1018,7 +1018,7 @@ "integrity": "sha512-BX8xKuQTO0HzINxT6j/GiCwoJB0AOMs0HmLbEnAvcte8U8rSkNa/eSCAY+l1OA4JnCVq2jw2p6U8QQryy2fTPg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-transform-react-jsx": { @@ -1027,9 +1027,9 @@ "integrity": "sha512-0TMP21hXsSUjIQJmu/r7RiVxeFrXRcMUigbKu0BLegJK9PkYodHstaszcig7zxXfaBji2LYUdtqIkHs+hgYkJQ==", "dev": true, "requires": { - "@babel/helper-builder-react-jsx": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-jsx": "^7.0.0" + "@babel/helper-builder-react-jsx": "7.0.0", + "@babel/helper-plugin-utils": "7.0.0", + "@babel/plugin-syntax-jsx": "7.0.0" } }, "@babel/plugin-transform-react-jsx-self": { @@ -1038,8 +1038,8 @@ "integrity": "sha512-pymy+AK12WO4safW1HmBpwagUQRl9cevNX+82AIAtU1pIdugqcH+nuYP03Ja6B+N4gliAaKWAegIBL/ymALPHA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-jsx": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0", + "@babel/plugin-syntax-jsx": "7.0.0" } }, "@babel/plugin-transform-react-jsx-source": { @@ -1048,8 +1048,8 @@ "integrity": "sha512-OSeEpFJEH5dw/TtxTg4nijl4nHBbhqbKL94Xo/Y17WKIf2qJWeIk/QeXACF19lG1vMezkxqruwnTjVizaW7u7w==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-jsx": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0", + "@babel/plugin-syntax-jsx": "7.0.0" } }, "@babel/plugin-transform-regenerator": { @@ -1058,7 +1058,7 @@ "integrity": "sha512-sj2qzsEx8KDVv1QuJc/dEfilkg3RRPvPYx/VnKLtItVQRWt1Wqf5eVCOLZm29CiGFfYYsA3VPjfizTCV0S0Dlw==", "dev": true, "requires": { - "regenerator-transform": "^0.13.3" + "regenerator-transform": "0.13.3" }, "dependencies": { "regenerator-transform": { @@ -1067,7 +1067,7 @@ "integrity": "sha512-5ipTrZFSq5vU2YoGoww4uaRVAK4wyYC4TSICibbfEPOruUu8FFP7ErV0BjmbIOEpn3O/k9na9UEdYR/3m7N6uA==", "dev": true, "requires": { - "private": "^0.1.6" + "private": "0.1.8" } } } @@ -1078,7 +1078,7 @@ "integrity": "sha512-g/99LI4vm5iOf5r1Gdxq5Xmu91zvjhEG5+yZDJW268AZELAu4J1EiFLnkSG3yuUsZyOipVOVUKoGPYwfsTymhw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-transform-spread": { @@ -1087,7 +1087,7 @@ "integrity": "sha512-L702YFy2EvirrR4shTj0g2xQp7aNwZoWNCkNu2mcoU0uyzMl0XRwDSwzB/xp6DSUFiBmEXuyAyEN16LsgVqGGQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-transform-sticky-regex": { @@ -1096,8 +1096,8 @@ "integrity": "sha512-LFUToxiyS/WD+XEWpkx/XJBrUXKewSZpzX68s+yEOtIbdnsRjpryDw9U06gYc6klYEij/+KQVRnD3nz3AoKmjw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-regex": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0", + "@babel/helper-regex": "7.0.0" } }, "@babel/plugin-transform-template-literals": { @@ -1106,8 +1106,8 @@ "integrity": "sha512-vA6rkTCabRZu7Nbl9DfLZE1imj4tzdWcg5vtdQGvj+OH9itNNB6hxuRMHuIY8SGnEt1T9g5foqs9LnrHzsqEFg==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-annotate-as-pure": "7.0.0", + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-transform-typeof-symbol": { @@ -1116,7 +1116,7 @@ "integrity": "sha512-1r1X5DO78WnaAIvs5uC48t41LLckxsYklJrZjNKcevyz83sF2l4RHbw29qrCPr/6ksFsdfRpT/ZgxNWHXRnffg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0" } }, "@babel/plugin-transform-unicode-regex": { @@ -1125,9 +1125,9 @@ "integrity": "sha512-uJBrJhBOEa3D033P95nPHu3nbFwFE9ZgXsfEitzoIXIwqAZWk7uXcg06yFKXz9FSxBH5ucgU/cYdX0IV8ldHKw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-regex": "^7.0.0", - "regexpu-core": "^4.1.3" + "@babel/helper-plugin-utils": "7.0.0", + "@babel/helper-regex": "7.0.0", + "regexpu-core": "4.2.0" }, "dependencies": { "jsesc": { @@ -1142,12 +1142,12 @@ "integrity": "sha512-Z835VSnJJ46CNBttalHD/dB+Sj2ezmY6Xp38npwU87peK6mqOzOpV8eYktdkLTEkzzD+JsTcxd84ozd8I14+rw==", "dev": true, "requires": { - "regenerate": "^1.4.0", - "regenerate-unicode-properties": "^7.0.0", - "regjsgen": "^0.4.0", - "regjsparser": "^0.3.0", - "unicode-match-property-ecmascript": "^1.0.4", - "unicode-match-property-value-ecmascript": "^1.0.2" + "regenerate": "1.4.0", + "regenerate-unicode-properties": "7.0.0", + "regjsgen": "0.4.0", + "regjsparser": "0.3.0", + "unicode-match-property-ecmascript": "1.0.4", + "unicode-match-property-value-ecmascript": "1.0.2" } }, "regjsgen": { @@ -1162,7 +1162,7 @@ "integrity": "sha512-zza72oZBBHzt64G7DxdqrOo/30bhHkwMUoT0WqfGu98XLd7N+1tsy5MJ96Bk4MD0y74n629RhmrGW6XlnLLwCA==", "dev": true, "requires": { - "jsesc": "~0.5.0" + "jsesc": "0.5.0" } } } @@ -1173,47 +1173,47 @@ "integrity": "sha512-ZLVSynfAoDHB/34A17/JCZbyrzbQj59QC1Anyueb4Bwjh373nVPq5/HMph0z+tCmcDjXDe+DlKQq9ywQuvWrQg==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-async-generator-functions": "^7.1.0", - "@babel/plugin-proposal-json-strings": "^7.0.0", - "@babel/plugin-proposal-object-rest-spread": "^7.0.0", - "@babel/plugin-proposal-optional-catch-binding": "^7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.0.0", - "@babel/plugin-syntax-async-generators": "^7.0.0", - "@babel/plugin-syntax-object-rest-spread": "^7.0.0", - "@babel/plugin-syntax-optional-catch-binding": "^7.0.0", - "@babel/plugin-transform-arrow-functions": "^7.0.0", - "@babel/plugin-transform-async-to-generator": "^7.1.0", - "@babel/plugin-transform-block-scoped-functions": "^7.0.0", - "@babel/plugin-transform-block-scoping": "^7.0.0", - "@babel/plugin-transform-classes": "^7.1.0", - "@babel/plugin-transform-computed-properties": "^7.0.0", - "@babel/plugin-transform-destructuring": "^7.0.0", - "@babel/plugin-transform-dotall-regex": "^7.0.0", - "@babel/plugin-transform-duplicate-keys": "^7.0.0", - "@babel/plugin-transform-exponentiation-operator": "^7.1.0", - "@babel/plugin-transform-for-of": "^7.0.0", - "@babel/plugin-transform-function-name": "^7.1.0", - "@babel/plugin-transform-literals": "^7.0.0", - "@babel/plugin-transform-modules-amd": "^7.1.0", - "@babel/plugin-transform-modules-commonjs": "^7.1.0", - "@babel/plugin-transform-modules-systemjs": "^7.0.0", - "@babel/plugin-transform-modules-umd": "^7.1.0", - "@babel/plugin-transform-new-target": "^7.0.0", - "@babel/plugin-transform-object-super": "^7.1.0", - "@babel/plugin-transform-parameters": "^7.1.0", - "@babel/plugin-transform-regenerator": "^7.0.0", - "@babel/plugin-transform-shorthand-properties": "^7.0.0", - "@babel/plugin-transform-spread": "^7.0.0", - "@babel/plugin-transform-sticky-regex": "^7.0.0", - "@babel/plugin-transform-template-literals": "^7.0.0", - "@babel/plugin-transform-typeof-symbol": "^7.0.0", - "@babel/plugin-transform-unicode-regex": "^7.0.0", - "browserslist": "^4.1.0", - "invariant": "^2.2.2", - "js-levenshtein": "^1.1.3", - "semver": "^5.3.0" + "@babel/helper-module-imports": "7.0.0", + "@babel/helper-plugin-utils": "7.0.0", + "@babel/plugin-proposal-async-generator-functions": "7.1.0", + "@babel/plugin-proposal-json-strings": "7.0.0", + "@babel/plugin-proposal-object-rest-spread": "7.0.0", + "@babel/plugin-proposal-optional-catch-binding": "7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "7.0.0", + "@babel/plugin-syntax-async-generators": "7.0.0", + "@babel/plugin-syntax-object-rest-spread": "7.0.0", + "@babel/plugin-syntax-optional-catch-binding": "7.0.0", + "@babel/plugin-transform-arrow-functions": "7.0.0", + "@babel/plugin-transform-async-to-generator": "7.1.0", + "@babel/plugin-transform-block-scoped-functions": "7.0.0", + "@babel/plugin-transform-block-scoping": "7.0.0", + "@babel/plugin-transform-classes": "7.1.0", + "@babel/plugin-transform-computed-properties": "7.0.0", + "@babel/plugin-transform-destructuring": "7.1.2", + "@babel/plugin-transform-dotall-regex": "7.0.0", + "@babel/plugin-transform-duplicate-keys": "7.0.0", + "@babel/plugin-transform-exponentiation-operator": "7.1.0", + "@babel/plugin-transform-for-of": "7.0.0", + "@babel/plugin-transform-function-name": "7.1.0", + "@babel/plugin-transform-literals": "7.0.0", + "@babel/plugin-transform-modules-amd": "7.1.0", + "@babel/plugin-transform-modules-commonjs": "7.1.0", + "@babel/plugin-transform-modules-systemjs": "7.0.0", + "@babel/plugin-transform-modules-umd": "7.1.0", + "@babel/plugin-transform-new-target": "7.0.0", + "@babel/plugin-transform-object-super": "7.1.0", + "@babel/plugin-transform-parameters": "7.1.0", + "@babel/plugin-transform-regenerator": "7.0.0", + "@babel/plugin-transform-shorthand-properties": "7.0.0", + "@babel/plugin-transform-spread": "7.0.0", + "@babel/plugin-transform-sticky-regex": "7.0.0", + "@babel/plugin-transform-template-literals": "7.0.0", + "@babel/plugin-transform-typeof-symbol": "7.0.0", + "@babel/plugin-transform-unicode-regex": "7.0.0", + "browserslist": "4.1.2", + "invariant": "2.2.4", + "js-levenshtein": "1.1.4", + "semver": "5.5.1" }, "dependencies": { "browserslist": { @@ -1222,9 +1222,9 @@ "integrity": "sha512-docXmVcYth9AiW5183dEe2IxnbmpXF4jiM6efGBVRAli/iDSS894Svvjenrv5NPqAJ4dEJULmT4MSvmLG9qoYg==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30000888", - "electron-to-chromium": "^1.3.73", - "node-releases": "^1.0.0-alpha.12" + "caniuse-lite": "1.0.30000888", + "electron-to-chromium": "1.3.73", + "node-releases": "1.0.0-alpha.12" } }, "caniuse-lite": { @@ -1247,8 +1247,8 @@ "integrity": "sha512-bJOHrYOPqJZCkPVbG1Lot2r5OSsB+iUOaxiHdlOeB1yPWS6evswVHwvkDLZ54WTaTRIk89ds0iHmGZSnxlPejQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-transform-flow-strip-types": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0", + "@babel/plugin-transform-flow-strip-types": "7.0.0" } }, "@babel/preset-react": { @@ -1257,11 +1257,11 @@ "integrity": "sha512-oayxyPS4Zj+hF6Et11BwuBkmpgT/zMxyuZgFrMeZID6Hdh3dGlk4sHCAhdBCpuCKW2ppBfl2uCCetlrUIJRY3w==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-transform-react-display-name": "^7.0.0", - "@babel/plugin-transform-react-jsx": "^7.0.0", - "@babel/plugin-transform-react-jsx-self": "^7.0.0", - "@babel/plugin-transform-react-jsx-source": "^7.0.0" + "@babel/helper-plugin-utils": "7.0.0", + "@babel/plugin-transform-react-display-name": "7.0.0", + "@babel/plugin-transform-react-jsx": "7.0.0", + "@babel/plugin-transform-react-jsx-self": "7.0.0", + "@babel/plugin-transform-react-jsx-source": "7.0.0" } }, "@babel/preset-stage-0": { @@ -1276,13 +1276,13 @@ "integrity": "sha512-f/+CRmaCe7rVEvcvPvxeA8j5aJhHC3aJie7YuqcMDhUOuyWLA7J/aNrTaHIzoWPEhpHA54mec4Mm8fv8KBlv3g==", "dev": true, "requires": { - "core-js": "^2.5.7", - "find-cache-dir": "^1.0.0", - "home-or-tmp": "^3.0.0", - "lodash": "^4.17.10", - "mkdirp": "^0.5.1", - "pirates": "^4.0.0", - "source-map-support": "^0.5.9" + "core-js": "2.5.7", + "find-cache-dir": "1.0.0", + "home-or-tmp": "3.0.0", + "lodash": "4.17.11", + "mkdirp": "0.5.1", + "pirates": "4.0.0", + "source-map-support": "0.5.9" }, "dependencies": { "home-or-tmp": { @@ -1303,8 +1303,8 @@ "integrity": "sha512-gR6Rw4MvUlYy83vP0vxoVNzM6t8MUXqNuRsuBmBHQDu1Fh6X015FrLdgoDKcNdkwGubozq0P4N0Q37UyFVr1EA==", "dev": true, "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" + "buffer-from": "1.1.1", + "source-map": "0.6.1" } } } @@ -1315,9 +1315,9 @@ "integrity": "sha512-SY1MmplssORfFiLDcOETrW7fCLl+PavlwMh92rrGcikQaRq4iWPVH0MpwPpY3etVMx6RnDjXtr6VZYr/IbP/Ag==", "dev": true, "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.1.2", - "@babel/types": "^7.1.2" + "@babel/code-frame": "7.0.0", + "@babel/parser": "7.1.2", + "@babel/types": "7.1.2" } }, "@babel/traverse": { @@ -1326,15 +1326,15 @@ "integrity": "sha512-bwgln0FsMoxm3pLOgrrnGaXk18sSM9JNf1/nHC/FksmNGFbYnPWY4GYCfLxyP1KRmfsxqkRpfoa6xr6VuuSxdw==", "dev": true, "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.0.0", - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.0.0", - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", - "debug": "^3.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.10" + "@babel/code-frame": "7.0.0", + "@babel/generator": "7.1.2", + "@babel/helper-function-name": "7.1.0", + "@babel/helper-split-export-declaration": "7.0.0", + "@babel/parser": "7.1.2", + "@babel/types": "7.1.2", + "debug": "3.2.5", + "globals": "11.8.0", + "lodash": "4.17.11" }, "dependencies": { "debug": { @@ -1343,7 +1343,7 @@ "integrity": "sha512-D61LaDQPQkxJ5AUM2mbSJRbPkNs/TmdmOeLAi1hgDkpDfIfetSrjmWhccwtuResSwMbACjx/xXQofvM9CE/aeg==", "dev": true, "requires": { - "ms": "^2.1.1" + "ms": "2.1.1" } }, "globals": { @@ -1366,9 +1366,9 @@ "integrity": "sha512-pb1I05sZEKiSlMUV9UReaqsCPUpgbHHHu2n1piRm7JkuBkm6QxcaIzKu6FMnMtCbih/cEYTR+RGYYC96Yk9HAg==", "dev": true, "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.10", - "to-fast-properties": "^2.0.0" + "esutils": "2.0.2", + "lodash": "4.17.11", + "to-fast-properties": "2.0.0" }, "dependencies": { "to-fast-properties": { @@ -1453,7 +1453,7 @@ "integrity": "sha512-HRcWcY+YWt4+s/CvQn+vnSPfRaD4KkuzQFt5MNaELXXHSjelHlSEA8ZcqT69q0GTIuLWZ6JaoKar4yWHVpZHsQ==", "dev": true, "requires": { - "@xtuc/ieee754": "^1.2.0" + "@xtuc/ieee754": "1.2.0" } }, "@webassemblyjs/leb128": { @@ -1569,8 +1569,8 @@ "integrity": "sha512-Y7vfi3I5oMOYIr+WxV8NZxDSwcbNgzdKYsTNInmycOq9bUYwGg9ryu57Wg5NLmCjqdFPNUmpMBo3kSJN9tCbXg==", "dev": true, "requires": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" + "jsonparse": "1.3.1", + "through": "2.3.8" } }, "abab": { @@ -1591,7 +1591,7 @@ "integrity": "sha512-zVWV8Z8lislJoOKKqdNMOB+s6+XV5WERty8MnKBeFgwA+19XJjJHs2RP5dzM57FftIs+jQnRToLiWazKr6sSWg==", "dev": true, "requires": { - "acorn": "^5.0.0" + "acorn": "5.7.3" } }, "acorn-globals": { @@ -1600,7 +1600,7 @@ "integrity": "sha1-VbtemGkVB7dFedBRNBMhfDgMVM8=", "dev": true, "requires": { - "acorn": "^2.1.0" + "acorn": "2.7.0" }, "dependencies": { "acorn": { @@ -1617,10 +1617,10 @@ "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", "dev": true, "requires": { - "co": "^4.6.0", - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" + "co": "4.6.0", + "fast-deep-equal": "1.1.0", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.3.1" } }, "ajv-keywords": { @@ -1653,8 +1653,8 @@ "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", "dev": true, "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" + "micromatch": "3.1.10", + "normalize-path": "2.1.1" } }, "append-buffer": { @@ -1663,7 +1663,7 @@ "integrity": "sha1-2CIM9GYIFSXv6lBhTz3mUU36WPE=", "dev": true, "requires": { - "buffer-equal": "^1.0.0" + "buffer-equal": "1.0.0" } }, "aproba": { @@ -1678,7 +1678,7 @@ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "requires": { - "sprintf-js": "~1.0.2" + "sprintf-js": "1.0.3" } }, "arr-flatten": { @@ -1705,7 +1705,7 @@ "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", "dev": true, "requires": { - "safer-buffer": "~2.1.0" + "safer-buffer": "2.1.2" } }, "asn1.js": { @@ -1714,9 +1714,9 @@ "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", "dev": true, "requires": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" + "bn.js": "4.11.8", + "inherits": "2.0.3", + "minimalistic-assert": "1.0.1" } }, "assert": { @@ -1793,10 +1793,10 @@ "integrity": "sha512-fhBhNkUToJcW9nV46v8w87AJOwAJDz84c1CL57n3Stj73FANM/b9TbCUK4YhdOwEyZ+OxhYpdeZDNzSI29Firw==", "dev": true, "requires": { - "find-cache-dir": "^1.0.0", - "loader-utils": "^1.0.2", - "mkdirp": "^0.5.1", - "util.promisify": "^1.0.0" + "find-cache-dir": "1.0.0", + "loader-utils": "1.1.0", + "mkdirp": "0.5.1", + "util.promisify": "1.0.0" } }, "babelify": { @@ -1823,13 +1823,13 @@ "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", "dev": true, "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" + "cache-base": "1.0.1", + "class-utils": "0.3.6", + "component-emitter": "1.2.1", + "define-property": "1.0.0", + "isobject": "3.0.1", + "mixin-deep": "1.3.1", + "pascalcase": "0.1.1" }, "dependencies": { "define-property": { @@ -1838,7 +1838,7 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "^1.0.0" + "is-descriptor": "1.0.2" } }, "is-accessor-descriptor": { @@ -1847,7 +1847,7 @@ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-data-descriptor": { @@ -1856,7 +1856,7 @@ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-descriptor": { @@ -1865,9 +1865,9 @@ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" } }, "isobject": { @@ -1897,7 +1897,7 @@ "dev": true, "optional": true, "requires": { - "tweetnacl": "^0.14.3" + "tweetnacl": "0.14.5" } }, "big.js": { @@ -1930,10 +1930,10 @@ "integrity": "sha1-5LoM5BCkaTYyM2dgnstOZVMSUGk=", "dev": true, "requires": { - "continuable-cache": "^0.3.1", - "error": "^7.0.0", - "raw-body": "~1.1.0", - "safe-json-parse": "~1.0.1" + "continuable-cache": "0.3.1", + "error": "7.0.2", + "raw-body": "1.1.7", + "safe-json-parse": "1.0.1" } }, "brace-expansion": { @@ -1942,7 +1942,7 @@ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { - "balanced-match": "^1.0.0", + "balanced-match": "1.0.0", "concat-map": "0.0.1" } }, @@ -1981,12 +1981,12 @@ "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "dev": true, "requires": { - "buffer-xor": "^1.0.3", - "cipher-base": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.3", - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" + "buffer-xor": "1.0.3", + "cipher-base": "1.0.4", + "create-hash": "1.2.0", + "evp_bytestokey": "1.0.3", + "inherits": "2.0.3", + "safe-buffer": "5.1.2" } }, "browserify-cipher": { @@ -1995,9 +1995,9 @@ "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", "dev": true, "requires": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.0" + "browserify-aes": "1.2.0", + "browserify-des": "1.0.2", + "evp_bytestokey": "1.0.3" } }, "browserify-des": { @@ -2006,10 +2006,10 @@ "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", "dev": true, "requires": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" + "cipher-base": "1.0.4", + "des.js": "1.0.0", + "inherits": "2.0.3", + "safe-buffer": "5.1.2" } }, "browserify-rsa": { @@ -2018,8 +2018,8 @@ "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", "dev": true, "requires": { - "bn.js": "^4.1.0", - "randombytes": "^2.0.1" + "bn.js": "4.11.8", + "randombytes": "2.0.6" } }, "browserify-sign": { @@ -2028,13 +2028,13 @@ "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", "dev": true, "requires": { - "bn.js": "^4.1.1", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.2", - "elliptic": "^6.0.0", - "inherits": "^2.0.1", - "parse-asn1": "^5.0.0" + "bn.js": "4.11.8", + "browserify-rsa": "4.0.1", + "create-hash": "1.2.0", + "create-hmac": "1.1.7", + "elliptic": "6.4.1", + "inherits": "2.0.3", + "parse-asn1": "5.1.1" } }, "browserify-zlib": { @@ -2043,7 +2043,7 @@ "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", "dev": true, "requires": { - "pako": "~1.0.5" + "pako": "1.0.6" } }, "buffer": { @@ -2052,9 +2052,9 @@ "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", "dev": true, "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" + "base64-js": "1.3.0", + "ieee754": "1.1.12", + "isarray": "1.0.0" } }, "buffer-equal": { @@ -2105,19 +2105,19 @@ "integrity": "sha512-Dph0MzuH+rTQzGPNT9fAnrPmMmjKfST6trxJeK7NQuHRaVw24VzPRWTmg9MpcwOVQZO0E1FBICUlFeNaKPIfHA==", "dev": true, "requires": { - "bluebird": "^3.5.1", - "chownr": "^1.0.1", - "glob": "^7.1.2", - "graceful-fs": "^4.1.11", - "lru-cache": "^4.1.1", - "mississippi": "^2.0.0", - "mkdirp": "^0.5.1", - "move-concurrently": "^1.0.1", - "promise-inflight": "^1.0.1", - "rimraf": "^2.6.2", - "ssri": "^5.2.4", - "unique-filename": "^1.1.0", - "y18n": "^4.0.0" + "bluebird": "3.5.2", + "chownr": "1.1.1", + "glob": "7.1.3", + "graceful-fs": "4.1.11", + "lru-cache": "4.1.3", + "mississippi": "2.0.0", + "mkdirp": "0.5.1", + "move-concurrently": "1.0.1", + "promise-inflight": "1.0.1", + "rimraf": "2.6.2", + "ssri": "5.3.0", + "unique-filename": "1.1.1", + "y18n": "4.0.0" }, "dependencies": { "lru-cache": { @@ -2126,8 +2126,8 @@ "integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==", "dev": true, "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" + "pseudomap": "1.0.2", + "yallist": "2.1.2" } }, "y18n": { @@ -2144,15 +2144,15 @@ "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", "dev": true, "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" + "collection-visit": "1.0.0", + "component-emitter": "1.2.1", + "get-value": "2.0.6", + "has-value": "1.0.0", + "isobject": "3.0.1", + "set-value": "2.0.0", + "to-object-path": "0.3.0", + "union-value": "1.0.0", + "unset-value": "1.0.0" }, "dependencies": { "isobject": { @@ -2193,9 +2193,9 @@ "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", "dev": true, "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "ansi-styles": { @@ -2204,7 +2204,7 @@ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { - "color-convert": "^1.9.0" + "color-convert": "1.9.3" } } } @@ -2239,19 +2239,19 @@ "integrity": "sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ==", "dev": true, "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.0", - "braces": "^2.3.0", - "fsevents": "^1.2.2", - "glob-parent": "^3.1.0", - "inherits": "^2.0.1", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "lodash.debounce": "^4.0.8", - "normalize-path": "^2.1.1", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.0.0", - "upath": "^1.0.5" + "anymatch": "2.0.0", + "async-each": "1.0.1", + "braces": "2.3.2", + "fsevents": "1.2.4", + "glob-parent": "3.1.0", + "inherits": "2.0.3", + "is-binary-path": "1.0.1", + "is-glob": "4.0.0", + "lodash.debounce": "4.0.8", + "normalize-path": "2.1.1", + "path-is-absolute": "1.0.1", + "readdirp": "2.2.1", + "upath": "1.1.0" }, "dependencies": { "array-unique": { @@ -2266,16 +2266,16 @@ "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "dev": true, "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" + "arr-flatten": "1.1.0", + "array-unique": "0.3.2", + "extend-shallow": "2.0.1", + "fill-range": "4.0.0", + "isobject": "3.0.1", + "repeat-element": "1.1.3", + "snapdragon": "0.8.2", + "snapdragon-node": "2.1.1", + "split-string": "3.1.0", + "to-regex": "3.0.2" } }, "extend-shallow": { @@ -2284,7 +2284,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } }, "fill-range": { @@ -2293,10 +2293,10 @@ "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", "dev": true, "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" + "extend-shallow": "2.0.1", + "is-number": "3.0.0", + "repeat-string": "1.6.1", + "to-regex-range": "2.1.1" } }, "glob-parent": { @@ -2305,8 +2305,8 @@ "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", "dev": true, "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" + "is-glob": "3.1.0", + "path-dirname": "1.0.2" }, "dependencies": { "is-glob": { @@ -2315,7 +2315,7 @@ "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", "dev": true, "requires": { - "is-extglob": "^2.1.0" + "is-extglob": "2.1.1" } } } @@ -2332,7 +2332,7 @@ "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", "dev": true, "requires": { - "is-extglob": "^2.1.1" + "is-extglob": "2.1.1" } }, "is-number": { @@ -2341,7 +2341,7 @@ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" } }, "isobject": { @@ -2364,7 +2364,7 @@ "integrity": "sha512-xDbVgyfDTT2piup/h8dK/y4QZfJRSa73bw1WZ8b4XM1o7fsFubUVGYcE+1ANtOzJJELGpYoG2961z0Z6OAld9A==", "dev": true, "requires": { - "tslib": "^1.9.0" + "tslib": "1.9.3" } }, "cipher-base": { @@ -2373,8 +2373,8 @@ "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", "dev": true, "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" + "inherits": "2.0.3", + "safe-buffer": "5.1.2" } }, "class-utils": { @@ -2383,10 +2383,10 @@ "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", "dev": true, "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" + "arr-union": "3.1.0", + "define-property": "0.2.5", + "isobject": "3.0.1", + "static-extend": "0.1.2" }, "dependencies": { "define-property": { @@ -2395,7 +2395,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } }, "isobject": { @@ -2412,9 +2412,9 @@ "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", "dev": true, "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wrap-ansi": "^2.0.0" + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wrap-ansi": "2.1.0" } }, "clone": { @@ -2441,9 +2441,9 @@ "integrity": "sha512-Bq6+4t+lbM8vhTs/Bef5c5AdEMtapp/iFb6+s4/Hh9MVTt8OLKH7ZOOZSCT+Ys7hsHvqv0GuMPJ1lnQJVHvxpg==", "dev": true, "requires": { - "inherits": "^2.0.1", - "process-nextick-args": "^2.0.0", - "readable-stream": "^2.3.5" + "inherits": "2.0.3", + "process-nextick-args": "2.0.0", + "readable-stream": "2.3.6" } }, "co": { @@ -2470,8 +2470,8 @@ "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", "dev": true, "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" + "map-visit": "1.0.0", + "object-visit": "1.0.1" } }, "color-convert": { @@ -2495,7 +2495,7 @@ "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", "dev": true, "requires": { - "delayed-stream": "~1.0.0" + "delayed-stream": "1.0.0" } }, "comma-separated-tokens": { @@ -2537,10 +2537,10 @@ "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", "dev": true, "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" + "buffer-from": "1.1.1", + "inherits": "2.0.3", + "readable-stream": "2.3.6", + "typedarray": "0.0.6" } }, "console-browserify": { @@ -2549,7 +2549,7 @@ "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", "dev": true, "requires": { - "date-now": "^0.1.4" + "date-now": "0.1.4" } }, "constants-browserify": { @@ -2576,7 +2576,7 @@ "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", "dev": true, "requires": { - "safe-buffer": "~5.1.1" + "safe-buffer": "5.1.2" } }, "copy-concurrently": { @@ -2585,12 +2585,12 @@ "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", "dev": true, "requires": { - "aproba": "^1.1.1", - "fs-write-stream-atomic": "^1.0.8", - "iferr": "^0.1.5", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.0" + "aproba": "1.2.0", + "fs-write-stream-atomic": "1.0.10", + "iferr": "0.1.5", + "mkdirp": "0.5.1", + "rimraf": "2.6.2", + "run-queue": "1.0.3" } }, "copy-descriptor": { @@ -2617,8 +2617,8 @@ "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", "dev": true, "requires": { - "bn.js": "^4.1.0", - "elliptic": "^6.0.0" + "bn.js": "4.11.8", + "elliptic": "6.4.1" } }, "create-hash": { @@ -2627,11 +2627,11 @@ "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "dev": true, "requires": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" + "cipher-base": "1.0.4", + "inherits": "2.0.3", + "md5.js": "1.3.5", + "ripemd160": "2.0.2", + "sha.js": "2.4.11" } }, "create-hmac": { @@ -2640,12 +2640,12 @@ "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "dev": true, "requires": { - "cipher-base": "^1.0.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" + "cipher-base": "1.0.4", + "create-hash": "1.2.0", + "inherits": "2.0.3", + "ripemd160": "2.0.2", + "safe-buffer": "5.1.2", + "sha.js": "2.4.11" } }, "cross-spawn": { @@ -2654,11 +2654,11 @@ "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", "dev": true, "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + "nice-try": "1.0.5", + "path-key": "2.0.1", + "semver": "5.5.1", + "shebang-command": "1.2.0", + "which": "1.3.1" } }, "crypto-browserify": { @@ -2667,17 +2667,17 @@ "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", "dev": true, "requires": { - "browserify-cipher": "^1.0.0", - "browserify-sign": "^4.0.0", - "create-ecdh": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.0", - "diffie-hellman": "^5.0.0", - "inherits": "^2.0.1", - "pbkdf2": "^3.0.3", - "public-encrypt": "^4.0.0", - "randombytes": "^2.0.0", - "randomfill": "^1.0.3" + "browserify-cipher": "1.0.1", + "browserify-sign": "4.0.4", + "create-ecdh": "4.0.3", + "create-hash": "1.2.0", + "create-hmac": "1.1.7", + "diffie-hellman": "5.0.3", + "inherits": "2.0.3", + "pbkdf2": "3.0.17", + "public-encrypt": "4.0.3", + "randombytes": "2.0.6", + "randomfill": "1.0.4" } }, "cssom": { @@ -2692,7 +2692,7 @@ "integrity": "sha1-VBCXI0yyUTyDzu06zdwn/yeYfVQ=", "dev": true, "requires": { - "cssom": "0.3.x" + "cssom": "0.3.4" } }, "cyclist": { @@ -2707,7 +2707,7 @@ "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", "dev": true, "requires": { - "assert-plus": "^1.0.0" + "assert-plus": "1.0.0" } }, "date-now": { @@ -2755,7 +2755,7 @@ "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", "dev": true, "requires": { - "object-keys": "^1.0.12" + "object-keys": "1.0.12" } }, "define-property": { @@ -2764,8 +2764,8 @@ "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", "dev": true, "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" + "is-descriptor": "1.0.2", + "isobject": "3.0.1" }, "dependencies": { "is-accessor-descriptor": { @@ -2774,7 +2774,7 @@ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-data-descriptor": { @@ -2783,7 +2783,7 @@ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-descriptor": { @@ -2792,9 +2792,9 @@ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" } }, "isobject": { @@ -2829,8 +2829,8 @@ "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=", "dev": true, "requires": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" + "inherits": "2.0.3", + "minimalistic-assert": "1.0.1" } }, "detab": { @@ -2839,7 +2839,7 @@ "integrity": "sha512-/hhdqdQc5thGrqzjyO/pz76lDZ5GSuAs6goxOaKTsvPk7HNnzAyFN5lyHgqpX4/s1i66K8qMGj+VhA9504x7DQ==", "dev": true, "requires": { - "repeat-string": "^1.5.4" + "repeat-string": "1.6.1" } }, "detective": { @@ -2848,8 +2848,8 @@ "integrity": "sha512-H6PmeeUcZloWtdt4DAkFyzFL94arpHr3NOwwmVILFiy+9Qd4JTxxXrzfyGk/lmct2qVGBwTSwSXagqu2BxmWig==", "dev": true, "requires": { - "acorn": "^5.2.1", - "defined": "^1.0.0" + "acorn": "5.7.3", + "defined": "1.0.0" } }, "diff": { @@ -2864,9 +2864,9 @@ "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "dev": true, "requires": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.0.0" + "bn.js": "4.11.8", + "miller-rabin": "4.0.1", + "randombytes": "2.0.6" } }, "disparity": { @@ -2875,8 +2875,8 @@ "integrity": "sha1-V92stHMkrl9Y0swNqIbbTOnutxg=", "dev": true, "requires": { - "ansi-styles": "^2.0.1", - "diff": "^1.3.2" + "ansi-styles": "2.2.1", + "diff": "1.4.0" } }, "doctrine-temporary-fork": { @@ -2885,7 +2885,7 @@ "integrity": "sha512-+GQh3niRkKtSr7cKDo8po+NHkJZyC2Ebwvjz9fvq0ReQr9kIDS6BY9MDrzx+KbbLxvSj3vD/eUaeIoURHzEAFQ==", "dev": true, "requires": { - "esutils": "^2.0.2" + "esutils": "2.0.2" } }, "documentation": { @@ -2894,70 +2894,70 @@ "integrity": "sha512-fV93R6Dqs0cjvVjjmAK9c5wcFYo9j95oXL3yibJzlTZO2y1hHVHMN+xyD7YeSWKkqz+jWafYRXnJ/vIBYNq80g==", "dev": true, "requires": { - "@babel/core": "^7.0.0", - "@babel/generator": "^7.0.0", + "@babel/core": "7.1.2", + "@babel/generator": "7.1.2", "@babel/parser": "7.1.0", - "@babel/plugin-proposal-class-properties": "^7.0.0", - "@babel/plugin-proposal-decorators": "^7.0.0", - "@babel/plugin-proposal-do-expressions": "^7.0.0", - "@babel/plugin-proposal-export-default-from": "^7.0.0", - "@babel/plugin-proposal-export-namespace-from": "^7.0.0", - "@babel/plugin-proposal-function-bind": "^7.0.0", - "@babel/plugin-proposal-function-sent": "^7.0.0", - "@babel/plugin-proposal-json-strings": "^7.0.0", - "@babel/plugin-proposal-logical-assignment-operators": "^7.0.0", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.0.0", - "@babel/plugin-proposal-numeric-separator": "^7.0.0", - "@babel/plugin-proposal-optional-chaining": "^7.0.0", - "@babel/plugin-proposal-pipeline-operator": "^7.0.0", - "@babel/plugin-proposal-throw-expressions": "^7.0.0", - "@babel/plugin-syntax-dynamic-import": "^7.0.0", - "@babel/plugin-syntax-import-meta": "^7.0.0", - "@babel/preset-env": "^7.0.0", - "@babel/preset-flow": "^7.0.0", - "@babel/preset-react": "^7.0.0", - "@babel/preset-stage-0": "^7.0.0", - "@babel/traverse": "^7.1.0", - "@babel/types": "^7.0.0", - "ansi-html": "^0.0.7", - "babelify": "^10.0.0", - "chalk": "^2.3.0", - "chokidar": "^2.0.0", - "concat-stream": "^1.6.0", - "disparity": "^2.0.0", + "@babel/plugin-proposal-class-properties": "7.1.0", + "@babel/plugin-proposal-decorators": "7.1.2", + "@babel/plugin-proposal-do-expressions": "7.0.0", + "@babel/plugin-proposal-export-default-from": "7.0.0", + "@babel/plugin-proposal-export-namespace-from": "7.0.0", + "@babel/plugin-proposal-function-bind": "7.0.0", + "@babel/plugin-proposal-function-sent": "7.1.0", + "@babel/plugin-proposal-json-strings": "7.0.0", + "@babel/plugin-proposal-logical-assignment-operators": "7.0.0", + "@babel/plugin-proposal-nullish-coalescing-operator": "7.0.0", + "@babel/plugin-proposal-numeric-separator": "7.0.0", + "@babel/plugin-proposal-optional-chaining": "7.0.0", + "@babel/plugin-proposal-pipeline-operator": "7.0.0", + "@babel/plugin-proposal-throw-expressions": "7.0.0", + "@babel/plugin-syntax-dynamic-import": "7.0.0", + "@babel/plugin-syntax-import-meta": "7.0.0", + "@babel/preset-env": "7.1.0", + "@babel/preset-flow": "7.0.0", + "@babel/preset-react": "7.0.0", + "@babel/preset-stage-0": "7.0.0", + "@babel/traverse": "7.1.0", + "@babel/types": "7.1.2", + "ansi-html": "0.0.7", + "babelify": "10.0.0", + "chalk": "2.4.1", + "chokidar": "2.0.4", + "concat-stream": "1.6.2", + "disparity": "2.0.0", "doctrine-temporary-fork": "2.0.1", - "get-port": "^4.0.0", - "git-url-parse": "^10.0.1", + "get-port": "4.0.0", + "git-url-parse": "10.0.1", "github-slugger": "1.2.0", - "glob": "^7.1.2", - "globals-docs": "^2.4.0", - "highlight.js": "^9.12.0", - "js-yaml": "^3.10.0", - "lodash": "^4.17.10", - "mdast-util-inject": "^1.1.0", - "micromatch": "^3.1.5", - "mime": "^2.2.0", + "glob": "7.1.3", + "globals-docs": "2.4.0", + "highlight.js": "9.12.0", + "js-yaml": "3.12.0", + "lodash": "4.17.11", + "mdast-util-inject": "1.1.0", + "micromatch": "3.1.10", + "mime": "2.3.1", "module-deps-sortable": "5.0.0", - "parse-filepath": "^1.0.2", - "pify": "^4.0.0", - "read-pkg-up": "^4.0.0", - "remark": "^9.0.0", - "remark-html": "^8.0.0", - "remark-reference-links": "^4.0.1", - "remark-toc": "^5.0.0", + "parse-filepath": "1.0.2", + "pify": "4.0.0", + "read-pkg-up": "4.0.0", + "remark": "9.0.0", + "remark-html": "8.0.0", + "remark-reference-links": "4.0.2", + "remark-toc": "5.0.0", "remote-origin-url": "0.4.0", - "stream-array": "^1.1.2", - "strip-json-comments": "^2.0.1", - "tiny-lr": "^1.1.0", - "unist-builder": "^1.0.2", - "unist-util-visit": "^1.3.0", - "vfile": "^3.0.0", - "vfile-reporter": "^5.0.0", - "vfile-sort": "^2.1.0", - "vinyl": "^2.1.0", - "vinyl-fs": "^3.0.2", - "vue-template-compiler": "^2.5.16", - "yargs": "^9.0.1" + "stream-array": "1.1.2", + "strip-json-comments": "2.0.1", + "tiny-lr": "1.1.1", + "unist-builder": "1.0.3", + "unist-util-visit": "1.4.0", + "vfile": "3.0.0", + "vfile-reporter": "5.0.0", + "vfile-sort": "2.1.1", + "vinyl": "2.2.0", + "vinyl-fs": "3.0.3", + "vue-template-compiler": "2.5.17", + "yargs": "9.0.1" }, "dependencies": { "@babel/parser": { @@ -2972,7 +2972,7 @@ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { - "color-convert": "^1.9.0" + "color-convert": "1.9.3" } }, "chalk": { @@ -2981,9 +2981,9 @@ "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", "dev": true, "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" } }, "pify": { @@ -2998,7 +2998,7 @@ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -3015,7 +3015,7 @@ "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", "dev": true, "requires": { - "readable-stream": "^2.0.2" + "readable-stream": "2.3.6" } }, "duplexify": { @@ -3024,10 +3024,10 @@ "integrity": "sha512-fO3Di4tBKJpYTFHAxTU00BcfWMY9w24r/x21a6rZRbsD/ToUgGxsMbiGRmB7uVAXeGKXD9MwiLZa5E97EVgIRQ==", "dev": true, "requires": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", - "stream-shift": "^1.0.0" + "end-of-stream": "1.4.1", + "inherits": "2.0.3", + "readable-stream": "2.3.6", + "stream-shift": "1.0.0" } }, "ecc-jsbn": { @@ -3037,8 +3037,8 @@ "dev": true, "optional": true, "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" + "jsbn": "0.1.1", + "safer-buffer": "2.1.2" } }, "elliptic": { @@ -3047,13 +3047,13 @@ "integrity": "sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ==", "dev": true, "requires": { - "bn.js": "^4.4.0", - "brorand": "^1.0.1", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.0" + "bn.js": "4.11.8", + "brorand": "1.1.0", + "hash.js": "1.1.5", + "hmac-drbg": "1.0.1", + "inherits": "2.0.3", + "minimalistic-assert": "1.0.1", + "minimalistic-crypto-utils": "1.0.1" } }, "emoji-regex": { @@ -3074,7 +3074,7 @@ "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", "dev": true, "requires": { - "once": "^1.4.0" + "once": "1.4.0" } }, "enhanced-resolve": { @@ -3083,9 +3083,9 @@ "integrity": "sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng==", "dev": true, "requires": { - "graceful-fs": "^4.1.2", - "memory-fs": "^0.4.0", - "tapable": "^1.0.0" + "graceful-fs": "4.1.11", + "memory-fs": "0.4.1", + "tapable": "1.1.0" } }, "errno": { @@ -3094,7 +3094,7 @@ "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", "dev": true, "requires": { - "prr": "~1.0.1" + "prr": "1.0.1" } }, "error": { @@ -3103,8 +3103,8 @@ "integrity": "sha1-pfdf/02ZJhJt2sDqXcOOaJFTywI=", "dev": true, "requires": { - "string-template": "~0.2.1", - "xtend": "~4.0.0" + "string-template": "0.2.1", + "xtend": "4.0.1" } }, "error-ex": { @@ -3113,7 +3113,7 @@ "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "dev": true, "requires": { - "is-arrayish": "^0.2.1" + "is-arrayish": "0.2.1" } }, "es-abstract": { @@ -3122,11 +3122,11 @@ "integrity": "sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA==", "dev": true, "requires": { - "es-to-primitive": "^1.1.1", - "function-bind": "^1.1.1", - "has": "^1.0.1", - "is-callable": "^1.1.3", - "is-regex": "^1.0.4" + "es-to-primitive": "1.2.0", + "function-bind": "1.1.1", + "has": "1.0.3", + "is-callable": "1.1.4", + "is-regex": "1.0.4" } }, "es-to-primitive": { @@ -3135,9 +3135,9 @@ "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", "dev": true, "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" + "is-callable": "1.1.4", + "is-date-object": "1.0.1", + "is-symbol": "1.0.2" } }, "escape-string-regexp": { @@ -3152,11 +3152,11 @@ "integrity": "sha512-IeMV45ReixHS53K/OmfKAIztN/igDHzTJUhZM3k1jMhIZWjk45SMwAtBsEXiJp3vSPmTcu6CXn7mDvFHRN66fw==", "dev": true, "requires": { - "esprima": "^3.1.3", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" + "esprima": "3.1.3", + "estraverse": "4.2.0", + "esutils": "2.0.2", + "optionator": "0.8.2", + "source-map": "0.6.1" }, "dependencies": { "esprima": { @@ -3180,8 +3180,8 @@ "integrity": "sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA==", "dev": true, "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" + "esrecurse": "4.2.1", + "estraverse": "4.2.0" } }, "esprima": { @@ -3196,7 +3196,7 @@ "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", "dev": true, "requires": { - "estraverse": "^4.1.0" + "estraverse": "4.2.0" } }, "estraverse": { @@ -3223,8 +3223,8 @@ "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", "dev": true, "requires": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" + "md5.js": "1.3.5", + "safe-buffer": "5.1.2" } }, "execa": { @@ -3233,13 +3233,13 @@ "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", "dev": true, "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" + "cross-spawn": "5.1.0", + "get-stream": "3.0.0", + "is-stream": "1.1.0", + "npm-run-path": "2.0.2", + "p-finally": "1.0.0", + "signal-exit": "3.0.2", + "strip-eof": "1.0.0" }, "dependencies": { "cross-spawn": { @@ -3248,9 +3248,9 @@ "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", "dev": true, "requires": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + "lru-cache": "4.1.3", + "shebang-command": "1.2.0", + "which": "1.3.1" } }, "lru-cache": { @@ -3259,8 +3259,8 @@ "integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==", "dev": true, "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" + "pseudomap": "1.0.2", + "yallist": "2.1.2" } } } @@ -3283,8 +3283,8 @@ "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", "dev": true, "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" + "assign-symbols": "1.0.0", + "is-extendable": "1.0.1" }, "dependencies": { "is-extendable": { @@ -3293,7 +3293,7 @@ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "requires": { - "is-plain-object": "^2.0.4" + "is-plain-object": "2.0.4" } } } @@ -3328,7 +3328,7 @@ "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", "dev": true, "requires": { - "websocket-driver": ">=0.5.1" + "websocket-driver": "0.7.0" } }, "find-cache-dir": { @@ -3337,9 +3337,9 @@ "integrity": "sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=", "dev": true, "requires": { - "commondir": "^1.0.1", - "make-dir": "^1.0.0", - "pkg-dir": "^2.0.0" + "commondir": "1.0.1", + "make-dir": "1.3.0", + "pkg-dir": "2.0.0" } }, "find-up": { @@ -3348,7 +3348,7 @@ "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", "dev": true, "requires": { - "locate-path": "^2.0.0" + "locate-path": "2.0.0" } }, "flush-write-stream": { @@ -3357,8 +3357,8 @@ "integrity": "sha512-calZMC10u0FMUqoiunI2AiGIIUtUIvifNwkHhNupZH4cbNnW1Itkoh/Nf5HFYmDrwWPjrUxpkZT0KhuCq0jmGw==", "dev": true, "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.4" + "inherits": "2.0.3", + "readable-stream": "2.3.6" } }, "for-in": { @@ -3379,9 +3379,9 @@ "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", "dev": true, "requires": { - "asynckit": "^0.4.0", + "asynckit": "0.4.0", "combined-stream": "1.0.6", - "mime-types": "^2.1.12" + "mime-types": "2.1.20" } }, "formatio": { @@ -3390,7 +3390,7 @@ "integrity": "sha1-XtPM1jZVEJc4NGXZlhmRAOhhYek=", "dev": true, "requires": { - "samsam": "~1.1" + "samsam": "1.1.2" } }, "fragment-cache": { @@ -3399,7 +3399,7 @@ "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", "dev": true, "requires": { - "map-cache": "^0.2.2" + "map-cache": "0.2.2" } }, "from2": { @@ -3408,8 +3408,8 @@ "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", "dev": true, "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.0" + "inherits": "2.0.3", + "readable-stream": "2.3.6" } }, "fs-mkdirp-stream": { @@ -3418,8 +3418,8 @@ "integrity": "sha1-C3gV/DIBxqaeFNuYzgmMFpNSWes=", "dev": true, "requires": { - "graceful-fs": "^4.1.11", - "through2": "^2.0.3" + "graceful-fs": "4.1.11", + "through2": "2.0.3" } }, "fs-write-stream-atomic": { @@ -3428,10 +3428,10 @@ "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", "dev": true, "requires": { - "graceful-fs": "^4.1.2", - "iferr": "^0.1.5", - "imurmurhash": "^0.1.4", - "readable-stream": "1 || 2" + "graceful-fs": "4.1.11", + "iferr": "0.1.5", + "imurmurhash": "0.1.4", + "readable-stream": "2.3.6" } }, "fs.realpath": { @@ -3447,8 +3447,8 @@ "dev": true, "optional": true, "requires": { - "nan": "^2.9.2", - "node-pre-gyp": "^0.10.0" + "nan": "2.11.0", + "node-pre-gyp": "0.10.0" }, "dependencies": { "abbrev": { @@ -3474,8 +3474,8 @@ "dev": true, "optional": true, "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" + "delegates": "1.0.0", + "readable-stream": "2.3.6" } }, "balanced-match": { @@ -3488,7 +3488,7 @@ "bundled": true, "dev": true, "requires": { - "balanced-match": "^1.0.0", + "balanced-match": "1.0.0", "concat-map": "0.0.1" } }, @@ -3552,7 +3552,7 @@ "dev": true, "optional": true, "requires": { - "minipass": "^2.2.1" + "minipass": "2.2.4" } }, "fs.realpath": { @@ -3567,14 +3567,14 @@ "dev": true, "optional": true, "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" + "aproba": "1.2.0", + "console-control-strings": "1.1.0", + "has-unicode": "2.0.1", + "object-assign": "4.1.1", + "signal-exit": "3.0.2", + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wide-align": "1.1.2" } }, "glob": { @@ -3583,12 +3583,12 @@ "dev": true, "optional": true, "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" } }, "has-unicode": { @@ -3603,7 +3603,7 @@ "dev": true, "optional": true, "requires": { - "safer-buffer": "^2.1.0" + "safer-buffer": "2.1.2" } }, "ignore-walk": { @@ -3612,7 +3612,7 @@ "dev": true, "optional": true, "requires": { - "minimatch": "^3.0.4" + "minimatch": "3.0.4" } }, "inflight": { @@ -3621,8 +3621,8 @@ "dev": true, "optional": true, "requires": { - "once": "^1.3.0", - "wrappy": "1" + "once": "1.4.0", + "wrappy": "1.0.2" } }, "inherits": { @@ -3641,7 +3641,7 @@ "bundled": true, "dev": true, "requires": { - "number-is-nan": "^1.0.0" + "number-is-nan": "1.0.1" } }, "isarray": { @@ -3655,7 +3655,7 @@ "bundled": true, "dev": true, "requires": { - "brace-expansion": "^1.1.7" + "brace-expansion": "1.1.11" } }, "minimist": { @@ -3668,8 +3668,8 @@ "bundled": true, "dev": true, "requires": { - "safe-buffer": "^5.1.1", - "yallist": "^3.0.0" + "safe-buffer": "5.1.1", + "yallist": "3.0.2" } }, "minizlib": { @@ -3678,7 +3678,7 @@ "dev": true, "optional": true, "requires": { - "minipass": "^2.2.1" + "minipass": "2.2.4" } }, "mkdirp": { @@ -3701,9 +3701,9 @@ "dev": true, "optional": true, "requires": { - "debug": "^2.1.2", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" + "debug": "2.6.9", + "iconv-lite": "0.4.21", + "sax": "1.2.4" } }, "node-pre-gyp": { @@ -3712,16 +3712,16 @@ "dev": true, "optional": true, "requires": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.1", - "needle": "^2.2.0", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.1.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4" + "detect-libc": "1.0.3", + "mkdirp": "0.5.1", + "needle": "2.2.0", + "nopt": "4.0.1", + "npm-packlist": "1.1.10", + "npmlog": "4.1.2", + "rc": "1.2.7", + "rimraf": "2.6.2", + "semver": "5.5.0", + "tar": "4.4.1" } }, "nopt": { @@ -3730,8 +3730,8 @@ "dev": true, "optional": true, "requires": { - "abbrev": "1", - "osenv": "^0.1.4" + "abbrev": "1.1.1", + "osenv": "0.1.5" } }, "npm-bundled": { @@ -3746,8 +3746,8 @@ "dev": true, "optional": true, "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1" + "ignore-walk": "3.0.1", + "npm-bundled": "1.0.3" } }, "npmlog": { @@ -3756,10 +3756,10 @@ "dev": true, "optional": true, "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" + "are-we-there-yet": "1.1.4", + "console-control-strings": "1.1.0", + "gauge": "2.7.4", + "set-blocking": "2.0.0" } }, "number-is-nan": { @@ -3778,7 +3778,7 @@ "bundled": true, "dev": true, "requires": { - "wrappy": "1" + "wrappy": "1.0.2" } }, "os-homedir": { @@ -3799,8 +3799,8 @@ "dev": true, "optional": true, "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" + "os-homedir": "1.0.2", + "os-tmpdir": "1.0.2" } }, "path-is-absolute": { @@ -3821,10 +3821,10 @@ "dev": true, "optional": true, "requires": { - "deep-extend": "^0.5.1", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" + "deep-extend": "0.5.1", + "ini": "1.3.5", + "minimist": "1.2.0", + "strip-json-comments": "2.0.1" }, "dependencies": { "minimist": { @@ -3841,13 +3841,13 @@ "dev": true, "optional": true, "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.1", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" } }, "rimraf": { @@ -3856,7 +3856,7 @@ "dev": true, "optional": true, "requires": { - "glob": "^7.0.5" + "glob": "7.1.2" } }, "safe-buffer": { @@ -3899,9 +3899,9 @@ "bundled": true, "dev": true, "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" } }, "string_decoder": { @@ -3910,7 +3910,7 @@ "dev": true, "optional": true, "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.1" } }, "strip-ansi": { @@ -3918,7 +3918,7 @@ "bundled": true, "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "2.1.1" } }, "strip-json-comments": { @@ -3933,13 +3933,13 @@ "dev": true, "optional": true, "requires": { - "chownr": "^1.0.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.2.4", - "minizlib": "^1.1.0", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.1", - "yallist": "^3.0.2" + "chownr": "1.0.1", + "fs-minipass": "1.2.5", + "minipass": "2.2.4", + "minizlib": "1.1.0", + "mkdirp": "0.5.1", + "safe-buffer": "5.1.1", + "yallist": "3.0.2" } }, "util-deprecate": { @@ -3954,7 +3954,7 @@ "dev": true, "optional": true, "requires": { - "string-width": "^1.0.2" + "string-width": "1.0.2" } }, "wrappy": { @@ -4005,7 +4005,7 @@ "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", "dev": true, "requires": { - "assert-plus": "^1.0.0" + "assert-plus": "1.0.0" } }, "git-up": { @@ -4014,8 +4014,8 @@ "integrity": "sha512-2v4UN3qV2RGypD9QpmUjpk+4+RlYpW8GFuiZqQnKmvei08HsFPd0RfbDvEhnE4wBvnYs8ORVtYpOFuuCEmBVBw==", "dev": true, "requires": { - "is-ssh": "^1.3.0", - "parse-url": "^1.3.0" + "is-ssh": "1.3.0", + "parse-url": "1.3.11" } }, "git-url-parse": { @@ -4024,7 +4024,7 @@ "integrity": "sha512-Tq2u8UPXc/FawC/dO8bvh8jcck0Lkor5OhuZvmVSeyJGRucDBfw9y2zy/GNCx28lMYh1N12IzPwDexjUNFyAeg==", "dev": true, "requires": { - "git-up": "^2.0.0" + "git-up": "2.0.10" } }, "github-slugger": { @@ -4033,7 +4033,7 @@ "integrity": "sha512-wIaa75k1vZhyPm9yWrD08A5Xnx/V+RmzGrpjQuLemGKSb77Qukiaei58Bogrl/LZSADDfPzKJX8jhLs4CRTl7Q==", "dev": true, "requires": { - "emoji-regex": ">=6.0.0 <=6.1.1" + "emoji-regex": "6.1.1" } }, "glob": { @@ -4042,12 +4042,12 @@ "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", "dev": true, "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" } }, "glob-stream": { @@ -4056,16 +4056,16 @@ "integrity": "sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ=", "dev": true, "requires": { - "extend": "^3.0.0", - "glob": "^7.1.1", - "glob-parent": "^3.1.0", - "is-negated-glob": "^1.0.0", - "ordered-read-streams": "^1.0.0", - "pumpify": "^1.3.5", - "readable-stream": "^2.1.5", - "remove-trailing-separator": "^1.0.1", - "to-absolute-glob": "^2.0.0", - "unique-stream": "^2.0.2" + "extend": "3.0.2", + "glob": "7.1.3", + "glob-parent": "3.1.0", + "is-negated-glob": "1.0.0", + "ordered-read-streams": "1.0.1", + "pumpify": "1.5.1", + "readable-stream": "2.3.6", + "remove-trailing-separator": "1.1.0", + "to-absolute-glob": "2.0.2", + "unique-stream": "2.2.1" }, "dependencies": { "glob-parent": { @@ -4074,8 +4074,8 @@ "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", "dev": true, "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" + "is-glob": "3.1.0", + "path-dirname": "1.0.2" } }, "is-extglob": { @@ -4090,7 +4090,7 @@ "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", "dev": true, "requires": { - "is-extglob": "^2.1.0" + "is-extglob": "2.1.1" } } } @@ -4131,8 +4131,8 @@ "integrity": "sha512-+qnmNjI4OfH2ipQ9VQOw23bBd/ibtfbVdK2fYbY4acTDqKTW/YDp9McimZdDbG8iV9fZizUqQMD5xvriB146TA==", "dev": true, "requires": { - "ajv": "^5.3.0", - "har-schema": "^2.0.0" + "ajv": "5.5.2", + "har-schema": "2.0.0" } }, "has": { @@ -4141,7 +4141,7 @@ "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "dev": true, "requires": { - "function-bind": "^1.1.1" + "function-bind": "1.1.1" } }, "has-flag": { @@ -4162,9 +4162,9 @@ "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", "dev": true, "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" + "get-value": "2.0.6", + "has-values": "1.0.0", + "isobject": "3.0.1" }, "dependencies": { "isobject": { @@ -4181,8 +4181,8 @@ "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", "dev": true, "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" + "is-number": "3.0.0", + "kind-of": "4.0.0" }, "dependencies": { "is-number": { @@ -4191,7 +4191,7 @@ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -4200,7 +4200,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -4211,7 +4211,7 @@ "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -4222,8 +4222,8 @@ "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", "dev": true, "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" + "inherits": "2.0.3", + "safe-buffer": "5.1.2" } }, "hash.js": { @@ -4232,8 +4232,8 @@ "integrity": "sha512-eWI5HG9Np+eHV1KQhisXWwM+4EPPYe5dFX1UZZH7k/E3JzDEazVH+VGlZi6R94ZqImq+A3D1mCEtrFIfg/E7sA==", "dev": true, "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" + "inherits": "2.0.3", + "minimalistic-assert": "1.0.1" } }, "hast-util-is-element": { @@ -4248,7 +4248,7 @@ "integrity": "sha512-VwCTqjt6fbMGacxGB1FKV5sBJaVVkyCGVMDwb4nnqvCW2lkqscA2GEpOyBx4ZWRXty1eAZF58MHBrllEoQEoBg==", "dev": true, "requires": { - "xtend": "^4.0.1" + "xtend": "4.0.1" } }, "hast-util-to-html": { @@ -4257,16 +4257,16 @@ "integrity": "sha512-2emzwyf0xEsc4TBIPmDJmBttIw8R4SXAJiJZoiRR/s47ODYWgOqNoDbf2SJAbMbfNdFWMiCSOrI3OVnX6Qq2Mg==", "dev": true, "requires": { - "ccount": "^1.0.0", - "comma-separated-tokens": "^1.0.1", - "hast-util-is-element": "^1.0.0", - "hast-util-whitespace": "^1.0.0", - "html-void-elements": "^1.0.0", - "property-information": "^4.0.0", - "space-separated-tokens": "^1.0.0", - "stringify-entities": "^1.0.1", - "unist-util-is": "^2.0.0", - "xtend": "^4.0.1" + "ccount": "1.0.3", + "comma-separated-tokens": "1.0.5", + "hast-util-is-element": "1.0.1", + "hast-util-whitespace": "1.0.1", + "html-void-elements": "1.0.3", + "property-information": "4.2.0", + "space-separated-tokens": "1.1.2", + "stringify-entities": "1.3.2", + "unist-util-is": "2.1.2", + "xtend": "4.0.1" } }, "hast-util-whitespace": { @@ -4293,9 +4293,9 @@ "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", "dev": true, "requires": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" + "hash.js": "1.1.5", + "minimalistic-assert": "1.0.1", + "minimalistic-crypto-utils": "1.0.1" } }, "hosted-git-info": { @@ -4310,7 +4310,7 @@ "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", "dev": true, "requires": { - "whatwg-encoding": "^1.0.1" + "whatwg-encoding": "1.0.4" } }, "html-void-elements": { @@ -4331,9 +4331,9 @@ "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", "dev": true, "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" + "assert-plus": "1.0.0", + "jsprim": "1.4.1", + "sshpk": "1.14.2" } }, "https-browserify": { @@ -4348,7 +4348,7 @@ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, "requires": { - "safer-buffer": ">= 2.1.2 < 3" + "safer-buffer": "2.1.2" } }, "ieee754": { @@ -4369,8 +4369,8 @@ "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", "dev": true, "requires": { - "pkg-dir": "^3.0.0", - "resolve-cwd": "^2.0.0" + "pkg-dir": "3.0.0", + "resolve-cwd": "2.0.0" }, "dependencies": { "find-up": { @@ -4379,7 +4379,7 @@ "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "dev": true, "requires": { - "locate-path": "^3.0.0" + "locate-path": "3.0.0" } }, "locate-path": { @@ -4388,8 +4388,8 @@ "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "dev": true, "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" + "p-locate": "3.0.0", + "path-exists": "3.0.0" } }, "p-limit": { @@ -4398,7 +4398,7 @@ "integrity": "sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A==", "dev": true, "requires": { - "p-try": "^2.0.0" + "p-try": "2.0.0" } }, "p-locate": { @@ -4407,7 +4407,7 @@ "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "dev": true, "requires": { - "p-limit": "^2.0.0" + "p-limit": "2.0.0" } }, "p-try": { @@ -4422,7 +4422,7 @@ "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", "dev": true, "requires": { - "find-up": "^3.0.0" + "find-up": "3.0.0" } } } @@ -4445,8 +4445,8 @@ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { - "once": "^1.3.0", - "wrappy": "1" + "once": "1.4.0", + "wrappy": "1.0.2" } }, "inherits": { @@ -4473,7 +4473,7 @@ "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", "dev": true, "requires": { - "loose-envify": "^1.0.0" + "loose-envify": "1.4.0" } }, "invert-kv": { @@ -4488,8 +4488,8 @@ "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", "dev": true, "requires": { - "is-relative": "^1.0.0", - "is-windows": "^1.0.1" + "is-relative": "1.0.0", + "is-windows": "1.0.2" } }, "is-accessor-descriptor": { @@ -4498,7 +4498,7 @@ "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" } }, "is-alphabetical": { @@ -4519,8 +4519,8 @@ "integrity": "sha512-pyfU/0kHdISIgslFfZN9nfY1Gk3MquQgUm1mJTjdkEPpkAKNWuBTSqFwewOpR7N351VkErCiyV71zX7mlQQqsg==", "dev": true, "requires": { - "is-alphabetical": "^1.0.0", - "is-decimal": "^1.0.0" + "is-alphabetical": "1.0.2", + "is-decimal": "1.0.2" } }, "is-arrayish": { @@ -4535,7 +4535,7 @@ "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", "dev": true, "requires": { - "binary-extensions": "^1.0.0" + "binary-extensions": "1.11.0" } }, "is-buffer": { @@ -4550,7 +4550,7 @@ "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", "dev": true, "requires": { - "builtin-modules": "^1.0.0" + "builtin-modules": "1.1.1" } }, "is-callable": { @@ -4565,7 +4565,7 @@ "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "dev": true, "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" } }, "is-date-object": { @@ -4586,9 +4586,9 @@ "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", "dev": true, "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" + "is-accessor-descriptor": "0.1.6", + "is-data-descriptor": "0.1.4", + "kind-of": "5.1.0" }, "dependencies": { "kind-of": { @@ -4611,7 +4611,7 @@ "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, "requires": { - "number-is-nan": "^1.0.0" + "number-is-nan": "1.0.1" } }, "is-hexadecimal": { @@ -4638,7 +4638,7 @@ "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "dev": true, "requires": { - "isobject": "^3.0.1" + "isobject": "3.0.1" }, "dependencies": { "isobject": { @@ -4655,7 +4655,7 @@ "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", "dev": true, "requires": { - "has": "^1.0.1" + "has": "1.0.3" } }, "is-relative": { @@ -4664,7 +4664,7 @@ "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", "dev": true, "requires": { - "is-unc-path": "^1.0.0" + "is-unc-path": "1.0.0" } }, "is-ssh": { @@ -4673,7 +4673,7 @@ "integrity": "sha1-6+oRaaJhTaOSpjdANmw84EnY3/Y=", "dev": true, "requires": { - "protocols": "^1.1.0" + "protocols": "1.4.6" } }, "is-stream": { @@ -4688,7 +4688,7 @@ "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", "dev": true, "requires": { - "has-symbols": "^1.0.0" + "has-symbols": "1.0.0" } }, "is-typedarray": { @@ -4703,7 +4703,7 @@ "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", "dev": true, "requires": { - "unc-path-regex": "^0.1.2" + "unc-path-regex": "0.1.2" } }, "is-utf8": { @@ -4772,8 +4772,8 @@ "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", "dev": true, "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "argparse": "1.0.10", + "esprima": "4.0.1" } }, "jsbn": { @@ -4789,26 +4789,26 @@ "integrity": "sha1-/eKcEJwyoRMeC2xlkU5kGY+Xw3A=", "dev": true, "requires": { - "abab": "^1.0.0", - "acorn": "^2.4.0", - "acorn-globals": "^1.0.4", - "array-equal": "^1.0.0", - "content-type-parser": "^1.0.1", - "cssom": ">= 0.3.0 < 0.4.0", - "cssstyle": ">= 0.2.36 < 0.3.0", - "escodegen": "^1.6.1", - "html-encoding-sniffer": "^1.0.1", - "iconv-lite": "^0.4.13", - "nwmatcher": ">= 1.3.7 < 2.0.0", - "parse5": "^1.5.1", - "request": "^2.55.0", - "sax": "^1.1.4", - "symbol-tree": ">= 3.1.0 < 4.0.0", - "tough-cookie": "^2.3.1", - "webidl-conversions": "^3.0.1", - "whatwg-encoding": "^1.0.1", - "whatwg-url": "^3.0.0", - "xml-name-validator": ">= 2.0.1 < 3.0.0" + "abab": "1.0.4", + "acorn": "2.7.0", + "acorn-globals": "1.0.9", + "array-equal": "1.0.0", + "content-type-parser": "1.0.2", + "cssom": "0.3.4", + "cssstyle": "0.2.37", + "escodegen": "1.11.0", + "html-encoding-sniffer": "1.0.2", + "iconv-lite": "0.4.24", + "nwmatcher": "1.4.4", + "parse5": "1.5.1", + "request": "2.88.0", + "sax": "1.2.4", + "symbol-tree": "3.2.2", + "tough-cookie": "2.4.3", + "webidl-conversions": "3.0.1", + "whatwg-encoding": "1.0.4", + "whatwg-url": "3.1.0", + "xml-name-validator": "2.0.1" }, "dependencies": { "acorn": { @@ -4849,7 +4849,7 @@ "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", "dev": true, "requires": { - "jsonify": "~0.0.0" + "jsonify": "0.0.0" } }, "json-stringify-safe": { @@ -4894,7 +4894,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } }, "lazystream": { @@ -4903,7 +4903,7 @@ "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=", "dev": true, "requires": { - "readable-stream": "^2.0.5" + "readable-stream": "2.3.6" } }, "lcid": { @@ -4912,7 +4912,7 @@ "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", "dev": true, "requires": { - "invert-kv": "^1.0.0" + "invert-kv": "1.0.0" } }, "lead": { @@ -4921,7 +4921,7 @@ "integrity": "sha1-bxT5mje+Op3XhPVJVpDlkDRm7kI=", "dev": true, "requires": { - "flush-write-stream": "^1.0.2" + "flush-write-stream": "1.0.3" } }, "levn": { @@ -4930,8 +4930,8 @@ "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", "dev": true, "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" + "prelude-ls": "1.1.2", + "type-check": "0.3.2" } }, "livereload-js": { @@ -4946,10 +4946,10 @@ "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", "dev": true, "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" + "graceful-fs": "4.1.11", + "parse-json": "4.0.0", + "pify": "3.0.0", + "strip-bom": "3.0.0" } }, "loader-runner": { @@ -4964,9 +4964,9 @@ "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=", "dev": true, "requires": { - "big.js": "^3.1.3", - "emojis-list": "^2.0.0", - "json5": "^0.5.0" + "big.js": "3.2.0", + "emojis-list": "2.1.0", + "json5": "0.5.1" } }, "locate-path": { @@ -4975,8 +4975,8 @@ "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", "dev": true, "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" + "p-locate": "2.0.0", + "path-exists": "3.0.0" } }, "lodash": { @@ -5009,7 +5009,7 @@ "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", "dev": true, "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" + "js-tokens": "3.0.2" } }, "make-dir": { @@ -5018,7 +5018,7 @@ "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", "dev": true, "requires": { - "pify": "^3.0.0" + "pify": "3.0.0" } }, "map-age-cleaner": { @@ -5027,7 +5027,7 @@ "integrity": "sha512-UN1dNocxQq44IhJyMI4TU8phc2m9BddacHRPRjKGLYaF0jqd3xLz0jS0skpAU9WgYyoR4gHtUpzytNBS385FWQ==", "dev": true, "requires": { - "p-defer": "^1.0.0" + "p-defer": "1.0.0" } }, "map-cache": { @@ -5042,7 +5042,7 @@ "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", "dev": true, "requires": { - "object-visit": "^1.0.0" + "object-visit": "1.0.1" } }, "markdown-escapes": { @@ -5063,9 +5063,9 @@ "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", "dev": true, "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" + "hash-base": "3.0.4", + "inherits": "2.0.3", + "safe-buffer": "5.1.2" } }, "mdast-util-compact": { @@ -5074,7 +5074,7 @@ "integrity": "sha512-d2WS98JSDVbpSsBfVvD9TaDMlqPRz7ohM/11G0rp5jOBb5q96RJ6YLszQ/09AAixyzh23FeIpCGqfaamEADtWg==", "dev": true, "requires": { - "unist-util-visit": "^1.1.0" + "unist-util-visit": "1.4.0" } }, "mdast-util-definitions": { @@ -5083,7 +5083,7 @@ "integrity": "sha512-P6wpRO8YVQ1iv30maMc93NLh7COvufglBE8/ldcOyYmk5EbfF0YeqlLgtqP/FOBU501Kqar1x5wYWwB3Nga74g==", "dev": true, "requires": { - "unist-util-visit": "^1.0.0" + "unist-util-visit": "1.4.0" } }, "mdast-util-inject": { @@ -5092,7 +5092,7 @@ "integrity": "sha1-2wa4tYW+lZotzS+H9HK6m3VvNnU=", "dev": true, "requires": { - "mdast-util-to-string": "^1.0.0" + "mdast-util-to-string": "1.0.5" } }, "mdast-util-to-hast": { @@ -5101,17 +5101,17 @@ "integrity": "sha512-YI8Ea3TFWEZrS31+6Q/d8ZYTOSDKM06IPc3l2+OMFX1o3JTG2mrztlmzDsUMwIXLWofEdTVl/WXBgRG6ddlU/A==", "dev": true, "requires": { - "collapse-white-space": "^1.0.0", - "detab": "^2.0.0", - "mdast-util-definitions": "^1.2.0", - "mdurl": "^1.0.1", + "collapse-white-space": "1.0.4", + "detab": "2.0.1", + "mdast-util-definitions": "1.2.3", + "mdurl": "1.0.1", "trim": "0.0.1", - "trim-lines": "^1.0.0", - "unist-builder": "^1.0.1", - "unist-util-generated": "^1.1.0", - "unist-util-position": "^3.0.0", - "unist-util-visit": "^1.1.0", - "xtend": "^4.0.1" + "trim-lines": "1.1.1", + "unist-builder": "1.0.3", + "unist-util-generated": "1.1.2", + "unist-util-position": "3.0.1", + "unist-util-visit": "1.4.0", + "xtend": "4.0.1" } }, "mdast-util-to-string": { @@ -5126,9 +5126,9 @@ "integrity": "sha512-ove/QQWSrYOrf9G3xn2MTAjy7PKCtCmm261wpQwecoPAsUtkihkMVczxFqil7VihxgSz4ID9c8bBTsyXR30gQg==", "dev": true, "requires": { - "github-slugger": "^1.1.1", - "mdast-util-to-string": "^1.0.2", - "unist-util-visit": "^1.1.0" + "github-slugger": "1.2.0", + "mdast-util-to-string": "1.0.5", + "unist-util-visit": "1.4.0" } }, "mdurl": { @@ -5143,7 +5143,7 @@ "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", "dev": true, "requires": { - "mimic-fn": "^1.0.0" + "mimic-fn": "1.2.0" } }, "memory-fs": { @@ -5152,8 +5152,8 @@ "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", "dev": true, "requires": { - "errno": "^0.1.3", - "readable-stream": "^2.0.1" + "errno": "0.1.7", + "readable-stream": "2.3.6" } }, "micromatch": { @@ -5162,19 +5162,19 @@ "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", "dev": true, "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" + "arr-diff": "4.0.0", + "array-unique": "0.3.2", + "braces": "2.3.2", + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "extglob": "2.0.4", + "fragment-cache": "0.2.1", + "kind-of": "6.0.2", + "nanomatch": "1.2.13", + "object.pick": "1.3.0", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" }, "dependencies": { "arr-diff": { @@ -5195,16 +5195,16 @@ "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "dev": true, "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" + "arr-flatten": "1.1.0", + "array-unique": "0.3.2", + "extend-shallow": "2.0.1", + "fill-range": "4.0.0", + "isobject": "3.0.1", + "repeat-element": "1.1.3", + "snapdragon": "0.8.2", + "snapdragon-node": "2.1.1", + "split-string": "3.1.0", + "to-regex": "3.0.2" }, "dependencies": { "extend-shallow": { @@ -5213,7 +5213,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -5224,13 +5224,13 @@ "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", "dev": true, "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "debug": "2.6.9", + "define-property": "0.2.5", + "extend-shallow": "2.0.1", + "posix-character-classes": "0.1.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" }, "dependencies": { "define-property": { @@ -5239,7 +5239,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } }, "extend-shallow": { @@ -5248,7 +5248,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } }, "is-accessor-descriptor": { @@ -5257,7 +5257,7 @@ "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -5266,7 +5266,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -5277,7 +5277,7 @@ "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "dev": true, "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -5286,7 +5286,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -5297,9 +5297,9 @@ "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", "dev": true, "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" + "is-accessor-descriptor": "0.1.6", + "is-data-descriptor": "0.1.4", + "kind-of": "5.1.0" } }, "kind-of": { @@ -5316,14 +5316,14 @@ "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", "dev": true, "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "array-unique": "0.3.2", + "define-property": "1.0.0", + "expand-brackets": "2.1.4", + "extend-shallow": "2.0.1", + "fragment-cache": "0.2.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" }, "dependencies": { "define-property": { @@ -5332,7 +5332,7 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "^1.0.0" + "is-descriptor": "1.0.2" } }, "extend-shallow": { @@ -5341,7 +5341,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -5352,10 +5352,10 @@ "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", "dev": true, "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" + "extend-shallow": "2.0.1", + "is-number": "3.0.0", + "repeat-string": "1.6.1", + "to-regex-range": "2.1.1" }, "dependencies": { "extend-shallow": { @@ -5364,7 +5364,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -5375,7 +5375,7 @@ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-data-descriptor": { @@ -5384,7 +5384,7 @@ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-descriptor": { @@ -5393,9 +5393,9 @@ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" } }, "is-number": { @@ -5404,7 +5404,7 @@ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -5413,7 +5413,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -5438,8 +5438,8 @@ "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", "dev": true, "requires": { - "bn.js": "^4.0.0", - "brorand": "^1.0.1" + "bn.js": "4.11.8", + "brorand": "1.1.0" } }, "mime": { @@ -5460,7 +5460,7 @@ "integrity": "sha512-HrkrPaP9vGuWbLK1B1FfgAkbqNjIuy4eHlIYnFi7kamZyLLrGlo2mpcx0bBmNpKqBtYtAfGbodDddIgddSJC2A==", "dev": true, "requires": { - "mime-db": "~1.36.0" + "mime-db": "1.36.0" } }, "mimic-fn": { @@ -5487,7 +5487,7 @@ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "brace-expansion": "^1.1.7" + "brace-expansion": "1.1.11" } }, "minimist": { @@ -5502,16 +5502,16 @@ "integrity": "sha512-zHo8v+otD1J10j/tC+VNoGK9keCuByhKovAvdn74dmxJl9+mWHnx6EMsDN4lgRoMI/eYo2nchAxniIbUPb5onw==", "dev": true, "requires": { - "concat-stream": "^1.5.0", - "duplexify": "^3.4.2", - "end-of-stream": "^1.1.0", - "flush-write-stream": "^1.0.0", - "from2": "^2.1.0", - "parallel-transform": "^1.1.0", - "pump": "^2.0.1", - "pumpify": "^1.3.3", - "stream-each": "^1.1.0", - "through2": "^2.0.0" + "concat-stream": "1.6.2", + "duplexify": "3.6.0", + "end-of-stream": "1.4.1", + "flush-write-stream": "1.0.3", + "from2": "2.3.0", + "parallel-transform": "1.1.0", + "pump": "2.0.1", + "pumpify": "1.5.1", + "stream-each": "1.2.3", + "through2": "2.0.3" } }, "mixin-deep": { @@ -5520,8 +5520,8 @@ "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", "dev": true, "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" + "for-in": "1.0.2", + "is-extendable": "1.0.1" }, "dependencies": { "is-extendable": { @@ -5530,7 +5530,7 @@ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "requires": { - "is-plain-object": "^2.0.4" + "is-plain-object": "2.0.4" } } } @@ -5584,12 +5584,12 @@ "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" } }, "he": { @@ -5604,7 +5604,7 @@ "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -5621,20 +5621,20 @@ "integrity": "sha512-bnGGeghQmz/t/6771/KC4FmxpVm126iR6AAzzq4N6hVZQVl4+ZZBv+VF3PJmDyxXtVtgcgTSSP7NL+jq1QAHrg==", "dev": true, "requires": { - "JSONStream": "^1.0.3", - "browser-resolve": "^1.7.0", - "cached-path-relative": "^1.0.0", - "concat-stream": "~1.5.0", - "defined": "^1.0.0", - "detective": "^4.0.0", - "duplexer2": "^0.1.2", - "inherits": "^2.0.1", - "readable-stream": "^2.0.2", - "resolve": "^1.1.3", - "stream-combiner2": "^1.1.1", - "subarg": "^1.0.0", - "through2": "^2.0.0", - "xtend": "^4.0.0" + "JSONStream": "1.3.4", + "browser-resolve": "1.11.3", + "cached-path-relative": "1.0.1", + "concat-stream": "1.5.2", + "defined": "1.0.0", + "detective": "4.7.1", + "duplexer2": "0.1.4", + "inherits": "2.0.3", + "readable-stream": "2.3.6", + "resolve": "1.8.1", + "stream-combiner2": "1.1.1", + "subarg": "1.0.0", + "through2": "2.0.3", + "xtend": "4.0.1" }, "dependencies": { "concat-stream": { @@ -5643,9 +5643,9 @@ "integrity": "sha1-cIl4Yk2FavQaWnQd790mHadSwmY=", "dev": true, "requires": { - "inherits": "~2.0.1", - "readable-stream": "~2.0.0", - "typedarray": "~0.0.5" + "inherits": "2.0.3", + "readable-stream": "2.0.6", + "typedarray": "0.0.6" }, "dependencies": { "readable-stream": { @@ -5654,12 +5654,12 @@ "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", "dev": true, "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "~1.0.0", - "process-nextick-args": "~1.0.6", - "string_decoder": "~0.10.x", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "string_decoder": "0.10.31", + "util-deprecate": "1.0.2" } } } @@ -5684,12 +5684,12 @@ "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", "dev": true, "requires": { - "aproba": "^1.1.1", - "copy-concurrently": "^1.0.0", - "fs-write-stream-atomic": "^1.0.8", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.3" + "aproba": "1.2.0", + "copy-concurrently": "1.0.5", + "fs-write-stream-atomic": "1.0.10", + "mkdirp": "0.5.1", + "rimraf": "2.6.2", + "run-queue": "1.0.3" } }, "ms": { @@ -5711,17 +5711,17 @@ "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", "dev": true, "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "arr-diff": "4.0.0", + "array-unique": "0.3.2", + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "fragment-cache": "0.2.1", + "is-windows": "1.0.2", + "kind-of": "6.0.2", + "object.pick": "1.3.0", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" }, "dependencies": { "arr-diff": { @@ -5762,28 +5762,28 @@ "integrity": "sha512-5AzFzdoIMb89hBGMZglEegffzgRg+ZFoUmisQ8HI4j1KDdpx13J0taNp2y9xPbur6W61gepGDDotGBVQ7mfUCg==", "dev": true, "requires": { - "assert": "^1.1.1", - "browserify-zlib": "^0.2.0", - "buffer": "^4.3.0", - "console-browserify": "^1.1.0", - "constants-browserify": "^1.0.0", - "crypto-browserify": "^3.11.0", - "domain-browser": "^1.1.1", - "events": "^1.0.0", - "https-browserify": "^1.0.0", - "os-browserify": "^0.3.0", + "assert": "1.4.1", + "browserify-zlib": "0.2.0", + "buffer": "4.9.1", + "console-browserify": "1.1.0", + "constants-browserify": "1.0.0", + "crypto-browserify": "3.12.0", + "domain-browser": "1.2.0", + "events": "1.1.1", + "https-browserify": "1.0.0", + "os-browserify": "0.3.0", "path-browserify": "0.0.0", - "process": "^0.11.10", - "punycode": "^1.2.4", - "querystring-es3": "^0.2.0", - "readable-stream": "^2.3.3", - "stream-browserify": "^2.0.1", - "stream-http": "^2.7.2", - "string_decoder": "^1.0.0", - "timers-browserify": "^2.0.4", + "process": "0.11.10", + "punycode": "1.4.1", + "querystring-es3": "0.2.1", + "readable-stream": "2.3.6", + "stream-browserify": "2.0.1", + "stream-http": "2.8.3", + "string_decoder": "1.1.1", + "timers-browserify": "2.0.10", "tty-browserify": "0.0.0", - "url": "^0.11.0", - "util": "^0.10.3", + "url": "0.11.0", + "util": "0.10.4", "vm-browserify": "0.0.4" }, "dependencies": { @@ -5810,7 +5810,7 @@ "integrity": "sha512-VPB4rTPqpVyWKBHbSa4YPFme3+8WHsOSpvbp0Mfj0bWsC8TEjt4HQrLl1hsBDELlp1nB4lflSgSuGTYiuyaP7Q==", "dev": true, "requires": { - "semver": "^5.3.0" + "semver": "5.5.1" } }, "normalize-package-data": { @@ -5819,10 +5819,10 @@ "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", "dev": true, "requires": { - "hosted-git-info": "^2.1.4", - "is-builtin-module": "^1.0.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" + "hosted-git-info": "2.7.1", + "is-builtin-module": "1.0.0", + "semver": "5.5.1", + "validate-npm-package-license": "3.0.4" } }, "normalize-path": { @@ -5831,7 +5831,7 @@ "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", "dev": true, "requires": { - "remove-trailing-separator": "^1.0.1" + "remove-trailing-separator": "1.1.0" } }, "now-and-later": { @@ -5840,7 +5840,7 @@ "integrity": "sha1-vGHLtFbXnLMiB85HygUTb/Ln1u4=", "dev": true, "requires": { - "once": "^1.3.2" + "once": "1.4.0" } }, "npm-run-path": { @@ -5849,7 +5849,7 @@ "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "dev": true, "requires": { - "path-key": "^2.0.0" + "path-key": "2.0.1" } }, "number-is-nan": { @@ -5882,9 +5882,9 @@ "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", "dev": true, "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" + "copy-descriptor": "0.1.1", + "define-property": "0.2.5", + "kind-of": "3.2.2" }, "dependencies": { "define-property": { @@ -5893,7 +5893,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } } } @@ -5910,7 +5910,7 @@ "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", "dev": true, "requires": { - "isobject": "^3.0.0" + "isobject": "3.0.1" }, "dependencies": { "isobject": { @@ -5927,10 +5927,10 @@ "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", "dev": true, "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" + "define-properties": "1.1.3", + "function-bind": "1.1.1", + "has-symbols": "1.0.0", + "object-keys": "1.0.12" } }, "object.getownpropertydescriptors": { @@ -5939,8 +5939,8 @@ "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", "dev": true, "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.5.1" + "define-properties": "1.1.3", + "es-abstract": "1.12.0" } }, "object.pick": { @@ -5949,7 +5949,7 @@ "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", "dev": true, "requires": { - "isobject": "^3.0.1" + "isobject": "3.0.1" }, "dependencies": { "isobject": { @@ -5966,7 +5966,7 @@ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { - "wrappy": "1" + "wrappy": "1.0.2" } }, "optionator": { @@ -5975,12 +5975,12 @@ "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", "dev": true, "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.4", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "wordwrap": "~1.0.0" + "deep-is": "0.1.3", + "fast-levenshtein": "2.0.6", + "levn": "0.3.0", + "prelude-ls": "1.1.2", + "type-check": "0.3.2", + "wordwrap": "1.0.0" } }, "ordered-read-streams": { @@ -5989,7 +5989,7 @@ "integrity": "sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4=", "dev": true, "requires": { - "readable-stream": "^2.0.1" + "readable-stream": "2.3.6" } }, "os-browserify": { @@ -6004,9 +6004,9 @@ "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", "dev": true, "requires": { - "execa": "^0.7.0", - "lcid": "^1.0.0", - "mem": "^1.1.0" + "execa": "0.7.0", + "lcid": "1.0.0", + "mem": "1.1.0" } }, "p-defer": { @@ -6033,7 +6033,7 @@ "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", "dev": true, "requires": { - "p-try": "^1.0.0" + "p-try": "1.0.0" } }, "p-locate": { @@ -6042,7 +6042,7 @@ "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", "dev": true, "requires": { - "p-limit": "^1.1.0" + "p-limit": "1.3.0" } }, "p-try": { @@ -6063,9 +6063,9 @@ "integrity": "sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY=", "dev": true, "requires": { - "cyclist": "~0.2.2", - "inherits": "^2.0.3", - "readable-stream": "^2.1.5" + "cyclist": "0.2.2", + "inherits": "2.0.3", + "readable-stream": "2.3.6" } }, "parse-asn1": { @@ -6074,11 +6074,11 @@ "integrity": "sha512-KPx7flKXg775zZpnp9SxJlz00gTd4BmJ2yJufSc44gMCRrRQ7NSzAcSJQfifuOLgW6bEi+ftrALtsgALeB2Adw==", "dev": true, "requires": { - "asn1.js": "^4.0.0", - "browserify-aes": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.0", - "pbkdf2": "^3.0.3" + "asn1.js": "4.10.1", + "browserify-aes": "1.2.0", + "create-hash": "1.2.0", + "evp_bytestokey": "1.0.3", + "pbkdf2": "3.0.17" } }, "parse-entities": { @@ -6087,12 +6087,12 @@ "integrity": "sha512-XXtDdOPLSB0sHecbEapQi6/58U/ODj/KWfIXmmMCJF/eRn8laX6LZbOyioMoETOOJoWRW8/qTSl5VQkUIfKM5g==", "dev": true, "requires": { - "character-entities": "^1.0.0", - "character-entities-legacy": "^1.0.0", - "character-reference-invalid": "^1.0.0", - "is-alphanumerical": "^1.0.0", - "is-decimal": "^1.0.0", - "is-hexadecimal": "^1.0.0" + "character-entities": "1.2.2", + "character-entities-legacy": "1.1.2", + "character-reference-invalid": "1.1.2", + "is-alphanumerical": "1.0.2", + "is-decimal": "1.0.2", + "is-hexadecimal": "1.0.2" } }, "parse-filepath": { @@ -6101,9 +6101,9 @@ "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=", "dev": true, "requires": { - "is-absolute": "^1.0.0", - "map-cache": "^0.2.0", - "path-root": "^0.1.1" + "is-absolute": "1.0.0", + "map-cache": "0.2.2", + "path-root": "0.1.1" } }, "parse-git-config": { @@ -6112,7 +6112,7 @@ "integrity": "sha1-Jygz/dFf6hRvt10zbSNrljtv9wY=", "dev": true, "requires": { - "ini": "^1.3.3" + "ini": "1.3.5" } }, "parse-json": { @@ -6121,8 +6121,8 @@ "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", "dev": true, "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" + "error-ex": "1.3.2", + "json-parse-better-errors": "1.0.2" } }, "parse-url": { @@ -6131,8 +6131,8 @@ "integrity": "sha1-V8FUKKuKiSsfQ4aWRccR0OFEtVQ=", "dev": true, "requires": { - "is-ssh": "^1.3.0", - "protocols": "^1.4.0" + "is-ssh": "1.3.0", + "protocols": "1.4.6" } }, "parse5": { @@ -6189,7 +6189,7 @@ "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", "dev": true, "requires": { - "path-root-regex": "^0.1.0" + "path-root-regex": "0.1.2" } }, "path-root-regex": { @@ -6204,7 +6204,7 @@ "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", "dev": true, "requires": { - "pify": "^3.0.0" + "pify": "3.0.0" } }, "pbkdf2": { @@ -6213,11 +6213,11 @@ "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==", "dev": true, "requires": { - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4", - "ripemd160": "^2.0.1", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" + "create-hash": "1.2.0", + "create-hmac": "1.1.7", + "ripemd160": "2.0.2", + "safe-buffer": "5.1.2", + "sha.js": "2.4.11" } }, "performance-now": { @@ -6238,7 +6238,7 @@ "integrity": "sha512-8t5BsXy1LUIjn3WWOlOuFDuKswhQb/tkak641lvBgmPOBUQHXveORtlMCp6OdPV1dtuTaEahKA8VNz6uLfKBtA==", "dev": true, "requires": { - "node-modules-regexp": "^1.0.0" + "node-modules-regexp": "1.0.0" } }, "pkg-dir": { @@ -6247,7 +6247,7 @@ "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", "dev": true, "requires": { - "find-up": "^2.1.0" + "find-up": "2.1.0" } }, "posix-character-classes": { @@ -6292,7 +6292,7 @@ "integrity": "sha512-TlgDPagHh+eBKOnH2VYvk8qbwsCG/TAJdmTL7f1PROUcSO8qt/KSmShEQ/OKvock8X9tFjtqjCScyOkkkvIKVQ==", "dev": true, "requires": { - "xtend": "^4.0.1" + "xtend": "4.0.1" } }, "protocols": { @@ -6325,12 +6325,12 @@ "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", "dev": true, "requires": { - "bn.js": "^4.1.0", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "parse-asn1": "^5.0.0", - "randombytes": "^2.0.1", - "safe-buffer": "^5.1.2" + "bn.js": "4.11.8", + "browserify-rsa": "4.0.1", + "create-hash": "1.2.0", + "parse-asn1": "5.1.1", + "randombytes": "2.0.6", + "safe-buffer": "5.1.2" } }, "pump": { @@ -6339,8 +6339,8 @@ "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", "dev": true, "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "end-of-stream": "1.4.1", + "once": "1.4.0" } }, "pumpify": { @@ -6349,9 +6349,9 @@ "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", "dev": true, "requires": { - "duplexify": "^3.6.0", - "inherits": "^2.0.3", - "pump": "^2.0.0" + "duplexify": "3.6.0", + "inherits": "2.0.3", + "pump": "2.0.1" } }, "punycode": { @@ -6384,7 +6384,7 @@ "integrity": "sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A==", "dev": true, "requires": { - "safe-buffer": "^5.1.0" + "safe-buffer": "5.1.2" } }, "randomfill": { @@ -6393,8 +6393,8 @@ "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", "dev": true, "requires": { - "randombytes": "^2.0.5", - "safe-buffer": "^5.1.0" + "randombytes": "2.0.6", + "safe-buffer": "5.1.2" } }, "raw-body": { @@ -6403,8 +6403,8 @@ "integrity": "sha1-HQJ8K/oRasxmI7yo8AAWVyqH1CU=", "dev": true, "requires": { - "bytes": "1", - "string_decoder": "0.10" + "bytes": "1.0.0", + "string_decoder": "0.10.31" }, "dependencies": { "string_decoder": { @@ -6421,9 +6421,9 @@ "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", "dev": true, "requires": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" + "load-json-file": "4.0.0", + "normalize-package-data": "2.4.0", + "path-type": "3.0.0" } }, "read-pkg-up": { @@ -6432,8 +6432,8 @@ "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", "dev": true, "requires": { - "find-up": "^3.0.0", - "read-pkg": "^3.0.0" + "find-up": "3.0.0", + "read-pkg": "3.0.0" }, "dependencies": { "find-up": { @@ -6442,7 +6442,7 @@ "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "dev": true, "requires": { - "locate-path": "^3.0.0" + "locate-path": "3.0.0" } }, "locate-path": { @@ -6451,8 +6451,8 @@ "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "dev": true, "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" + "p-locate": "3.0.0", + "path-exists": "3.0.0" } }, "p-limit": { @@ -6461,7 +6461,7 @@ "integrity": "sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A==", "dev": true, "requires": { - "p-try": "^2.0.0" + "p-try": "2.0.0" } }, "p-locate": { @@ -6470,7 +6470,7 @@ "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "dev": true, "requires": { - "p-limit": "^2.0.0" + "p-limit": "2.0.0" } }, "p-try": { @@ -6487,13 +6487,13 @@ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.2", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" } }, "readdirp": { @@ -6502,9 +6502,9 @@ "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", "dev": true, "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" + "graceful-fs": "4.1.11", + "micromatch": "3.1.10", + "readable-stream": "2.3.6" } }, "regenerate": { @@ -6519,7 +6519,7 @@ "integrity": "sha512-s5NGghCE4itSlUS+0WUj88G6cfMVMmH8boTPNvABf8od+2dhT9WDlWu8n01raQAJZMOK8Ch6jSexaRO7swd6aw==", "dev": true, "requires": { - "regenerate": "^1.4.0" + "regenerate": "1.4.0" } }, "regex-not": { @@ -6528,8 +6528,8 @@ "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", "dev": true, "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" + "extend-shallow": "3.0.2", + "safe-regex": "1.1.0" } }, "remark": { @@ -6538,9 +6538,9 @@ "integrity": "sha512-amw8rGdD5lHbMEakiEsllmkdBP+/KpjW/PRK6NSGPZKCQowh0BT4IWXDAkRMyG3SB9dKPXWMviFjNusXzXNn3A==", "dev": true, "requires": { - "remark-parse": "^5.0.0", - "remark-stringify": "^5.0.0", - "unified": "^6.0.0" + "remark-parse": "5.0.0", + "remark-stringify": "5.0.0", + "unified": "6.2.0" } }, "remark-html": { @@ -6549,10 +6549,10 @@ "integrity": "sha512-3V2391GL3hxKhrkzYOyfPpxJ6taIKLCfuLVqumeWQOk3H9nTtSQ8St8kMYkBVIEAquXN1chT83qJ/2lAW+dpEg==", "dev": true, "requires": { - "hast-util-sanitize": "^1.0.0", - "hast-util-to-html": "^4.0.0", - "mdast-util-to-hast": "^3.0.0", - "xtend": "^4.0.1" + "hast-util-sanitize": "1.2.0", + "hast-util-to-html": "4.0.1", + "mdast-util-to-hast": "3.0.2", + "xtend": "4.0.1" } }, "remark-parse": { @@ -6561,21 +6561,21 @@ "integrity": "sha512-b3iXszZLH1TLoyUzrATcTQUZrwNl1rE70rVdSruJFlDaJ9z5aMkhrG43Pp68OgfHndL/ADz6V69Zow8cTQu+JA==", "dev": true, "requires": { - "collapse-white-space": "^1.0.2", - "is-alphabetical": "^1.0.0", - "is-decimal": "^1.0.0", - "is-whitespace-character": "^1.0.0", - "is-word-character": "^1.0.0", - "markdown-escapes": "^1.0.0", - "parse-entities": "^1.1.0", - "repeat-string": "^1.5.4", - "state-toggle": "^1.0.0", + "collapse-white-space": "1.0.4", + "is-alphabetical": "1.0.2", + "is-decimal": "1.0.2", + "is-whitespace-character": "1.0.2", + "is-word-character": "1.0.2", + "markdown-escapes": "1.0.2", + "parse-entities": "1.2.0", + "repeat-string": "1.6.1", + "state-toggle": "1.0.1", "trim": "0.0.1", - "trim-trailing-lines": "^1.0.0", - "unherit": "^1.0.4", - "unist-util-remove-position": "^1.0.0", - "vfile-location": "^2.0.0", - "xtend": "^4.0.1" + "trim-trailing-lines": "1.1.1", + "unherit": "1.1.1", + "unist-util-remove-position": "1.1.2", + "vfile-location": "2.0.3", + "xtend": "4.0.1" } }, "remark-reference-links": { @@ -6584,7 +6584,7 @@ "integrity": "sha512-871gKTysBtdQUjoqXA0URWmVhI2jFrpLkWrM3/bydAbsngilDYRjjl2LDAgmNooW8bYbHa57YQ13ld+mYr3TLg==", "dev": true, "requires": { - "unist-util-visit": "^1.0.0" + "unist-util-visit": "1.4.0" } }, "remark-slug": { @@ -6593,9 +6593,9 @@ "integrity": "sha512-FW/V7b3ekfDL1eyPDyzfq0qz5HFPKPNWVC2eqFDie45r774FLGoymOS1oU7LVQfdFNEvNLZ6oBJT/oIxAyBISg==", "dev": true, "requires": { - "github-slugger": "^1.0.0", - "mdast-util-to-string": "^1.0.0", - "unist-util-visit": "^1.0.0" + "github-slugger": "1.2.0", + "mdast-util-to-string": "1.0.5", + "unist-util-visit": "1.4.0" } }, "remark-stringify": { @@ -6604,20 +6604,20 @@ "integrity": "sha512-Ws5MdA69ftqQ/yhRF9XhVV29mhxbfGhbz0Rx5bQH+oJcNhhSM6nCu1EpLod+DjrFGrU0BMPs+czVmJZU7xiS7w==", "dev": true, "requires": { - "ccount": "^1.0.0", - "is-alphanumeric": "^1.0.0", - "is-decimal": "^1.0.0", - "is-whitespace-character": "^1.0.0", - "longest-streak": "^2.0.1", - "markdown-escapes": "^1.0.0", - "markdown-table": "^1.1.0", - "mdast-util-compact": "^1.0.0", - "parse-entities": "^1.0.2", - "repeat-string": "^1.5.4", - "state-toggle": "^1.0.0", - "stringify-entities": "^1.0.1", - "unherit": "^1.0.4", - "xtend": "^4.0.1" + "ccount": "1.0.3", + "is-alphanumeric": "1.0.0", + "is-decimal": "1.0.2", + "is-whitespace-character": "1.0.2", + "longest-streak": "2.0.2", + "markdown-escapes": "1.0.2", + "markdown-table": "1.1.2", + "mdast-util-compact": "1.0.2", + "parse-entities": "1.2.0", + "repeat-string": "1.6.1", + "state-toggle": "1.0.1", + "stringify-entities": "1.3.2", + "unherit": "1.1.1", + "xtend": "4.0.1" } }, "remark-toc": { @@ -6626,8 +6626,8 @@ "integrity": "sha512-j2A/fpio1nzNRJtY6nVaFUCtXNfFPxaj6I5UHFsFgo4xKmc0VokRRIzGqz4Vfs7u+dPrHjnoHkImu1Dia0jDSQ==", "dev": true, "requires": { - "mdast-util-toc": "^2.0.0", - "remark-slug": "^5.0.0" + "mdast-util-toc": "2.1.0", + "remark-slug": "5.1.0" } }, "remote-origin-url": { @@ -6636,7 +6636,7 @@ "integrity": "sha1-TT4pAvNOLTfRwmPYdxC3frQIajA=", "dev": true, "requires": { - "parse-git-config": "^0.2.0" + "parse-git-config": "0.2.0" } }, "remove-bom-buffer": { @@ -6645,8 +6645,8 @@ "integrity": "sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==", "dev": true, "requires": { - "is-buffer": "^1.1.5", - "is-utf8": "^0.2.1" + "is-buffer": "1.1.6", + "is-utf8": "0.2.1" } }, "remove-bom-stream": { @@ -6655,9 +6655,9 @@ "integrity": "sha1-BfGlk/FuQuH7kOv1nejlaVJflSM=", "dev": true, "requires": { - "remove-bom-buffer": "^3.0.0", - "safe-buffer": "^5.1.0", - "through2": "^2.0.3" + "remove-bom-buffer": "3.0.0", + "safe-buffer": "5.1.2", + "through2": "2.0.3" } }, "remove-trailing-separator": { @@ -6690,26 +6690,26 @@ "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", "dev": true, "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.0", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.4.3", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" + "aws-sign2": "0.7.0", + "aws4": "1.8.0", + "caseless": "0.12.0", + "combined-stream": "1.0.6", + "extend": "3.0.2", + "forever-agent": "0.6.1", + "form-data": "2.3.2", + "har-validator": "5.1.0", + "http-signature": "1.2.0", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.20", + "oauth-sign": "0.9.0", + "performance-now": "2.1.0", + "qs": "6.5.2", + "safe-buffer": "5.1.2", + "tough-cookie": "2.4.3", + "tunnel-agent": "0.6.0", + "uuid": "3.3.2" } }, "require-directory": { @@ -6730,7 +6730,7 @@ "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", "dev": true, "requires": { - "path-parse": "^1.0.5" + "path-parse": "1.0.6" } }, "resolve-cwd": { @@ -6739,7 +6739,7 @@ "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", "dev": true, "requires": { - "resolve-from": "^3.0.0" + "resolve-from": "3.0.0" } }, "resolve-from": { @@ -6754,7 +6754,7 @@ "integrity": "sha1-MrueOcBtZzONyTeMDW1gdFZq0TE=", "dev": true, "requires": { - "value-or-function": "^3.0.0" + "value-or-function": "3.0.0" } }, "resolve-url": { @@ -6775,7 +6775,7 @@ "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", "dev": true, "requires": { - "glob": "^7.0.5" + "glob": "7.1.3" } }, "ripemd160": { @@ -6784,8 +6784,8 @@ "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", "dev": true, "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" + "hash-base": "3.0.4", + "inherits": "2.0.3" } }, "run-queue": { @@ -6794,7 +6794,7 @@ "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", "dev": true, "requires": { - "aproba": "^1.1.1" + "aproba": "1.2.0" } }, "safe-buffer": { @@ -6815,7 +6815,7 @@ "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "dev": true, "requires": { - "ret": "~0.1.10" + "ret": "0.1.15" } }, "safer-buffer": { @@ -6842,8 +6842,8 @@ "integrity": "sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ==", "dev": true, "requires": { - "ajv": "^6.1.0", - "ajv-keywords": "^3.1.0" + "ajv": "6.5.4", + "ajv-keywords": "3.2.0" }, "dependencies": { "ajv": { @@ -6852,10 +6852,10 @@ "integrity": "sha512-4Wyjt8+t6YszqaXnLDfMmG/8AlO5Zbcsy3ATHncCzjW/NoPzAId8AK6749Ybjmdt+kUY1gP60fCu46oDxPv/mg==", "dev": true, "requires": { - "fast-deep-equal": "^2.0.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "fast-deep-equal": "2.0.1", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.4.1", + "uri-js": "4.2.2" } }, "fast-deep-equal": { @@ -6896,10 +6896,10 @@ "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", "dev": true, "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" + "extend-shallow": "2.0.1", + "is-extendable": "0.1.1", + "is-plain-object": "2.0.4", + "split-string": "3.1.0" }, "dependencies": { "extend-shallow": { @@ -6908,7 +6908,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -6925,8 +6925,8 @@ "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "dev": true, "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" + "inherits": "2.0.3", + "safe-buffer": "5.1.2" } }, "shebang-command": { @@ -6935,7 +6935,7 @@ "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "dev": true, "requires": { - "shebang-regex": "^1.0.0" + "shebang-regex": "1.0.0" } }, "shebang-regex": { @@ -6959,7 +6959,7 @@ "formatio": "1.1.1", "lolex": "1.3.2", "samsam": "1.1.2", - "util": ">=0.10.3 <1" + "util": "0.11.0" } }, "snapdragon": { @@ -6968,14 +6968,14 @@ "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", "dev": true, "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" + "base": "0.11.2", + "debug": "2.6.9", + "define-property": "0.2.5", + "extend-shallow": "2.0.1", + "map-cache": "0.2.2", + "source-map": "0.5.7", + "source-map-resolve": "0.5.2", + "use": "3.1.1" }, "dependencies": { "define-property": { @@ -6984,7 +6984,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } }, "extend-shallow": { @@ -6993,7 +6993,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -7004,9 +7004,9 @@ "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", "dev": true, "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" + "define-property": "1.0.0", + "isobject": "3.0.1", + "snapdragon-util": "3.0.1" }, "dependencies": { "define-property": { @@ -7015,7 +7015,7 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "^1.0.0" + "is-descriptor": "1.0.2" } }, "is-accessor-descriptor": { @@ -7024,7 +7024,7 @@ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-data-descriptor": { @@ -7033,7 +7033,7 @@ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-descriptor": { @@ -7042,9 +7042,9 @@ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" } }, "isobject": { @@ -7067,7 +7067,7 @@ "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", "dev": true, "requires": { - "kind-of": "^3.2.0" + "kind-of": "3.2.2" } }, "source-list-map": { @@ -7088,11 +7088,11 @@ "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", "dev": true, "requires": { - "atob": "^2.1.1", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" + "atob": "2.1.2", + "decode-uri-component": "0.2.0", + "resolve-url": "0.2.1", + "source-map-url": "0.4.0", + "urix": "0.1.0" } }, "source-map-url": { @@ -7116,8 +7116,8 @@ "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==", "dev": true, "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" + "spdx-expression-parse": "3.0.0", + "spdx-license-ids": "3.0.1" } }, "spdx-exceptions": { @@ -7132,8 +7132,8 @@ "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", "dev": true, "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" + "spdx-exceptions": "2.1.0", + "spdx-license-ids": "3.0.1" } }, "spdx-license-ids": { @@ -7148,7 +7148,7 @@ "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", "dev": true, "requires": { - "extend-shallow": "^3.0.0" + "extend-shallow": "3.0.2" } }, "sprintf-js": { @@ -7163,15 +7163,15 @@ "integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=", "dev": true, "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" + "asn1": "0.2.4", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.2", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.2", + "getpass": "0.1.7", + "jsbn": "0.1.1", + "safer-buffer": "2.1.2", + "tweetnacl": "0.14.5" } }, "ssri": { @@ -7180,7 +7180,7 @@ "integrity": "sha512-XRSIPqLij52MtgoQavH/x/dU1qVKtWUAAZeOHsR9c2Ddi4XerFy3mc1alf+dLJKl9EUIm/Ht+EowFkTUOA6GAQ==", "dev": true, "requires": { - "safe-buffer": "^5.1.1" + "safe-buffer": "5.1.2" } }, "state-toggle": { @@ -7195,8 +7195,8 @@ "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", "dev": true, "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" + "define-property": "0.2.5", + "object-copy": "0.1.0" }, "dependencies": { "define-property": { @@ -7205,7 +7205,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } } } @@ -7216,7 +7216,7 @@ "integrity": "sha1-nl9zRfITfDDuO0mLkRToC1K7frU=", "dev": true, "requires": { - "readable-stream": "~2.1.0" + "readable-stream": "2.1.5" }, "dependencies": { "process-nextick-args": { @@ -7231,13 +7231,13 @@ "integrity": "sha1-ZvqLcg4UOLNkaB8q0aY8YYRIydA=", "dev": true, "requires": { - "buffer-shims": "^1.0.0", - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "~1.0.0", - "process-nextick-args": "~1.0.6", - "string_decoder": "~0.10.x", - "util-deprecate": "~1.0.1" + "buffer-shims": "1.0.0", + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "string_decoder": "0.10.31", + "util-deprecate": "1.0.2" } }, "string_decoder": { @@ -7254,8 +7254,8 @@ "integrity": "sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=", "dev": true, "requires": { - "inherits": "~2.0.1", - "readable-stream": "^2.0.2" + "inherits": "2.0.3", + "readable-stream": "2.3.6" } }, "stream-combiner2": { @@ -7264,8 +7264,8 @@ "integrity": "sha1-+02KFCDqNidk4hrUeAOXvry0HL4=", "dev": true, "requires": { - "duplexer2": "~0.1.0", - "readable-stream": "^2.0.2" + "duplexer2": "0.1.4", + "readable-stream": "2.3.6" } }, "stream-each": { @@ -7274,8 +7274,8 @@ "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", "dev": true, "requires": { - "end-of-stream": "^1.1.0", - "stream-shift": "^1.0.0" + "end-of-stream": "1.4.1", + "stream-shift": "1.0.0" } }, "stream-http": { @@ -7284,11 +7284,11 @@ "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", "dev": true, "requires": { - "builtin-status-codes": "^3.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.3.6", - "to-arraybuffer": "^1.0.0", - "xtend": "^4.0.0" + "builtin-status-codes": "3.0.0", + "inherits": "2.0.3", + "readable-stream": "2.3.6", + "to-arraybuffer": "1.0.1", + "xtend": "4.0.1" } }, "stream-shift": { @@ -7309,9 +7309,9 @@ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" } }, "string_decoder": { @@ -7320,7 +7320,7 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.2" } }, "stringify-entities": { @@ -7329,10 +7329,10 @@ "integrity": "sha512-nrBAQClJAPN2p+uGCVJRPIPakKeKWZ9GtBCmormE7pWOSlHat7+x5A8gx85M7HM5Dt0BP3pP5RhVW77WdbJJ3A==", "dev": true, "requires": { - "character-entities-html4": "^1.0.0", - "character-entities-legacy": "^1.0.0", - "is-alphanumerical": "^1.0.0", - "is-hexadecimal": "^1.0.0" + "character-entities-html4": "1.1.2", + "character-entities-legacy": "1.1.2", + "is-alphanumerical": "1.0.2", + "is-hexadecimal": "1.0.2" } }, "strip-ansi": { @@ -7341,7 +7341,7 @@ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "2.1.1" } }, "strip-bom": { @@ -7368,7 +7368,7 @@ "integrity": "sha1-9izxdYHplrSPyWVpn1TAauJouNI=", "dev": true, "requires": { - "minimist": "^1.1.0" + "minimist": "1.2.0" }, "dependencies": { "minimist": { @@ -7385,7 +7385,7 @@ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } }, "symbol-tree": { @@ -7412,8 +7412,8 @@ "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", "dev": true, "requires": { - "readable-stream": "^2.1.5", - "xtend": "~4.0.1" + "readable-stream": "2.3.6", + "xtend": "4.0.1" } }, "through2-filter": { @@ -7422,8 +7422,8 @@ "integrity": "sha1-YLxVoNrLdghdsfna6Zq0P4PWIuw=", "dev": true, "requires": { - "through2": "~2.0.0", - "xtend": "~4.0.0" + "through2": "2.0.3", + "xtend": "4.0.1" } }, "timers-browserify": { @@ -7432,7 +7432,7 @@ "integrity": "sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg==", "dev": true, "requires": { - "setimmediate": "^1.0.4" + "setimmediate": "1.0.5" } }, "tiny-lr": { @@ -7441,12 +7441,12 @@ "integrity": "sha512-44yhA3tsaRoMOjQQ+5v5mVdqef+kH6Qze9jTpqtVufgYjYt08zyZAwNwwVBj3i1rJMnR52IxOW0LK0vBzgAkuA==", "dev": true, "requires": { - "body": "^5.1.0", - "debug": "^3.1.0", - "faye-websocket": "~0.10.0", - "livereload-js": "^2.3.0", - "object-assign": "^4.1.0", - "qs": "^6.4.0" + "body": "5.1.0", + "debug": "3.2.6", + "faye-websocket": "0.10.0", + "livereload-js": "2.3.0", + "object-assign": "4.1.1", + "qs": "6.5.2" }, "dependencies": { "debug": { @@ -7455,7 +7455,7 @@ "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", "dev": true, "requires": { - "ms": "^2.1.1" + "ms": "2.1.1" } }, "ms": { @@ -7472,8 +7472,8 @@ "integrity": "sha1-GGX0PZ50sIItufFFt4z/fQ98hJs=", "dev": true, "requires": { - "is-absolute": "^1.0.0", - "is-negated-glob": "^1.0.0" + "is-absolute": "1.0.0", + "is-negated-glob": "1.0.0" } }, "to-arraybuffer": { @@ -7488,7 +7488,7 @@ "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", "dev": true, "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" } }, "to-regex": { @@ -7497,10 +7497,10 @@ "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", "dev": true, "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "regex-not": "1.0.2", + "safe-regex": "1.1.0" } }, "to-regex-range": { @@ -7509,8 +7509,8 @@ "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", "dev": true, "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" + "is-number": "3.0.0", + "repeat-string": "1.6.1" }, "dependencies": { "is-number": { @@ -7519,7 +7519,7 @@ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" } } } @@ -7530,7 +7530,7 @@ "integrity": "sha1-/JKtq6ByZHvAtn1rA2ZKoZUJOvY=", "dev": true, "requires": { - "through2": "^2.0.3" + "through2": "2.0.3" } }, "tough-cookie": { @@ -7539,8 +7539,8 @@ "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", "dev": true, "requires": { - "psl": "^1.1.24", - "punycode": "^1.4.1" + "psl": "1.1.29", + "punycode": "1.4.1" } }, "tr46": { @@ -7597,7 +7597,7 @@ "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", "dev": true, "requires": { - "safe-buffer": "^5.0.1" + "safe-buffer": "5.1.2" } }, "tweetnacl": { @@ -7613,7 +7613,7 @@ "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", "dev": true, "requires": { - "prelude-ls": "~1.1.2" + "prelude-ls": "1.1.2" } }, "typedarray": { @@ -7628,8 +7628,8 @@ "integrity": "sha512-r+MU0rfv4L/0eeW3xZrd16t4NZfK8Ld4SWVglYBb7ez5uXFWHuVRs6xCTrf1yirs9a4j4Y27nn7SRfO6v67XsQ==", "dev": true, "requires": { - "commander": "~2.13.0", - "source-map": "~0.6.1" + "commander": "2.13.0", + "source-map": "0.6.1" }, "dependencies": { "commander": { @@ -7652,14 +7652,14 @@ "integrity": "sha512-ovHIch0AMlxjD/97j9AYovZxG5wnHOPkL7T1GKochBADp/Zwc44pEWNqpKl1Loupp1WhFg7SlYmHZRUfdAacgw==", "dev": true, "requires": { - "cacache": "^10.0.4", - "find-cache-dir": "^1.0.0", - "schema-utils": "^0.4.5", - "serialize-javascript": "^1.4.0", - "source-map": "^0.6.1", - "uglify-es": "^3.3.4", - "webpack-sources": "^1.1.0", - "worker-farm": "^1.5.2" + "cacache": "10.0.4", + "find-cache-dir": "1.0.0", + "schema-utils": "0.4.7", + "serialize-javascript": "1.5.0", + "source-map": "0.6.1", + "uglify-es": "3.3.9", + "webpack-sources": "1.3.0", + "worker-farm": "1.6.0" }, "dependencies": { "source-map": { @@ -7682,8 +7682,8 @@ "integrity": "sha512-+XZuV691Cn4zHsK0vkKYwBEwB74T3IZIcxrgn2E4rKwTfFyI1zCh7X7grwh9Re08fdPlarIdyWgI8aVB3F5A5g==", "dev": true, "requires": { - "inherits": "^2.0.1", - "xtend": "^4.0.1" + "inherits": "2.0.3", + "xtend": "4.0.1" } }, "unicode-canonical-property-names-ecmascript": { @@ -7698,8 +7698,8 @@ "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", "dev": true, "requires": { - "unicode-canonical-property-names-ecmascript": "^1.0.4", - "unicode-property-aliases-ecmascript": "^1.0.4" + "unicode-canonical-property-names-ecmascript": "1.0.4", + "unicode-property-aliases-ecmascript": "1.0.4" } }, "unicode-match-property-value-ecmascript": { @@ -7720,12 +7720,12 @@ "integrity": "sha512-1k+KPhlVtqmG99RaTbAv/usu85fcSRu3wY8X+vnsEhIxNP5VbVIDiXnLqyKIG+UMdyTg0ZX9EI6k2AfjJkHPtA==", "dev": true, "requires": { - "bail": "^1.0.0", - "extend": "^3.0.0", - "is-plain-obj": "^1.1.0", - "trough": "^1.0.0", - "vfile": "^2.0.0", - "x-is-string": "^0.1.0" + "bail": "1.0.3", + "extend": "3.0.2", + "is-plain-obj": "1.1.0", + "trough": "1.0.3", + "vfile": "2.3.0", + "x-is-string": "0.1.0" }, "dependencies": { "vfile": { @@ -7734,10 +7734,10 @@ "integrity": "sha512-ASt4mBUHcTpMKD/l5Q+WJXNtshlWxOogYyGYYrg4lt/vuRjC1EFQtlAofL5VmtVNIZJzWYFJjzGWZ0Gw8pzW1w==", "dev": true, "requires": { - "is-buffer": "^1.1.4", + "is-buffer": "1.1.6", "replace-ext": "1.0.0", - "unist-util-stringify-position": "^1.0.0", - "vfile-message": "^1.0.0" + "unist-util-stringify-position": "1.1.2", + "vfile-message": "1.0.1" } } } @@ -7748,10 +7748,10 @@ "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", "dev": true, "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^0.4.3" + "arr-union": "3.1.0", + "get-value": "2.0.6", + "is-extendable": "0.1.1", + "set-value": "0.4.3" }, "dependencies": { "extend-shallow": { @@ -7760,7 +7760,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } }, "set-value": { @@ -7769,10 +7769,10 @@ "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", "dev": true, "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.1", - "to-object-path": "^0.3.0" + "extend-shallow": "2.0.1", + "is-extendable": "0.1.1", + "is-plain-object": "2.0.4", + "to-object-path": "0.3.0" } } } @@ -7783,7 +7783,7 @@ "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", "dev": true, "requires": { - "unique-slug": "^2.0.0" + "unique-slug": "2.0.1" } }, "unique-slug": { @@ -7792,7 +7792,7 @@ "integrity": "sha512-n9cU6+gITaVu7VGj1Z8feKMmfAjEAQGhwD9fE3zvpRRa0wEIx8ODYkVGfSc94M2OX00tUFV8wH3zYbm1I8mxFg==", "dev": true, "requires": { - "imurmurhash": "^0.1.4" + "imurmurhash": "0.1.4" } }, "unique-stream": { @@ -7801,8 +7801,8 @@ "integrity": "sha1-WqADz76Uxf+GbE59ZouxxNuts2k=", "dev": true, "requires": { - "json-stable-stringify": "^1.0.0", - "through2-filter": "^2.0.0" + "json-stable-stringify": "1.0.1", + "through2-filter": "2.0.0" } }, "unist-builder": { @@ -7811,7 +7811,7 @@ "integrity": "sha512-/KB8GEaoeHRyIqClL+Kam+Y5NWJ6yEiPsAfv1M+O1p+aKGgjR89WwoEHKTyOj17L6kAlqtKpAgv2nWvdbQDEig==", "dev": true, "requires": { - "object-assign": "^4.1.0" + "object-assign": "4.1.1" } }, "unist-util-generated": { @@ -7838,7 +7838,7 @@ "integrity": "sha512-XxoNOBvq1WXRKXxgnSYbtCF76TJrRoe5++pD4cCBsssSiWSnPEktyFrFLE8LTk3JW5mt9hB0Sk5zn4x/JeWY7Q==", "dev": true, "requires": { - "unist-util-visit": "^1.1.0" + "unist-util-visit": "1.4.0" } }, "unist-util-stringify-position": { @@ -7853,7 +7853,7 @@ "integrity": "sha512-FiGu34ziNsZA3ZUteZxSFaczIjGmksfSgdKqBfOejrrfzyUy5b7YrlzT1Bcvi+djkYDituJDy2XB7tGTeBieKw==", "dev": true, "requires": { - "unist-util-visit-parents": "^2.0.0" + "unist-util-visit-parents": "2.0.1" } }, "unist-util-visit-parents": { @@ -7862,7 +7862,7 @@ "integrity": "sha512-6B0UTiMfdWql4cQ03gDTCSns+64Zkfo2OCbK31Ov0uMizEz+CJeAp0cgZVb5Fhmcd7Bct2iRNywejT0orpbqUA==", "dev": true, "requires": { - "unist-util-is": "^2.1.2" + "unist-util-is": "2.1.2" } }, "unset-value": { @@ -7871,8 +7871,8 @@ "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", "dev": true, "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" + "has-value": "0.3.1", + "isobject": "3.0.1" }, "dependencies": { "has-value": { @@ -7881,9 +7881,9 @@ "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", "dev": true, "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" + "get-value": "2.0.6", + "has-values": "0.1.4", + "isobject": "2.1.0" }, "dependencies": { "isobject": { @@ -7923,7 +7923,7 @@ "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", "dev": true, "requires": { - "punycode": "^2.1.0" + "punycode": "2.1.1" }, "dependencies": { "punycode": { @@ -7985,8 +7985,8 @@ "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", "dev": true, "requires": { - "define-properties": "^1.1.2", - "object.getownpropertydescriptors": "^2.0.3" + "define-properties": "1.1.3", + "object.getownpropertydescriptors": "2.0.3" } }, "uuid": { @@ -8007,8 +8007,8 @@ "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", "dev": true, "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" + "spdx-correct": "3.0.0", + "spdx-expression-parse": "3.0.0" } }, "value-or-function": { @@ -8023,9 +8023,9 @@ "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", "dev": true, "requires": { - "assert-plus": "^1.0.0", + "assert-plus": "1.0.0", "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" + "extsprintf": "1.3.0" } }, "vfile": { @@ -8034,10 +8034,10 @@ "integrity": "sha512-X2DiPHL9Nxgfyu5DNVgtTkZtD4d4Zzf7rVBVI+uXP2pWWIQG8Ri+xAP9KdH/sB6SS0a1niWp5bRF88n4ciwhoA==", "dev": true, "requires": { - "is-buffer": "^2.0.0", + "is-buffer": "2.0.3", "replace-ext": "1.0.0", - "unist-util-stringify-position": "^1.0.0", - "vfile-message": "^1.0.0" + "unist-util-stringify-position": "1.1.2", + "vfile-message": "1.0.1" }, "dependencies": { "is-buffer": { @@ -8060,7 +8060,7 @@ "integrity": "sha512-vSGCkhNvJzO6VcWC6AlJW4NtYOVtS+RgCaqFIYUjoGIlHnFL+i0LbtYvonDWOMcB97uTPT4PRsyYY7REWC9vug==", "dev": true, "requires": { - "unist-util-stringify-position": "^1.1.1" + "unist-util-stringify-position": "1.1.2" } }, "vfile-reporter": { @@ -8069,11 +8069,11 @@ "integrity": "sha512-p1zv4/AfRWUtXEJ0dYSPo1JGS1qL4R95YiHKF7V/8BcXq1buSYIwE660QAHmE7u8tVOjgKp2+oW4RHe+AO+K5Q==", "dev": true, "requires": { - "repeat-string": "^1.5.0", - "string-width": "^2.0.0", - "supports-color": "^5.4.0", - "unist-util-stringify-position": "^1.0.0", - "vfile-statistics": "^1.1.0" + "repeat-string": "1.6.1", + "string-width": "2.1.1", + "supports-color": "5.5.0", + "unist-util-stringify-position": "1.1.2", + "vfile-statistics": "1.1.1" }, "dependencies": { "ansi-regex": { @@ -8094,8 +8094,8 @@ "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" } }, "strip-ansi": { @@ -8104,7 +8104,7 @@ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { - "ansi-regex": "^3.0.0" + "ansi-regex": "3.0.0" } }, "supports-color": { @@ -8113,7 +8113,7 @@ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -8136,12 +8136,12 @@ "integrity": "sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==", "dev": true, "requires": { - "clone": "^2.1.1", - "clone-buffer": "^1.0.0", - "clone-stats": "^1.0.0", - "cloneable-readable": "^1.0.0", - "remove-trailing-separator": "^1.0.1", - "replace-ext": "^1.0.0" + "clone": "2.1.2", + "clone-buffer": "1.0.0", + "clone-stats": "1.0.0", + "cloneable-readable": "1.1.2", + "remove-trailing-separator": "1.1.0", + "replace-ext": "1.0.0" } }, "vinyl-fs": { @@ -8150,23 +8150,23 @@ "integrity": "sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==", "dev": true, "requires": { - "fs-mkdirp-stream": "^1.0.0", - "glob-stream": "^6.1.0", - "graceful-fs": "^4.0.0", - "is-valid-glob": "^1.0.0", - "lazystream": "^1.0.0", - "lead": "^1.0.0", - "object.assign": "^4.0.4", - "pumpify": "^1.3.5", - "readable-stream": "^2.3.3", - "remove-bom-buffer": "^3.0.0", - "remove-bom-stream": "^1.2.0", - "resolve-options": "^1.1.0", - "through2": "^2.0.0", - "to-through": "^2.0.0", - "value-or-function": "^3.0.0", - "vinyl": "^2.0.0", - "vinyl-sourcemap": "^1.1.0" + "fs-mkdirp-stream": "1.0.0", + "glob-stream": "6.1.0", + "graceful-fs": "4.1.11", + "is-valid-glob": "1.0.0", + "lazystream": "1.0.0", + "lead": "1.0.0", + "object.assign": "4.1.0", + "pumpify": "1.5.1", + "readable-stream": "2.3.6", + "remove-bom-buffer": "3.0.0", + "remove-bom-stream": "1.2.0", + "resolve-options": "1.1.0", + "through2": "2.0.3", + "to-through": "2.0.0", + "value-or-function": "3.0.0", + "vinyl": "2.2.0", + "vinyl-sourcemap": "1.1.0" } }, "vinyl-sourcemap": { @@ -8175,13 +8175,13 @@ "integrity": "sha1-kqgAWTo4cDqM2xHYswCtS+Y7PhY=", "dev": true, "requires": { - "append-buffer": "^1.0.2", - "convert-source-map": "^1.5.0", - "graceful-fs": "^4.1.6", - "normalize-path": "^2.1.1", - "now-and-later": "^2.0.0", - "remove-bom-buffer": "^3.0.0", - "vinyl": "^2.0.0" + "append-buffer": "1.0.2", + "convert-source-map": "1.6.0", + "graceful-fs": "4.1.11", + "normalize-path": "2.1.1", + "now-and-later": "2.0.0", + "remove-bom-buffer": "3.0.0", + "vinyl": "2.2.0" } }, "vm-browserify": { @@ -8199,8 +8199,8 @@ "integrity": "sha512-63uI4syCwtGR5IJvZM0LN5tVsahrelomHtCxvRkZPJ/Tf3ADm1U1wG6KWycK3qCfqR+ygM5vewUvmJ0REAYksg==", "dev": true, "requires": { - "de-indent": "^1.0.2", - "he": "^1.1.0" + "de-indent": "1.0.2", + "he": "1.2.0" } }, "watchpack": { @@ -8209,9 +8209,9 @@ "integrity": "sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA==", "dev": true, "requires": { - "chokidar": "^2.0.2", - "graceful-fs": "^4.1.2", - "neo-async": "^2.5.0" + "chokidar": "2.0.4", + "graceful-fs": "4.1.11", + "neo-async": "2.5.2" } }, "webidl-conversions": { @@ -8230,26 +8230,26 @@ "@webassemblyjs/helper-module-context": "1.7.10", "@webassemblyjs/wasm-edit": "1.7.10", "@webassemblyjs/wasm-parser": "1.7.10", - "acorn": "^5.6.2", - "acorn-dynamic-import": "^3.0.0", - "ajv": "^6.1.0", - "ajv-keywords": "^3.1.0", - "chrome-trace-event": "^1.0.0", - "enhanced-resolve": "^4.1.0", - "eslint-scope": "^4.0.0", - "json-parse-better-errors": "^1.0.2", - "loader-runner": "^2.3.0", - "loader-utils": "^1.1.0", - "memory-fs": "~0.4.1", - "micromatch": "^3.1.8", - "mkdirp": "~0.5.0", - "neo-async": "^2.5.0", - "node-libs-browser": "^2.0.0", - "schema-utils": "^0.4.4", - "tapable": "^1.1.0", - "uglifyjs-webpack-plugin": "^1.2.4", - "watchpack": "^1.5.0", - "webpack-sources": "^1.3.0" + "acorn": "5.7.3", + "acorn-dynamic-import": "3.0.0", + "ajv": "6.5.4", + "ajv-keywords": "3.2.0", + "chrome-trace-event": "1.0.0", + "enhanced-resolve": "4.1.0", + "eslint-scope": "4.0.0", + "json-parse-better-errors": "1.0.2", + "loader-runner": "2.3.1", + "loader-utils": "1.1.0", + "memory-fs": "0.4.1", + "micromatch": "3.1.10", + "mkdirp": "0.5.1", + "neo-async": "2.5.2", + "node-libs-browser": "2.1.0", + "schema-utils": "0.4.7", + "tapable": "1.1.0", + "uglifyjs-webpack-plugin": "1.3.0", + "watchpack": "1.6.0", + "webpack-sources": "1.3.0" }, "dependencies": { "ajv": { @@ -8258,10 +8258,10 @@ "integrity": "sha512-4Wyjt8+t6YszqaXnLDfMmG/8AlO5Zbcsy3ATHncCzjW/NoPzAId8AK6749Ybjmdt+kUY1gP60fCu46oDxPv/mg==", "dev": true, "requires": { - "fast-deep-equal": "^2.0.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "fast-deep-equal": "2.0.1", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.4.1", + "uri-js": "4.2.2" } }, "fast-deep-equal": { @@ -8284,16 +8284,16 @@ "integrity": "sha512-Cnqo7CeqeSvC6PTdts+dywNi5CRlIPbLx1AoUPK2T6vC1YAugMG3IOoO9DmEscd+Dghw7uRlnzV1KwOe5IrtgQ==", "dev": true, "requires": { - "chalk": "^2.4.1", - "cross-spawn": "^6.0.5", - "enhanced-resolve": "^4.1.0", - "global-modules-path": "^2.3.0", - "import-local": "^2.0.0", - "interpret": "^1.1.0", - "loader-utils": "^1.1.0", - "supports-color": "^5.5.0", - "v8-compile-cache": "^2.0.2", - "yargs": "^12.0.2" + "chalk": "2.4.1", + "cross-spawn": "6.0.5", + "enhanced-resolve": "4.1.0", + "global-modules-path": "2.3.0", + "import-local": "2.0.0", + "interpret": "1.1.0", + "loader-utils": "1.1.0", + "supports-color": "5.5.0", + "v8-compile-cache": "2.0.2", + "yargs": "12.0.2" }, "dependencies": { "ansi-regex": { @@ -8308,9 +8308,9 @@ "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", "dev": true, "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" + "string-width": "2.1.1", + "strip-ansi": "4.0.0", + "wrap-ansi": "2.1.0" } }, "decamelize": { @@ -8328,13 +8328,13 @@ "integrity": "sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw==", "dev": true, "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" + "cross-spawn": "6.0.5", + "get-stream": "3.0.0", + "is-stream": "1.1.0", + "npm-run-path": "2.0.2", + "p-finally": "1.0.0", + "signal-exit": "3.0.2", + "strip-eof": "1.0.0" } }, "find-up": { @@ -8343,7 +8343,7 @@ "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "dev": true, "requires": { - "locate-path": "^3.0.0" + "locate-path": "3.0.0" } }, "invert-kv": { @@ -8364,7 +8364,7 @@ "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", "dev": true, "requires": { - "invert-kv": "^2.0.0" + "invert-kv": "2.0.0" } }, "locate-path": { @@ -8373,8 +8373,8 @@ "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "dev": true, "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" + "p-locate": "3.0.0", + "path-exists": "3.0.0" } }, "mem": { @@ -8383,9 +8383,9 @@ "integrity": "sha512-WQxG/5xYc3tMbYLXoXPm81ET2WDULiU5FxbuIoNbJqLOOI8zehXFdZuiUEgfdrU2mVB1pxBZUGlYORSrpuJreA==", "dev": true, "requires": { - "map-age-cleaner": "^0.1.1", - "mimic-fn": "^1.0.0", - "p-is-promise": "^1.1.0" + "map-age-cleaner": "0.1.2", + "mimic-fn": "1.2.0", + "p-is-promise": "1.1.0" } }, "os-locale": { @@ -8394,9 +8394,9 @@ "integrity": "sha512-7g5e7dmXPtzcP4bgsZ8ixDVqA7oWYuEz4lOSujeWyliPai4gfVDiFIcwBg3aGCPnmSGfzOKTK3ccPn0CKv3DBw==", "dev": true, "requires": { - "execa": "^0.10.0", - "lcid": "^2.0.0", - "mem": "^4.0.0" + "execa": "0.10.0", + "lcid": "2.0.0", + "mem": "4.0.0" } }, "p-limit": { @@ -8405,7 +8405,7 @@ "integrity": "sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A==", "dev": true, "requires": { - "p-try": "^2.0.0" + "p-try": "2.0.0" } }, "p-locate": { @@ -8414,7 +8414,7 @@ "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "dev": true, "requires": { - "p-limit": "^2.0.0" + "p-limit": "2.0.0" } }, "p-try": { @@ -8429,8 +8429,8 @@ "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" } }, "strip-ansi": { @@ -8439,7 +8439,7 @@ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { - "ansi-regex": "^3.0.0" + "ansi-regex": "3.0.0" } }, "yargs": { @@ -8448,18 +8448,18 @@ "integrity": "sha512-e7SkEx6N6SIZ5c5H22RTZae61qtn3PYUE8JYbBFlK9sYmh3DMQ6E5ygtaG/2BW0JZi4WGgTR2IV5ChqlqrDGVQ==", "dev": true, "requires": { - "cliui": "^4.0.0", - "decamelize": "^2.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^1.0.1", - "os-locale": "^3.0.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1 || ^4.0.0", - "yargs-parser": "^10.1.0" + "cliui": "4.1.0", + "decamelize": "2.0.0", + "find-up": "3.0.0", + "get-caller-file": "1.0.3", + "os-locale": "3.0.1", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "2.1.1", + "which-module": "2.0.0", + "y18n": "3.2.1", + "yargs-parser": "10.1.0" } }, "yargs-parser": { @@ -8468,7 +8468,7 @@ "integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==", "dev": true, "requires": { - "camelcase": "^4.1.0" + "camelcase": "4.1.0" } } } @@ -8479,8 +8479,8 @@ "integrity": "sha512-OiVgSrbGu7NEnEvQJJgdSFPl2qWKkWq5lHMhgiToIiN9w34EBnjYzSYs+VbL5KoYiLNtFFa7BZIKxRED3I32pA==", "dev": true, "requires": { - "source-list-map": "^2.0.0", - "source-map": "~0.6.1" + "source-list-map": "2.0.1", + "source-map": "0.6.1" }, "dependencies": { "source-map": { @@ -8497,8 +8497,8 @@ "integrity": "sha1-DK+dLXVdk67gSdS90NP+LMoqJOs=", "dev": true, "requires": { - "http-parser-js": ">=0.4.0", - "websocket-extensions": ">=0.1.1" + "http-parser-js": "0.4.13", + "websocket-extensions": "0.1.3" } }, "websocket-extensions": { @@ -8522,7 +8522,7 @@ "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", "dev": true, "requires": { - "safer-buffer": ">= 2.1.2 < 3" + "safer-buffer": "2.1.2" } } } @@ -8533,8 +8533,8 @@ "integrity": "sha1-e9yuSQ+SGu9kUftnOexrvY6Qe/Y=", "dev": true, "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" + "tr46": "0.0.3", + "webidl-conversions": "3.0.1" } }, "which": { @@ -8543,7 +8543,7 @@ "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, "requires": { - "isexe": "^2.0.0" + "isexe": "2.0.0" } }, "which-module": { @@ -8564,7 +8564,7 @@ "integrity": "sha512-6w+3tHbM87WnSWnENBUvA2pxJPLhQUg5LKwUQHq3r+XPhIM+Gh2R5ycbwPCyuGbNg+lPgdcnQUhuC02kJCvffQ==", "dev": true, "requires": { - "errno": "~0.1.7" + "errno": "0.1.7" } }, "wrap-ansi": { @@ -8573,8 +8573,8 @@ "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "dev": true, "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" + "string-width": "1.0.2", + "strip-ansi": "3.0.1" } }, "wrappy": { @@ -8625,19 +8625,19 @@ "integrity": "sha1-UqzCP+7Kw0BCB47njAwAf1CF20w=", "dev": true, "requires": { - "camelcase": "^4.1.0", - "cliui": "^3.2.0", - "decamelize": "^1.1.1", - "get-caller-file": "^1.0.1", - "os-locale": "^2.0.0", - "read-pkg-up": "^2.0.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1", - "yargs-parser": "^7.0.0" + "camelcase": "4.1.0", + "cliui": "3.2.0", + "decamelize": "1.2.0", + "get-caller-file": "1.0.3", + "os-locale": "2.1.0", + "read-pkg-up": "2.0.0", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "2.1.1", + "which-module": "2.0.0", + "y18n": "3.2.1", + "yargs-parser": "7.0.0" }, "dependencies": { "ansi-regex": { @@ -8658,10 +8658,10 @@ "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", "dev": true, "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "strip-bom": "^3.0.0" + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "strip-bom": "3.0.0" } }, "parse-json": { @@ -8670,7 +8670,7 @@ "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", "dev": true, "requires": { - "error-ex": "^1.2.0" + "error-ex": "1.3.2" } }, "path-type": { @@ -8679,7 +8679,7 @@ "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", "dev": true, "requires": { - "pify": "^2.0.0" + "pify": "2.3.0" } }, "pify": { @@ -8694,9 +8694,9 @@ "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", "dev": true, "requires": { - "load-json-file": "^2.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^2.0.0" + "load-json-file": "2.0.0", + "normalize-package-data": "2.4.0", + "path-type": "2.0.0" } }, "read-pkg-up": { @@ -8705,8 +8705,8 @@ "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", "dev": true, "requires": { - "find-up": "^2.0.0", - "read-pkg": "^2.0.0" + "find-up": "2.1.0", + "read-pkg": "2.0.0" } }, "string-width": { @@ -8715,8 +8715,8 @@ "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" } }, "strip-ansi": { @@ -8725,7 +8725,7 @@ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { - "ansi-regex": "^3.0.0" + "ansi-regex": "3.0.0" } } } @@ -8736,7 +8736,7 @@ "integrity": "sha1-jQrELxbqVd69MyyvTEA4s+P139k=", "dev": true, "requires": { - "camelcase": "^4.1.0" + "camelcase": "4.1.0" } } } diff --git a/installer/templates/phx_assets/phoenix.js b/installer/templates/phx_assets/phoenix.js index 1e307e5a2b..f5f9b2a08b 100644 --- a/installer/templates/phx_assets/phoenix.js +++ b/installer/templates/phx_assets/phoenix.js @@ -1 +1 @@ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.Phoenix=t():e.Phoenix=t()}(window,function(){return function(e){var t={};function n(i){if(t[i])return t[i].exports;var o=t[i]={i:i,l:!1,exports:{}};return e[i].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,i){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:i})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var i=Object.create(null);if(n.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(i,o,function(t){return e[t]}.bind(null,o));return i},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=0)}([function(e,t,n){(function(t){e.exports=t.Phoenix=n(2)}).call(this,n(1))},function(e,t){var n;n=function(){return this}();try{n=n||Function("return this")()||(0,eval)("this")}catch(e){"object"==typeof window&&(n=window)}e.exports=n},function(e,t,n){"use strict";function i(e){return function(e){if(Array.isArray(e)){for(var t=0,n=new Array(e.length);t0&&void 0!==arguments[0]?arguments[0]:this.timeout;if(this.joinedOnce)throw"tried to join multiple times. 'join' can only be called a single time per channel instance";return this.joinedOnce=!0,this.rejoin(e),this.joinPush}},{key:"onClose",value:function(e){this.on(p.close,e)}},{key:"onError",value:function(e){return this.on(p.error,function(t){return e(t)})}},{key:"on",value:function(e,t){var n=this.bindingRef++;return this.bindings.push({event:e,ref:n,callback:t}),n}},{key:"off",value:function(e,t){this.bindings=this.bindings.filter(function(n){return!(n.event===e&&(void 0===t||t===n.ref))})}},{key:"canPush",value:function(){return this.socket.isConnected()&&this.isJoined()}},{key:"push",value:function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:this.timeout;if(!this.joinedOnce)throw"tried to push '".concat(e,"' to '").concat(this.topic,"' before joining. Use channel.join() before pushing events");var i=new g(this,e,function(){return t},n);return this.canPush()?i.send():(i.startTimeout(),this.pushBuffer.push(i)),i}},{key:"leave",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.timeout;this.state=f.leaving;var n=function(){e.socket.hasLogger()&&e.socket.log("channel","leave ".concat(e.topic)),e.trigger(p.close,"leave")},i=new g(this,p.leave,y({}),t);return i.receive("ok",function(){return n()}).receive("timeout",function(){return n()}),i.send(),this.canPush()||i.trigger("ok",{}),i}},{key:"onMessage",value:function(e,t,n){return t}},{key:"isLifecycleEvent",value:function(e){return d.indexOf(e)>=0}},{key:"isMember",value:function(e,t,n,i){return this.topic===e&&(!i||i===this.joinRef()||!this.isLifecycleEvent(t)||(this.socket.hasLogger()&&this.socket.log("channel","dropping outdated message",{topic:e,event:t,payload:n,joinRef:i}),!1))}},{key:"joinRef",value:function(){return this.joinPush.ref}},{key:"sendJoin",value:function(e){this.state=f.joining,this.joinPush.resend(e)}},{key:"rejoin",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.timeout;this.isLeaving()||this.sendJoin(e)}},{key:"trigger",value:function(e,t,n,i){var o=this.onMessage(e,t,n,i);if(t&&!o)throw"channel onMessage callbacks must return the payload, modified or unmodified";for(var r=0;r1&&void 0!==arguments[1]?arguments[1]:{};s(this,e),this.stateChangeCallbacks={open:[],close:[],error:[],message:[]},this.channels=[],this.sendBuffer=[],this.ref=0,this.timeout=i.timeout||l,this.transport=i.transport||u.WebSocket||j,this.defaultEncoder=k.encode,this.defaultDecoder=k.decode,this.transport!==j?(this.encode=i.encode||this.defaultEncoder,this.decode=i.decode||this.defaultDecoder):(this.encode=this.defaultEncoder,this.decode=this.defaultDecoder),this.heartbeatIntervalMs=i.heartbeatIntervalMs||3e4,this.reconnectAfterMs=i.reconnectAfterMs||function(e){return[1e3,2e3,5e3,1e4][e-1]||1e4},this.logger=i.logger||null,this.longpollerTimeout=i.longpollerTimeout||2e4,this.params=y(i.params||{}),this.endPoint="".concat(t,"/").concat(v.websocket),this.heartbeatTimer=null,this.pendingHeartbeatRef=null,this.reconnectTimer=new S(function(){n.teardown(function(){return n.connect()})},this.reconnectAfterMs)}return c(e,[{key:"protocol",value:function(){return location.protocol.match(/^https/)?"wss":"ws"}},{key:"endPointURL",value:function(){var e=R.appendParams(R.appendParams(this.endPoint,this.params()),{vsn:"2.0.0"});return"/"!==e.charAt(0)?e:"/"===e.charAt(1)?"".concat(this.protocol(),":").concat(e):"".concat(this.protocol(),"://").concat(location.host).concat(e)}},{key:"disconnect",value:function(e,t,n){this.reconnectTimer.reset(),this.teardown(e,t,n)}},{key:"connect",value:function(e){var t=this;e&&(console&&console.log("passing params to connect is deprecated. Instead pass :params to the Socket constructor"),this.params=y(e)),this.conn||(this.conn=new this.transport(this.endPointURL()),this.conn.timeout=this.longpollerTimeout,this.conn.onopen=function(){return t.onConnOpen()},this.conn.onerror=function(e){return t.onConnError(e)},this.conn.onmessage=function(e){return t.onConnMessage(e)},this.conn.onclose=function(e){return t.onConnClose(e)})}},{key:"log",value:function(e,t,n){this.logger(e,t,n)}},{key:"hasLogger",value:function(){return null!==this.logger}},{key:"onOpen",value:function(e){this.stateChangeCallbacks.open.push(e)}},{key:"onClose",value:function(e){this.stateChangeCallbacks.close.push(e)}},{key:"onError",value:function(e){this.stateChangeCallbacks.error.push(e)}},{key:"onMessage",value:function(e){this.stateChangeCallbacks.message.push(e)}},{key:"onConnOpen",value:function(){this.hasLogger()&&this.log("transport","connected to ".concat(this.endPointURL())),this.flushSendBuffer(),this.reconnectTimer.reset(),this.resetHeartbeat(),this.stateChangeCallbacks.open.forEach(function(e){return e()})}},{key:"resetHeartbeat",value:function(){var e=this;this.conn.skipHeartbeat||(this.pendingHeartbeatRef=null,clearInterval(this.heartbeatTimer),this.heartbeatTimer=setInterval(function(){return e.sendHeartbeat()},this.heartbeatIntervalMs))}},{key:"teardown",value:function(e,t,n){this.conn&&(this.conn.onclose=function(){},t?this.conn.close(t,n||""):this.conn.close(),this.conn=null),e&&e()}},{key:"onConnClose",value:function(e){this.hasLogger()&&this.log("transport","close",e),this.triggerChanError(),clearInterval(this.heartbeatTimer),e&&1e3!==e.code&&this.reconnectTimer.scheduleTimeout(),this.stateChangeCallbacks.close.forEach(function(t){return t(e)})}},{key:"onConnError",value:function(e){this.hasLogger()&&this.log("transport",e),this.triggerChanError(),this.stateChangeCallbacks.error.forEach(function(t){return t(e)})}},{key:"triggerChanError",value:function(){this.channels.forEach(function(e){return e.trigger(p.error)})}},{key:"connectionState",value:function(){switch(this.conn&&this.conn.readyState){case h.connecting:return"connecting";case h.open:return"open";case h.closing:return"closing";default:return"closed"}}},{key:"isConnected",value:function(){return"open"===this.connectionState()}},{key:"remove",value:function(e){this.channels=this.channels.filter(function(t){return t.joinRef()!==e.joinRef()})}},{key:"channel",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=new m(e,t,this);return this.channels.push(n),n}},{key:"push",value:function(e){var t=this;if(this.hasLogger()){var n=e.topic,i=e.event,o=e.payload,r=e.ref,s=e.join_ref;this.log("push","".concat(n," ").concat(i," (").concat(s,", ").concat(r,")"),o)}this.isConnected()?this.encode(e,function(e){return t.conn.send(e)}):this.sendBuffer.push(function(){return t.encode(e,function(e){return t.conn.send(e)})})}},{key:"makeRef",value:function(){var e=this.ref+1;return e===this.ref?this.ref=0:this.ref=e,this.ref.toString()}},{key:"sendHeartbeat",value:function(){if(this.isConnected()){if(this.pendingHeartbeatRef)return this.pendingHeartbeatRef=null,this.hasLogger()&&this.log("transport","heartbeat timeout. Attempting to re-establish connection"),void this.conn.close(1e3,"hearbeat timeout");this.pendingHeartbeatRef=this.makeRef(),this.push({topic:"phoenix",event:"heartbeat",payload:{},ref:this.pendingHeartbeatRef})}}},{key:"flushSendBuffer",value:function(){this.isConnected()&&this.sendBuffer.length>0&&(this.sendBuffer.forEach(function(e){return e()}),this.sendBuffer=[])}},{key:"onConnMessage",value:function(e){var t=this;this.decode(e.data,function(e){var n=e.topic,i=e.event,o=e.payload,r=e.ref,s=e.join_ref;r&&r===t.pendingHeartbeatRef&&(t.pendingHeartbeatRef=null),t.hasLogger()&&t.log("receive","".concat(o.status||""," ").concat(n," ").concat(i," ").concat(r&&"("+r+")"||""),o);for(var a=0;a1&&void 0!==arguments[1]?arguments[1]:{};s(this,e);var o=i.events||{state:"presence_state",diff:"presence_diff"};this.state={},this.pendingDiffs=[],this.channel=t,this.joinRef=null,this.caller={onJoin:function(){},onLeave:function(){},onSync:function(){}},this.channel.on(o.state,function(t){var i=n.caller,o=i.onJoin,r=i.onLeave,s=i.onSync;n.joinRef=n.channel.joinRef(),n.state=e.syncState(n.state,t,o,r),n.pendingDiffs.forEach(function(t){n.state=e.syncDiff(n.state,t,o,r)}),n.pendingDiffs=[],s()}),this.channel.on(o.diff,function(t){var i=n.caller,o=i.onJoin,r=i.onLeave,s=i.onSync;n.inPendingSyncState()?n.pendingDiffs.push(t):(n.state=e.syncDiff(n.state,t,o,r),s())})}return c(e,[{key:"onJoin",value:function(e){this.caller.onJoin=e}},{key:"onLeave",value:function(e){this.caller.onLeave=e}},{key:"onSync",value:function(e){this.caller.onSync=e}},{key:"list",value:function(t){return e.list(this.state,t)}},{key:"inPendingSyncState",value:function(){return!this.joinRef||this.joinRef!==this.channel.joinRef()}}],[{key:"syncState",value:function(e,t,n,i){var o=this,r=this.clone(e),s={},a={};return this.map(r,function(e,n){t[e]||(a[e]=n)}),this.map(t,function(e,t){var n=r[e];if(n){var i=t.metas.map(function(e){return e.phx_ref}),c=n.metas.map(function(e){return e.phx_ref}),u=t.metas.filter(function(e){return c.indexOf(e.phx_ref)<0}),h=n.metas.filter(function(e){return i.indexOf(e.phx_ref)<0});u.length>0&&(s[e]=t,s[e].metas=u),h.length>0&&(a[e]=o.clone(n),a[e].metas=h)}else s[e]=t}),this.syncDiff(r,{joins:s,leaves:a},n,i)}},{key:"syncDiff",value:function(e,t,n,o){var r=t.joins,s=t.leaves,a=this.clone(e);return n||(n=function(){}),o||(o=function(){}),this.map(r,function(e,t){var o=a[e];if(a[e]=t,o){var r,s=a[e].metas.map(function(e){return e.phx_ref}),c=o.metas.filter(function(e){return s.indexOf(e.phx_ref)<0});(r=a[e].metas).unshift.apply(r,i(c))}n(e,o,t)}),this.map(s,function(e,t){var n=a[e];if(n){var i=t.metas.map(function(e){return e.phx_ref});n.metas=n.metas.filter(function(e){return i.indexOf(e.phx_ref)<0}),o(e,n,t),0===n.metas.length&&delete a[e]}}),a}},{key:"list",value:function(e,t){return t||(t=function(e,t){return t}),this.map(e,function(e,n){return t(e,n)})}},{key:"map",value:function(e,t){return Object.getOwnPropertyNames(e).map(function(n){return t(n,e[n])})}},{key:"clone",value:function(e){return JSON.parse(JSON.stringify(e))}}]),e}(),S=function(){function e(t,n){s(this,e),this.callback=t,this.timerCalc=n,this.timer=null,this.tries=0}return c(e,[{key:"reset",value:function(){this.tries=0,clearTimeout(this.timer)}},{key:"scheduleTimeout",value:function(){var e=this;clearTimeout(this.timer),this.timer=setTimeout(function(){e.tries=e.tries+1,e.callback()},this.timerCalc(this.tries+1))}}]),e}()}])}); \ No newline at end of file +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.Phoenix=t():e.Phoenix=t()}(window,function(){return function(e){var t={};function n(i){if(t[i])return t[i].exports;var o=t[i]={i:i,l:!1,exports:{}};return e[i].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,i){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:i})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var i=Object.create(null);if(n.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(i,o,function(t){return e[t]}.bind(null,o));return i},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=0)}([function(e,t,n){(function(t){e.exports=t.Phoenix=n(2)}).call(this,n(1))},function(e,t){var n;n=function(){return this}();try{n=n||Function("return this")()||(0,eval)("this")}catch(e){"object"==typeof window&&(n=window)}e.exports=n},function(e,t,n){"use strict";function i(e){return function(e){if(Array.isArray(e)){for(var t=0,n=new Array(e.length);t0&&void 0!==arguments[0]?arguments[0]:this.timeout;if(this.joinedOnce)throw"tried to join multiple times. 'join' can only be called a single time per channel instance";return this.joinedOnce=!0,this.rejoin(e),this.joinPush}},{key:"onClose",value:function(e){this.on(p.close,e)}},{key:"onError",value:function(e){return this.on(p.error,function(t){return e(t)})}},{key:"on",value:function(e,t){var n=this.bindingRef++;return this.bindings.push({event:e,ref:n,callback:t}),n}},{key:"off",value:function(e,t){this.bindings=this.bindings.filter(function(n){return!(n.event===e&&(void 0===t||t===n.ref))})}},{key:"canPush",value:function(){return this.socket.isConnected()&&this.isJoined()}},{key:"push",value:function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:this.timeout;if(!this.joinedOnce)throw"tried to push '".concat(e,"' to '").concat(this.topic,"' before joining. Use channel.join() before pushing events");var i=new m(this,e,function(){return t},n);return this.canPush()?i.send():(i.startTimeout(),this.pushBuffer.push(i)),i}},{key:"leave",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.timeout;this.state=f.leaving;var n=function(){e.socket.hasLogger()&&e.socket.log("channel","leave ".concat(e.topic)),e.trigger(p.close,"leave")},i=new m(this,p.leave,y({}),t);return i.receive("ok",function(){return n()}).receive("timeout",function(){return n()}),i.send(),this.canPush()||i.trigger("ok",{}),i}},{key:"onMessage",value:function(e,t,n){return t}},{key:"isLifecycleEvent",value:function(e){return d.indexOf(e)>=0}},{key:"isMember",value:function(e,t,n,i){return this.topic===e&&(!i||i===this.joinRef()||!this.isLifecycleEvent(t)||(this.socket.hasLogger()&&this.socket.log("channel","dropping outdated message",{topic:e,event:t,payload:n,joinRef:i}),!1))}},{key:"joinRef",value:function(){return this.joinPush.ref}},{key:"sendJoin",value:function(e){this.state=f.joining,this.joinPush.resend(e)}},{key:"rejoin",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.timeout;this.isLeaving()||this.sendJoin(e)}},{key:"trigger",value:function(e,t,n,i){var o=this.onMessage(e,t,n,i);if(t&&!o)throw"channel onMessage callbacks must return the payload, modified or unmodified";for(var r=0;r1&&void 0!==arguments[1]?arguments[1]:{};s(this,e),this.stateChangeCallbacks={open:[],close:[],error:[],message:[]},this.channels=[],this.sendBuffer=[],this.ref=0,this.timeout=i.timeout||l,this.transport=i.transport||u.WebSocket||j,this.defaultEncoder=k.encode,this.defaultDecoder=k.decode,this.transport!==j?(this.encode=i.encode||this.defaultEncoder,this.decode=i.decode||this.defaultDecoder):(this.encode=this.defaultEncoder,this.decode=this.defaultDecoder),this.heartbeatIntervalMs=i.heartbeatIntervalMs||3e4,this.reconnectAfterMs=i.reconnectAfterMs||function(e){return[1e3,2e3,5e3,1e4][e-1]||1e4},this.logger=i.logger||null,this.longpollerTimeout=i.longpollerTimeout||2e4,this.params=y(i.params||{}),this.endPoint="".concat(t,"/").concat(v.websocket),this.heartbeatTimer=null,this.pendingHeartbeatRef=null,this.reconnectTimer=new C(function(){n.teardown(function(){return n.connect()})},this.reconnectAfterMs)}return c(e,[{key:"protocol",value:function(){return location.protocol.match(/^https/)?"wss":"ws"}},{key:"endPointURL",value:function(){var e=R.appendParams(R.appendParams(this.endPoint,this.params()),{vsn:"2.0.0"});return"/"!==e.charAt(0)?e:"/"===e.charAt(1)?"".concat(this.protocol(),":").concat(e):"".concat(this.protocol(),"://").concat(location.host).concat(e)}},{key:"disconnect",value:function(e,t,n){this.reconnectTimer.reset(),this.teardown(e,t,n)}},{key:"connect",value:function(e){var t=this;e&&(console&&console.log("passing params to connect is deprecated. Instead pass :params to the Socket constructor"),this.params=y(e)),this.conn||(this.conn=new this.transport(this.endPointURL()),this.conn.timeout=this.longpollerTimeout,this.conn.onopen=function(){return t.onConnOpen()},this.conn.onerror=function(e){return t.onConnError(e)},this.conn.onmessage=function(e){return t.onConnMessage(e)},this.conn.onclose=function(e){return t.onConnClose(e)})}},{key:"log",value:function(e,t,n){this.logger(e,t,n)}},{key:"hasLogger",value:function(){return null!==this.logger}},{key:"onOpen",value:function(e){this.stateChangeCallbacks.open.push(e)}},{key:"onClose",value:function(e){this.stateChangeCallbacks.close.push(e)}},{key:"onError",value:function(e){this.stateChangeCallbacks.error.push(e)}},{key:"onMessage",value:function(e){this.stateChangeCallbacks.message.push(e)}},{key:"onConnOpen",value:function(){this.hasLogger()&&this.log("transport","connected to ".concat(this.endPointURL())),this.flushSendBuffer(),this.reconnectTimer.reset(),this.resetHeartbeat(),this.resetChannelTimers(),this.stateChangeCallbacks.open.forEach(function(e){return e()})}},{key:"resetHeartbeat",value:function(){var e=this;this.conn.skipHeartbeat||(this.pendingHeartbeatRef=null,clearInterval(this.heartbeatTimer),this.heartbeatTimer=setInterval(function(){return e.sendHeartbeat()},this.heartbeatIntervalMs))}},{key:"teardown",value:function(e,t,n){this.conn&&(this.conn.onclose=function(){},t?this.conn.close(t,n||""):this.conn.close(),this.conn=null),e&&e()}},{key:"onConnClose",value:function(e){this.hasLogger()&&this.log("transport","close",e),this.triggerChanError(),clearInterval(this.heartbeatTimer),e&&1e3!==e.code&&this.reconnectTimer.scheduleTimeout(),this.stateChangeCallbacks.close.forEach(function(t){return t(e)})}},{key:"onConnError",value:function(e){this.hasLogger()&&this.log("transport",e),this.triggerChanError(),this.stateChangeCallbacks.error.forEach(function(t){return t(e)})}},{key:"triggerChanError",value:function(){this.channels.forEach(function(e){return e.trigger(p.error)})}},{key:"connectionState",value:function(){switch(this.conn&&this.conn.readyState){case h.connecting:return"connecting";case h.open:return"open";case h.closing:return"closing";default:return"closed"}}},{key:"isConnected",value:function(){return"open"===this.connectionState()}},{key:"remove",value:function(e){this.channels=this.channels.filter(function(t){return t.joinRef()!==e.joinRef()})}},{key:"channel",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=new g(e,t,this);return this.channels.push(n),n}},{key:"push",value:function(e){var t=this;if(this.hasLogger()){var n=e.topic,i=e.event,o=e.payload,r=e.ref,s=e.join_ref;this.log("push","".concat(n," ").concat(i," (").concat(s,", ").concat(r,")"),o)}this.isConnected()?this.encode(e,function(e){return t.conn.send(e)}):this.sendBuffer.push(function(){return t.encode(e,function(e){return t.conn.send(e)})})}},{key:"makeRef",value:function(){var e=this.ref+1;return e===this.ref?this.ref=0:this.ref=e,this.ref.toString()}},{key:"sendHeartbeat",value:function(){if(this.isConnected()){if(this.pendingHeartbeatRef)return this.pendingHeartbeatRef=null,this.hasLogger()&&this.log("transport","heartbeat timeout. Attempting to re-establish connection"),void this.conn.close(1e3,"hearbeat timeout");this.pendingHeartbeatRef=this.makeRef(),this.push({topic:"phoenix",event:"heartbeat",payload:{},ref:this.pendingHeartbeatRef})}}},{key:"flushSendBuffer",value:function(){this.isConnected()&&this.sendBuffer.length>0&&(this.sendBuffer.forEach(function(e){return e()}),this.sendBuffer=[])}},{key:"onConnMessage",value:function(e){var t=this;this.decode(e.data,function(e){var n=e.topic,i=e.event,o=e.payload,r=e.ref,s=e.join_ref;r&&r===t.pendingHeartbeatRef&&(t.pendingHeartbeatRef=null),t.hasLogger()&&t.log("receive","".concat(o.status||""," ").concat(n," ").concat(i," ").concat(r&&"("+r+")"||""),o);for(var a=0;a1&&void 0!==arguments[1]?arguments[1]:{};s(this,e);var o=i.events||{state:"presence_state",diff:"presence_diff"};this.state={},this.pendingDiffs=[],this.channel=t,this.joinRef=null,this.caller={onJoin:function(){},onLeave:function(){},onSync:function(){}},this.channel.on(o.state,function(t){var i=n.caller,o=i.onJoin,r=i.onLeave,s=i.onSync;n.joinRef=n.channel.joinRef(),n.state=e.syncState(n.state,t,o,r),n.pendingDiffs.forEach(function(t){n.state=e.syncDiff(n.state,t,o,r)}),n.pendingDiffs=[],s()}),this.channel.on(o.diff,function(t){var i=n.caller,o=i.onJoin,r=i.onLeave,s=i.onSync;n.inPendingSyncState()?n.pendingDiffs.push(t):(n.state=e.syncDiff(n.state,t,o,r),s())})}return c(e,[{key:"onJoin",value:function(e){this.caller.onJoin=e}},{key:"onLeave",value:function(e){this.caller.onLeave=e}},{key:"onSync",value:function(e){this.caller.onSync=e}},{key:"list",value:function(t){return e.list(this.state,t)}},{key:"inPendingSyncState",value:function(){return!this.joinRef||this.joinRef!==this.channel.joinRef()}}],[{key:"syncState",value:function(e,t,n,i){var o=this,r=this.clone(e),s={},a={};return this.map(r,function(e,n){t[e]||(a[e]=n)}),this.map(t,function(e,t){var n=r[e];if(n){var i=t.metas.map(function(e){return e.phx_ref}),c=n.metas.map(function(e){return e.phx_ref}),u=t.metas.filter(function(e){return c.indexOf(e.phx_ref)<0}),h=n.metas.filter(function(e){return i.indexOf(e.phx_ref)<0});u.length>0&&(s[e]=t,s[e].metas=u),h.length>0&&(a[e]=o.clone(n),a[e].metas=h)}else s[e]=t}),this.syncDiff(r,{joins:s,leaves:a},n,i)}},{key:"syncDiff",value:function(e,t,n,o){var r=t.joins,s=t.leaves,a=this.clone(e);return n||(n=function(){}),o||(o=function(){}),this.map(r,function(e,t){var o=a[e];if(a[e]=t,o){var r,s=a[e].metas.map(function(e){return e.phx_ref}),c=o.metas.filter(function(e){return s.indexOf(e.phx_ref)<0});(r=a[e].metas).unshift.apply(r,i(c))}n(e,o,t)}),this.map(s,function(e,t){var n=a[e];if(n){var i=t.metas.map(function(e){return e.phx_ref});n.metas=n.metas.filter(function(e){return i.indexOf(e.phx_ref)<0}),o(e,n,t),0===n.metas.length&&delete a[e]}}),a}},{key:"list",value:function(e,t){return t||(t=function(e,t){return t}),this.map(e,function(e,n){return t(e,n)})}},{key:"map",value:function(e,t){return Object.getOwnPropertyNames(e).map(function(n){return t(n,e[n])})}},{key:"clone",value:function(e){return JSON.parse(JSON.stringify(e))}}]),e}(),C=function(){function e(t,n){s(this,e),this.callback=t,this.timerCalc=n,this.timer=null,this.tries=0}return c(e,[{key:"reset",value:function(){this.tries=0,this.clearTimer()}},{key:"restart",value:function(){var e=null!==this.timer;this.reset(),e&&this.scheduleTimeout()}},{key:"scheduleTimeout",value:function(){var e=this;this.clearTimer(),this.timer=setTimeout(function(){e.tries=e.tries+1,e.callback()},this.timerCalc(this.tries+1))}},{key:"clearTimer",value:function(){clearTimeout(this.timer),this.timer=null}}]),e}()}])}); \ No newline at end of file diff --git a/priv/static/phoenix.js b/priv/static/phoenix.js index 1e307e5a2b..f5f9b2a08b 100644 --- a/priv/static/phoenix.js +++ b/priv/static/phoenix.js @@ -1 +1 @@ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.Phoenix=t():e.Phoenix=t()}(window,function(){return function(e){var t={};function n(i){if(t[i])return t[i].exports;var o=t[i]={i:i,l:!1,exports:{}};return e[i].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,i){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:i})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var i=Object.create(null);if(n.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(i,o,function(t){return e[t]}.bind(null,o));return i},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=0)}([function(e,t,n){(function(t){e.exports=t.Phoenix=n(2)}).call(this,n(1))},function(e,t){var n;n=function(){return this}();try{n=n||Function("return this")()||(0,eval)("this")}catch(e){"object"==typeof window&&(n=window)}e.exports=n},function(e,t,n){"use strict";function i(e){return function(e){if(Array.isArray(e)){for(var t=0,n=new Array(e.length);t0&&void 0!==arguments[0]?arguments[0]:this.timeout;if(this.joinedOnce)throw"tried to join multiple times. 'join' can only be called a single time per channel instance";return this.joinedOnce=!0,this.rejoin(e),this.joinPush}},{key:"onClose",value:function(e){this.on(p.close,e)}},{key:"onError",value:function(e){return this.on(p.error,function(t){return e(t)})}},{key:"on",value:function(e,t){var n=this.bindingRef++;return this.bindings.push({event:e,ref:n,callback:t}),n}},{key:"off",value:function(e,t){this.bindings=this.bindings.filter(function(n){return!(n.event===e&&(void 0===t||t===n.ref))})}},{key:"canPush",value:function(){return this.socket.isConnected()&&this.isJoined()}},{key:"push",value:function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:this.timeout;if(!this.joinedOnce)throw"tried to push '".concat(e,"' to '").concat(this.topic,"' before joining. Use channel.join() before pushing events");var i=new g(this,e,function(){return t},n);return this.canPush()?i.send():(i.startTimeout(),this.pushBuffer.push(i)),i}},{key:"leave",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.timeout;this.state=f.leaving;var n=function(){e.socket.hasLogger()&&e.socket.log("channel","leave ".concat(e.topic)),e.trigger(p.close,"leave")},i=new g(this,p.leave,y({}),t);return i.receive("ok",function(){return n()}).receive("timeout",function(){return n()}),i.send(),this.canPush()||i.trigger("ok",{}),i}},{key:"onMessage",value:function(e,t,n){return t}},{key:"isLifecycleEvent",value:function(e){return d.indexOf(e)>=0}},{key:"isMember",value:function(e,t,n,i){return this.topic===e&&(!i||i===this.joinRef()||!this.isLifecycleEvent(t)||(this.socket.hasLogger()&&this.socket.log("channel","dropping outdated message",{topic:e,event:t,payload:n,joinRef:i}),!1))}},{key:"joinRef",value:function(){return this.joinPush.ref}},{key:"sendJoin",value:function(e){this.state=f.joining,this.joinPush.resend(e)}},{key:"rejoin",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.timeout;this.isLeaving()||this.sendJoin(e)}},{key:"trigger",value:function(e,t,n,i){var o=this.onMessage(e,t,n,i);if(t&&!o)throw"channel onMessage callbacks must return the payload, modified or unmodified";for(var r=0;r1&&void 0!==arguments[1]?arguments[1]:{};s(this,e),this.stateChangeCallbacks={open:[],close:[],error:[],message:[]},this.channels=[],this.sendBuffer=[],this.ref=0,this.timeout=i.timeout||l,this.transport=i.transport||u.WebSocket||j,this.defaultEncoder=k.encode,this.defaultDecoder=k.decode,this.transport!==j?(this.encode=i.encode||this.defaultEncoder,this.decode=i.decode||this.defaultDecoder):(this.encode=this.defaultEncoder,this.decode=this.defaultDecoder),this.heartbeatIntervalMs=i.heartbeatIntervalMs||3e4,this.reconnectAfterMs=i.reconnectAfterMs||function(e){return[1e3,2e3,5e3,1e4][e-1]||1e4},this.logger=i.logger||null,this.longpollerTimeout=i.longpollerTimeout||2e4,this.params=y(i.params||{}),this.endPoint="".concat(t,"/").concat(v.websocket),this.heartbeatTimer=null,this.pendingHeartbeatRef=null,this.reconnectTimer=new S(function(){n.teardown(function(){return n.connect()})},this.reconnectAfterMs)}return c(e,[{key:"protocol",value:function(){return location.protocol.match(/^https/)?"wss":"ws"}},{key:"endPointURL",value:function(){var e=R.appendParams(R.appendParams(this.endPoint,this.params()),{vsn:"2.0.0"});return"/"!==e.charAt(0)?e:"/"===e.charAt(1)?"".concat(this.protocol(),":").concat(e):"".concat(this.protocol(),"://").concat(location.host).concat(e)}},{key:"disconnect",value:function(e,t,n){this.reconnectTimer.reset(),this.teardown(e,t,n)}},{key:"connect",value:function(e){var t=this;e&&(console&&console.log("passing params to connect is deprecated. Instead pass :params to the Socket constructor"),this.params=y(e)),this.conn||(this.conn=new this.transport(this.endPointURL()),this.conn.timeout=this.longpollerTimeout,this.conn.onopen=function(){return t.onConnOpen()},this.conn.onerror=function(e){return t.onConnError(e)},this.conn.onmessage=function(e){return t.onConnMessage(e)},this.conn.onclose=function(e){return t.onConnClose(e)})}},{key:"log",value:function(e,t,n){this.logger(e,t,n)}},{key:"hasLogger",value:function(){return null!==this.logger}},{key:"onOpen",value:function(e){this.stateChangeCallbacks.open.push(e)}},{key:"onClose",value:function(e){this.stateChangeCallbacks.close.push(e)}},{key:"onError",value:function(e){this.stateChangeCallbacks.error.push(e)}},{key:"onMessage",value:function(e){this.stateChangeCallbacks.message.push(e)}},{key:"onConnOpen",value:function(){this.hasLogger()&&this.log("transport","connected to ".concat(this.endPointURL())),this.flushSendBuffer(),this.reconnectTimer.reset(),this.resetHeartbeat(),this.stateChangeCallbacks.open.forEach(function(e){return e()})}},{key:"resetHeartbeat",value:function(){var e=this;this.conn.skipHeartbeat||(this.pendingHeartbeatRef=null,clearInterval(this.heartbeatTimer),this.heartbeatTimer=setInterval(function(){return e.sendHeartbeat()},this.heartbeatIntervalMs))}},{key:"teardown",value:function(e,t,n){this.conn&&(this.conn.onclose=function(){},t?this.conn.close(t,n||""):this.conn.close(),this.conn=null),e&&e()}},{key:"onConnClose",value:function(e){this.hasLogger()&&this.log("transport","close",e),this.triggerChanError(),clearInterval(this.heartbeatTimer),e&&1e3!==e.code&&this.reconnectTimer.scheduleTimeout(),this.stateChangeCallbacks.close.forEach(function(t){return t(e)})}},{key:"onConnError",value:function(e){this.hasLogger()&&this.log("transport",e),this.triggerChanError(),this.stateChangeCallbacks.error.forEach(function(t){return t(e)})}},{key:"triggerChanError",value:function(){this.channels.forEach(function(e){return e.trigger(p.error)})}},{key:"connectionState",value:function(){switch(this.conn&&this.conn.readyState){case h.connecting:return"connecting";case h.open:return"open";case h.closing:return"closing";default:return"closed"}}},{key:"isConnected",value:function(){return"open"===this.connectionState()}},{key:"remove",value:function(e){this.channels=this.channels.filter(function(t){return t.joinRef()!==e.joinRef()})}},{key:"channel",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=new m(e,t,this);return this.channels.push(n),n}},{key:"push",value:function(e){var t=this;if(this.hasLogger()){var n=e.topic,i=e.event,o=e.payload,r=e.ref,s=e.join_ref;this.log("push","".concat(n," ").concat(i," (").concat(s,", ").concat(r,")"),o)}this.isConnected()?this.encode(e,function(e){return t.conn.send(e)}):this.sendBuffer.push(function(){return t.encode(e,function(e){return t.conn.send(e)})})}},{key:"makeRef",value:function(){var e=this.ref+1;return e===this.ref?this.ref=0:this.ref=e,this.ref.toString()}},{key:"sendHeartbeat",value:function(){if(this.isConnected()){if(this.pendingHeartbeatRef)return this.pendingHeartbeatRef=null,this.hasLogger()&&this.log("transport","heartbeat timeout. Attempting to re-establish connection"),void this.conn.close(1e3,"hearbeat timeout");this.pendingHeartbeatRef=this.makeRef(),this.push({topic:"phoenix",event:"heartbeat",payload:{},ref:this.pendingHeartbeatRef})}}},{key:"flushSendBuffer",value:function(){this.isConnected()&&this.sendBuffer.length>0&&(this.sendBuffer.forEach(function(e){return e()}),this.sendBuffer=[])}},{key:"onConnMessage",value:function(e){var t=this;this.decode(e.data,function(e){var n=e.topic,i=e.event,o=e.payload,r=e.ref,s=e.join_ref;r&&r===t.pendingHeartbeatRef&&(t.pendingHeartbeatRef=null),t.hasLogger()&&t.log("receive","".concat(o.status||""," ").concat(n," ").concat(i," ").concat(r&&"("+r+")"||""),o);for(var a=0;a1&&void 0!==arguments[1]?arguments[1]:{};s(this,e);var o=i.events||{state:"presence_state",diff:"presence_diff"};this.state={},this.pendingDiffs=[],this.channel=t,this.joinRef=null,this.caller={onJoin:function(){},onLeave:function(){},onSync:function(){}},this.channel.on(o.state,function(t){var i=n.caller,o=i.onJoin,r=i.onLeave,s=i.onSync;n.joinRef=n.channel.joinRef(),n.state=e.syncState(n.state,t,o,r),n.pendingDiffs.forEach(function(t){n.state=e.syncDiff(n.state,t,o,r)}),n.pendingDiffs=[],s()}),this.channel.on(o.diff,function(t){var i=n.caller,o=i.onJoin,r=i.onLeave,s=i.onSync;n.inPendingSyncState()?n.pendingDiffs.push(t):(n.state=e.syncDiff(n.state,t,o,r),s())})}return c(e,[{key:"onJoin",value:function(e){this.caller.onJoin=e}},{key:"onLeave",value:function(e){this.caller.onLeave=e}},{key:"onSync",value:function(e){this.caller.onSync=e}},{key:"list",value:function(t){return e.list(this.state,t)}},{key:"inPendingSyncState",value:function(){return!this.joinRef||this.joinRef!==this.channel.joinRef()}}],[{key:"syncState",value:function(e,t,n,i){var o=this,r=this.clone(e),s={},a={};return this.map(r,function(e,n){t[e]||(a[e]=n)}),this.map(t,function(e,t){var n=r[e];if(n){var i=t.metas.map(function(e){return e.phx_ref}),c=n.metas.map(function(e){return e.phx_ref}),u=t.metas.filter(function(e){return c.indexOf(e.phx_ref)<0}),h=n.metas.filter(function(e){return i.indexOf(e.phx_ref)<0});u.length>0&&(s[e]=t,s[e].metas=u),h.length>0&&(a[e]=o.clone(n),a[e].metas=h)}else s[e]=t}),this.syncDiff(r,{joins:s,leaves:a},n,i)}},{key:"syncDiff",value:function(e,t,n,o){var r=t.joins,s=t.leaves,a=this.clone(e);return n||(n=function(){}),o||(o=function(){}),this.map(r,function(e,t){var o=a[e];if(a[e]=t,o){var r,s=a[e].metas.map(function(e){return e.phx_ref}),c=o.metas.filter(function(e){return s.indexOf(e.phx_ref)<0});(r=a[e].metas).unshift.apply(r,i(c))}n(e,o,t)}),this.map(s,function(e,t){var n=a[e];if(n){var i=t.metas.map(function(e){return e.phx_ref});n.metas=n.metas.filter(function(e){return i.indexOf(e.phx_ref)<0}),o(e,n,t),0===n.metas.length&&delete a[e]}}),a}},{key:"list",value:function(e,t){return t||(t=function(e,t){return t}),this.map(e,function(e,n){return t(e,n)})}},{key:"map",value:function(e,t){return Object.getOwnPropertyNames(e).map(function(n){return t(n,e[n])})}},{key:"clone",value:function(e){return JSON.parse(JSON.stringify(e))}}]),e}(),S=function(){function e(t,n){s(this,e),this.callback=t,this.timerCalc=n,this.timer=null,this.tries=0}return c(e,[{key:"reset",value:function(){this.tries=0,clearTimeout(this.timer)}},{key:"scheduleTimeout",value:function(){var e=this;clearTimeout(this.timer),this.timer=setTimeout(function(){e.tries=e.tries+1,e.callback()},this.timerCalc(this.tries+1))}}]),e}()}])}); \ No newline at end of file +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.Phoenix=t():e.Phoenix=t()}(window,function(){return function(e){var t={};function n(i){if(t[i])return t[i].exports;var o=t[i]={i:i,l:!1,exports:{}};return e[i].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,i){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:i})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var i=Object.create(null);if(n.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(i,o,function(t){return e[t]}.bind(null,o));return i},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=0)}([function(e,t,n){(function(t){e.exports=t.Phoenix=n(2)}).call(this,n(1))},function(e,t){var n;n=function(){return this}();try{n=n||Function("return this")()||(0,eval)("this")}catch(e){"object"==typeof window&&(n=window)}e.exports=n},function(e,t,n){"use strict";function i(e){return function(e){if(Array.isArray(e)){for(var t=0,n=new Array(e.length);t0&&void 0!==arguments[0]?arguments[0]:this.timeout;if(this.joinedOnce)throw"tried to join multiple times. 'join' can only be called a single time per channel instance";return this.joinedOnce=!0,this.rejoin(e),this.joinPush}},{key:"onClose",value:function(e){this.on(p.close,e)}},{key:"onError",value:function(e){return this.on(p.error,function(t){return e(t)})}},{key:"on",value:function(e,t){var n=this.bindingRef++;return this.bindings.push({event:e,ref:n,callback:t}),n}},{key:"off",value:function(e,t){this.bindings=this.bindings.filter(function(n){return!(n.event===e&&(void 0===t||t===n.ref))})}},{key:"canPush",value:function(){return this.socket.isConnected()&&this.isJoined()}},{key:"push",value:function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:this.timeout;if(!this.joinedOnce)throw"tried to push '".concat(e,"' to '").concat(this.topic,"' before joining. Use channel.join() before pushing events");var i=new m(this,e,function(){return t},n);return this.canPush()?i.send():(i.startTimeout(),this.pushBuffer.push(i)),i}},{key:"leave",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.timeout;this.state=f.leaving;var n=function(){e.socket.hasLogger()&&e.socket.log("channel","leave ".concat(e.topic)),e.trigger(p.close,"leave")},i=new m(this,p.leave,y({}),t);return i.receive("ok",function(){return n()}).receive("timeout",function(){return n()}),i.send(),this.canPush()||i.trigger("ok",{}),i}},{key:"onMessage",value:function(e,t,n){return t}},{key:"isLifecycleEvent",value:function(e){return d.indexOf(e)>=0}},{key:"isMember",value:function(e,t,n,i){return this.topic===e&&(!i||i===this.joinRef()||!this.isLifecycleEvent(t)||(this.socket.hasLogger()&&this.socket.log("channel","dropping outdated message",{topic:e,event:t,payload:n,joinRef:i}),!1))}},{key:"joinRef",value:function(){return this.joinPush.ref}},{key:"sendJoin",value:function(e){this.state=f.joining,this.joinPush.resend(e)}},{key:"rejoin",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.timeout;this.isLeaving()||this.sendJoin(e)}},{key:"trigger",value:function(e,t,n,i){var o=this.onMessage(e,t,n,i);if(t&&!o)throw"channel onMessage callbacks must return the payload, modified or unmodified";for(var r=0;r1&&void 0!==arguments[1]?arguments[1]:{};s(this,e),this.stateChangeCallbacks={open:[],close:[],error:[],message:[]},this.channels=[],this.sendBuffer=[],this.ref=0,this.timeout=i.timeout||l,this.transport=i.transport||u.WebSocket||j,this.defaultEncoder=k.encode,this.defaultDecoder=k.decode,this.transport!==j?(this.encode=i.encode||this.defaultEncoder,this.decode=i.decode||this.defaultDecoder):(this.encode=this.defaultEncoder,this.decode=this.defaultDecoder),this.heartbeatIntervalMs=i.heartbeatIntervalMs||3e4,this.reconnectAfterMs=i.reconnectAfterMs||function(e){return[1e3,2e3,5e3,1e4][e-1]||1e4},this.logger=i.logger||null,this.longpollerTimeout=i.longpollerTimeout||2e4,this.params=y(i.params||{}),this.endPoint="".concat(t,"/").concat(v.websocket),this.heartbeatTimer=null,this.pendingHeartbeatRef=null,this.reconnectTimer=new C(function(){n.teardown(function(){return n.connect()})},this.reconnectAfterMs)}return c(e,[{key:"protocol",value:function(){return location.protocol.match(/^https/)?"wss":"ws"}},{key:"endPointURL",value:function(){var e=R.appendParams(R.appendParams(this.endPoint,this.params()),{vsn:"2.0.0"});return"/"!==e.charAt(0)?e:"/"===e.charAt(1)?"".concat(this.protocol(),":").concat(e):"".concat(this.protocol(),"://").concat(location.host).concat(e)}},{key:"disconnect",value:function(e,t,n){this.reconnectTimer.reset(),this.teardown(e,t,n)}},{key:"connect",value:function(e){var t=this;e&&(console&&console.log("passing params to connect is deprecated. Instead pass :params to the Socket constructor"),this.params=y(e)),this.conn||(this.conn=new this.transport(this.endPointURL()),this.conn.timeout=this.longpollerTimeout,this.conn.onopen=function(){return t.onConnOpen()},this.conn.onerror=function(e){return t.onConnError(e)},this.conn.onmessage=function(e){return t.onConnMessage(e)},this.conn.onclose=function(e){return t.onConnClose(e)})}},{key:"log",value:function(e,t,n){this.logger(e,t,n)}},{key:"hasLogger",value:function(){return null!==this.logger}},{key:"onOpen",value:function(e){this.stateChangeCallbacks.open.push(e)}},{key:"onClose",value:function(e){this.stateChangeCallbacks.close.push(e)}},{key:"onError",value:function(e){this.stateChangeCallbacks.error.push(e)}},{key:"onMessage",value:function(e){this.stateChangeCallbacks.message.push(e)}},{key:"onConnOpen",value:function(){this.hasLogger()&&this.log("transport","connected to ".concat(this.endPointURL())),this.flushSendBuffer(),this.reconnectTimer.reset(),this.resetHeartbeat(),this.resetChannelTimers(),this.stateChangeCallbacks.open.forEach(function(e){return e()})}},{key:"resetHeartbeat",value:function(){var e=this;this.conn.skipHeartbeat||(this.pendingHeartbeatRef=null,clearInterval(this.heartbeatTimer),this.heartbeatTimer=setInterval(function(){return e.sendHeartbeat()},this.heartbeatIntervalMs))}},{key:"teardown",value:function(e,t,n){this.conn&&(this.conn.onclose=function(){},t?this.conn.close(t,n||""):this.conn.close(),this.conn=null),e&&e()}},{key:"onConnClose",value:function(e){this.hasLogger()&&this.log("transport","close",e),this.triggerChanError(),clearInterval(this.heartbeatTimer),e&&1e3!==e.code&&this.reconnectTimer.scheduleTimeout(),this.stateChangeCallbacks.close.forEach(function(t){return t(e)})}},{key:"onConnError",value:function(e){this.hasLogger()&&this.log("transport",e),this.triggerChanError(),this.stateChangeCallbacks.error.forEach(function(t){return t(e)})}},{key:"triggerChanError",value:function(){this.channels.forEach(function(e){return e.trigger(p.error)})}},{key:"connectionState",value:function(){switch(this.conn&&this.conn.readyState){case h.connecting:return"connecting";case h.open:return"open";case h.closing:return"closing";default:return"closed"}}},{key:"isConnected",value:function(){return"open"===this.connectionState()}},{key:"remove",value:function(e){this.channels=this.channels.filter(function(t){return t.joinRef()!==e.joinRef()})}},{key:"channel",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=new g(e,t,this);return this.channels.push(n),n}},{key:"push",value:function(e){var t=this;if(this.hasLogger()){var n=e.topic,i=e.event,o=e.payload,r=e.ref,s=e.join_ref;this.log("push","".concat(n," ").concat(i," (").concat(s,", ").concat(r,")"),o)}this.isConnected()?this.encode(e,function(e){return t.conn.send(e)}):this.sendBuffer.push(function(){return t.encode(e,function(e){return t.conn.send(e)})})}},{key:"makeRef",value:function(){var e=this.ref+1;return e===this.ref?this.ref=0:this.ref=e,this.ref.toString()}},{key:"sendHeartbeat",value:function(){if(this.isConnected()){if(this.pendingHeartbeatRef)return this.pendingHeartbeatRef=null,this.hasLogger()&&this.log("transport","heartbeat timeout. Attempting to re-establish connection"),void this.conn.close(1e3,"hearbeat timeout");this.pendingHeartbeatRef=this.makeRef(),this.push({topic:"phoenix",event:"heartbeat",payload:{},ref:this.pendingHeartbeatRef})}}},{key:"flushSendBuffer",value:function(){this.isConnected()&&this.sendBuffer.length>0&&(this.sendBuffer.forEach(function(e){return e()}),this.sendBuffer=[])}},{key:"onConnMessage",value:function(e){var t=this;this.decode(e.data,function(e){var n=e.topic,i=e.event,o=e.payload,r=e.ref,s=e.join_ref;r&&r===t.pendingHeartbeatRef&&(t.pendingHeartbeatRef=null),t.hasLogger()&&t.log("receive","".concat(o.status||""," ").concat(n," ").concat(i," ").concat(r&&"("+r+")"||""),o);for(var a=0;a1&&void 0!==arguments[1]?arguments[1]:{};s(this,e);var o=i.events||{state:"presence_state",diff:"presence_diff"};this.state={},this.pendingDiffs=[],this.channel=t,this.joinRef=null,this.caller={onJoin:function(){},onLeave:function(){},onSync:function(){}},this.channel.on(o.state,function(t){var i=n.caller,o=i.onJoin,r=i.onLeave,s=i.onSync;n.joinRef=n.channel.joinRef(),n.state=e.syncState(n.state,t,o,r),n.pendingDiffs.forEach(function(t){n.state=e.syncDiff(n.state,t,o,r)}),n.pendingDiffs=[],s()}),this.channel.on(o.diff,function(t){var i=n.caller,o=i.onJoin,r=i.onLeave,s=i.onSync;n.inPendingSyncState()?n.pendingDiffs.push(t):(n.state=e.syncDiff(n.state,t,o,r),s())})}return c(e,[{key:"onJoin",value:function(e){this.caller.onJoin=e}},{key:"onLeave",value:function(e){this.caller.onLeave=e}},{key:"onSync",value:function(e){this.caller.onSync=e}},{key:"list",value:function(t){return e.list(this.state,t)}},{key:"inPendingSyncState",value:function(){return!this.joinRef||this.joinRef!==this.channel.joinRef()}}],[{key:"syncState",value:function(e,t,n,i){var o=this,r=this.clone(e),s={},a={};return this.map(r,function(e,n){t[e]||(a[e]=n)}),this.map(t,function(e,t){var n=r[e];if(n){var i=t.metas.map(function(e){return e.phx_ref}),c=n.metas.map(function(e){return e.phx_ref}),u=t.metas.filter(function(e){return c.indexOf(e.phx_ref)<0}),h=n.metas.filter(function(e){return i.indexOf(e.phx_ref)<0});u.length>0&&(s[e]=t,s[e].metas=u),h.length>0&&(a[e]=o.clone(n),a[e].metas=h)}else s[e]=t}),this.syncDiff(r,{joins:s,leaves:a},n,i)}},{key:"syncDiff",value:function(e,t,n,o){var r=t.joins,s=t.leaves,a=this.clone(e);return n||(n=function(){}),o||(o=function(){}),this.map(r,function(e,t){var o=a[e];if(a[e]=t,o){var r,s=a[e].metas.map(function(e){return e.phx_ref}),c=o.metas.filter(function(e){return s.indexOf(e.phx_ref)<0});(r=a[e].metas).unshift.apply(r,i(c))}n(e,o,t)}),this.map(s,function(e,t){var n=a[e];if(n){var i=t.metas.map(function(e){return e.phx_ref});n.metas=n.metas.filter(function(e){return i.indexOf(e.phx_ref)<0}),o(e,n,t),0===n.metas.length&&delete a[e]}}),a}},{key:"list",value:function(e,t){return t||(t=function(e,t){return t}),this.map(e,function(e,n){return t(e,n)})}},{key:"map",value:function(e,t){return Object.getOwnPropertyNames(e).map(function(n){return t(n,e[n])})}},{key:"clone",value:function(e){return JSON.parse(JSON.stringify(e))}}]),e}(),C=function(){function e(t,n){s(this,e),this.callback=t,this.timerCalc=n,this.timer=null,this.tries=0}return c(e,[{key:"reset",value:function(){this.tries=0,this.clearTimer()}},{key:"restart",value:function(){var e=null!==this.timer;this.reset(),e&&this.scheduleTimeout()}},{key:"scheduleTimeout",value:function(){var e=this;this.clearTimer(),this.timer=setTimeout(function(){e.tries=e.tries+1,e.callback()},this.timerCalc(this.tries+1))}},{key:"clearTimer",value:function(){clearTimeout(this.timer),this.timer=null}}]),e}()}])}); \ No newline at end of file From 03243c69a20ff4b6ea757fc216a0569efb18827a Mon Sep 17 00:00:00 2001 From: Chris McCord Date: Wed, 7 Nov 2018 13:50:06 -0500 Subject: [PATCH 07/61] Release 1.4.0 --- CHANGELOG.md | 86 ++++++------------- RELEASE.md | 15 ++-- assets/package-lock.json | 2 +- assets/package.json | 2 +- guides/ecto.md | 8 +- guides/introduction/installation.md | 2 +- installer/README.md | 2 +- installer/lib/phx_new/generator.ex | 2 +- installer/mix.exs | 5 +- installer/templates/phx_single/mix.exs | 2 +- .../phx_umbrella/apps/app_name_web/mix.exs | 2 +- mix.exs | 2 +- package.json | 2 +- 13 files changed, 48 insertions(+), 84 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d41a0bcfb..8ba3230fdb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,6 @@ # Changelog for v1.4 -See the [upgrade guides](https://gist.github.com/chrismccord/bb1f8b136f5a9e4abc0bfc07b832257e) to bring your Phoenix 1.3.x apps up to speed. - -## Cowboy 2 support - -TODO: Write about how to use Cowboy 2 +See the [upgrade guides](https://gist.github.com/chrismccord/bb1f8b136f5a9e4abc0bfc07b832257e) to bring your Phoenix 1.3.x apps up to speed, including instructions on upgrading to Cowboy 2 for HTTP support. ## The Socket <-> Transport contract @@ -29,92 +25,62 @@ Note the websocket/longpoll configuration given to socket/3 will only apply afte The old APIs for building transports are also deprecated. The good news is: adapting an existing transport to the new API is a less error prone process where you should mostly remove code. -## 1.4.0-rc.4 - -### Enhancements - * [Endpoint] Allow custom keyword pairs to be passed to the socket `:connect_info` options. - -## 1.4.0-rc.3 (2018-10-30) +## 1.4.0 (2018-11-07) ### Enhancements * [phx.new] Update Ecto deps with the release of Ecto 3.0 including `phoenix_ecto` 4.0 * [phx.new] Import Ecto's `.formatter.exs` in new projects - * [Endpoint] Log the configured url instead of raw IP when booting endpoint webserver - -## 1.4.0-rc.2 (2018-10-20) - -### Enhancements - * [phx.new] Use Ecto 3.0RC, with `ecto_sql` in new project deps * [phx.new] Use Plug 1.7 with new `:plug_cowboy` dependency for cowboy adapter * [phx.gen.html|json|schema|context] Support new Ecto 3.0 usec datetime types - -### Bug Fixes - - * [Routes] Fix regression in router compilation failing to escape plug options - * [phx.gen.json|html] Fix generator tests incorrectly encoding datetimes - * [phx.gen.cert] Fix generation of cert inside umbrella projects - -## 1.4.0-rc.1 (2018-10-12) - -### Enhancements - - * [Socket] Improve error message when missing socket mount in endpoint - -### Bug Fixes - - * Add missing `.formatter.exs` to hex package for proper elixir formatter integration - * [phx.gen.cert] Fix usage inside umbrella applications - * [phx.new] Revert `Routes.static_url` in app layout in favor of original `Routes.static_path` - * [phx.new] Use phoenix_live_reload 1.2-rc to fix hex version errors - -### JavaScript client - - * Fix reconnect caused by pending heartbeat - -## 1.4.0-rc.0 (2018-10-09) - -### Enhancements - - * [ChannelTest] Respect user's configured ExUnit `:assert_receive_timeout` for macro assertions - * [Controller] Support partial file downloads with `:offset` and `:length` options to `send_download/3` - * [Controller] Add additional security headers to `put_secure_browser_headers` (`x-content-type-options`, `x-download-options`, and `x-permitted-cross-domain-policies`) - * [Controller] Add `put_router_url/2` to override the default URL generation pulled from endpoint configuration + * [Phoenix] Add `Phoenix.json_library/0` and replace `Poison` with `Jason` for JSON encoding in new projects * [Endpoint] Add `Cowboy2Adapter` for HTTP2 support with cowboy2 * [Endpoint] The `socket/3` macro now accepts direct configuration about websockets and longpoll * [Endpoint] Support MFA function in `:check_origin` config for custom origin checking * [Endpoint] Add new `:phoenix_error_render` instrumentation callback - * [Logger] Add whitelist support to `filter_parameters` logger configuration, via new `:keep` tuple format - * [Phoenix] Add `Phoenix.json_library/0` and replace `Poison` with `Jason` for JSON encoding in new projects + * [Endpoint] Log the configured url instead of raw IP when booting endpoint webserver + * [Endpoint] Allow custom keyword pairs to be passed to the socket `:connect_info` options. * [Router] Display list of available routes on debugger 404 error page * [Router] Raise on duplicate plugs in `pipe_through` scopes - * [Presence] Add `Presence.get_by_key` to fetch presences for specific user + * [Controller] Support partial file downloads with `:offset` and `:length` options to `send_download/3` + * [Controller] Add additional security headers to `put_secure_browser_headers` (`x-content-type-options`, `x-download-options`, and `x-permitted-cross-domain-policies`) + * [Controller] Add `put_router_url/2` to override the default URL generation pulled from endpoint configuration + * [Logger] Add whitelist support to `filter_parameters` logger configuration, via new `:keep` tuple format * [Socket] Add new `phoenix_socket_connect` instrumentation + * [Socket] Improve error message when missing socket mount in endpoint * [Logger] Log calls to user socket connect + * [Presence] Add `Presence.get_by_key` to fetch presences for specific user * [CodeReloader] Add `:reloadable_apps` endpoint configuration option to allow recompiling local dependencies + * [ChannelTest] Respect user's configured ExUnit `:assert_receive_timeout` for macro assertions -### Bug Fixes +### Bug Fixes + * Add missing `.formatter.exs` to hex package for proper elixir formatter integration + * [phx.gen.cert] Fix usage inside umbrella applications + * [phx.new] Revert `Routes.static_url` in app layout in favor of original `Routes.static_path` + * [phx.new] Use phoenix_live_reload 1.2-rc to fix hex version errors + * [phx.gen.json|html] Fix generator tests incorrectly encoding datetimes + * [phx.gen.cert] Fix generation of cert inside umbrella projects * [Channel] Fix issue with WebSocket transport sending wrong ContentLength header with 403 response * [Router] Fix forward aliases failing to expand within scope block + * [Router] Fix regression in router compilation failing to escape plug options -### Deprecations +### phx.new installer + * Generate new Elixir 1.5+ child spec (therefore new apps require Elixir v1.5) + * Use webpack for asset bundling +### Deprecations * [Controller] Passing a view in `render/3` and `render/4` is deprecated in favor of `put_view/2` * [Endpoint] The `:handler` option in the endpoint is deprecated in favor of `:adapter` * [Socket] `transport/3` is deprecated. The transport is now specified in the endpoint * [Transport] The transport system has seen an overhaul and been drastically simplified. The previous mechanism for building transports is still supported but it is deprecated. Please see `Phoenix.Socket.Transport` for more information -### phx.new installer - - * Generate new Elixir 1.5+ child spec (therefore new apps require Elixir v1.5) - * Use webpack for asset bundling - ### JavaScript client - * Add new instance-based Presence API with simplified synchronization callbacks * Accept a function for socket and channel `params` for dynamic parameter generation when connecting and joining * Fix race condition when presence diff arrives before state + * Immediately rejoin channels on socket reconnect for faster recovery after reconnection + * Fix reconnect caused by pending heartbeat ## v1.3 diff --git a/RELEASE.md b/RELEASE.md index 7b810cb9eb..f7b7347c76 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -6,15 +6,12 @@ 2. Bump version in related files below 3. Update `phoenix_dep` in `installer/lib/phoenix_new.ex` and `installer/lib/phx_new/generator.ex` to "~> version to be released" 4. Run tests, commit, push code - 5. Publish packages and docs after pruning any extraneous uncommitted files - 6. Run `MIX_ENV=prod mix archive.build` and `MIX_ENV=prod mix archive.build -o phx_new.ez` inside "installer" directory to build new installers - 7. Copy new installers to "phoenixframework/archives" project - 8. Test installer by generating a new app, running `mix deps.get`, and compiling - 9. Start -dev version in related files below - 10. Update `phoenix_dep` in `installer/lib/phoenix_new.ex` back to git - 11. Publish to `npm` with `npm publish` - 12. Replace `master` for `source_url_pattern` in `installer/mix.exs` - 13. Push installer (phx_new hex package) to hex + 5. Publish `phx_new` and `phoenix` packages and docs after pruning any extraneous uncommitted files + 6. Test installer by generating a new app, running `mix deps.get`, and compiling + 7. Start -dev version in related files below + 8. Update `phoenix_dep` in `installer/lib/phoenix_new.ex` back to git + 9. Publish to `npm` with `npm publish` + 10. Replace `master` for `source_url_pattern` in `installer/mix.exs` ## Files with version diff --git a/assets/package-lock.json b/assets/package-lock.json index 7f2e3a81fa..cfd6385dcc 100644 --- a/assets/package-lock.json +++ b/assets/package-lock.json @@ -1,6 +1,6 @@ { "name": "phoenix", - "version": "1.4.0-rc.3", + "version": "1.4.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/assets/package.json b/assets/package.json index d52aa75fd8..5384420fb4 100644 --- a/assets/package.json +++ b/assets/package.json @@ -1,6 +1,6 @@ { "name": "phoenix", - "version": "1.4.0-rc.3", + "version": "1.4.0", "description": "The official JavaScript client for the Phoenix web framework.", "license": "MIT", "main": "./priv/static/phoenix.js", diff --git a/guides/ecto.md b/guides/ecto.md index 77a045282e..46b0f461ae 100644 --- a/guides/ecto.md +++ b/guides/ecto.md @@ -469,13 +469,13 @@ defmodule HelloPhoenix.MixProject do # Type `mix help deps` for examples and options. defp deps do [ - {:phoenix, "~> 1.3.0"}, - {:phoenix_pubsub, "~> 1.0"}, + {:phoenix, "~> 1.4.0"}, + {:phoenix_pubsub, "~> 1.1"}, {:phoenix_ecto, "~> 4.0"}, {:ecto_sql, "~> 3.0"}, {:mariaex, ">= 0.0.0"}, - {:phoenix_html, "~> 2.10"}, - {:phoenix_live_reload, "~> 1.2-rc", only: :dev}, + {:phoenix_html, "~> 2.11"}, + {:phoenix_live_reload, "~> 1.2", only: :dev}, {:gettext, "~> 0.11"}, {:plug_cowboy, "~> 2.0"} ] diff --git a/guides/introduction/installation.md b/guides/introduction/installation.md index 6a06bcf1f5..13a5da373f 100644 --- a/guides/introduction/installation.md +++ b/guides/introduction/installation.md @@ -45,7 +45,7 @@ Once we have Elixir and Erlang, we are ready to install the Phoenix Mix archive. Here's the command to install the Phoenix archive: ```console -$ mix archive.install hex phx_new 1.4.0-rc.3 +$ mix archive.install hex phx_new 1.4.0 ``` > Note: if the Phoenix archive won't install properly with this command, we can download the package from the [Phoenix archives](https://github.com/phoenixframework/archives), save it to the filesystem, and then run: `mix archive.install /path/to/local/phx_new.ez`. diff --git a/installer/README.md b/installer/README.md index ea238babff..6d0300a13d 100644 --- a/installer/README.md +++ b/installer/README.md @@ -4,7 +4,7 @@ Provides `phx.new` installer as an archive. To install from hex, run: - $ mix archive.install hex phx_new 1.4.0-rc.3 + $ mix archive.install hex phx_new 1.4.0 To build and install it locally, ensure any previous archive versions are removed: diff --git a/installer/lib/phx_new/generator.ex b/installer/lib/phx_new/generator.ex index 2db124c1af..854af18d55 100644 --- a/installer/lib/phx_new/generator.ex +++ b/installer/lib/phx_new/generator.ex @@ -5,7 +5,7 @@ defmodule Phx.New.Generator do @phoenix Path.expand("../..", __DIR__) - @phoenix_version Version.parse!("1.4.0-rc") + @phoenix_version Version.parse!("1.4.0") @callback prepare_project(Project.t) :: Project.t @callback generate(Project.t) :: Project.t diff --git a/installer/mix.exs b/installer/mix.exs index 759d59fc0a..bfc57d8f15 100644 --- a/installer/mix.exs +++ b/installer/mix.exs @@ -1,6 +1,7 @@ defmodule Phx.New.MixProject do use Mix.Project + @version "1.4.0" @github_path "phoenixframework/phoenix" @url "https://github.com/#{@github_path}" @@ -8,7 +9,7 @@ defmodule Phx.New.MixProject do [ app: :phx_new, start_permanent: Mix.env() == :prod, - version: "1.4.0-rc.3", + version: @version, elixir: "~> 1.5", deps: deps(), package: [ @@ -42,7 +43,7 @@ defmodule Phx.New.MixProject do defp docs do [ - source_url_pattern: "https://github.com/#{@github_path}/blob/master/installer/%{path}#L%{line}" + source_url_pattern: "https://github.com/#{@github_path}/blob/v#{@version}/installer/%{path}#L%{line}" ] end diff --git a/installer/templates/phx_single/mix.exs b/installer/templates/phx_single/mix.exs index e05fce27eb..f3ed6d70fc 100644 --- a/installer/templates/phx_single/mix.exs +++ b/installer/templates/phx_single/mix.exs @@ -43,7 +43,7 @@ defmodule <%= app_module %>.MixProject do {:ecto_sql, "~> 3.0"}, {<%= inspect adapter_app %>, ">= 0.0.0"},<% end %><%= if html do %> {:phoenix_html, "~> 2.11"}, - {:phoenix_live_reload, "~> 1.2-rc", only: :dev},<% end %> + {:phoenix_live_reload, "~> 1.2", only: :dev},<% end %> {:gettext, "~> 0.11"}, {:jason, "~> 1.0"}, {:plug_cowboy, "~> 2.0"} diff --git a/installer/templates/phx_umbrella/apps/app_name_web/mix.exs b/installer/templates/phx_umbrella/apps/app_name_web/mix.exs index 77d1dc457c..cfaef2e1b6 100644 --- a/installer/templates/phx_umbrella/apps/app_name_web/mix.exs +++ b/installer/templates/phx_umbrella/apps/app_name_web/mix.exs @@ -41,7 +41,7 @@ defmodule <%= web_namespace %>.MixProject do {:phoenix_pubsub, "~> 1.1"},<%= if ecto do %> {:phoenix_ecto, "~> 4.0"},<% end %><%= if html do %> {:phoenix_html, "~> 2.11"}, - {:phoenix_live_reload, "~> 1.2-rc", only: :dev},<% end %> + {:phoenix_live_reload, "~> 1.2", only: :dev},<% end %> {:gettext, "~> 0.11"},<%= if app_name != web_app_name do %> {:<%= app_name %>, in_umbrella: true},<% end %> {:jason, "~> 1.0"}, diff --git a/mix.exs b/mix.exs index 967f06a109..1c8f6b26e1 100644 --- a/mix.exs +++ b/mix.exs @@ -1,7 +1,7 @@ defmodule Phoenix.MixProject do use Mix.Project - @version "1.4.0-rc.3" + @version "1.4.0" def project do [ diff --git a/package.json b/package.json index fd5bcd5bf4..a922680e03 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "phoenix", - "version": "1.4.0-rc.3", + "version": "1.4.0", "description": "The official JavaScript client for the Phoenix web framework.", "license": "MIT", "main": "./priv/static/phoenix.js", From 75773fe9c67e627c389ede4275dafa3a19c870cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20=C5=81=C4=99picki?= Date: Thu, 8 Nov 2018 14:25:53 +0100 Subject: [PATCH 08/61] Remove archives repo mention from guides (#3144) --- guides/introduction/installation.md | 1 - 1 file changed, 1 deletion(-) diff --git a/guides/introduction/installation.md b/guides/introduction/installation.md index 13a5da373f..e2fd245919 100644 --- a/guides/introduction/installation.md +++ b/guides/introduction/installation.md @@ -47,7 +47,6 @@ Here's the command to install the Phoenix archive: ```console $ mix archive.install hex phx_new 1.4.0 ``` -> Note: if the Phoenix archive won't install properly with this command, we can download the package from the [Phoenix archives](https://github.com/phoenixframework/archives), save it to the filesystem, and then run: `mix archive.install /path/to/local/phx_new.ez`. ### Plug, Cowboy, and Ecto From 1feddfbfe49f6d77e468892396e16b1f4022bcc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sat, 10 Nov 2018 11:05:20 +0100 Subject: [PATCH 09/61] Start v1.5 CHANGELOG --- CHANGELOG.md | 80 ++++------------------------------------------------ 1 file changed, 6 insertions(+), 74 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ba3230fdb..100b607c12 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,87 +1,19 @@ # Changelog for v1.4 -See the [upgrade guides](https://gist.github.com/chrismccord/bb1f8b136f5a9e4abc0bfc07b832257e) to bring your Phoenix 1.3.x apps up to speed, including instructions on upgrading to Cowboy 2 for HTTP support. +## New feature! -## The Socket <-> Transport contract - -We have used the opportunity of writing the new Cowboy 2 adapter to do an overhaul in how `Phoenix.Socket` interacts with transports. The result is a new API that makes it very easy to implement new transports and also allows developers to provide custom socket implementations without ceremony. For example, if you would like to have direct control of the socket and bypass the channel implementation completely, it is now very straight-forward to do so. See the `Phoenix.Socket.Transport` behaviour for more information. - -This overhaul means that the `transport/3` macro in `Phoenix.Socket` is deprecated. Instead of defining transports in your socket.ex file: - - transport :websocket, Phoenix.Transport.Websocket, - key1: value1, key2: value2, key3: value3 - - transport :longpoll, Phoenix.Transport.LongPoll, - key1: value1, key2: value2, key3: value3 - -Configurations must be applied directly in your endpoint file via the `Phoenix.Endpoint.socket/3` macro: - - socket "/socket", MyApp.UserSocket, - websocket: [key1: value1, key2: value2, key3: value3], - longpoll: [key1: value1, key2: value2, key3: value3] - -Note the websocket/longpoll configuration given to socket/3 will only apply after you remove all `transport/3` calls from your socket definition. If you have explicitly upgraded to Cowboy 2, any transport defined with the `transport/3` macro will be ignored. - -The old APIs for building transports are also deprecated. The good news is: adapting an existing transport to the new API is a less error prone process where you should mostly remove code. - - -## 1.4.0 (2018-11-07) +## 1.5.0-dev ### Enhancements - * [phx.new] Update Ecto deps with the release of Ecto 3.0 including `phoenix_ecto` 4.0 - * [phx.new] Import Ecto's `.formatter.exs` in new projects - * [phx.new] Use Ecto 3.0RC, with `ecto_sql` in new project deps - * [phx.new] Use Plug 1.7 with new `:plug_cowboy` dependency for cowboy adapter - * [phx.gen.html|json|schema|context] Support new Ecto 3.0 usec datetime types - * [Phoenix] Add `Phoenix.json_library/0` and replace `Poison` with `Jason` for JSON encoding in new projects - * [Endpoint] Add `Cowboy2Adapter` for HTTP2 support with cowboy2 - * [Endpoint] The `socket/3` macro now accepts direct configuration about websockets and longpoll - * [Endpoint] Support MFA function in `:check_origin` config for custom origin checking - * [Endpoint] Add new `:phoenix_error_render` instrumentation callback - * [Endpoint] Log the configured url instead of raw IP when booting endpoint webserver - * [Endpoint] Allow custom keyword pairs to be passed to the socket `:connect_info` options. - * [Router] Display list of available routes on debugger 404 error page - * [Router] Raise on duplicate plugs in `pipe_through` scopes - * [Controller] Support partial file downloads with `:offset` and `:length` options to `send_download/3` - * [Controller] Add additional security headers to `put_secure_browser_headers` (`x-content-type-options`, `x-download-options`, and `x-permitted-cross-domain-policies`) - * [Controller] Add `put_router_url/2` to override the default URL generation pulled from endpoint configuration - * [Logger] Add whitelist support to `filter_parameters` logger configuration, via new `:keep` tuple format - * [Socket] Add new `phoenix_socket_connect` instrumentation - * [Socket] Improve error message when missing socket mount in endpoint - * [Logger] Log calls to user socket connect - * [Presence] Add `Presence.get_by_key` to fetch presences for specific user - * [CodeReloader] Add `:reloadable_apps` endpoint configuration option to allow recompiling local dependencies - * [ChannelTest] Respect user's configured ExUnit `:assert_receive_timeout` for macro assertions - ### Bug Fixes - * Add missing `.formatter.exs` to hex package for proper elixir formatter integration - * [phx.gen.cert] Fix usage inside umbrella applications - * [phx.new] Revert `Routes.static_url` in app layout in favor of original `Routes.static_path` - * [phx.new] Use phoenix_live_reload 1.2-rc to fix hex version errors - * [phx.gen.json|html] Fix generator tests incorrectly encoding datetimes - * [phx.gen.cert] Fix generation of cert inside umbrella projects - * [Channel] Fix issue with WebSocket transport sending wrong ContentLength header with 403 response - * [Router] Fix forward aliases failing to expand within scope block - * [Router] Fix regression in router compilation failing to escape plug options - -### phx.new installer - * Generate new Elixir 1.5+ child spec (therefore new apps require Elixir v1.5) - * Use webpack for asset bundling ### Deprecations - * [Controller] Passing a view in `render/3` and `render/4` is deprecated in favor of `put_view/2` - * [Endpoint] The `:handler` option in the endpoint is deprecated in favor of `:adapter` - * [Socket] `transport/3` is deprecated. The transport is now specified in the endpoint - * [Transport] The transport system has seen an overhaul and been drastically simplified. The previous mechanism for building transports is still supported but it is deprecated. Please see `Phoenix.Socket.Transport` for more information + +### phx.new installer ### JavaScript client - * Add new instance-based Presence API with simplified synchronization callbacks - * Accept a function for socket and channel `params` for dynamic parameter generation when connecting and joining - * Fix race condition when presence diff arrives before state - * Immediately rejoin channels on socket reconnect for faster recovery after reconnection - * Fix reconnect caused by pending heartbeat -## v1.3 +## v1.4 -The CHANGELOG for v1.3 releases can be found [in the v1.3 branch](https://github.com/phoenixframework/phoenix/blob/v1.3/CHANGELOG.md). +The CHANGELOG for v1.4 releases can be found [in the v1.4 branch](https://github.com/phoenixframework/phoenix/blob/v1.4/CHANGELOG.md). From 627d5a759526df6a271c2015c85feab78a6fc9cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sat, 10 Nov 2018 11:09:57 +0100 Subject: [PATCH 10/61] Remove deprecated transport code --- lib/phoenix/endpoint/cowboy_adapter.ex | 28 +------ lib/phoenix/socket.ex | 101 ++----------------------- lib/phoenix/socket/transport.ex | 84 -------------------- 3 files changed, 7 insertions(+), 206 deletions(-) diff --git a/lib/phoenix/endpoint/cowboy_adapter.ex b/lib/phoenix/endpoint/cowboy_adapter.ex index 6ba4c14884..117ab060e4 100644 --- a/lib/phoenix/endpoint/cowboy_adapter.ex +++ b/lib/phoenix/endpoint/cowboy_adapter.ex @@ -97,29 +97,7 @@ defmodule Phoenix.Endpoint.CowboyAdapter do update_in(spec.start, &{__MODULE__, :start_link, [scheme, endpoint, &1]}) end - defp transports(endpoint, path, socket, socket_opts) do - case deprecated_transports(socket) do - transports when transports == %{} -> - socket_transports(endpoint, path, socket, socket_opts) - - transports -> - for {transport, {module, config}} <- transports, - handler = config[:cowboy] || default_for(module), - do: - {Path.join(path, Atom.to_string(transport)), handler, - {module, {endpoint, socket, config}}} - end - end - - defp deprecated_transports(socket) do - if Code.ensure_loaded?(socket) and function_exported?(socket, :__transports__, 0) do - socket.__transports__ - else - %{} - end - end - - defp socket_transports(endpoint, path, socket, opts) do + defp transports(endpoint, path, socket, opts) do paths = [] websocket = Keyword.get(opts, :websocket, true) longpoll = Keyword.get(opts, :longpoll, false) @@ -161,10 +139,6 @@ defmodule Phoenix.Endpoint.CowboyAdapter do defp socket_config(true, module), do: module.default_config() defp socket_config(config, module), do: Keyword.merge(module.default_config(), config) - defp default_for(Phoenix.Transports.LongPoll), do: Plug.Adapters.Cowboy.Handler - defp default_for(Phoenix.Transports.WebSocket), do: Phoenix.Endpoint.CowboyWebSocket - defp default_for(_), do: nil - @doc false def start_link(scheme, endpoint, {m, f, [ref | _] = a}) do # ref is used by Ranch to identify its listeners, defaulting diff --git a/lib/phoenix/socket.ex b/lib/phoenix/socket.ex index 69ff8de039..417d51f6e0 100644 --- a/lib/phoenix/socket.ex +++ b/lib/phoenix/socket.ex @@ -219,7 +219,6 @@ defmodule Phoenix.Socket do @behaviour Phoenix.Socket @before_compile Phoenix.Socket Module.register_attribute(__MODULE__, :phoenix_channels, accumulate: true) - @phoenix_transports %{} @phoenix_log Keyword.get(unquote(opts), :log, :info) ## Callbacks @@ -315,104 +314,14 @@ defmodule Phoenix.Socket do # but we should keep the warning for backwards compatibility. @doc false - defmacro transport(name, module, config \\ []) do + defmacro transport(_name, _module, _config \\ []) do quote do - @phoenix_transports Phoenix.Socket.__transport__( - @phoenix_transports, unquote(name), unquote(module), unquote(config)) + IO.warn "transport/3 in Phoenix.Socket is deprecated and has no effect" end end - @doc false - def __transport__(transports, name, module, user_conf) do - IO.warn """ - transport/3 in Phoenix.Socket is deprecated. - - Instead of defining transports in your socket.ex file: - - transport :websocket, Phoenix.Transport.Websocket, - key1: value1, key2: value2, key3: value3 - - transport :longpoll, Phoenix.Transport.LongPoll, - key1: value1, key2: value2, key3: value3 - - You should configure websocket/longpoll in your endpoint.ex: - - socket "/socket", MyApp.UserSocket, - websocket: [key1: value1, key2: value2, key3: value3], - longpoll: [key1: value1, key2: value2, key3: value3] - - Note the websocket/longpoll configuration given to socket/3 - will only apply after you remove all transport/3 calls from - your socket definition. If you have explicitly upgraded to - Cowboy 2, any transport defined with the transport/3 macro - will be ignored. - """ - - defaults = module.default_config() - - conf = - user_conf - |> normalize_serializer_conf(name, module, defaults[:serializer] || []) - |> merge_defaults(defaults) - - Map.update(transports, name, {module, conf}, fn {dup_module, _} -> - raise ArgumentError, - "duplicate transports (#{inspect dup_module} and #{inspect module}) defined for #{inspect name}" - end) - end - defp merge_defaults(conf, defaults), do: Keyword.merge(defaults, conf) - - defp normalize_serializer_conf(conf, name, transport_mod, default) do - update_in(conf[:serializer], fn - nil -> - precompile_serializers(default) - - Phoenix.Transports.LongPollSerializer = serializer -> - warn_serializer_deprecation(name, transport_mod, serializer) - precompile_serializers(default) - - Phoenix.Transports.WebSocketSerializer = serializer -> - warn_serializer_deprecation(name, transport_mod, serializer) - precompile_serializers(default) - - [_ | _] = serializer -> - precompile_serializers(serializer) - - serializer when is_atom(serializer) -> - warn_serializer_deprecation(name, transport_mod, serializer) - precompile_serializers([{serializer, "~> 1.0.0"}]) - end) - end - - defp warn_serializer_deprecation(name, transport_mod, serializer) do - IO.warn """ - passing a serializer module to the transport macro is deprecated. - Use a list with version requirements instead. For example: - - transport :#{name}, #{inspect transport_mod}, - serializer: [{#{inspect serializer}, "~> 1.0.0"}] - - """ - end - - defp precompile_serializers(serializers) do - for {module, requirement} <- serializers do - case Version.parse_requirement(requirement) do - {:ok, requirement} -> {rewrite_serializer(module), requirement} - :error -> Version.match?("1.0.0", requirement) - end - end - end - - defp rewrite_serializer(Phoenix.Transports.V2.WebSocketSerializer), do: Phoenix.Socket.V2.JSONSerializer - defp rewrite_serializer(Phoenix.Transports.V2.LongPollSerializer), do: Phoenix.Socket.V2.JSONSerializer - defp rewrite_serializer(Phoenix.Transports.WebSocketSerializer), do: Phoenix.Socket.V1.JSONSerializer - defp rewrite_serializer(Phoenix.Transports.LongPollSerializer), do: Phoenix.Socket.V1.JSONSerializer - defp rewrite_serializer(module), do: module - defmacro __before_compile__(env) do - transports = Module.get_attribute(env.module, :phoenix_transports) - channels = Module.get_attribute(env.module, :phoenix_channels) + channels = Module.get_attribute(env.module, :phoenix_channels) channel_defs = for {topic_pattern, module, opts} <- channels do @@ -422,7 +331,6 @@ defmodule Phoenix.Socket do end quote do - def __transports__, do: unquote(Macro.escape(transports)) unquote(channel_defs) def __channel__(_topic), do: nil end @@ -542,6 +450,9 @@ defmodule Phoenix.Socket do end def __terminate__(_reason, {%{channels_inverse: channels_inverse}, _socket}) do + # Although this is not strictly necessary, as each channel server + # watches the transport, it is a more efficient way of doing as + # we terminate all channels at once. Phoenix.Channel.Server.close(Map.keys(channels_inverse)) :ok end diff --git a/lib/phoenix/socket/transport.ex b/lib/phoenix/socket/transport.ex index 6f00b24c0f..716f971a5a 100644 --- a/lib/phoenix/socket/transport.ex +++ b/lib/phoenix/socket/transport.ex @@ -195,90 +195,6 @@ defmodule Phoenix.Socket.Transport do @callback terminate(reason :: term, state) :: :ok require Logger - alias Phoenix.Socket.{Reply, Message} - - @doc false - def protocol_version do - IO.warn "Phoenix.Socket.Transport.protocol_version/0 is deprecated" - "2.0.0" - end - - @doc false - def connect(endpoint, handler, _transport_name, transport, serializers, params, _pid \\ self()) do - IO.warn "Phoenix.Socket.Transport.connect/7 is deprecated" - - handler.connect(%{ - endpoint: endpoint, - transport: transport, - options: [serializer: serializers], - params: params - }) - end - - @doc false - def dispatch(msg, channels, socket) - - def dispatch(%{ref: ref, topic: "phoenix", event: "heartbeat"}, _channels, socket) do - IO.warn "Phoenix.Socket.Transport.dispatch/3 is deprecated" - {:reply, %Reply{join_ref: socket.join_ref, ref: ref, topic: "phoenix", status: :ok, payload: %{}}} - end - - def dispatch(%Message{} = msg, channels, socket) do - IO.warn "Phoenix.Socket.Transport.dispatch/3 is deprecated" - channels - |> Map.get(msg.topic) - |> do_dispatch(msg, socket) - end - - defp do_dispatch(nil, %{event: "phx_join", topic: topic, ref: ref} = msg, socket) do - case socket.handler.__channel__(topic) do - {channel, opts} -> - case Phoenix.Channel.Server.join(socket, channel, msg, opts) do - {:ok, reply, pid} -> - {:joined, pid, %Reply{join_ref: ref, ref: ref, topic: topic, status: :ok, payload: reply}} - - {:error, reply} -> - {:error, reply, %Reply{join_ref: ref, ref: ref, topic: topic, status: :error, payload: reply}} - end - - nil -> - reply_ignore(msg, socket) - end - end - - defp do_dispatch({pid, _ref}, %{event: "phx_join"} = msg, socket) when is_pid(pid) do - Logger.debug "Duplicate channel join for topic \"#{msg.topic}\" in #{inspect(socket.handler)}. " <> - "Closing existing channel for new join." - :ok = Phoenix.Channel.Server.close([pid]) - do_dispatch(nil, msg, socket) - end - - defp do_dispatch(nil, msg, socket) do - reply_ignore(msg, socket) - end - - defp do_dispatch({channel_pid, _ref}, msg, _socket) do - send(channel_pid, msg) - :noreply - end - - defp reply_ignore(msg, socket) do - Logger.warn fn -> "Ignoring unmatched topic \"#{msg.topic}\" in #{inspect(socket.handler)}" end - {:error, :unmatched_topic, %Reply{join_ref: socket.join_ref, ref: msg.ref, topic: msg.topic, status: :error, - payload: %{reason: "unmatched topic"}}} - end - - @doc false - def on_exit_message(topic, join_ref, _reason) do - IO.warn "Phoenix.Socket.Transport.on_exit_mesage/3 is deprecated" - %Message{join_ref: join_ref, ref: join_ref, topic: topic, event: "phx_error", payload: %{}} - end - - @doc false - def on_exit_message(topic, reason) do - IO.warn "Phoenix.Transport.on_exit_message/2 is deprecated" - on_exit_message(topic, nil, reason) - end @doc """ Runs the code reloader if enabled. From 974e6ba432790d9a04841eca4b302f69ccdbdcd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Thu, 15 Nov 2018 17:20:25 +0100 Subject: [PATCH 11/61] Remove old conditional branch on route building --- lib/phoenix/router/route.ex | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/lib/phoenix/router/route.ex b/lib/phoenix/router/route.ex index fcda6bba53..0a8ad59c90 100644 --- a/lib/phoenix/router/route.ex +++ b/lib/phoenix/router/route.ex @@ -77,8 +77,8 @@ defmodule Phoenix.Router.Route do defp build_path_and_binding(%Route{path: path} = route) do {params, segments} = case route.kind do - :forward -> build_path_match(path <> "/*_forward_path_info") - :match -> build_path_match(path) + :forward -> Plug.Router.Utils.build_path_match(path <> "/*_forward_path_info") + :match -> Plug.Router.Utils.build_path_match(path) end binding = for var <- params, var != :_forward_path_info do @@ -118,7 +118,7 @@ defmodule Phoenix.Router.Route do end defp build_dispatch(%Route{kind: :forward} = route) do - {_params, fwd_segments} = build_path_match(route.path) + {_params, fwd_segments} = Plug.Router.Utils.build_path_match(route.path) quote do { @@ -160,7 +160,7 @@ defmodule Phoenix.Router.Route do `path` contains a dynamic segment. """ def forward_path_segments(path, plug, phoenix_forwards) do - case build_path_match(path) do + case Plug.Router.Utils.build_path_match(path) do {[], path_segments} -> if phoenix_forwards[plug] do raise ArgumentError, "#{inspect plug} has already been forwarded to. A module can only be forwarded a single time." @@ -170,14 +170,4 @@ defmodule Phoenix.Router.Route do raise ArgumentError, "dynamic segment \"#{path}\" not allowed when forwarding. Use a static path instead." end end - - if Code.ensure_loaded?(Plug.Router.Utils) do - defp build_path_match(path) do - Plug.Router.Utils.build_path_match(path) - end - else - defp build_path_match(path) do - Plug.Router.Compiler.build_path_match(path) - end - end end From 393203b88b7f53866a9c4c7ce7e038ba1fe8b99c Mon Sep 17 00:00:00 2001 From: Ahmed Mokhtar Date: Fri, 16 Nov 2018 11:37:25 +0200 Subject: [PATCH 12/61] Use `phx-hero` class instead of `jumbotron` in guides (#3153) --- guides/adding_pages.md | 4 ++-- guides/templates.md | 8 ++++---- guides/views.md | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/guides/adding_pages.md b/guides/adding_pages.md index 4ac4f68a23..79386de0bf 100644 --- a/guides/adding_pages.md +++ b/guides/adding_pages.md @@ -189,7 +189,7 @@ Templates are scoped to a view, which are scoped to controller. Phoenix creates Let's do that now. Create `lib/hello_web/templates/hello/index.html.eex` and make it look like this: ```html -
+

Hello World, from Phoenix!

``` @@ -262,7 +262,7 @@ To do that, we'll use the special EEx tags for executing Elixir expressions - `< And this is what the template should look like: ```html -
+

Hello World, from <%= @messenger %>!

``` diff --git a/guides/templates.md b/guides/templates.md index b8380bb5ba..7708db511c 100644 --- a/guides/templates.md +++ b/guides/templates.md @@ -88,7 +88,7 @@ end We have a route. We created a new controller action. We have made modifications to the main application view. Now all we need is a new template to display the string we get from `handler_info/1`. Let's create a new one at `lib/hello_web/templates/page/test.html.eex`. ```html -
+

<%= handler_info(@conn) %>

``` @@ -110,7 +110,7 @@ Now that we have a function, visible to our template, that returns a list of key We can add a header and a list comprehension like this. ```html -
+

<%= handler_info(@conn) %>

Keys for the conn Struct

@@ -147,7 +147,7 @@ We need to change `key` to `@key` here because this is a new template, not part Now that we have a template, we simply render it within our list comprehension in the `test.html.eex` template. ```html -
+

<%= handler_info(@conn) %>

Keys for the conn Struct

@@ -169,7 +169,7 @@ Let's move our template into a shared view. `key.html.eex` is currently rendered by the `HelloWeb.PageView` module, but we use a render call which assumes that the current schema is what we want to render with. We could make that explicit, and re-write it like this: ```html -
+
... <%= for key <- connection_keys(@conn) do %> diff --git a/guides/views.md b/guides/views.md index ae2911e3d4..0d7291432e 100644 --- a/guides/views.md +++ b/guides/views.md @@ -73,7 +73,7 @@ When we `use HelloWeb, :view`, we get other conveniences as well. Since `view/0` Let's open up the `lib/hello_web/templates/page/index.html.eex` and locate this stanza. ```html -
+

<%= gettext("Welcome to %{name}!", name: "Phoenix") %>

A productive web framework that
does not compromise speed and maintainability.

@@ -82,7 +82,7 @@ Let's open up the `lib/hello_web/templates/page/index.html.eex` and locate this Then let's add a line with a link back to the same page. (The objective is to see how path helpers respond in a template, not to add any functionality.) ```html -
+

<%= gettext("Welcome to %{name}!", name: "Phoenix") %>

A productive web framework that
does not compromise speed and maintainability.

Link back to this page

@@ -250,7 +250,7 @@ Great, so we have a `render/2` function that takes a template and an `assigns` m
-
+

Sorry, the page you are looking for does not exist.

From b6540d89cfe30a43f0ca841f6dcec37f6b8b758b Mon Sep 17 00:00:00 2001 From: Renan Date: Fri, 16 Nov 2018 07:42:25 -0200 Subject: [PATCH 13/61] Remove duplicated word on Ecto guide (#3159) --- guides/ecto.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guides/ecto.md b/guides/ecto.md index 46b0f461ae..08b5a13877 100644 --- a/guides/ecto.md +++ b/guides/ecto.md @@ -415,7 +415,7 @@ SELECT u0."email" FROM "users" AS u0 [] ["user1@example.com", "user2@example.com"] ``` -First, we imported `Ecto.Query`, which imports the `from` macro of Ecto's Query DSL. Next, we built a query which selects all the the email addresses in our user's table. Let's try another example. +First, we imported `Ecto.Query`, which imports the `from` macro of Ecto's Query DSL. Next, we built a query which selects all the email addresses in our user's table. Let's try another example. ```console iex)> Repo.one(from u in User, where: ilike(u.email, "%1%"), From 560fde8d4dfa4f19236d6068181ef4a41353d0a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20=C5=81=C4=99picki?= Date: Fri, 16 Nov 2018 10:43:38 +0100 Subject: [PATCH 14/61] Guides updates for Phoenix 1.4 (#3164) * Update the Up and Running and Routing guides for Phoenix 1.4 * Remove old installer routing template comment from guides --- guides/adding_pages.md | 6 +++--- guides/contexts.md | 4 ++-- guides/routing.md | 21 +++++++++------------ guides/templates.md | 2 +- guides/testing/testing.md | 2 +- guides/testing/testing_controllers.md | 2 +- guides/testing/testing_schemas.md | 2 +- guides/up_and_running.md | 14 +++++++++----- 8 files changed, 27 insertions(+), 26 deletions(-) diff --git a/guides/adding_pages.md b/guides/adding_pages.md index 79386de0bf..1157a1e03c 100644 --- a/guides/adding_pages.md +++ b/guides/adding_pages.md @@ -109,7 +109,7 @@ defmodule HelloWeb.Router do end scope "/", HelloWeb do - pipe_through :browser # Use the default browser stack + pipe_through :browser get "/", PageController, :index end @@ -134,7 +134,7 @@ The `scope "/"` block of our `router.ex` file should now look like this: ```elixir scope "/", HelloWeb do - pipe_through :browser # Use the default browser stack + pipe_through :browser get "/", PageController, :index get "/hello", HelloController, :index @@ -218,7 +218,7 @@ For this exercise, we're going to re-use the `HelloController` we just created a ```elixir scope "/", HelloWeb do - pipe_through :browser # Use the default browser stack. + pipe_through :browser get "/", PageController, :index get "/hello", HelloController, :index diff --git a/guides/contexts.md b/guides/contexts.md index 1ef674e473..996bc7312a 100644 --- a/guides/contexts.md +++ b/guides/contexts.md @@ -79,7 +79,7 @@ Phoenix generated the web files as expected in `lib/hello_web/`. We can also see ```elixir scope "/", HelloWeb do - pipe_through :browser # Use the default browser stack + pipe_through :browser get "/", PageController, :index + resources "/users", UserController @@ -497,7 +497,7 @@ Next, let's wire up our session routes in `lib/hello_web/router.ex`: ```elixir scope "/", HelloWeb do - pipe_through :browser # Use the default browser stack + pipe_through :browser get "/", PageController, :index resources "/users", UserController diff --git a/guides/routing.md b/guides/routing.md index eb4195963d..8ca73f3039 100644 --- a/guides/routing.md +++ b/guides/routing.md @@ -21,7 +21,7 @@ defmodule HelloWeb.Router do end scope "/", HelloWeb do - pipe_through :browser # Use the default browser stack + pipe_through :browser get "/", PageController, :index end @@ -92,7 +92,7 @@ Let's add a resource to our `lib/hello_web/router.ex` file like this: ```elixir scope "/", HelloWeb do - pipe_through :browser # Use the default browser stack + pipe_through :browser get "/", PageController, :index resources "/users", UserController @@ -797,7 +797,6 @@ defmodule HelloWeb.Router do ... scope "/reviews" do - # Use the default browser stack. pipe_through [:browser, :review_checks, :other_great_stuff] resources "/", HelloWeb.ReviewController @@ -873,13 +872,17 @@ We mount socket handlers in our endpoint at `lib/hello_web/endpoint.ex`. Socket ```elixir defmodule HelloWeb.Endpoint do - use Phoenix.Endpoint + use Phoenix.Endpoint, otp_app: :hello - socket "/socket", HelloWeb.UserSocket + socket "/socket", HelloWeb.UserSocket, + websocket: true, + longpoll: false ... end ``` +By default, Phoenix supports both websockets and longpoll when invoking Phoenix.Endpoint.socket/3 in your endpoint. Here we're specifying that incoming socket connections can be made via a WebSocket connection. + Next, we need to open our `lib/hello_web/channels/user_socket.ex` file and use the `channel/3` macro to define our channel routes. The routes will match a topic pattern to a channel to handle events. If we have a channel module called `RoomChannel` and a topic called `"rooms:*"`, the code to do this is straightforward. ```elixir @@ -893,16 +896,10 @@ end Topics are just string identifiers. The form we are using here is a convention which allows us to define topics and subtopics in the same string - "topic:subtopic". The `*` is a wildcard character which allows us to match on any subtopic, so `"rooms:lobby"` and `"rooms:kitchen"` would both match this route. -Phoenix abstracts the socket transport layer and includes two transport mechanisms out of the box - WebSockets and Long-Polling. If we wanted to make sure that our channel is handled by only one type of transport, we could specify that using the `via` option, like this. - -```elixir -channel "rooms:*", HelloWeb.RoomChannel, via: [Phoenix.Transports.WebSocket] -``` - Each socket can handle requests for multiple channels. ```elixir -channel "rooms:*", HelloWeb.RoomChannel, via: [Phoenix.Transports.WebSocket] +channel "rooms:*", HelloWeb.RoomChannel channel "foods:*", HelloWeb.FoodChannel ``` diff --git a/guides/templates.md b/guides/templates.md index 7708db511c..437f03a580 100644 --- a/guides/templates.md +++ b/guides/templates.md @@ -23,7 +23,7 @@ defmodule HelloWeb.Router do ... scope "/", HelloWeb do - pipe_through :browser # Use the default browser stack + pipe_through :browser get "/", PageController, :index get "/test", PageController, :test diff --git a/guides/testing/testing.md b/guides/testing/testing.md index 19f477ccaa..4041246b30 100644 --- a/guides/testing/testing.md +++ b/guides/testing/testing.md @@ -466,7 +466,7 @@ defmodule HelloWeb.Router do ... scope "/", Hello do - pipe_through :browser # Use the default browser stack + pipe_through :browser get "/", PageController, :index resources "/users", UserController diff --git a/guides/testing/testing_controllers.md b/guides/testing/testing_controllers.md index 0f5e5ec239..909bd674c4 100644 --- a/guides/testing/testing_controllers.md +++ b/guides/testing/testing_controllers.md @@ -177,7 +177,7 @@ defmodule HelloWeb.Router do end scope "/", HelloWeb do - pipe_through :browser # Use the default browser stack + pipe_through :browser get "/", PageController, :index end diff --git a/guides/testing/testing_schemas.md b/guides/testing/testing_schemas.md index 2d0f4046e7..5159297ba9 100644 --- a/guides/testing/testing_schemas.md +++ b/guides/testing/testing_schemas.md @@ -497,7 +497,7 @@ defmodule HelloWeb.Router do ... scope "/", HelloWeb do - pipe_through :browser # Use the default browser stack + pipe_through :browser get "/", PageController, :index resources "/users", UserController diff --git a/guides/up_and_running.md b/guides/up_and_running.md index c010a56799..82d703507a 100644 --- a/guides/up_and_running.md +++ b/guides/up_and_running.md @@ -26,8 +26,8 @@ mix phx.new hello * creating hello/config/dev.exs * creating hello/config/prod.exs ... -* creating hello/lib/hello_web/views/layout_view.ex -* creating hello/lib/hello_web/views/page_view.ex +* creating hello/assets/static/images/phoenix.png +* creating hello/assets/static/favicon.ico Fetch and install dependencies? [Yn] ``` @@ -40,7 +40,7 @@ Fetch and install dependencies? [Yn] Y * running mix deps.compile * running cd assets && npm install && node node_modules/webpack/bin/webpack.js --mode development -We are all set! Go into your application by running: +We are almost there! The following steps are missing: $ cd hello @@ -69,6 +69,8 @@ Now we'll create our database: ``` $ mix ecto.create +Compiling 13 files (.ex) +Generated hello app The database for Hello.Repo has been created ``` @@ -78,8 +80,10 @@ And finally, we'll start the Phoenix server: ```console $ mix phx.server -[info] Running HelloWeb.Endpoint with Cowboy using http://0.0.0.0:4000 -19:30:43 - info: compiled 6 files into 2 files, copied 3 in 2.1 sec +[info] Running HelloWeb.Endpoint with cowboy 2.5.0 at http://localhost:4000 + +Webpack is watching the files… +... ``` If we choose not to have Phoenix install our dependencies when we generate a new application, the `phx.new` task will prompt us to take the necessary steps when we do want to install them. From 87244793035572d9b119a90b1294db8e34961f8b Mon Sep 17 00:00:00 2001 From: Gary Rennie Date: Fri, 16 Nov 2018 12:08:49 +0000 Subject: [PATCH 15/61] Allow custom paths to be provided to :websocket and :longpoll (#3166) * Allow custom paths to be provided to :websocket and :longpoll Previously, it was not possible to use a socket with a path that differed from the key name. For example `:websocket` would always end with `/websocket` and `:longpoll` would always end with `/longpoll`. This commit allows a `:path` to be passed into the keyword options, the path will be used instead of the default if available. --- lib/phoenix/endpoint.ex | 18 ++++++++++++------ lib/phoenix/endpoint/cowboy_adapter.ex | 16 +++++++++------- lib/phoenix/transports/long_poll.ex | 1 + lib/phoenix/transports/websocket.ex | 1 + .../integration/websocket_socket_test.exs | 9 +++++++++ 5 files changed, 32 insertions(+), 13 deletions(-) diff --git a/lib/phoenix/endpoint.ex b/lib/phoenix/endpoint.ex index 5322a95429..f84907d9a2 100644 --- a/lib/phoenix/endpoint.ex +++ b/lib/phoenix/endpoint.ex @@ -777,16 +777,18 @@ defmodule Phoenix.Endpoint do paths = if websocket do - triplet = {:websocket, socket, socket_config(websocket, Phoenix.Transports.WebSocket)} - [{socket_path(path, :websocket), triplet} | paths] + config = socket_config(websocket, Phoenix.Transports.WebSocket) + triplet = {:websocket, socket, config} + [{socket_path(path, config), triplet} | paths] else paths end paths = if longpoll do - plug_init = {endpoint, socket, socket_config(longpoll, Phoenix.Transports.LongPoll)} - [{socket_path(path, :longpoll), {:plug, Phoenix.Transports.LongPoll, plug_init}} | paths] + config = socket_config(longpoll, Phoenix.Transports.LongPoll) + plug_init = {endpoint, socket, config} + [{socket_path(path, config), {:plug, Phoenix.Transports.LongPoll, plug_init}} | paths] else paths end @@ -794,8 +796,9 @@ defmodule Phoenix.Endpoint do paths end - defp socket_path(path, key) do - String.split(path, "/", trim: true) ++ [Atom.to_string(key)] + defp socket_path(path, config) do + end_path_fragment = Keyword.fetch!(config, :path) + String.split(path <> "/" <> end_path_fragment, "/", trim: true) end defp socket_config(true, module), do: module.default_config() @@ -839,6 +842,9 @@ defmodule Phoenix.Endpoint do The configuration below can be given to both `:websocket` and `:longpoll` keys: + * `:path` - the path to use for the transport. Will default + to the transport name ("/websocket" or "/longpoll") + * `:serializer` - a list of serializers for messages. See `Phoenix.Socket` for more information diff --git a/lib/phoenix/endpoint/cowboy_adapter.ex b/lib/phoenix/endpoint/cowboy_adapter.ex index 117ab060e4..0ce4fec105 100644 --- a/lib/phoenix/endpoint/cowboy_adapter.ex +++ b/lib/phoenix/endpoint/cowboy_adapter.ex @@ -104,10 +104,11 @@ defmodule Phoenix.Endpoint.CowboyAdapter do paths = if websocket do - init = {endpoint, socket, socket_config(websocket, Phoenix.Transports.WebSocket)} + config = socket_config(websocket, Phoenix.Transports.WebSocket) + init = {endpoint, socket, config} [ - {socket_path(path, :websocket), Phoenix.Endpoint.CowboyWebSocket, + {socket_path(path, config), Phoenix.Endpoint.CowboyWebSocket, {Phoenix.Transports.WebSocket, init}} | paths ] @@ -117,10 +118,11 @@ defmodule Phoenix.Endpoint.CowboyAdapter do paths = if longpoll do - init = {endpoint, socket, socket_config(longpoll, Phoenix.Transports.LongPoll)} + config = socket_config(longpoll, Phoenix.Transports.LongPoll) + init = {endpoint, socket, config} [ - {socket_path(path, :longpoll), Plug.Adapters.Cowboy.Handler, + {socket_path(path, config), Plug.Adapters.Cowboy.Handler, {Phoenix.Transports.LongPoll, init}} | paths ] @@ -130,9 +132,9 @@ defmodule Phoenix.Endpoint.CowboyAdapter do paths end - - defp socket_path(path, key) do - parts = String.split(path, "/", trim: true) ++ [Atom.to_string(key)] + defp socket_path(path, config) do + end_path_fragment = Keyword.fetch!(config, :path) + parts = String.split(path <> "/" <> end_path_fragment, "/", trim: true) "/" <> Path.join(parts) end diff --git a/lib/phoenix/transports/long_poll.ex b/lib/phoenix/transports/long_poll.ex index 89f0c47692..a2436b0e86 100644 --- a/lib/phoenix/transports/long_poll.ex +++ b/lib/phoenix/transports/long_poll.ex @@ -8,6 +8,7 @@ defmodule Phoenix.Transports.LongPoll do def default_config() do [ window_ms: 10_000, + path: "/longpoll", pubsub_timeout_ms: 2_000, serializer: [{V1.JSONSerializer, "~> 1.0.0"}, {V2.JSONSerializer, "~> 2.0.0"}], transport_log: false, diff --git a/lib/phoenix/transports/websocket.ex b/lib/phoenix/transports/websocket.ex index d86baaa04b..0e59952590 100644 --- a/lib/phoenix/transports/websocket.ex +++ b/lib/phoenix/transports/websocket.ex @@ -4,6 +4,7 @@ defmodule Phoenix.Transports.WebSocket do def default_config() do [ + path: "/websocket", serializer: [{V1.JSONSerializer, "~> 1.0.0"}, {V2.JSONSerializer, "~> 2.0.0"}], timeout: 60_000, transport_log: false, diff --git a/test/phoenix/integration/websocket_socket_test.exs b/test/phoenix/integration/websocket_socket_test.exs index 7736f220cb..1087e9584c 100644 --- a/test/phoenix/integration/websocket_socket_test.exs +++ b/test/phoenix/integration/websocket_socket_test.exs @@ -63,6 +63,10 @@ defmodule Phoenix.Integration.WebSocketTest do socket "/ws", UserSocket, websocket: [check_origin: ["//example.com"], timeout: 200], custom: :value + + socket "/custom/some_path", UserSocket, + websocket: [path: "nested/path", check_origin: ["//example.com"], timeout: 200], + custom: :value end setup_all do @@ -91,4 +95,9 @@ defmodule Phoenix.Integration.WebSocketTest do WebsocketClient.send_message(client, "ping") assert_receive {:text, "pong"} end + + test "allows a custom path" do + path = "ws://127.0.0.1:#{@port}/custom/some_path/nested/path" + assert {:ok, client} = WebsocketClient.start_link(self(), "#{path}?key=value", :noop) + end end From e43bafdb505d5b10cd21fe07496aa8e96dc161d5 Mon Sep 17 00:00:00 2001 From: Gary Rennie Date: Fri, 16 Nov 2018 12:13:05 +0000 Subject: [PATCH 16/61] Allow variables to be used when defining socket paths This commit allows sockets (websocket/longpoll) to use variables in the path. For example, a socket can be defined with: socket "/ws/:user_id", MyApp.UserSocket, websocket: [path: "/project/:project_id"] The params will be available in the connect map: def connect(%{"user_id" => user_id, "project_id" => project_id}), do: ... The `__handler__/2` function now hands off the a `do_handler` which is responsible for modifying the passed `conn` to add the `path_params` and `params`. `__handler__/2` is now called with the entire `conn` instead of just the `path_info` and expects a `conn` to be available in the returned tuple. As this is only supported in Cowboy 2, the `test_helper.exs` has been updated to ignore `:cowboy2` tests when testing with `plug_cowboy` 1.x. --- lib/phoenix/endpoint.ex | 50 +++++++++++++++---- lib/phoenix/endpoint/cowboy2_handler.ex | 9 ++-- .../integration/long_poll_socket_test.exs | 40 +++++++++++---- .../integration/websocket_socket_test.exs | 15 ++++++ test/test_helper.exs | 3 +- 5 files changed, 92 insertions(+), 25 deletions(-) diff --git a/lib/phoenix/endpoint.ex b/lib/phoenix/endpoint.ex index f84907d9a2..be35cc79a0 100644 --- a/lib/phoenix/endpoint.ex +++ b/lib/phoenix/endpoint.ex @@ -730,9 +730,11 @@ defmodule Phoenix.Endpoint do dispatches = for {path, socket, socket_opts} <- sockets, - {path, return} <- socket_paths(module, path, socket, socket_opts) do + {path, type, conn_ast, socket, opts} <- socket_paths(module, path, socket, socket_opts) do quote do - def __handler__(unquote(path), _opts), do: unquote(Macro.escape(return)) + defp do_handler(unquote(path), conn, _opts) do + {unquote(type), unquote(conn_ast), unquote(socket), unquote(Macro.escape(opts))} + end end end @@ -762,11 +764,12 @@ defmodule Phoenix.Endpoint do def __sockets__, do: unquote(Macro.escape(sockets)) @doc false - def __handler__(path, opts) - unquote(dispatches) - def __handler__(_, opts), do: {:plug, __MODULE__, opts} + def __handler__(%{path_info: path} = conn, opts), do: do_handler(path, conn, opts) unquote(instrumentation) + + unquote(dispatches) + defp do_handler(_path, conn, opts), do: {:plug, conn, __MODULE__, opts} end end @@ -778,8 +781,8 @@ defmodule Phoenix.Endpoint do paths = if websocket do config = socket_config(websocket, Phoenix.Transports.WebSocket) - triplet = {:websocket, socket, config} - [{socket_path(path, config), triplet} | paths] + {conn_ast, match_path} = socket_path(path, config) + [{match_path, :websocket, conn_ast, socket, config} | paths] else paths end @@ -788,7 +791,8 @@ defmodule Phoenix.Endpoint do if longpoll do config = socket_config(longpoll, Phoenix.Transports.LongPoll) plug_init = {endpoint, socket, config} - [{socket_path(path, config), {:plug, Phoenix.Transports.LongPoll, plug_init}} | paths] + {conn_ast, match_path} = socket_path(path, config) + [{match_path, :plug, conn_ast, Phoenix.Transports.LongPoll, plug_init} | paths] else paths end @@ -798,7 +802,25 @@ defmodule Phoenix.Endpoint do defp socket_path(path, config) do end_path_fragment = Keyword.fetch!(config, :path) - String.split(path <> "/" <> end_path_fragment, "/", trim: true) + {vars, path} = + String.split(path <> "/" <> end_path_fragment, "/", trim: true) + |> Enum.join("/") + |> Plug.Router.Utils.build_path_match() + + conn_ast = + if vars == [] do + quote do + conn + end + else + params_map = {:%{}, [], Plug.Router.Utils.build_path_params_match(vars)} + quote do + params = unquote(params_map) + %{conn | path_params: params, params: params} + end + end + + {conn_ast, path} end defp socket_config(true, module), do: module.default_config() @@ -837,6 +859,16 @@ defmodule Phoenix.Endpoint do longpoll: true, websocket: [compress: true] + ## Path params + + It is possible to include variables in the path, these will be + available in the `params` that are passed to the socket. + + socket "/ws/:user_id", MyApp.UserSocket, + websocket: [path: "/project/:project_id"] + + Note: This feature is not supported with the Cowboy 1 adapter. + ## Shared configuration The configuration below can be given to both `:websocket` and diff --git a/lib/phoenix/endpoint/cowboy2_handler.ex b/lib/phoenix/endpoint/cowboy2_handler.ex index 32a1c5490d..87cf1fc037 100644 --- a/lib/phoenix/endpoint/cowboy2_handler.ex +++ b/lib/phoenix/endpoint/cowboy2_handler.ex @@ -12,11 +12,10 @@ defmodule Phoenix.Endpoint.Cowboy2Handler do # Note we keep the websocket state as [handler | state] # to avoid conflicts with {endpoint, opts}. def init(req, {endpoint, opts}) do - %{path_info: path_info} = conn = @connection.conn(req) - + conn = @connection.conn(req) try do - case endpoint.__handler__(path_info, opts) do - {:websocket, handler, opts} -> + case endpoint.__handler__(conn, opts) do + {:websocket, conn, handler, opts} -> case Phoenix.Transports.WebSocket.connect(conn, endpoint, handler, opts) do {:ok, %{adapter: {@connection, req}}, state} -> timeout = Keyword.fetch!(opts, :timeout) @@ -28,7 +27,7 @@ defmodule Phoenix.Endpoint.Cowboy2Handler do {:ok, req, {handler, opts}} end - {:plug, handler, opts} -> + {:plug, conn, handler, opts} -> %{adapter: {@connection, req}} = conn |> handler.call(opts) diff --git a/test/phoenix/integration/long_poll_socket_test.exs b/test/phoenix/integration/long_poll_socket_test.exs index 6bd99ae1c5..f3cc39b0c3 100644 --- a/test/phoenix/integration/long_poll_socket_test.exs +++ b/test/phoenix/integration/long_poll_socket_test.exs @@ -65,6 +65,10 @@ defmodule Phoenix.Integration.LongPollSocketTest do socket "/ws", UserSocket, longpoll: [window_ms: 200, pubsub_timeout_ms: 200, check_origin: ["//example.com"]], custom: :value + + socket "/custom/:socket_var", UserSocket, + longpoll: [path: ":path_var/path", check_origin: ["//example.com"], timeout: 200], + custom: :value end setup_all do @@ -80,48 +84,64 @@ defmodule Phoenix.Integration.LongPollSocketTest do :ok end - def poll(method, params, body \\ nil, headers \\ %{}) do + def poll(method, path, params, body \\ nil, headers \\ %{}) do headers = Map.merge(%{"content-type" => "application/json"}, headers) - url = "http://127.0.0.1:#{@port}/ws/longpoll?" <> URI.encode_query(params) + url = "http://127.0.0.1:#{@port}/#{path}?" <> URI.encode_query(params) {:ok, resp} = HTTPClient.request(method, url, headers, body) update_in(resp.body, &Phoenix.json_library().decode!(&1)) end test "refuses unallowed origins" do capture_log(fn -> - resp = poll(:get, %{}, nil, %{"origin" => "https://example.com"}) + resp = poll(:get, "ws/longpoll", %{}, nil, %{"origin" => "https://example.com"}) assert resp.body["status"] == 410 - resp = poll(:get, %{}, nil, %{"origin" => "http://notallowed.com"}) + resp = poll(:get, "ws/longpoll", %{}, nil, %{"origin" => "http://notallowed.com"}) assert resp.body["status"] == 403 end) end test "returns params with sync request" do - resp = poll(:get, %{"hello" => "world"}, nil) + resp = poll(:get, "ws/longpoll", %{"hello" => "world"}, nil) assert resp.body["token"] assert resp.body["status"] == 410 assert resp.status == 200 secret = Map.take(resp.body, ["token"]) - resp = poll(:post, secret, "params") + resp = poll(:post, "ws/longpoll", secret, "params") assert resp.body["status"] == 200 - resp = poll(:get, secret, nil) + resp = poll(:get, "ws/longpoll", secret, nil) assert resp.body["messages"] == [~s(%{"hello" => "world"})] end + @tag :cowboy2 + test "allows a path with variables" do + path = "custom/123/456/path" + resp = poll(:get, path, %{"key" => "value"}, nil) + secret = Map.take(resp.body, ["token"]) + + resp = poll(:post, path, secret, "params") + assert resp.body["status"] == 200 + + resp = poll(:get, path, secret, nil) + [params] = resp.body["messages"] + assert params =~ ~s("key" => "value") + assert params =~ ~s("socket_var" => "123") + assert params =~ ~s(path_var" => "456") + end + test "returns pong from async request" do - resp = poll(:get, %{"hello" => "world"}, nil) + resp = poll(:get, "ws/longpoll", %{"hello" => "world"}, nil) assert resp.body["token"] assert resp.body["status"] == 410 assert resp.status == 200 secret = Map.take(resp.body, ["token"]) - resp = poll(:post, secret, "ping") + resp = poll(:post, "ws/longpoll", secret, "ping") assert resp.body["status"] == 200 - resp = poll(:get, secret, nil) + resp = poll(:get, "ws/longpoll", secret, nil) assert resp.body["messages"] == ["pong"] end end diff --git a/test/phoenix/integration/websocket_socket_test.exs b/test/phoenix/integration/websocket_socket_test.exs index 1087e9584c..c0fb5d558f 100644 --- a/test/phoenix/integration/websocket_socket_test.exs +++ b/test/phoenix/integration/websocket_socket_test.exs @@ -67,6 +67,10 @@ defmodule Phoenix.Integration.WebSocketTest do socket "/custom/some_path", UserSocket, websocket: [path: "nested/path", check_origin: ["//example.com"], timeout: 200], custom: :value + + socket "/custom/:socket_var", UserSocket, + websocket: [path: ":path_var/path", check_origin: ["//example.com"], timeout: 200], + custom: :value end setup_all do @@ -98,6 +102,17 @@ defmodule Phoenix.Integration.WebSocketTest do test "allows a custom path" do path = "ws://127.0.0.1:#{@port}/custom/some_path/nested/path" + assert {:ok, _} = WebsocketClient.start_link(self(), "#{path}?key=value", :noop) + end + + @tag :cowboy2 + test "allows a path with variables" do + path = "ws://127.0.0.1:#{@port}/custom/123/456/path" assert {:ok, client} = WebsocketClient.start_link(self(), "#{path}?key=value", :noop) + WebsocketClient.send_message(client, "params") + assert_receive {:text, params} + assert params =~ ~s("key" => "value") + assert params =~ ~s("socket_var" => "123") + assert params =~ ~s(path_var" => "456") end end diff --git a/test/test_helper.exs b/test/test_helper.exs index 07c139d012..c000fcfc8d 100644 --- a/test/test_helper.exs +++ b/test/test_helper.exs @@ -30,5 +30,6 @@ assert_timeout = String.to_integer( System.get_env("ELIXIR_ASSERT_TIMEOUT") || "200" ) -exclude = if Version.match?(System.version, "~> 1.5"), do: [], else: [phx_new: true] +exclude = if Version.match?(System.version, "~> 1.5"), do: [], else: [:phx_new] +exclude = if hd(Application.spec(:plug_cowboy, :vsn)) == ?1, do: [:cowboy2 | exclude], else: exclude ExUnit.start(assert_receive_timeout: assert_timeout, exclude: exclude) From f5d1d3ca09f939b0ae33ba4561c28ea6542a38d4 Mon Sep 17 00:00:00 2001 From: Lachezar Yankov Date: Mon, 19 Nov 2018 23:23:55 +0100 Subject: [PATCH 17/61] Expose cowboy 2.3 max_frame_size config for websockets (#3173) --- lib/phoenix/endpoint.ex | 5 ++++- lib/phoenix/endpoint/cowboy2_handler.ex | 13 ++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/lib/phoenix/endpoint.ex b/lib/phoenix/endpoint.ex index f84907d9a2..b79a0e5fc3 100644 --- a/lib/phoenix/endpoint.ex +++ b/lib/phoenix/endpoint.ex @@ -837,7 +837,7 @@ defmodule Phoenix.Endpoint do longpoll: true, websocket: [compress: true] - ## Shared configuration + ## Common configuration The configuration below can be given to both `:websocket` and `:longpoll` keys: @@ -900,6 +900,9 @@ defmodule Phoenix.Endpoint do * `:timeout` - the timeout for keeping websocket connections open after it last received data, defaults to 60_000ms + * `:max_frame_size` - the maximum allowed frame size in bytes. + Supported from Cowboy 2.3 onwards, defaults to "infinity" + ## Longpoll configuration The following configuration applies only to `:longpoll`: diff --git a/lib/phoenix/endpoint/cowboy2_handler.ex b/lib/phoenix/endpoint/cowboy2_handler.ex index 32a1c5490d..45ae2a0b57 100644 --- a/lib/phoenix/endpoint/cowboy2_handler.ex +++ b/lib/phoenix/endpoint/cowboy2_handler.ex @@ -19,9 +19,16 @@ defmodule Phoenix.Endpoint.Cowboy2Handler do {:websocket, handler, opts} -> case Phoenix.Transports.WebSocket.connect(conn, endpoint, handler, opts) do {:ok, %{adapter: {@connection, req}}, state} -> - timeout = Keyword.fetch!(opts, :timeout) - compress = Keyword.fetch!(opts, :compress) - cowboy_opts = %{idle_timeout: timeout, compress: compress} + cowboy_opts = + opts + |> Enum.flat_map(fn + {:timeout, timeout} -> [idle_timeout: timeout] + {:compress, _} = opt -> [opt] + {:max_frame_size, _} = opt -> [opt] + _other -> [] + end) + |> Map.new() + {:cowboy_websocket, req, [handler | state], cowboy_opts} {:error, %{adapter: {@connection, req}}} -> From 5b39cf0e94ee30ae55bae3833f194d6574caf01d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sat, 17 Nov 2018 20:23:04 +0100 Subject: [PATCH 18/61] Streamline channel shutdown * We no longer shutdown all channels when the socket/transport closes. Instead, we handle the DOWN message in the channel and accordingly convert :normal` to `{:shutdown, :closed}` * A channel being closed due to a duplicate join is now terminated with reason `{:shutdown, :duplicate_join}` * We no longer hide the actual socket/transport shutdown reason. So if longpool shuts down with reason `{:shutdown, :inactive}`, this information will also be available to channels --- lib/phoenix/channel/server.ex | 73 +++++----------- lib/phoenix/socket.ex | 84 ++++++++++++------- lib/phoenix/test/channel_test.ex | 2 +- .../integration/long_poll_channels_test.exs | 6 +- .../integration/websocket_channels_test.exs | 3 +- test/phoenix/test/channel_test.exs | 6 +- 6 files changed, 81 insertions(+), 93 deletions(-) diff --git a/lib/phoenix/channel/server.ex b/lib/phoenix/channel/server.ex index 6a8928a557..bedb881d69 100644 --- a/lib/phoenix/channel/server.ex +++ b/lib/phoenix/channel/server.ex @@ -63,6 +63,8 @@ defmodule Phoenix.Channel.Server do @doc """ Gets the socket from the channel. + + Used by channel tests. """ @spec socket(pid) :: Socket.t def socket(pid) do @@ -70,54 +72,21 @@ defmodule Phoenix.Channel.Server do end @doc """ - Notifies the channels the clients closed. + Emulates the socket being closed. - This event is synchronous as we want to guarantee - proper termination of the channels. + Used by channel tests. """ - @spec close([pid], timeout) :: :ok - def close(pids, timeout \\ 5000) - - def close([], _timeout) do - :ok - end - - def close(pids, timeout) do - # We need to guarantee that the channel has been closed - # otherwise the link in the transport will trigger it to crash. - pids_and_refs = - for pid <- pids do - ref = Process.monitor(pid) - GenServer.cast(pid, :close) - {pid, ref} - end - - timeout_ref = make_ref() - timer_ref = Process.send_after(self(), {:timeout, timeout_ref}, timeout) - - Enum.reduce(pids_and_refs, :infinity, fn {pid, ref}, timeout -> - receive do - {:DOWN, ^ref, _, _, _} -> timeout - {:timeout, ^timeout_ref} -> kill(pid, ref) - after - timeout -> kill(pid, ref) - end - end) - - Process.cancel_timer(timer_ref) + @spec close(pid, timeout) :: :ok + def close(pid, timeout) do + GenServer.cast(pid, :close) + ref = Process.monitor(pid) receive do - {:timeout, ^timeout_ref} -> :ok + {:DOWN, ^ref, _, _, _} -> :ok after - 0 -> :ok - end - end - - defp kill(pid, ref) do - Process.exit(pid, :kill) - - receive do - {:DOWN, ^ref, _, _, _} -> 0 + timeout -> + Process.exit(pid, :kill) + receive do: ({:DOWN, ^ref, _, _, _} -> :ok) end end @@ -277,7 +246,7 @@ defmodule Phoenix.Channel.Server do @doc false def handle_cast(:close, socket) do - handle_result({:stop, {:shutdown, :closed}, socket}, :handle_cast) + {:stop, {:shutdown, :closed}, socket} end @doc false @@ -303,7 +272,8 @@ defmodule Phoenix.Channel.Server do end def handle_info({:DOWN, _, _, transport_pid, reason}, %{transport_pid: transport_pid} = socket) do - handle_result({:stop, reason, socket}, :handle_info) + reason = if reason == :normal, do: {:shutdown, :closed}, else: reason + {:stop, reason, socket} end def handle_info(msg, %{channel: channel} = socket) do @@ -381,9 +351,9 @@ defmodule Phoenix.Channel.Server do defp handle_result({:stop, reason, socket}, _callback) do case reason do - :normal -> notify_transport_of_graceful_exit(socket) - :shutdown -> notify_transport_of_graceful_exit(socket) - {:shutdown, _} -> notify_transport_of_graceful_exit(socket) + :normal -> send_socket_close(socket, reason) + :shutdown -> send_socket_close(socket, reason) + {:shutdown, _} -> send_socket_close(socket, reason) _ -> :noop end {:stop, reason, socket} @@ -425,11 +395,8 @@ defmodule Phoenix.Channel.Server do """ end - defp notify_transport_of_graceful_exit(socket) do - %{topic: topic, join_ref: ref, transport_pid: transport_pid} = socket - close_msg = %Message{join_ref: ref, ref: ref, topic: topic, event: "phx_close", payload: %{}} - send(transport_pid, {:graceful_exit, self(), close_msg}) - :ok + defp send_socket_close(%{transport_pid: transport_pid}, reason) do + send(transport_pid, {:socket_close, self(), reason}) end ## Handle in/replies diff --git a/lib/phoenix/socket.ex b/lib/phoenix/socket.ex index 417d51f6e0..7743172eab 100644 --- a/lib/phoenix/socket.ex +++ b/lib/phoenix/socket.ex @@ -76,6 +76,14 @@ defmodule Phoenix.Socket do Defaults to the `:info` log level. Pass `false` to disable logging. + ## Garbage collection + + It's possible to force garbage collection in the transport process after + processing large messages. For example, to trigger such from your channels, + run: + + send(socket.transport_pid, :garbage_collect) + ## Client-server communication The encoding of server data and the decoding of client data is done @@ -83,9 +91,6 @@ defmodule Phoenix.Socket do By default, JSON encoding is used to broker messages to and from clients with `Phoenix.Socket.V2.JSONSerializer`. - The serializer `encode!/1` and `fastlane!/1` functions must return - a tuple in the format `{:text | :binary, iodata}`. - The serializer `decode!` function must return a `Phoenix.Socket.Message` which is forwarded to channels except: @@ -118,14 +123,6 @@ defmodule Phoenix.Socket do writing your own socket that does not leverage channels or for writing your own transports that interacts with other sockets. - ## Garbage collection - - It's possible to force garbage collection in the transport process after - processing large messages. For example, to trigger such from your channels, - run: - - send(socket.transport_pid, :garbage_collect) - """ require Logger @@ -418,20 +415,6 @@ defmodule Phoenix.Socket do end end - def __info__({:graceful_exit, pid, %Phoenix.Socket.Message{} = message}, {state, socket}) do - state = - case state.channels_inverse do - %{^pid => {topic, _join_ref}} -> - {^pid, monitor_ref} = Map.fetch!(state.channels, topic) - delete_channel(state, pid, topic, monitor_ref) - - %{} -> - state - end - - {:push, encode_reply(socket, message), {state, socket}} - end - def __info__(%Broadcast{event: "disconnect"}, state) do {:stop, {:shutdown, :disconnected}, state} end @@ -440,6 +423,19 @@ defmodule Phoenix.Socket do {:push, {opcode, payload}, state} end + def __info__({:socket_close, pid, _reason}, {state, socket}) do + case state.channels_inverse do + %{^pid => {topic, join_ref}} -> + {^pid, monitor_ref} = Map.fetch!(state.channels, topic) + state = delete_channel(state, pid, topic, monitor_ref) + {:socket_push, opcode, payload} = serialize_close(socket, topic, join_ref) + {:push, {opcode, payload}, {state, socket}} + + %{} -> + {:ok, {state, socket}} + end + end + def __info__(:garbage_collect, state) do :erlang.garbage_collect(self()) {:ok, state} @@ -449,11 +445,7 @@ defmodule Phoenix.Socket do {:ok, state} end - def __terminate__(_reason, {%{channels_inverse: channels_inverse}, _socket}) do - # Although this is not strictly necessary, as each channel server - # watches the transport, it is a more efficient way of doing as - # we terminate all channels at once. - Phoenix.Channel.Server.close(Map.keys(channels_inverse)) + def __terminate__(_reason, _state_socket) do :ok end @@ -563,8 +555,18 @@ defmodule Phoenix.Socket do "Closing existing channel for new join." end - :ok = Phoenix.Channel.Server.close([pid]) - handle_in(nil, message, delete_channel(state, pid, topic, ref), socket) + :ok = shutdown_duplicate_channel(pid) + + # We have to send a message to the client because the client + # may be expecting us to explicitly shutdown previous channels, + # even when they are duplicate. Instead, we would prefer for + # the client to automatically handle this, but that was not the + # case up to Phoenix v1.4.0. + {^topic, join_ref} = Map.fetch!(state.channels_inverse, pid) + send self(), serialize_close(socket, topic, join_ref) + + state = delete_channel(state, pid, topic, ref) + handle_in(nil, message, state, socket) end defp handle_in({pid, _ref}, message, state, socket) do @@ -613,4 +615,22 @@ defmodule Phoenix.Socket do {:socket_push, opcode, payload} = serializer.encode!(message) {opcode, payload} end + + defp serialize_close(%{serializer: serializer}, topic, join_ref) do + message = %Message{join_ref: join_ref, ref: join_ref, topic: topic, event: "phx_close", payload: %{}} + serializer.encode!(message) + end + + defp shutdown_duplicate_channel(pid) do + ref = Process.monitor(pid) + Process.exit(pid, {:shutdown, :duplicate_join}) + + receive do + {:DOWN, ^ref, _, _, _} -> :ok + after + 5_000 -> + Process.exit(pid, :kill) + receive do: ({:DOWN, ^ref, _, _, _} -> :ok) + end + end end diff --git a/lib/phoenix/test/channel_test.ex b/lib/phoenix/test/channel_test.ex index 8ce20b98fe..b758b0e0e9 100644 --- a/lib/phoenix/test/channel_test.ex +++ b/lib/phoenix/test/channel_test.ex @@ -417,7 +417,7 @@ defmodule Phoenix.ChannelTest do of 5000 milliseconds. """ def close(socket, timeout \\ 5000) do - Server.close([socket.channel_pid], timeout) + Server.close(socket.channel_pid, timeout) end @doc """ diff --git a/test/phoenix/integration/long_poll_channels_test.exs b/test/phoenix/integration/long_poll_channels_test.exs index ecab8b0da5..c8d4a9af4c 100644 --- a/test/phoenix/integration/long_poll_channels_test.exs +++ b/test/phoenix/integration/long_poll_channels_test.exs @@ -355,7 +355,7 @@ defmodule Phoenix.Integration.LongPollChannelsTest do assert channel Process.monitor(channel) - assert_receive({:DOWN, _, :process, ^channel, {:shutdown, :closed}}, 5000) + assert_receive({:DOWN, _, :process, ^channel, {:shutdown, :inactive}}, 5000) resp = poll(:post, "/ws", @vsn, session) assert resp.body["status"] == 410 end @@ -462,8 +462,8 @@ defmodule Phoenix.Integration.LongPollChannelsTest do Endpoint.broadcast("user_sockets:456", "disconnect", %{}) - assert_receive {:DOWN, _, :process, ^chan1, {:shutdown, :closed}} - assert_receive {:DOWN, _, :process, ^chan2, {:shutdown, :closed}} + assert_receive {:DOWN, _, :process, ^chan1, {:shutdown, :disconnected}} + assert_receive {:DOWN, _, :process, ^chan2, {:shutdown, :disconnected}} poll(:get, "/ws", @vsn, session) assert resp.body["status"] == 410 diff --git a/test/phoenix/integration/websocket_channels_test.exs b/test/phoenix/integration/websocket_channels_test.exs index 7811eb2717..38184aa6dc 100644 --- a/test/phoenix/integration/websocket_channels_test.exs +++ b/test/phoenix/integration/websocket_channels_test.exs @@ -334,7 +334,8 @@ defmodule Phoenix.Integration.WebSocketChannelsTest do Process.monitor(channel) WebsocketClient.close(sock) - assert_receive {:DOWN, _, :process, ^channel, {:shutdown, :closed}} + assert_receive {:DOWN, _, :process, ^channel, shutdown} + when shutdown in [:shutdown, {:shutdown, :closed}] end test "refuses websocket events that haven't joined" do diff --git a/test/phoenix/test/channel_test.exs b/test/phoenix/test/channel_test.exs index d249495bb3..805ba9c59e 100644 --- a/test/phoenix/test/channel_test.exs +++ b/test/phoenix/test/channel_test.exs @@ -16,7 +16,7 @@ defmodule Phoenix.Test.ChannelTest do @moduletag :capture_log defp assert_graceful_exit(pid) do - assert_receive {:graceful_exit, ^pid, %Message{event: "phx_close"}} + assert_receive {:socket_close, ^pid, _} end defmodule EmptyChannel do @@ -263,7 +263,7 @@ defmodule Phoenix.Test.ChannelTest do pid = socket.channel_pid assert_receive {:terminate, _} assert_receive {:EXIT, ^pid, _} - refute_receive {:graceful_exit, _, _} + refute_receive {:socket_close, _, _} end test "pushes on stop" do @@ -400,7 +400,7 @@ defmodule Phoenix.Test.ChannelTest do pid = socket.channel_pid assert_receive {:terminate, {:shutdown, :closed}} - assert_graceful_exit(pid) + assert_receive {:EXIT, ^pid, {:shutdown, :closed}} # Closing again doesn't crash _ = close(socket) From 3be52e816a6198f6f3463a762449bbc835f80985 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sat, 17 Nov 2018 22:18:13 +0100 Subject: [PATCH 19/61] Allow custom channels This is done by invoking the start_link/1 function in the channel module. Therefore this commit defines a start_link/1 function on every channel module. This API is experimental as we will modify this behaviour in future releases to invoke child_spec/1 instead. --- lib/phoenix/channel.ex | 4 + lib/phoenix/channel/server.ex | 106 +++++++++--------- lib/phoenix/socket.ex | 54 +++++++++ .../integration/websocket_channels_test.exs | 72 +++++++++++- test/phoenix/logger_test.exs | 1 - 5 files changed, 185 insertions(+), 52 deletions(-) diff --git a/lib/phoenix/channel.ex b/lib/phoenix/channel.ex index 312296134d..c02a3acda4 100644 --- a/lib/phoenix/channel.ex +++ b/lib/phoenix/channel.ex @@ -353,6 +353,10 @@ defmodule Phoenix.Channel do import unquote(__MODULE__) import Phoenix.Socket, only: [assign: 3] + def start_link(triplet) do + GenServer.start_link(Phoenix.Channel.Server, triplet) + end + def __socket__(:private) do %{log_join: @phoenix_log_join, log_handle_in: @phoenix_log_handle_in} end diff --git a/lib/phoenix/channel/server.ex b/lib/phoenix/channel/server.ex index bedb881d69..bc3542f5c8 100644 --- a/lib/phoenix/channel/server.ex +++ b/lib/phoenix/channel/server.ex @@ -9,58 +9,45 @@ defmodule Phoenix.Channel.Server do alias Phoenix.Socket alias Phoenix.Socket.{Broadcast, Message, Reply, PoolSupervisor} - ## Transport API + ## Socket API @doc """ Starts a channel server. + + It is just some basic indirection to please a simple_one_for_one supervisor. """ - def start_link(socket, payload, pid, ref) do - GenServer.start_link(__MODULE__, {socket, payload, pid, ref}) + def start_link(channel, triplet) do + channel.start_link(triplet) end @doc """ Joins the channel in socket with authentication payload. """ - @spec join(Socket.t, module, Message.t, keyword) :: {:ok, map, pid, Socket.t} | {:error, map} + @spec join(Socket.t, module, Message.t, keyword) :: {:ok, term, pid} | {:error, term} def join(socket, channel, message, opts) do %{topic: topic, payload: payload, ref: join_ref} = message - assigns = Keyword.get(opts, :assigns, %{}) - - socket = - %Socket{ - socket - | topic: topic, - channel: channel, - join_ref: join_ref, - assigns: Map.merge(socket.assigns, assigns), - private: Map.merge(channel.__socket__(:private), socket.private) - } - - instrument = %{params: payload, socket: socket} - - Phoenix.Endpoint.instrument socket, :phoenix_channel_join, instrument, fn -> - ref = make_ref() - key = {self(), ref} - args = [socket, payload, self(), ref] - - case PoolSupervisor.start_child(socket.endpoint, socket.handler, key, args) do - {:ok, :undefined} -> - log_join socket, topic, fn -> "Replied #{topic} :error" end - receive do: ({^ref, reply} -> {:error, reply}) - {:ok, pid} -> - log_join socket, topic, fn -> "Replied #{topic} :ok" end - receive do: ({^ref, reply} -> {:ok, reply, pid}) - {:error, reason} -> - Logger.error fn -> Exception.format_exit(reason) end - {:error, %{reason: "join crashed"}} - end + assigns = Map.merge(socket.assigns, Keyword.get(opts, :assigns, %{})) + socket = %{socket | topic: topic, channel: channel, join_ref: join_ref, assigns: assigns} + + ref = make_ref() + from = {self(), ref} + + # TODO: When we migrate to DynamicSupervisor, we will start + # {channel, {payload, from, socket}} and have its child spec + # point back to this module start link. + args = [channel, {payload, from, socket}] + + case PoolSupervisor.start_child(socket.endpoint, socket.handler, from, args) do + {:ok, :undefined} -> + receive do: ({^ref, reply} -> {:error, reply}) + {:ok, pid} -> + receive do: ({^ref, reply} -> {:ok, reply, pid}) + {:error, reason} -> + Logger.error fn -> Exception.format_exit(reason) end + {:error, %{reason: "join crashed"}} end end - defp log_join(_, "phoenix" <> _, _func), do: :noop - defp log_join(%{private: %{log_join: false}}, _topic, _func), do: :noop - defp log_join(%{private: %{log_join: level}}, _topic, func), do: Logger.log(level, func) - @doc """ Gets the socket from the channel. @@ -206,18 +193,21 @@ defmodule Phoenix.Channel.Server do ## Callbacks @doc false - def init({socket, auth_payload, parent, ref}) do - _ = Process.monitor(socket.transport_pid) - %{channel: channel, topic: topic} = socket - socket = %{socket | channel_pid: self()} + def init({auth_payload, from, socket}) do + %{channel: channel, topic: topic, private: private} = socket - case channel.join(topic, auth_payload, socket) do + socket = %{socket + | channel_pid: self(), + private: Map.merge(channel.__socket__(:private), private)} + + case channel_join(socket, channel, topic, auth_payload) do {:ok, socket} -> - init(socket, %{}, parent, ref) + init(socket, channel, topic, %{}, from) {:ok, reply, socket} -> - init(socket, reply, parent, ref) + init(socket, channel, topic, reply, from) {:error, reply} -> - send(parent, {ref, reply}) + log_join socket, topic, fn -> "Replied #{topic} :error" end + GenServer.reply(from, reply) :ignore other -> raise """ @@ -232,13 +222,29 @@ defmodule Phoenix.Channel.Server do end end - defp init(socket, reply, parent, ref) do - fastlane = {socket.transport_pid, socket.serializer, socket.channel.__intercepts__()} - PubSub.subscribe(socket.pubsub_server, socket.topic, link: true, fastlane: fastlane) - send(parent, {ref, reply}) + defp channel_join(socket, channel, topic, auth_payload) do + instrument = %{params: auth_payload, socket: socket} + + Phoenix.Endpoint.instrument socket, :phoenix_channel_join, instrument, fn -> + channel.join(topic, auth_payload, socket) + end + end + + defp init(socket, channel, topic, reply, from) do + %{transport_pid: transport_pid, serializer: serializer, pubsub_server: pubsub_server} = socket + Process.monitor(transport_pid) + + fastlane = {transport_pid, serializer, channel.__intercepts__()} + PubSub.subscribe(pubsub_server, topic, link: true, fastlane: fastlane) + + log_join socket, topic, fn -> "Replied #{topic} :ok" end + GenServer.reply(from, reply) {:ok, %{socket | joined: true}} end + defp log_join(%{private: %{log_join: false}}, _topic, _func), do: :noop + defp log_join(%{private: %{log_join: level}}, _topic, func), do: Logger.log(level, func) + @doc false def handle_call(:socket, _from, socket) do {:reply, socket, socket} diff --git a/lib/phoenix/socket.ex b/lib/phoenix/socket.ex index 7743172eab..305fb2c37b 100644 --- a/lib/phoenix/socket.ex +++ b/lib/phoenix/socket.ex @@ -123,6 +123,59 @@ defmodule Phoenix.Socket do writing your own socket that does not leverage channels or for writing your own transports that interacts with other sockets. + ## Custom channels + + You can list any module as a channel as long as it implements + a `start_link/1` function that receives a tuple with three elements: + + {auth_payload, from, socket} + + A custom channel implementation MUST invoke + `GenServer.reply(from, reply_payload)` during its initialization + with a custom `reply_payload` that will be sent as a reply to the + client. Failing to do so will block the socket forever. + + A custom channel receives `Phoenix.Socket.Message` structs as regular + messages from the transport. Replies to those messages and custom + messages can be sent to the socket at any moment by building an + appropriate `Phoenix.Socket.Reply` and `Phoenix.Socket.Message` + structs, encoding them with the serializer and dispatching the + serialized result to the transport. + + For example, to handle "phx_leave" messages, which is recommended + to be handled by all channel implementations, one may do: + + def handle_info( + %Message{topic: topic, event: "phx_leave"} = message, + %{topic: topic, serializer: serializer, transport_pid: transport_pid} = socket + ) do + send transport_pid, serializer.encode!(build_leave_reply(message)) + {:stop, {:shutdown, :left}, socket} + end + + We also recommend all channels to monitor the `transport_pid` + on `init` and exit if the transport exits. We also advise to rewrite + `:normal` exit reasons (usually due to the socket being closed) + to the `{:shutdown, :closed}` to guarantee links are broken on + the channel exit (as a `:normal` exit does not break links): + + def handle_info({:DOWN, _, _, transport_pid, reason}, %{transport_pid: transport_pid} = socket) do + reason = if reason == :normal, do: {:shutdown, :closed}, else: reason + {:stop, reason, socket} + end + + Any process exit is treated as an error by the socket layer unless + a `{:socket_close, pid, reason}` message is sent to the socket before + shutdown. + + Custom channel implementations cannot be tested with `Phoenix.ChannelTest` + and are currently considered experimental. The underlying API may be + changed at any moment. + + **Note:** in future Phoenix versions we will require custom channels + to provide a custom `child_spec/1` function instead of `start_link/1`. + Since the default behaviour of `child_spec/1` is to invoke `start_link/1`, + this behaviour should be backwards compatible in almost all cases. """ require Logger @@ -562,6 +615,7 @@ defmodule Phoenix.Socket do # even when they are duplicate. Instead, we would prefer for # the client to automatically handle this, but that was not the # case up to Phoenix v1.4.0. + # TODO: Remove this message on Phoenix v1.5+ {^topic, join_ref} = Map.fetch!(state.channels_inverse, pid) send self(), serialize_close(socket, topic, join_ref) diff --git a/test/phoenix/integration/websocket_channels_test.exs b/test/phoenix/integration/websocket_channels_test.exs index 38184aa6dc..8d969a4f72 100644 --- a/test/phoenix/integration/websocket_channels_test.exs +++ b/test/phoenix/integration/websocket_channels_test.exs @@ -60,6 +60,34 @@ defmodule Phoenix.Integration.WebSocketChannelsTest do end end + defmodule CustomChannel do + use GenServer + + def start_link(triplet) do + GenServer.start_link(__MODULE__, triplet) + end + + def init({payload, from, socket}) do + case payload["action"] do + "ok" -> + GenServer.reply(from, %{"action" => "ok"}) + {:ok, socket} + + "ignore" -> + GenServer.reply(from, %{"action" => "ignore"}) + :ignore + + "error" -> + raise "oops" + end + end + + def handle_info(%Message{event: "close"}, socket) do + send socket.transport_pid, {:socket_close, self(), :shutdown} + {:stop, :shutdown, socket} + end + end + defmodule UserSocketConnectInfo do use Phoenix.Socket, log: false @@ -94,6 +122,7 @@ defmodule Phoenix.Integration.WebSocketChannelsTest do use Phoenix.Socket channel "room:*", RoomChannel + channel "custom:*", CustomChannel def connect(%{"reject" => "true"}, _socket) do :error @@ -137,7 +166,6 @@ defmodule Phoenix.Integration.WebSocketChannelsTest do timeout: 200, connect_info: [:x_headers, :peer_data, :uri, signing_salt: "salt"] ] - end setup_all do @@ -445,4 +473,46 @@ defmodule Phoenix.Integration.WebSocketChannelsTest do end end end + + # Those tests are not transport specific but for integration purposes + # it is best to assert custom channels work throughout the whole stack, + # compared to only testing the socket <-> channel communication. Which + # is why test them under the latest websocket transport. + describe "custom channels" do + @serializer V2.JSONSerializer + @vsn "2.0.0" + @vsn_path "ws://127.0.0.1:#{@port}/ws/websocket?vsn=#{@vsn}" + + test "join, ignore, error, and event messages" do + {:ok, sock} = WebsocketClient.start_link(self(), @vsn_path, @serializer) + + WebsocketClient.join(sock, "custom:ignore", %{"action" => "ignore"}) + + assert_receive %Message{event: "phx_reply", + join_ref: "1", + payload: %{"response" => %{"action" => "ignore"}, "status" => "error"}, + ref: "1", + topic: "custom:ignore"} + + + WebsocketClient.join(sock, "custom:error", %{"action" => "error"}) + + assert_receive %Message{event: "phx_reply", + join_ref: "2", + payload: %{"response" => %{"reason" => "join crashed"}, "status" => "error"}, + ref: "2", + topic: "custom:error"} + + WebsocketClient.join(sock, "custom:ok", %{"action" => "ok"}) + + assert_receive %Message{event: "phx_reply", + join_ref: "3", + payload: %{"response" => %{"action" => "ok"}, "status" => "ok"}, + ref: "3", + topic: "custom:ok"} + + WebsocketClient.send_event(sock, "custom:ok", "close", %{body: "bye!"}) + assert_receive %Message{event: "phx_close", payload: %{}} + end + end end diff --git a/test/phoenix/logger_test.exs b/test/phoenix/logger_test.exs index 06011a1414..764c9f32d7 100644 --- a/test/phoenix/logger_test.exs +++ b/test/phoenix/logger_test.exs @@ -136,7 +136,6 @@ defmodule Phoenix.LoggerTest do end test "logs phoenix_channel_join as configured by the channel" do - log = capture_log(fn -> socket = %Phoenix.Socket{private: %{log_join: :info}} Phoenix.Logger.phoenix_channel_join(:start, %{}, %{socket: socket, params: %{}}) From de5996126cf99bea42d99fd0fb8dc0b4b3731a26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Tue, 20 Nov 2018 13:06:04 +0100 Subject: [PATCH 20/61] List phoenix_html as an optional dependency --- lib/phoenix/template.ex | 4 ++-- lib/phoenix/template/eex_engine.ex | 3 ++- lib/phoenix/template/html.ex | 14 -------------- mix.exs | 7 ++++--- mix.lock | 4 ++-- test/phoenix/template_test.exs | 4 ++-- 6 files changed, 12 insertions(+), 24 deletions(-) delete mode 100644 lib/phoenix/template/html.ex diff --git a/lib/phoenix/template.ex b/lib/phoenix/template.ex index 6941de6bd3..d6b49ceaa4 100644 --- a/lib/phoenix/template.ex +++ b/lib/phoenix/template.ex @@ -89,7 +89,7 @@ defmodule Phoenix.Template do New encoders can be added via the format encoder option: config :phoenix, :format_encoders, - html: Phoenix.Template.HTML + html: Phoenix.HTML.Engine """ @@ -219,7 +219,7 @@ defmodule Phoenix.Template do end defp default_encoders do - [html: Phoenix.Template.HTML, json: Phoenix.json_library(), js: Phoenix.Template.HTML] + [html: Phoenix.HTML.Engine, json: Phoenix.json_library(), js: Phoenix.HTML.Engine] end @doc """ diff --git a/lib/phoenix/template/eex_engine.ex b/lib/phoenix/template/eex_engine.ex index cd6ddaff91..4c76eea30e 100644 --- a/lib/phoenix/template/eex_engine.ex +++ b/lib/phoenix/template/eex_engine.ex @@ -11,12 +11,13 @@ defmodule Phoenix.Template.EExEngine do defp engine_for(name) do case Phoenix.Template.format_encoder(name) do - Phoenix.Template.HTML -> + Phoenix.HTML.Engine -> unless Code.ensure_loaded?(Phoenix.HTML.Engine) do raise "could not load Phoenix.HTML.Engine to use with .html.eex templates. " <> "You can configure your own format encoder for HTML but we recommend " <> "adding phoenix_html as a dependency as it provides XSS protection." end + Phoenix.HTML.Engine _ -> EEx.SmartEngine diff --git a/lib/phoenix/template/html.ex b/lib/phoenix/template/html.ex deleted file mode 100644 index 8e3402d44a..0000000000 --- a/lib/phoenix/template/html.ex +++ /dev/null @@ -1,14 +0,0 @@ -defmodule Phoenix.Template.HTML do - @moduledoc """ - The default HTML encoder that ships with Phoenix. - - It expects `{:safe, body}` as a safe response or - body as a string which will be HTML escaped. - """ - - @doc """ - Encodes the HTML templates to iodata. - """ - def encode_to_iodata!({:safe, body}), do: body - def encode_to_iodata!(body) when is_binary(body), do: Plug.HTML.html_escape(body) -end diff --git a/mix.exs b/mix.exs index 1c8f6b26e1..0116e3a5d4 100644 --- a/mix.exs +++ b/mix.exs @@ -47,10 +47,13 @@ defmodule Phoenix.MixProject do defp deps do [ - {:plug_cowboy, "~> 1.0 or ~> 2.0", optional: true}, {:plug, "~> 1.7"}, {:phoenix_pubsub, "~> 1.1"}, + + # Optional deps + {:plug_cowboy, "~> 1.0 or ~> 2.0", optional: true}, {:jason, "~> 1.0", optional: true}, + {:phoenix_html, "~> 2.13", github: "phoenixframework/phoenix_html", optional: true}, # Docs dependencies {:ex_doc, "~> 0.19.1", only: :docs}, @@ -58,7 +61,6 @@ defmodule Phoenix.MixProject do # Test dependencies {:gettext, "~> 0.15.0", only: :test}, - {:phoenix_html, "~> 2.11", only: :test}, {:websocket_client, git: "https://github.com/jeremyong/websocket_client.git", only: :test} ] end @@ -179,7 +181,6 @@ defmodule Phoenix.MixProject do Phoenix.Template.EExEngine, Phoenix.Template.Engine, Phoenix.Template.ExsEngine, - Phoenix.Template.HTML, ], ] end diff --git a/mix.lock b/mix.lock index ce15280057..bead5b3414 100644 --- a/mix.lock +++ b/mix.lock @@ -10,9 +10,9 @@ "makeup_elixir": {:hex, :makeup_elixir, "0.8.0", "1204a2f5b4f181775a0e456154830524cf2207cf4f9112215c05e0b76e4eca8b", [:mix], [{:makeup, "~> 0.5.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 0.2.2", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm"}, "mime": {:hex, :mime, "1.3.0", "5e8d45a39e95c650900d03f897fbf99ae04f60ab1daa4a34c7a20a5151b7a5fe", [:mix], [], "hexpm"}, "nimble_parsec": {:hex, :nimble_parsec, "0.2.2", "d526b23bdceb04c7ad15b33c57c4526bf5f50aaa70c7c141b4b4624555c68259", [:mix], [], "hexpm"}, - "phoenix_html": {:hex, :phoenix_html, "2.11.0", "ead10dd1e36d5b8b5cc55642ba337832ec62617efd5765cddaa1a36c8b3891ca", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, + "phoenix_html": {:git, "https://github.com/phoenixframework/phoenix_html.git", "e663256cd57256f2921be808e553180fba96423f", []}, "phoenix_pubsub": {:hex, :phoenix_pubsub, "1.1.0", "d55e25ff1ff8ea2f9964638366dfd6e361c52dedfd50019353598d11d4441d14", [:mix], [], "hexpm"}, - "plug": {:hex, :plug, "1.7.0", "cd8c8de89bd9de55eba1c918bf0e7f319737e109b6014875104af025a623e16e", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}], "hexpm"}, + "plug": {:hex, :plug, "1.7.1", "8516d565fb84a6a8b2ca722e74e2cd25ca0fc9d64f364ec9dbec09d33eb78ccd", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}], "hexpm"}, "plug_cowboy": {:hex, :plug_cowboy, "2.0.0", "ab0c92728f2ba43c544cce85f0f220d8d30fc0c90eaa1e6203683ab039655062", [: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], []}, diff --git a/test/phoenix/template_test.exs b/test/phoenix/template_test.exs index eb52664244..d187868bea 100644 --- a/test/phoenix/template_test.exs +++ b/test/phoenix/template_test.exs @@ -45,8 +45,8 @@ defmodule Phoenix.TemplateTest do end test "format_encoder/1 returns the formatter for a given template" do - assert Template.format_encoder("hello.html") == Phoenix.Template.HTML - assert Template.format_encoder("hello.js") == Phoenix.Template.HTML + assert Template.format_encoder("hello.html") == Phoenix.HTML.Engine + assert Template.format_encoder("hello.js") == Phoenix.HTML.Engine assert Template.format_encoder("hello.unknown") == nil end From c653047a6606cc94e16c01f592c1ad6cff0fdf35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Tue, 20 Nov 2018 16:33:15 +0100 Subject: [PATCH 21/61] No longer send socket close on duplicate join --- lib/phoenix/socket.ex | 17 +++-------------- .../integration/websocket_channels_test.exs | 3 --- 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/lib/phoenix/socket.ex b/lib/phoenix/socket.ex index 305fb2c37b..c6eeb908bf 100644 --- a/lib/phoenix/socket.ex +++ b/lib/phoenix/socket.ex @@ -481,8 +481,7 @@ defmodule Phoenix.Socket do %{^pid => {topic, join_ref}} -> {^pid, monitor_ref} = Map.fetch!(state.channels, topic) state = delete_channel(state, pid, topic, monitor_ref) - {:socket_push, opcode, payload} = serialize_close(socket, topic, join_ref) - {:push, {opcode, payload}, {state, socket}} + {:push, encode_close(socket, topic, join_ref), {state, socket}} %{} -> {:ok, {state, socket}} @@ -609,16 +608,6 @@ defmodule Phoenix.Socket do end :ok = shutdown_duplicate_channel(pid) - - # We have to send a message to the client because the client - # may be expecting us to explicitly shutdown previous channels, - # even when they are duplicate. Instead, we would prefer for - # the client to automatically handle this, but that was not the - # case up to Phoenix v1.4.0. - # TODO: Remove this message on Phoenix v1.5+ - {^topic, join_ref} = Map.fetch!(state.channels_inverse, pid) - send self(), serialize_close(socket, topic, join_ref) - state = delete_channel(state, pid, topic, ref) handle_in(nil, message, state, socket) end @@ -670,9 +659,9 @@ defmodule Phoenix.Socket do {opcode, payload} end - defp serialize_close(%{serializer: serializer}, topic, join_ref) do + defp encode_close(socket, topic, join_ref) do message = %Message{join_ref: join_ref, ref: join_ref, topic: topic, event: "phx_close", payload: %{}} - serializer.encode!(message) + encode_reply(socket, message) end defp shutdown_duplicate_channel(pid) do diff --git a/test/phoenix/integration/websocket_channels_test.exs b/test/phoenix/integration/websocket_channels_test.exs index 8d969a4f72..526a495e46 100644 --- a/test/phoenix/integration/websocket_channels_test.exs +++ b/test/phoenix/integration/websocket_channels_test.exs @@ -430,9 +430,6 @@ defmodule Phoenix.Integration.WebSocketChannelsTest do WebsocketClient.join(sock, "room:joiner", %{}) assert_receive %Message{topic: "room:joiner", event: "phx_reply", ref: "2", payload: %{"response" => %{}, "status" => "ok"}} - - assert_receive %Message{topic: "room:joiner", event: "phx_close", - ref: "1", payload: %{}} end test "returns 403 when versions to not match" do From 9a9eae23d3f10f8e0d5f457b1ccde8c2839da2a1 Mon Sep 17 00:00:00 2001 From: Thomas Depierre Date: Wed, 21 Nov 2018 13:10:08 +0000 Subject: [PATCH 22/61] Make explicit the status code in case of redirect --- lib/phoenix/controller.ex | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/phoenix/controller.ex b/lib/phoenix/controller.ex index 3b244eb767..e43a7657c7 100644 --- a/lib/phoenix/controller.ex +++ b/lib/phoenix/controller.ex @@ -381,6 +381,9 @@ defmodule Phoenix.Controller do For security, `:to` only accepts paths. Use the `:external` option to redirect to any URL. + + It will use the status code defined in the conn. If no + status code is set, it sends a 302. ## Examples From e4936bf6462a2291c3776bf5e54d69b176d2ed49 Mon Sep 17 00:00:00 2001 From: Chris McCord Date: Wed, 21 Nov 2018 15:18:43 -0500 Subject: [PATCH 23/61] Bump changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 100b607c12..0f52f37089 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ ### Enhancements + * [Endpoint] Allow named params to be used when defining socket paths + ### Bug Fixes ### Deprecations From 39068a5640327397c5207f6974905e4381fca5f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20=C5=81=C4=99picki?= Date: Wed, 21 Nov 2018 21:23:24 +0100 Subject: [PATCH 24/61] Guides hyperlinks fixes (#3170) * Add missing hyperlink to socket/3 in the routing guide * Mix Tasks guides hyperlinks changes Fix links to mix tasks in the Mix Tasks guide; Add precise links to Mix Tasks guide in the Up and Running guide; * Leverage ex_doc's new mix task docs auto-linking in Up and Running and Mix Tasks guides * Revert unnecessary change in the Up and Running guide --- guides/phoenix_mix_tasks.md | 64 ++++++++++++++++++------------------- guides/routing.md | 2 +- guides/up_and_running.md | 8 ++--- 3 files changed, 37 insertions(+), 37 deletions(-) diff --git a/guides/phoenix_mix_tasks.md b/guides/phoenix_mix_tasks.md index 47b78723e1..c0171776bc 100644 --- a/guides/phoenix_mix_tasks.md +++ b/guides/phoenix_mix_tasks.md @@ -30,15 +30,15 @@ mix phx.server # Starts applications and their servers We have seen all of these at one point or another in the guides, but having all the information about them in one place seems like a good idea. And here we are. -#### `mix phx.new` +### `mix phx.new` This is how we tell Phoenix the framework to generate a new Phoenix application for us. We saw it early on in the [Up and Running Guide](up_and_running.html). Before we begin, we should note that Phoenix uses [Ecto](https://github.com/elixir-lang/ecto) for database access and [webpack](https://webpack.js.org/) for asset management by default. We can pass `--no-ecto` to opt out of Ecto and `--no-webpack` to opt out of webpack. -> Note: If we do use webpack, we need to install its dependencies before we start our application. `phx.new` will ask to do this for us. Otherwise, we can install them with `npm install`. If we don't install them, the app will throw errors and may not serve our assets properly. +> Note: If we do use webpack, we need to install its dependencies before we start our application. `mix phx.new` will ask to do this for us. Otherwise, we can install them with `npm install`. If we don't install them, the app will throw errors and may not serve our assets properly. -We need to pass `phx.new` a name for our application. Conventionally, we use all lower-case letters with underscores. +We need to pass a name for our application to `mix phx.new`. Conventionally, we use all lower-case letters with underscores. ```console $ mix phx.new task_tester @@ -64,7 +64,7 @@ $ mix phx.new /Users/me/work/task_tester . . . ``` -The `phx.new` task will also ask us if we want to install our dependencies. (Please see the note above about webpack dependencies.) +The `mix phx.new` task will also ask us if we want to install our dependencies. (Please see the note above about webpack dependencies.) ```console Fetch and install dependencies? [Yn] y @@ -72,7 +72,7 @@ Fetch and install dependencies? [Yn] y * running mix deps.get ``` -Once all of our dependencies are installed, `phx.new` will tell us what our next steps are. +Once all of our dependencies are installed, `mix phx.new` will tell us what our next steps are. ```console We are all set! Run your Phoenix application: @@ -85,7 +85,7 @@ You can also run it inside IEx (Interactive Elixir) as: $ iex -S mix phx.server ``` -By default `phx.new` will assume we want to use ecto for our contexts. If we don't want to use ecto in our application, we can use the `--no-ecto` flag. +By default `mix phx.new` will assume we want to use ecto for our contexts. If we don't want to use ecto in our application, we can use the `--no-ecto` flag. ```console $ mix phx.new task_tester --no-ecto @@ -95,7 +95,7 @@ $ mix phx.new task_tester --no-ecto With the `--no-ecto` flag, Phoenix will not make either ecto or postgrex a dependency of our application, and it will not create a `repo.ex` file. -By default, Phoenix will name our OTP application after the name we pass into `phx.new`. If we want, we can specify a different OTP application name with the `--app` flag. +By default, Phoenix will name our OTP application after the name we pass into `mix phx.new`. If we want, we can specify a different OTP application name with the `--app` flag. ```console $ mix phx.new task_tester --app hello @@ -187,11 +187,11 @@ defmodule Hello.MixProject do . . . ``` -#### [mix phx.gen.html](`Mix.Tasks.Phx.Gen.Html.run/1`) +### `mix phx.gen.html` Phoenix now offers the ability to generate all the code to stand up a complete HTML resource - ecto migration, ecto context, controller with all the necessary actions, view, and templates. This can be a tremendous timesaver. Let's take a look at how to make this happen. -The `phx.gen.html` task takes a number of arguments, the module name of the context, the module name of the schema, the resource name, and a list of column_name:type attributes. The module name we pass in must conform to the Elixir rules of module naming, following proper capitalization. +The `mix phx.gen.html` task takes a number of arguments, the module name of the context, the module name of the schema, the resource name, and a list of column_name:type attributes. The module name we pass in must conform to the Elixir rules of module naming, following proper capitalization. ```console $ mix phx.gen.html Blog Post posts body:string word_count:integer @@ -211,7 +211,7 @@ $ mix phx.gen.html Blog Post posts body:string word_count:integer * injecting test/hello/blog/blog_test.exs ``` -When `phx.gen.html` is done creating files, it helpfully tells us that we need to add a line to our router file as well as run our ecto migrations. +When `mix phx.gen.html` is done creating files, it helpfully tells us that we need to add a line to our router file as well as run our ecto migrations. ```console Add the resource to your browser scope in lib/hello_web/router.ex: @@ -301,11 +301,11 @@ warning: function HelloWeb.Router.Helpers.post_path/3 is undefined or private lib/hello_web/templates/post/edit.html.eex:3 ``` -#### [mix phx.gen.json](`Mix.Tasks.Phx.Gen.Json.run/1`) +### `mix phx.gen.json` Phoenix also offers the ability to generate all the code to stand up a complete JSON resource - ecto migration, ecto schema, controller with all the necessary actions and view. This command will not create any template for the app. -The `phx.gen.json` task takes a number of arguments, the module name of the context, the module name of the schema, the resource name, and a list of column_name:type attributes. The module name we pass in must conform to the Elixir rules of module naming, following proper capitalization. +The `mix phx.gen.json` task takes a number of arguments, the module name of the context, the module name of the schema, the resource name, and a list of column_name:type attributes. The module name we pass in must conform to the Elixir rules of module naming, following proper capitalization. ```console $ mix phx.gen.json Blog Post posts title:string content:string @@ -322,7 +322,7 @@ $ mix phx.gen.json Blog Post posts title:string content:string * injecting test/hello/blog/blog_test.exs ``` -When `phx.gen.json` is done creating files, it helpfully tells us that we need to add a line to our router file as well as run our ecto migrations. +When `mix phx.gen.json` is done creating files, it helpfully tells us that we need to add a line to our router file as well as run our ecto migrations. ```console Add the resource to your :api scope in lib/hello_web/router.ex: @@ -415,11 +415,11 @@ Compiling 18 files (.ex) (elixir) lib/kernel/parallel_compiler.ex:121: anonymous fn/4 in Kernel.ParallelCompiler.spawn_compilers/1 ``` -#### [mix phx.gen.context](`Mix.Tasks.Phx.Gen.Context.run/1`) +### `mix phx.gen.context` -If we don't need a complete HTML/JSON resource and instead are only interested in a context, we can use the `phx.gen.context` task. It will generate a context, a schema, a migration and a test case. +If we don't need a complete HTML/JSON resource and instead are only interested in a context, we can use the `mix phx.gen.context` task. It will generate a context, a schema, a migration and a test case. -The `phx.gen.context` task takes a number of arguments, the module name of the context, the module name of the schema, the resource name, and a list of column_name:type attributes. +The `mix phx.gen.context` task takes a number of arguments, the module name of the context, the module name of the schema, the resource name, and a list of column_name:type attributes. ```console $ mix phx.gen.context Accounts User users name:string age:integer @@ -442,11 +442,11 @@ $ mix phx.gen.context Accounts User users name:string age:integer * injecting test/hello/admin/accounts/accounts_test.exs ``` -#### [mix phx.gen.schema](`Mix.Tasks.Phx.Gen.Schema.run/1`) +### `mix phx.gen.schema` -If we don't need a complete HTML/JSON resource and are not interested in generating or altering a context we can use the `phx.gen.schema` task. It will generate a schema, and a migration. +If we don't need a complete HTML/JSON resource and are not interested in generating or altering a context we can use the `mix phx.gen.schema` task. It will generate a schema, and a migration. -The `phx.gen.schema` task takes a number of arguments, the module name of the schema (which may be namespaced), the resource name, and a list of column_name:type attributes. +The `mix phx.gen.schema` task takes a number of arguments, the module name of the schema (which may be namespaced), the resource name, and a list of column_name:type attributes. ```console $ mix phx.gen.schema Accounts.Credential credentials email:string:unique user_id:references:users @@ -454,7 +454,7 @@ $ mix phx.gen.schema Accounts.Credential credentials email:string:unique user_id * creating priv/repo/migrations/20170906162013_create_credentials.exs ``` -#### [mix phx.gen.channel](`Mix.Tasks.Phx.Gen.Channel.run/1`) +### `mix phx.gen.channel` This task will generate a basic Phoenix channel as well a test case for it. It takes the module name for the channel as argument: @@ -464,7 +464,7 @@ $ mix phx.gen.channel Room * creating test/hello_web/channels/room_channel_test.exs ``` -When `phx.gen.channel` is done, it helpfully tells us that we need to add a channel route to our router file. +When `mix phx.gen.channel` is done, it helpfully tells us that we need to add a channel route to our router file. ```console Add the channel to your `lib/hello_web/channels/user_socket.ex` handler, for example: @@ -472,7 +472,7 @@ Add the channel to your `lib/hello_web/channels/user_socket.ex` handler, for exa channel "rooms:lobby", HelloWeb.RoomChannel ``` -#### [mix phx.gen.presence](`Mix.Tasks.Phx.Gen.Presence.run/1`) +### `mix phx.gen.presence` This task will generate a Presence tracker. The module name can be passed as an argument, `Presence` is used if no module name is passed. @@ -482,7 +482,7 @@ $ mix phx.gen.presence Presence $ lib/hello_web/channels/presence.ex ``` -#### `mix [mix phx.routes](`Mix.Tasks.Phx.Routes.run/1`) +### `mix phx.routes` This task has a single purpose, to show us all the routes defined for a given router. We saw it used extensively in the [Routing Guide](routing.html). @@ -499,7 +499,7 @@ $ mix phx.routes TaskTesterWeb.Router page_path GET / TaskTesterWeb.PageController.index/2 ``` -#### [mix phx.server](`Mix.Tasks.Phx.Server.run/1`) +### `mix phx.server` This is the task we use to get our application running. It takes no arguments at all. If we pass any in, they will be silently ignored. @@ -524,7 +524,7 @@ Interactive Elixir (1.0.4) - press Ctrl+C to exit (type h() ENTER for help) iex(1)> ``` -#### [mix phx.digest](`Mix.Tasks.Phx.Digest.run/1`) +### `mix phx.digest` This task does two things, it creates a digest for our static assets and then compresses them. @@ -571,7 +571,7 @@ We can optionally determine which files should be gzipped by using the `:gzippab config :phoenix, :gzippable_exts, ~w(.js .css) ``` -> Note: We can specify a different output folder where `phx.digest` will put processed files. The first argument is the path where the static files are located. +> Note: We can specify a different output folder where `mix phx.digest` will put processed files. The first argument is the path where the static files are located. ```console $ mix phx.digest priv/static -o www/public Check your digested files at 'www/public'. @@ -579,7 +579,7 @@ Check your digested files at 'www/public'. ## Ecto Specific Mix Tasks -Newly generated Phoenix applications now include ecto and postgrex as dependencies by default (which is to say, unless we use the `--no-ecto` flag with `phx.new`). With those dependencies come mix tasks to take care of common ecto operations. Let's see which tasks we get out of the box. +Newly generated Phoenix applications now include ecto and postgrex as dependencies by default (which is to say, unless we use `mix phx.new` with the `--no-ecto` flag). With those dependencies come mix tasks to take care of common ecto operations. Let's see which tasks we get out of the box. ```console $ mix help | grep -i ecto @@ -593,7 +593,7 @@ mix ecto.rollback # Reverts migrations down on a repo Note: We can run any of the tasks above with the `--no-start` flag to execute the task without starting the application. -#### `ecto.create` +### `mix ecto.create` This task will create the database specified in our repo. By default it will look for the repo named after our application (the one generated with our app unless we opted out of ecto), but we can pass in another repo if we want. Here's what it looks like in action. @@ -677,7 +677,7 @@ $ mix ecto.drop -r OurCustom.Repo The database for OurCustom.Repo has been dropped. ``` -#### `ecto.gen.repo` +### `mix ecto.gen.repo` Many applications require more than one data store. For each data store, we'll need a new repo, and we can generate them automatically with `ecto.gen.repo`. @@ -724,7 +724,7 @@ children = [ . . . ``` -#### `ecto.gen.migration` +### `mix ecto.gen.migration` Migrations are a programmatic, repeatable way to affect changes to a database schema. Migrations are also just modules, and we can create them with the `ecto.gen.migration` task. Let's walk through the steps to create a migration for a new comments table. @@ -779,7 +779,7 @@ For example, to alter an existing schema see the documentation on ecto’s That's it! We're ready to run our migration. -#### `ecto.migrate` +### `mix ecto.migrate` Once we have our migration module ready, we can simply run `mix ecto.migrate` to have our changes applied to the database. @@ -837,7 +837,7 @@ The `--to` option will behave the same way. mix ecto.migrate --to 20150317170448 ``` -#### `ecto.rollback` +### `mix ecto.rollback` The `ecto.rollback` task will reverse the last migration we have run, undoing the schema changes. `ecto.migrate` and `ecto.rollback` are mirror images of each other. diff --git a/guides/routing.md b/guides/routing.md index 8ca73f3039..1dd4d2e751 100644 --- a/guides/routing.md +++ b/guides/routing.md @@ -881,7 +881,7 @@ defmodule HelloWeb.Endpoint do end ``` -By default, Phoenix supports both websockets and longpoll when invoking Phoenix.Endpoint.socket/3 in your endpoint. Here we're specifying that incoming socket connections can be made via a WebSocket connection. +By default, Phoenix supports both websockets and longpoll when invoking `Phoenix.Endpoint.socket/3` in your endpoint. Here we're specifying that incoming socket connections can be made via a WebSocket connection. Next, we need to open our `lib/hello_web/channels/user_socket.ex` file and use the `channel/3` macro to define our channel routes. The routes will match a topic pattern to a channel to handle events. If we have a channel module called `RoomChannel` and a topic called `"rooms:*"`, the code to do this is straightforward. diff --git a/guides/up_and_running.md b/guides/up_and_running.md index 82d703507a..c17f3baed3 100644 --- a/guides/up_and_running.md +++ b/guides/up_and_running.md @@ -16,9 +16,9 @@ $ mix phx.new hello > A note about [webpack](https://webpack.js.org/) before we begin: Phoenix will use webpack for asset management by default. Webpacks' dependencies are installed via the node package manager, not mix. Phoenix will prompt us to install them at the end of the `mix phx.new` task. If we say "no" at that point, and if we don't install those dependencies later with `npm install`, our application will raise errors when we try to start it, and our assets may not load properly. If we don't want to use webpack at all, we can simply pass `--no-webpack` to `mix phx.new`. -> A note about [Ecto](https://hexdocs.pm/phoenix/ecto.html): Ecto allows our Phoenix application to communicate with a data store, such as PostgreSQL or MongoDB. If our application will not require this component we can skip this dependency by passing the `--no-ecto` flag to the `mix phx.new`. This flag may also be combined with `--no-webpack` to create a skeleton application. +> A note about [Ecto](https://hexdocs.pm/phoenix/ecto.html): Ecto allows our Phoenix application to communicate with a data store, such as PostgreSQL or MongoDB. If our application will not require this component we can skip this dependency by passing the `--no-ecto` flag to `mix phx.new`. This flag may also be combined with `--no-webpack` to create a skeleton application. -> Note to learn more about `mix phx.new` read [Phoenix Mix Tasks](phoenix_mix_tasks.html). +> To learn more about `mix phx.new` you can read the [Mix Tasks Guide](phoenix_mix_tasks.html#phoenix-specific-mix-tasks). ```console mix phx.new hello @@ -59,7 +59,7 @@ You can also run your app inside IEx (Interactive Elixir) as: Once our dependencies are installed, the task will prompt us to change into our project directory and start our application. -Phoenix assumes that our PostgreSQL database will have a `postgres` user account with the correct permissions and a password of "postgres". If that isn't the case, please see the instructions for the [ecto.create](phoenix_mix_tasks.html#ecto-specific-mix-tasks) mix task. +Phoenix assumes that our PostgreSQL database will have a `postgres` user account with the correct permissions and a password of "postgres". If that isn't the case, please see the [`Mix Tasks Guide`](phoenix_mix_tasks.html#ecto-specific-mix-tasks) to learn more about the `mix ecto.create` task. Ok, let's give it a try. First, we'll `cd` into the `hello/` directory we've just created: @@ -86,7 +86,7 @@ Webpack is watching the files… ... ``` -If we choose not to have Phoenix install our dependencies when we generate a new application, the `phx.new` task will prompt us to take the necessary steps when we do want to install them. +If we choose not to have Phoenix install our dependencies when we generate a new application, the `mix phx.new` task will prompt us to take the necessary steps when we do want to install them. ```console Fetch and install dependencies? [Yn] n From f9fd21d634452d11cde72251b593156da877bef4 Mon Sep 17 00:00:00 2001 From: Chris McCord Date: Wed, 21 Nov 2018 15:33:09 -0500 Subject: [PATCH 25/61] Touch up docs --- lib/phoenix/controller.ex | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/phoenix/controller.ex b/lib/phoenix/controller.ex index e43a7657c7..56646347a7 100644 --- a/lib/phoenix/controller.ex +++ b/lib/phoenix/controller.ex @@ -381,9 +381,10 @@ defmodule Phoenix.Controller do For security, `:to` only accepts paths. Use the `:external` option to redirect to any URL. - - It will use the status code defined in the conn. If no - status code is set, it sends a 302. + + The response will be sent with the status code defined within + the connection, via `Plug.Conn.put_status/2`. If no status + code is set, a 302 response is sent. ## Examples From fa3cceccd9a6b65bec666157e665a6dd6e14fe31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Wed, 21 Nov 2018 15:42:03 +0100 Subject: [PATCH 26/61] Support to_iodata on render outcome --- mix.lock | 2 +- test/fixtures/views.exs | 4 ++++ test/phoenix/template_test.exs | 8 ++++---- test/phoenix/view_test.exs | 29 ++++++++++++++++++++--------- 4 files changed, 29 insertions(+), 14 deletions(-) diff --git a/mix.lock b/mix.lock index bead5b3414..68f107aad1 100644 --- a/mix.lock +++ b/mix.lock @@ -10,7 +10,7 @@ "makeup_elixir": {:hex, :makeup_elixir, "0.8.0", "1204a2f5b4f181775a0e456154830524cf2207cf4f9112215c05e0b76e4eca8b", [:mix], [{:makeup, "~> 0.5.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 0.2.2", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm"}, "mime": {:hex, :mime, "1.3.0", "5e8d45a39e95c650900d03f897fbf99ae04f60ab1daa4a34c7a20a5151b7a5fe", [:mix], [], "hexpm"}, "nimble_parsec": {:hex, :nimble_parsec, "0.2.2", "d526b23bdceb04c7ad15b33c57c4526bf5f50aaa70c7c141b4b4624555c68259", [:mix], [], "hexpm"}, - "phoenix_html": {:git, "https://github.com/phoenixframework/phoenix_html.git", "e663256cd57256f2921be808e553180fba96423f", []}, + "phoenix_html": {:git, "https://github.com/phoenixframework/phoenix_html.git", "53326e81b23ad38544dd39d9e7fdc9c6fc5da451", []}, "phoenix_pubsub": {:hex, :phoenix_pubsub, "1.1.0", "d55e25ff1ff8ea2f9964638366dfd6e361c52dedfd50019353598d11d4441d14", [:mix], [], "hexpm"}, "plug": {:hex, :plug, "1.7.1", "8516d565fb84a6a8b2ca722e74e2cd25ca0fc9d64f364ec9dbec09d33eb78ccd", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}], "hexpm"}, "plug_cowboy": {:hex, :plug_cowboy, "2.0.0", "ab0c92728f2ba43c544cce85f0f220d8d30fc0c90eaa1e6203683ab039655062", [:mix], [{:cowboy, "~> 2.5", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, diff --git a/test/fixtures/views.exs b/test/fixtures/views.exs index e55d4a6197..f5143c630a 100644 --- a/test/fixtures/views.exs +++ b/test/fixtures/views.exs @@ -56,6 +56,10 @@ defmodule MyApp.UserView do def render("render_template.html" = tpl, %{name: name}) do render_template(tpl, %{name: String.upcase(name)}) end + + def render("to_iodata.html", %{to_iodata: to_iodata}) do + to_iodata + end end defmodule MyApp.Templates.UserView do diff --git a/test/phoenix/template_test.exs b/test/phoenix/template_test.exs index d187868bea..7d8ca8d27f 100644 --- a/test/phoenix/template_test.exs +++ b/test/phoenix/template_test.exs @@ -62,20 +62,20 @@ defmodule Phoenix.TemplateTest do test "render eex templates sanitizes against xss by default" do assert View.render("show.html", %{message: ""}) == - {:safe, [[["" | "
Show! "]] | "
\n"]} + {:safe, ["
Show! ", [], "
\n"]} assert View.render("show.html", %{message: ""}) == - {:safe, [[["" | "
Show! "], [[[[[[] | "<"], "script" | ">"], "alert(" | "'"], "xss" | "'"], ");" | "<"], "/script" | ">"] | "
\n"]} + {:safe, ["
Show! ", [[[[[[[] | "<"], "script" | ">"], "alert(" | "'"], "xss" | "'"], ");" | "<"], "/script" | ">"], "
\n"]} end test "render eex templates allows raw data to be injected" do assert View.render("safe.html", %{message: ""}) == - {:safe, [[["" | "Raw "] | ""] | "\n"]} + {:safe, ["Raw ", "", "\n"]} end test "compiles templates from path" do assert View.render("show.html", %{message: "hello!"}) == - {:safe, [[["" | "
Show! "] | "hello!"] | "
\n"]} + {:safe, ["
Show! ", "hello!", "
\n"]} end test "adds catch-all render_template/2 that raises UndefinedError" do diff --git a/test/phoenix/view_test.exs b/test/phoenix/view_test.exs index 66ba16fc4d..51bf7a7fad 100644 --- a/test/phoenix/view_test.exs +++ b/test/phoenix/view_test.exs @@ -16,7 +16,7 @@ defmodule Phoenix.ViewTest do test "renders views defined on root" do assert render(MyApp.View, "show.html", message: "Hello world") == - {:safe, [[["" | "
Show! "] | "Hello world"] | "
\n"]} + {:safe, ["
Show! ", "Hello world", "
\n"]} end test "renders views without assigns" do @@ -38,7 +38,7 @@ defmodule Phoenix.ViewTest do test "renders subviews with helpers" do assert render(MyApp.UserView, "index.html", title: "Hello world") == - {:safe, ["" | "Hello world"]} + {:safe, ["Hello world"]} assert render(MyApp.UserView, "show.json", []) == %{foo: "bar"} @@ -60,8 +60,7 @@ defmodule Phoenix.ViewTest do ) assert html == - {:safe, [[[[["" | "\n "] | "Test"] | "\n"], - [["" | "
Show! "] | "Hello world"] | "
\n"] | "\n"]} + {:safe, ["\n ", "Test", "\n", ["
Show! ", "Hello world", "
\n"], "\n"]} end test "validates explicitly passed layout" do @@ -81,12 +80,12 @@ defmodule Phoenix.ViewTest do ) assert html == - [[[[["" | "\n "] | "Test"] | "\n"] | "EDIT - Test"] | "\n"] + ["\n ", "Test", "\n", "EDIT - Test", "\n"] end test "renders views to iodata/string using encoders" do assert render_to_iodata(MyApp.UserView, "index.html", title: "Hello world") == - ["" | "Hello world"] + ["Hello world"] assert render_to_iodata(MyApp.UserView, "show.json", []) == ["{\"", [[], "foo"], "\":", [34, [], "bar", 34], 125] @@ -96,6 +95,9 @@ defmodule Phoenix.ViewTest do assert render_to_string(MyApp.UserView, "show.json", []) == "{\"foo\":\"bar\"}" + + assert render_to_string(MyApp.UserView, "to_iodata.html", to_iodata: 123) == + "123" end test "renders views with layouts to iodata/string using encoders" do @@ -106,8 +108,7 @@ defmodule Phoenix.ViewTest do ) assert html == - [[[[["" | "\n "] | "Test"] | "\n"], - [["" | "
Show! "] | "Hello world"] | "
\n"] | "\n"] + ["\n ", "Test", "\n", ["
Show! ", "Hello world", "
\n"], "\n"] html = render_to_string(MyApp.View, "show.html", title: "Test", @@ -117,6 +118,16 @@ defmodule Phoenix.ViewTest do assert html == "\n Test\n
Show! Hello world
\n\n" + + html = render_to_string(MyApp.UserView, "to_iodata.html", + title: "Test", + message: "Hello world", + to_iodata: 123, + layout: {MyApp.LayoutView, "app.html"} + ) + + assert html == + "\n Test\n123\n" end ## render_many @@ -163,7 +174,7 @@ defmodule Phoenix.ViewTest do test "renders_existing/3 renders template if it exists" do assert render_existing(MyApp.UserView, "index.html", title: "Test") == - {:safe, ["" | "Test"]} + {:safe, ["Test"]} end test "renders_existing/3 returns nil if template does not exist" do From 332a89edda1ad801434d55efc53a287fa4da6236 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Thu, 22 Nov 2018 20:56:22 +0100 Subject: [PATCH 27/61] Bump version to v1.5.0-dev --- lib/phoenix/socket.ex | 3 --- mix.exs | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/phoenix/socket.ex b/lib/phoenix/socket.ex index c6eeb908bf..fae93c2687 100644 --- a/lib/phoenix/socket.ex +++ b/lib/phoenix/socket.ex @@ -360,9 +360,6 @@ defmodule Phoenix.Socket do end defp tear_alias(other), do: other - # TODO: Remove the transport/3 implementation on v1.5 - # but we should keep the warning for backwards compatibility. - @doc false defmacro transport(_name, _module, _config \\ []) do quote do diff --git a/mix.exs b/mix.exs index 0116e3a5d4..ec066395d3 100644 --- a/mix.exs +++ b/mix.exs @@ -1,7 +1,7 @@ defmodule Phoenix.MixProject do use Mix.Project - @version "1.4.0" + @version "1.5.0-dev" def project do [ From e34c8b6e3bc3a57191097d723c5c9795c5118bf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Thu, 22 Nov 2018 21:22:39 +0100 Subject: [PATCH 28/61] Streamline JSON warnings --- lib/phoenix.ex | 51 +++++++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/lib/phoenix.ex b/lib/phoenix.ex index f73b6fad6c..8269c2d50c 100644 --- a/lib/phoenix.ex +++ b/lib/phoenix.ex @@ -71,44 +71,49 @@ defmodule Phoenix do Application.get_env(:phoenix, :json_library, Poison) end - @doc false - # Returns the `:init_mode` to pass to `Plug.Builder.compile/3`. + @doc """ + Returns the `:plug_init_mode` that controls when plugs are + initialized. + + We recommend to set it to `:runtime` in development for + compilation time improvements. It must be `:compile` in + production (the default). + + This option is passed as the `:init_mode` to `Plug.Builder.compile/3`. + """ def plug_init_mode do Application.get_env(:phoenix, :plug_init_mode, :compile) end defp warn_on_missing_json_library do configured_lib = Application.get_env(:phoenix, :json_library) - default_lib = json_library() cond do + configured_lib && Code.ensure_loaded?(configured_lib) -> + true + configured_lib && not Code.ensure_loaded?(configured_lib) -> - warn_json configured_lib, """ + IO.warn """ found #{inspect(configured_lib)} in your application configuration - for Phoenix JSON encoding, but failed to load the library. + for Phoenix JSON encoding, but module #{inspect(configured_lib)} is not available. + Ensure #{inspect(configured_lib)} is listed as a dependency in mix.exs. """ - not Code.ensure_loaded?(default_lib) and Code.ensure_loaded?(Jason) -> - warn_json(Jason) + true -> + IO.warn """ + Phoenix now requires you to explicitly list which engine to use + for Phoenix JSON encoding. We recommend everyone to upgrade to + Jason by setting in your config/config.exs: - not Code.ensure_loaded?(default_lib) -> - warn_json(default_lib) + config :phoenix, :json_encoding, Jason - true -> :ok - end - end - - defp warn_json(lib, preabmle \\ nil) do - IO.warn """ - #{preabmle || "failed to load #{inspect(lib)} for Phoenix JSON encoding"} - (module #{inspect(lib)} is not available). + And then adding {:jason, "~> 1.0"} as a dependency. - Ensure #{inspect(lib)} exists in your deps in mix.exs, - and you have configured Phoenix to use it for JSON encoding by - verifying the following exists in your config/config.exs: + If instead you would rather continue using Poison, then add to + your config/config.exs: - config :phoenix, :json_library, #{inspect(lib)} - - """ + config :phoenix, :json_encoding, Poison + """ + end end end From b22fde432862c0c1e161477ec2548efdce4ed136 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Fri, 23 Nov 2018 14:10:41 +0100 Subject: [PATCH 29/61] No need to publish assets to hex.pm --- mix.exs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mix.exs b/mix.exs index ec066395d3..b2a7fae1b5 100644 --- a/mix.exs +++ b/mix.exs @@ -80,8 +80,7 @@ defmodule Phoenix.MixProject do ], licenses: ["MIT"], links: %{github: "https://github.com/phoenixframework/phoenix"}, - files: ~w(assets lib priv) ++ - ~w(CHANGELOG.md LICENSE.md mix.exs package.json README.md .formatter.exs) + files: ~w(lib priv CHANGELOG.md LICENSE.md mix.exs package.json README.md .formatter.exs) ] end From 1ab6891e50ba6e7cdc4ac36216c61b40c5c6ae67 Mon Sep 17 00:00:00 2001 From: Chris McCord Date: Fri, 23 Nov 2018 08:14:40 -0500 Subject: [PATCH 30/61] Use global reference compatible with webworkers. Closes #3168 --- assets/js/phoenix.js | 4 +++- assets/webpack.config.js | 3 ++- priv/static/phoenix.js | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/assets/js/phoenix.js b/assets/js/phoenix.js index 78149265a9..235c35dd12 100644 --- a/assets/js/phoenix.js +++ b/assets/js/phoenix.js @@ -185,7 +185,9 @@ * @module phoenix */ -const global = typeof self !== "undefined" ? self : window +const globalSelf = typeof self !== "undefined" ? self : null +const globalWindow = typeof window !== "undefined" ? window : null +const global = globalSelf || globalWindow || this const VSN = "2.0.0" const SOCKET_STATES = {connecting: 0, open: 1, closing: 2, closed: 3} const DEFAULT_TIMEOUT = 10000 diff --git a/assets/webpack.config.js b/assets/webpack.config.js index fe09b4507f..df9ac37b10 100644 --- a/assets/webpack.config.js +++ b/assets/webpack.config.js @@ -6,7 +6,8 @@ module.exports = { filename: 'phoenix.js', path: path.resolve(__dirname, '../priv/static'), library: 'Phoenix', - libraryTarget: 'umd' + libraryTarget: 'umd', + globalObject: 'this' }, module: { rules: [ diff --git a/priv/static/phoenix.js b/priv/static/phoenix.js index f5f9b2a08b..ce4bdf1087 100644 --- a/priv/static/phoenix.js +++ b/priv/static/phoenix.js @@ -1 +1 @@ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.Phoenix=t():e.Phoenix=t()}(window,function(){return function(e){var t={};function n(i){if(t[i])return t[i].exports;var o=t[i]={i:i,l:!1,exports:{}};return e[i].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,i){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:i})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var i=Object.create(null);if(n.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(i,o,function(t){return e[t]}.bind(null,o));return i},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=0)}([function(e,t,n){(function(t){e.exports=t.Phoenix=n(2)}).call(this,n(1))},function(e,t){var n;n=function(){return this}();try{n=n||Function("return this")()||(0,eval)("this")}catch(e){"object"==typeof window&&(n=window)}e.exports=n},function(e,t,n){"use strict";function i(e){return function(e){if(Array.isArray(e)){for(var t=0,n=new Array(e.length);t0&&void 0!==arguments[0]?arguments[0]:this.timeout;if(this.joinedOnce)throw"tried to join multiple times. 'join' can only be called a single time per channel instance";return this.joinedOnce=!0,this.rejoin(e),this.joinPush}},{key:"onClose",value:function(e){this.on(p.close,e)}},{key:"onError",value:function(e){return this.on(p.error,function(t){return e(t)})}},{key:"on",value:function(e,t){var n=this.bindingRef++;return this.bindings.push({event:e,ref:n,callback:t}),n}},{key:"off",value:function(e,t){this.bindings=this.bindings.filter(function(n){return!(n.event===e&&(void 0===t||t===n.ref))})}},{key:"canPush",value:function(){return this.socket.isConnected()&&this.isJoined()}},{key:"push",value:function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:this.timeout;if(!this.joinedOnce)throw"tried to push '".concat(e,"' to '").concat(this.topic,"' before joining. Use channel.join() before pushing events");var i=new m(this,e,function(){return t},n);return this.canPush()?i.send():(i.startTimeout(),this.pushBuffer.push(i)),i}},{key:"leave",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.timeout;this.state=f.leaving;var n=function(){e.socket.hasLogger()&&e.socket.log("channel","leave ".concat(e.topic)),e.trigger(p.close,"leave")},i=new m(this,p.leave,y({}),t);return i.receive("ok",function(){return n()}).receive("timeout",function(){return n()}),i.send(),this.canPush()||i.trigger("ok",{}),i}},{key:"onMessage",value:function(e,t,n){return t}},{key:"isLifecycleEvent",value:function(e){return d.indexOf(e)>=0}},{key:"isMember",value:function(e,t,n,i){return this.topic===e&&(!i||i===this.joinRef()||!this.isLifecycleEvent(t)||(this.socket.hasLogger()&&this.socket.log("channel","dropping outdated message",{topic:e,event:t,payload:n,joinRef:i}),!1))}},{key:"joinRef",value:function(){return this.joinPush.ref}},{key:"sendJoin",value:function(e){this.state=f.joining,this.joinPush.resend(e)}},{key:"rejoin",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.timeout;this.isLeaving()||this.sendJoin(e)}},{key:"trigger",value:function(e,t,n,i){var o=this.onMessage(e,t,n,i);if(t&&!o)throw"channel onMessage callbacks must return the payload, modified or unmodified";for(var r=0;r1&&void 0!==arguments[1]?arguments[1]:{};s(this,e),this.stateChangeCallbacks={open:[],close:[],error:[],message:[]},this.channels=[],this.sendBuffer=[],this.ref=0,this.timeout=i.timeout||l,this.transport=i.transport||u.WebSocket||j,this.defaultEncoder=k.encode,this.defaultDecoder=k.decode,this.transport!==j?(this.encode=i.encode||this.defaultEncoder,this.decode=i.decode||this.defaultDecoder):(this.encode=this.defaultEncoder,this.decode=this.defaultDecoder),this.heartbeatIntervalMs=i.heartbeatIntervalMs||3e4,this.reconnectAfterMs=i.reconnectAfterMs||function(e){return[1e3,2e3,5e3,1e4][e-1]||1e4},this.logger=i.logger||null,this.longpollerTimeout=i.longpollerTimeout||2e4,this.params=y(i.params||{}),this.endPoint="".concat(t,"/").concat(v.websocket),this.heartbeatTimer=null,this.pendingHeartbeatRef=null,this.reconnectTimer=new C(function(){n.teardown(function(){return n.connect()})},this.reconnectAfterMs)}return c(e,[{key:"protocol",value:function(){return location.protocol.match(/^https/)?"wss":"ws"}},{key:"endPointURL",value:function(){var e=R.appendParams(R.appendParams(this.endPoint,this.params()),{vsn:"2.0.0"});return"/"!==e.charAt(0)?e:"/"===e.charAt(1)?"".concat(this.protocol(),":").concat(e):"".concat(this.protocol(),"://").concat(location.host).concat(e)}},{key:"disconnect",value:function(e,t,n){this.reconnectTimer.reset(),this.teardown(e,t,n)}},{key:"connect",value:function(e){var t=this;e&&(console&&console.log("passing params to connect is deprecated. Instead pass :params to the Socket constructor"),this.params=y(e)),this.conn||(this.conn=new this.transport(this.endPointURL()),this.conn.timeout=this.longpollerTimeout,this.conn.onopen=function(){return t.onConnOpen()},this.conn.onerror=function(e){return t.onConnError(e)},this.conn.onmessage=function(e){return t.onConnMessage(e)},this.conn.onclose=function(e){return t.onConnClose(e)})}},{key:"log",value:function(e,t,n){this.logger(e,t,n)}},{key:"hasLogger",value:function(){return null!==this.logger}},{key:"onOpen",value:function(e){this.stateChangeCallbacks.open.push(e)}},{key:"onClose",value:function(e){this.stateChangeCallbacks.close.push(e)}},{key:"onError",value:function(e){this.stateChangeCallbacks.error.push(e)}},{key:"onMessage",value:function(e){this.stateChangeCallbacks.message.push(e)}},{key:"onConnOpen",value:function(){this.hasLogger()&&this.log("transport","connected to ".concat(this.endPointURL())),this.flushSendBuffer(),this.reconnectTimer.reset(),this.resetHeartbeat(),this.resetChannelTimers(),this.stateChangeCallbacks.open.forEach(function(e){return e()})}},{key:"resetHeartbeat",value:function(){var e=this;this.conn.skipHeartbeat||(this.pendingHeartbeatRef=null,clearInterval(this.heartbeatTimer),this.heartbeatTimer=setInterval(function(){return e.sendHeartbeat()},this.heartbeatIntervalMs))}},{key:"teardown",value:function(e,t,n){this.conn&&(this.conn.onclose=function(){},t?this.conn.close(t,n||""):this.conn.close(),this.conn=null),e&&e()}},{key:"onConnClose",value:function(e){this.hasLogger()&&this.log("transport","close",e),this.triggerChanError(),clearInterval(this.heartbeatTimer),e&&1e3!==e.code&&this.reconnectTimer.scheduleTimeout(),this.stateChangeCallbacks.close.forEach(function(t){return t(e)})}},{key:"onConnError",value:function(e){this.hasLogger()&&this.log("transport",e),this.triggerChanError(),this.stateChangeCallbacks.error.forEach(function(t){return t(e)})}},{key:"triggerChanError",value:function(){this.channels.forEach(function(e){return e.trigger(p.error)})}},{key:"connectionState",value:function(){switch(this.conn&&this.conn.readyState){case h.connecting:return"connecting";case h.open:return"open";case h.closing:return"closing";default:return"closed"}}},{key:"isConnected",value:function(){return"open"===this.connectionState()}},{key:"remove",value:function(e){this.channels=this.channels.filter(function(t){return t.joinRef()!==e.joinRef()})}},{key:"channel",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=new g(e,t,this);return this.channels.push(n),n}},{key:"push",value:function(e){var t=this;if(this.hasLogger()){var n=e.topic,i=e.event,o=e.payload,r=e.ref,s=e.join_ref;this.log("push","".concat(n," ").concat(i," (").concat(s,", ").concat(r,")"),o)}this.isConnected()?this.encode(e,function(e){return t.conn.send(e)}):this.sendBuffer.push(function(){return t.encode(e,function(e){return t.conn.send(e)})})}},{key:"makeRef",value:function(){var e=this.ref+1;return e===this.ref?this.ref=0:this.ref=e,this.ref.toString()}},{key:"sendHeartbeat",value:function(){if(this.isConnected()){if(this.pendingHeartbeatRef)return this.pendingHeartbeatRef=null,this.hasLogger()&&this.log("transport","heartbeat timeout. Attempting to re-establish connection"),void this.conn.close(1e3,"hearbeat timeout");this.pendingHeartbeatRef=this.makeRef(),this.push({topic:"phoenix",event:"heartbeat",payload:{},ref:this.pendingHeartbeatRef})}}},{key:"flushSendBuffer",value:function(){this.isConnected()&&this.sendBuffer.length>0&&(this.sendBuffer.forEach(function(e){return e()}),this.sendBuffer=[])}},{key:"onConnMessage",value:function(e){var t=this;this.decode(e.data,function(e){var n=e.topic,i=e.event,o=e.payload,r=e.ref,s=e.join_ref;r&&r===t.pendingHeartbeatRef&&(t.pendingHeartbeatRef=null),t.hasLogger()&&t.log("receive","".concat(o.status||""," ").concat(n," ").concat(i," ").concat(r&&"("+r+")"||""),o);for(var a=0;a1&&void 0!==arguments[1]?arguments[1]:{};s(this,e);var o=i.events||{state:"presence_state",diff:"presence_diff"};this.state={},this.pendingDiffs=[],this.channel=t,this.joinRef=null,this.caller={onJoin:function(){},onLeave:function(){},onSync:function(){}},this.channel.on(o.state,function(t){var i=n.caller,o=i.onJoin,r=i.onLeave,s=i.onSync;n.joinRef=n.channel.joinRef(),n.state=e.syncState(n.state,t,o,r),n.pendingDiffs.forEach(function(t){n.state=e.syncDiff(n.state,t,o,r)}),n.pendingDiffs=[],s()}),this.channel.on(o.diff,function(t){var i=n.caller,o=i.onJoin,r=i.onLeave,s=i.onSync;n.inPendingSyncState()?n.pendingDiffs.push(t):(n.state=e.syncDiff(n.state,t,o,r),s())})}return c(e,[{key:"onJoin",value:function(e){this.caller.onJoin=e}},{key:"onLeave",value:function(e){this.caller.onLeave=e}},{key:"onSync",value:function(e){this.caller.onSync=e}},{key:"list",value:function(t){return e.list(this.state,t)}},{key:"inPendingSyncState",value:function(){return!this.joinRef||this.joinRef!==this.channel.joinRef()}}],[{key:"syncState",value:function(e,t,n,i){var o=this,r=this.clone(e),s={},a={};return this.map(r,function(e,n){t[e]||(a[e]=n)}),this.map(t,function(e,t){var n=r[e];if(n){var i=t.metas.map(function(e){return e.phx_ref}),c=n.metas.map(function(e){return e.phx_ref}),u=t.metas.filter(function(e){return c.indexOf(e.phx_ref)<0}),h=n.metas.filter(function(e){return i.indexOf(e.phx_ref)<0});u.length>0&&(s[e]=t,s[e].metas=u),h.length>0&&(a[e]=o.clone(n),a[e].metas=h)}else s[e]=t}),this.syncDiff(r,{joins:s,leaves:a},n,i)}},{key:"syncDiff",value:function(e,t,n,o){var r=t.joins,s=t.leaves,a=this.clone(e);return n||(n=function(){}),o||(o=function(){}),this.map(r,function(e,t){var o=a[e];if(a[e]=t,o){var r,s=a[e].metas.map(function(e){return e.phx_ref}),c=o.metas.filter(function(e){return s.indexOf(e.phx_ref)<0});(r=a[e].metas).unshift.apply(r,i(c))}n(e,o,t)}),this.map(s,function(e,t){var n=a[e];if(n){var i=t.metas.map(function(e){return e.phx_ref});n.metas=n.metas.filter(function(e){return i.indexOf(e.phx_ref)<0}),o(e,n,t),0===n.metas.length&&delete a[e]}}),a}},{key:"list",value:function(e,t){return t||(t=function(e,t){return t}),this.map(e,function(e,n){return t(e,n)})}},{key:"map",value:function(e,t){return Object.getOwnPropertyNames(e).map(function(n){return t(n,e[n])})}},{key:"clone",value:function(e){return JSON.parse(JSON.stringify(e))}}]),e}(),C=function(){function e(t,n){s(this,e),this.callback=t,this.timerCalc=n,this.timer=null,this.tries=0}return c(e,[{key:"reset",value:function(){this.tries=0,this.clearTimer()}},{key:"restart",value:function(){var e=null!==this.timer;this.reset(),e&&this.scheduleTimeout()}},{key:"scheduleTimeout",value:function(){var e=this;this.clearTimer(),this.timer=setTimeout(function(){e.tries=e.tries+1,e.callback()},this.timerCalc(this.tries+1))}},{key:"clearTimer",value:function(){clearTimeout(this.timer),this.timer=null}}]),e}()}])}); \ No newline at end of file +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.Phoenix=t():e.Phoenix=t()}(this,function(){return function(e){var t={};function n(i){if(t[i])return t[i].exports;var o=t[i]={i:i,l:!1,exports:{}};return e[i].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,i){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:i})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var i=Object.create(null);if(n.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(i,o,function(t){return e[t]}.bind(null,o));return i},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=0)}([function(e,t,n){(function(t){e.exports=t.Phoenix=n(2)}).call(this,n(1))},function(e,t){var n;n=function(){return this}();try{n=n||Function("return this")()||(0,eval)("this")}catch(e){"object"==typeof window&&(n=window)}e.exports=n},function(e,t,n){"use strict";function i(e){return function(e){if(Array.isArray(e)){for(var t=0,n=new Array(e.length);t0&&void 0!==arguments[0]?arguments[0]:this.timeout;if(this.joinedOnce)throw"tried to join multiple times. 'join' can only be called a single time per channel instance";return this.joinedOnce=!0,this.rejoin(e),this.joinPush}},{key:"onClose",value:function(e){this.on(v.close,e)}},{key:"onError",value:function(e){return this.on(v.error,function(t){return e(t)})}},{key:"on",value:function(e,t){var n=this.bindingRef++;return this.bindings.push({event:e,ref:n,callback:t}),n}},{key:"off",value:function(e,t){this.bindings=this.bindings.filter(function(n){return!(n.event===e&&(void 0===t||t===n.ref))})}},{key:"canPush",value:function(){return this.socket.isConnected()&&this.isJoined()}},{key:"push",value:function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:this.timeout;if(!this.joinedOnce)throw"tried to push '".concat(e,"' to '").concat(this.topic,"' before joining. Use channel.join() before pushing events");var i=new k(this,e,function(){return t},n);return this.canPush()?i.send():(i.startTimeout(),this.pushBuffer.push(i)),i}},{key:"leave",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.timeout;this.state=d.leaving;var n=function(){e.socket.hasLogger()&&e.socket.log("channel","leave ".concat(e.topic)),e.trigger(v.close,"leave")},i=new k(this,v.leave,g({}),t);return i.receive("ok",function(){return n()}).receive("timeout",function(){return n()}),i.send(),this.canPush()||i.trigger("ok",{}),i}},{key:"onMessage",value:function(e,t,n){return t}},{key:"isLifecycleEvent",value:function(e){return y.indexOf(e)>=0}},{key:"isMember",value:function(e,t,n,i){return this.topic===e&&(!i||i===this.joinRef()||!this.isLifecycleEvent(t)||(this.socket.hasLogger()&&this.socket.log("channel","dropping outdated message",{topic:e,event:t,payload:n,joinRef:i}),!1))}},{key:"joinRef",value:function(){return this.joinPush.ref}},{key:"sendJoin",value:function(e){this.state=d.joining,this.joinPush.resend(e)}},{key:"rejoin",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.timeout;this.isLeaving()||this.sendJoin(e)}},{key:"trigger",value:function(e,t,n,i){var o=this.onMessage(e,t,n,i);if(t&&!o)throw"channel onMessage callbacks must return the payload, modified or unmodified";for(var r=0;r1&&void 0!==arguments[1]?arguments[1]:{};s(this,e),this.stateChangeCallbacks={open:[],close:[],error:[],message:[]},this.channels=[],this.sendBuffer=[],this.ref=0,this.timeout=i.timeout||p,this.transport=i.transport||l.WebSocket||T,this.defaultEncoder=j.encode,this.defaultDecoder=j.decode,this.transport!==T?(this.encode=i.encode||this.defaultEncoder,this.decode=i.decode||this.defaultDecoder):(this.encode=this.defaultEncoder,this.decode=this.defaultDecoder),this.heartbeatIntervalMs=i.heartbeatIntervalMs||3e4,this.reconnectAfterMs=i.reconnectAfterMs||function(e){return[1e3,2e3,5e3,1e4][e-1]||1e4},this.logger=i.logger||null,this.longpollerTimeout=i.longpollerTimeout||2e4,this.params=g(i.params||{}),this.endPoint="".concat(t,"/").concat(m.websocket),this.heartbeatTimer=null,this.pendingHeartbeatRef=null,this.reconnectTimer=new w(function(){n.teardown(function(){return n.connect()})},this.reconnectAfterMs)}return c(e,[{key:"protocol",value:function(){return location.protocol.match(/^https/)?"wss":"ws"}},{key:"endPointURL",value:function(){var e=C.appendParams(C.appendParams(this.endPoint,this.params()),{vsn:"2.0.0"});return"/"!==e.charAt(0)?e:"/"===e.charAt(1)?"".concat(this.protocol(),":").concat(e):"".concat(this.protocol(),"://").concat(location.host).concat(e)}},{key:"disconnect",value:function(e,t,n){this.reconnectTimer.reset(),this.teardown(e,t,n)}},{key:"connect",value:function(e){var t=this;e&&(console&&console.log("passing params to connect is deprecated. Instead pass :params to the Socket constructor"),this.params=g(e)),this.conn||(this.conn=new this.transport(this.endPointURL()),this.conn.timeout=this.longpollerTimeout,this.conn.onopen=function(){return t.onConnOpen()},this.conn.onerror=function(e){return t.onConnError(e)},this.conn.onmessage=function(e){return t.onConnMessage(e)},this.conn.onclose=function(e){return t.onConnClose(e)})}},{key:"log",value:function(e,t,n){this.logger(e,t,n)}},{key:"hasLogger",value:function(){return null!==this.logger}},{key:"onOpen",value:function(e){this.stateChangeCallbacks.open.push(e)}},{key:"onClose",value:function(e){this.stateChangeCallbacks.close.push(e)}},{key:"onError",value:function(e){this.stateChangeCallbacks.error.push(e)}},{key:"onMessage",value:function(e){this.stateChangeCallbacks.message.push(e)}},{key:"onConnOpen",value:function(){this.hasLogger()&&this.log("transport","connected to ".concat(this.endPointURL())),this.flushSendBuffer(),this.reconnectTimer.reset(),this.resetHeartbeat(),this.resetChannelTimers(),this.stateChangeCallbacks.open.forEach(function(e){return e()})}},{key:"resetHeartbeat",value:function(){var e=this;this.conn.skipHeartbeat||(this.pendingHeartbeatRef=null,clearInterval(this.heartbeatTimer),this.heartbeatTimer=setInterval(function(){return e.sendHeartbeat()},this.heartbeatIntervalMs))}},{key:"teardown",value:function(e,t,n){this.conn&&(this.conn.onclose=function(){},t?this.conn.close(t,n||""):this.conn.close(),this.conn=null),e&&e()}},{key:"onConnClose",value:function(e){this.hasLogger()&&this.log("transport","close",e),this.triggerChanError(),clearInterval(this.heartbeatTimer),e&&1e3!==e.code&&this.reconnectTimer.scheduleTimeout(),this.stateChangeCallbacks.close.forEach(function(t){return t(e)})}},{key:"onConnError",value:function(e){this.hasLogger()&&this.log("transport",e),this.triggerChanError(),this.stateChangeCallbacks.error.forEach(function(t){return t(e)})}},{key:"triggerChanError",value:function(){this.channels.forEach(function(e){return e.trigger(v.error)})}},{key:"connectionState",value:function(){switch(this.conn&&this.conn.readyState){case f.connecting:return"connecting";case f.open:return"open";case f.closing:return"closing";default:return"closed"}}},{key:"isConnected",value:function(){return"open"===this.connectionState()}},{key:"remove",value:function(e){this.channels=this.channels.filter(function(t){return t.joinRef()!==e.joinRef()})}},{key:"channel",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=new b(e,t,this);return this.channels.push(n),n}},{key:"push",value:function(e){var t=this;if(this.hasLogger()){var n=e.topic,i=e.event,o=e.payload,r=e.ref,s=e.join_ref;this.log("push","".concat(n," ").concat(i," (").concat(s,", ").concat(r,")"),o)}this.isConnected()?this.encode(e,function(e){return t.conn.send(e)}):this.sendBuffer.push(function(){return t.encode(e,function(e){return t.conn.send(e)})})}},{key:"makeRef",value:function(){var e=this.ref+1;return e===this.ref?this.ref=0:this.ref=e,this.ref.toString()}},{key:"sendHeartbeat",value:function(){if(this.isConnected()){if(this.pendingHeartbeatRef)return this.pendingHeartbeatRef=null,this.hasLogger()&&this.log("transport","heartbeat timeout. Attempting to re-establish connection"),void this.conn.close(1e3,"hearbeat timeout");this.pendingHeartbeatRef=this.makeRef(),this.push({topic:"phoenix",event:"heartbeat",payload:{},ref:this.pendingHeartbeatRef})}}},{key:"flushSendBuffer",value:function(){this.isConnected()&&this.sendBuffer.length>0&&(this.sendBuffer.forEach(function(e){return e()}),this.sendBuffer=[])}},{key:"onConnMessage",value:function(e){var t=this;this.decode(e.data,function(e){var n=e.topic,i=e.event,o=e.payload,r=e.ref,s=e.join_ref;r&&r===t.pendingHeartbeatRef&&(t.pendingHeartbeatRef=null),t.hasLogger()&&t.log("receive","".concat(o.status||""," ").concat(n," ").concat(i," ").concat(r&&"("+r+")"||""),o);for(var a=0;a1&&void 0!==arguments[1]?arguments[1]:{};s(this,e);var o=i.events||{state:"presence_state",diff:"presence_diff"};this.state={},this.pendingDiffs=[],this.channel=t,this.joinRef=null,this.caller={onJoin:function(){},onLeave:function(){},onSync:function(){}},this.channel.on(o.state,function(t){var i=n.caller,o=i.onJoin,r=i.onLeave,s=i.onSync;n.joinRef=n.channel.joinRef(),n.state=e.syncState(n.state,t,o,r),n.pendingDiffs.forEach(function(t){n.state=e.syncDiff(n.state,t,o,r)}),n.pendingDiffs=[],s()}),this.channel.on(o.diff,function(t){var i=n.caller,o=i.onJoin,r=i.onLeave,s=i.onSync;n.inPendingSyncState()?n.pendingDiffs.push(t):(n.state=e.syncDiff(n.state,t,o,r),s())})}return c(e,[{key:"onJoin",value:function(e){this.caller.onJoin=e}},{key:"onLeave",value:function(e){this.caller.onLeave=e}},{key:"onSync",value:function(e){this.caller.onSync=e}},{key:"list",value:function(t){return e.list(this.state,t)}},{key:"inPendingSyncState",value:function(){return!this.joinRef||this.joinRef!==this.channel.joinRef()}}],[{key:"syncState",value:function(e,t,n,i){var o=this,r=this.clone(e),s={},a={};return this.map(r,function(e,n){t[e]||(a[e]=n)}),this.map(t,function(e,t){var n=r[e];if(n){var i=t.metas.map(function(e){return e.phx_ref}),c=n.metas.map(function(e){return e.phx_ref}),u=t.metas.filter(function(e){return c.indexOf(e.phx_ref)<0}),h=n.metas.filter(function(e){return i.indexOf(e.phx_ref)<0});u.length>0&&(s[e]=t,s[e].metas=u),h.length>0&&(a[e]=o.clone(n),a[e].metas=h)}else s[e]=t}),this.syncDiff(r,{joins:s,leaves:a},n,i)}},{key:"syncDiff",value:function(e,t,n,o){var r=t.joins,s=t.leaves,a=this.clone(e);return n||(n=function(){}),o||(o=function(){}),this.map(r,function(e,t){var o=a[e];if(a[e]=t,o){var r,s=a[e].metas.map(function(e){return e.phx_ref}),c=o.metas.filter(function(e){return s.indexOf(e.phx_ref)<0});(r=a[e].metas).unshift.apply(r,i(c))}n(e,o,t)}),this.map(s,function(e,t){var n=a[e];if(n){var i=t.metas.map(function(e){return e.phx_ref});n.metas=n.metas.filter(function(e){return i.indexOf(e.phx_ref)<0}),o(e,n,t),0===n.metas.length&&delete a[e]}}),a}},{key:"list",value:function(e,t){return t||(t=function(e,t){return t}),this.map(e,function(e,n){return t(e,n)})}},{key:"map",value:function(e,t){return Object.getOwnPropertyNames(e).map(function(n){return t(n,e[n])})}},{key:"clone",value:function(e){return JSON.parse(JSON.stringify(e))}}]),e}(),w=function(){function e(t,n){s(this,e),this.callback=t,this.timerCalc=n,this.timer=null,this.tries=0}return c(e,[{key:"reset",value:function(){this.tries=0,this.clearTimer()}},{key:"restart",value:function(){var e=null!==this.timer;this.reset(),e&&this.scheduleTimeout()}},{key:"scheduleTimeout",value:function(){var e=this;this.clearTimer(),this.timer=setTimeout(function(){e.tries=e.tries+1,e.callback()},this.timerCalc(this.tries+1))}},{key:"clearTimer",value:function(){clearTimeout(this.timer),this.timer=null}}]),e}()}])}); \ No newline at end of file From 9b4d360b1ecca7a9baacd3b4e76dbcda45a59d33 Mon Sep 17 00:00:00 2001 From: Chris McCord Date: Fri, 23 Nov 2018 08:17:17 -0500 Subject: [PATCH 31/61] Update template phoenix.js build --- installer/templates/phx_assets/phoenix.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/installer/templates/phx_assets/phoenix.js b/installer/templates/phx_assets/phoenix.js index f5f9b2a08b..ce4bdf1087 100644 --- a/installer/templates/phx_assets/phoenix.js +++ b/installer/templates/phx_assets/phoenix.js @@ -1 +1 @@ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.Phoenix=t():e.Phoenix=t()}(window,function(){return function(e){var t={};function n(i){if(t[i])return t[i].exports;var o=t[i]={i:i,l:!1,exports:{}};return e[i].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,i){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:i})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var i=Object.create(null);if(n.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(i,o,function(t){return e[t]}.bind(null,o));return i},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=0)}([function(e,t,n){(function(t){e.exports=t.Phoenix=n(2)}).call(this,n(1))},function(e,t){var n;n=function(){return this}();try{n=n||Function("return this")()||(0,eval)("this")}catch(e){"object"==typeof window&&(n=window)}e.exports=n},function(e,t,n){"use strict";function i(e){return function(e){if(Array.isArray(e)){for(var t=0,n=new Array(e.length);t0&&void 0!==arguments[0]?arguments[0]:this.timeout;if(this.joinedOnce)throw"tried to join multiple times. 'join' can only be called a single time per channel instance";return this.joinedOnce=!0,this.rejoin(e),this.joinPush}},{key:"onClose",value:function(e){this.on(p.close,e)}},{key:"onError",value:function(e){return this.on(p.error,function(t){return e(t)})}},{key:"on",value:function(e,t){var n=this.bindingRef++;return this.bindings.push({event:e,ref:n,callback:t}),n}},{key:"off",value:function(e,t){this.bindings=this.bindings.filter(function(n){return!(n.event===e&&(void 0===t||t===n.ref))})}},{key:"canPush",value:function(){return this.socket.isConnected()&&this.isJoined()}},{key:"push",value:function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:this.timeout;if(!this.joinedOnce)throw"tried to push '".concat(e,"' to '").concat(this.topic,"' before joining. Use channel.join() before pushing events");var i=new m(this,e,function(){return t},n);return this.canPush()?i.send():(i.startTimeout(),this.pushBuffer.push(i)),i}},{key:"leave",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.timeout;this.state=f.leaving;var n=function(){e.socket.hasLogger()&&e.socket.log("channel","leave ".concat(e.topic)),e.trigger(p.close,"leave")},i=new m(this,p.leave,y({}),t);return i.receive("ok",function(){return n()}).receive("timeout",function(){return n()}),i.send(),this.canPush()||i.trigger("ok",{}),i}},{key:"onMessage",value:function(e,t,n){return t}},{key:"isLifecycleEvent",value:function(e){return d.indexOf(e)>=0}},{key:"isMember",value:function(e,t,n,i){return this.topic===e&&(!i||i===this.joinRef()||!this.isLifecycleEvent(t)||(this.socket.hasLogger()&&this.socket.log("channel","dropping outdated message",{topic:e,event:t,payload:n,joinRef:i}),!1))}},{key:"joinRef",value:function(){return this.joinPush.ref}},{key:"sendJoin",value:function(e){this.state=f.joining,this.joinPush.resend(e)}},{key:"rejoin",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.timeout;this.isLeaving()||this.sendJoin(e)}},{key:"trigger",value:function(e,t,n,i){var o=this.onMessage(e,t,n,i);if(t&&!o)throw"channel onMessage callbacks must return the payload, modified or unmodified";for(var r=0;r1&&void 0!==arguments[1]?arguments[1]:{};s(this,e),this.stateChangeCallbacks={open:[],close:[],error:[],message:[]},this.channels=[],this.sendBuffer=[],this.ref=0,this.timeout=i.timeout||l,this.transport=i.transport||u.WebSocket||j,this.defaultEncoder=k.encode,this.defaultDecoder=k.decode,this.transport!==j?(this.encode=i.encode||this.defaultEncoder,this.decode=i.decode||this.defaultDecoder):(this.encode=this.defaultEncoder,this.decode=this.defaultDecoder),this.heartbeatIntervalMs=i.heartbeatIntervalMs||3e4,this.reconnectAfterMs=i.reconnectAfterMs||function(e){return[1e3,2e3,5e3,1e4][e-1]||1e4},this.logger=i.logger||null,this.longpollerTimeout=i.longpollerTimeout||2e4,this.params=y(i.params||{}),this.endPoint="".concat(t,"/").concat(v.websocket),this.heartbeatTimer=null,this.pendingHeartbeatRef=null,this.reconnectTimer=new C(function(){n.teardown(function(){return n.connect()})},this.reconnectAfterMs)}return c(e,[{key:"protocol",value:function(){return location.protocol.match(/^https/)?"wss":"ws"}},{key:"endPointURL",value:function(){var e=R.appendParams(R.appendParams(this.endPoint,this.params()),{vsn:"2.0.0"});return"/"!==e.charAt(0)?e:"/"===e.charAt(1)?"".concat(this.protocol(),":").concat(e):"".concat(this.protocol(),"://").concat(location.host).concat(e)}},{key:"disconnect",value:function(e,t,n){this.reconnectTimer.reset(),this.teardown(e,t,n)}},{key:"connect",value:function(e){var t=this;e&&(console&&console.log("passing params to connect is deprecated. Instead pass :params to the Socket constructor"),this.params=y(e)),this.conn||(this.conn=new this.transport(this.endPointURL()),this.conn.timeout=this.longpollerTimeout,this.conn.onopen=function(){return t.onConnOpen()},this.conn.onerror=function(e){return t.onConnError(e)},this.conn.onmessage=function(e){return t.onConnMessage(e)},this.conn.onclose=function(e){return t.onConnClose(e)})}},{key:"log",value:function(e,t,n){this.logger(e,t,n)}},{key:"hasLogger",value:function(){return null!==this.logger}},{key:"onOpen",value:function(e){this.stateChangeCallbacks.open.push(e)}},{key:"onClose",value:function(e){this.stateChangeCallbacks.close.push(e)}},{key:"onError",value:function(e){this.stateChangeCallbacks.error.push(e)}},{key:"onMessage",value:function(e){this.stateChangeCallbacks.message.push(e)}},{key:"onConnOpen",value:function(){this.hasLogger()&&this.log("transport","connected to ".concat(this.endPointURL())),this.flushSendBuffer(),this.reconnectTimer.reset(),this.resetHeartbeat(),this.resetChannelTimers(),this.stateChangeCallbacks.open.forEach(function(e){return e()})}},{key:"resetHeartbeat",value:function(){var e=this;this.conn.skipHeartbeat||(this.pendingHeartbeatRef=null,clearInterval(this.heartbeatTimer),this.heartbeatTimer=setInterval(function(){return e.sendHeartbeat()},this.heartbeatIntervalMs))}},{key:"teardown",value:function(e,t,n){this.conn&&(this.conn.onclose=function(){},t?this.conn.close(t,n||""):this.conn.close(),this.conn=null),e&&e()}},{key:"onConnClose",value:function(e){this.hasLogger()&&this.log("transport","close",e),this.triggerChanError(),clearInterval(this.heartbeatTimer),e&&1e3!==e.code&&this.reconnectTimer.scheduleTimeout(),this.stateChangeCallbacks.close.forEach(function(t){return t(e)})}},{key:"onConnError",value:function(e){this.hasLogger()&&this.log("transport",e),this.triggerChanError(),this.stateChangeCallbacks.error.forEach(function(t){return t(e)})}},{key:"triggerChanError",value:function(){this.channels.forEach(function(e){return e.trigger(p.error)})}},{key:"connectionState",value:function(){switch(this.conn&&this.conn.readyState){case h.connecting:return"connecting";case h.open:return"open";case h.closing:return"closing";default:return"closed"}}},{key:"isConnected",value:function(){return"open"===this.connectionState()}},{key:"remove",value:function(e){this.channels=this.channels.filter(function(t){return t.joinRef()!==e.joinRef()})}},{key:"channel",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=new g(e,t,this);return this.channels.push(n),n}},{key:"push",value:function(e){var t=this;if(this.hasLogger()){var n=e.topic,i=e.event,o=e.payload,r=e.ref,s=e.join_ref;this.log("push","".concat(n," ").concat(i," (").concat(s,", ").concat(r,")"),o)}this.isConnected()?this.encode(e,function(e){return t.conn.send(e)}):this.sendBuffer.push(function(){return t.encode(e,function(e){return t.conn.send(e)})})}},{key:"makeRef",value:function(){var e=this.ref+1;return e===this.ref?this.ref=0:this.ref=e,this.ref.toString()}},{key:"sendHeartbeat",value:function(){if(this.isConnected()){if(this.pendingHeartbeatRef)return this.pendingHeartbeatRef=null,this.hasLogger()&&this.log("transport","heartbeat timeout. Attempting to re-establish connection"),void this.conn.close(1e3,"hearbeat timeout");this.pendingHeartbeatRef=this.makeRef(),this.push({topic:"phoenix",event:"heartbeat",payload:{},ref:this.pendingHeartbeatRef})}}},{key:"flushSendBuffer",value:function(){this.isConnected()&&this.sendBuffer.length>0&&(this.sendBuffer.forEach(function(e){return e()}),this.sendBuffer=[])}},{key:"onConnMessage",value:function(e){var t=this;this.decode(e.data,function(e){var n=e.topic,i=e.event,o=e.payload,r=e.ref,s=e.join_ref;r&&r===t.pendingHeartbeatRef&&(t.pendingHeartbeatRef=null),t.hasLogger()&&t.log("receive","".concat(o.status||""," ").concat(n," ").concat(i," ").concat(r&&"("+r+")"||""),o);for(var a=0;a1&&void 0!==arguments[1]?arguments[1]:{};s(this,e);var o=i.events||{state:"presence_state",diff:"presence_diff"};this.state={},this.pendingDiffs=[],this.channel=t,this.joinRef=null,this.caller={onJoin:function(){},onLeave:function(){},onSync:function(){}},this.channel.on(o.state,function(t){var i=n.caller,o=i.onJoin,r=i.onLeave,s=i.onSync;n.joinRef=n.channel.joinRef(),n.state=e.syncState(n.state,t,o,r),n.pendingDiffs.forEach(function(t){n.state=e.syncDiff(n.state,t,o,r)}),n.pendingDiffs=[],s()}),this.channel.on(o.diff,function(t){var i=n.caller,o=i.onJoin,r=i.onLeave,s=i.onSync;n.inPendingSyncState()?n.pendingDiffs.push(t):(n.state=e.syncDiff(n.state,t,o,r),s())})}return c(e,[{key:"onJoin",value:function(e){this.caller.onJoin=e}},{key:"onLeave",value:function(e){this.caller.onLeave=e}},{key:"onSync",value:function(e){this.caller.onSync=e}},{key:"list",value:function(t){return e.list(this.state,t)}},{key:"inPendingSyncState",value:function(){return!this.joinRef||this.joinRef!==this.channel.joinRef()}}],[{key:"syncState",value:function(e,t,n,i){var o=this,r=this.clone(e),s={},a={};return this.map(r,function(e,n){t[e]||(a[e]=n)}),this.map(t,function(e,t){var n=r[e];if(n){var i=t.metas.map(function(e){return e.phx_ref}),c=n.metas.map(function(e){return e.phx_ref}),u=t.metas.filter(function(e){return c.indexOf(e.phx_ref)<0}),h=n.metas.filter(function(e){return i.indexOf(e.phx_ref)<0});u.length>0&&(s[e]=t,s[e].metas=u),h.length>0&&(a[e]=o.clone(n),a[e].metas=h)}else s[e]=t}),this.syncDiff(r,{joins:s,leaves:a},n,i)}},{key:"syncDiff",value:function(e,t,n,o){var r=t.joins,s=t.leaves,a=this.clone(e);return n||(n=function(){}),o||(o=function(){}),this.map(r,function(e,t){var o=a[e];if(a[e]=t,o){var r,s=a[e].metas.map(function(e){return e.phx_ref}),c=o.metas.filter(function(e){return s.indexOf(e.phx_ref)<0});(r=a[e].metas).unshift.apply(r,i(c))}n(e,o,t)}),this.map(s,function(e,t){var n=a[e];if(n){var i=t.metas.map(function(e){return e.phx_ref});n.metas=n.metas.filter(function(e){return i.indexOf(e.phx_ref)<0}),o(e,n,t),0===n.metas.length&&delete a[e]}}),a}},{key:"list",value:function(e,t){return t||(t=function(e,t){return t}),this.map(e,function(e,n){return t(e,n)})}},{key:"map",value:function(e,t){return Object.getOwnPropertyNames(e).map(function(n){return t(n,e[n])})}},{key:"clone",value:function(e){return JSON.parse(JSON.stringify(e))}}]),e}(),C=function(){function e(t,n){s(this,e),this.callback=t,this.timerCalc=n,this.timer=null,this.tries=0}return c(e,[{key:"reset",value:function(){this.tries=0,this.clearTimer()}},{key:"restart",value:function(){var e=null!==this.timer;this.reset(),e&&this.scheduleTimeout()}},{key:"scheduleTimeout",value:function(){var e=this;this.clearTimer(),this.timer=setTimeout(function(){e.tries=e.tries+1,e.callback()},this.timerCalc(this.tries+1))}},{key:"clearTimer",value:function(){clearTimeout(this.timer),this.timer=null}}]),e}()}])}); \ No newline at end of file +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.Phoenix=t():e.Phoenix=t()}(this,function(){return function(e){var t={};function n(i){if(t[i])return t[i].exports;var o=t[i]={i:i,l:!1,exports:{}};return e[i].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,i){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:i})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var i=Object.create(null);if(n.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(i,o,function(t){return e[t]}.bind(null,o));return i},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=0)}([function(e,t,n){(function(t){e.exports=t.Phoenix=n(2)}).call(this,n(1))},function(e,t){var n;n=function(){return this}();try{n=n||Function("return this")()||(0,eval)("this")}catch(e){"object"==typeof window&&(n=window)}e.exports=n},function(e,t,n){"use strict";function i(e){return function(e){if(Array.isArray(e)){for(var t=0,n=new Array(e.length);t0&&void 0!==arguments[0]?arguments[0]:this.timeout;if(this.joinedOnce)throw"tried to join multiple times. 'join' can only be called a single time per channel instance";return this.joinedOnce=!0,this.rejoin(e),this.joinPush}},{key:"onClose",value:function(e){this.on(v.close,e)}},{key:"onError",value:function(e){return this.on(v.error,function(t){return e(t)})}},{key:"on",value:function(e,t){var n=this.bindingRef++;return this.bindings.push({event:e,ref:n,callback:t}),n}},{key:"off",value:function(e,t){this.bindings=this.bindings.filter(function(n){return!(n.event===e&&(void 0===t||t===n.ref))})}},{key:"canPush",value:function(){return this.socket.isConnected()&&this.isJoined()}},{key:"push",value:function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:this.timeout;if(!this.joinedOnce)throw"tried to push '".concat(e,"' to '").concat(this.topic,"' before joining. Use channel.join() before pushing events");var i=new k(this,e,function(){return t},n);return this.canPush()?i.send():(i.startTimeout(),this.pushBuffer.push(i)),i}},{key:"leave",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.timeout;this.state=d.leaving;var n=function(){e.socket.hasLogger()&&e.socket.log("channel","leave ".concat(e.topic)),e.trigger(v.close,"leave")},i=new k(this,v.leave,g({}),t);return i.receive("ok",function(){return n()}).receive("timeout",function(){return n()}),i.send(),this.canPush()||i.trigger("ok",{}),i}},{key:"onMessage",value:function(e,t,n){return t}},{key:"isLifecycleEvent",value:function(e){return y.indexOf(e)>=0}},{key:"isMember",value:function(e,t,n,i){return this.topic===e&&(!i||i===this.joinRef()||!this.isLifecycleEvent(t)||(this.socket.hasLogger()&&this.socket.log("channel","dropping outdated message",{topic:e,event:t,payload:n,joinRef:i}),!1))}},{key:"joinRef",value:function(){return this.joinPush.ref}},{key:"sendJoin",value:function(e){this.state=d.joining,this.joinPush.resend(e)}},{key:"rejoin",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.timeout;this.isLeaving()||this.sendJoin(e)}},{key:"trigger",value:function(e,t,n,i){var o=this.onMessage(e,t,n,i);if(t&&!o)throw"channel onMessage callbacks must return the payload, modified or unmodified";for(var r=0;r1&&void 0!==arguments[1]?arguments[1]:{};s(this,e),this.stateChangeCallbacks={open:[],close:[],error:[],message:[]},this.channels=[],this.sendBuffer=[],this.ref=0,this.timeout=i.timeout||p,this.transport=i.transport||l.WebSocket||T,this.defaultEncoder=j.encode,this.defaultDecoder=j.decode,this.transport!==T?(this.encode=i.encode||this.defaultEncoder,this.decode=i.decode||this.defaultDecoder):(this.encode=this.defaultEncoder,this.decode=this.defaultDecoder),this.heartbeatIntervalMs=i.heartbeatIntervalMs||3e4,this.reconnectAfterMs=i.reconnectAfterMs||function(e){return[1e3,2e3,5e3,1e4][e-1]||1e4},this.logger=i.logger||null,this.longpollerTimeout=i.longpollerTimeout||2e4,this.params=g(i.params||{}),this.endPoint="".concat(t,"/").concat(m.websocket),this.heartbeatTimer=null,this.pendingHeartbeatRef=null,this.reconnectTimer=new w(function(){n.teardown(function(){return n.connect()})},this.reconnectAfterMs)}return c(e,[{key:"protocol",value:function(){return location.protocol.match(/^https/)?"wss":"ws"}},{key:"endPointURL",value:function(){var e=C.appendParams(C.appendParams(this.endPoint,this.params()),{vsn:"2.0.0"});return"/"!==e.charAt(0)?e:"/"===e.charAt(1)?"".concat(this.protocol(),":").concat(e):"".concat(this.protocol(),"://").concat(location.host).concat(e)}},{key:"disconnect",value:function(e,t,n){this.reconnectTimer.reset(),this.teardown(e,t,n)}},{key:"connect",value:function(e){var t=this;e&&(console&&console.log("passing params to connect is deprecated. Instead pass :params to the Socket constructor"),this.params=g(e)),this.conn||(this.conn=new this.transport(this.endPointURL()),this.conn.timeout=this.longpollerTimeout,this.conn.onopen=function(){return t.onConnOpen()},this.conn.onerror=function(e){return t.onConnError(e)},this.conn.onmessage=function(e){return t.onConnMessage(e)},this.conn.onclose=function(e){return t.onConnClose(e)})}},{key:"log",value:function(e,t,n){this.logger(e,t,n)}},{key:"hasLogger",value:function(){return null!==this.logger}},{key:"onOpen",value:function(e){this.stateChangeCallbacks.open.push(e)}},{key:"onClose",value:function(e){this.stateChangeCallbacks.close.push(e)}},{key:"onError",value:function(e){this.stateChangeCallbacks.error.push(e)}},{key:"onMessage",value:function(e){this.stateChangeCallbacks.message.push(e)}},{key:"onConnOpen",value:function(){this.hasLogger()&&this.log("transport","connected to ".concat(this.endPointURL())),this.flushSendBuffer(),this.reconnectTimer.reset(),this.resetHeartbeat(),this.resetChannelTimers(),this.stateChangeCallbacks.open.forEach(function(e){return e()})}},{key:"resetHeartbeat",value:function(){var e=this;this.conn.skipHeartbeat||(this.pendingHeartbeatRef=null,clearInterval(this.heartbeatTimer),this.heartbeatTimer=setInterval(function(){return e.sendHeartbeat()},this.heartbeatIntervalMs))}},{key:"teardown",value:function(e,t,n){this.conn&&(this.conn.onclose=function(){},t?this.conn.close(t,n||""):this.conn.close(),this.conn=null),e&&e()}},{key:"onConnClose",value:function(e){this.hasLogger()&&this.log("transport","close",e),this.triggerChanError(),clearInterval(this.heartbeatTimer),e&&1e3!==e.code&&this.reconnectTimer.scheduleTimeout(),this.stateChangeCallbacks.close.forEach(function(t){return t(e)})}},{key:"onConnError",value:function(e){this.hasLogger()&&this.log("transport",e),this.triggerChanError(),this.stateChangeCallbacks.error.forEach(function(t){return t(e)})}},{key:"triggerChanError",value:function(){this.channels.forEach(function(e){return e.trigger(v.error)})}},{key:"connectionState",value:function(){switch(this.conn&&this.conn.readyState){case f.connecting:return"connecting";case f.open:return"open";case f.closing:return"closing";default:return"closed"}}},{key:"isConnected",value:function(){return"open"===this.connectionState()}},{key:"remove",value:function(e){this.channels=this.channels.filter(function(t){return t.joinRef()!==e.joinRef()})}},{key:"channel",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=new b(e,t,this);return this.channels.push(n),n}},{key:"push",value:function(e){var t=this;if(this.hasLogger()){var n=e.topic,i=e.event,o=e.payload,r=e.ref,s=e.join_ref;this.log("push","".concat(n," ").concat(i," (").concat(s,", ").concat(r,")"),o)}this.isConnected()?this.encode(e,function(e){return t.conn.send(e)}):this.sendBuffer.push(function(){return t.encode(e,function(e){return t.conn.send(e)})})}},{key:"makeRef",value:function(){var e=this.ref+1;return e===this.ref?this.ref=0:this.ref=e,this.ref.toString()}},{key:"sendHeartbeat",value:function(){if(this.isConnected()){if(this.pendingHeartbeatRef)return this.pendingHeartbeatRef=null,this.hasLogger()&&this.log("transport","heartbeat timeout. Attempting to re-establish connection"),void this.conn.close(1e3,"hearbeat timeout");this.pendingHeartbeatRef=this.makeRef(),this.push({topic:"phoenix",event:"heartbeat",payload:{},ref:this.pendingHeartbeatRef})}}},{key:"flushSendBuffer",value:function(){this.isConnected()&&this.sendBuffer.length>0&&(this.sendBuffer.forEach(function(e){return e()}),this.sendBuffer=[])}},{key:"onConnMessage",value:function(e){var t=this;this.decode(e.data,function(e){var n=e.topic,i=e.event,o=e.payload,r=e.ref,s=e.join_ref;r&&r===t.pendingHeartbeatRef&&(t.pendingHeartbeatRef=null),t.hasLogger()&&t.log("receive","".concat(o.status||""," ").concat(n," ").concat(i," ").concat(r&&"("+r+")"||""),o);for(var a=0;a1&&void 0!==arguments[1]?arguments[1]:{};s(this,e);var o=i.events||{state:"presence_state",diff:"presence_diff"};this.state={},this.pendingDiffs=[],this.channel=t,this.joinRef=null,this.caller={onJoin:function(){},onLeave:function(){},onSync:function(){}},this.channel.on(o.state,function(t){var i=n.caller,o=i.onJoin,r=i.onLeave,s=i.onSync;n.joinRef=n.channel.joinRef(),n.state=e.syncState(n.state,t,o,r),n.pendingDiffs.forEach(function(t){n.state=e.syncDiff(n.state,t,o,r)}),n.pendingDiffs=[],s()}),this.channel.on(o.diff,function(t){var i=n.caller,o=i.onJoin,r=i.onLeave,s=i.onSync;n.inPendingSyncState()?n.pendingDiffs.push(t):(n.state=e.syncDiff(n.state,t,o,r),s())})}return c(e,[{key:"onJoin",value:function(e){this.caller.onJoin=e}},{key:"onLeave",value:function(e){this.caller.onLeave=e}},{key:"onSync",value:function(e){this.caller.onSync=e}},{key:"list",value:function(t){return e.list(this.state,t)}},{key:"inPendingSyncState",value:function(){return!this.joinRef||this.joinRef!==this.channel.joinRef()}}],[{key:"syncState",value:function(e,t,n,i){var o=this,r=this.clone(e),s={},a={};return this.map(r,function(e,n){t[e]||(a[e]=n)}),this.map(t,function(e,t){var n=r[e];if(n){var i=t.metas.map(function(e){return e.phx_ref}),c=n.metas.map(function(e){return e.phx_ref}),u=t.metas.filter(function(e){return c.indexOf(e.phx_ref)<0}),h=n.metas.filter(function(e){return i.indexOf(e.phx_ref)<0});u.length>0&&(s[e]=t,s[e].metas=u),h.length>0&&(a[e]=o.clone(n),a[e].metas=h)}else s[e]=t}),this.syncDiff(r,{joins:s,leaves:a},n,i)}},{key:"syncDiff",value:function(e,t,n,o){var r=t.joins,s=t.leaves,a=this.clone(e);return n||(n=function(){}),o||(o=function(){}),this.map(r,function(e,t){var o=a[e];if(a[e]=t,o){var r,s=a[e].metas.map(function(e){return e.phx_ref}),c=o.metas.filter(function(e){return s.indexOf(e.phx_ref)<0});(r=a[e].metas).unshift.apply(r,i(c))}n(e,o,t)}),this.map(s,function(e,t){var n=a[e];if(n){var i=t.metas.map(function(e){return e.phx_ref});n.metas=n.metas.filter(function(e){return i.indexOf(e.phx_ref)<0}),o(e,n,t),0===n.metas.length&&delete a[e]}}),a}},{key:"list",value:function(e,t){return t||(t=function(e,t){return t}),this.map(e,function(e,n){return t(e,n)})}},{key:"map",value:function(e,t){return Object.getOwnPropertyNames(e).map(function(n){return t(n,e[n])})}},{key:"clone",value:function(e){return JSON.parse(JSON.stringify(e))}}]),e}(),w=function(){function e(t,n){s(this,e),this.callback=t,this.timerCalc=n,this.timer=null,this.tries=0}return c(e,[{key:"reset",value:function(){this.tries=0,this.clearTimer()}},{key:"restart",value:function(){var e=null!==this.timer;this.reset(),e&&this.scheduleTimeout()}},{key:"scheduleTimeout",value:function(){var e=this;this.clearTimer(),this.timer=setTimeout(function(){e.tries=e.tries+1,e.callback()},this.timerCalc(this.tries+1))}},{key:"clearTimer",value:function(){clearTimeout(this.timer),this.timer=null}}]),e}()}])}); \ No newline at end of file From 48b0f683784bdd83836952894926d3cba370d40b Mon Sep 17 00:00:00 2001 From: Chris McCord Date: Fri, 23 Nov 2018 08:17:26 -0500 Subject: [PATCH 32/61] Update maintainers --- mix.exs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/mix.exs b/mix.exs index b2a7fae1b5..c67edaad8d 100644 --- a/mix.exs +++ b/mix.exs @@ -74,10 +74,7 @@ defmodule Phoenix.MixProject do defp package do [ - maintainers: [ - "Chris McCord", "José Valim", "Lance Halvorsen", "Gary Rennie", - "Jason Stiebs", "Eric Meadows-Jönsson", "Sonny Scroggin" - ], + maintainers: ["Chris McCord", "José Valim", "Gary Rennie", "Jason Stiebs"], licenses: ["MIT"], links: %{github: "https://github.com/phoenixframework/phoenix"}, files: ~w(lib priv CHANGELOG.md LICENSE.md mix.exs package.json README.md .formatter.exs) From 60fce56798cf074a784988ebedb97d17247e5d68 Mon Sep 17 00:00:00 2001 From: Chris McCord Date: Fri, 23 Nov 2018 08:18:12 -0500 Subject: [PATCH 33/61] Bump changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f52f37089..419005e763 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ ### JavaScript client + * Fix `window` reference causing phoenix.js errors in environments without global window object. + ## v1.4 The CHANGELOG for v1.4 releases can be found [in the v1.4 branch](https://github.com/phoenixframework/phoenix/blob/v1.4/CHANGELOG.md). From 3ecacda2b30cc6249c328d92bb645813b58bb69c Mon Sep 17 00:00:00 2001 From: Ben Damman Date: Mon, 3 Dec 2018 06:43:08 -0800 Subject: [PATCH 34/61] Added 3rd party elixir client library to guide (#3192) * Added link to Phoenix.Channels.GenSocketClient, a stable Elixir client library for Channels * This is especially useful for anyone that desires to use Channels from a Nerves project --- guides/channels.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/guides/channels.md b/guides/channels.md index eb80ae3058..6617390135 100644 --- a/guides/channels.md +++ b/guides/channels.md @@ -179,6 +179,8 @@ Phoenix ships with a JavaScript client that is available when generating a new P + C# - [PhoenixSharp](https://github.com/Mazyod/PhoenixSharp) - [dn-phoenix](https://github.com/jfis/dn-phoenix) ++ Elixir + - [phoenix_gen_socket_client](https://github.com/Aircloak/phoenix_gen_socket_client) ## Tying it all together Let's tie all these ideas together by building a simple chat application. After [generating a new Phoenix application](https://hexdocs.pm/phoenix/up_and_running.html) we'll see that the endpoint is already set up for us in `lib/hello_web/endpoint.ex`: From 9dea676d92524374d1cf893f024d94dec484fd87 Mon Sep 17 00:00:00 2001 From: Jason Axelson Date: Mon, 3 Dec 2018 04:46:16 -1000 Subject: [PATCH 35/61] Fix doc rendering bugs (#3191) Avoid smart quotes by using backticks around string literals in the documentation. Also explain what a splat is use more consistent language between `Phoenix.Channel` and `Phoenix.Socket`. --- lib/phoenix/channel.ex | 5 +++-- lib/phoenix/socket.ex | 25 +++++++++++++------------ 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/lib/phoenix/channel.ex b/lib/phoenix/channel.ex index c02a3acda4..71d53f5744 100644 --- a/lib/phoenix/channel.ex +++ b/lib/phoenix/channel.ex @@ -10,8 +10,9 @@ defmodule Phoenix.Channel do Every time you join a channel, you need to choose which particular topic you want to listen to. The topic is just an identifier, but by convention it is often made of two parts: `"topic:subtopic"`. Using the `"topic:subtopic"` - approach pairs nicely with the `Phoenix.Socket.channel/2` allowing you to - match on all topics starting with a given prefix: + approach pairs nicely with the `Phoenix.Socket.channel/3` allowing you to + match on all topics starting with a given prefix by using a splat (the `*` + character) as the last character in the topic pattern: channel "room:*", MyApp.RoomChannel diff --git a/lib/phoenix/socket.ex b/lib/phoenix/socket.ex index fae93c2687..01234dad2f 100644 --- a/lib/phoenix/socket.ex +++ b/lib/phoenix/socket.ex @@ -94,9 +94,9 @@ defmodule Phoenix.Socket do The serializer `decode!` function must return a `Phoenix.Socket.Message` which is forwarded to channels except: - * "heartbeat" events in the "phoenix" topic - should just emit an OK reply - * "phx_join" on any topic - should join the topic - * "phx_leave" on any topic - should leave the topic + * `"heartbeat"` events in the "phoenix" topic - should just emit an OK reply + * `"phx_join"` on any topic - should join the topic + * `"phx_leave"` on any topic - should leave the topic Each message also has a `ref` field which is used to track responses. @@ -108,10 +108,10 @@ defmodule Phoenix.Socket do The `Phoenix.Socket` implementation may also sent special messages and replies: - * "phx_error" - in case of errors, such as a channel process + * `"phx_error"` - in case of errors, such as a channel process crashing, or when attempting to join an already joined channel - * "phx_close" - the channel was gracefully closed + * `"phx_close"` - the channel was gracefully closed Phoenix ships with a JavaScript implementation of both websocket and long polling that interacts with Phoenix.Socket and can be @@ -210,7 +210,7 @@ defmodule Phoenix.Socket do def id(socket), do: "users_socket:#{socket.assigns.user_id}" - Would allow you to broadcast a "disconnect" event and terminate + Would allow you to broadcast a `"disconnect"` event and terminate all active sockets and channels for a given user: MyApp.Endpoint.broadcast("users_socket:" <> user.id, "disconnect", %{}) @@ -318,7 +318,8 @@ defmodule Phoenix.Socket do @doc """ Defines a channel matching the given topic and transports. - * `topic_pattern` - The string pattern, for example "room:*", "users:*", "system" + * `topic_pattern` - The string pattern, for example `"room:*"`, `"users:*"`, + or `"system"` * `module` - The channel module handler, for example `MyApp.RoomChannel` * `opts` - The optional list of options, see below @@ -332,11 +333,11 @@ defmodule Phoenix.Socket do ## Topic Patterns - The `channel` macro accepts topic patterns in two flavors. A splat argument - can be provided as the last character to indicate a "topic:subtopic" match. If - a plain string is provided, only that topic will match the channel handler. - Most use-cases will use the "topic:*" pattern to allow more versatile topic - scoping. + The `channel` macro accepts topic patterns in two flavors. A splat (the `*` + character) argument can be provided as the last character to indicate a + `"topic:subtopic"` match. If a plain string is provided, only that topic will + match the channel handler. Most use-cases will use the `"topic:*"` pattern to + allow more versatile topic scoping. See `Phoenix.Channel` for more information """ From 0a1f42b03e9ba21fce2eba4d1c0325b23cf1ca38 Mon Sep 17 00:00:00 2001 From: nysertxs Date: Wed, 5 Dec 2018 01:54:56 -0600 Subject: [PATCH 36/61] Removes extra line break (#3196) Removes extra line break that makes the formatter update newly generated schema file --- priv/templates/phx.gen.schema/schema.ex | 1 - test/mix/tasks/phx.gen.schema_test.exs | 10 ++++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/priv/templates/phx.gen.schema/schema.ex b/priv/templates/phx.gen.schema/schema.ex index fa1a6e705f..6ef1af53d8 100644 --- a/priv/templates/phx.gen.schema/schema.ex +++ b/priv/templates/phx.gen.schema/schema.ex @@ -1,7 +1,6 @@ defmodule <%= inspect schema.module %> do use Ecto.Schema import Ecto.Changeset - <%= if schema.binary_id do %> @primary_key {:id, :binary_id, autogenerate: true} @foreign_key_type :binary_id<% end %> diff --git a/test/mix/tasks/phx.gen.schema_test.exs b/test/mix/tasks/phx.gen.schema_test.exs index d6f769e8f8..b701702d11 100644 --- a/test/mix/tasks/phx.gen.schema_test.exs +++ b/test/mix/tasks/phx.gen.schema_test.exs @@ -270,6 +270,16 @@ defmodule Mix.Tasks.Phx.Gen.SchemaTest do end end + test "generates schema without extra line break", config do + in_tmp_project config.test, fn -> + Gen.Schema.run(~w(Blog.Post posts title)) + + assert_file "lib/phoenix/blog/post.ex", fn file -> + assert file =~ "import Ecto.Changeset\n\n schema" + end + end + end + describe "inside umbrella" do test "raises with false context_app", config do in_tmp_umbrella_project config.test, fn -> From c84758fa44fd11b5a6a00c2670265635443c1cbd Mon Sep 17 00:00:00 2001 From: Stephen Bussey Date: Wed, 5 Dec 2018 11:02:36 -0500 Subject: [PATCH 37/61] Document the use of `Phoenix.Tracker` instead of `Phoenix.Presence` (#3198) --- lib/phoenix/presence.ex | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/phoenix/presence.ex b/lib/phoenix/presence.ex index 3b041a97b1..e16c2581b2 100644 --- a/lib/phoenix/presence.ex +++ b/lib/phoenix/presence.ex @@ -5,9 +5,15 @@ defmodule Phoenix.Presence do This behaviour provides presence features such as fetching presences for a given topic, as well as handling diffs of join and leave events as they occur in real-time. Using this - module defines a supervisor and allows the calling module to - implement the `Phoenix.Tracker` behaviour which starts a - tracker process to handle presence information. + module defines a supervisor and a module that implements the + `Phoenix.Tracker` behaviour that uses `Phoenix.PubSub` to + broadcast presence updates. + + In case you want to use only a subset of the functionality + provided by `Phoenix.Presence`, such as tracking processes + but without broadcasting updates, we recommend that you look + at the `Phoenix.Tracker` functionality from the `phoenix_pubsub` + project. ## Example Usage From 8d37387106bc73f5f2023ea791fe83f423b808a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Wed, 5 Dec 2018 17:03:23 +0100 Subject: [PATCH 38/61] Automatically hibernate channels after some time (#3197) --- lib/phoenix/channel.ex | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/lib/phoenix/channel.ex b/lib/phoenix/channel.ex index 71d53f5744..427c7f65ac 100644 --- a/lib/phoenix/channel.ex +++ b/lib/phoenix/channel.ex @@ -185,16 +185,15 @@ defmodule Phoenix.Channel do You have three options to choose from when shutting down a channel: - * `:normal` - in such cases, the exit won't be logged, there is no restart - in transient mode, and linked processes do not exit + * `:normal` - in such cases, the exit won't be logged and linked processes + do not exit * `:shutdown` or `{:shutdown, term}` - in such cases, the exit won't be - logged, there is no restart in transient mode, and linked processes exit - with the same reason unless they're trapping exits + logged and linked processes exit with the same reason unless they're + trapping exits - * any other term - in such cases, the exit will be logged, there are - restarts in transient mode, and linked processes exit with the same reason - unless they're trapping exits + * any other term - in such cases, the exit will be logged and linked + processes exit with the same reason unless they're trapping exits ## Subscribing to external topics @@ -249,6 +248,16 @@ defmodule Phoenix.Channel do {:noreply, socket} end + ## Hibernation + + From Erlang/OTP 20, channels automatically hibernate to save memory + after 15_000 milliseconds of inactivity. This can be customized by + passing the `:hibernate_after` option to `use Phoenix.Channel`: + + use Phoenix.Channel, hibernate_after: 60_000 + + You can also set it to `:infinity` to fully disable it. + ## Logging By default, channel `"join"` and `"handle_in"` events are logged, using @@ -350,12 +359,13 @@ defmodule Phoenix.Channel do @phoenix_intercepts [] @phoenix_log_join Keyword.get(opts, :log_join, :info) @phoenix_log_handle_in Keyword.get(opts, :log_handle_in, :debug) + @phoenix_hibernate_after Keyword.get(opts, :hibernate_after, 15_000) import unquote(__MODULE__) import Phoenix.Socket, only: [assign: 3] def start_link(triplet) do - GenServer.start_link(Phoenix.Channel.Server, triplet) + GenServer.start_link(Phoenix.Channel.Server, triplet, hibernate_after: @phoenix_hibernate_after) end def __socket__(:private) do From 4da40a29f968b6e834ab55849af4a7337815ea50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sun, 9 Dec 2018 12:33:25 +0100 Subject: [PATCH 39/61] Update phoenix_html dep --- mix.exs | 2 +- mix.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mix.exs b/mix.exs index c67edaad8d..fc43e63f66 100644 --- a/mix.exs +++ b/mix.exs @@ -53,7 +53,7 @@ defmodule Phoenix.MixProject do # Optional deps {:plug_cowboy, "~> 1.0 or ~> 2.0", optional: true}, {:jason, "~> 1.0", optional: true}, - {:phoenix_html, "~> 2.13", github: "phoenixframework/phoenix_html", optional: true}, + {:phoenix_html, "~> 2.13", optional: true}, # Docs dependencies {:ex_doc, "~> 0.19.1", only: :docs}, diff --git a/mix.lock b/mix.lock index 68f107aad1..4a81419caa 100644 --- a/mix.lock +++ b/mix.lock @@ -10,7 +10,7 @@ "makeup_elixir": {:hex, :makeup_elixir, "0.8.0", "1204a2f5b4f181775a0e456154830524cf2207cf4f9112215c05e0b76e4eca8b", [:mix], [{:makeup, "~> 0.5.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 0.2.2", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm"}, "mime": {:hex, :mime, "1.3.0", "5e8d45a39e95c650900d03f897fbf99ae04f60ab1daa4a34c7a20a5151b7a5fe", [:mix], [], "hexpm"}, "nimble_parsec": {:hex, :nimble_parsec, "0.2.2", "d526b23bdceb04c7ad15b33c57c4526bf5f50aaa70c7c141b4b4624555c68259", [:mix], [], "hexpm"}, - "phoenix_html": {:git, "https://github.com/phoenixframework/phoenix_html.git", "53326e81b23ad38544dd39d9e7fdc9c6fc5da451", []}, + "phoenix_html": {:hex, :phoenix_html, "2.13.0", "3bad10de5efb6c590f7aa5b316ad0d3faa054715414c9b562c410de4ffb885c5", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "phoenix_pubsub": {:hex, :phoenix_pubsub, "1.1.0", "d55e25ff1ff8ea2f9964638366dfd6e361c52dedfd50019353598d11d4441d14", [:mix], [], "hexpm"}, "plug": {:hex, :plug, "1.7.1", "8516d565fb84a6a8b2ca722e74e2cd25ca0fc9d64f364ec9dbec09d33eb78ccd", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}], "hexpm"}, "plug_cowboy": {:hex, :plug_cowboy, "2.0.0", "ab0c92728f2ba43c544cce85f0f220d8d30fc0c90eaa1e6203683ab039655062", [:mix], [{:cowboy, "~> 2.5", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, From b93ba734697dd3c20df292b92b8a0c1777088c65 Mon Sep 17 00:00:00 2001 From: Tomoaki Tsuruta Date: Mon, 10 Dec 2018 23:49:27 -0800 Subject: [PATCH 40/61] Make doc more consistent (#3182) --- guides/testing/testing.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/guides/testing/testing.md b/guides/testing/testing.md index 4041246b30..604a667225 100644 --- a/guides/testing/testing.md +++ b/guides/testing/testing.md @@ -84,7 +84,7 @@ defmodule HelloWeb.ErrorViewTest do "Not Found" end - test "render 500.html" do + test "renders 500.html" do assert render_to_string(HelloWeb.ErrorView, "500.html", []) == "Internal Server Error" end @@ -301,7 +301,7 @@ defmodule HelloWeb.ErrorViewTest do end @tag individual_test: "nope" - test "render 500.html" do + test "renders 500.html" do assert render_to_string(HelloWeb.ErrorView, "500.html", []) == "Internal Server Error" end From 46f3aa8fd06cc69254912ffe1dceafd87343348c Mon Sep 17 00:00:00 2001 From: Sam Chen Date: Tue, 11 Dec 2018 15:51:43 +0800 Subject: [PATCH 41/61] Fix code block format (#3184) --- lib/phoenix/test/conn_test.ex | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/phoenix/test/conn_test.ex b/lib/phoenix/test/conn_test.ex index 416030031b..f8edffec89 100644 --- a/lib/phoenix/test/conn_test.ex +++ b/lib/phoenix/test/conn_test.ex @@ -54,12 +54,12 @@ defmodule Phoenix.ConnTest do For such cases, you need to set the `@endpoint` attribute to your controller and pass an atom representing the action to dispatch: - @endpoint MyAppWeb.HomeController + @endpoint MyAppWeb.HomeController - test "says welcome on the home page" do - conn = get(build_conn(), :index) - assert conn.resp_body =~ "Welcome!" - end + test "says welcome on the home page" do + conn = get(build_conn(), :index) + assert conn.resp_body =~ "Welcome!" + end Keep in mind that, once the `@endpoint` variable is set, all tests after setting it will be affected. From 2cdd8e4adb8598dbd7cca82294a7a6ea2a742dfa Mon Sep 17 00:00:00 2001 From: Kosmas Chatzimichalis Date: Tue, 11 Dec 2018 08:52:47 +0100 Subject: [PATCH 42/61] Fix typo - also created to also create (#3185) --- lib/phoenix/test/conn_test.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/phoenix/test/conn_test.ex b/lib/phoenix/test/conn_test.ex index f8edffec89..cd1eeeec60 100644 --- a/lib/phoenix/test/conn_test.ex +++ b/lib/phoenix/test/conn_test.ex @@ -39,7 +39,7 @@ defmodule Phoenix.ConnTest do |> put_req_header("accept", "application/json") |> get("/") - You can also created your own helpers, such as `json_conn()` that uses + You can also create your own helpers, such as `json_conn()` that uses `build_conn/0` and `put_req_header/3`, so you avoid repeating the connection setup throughout your tests. From d0e11728142757680276d77e2c67bed176890c2d Mon Sep 17 00:00:00 2001 From: Byron Hambly Date: Tue, 11 Dec 2018 09:53:29 +0200 Subject: [PATCH 43/61] fix minor typo of function name (#3186) --- guides/contexts.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guides/contexts.md b/guides/contexts.md index 996bc7312a..531a4bcc4d 100644 --- a/guides/contexts.md +++ b/guides/contexts.md @@ -1105,6 +1105,6 @@ defmodule Hello.UserRegistration do end end ``` -We can take advantage of `Ecto.Multi` to create a pipeline of operations that can be run inside a transaction of our `Repo`. If any given operation fails, the transaction will be rolled back and an error will be returned containing which operation failed, as well as the changes up to that point. In our `register_user/1` example, we specified two operations, one that calls into `Accounts.create_user/1` and another that passes the newly created user to `CMS.ensure_author_exits/1`. The final step of our function is to invoke the operations with `Repo.transaction/1`. +We can take advantage of `Ecto.Multi` to create a pipeline of operations that can be run inside a transaction of our `Repo`. If any given operation fails, the transaction will be rolled back and an error will be returned containing which operation failed, as well as the changes up to that point. In our `register_user/1` example, we specified two operations, one that calls into `Accounts.create_user/1` and another that passes the newly created user to `CMS.ensure_author_exists/1`. The final step of our function is to invoke the operations with `Repo.transaction/1`. The `UserRegistration` setup is likely simpler to implement than the dynamic author system we built – we decided to take the harder path exactly because those are decisions developers take on their applications every day. From b1460205e695ac5e3980da98b605138636c55f27 Mon Sep 17 00:00:00 2001 From: Rico Moorman Date: Tue, 11 Dec 2018 08:54:35 +0100 Subject: [PATCH 44/61] Apply generator conventions to code samples (#3202) --- guides/testing/testing_schemas.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/guides/testing/testing_schemas.md b/guides/testing/testing_schemas.md index 5159297ba9..71ebfbfc2e 100644 --- a/guides/testing/testing_schemas.md +++ b/guides/testing/testing_schemas.md @@ -109,9 +109,9 @@ It fails - which is exactly what it should do! We haven't written the code to ma defmodule Hello.Accounts.User do ... - def changeset(struct, params \\ %{}) do - struct - |> cast(params, [:name, :email, :bio, :number_of_pets]) + def changeset(%User{} = user, attrs) do + user + |> cast(attrs, [:name, :email, :bio, :number_of_pets]) |> validate_required([:name, :email, :bio]) end end @@ -228,9 +228,9 @@ Our test has pointed the way. Now let's make it pass by adding that validation. defmodule Hello.Accounts.User do ... - def changeset(struct, params \\ %{}) do - struct - |> cast(params, [:name, :email, :bio, :number_of_pets]) + def changeset(%User{} = user, attrs) do + user + |> cast(attrs, [:name, :email, :bio, :number_of_pets]) |> validate_required([:name, :email, :bio]) |> validate_length(:bio, min: 2) end @@ -293,9 +293,9 @@ To make this test pass, we need to add a maximum to the length validation of the defmodule Hello.Accounts.User do ... - def changeset(struct, params \\ %{}) do - struct - |> cast(params, [:name, :email, :bio, :number_of_pets]) + def changeset(%User{} = user, attrs) do + user + |> cast(attrs, [:name, :email, :bio, :number_of_pets]) |> validate_required([:name, :email, :bio]) |> validate_length(:bio, min: 2, max: 140) end @@ -360,9 +360,9 @@ Then we add the new validation to generate the error our test is looking for. defmodule Hello.Accounts.User do ... - def changeset(struct, params \\ %{}) do - struct - |> cast(params, [:name, :email, :bio, :number_of_pets]) + def changeset(%User{} = user, attrs) do + user + |> cast(attrs, [:name, :email, :bio, :number_of_pets]) |> validate_required([:name, :email, :bio]) |> validate_length(:bio, min: 2, max: 140) |> validate_format(:email, ~r/@/) From eb03a703434bafb8b61137e877d99015a45dd5f9 Mon Sep 17 00:00:00 2001 From: Rico Moorman Date: Tue, 11 Dec 2018 08:55:06 +0100 Subject: [PATCH 45/61] Apply generator conventions to code sample and adjust wording (#3203) --- guides/ecto.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/guides/ecto.md b/guides/ecto.md index 08b5a13877..349a4da54a 100644 --- a/guides/ecto.md +++ b/guides/ecto.md @@ -339,9 +339,9 @@ If we also have a requirement for the maximum length that a bio can have, we can Let's say we want to perform at least some rudimentary format validation on the `email` field. All we want to check for is the presence of the "@". The `validate_format/3` function is just what we need. ```elixir - def changeset(struct, params \\ %{}) do - struct - |> cast(params, [:name, :email, :bio, :number_of_pets]) + def changeset(%User{} = user, attrs) do + user + |> cast(attrs, [:name, :email, :bio, :number_of_pets]) |> validate_required([:name, :email, :bio, :number_of_pets]) |> validate_length(:bio, min: 2) |> validate_length(:bio, max: 140) @@ -361,9 +361,9 @@ There are many more validations and transformations we can perform in a changese ## Data Persistence -We've talked a lot about migrations and data-storage, but we haven't yet persisted any of our schemas or changesets. We briefly looked at our repo module in `lib/hello/repo.ex` earlier, now it's time to put it to use. Ecto Repo's are the interface into a storage system, be it a Database like PostgreSQL, or an external service like a RESTful API. The Repo module's purpose is to take care of the finer details of persistence and data querying for us. As the caller, we only care about fetching and persisting data. The Repo takes care of the underlying Database adapter communication, connection pooling, and error translation for database constraint violations. +We've talked a lot about migrations and data-storage, but we haven't yet persisted any of our schemas or changesets. We briefly looked at our repo module in `lib/hello/repo.ex` earlier, now it's time to put it to use. Ecto Repos are the interface into a storage system, be it a Database like PostgreSQL or an external service like a RESTful API. The Repo module's purpose is to take care of the finer details of persistence and data querying for us. As the caller, we only care about fetching and persisting data. The Repo takes care of the underlying Database adapter communication, connection pooling, and error translation for database constraint violations. -Let's head back over to IEx with `iex -S mix`, and insert a couple of users to the database. +Let's head back over to IEx with `iex -S mix`, and insert a couple of users into the database. ```console iex> alias Hello.{Repo, User} @@ -415,7 +415,7 @@ SELECT u0."email" FROM "users" AS u0 [] ["user1@example.com", "user2@example.com"] ``` -First, we imported `Ecto.Query`, which imports the `from` macro of Ecto's Query DSL. Next, we built a query which selects all the email addresses in our user's table. Let's try another example. +First, we imported `Ecto.Query`, which imports the `from` macro of Ecto's Query DSL. Next, we built a query which selects all the email addresses in our users table. Let's try another example. ```console iex)> Repo.one(from u in User, where: ilike(u.email, "%1%"), From 19180661650a30ea8382c306b4e5d50182d0b3ab Mon Sep 17 00:00:00 2001 From: kazk Date: Mon, 10 Dec 2018 23:55:26 -0800 Subject: [PATCH 46/61] Fix Mocha warning about --compilers (#3183) See https://github.com/mochajs/mocha/wiki/compilers-deprecation --- assets/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/package.json b/assets/package.json index 5384420fb4..731a33dccb 100644 --- a/assets/package.json +++ b/assets/package.json @@ -27,7 +27,7 @@ }, "sideEffects": false, "scripts": { - "test": "mocha ./test/**/*.js --exit --compilers js:@babel/register -r jsdom-global/register", + "test": "mocha ./test/**/*.js --exit -r @babel/register -r jsdom-global/register", "docs": "documentation build js/phoenix.js -f html -o ../doc/js", "build": "webpack --mode production", "watch": "webpack --mode development --watch" From daa4ebe92fb2456de06a00199465df56c1125115 Mon Sep 17 00:00:00 2001 From: Kuba Subczynski Date: Tue, 11 Dec 2018 02:56:00 -0500 Subject: [PATCH 47/61] Minor typo/grammar change (#3207) - typo: "of" -> "off" - grammar: moved "repeatedly" up in the sentence --- lib/phoenix/controller.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/phoenix/controller.ex b/lib/phoenix/controller.ex index 56646347a7..8e5f875a25 100644 --- a/lib/phoenix/controller.ex +++ b/lib/phoenix/controller.ex @@ -128,7 +128,7 @@ defmodule Phoenix.Controller do function matched from the router. By default, it passes the conn and params. In some cases, overriding the `action/2` plug in your controller is a useful way to inject arguments into your actions that you would otherwise - need to fetch of the connection repeatedly. For example, imagine if you + need to repeatedly fetch off the connection. For example, imagine if you stored a `conn.assigns.current_user` in the connection and wanted quick access to the user for every action in your controller: From c669f868f6aab8c57cf4f3610a978f5354524e26 Mon Sep 17 00:00:00 2001 From: Udo Kramer Date: Tue, 11 Dec 2018 08:56:58 +0100 Subject: [PATCH 48/61] update link to phoenix.js (#3199) --- guides/channels.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guides/channels.md b/guides/channels.md index 6617390135..ae6c35c41a 100644 --- a/guides/channels.md +++ b/guides/channels.md @@ -168,7 +168,7 @@ The following libraries exist today, and new ones are always welcome. #### Official -Phoenix ships with a JavaScript client that is available when generating a new Phoenix project. The documentation for the JavaScript module is available at [https://hexdocs.pm/phoenix/js/](https://hexdocs.pm/phoenix/js/); the code is in [phoenix.js](https://github.com/phoenixframework/phoenix/blob/v1.3/assets/js/phoenix.js). +Phoenix ships with a JavaScript client that is available when generating a new Phoenix project. The documentation for the JavaScript module is available at [https://hexdocs.pm/phoenix/js/](https://hexdocs.pm/phoenix/js/); the code is in [phoenix.js](https://github.com/phoenixframework/phoenix/blob/v1.4/assets/js/phoenix.js). #### 3rd Party From 091e7bb82ddab262e5690998f82db82afaf556ee Mon Sep 17 00:00:00 2001 From: Sfusato Date: Tue, 11 Dec 2018 14:38:41 +0200 Subject: [PATCH 49/61] Switch from uglifyjs-webpack-plugin to terser-webpack-plugin (#3189) * Switch from uglifyjs-webpack-plugin to terser-webpack-plugin * spaces instead of tabs --- installer/templates/phx_assets/webpack/package.json | 2 +- installer/templates/phx_assets/webpack/webpack.config.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/installer/templates/phx_assets/webpack/package.json b/installer/templates/phx_assets/webpack/package.json index d065f42bfb..d8eb8e501a 100644 --- a/installer/templates/phx_assets/webpack/package.json +++ b/installer/templates/phx_assets/webpack/package.json @@ -17,7 +17,7 @@ "css-loader": "^0.28.10", "mini-css-extract-plugin": "^0.4.0", "optimize-css-assets-webpack-plugin": "^4.0.0", - "uglifyjs-webpack-plugin": "^1.2.4", + "terser-webpack-plugin": "^1.1.0", "webpack": "4.4.0", "webpack-cli": "^2.0.10" } diff --git a/installer/templates/phx_assets/webpack/webpack.config.js b/installer/templates/phx_assets/webpack/webpack.config.js index 45ab14fddd..ffb12f7ae9 100644 --- a/installer/templates/phx_assets/webpack/webpack.config.js +++ b/installer/templates/phx_assets/webpack/webpack.config.js @@ -1,14 +1,14 @@ const path = require('path'); const glob = require('glob'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); -const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); +const TerserPlugin = require('terser-webpack-plugin'); const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin'); const CopyWebpackPlugin = require('copy-webpack-plugin'); module.exports = (env, options) => ({ optimization: { minimizer: [ - new UglifyJsPlugin({ cache: true, parallel: true, sourceMap: false }), + new TerserPlugin({ cache: true, parallel: true, sourceMap: false }), new OptimizeCSSAssetsPlugin({}) ] }, From 9c7ef11bed65368b2d3559d86c968f6db8d15cba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20=C5=81=C4=99picki?= Date: Wed, 12 Dec 2018 15:38:55 +0100 Subject: [PATCH 50/61] Update webpack-cli, fix npm install warnings, colorful webpack output in mix phx.server (#3210) * upgrade webpack-cli version silences babel-preset-es2015 and nomnom npm warnings * preserve colors in webpack output * add description to silence npm warning * disable colors in webpack output on windows --- installer/templates/phx_assets/webpack/package.json | 3 ++- installer/templates/phx_assets/webpack/webpack.config.js | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/installer/templates/phx_assets/webpack/package.json b/installer/templates/phx_assets/webpack/package.json index d8eb8e501a..7be6b8ac07 100644 --- a/installer/templates/phx_assets/webpack/package.json +++ b/installer/templates/phx_assets/webpack/package.json @@ -1,5 +1,6 @@ { "repository": {}, + "description": " ", "license": "MIT", "scripts": { "deploy": "webpack --mode production", @@ -19,6 +20,6 @@ "optimize-css-assets-webpack-plugin": "^4.0.0", "terser-webpack-plugin": "^1.1.0", "webpack": "4.4.0", - "webpack-cli": "^2.0.10" + "webpack-cli": "^3.1.2" } } diff --git a/installer/templates/phx_assets/webpack/webpack.config.js b/installer/templates/phx_assets/webpack/webpack.config.js index ffb12f7ae9..d63d8e7995 100644 --- a/installer/templates/phx_assets/webpack/webpack.config.js +++ b/installer/templates/phx_assets/webpack/webpack.config.js @@ -19,6 +19,9 @@ module.exports = (env, options) => ({ filename: 'app.js', path: path.resolve(__dirname, '../priv/static/js') }, + stats: { + colors: !/^win/i.test(process.platform) + }, module: { rules: [ { From 473a3cb40aae1ba36c70dfc4841ace2d3aab7471 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sat, 15 Dec 2018 22:11:34 +0100 Subject: [PATCH 51/61] Optimize helpers compilation This brings down the time to compile a large router file we use in our tests down to half. --- lib/phoenix/router/helpers.ex | 142 +++++++++++++++------------ test/phoenix/router/helpers_test.exs | 44 --------- 2 files changed, 80 insertions(+), 106 deletions(-) diff --git a/lib/phoenix/router/helpers.ex b/lib/phoenix/router/helpers.ex index c43be25cf8..c6a1704ccd 100644 --- a/lib/phoenix/router/helpers.ex +++ b/lib/phoenix/router/helpers.ex @@ -6,6 +6,12 @@ defmodule Phoenix.Router.Helpers do alias Phoenix.Socket alias Plug.Conn + @anno (if :erlang.system_info(:otp_release) >= '19' do + [generated: true, unquote: false] + else + [line: -1, unquote: false] + end) + @doc """ Callback invoked by the url generated in each helper module. """ @@ -107,6 +113,62 @@ defmodule Phoenix.Router.Helpers do groups = Enum.group_by(routes, fn {route, _exprs} -> route.helper end) catch_all = Enum.map(groups, &defhelper_catch_all/1) + defhelper = quote @anno do + defhelper = fn helper, vars, opts, bins, segs -> + def unquote(:"#{helper}_path")(conn_or_endpoint, unquote(opts), unquote_splicing(vars)) do + unquote(:"#{helper}_path")(conn_or_endpoint, unquote(opts), unquote_splicing(vars), []) + end + + def unquote(:"#{helper}_path")(conn_or_endpoint, unquote(opts), unquote_splicing(vars), params) + when is_list(params) or is_map(params) do + path(conn_or_endpoint, segments(unquote(segs), params, unquote(bins), + {unquote(helper), unquote(opts), unquote(Enum.map(vars, &Macro.to_string/1))})) + end + + def unquote(:"#{helper}_url")(conn_or_endpoint, unquote(opts), unquote_splicing(vars)) do + unquote(:"#{helper}_url")(conn_or_endpoint, unquote(opts), unquote_splicing(vars), []) + end + + def unquote(:"#{helper}_url")(conn_or_endpoint, unquote(opts), unquote_splicing(vars), params) + when is_list(params) or is_map(params) do + url(conn_or_endpoint) <> unquote(:"#{helper}_path")(conn_or_endpoint, unquote(opts), unquote_splicing(vars), params) + end + end + end + + defcatch_all = quote @anno do + defcatch_all = fn helper, bindings, routes -> + for binding <- bindings do + arity = length(binding) + 2 + + def unquote(:"#{helper}_path")(conn_or_endpoint, action, unquote_splicing(binding)) do + path(conn_or_endpoint, "/") + raise_route_error(unquote(helper), :path, unquote(arity), action, []) + end + + def unquote(:"#{helper}_path")(conn_or_endpoint, action, unquote_splicing(binding), params) do + path(conn_or_endpoint, "/") + raise_route_error(unquote(helper), :path, unquote(arity + 1), action, params) + end + + def unquote(:"#{helper}_url")(conn_or_endpoint, action, unquote_splicing(binding)) do + url(conn_or_endpoint) + raise_route_error(unquote(helper), :url, unquote(arity), action, []) + end + + def unquote(:"#{helper}_url")(conn_or_endpoint, action, unquote_splicing(binding), params) do + url(conn_or_endpoint) + raise_route_error(unquote(helper), :url, unquote(arity + 1), action, params) + end + end + + defp raise_route_error(unquote(helper), suffix, arity, action, params) do + Phoenix.Router.Helpers.raise_route_error(__MODULE__, "#{unquote(helper)}_#{suffix}", + arity, action, unquote(routes), params) + end + end + end + # It is in general bad practice to generate large chunks of code # inside quoted expressions. However, we can get away with this # here for two reasons: @@ -120,6 +182,8 @@ defmodule Phoenix.Router.Helpers do @moduledoc """ Module with named helpers generated from #{inspect unquote(env.module)}. """ + unquote(defhelper) + unquote(defcatch_all) unquote_splicing(impls) unquote_splicing(catch_all) @@ -193,16 +257,9 @@ defmodule Phoenix.Router.Helpers do end end - Module.create(Module.concat(env.module, Helpers), code, - line: env.line, file: env.file) + Module.create(Module.concat(env.module, Helpers), code, line: env.line, file: env.file) end - @anno (if :erlang.system_info(:otp_release) >= '19' do - [generated: true] - else - [line: -1] - end) - @doc """ Receives a route and returns the quoted definition for its helper function. @@ -215,26 +272,14 @@ defmodule Phoenix.Router.Helpers do {bins, vars} = :lists.unzip(exprs.binding) segs = expand_segments(exprs.path) - # We are using @anno to avoid warnings in case a path has already been defined. - quote @anno do - def unquote(:"#{helper}_path")(conn_or_endpoint, unquote(opts), unquote_splicing(vars)) do - unquote(:"#{helper}_path")(conn_or_endpoint, unquote(opts), unquote_splicing(vars), []) - end - - def unquote(:"#{helper}_path")(conn_or_endpoint, unquote(opts), unquote_splicing(vars), params) - when is_list(params) or is_map(params) do - path(conn_or_endpoint, segments(unquote(segs), params, unquote(bins), - {unquote(helper), unquote(opts), unquote(Enum.map(vars, &Macro.to_string/1))})) - end - - def unquote(:"#{helper}_url")(conn_or_endpoint, unquote(opts), unquote_splicing(vars)) do - unquote(:"#{helper}_url")(conn_or_endpoint, unquote(opts), unquote_splicing(vars), []) - end - - def unquote(:"#{helper}_url")(conn_or_endpoint, unquote(opts), unquote_splicing(vars), params) - when is_list(params) or is_map(params) do - url(conn_or_endpoint) <> unquote(:"#{helper}_path")(conn_or_endpoint, unquote(opts), unquote_splicing(vars), params) - end + quote do + defhelper.( + unquote(helper), + unquote(Macro.escape(vars)), + unquote(opts), + unquote(Macro.escape(bins)), + unquote(Macro.escape(segs)) + ) end end @@ -249,40 +294,13 @@ defmodule Phoenix.Router.Helpers do |> Enum.map(fn {_, bindings} -> Enum.map(bindings, fn _ -> {:_, [], nil} end) end) |> Enum.uniq() - catch_alls = - for binding <- bindings do - arity = length(binding) + 2 - - # We are using @anno to avoid warnings in case a path has already been defined. - quote @anno do - def unquote(:"#{helper}_path")(conn_or_endpoint, action, unquote_splicing(binding)) do - path(conn_or_endpoint, "/") - raise_route_error(unquote(helper), :path, unquote(arity), action, []) - end - - def unquote(:"#{helper}_path")(conn_or_endpoint, action, unquote_splicing(binding), params) do - path(conn_or_endpoint, "/") - raise_route_error(unquote(helper), :path, unquote(arity + 1), action, params) - end - - def unquote(:"#{helper}_url")(conn_or_endpoint, action, unquote_splicing(binding)) do - url(conn_or_endpoint) - raise_route_error(unquote(helper), :url, unquote(arity), action, []) - end - - def unquote(:"#{helper}_url")(conn_or_endpoint, action, unquote_splicing(binding), params) do - url(conn_or_endpoint) - raise_route_error(unquote(helper), :url, unquote(arity + 1), action, params) - end - end - end - - [quote @anno do - defp raise_route_error(unquote(helper), suffix, arity, action, params) do - Phoenix.Router.Helpers.raise_route_error(__MODULE__, "#{unquote(helper)}_#{suffix}", - arity, action, unquote(routes), params) - end - end | catch_alls] + quote do + defcatch_all.( + unquote(helper), + unquote(Macro.escape(bindings)), + unquote(Macro.escape(routes)) + ) + end end @doc """ diff --git a/test/phoenix/router/helpers_test.exs b/test/phoenix/router/helpers_test.exs index 6d780612cd..7d989403b6 100644 --- a/test/phoenix/router/helpers_test.exs +++ b/test/phoenix/router/helpers_test.exs @@ -4,50 +4,6 @@ defmodule Phoenix.Router.HelpersTest do alias Phoenix.Router.Helpers - ## Unit tests - - test "defhelper with :identifiers" do - route = build(:match, :get, "/foo/:bar", nil, Hello, :world, "hello_world") - assert extract_defhelper(route, 0) == String.trim """ - def(hello_world_path(conn_or_endpoint, :world, bar)) do - hello_world_path(conn_or_endpoint, :world, bar, []) - end - """ - - assert extract_defhelper(route, 1) == String.trim """ - def(hello_world_path(conn_or_endpoint, :world, bar, params) when is_list(params) or is_map(params)) do - path(conn_or_endpoint, segments(("" <> "/foo") <> "/" <> URI.encode(to_param(bar), &URI.char_unreserved?/1), params, ["bar"], {"hello_world", :world, ["bar"]})) - end - """ - end - - test "defhelper with *identifiers" do - route = build(:match, :get, "/foo/*bar", nil, Hello, :world, "hello_world") - - assert extract_defhelper(route, 0) == String.trim """ - def(hello_world_path(conn_or_endpoint, :world, bar)) do - hello_world_path(conn_or_endpoint, :world, bar, []) - end - """ - - assert extract_defhelper(route, 1) == String.trim """ - def(hello_world_path(conn_or_endpoint, :world, bar, params) when is_list(params) or is_map(params)) do - path(conn_or_endpoint, segments(("" <> "/foo") <> "/" <> Enum.map_join(bar, "/", fn s -> URI.encode(s, &URI.char_unreserved?/1) end), params, ["bar"], {"hello_world", :world, ["bar"]})) - end - """ - end - - defp build(kind, verb, path, host, controller, action, helper) do - Phoenix.Router.Route.build(1, kind, verb, path, host, controller, action, helper, [], %{}, %{}) - end - - defp extract_defhelper(route, pos) do - {:__block__, _, block} = Helpers.defhelper(route, Phoenix.Router.Route.exprs(route)) - Enum.fetch!(block, pos) |> Macro.to_string() - end - - ## Integration tests - defmodule Router do use Phoenix.Router From 5cd8f2612a95757dbdceffa40b05eeca231be828 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Thu, 27 Dec 2018 17:03:20 +0100 Subject: [PATCH 52/61] Prepare for firenest integration --- lib/phoenix/endpoint.ex | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/lib/phoenix/endpoint.ex b/lib/phoenix/endpoint.ex index 341e93f75e..2418f2b941 100644 --- a/lib/phoenix/endpoint.ex +++ b/lib/phoenix/endpoint.ex @@ -529,15 +529,6 @@ defmodule Phoenix.Endpoint do &Phoenix.Endpoint.Supervisor.pubsub_server/1) end - # TODO v2: Remove pid version - @doc false - def subscribe(pid, topic) when is_pid(pid) and is_binary(topic) do - IO.warn "#{__MODULE__}.subscribe/2 is deprecated, please use subscribe/1" - Phoenix.PubSub.subscribe(Phoenix.Endpoint.__pubsub_server__!(__MODULE__), pid, topic, []) - end - def subscribe(pid, topic, opts) when is_pid(pid) and is_binary(topic) and is_list(opts) do - Phoenix.PubSub.subscribe(Phoenix.Endpoint.__pubsub_server__!(__MODULE__), pid, topic, opts) - end def subscribe(topic) when is_binary(topic) do Phoenix.PubSub.subscribe(Phoenix.Endpoint.__pubsub_server__!(__MODULE__), topic, []) end @@ -545,12 +536,6 @@ defmodule Phoenix.Endpoint do Phoenix.PubSub.subscribe(Phoenix.Endpoint.__pubsub_server__!(__MODULE__), topic, opts) end - # TODO v2: Remove pid version - @doc false - def unsubscribe(pid, topic) do - IO.warn "#{__MODULE__}.unsubscribe/2 is deprecated, please use unsubscribe/1" - Phoenix.PubSub.unsubscribe(Phoenix.Endpoint.__pubsub_server__!(__MODULE__), topic) - end def unsubscribe(topic) do Phoenix.PubSub.unsubscribe(Phoenix.Endpoint.__pubsub_server__!(__MODULE__), topic) end From ce70f7295c82dd13deb369b1786ea053f079007c Mon Sep 17 00:00:00 2001 From: efexen Date: Tue, 1 Jan 2019 20:20:37 +0100 Subject: [PATCH 53/61] Improved phx.routes umbrella error message --- lib/mix/tasks/phx.routes.ex | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/mix/tasks/phx.routes.ex b/lib/mix/tasks/phx.routes.ex index b37aa26c74..332d215695 100644 --- a/lib/mix/tasks/phx.routes.ex +++ b/lib/mix/tasks/phx.routes.ex @@ -38,14 +38,20 @@ defmodule Mix.Tasks.Phx.Routes do defp router(nil, base) do if Mix.Project.umbrella?() do - Mix.raise "umbrella applications require an explicit router to be given to phx.routes" + Mix.raise """ + umbrella applications require an explicit router to be given to phx.routes, for example: + + $ mix phx.routes MyAppWeb.Router + """ end web_router = web_mod(base, "Router") old_router = app_mod(base, "Router") loaded(web_router) || loaded(old_router) || Mix.raise """ no router found at #{inspect web_router} or #{inspect old_router}. - An explicit router module may be given to phx.routes. + An explicit router module may be given to phx.routes, for example: + + $ mix phx.routes MyAppWeb.Router """ end defp router(router_name, _base) do From 2e4af9977f0fd800d466a3b788f50cc0d9dd0adc Mon Sep 17 00:00:00 2001 From: Chris McCord Date: Tue, 1 Jan 2019 22:54:08 -0500 Subject: [PATCH 54/61] Fixup docs --- lib/mix/tasks/phx.routes.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/mix/tasks/phx.routes.ex b/lib/mix/tasks/phx.routes.ex index 332d215695..96b8ee7fcb 100644 --- a/lib/mix/tasks/phx.routes.ex +++ b/lib/mix/tasks/phx.routes.ex @@ -41,7 +41,7 @@ defmodule Mix.Tasks.Phx.Routes do Mix.raise """ umbrella applications require an explicit router to be given to phx.routes, for example: - $ mix phx.routes MyAppWeb.Router + $ mix phx.routes MyAppWeb.Router """ end web_router = web_mod(base, "Router") @@ -51,7 +51,7 @@ defmodule Mix.Tasks.Phx.Routes do no router found at #{inspect web_router} or #{inspect old_router}. An explicit router module may be given to phx.routes, for example: - $ mix phx.routes MyAppWeb.Router + $ mix phx.routes MyAppWeb.Router """ end defp router(router_name, _base) do From c4dd2cfba37a6225b523481658bac125f53f20d0 Mon Sep 17 00:00:00 2001 From: Monting Date: Wed, 2 Jan 2019 17:22:00 -0500 Subject: [PATCH 55/61] URL encode default phoenix.css template's `