Major updates: - Complete Rust rewrite (pilot-v2/) with working MQTT client - Fixed MQTT event loop deadlock (background task pattern) - Battery telemetry for Linux (auto-detected via /sys/class/power_supply) - Home Assistant auto-discovery for all sensors and switches - Comprehensive documentation (AVANCEMENT.md, CLAUDE.md, roadmap) - Docker test environment with Mosquitto broker - Helper scripts for development and testing Features working: ✅ MQTT connectivity with LWT ✅ YAML configuration with validation ✅ Telemetry: CPU, memory, IP, battery (Linux) ✅ Commands: shutdown, reboot, sleep, screen (dry-run tested) ✅ HA discovery and integration ✅ Allowlist and cooldown protection Ready for testing on real hardware. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
165 lines
21 KiB
HTML
165 lines
21 KiB
HTML
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="sysinfo "><title>sysinfo - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../static.files/rustdoc-ca0dd0c4.css"><meta name="rustdoc-vars" data-root-path="../" data-static-root-path="../static.files/" data-current-crate="sysinfo" data-themes="" data-resource-suffix="" data-rustdoc-version="1.92.0 (ded5c06cf 2025-12-08)" data-channel="1.92.0" data-search-js="search-d69d8955.js" data-stringdex-js="stringdex-c3e638e9.js" data-settings-js="settings-c38705f0.js" ><script src="../static.files/storage-e2aeef58.js"></script><script defer src="../crates.js"></script><script defer src="../static.files/main-ce535bd0.js"></script><noscript><link rel="stylesheet" href="../static.files/noscript-263c88ec.css"></noscript><link rel="alternate icon" type="image/png" href="../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../static.files/favicon-044be391.svg"></head><body class="rustdoc mod crate"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">Crate sysinfo</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../sysinfo/index.html">sysinfo</a><span class="version">0.30.13</span></h2></div><div class="sidebar-elems"><ul class="block"><li><a id="all-types" href="all.html">All Items</a></li></ul><section id="rustdoc-toc"><h3><a href="#">Sections</a></h3><ul class="block top-toc"><li><a href="#sysinfo--" title="sysinfo ">sysinfo </a><ul><li><a href="#supported-oses" title="Supported OSes">Supported OSes</a></li><li><a href="#usage" title="Usage">Usage</a></li><li><a href="#donations" title="Donations">Donations</a></li></ul></li></ul><h3><a href="#structs">Crate Items</a></h3><ul class="block"><li><a href="#structs" title="Structs">Structs</a></li><li><a href="#enums" title="Enums">Enums</a></li><li><a href="#constants" title="Constants">Constants</a></li><li><a href="#functions" title="Functions">Functions</a></li></ul></section><div id="rustdoc-modnav"></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content"><div class="main-heading"><h1>Crate <span>sysinfo</span> <button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../src/sysinfo/lib.rs.html#3-582">Source</a> </span></div><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><h2 id="sysinfo--"><a class="doc-anchor" href="#sysinfo--">§</a>sysinfo <a href="https://crates.io/crates/sysinfo"><img src="https://img.shields.io/crates/v/sysinfo.svg" alt="" /></a> <a href="https://docs.rs/sysinfo/"><img src="https://img.shields.io/badge/rust-documentation-blue.svg" alt="" /></a></h2>
|
||
<p><code>sysinfo</code> is a crate used to get a system’s information.</p>
|
||
<h3 id="supported-oses"><a class="doc-anchor" href="#supported-oses">§</a>Supported OSes</h3>
|
||
<p>It currently supports the following OSes (alphabetically sorted):</p>
|
||
<ul>
|
||
<li>Android</li>
|
||
<li>FreeBSD</li>
|
||
<li>iOS</li>
|
||
<li>Linux</li>
|
||
<li>macOS</li>
|
||
<li>Raspberry Pi</li>
|
||
<li>Windows</li>
|
||
</ul>
|
||
<p>You can still use <code>sysinfo</code> on non-supported OSes, it’ll simply do nothing and always return
|
||
empty values. You can check in your program directly if an OS is supported by checking the
|
||
<a href="constant.IS_SUPPORTED_SYSTEM.html" title="constant sysinfo::IS_SUPPORTED_SYSTEM"><code>IS_SUPPORTED_SYSTEM</code></a> constant.</p>
|
||
<p>The minimum-supported version of <code>rustc</code> is <strong>1.69</strong>.</p>
|
||
<h3 id="usage"><a class="doc-anchor" href="#usage">§</a>Usage</h3>
|
||
<p>If you want to migrate from an older version, don’t hesitate to take a look at the
|
||
<a href="https://github.com/GuillaumeGomez/sysinfo/blob/master/CHANGELOG.md">CHANGELOG</a> and at the
|
||
<a href="https://github.com/GuillaumeGomez/sysinfo/blob/master/migration_guide.md">migration guide</a>.</p>
|
||
<p>⚠️ Before any attempt to read the different structs’ information, you need to update them to
|
||
get up-to-date information because for most of them, it works on diff between the current value
|
||
and the old one.</p>
|
||
<p>Which is why, it’s much better to keep the same instance of <a href="struct.System.html" title="struct sysinfo::System"><code>System</code></a> around instead of
|
||
recreating it multiple times.</p>
|
||
<p>You have an example into the <code>examples</code> folder. You can run it with <code>cargo run --example simple</code>.</p>
|
||
<p>Otherwise, here is a little code sample:</p>
|
||
|
||
<div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="kw">use </span>sysinfo::{
|
||
Components, Disks, Networks, System,
|
||
};
|
||
|
||
<span class="comment">// Please note that we use "new_all" to ensure that all list of
|
||
// components, network interfaces, disks and users are already
|
||
// filled!
|
||
</span><span class="kw">let </span><span class="kw-2">mut </span>sys = System::new_all();
|
||
|
||
<span class="comment">// First we update all information of our `System` struct.
|
||
</span>sys.refresh_all();
|
||
|
||
<span class="macro">println!</span>(<span class="string">"=> system:"</span>);
|
||
<span class="comment">// RAM and swap information:
|
||
</span><span class="macro">println!</span>(<span class="string">"total memory: {} bytes"</span>, sys.total_memory());
|
||
<span class="macro">println!</span>(<span class="string">"used memory : {} bytes"</span>, sys.used_memory());
|
||
<span class="macro">println!</span>(<span class="string">"total swap : {} bytes"</span>, sys.total_swap());
|
||
<span class="macro">println!</span>(<span class="string">"used swap : {} bytes"</span>, sys.used_swap());
|
||
|
||
<span class="comment">// Display system information:
|
||
</span><span class="macro">println!</span>(<span class="string">"System name: {:?}"</span>, System::name());
|
||
<span class="macro">println!</span>(<span class="string">"System kernel version: {:?}"</span>, System::kernel_version());
|
||
<span class="macro">println!</span>(<span class="string">"System OS version: {:?}"</span>, System::os_version());
|
||
<span class="macro">println!</span>(<span class="string">"System host name: {:?}"</span>, System::host_name());
|
||
|
||
<span class="comment">// Number of CPUs:
|
||
</span><span class="macro">println!</span>(<span class="string">"NB CPUs: {}"</span>, sys.cpus().len());
|
||
|
||
<span class="comment">// Display processes ID, name na disk usage:
|
||
</span><span class="kw">for </span>(pid, process) <span class="kw">in </span>sys.processes() {
|
||
<span class="macro">println!</span>(<span class="string">"[{pid}] {} {:?}"</span>, process.name(), process.disk_usage());
|
||
}
|
||
|
||
<span class="comment">// We display all disks' information:
|
||
</span><span class="macro">println!</span>(<span class="string">"=> disks:"</span>);
|
||
<span class="kw">let </span>disks = Disks::new_with_refreshed_list();
|
||
<span class="kw">for </span>disk <span class="kw">in </span><span class="kw-2">&</span>disks {
|
||
<span class="macro">println!</span>(<span class="string">"{disk:?}"</span>);
|
||
}
|
||
|
||
<span class="comment">// Network interfaces name, total data received and total data transmitted:
|
||
</span><span class="kw">let </span>networks = Networks::new_with_refreshed_list();
|
||
<span class="macro">println!</span>(<span class="string">"=> networks:"</span>);
|
||
<span class="kw">for </span>(interface_name, data) <span class="kw">in </span><span class="kw-2">&</span>networks {
|
||
<span class="macro">println!</span>(
|
||
<span class="string">"{interface_name}: {} B (down) / {} B (up)"</span>,
|
||
data.total_received(),
|
||
data.total_transmitted(),
|
||
);
|
||
<span class="comment">// If you want the amount of data received/transmitted since last call
|
||
// to `Networks::refresh`, use `received`/`transmitted`.
|
||
</span>}
|
||
|
||
<span class="comment">// Components temperature:
|
||
</span><span class="kw">let </span>components = Components::new_with_refreshed_list();
|
||
<span class="macro">println!</span>(<span class="string">"=> components:"</span>);
|
||
<span class="kw">for </span>component <span class="kw">in </span><span class="kw-2">&</span>components {
|
||
<span class="macro">println!</span>(<span class="string">"{component:?}"</span>);
|
||
}</code></pre></div>
|
||
<p>Please remember that to have some up-to-date information, you need to call the equivalent
|
||
<code>refresh</code> method. For example, for the CPU usage:</p>
|
||
|
||
<div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="kw">use </span>sysinfo::System;
|
||
|
||
<span class="kw">let </span><span class="kw-2">mut </span>sys = System::new();
|
||
|
||
<span class="kw">loop </span>{
|
||
sys.refresh_cpu(); <span class="comment">// Refreshing CPU information.
|
||
</span><span class="kw">for </span>cpu <span class="kw">in </span>sys.cpus() {
|
||
<span class="macro">print!</span>(<span class="string">"{}% "</span>, cpu.cpu_usage());
|
||
}
|
||
<span class="comment">// Sleeping to let time for the system to run for long
|
||
// enough to have useful information.
|
||
</span>std::thread::sleep(sysinfo::MINIMUM_CPU_UPDATE_INTERVAL);
|
||
}</code></pre></div>
|
||
<p>By default, <code>sysinfo</code> uses multiple threads. However, this can increase the memory usage on some
|
||
platforms (macOS for example). The behavior can be disabled by setting <code>default-features = false</code>
|
||
in <code>Cargo.toml</code> (which disables the <code>multithread</code> cargo feature).</p>
|
||
<h4 id="good-practice--performance-tips"><a class="doc-anchor" href="#good-practice--performance-tips">§</a>Good practice / Performance tips</h4>
|
||
<p>Most of the time, you don’t want all information provided by <code>sysinfo</code> but just a subset of it.
|
||
In this case, it’s recommended to use <code>refresh_specifics(...)</code> methods with only what you need
|
||
to have much better performance.</p>
|
||
<p>Another issues frequently encountered: unless you know what you’re doing, it’s almost all the
|
||
time better to instantiate the <code>System</code> struct once and use this one instance through your
|
||
program. The reason is because a lot of information needs a previous measure to be computed
|
||
(the CPU usage for example). Another example why it’s much better: in case you want to list
|
||
all running processes, <code>sysinfo</code> needs to allocate all memory for the <code>Process</code> struct list,
|
||
which takes quite some time on the first run.</p>
|
||
<p>If your program needs to use a lot of file descriptors, you’d better use:</p>
|
||
|
||
<div class="example-wrap"><pre class="rust rust-example-rendered"><code>sysinfo::set_open_files_limit(<span class="number">0</span>);</code></pre></div>
|
||
<p>as <code>sysinfo</code> keeps a number of file descriptors open to have better performance on some
|
||
targets when refreshing processes.</p>
|
||
<h4 id="running-on-raspberry-pi"><a class="doc-anchor" href="#running-on-raspberry-pi">§</a>Running on Raspberry Pi</h4>
|
||
<p>It’ll be difficult to build on Raspberry Pi. A good way-around is to cross-build, then send the
|
||
executable to your Raspberry Pi.</p>
|
||
<p>First install the arm toolchain, for example on Ubuntu:</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>> sudo apt-get install gcc-multilib-arm-linux-gnueabihf</code></pre></div>
|
||
<p>Then configure cargo to use the corresponding toolchain:</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>cat << EOF > ~/.cargo/config
|
||
[target.armv7-unknown-linux-gnueabihf]
|
||
linker = "arm-linux-gnueabihf-gcc"
|
||
EOF</code></pre></div>
|
||
<p>Finally, cross compile:</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>rustup target add armv7-unknown-linux-gnueabihf
|
||
cargo build --target=armv7-unknown-linux-gnueabihf</code></pre></div><h4 id="linux-on-docker--windows-subsystem-for-linux-wsl"><a class="doc-anchor" href="#linux-on-docker--windows-subsystem-for-linux-wsl">§</a>Linux on Docker & Windows Subsystem for Linux (WSL)</h4>
|
||
<p>Virtual Linux systems, such as those run through Docker and Windows Subsystem for Linux (WSL), do
|
||
not receive host hardware information via <code>/sys/class/hwmon</code> or <code>/sys/class/thermal</code>. As such,
|
||
querying for components may return no results (or unexpected results) when using this library on
|
||
virtual systems.</p>
|
||
<h4 id="use-in-binaries-running-inside-the-macos-or-ios-sandboxstores"><a class="doc-anchor" href="#use-in-binaries-running-inside-the-macos-or-ios-sandboxstores">§</a>Use in binaries running inside the macOS or iOS Sandbox/stores</h4>
|
||
<p>Apple has restrictions as to which APIs can be linked into binaries that are distributed through the app store.
|
||
By default, <code>sysinfo</code> is not compatible with these restrictions. You can use the <code>apple-app-store</code>
|
||
feature flag to disable the Apple prohibited features. This also enables the <code>apple-sandbox</code> feature.
|
||
In the case of applications using the sandbox outside of the app store, the <code>apple-sandbox</code> feature
|
||
can be used alone to avoid causing policy violations at runtime.</p>
|
||
<h4 id="how-it-works"><a class="doc-anchor" href="#how-it-works">§</a>How it works</h4>
|
||
<p>I wrote a blog post you can find <a href="https://blog.guillaume-gomez.fr/articles/2021-09-06+sysinfo%3A+how+to+extract+systems%27+information">here</a> which explains how <code>sysinfo</code> extracts information
|
||
on the different systems.</p>
|
||
<h4 id="c-interface"><a class="doc-anchor" href="#c-interface">§</a>C interface</h4>
|
||
<p>It’s possible to use this crate directly from C. Take a look at the <code>Makefile</code> and at the
|
||
<code>examples/simple.c</code> file.</p>
|
||
<p>To build the C example, just run:</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>> make
|
||
> ./simple
|
||
# If needed:
|
||
> LD_LIBRARY_PATH=target/debug/ ./simple</code></pre></div><h4 id="benchmarks"><a class="doc-anchor" href="#benchmarks">§</a>Benchmarks</h4>
|
||
<p>You can run the benchmarks locally with rust <strong>nightly</strong> by doing:</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>> cargo bench</code></pre></div><h3 id="donations"><a class="doc-anchor" href="#donations">§</a>Donations</h3>
|
||
<p>If you appreciate my work and want to support me, you can do it with
|
||
<a href="https://github.com/sponsors/GuillaumeGomez">github sponsors</a> or with
|
||
<a href="https://www.patreon.com/GuillaumeGomez">patreon</a>.</p>
|
||
</div></details><h2 id="structs" class="section-header">Structs<a href="#structs" class="anchor">§</a></h2><dl class="item-table"><dt><a class="struct" href="struct.CGroupLimits.html" title="struct sysinfo::CGroupLimits">CGroup<wbr>Limits</a></dt><dd>Contains memory limits for the current process.</dd><dt><a class="struct" href="struct.Component.html" title="struct sysinfo::Component">Component</a></dt><dd>Getting a component temperature information.</dd><dt><a class="struct" href="struct.Components.html" title="struct sysinfo::Components">Components</a></dt><dd>Interacting with components.</dd><dt><a class="struct" href="struct.Cpu.html" title="struct sysinfo::Cpu">Cpu</a></dt><dd>Contains all the methods of the <a href="struct.Cpu.html" title="struct sysinfo::Cpu"><code>Cpu</code></a> struct.</dd><dt><a class="struct" href="struct.CpuRefreshKind.html" title="struct sysinfo::CpuRefreshKind">CpuRefresh<wbr>Kind</a></dt><dd>Used to determine what you want to refresh specifically on the <a href="struct.Cpu.html" title="struct sysinfo::Cpu"><code>Cpu</code></a> type.</dd><dt><a class="struct" href="struct.Disk.html" title="struct sysinfo::Disk">Disk</a></dt><dd>Struct containing a disk information.</dd><dt><a class="struct" href="struct.DiskUsage.html" title="struct sysinfo::DiskUsage">Disk<wbr>Usage</a></dt><dd>Type containing read and written bytes.</dd><dt><a class="struct" href="struct.Disks.html" title="struct sysinfo::Disks">Disks</a></dt><dd>Disks interface.</dd><dt><a class="struct" href="struct.Gid.html" title="struct sysinfo::Gid">Gid</a></dt><dd>A group id wrapping a platform specific type.</dd><dt><a class="struct" href="struct.Group.html" title="struct sysinfo::Group">Group</a></dt><dd>Type containing group information.</dd><dt><a class="struct" href="struct.Groups.html" title="struct sysinfo::Groups">Groups</a></dt><dd>Interacting with groups.</dd><dt><a class="struct" href="struct.LoadAvg.html" title="struct sysinfo::LoadAvg">LoadAvg</a></dt><dd>A struct representing system load average value.</dd><dt><a class="struct" href="struct.MacAddr.html" title="struct sysinfo::MacAddr">MacAddr</a></dt><dd>MAC address for network interface.</dd><dt><a class="struct" href="struct.MemoryRefreshKind.html" title="struct sysinfo::MemoryRefreshKind">Memory<wbr>Refresh<wbr>Kind</a></dt><dd>Used to determine which memory you want to refresh specifically.</dd><dt><a class="struct" href="struct.NetworkData.html" title="struct sysinfo::NetworkData">Network<wbr>Data</a></dt><dd>Getting volume of received and transmitted data.</dd><dt><a class="struct" href="struct.Networks.html" title="struct sysinfo::Networks">Networks</a></dt><dd>Interacting with network interfaces.</dd><dt><a class="struct" href="struct.Pid.html" title="struct sysinfo::Pid">Pid</a></dt><dd>Process ID.</dd><dt><a class="struct" href="struct.Process.html" title="struct sysinfo::Process">Process</a></dt><dd>Struct containing information of a process.</dd><dt><a class="struct" href="struct.ProcessRefreshKind.html" title="struct sysinfo::ProcessRefreshKind">Process<wbr>Refresh<wbr>Kind</a></dt><dd>Used to determine what you want to refresh specifically on the <a href="struct.Process.html" title="struct sysinfo::Process"><code>Process</code></a> type.</dd><dt><a class="struct" href="struct.RefreshKind.html" title="struct sysinfo::RefreshKind">Refresh<wbr>Kind</a></dt><dd>Used to determine what you want to refresh specifically on the <a href="struct.System.html" title="struct sysinfo::System"><code>System</code></a> type.</dd><dt><a class="struct" href="struct.System.html" title="struct sysinfo::System">System</a></dt><dd>Structs containing system’s information such as processes, memory and CPU.</dd><dt><a class="struct" href="struct.Uid.html" title="struct sysinfo::Uid">Uid</a></dt><dd>A user id wrapping a platform specific type.</dd><dt><a class="struct" href="struct.User.html" title="struct sysinfo::User">User</a></dt><dd>Type containing user information.</dd><dt><a class="struct" href="struct.Users.html" title="struct sysinfo::Users">Users</a></dt><dd>Interacting with users.</dd></dl><h2 id="enums" class="section-header">Enums<a href="#enums" class="anchor">§</a></h2><dl class="item-table"><dt><a class="enum" href="enum.DiskKind.html" title="enum sysinfo::DiskKind">Disk<wbr>Kind</a></dt><dd>Enum containing the different supported kinds of disks.</dd><dt><a class="enum" href="enum.ProcessStatus.html" title="enum sysinfo::ProcessStatus">Process<wbr>Status</a></dt><dd>Enum describing the different status of a process.</dd><dt><a class="enum" href="enum.Signal.html" title="enum sysinfo::Signal">Signal</a></dt><dd>An enum representing signals on UNIX-like systems.</dd><dt><a class="enum" href="enum.ThreadKind.html" title="enum sysinfo::ThreadKind">Thread<wbr>Kind</a></dt><dd>Enum describing the different kind of threads.</dd><dt><a class="enum" href="enum.UpdateKind.html" title="enum sysinfo::UpdateKind">Update<wbr>Kind</a></dt><dd>This enum allows you to specify when you want the related information to be updated.</dd></dl><h2 id="constants" class="section-header">Constants<a href="#constants" class="anchor">§</a></h2><dl class="item-table"><dt><a class="constant" href="constant.IS_SUPPORTED_SYSTEM.html" title="constant sysinfo::IS_SUPPORTED_SYSTEM">IS_<wbr>SUPPORTED_<wbr>SYSTEM</a></dt><dd>Returns <code>true</code> if this OS is supported. Please refer to the
|
||
<a href="index.html">crate-level documentation</a> to get the list of supported OSes.</dd><dt><a class="constant" href="constant.MINIMUM_CPU_UPDATE_INTERVAL.html" title="constant sysinfo::MINIMUM_CPU_UPDATE_INTERVAL">MINIMUM_<wbr>CPU_<wbr>UPDATE_<wbr>INTERVAL</a></dt><dd>This is the minimum interval time used internally by <code>sysinfo</code> to refresh the CPU time.</dd><dt><a class="constant" href="constant.SUPPORTED_SIGNALS.html" title="constant sysinfo::SUPPORTED_SIGNALS">SUPPORTED_<wbr>SIGNALS</a></dt><dd>Returns the list of the supported signals on this system (used by
|
||
<a href="struct.Process.html#method.kill_with" title="method sysinfo::Process::kill_with"><code>Process::kill_with</code></a>).</dd></dl><h2 id="functions" class="section-header">Functions<a href="#functions" class="anchor">§</a></h2><dl class="item-table"><dt><a class="fn" href="fn.get_current_pid.html" title="fn sysinfo::get_current_pid">get_<wbr>current_<wbr>pid</a></dt><dd>Returns the pid for the current process.</dd><dt><a class="fn" href="fn.set_open_files_limit.html" title="fn sysinfo::set_open_files_limit">set_<wbr>open_<wbr>files_<wbr>limit</a></dt><dd>This function is only used on Linux targets, on the other platforms it does nothing and returns
|
||
<code>false</code>.</dd></dl></section></div></main></body></html> |