Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package erldash for openSUSE:Factory checked 
in at 2023-10-19 22:49:38
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/erldash (Old)
 and      /work/SRC/openSUSE:Factory/.erldash.new.1945 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "erldash"

Thu Oct 19 22:49:38 2023 rev:5 rq:1118838 version:0.1.5~0

Changes:
--------
--- /work/SRC/openSUSE:Factory/erldash/erldash.changes  2023-09-20 
13:33:14.479354719 +0200
+++ /work/SRC/openSUSE:Factory/.erldash.new.1945/erldash.changes        
2023-10-19 22:52:02.232698607 +0200
@@ -1,0 +2,7 @@
+Thu Oct 19 07:46:43 UTC 2023 - Michael Vetter <jub...@iodoru.org>
+
+- Update to 0.1.5:
+  * Update dependencies and remove ordered-float crate #5
+  * Add --record and --replay options #6
+
+-------------------------------------------------------------------

Old:
----
  erldash-0.1.3~0.tar.xz

New:
----
  erldash-0.1.5~0.tar.xz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ erldash.spec ++++++
--- /var/tmp/diff_new_pack.248QbE/_old  2023-10-19 22:52:03.952760992 +0200
+++ /var/tmp/diff_new_pack.248QbE/_new  2023-10-19 22:52:03.968761573 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           erldash
-Version:        0.1.3~0
+Version:        0.1.5~0
 Release:        0
 Summary:        A simple, terminal-based Erlang dashboard
 License:        (Apache-2.0 OR MIT) AND MIT AND Apache-2.0 WITH LLVM-exception 
AND MPL-2.0

++++++ _service ++++++
--- /var/tmp/diff_new_pack.248QbE/_old  2023-10-19 22:52:04.300773614 +0200
+++ /var/tmp/diff_new_pack.248QbE/_new  2023-10-19 22:52:04.340775065 +0200
@@ -3,7 +3,7 @@
     <param name="url">https://github.com/sile/erldash.git</param>
     <param name="versionformat">@PARENT_TAG@~@TAG_OFFSET@</param>
     <param name="scm">git</param>
-    <param name="revision">0.1.3</param>
+    <param name="revision">0.1.5</param>
     <param name="match-tag">*</param>
     <param name="versionrewrite-pattern">v(\d+\.\d+\.\d+)</param>
     <param name="versionrewrite-replacement">\1</param>

++++++ erldash-0.1.3~0.tar.xz -> erldash-0.1.5~0.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/erldash-0.1.3~0/Cargo.lock 
new/erldash-0.1.5~0/Cargo.lock
--- old/erldash-0.1.3~0/Cargo.lock      2023-08-08 13:43:08.000000000 +0200
+++ new/erldash-0.1.5~0/Cargo.lock      2023-10-19 04:24:59.000000000 +0200
@@ -10,30 +10,29 @@
 
 [[package]]
 name = "anstream"
-version = "0.3.2"
+version = "0.6.4"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163"
+checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44"
 dependencies = [
  "anstyle",
  "anstyle-parse",
  "anstyle-query",
  "anstyle-wincon",
  "colorchoice",
- "is-terminal",
  "utf8parse",
 ]
 
 [[package]]
 name = "anstyle"
-version = "1.0.1"
+version = "1.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd"
+checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87"
 
 [[package]]
 name = "anstyle-parse"
-version = "0.2.1"
+version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333"
+checksum = "317b9a89c1868f5ea6ff1d9539a69f45dffc21ce321ac1fd1160dfa48c8e2140"
 dependencies = [
  "utf8parse",
 ]
@@ -49,9 +48,9 @@
 
 [[package]]
 name = "anstyle-wincon"
