<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ilia Alshanetsky</title>
    <description>The latest articles on DEV Community by Ilia Alshanetsky (@iliaa).</description>
    <link>https://dev.to/iliaa</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3866511%2Ff435f62a-66cb-4c1a-bdf4-aa79870ddd9a.png</url>
      <title>DEV Community: Ilia Alshanetsky</title>
      <link>https://dev.to/iliaa</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/iliaa"/>
    <language>en</language>
    <item>
      <title>It's Alive! statgrab Returns After 20 Years</title>
      <dc:creator>Ilia Alshanetsky</dc:creator>
      <pubDate>Tue, 28 Apr 2026 21:15:29 +0000</pubDate>
      <link>https://dev.to/iliaa/its-alive-statgrab-returns-after-20-years-36e3</link>
      <guid>https://dev.to/iliaa/its-alive-statgrab-returns-after-20-years-36e3</guid>
      <description>&lt;p&gt;In 2005 I wrote a PHP binding for libstatgrab and pushed it to PECL. The extension took CPU, memory, disk I/O, network, process, and user statistics from a cross-platform C library and exposed them to PHP as plain functions. I moved on to other things, libstatgrab kept evolving, PHP went through three major versions, and the binding sat untouched. By 2020 you could not build it against PHP 7 without patches. By PHP 8 it was effectively gone.&lt;/p&gt;

&lt;p&gt;statgrab 2.0 brings it back. PHP 8.0 through 8.5, libstatgrab 0.92+, glibc Linux, musl, macOS, FreeBSD. The 2006 procedural API still works (&lt;code&gt;sg_cpu_percent_usage&lt;/code&gt;, &lt;code&gt;sg_memory_stats&lt;/code&gt;, &lt;code&gt;sg_diskio_stats&lt;/code&gt;), there is a modern OO surface (&lt;code&gt;Statgrab::cpu()&lt;/code&gt;, &lt;code&gt;Statgrab::memory()&lt;/code&gt;, &lt;code&gt;Statgrab::processes()&lt;/code&gt;), counters return as 64-bit &lt;code&gt;int&lt;/code&gt; instead of the 2006 stringified &lt;code&gt;%lld&lt;/code&gt;, and the BC bugs that were latent in the original (swapped page-stat keys, copy-pasted gid/egid fields, the flat &lt;code&gt;name_list&lt;/code&gt; for users) are fixed.&lt;/p&gt;

&lt;p&gt;A few things had to change to get there. One of them was upstreaming a memory leak fix to libstatgrab itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why bring it back at all
&lt;/h2&gt;

&lt;p&gt;I do not pull old extensions forward by default. I learned why with &lt;a href="https://github.com/iliaal/lchash" rel="noopener noreferrer"&gt;&lt;code&gt;lchash&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;lchash is another extension I originally pushed to PECL in 2005: a string-keyed hash table for PHP, designed around the idea that PHP's array implementation, while general, carried ordering and bucket-reallocation overhead that pure key-value workloads did not need. Tighter memory footprint, faster lookup, simpler semantics ("first writer wins" like glibc &lt;code&gt;hsearch(ENTER)&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;I shipped a 1.0.0 modernization this week. Rebuilt the storage on top of &lt;a href="https://github.com/attractivechaos/klib" rel="noopener noreferrer"&gt;klib khash&lt;/a&gt;, got it green on PHP 7.4 through 8.5 NTS and ZTS, added a proper OO surface (&lt;code&gt;LcHash&lt;/code&gt; with &lt;code&gt;$obj[$key]&lt;/code&gt; dimension access), wrote a benchmark script and let it run.&lt;/p&gt;

