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}}
}