diff --git a/assets/js/app.js b/assets/js/app.js index 268da37426..777795ea27 100644 --- a/assets/js/app.js +++ b/assets/js/app.js @@ -3,14 +3,14 @@ // its own CSS file. import { } from "./ui"; import { + initBoxPlotTransactionsAvgDurationChart, initNetworkTransactionsCountChart, initNetworkTransactionsAvgDurationChart, initNodeTransactionsCountChart, - initNodeTransactionsAvgDurationChart, + updateBoxPlotTransactionsAvgDurationChart, updateNetworkTransactionsCountChart, updateNetworkTransactionsAvgDurationChart, - updateNodeTransactionsCountChart, - updateNodeTransactionsAvgDurationChart + updateNodeTransactionsCountChart } from "./metric_config.js"; import { createWorldmap, updateWorldmap } from "./worldmap"; @@ -116,11 +116,12 @@ Hooks.node_transactions_count_chart = { } }; -Hooks.node_transactions_avg_duration_chart = { + +Hooks.boxplot_transactions_avg_duration = { mounted() { - const chart = initNodeTransactionsAvgDurationChart(this.el.querySelector(".chart")); - this.handleEvent("node_transactions_avg_duration", (stats) => { - updateNodeTransactionsAvgDurationChart(chart, stats); + const chart = initBoxPlotTransactionsAvgDurationChart(this.el.querySelector(".chart")); + this.handleEvent("boxplot_transactions_avg_duration", (stats) => { + updateBoxPlotTransactionsAvgDurationChart(chart, stats); }); } }; diff --git a/assets/js/metric_config.js b/assets/js/metric_config.js index 2b4eb37130..7c6699364e 100644 --- a/assets/js/metric_config.js +++ b/assets/js/metric_config.js @@ -1,6 +1,6 @@ import * as echarts from "echarts"; -export function initNetworkTransactionsCountChart(el) { +export function initBoxPlotTransactionsAvgDurationChart(el) { let chart = echarts.init(el); chart.setOption({ grid: { @@ -11,7 +11,7 @@ export function initNetworkTransactionsCountChart(el) { }, title: { left: "center", - text: "Transactions count", + text: "Average validation time", textStyle: { fontSize: 14, }, @@ -25,6 +25,7 @@ export function initNetworkTransactionsCountChart(el) { yAxis: { type: "value", axisLabel: { + formatter: '{value} ms', textStyle: { fontSize: 14, }, @@ -32,18 +33,15 @@ export function initNetworkTransactionsCountChart(el) { }, series: [ { - type: "line", - areaStyle: {}, - data: [], - smooth: 0.2, + type: 'boxplot', tooltip: { valueFormatter: value => { - const plural = value > 1 ? "s" : "" - return value + ' transaction' + plural + if (value == 0) return "-" + + return Number.parseFloat(value).toFixed(1) + ' ms' } }, - showSymbol: false - }, + } ], }); @@ -54,13 +52,11 @@ export function initNetworkTransactionsCountChart(el) { return chart; } -export function initNetworkTransactionsAvgDurationChart(el) { + + +export function initNetworkTransactionsCountChart(el) { let chart = echarts.init(el); chart.setOption({ - legend: { - bottom: 0, - type: 'scroll', - }, grid: { left: "10%", right: "5%", @@ -69,7 +65,7 @@ export function initNetworkTransactionsAvgDurationChart(el) { }, title: { left: "center", - text: "Average validation time", + text: "Transactions count", textStyle: { fontSize: 14, }, @@ -83,26 +79,26 @@ export function initNetworkTransactionsAvgDurationChart(el) { yAxis: { type: "value", axisLabel: { - formatter: '{value} ms', textStyle: { fontSize: 14, }, }, }, - series: [{ - type: "line", - areaStyle: {}, - data: [], - smooth: 0.2, - showSymbol: false, - tooltip: { - valueFormatter: value => { - if (value == 0) return "-" - - return Number.parseFloat(value).toFixed(1) + ' ms' - } + series: [ + { + type: "line", + areaStyle: {}, + data: [], + smooth: 0.2, + tooltip: { + valueFormatter: value => { + const plural = value > 1 ? "s" : "" + return value + ' transaction' + plural + } + }, + showSymbol: false }, - },], + ], }); window.addEventListener("resize", function () { @@ -112,7 +108,7 @@ export function initNetworkTransactionsAvgDurationChart(el) { return chart; } -export function initNodeTransactionsCountChart(el) { +export function initNetworkTransactionsAvgDurationChart(el) { let chart = echarts.init(el); chart.setOption({ legend: { @@ -127,7 +123,7 @@ export function initNodeTransactionsCountChart(el) { }, title: { left: "center", - text: "Transactions count by node", + text: "Average validation time", textStyle: { fontSize: 14, }, @@ -141,12 +137,26 @@ export function initNodeTransactionsCountChart(el) { yAxis: { type: "value", axisLabel: { + formatter: '{value} ms', textStyle: { fontSize: 14, }, }, }, - series: [], + series: [{ + type: "line", + areaStyle: {}, + data: [], + smooth: 0.2, + showSymbol: false, + tooltip: { + valueFormatter: value => { + if (value == 0) return "-" + + return Number.parseFloat(value).toFixed(1) + ' ms' + } + }, + },], }); window.addEventListener("resize", function () { @@ -155,7 +165,8 @@ export function initNodeTransactionsCountChart(el) { return chart; } -export function initNodeTransactionsAvgDurationChart(el) { + +export function initNodeTransactionsCountChart(el) { let chart = echarts.init(el); chart.setOption({ legend: { @@ -170,7 +181,7 @@ export function initNodeTransactionsAvgDurationChart(el) { }, title: { left: "center", - text: "Average validation time by node", + text: "Transactions count by node (last 60min)", textStyle: { fontSize: 14, }, @@ -179,18 +190,26 @@ export function initNodeTransactionsAvgDurationChart(el) { trigger: 'axis' }, xAxis: { + show: false, type: "category" }, yAxis: { type: "value", axisLabel: { - formatter: '{value} ms', textStyle: { fontSize: 14, }, }, }, - series: [], + series: [{ + type: "bar", + tooltip: { + valueFormatter: value => { + const plural = value > 1 ? "s" : "" + return value + ' transaction' + plural + } + } + }] }); window.addEventListener("resize", function () { @@ -200,11 +219,24 @@ export function initNodeTransactionsAvgDurationChart(el) { return chart; } +export function updateBoxPlotTransactionsAvgDurationChart(chart, stats) { + chart.setOption({ + xAxis: { + data: Object.keys(stats) + .map(timestampToString) + }, + series: [{ + data: Object.values(stats) + .map((durationsBucket) => durationsBucket.map((duration) => duration / 1000000)) + }], + }); +} + export function updateNetworkTransactionsCountChart(chart, stats) { chart.setOption({ xAxis: { data: Object.keys(stats) - .map((timestamp) => timestampToString(timestamp)) + .map(timestampToString) }, series: [{ data: Object.values(stats) @@ -216,7 +248,7 @@ export function updateNetworkTransactionsAvgDurationChart(chart, stats) { chart.setOption({ xAxis: { data: Object.keys(stats) - .map((timestamp) => timestampToString(timestamp)) + .map(timestampToString) }, series: [{ data: Object.values(stats) @@ -227,62 +259,17 @@ export function updateNetworkTransactionsAvgDurationChart(chart, stats) { export function updateNodeTransactionsCountChart(chart, stats) { chart.setOption({ - series: Object.entries(stats) - .map(([node_public_key, data]) => { - let seriesData = []; - for (let i = 0; i < data.timestamps.length; i++) { - seriesData.push([ - timestampToString(data.timestamps[i]), - data.counts[i] - ]); - } - - return { - type: "line", - name: format_public_key(node_public_key), - smooth: 0.2, - tooltip: { - valueFormatter: value => { - const plural = value > 1 ? "s" : "" - return value + ' transaction' + plural - } - }, - showSymbol: false, - data: seriesData - }; - }) + xAxis: { + data: Object.keys(stats) + .map(format_public_key) + }, + series: [{ + data: Object.values(stats) + }], }); } -export function updateNodeTransactionsAvgDurationChart(chart, stats) { - chart.setOption({ - series: Object.entries(stats) - .map(([node_public_key, data]) => { - let seriesData = []; - for (let i = 0; i < data.timestamps.length; i++) { - seriesData.push([ - timestampToString(data.timestamps[i]), - data.average_durations[i] / 1_000_000 - ]); - } - - return { - type: "line", - name: format_public_key(node_public_key), - smooth: 0.2, - tooltip: { - valueFormatter: value => { - if (value == 0) return "-" - return Number.parseFloat(value).toFixed(1) + ' ms' - } - }, - showSymbol: false, - data: seriesData - }; - }) - }); -} function timestampToString(timestamp) { return dateToString(new Date(timestamp * 1000)); diff --git a/config/dev.exs b/config/dev.exs index e50d3123c5..0036b2ecd1 100755 --- a/config/dev.exs +++ b/config/dev.exs @@ -44,10 +44,32 @@ config :archethic, Archethic.Bootstrap, config :archethic, Archethic.Bootstrap.NetworkInit, genesis_pools: [ %{ + # faucet address: "00001259AE51A6E63A1E04E308C5E769E0E9D15BFFE4E7880266C8FA10C3ADD7B7A2" |> Base.decode16!(case: :mixed), amount: 1_000_000_000_000_000 + }, + %{ + # seed + address: + "00005cb8bdbca14bb90aeba901f6ec06499d6da6f77879ab2250da237a8a58cb4cbd" + |> Base.decode16!(case: :mixed), + amount: 1_000_000_000_000_000 + }, + %{ + # bastien + address: + "000030831178cd6a49fe446778455a7a980729a293bfa16b0a1d2743935db210da76" + |> Base.decode16!(case: :mixed), + amount: 1_000_000_000_000_000 + }, + %{ + # sc2 + address: + "0000238c3a9cb5bfb7a863d698b71dfff0c9c5c40cff21ebda2d83ebaedda1c6e10d" + |> Base.decode16!(case: :mixed), + amount: 1_000_000_000_000_000 } ] @@ -142,7 +164,7 @@ config :archethic, ArchethicWeb.Endpoint, URI.to_string(%URI{ scheme: "https", host: System.get_env("ARCHETHIC_DOMAIN_NAME", "localhost"), - port: System.get_env("ARCHETHIC_HTTPS_PORT", "5000") |> String.to_integer(), + port: System.get_env("ARCHETHIC_HTTPS_PORT", "10000") |> String.to_integer(), path: "/explorer" }), http: [port: System.get_env("ARCHETHIC_HTTP_PORT", "4000") |> String.to_integer()], @@ -159,7 +181,7 @@ config :archethic, ArchethicWeb.Endpoint, } ], https: [ - port: System.get_env("ARCHETHIC_HTTPS_PORT", "5000") |> String.to_integer(), + port: System.get_env("ARCHETHIC_HTTPS_PORT", "10000") |> String.to_integer(), cipher_suite: :strong, otp_app: :archethic, sni_fun: &ArchethicWeb.AEWeb.Domain.sni/1, @@ -170,13 +192,13 @@ config :archethic, ArchethicWeb.Endpoint, config :archethic, :throttle, by_ip_high: [ period: 1000, - limit: System.get_env("ARCHETHIC_THROTTLE_IP_HIGH", "5000") |> String.to_integer() + limit: System.get_env("ARCHETHIC_THROTTLE_IP_HIGH", "10000") |> String.to_integer() ], by_ip_low: [ period: 1000, - limit: System.get_env("ARCHETHIC_THROTTLE_IP_LOW", "5000") |> String.to_integer() + limit: System.get_env("ARCHETHIC_THROTTLE_IP_LOW", "10000") |> String.to_integer() ], by_ip_and_path: [ period: 1000, - limit: System.get_env("ARCHETHIC_THROTTLE_IP_AND_PATH", "5000") |> String.to_integer() + limit: System.get_env("ARCHETHIC_THROTTLE_IP_AND_PATH", "10000") |> String.to_integer() ] diff --git a/lib/archethic/bootstrap/network_init.ex b/lib/archethic/bootstrap/network_init.ex index 8f013456ba..71ba3d2cf0 100644 --- a/lib/archethic/bootstrap/network_init.ex +++ b/lib/archethic/bootstrap/network_init.ex @@ -60,7 +60,7 @@ defmodule Archethic.Bootstrap.NetworkInit do @spec create_storage_nonce() :: :ok def create_storage_nonce do Logger.info("Create storage nonce") - storage_nonce_seed = :crypto.strong_rand_bytes(32) + storage_nonce_seed = <<0::256>> {_, pv} = Crypto.generate_deterministic_keypair(storage_nonce_seed) Crypto.decrypt_and_set_storage_nonce(Crypto.ec_encrypt(pv, Crypto.last_node_public_key())) end diff --git a/lib/archethic/utils.ex b/lib/archethic/utils.ex index f6fae211d7..b9f4b26845 100644 --- a/lib/archethic/utils.ex +++ b/lib/archethic/utils.ex @@ -789,23 +789,39 @@ defmodule Archethic.Utils do @doc """ Get the median value from a list. + You may send the sorted: true flag to avoid sorting an already-sorted list + ## Examples iex> Utils.median([]) nil - iex> Utils.median([1,2,3]) + iex> Utils.median([3]) + 3 + iex> Utils.median([2,2,1]) 2 - iex> Utils.median([1,2,3,4]) + iex> Utils.median([1,2,2,2,2], true) + 2 + iex> Utils.median([3,1,2,4]) + 2.5 + iex> Utils.median([1,2,3,4], true) 2.5 """ - @spec median([number]) :: number | nil - def median([]), do: nil + @spec median([number], Keyword.t()) :: number | nil + def median(numbers, opts \\ []) + + def median([], _opts), do: nil ## To avoid all calculation from general clause to follow - def median([number]), do: number + def median([number], _opts), do: number ## To avoid all calculation from general clause to follow - def median(numbers) do - sorted = Enum.sort(numbers) + def median(numbers, opts) do + sorted = + if Keyword.get(opts, :sorted, false) do + Enum.sort(numbers) + else + numbers + end + length_list = length(sorted) case rem(length_list, 2) do diff --git a/lib/archethic_web/explorer/live/dashboard_live.ex b/lib/archethic_web/explorer/live/dashboard_live.ex index f975f3c800..ccb0cb8b70 100755 --- a/lib/archethic_web/explorer/live/dashboard_live.ex +++ b/lib/archethic_web/explorer/live/dashboard_live.ex @@ -4,6 +4,7 @@ defmodule ArchethicWeb.Explorer.DashboardLive do """ use ArchethicWeb.Explorer, :live_view + alias Archethic.Utils alias ArchethicWeb.DashboardMetricsAggregator alias ArchethicWeb.Explorer.DashboardView @@ -15,16 +16,18 @@ defmodule ArchethicWeb.Explorer.DashboardLive do Process.send_after(self(), :tick, 30_000) end + # TODO: check if it's called once or twice + version = Application.spec(:archethic, :vsn) stats = fetch_stats() {:ok, socket |> assign(version: version) + |> push_event("boxplot_transactions_avg_duration", boxplot_transactions_avg_duration(stats)) |> push_event("network_transactions_count", network_transactions_count(stats)) |> push_event("network_transactions_avg_duration", network_transactions_avg_duration(stats)) - |> push_event("node_transactions_count", node_transactions_count(stats)) - |> push_event("node_transactions_avg_duration", node_transactions_avg_duration(stats))} + |> push_event("node_transactions_count", node_transactions_count(stats))} end def render(assigns) do @@ -40,10 +43,10 @@ defmodule ArchethicWeb.Explorer.DashboardLive do {:noreply, socket + |> push_event("boxplot_transactions_avg_duration", boxplot_transactions_avg_duration(stats)) |> push_event("network_transactions_count", network_transactions_count(stats)) |> push_event("network_transactions_avg_duration", network_transactions_avg_duration(stats)) - |> push_event("node_transactions_count", node_transactions_count(stats)) - |> push_event("node_transactions_avg_duration", node_transactions_avg_duration(stats))} + |> push_event("node_transactions_count", node_transactions_count(stats))} end def display_time(datetime) do @@ -68,6 +71,35 @@ defmodule ArchethicWeb.Explorer.DashboardLive do |> Enum.sort_by(fn {{_, datetime}, _} -> datetime end, {:asc, DateTime}) end + defp boxplot_transactions_avg_duration(stats) do + stats + |> Enum.reduce(%{}, fn {{_node, datetime}, duration_by_address}, acc -> + durations = + duration_by_address + |> Enum.map(&elem(&1, 1)) + + Map.update( + acc, + DateTime.to_unix(datetime), + durations, + &(&1 ++ durations) + ) + end) + |> Enum.map(fn {timestamp, durations} -> + durations_length = length(durations) + + sorted = Enum.sort(durations) + min = hd(sorted) + max = List.last(sorted) + q2 = Utils.median(sorted, sorted: true) + q1 = Utils.median(Enum.take(sorted, div(durations_length, 2)), sorted: true) + q3 = Utils.median(Enum.drop(sorted, div(durations_length + 1, 2)), sorted: true) + + {timestamp, [min, q1, q2, q3, max]} + end) + |> Enum.into(%{}) + end + defp network_transactions_count(stats) do stats |> Enum.reduce(%{}, fn {{_node, datetime}, duration_by_address}, acc -> @@ -113,57 +145,21 @@ defmodule ArchethicWeb.Explorer.DashboardLive do {timestamp, 0} {timestamp, %{count: count, sum: sum}} -> - {timestamp, div(sum, count) / 1_000_000} + {timestamp, sum / count} end) |> Enum.into(%{}) end defp node_transactions_count(stats) do - Enum.reduce(stats, %{}, fn {{node, datetime}, duration_by_address}, acc -> - timestamp = DateTime.to_unix(datetime) + Enum.reduce(stats, %{}, fn {{node, _datetime}, duration_by_address}, acc -> count = length(duration_by_address) - default = %{timestamps: [timestamp], counts: [count]} - - Map.update(acc, node, default, fn %{timestamps: timestamps_acc, counts: counts_acc} -> - %{timestamps: [timestamp | timestamps_acc], counts: [count | counts_acc]} - end) - end) - |> Enum.map(fn {node, %{timestamps: timestamps, counts: counts}} -> - {node, %{timestamps: Enum.reverse(timestamps), counts: Enum.reverse(counts)}} - end) - |> Enum.into(%{}) - end - - defp node_transactions_avg_duration(stats) do - Enum.reduce(stats, %{}, fn {{node, datetime}, duration_by_address}, acc -> - timestamp = DateTime.to_unix(datetime) - durations = Enum.map(duration_by_address, &elem(&1, 1)) - count = length(durations) - - average_duration = - if count == 0 do - 0 - else - Enum.sum(durations) / count - end - - default = %{timestamps: [timestamp], average_durations: [average_duration]} - - Map.update(acc, node, default, fn %{ - timestamps: timestamps_acc, - average_durations: average_durations_acc - } -> - %{ - timestamps: [timestamp | timestamps_acc], - average_durations: [average_duration | average_durations_acc] - } - end) - end) - |> Enum.map(fn {node, %{timestamps: timestamps, average_durations: average_durations}} -> - {node, - %{timestamps: Enum.reverse(timestamps), average_durations: Enum.reverse(average_durations)}} + Map.update( + acc, + node, + count, + &(&1 + count) + ) end) - |> Enum.into(%{}) end end diff --git a/lib/archethic_web/explorer/templates/dashboard/dashboard.html.heex b/lib/archethic_web/explorer/templates/dashboard/dashboard.html.heex index c15318299a..2b2d88dc76 100644 --- a/lib/archethic_web/explorer/templates/dashboard/dashboard.html.heex +++ b/lib/archethic_web/explorer/templates/dashboard/dashboard.html.heex @@ -20,7 +20,7 @@
-
+
diff --git a/mix.exs b/mix.exs index a657abc63f..94e6e9fc82 100644 --- a/mix.exs +++ b/mix.exs @@ -13,7 +13,7 @@ defmodule Archethic.MixProject do elixir: "~> 1.14", start_permanent: Mix.env() == :prod, deps: deps(), - compilers: [:elixir_make] ++ Mix.compilers(), + # compilers: [:elixir_make] ++ Mix.compilers(), elixirc_paths: elixirc_paths(Mix.env()), elixirc_options: [warnings_as_errors: true], dialyzer: dialyzer() @@ -136,7 +136,7 @@ defmodule Archethic.MixProject do defp aliases do [ "check.updates": ["cmd mix hex.outdated --within-requirements || echo 'Updates available!'"], - compile: ["git_hooks.install", "compile"], + # compile: ["git_hooks.install", "compile"], "dev.update_deps": [ "hex.outdated --within-requirements", "deps.update --all --only", diff --git a/priv/static/cache_manifest.json b/priv/static/cache_manifest.json index 7352d80533..1e4dd9e40c 100644 --- a/priv/static/cache_manifest.json +++ b/priv/static/cache_manifest.json @@ -1,6 +1,6 @@ { "!comment!":"This is file was auto-generated by `mix phx.digest`. Remove it and all generated artefacts with `mix phx.digest.clean --all`", "version":1, - "latest":{"css/app.css":"css/app-00f83227a76f1ff82779ab6fa2fc6558.css","favicon.ico":"favicon-a8ca4e3a2bb8fea46a9ee9e102e7d3eb.ico","images/logo_full_white.svg":"images/logo_full_white-1f74208d75fe567d7a94263a1aca6fe0.svg","js/app.js":"js/app-0966d7c17bd5dd772e67cae65b0ddc7a.js","robots.txt":"robots-067185ba27a5d9139b10a759679045bf.txt"}, - "digests":{"css/app-00f83227a76f1ff82779ab6fa2fc6558.css":{"digest":"00f83227a76f1ff82779ab6fa2fc6558","logical_path":"css/app.css","mtime":63870315418,"sha512":"JEYGsXduQvkD/f1WezVoztHGgYgHT3OjOdoOff5xGq7R7RrsacN3ebFEDnANozBAMTCu8AFLAncGdlZYFpuJNA==","size":210771},"favicon-a8ca4e3a2bb8fea46a9ee9e102e7d3eb.ico":{"digest":"a8ca4e3a2bb8fea46a9ee9e102e7d3eb","logical_path":"favicon.ico","mtime":63870315418,"sha512":"vCKvNNXeSP/2RRr6IN8PVa8/Hl6ImUO7miAOIMABYwbCzlm0UTRsY30uYb1k5gcCOPIsv6nZuFlJj/h8z+InzQ==","size":1258},"images/logo_full_white-1f74208d75fe567d7a94263a1aca6fe0.svg":{"digest":"1f74208d75fe567d7a94263a1aca6fe0","logical_path":"images/logo_full_white.svg","mtime":63870315418,"sha512":"JVndjFW4w92w+wyzS1rXnfqg3zFGeOh7x8GQ3CB+MD/obVwlr7N7bhxYJ5A458Lmt9AK1yu2OBBRGyM3+2lGKA==","size":55506},"js/app-0635b8508a44f64d2a0e5281012a4604.js":{"digest":"0635b8508a44f64d2a0e5281012a4604","logical_path":"js/app.js","mtime":63870220568,"sha512":"mhTuzGvChfwyNKy3GPyO0FfOr2KnyXzNntIS8S/RNpd9w4g0E0Gw5M1FkL/QaqHRoZiXN+t8sqJxfwdfWD6wYg==","size":5318641},"js/app-0966d7c17bd5dd772e67cae65b0ddc7a.js":{"digest":"0966d7c17bd5dd772e67cae65b0ddc7a","logical_path":"js/app.js","mtime":63870315418,"sha512":"apfr9x8IGAaFtWnf99l5z3Cpkr8Qr+bsQbg9nTdLY1isIwibx6voEx3LK5nXAZIDFOjvgsHRL3vjU+xNhMkHgQ==","size":2835800},"js/app-132d79fcb3b3c04c957f985665bd505d.js":{"digest":"132d79fcb3b3c04c957f985665bd505d","logical_path":"js/app.js","mtime":63870220641,"sha512":"vOJwbQNSB/LKtTWHUPax+iuEq+/+g0tvpR6+m6pHUu1T/+8DugUwLhFmzGG6quME4BHZ2uVB5Vbs0crEa1B2dA==","size":5318713},"js/app-46c43d95c0ce9dfcccc53f35a583d6a4.js":{"digest":"46c43d95c0ce9dfcccc53f35a583d6a4","logical_path":"js/app.js","mtime":63870222877,"sha512":"4f+t4VpBxn362tyhLxLfHEOq9Pu/mTNr424PBzMmYpSdCq8YVVRpcY84fbDL7072P9n43GuV6uWBD0o+Zuqe9A==","size":5319000},"js/app-62fa31f8a5118f544670cc577522eb6a.js":{"digest":"62fa31f8a5118f544670cc577522eb6a","logical_path":"js/app.js","mtime":63870223169,"sha512":"K/+sFQK/wZjLtGqAJY4PVyeM0+OWHTgZSY9uHckLy4z+WDP4+G9n6G6HRzChdowS/IZCo67C14LR5yky3QkRWw==","size":5319096},"js/app-6402ab373cc443ece8668f118884b380.js":{"digest":"6402ab373cc443ece8668f118884b380","logical_path":"js/app.js","mtime":63870218273,"sha512":"F+uWokS9ws6KIEt4UwE+9tiP4Yl9nE1gcghExaiWc8vKRyEnjgZTM5sSPrIC4Z3WcTFz8Y4UMLq+narqjyHhsA==","size":5318793},"js/app-6a5252233d955481b9d39dbfb8b35841.js":{"digest":"6a5252233d955481b9d39dbfb8b35841","logical_path":"js/app.js","mtime":63870219877,"sha512":"Dek8aNtfQEsgtgchRFaEhvm0NIgRYphOBOPd7lLAJTRw4ObxCSDodjzTW6fIkFePFZdKXURgFDptUfAxDsrvRw==","size":5318683},"js/app-707454a0f24870acf40cb67888ccfcb4.js":{"digest":"707454a0f24870acf40cb67888ccfcb4","logical_path":"js/app.js","mtime":63870200444,"sha512":"tHMBgfqPyz1ni156EYZ66XqQqhzIdaeee/JhKouG+O2FGg2sJuRbfTJeCYfEj6ampjvaLTlnknSpdpRAqasbuA==","size":2835100},"js/app-7153aa4d9451ae25aa698670bf6238a4.js":{"digest":"7153aa4d9451ae25aa698670bf6238a4","logical_path":"js/app.js","mtime":63870215538,"sha512":"DMzgC1O2SXOEU0yeBp40fT3peczD9zOnoQkM3MF6XKYsuefYcwEi1fMmqbGOcC7jEGCQUY5NAM5IzGuz4Cw3NA==","size":2834957},"js/app-727f3cac32d69ccda86285181d471ca9.js":{"digest":"727f3cac32d69ccda86285181d471ca9","logical_path":"js/app.js","mtime":63870223145,"sha512":"zJR0Cf04o1XZzx9aRSf0y4hMt7iiAPeTlZi+G/hYV3W61fdghmspAMlpvUtUmYvt084QMIrcB6KNEFujH0KsJQ==","size":5319073},"js/app-772b8508861b9092fc44d7924256f519.js":{"digest":"772b8508861b9092fc44d7924256f519","logical_path":"js/app.js","mtime":63870216339,"sha512":"nZ1WC4c0flCnL/wPrayhBKGoE9TGS8Si4qG1nNwvm2aYhBPiBzm6hpkeK5LnTNrgU5om0pEsxgyYSN7ipaBVLg==","size":5318825},"js/app-7a0cfba1063df143013fa81443945ab3.js":{"digest":"7a0cfba1063df143013fa81443945ab3","logical_path":"js/app.js","mtime":63870218199,"sha512":"XNFE7c48ntlSNbM2U1W0hUKfLCfdLt/inxD8zPjE2Cpgp+Alb0FlHKrq6l9WgzOHhyTbuk1cWRckKh5UCEzNEQ==","size":5318659},"js/app-af2c5fb9a0c530e424b87fb3f4944ebe.js":{"digest":"af2c5fb9a0c530e424b87fb3f4944ebe","logical_path":"js/app.js","mtime":63870314663,"sha512":"Xgihe0e26jVncPJxBdzW2A05YyxQAohrwfDlfNte0FdD4aEkBEj7XagX9ngTsG4jkcftUrRPagz47Z7csaOAeQ==","size":2835711},"js/app-be27081654b0a72101b2b4d8293fab1d.js":{"digest":"be27081654b0a72101b2b4d8293fab1d","logical_path":"js/app.js","mtime":63870219395,"sha512":"7rWx+wgYfMJ0VjQNMKJ6yRszT+2SxeBfpuwm64Q837OKy6INsY2UEyAMSls+IAKjOu0jYmN06Zm+4j/Eq+GBww==","size":5318646},"js/app-c961222adb67ccebeadee89404ddf3e2.js":{"digest":"c961222adb67ccebeadee89404ddf3e2","logical_path":"js/app.js","mtime":63870221588,"sha512":"FfzZ6RiIgp9M4/ulQJh7jmAb5ek0zf8M+h1vxAAe9fkj6J0cFZg0kan3IuK8pLzZ+hJxdu1EvDVP5Z+1S/kKyA==","size":5318806},"js/app-d2980a638c3f78f4d859fe898385fd41.js":{"digest":"d2980a638c3f78f4d859fe898385fd41","logical_path":"js/app.js","mtime":63870315363,"sha512":"+TtgzzvkV0xp/gKmIMKqabKKkJHeVpuVLPQfnQE8fSxLusceVsgsgCfdxByB6+A5Vn6z8Ya0b3ySEJZ+i31sWg==","size":2835725},"js/app-ee0c30743412e744696376b74658d802.js":{"digest":"ee0c30743412e744696376b74658d802","logical_path":"js/app.js","mtime":63870220517,"sha512":"yZL7Y5HGoPCvBuqqZLF+hFlWCznZO1r9SdYRLZOWBUhuL+PR4WS6ufDu47e4xkBDthZP6mJGb/2D+Ia2UD1vdA==","size":5318763},"js/app-f3b8d86bf755d988d3cb45a3b8f2fa7c.js":{"digest":"f3b8d86bf755d988d3cb45a3b8f2fa7c","logical_path":"js/app.js","mtime":63870216792,"sha512":"5OLZRuI+Kq2Rvdsx4zXKz5EiwFsdjkp9Nb6irptcezHY/32gbVCSXf2S5y2QiiNEaxop9OTj/vb7Ad65LQ5k/w==","size":5318709},"js/app-f3ddb38b1da003de316d6c52389864b1.js":{"digest":"f3ddb38b1da003de316d6c52389864b1","logical_path":"js/app.js","mtime":63870216586,"sha512":"Md4tLe/4ua6amKo0UhZA47itpphEECsEjJBK/A8YxTJnI0tBPcOh/hu+p0Mq2KLNNxDaiO+ZsydHxuDKlmDuTQ==","size":5318674},"robots-067185ba27a5d9139b10a759679045bf.txt":{"digest":"067185ba27a5d9139b10a759679045bf","logical_path":"robots.txt","mtime":63870315418,"sha512":"8FA6TZeCo3hFYcQ+9knbh3TrhkqGzYJx/uD5yRvggwM7gwfBPrPGqqrbVTZjnnnvlsw1zs1WJTPYez1zr/U4ug==","size":202}} + "latest":{"css/app.css":"css/app-00f83227a76f1ff82779ab6fa2fc6558.css","favicon.ico":"favicon-a8ca4e3a2bb8fea46a9ee9e102e7d3eb.ico","images/logo_full_white.svg":"images/logo_full_white-1f74208d75fe567d7a94263a1aca6fe0.svg","js/app.js":"js/app-b87cc1de5c3e10d451f6b10686864367.js","robots.txt":"robots-067185ba27a5d9139b10a759679045bf.txt"}, + "digests":{"js/app-7a0cfba1063df143013fa81443945ab3.js":{"digest":"7a0cfba1063df143013fa81443945ab3","logical_path":"js/app.js","mtime":63870218199,"sha512":"XNFE7c48ntlSNbM2U1W0hUKfLCfdLt/inxD8zPjE2Cpgp+Alb0FlHKrq6l9WgzOHhyTbuk1cWRckKh5UCEzNEQ==","size":5318659},"js/app-d7ee25dee00c52d9a722de5657f1be50.js":{"digest":"d7ee25dee00c52d9a722de5657f1be50","logical_path":"js/app.js","mtime":63870398224,"sha512":"raJWST7OIDwJGU+bR1IVjCfMf66usn/XB4aJQd7sNyY7QqVEYupkPBaA3TrNGWRww69Ts1OuJy8p3Lic4Tj23Q==","size":2836451},"js/app-e9c888ce3a8cd148abb2a27d3d188fe1.js":{"digest":"e9c888ce3a8cd148abb2a27d3d188fe1","logical_path":"js/app.js","mtime":63870404400,"sha512":"+Aph7Fuc+OtXoerQ0gIsNYZWzsPey6GWWYSFJ0eDHlNzg6KcmVIyUfsq7DXWBWoFgoAl5WQcQIbgaASUI953eQ==","size":2835515},"js/app-d6df4a5afeaa20ec31a9170a8e3bddb4.js":{"digest":"d6df4a5afeaa20ec31a9170a8e3bddb4","logical_path":"js/app.js","mtime":63870398175,"sha512":"nhDVh3hXpkH+eUyIBnfSWqlNFnAj2yO//+InSxd6K5IRDb1QxFU6fp2YaKbM7g78YDxx/CzBRI3PKPOEnVwfxg==","size":2836465},"js/app-89b7452fdcce05b893350a7147b62dcc.js":{"digest":"89b7452fdcce05b893350a7147b62dcc","logical_path":"js/app.js","mtime":63870396290,"sha512":"BV5f32hIHwp7QvFSgd3DpIx940TRaKQLSfFkGR0jhIMIwKsu0HjqNPsHTMCluG2qi+mRkAvQ7Gfj3u6tWb6xlw==","size":2835812},"js/app-29594aa9594b85f09b7c7c6d3c8003c0.js":{"digest":"29594aa9594b85f09b7c7c6d3c8003c0","logical_path":"js/app.js","mtime":63870398602,"sha512":"FIlsBohYhJxXRDvuU4pVLGy0Iwh7lJdr0/8m8FTrPEVWy27GiLdbgagjaGWi7qbdP9DiTjXtaz6KfUZWojU7UQ==","size":2836498},"js/app-10293cdbb7c72c5c2bc4bfbedf283658.js":{"digest":"10293cdbb7c72c5c2bc4bfbedf283658","logical_path":"js/app.js","mtime":63870405432,"sha512":"DVZ71TaNYGmwzLNBEJinbd29Jsin1l2u3bOjSswWWeuraLlgBJAogeUsNYmyXDjZry/KKSbWt3B3hMu5pvn34Q==","size":2835485},"js/app-707454a0f24870acf40cb67888ccfcb4.js":{"digest":"707454a0f24870acf40cb67888ccfcb4","logical_path":"js/app.js","mtime":63870200444,"sha512":"tHMBgfqPyz1ni156EYZ66XqQqhzIdaeee/JhKouG+O2FGg2sJuRbfTJeCYfEj6ampjvaLTlnknSpdpRAqasbuA==","size":2835100},"js/app-f3b8d86bf755d988d3cb45a3b8f2fa7c.js":{"digest":"f3b8d86bf755d988d3cb45a3b8f2fa7c","logical_path":"js/app.js","mtime":63870216792,"sha512":"5OLZRuI+Kq2Rvdsx4zXKz5EiwFsdjkp9Nb6irptcezHY/32gbVCSXf2S5y2QiiNEaxop9OTj/vb7Ad65LQ5k/w==","size":5318709},"js/app-772b8508861b9092fc44d7924256f519.js":{"digest":"772b8508861b9092fc44d7924256f519","logical_path":"js/app.js","mtime":63870216339,"sha512":"nZ1WC4c0flCnL/wPrayhBKGoE9TGS8Si4qG1nNwvm2aYhBPiBzm6hpkeK5LnTNrgU5om0pEsxgyYSN7ipaBVLg==","size":5318825},"js/app-d2980a638c3f78f4d859fe898385fd41.js":{"digest":"d2980a638c3f78f4d859fe898385fd41","logical_path":"js/app.js","mtime":63870315363,"sha512":"+TtgzzvkV0xp/gKmIMKqabKKkJHeVpuVLPQfnQE8fSxLusceVsgsgCfdxByB6+A5Vn6z8Ya0b3ySEJZ+i31sWg==","size":2835725},"js/app-6402ab373cc443ece8668f118884b380.js":{"digest":"6402ab373cc443ece8668f118884b380","logical_path":"js/app.js","mtime":63870218273,"sha512":"F+uWokS9ws6KIEt4UwE+9tiP4Yl9nE1gcghExaiWc8vKRyEnjgZTM5sSPrIC4Z3WcTFz8Y4UMLq+narqjyHhsA==","size":5318793},"js/app-7f6b164884ad1aecd28bb6f392f479ab.js":{"digest":"7f6b164884ad1aecd28bb6f392f479ab","logical_path":"js/app.js","mtime":63870398423,"sha512":"hvHAVNez5x4z30dLdKG+yfdx8+rgbPdWBqnEUb5uBcYppc1BwvbpewANZK/02wYinVfx/9KlBJ3qOVOeCA58Vg==","size":2836525},"images/logo_full_white-1f74208d75fe567d7a94263a1aca6fe0.svg":{"digest":"1f74208d75fe567d7a94263a1aca6fe0","logical_path":"images/logo_full_white.svg","mtime":63870405653,"sha512":"JVndjFW4w92w+wyzS1rXnfqg3zFGeOh7x8GQ3CB+MD/obVwlr7N7bhxYJ5A458Lmt9AK1yu2OBBRGyM3+2lGKA==","size":55506},"js/app-95121fdc83ff6d36c7d37c53ed95c6c7.js":{"digest":"95121fdc83ff6d36c7d37c53ed95c6c7","logical_path":"js/app.js","mtime":63870398060,"sha512":"ZYLqNWEAG2ao6FQY0hWMBmGRBU951+8zrjg1JYR7ZBV7Td+6Uid+3GnGxrHi4HgDnJ1bROy7M6f4ogPk+dhdxw==","size":2836446},"js/app-cf39db2f825d2f2d4dfe91d0ea78d30e.js":{"digest":"cf39db2f825d2f2d4dfe91d0ea78d30e","logical_path":"js/app.js","mtime":63870401484,"sha512":"ce17NzelX6wpyo0JHqJGcPNnHmq0Q5CDpODN1N3z7kOewCvjXJ7qs9ZK4hkGiAWz8JBIFfrca8QjGR34lN8mrQ==","size":2836475},"js/app-8eeb88849d6e40953ad39c69b8b70652.js":{"digest":"8eeb88849d6e40953ad39c69b8b70652","logical_path":"js/app.js","mtime":63870398372,"sha512":"OmvdExkX1lvWS4Sl1aITnIoHkHaIcfH0YT12js+7JIQ+9QtLyLJIflaOMoqK5QTSZhOnbby2BdJv5KAjZrgR/Q==","size":2836495},"js/app-62fa31f8a5118f544670cc577522eb6a.js":{"digest":"62fa31f8a5118f544670cc577522eb6a","logical_path":"js/app.js","mtime":63870223169,"sha512":"K/+sFQK/wZjLtGqAJY4PVyeM0+OWHTgZSY9uHckLy4z+WDP4+G9n6G6HRzChdowS/IZCo67C14LR5yky3QkRWw==","size":5319096},"js/app-6a5252233d955481b9d39dbfb8b35841.js":{"digest":"6a5252233d955481b9d39dbfb8b35841","logical_path":"js/app.js","mtime":63870219877,"sha512":"Dek8aNtfQEsgtgchRFaEhvm0NIgRYphOBOPd7lLAJTRw4ObxCSDodjzTW6fIkFePFZdKXURgFDptUfAxDsrvRw==","size":5318683},"js/app-0635b8508a44f64d2a0e5281012a4604.js":{"digest":"0635b8508a44f64d2a0e5281012a4604","logical_path":"js/app.js","mtime":63870220568,"sha512":"mhTuzGvChfwyNKy3GPyO0FfOr2KnyXzNntIS8S/RNpd9w4g0E0Gw5M1FkL/QaqHRoZiXN+t8sqJxfwdfWD6wYg==","size":5318641},"js/app-9673bfc3e43dd5d067a775a818c4a277.js":{"digest":"9673bfc3e43dd5d067a775a818c4a277","logical_path":"js/app.js","mtime":63870404563,"sha512":"Kp9Pbgetr5BzlRsSdy172qhIfN/gzu3uKfdX/rbw2Jni4S6IdrJwgTpmhgImBc81mwZWoEthYdJlPA1NDoSsQA==","size":2835578},"css/app-00f83227a76f1ff82779ab6fa2fc6558.css":{"digest":"00f83227a76f1ff82779ab6fa2fc6558","logical_path":"css/app.css","mtime":63870405653,"sha512":"JEYGsXduQvkD/f1WezVoztHGgYgHT3OjOdoOff5xGq7R7RrsacN3ebFEDnANozBAMTCu8AFLAncGdlZYFpuJNA==","size":210771},"js/app-b0c73db2f546413eea32553ccb749b6c.js":{"digest":"b0c73db2f546413eea32553ccb749b6c","logical_path":"js/app.js","mtime":63870404502,"sha512":"IuUEZ2eFKqTnfv0xVI6cy7IqJSDZsLJrJh5KZUy5nEgTMxeEdhkcdmQ+lWZUjhc1xdC9u38t+QKXAey7dPYOjw==","size":2835578},"js/app-af2c5fb9a0c530e424b87fb3f4944ebe.js":{"digest":"af2c5fb9a0c530e424b87fb3f4944ebe","logical_path":"js/app.js","mtime":63870314663,"sha512":"Xgihe0e26jVncPJxBdzW2A05YyxQAohrwfDlfNte0FdD4aEkBEj7XagX9ngTsG4jkcftUrRPagz47Z7csaOAeQ==","size":2835711},"js/app-841d799f772192b85486c313d1b79a58.js":{"digest":"841d799f772192b85486c313d1b79a58","logical_path":"js/app.js","mtime":63870385413,"sha512":"bxRNy0+z8yyo8u51DY/f2a7LAIXOTVAGCBD1LLRlQIEYzhb2aOVId4oth0/ZvlSZ735utGoqK4E/LgOeAFQV9Q==","size":2835840},"js/app-132d79fcb3b3c04c957f985665bd505d.js":{"digest":"132d79fcb3b3c04c957f985665bd505d","logical_path":"js/app.js","mtime":63870220641,"sha512":"vOJwbQNSB/LKtTWHUPax+iuEq+/+g0tvpR6+m6pHUu1T/+8DugUwLhFmzGG6quME4BHZ2uVB5Vbs0crEa1B2dA==","size":5318713},"js/app-8bfef55cd53a0c0043be18ef0404bb6e.js":{"digest":"8bfef55cd53a0c0043be18ef0404bb6e","logical_path":"js/app.js","mtime":63870397515,"sha512":"gNJ/2pPJKpEGW7g3YGszFfyadCJEqJFTw1cVgPj4bzkhmRHEM1p9MUAE3xxR6yqloLb39FjhJqyWRYs0fTa1jA==","size":2836734},"js/app-46c43d95c0ce9dfcccc53f35a583d6a4.js":{"digest":"46c43d95c0ce9dfcccc53f35a583d6a4","logical_path":"js/app.js","mtime":63870222877,"sha512":"4f+t4VpBxn362tyhLxLfHEOq9Pu/mTNr424PBzMmYpSdCq8YVVRpcY84fbDL7072P9n43GuV6uWBD0o+Zuqe9A==","size":5319000},"js/app-659f1b2b3b8cb181988dfe2cf48df392.js":{"digest":"659f1b2b3b8cb181988dfe2cf48df392","logical_path":"js/app.js","mtime":63870404130,"sha512":"+I4UH+DHYYeCm7jalnXZoDFsCzZKrLxJs6rCbGbOUi9dXzvD2T4qt4mZ0cE2VCZCtn2WGXDTyCY5Fnq05FUalA==","size":2835576},"js/app-0aca6c7395e26cc665fa8768192b5dd9.js":{"digest":"0aca6c7395e26cc665fa8768192b5dd9","logical_path":"js/app.js","mtime":63870396685,"sha512":"OvfNrS/qtl8GUvBnjWd34MFMH4NoD1h0MRXJUljL3q6YUxe2Mfv5pF6P2Qcjq0XfdKhl3bcGjmVT44d/O019aQ==","size":2836662},"js/app-7153aa4d9451ae25aa698670bf6238a4.js":{"digest":"7153aa4d9451ae25aa698670bf6238a4","logical_path":"js/app.js","mtime":63870215538,"sha512":"DMzgC1O2SXOEU0yeBp40fT3peczD9zOnoQkM3MF6XKYsuefYcwEi1fMmqbGOcC7jEGCQUY5NAM5IzGuz4Cw3NA==","size":2834957},"js/app-0966d7c17bd5dd772e67cae65b0ddc7a.js":{"digest":"0966d7c17bd5dd772e67cae65b0ddc7a","logical_path":"js/app.js","mtime":63870315418,"sha512":"apfr9x8IGAaFtWnf99l5z3Cpkr8Qr+bsQbg9nTdLY1isIwibx6voEx3LK5nXAZIDFOjvgsHRL3vjU+xNhMkHgQ==","size":2835800},"robots-067185ba27a5d9139b10a759679045bf.txt":{"digest":"067185ba27a5d9139b10a759679045bf","logical_path":"robots.txt","mtime":63870405653,"sha512":"8FA6TZeCo3hFYcQ+9knbh3TrhkqGzYJx/uD5yRvggwM7gwfBPrPGqqrbVTZjnnnvlsw1zs1WJTPYez1zr/U4ug==","size":202},"js/app-93ca36c193699b3f29b2782b5f5cd0ac.js":{"digest":"93ca36c193699b3f29b2782b5f5cd0ac","logical_path":"js/app.js","mtime":63870386233,"sha512":"hv6kenjdpcRlB3G5EHJc2AtwK29mR6EFSM5aZO3VLQmk2s9Hd3mTvsVPn0xu49AsczArL93dMNUZDcEng5p+5Q==","size":2835750},"js/app-ee0c30743412e744696376b74658d802.js":{"digest":"ee0c30743412e744696376b74658d802","logical_path":"js/app.js","mtime":63870220517,"sha512":"yZL7Y5HGoPCvBuqqZLF+hFlWCznZO1r9SdYRLZOWBUhuL+PR4WS6ufDu47e4xkBDthZP6mJGb/2D+Ia2UD1vdA==","size":5318763},"js/app-520ef198aec843700b73a8af87f29ef9.js":{"digest":"520ef198aec843700b73a8af87f29ef9","logical_path":"js/app.js","mtime":63870404533,"sha512":"wYUQewORckI64xKSlpwPDQs/JrzX4NOUJXwr2S9X7HhbUiGIM7EBjz8E03YkHusZi30WpZR7/8JplF6mCq8nrw==","size":2835584},"favicon-a8ca4e3a2bb8fea46a9ee9e102e7d3eb.ico":{"digest":"a8ca4e3a2bb8fea46a9ee9e102e7d3eb","logical_path":"favicon.ico","mtime":63870405653,"sha512":"vCKvNNXeSP/2RRr6IN8PVa8/Hl6ImUO7miAOIMABYwbCzlm0UTRsY30uYb1k5gcCOPIsv6nZuFlJj/h8z+InzQ==","size":1258},"js/app-f3ddb38b1da003de316d6c52389864b1.js":{"digest":"f3ddb38b1da003de316d6c52389864b1","logical_path":"js/app.js","mtime":63870216586,"sha512":"Md4tLe/4ua6amKo0UhZA47itpphEECsEjJBK/A8YxTJnI0tBPcOh/hu+p0Mq2KLNNxDaiO+ZsydHxuDKlmDuTQ==","size":5318674},"js/app-8ee7e860d67b037e3322e9dfee3b4105.js":{"digest":"8ee7e860d67b037e3322e9dfee3b4105","logical_path":"js/app.js","mtime":63870403372,"sha512":"uA3Ok3zWYN0syd6Jx7FtizUWfnPKzHPfp0sUzfE1oAWZVFpEOZ2spkyRnaEHlcSUtNVOglS3oS6HLwq+wWrChA==","size":2836498},"js/app-7be59dba21480cb6f90920248a0c6ee3.js":{"digest":"7be59dba21480cb6f90920248a0c6ee3","logical_path":"js/app.js","mtime":63870403446,"sha512":"hD60jtO2Y5iTpzL4ShA7dJuGkauHbwE9aA1XFobHDgDVTAgX09+qkpZC5oXoVa1JbuhlbIjWotgSYAqWoOszfg==","size":2836573},"js/app-be27081654b0a72101b2b4d8293fab1d.js":{"digest":"be27081654b0a72101b2b4d8293fab1d","logical_path":"js/app.js","mtime":63870219395,"sha512":"7rWx+wgYfMJ0VjQNMKJ6yRszT+2SxeBfpuwm64Q837OKy6INsY2UEyAMSls+IAKjOu0jYmN06Zm+4j/Eq+GBww==","size":5318646},"js/app-a52bd73970c7dd17899aeac734f2f157.js":{"digest":"a52bd73970c7dd17899aeac734f2f157","logical_path":"js/app.js","mtime":63870386613,"sha512":"gnwU1eOMbZ7ftFzcEkprsZqxUxYWC4FFfMn95Pi5YVh3Kqfn7DbPQ8dXvf6rzkIpIvN1oHpPHj/Q81l0riZXtQ==","size":2835810},"js/app-727f3cac32d69ccda86285181d471ca9.js":{"digest":"727f3cac32d69ccda86285181d471ca9","logical_path":"js/app.js","mtime":63870223145,"sha512":"zJR0Cf04o1XZzx9aRSf0y4hMt7iiAPeTlZi+G/hYV3W61fdghmspAMlpvUtUmYvt084QMIrcB6KNEFujH0KsJQ==","size":5319073},"js/app-b87cc1de5c3e10d451f6b10686864367.js":{"digest":"b87cc1de5c3e10d451f6b10686864367","logical_path":"js/app.js","mtime":63870405653,"sha512":"dh1po0Gj0tgzn9SNVDRbfD43Xs/Myl6z25R7kmiuHRUAVDcng8KZFoA/+GTZfR3FUIw8Djmrvzu+ltwjI6B1yA==","size":2835560},"js/app-c961222adb67ccebeadee89404ddf3e2.js":{"digest":"c961222adb67ccebeadee89404ddf3e2","logical_path":"js/app.js","mtime":63870221588,"sha512":"FfzZ6RiIgp9M4/ulQJh7jmAb5ek0zf8M+h1vxAAe9fkj6J0cFZg0kan3IuK8pLzZ+hJxdu1EvDVP5Z+1S/kKyA==","size":5318806},"js/app-b16957583bc66fd90ee2dca6d8705ece.js":{"digest":"b16957583bc66fd90ee2dca6d8705ece","logical_path":"js/app.js","mtime":63870398289,"sha512":"YFQWUvwdE/CgMgslCYkHDleXKFiwjwC3XHstmjHWQGAWKfjfhmo+P83Mq7Jx7pNjlZZN9nhtk2F38lB3fZkUIw==","size":2836481}} }