&lt;p&gt;The numbers were not flattering. On a release build of PHP 8.4 NTS, glibc Linux x86_64, lchash takes 1.4x to 1.7x longer to insert and around 2x longer to look up than a native PHP array, at 10k, 100k, and 1M entries. That gap is structural. The PHP 7 array rewrite (Dmitry Stogov's packed-array work) and the 8.x JIT with inline caching produced a hash table the runtime treats as a first-class type, with opcode-level array-access specialization that no extension can match.&lt;/p&gt;

&lt;p&gt;The flip: lchash uses 40 to 80 percent of the memory PHP arrays do at the same entry count, because keys and values are stored as refcount-shared &lt;code&gt;zend_string&lt;/code&gt;s with no per-entry Bucket overhead. That makes the extension a real win for memory-tight workloads (a long-running CLI worker holding hundreds of thousands of small mappings), and it still has the legacy-compat and C-porting use cases it had in 2005. For general code, the answer is "just use a PHP array."&lt;/p&gt;

&lt;p&gt;I shipped lchash 1.0.0 anyway, with the benchmark table at the top of the README and the use cases honestly scoped. The lesson is not "do not revive things." It is: the revival has to be honest about what changed underneath. PHP arrays grew up. lchash now competes on memory, not speed, and the README says so before anyone has to find out.&lt;/p&gt;

&lt;p&gt;statgrab is not in that situation. PHP 8 arrays are not a substitute for cross-platform system stats. The choice today, for someone running PHP on a server who needs CPU, memory, or disk numbers, is still one of:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Shell out to &lt;code&gt;w&lt;/code&gt;, &lt;code&gt;vmstat&lt;/code&gt;, &lt;code&gt;df&lt;/code&gt;, &lt;code&gt;ps&lt;/code&gt; and parse output that drifts between OS versions. &lt;code&gt;fork&lt;/code&gt;+&lt;code&gt;exec&lt;/code&gt; overhead per call.&lt;/li&gt;
&lt;li&gt;Read &lt;code&gt;/proc&lt;/code&gt; by hand. Linux-only, format keeps shifting between kernel releases, every file (&lt;code&gt;meminfo&lt;/code&gt;, &lt;code&gt;loadavg&lt;/code&gt;, &lt;code&gt;diskstats&lt;/code&gt;, &lt;code&gt;net/dev&lt;/code&gt;) has its own quirks.&lt;/li&gt;
&lt;li&gt;Run a separate stats daemon (collectd, telegraf, node_exporter) and hit it over a socket. Adds a process and a network hop.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;libstatgrab is the right primitive for option 4: a single C library that handles the per-OS path internally (Linux &lt;code&gt;/proc&lt;/code&gt;, FreeBSD &lt;code&gt;kvm&lt;/code&gt;, macOS &lt;code&gt;host_*&lt;/code&gt; APIs) and exposes one typed surface. It has been in the Debian, Ubuntu, FreeBSD, and Homebrew package repositories for fifteen years. It just needed a PHP binding that worked on a current interpreter.&lt;/p&gt;

&lt;h2&gt;
  
  
  What modernization meant in practice
&lt;/h2&gt;

&lt;p&gt;The 2006 binding was written against PHP 5, Zend 1, and 32-bit &lt;code&gt;long&lt;/code&gt;. Most of the rewrite is mechanical: convert TSRM-style globals, replace &lt;code&gt;Z_LVAL_PP&lt;/code&gt; patterns, switch to the typed parameter parsing macros. The non-mechanical parts were the BC quirks of the original API.&lt;/p&gt;

&lt;p&gt;Four bugs were latent in the 2006 release.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stringified counters.&lt;/strong&gt; Memory totals, filesystem sizes, and CPU jiffies were returned as PHP strings. The reason was that 32-bit PHP could not hold a &lt;code&gt;uint64_t&lt;/code&gt;, so the binding called &lt;code&gt;snprintf("%lld", value)&lt;/code&gt; and shoved the string into a zval. Modern PHP runs on 64-bit &lt;code&gt;zend_long&lt;/code&gt;. The 2.0 release returns these as plain integers. Callers comparing against numeric thresholds (&lt;code&gt;if ($mem['total'] &amp;gt; 1_000_000_000)&lt;/code&gt;) now work correctly without an &lt;code&gt;intval()&lt;/code&gt; wrapping every read.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Swapped page-stat keys.&lt;/strong&gt; &lt;code&gt;sg_page_stats()&lt;/code&gt; returned &lt;code&gt;pages_in&lt;/code&gt; and &lt;code&gt;pages_out&lt;/code&gt; swapped. Anyone who used the function and noticed inverted memory pressure curves probably worked around it locally. Fixed in 2.0.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;gid&lt;/code&gt; and &lt;code&gt;egid&lt;/code&gt; were copies of &lt;code&gt;uid&lt;/code&gt; and &lt;code&gt;euid&lt;/code&gt;.&lt;/strong&gt; A copy-paste in the 2006 process-stats handler. Anyone filtering by group ID had been getting user IDs back. Fixed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;sg_user_stats()&lt;/code&gt; returned a flat list of usernames.&lt;/strong&gt; This one is a libstatgrab change, not just a binding fix. The old library exposed a &lt;code&gt;name_list&lt;/code&gt; array; the new library returns per-user records (login name, device, PID, login time, hostname). The new shape is strictly more useful. Callers reading &lt;code&gt;name_list&lt;/code&gt; migrate to reading &lt;code&gt;login_name&lt;/code&gt; from each record.&lt;/p&gt;

&lt;p&gt;The full BC catalog is in the README. None of these are surprises if you read the libstatgrab CHANGELOG; they are surprises only if you remember the 2006 binding from when you last used it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The leak I didn't expect
&lt;/h2&gt;

&lt;p&gt;While running the new test suite under AddressSanitizer, statgrab's process-exit path leaked memory. Several allocations from libstatgrab's internal structures were never freed when the library shut down.&lt;/p&gt;

&lt;p&gt;This is the kind of leak that does not matter for a long-running CLI process and does not show up in a typical request-response PHP cycle (the SAPI tears down the heap on each request). It matters for ASan-clean test runs, for valgrind-clean integration tests, and for anyone embedding libstatgrab in a long-lived process where shutdown order matters.&lt;/p&gt;

&lt;p&gt;I traced it into libstatgrab itself. The library has a &lt;code&gt;sg_shutdown()&lt;/code&gt; function but several globals were not on the cleanup path. I wrote the patch and submitted it upstream against libstatgrab 0.92.1; it is pending review. The libstatgrab release cadence is slow regardless, so the statgrab repo carries a vendored copy of libstatgrab 0.92.1 with the local patch documented under &lt;code&gt;vendor/libstatgrab/LOCAL_PATCHES.md&lt;/code&gt; in the meantime.&lt;/p&gt;

&lt;p&gt;If you build with &lt;code&gt;--with-statgrab=bundled&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;vendor/libstatgrab &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; ./configure &lt;span class="nt"&gt;--enable-static&lt;/span&gt; &lt;span class="nt"&gt;--disable-shared&lt;/span&gt; &lt;span class="nt"&gt;--without-ncurses&lt;/span&gt; &lt;span class="nt"&gt;--with-pic&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; make&lt;span class="o"&gt;)&lt;/span&gt;
phpize
./configure &lt;span class="nt"&gt;--with-statgrab&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;bundled
make
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The resulting &lt;code&gt;statgrab.so&lt;/code&gt; has no runtime dependency on &lt;code&gt;libstatgrab.so&lt;/code&gt;. It links the patched copy in statically. For containerized or shared-hosting deployments this matters: you do not need to install &lt;code&gt;libstatgrab&lt;/code&gt; on the target system, and you do not pick up whatever version the package manager happens to have. Once libstatgrab cuts a release with the patch, the bundled tree gets dropped or pinned to the released tarball.&lt;/p&gt;