-version = "1.0.1"
+version = "3.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188"
+checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628"
 dependencies = [
  "anstyle",
  "windows-sys",
@@ -59,9 +58,9 @@
 
 [[package]]
 name = "anyhow"
-version = "1.0.72"
+version = "1.0.75"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854"
+checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
 
 [[package]]
 name = "async-channel"
@@ -70,20 +69,20 @@
 checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35"
 dependencies = [
  "concurrent-queue",
- "event-listener",
+ "event-listener 2.5.3",
  "futures-core",
 ]
 
 [[package]]
 name = "async-executor"
-version = "1.5.1"
+version = "1.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "6fa3dc5f2a8564f07759c008b9109dc0d39de92a88d5588b8a5036d286383afb"
+checksum = "4b0c4a4f319e45986f347ee47fef8bf5e81c9abc3f6f58dc2391439f30df65f0"
 dependencies = [
  "async-lock",
  "async-task",
  "concurrent-queue",
- "fastrand",
+ "fastrand 2.0.1",
  "futures-lite",
  "slab",
 ]
@@ -114,7 +113,7 @@
  "log",
  "parking",
  "polling",
- "rustix 0.37.23",
+ "rustix 0.37.25",
  "slab",
  "socket2",
  "waker-fn",
@@ -122,54 +121,70 @@
 
 [[package]]
 name = "async-lock"
-version = "2.7.0"
+version = "2.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "fa24f727524730b077666307f2734b4a1a1c57acb79193127dcc8914d5242dd7"
+checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b"
 dependencies = [
- "event-listener",
+ "event-listener 2.5.3",
 ]
 
 [[package]]
 name = "async-net"
-version = "1.7.0"
+version = "1.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "4051e67316bc7eff608fe723df5d32ed639946adcd69e07df41fd42a7b411f1f"
+checksum = "0434b1ed18ce1cf5769b8ac540e33f01fa9471058b5e89da9e06f3c882a8c12f"
 dependencies = [
  "async-io",
- "autocfg",
  "blocking",
  "futures-lite",
 ]
 
 [[package]]
 name = "async-process"
-version = "1.7.0"
+version = "1.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "7a9d28b1d97e08915212e2e45310d47854eafa69600756fc735fb788f75199c9"
+checksum = "ea6438ba0a08d81529c69b36700fa2f95837bfe3e776ab39cde9c14d9149da88"
 dependencies = [
  "async-io",
  "async-lock",
- "autocfg",
+ "async-signal",
  "blocking",
  "cfg-if",
- "event-listener",
+ "event-listener 3.0.0",
  "futures-lite",
- "rustix 0.37.23",
- "signal-hook",
+ "rustix 0.38.19",
+ "windows-sys",
+]
+
+[[package]]
+name = "async-signal"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "d2a5415b7abcdc9cd7d63d6badba5288b2ca017e3fbd4173b8f405449f1a2399"
+dependencies = [
+ "async-io",
+ "async-lock",
+ "atomic-waker",
+ "cfg-if",
+ "futures-core",
+ "futures-io",
+ "rustix 0.38.19",
+ "signal-hook-registry",
+ "slab",
  "windows-sys",
 ]
 
 [[package]]
 name = "async-task"
-version = "4.4.0"
+version = "4.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "ecc7ab41815b3c653ccd2978ec3255c81349336702dfdf62ee6f7069b12a3aae"
+checksum = "b4eb2cdb97421e01129ccb49169d8279ed21e829929144f4a22a6e54ac549ca1"
 
 [[package]]
 name = "atomic-waker"
-version = "1.1.1"
+version = "1.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "1181e1e0d1fce796a03db1ae795d67167da795f9cf4a39c37589e85ef57f26d3"
+checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
 
 [[package]]
 name = "autocfg"
@@ -185,30 +200,31 @@
 
 [[package]]
 name = "bitflags"
-version = "2.3.3"
+version = "2.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42"
+checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
 
 [[package]]
 name = "blocking"
-version = "1.3.1"
+version = "1.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "77231a1c8f801696fc0123ec6150ce92cffb8e164a02afb9c8ddee0e9b65ad65"
+checksum = "8c36a4d0d48574b3dd360b4b7d95cc651d2b6557b6402848a27d4b228a473e2a"
 dependencies = [
  "async-channel",
  "async-lock",
  "async-task",
- "atomic-waker",
- "fastrand",
+ "fastrand 2.0.1",
+ "futures-io",
  "futures-lite",
- "log",
+ "piper",
+ "tracing",
 ]
 
 [[package]]
 name = "byteorder"
-version = "1.4.3"
+version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
 
 [[package]]
 name = "cassowary"
@@ -217,15 +233,6 @@
 checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
 
 [[package]]
-name = "cc"
-version = "1.0.82"
-source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "305fe645edc1442a0fa8b6726ba61d422798d37a52e12eaecf4b022ebbb88f01"
-dependencies = [
- "libc",
-]
-
-[[package]]
 name = "cfg-if"
 version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
@@ -233,20 +240,19 @@
 
 [[package]]
 name = "clap"
-version = "4.3.21"
+version = "4.4.6"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "c27cdf28c0f604ba3f512b0c9a409f8de8513e4816705deb0498b627e7c3a3fd"
+checksum = "d04704f56c2cde07f43e8e2c154b43f216dc5c92fc98ada720177362f953b956"
 dependencies = [
  "clap_builder",
  "clap_derive",
- "once_cell",
 ]
 
 [[package]]
 name = "clap_builder"
-version = "4.3.21"
+version = "4.4.6"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "08a9f1ab5e9f01a9b81f202e8562eb9a10de70abf9eaeac1be465c28b75aa4aa"
+checksum = "0e231faeaca65ebd1ea3c737966bf858971cd38c3849107aa3ea7de90a804e45"
 dependencies = [
  "anstream",
  "anstyle",
@@ -256,9 +262,9 @@
 
 [[package]]
 name = "clap_derive"
-version = "4.3.12"
+version = "4.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "54a9bb5758fc5dfe728d1019941681eccaf0cf8a4189b692a0ee2f2ecf90a050"
+checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873"
 dependencies = [
  "heck",
  "proc-macro2",
@@ -268,9 +274,9 @@
 
 [[package]]
 name = "clap_lex"
-version = "0.5.0"
+version = "0.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b"
+checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961"
 
 [[package]]
 name = "colorchoice"
@@ -280,9 +286,9 @@
 
 [[package]]
 name = "concurrent-queue"
-version = "2.2.0"
+version = "2.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "62ec6771ecfa0762d24683ee5a32ad78487a3d3afdc0fb8cae19d2c5deb50b7c"
+checksum = "f057a694a54f12365049b0958a1685bb52d567f5593b355fbf685838e873d400"
 dependencies = [
  "crossbeam-utils",
 ]
@@ -327,7 +333,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index";
 checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df"
 dependencies = [
- "bitflags 2.3.3",
+ "bitflags 2.4.1",
  "crossterm_winapi",
  "libc",
  "mio",
@@ -348,9 +354,12 @@
 
 [[package]]
 name = "deranged"
-version = "0.3.7"
+version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "7684a49fb1af197853ef7b2ee694bc1f5b4179556f1e5710e1760c5db6f5e929"
+checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3"
+dependencies = [
+ "powerfmt",
+]
 
 [[package]]
 name = "dirs"
@@ -382,7 +391,7 @@
  "byteorder",
  "libflate",
  "num",
- "ordered-float 2.10.0",
+ "ordered-float",
  "thiserror",
 ]
 
@@ -416,7 +425,7 @@
 
 [[package]]
 name = "erldash"
-version = "0.1.3"
+version = "0.1.5"
 dependencies = [
  "anyhow",
  "clap",
@@ -426,7 +435,8 @@
  "erl_rpc",
  "futures",
  "log",
- "ordered-float 3.7.0",
+ "serde",
+ "serde_json",
  "simplelog",
  "smol",
  "tui",
@@ -434,30 +444,30 @@
 
 [[package]]
 name = "errno"
-version = "0.3.2"
+version = "0.3.5"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f"
+checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860"
 dependencies = [
- "errno-dragonfly",
  "libc",
  "windows-sys",
 ]
 
 [[package]]
-name = "errno-dragonfly"
-version = "0.1.2"
+name = "event-listener"
+version = "2.5.3"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
-dependencies = [
- "cc",
- "libc",
-]
+checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
 
 [[package]]
 name = "event-listener"
-version = "2.5.3"
+version = "3.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
+checksum = "29e56284f00d94c1bc7fd3c77027b4623c88c1f53d8d2394c6199f2921dea325"
+dependencies = [
+ "concurrent-queue",
+ "parking",
+ "pin-project-lite",
+]
 
 [[package]]
 name = "fastrand"
@@ -469,6 +479,12 @@
 ]
 
 [[package]]
+name = "fastrand"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5"
+
+[[package]]
 name = "futures"
 version = "0.3.28"
 source = "registry+https://github.com/rust-lang/crates.io-index";
@@ -522,7 +538,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index";
 checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce"
 dependencies = [
- "fastrand",
+ "fastrand 1.9.0",
  "futures-core",
  "futures-io",
  "memchr",
@@ -591,9 +607,9 @@
 
 [[package]]
 name = "hermit-abi"
-version = "0.3.2"
+version = "0.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
+checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7"
 
 [[package]]
 name = "instant"
@@ -616,17 +632,6 @@
 ]
 
 [[package]]
-name = "is-terminal"
-version = "0.4.9"
-source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
-dependencies = [
- "hermit-abi",
- "rustix 0.38.7",
- "windows-sys",
-]
-
-[[package]]
 name = "itoa"
 version = "1.0.9"
 source = "registry+https://github.com/rust-lang/crates.io-index";
@@ -634,9 +639,9 @@
 
 [[package]]
 name = "libc"
-version = "0.2.147"
+version = "0.2.149"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
+checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b"
 
 [[package]]
 name = "libflate"
@@ -666,15 +671,15 @@
 
 [[package]]
 name = "linux-raw-sys"
-version = "0.4.5"
+version = "0.4.10"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503"
+checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f"
 
 [[package]]
 name = "lock_api"
-version = "0.4.10"
+version = "0.4.11"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16"
+checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45"
 dependencies = [
  "autocfg",
  "scopeguard",
@@ -682,9 +687,9 @@
 
 [[package]]
 name = "log"
-version = "0.4.19"
+version = "0.4.20"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4"
+checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
 
 [[package]]
 name = "md5"
@@ -694,9 +699,9 @@
 
 [[package]]
 name = "memchr"
-version = "2.5.0"
+version = "2.6.4"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
+checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
 
 [[package]]
 name = "mio"
@@ -726,9 +731,9 @@
 
 [[package]]
 name = "num-bigint"
-version = "0.4.3"
+version = "0.4.4"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f"
+checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0"
 dependencies = [
  "autocfg",
  "num-integer",
@@ -737,9 +742,9 @@
 
 [[package]]
 name = "num-complex"
-version = "0.4.3"
+version = "0.4.4"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d"
+checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214"
 dependencies = [
  "num-traits",
 ]
@@ -779,9 +784,9 @@
 
 [[package]]
 name = "num-traits"
-version = "0.2.16"
+version = "0.2.17"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2"
+checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
 dependencies = [
  "autocfg",
 ]
@@ -796,12 +801,6 @@
 ]
 
 [[package]]
-name = "once_cell"
-version = "1.18.0"
-source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
-
-[[package]]
 name = "option-ext"
 version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
@@ -809,27 +808,18 @@
 
 [[package]]
 name = "ordered-float"
-version = "2.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "7940cf2ca942593318d07fcf2596cdca60a85c9e7fab408a5e21a4f9dcd40d87"
-dependencies = [
- "num-traits",
-]
-
-[[package]]
-name = "ordered-float"
-version = "3.7.0"
+version = "2.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "2fc2dbde8f8a79f2102cc474ceb0ad68e3b80b85289ea62389b60e66777e4213"
+checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c"
 dependencies = [
  "num-traits",
 ]
 
 [[package]]
 name = "parking"
-version = "2.1.0"
+version = "2.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "14f2252c834a40ed9bb5422029649578e63aa341ac401f74e719dd1afda8394e"
+checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae"
 
 [[package]]
 name = "parking_lot"
@@ -843,22 +833,22 @@
 
 [[package]]
 name = "parking_lot_core"
-version = "0.9.8"
+version = "0.9.9"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447"
+checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e"
 dependencies = [
  "cfg-if",
  "libc",
- "redox_syscall 0.3.5",
+ "redox_syscall 0.4.1",
  "smallvec",
  "windows-targets",
 ]
 
 [[package]]
 name = "pin-project-lite"
-version = "0.2.11"
+version = "0.2.13"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "2c516611246607d0c04186886dbb3a754368ef82c79e9827a802c6d836dd111c"
+checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
 
 [[package]]
 name = "pin-utils"
@@ -867,6 +857,17 @@
 checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
 
 [[package]]
+name = "piper"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "668d31b1c4eba19242f2088b2bf3316b82ca31082a8335764db4e083db7485d4"
+dependencies = [
+ "atomic-waker",
+ "fastrand 2.0.1",
+ "futures-io",
+]
+
+[[package]]
 name = "polling"
 version = "2.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
@@ -883,6 +884,12 @@
 ]
 
 [[package]]
+name = "powerfmt"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
+
+[[package]]
 name = "ppv-lite86"
 version = "0.2.17"
 source = "registry+https://github.com/rust-lang/crates.io-index";
@@ -890,18 +897,18 @@
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.66"
+version = "1.0.69"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
+checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
 dependencies = [
  "unicode-ident",
 ]
 
 [[package]]
 name = "quote"
-version = "1.0.32"
+version = "1.0.33"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965"
+checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
 dependencies = [
  "proc-macro2",
 ]
@@ -947,9 +954,9 @@
 
 [[package]]
 name = "redox_syscall"
-version = "0.3.5"
+version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
+checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
 dependencies = [
  "bitflags 1.3.2",
 ]
@@ -973,9 +980,9 @@
 
 [[package]]
 name = "rustix"
-version = "0.37.23"
+version = "0.37.25"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06"
+checksum = "d4eb579851244c2c03e7c24f501c3432bed80b8f720af1d6e5b0e0f01555a035"
 dependencies = [
  "bitflags 1.3.2",
  "errno",
@@ -987,18 +994,24 @@
 
 [[package]]
 name = "rustix"
-version = "0.38.7"
+version = "0.38.19"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "172891ebdceb05aa0005f533a6cbfca599ddd7d966f6f5d4d9b2e70478e70399"
+checksum = "745ecfa778e66b2b63c88a61cb36e0eea109e803b0b86bf9879fbc77c70e86ed"
 dependencies = [
- "bitflags 2.3.3",
+ "bitflags 2.4.1",
  "errno",
  "libc",
- "linux-raw-sys 0.4.5",
+ "linux-raw-sys 0.4.10",
  "windows-sys",
 ]
 
 [[package]]
+name = "ryu"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
+
+[[package]]
 name = "scopeguard"
 version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
@@ -1006,9 +1019,34 @@
 
 [[package]]
 name = "serde"
-version = "1.0.183"
+version = "1.0.189"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "32ac8da02677876d532745a130fc9d8e6edfa81a269b107c5b00829b91d8eb3c"
+checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.189"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.107"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65"
+dependencies = [
+ "itoa",
+ "ryu",
+ "serde",
+]
 
 [[package]]
 name = "signal-hook"
@@ -1053,18 +1091,18 @@
 
 [[package]]
 name = "slab"
-version = "0.4.8"
+version = "0.4.9"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d"
+checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
 dependencies = [
  "autocfg",
 ]
 
 [[package]]
 name = "smallvec"
-version = "1.11.0"
+version = "1.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9"
+checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a"
 
 [[package]]
 name = "smol"
@@ -1101,9 +1139,9 @@
 
 [[package]]
 name = "syn"
-version = "2.0.28"
+version = "2.0.38"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567"
+checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1121,18 +1159,18 @@
 
 [[package]]
 name = "thiserror"
-version = "1.0.44"
+version = "1.0.49"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90"
+checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.44"
+version = "1.0.49"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96"
+checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1141,14 +1179,15 @@
 
 [[package]]
 name = "time"
-version = "0.3.25"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "b0fdd63d58b18d663fbdf70e049f00a22c8e42be082203be7f26589213cd75ea"
+checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5"
 dependencies = [
  "deranged",
  "itoa",
  "libc",
  "num_threads",
+ "powerfmt",
  "serde",
  "time-core",
  "time-macros",
@@ -1156,20 +1195,36 @@
 
 [[package]]
 name = "time-core"
-version = "0.1.1"
+version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb"
+checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
 
 [[package]]
 name = "time-macros"
-version = "0.2.11"
+version = "0.2.15"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "eb71511c991639bb078fd5bf97757e03914361c48100d52878b8e52b46fb92cd"
+checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20"
 dependencies = [
  "time-core",
 ]
 
 [[package]]
+name = "tracing"
+version = "0.1.39"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "ee2ef2af84856a50c1d430afce2fdded0a4ec7eda868db86409b4543df0797f9"
+dependencies = [
+ "pin-project-lite",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.32"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
+
+[[package]]
 name = "tui"
 version = "0.19.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
@@ -1184,9 +1239,9 @@
 
 [[package]]
 name = "unicode-ident"
-version = "1.0.11"
+version = "1.0.12"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c"
+checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
 
 [[package]]
 name = "unicode-segmentation"
@@ -1196,9 +1251,9 @@
 
 [[package]]
 name = "unicode-width"
-version = "0.1.10"
+version = "0.1.11"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
+checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
 
 [[package]]
 name = "utf8parse"
@@ -1208,9 +1263,9 @@
 
 [[package]]
 name = "waker-fn"
-version = "1.1.0"
+version = "1.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca"
+checksum = "f3c4517f54858c779bbcbf228f4fca63d121bf85fbecb2dc578cdf4a39395690"
 
 [[package]]
 name = "wasi"
@@ -1236,9 +1291,9 @@
 
 [[package]]
 name = "winapi-util"
-version = "0.1.5"
+version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
+checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
 dependencies = [
  "winapi",
 ]
@@ -1260,9 +1315,9 @@
 
 [[package]]
 name = "windows-targets"
-version = "0.48.1"
+version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f"
+checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
 dependencies = [
  "windows_aarch64_gnullvm",
  "windows_aarch64_msvc",
@@ -1275,42 +1330,42 @@
 
 [[package]]
 name = "windows_aarch64_gnullvm"
-version = "0.48.0"
+version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
+checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
 
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.48.0"
+version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
+checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.48.0"
+version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
+checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.48.0"
+version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
+checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.48.0"
+version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
+checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
-version = "0.48.0"
+version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
+checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
 
 [[package]]
 name = "windows_x86_64_msvc"
-version = "0.48.0"
+version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
+checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/erldash-0.1.3~0/Cargo.toml 
new/erldash-0.1.5~0/Cargo.toml
--- old/erldash-0.1.3~0/Cargo.toml      2023-08-08 13:43:08.000000000 +0200
+++ new/erldash-0.1.5~0/Cargo.toml      2023-10-19 04:24:59.000000000 +0200
@@ -1,6 +1,6 @@
 [package]
 name = "erldash"
-version = "0.1.3"
+version = "0.1.5"
 edition = "2021"
 authors = ["Takeru Ohta <phjgt...@gmail.com>"]
 license = "MIT OR Apache-2.0"
@@ -20,7 +20,8 @@
 erl_rpc = "0.2"
 futures = "0.3"
 log = "0.4"
-ordered-float = "3"
+serde = { version = "1.0.189", features = ["derive"] }
+serde_json = "1.0.107"
 simplelog = "0.12"
 smol = "1"
 tui = "0.19"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/erldash-0.1.3~0/src/erlang.rs 
new/erldash-0.1.5~0/src/erlang.rs
--- old/erldash-0.1.3~0/src/erlang.rs   2023-08-08 13:43:08.000000000 +0200
+++ new/erldash-0.1.5~0/src/erlang.rs   2023-10-19 04:24:59.000000000 +0200
@@ -1,8 +1,9 @@
 use erl_dist::node::NodeName;
 use erl_dist::term::{Atom, List, Map, Term, Tuple};
+use serde::{Deserialize, Serialize};
 use std::collections::BTreeMap;
 
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
 pub struct SystemVersion(String);
 
 impl SystemVersion {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/erldash-0.1.3~0/src/lib.rs 
new/erldash-0.1.5~0/src/lib.rs
--- old/erldash-0.1.3~0/src/lib.rs      2023-08-08 13:43:08.000000000 +0200
+++ new/erldash-0.1.5~0/src/lib.rs      2023-10-19 04:24:59.000000000 +0200
@@ -1,4 +1,5 @@
 //! A simple, terminal-based Erlang dashboard.
+use std::path::PathBuf;
 pub mod erlang;
 pub mod metrics;
 pub mod ui;
@@ -17,6 +18,14 @@
     /// By default, the content of the `$HOME/.erlang.cookie` file is used.
     #[clap(long, short = 'c')]
     pub cookie: Option<String>,
+
+    /// If specified, the collected metrics will be recorded to the given file 
and can be replayed later.
+    #[clap(long, value_name = "FILE")]
+    pub record: Option<PathBuf>,
+
+    /// If specified, the recorded metrics will be replayed.
+    #[clap(long, requires = "record")]
+    pub replay: bool,
 }
 
 impl Options {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/erldash-0.1.3~0/src/metrics.rs 
new/erldash-0.1.5~0/src/metrics.rs
--- old/erldash-0.1.3~0/src/metrics.rs  2023-08-08 13:43:08.000000000 +0200
+++ new/erldash-0.1.5~0/src/metrics.rs  2023-10-19 04:24:59.000000000 +0200
@@ -1,22 +1,27 @@
 use crate::erlang::{MSAccThread, RpcClient, SystemVersion};
 use crate::Options;
+use anyhow::Context;
+use serde::{Deserialize, Serialize};
+use smol::fs::File;
+use smol::io::AsyncWriteExt;
 use std::collections::BTreeMap;
+use std::io::BufRead;
 use std::sync::mpsc;
 use std::time::{Duration, Instant};
 
 type MetricsReceiver = mpsc::Receiver<Metrics>;
 type MetricsSender = mpsc::Sender<Metrics>;
 
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
 pub struct Metrics {
-    pub timestamp: Instant,
+    pub timestamp: Duration,
     pub items: BTreeMap<String, MetricValue>,
 }
 
 impl Metrics {
-    fn new() -> Self {
+    fn new(start: Instant) -> Self {
         Self {
-            timestamp: Instant::now(),
+            timestamp: start.elapsed(),
             items: BTreeMap::new(),
         }
     }
@@ -65,7 +70,7 @@
     }
 }
 
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
 pub enum MetricValue {
     Gauge {
         value: u64,
@@ -230,20 +235,121 @@
 }
 
 #[derive(Debug)]
-pub struct MetricsPoller {
-    pub rx: MetricsReceiver,
-    pub system_version: SystemVersion,
-    rpc_client: RpcClient,
-    old_microstate_accounting_flag: bool,
+pub enum MetricsPoller {
+    Realtime(RealtimeMetricsPoller),
+    Replay(ReplayMetricsPoller),
 }
 
 impl MetricsPoller {
     pub fn start_thread(options: Options) -> anyhow::Result<Self> {
+        if options.replay {
+            ReplayMetricsPoller::new(options).map(Self::Replay)
+        } else {
+            RealtimeMetricsPoller::start_thread(options).map(Self::Realtime)
+        }
+    }
+
+    pub fn is_replay(&self) -> bool {
+        matches!(self, Self::Replay(_))
+    }
+
+    pub fn system_version(&self) -> &SystemVersion {
+        match self {
+            Self::Realtime(poller) => &poller.system_version,
+            Self::Replay(poller) => &poller.system_version,
+        }
+    }
+
+    pub fn poll_metrics(&self, timeout: Duration) -> Result<Metrics, 
mpsc::RecvTimeoutError> {
+        match self {
+            Self::Realtime(poller) => poller.rx.recv_timeout(timeout),
+            Self::Replay(_) => {
+                unreachable!()
+            }
+        }
+    }
+
+    pub fn replay_last_time(&self) -> Duration {
+        match self {
+            Self::Realtime(_) => Duration::from_secs(0),
+            Self::Replay(poller) => poller
+                .metrics_log
+                .last()
+                .map(|m| m.timestamp)
+                .unwrap_or_default(),
+        }
+    }
+
+    pub fn get_metrics_range(
+        &self,
+        start_time: Duration,
+        end_time: Duration,
+    ) -> anyhow::Result<impl '_ + Iterator<Item = &Metrics>> {
+        let Self::Replay(poller) = self else {
+            anyhow::bail!("`get_metrics_range()` is only available in replay 
mode");
+        };
+        Ok(poller.metrics_log.iter().filter(move |metrics| {
+            let time = metrics.timestamp;
+            start_time <= time && time <= end_time
+        }))
+    }
+}
+
+#[derive(Debug)]
+pub struct ReplayMetricsPoller {
+    system_version: SystemVersion,
+    metrics_log: Vec<Metrics>,
+}
+
+impl ReplayMetricsPoller {
+    fn new(options: Options) -> anyhow::Result<Self> {
+        let Some(record_file_path) = options.record else {
+            anyhow::bail!("`--record` is required for replay mode");
+        };
+        let file = std::fs::File::open(&record_file_path).with_context(|| {
+            format!("failed to open record file: {}", 
record_file_path.display())
+        })?;
+        let reader = std::io::BufReader::new(file);
+
+        let mut system_version = None;
+        let mut metrics_log = Vec::new();
+        for (i, line) in reader.lines().enumerate() {
+            let line = line?;
+            if i == 0 {
+                system_version = Some(
+                    serde_json::from_str(&line)
+                        .with_context(|| format!("failed to parse record file: 
line={}", i + 1))?,
+                );
+                continue;
+            }
+            let metrics = serde_json::from_str(&line)
+                .with_context(|| format!("failed to parse record file: 
line={}", i + 1))?;
+            metrics_log.push(metrics);
+        }
+        let system_version =
+            system_version.ok_or_else(|| anyhow::anyhow!("record file is 
empty"))?;
+        Ok(Self {
+            system_version,
+            metrics_log,
+        })
+    }
+}
+
+#[derive(Debug)]
+pub struct RealtimeMetricsPoller {
+    rx: MetricsReceiver,
+    system_version: SystemVersion,
+    rpc_client: RpcClient,
+    old_microstate_accounting_flag: bool,
+}
+
+impl RealtimeMetricsPoller {
+    fn start_thread(options: Options) -> anyhow::Result<Self> {
         MetricsPollerThread::start_thread(options)
     }
 }
 
-impl Drop for MetricsPoller {
+impl Drop for RealtimeMetricsPoller {
     fn drop(&mut self) {
         if !self.old_microstate_accounting_flag {
             if let Err(e) = smol::block_on(
@@ -264,10 +370,13 @@
     rpc_client: RpcClient,
     tx: MetricsSender,
     prev_metrics: Metrics,
+    start: Instant,
+    system_version: SystemVersion,
+    record_file: Option<File>,
 }
 
 impl MetricsPollerThread {
-    fn start_thread(options: Options) -> anyhow::Result<MetricsPoller> {
+    fn start_thread(options: Options) -> anyhow::Result<RealtimeMetricsPoller> 
{
         let (tx, rx) = mpsc::channel();
 
         let rpc_client: RpcClient = smol::block_on(async {
@@ -282,28 +391,56 @@
             "enabled microstate accounting (old flag state is 
{old_microstate_accounting_flag})"
         );
 
-        let poller = MetricsPoller {
+        let poller = RealtimeMetricsPoller {
             rx,
-            system_version,
+            system_version: system_version.clone(),
             rpc_client: rpc_client.clone(),
             old_microstate_accounting_flag,
         };
 
+        let record_file = if let Some(path) = &options.record {
+            Some(File::from(std::fs::File::create(path).with_context(
+                || format!("failed to record file {}", path.display()),
+            )?))
+        } else {
+            None
+        };
+
         std::thread::spawn(|| {
+            let start = Instant::now();
             Self {
                 options,
                 rpc_client,
                 tx,
-                prev_metrics: Metrics::new(),
+                prev_metrics: Metrics::new(start),
+                start,
+                system_version,
+                record_file,
             }
             .run()
         });
         Ok(poller)
     }
 
+    async fn write_json_line(&mut self, value: &impl serde::Serialize) -> 
anyhow::Result<()> {
+        if let Some(file) = &mut self.record_file {
+            let mut bytes = serde_json::to_vec(value)?;
+            bytes.push(b'\n');
+            file.write_all(&bytes).await?;
+            file.flush().await?;
+        }
+        Ok(())
+    }
+
     fn run(mut self) {
         let interval = Duration::from_secs(self.options.polling_interval.get() 
as u64);
+        let mut next_time = Duration::from_secs(0);
         smol::block_on(async {
+            if let Err(e) = 
self.write_json_line(&self.system_version.clone()).await {
+                log::error!("faild to write record file: {e}");
+                return;
+            }
+
             loop {
                 match self.poll_once().await {
                     Err(e) => {
@@ -311,12 +448,20 @@
                         break;
                     }
                     Ok(metrics) => {
-                        let elapsed = metrics.timestamp.elapsed();
+                        let elapsed = metrics.timestamp;
+
+                        if let Err(e) = self.write_json_line(&metrics).await {
+                            log::error!("faild to write record file: {e}");
+                            break;
+                        }
+
                         if self.tx.send(metrics).is_err() {
                             log::debug!("the main thread has terminated");
                             break;
                         }
-                        if let Some(sleep_duration) = 
interval.checked_sub(elapsed) {
+
+                        next_time += interval;
+                        if let Some(sleep_duration) = 
next_time.checked_sub(elapsed) {
                             std::thread::sleep(sleep_duration);
                         }
                     }
@@ -379,7 +524,7 @@
     }
 
     async fn poll_once(&mut self) -> anyhow::Result<Metrics> {
-        let mut metrics = Metrics::new();
+        let mut metrics = Metrics::new(self.start);
 
         let msacc = self
             .rpc_client
@@ -476,7 +621,7 @@
 
         log::debug!(
             "MetricsPoller::poll_once(): elapsed={:?}",
-            metrics.timestamp.elapsed()
+            metrics.timestamp
         );
         metrics.calc_delta(&self.prev_metrics);
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/erldash-0.1.3~0/src/ui.rs 
new/erldash-0.1.5~0/src/ui.rs
--- old/erldash-0.1.3~0/src/ui.rs       2023-08-08 13:43:08.000000000 +0200
+++ new/erldash-0.1.5~0/src/ui.rs       2023-10-19 04:24:59.000000000 +0200
@@ -1,7 +1,6 @@
 use crate::erlang::SystemVersion;
 use crate::metrics::{format_u64, MetricValue, Metrics, MetricsPoller};
 use crossterm::event::{KeyCode, KeyEvent};
-use ordered_float::OrderedFloat;
 use std::collections::{BTreeMap, VecDeque};
 use std::sync::mpsc;
 use std::time::{Duration, Instant};
@@ -24,6 +23,7 @@
     terminal: Terminal,
     poller: MetricsPoller,
     ui: UiState,
+    replay_cursor_time: Duration,
 }
 
 impl App {
@@ -31,20 +31,23 @@
         let terminal = Self::setup_terminal()?;
         log::debug!("setup terminal");
 
-        let system_version = poller.system_version.clone();
+        let replay_mode = poller.is_replay();
+        let system_version = poller.system_version().clone();
         Ok(Self {
             terminal,
             poller,
-            ui: UiState::new(system_version),
+            ui: UiState::new(system_version, replay_mode),
+            replay_cursor_time: Duration::default(),
         })
     }
 
     pub fn run(mut self) -> anyhow::Result<()> {
+        self.render_replay_ui_if_need()?;
         loop {
             if self.handle_event()? {
                 break;
             }
-            if self.ui.pause {
+            if self.ui.pause || self.ui.replay_mode {
                 std::thread::sleep(POLL_TIMEOUT);
             } else {
                 self.handle_poll()?;
@@ -54,7 +57,7 @@
     }
 
     fn handle_poll(&mut self) -> anyhow::Result<()> {
-        match self.poller.rx.recv_timeout(POLL_TIMEOUT) {
+        match self.poller.poll_metrics(POLL_TIMEOUT) {
             Err(mpsc::RecvTimeoutError::Disconnected) => {
                 anyhow::bail!("Erlang metrics polling thread terminated 
unexpectedly");
             }
@@ -120,6 +123,20 @@
             KeyCode::Char('p') => {
                 self.ui.pause = !self.ui.pause;
             }
+            KeyCode::Char('h') => {
+                self.replay_cursor_time = self
+                    .replay_cursor_time
+                    .saturating_sub(Duration::from_secs(1));
+                self.render_replay_ui_if_need()?;
+            }
+            KeyCode::Char('l') => {
+                if (self.replay_cursor_time + Duration::from_secs(1))
+                    < self.poller.replay_last_time()
+                {
+                    self.replay_cursor_time += Duration::from_secs(1);
+                    self.render_replay_ui_if_need()?;
+                }
+            }
             KeyCode::Left => {
                 self.ui.focus = Focus::Main;
             }
@@ -161,6 +178,41 @@
         Ok(())
     }
 
+    fn render_replay_ui_if_need(&mut self) -> anyhow::Result<()> {
+        if !self.ui.replay_mode {
+            return Ok(());
+        }
+
+        let time = self.replay_cursor_time;
+
+        self.ui.history.clear();
+        for metrics in self
+            .poller
+            .get_metrics_range(time, time + 
Duration::from_secs(CHART_DURATION))?
+        {
+            self.ui.history.push_back(metrics.clone());
+        }
+
+        self.ui.averages.clear();
+        for metrics in self.poller.get_metrics_range(
+            time.saturating_sub(Duration::from_secs(CHART_DURATION)),
+            time,
+        )? {
+            for (name, item) in &metrics.items {
+                if let Some(avg) = self.ui.averages.get_mut(name) {
+                    avg.add(item.clone());
+                } else {
+                    self.ui
+                        .averages
+                        .insert(name.clone(), AvgValue::new(item.clone()));
+                }
+            }
+        }
+
+        self.render_ui()?;
+        Ok(())
+    }
+
     fn setup_terminal() -> anyhow::Result<Terminal> {
         crossterm::terminal::enable_raw_mode()?;
         let mut stdout = std::io::stdout();
@@ -201,10 +253,11 @@
     focus: Focus,
     metrics_table_state: TableState,
     detail_table_state: TableState,
+    replay_mode: bool,
 }
 
 impl UiState {
-    fn new(system_version: SystemVersion) -> Self {
+    fn new(system_version: SystemVersion, replay_mode: bool) -> Self {
         Self {
             start: Instant::now(),
             system_version,
@@ -214,6 +267,7 @@
             focus: Focus::Main,
             metrics_table_state: TableState::default(),
             detail_table_state: TableState::default(),
+            replay_mode,
         }
     }
 
@@ -254,7 +308,9 @@
     }
 
     fn render_metrics(&mut self, f: &mut Frame, area: Rect) {
-        let block = if self.pause {
+        let block = if self.replay_mode {
+            self.make_block("Metrics (REPLAY)")
+        } else if self.pause {
             self.make_block("Metrics (PAUSED)")
         } else {
             self.make_block("Metrics")
@@ -329,11 +385,19 @@
     }
 
     fn render_help(&mut self, f: &mut Frame, area: Rect) {
-        let paragraph = Paragraph::new(vec![
-            Spans::from("Quit:           'q' key"),
-            Spans::from("Pause / Resume: 'p' key"),
-            Spans::from("Move:           UP / DOWN / LEFT / RIGHT keys"),
-        ])
+        let paragraph = if self.replay_mode {
+            Paragraph::new(vec![
+                Spans::from("Quit:           'q' key"),
+                Spans::from("Prev / Next:    'h' / 'l' keys"),
+                Spans::from("Move:           UP / DOWN / LEFT / RIGHT keys"),
+            ])
+        } else {
+            Paragraph::new(vec![
+                Spans::from("Quit:           'q' key"),
+                Spans::from("Pause / Resume: 'p' key"),
+                Spans::from("Move:           UP / DOWN / LEFT / RIGHT keys"),
+            ])
+        }
         .block(self.make_block("Help"))
         .alignment(Alignment::Left);
         f.render_widget(paragraph, area);
@@ -384,16 +448,14 @@
 
         let lower_bound = data
             .iter()
-            .map(|(_, y)| OrderedFloat(*y))
-            .min()
-            .map(|y| y.0)
+            .map(|(_, y)| *y)
+            .min_by(|a, b| a.total_cmp(b))
             .expect("unreachable")
             .floor();
         let mut upper_bound = data
             .iter()
-            .map(|(_, y)| OrderedFloat(*y))
-            .max()
-            .map(|y| y.0)
+            .map(|(_, y)| *y)
+            .max_by(|a, b| a.total_cmp(b))
             .expect("unreachable")
             .ceil();
         let is_constant = lower_bound == upper_bound;

++++++ vendor.tar.xz ++++++
/work/SRC/openSUSE:Factory/erldash/vendor.tar.xz 
/work/SRC/openSUSE:Factory/.erldash.new.1945/vendor.tar.xz differ: char 26, 
line 1

Reply via email to