&lt;p&gt;The legal bookkeeping: vendored libstatgrab stays LGPL 2.1+, the extension code stays PHP-3.01. Static linking does not infect the extension because LGPL explicitly permits this with the standard provisions; the LICENSE files document both.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cross-platform is the actual feature
&lt;/h2&gt;

&lt;p&gt;Most of the value is right here. The same PHP code that reads CPU usage on a glibc Linux box reads it on Alpine, on macOS, on FreeBSD. No conditional based on &lt;code&gt;PHP_OS&lt;/code&gt;, no different parser per platform, no surprise when an Alpine container behaves differently from the dev box because &lt;code&gt;/proc/meminfo&lt;/code&gt; formatting differs.&lt;/p&gt;

&lt;p&gt;libstatgrab does the per-OS adaptation in C, once, with tests. Linux uses &lt;code&gt;/proc&lt;/code&gt; and &lt;code&gt;sysfs&lt;/code&gt;. FreeBSD uses the &lt;code&gt;kvm&lt;/code&gt; interface. macOS uses &lt;code&gt;host_statistics()&lt;/code&gt;, &lt;code&gt;host_processor_info()&lt;/code&gt;, the BSD-style &lt;code&gt;sysctl&lt;/code&gt; tree. The binding is the same shape regardless. From the PHP side:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$cpu&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sg_cpu_percent_usage&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nv"&gt;$mem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sg_memory_stats&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nv"&gt;$load&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sg_load_stats&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those three calls return populated arrays on every supported OS. There is no "if Linux, do this; else do that" in your code.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you actually do with it
&lt;/h2&gt;

&lt;p&gt;The thing PHP people kept asking me about, when statgrab existed in 2006, was health endpoints. A small JSON endpoint that returns CPU usage, memory pressure, and load average so the load balancer or the orchestrator can decide whether to send traffic. Today that is more often the job of a Prometheus exporter or a sidecar agent, but the in-process version still has its place: when the application itself wants to know its own state.&lt;/p&gt;

&lt;p&gt;Concrete examples that come up:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A queue worker that throttles its concurrency when load average crosses a threshold.&lt;/li&gt;
&lt;li&gt;An admin dashboard inside a long-running CLI tool showing live disk I/O and network throughput.&lt;/li&gt;
&lt;li&gt;A test harness that asserts memory stays below a budget under a synthetic workload.&lt;/li&gt;
&lt;li&gt;A graceful-shutdown hook that waits for filesystem buffers to flush before exiting.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For each of those, shelling out is wrong (latency and parser fragility), and pulling in a stats daemon is overkill. statgrab fits the gap.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$mem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sg_memory_stats&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nv"&gt;$load&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sg_load_stats&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$load&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'min1'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nv"&gt;$mem&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'used'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nv"&gt;$mem&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'total'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.9&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$worker&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;throttle&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is one library call per stat, no fork, no parsing. Same code on Linux, macOS, FreeBSD.&lt;/p&gt;

&lt;p&gt;The OO surface is a thin layer for callers who prefer a class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$sg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Statgrab&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nv"&gt;$top&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$sg&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;processes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Statgrab&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;SORT_CPU&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$top&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$proc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$proc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'proc_name'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$proc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'cpu_percent'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;%&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Install
&lt;/h2&gt;

&lt;p&gt;PIE is the PHP Foundation's PECL successor and the recommended path on PHP 8.x:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pie &lt;span class="nb"&gt;install &lt;/span&gt;iliaal/statgrab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PECL still works for legacy installers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pecl &lt;span class="nb"&gt;install &lt;/span&gt;statgrab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From source against system libstatgrab (Debian, Ubuntu, macOS via Homebrew, FreeBSD pkg) is documented in the README. The &lt;code&gt;--with-statgrab=bundled&lt;/code&gt; path is for containerized environments and for picking up the unreleased leak fix.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pitch
&lt;/h2&gt;

&lt;p&gt;One library call instead of forking a process. One typed surface instead of a per-OS parser. The same PHP code reading CPU, memory, and load on Linux, macOS, and FreeBSD without conditionals.&lt;/p&gt;

&lt;p&gt;That is what the 2006 extension was reaching for, on PHP and libstatgrab versions that were not quite there yet. Both have caught up. The binding is the missing piece.&lt;/p&gt;

&lt;p&gt;If you run PHP on a server and have ever shelled out to &lt;code&gt;w&lt;/code&gt; or parsed &lt;code&gt;/proc/meminfo&lt;/code&gt; by hand, give it a look.&lt;/p&gt;

&lt;p&gt;Repository: &lt;a href="https://github.com/iliaal/statgrab" rel="noopener noreferrer"&gt;https://github.com/iliaal/statgrab&lt;/a&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>linux</category>
      <category>opensource</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
