[
  {
    "path": ".gitmodules",
    "content": "[submodule \"deps/javascriptlint\"]\n\tpath = deps/javascriptlint\n\turl = git://github.com/davepacheco/javascriptlint.git\n[submodule \"deps/jsstyle\"]\n\tpath = deps/jsstyle\n\turl = git://github.com/davepacheco/jsstyle.git\n"
  },
  {
    "path": "AUTHORS",
    "content": "# Statemap authors, ordered by first contribution\n\nBryan Cantrill <bryan@joyent.com>\nDavid Tolnay <dtolnay@gmail.com>\n\n"
  },
  {
    "path": "Cargo.toml",
    "content": "[package]\nname = \"statemap\"\nversion = \"0.1.0\"\nauthors = [\"Bryan Cantrill <bryan@joyent.com>\"]\n\n[dependencies]\ngetopts = \"0.2\"\nmemmap = \"0.6\"\nserde = \"1.0\"\nserde_json = \"1.0\"\nserde_derive = \"1.0\"\nnatord = \"1.0.9\"\npalette = \"0.4\"\nrand = \"0.5\"\n"
  },
  {
    "path": "LICENSE",
    "content": "Mozilla Public License Version 2.0\n==================================\n\n1. Definitions\n--------------\n\n1.1. \"Contributor\"\n    means each individual or legal entity that creates, contributes to\n    the creation of, or owns Covered Software.\n\n1.2. \"Contributor Version\"\n    means the combination of the Contributions of others (if any) used\n    by a Contributor and that particular Contributor's Contribution.\n\n1.3. \"Contribution\"\n    means Covered Software of a particular Contributor.\n\n1.4. \"Covered Software\"\n    means Source Code Form to which the initial Contributor has attached\n    the notice in Exhibit A, the Executable Form of such Source Code\n    Form, and Modifications of such Source Code Form, in each case\n    including portions thereof.\n\n1.5. \"Incompatible With Secondary Licenses\"\n    means\n\n    (a) that the initial Contributor has attached the notice described\n        in Exhibit B to the Covered Software; or\n\n    (b) that the Covered Software was made available under the terms of\n        version 1.1 or earlier of the License, but not also under the\n        terms of a Secondary License.\n\n1.6. \"Executable Form\"\n    means any form of the work other than Source Code Form.\n\n1.7. \"Larger Work\"\n    means a work that combines Covered Software with other material, in\n    a separate file or files, that is not Covered Software.\n\n1.8. \"License\"\n    means this document.\n\n1.9. \"Licensable\"\n    means having the right to grant, to the maximum extent possible,\n    whether at the time of the initial grant or subsequently, any and\n    all of the rights conveyed by this License.\n\n1.10. \"Modifications\"\n    means any of the following:\n\n    (a) any file in Source Code Form that results from an addition to,\n        deletion from, or modification of the contents of Covered\n        Software; or\n\n    (b) any new file in Source Code Form that contains any Covered\n        Software.\n\n1.11. \"Patent Claims\" of a Contributor\n    means any patent claim(s), including without limitation, method,\n    process, and apparatus claims, in any patent Licensable by such\n    Contributor that would be infringed, but for the grant of the\n    License, by the making, using, selling, offering for sale, having\n    made, import, or transfer of either its Contributions or its\n    Contributor Version.\n\n1.12. \"Secondary License\"\n    means either the GNU General Public License, Version 2.0, the GNU\n    Lesser General Public License, Version 2.1, the GNU Affero General\n    Public License, Version 3.0, or any later versions of those\n    licenses.\n\n1.13. \"Source Code Form\"\n    means the form of the work preferred for making modifications.\n\n1.14. \"You\" (or \"Your\")\n    means an individual or a legal entity exercising rights under this\n    License. For legal entities, \"You\" includes any entity that\n    controls, is controlled by, or is under common control with You. For\n    purposes of this definition, \"control\" means (a) the power, direct\n    or indirect, to cause the direction or management of such entity,\n    whether by contract or otherwise, or (b) ownership of more than\n    fifty percent (50%) of the outstanding shares or beneficial\n    ownership of such entity.\n\n2. License Grants and Conditions\n--------------------------------\n\n2.1. Grants\n\nEach Contributor hereby grants You a world-wide, royalty-free,\nnon-exclusive license:\n\n(a) under intellectual property rights (other than patent or trademark)\n    Licensable by such Contributor to use, reproduce, make available,\n    modify, display, perform, distribute, and otherwise exploit its\n    Contributions, either on an unmodified basis, with Modifications, or\n    as part of a Larger Work; and\n\n(b) under Patent Claims of such Contributor to make, use, sell, offer\n    for sale, have made, import, and otherwise transfer either its\n    Contributions or its Contributor Version.\n\n2.2. Effective Date\n\nThe licenses granted in Section 2.1 with respect to any Contribution\nbecome effective for each Contribution on the date the Contributor first\ndistributes such Contribution.\n\n2.3. Limitations on Grant Scope\n\nThe licenses granted in this Section 2 are the only rights granted under\nthis License. No additional rights or licenses will be implied from the\ndistribution or licensing of Covered Software under this License.\nNotwithstanding Section 2.1(b) above, no patent license is granted by a\nContributor:\n\n(a) for any code that a Contributor has removed from Covered Software;\n    or\n\n(b) for infringements caused by: (i) Your and any other third party's\n    modifications of Covered Software, or (ii) the combination of its\n    Contributions with other software (except as part of its Contributor\n    Version); or\n\n(c) under Patent Claims infringed by Covered Software in the absence of\n    its Contributions.\n\nThis License does not grant any rights in the trademarks, service marks,\nor logos of any Contributor (except as may be necessary to comply with\nthe notice requirements in Section 3.4).\n\n2.4. Subsequent Licenses\n\nNo Contributor makes additional grants as a result of Your choice to\ndistribute the Covered Software under a subsequent version of this\nLicense (see Section 10.2) or under the terms of a Secondary License (if\npermitted under the terms of Section 3.3).\n\n2.5. Representation\n\nEach Contributor represents that the Contributor believes its\nContributions are its original creation(s) or it has sufficient rights\nto grant the rights to its Contributions conveyed by this License.\n\n2.6. Fair Use\n\nThis License is not intended to limit any rights You have under\napplicable copyright doctrines of fair use, fair dealing, or other\nequivalents.\n\n2.7. Conditions\n\nSections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted\nin Section 2.1.\n\n3. Responsibilities\n-------------------\n\n3.1. Distribution of Source Form\n\nAll distribution of Covered Software in Source Code Form, including any\nModifications that You create or to which You contribute, must be under\nthe terms of this License. You must inform recipients that the Source\nCode Form of the Covered Software is governed by the terms of this\nLicense, and how they can obtain a copy of this License. You may not\nattempt to alter or restrict the recipients' rights in the Source Code\nForm.\n\n3.2. Distribution of Executable Form\n\nIf You distribute Covered Software in Executable Form then:\n\n(a) such Covered Software must also be made available in Source Code\n    Form, as described in Section 3.1, and You must inform recipients of\n    the Executable Form how they can obtain a copy of such Source Code\n    Form by reasonable means in a timely manner, at a charge no more\n    than the cost of distribution to the recipient; and\n\n(b) You may distribute such Executable Form under the terms of this\n    License, or sublicense it under different terms, provided that the\n    license for the Executable Form does not attempt to limit or alter\n    the recipients' rights in the Source Code Form under this License.\n\n3.3. Distribution of a Larger Work\n\nYou may create and distribute a Larger Work under terms of Your choice,\nprovided that You also comply with the requirements of this License for\nthe Covered Software. If the Larger Work is a combination of Covered\nSoftware with a work governed by one or more Secondary Licenses, and the\nCovered Software is not Incompatible With Secondary Licenses, this\nLicense permits You to additionally distribute such Covered Software\nunder the terms of such Secondary License(s), so that the recipient of\nthe Larger Work may, at their option, further distribute the Covered\nSoftware under the terms of either this License or such Secondary\nLicense(s).\n\n3.4. Notices\n\nYou may not remove or alter the substance of any license notices\n(including copyright notices, patent notices, disclaimers of warranty,\nor limitations of liability) contained within the Source Code Form of\nthe Covered Software, except that You may alter any license notices to\nthe extent required to remedy known factual inaccuracies.\n\n3.5. Application of Additional Terms\n\nYou may choose to offer, and to charge a fee for, warranty, support,\nindemnity or liability obligations to one or more recipients of Covered\nSoftware. However, You may do so only on Your own behalf, and not on\nbehalf of any Contributor. You must make it absolutely clear that any\nsuch warranty, support, indemnity, or liability obligation is offered by\nYou alone, and You hereby agree to indemnify every Contributor for any\nliability incurred by such Contributor as a result of warranty, support,\nindemnity or liability terms You offer. You may include additional\ndisclaimers of warranty and limitations of liability specific to any\njurisdiction.\n\n4. Inability to Comply Due to Statute or Regulation\n---------------------------------------------------\n\nIf it is impossible for You to comply with any of the terms of this\nLicense with respect to some or all of the Covered Software due to\nstatute, judicial order, or regulation then You must: (a) comply with\nthe terms of this License to the maximum extent possible; and (b)\ndescribe the limitations and the code they affect. Such description must\nbe placed in a text file included with all distributions of the Covered\nSoftware under this License. Except to the extent prohibited by statute\nor regulation, such description must be sufficiently detailed for a\nrecipient of ordinary skill to be able to understand it.\n\n5. Termination\n--------------\n\n5.1. The rights granted under this License will terminate automatically\nif You fail to comply with any of its terms. However, if You become\ncompliant, then the rights granted under this License from a particular\nContributor are reinstated (a) provisionally, unless and until such\nContributor explicitly and finally terminates Your grants, and (b) on an\nongoing basis, if such Contributor fails to notify You of the\nnon-compliance by some reasonable means prior to 60 days after You have\ncome back into compliance. Moreover, Your grants from a particular\nContributor are reinstated on an ongoing basis if such Contributor\nnotifies You of the non-compliance by some reasonable means, this is the\nfirst time You have received notice of non-compliance with this License\nfrom such Contributor, and You become compliant prior to 30 days after\nYour receipt of the notice.\n\n5.2. If You initiate litigation against any entity by asserting a patent\ninfringement claim (excluding declaratory judgment actions,\ncounter-claims, and cross-claims) alleging that a Contributor Version\ndirectly or indirectly infringes any patent, then the rights granted to\nYou by any and all Contributors for the Covered Software under Section\n2.1 of this License shall terminate.\n\n5.3. In the event of termination under Sections 5.1 or 5.2 above, all\nend user license agreements (excluding distributors and resellers) which\nhave been validly granted by You or Your distributors under this License\nprior to termination shall survive termination.\n\n************************************************************************\n*                                                                      *\n*  6. Disclaimer of Warranty                                           *\n*  -------------------------                                           *\n*                                                                      *\n*  Covered Software is provided under this License on an \"as is\"       *\n*  basis, without warranty of any kind, either expressed, implied, or  *\n*  statutory, including, without limitation, warranties that the       *\n*  Covered Software is free of defects, merchantable, fit for a        *\n*  particular purpose or non-infringing. The entire risk as to the     *\n*  quality and performance of the Covered Software is with You.        *\n*  Should any Covered Software prove defective in any respect, You     *\n*  (not any Contributor) assume the cost of any necessary servicing,   *\n*  repair, or correction. This disclaimer of warranty constitutes an   *\n*  essential part of this License. No use of any Covered Software is   *\n*  authorized under this License except under this disclaimer.         *\n*                                                                      *\n************************************************************************\n\n************************************************************************\n*                                                                      *\n*  7. Limitation of Liability                                          *\n*  --------------------------                                          *\n*                                                                      *\n*  Under no circumstances and under no legal theory, whether tort      *\n*  (including negligence), contract, or otherwise, shall any           *\n*  Contributor, or anyone who distributes Covered Software as          *\n*  permitted above, be liable to You for any direct, indirect,         *\n*  special, incidental, or consequential damages of any character      *\n*  including, without limitation, damages for lost profits, loss of    *\n*  goodwill, work stoppage, computer failure or malfunction, or any    *\n*  and all other commercial damages or losses, even if such party      *\n*  shall have been informed of the possibility of such damages. This   *\n*  limitation of liability shall not apply to liability for death or   *\n*  personal injury resulting from such party's negligence to the       *\n*  extent applicable law prohibits such limitation. Some               *\n*  jurisdictions do not allow the exclusion or limitation of           *\n*  incidental or consequential damages, so this exclusion and          *\n*  limitation may not apply to You.                                    *\n*                                                                      *\n************************************************************************\n\n8. Litigation\n-------------\n\nAny litigation relating to this License may be brought only in the\ncourts of a jurisdiction where the defendant maintains its principal\nplace of business and such litigation shall be governed by laws of that\njurisdiction, without reference to its conflict-of-law provisions.\nNothing in this Section shall prevent a party's ability to bring\ncross-claims or counter-claims.\n\n9. Miscellaneous\n----------------\n\nThis License represents the complete agreement concerning the subject\nmatter hereof. If any provision of this License is held to be\nunenforceable, such provision shall be reformed only to the extent\nnecessary to make it enforceable. Any law or regulation which provides\nthat the language of a contract shall be construed against the drafter\nshall not be used to construe this License against a Contributor.\n\n10. Versions of the License\n---------------------------\n\n10.1. New Versions\n\nMozilla Foundation is the license steward. Except as provided in Section\n10.3, no one other than the license steward has the right to modify or\npublish new versions of this License. Each version will be given a\ndistinguishing version number.\n\n10.2. Effect of New Versions\n\nYou may distribute the Covered Software under the terms of the version\nof the License under which You originally received the Covered Software,\nor under the terms of any subsequent version published by the license\nsteward.\n\n10.3. Modified Versions\n\nIf you create software not governed by this License, and you want to\ncreate a new license for such software, you may create and use a\nmodified version of this License if you rename the license and remove\nany references to the name of the license steward (except to note that\nsuch modified license differs from this License).\n\n10.4. Distributing Source Code Form that is Incompatible With Secondary\nLicenses\n\nIf You choose to distribute Source Code Form that is Incompatible With\nSecondary Licenses under the terms of this version of the License, the\nnotice described in Exhibit B of this License must be attached.\n\nExhibit A - Source Code Form License Notice\n-------------------------------------------\n\n  This Source Code Form is subject to the terms of the Mozilla Public\n  License, v. 2.0. If a copy of the MPL was not distributed with this\n  file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\nIf it is not possible or desirable to put the notice in a particular\nfile, then You may include the notice in a location (such as a LICENSE\nfile in a relevant directory) where a recipient would be likely to look\nfor such a notice.\n\nYou may add additional accurate notices of copyright ownership.\n\nExhibit B - \"Incompatible With Secondary Licenses\" Notice\n---------------------------------------------------------\n\n  This Source Code Form is \"Incompatible With Secondary Licenses\", as\n  defined by the Mozilla Public License, v. 2.0.\n"
  },
  {
    "path": "README.md",
    "content": "# Statemap\n\nThis repository contains the software for rendering _statemaps_, a\nsoftware visualization in which time is on the X axis and timelines\nfor discrete entities are stacked on the Y axis, with different states\nfor the discrete entities rendered in different colors.\n\nGenerating a statemap consists of two steps: *instrumentation* and\n*rendering*.  The result is a SVG that can be visualized with a SVG \nviewer (e.g., a web browser), allowing *interaction*.\n\n## Installation\n\nTo compile the command to render a statemap from instrumentation data:\n\n    cargo build --release\n\nNote that statemap requires Rust.\n\n## Instrumentation\n\nStatemaps themselves are methodology- and OS-agnostic, but instrumentation\nis usually more system-specific.\nThe `contrib` directory contains instrumentation for specific methodologies\nand systems that will generate data that can be used \nas input to the `statemap` command:\n\n<table>\n<tr>\n<th>Name</th>\n<th>Method</th>\n<th>OS</th>\n<th>Statemap description</th>\n</tr>\n<tr>\n<td><a href=\"./contrib/cpu-statemap.d\">cpu-statemap.d</a></td>\n<td>DTrace</td>\n<td>SmartOS</td>\n<td>CPU activity by CPU</td>\n</tr>\n<tr>\n<td><a href=\"./contrib/cpu-statemap-tagged.d\">cpu-statemap-tagged.d</a></td>\n<td>DTrace</td>\n<td>SmartOS</td>\n<td>CPU activity by CPU, tagged by origin of activity</td>\n</tr>\n<tr>\n<td><a href=\"./contrib/io-statemap.d\">io-statemap.d</a></td>\n<td>DTrace</td>\n<td>SmartOS</td>\n<td>SCSI devices in terms of number of outstanding I/O operations</td>\n</tr>\n<tr>\n<td><a href=\"./contrib/lx-cmd-statemap.d\">lx-cmd-statemap.d</a></td>\n<td>DTrace</td>\n<td>SmartOS</td>\n<td>Processes and threads of a specified command in an LX zone</td>\n</tr>\n<tr>\n<td><a href=\"./contrib/lx-statemap.d\">lx-statemap.d</a></td>\n<td>DTrace</td>\n<td>SmartOS</td>\n<td>Threads in a specified process in an LX zone</td>\n</tr>\n<tr>\n<td><a href=\"./contrib/postgres-statemap.d\">postgres-statemap.d</a></td>\n<td>DTrace</td>\n<td>SmartOS</td>\n<td>PostgreSQL processes</td>\n</tr>\n<tr>\n<td><a href=\"./contrib/postgres-zfs-statemap.d\">postgres-zfs-statemap.d</a></td>\n<td>DTrace</td>\n<td>SmartOS</td>\n<td>PostgreSQL processes, with ZFS-specific states</td>\n</tr>\n<tr>\n<td><a href=\"./contrib/spa-sync-statemap.d\">spa-sync-statemap.d</a></td>\n<td>DTrace</td>\n<td>SmartOS</td>\n<td>ZFS SPA sync thread state</td>\n</tr>\n<tr>\n<td><a href=\"./contrib/vdev-statemap.d\">vdev-statemap.d</a></td>\n<td>DTrace</td>\n<td>SmartOS</td>\n<td>I/O activity by ZFS vdev</td>\n</tr>\n</table>\n\n### Data format\n\nTo generate data for statemap generation,\ninstrumentation should create a file that consists of a stream of\nconcatenated JSON.\nThe expectation is that one JSON payload will consist of\nmetadata, with many JSON payloads containing data, but the metadata may\nbe split across multiple JSON payloads.  (No field can appear more than\nonce, however.)\n\n#### Metadata\n\nThe following metadata fields are required: \n\n- `start`: A two-element array of integers consisting of the start time of\nthe data in seconds (the 0th element) and nanoseconds within the \nsecond (the 1st element).  The start time should be expressed in UTC.\n\n- `states`: An object in which each member is the name of a valid\n  entity state.  Each member object can contain the following :\n\n  - `value`: The value by which this state will be referred to in the \n    data stream.\n\n  - `color`: The color that should be used to render the state. If the\n    color is not specified, a color will be selected at random.\n\n  For example, here is a valid `states` object:\n\n        \"states\": {\n                \"on-cpu\": {\"value\": 0, \"color\": \"#DAF7A6\" },\n                \"off-cpu-waiting\": {\"value\": 1, \"color\": \"#f9f9f9\" },\n                \"off-cpu-futex\": {\"value\": 2, \"color\": \"#f0f0f0\" },\n                \"off-cpu-io\": {\"value\": 3, \"color\": \"#FFC300\" },\n                \"off-cpu-blocked\": {\"value\": 4, \"color\": \"#C70039\" },\n                \"off-cpu-dead\": {\"value\": 5, \"color\": \"#581845\" }\n        }\n  \nIn addition, the metadata can contain the following optional fields are\noptional:\n\n- `title`: The title of the statemap, such that it can meaningfully be\n  in the clause \"statemap of `title` activity.\"\n\n- `host`: The host on which the data was gathered.\n\n#### Data\n\nThe data for a statemap is provided following the metadata as\nconcatenated JSON (that is, each JSON payload is a datum).  Each\ndatum is a JSON object that must contain the following members:\n\n- `entity`: The name of the entity.\n\n- `time`: The time of the datum, expressed as a nanosecond offset from\n  the `start` member present in the metadata.\n\n- `state`: The value of the state that begins at the time of the datum.\n\nEach datum may also contain an additional member:\n\n- `tag`: The tag for the state.  See State tagging, below.\n\n#### State tagging\n\nIt is often helpful to examine additional dimensionality within a particular\nstate or states.  For example, in understanding CPU activity, it may be\nhelpful to understand not just that a CPU was in a state in which it was\nexecuting a user thread, but the nature of the thread itself:  the thread\nidentifier, process identifier, process name, and so on.  To facilitate this,\nstatemaps support *state tagging* whereby an immutable tag is associated with a\nparticular transition to a particular state.  There can be an arbitrary\nnumber of such tags, but the expectation is that there are many more state\ntransitions than there are tags.  Tags are indicated by the `tag` member of\nthe state datum payload.  Elsewhere in the stream of data (though not\nnecessarily before the tag is used), the tag should be defined with\na tag-defining JSON payload that contains the following two members:\n\n- `tag`: A string that is the tag that is being defined.\n\n- `state`: The state that corresponds to this tag.  Each `state`/`tag` tuple\n  must have its own tag definition.\n\nBeyond these two members, the tag definition can have any number of scalar\nmembers.  Tags are immutable; if a tag is redefined, the last tag definition\nwill apply to all uses of that tag.  The tag should not contain member\ndefinitions that would cause it to be ambiguous with respect to data (namely,\n`entity` and `time` members).\n\nAs an example, here is a tag definition for a state that is associated with\ninterrupt activity that indicates the source device:\n\n```\n{ \"state\": 6, \"tag\": \"ffffd0c4f8f52000\", \"driver\": \"mpt_sas\", \"instance\": 1 }\n```\n\nAnd here is an example of a tagged state datum:\n\n```\n{ \"time\": \"1579579142\", \"entity\": \"55\", \"state\": 6, \"tag\": \"ffffd0c4f8f52000\" }\n```\n\nThis would indicate that at time 1579579142, entity 55 went into state 6 --\nand the tag for this state (in this case, the interrupting device) was\ninstance 1 of the `mpt_sas` driver.\n\n## Rendering\n\nTo render a statemap, run the `statemap` command, providing an instrumentation\ndata file.  The resulting statemap will be written as a SVG on standard\noutput:\n\n    statemap my-instrumentation-output.out > statemap.svg\n\nStatemaps are interactive; the resulting SVG will contain controls that\nenable it to be zoomed, panned, states selected, etc. (See Interaction,\nbelow.)\n\nBy default, statemaps consist of all states for the entire time duration\nrepresented in the input data.  Because there can be many, many states\nrepresented in the input, states will (by default) be _coalesced_ when\nthe time spent in a state is deemed a sufficiently small fraction of\nthe overall time.  For a coalesced state, the statemap will track the\noverall fraction of states present (and will use a color that represents\na proportional blend of those states' colors).  When a statemap contains\ncoalesced states, some information will be lost (namely, the exact\ntime delineations of state transitions within the coalesced state).\nCoalesced states can be eliminated in one of two ways:  either the\nstate coalescence target can be increased via the `-c` option, or the\nstatemap can be regenerated to cover a smaller range of time with some\ncombination of the `-b` option (to denote a beginning time) and the `-d`\noption (to denote a duration).  The number of coalesced states can be\ndetermined by looking at the metadata placed at the end of of the output\nSVG.\n\n### Options\n\nThe `statemap` command has the following options:\n\n- `-b` (`--begin`): Takes a time offset at which the statemap should begin.\nThe time offset may be expressed in floating point with an optional\nsuffix (e.g., `-b 12.719s`).\n\n- `-c` (`--coalesce`): Specifies the coalescing factor. Higher numbers will\nresult in less coalescence.\n\n- `-d` (`--duration`): Takes a duration time for the statemap.  The time\nmay be expressed in floating point with an optional suffix (e.g.,\n`-d 491.2ms`).\n\n- `-h` (`--state-height`): The height (in pixels) of each state in the\nstatemap.\n\n- `-i` (`--ignore-tags`): Ignore tags in the input, acting as if each state\nis untagged. (This will result in shorter run-time and a smaller resulting\nSVG.)\n\n- `-s` (`--sortby`): The state by which to sort (default is to sort by\nentity).\n\n- `-S` (`--stacksortby`): The state by which to sort statemaps, when\nmultiple like statemaps are stacked (default is for the statemaps to be in\nthe order specified).\n\n## Interaction\n\nA statemap has icons for zooming and panning.  As the statemap is zoomed,\nthe time labels on top of the X axis will be updatd to reflect the current\nduration.\n\nClicking on a statemap will highlight both the time at the point of the\nclick as well as the state.  Zooming when a time is selected will center\nthe zoomed statemap at the specified time.  To clear the time, click on\nthe time label above the statemap; to select another time, simply click\non the statemap.\n\nShift-clicking (or Option-/Alt-clicking) on a statemap when a time is\nhighlighted will highlight a dotted line at the time selected, as well\nas an indication of the time between the initial time highlighted and\nthe time selected.  This allows for the time delta between two events\nto be easily ascertained.\n\n## Stacked statemaps\n\nTo render a single SVG that contains multiple statemaps, multiple data\nfiles can be provided:\n\n    statemap data-1.out data-2.out > statemap.svg\n\nThe resulting statemaps will be stacked in the order of the data files as\nprovided on the command line, with the first data file dictating the time\nbounds of the resulting stack.  The statemaps can be similar statemaps from\ndissimilar entities (e.g., different machines), or they can be dissimilar\nstatemaps (e.g., different statemaps), or any mix of these.  Legends for\nsimilar statemaps will be shared.  The `-S` option can control the sorting\nof stacked like statemaps.\n\nWhen statemaps are stacked, the coalescing factor applies to *each* statemap\nrather than to the entire stack of statemaps.  When stacking many statemaps,\nlow coalescing factors will be needed to prevent the resulting SVG from\nbecoming excessively large.\n"
  },
  {
    "path": "contrib/cpu-statemap-tagged.d",
    "content": "#!/usr/sbin/dtrace -Cs\n\n/*\n * Copyright 2018, Joyent, Inc.\n */\n\n#pragma D option quiet\n#pragma D option destructive\n#pragma D option switchrate=500hz\n\n#define STATE_UTHREAD\t0\n#define STATE_KTHREAD\t1\n#define\tSTATE_INTR\t1\n#define STATE_IDLE\t17\n\n#define T_INTR\t1\ninline int STATE_MAX = 17;\n\n#define STATE_METADATA(_state, _str, _color) \\\n\tprintf(\"\\t\\t\\\"%s\\\": {\\\"value\\\": %d, \\\"color\\\": \\\"%s\\\" }%s\\n\", \\\n\t    _str, _state, _color, _state < STATE_MAX ? \",\" : \"\");\n\nBEGIN\n{\n\twall = walltimestamp;\n\tprintf(\"{\\n\\t\\\"start\\\": [ %d, %d ],\\n\",\n\t    wall / 1000000000, wall % 1000000000);\n\tprintf(\"\\t\\\"title\\\": \\\"CPU\\\",\\n\");\n\tprintf(\"\\t\\\"host\\\": \\\"%s\\\",\\n\", `utsname.nodename);\n\tprintf(\"\\t\\\"entityKind\\\": \\\"CPU\\\",\\n\");\n\tprintf(\"\\t\\\"states\\\": {\\n\");\n\n\t/*\n\t * Execution: shades of green\n\t */\n\tSTATE_METADATA(STATE_UTHREAD, \"uthread\", \"#9BC362\")\n\tSTATE_METADATA(STATE_KTHREAD, \"kthread\", \"#2E4E00\")\n\n\t/*\n\t * Low level interrupts: shades of aqua and then blue\n\t */\n\tSTATE_METADATA(STATE_INTR + 1, \"level-1\", \"#689D99\")\n\tSTATE_METADATA(STATE_INTR + 2, \"level-2\", \"#41837E\")\n\tSTATE_METADATA(STATE_INTR + 3, \"level-3\", \"#236863\")\n\tSTATE_METADATA(STATE_INTR + 4, \"level-4\", \"#0D4E4A\")\n\tSTATE_METADATA(STATE_INTR + 5, \"level-5\", \"#003430\")\n\tSTATE_METADATA(STATE_INTR + 6, \"level-6\", \"#817FB2\")\n\tSTATE_METADATA(STATE_INTR + 7, \"level-7\", \"#575594\")\n\tSTATE_METADATA(STATE_INTR + 8, \"level-8\", \"#363377\")\n\tSTATE_METADATA(STATE_INTR + 9, \"level-9\", \"#1C1A59\")\n\tSTATE_METADATA(STATE_INTR + 10, \"level-10\", \"#0A093B\")\n\n\t/*\n\t * High level interrupts: shades of red\n\t */\n\tSTATE_METADATA(STATE_INTR + 11, \"level-11\", \"#FFAAAA\")\n\tSTATE_METADATA(STATE_INTR + 12, \"level-12\", \"#D46A6A\")\n\tSTATE_METADATA(STATE_INTR + 13, \"level-13\", \"#AA3939\")\n\tSTATE_METADATA(STATE_INTR + 14, \"level-14\", \"#801515\")\n\tSTATE_METADATA(STATE_INTR + 15, \"level-15\", \"#550000\")\n\n\tSTATE_METADATA(STATE_IDLE, \"idle\", \"#e0e0e0\")\n\n\tprintf(\"\\t}\\n}\\n\");\n\tstart = timestamp;\n}\n\ninterrupt-start\n/arg0 != NULL && !itagged[arg0]/\n{\n\titagged[arg0] = 1;\n\n\tthis->pri = curthread->t_cpu->cpu_m.mcpu_pri;\n\tthis->devi = (struct dev_info *)arg0;\n\n\tprintf(\"{ \\\"state\\\": %d, \\\"tag\\\": \\\"%p\\\", \",\n\t    this->pri + STATE_INTR, arg0);\n\tprintf(\"\\\"driver\\\": \\\"%s\\\", \\\"instance\\\": %d }\\n\",\n\t    stringof(`devnamesp[this->devi->devi_major].dn_name),\n\t    this->devi->devi_instance);\n}\n\ninterrupt-start\n/arg0 == NULL/\n{\n\tthis->pri = curthread->t_cpu->cpu_m.mcpu_pri;\n\n\tprintf(\"{ \\\"time\\\": \\\"%d\\\", \\\"entity\\\": \\\"%d\\\", \\\"state\\\": %d }\\n\",\n\t    timestamp - start,\n\t    curthread->t_cpu->cpu_id, this->pri + STATE_INTR);\n}\n\ninterrupt-start\n/arg0 != NULL/\n{\n\tthis->pri = curthread->t_cpu->cpu_m.mcpu_pri;\n\n\tprintf(\"{ \\\"time\\\": \\\"%d\\\", \\\"entity\\\": \\\"%d\\\", \\\"state\\\": %d, \\\"tag\\\": \\\"%p\\\" }\\n\",\n\t    timestamp - start,\n\t    curthread->t_cpu->cpu_id, this->pri + STATE_INTR, arg0);\n\n\t/*\n\t * We set this, but we don't bother to ever clear it:  the number of\n\t * CPUs and number of interrupt levels are both finite and small.\n\t */\n\titag[curthread->t_cpu, this->pri] = arg0;\n}\n\nav_dispatch_softvect:entry\n/!itagged[curthread->t_pil]/\n{\n\titagged[curthread->t_pil] = 1;\n\n\tprintf(\"{ \\\"state\\\": %d, \\\"tag\\\": \\\"%p\\\", \", curthread->t_pil,\n\t    curthread->t_pil + STATE_INTR);\n\tprintf(\"\\\"driver\\\": \\\"softint\\\", \\\"instance\\\": 0 }\\n\");\n}\n\nav_dispatch_softvect:entry\n{\n\tprintf(\"{ \\\"time\\\": \\\"%d\\\", \\\"entity\\\": \\\"%d\\\", \\\"state\\\": %d, \\\"tag\\\": \\\"%p\\\" }\\n\",\n\t    timestamp - start,\n\t    curthread->t_cpu->cpu_id, curthread->t_pil + STATE_INTR,\n\t    curthread->t_pil);\n\n\titag[curthread->t_cpu, curthread->t_pil] = curthread->t_pil;\n}\n\ninterrupt-complete,\nav_dispatch_softvect:return\n{\n\tthis->intr = curthread->t_intr;\n\tthis->pri = curthread->t_cpu->cpu_m.mcpu_pri;\n\tthis->idle = 0;\n}\n\ninterrupt-complete,\nav_dispatch_softvect:return\n/(this->pri > 10 && curthread == curthread->t_cpu->cpu_idle_thread) ||\n    (this->pri <= 10 && (this->intr == NULL ||\n    this->intr == curthread->t_cpu->cpu_idle_thread))/\n{\n\tprintf(\"{ \\\"time\\\": \\\"%d\\\", \\\"entity\\\": \\\"%d\\\", \\\"state\\\": %d }\\n\",\n\t    timestamp - start,\n\t    curthread->t_cpu->cpu_id, STATE_IDLE);\n\tthis->idle = 1;\n}\n\ninterrupt-complete,\nav_dispatch_softvect:return\n/!this->idle/\n{\n\t/*\n\t * We want to set the state (and tag) back to the thread that we're\n\t * going to return to, which we do imperfectly in that we don't\n\t * reflect high-level interrupts interrupting high-level interrupts\n\t * (we will show this as the underlying thread executing).\n\t */\n\tprintf(\"{ \\\"time\\\": \\\"%d\\\", \\\"entity\\\": \\\"%d\\\", \\\"state\\\": %d, \\\"tag\\\": \\\"%p\\\" }\\n\",\n\t    timestamp - start, curthread->t_cpu->cpu_id, \n\t    this->pri > 10 ?\n\t    (curthread->t_pil > 0 ? curthread->t_pil + STATE_INTR :\n\t    curthread->t_procp == &`p0 ? STATE_KTHREAD : STATE_UTHREAD) :\n\t    (this->intr->t_pil > 0 ? this->intr->t_pil + STATE_INTR :\n\t    this->intr->t_procp == &`p0 ? STATE_KTHREAD : STATE_UTHREAD),\n\t    this->pri > 10 ? \n\t    (curthread->t_pil > 0 ? itag[curthread->t_cpu, curthread->t_pil] :\n\t    curthread->t_did) : \n\t    (this->intr->t_pil > 0 ? itag[curthread->t_cpu, this->intr->t_pil] :\n\t    this->intr->t_did));\n}\n\nsched:::on-cpu\n/curthread != curthread->t_cpu->cpu_idle_thread &&\n    pid == 0 && !tagged[curthread->t_did]/\n{\n\ttagged[curthread->t_did] = 1;\n\n\tprintf(\"{ \\\"state\\\": %d, \\\"tag\\\": \\\"%p\\\", \\\"thread\\\": \\\"%a\\\", \\\"taskq\\\": \\\"%s\\\" }\\n\",\n\t    STATE_KTHREAD,\n\t    curthread->t_did, curthread->t_startpc,\n\t    curthread->t_taskq != NULL ?\n\t    stringof(((taskq_t *)curthread->t_taskq)->tq_name) : \"<none>\");\n}\n\nsched:::on-cpu\n/curthread != curthread->t_cpu->cpu_idle_thread && pid != 0 &&\n    !tagged[curthread->t_did]/\n{\n\ttagged[curthread->t_did] = 1;\n\n\t/*\n\t * The godforsaken strtok() mess is to deal with pr_psargs that\n\t * contain an embedded quote, backslashing that quote to assure that\n\t * we generate valid JSON.  Yes, it would be (MUCH!) easier if DTrace\n\t * provided a subroutine to do this, and this is imperfect in that (1)\n\t * it will eat backslashes and turn them into backslashed quotes, even\n\t * if that's not correct and (2) it will elide the string with an\n\t * ellipsis after the third quote or backslash -- but at least it will\n\t * always yield parseable JSON!\n\t */\n\tprintf(\"{ \\\"state\\\": %d, \\\"tag\\\": \\\"%p\\\", \\\"pid\\\": \\\"%d\\\", \\\"tid\\\": \\\"%d\\\", \\\"execname\\\": \\\"%s\\\", \\\"psargs\\\": \\\"%s\\\" }\\n\",\n\t    STATE_UTHREAD, curthread->t_did, pid, tid,\n\t    execname, \n            strchr(curpsinfo->pr_psargs, '\"') == NULL ? curpsinfo->pr_psargs :\n            strjoin(strtok(curpsinfo->pr_psargs, \"\\\"\\\\\"),\n            (this->s = strtok(NULL, \"\\\"\\\\\")) == NULL ? \"\" :\n            strjoin(strjoin(\"\\\\\\\"\", this->s),\n            (this->s = strtok(NULL, \"\\\"\\\\\")) == NULL ? \"\" :\n            strjoin(strjoin(\"\\\\\\\"\", this->s),\n            (this->s = strtok(NULL, \"\\\"\\\\\")) == NULL ? \"\" :\n            strjoin(strjoin(\"\\\\\\\"\", this->s),\n            (this->s = strtok(NULL, \"\\\"\\\\\")) == NULL ? \"\" :\n            strjoin(\"\\\\\\\"\", this->s))))));\n}\n\nsched:::on-cpu\n/curthread != curthread->t_cpu->cpu_idle_thread/\n{\n\tprintf(\"{ \\\"time\\\": \\\"%d\\\", \\\"entity\\\": \\\"%d\\\", \\\"state\\\": %d, \\\"tag\\\": \\\"%p\\\" }\\n\",\n\t    timestamp - start,\n\t    curthread->t_cpu->cpu_id,\n\t    (curthread->t_flag & T_INTR) ? curthread->t_pil + STATE_INTR :\n\t    (curthread->t_procp == &`p0 ? STATE_KTHREAD : STATE_UTHREAD),\n\t    (curthread->t_flag & T_INTR) ?\n\t    itag[curthread->t_cpu, curthread->t_pil] :\n\t    curthread->t_did);\n}\n\nsched:::on-cpu\n/curthread == curthread->t_cpu->cpu_idle_thread/\n{\n\tprintf(\"{ \\\"time\\\": \\\"%d\\\", \\\"entity\\\": \\\"%d\\\", \\\"state\\\": %d }\\n\",\n\t    timestamp - start,\n\t    curthread->t_cpu->cpu_id, STATE_IDLE);\n}\n\ntick-1sec\n/timestamp - start > 10 * 1000000000/\n{\n\texit(0);\n}\n\n"
  },
  {
    "path": "contrib/cpu-statemap.d",
    "content": "#!/usr/sbin/dtrace -Cs\n\n/*\n * Copyright 2018, Joyent, Inc.\n */\n\n#pragma D option quiet\n#pragma D option destructive\n#pragma D option switchrate=100hz\n\n#define STATE_IDLE\t0\n#define STATE_UTHREAD\t16\n#define STATE_KTHREAD\t17\n\n#define T_INTR\t1\ninline int STATE_MAX = 17;\n\n#define STATE_METADATA(_state, _str, _color) \\\n\tprintf(\"\\t\\t\\\"%s\\\": {\\\"value\\\": %d, \\\"color\\\": \\\"%s\\\" }%s\\n\", \\\n\t    _str, _state, _color, _state < STATE_MAX ? \",\" : \"\");\n\nBEGIN\n{\n\twall = walltimestamp;\n\tprintf(\"{\\n\\t\\\"start\\\": [ %d, %d ],\\n\",\n\t    wall / 1000000000, wall % 1000000000);\n\tprintf(\"\\t\\\"title\\\": \\\"CPU\\\",\\n\");\n\tprintf(\"\\t\\\"host\\\": \\\"%s\\\",\\n\", `utsname.nodename);\n\tprintf(\"\\t\\\"states\\\": {\\n\");\n\n\tSTATE_METADATA(STATE_IDLE, \"idle\", \"#e0e0e0\")\n\n\t/*\n\t * Low level interrupts: shades of aqua and then blue\n\t */\n\tSTATE_METADATA(1, \"level-1\", \"#689D99\")\n\tSTATE_METADATA(2, \"level-2\", \"#41837E\")\n\tSTATE_METADATA(3, \"level-3\", \"#236863\")\n\tSTATE_METADATA(4, \"level-4\", \"#0D4E4A\")\n\tSTATE_METADATA(5, \"level-5\", \"#003430\")\n\tSTATE_METADATA(6, \"level-6\", \"#817FB2\")\n\tSTATE_METADATA(7, \"level-7\", \"#575594\")\n\tSTATE_METADATA(8, \"level-8\", \"#363377\")\n\tSTATE_METADATA(9, \"level-9\", \"#1C1A59\")\n\tSTATE_METADATA(10, \"level-10\", \"#0A093B\")\n\n\t/*\n\t * High level interrupts: shades of red\n\t */\n\tSTATE_METADATA(11, \"level-11\", \"#FFAAAA\")\n\tSTATE_METADATA(12, \"level-12\", \"#D46A6A\")\n\tSTATE_METADATA(13, \"level-13\", \"#AA3939\")\n\tSTATE_METADATA(14, \"level-14\", \"#801515\")\n\tSTATE_METADATA(15, \"level-15\", \"#550000\")\n\n\t/*\n\t * Execution: shades of green\n\t */\n\tSTATE_METADATA(STATE_UTHREAD, \"uthread\", \"#9BC362\")\n\tSTATE_METADATA(STATE_KTHREAD, \"kthread\", \"#2E4E00\")\n\n\tprintf(\"\\t}\\n}\\n\");\n\tstart = timestamp;\n}\n\ninterrupt-start\n{\n\tthis->pri = curthread->t_cpu->cpu_m.mcpu_pri;\n\n\tprintf(\"{ \\\"time\\\": \\\"%d\\\", \\\"entity\\\": \\\"%d\\\", \\\"state\\\": %d }\\n\",\n\t    timestamp - start,\n\t    curthread->t_cpu->cpu_id, this->pri);\n}\n\ninterrupt-complete\n{\n\tthis->intr = curthread->t_intr;\n\tthis->pri = curthread->t_cpu->cpu_m.mcpu_pri;\n\n\t/*\n\t * This is a bit gnarly: we need to set the state to be back to\n\t * what it was before the interrupt took place.  This is slightly\n\t * imperfect in that it doesn't quite reflect high-level interrupts\n\t * interrupting high-level interrupts, but that should be an unusual\n\t * enough condition that this should be good enough for most purposes.\n\t */\n\tprintf(\"{ \\\"time\\\": \\\"%d\\\", \\\"entity\\\": \\\"%d\\\", \\\"state\\\": %d }\\n\",\n\t    timestamp - start,\n\t    curthread->t_cpu->cpu_id,\n\t    this->pri > 10 ? \n\t    (curthread == curthread->t_cpu->cpu_idle_thread ? STATE_IDLE :\n\t    curthread->t_pil > 0 ? curthread->t_pil :\n\t    curthread->t_procp == &`p0 ? STATE_KTHREAD : STATE_UTHREAD) :\n\t    this->intr != NULL ?\n\t    (this->intr == curthread->t_cpu->cpu_idle_thread ? STATE_IDLE :\n\t    this->intr->t_pil > 0 ? this->intr->t_pil :\n\t    this->intr->t_procp == &`p0 ? STATE_KTHREAD : STATE_UTHREAD) :\n\t    STATE_IDLE);\n}\n\nsched:::on-cpu\n{\n\tprintf(\"{ \\\"time\\\": \\\"%d\\\", \\\"entity\\\": \\\"%d\\\", \\\"state\\\": %d }\\n\",\n\t    timestamp - start,\n\t    curthread->t_cpu->cpu_id,\n\t    curthread == curthread->t_cpu->cpu_idle_thread ? STATE_IDLE :\n\t    (curthread->t_flag & T_INTR) ? curthread->t_pil :\n\t    curthread->t_procp == &`p0 ? STATE_KTHREAD :\n\t    STATE_UTHREAD);\n}\n\ntick-1sec\n/timestamp - start > 10 * 1000000000/\n{\n\texit(0);\n}\n\n"
  },
  {
    "path": "contrib/io-statemap.d",
    "content": "#!/usr/sbin/dtrace -Cs\n\n/*\n * Copyright 2018, Joyent, Inc.\n */\n\n#pragma D option quiet\n#pragma D option destructive\n\ninline int STATE_MAXIO = 20;\n\n#define STATE_METADATA(_state, _str, _color) \\\n\tprintf(\"\\t\\t\\\"%s\\\": {\\\"value\\\": %d, \\\"color\\\": \\\"%s\\\" }%s\\n\", \\\n\t    _str, _state, _color, _state < STATE_MAXIO ? \",\" : \"\");\n\nBEGIN\n{\n\twall = walltimestamp;\n\tprintf(\"{\\n\\t\\\"start\\\": [ %d, %d ],\\n\",\n\t    wall / 1000000000, wall % 1000000000);\n\tprintf(\"\\t\\\"title\\\": \\\"disk I/O\\\",\\n\");\n\tprintf(\"\\t\\\"host\\\": \\\"%s\\\",\\n\", `utsname.nodename);\n\tprintf(\"\\t\\\"states\\\": {\\n\");\n\n\tSTATE_METADATA(0, \"no I/O\", \"#e0e0e0\")\n\tSTATE_METADATA(1, \"1 I/O\", \"#DFE500\");\n\tSTATE_METADATA(2, \"2 I/Os\", \"#DDD800\");\n\tSTATE_METADATA(3, \"3 I/Os\", \"#DBCC01\");\n\tSTATE_METADATA(4, \"4 I/Os\", \"#D9C002\");\n\tSTATE_METADATA(5, \"5 I/Os\", \"#D8B403\");\n\tSTATE_METADATA(6, \"6 I/Os\", \"#D6A804\");\n\tSTATE_METADATA(7, \"7 I/Os\", \"#D49C05\");\n\tSTATE_METADATA(8, \"8 I/Os\", \"#D39006\");\n\tSTATE_METADATA(9, \"9 I/Os\", \"#D18407\");\n\tSTATE_METADATA(10, \"10 I/Os\", \"#CF7808\");\n\tSTATE_METADATA(11, \"11 I/Os\", \"#CE6C09\");\n\tSTATE_METADATA(12, \"12 I/Os\", \"#CC600A\");\n\tSTATE_METADATA(13, \"13 I/Os\", \"#CA540B\");\n\tSTATE_METADATA(14, \"14 I/Os\", \"#C9480C\");\n\tSTATE_METADATA(15, \"15 I/Os\", \"#C73C0D\");\n\tSTATE_METADATA(16, \"16 I/Os\", \"#C5300E\");\n\tSTATE_METADATA(17, \"17 I/Os\", \"#C4240F\");\n\tSTATE_METADATA(18, \"18 I/Os\", \"#C21810\");\n\tSTATE_METADATA(19, \"19 I/Os\", \"#C00C11\");\n\tSTATE_METADATA(STATE_MAXIO, \">=20 I/Os\", \"#BF0012\");\n\n\tprintf(\"\\t}\\n}\\n\");\n\tstart = timestamp;\n}\n\nscsi-transport-dispatch\n{\n\tthis->b = (struct buf *)arg0;\n\tthis->u = ((struct sd_xbuf *)this->b->b_private)->xb_un;\n\n\tprintf(\"{ \\\"time\\\": \\\"%d\\\", \\\"entity\\\": \\\"sd%d\\\", \\\"state\\\": %d }\\n\",\n\t    timestamp - start,\n\t    ((struct dev_info *)this->u->un_sd->sd_dev)->devi_instance,\n\t    this->u->un_ncmds_in_transport < STATE_MAXIO ?\n\t    this->u->un_ncmds_in_transport : STATE_MAXIO);\n}\n\nsdintr:entry\n{\n\tthis->b = (struct buf *)args[0]->pkt_private;\n\tself->un = ((struct sd_xbuf *)this->b->b_private)->xb_un;\n}\n\nsdintr:return\n/(this->u = self->un) != NULL/\n{\n\tprintf(\"{ \\\"time\\\": \\\"%d\\\", \\\"entity\\\": \\\"sd%d\\\", \\\"state\\\": %d }\\n\",\n\t    timestamp - start,\n\t    ((struct dev_info *)this->u->un_sd->sd_dev)->devi_instance,\n\t    this->u->un_ncmds_in_transport < STATE_MAXIO ?\n\t    this->u->un_ncmds_in_transport : STATE_MAXIO);\n\n\tself->un = NULL;\n}\n\ntick-1sec\n/timestamp - start > 10 * 1000000000/\n{\n\texit(0);\n}\n"
  },
  {
    "path": "contrib/lx-cmd-statemap.d",
    "content": "#!/usr/sbin/dtrace -Cs \n\n/*\n * Copyright 2017, Joyent, Inc.\n */\n\n#pragma D option quiet\n#pragma D option destructive\n\n#define T_WAKEABLE\t0x0002\n\ntypedef enum {\n\tSTATE_ON_CPU = 0,\n\tSTATE_OFF_CPU_WAITING = 1,\n\tSTATE_OFF_CPU_FUTEX = 2,\n\tSTATE_OFF_CPU_IO = 3,\n\tSTATE_OFF_CPU_BLOCKED = 4,\n\tSTATE_OFF_CPU_DEAD = 5,\n\tSTATE_MAX = 6\n} state_t;\n\n#define STATE_METADATA(_state, _str, _color) \\\n\tprintf(\"\\t\\t\\\"%s\\\": {\\\"value\\\": %d, \\\"color\\\": \\\"%s\\\" }%s\\n\", \\\n\t    _str, _state, _color, _state < STATE_MAX - 1 ? \",\" : \"\");\n\nBEGIN\n{\n\twall = walltimestamp;\n\tprintf(\"{\\n\\t\\\"start\\\": [ %d, %d ],\\n\",\n\t    wall / 1000000000, wall % 1000000000);\n\tprintf(\"\\t\\\"title\\\": \\\"all %s LX processes\\\",\\n\", $$1);\n\tprintf(\"\\t\\\"host\\\": \\\"%s\\\",\\n\", `utsname.nodename);\n\tprintf(\"\\t\\\"states\\\": {\\n\");\n\n\tSTATE_METADATA(STATE_ON_CPU, \"on-cpu\", \"#DAF7A6\")\n\tSTATE_METADATA(STATE_OFF_CPU_WAITING, \"off-cpu-waiting\", \"#f9f9f9\")\n\tSTATE_METADATA(STATE_OFF_CPU_FUTEX, \"off-cpu-futex\", \"#f0f0f0\")\n\tSTATE_METADATA(STATE_OFF_CPU_IO, \"off-cpu-io\", \"#FFC300\")\n\tSTATE_METADATA(STATE_OFF_CPU_BLOCKED, \"off-cpu-blocked\", \"#C70039\")\n\tSTATE_METADATA(STATE_OFF_CPU_DEAD, \"off-cpu-dead\", \"#581845\")\n\n\tprintf(\"\\t}\\n}\\n\");\n\tstart = timestamp;\n}\n\nzfs_fillpage:entry\n/execname == $$1/\n{\n\tself->state = STATE_OFF_CPU_IO;\n}\n\nzfs_fillpage:return\n/execname == $$1/\n{\n\tself->state = STATE_ON_CPU;\n}\n\nlx_futex:entry\n/execname == $$1/\n{\n\tself->state = STATE_OFF_CPU_FUTEX;\n}\n\nlx_futex:return\n/execname == $$1/\n{\n\tself->state = STATE_ON_CPU;\n}\n\nsched:::off-cpu\n/execname == $$1/\n{\n\tprintf(\"{ \\\"time\\\": \\\"%d\\\", \\\"entity\\\": \\\"%d/%d\\\", \",\n\t    timestamp - start, pid, tid);\n\n\tprintf(\"\\\"state\\\": %d }\\n\", self->state != STATE_ON_CPU ?\n\t    self->state : curthread->t_flag & T_WAKEABLE ?\n\t    STATE_OFF_CPU_WAITING : STATE_OFF_CPU_BLOCKED);\n}\n\nsched:::on-cpu\n/execname == $$1/\n{\n\tself->state = STATE_ON_CPU;\n\tprintf(\"{ \\\"time\\\": \\\"%d\\\", \\\"entity\\\": \\\"%d/%d\\\", \",\n\t    timestamp - start, pid, tid);\n\tprintf(\"\\\"state\\\": %d }\\n\", self->state);\n}\n\nproc:::lwp-exit\n/execname == $$1/\n{\n\tprintf(\"{ \\\"time\\\": \\\"%d\\\", \\\"entity\\\": \\\"%d/%d\\\", \",\n\t    timestamp - start, pid, tid);\n\tprintf(\"\\\"state\\\": %d }\\n\", STATE_OFF_CPU_DEAD);\n}\n\ntick-1sec\n/timestamp - start > 60 * 1000000000/\n{\n\texit(0);\n}\n"
  },
  {
    "path": "contrib/lx-statemap.d",
    "content": "#!/usr/sbin/dtrace -Cs \n\n/*\n * Copyright 2017, Joyent, Inc.\n */\n\n#pragma D option quiet\n#pragma D option destructive\n\n#define T_WAKEABLE\t0x0002\n\ntypedef enum {\n\tSTATE_ON_CPU = 0,\n\tSTATE_OFF_CPU_WAITING = 1,\n\tSTATE_OFF_CPU_FUTEX = 2,\n\tSTATE_OFF_CPU_IO = 3,\n\tSTATE_OFF_CPU_BLOCKED = 4,\n\tSTATE_OFF_CPU_DEAD = 5,\n\tSTATE_MAX = 6\n} state_t;\n\n#define STATE_METADATA(_state, _str, _color) \\\n\tprintf(\"\\t\\t\\\"%s\\\": {\\\"value\\\": %d, \\\"color\\\": \\\"%s\\\" }%s\\n\", \\\n\t    _str, _state, _color, _state < STATE_MAX - 1 ? \",\" : \"\");\n\nBEGIN\n{\n\twall = walltimestamp;\n\tprintf(\"{\\n\\t\\\"start\\\": [ %d, %d ],\\n\",\n\t    wall / 1000000000, wall % 1000000000);\n\tprintf(\"\\t\\\"title\\\": \\\"LX process ID %s\\\",\\n\", $$1);\n\tprintf(\"\\t\\\"host\\\": \\\"%s\\\",\\n\", `utsname.nodename);\n\tprintf(\"\\t\\\"states\\\": {\\n\");\n\n\tSTATE_METADATA(STATE_ON_CPU, \"on-cpu\", \"#DAF7A6\")\n\tSTATE_METADATA(STATE_OFF_CPU_WAITING, \"off-cpu-waiting\", \"#f9f9f9\")\n\tSTATE_METADATA(STATE_OFF_CPU_FUTEX, \"off-cpu-futex\", \"#f0f0f0\")\n\tSTATE_METADATA(STATE_OFF_CPU_IO, \"off-cpu-io\", \"#FFC300\")\n\tSTATE_METADATA(STATE_OFF_CPU_BLOCKED, \"off-cpu-blocked\", \"#C70039\")\n\tSTATE_METADATA(STATE_OFF_CPU_DEAD, \"off-cpu-dead\", \"#581845\")\n\n\tprintf(\"\\t}\\n}\\n\");\n\tstart = timestamp;\n}\n\nsched:::wakeup\n/pid == $1 && args[1]->pr_pid == $1/\n{\n\tprintf(\"{ \\\"time\\\": \\\"%d\\\", \\\"entity\\\": \\\"%d\\\", \",\n\t    timestamp - start, tid);\n\tprintf(\"\\\"event\\\": \\\"wakeup\\\", \\\"target\\\": \\\"%d\\\" }\\n\",\n\t    args[0]->pr_lwpid);\n}\n\nzfs_fillpage:entry\n/pid == $1/\n{\n\tself->state = STATE_OFF_CPU_IO;\n}\n\nzfs_fillpage:return\n/pid == $1/\n{\n\tself->state = STATE_ON_CPU;\n}\n\nlx_futex:entry\n/pid == $1/\n{\n\tself->state = STATE_OFF_CPU_FUTEX;\n}\n\nlx_futex:return\n/pid == $1/\n{\n\tself->state = STATE_ON_CPU;\n}\n\nsched:::off-cpu\n/pid == $1/\n{\n\tprintf(\"{ \\\"time\\\": \\\"%d\\\", \\\"entity\\\": \\\"%d\\\", \",\n\t    timestamp - start, tid);\n\n\tprintf(\"\\\"state\\\": %d }\\n\", self->state != STATE_ON_CPU ?\n\t    self->state : curthread->t_flag & T_WAKEABLE ?\n\t    STATE_OFF_CPU_WAITING : STATE_OFF_CPU_BLOCKED);\n}\n\nsched:::on-cpu\n/pid == $1/\n{\n\tself->state = STATE_ON_CPU;\n\tprintf(\"{ \\\"time\\\": \\\"%d\\\", \\\"entity\\\": \\\"%d\\\", \",\n\t    timestamp - start, tid);\n\tprintf(\"\\\"state\\\": %d }\\n\", self->state);\n}\n\nproc:::lwp-exit\n/pid == $1/\n{\n\tprintf(\"{ \\\"time\\\": \\\"%d\\\", \\\"entity\\\": \\\"%d\\\", \",\n\t    timestamp - start, tid);\n\tprintf(\"\\\"state\\\": %d }\\n\", STATE_OFF_CPU_DEAD);\n}\n\ntick-1sec\n/timestamp - start > 60 * 1000000000/\n{\n\texit(0);\n}\n"
  },
  {
    "path": "contrib/postgres-statemap.d",
    "content": "#!/usr/sbin/dtrace -Cs \n\n/*\n * Copyright 2017, Joyent, Inc.\n */\n\n#pragma D option quiet\n#pragma D option destructive\n\n#define T_WAKEABLE\t0x0002\n\ntypedef enum {\n\tSTATE_ON_CPU = 0,\n\tSTATE_OFF_CPU_WAITING,\n\tSTATE_OFF_CPU_SEMOP,\n\tSTATE_OFF_CPU_BLOCKED,\n\tSTATE_OFF_CPU_IO_READ,\n\tSTATE_OFF_CPU_IO_WRITE,\n\tSTATE_OFF_CPU_DEAD,\n\tSTATE_MAX\n} state_t;\n\n#define STATE_METADATA(_state, _str, _color) \\\n\tprintf(\"\\t\\t\\\"%s\\\": {\\\"value\\\": %d, \\\"color\\\": \\\"%s\\\" }%s\\n\", \\\n\t    _str, _state, _color, _state < STATE_MAX - 1 ? \",\" : \"\");\n\nBEGIN\n{\n\twall = walltimestamp;\n\tprintf(\"{\\n\\t\\\"start\\\": [ %d, %d ],\\n\",\n\t    wall / 1000000000, wall % 1000000000);\n\tprintf(\"\\t\\\"title\\\": \\\"PostgreSQL\\\",\\n\");\n\tprintf(\"\\t\\\"host\\\": \\\"%s\\\",\\n\", `utsname.nodename);\n\tprintf(\"\\t\\\"entityKind\\\": \\\"Process\\\",\\n\");\n\tprintf(\"\\t\\\"states\\\": {\\n\");\n\n\tSTATE_METADATA(STATE_ON_CPU, \"on-cpu\", \"#DAF7A6\")\n\tSTATE_METADATA(STATE_OFF_CPU_WAITING, \"off-cpu-waiting\", \"#f9f9f9\")\n\tSTATE_METADATA(STATE_OFF_CPU_SEMOP, \"off-cpu-semop\", \"#FF5733\")\n\tSTATE_METADATA(STATE_OFF_CPU_BLOCKED, \"off-cpu-blocked\", \"#C70039\")\n\tSTATE_METADATA(STATE_OFF_CPU_IO_READ, \"off-cpu-io-read\", \"#FFC300\")\n\tSTATE_METADATA(STATE_OFF_CPU_IO_WRITE, \"off-cpu-io-write\", \"#338AFF\")\n\tSTATE_METADATA(STATE_OFF_CPU_DEAD, \"off-cpu-dead\", \"#E0E0E0\")\n\n\tprintf(\"\\t}\\n}\\n\");\n\tstart = timestamp;\n}\n\nsched:::wakeup\n/execname == \"postgres\" && args[1]->pr_fname == \"postgres\"/\n{\n\tprintf(\"{ \\\"time\\\": \\\"%d\\\", \\\"entity\\\": \\\"%d\\\", \",\n\t    timestamp - start, pid);\n\tprintf(\"\\\"event\\\": \\\"wakeup\\\", \\\"target\\\": \\\"%d\\\" }\\n\",\n\t    args[1]->pr_pid);\n}\n\nsyscall::read:entry\n/execname == \"postgres\"/\n{\n\tself->state = STATE_OFF_CPU_IO_READ;\n}\n\nsyscall::write:entry\n/execname == \"postgres\"/\n{\n\tself->state = STATE_OFF_CPU_IO_WRITE;\n}\n\nsyscall::read:return,\nsyscall::write:return\n/execname == \"postgres\"/\n{\n\tself->state = STATE_ON_CPU;\n}\n\nfbt::semop:entry\n/execname == \"postgres\"/\n{\n\tself->state = STATE_OFF_CPU_SEMOP;\n}\n\nfbt::semop:return\n/execname == \"postgres\"/\n{\n\tself->state = STATE_ON_CPU;\n}\n\nsched:::off-cpu\n/execname == \"postgres\"/\n{\n\tprintf(\"{ \\\"time\\\": \\\"%d\\\", \\\"entity\\\": \\\"%d\\\", \",\n\t    timestamp - start, pid);\n\n\tprintf(\"\\\"state\\\": %d }\\n\", self->state != STATE_ON_CPU ?\n\t    self->state : curthread->t_flag & T_WAKEABLE ?\n\t    STATE_OFF_CPU_WAITING : STATE_OFF_CPU_BLOCKED);\n}\n\nsched:::on-cpu\n/execname == \"postgres\"/\n{\n\tself->state = STATE_ON_CPU;\n\tprintf(\"{ \\\"time\\\": \\\"%d\\\", \\\"entity\\\": \\\"%d\\\", \",\n\t    timestamp - start, pid);\n\tprintf(\"\\\"state\\\": %d }\\n\", self->state);\n}\n\nproc:::exit\n/execname == \"postgres\"/\n{\n\tself->exiting = pid;\n}\n\nsched:::off-cpu\n/execname != \"postgres\" && self->exiting/\n{\n\tprintf(\"{ \\\"time\\\": \\\"%d\\\", \\\"entity\\\": \\\"%d\\\", \",\n\t    timestamp - start, self->exiting);\n\n\tprintf(\"\\\"state\\\": %d }\\n\", STATE_OFF_CPU_DEAD);\n\tself->exiting = 0;\n\tself->state = 0;\n}\n\n/*\n * This is -- to put it mildly -- very specific to the implementation of\n * PostgreSQL: if the process is long-running, it lifts argv[0] out of the\n * address space, and -- iff it matches the form \"postgres: [description]\n * process\", sets the description for the process to be [description].\n */\nsched:::on-cpu\n/execname == \"postgres\" &&\n    timestamp - curthread->t_procp->p_mstart > 1000000000 &&\n    !seen[pid]/\n{\n\tseen[pid] = 1;\n\tthis->arg = *(uintptr_t *)copyin(curthread->t_procp->p_user.u_argv, 8);\n\tthis->index = index(this->process = copyinstr(this->arg), \" process\");\n\n\tif (this->index > 0 && index(this->process, \"postgres: \") == 0) {\n\t\tprintf(\"{ \\\"entity\\\": \\\"%d\\\", \\\"description\\\": \\\"%s\\\" }\\n\",\n\t\t    pid, substr(this->process, 10, this->index - 10));\n\t}\n}\n\ntick-1sec\n/timestamp - start > 60 * 1000000000/\n{\n\texit(0);\n}\n"
  },
  {
    "path": "contrib/postgres-zfs-statemap.d",
    "content": "#!/usr/sbin/dtrace -Cs \n\n/*\n * Copyright 2018, Joyent, Inc.\n */\n\n#pragma D option quiet\n#pragma D option destructive\n\n#define T_WAKEABLE\t0x0002\n\ntypedef enum {\n\tSTATE_ON_CPU = 0,\n\tSTATE_OFF_CPU_WAITING,\n\tSTATE_OFF_CPU_SEMOP,\n\tSTATE_OFF_CPU_BLOCKED,\n\tSTATE_OFF_CPU_ZFS_READ,\n\tSTATE_OFF_CPU_ZFS_WRITE,\n\tSTATE_OFF_CPU_ZIL_COMMIT,\n\tSTATE_OFF_CPU_TX_DELAY,\n\tSTATE_OFF_CPU_DEAD,\n\tSTATE_MAX\n} state_t;\n\n#define STATE_METADATA(_state, _str, _color) \\\n\tprintf(\"\\t\\t\\\"%s\\\": {\\\"value\\\": %d, \\\"color\\\": \\\"%s\\\" }%s\\n\", \\\n\t    _str, _state, _color, _state < STATE_MAX - 1 ? \",\" : \"\");\n\nBEGIN\n{\n\twall = walltimestamp;\n\tprintf(\"{\\n\\t\\\"start\\\": [ %d, %d ],\\n\",\n\t    wall / 1000000000, wall % 1000000000);\n\tprintf(\"\\t\\\"title\\\": \\\"PostgreSQL\\\",\\n\");\n\tprintf(\"\\t\\\"host\\\": \\\"%s\\\",\\n\", `utsname.nodename);\n\tprintf(\"\\t\\\"entityKind\\\": \\\"Process\\\",\\n\");\n\tprintf(\"\\t\\\"states\\\": {\\n\");\n\n\tSTATE_METADATA(STATE_ON_CPU, \"on-cpu\", \"#DAF7A6\")\n\tSTATE_METADATA(STATE_OFF_CPU_WAITING, \"off-cpu-waiting\", \"#f9f9f9\")\n\tSTATE_METADATA(STATE_OFF_CPU_SEMOP, \"off-cpu-semop\", \"#FF5733\")\n\tSTATE_METADATA(STATE_OFF_CPU_BLOCKED, \"off-cpu-blocked\", \"#C70039\")\n\tSTATE_METADATA(STATE_OFF_CPU_ZFS_READ, \"off-cpu-zfs-read\", \"#FFC300\")\n\tSTATE_METADATA(STATE_OFF_CPU_ZFS_WRITE, \"off-cpu-zfs-write\", \"#338AFF\")\n\tSTATE_METADATA(STATE_OFF_CPU_ZIL_COMMIT,\n\t    \"off-cpu-zil-commit\", \"#66FFCC\")\n\tSTATE_METADATA(STATE_OFF_CPU_TX_DELAY, \"off-cpu-tx-delay\", \"#CCFF00\")\n\tSTATE_METADATA(STATE_OFF_CPU_DEAD, \"off-cpu-dead\", \"#E0E0E0\")\n\n\tprintf(\"\\t}\\n}\\n\");\n\tstart = timestamp;\n}\n\nsched:::wakeup\n/execname == \"postgres\" && args[1]->pr_fname == \"postgres\"/\n{\n\tprintf(\"{ \\\"time\\\": \\\"%d\\\", \\\"entity\\\": \\\"%d\\\", \",\n\t    timestamp - start, pid);\n\tprintf(\"\\\"event\\\": \\\"wakeup\\\", \\\"target\\\": \\\"%d\\\" }\\n\",\n\t    args[1]->pr_pid);\n}\n\nfbt::zfs_read:entry\n/execname == \"postgres\"/\n{\n\tself->state = STATE_OFF_CPU_ZFS_READ;\n}\n\nfbt::zfs_write:entry\n/execname == \"postgres\"/\n{\n\tself->state = STATE_OFF_CPU_ZFS_WRITE;\n}\n\nsyscall:::return\n/execname == \"postgres\"/\n{\n\tself->state = STATE_ON_CPU;\n}\n\nfbt::semop:entry\n/execname == \"postgres\"/\n{\n\tself->state = STATE_OFF_CPU_SEMOP;\n}\n\nfbt::semop:return\n/execname == \"postgres\"/\n{\n\tself->state = STATE_ON_CPU;\n}\n\nfbt::zil_commit:entry\n/self->state == STATE_OFF_CPU_ZFS_WRITE/\n{\n\tself->state = STATE_OFF_CPU_ZIL_COMMIT;\n}\n\nfbt::zil_commit:return\n/self->state == STATE_OFF_CPU_ZIL_COMMIT/\n{\n\tself->state = STATE_OFF_CPU_ZFS_WRITE;\n}\n\nfbt::dmu_tx_delay:entry\n/self->state == STATE_OFF_CPU_ZFS_WRITE/\n{\n\tself->state = STATE_OFF_CPU_TX_DELAY;\n}\n\nfbt::dmu_tx_delay:return\n/self->state == STATE_OFF_CPU_TX_DELAY/\n{\n\tself->state = STATE_OFF_CPU_ZFS_WRITE;\n}\n\nsched:::off-cpu\n/execname == \"postgres\"/\n{\n\tprintf(\"{ \\\"time\\\": \\\"%d\\\", \\\"entity\\\": \\\"%d\\\", \",\n\t    timestamp - start, pid);\n\n\tprintf(\"\\\"state\\\": %d }\\n\", self->state != STATE_ON_CPU ?\n\t    self->state : (curthread->t_flag & T_WAKEABLE ?\n\t    STATE_OFF_CPU_WAITING : STATE_OFF_CPU_BLOCKED));\n}\n\nsched:::on-cpu\n/execname == \"postgres\"/\n{\n\tprintf(\"{ \\\"time\\\": \\\"%d\\\", \\\"entity\\\": \\\"%d\\\", \",\n\t    timestamp - start, pid);\n\tprintf(\"\\\"state\\\": %d }\\n\", STATE_ON_CPU);\n}\n\nproc:::exit\n/execname == \"postgres\"/\n{\n\tself->exiting = pid;\n}\n\nsched:::off-cpu\n/execname != \"postgres\" && self->exiting/\n{\n\tprintf(\"{ \\\"time\\\": \\\"%d\\\", \\\"entity\\\": \\\"%d\\\", \",\n\t    timestamp - start, self->exiting);\n\n\tprintf(\"\\\"state\\\": %d }\\n\", STATE_OFF_CPU_DEAD);\n\tself->exiting = 0;\n\tself->state = 0;\n}\n\n/*\n * This is -- to put it mildly -- very specific to the implementation of\n * PostgreSQL: if the process is long-running, it lifts argv[0] out of the\n * address space, and -- iff it matches the form \"postgres: [description]\n * process\", sets the description for the process to be [description].\n */\nsched:::on-cpu\n/execname == \"postgres\" &&\n    timestamp - curthread->t_procp->p_mstart > 1000000000 &&\n    !seen[pid]/\n{\n\tseen[pid] = 1;\n\tthis->arg = *(uintptr_t *)copyin(curthread->t_procp->p_user.u_argv, 8);\n\tthis->index = index(this->process = copyinstr(this->arg), \" process\");\n\n\tif (this->index > 0 && index(this->process, \"postgres: \") == 0) {\n\t\tprintf(\"{ \\\"entity\\\": \\\"%d\\\", \\\"description\\\": \\\"%s\\\" }\\n\",\n\t\t    pid, substr(this->process, 10, this->index - 10));\n\t}\n}\n\ntick-1sec\n/timestamp - start > 120 * 1000000000/\n{\n\texit(0);\n}\n"
  },
  {
    "path": "contrib/spa-sync-statemap.d",
    "content": "#!/usr/sbin/dtrace -Cs \n\n/*\n * Copyright 2018, Joyent, Inc.\n */\n\n#pragma D option quiet\n\ntypedef enum {\n\tSTATE_ON_CPU = 0,\n\tSTATE_OFF_CPU_WAITING,\n\tSTATE_OFF_CPU_BLOCKED,\n\tSTATE_OFF_CPU_ZIO_WAIT,\n\tSTATE_OFF_CPU_ZIO_WAIT_MOS,\n\tSTATE_OFF_CPU_ZIO_WAIT_SYNC,\n\tSTATE_OFF_CPU_OBJSET_SYNC,\n\tSTATE_OFF_CPU_CV,\n\tSTATE_OFF_CPU_PREEMPTED,\n\tSTATE_MAX\n} state_t;\n\n#define STATE_METADATA(_state, _str, _color) \\\n\tprintf(\"\\t\\t\\\"%s\\\": {\\\"value\\\": %d, \\\"color\\\": \\\"%s\\\" }%s\\n\", \\\n\t    _str, _state, _color, _state < STATE_MAX - 1 ? \",\" : \"\");\n\nBEGIN\n{\n\twall = walltimestamp;\n\tprintf(\"{\\n\\t\\\"start\\\": [ %d, %d ],\\n\",\n\t    wall / 1000000000, wall % 1000000000);\n\tprintf(\"\\t\\\"title\\\": \\\"SPA sync\\\",\\n\");\n\tprintf(\"\\t\\\"host\\\": \\\"%s\\\",\\n\", `utsname.nodename);\n\tprintf(\"\\t\\\"entityKind\\\": \\\"SPA sync thread for pool\\\",\\n\");\n\tprintf(\"\\t\\\"states\\\": {\\n\");\n\n\tSTATE_METADATA(STATE_ON_CPU, \"on-cpu\", \"#DAF7A6\")\n\tSTATE_METADATA(STATE_OFF_CPU_WAITING, \"off-cpu-waiting\", \"#f9f9f9\")\n\tSTATE_METADATA(STATE_OFF_CPU_BLOCKED, \"off-cpu-blocked\", \"#C70039\")\n\tSTATE_METADATA(STATE_OFF_CPU_ZIO_WAIT, \"off-cpu-zio-wait\", \"#FFC300\")\n\tSTATE_METADATA(STATE_OFF_CPU_ZIO_WAIT_MOS,\n\t    \"off-cpu-zio-wait-mos\", \"#FF5733\")\n\tSTATE_METADATA(STATE_OFF_CPU_ZIO_WAIT_SYNC,\n\t    \"off-cpu-zio-wait-sync\", \"#BB8FCE\")\n\tSTATE_METADATA(STATE_OFF_CPU_OBJSET_SYNC,\n\t    \"off-cpu-objset-sync\", \"#338AFF\")\n\tSTATE_METADATA(STATE_OFF_CPU_CV, \"off-cpu-cv\", \"#66FFCC\")\n\tSTATE_METADATA(STATE_OFF_CPU_PREEMPTED, \"off-cpu-preempted\", \"#CCFF00\")\n\n\tprintf(\"\\t}\\n}\\n\");\n\tstart = timestamp;\n}\n\nfbt::spa_sync:return\n{\n\tself->state = STATE_OFF_CPU_WAITING;\n}\n\nfbt::spa_sync:entry\n{\n\tself->spa = args[0];\n\tself->state = STATE_ON_CPU;\n}\n\nfbt::zio_wait:entry\n/self->spa != NULL && self->state == STATE_ON_CPU/\n{\n\tself->state = STATE_OFF_CPU_ZIO_WAIT;\n\t\n}\n\nfbt::zio_wait:return\n/self->state == STATE_OFF_CPU_ZIO_WAIT/\n{\n\tself->state = STATE_ON_CPU;\n}\n\nfbt::vdev_config_sync:entry\n/self->state == STATE_ON_CPU/\n{\n\tself->state = STATE_OFF_CPU_ZIO_WAIT_SYNC;\n}\n\nfbt::vdev_config_sync:return\n/self->state == STATE_OFF_CPU_ZIO_WAIT_SYNC/\n{\n\tself->state = STATE_ON_CPU;\n}\n\nfbt::dsl_pool_sync_mos:entry\n/self->state == STATE_ON_CPU/\n{\n\tself->state = STATE_OFF_CPU_ZIO_WAIT_MOS;\n}\n\nfbt::dsl_pool_sync_mos:return\n/self->state == STATE_OFF_CPU_ZIO_WAIT_MOS/\n{\n\tself->state = STATE_ON_CPU;\n}\n\nfbt::dmu_objset_sync:entry\n/self->state == STATE_ON_CPU/\n{\n\tself->state = STATE_OFF_CPU_OBJSET_SYNC;\n}\n\nfbt::dmu_objset_sync:return\n/self->state == STATE_OFF_CPU_OBJSET_SYNC/\n{\n\tself->state = STATE_ON_CPU;\n}\n\nsched:::off-cpu\n/self->spa != NULL/\n{\n\tprintf(\"{ \\\"time\\\": \\\"%d\\\", \\\"entity\\\": \\\"%s\\\", \",\n\t    timestamp - start, self->spa->spa_name);\n\n\tprintf(\"\\\"state\\\": %d }\\n\",\n\t    self->state != STATE_ON_CPU ? self->state : \n\t    curthread->t_sobj_ops == NULL ? STATE_OFF_CPU_PREEMPTED :\n\t    curthread->t_sobj_ops == &`cv_sobj_ops ? STATE_OFF_CPU_CV :\n\t    STATE_OFF_CPU_BLOCKED);\n}\n\nsched:::on-cpu\n/self->spa != NULL/\n{\n\tprintf(\"{ \\\"time\\\": \\\"%d\\\", \\\"entity\\\": \\\"%s\\\", \",\n\t    timestamp - start, self->spa->spa_name);\n\tprintf(\"\\\"state\\\": %d }\\n\", STATE_ON_CPU);\n}\n\ntick-1sec\n/timestamp - start > 300 * 1000000000/\n{\n\texit(0);\n}\n\n"
  },
  {
    "path": "contrib/vdev-statemap.d",
    "content": "#!/usr/sbin/dtrace -Cs\n\n/*\n * Copyright 2018, Joyent, Inc.\n */\n\n#pragma D option quiet\n#pragma D option destructive\n\ntypedef enum zio_priority {\n\tZIO_PRIORITY_SYNC_READ,\n\tZIO_PRIORITY_SYNC_WRITE,        /* ZIL */\n\tZIO_PRIORITY_ASYNC_READ,        /* prefetch */\n\tZIO_PRIORITY_ASYNC_WRITE,       /* spa_sync() */\n\tZIO_PRIORITY_SCRUB,             /* asynchronous scrub/resilver reads */\n\tZIO_PRIORITY_REMOVAL,           /* reads/writes for vdev removal */\n\tZIO_PRIORITY_INITIALIZING,      /* initializing I/O */\n\tZIO_PRIORITY_NUM_QUEUEABLE\n} zio_priority_t;\n\ntypedef enum {\n\tSTATE_NONE = 0,\n\tSTATE_READ,\n\tSTATE_WRITE,\n\tSTATE_RW,\n\tSTATE_MAX\n} state_t;\n\nstate_t state[vdev_queue_t *];\n\n#define STATE_METADATA(_state, _str, _color) \\\n\tprintf(\"\\t\\t\\\"%s\\\": {\\\"value\\\": %d, \\\"color\\\": \\\"%s\\\" }%s\\n\", \\\n\t    _str, _state, _color, _state < STATE_MAX - 1 ? \",\" : \"\");\n\nBEGIN\n{\n\twall = walltimestamp;\n\tprintf(\"{\\n\\t\\\"start\\\": [ %d, %d ],\\n\",\n\t    wall / 1000000000, wall % 1000000000);\n\t\n\tprintf(\"\\t\\\"title\\\": \\\"vdev I/O\\\",\\n\");\n\tprintf(\"\\t\\\"host\\\": \\\"%s\\\",\\n\", `utsname.nodename);\n\tprintf(\"\\t\\\"states\\\": {\\n\");\n\n\tSTATE_METADATA(STATE_NONE, \"idle\", \"#e0e0e0\");\n\tSTATE_METADATA(STATE_READ, \"reading\", \"#FFC300\");\n\tSTATE_METADATA(STATE_WRITE, \"writing\", \"#FF5733\");\n\tSTATE_METADATA(STATE_RW, \"reading+writing\", \"#C70039\");\n\n\tprintf(\"\\t}\\n}\\n\");\n\tstart = timestamp;\n}\n\nvdev_queue_pending_add:entry\n{\n\tthis->prio = (args[1]->io_priority == ZIO_PRIORITY_SYNC_WRITE ||\n\t    args[1]->io_priority == ZIO_PRIORITY_ASYNC_WRITE) ?\n\t    STATE_WRITE : STATE_READ;\n\n\tthis->state = state[args[0]];\n\tthis->next = this->state != STATE_NONE ? this->state : this->prio;\n}\n\nvdev_queue_pending_add:entry\n/(this->state == STATE_READ && this->prio == STATE_WRITE) ||\n    (this->state == STATE_WRITE && this->prio == STATE_READ)/\n{\n\tthis->next = STATE_RW;\n}\n\nvdev_queue_pending_remove:entry\n{\n\tthis->prio = (args[1]->io_priority == ZIO_PRIORITY_SYNC_WRITE ||\n\t    args[1]->io_priority == ZIO_PRIORITY_ASYNC_WRITE) ?\n\t    STATE_WRITE : STATE_READ;\n\n\tthis->reads = args[0]->vq_class[ZIO_PRIORITY_ASYNC_READ].vqc_active +\n\t    args[0]->vq_class[ZIO_PRIORITY_SYNC_READ].vqc_active -\n\t    (this->prio == STATE_READ ? 1 : 0);\n\n\tthis->writes = args[0]->vq_class[ZIO_PRIORITY_ASYNC_WRITE].vqc_active +\n\t    args[0]->vq_class[ZIO_PRIORITY_SYNC_WRITE].vqc_active -\n\t    (this->prio == STATE_WRITE ? 1 : 0);\n\n\tthis->state = state[args[0]];\n\tthis->next = this->reads > 0 ?\n\t    (this->writes > 0 ? STATE_RW : STATE_READ) :\n\t    (this->writes > 0 ? STATE_WRITE : STATE_NONE);\n}\n\nvdev_queue_pending_add:entry,\nvdev_queue_pending_remove:entry\n/this->state != this->next/\n{\n\tthis->q = (vdev_queue_t *)arg0;\n\tprintf(\"{ \\\"time\\\": \\\"%d\\\", \\\"entity\\\": \\\"%s\\\", \\\"state\\\": %d }\\n\",\n\t    timestamp - start,\n\t    basename(this->q->vq_vdev->vdev_path), this->next);\n\n\tstate[this->q] = this->next;\n}\n\ntick-1sec\n/timestamp - start > 300 * 1000000000/\n{\n\texit(0);\n}\n"
  },
  {
    "path": "src/icons/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2016\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "src/icons/README.md",
    "content": "\n# Statemap icons\n\nThe icons here are from the [svg-icon](https://leungwensen.github.io/svg-icon/)\nproject, and in particular the\n[\"zero\" family](https://leungwensen.github.io/svg-icon/#zero).\n\n"
  },
  {
    "path": "src/main.rs",
    "content": "/*\n * Copyright 2018 Joyent, Inc.\n */ \n\n/*\n * We don't want to get away with not using values that we must use.\n */\n#![deny(unused_must_use)]\n\nextern crate getopts;\nuse getopts::Options;\nuse getopts::HasArg;\nuse std::env;\n\n#[macro_use]\nextern crate serde_derive;\n\n#[macro_use]\nextern crate serde_json;\n\nmod statemap;\n\nuse statemap::*;\n\nmacro_rules! fatal {\n    ($fmt:expr) => ({\n        eprint!(concat!(\"statemap: \", $fmt, \"\\n\"));\n        ::std::process::exit(1);\n    });\n    ($fmt:expr, $($arg:tt)*) => ({\n        eprint!(concat!(\"statemap: \", $fmt, \"\\n\"), $($arg)*);\n        ::std::process::exit(1);\n    });\n}\n\nfn usage(opts: Options) {\n    println!(\"{}\", opts.usage(\"Usage: statemap [options] FILE\"));\n    ::std::process::exit(0);\n}\n\nfn parse_offset(matches: &getopts::Matches, opt: &str) -> i64 {\n    fn parse_offset_val(val: &str) -> Option<i64> {\n        let mut mult: i64 = 1;\n        let mut num = val;\n\n        let suffixes: &[(&'static str, i64)] = &[\n            (\"ns\", 1), (\"us\", 1_000), (\"ms\", 1_000_000),\n            (\"s\", 1_000_000_000), (\"sec\", 1_000_000_000)\n        ];\n\n        for suffix in suffixes {\n            if val.ends_with(suffix.0) {\n                mult = suffix.1;\n                num = &val[..val.len() - suffix.0.len()];\n                break;\n            }\n        }\n\n        /*\n         * First attempt to parse our number as an integer, falling back\n         * on parsing it as floating point if that fails (and being sure\n         * to not allow some joker to specify \"NaNms\").\n         */\n        match num.parse::<i64>() {\n            Err(_err) => {\n                match num.parse::<f64>() {\n                    Err(_err) => None,\n                    Ok(val) => {\n                        if val.is_nan() {\n                            None\n                        } else {\n                            Some((val * mult as f64) as i64)\n                        }\n                    }\n                }\n            },\n            Ok(val) => Some(val * mult)\n        }\n    }\n\n    /*\n     * We can safely unwrap here because we should only be here if the option\n     * has been set.\n     */\n    let optval = matches.opt_str(opt).unwrap();\n\n    match parse_offset_val(&optval) {\n        Some(val) => val,\n        None => fatal!(concat!(\"value for {} is not a valid \",\n            \"expression of time: \\\"{}\\\"\"), opt, optval)\n    }\n}\n\nfn main() {\n    struct Opt {\n        name: (&'static str, &'static str),\n        help: &'static str,\n        hint: &'static str,\n        hasarg: HasArg,\n        alias: Option<&'static str>,\n    }\n\n    let opts: &[Opt] = &[\n        Opt {\n            name: (\"b\", \"begin\"),\n            help: \"time offset at which to begin statemap\",\n            hint: \"TIME\",\n            hasarg: HasArg::Yes,\n            alias: None,\n        },\n        Opt {\n            name: (\"e\", \"end\"),\n            help: \"time offset at which to end statemap\",\n            hint: \"TIME\",\n            hasarg: HasArg::Yes,\n            alias: None,\n        },\n        Opt {\n            name: (\"d\", \"duration\"),\n            help: \"time duration of statemap\",\n            hint: \"TIME\",\n            hasarg: HasArg::Yes,\n            alias: None,\n        },\n        Opt {\n            name: (\"c\", \"coalesce\"),\n            help: \"coalesce target\",\n            hint: \"TARGET\",\n            hasarg: HasArg::Yes,\n            alias: None,\n        },\n        Opt {\n            name: (\"?\", \"help\"),\n            help: \"print this usage message\",\n            hint: \"\",\n            hasarg: HasArg::No,\n            alias: None,\n        },\n        Opt {\n            name: (\"s\", \"sortby\"),\n            help: \"state to sort by (defaults to entity name)\",\n            hint: \"STATE\",\n            hasarg: HasArg::Yes,\n            alias: None,\n        },\n        Opt {\n            name: (\"S\", \"stacksortby\"),\n            help: \"state to sort stacked statemaps by\",\n            hint: \"STATE\",\n            hasarg: HasArg::Yes,\n            alias: None,\n        },\n        Opt {\n            name: (\"i\", \"ignore-tags\"),\n            help: \"ignore tags in input\",\n            hint: \"\",\n            hasarg: HasArg::No,\n            alias: Some(\"ignoreTags\"),\n        },\n        Opt {\n            name: (\"h\", \"state-height\"),\n            help: \"height of each state, in pixels\",\n            hint: \"PIXELS\",\n            hasarg: HasArg::Yes,\n            alias: Some(\"stateHeight\"),\n        },\n        Opt {\n            name: (\"n\", \"dry-run\"),\n            help: \"ingest data, but do not generate output\",\n            hint: \"\",\n            hasarg: HasArg::No,\n            alias: None,\n        },\n    ];\n\n    let mut args: Vec<String> = env::args().collect();\n\n    /*\n     * Iterate over our arguments and options, replacing any alias we find.\n     * This allows us to (silently -- and inelegantly) remain backward\n     * compatible with camel-cased options while moving to snake-cased ones.\n     */\n    for i in 0..args.len() {\n        for opt in opts {\n            if let Some(alias) = opt.alias {\n                if args[i].find(alias) != None {\n                    args[i] = args[i].replace(alias, opt.name.1);\n                }\n            }\n        }\n    }\n\n    let mut parser = Options::new();\n\n    /*\n     * Load the parser with our options.\n     */\n    for opt in opts {\n        parser.opt(opt.name.0, opt.name.1,\n            opt.help, opt.hint, opt.hasarg, getopts::Occur::Optional);\n    }\n\n    let matches = match parser.parse(&args[1..]) {\n        Ok(m) => { m }\n        Err(f) => { fatal!(\"{}\", f) }\n    };\n\n    if matches.opt_present(\"help\") {\n        usage(parser);\n    }\n\n    let mut begin: i64 = 0;\n    let mut end: i64 = 0;\n\n    let has_duration = matches.opt_present(\"duration\");\n    let has_begin = matches.opt_present(\"begin\");\n    let has_end = matches.opt_present(\"end\");\n\n    if has_duration {\n        let duration = parse_offset(&matches, \"duration\");\n\n        if has_begin {\n            if has_end {\n                fatal!(\"cannot specify all of begin, end, and duration\");\n            } else {\n                begin = parse_offset(&matches, \"begin\");\n                end = begin + duration;\n            }\n        } else {\n            if has_end {\n                end = parse_offset(&matches, \"end\");\n\n                if duration > end {\n                    fatal!(\"duration cannot exceed end offset\");\n                }\n\n                begin = end - duration;\n            } else {\n                end = duration;\n            }\n        }\n    } else {\n        if has_end {\n            end = parse_offset(&matches, \"end\")\n        }\n\n        if has_begin {\n            begin = parse_offset(&matches, \"begin\");\n            if end < begin {\n                fatal!(\"begin offset must be less than end offset\");\n            }\n        }\n    }\n\n    if matches.free.is_empty() {\n        fatal!(\"must specify a data file\");\n    }\n\n    let mut config = Config {\n        begin: begin,\n        end: end,\n        notags: matches.opt_present(\"ignore-tags\"),\n        abstime: false,\n        .. Default::default()\n    };\n\n    match matches.opt_str(\"coalesce\") {\n        Some(str) => match str.parse::<u64>() {\n            Err(_err) => fatal!(\"coalesce factor must be an integer\"),\n            Ok(val) => config.maxrect = val\n        }\n        _ => {}\n    }\n\n    let mut svgconf: StatemapSVGConfig = Default::default();\n\n    svgconf.sortby = matches.opt_str(\"sortby\");\n    svgconf.stacksortby = matches.opt_str(\"stacksortby\");\n\n    if let Some(str) = matches.opt_str(\"state-height\") {\n        match str.parse::<u32>() {\n            Err(_err) => fatal!(\"state height must be an integer\"),\n            Ok(val) => svgconf.stripHeight = val\n        }\n    }\n\n    let mut statemaps: Vec<Statemap> = vec![];\n\n    for i in 0..matches.free.len() {\n        let mut statemap = Statemap::new(&config);\n        let filename = &matches.free[i];\n\n        match statemap.ingest(filename) {\n            Err(f) => { fatal!(\"could not ingest {}: {}\", filename, f); }\n            Ok(k) => { k }\n        }\n\n        if !config.abstime {\n            /*\n             * If our time configuration is not absolute, we just processed\n             * our first statemap; change our time configuration to now be\n             * absolute to key the time for every subsequent statemap based\n             * on this first statemap.\n             */\n            assert!(i == 0);\n            config.abstime = true;\n            let timebounds = statemap.timebounds();\n            config.begin = timebounds.0 as i64;\n            config.end = timebounds.1 as i64;\n        }\n\n        statemaps.push(statemap);\n    }\n\n    if matches.opt_present(\"dry-run\") {\n        return;\n    }\n\n    let svg = StatemapSVG::new(&svgconf);\n\n    match svg.output(&statemaps) {\n        Err(f) => { fatal!(\"{}\", f); }\n        Ok(k) => { k }\n    }\n}\n"
  },
  {
    "path": "src/statemap-svg.css",
    "content": "/*\n * Copyright 2018, Joyent, Inc.\n */\n\n.sansserif {\n\tfont-family: Verdana, Arial, Helvetica, sans-serif;\n}\n\n.button {\n        fill: #fff;\n}\n\n.statemap-border {\n\tfill: none;\n\tstroke: black;\n\tstroke-width: 0.5;\n}\n\n.statemap-highlight {\n\tfill:\t\tblue;\n}\n\n.statemap-title {\n\tfont-size:\t10pt;\n\tfont-weight:\tbold;\n\ttext-anchor:\tmiddle;\n\tcursor:\t\tdefault;\n}\n\n.statemap-timelabel {\n\tfont-size:\t8pt;\n\ttext-anchor:\tmiddle;\n\tcursor:\t\tdefault;\n}\n\n.statemap-timebar {\n\tstroke:\t\tblue;\n\tfill:\t\tblue;\n\tstroke-width:\t1px;\n}\n\n.statemap-timetext {\n\tfont-size:\t8pt;\n\tfont-weight:\tnormal;\n\tfill:\t\tblue;\n\tstroke:\t\tblue;\n\tstroke-width:\t0px;\n\tcursor:\t\tdefault;\n}\n\n.statemap-timebreaktext {\n\tfont-size:\t8pt;\n\tfont-weight:\tbold;\n\tfill:\t\tblue;\n\tstroke:\t\twhite;\n\tstroke-width:\t0.3px;\n\tcursor:\t\tdefault;\n}\n\n.statemap-subbar {\n\tstroke:\t\tblue;\n\tfill:\t\tblue;\n\tstroke-width:\t1px;\n\tstroke-dasharray: 5.7;\n}\n\n.statemap-subbar-span {\n\tstroke:\t\tblue;\n\tfill:\t\tblue;\n\tstroke-width:\t0.75px;\n\tstroke-dasharray: 1;\n}\n\n.statemap-subbar-text {\n\tfont-size:\t8pt;\n\tfont-weight:\tbold;\n\tfill:\t\tblue;\n\tstroke:\t\twhite;\n\tstroke-width:\t0.3px;\n\tcursor:\t\tdefault;\n}\n\n.statemap-statebar {\n\tstroke:\t\tblue;\n\tfill:\t\tblue;\n\tstroke-width:\t1px;\n}\n\n.statemap-statetext {\n\tfont-size:\t8pt;\n\tfont-weight:\tnormal;\n\tfill:\t\tblue;\n\tstroke:\t\tblue;\n\tstroke-width:\t0px;\n\tcursor:\t\tdefault;\n}\n\n.statemap-timeline {\n\tstroke: black;\n\tstroke-width:\t0.5pt;\n\tmarker-start:\turl(#startarrow);\n\tmarker-end:\turl(#endarrow);\n}\n\n.statemap-legend {\n\tstroke: black;\n\tstroke-width:\t0.5pt;\n}\n\n.statemap-legend-highlighted {\n\tstroke:\t\tblue;\n\tstroke-width:\t3pt;\n}\n\n.statemap-legendlabel {\n\tfont-size:\t7pt;\n\ttext-anchor:\tmiddle;\n\tcursor:\t\tdefault;\n}\n\n.statemap-tagbox {\n\tstroke:\t\tblack;\n\tstroke-width:\t0.5pt;\n\talignment-baseline:\thanging;\n\ttext-anchor:\tstart;\n\tcursor:\t\tdefault;\n}\n\n.statemap-tagbox-header {\n\tfont-size:\t9pt;\n\tfont-weight:\tbold;\n\ttext-anchor:\tstart;\n\tfont-style:\toblique;\n\tcursor:\t\tdefault;\n}\n\n.statemap-tagbox-header-line {\n\tstroke:\t\tblack;\n\tstroke-width:\t1pt;\n}\n\n.statemap-tagbox-tag {\n\tfont-size:\t9pt;\n\tcursor:\t\tdefault;\n}\n\n.statemap-tagbox-tag-highlighted {\n\tfont-weight:\tbold;\n}\n\n.statemap-tagbox-select-header {\n\tfont-size:\t8pt;\n\ttext-anchor:\tstart;\n\tfont-style:\toblique;\n\tcursor:\t\tdefault;\n}\n\n.statemap-tagbox-select {\n\tfont-size:\t8pt;\n\ttext-anchor:\tstart;\n\tcursor:\t\tdefault;\n}\n\n.statemap-tagbox-select-perc {\n\tfont-size:\t8pt;\n\ttext-anchor:\tend;\n\tcursor:\t\tdefault;\n}\n\n.statemap-tagbox-select-header-line {\n\tstroke:\t\tblack;\n\tstroke-width:\t0.5pt;\n}\n\n.statemap-tagbox-select-sum-line {\n\tstroke:\t\tblack;\n\tstroke-width:\t0.25pt;\n}\n\n.statemap-tagbox-select-highlighted {\n\tfont-weight:\tbold;\n}\n"
  },
  {
    "path": "src/statemap-svg.defs",
    "content": "\n<!-- This file is pulled into the <defs> section !-->\n\n <marker id=\"startarrow\" markerWidth=\"10\" markerHeight=\"7\" \n    refX=\"10\" refY=\"3.5\" orient=\"auto\">\n      <polygon points=\"10 0, 10 7, 0 3.5\" fill=\"black\" />\n    </marker>\n    <marker id=\"endarrow\" markerWidth=\"10\" markerHeight=\"7\" \n    refX=\"0\" refY=\"3.5\" orient=\"auto\" markerUnits=\"strokeWidth\">\n        <polygon points=\"0 0, 10 3.5, 0 7\" fill=\"black\" />\n    </marker>\n\n"
  },
  {
    "path": "src/statemap-svg.js",
    "content": "/*\n * Copyright 2018, Joyent, Inc.\n */\n\n/*\n * This file is dropped into the generated SVG -- and if you're looking at\n * the generated SVG and wondering where this comes from, look for\n * statemap-svg.js in statemap's src directory.\n */\n\nvar g_transMatrix = [1, 0, 0, 1, 0, 0];\t\t/* transform of statemap */\nvar g_svgDoc;\t\t\t\t\t/* our SVG document */\nvar g_offset;\t\t\t\t\t/* x offset of statemap */\nvar g_timelabel;\t\t\t\t/* label for time spanned */\nvar g_timebar;\t\t\t\t\t/* timebar, if any */\nvar g_statebar;\t\t\t\t\t/* statebar, if any */\nvar g_height;\t\t\t\t\t/* pixel height of statemap */\nvar g_width;\t\t\t\t\t/* pixel width of statemap */\nvar g_statesel;\t\t\t\t\t/* state selection, if any */\nvar g_tagsel;\t\t\t\t\t/* tag selection, if any */\nvar g_tagvalsel;\t\t\t\t/* tag val selection, if any */\n\nvar g_statemaps = [];\t\t\t\t/* array of statemaps */\n\nvar timeunits = function (timeval)\n{\n\tvar i, rem;\n\tvar suffixes = [ 'ns', 'μs', 'ms', 's' ];\n\n\tif (timeval === 0)\n\t\treturn ('0');\n\n\tfor (i = 0; (timeval > 1000 || timeval < -1000) &&\n\t    i < suffixes.length - 1; i++)\n\t\ttimeval /= 1000;\n\n\trem = Math.floor((timeval - Math.floor(timeval)) * 1000);\n\n\treturn (Math.floor(timeval) + '.' +\n\t    (rem < 100 ? '0' : '') + (rem < 10 ? '0' : '') + rem +\n\t    suffixes[i]);\n};\n\nvar timeFromMapX = function (mapX)\n{\n\tvar base, offs;\n\tvar timeWidth = globals.timeWidth;\n\n\t/*\n\t * Our base (in nanoseconds) is our X offset in the transformation\n\t * matrix as a ratio of our total (scaled) width, times our timeWidth.\n\t */\n\tbase = (-g_transMatrix[4] / (g_transMatrix[0] * g_width)) * timeWidth;\n\n\t/*\n\t * Our offset (in nanoseconds) is the X offset within the statemap\n\t * as a ratio of the statemap width, times the number of nanoseconds\n\t * visible in the statemap (which itself is the timeWidth divided by\n\t * our scaling factor).\n\t */\n\toffs = (mapX / g_width) * (timeWidth / g_transMatrix[0]);\n\n\treturn (base + offs);\n};\n\nvar timeToMapX = function (time)\n{\n\t/*\n\t * We take the ratio of the time of the timebar of the total time\n\t * width times the width times the scale, and then add that to the\n\t * X offset in the transformation matrix.\n\t */\n\treturn (((time / globals.timeWidth) * g_width *\n\t    g_transMatrix[0]) + g_transMatrix[4]);\n};\n\nvar timeToText = function (time)\n{\n\tvar t;\n\n\tif (g_transMatrix[0] === 1 && globals.begin === 0) {\n\t\tt = 'offset = ' + timeunits(time);\n\t} else {\n\t\tt = 'offset = ' + timeunits(time) + ', ' +\n\t\t    timeunits(time + globals.begin) + ' overall';\n\t}\n\n\tif (globals.start) {\n\t\tvar s = globals.start[0] +\n\t\t    (time + globals.start[1]) / 1000000000;\n\n\t\tt += ' (Epoch + ' + Math.floor(s) + 's)';\n\t}\n\n\treturn (t);\n};\n\nvar timeSetSpanLabel = function ()\n{\n\tvar t = 'span = ' + timeunits(globals.timeWidth / g_transMatrix[0]);\n\n\tif (g_transMatrix[0] != 1 || globals.begin !== 0)\n\t\tt += '; ' + timeToText(timeFromMapX(0));\n\n\tg_timelabel.textContent = t;\n};\n\nvar initStatemap = function (statemap, elem, position)\n{\n\tvar i, highlight;\n\tvar prefix = globals.entityPrefix + statemap + '-';\n\n\tg_statemaps[statemap].elem = elem;\n\tg_statemaps[statemap].position = position;\n\tg_statemaps[statemap].nentities = 0;\n\n\t/*\n\t * Iterate over this statemap's children, looking for entities.\n\t */\n\tfor (i = 0; i < elem.childNodes.length; i++) {\n\t\tvar id = elem.childNodes[i].id, entity;\n\n\t\tif (!id || id.indexOf(prefix) !== 0)\n\t\t\tcontinue;\n\n\t\tentity = {\n\t\t\tname: id.substr(prefix.length),\n\t\t\telement: elem.childNodes[i],\n\t\t\tposition: position++,\n\t\t\tstatemap: statemap\n\t\t};\n\n\t\tentity.description =\n\t\t    g_statemaps[statemap].entities[entity.name].description;\n\n\t\tg_entities[id] = entity;\n\t\tg_statemaps[statemap].nentities++;\n\t}\n\n\t/*\n\t * Determine the legend that this statemap is using.\n\t */\n\tfor (i = statemap; i >= 0; i--) {\n\t\tif (g_svgDoc.getElementById('statemap-legend-' + i + '-0')) {\n\t\t\tg_statemaps[statemap].legend = i;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tconsole.assert(i >= 0);\n\n\t/*\n\t * Dynamically change the styling of the highlight rectangle.\n\t */\n\thighlight = g_svgDoc.getElementById('statemap-' +\n\t    statemap + '-highlight');\n\thighlight.classList.add('statemap-highlight');\n\n\treturn (position);\n};\n\nvar init = function (evt)\n{\n\tvar i = 0, position = 0, statemap;\n\n\tg_svgDoc = evt.target.ownerDocument;\n\tg_entities = [];\n\n\twhile ((statemap = g_svgDoc.getElementById('statemap-' + i)) != null)\n\t\tposition = initStatemap(i++, statemap, position);\n\n\tg_height = globals.pixelHeight;\n\tg_width = globals.pixelWidth;\n\n\tg_offset = evt.target.getAttributeNS(null, 'width') -\n\t    (g_width + globals.tagWidth);\n\n\tg_timelabel = g_svgDoc.getElementById('statemap-timelabel');\n\ttimeSetSpanLabel();\n\n\tg_timebar = undefined;\n};\n\nvar entityForEachDatum = function (entity, time, etime, func)\n{\n\tvar data = g_statemaps[entity.statemap].data[entity.name];\n\n\tvar idx, length = data.length;\n\tvar floor = 0;\n\tvar ceil = length;\n\tvar datum, t, span;\n\n\tif (length === 0 || (data[0].t > time && !etime))\n\t\treturn;\n\n\tif (data[0].t > time) {\n\t\tidx = 0;\n\t} else {\n\t\t/*\n\t\t * Binary search our data until we find a datum that contains\n\t\t * the start of our time range.\n\t\t */\n\t\tfor (;;) {\n\t\t\tidx = floor + Math.floor((ceil - floor) / 2);\n\n\t\t\tif (data[idx].t > time) {\n\t\t\t\tceil = idx;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (idx + 1 == length || data[idx + 1].t > time)\n\t\t\t\tbreak;\n\n\t\t\tfloor = idx;\n\t\t}\n\t}\n\n\t/*\n\t * If we don't have a specified etime, we have found the datum that\n\t * contains the time; just call our function and return.\n\t */\n\tif (!etime) {\n\t\tfunc(data[idx], idx, 1);\n\t\treturn;\n\t}\n\n\t/*\n\t * Now we're going to iterate forward, calling our function until we\n\t * get past our specified etime.\n\t */\n\tfor (; idx < length; idx++) {\n\t\tdatum = data[idx];\n\n\t\tif (datum.t > etime)\n\t\t\treturn;\n\n\t\tif ((t = datum.t) < time)\n\t\t\tt = time;\n\n\t\tif (idx + 1 == length || data[idx + 1].t > etime) {\n\t\t\t/*\n\t\t\t * This datum contains the end of the range; our span\n\t\t\t * is our etime minus this datum's start time (or our\n\t\t\t * specified time, whichever is greater).\n\t\t\t */\n\t\t\tspan = etime - t;\n\t\t} else {\n\t\t\t/*\n\t\t\t * The end of the datum is covered by the range; our\n\t\t\t * span is the time width of the datum.\n\t\t\t */\n\t\t\tspan = data[idx + 1].t - t;\n\t\t}\n\n\t\tfunc(datum, idx, span);\n\t}\n};\n\nvar entityDatum = function (entity, idx)\n{\n\tvar data = g_statemaps[entity.statemap].data[entity.name];\n\tvar datum = data[idx];\n\tvar rval = { time: datum.t };\n\n\tif (datum.s instanceof Object) {\n\t\trval.states = datum.s;\n\t} else {\n\t\trval.state = datum.s;\n\t}\n\n\tif (idx + 1 < data.length) {\n\t\trval.etime = data[idx + 1].t;\n\t} else {\n\t\trval.etime = globals.timeWidth + globals.begin;\n\t}\n\n\treturn (rval);\n};\n\nvar entityBreakdown = function (entity, time, etime)\n{\n\tvar data = g_statemaps[entity.statemap].data[entity.name];\n\tvar rval = {};\n\n\tvar idx, length = data.length;\n\tvar floor = 0;\n\tvar ceil = length;\n\tvar datum, t, span, state;\n\n\ttime += g_statemaps[entity.statemap].offset;\n\n\tif (length === 0 || data[0].t > time)\n\t\treturn ({});\n\n\t/*\n\t * Binary search our data until we find a datum that contains the\n\t * specified time.\n\t */\n\tfor (;;) {\n\t\tidx = floor + Math.floor((ceil - floor) / 2);\n\n\t\tif (data[idx].t > time) {\n\t\t\tceil = idx;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (idx + 1 == length || data[idx + 1].t > time)\n\t\t\tbreak;\n\n\t\tfloor = idx;\n\t}\n\n\t/*\n\t * If we don't have a specified etime, we want to just return the state\n\t * breakdown at the specified time.\n\t */\n\tif (!etime) {\n\t\tdatum = data[idx];\n\n\t\tif (datum.s instanceof Object)\n\t\t\treturn (datum.s);\n\n\t\trval[datum.s] = 1.0;\n\n\t\treturn (rval);\n\t}\n\n\t/*\n\t * Now we're going to iterate forward until we get past our specified\n\t * etime.\n\t */\n\tfor (; idx < length; idx++) {\n\t\tdatum = data[idx];\n\n\t\tif (datum.t > etime)\n\t\t\tbreak;\n\n\t\tif ((t = datum.t) < time)\n\t\t\tt = time;\n\n\t\tif (idx + 1 == length || data[idx + 1].t > etime) {\n\t\t\t/*\n\t\t\t * This datum contains the end of the range; our span\n\t\t\t * is our etime minus this datum's start time (or our\n\t\t\t * specified time, whichever is greater).\n\t\t\t */\n\t\t\tspan = etime - t;\n\t\t} else {\n\t\t\t/*\n\t\t\t * The end of the datum is covered by the range; our\n\t\t\t * span is the time width of the datum.\n\t\t\t */\n\t\t\tspan = data[idx + 1].t - t;\n\t\t}\n\n\t\t/*\n\t\t * Express our span as a ratio of the overall time.\n\t\t */\n\t\tspan /= (etime - time);\n\n\t\tif (datum.s instanceof Object) {\n\t\t\tfor (state in datum.s) {\n\t\t\t\tif (!rval.hasOwnProperty(state))\n\t\t\t\t\trval[state] = 0;\n\n\t\t\t\trval[state] += (datum[state] * span);\n\t\t\t}\n\t\t} else {\n\t\t\tstate = datum.s;\n\n\t\t\tif (!rval.hasOwnProperty(state))\n\t\t\t\trval[state] = 0;\n\n\t\t\trval[state] += span;\n\t\t}\n\t}\n\n\treturn (rval);\n};\n\nvar statebarCreateBar = function (statebar, x1, y1, x2, y2)\n{\n\tvar parent = statebar.parent;\n\n\tvar bar = g_svgDoc.createElementNS(parent.namespaceURI, 'line');\n\tbar.classList.add('statemap-statebar');\n\tbar.x1.baseVal.value = x1;\n\tbar.y1.baseVal.value = y1;\n\tbar.x2.baseVal.value = x2;\n\tbar.y2.baseVal.value = y2;\n\tparent.appendChild(bar);\n\tstatebar.bars.push(bar);\n};\n\nvar statebarCreate = function (elem, idx)\n{\n\tvar parent = g_statemaps[0].elem.parentNode.parentNode;\n\tvar statebar = { parent: parent, hidden: false };\n\tvar entity = g_entities[elem.parentNode.id];\n\tvar statemap = g_statemaps[entity.statemap];\n\tvar states = statemap.states;\n\tvar datum = entityDatum(entity, idx);\n\tvar pos = (entity.position * globals.stripHeight) +\n\t    (entity.statemap * globals.smargin);\n\tvar x = globals.lmargin - 2;\n\tvar y = globals.tmargin + pos;\n\tvar elbow = { x: 8, y: 10 };\n\tvar nudge = { x: 3, y: 2 };\n\tvar direction = 1, anchor;\n\tvar anchors = [ 'start', 'end' ];\n\tvar text;\n\n\tif (pos < (globals.totalHeight - globals.tmargin) / 2) {\n\t\tdirection = 1;\n\t\tanchor = 1;\n\t} else {\n\t\tdirection = -1;\n\t\tanchor = 0;\n\t}\n\n\tstatebar.bars = [];\n\n\t/*\n\t * We have three bars to draw:  our bar that runs the height of the\n\t * strip, followed by our elbow.\n\t */\n\tstatebarCreateBar(statebar, x, y, x, y + globals.stripHeight);\n\n\ty += 0.5 * globals.stripHeight;\n\tstatebarCreateBar(statebar, x - elbow.x, y, x, y);\n\n\tx -= elbow.x;\n\tstatebarCreateBar(statebar, x, y, x, y + (elbow.y * direction));\n\n\t/*\n\t * Now create the text at the end of the elbow.\n\t */\n\ty += (elbow.y + nudge.y) * direction;\n\tx += nudge.x;\n\ttext = g_svgDoc.createElementNS(parent.namespaceURI, 'text');\n\ttext.classList.add('sansserif');\n\ttext.classList.add('statemap-statetext');\n\n\tvar t = statemap.entityKind + ' ' + entity.name;\n\n\tif (entity.description)\n\t\tt += ' (' + entity.description + ')';\n\n\tif (datum.hasOwnProperty('state')) {\n\t\tt += ', ' + states[datum.state].name;\n\t} else {\n\t\tvar i, total = 0, max = 0, maxstate;\n\n\t\tfor (i in datum.states) {\n\t\t\ttotal += datum.states[i];\n\n\t\t\tif (datum.states[i] > max) {\n\t\t\t\tmaxstate = i;\n\t\t\t\tmax = datum.states[i];\n\t\t\t}\n\t\t}\n\n\t\tt += ', ' + Math.floor((datum.states[maxstate] / total) * 100);\n\t\tt += '% ' + states[maxstate].name;\n\t}\n\n\tt += ' at ' + timeunits(datum.time);\n\tt += ' for ' + timeunits(datum.etime - datum.time);\n\n\ttext.appendChild(g_svgDoc.createTextNode(t));\n\ttext.setAttributeNS(null, 'x', x);\n\ttext.setAttributeNS(null, 'y', y);\n\ttext.setAttributeNS(null, 'transform',\n\t    'rotate(270,' + x + ',' + y + ')');\n\ttext.setAttributeNS(null, 'text-anchor', anchors[anchor]);\n\ttext.addEventListener('click', function () {\n\t\tstatebarRemove(statebar);\n\t\tstateselUpdate();\n\t});\n\n\tparent.appendChild(text);\n\tstatebar.bars.push(text);\n\n\tstatebar.entity = entity;\n\n\tif (g_statemaps.length == 1)\n\t\treturn (statebar);\n\n\t/*\n\t * If we have more than one statemap, we want to add a bar to the right\n\t * side to indicate which statemap this is.\n\t */\n\tvar pos = (statemap.position * globals.stripHeight) +\n\t    (entity.statemap * globals.smargin);\n\n\tx = globals.lmargin + g_width + 2;\n\ty = globals.tmargin + pos;\n\n\tvar pos = (statemap.position * globals.stripHeight) +\n\t    (entity.statemap * globals.smargin);\n\n\tvar height = statemap.nentities * globals.stripHeight;\n\n\tstatebarCreateBar(statebar, x, y, x, y + height);\n\n\ty += 0.5 * height;\n\tstatebarCreateBar(statebar, x + elbow.x, y, x, y);\n\n\tx += elbow.x;\n\tstatebarCreateBar(statebar, x, y, x, y + (elbow.y * direction));\n\n\t/*\n\t * Now create the text at the end of the elbow.\n\t */\n\ty += (elbow.y + nudge.y) * direction;\n\tx -= nudge.x;\n\ttext = g_svgDoc.createElementNS(parent.namespaceURI, 'text');\n\ttext.classList.add('sansserif');\n\ttext.classList.add('statemap-statetext');\n\ttext.appendChild(g_svgDoc.createTextNode(statemap.title));\n\ttext.setAttributeNS(null, 'x', x);\n\ttext.setAttributeNS(null, 'y', y);\n\ttext.setAttributeNS(null, 'transform',\n\t    'rotate(90,' + x + ',' + y + ')');\n\ttext.setAttributeNS(null, 'text-anchor', anchors[anchor ^ 1]);\n\n\tparent.appendChild(text);\n\tstatebar.bars.push(text);\n\n\treturn (statebar);\n};\n\nvar statebarRemove = function (statebar)\n{\n\tvar i;\n\n\tif (!statebar)\n\t\treturn;\n\n\tif (statebar.bars) {\n\t\tfor (i = 0; i < statebar.bars.length; i++)\n\t\t\tstatebar.parent.removeChild(statebar.bars[i]);\n\t}\n\n\tstatebar.bars = undefined;\n\tstatebar.entity = undefined;\n};\n\nvar timebarRemove = function (timebar)\n{\n\tif (!timebar)\n\t\treturn;\n\n\ttimebarRemoveSubbar(timebar);\n\n\tif (timebar.bar && !timebar.hidden) {\n\t\ttimebar.parent.removeChild(timebar.bar);\n\t\ttimebar.parent.removeChild(timebar.text);\n\t}\n\n\tif (timebar.breakdown) {\n\t\tvar i;\n\n\t\tfor (i = 0; i < timebar.breakdown.length; i++) {\n\t\t\tvar elem = timebar.breakdown[i];\n\t\t\telem.parentNode.removeChild(elem);\n\t\t}\n\t}\n\n\ttimebar.bar = undefined;\n\ttimebar.text = undefined;\n\ttimebar.breakdown = undefined;\n};\n\nvar timebarSetBarLocation = function (bar, mapX)\n{\n\tvar absX = mapX + g_offset;\n\tvar nubheight = 15;\n\n\tbar.x1.baseVal.value = absX;\n\tbar.y1.baseVal.value = globals.tmargin - nubheight;\n\tbar.x2.baseVal.value = absX;\n\tbar.y2.baseVal.value = globals.tmargin + g_height;\n};\n\nvar timebarSetSubbarLocation = function (subbar, mapX, timebarX)\n{\n\tvar absX = mapX + g_offset, x;\n\tvar bar = subbar.bar;\n\tvar span = subbar.span;\n\tvar text = subbar.text;\n\tvar nudge = { x: 0, y: 10 };\n\n\tbar.x1.baseVal.value = absX;\n\tbar.y1.baseVal.value = globals.tmargin;\n\tbar.x2.baseVal.value = absX;\n\tbar.y2.baseVal.value = globals.tmargin + g_height;\n\n\tspan.x1.baseVal.value = timebarX + g_offset;\n\tspan.y1.baseVal.value = subbar.y;\n\tspan.x2.baseVal.value = absX;\n\tspan.y2.baseVal.value = subbar.y;\n\n\tx = (timebarX < mapX ? timebarX : mapX) +\n\t    Math.abs(timebarX - mapX) / 2;\n\n\ttext.setAttributeNS(null, 'text-anchor', 'middle');\n\ttext.setAttributeNS(null, 'x', x + g_offset);\n\ttext.setAttributeNS(null, 'y', subbar.y + nudge.y);\n};\n\nvar timebarSetTextLocation = function (text, mapX)\n{\n\tvar absX = mapX + g_offset;\n\tvar nudge = { x: 3, y: 5 };\n\tvar direction, anchor;\n\tvar time;\n\n\t/*\n\t * The side of the timebar that we actually render the text containing\n\t * the offset and the time depends on the location of our timebar with\n\t * respect to the center of the visible statemap.\n\t */\n\tif (mapX < (g_width / 2)) {\n\t\tdirection = 1;\n\t\tanchor = 'start';\n\t} else {\n\t\tdirection = -1;\n\t\tanchor = 'end';\n\t}\n\n\ttext.setAttributeNS(null, 'x', absX + (direction * nudge.x));\n\ttext.setAttributeNS(null, 'y', globals.tmargin - nudge.y);\n\ttext.setAttributeNS(null, 'text-anchor', anchor);\n\n\ttime = timeFromMapX(mapX);\n\ttext.childNodes[0].textContent = timeToText(time);\n\n\treturn (time);\n};\n\nvar timebarHideSubbar = function (timebar)\n{\n\tvar parent, subbar;\n\n\tif (!timebar || !(subbar = timebar.subbar) || subbar.hidden)\n\t\treturn;\n\n\tparent = timebar.parent;\n\tparent.removeChild(subbar.bar);\n\tparent.removeChild(subbar.span);\n\tparent.removeChild(subbar.text);\n\n\tsubbar.hidden = true;\n};\n\nvar timebarShowSubbar = function (timebar)\n{\n\tvar parent, subbar, mapX;\n\n\tif (!timebar || !(subbar = timebar.subbar) || !subbar.hidden)\n\t\treturn;\n\n\tmapX = timeToMapX(subbar.time)\n\n\tif (mapX < 0 || mapX >= g_width)\n\t\treturn;\n\n\ttimebarSetSubbarLocation(subbar, mapX, timebar.x);\n\n\tparent = timebar.parent;\n\tparent.appendChild(subbar.bar);\n\tparent.appendChild(subbar.span);\n\tparent.appendChild(subbar.text);\n\n\tsubbar.hidden = false;\n}\n\nvar timebarHide = function (timebar)\n{\n\tif (!timebar || timebar.hidden || !timebar.bar)\n\t\treturn;\n\n\ttimebar.parent.removeChild(timebar.bar);\n\ttimebar.parent.removeChild(timebar.text);\n\ttimebar.hidden = true;\n\ttimebarHideSubbar(timebar);\n};\n\nvar timebarShow = function (timebar)\n{\n\tvar mapX;\n\n\tif (!timebar || !timebar.hidden)\n\t\treturn;\n\n\tmapX = timeToMapX(timebar.time);\n\n\tif (mapX < 0 || mapX >= g_width)\n\t\treturn;\n\n\ttimebarSetBarLocation(timebar.bar, mapX);\n\ttimebarSetTextLocation(timebar.text, mapX);\n\ttimebar.x = mapX;\n\n\ttimebar.parent.appendChild(timebar.bar);\n\ttimebar.parent.appendChild(timebar.text);\n\ttimebar.hidden = false;\n\n\ttimebarShowSubbar(timebar);\n};\n\nvar timebarSetMiddle = function (timebar)\n{\n\tvar mapX = g_width / 2;\n\n\tif (!timebar || !timebar.bar)\n\t\treturn;\n\n\t/*\n\t * This is just an algebraic rearrangement of the mapX calculation\n\t * in timebarShow(), above.\n\t */\n\tg_transMatrix[4] = -(((timebar.time / globals.timeWidth) * g_width *\n\t    g_transMatrix[0]) - mapX);\n};\n\nvar timebarSetBreakdown = function (time)\n{\n\tvar breakdown, state, total = [];\n\tvar entity;\n\tvar sum = {};\n\tvar rval = [];\n\n\tvar click = function (statemap, s) {\n\t\treturn (function (evt) { legendclick(evt, statemap, s); });\n\t};\n\n\ttime += globals.begin;\n\n\tfor (entity in g_entities) {\n\t\tvar statemap = g_statemaps[g_entities[entity].statemap].legend;\n\n\t\tbreakdown = entityBreakdown(g_entities[entity], time);\n\n\t\tif (!total[statemap]) {\n\t\t\ttotal[statemap] = {};\n\t\t\tsum[statemap] = 0;\n\t\t}\n\n\t\tfor (state in breakdown) {\n\t\t\tif (!total[statemap].hasOwnProperty(state))\n\t\t\t\ttotal[statemap][state] = 0;\n\n\t\t\tsum[statemap] += breakdown[state];\n\t\t\ttotal[statemap][state] += breakdown[state];\n\t\t}\n\t}\n\n\tvar settotal = function (statemap, state) {\n\t\tvar legend, parent, text;\n\t\tvar x, y, width, height, t;\n\t\tvar nudge = 3;\n\n\t\t/*\n\t\t * Iterate down until we find a valid legend.  We know that\n\t\t * that there will be at least one, but we break out of the\n\t\t * loop anyway if we don't find it to allow the failure mode\n\t\t * here to be an unreferenced property rather than an\n\t\t * inifinite loop.\n\t\t */\n\t\tlegend = g_svgDoc.getElementById('statemap-legend-' +\n\t\t    statemap + '-' + state);\n\n\t\tparent = legend.parentNode;\n\n\t\tx = parseInt(legend.getAttributeNS(null, 'x'), 10);\n\t\ty = parseInt(legend.getAttributeNS(null, 'y'), 10);\n\t\twidth = parseInt(legend.getAttributeNS(null, 'width'), 10);\n\t\theight = parseInt(legend.getAttributeNS(null, 'height'), 10);\n\n\t\tt = Math.floor(total[statemap][state]) + ' (' +\n\t\t    Math.floor((total[statemap][state] /\n\t\t    sum[statemap]) * 100) + '%)';\n\n\t\ttext = g_svgDoc.createElementNS(parent.namespaceURI, 'text');\n\t\ttext.classList.add('sansserif');\n\t\ttext.classList.add('statemap-timebreaktext');\n\n\t\ttext.appendChild(g_svgDoc.createTextNode(t));\n\t\ttext.setAttributeNS(null, 'x', x + (width / 2));\n\t\ttext.setAttributeNS(null, 'y', y + (height / 2) + nudge);\n\t\ttext.setAttributeNS(null, 'text-anchor', 'middle');\n\n\t\ttext.addEventListener('click',\n\t\t    click(statemap, g_statemaps[statemap].states[state].value));\n\n\t\tparent.appendChild(text);\n\t\trval.push(text);\n\t};\n\n\tfor (statemap in total) {\n\t\tfor (state in total[statemap])\n\t\t\tsettotal(statemap, state);\n\t}\n\n\treturn (rval);\n};\n\nvar timebarCreate = function (mapX)\n{\n\tvar parent = g_statemaps[0].elem.parentNode.parentNode;\n\tvar bar, text;\n\tvar timebar = { parent: parent, hidden: false };\n\n\tbar = g_svgDoc.createElementNS(parent.namespaceURI, 'line');\n\tbar.classList.add('statemap-timebar');\n\n\ttimebarSetBarLocation(bar, mapX);\n\tparent.appendChild(bar);\n\n\ttext = g_svgDoc.createElementNS(parent.namespaceURI, 'text');\n\ttext.classList.add('sansserif');\n\ttext.classList.add('statemap-timetext');\n\ttext.appendChild(g_svgDoc.createTextNode(''));\n\n\ttimebar.time = timebarSetTextLocation(text, mapX);\n\ttimebar.breakdown = timebarSetBreakdown(timebar.time);\n\ttimebar.x = mapX;\n\n\ttext.addEventListener('click', function () {\n\t\ttimebarRemove(timebar);\n\t\tstateselUpdate();\n\t});\n\n\tparent.appendChild(text);\n\n\ttimebar.bar = bar;\n\ttimebar.text = text;\n\n\treturn (timebar);\n};\n\nvar timebarCreateSubbar = function (timebar, mapX, absY)\n{\n\tvar parent = timebar.parent;\n\tvar subbar, bar, span, text, time, delta;\n\n\tbar = g_svgDoc.createElementNS(parent.namespaceURI, 'line');\n\tbar.classList.add('statemap-subbar');\n\n\tspan = g_svgDoc.createElementNS(parent.namespaceURI, 'line');\n\tspan.classList.add('statemap-subbar-span');\n\n\ttime = timeFromMapX(mapX);\n\tdelta = Math.abs(timebar.time - time);\n\n\ttext = g_svgDoc.createElementNS(parent.namespaceURI, 'text');\n\ttext.classList.add('sansserif');\n\ttext.classList.add('statemap-subbar-text');\n\ttext.appendChild(g_svgDoc.createTextNode(timeunits(delta)));\n\n\tvar subbar = { bar: bar, span: span, text: text,\n\t    time: time, y: absY, hidden: false };\n\n\ttimebarSetSubbarLocation(subbar, mapX, timebar.x);\n\n\tparent.appendChild(bar);\n\tparent.appendChild(span);\n\tparent.appendChild(text);\n\n\ttimebar.subbar = subbar;\n}\n\nvar timebarRemoveSubbar = function (timebar)\n{\n\tvar subbar = timebar.subbar;\n\n\tif (!subbar)\n\t\treturn;\n\n\tif (!subbar.hidden) {\n\t\ttimebar.parent.removeChild(subbar.bar);\n\t\ttimebar.parent.removeChild(subbar.span);\n\t\ttimebar.parent.removeChild(subbar.text);\n\t}\n\n\ttimebar.subbar = undefined;\n}\n\nvar stateselTagvalSelect = function (evt, tagval)\n{\n\tvar tagdefs = {};\n\tvar i, entity;\n\tvar state, tags;\n\tvar child;\n\tvar highlight = 'statemap-tagbox-select-highlighted';\n\n\tif (g_statesel == undefined)\n\t\treturn;\n\n\tstate = g_statesel.state;\n\ttags = g_statemaps[g_statesel.statemap].tags;\n\n\tif (g_tagvalsel && g_tagvalsel.selected) {\n\t\tfor (i = 0; i < g_tagvalsel.selected.length; i++) {\n\t\t\tchild = g_tagvalsel.selected[i];\n\t\t\tchild.removeAttribute('fill-opacity');\n\t\t}\n\n\t\tif (g_tagvalsel.element)\n\t\t\tg_tagvalsel.element.classList.remove(highlight);\n\n\t\t/*\n\t\t * If our selection matches the selection that we have already\n\t\t * made, then we are unselecting this tag value; we need only\n\t\t * return.\n\t\t */\n\t\tif (g_tagvalsel.tag == g_tagsel.tag &&\n\t\t    g_tagvalsel.tagval == tagval) {\n\t\t\tg_tagvalsel = undefined;\n\t\t\treturn;\n\t\t}\n\t}\n\n\tg_tagvalsel = { selected: [], tag: g_tagsel.tag, tagval: tagval };\n\n\tevt.target.classList.add(highlight);\n\tg_tagvalsel.element = evt.target;\n\n\t/*\n\t * Iterate over all of our tag definitions, looking for a match where\n\t * the specified tag (for the specified state) matches the specified\n\t * tag value.\n\t */\n\tfor (i = 0; i < tags.length; i++) {\n\t\tif (tags[i].state != state)\n\t\t\tcontinue;\n\n\t\tif (tags[i][g_tagsel.tag] != tagval)\n\t\t\tcontinue;\n\n\t\ttagdefs[i] = true;\n\t}\n\n\t/*\n\t * Now for each entity, we will plow through every rectangle.\n\t */\n\tfor (id in g_entities) {\n\t\tvar entity = g_entities[id];\n\t\tvar elem = entity.element;\n\t\tvar data = g_statemaps[entity.statemap].data[entity.name];\n\t\tvar j = 0;\n\n\t\tfor (i = 0; i < elem.childNodes.length; i++) {\n\t\t\tchild = elem.childNodes[i];\n\n\t\t\tif (child.nodeName != 'rect')\n\t\t\t\tcontinue;\n\n\t\t\tvar datum = data[j++];\n\t\t\tvar tag;\n\n\t\t\tif (datum.s instanceof Object) {\n\t\t\t\tif (!datum.s[state])\n\t\t\t\t\tcontinue;\n\t\t\t} else {\n\t\t\t\tif (datum.s != state)\n\t\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (!datum.g)\n\t\t\t\tcontinue;\n\n\t\t\tvar ratio = 0;\n\n\t\t\tfor (tag in datum.g) {\n\t\t\t\tif (tagdefs[tag])\n\t\t\t\t\tratio += datum.g[tag];\n\t\t\t}\n\n\t\t\tif (ratio === 0)\n\t\t\t\tcontinue;\n\n\t\t\t/*\n\t\t\t * At this point we have found a rectangle that we\n\t\t\t * want to color, and we know the degree that we\n\t\t\t * want to color it!\n\t\t\t */\n\t\t\tchild.setAttributeNS(null, 'fill-opacity', 1 - ratio);\n\t\t\tg_tagvalsel.selected.push(child);\n\t\t}\n\t}\n};\n\nvar stateselUpdate = function ()\n{\n\tvar base, etime, nentities = 0;\n\tvar state, entity;\n\tvar bytag = {}, tagval;\n\tvar header, i, tags;\n\n\tif (g_statesel == undefined)\n\t\treturn;\n\n\tstate = g_statesel.state;\n\ttags = g_statemaps[g_statesel.statemap].tags;\n\n\tvar sum = function (datum, id, span) {\n\t\tvar tid, tag;\n\n\t\tif (!(datum.s instanceof Object)) {\n\t\t\tif (datum.s != state)\n\t\t\t\treturn;\n\t\t} else {\n\t\t\tvar ratio;\n\n\t\t\tif (!(ratio = datum.s[state]))\n\t\t\t\treturn;\n\t\t}\n\n\t\tif (!datum.g)\n\t\t\treturn;\n\n\t\tfor (tid in datum.g) {\n\t\t\ttag = tags[tid];\n\n\t\t\tif (tag.state != state)\n\t\t\t\tcontinue;\n\n\t\t\tif (!(tagval = tag[g_tagsel.tag]))\n\t\t\t\tcontinue;\n\n\t\t\tif (!bytag[tagval])\n\t\t\t\tbytag[tagval] = 0;\n\n\t\t\tbytag[tagval] += span * datum.g[tid];\n\t\t}\n\t};\n\n\tif (!g_tagsel)\n\t\treturn;\n\n\theader = '';\n\n\tif (g_statebar && g_statebar.entity) {\n\t\theader = g_statemaps[g_statesel.statemap].entityKind + ' ' +\n\t\t    g_statebar.entity.name + ' ';\n\t}\n\n\theader += 'by ' + g_tagsel.tag + ' ';\n\n\tif (g_timebar && g_timebar.bar) {\n\t\tbase = g_timebar.time + globals.begin;\n\t\tetime = 0;\n\t\theader += 'at ' + timeunits(g_timebar.time);\n\t} else {\n\t\tbase = timeFromMapX(0) + globals.begin;\n\t\tetime = timeFromMapX(g_width) + globals.begin;\n\t\theader += 'over span';\n\t}\n\n\theader = header.charAt(0).toUpperCase() + header.substr(1) + ':';\n\n\tif (g_statebar && g_statebar.entity) {\n\t\tentityForEachDatum(g_statebar.entity, base, etime, sum);\n\t\tnentities++;\n\t} else {\n\t\t/*\n\t\t * For each entity, we need to determine the amount of time\n\t\t * in our selected state.\n\t\t */\n\t\tfor (entity in g_entities) {\n\t\t\tentityForEachDatum(g_entities[entity],\n\t\t\t    base, etime, sum);\n\t\t\tnentities++;\n\t\t}\n\t}\n\n\tvar sorted = Object.keys(bytag).sort(function (lhs, rhs) {\n\t\tif (bytag[lhs] < bytag[rhs]) {\n\t\t\treturn (1);\n\t\t} else if (bytag[lhs] > bytag[rhs]) {\n\t\t\treturn (-1);\n\t\t} else {\n\t\t\treturn (0);\n\t\t}\n\t});\n\n\tvar divisor;\n\n\tif (etime === 0) {\n\t\tdivisor = nentities;\n\t} else {\n\t\tdivisor = (etime - base) * nentities;\n\t}\n\n\tvar x = g_statesel.x;\n\tvar y = g_statesel.y + 10;\n\n\tvar elem = g_svgDoc.getElementById('statemap-tagbox-select');\n\n\twhile (elem.childNodes.length > 0)\n\t\telem.removeChild(elem.childNodes[0]);\n\n\tif (g_tagvalsel && g_tagvalsel.element)\n\t\tg_tagvalsel.element = undefined;\n\n\tvar text = g_svgDoc.createElementNS(elem.namespaceURI, 'text');\n\ttext.classList.add('statemap-tagbox-select-header');\n\ttext.classList.add('sansserif');\n\n\ttext.appendChild(g_svgDoc.createTextNode(header));\n\ttext.setAttributeNS(null, 'x', x);\n\ttext.setAttributeNS(null, 'y', y);\n\telem.appendChild(text);\n\ty += 9;\n\n\tvar line = g_svgDoc.createElementNS(elem.namespaceURI, 'line');\n\tline.classList.add('statemap-tagbox-select-header-line');\n\tline.x1.baseVal.value = x - 2;\n\tline.y1.baseVal.value = y;\n\tline.x2.baseVal.value = g_statesel.x2;\n\tline.y2.baseVal.value = y;\n\telem.appendChild(line);\n\ty += 18;\n\n\tvar bmargin = 60;\n\tvar ttl = 0;\n\tvar ellipsis = false;\n\n\tvar click = function (tv) {\n\t\treturn (function (evt) { stateselTagvalSelect(evt, tv); });\n\t};\n\n\tfor (i = 0; i <= sorted.length; i++) {\n\t\tvar t, perc;\n\n\t\tif (i < sorted.length) {\n\t\t\tperc = (bytag[sorted[i]] / divisor) * 100.0;\n\t\t\ttagval = sorted[i];\n\t\t\tttl += perc;\n\n\t\t\tif (y > globals.totalHeight - bmargin) {\n\t\t\t\tif (ellipsis)\n\t\t\t\t\tcontinue;\n\n\t\t\t\tellipsis = true;\n\t\t\t\ttagval = '...';\n\t\t\t}\n\t\t} else {\n\t\t\tperc = ttl;\n\t\t\ttagval = 'total';\n\n\t\t\ty -= 5;\n\t\t\tline = g_svgDoc.createElementNS(elem.namespaceURI,\n\t\t\t    'line');\n\t\t\tline.classList.add('statemap-tagbox-select-sum-line');\n\t\t\tline.x1.baseVal.value = x - 2;\n\t\t\tline.y1.baseVal.value = y;\n\t\t\tline.x2.baseVal.value = g_statesel.x2;\n\t\t\tline.y2.baseVal.value = y;\n\t\t\telem.appendChild(line);\n\t\t\ty += 15;\n\t\t}\n\n\t\tif (i != sorted.length && ellipsis) {\n\t\t\tt = '...';\n\t\t} else {\n\t\t\tt = Math.trunc(perc) + '.' +\n\t\t\t    (Math.round(perc * 100) % 100) + '%';\n\t\t}\n\n\t\ttext = g_svgDoc.createElementNS(elem.namespaceURI, 'text');\n\t\ttext.classList.add('statemap-tagbox-select-perc');\n\t\ttext.classList.add('sansserif');\n\t\ttext.appendChild(g_svgDoc.createTextNode(t));\n\t\ttext.setAttributeNS(null, 'x', x + 45);\n\t\ttext.setAttributeNS(null, 'y', y);\n\t\telem.appendChild(text);\n\n\t\ttext = g_svgDoc.createElementNS(elem.namespaceURI, 'text');\n\t\ttext.classList.add('statemap-tagbox-select');\n\t\ttext.classList.add('sansserif');\n\t\ttext.appendChild(g_svgDoc.createTextNode(tagval));\n\t\ttext.setAttributeNS(null, 'x', x + 50);\n\t\ttext.setAttributeNS(null, 'y', y);\n\n\t\t/*\n\t\t * If we already have a tag value selection and it matches\n\t\t * what we're about to display, indicate as much by\n\t\t * highlighting it.\n\t\t */\n\t\tif (g_tagvalsel && g_tagvalsel.tag == g_tagsel.tag &&\n\t\t    g_tagvalsel.tagval == tagval) {\n\t\t\tvar highlight = 'statemap-tagbox-select-highlighted';\n\t\t\ttext.classList.add(highlight);\n\t\t\tg_tagvalsel.element = text;\n\t\t}\n\n\t\ttext.addEventListener('click', click(tagval));\n\n\t\telem.title = t;\n\t\telem.appendChild(text);\n\t\ty += 15;\n\t}\n};\n\nvar stateselTagSelect = function (evt, tag)\n{\n\tvar elem, prefix = 'statemap-tagbox-tag-';\n\n\tif (g_tagsel) {\n\t\telem = g_svgDoc.getElementById(prefix + g_tagsel.tag);\n\t\telem.classList.remove(prefix + 'highlighted');\n\n\t\tif (g_tagsel.tag == tag) {\n\t\t\tg_tagsel = undefined;\n\t\t\tstateselUpdate();\n\t\t\treturn;\n\t\t}\n\t}\n\n\telem = g_svgDoc.getElementById(prefix + tag);\n\telem.classList.add(prefix + 'highlighted');\n\tg_tagsel = { tag: tag };\n\tstateselUpdate();\n};\n\nvar stateselClearTagbox = function ()\n{\n\tvar tagbox = g_svgDoc.getElementById('statemap-tagbox'), elem;\n\n\tif (!tagbox)\n\t\treturn;\n\n\twhile (tagbox.childNodes.length > 0)\n\t\ttagbox.removeChild(tagbox.childNodes[0]);\n\n\telem = g_svgDoc.getElementById('statemap-tagbox-select');\n\n\twhile (elem.childNodes.length > 0)\n\t\telem.removeChild(elem.childNodes[0]);\n};\n\nvar stateselSelect = function (statemap, state)\n{\n\tvar legend = g_svgDoc.getElementById('statemap-legend-' +\n\t    g_statemaps[statemap].legend + '-' + state);\n\tvar states = g_statemaps[statemap].states;\n\tvar alltags = g_statemaps[statemap].tags;\n\tvar tags = {};\n\tvar i, t;\n\tvar lmargin = 20;\n\tvar offset = globals.lmargin + globals.pixelWidth;\n\n\tlegend.classList.add('statemap-legend-highlighted');\n\tstateselClearTagbox();\n\n\tt = 'tags for ' + states[state].name;\n\n\tvar tagbox = g_svgDoc.getElementById('statemap-tagbox');\n\tvar x = offset + lmargin;\n\tvar y = globals.tmargin;\n\tvar x2 = x + (globals.tagWidth - lmargin);\n\n\tvar text = g_svgDoc.createElementNS(tagbox.namespaceURI, 'text');\n\ttext.classList.add('statemap-tagbox-header');\n\ttext.classList.add('sansserif');\n\n\ttext.appendChild(g_svgDoc.createTextNode(t));\n\ttext.setAttributeNS(null, 'x', x);\n\ttext.setAttributeNS(null, 'y', y);\n\ttagbox.appendChild(text);\n\ty += 10;\n\n\tvar line = g_svgDoc.createElementNS(tagbox.namespaceURI, 'line');\n\tline.classList.add('statemap-tagbox-header-line');\n\tline.x1.baseVal.value = x - 2;\n\tline.y1.baseVal.value = y;\n\tline.x2.baseVal.value = x2;\n\tline.y2.baseVal.value = y;\n\ttagbox.appendChild(line);\n\ty += 20;\n\n\t/*\n\t * Now add text for each possible tag for this state.\n\t */\n\tfor (i = 0; i < alltags.length; i++) {\n\t\tif (alltags[i].state !== state)\n\t\t\tcontinue;\n\n\t\tfor (t in alltags[i]) {\n\t\t\tif (t == 'state' || t == 'tag')\n\t\t\t\tcontinue;\n\n\t\t\ttags[t] = true;\n\t\t}\n\t}\n\n\ttags = Object.keys(tags).sort();\n\n\tvar click = function (tag) {\n\t\treturn (function (evt) { stateselTagSelect(evt, tag); });\n\t};\n\n\tfor (i = 0; i < tags.length; i++) {\n\t\ttext = g_svgDoc.createElementNS(tagbox.namespaceURI, 'text');\n\t\ttext.classList.add('statemap-tagbox-tag');\n\t\ttext.classList.add('sansserif');\n\t\ttext.id = 'statemap-tagbox-tag-' + tags[i];\n\n\t\ttext.appendChild(g_svgDoc.createTextNode(tags[i]));\n\t\ttext.setAttributeNS(null, 'x', x);\n\t\ttext.setAttributeNS(null, 'y', y);\n\t\ttext.addEventListener('click', click(tags[i]));\n\n\t\ttagbox.appendChild(text);\n\t\ty += 18;\n\t}\n\n\tg_statesel = { statemap: statemap, state: state, x: x, y: y, x2: x2 };\n\tstateselUpdate();\n};\n\nvar stateselClear = function ()\n{\n\tvar state, statemap, legend;\n\n\tif (g_statesel == undefined)\n\t\treturn (-1);\n\n\tstate = g_statesel.state;\n\tstatemap = g_statesel.statemap;\n\tlegend = g_svgDoc.getElementById('statemap-legend-' +\n\t    statemap + '-' + state);\n\tlegend.classList.remove('statemap-legend-highlighted');\n\n\tstateselClearTagbox();\n\tg_statesel = undefined;\n\tg_tagsel = undefined;\n\n\treturn (state);\n};\n\nvar statemapsUpdate = function ()\n{\n\tvar i;\n\tvar newMatrix = 'matrix(' +  g_transMatrix.join(' ') + ')';\n\n\tfor (i = 0; i < g_statemaps.length; i++) {\n\t\tg_statemaps[i].elem.setAttributeNS(null,\n\t\t    'transform', newMatrix);\n\t}\n};\n\n/*\n * All of the following *click() functions are added at the time of statemap\n * generation.\n */\nvar legendclick = function (evt, statemap, state)\n{\n\tif (globals.notags || stateselClear() == state)\n\t\treturn;\n\n\tstateselSelect(statemap, state);\n\tstateselUpdate();\n};\n\nvar mapclick = function (evt, idx)\n{\n\tvar x = evt.clientX - g_offset;\n\n\tif (evt.shiftKey || evt.altKey) {\n\t\tif (!g_timebar || !g_timebar.bar)\n\t\t\treturn;\n\n\t\ttimebarRemoveSubbar(g_timebar);\n\t\ttimebarCreateSubbar(g_timebar, x, evt.clientY);\n\t\treturn;\n\t}\n\n\ttimebarRemove(g_timebar);\n\tg_timebar = timebarCreate(x);\n\n\tstatebarRemove(g_statebar);\n\tg_statebar = statebarCreate(evt.target, idx);\n\n\tstateselUpdate();\n};\n\nvar panclick = function (dx, dy)\n{\n\tvar minX = -(g_width * g_transMatrix[0] - g_width);\n\tvar minY = -(g_height * g_transMatrix[0] - g_height);\n\n\tg_transMatrix[4] += dx;\n\tg_transMatrix[5] += dy;\n\n\ttimebarHide(g_timebar);\n\n\tif (g_transMatrix[4] > 0)\n\t\tg_transMatrix[4] = 0;\n\n\tif (g_transMatrix[4] < minX)\n\t\tg_transMatrix[4] = minX;\n\n\tif (g_transMatrix[5] > 0)\n\t\tg_transMatrix[5] = 0;\n\n\tif (g_transMatrix[5] < minY)\n\t\tg_transMatrix[5] = minY;\n\n\ttimeSetSpanLabel();\n\tstatemapsUpdate();\n\ttimebarShow(g_timebar);\n\tstateselUpdate();\n};\n\nvar zoomclick = function (scale)\n{\n\tvar i;\n\n\ttimebarHide(g_timebar);\n\n\tfor (i = 0; i < g_transMatrix.length; i++) {\n\t\t/*\n\t\t * We don't scale the Y direction on a zoom.\n\t\t */\n\t\tif (i != 3)\n\t\t\tg_transMatrix[i] *= scale;\n\t}\n\n\tvar minX = -(g_width * g_transMatrix[0] - g_width);\n\tvar minY = -(g_height * g_transMatrix[0] - g_height);\n\n\tg_transMatrix[4] += (1 - scale) * g_width / 2;\n\ttimebarSetMiddle(g_timebar);\n\n\tif (g_transMatrix[4] > 0)\n\t\tg_transMatrix[4] = 0;\n\n\tif (g_transMatrix[4] < minX)\n\t\tg_transMatrix[4] = minX;\n\n\tif (g_transMatrix[5] > 0)\n\t\tg_transMatrix[5] = 0;\n\n\tif (g_transMatrix[5] < minY)\n\t\tg_transMatrix[5] = minY;\n\n\tif (g_transMatrix[0] < 1)\n\t\tg_transMatrix = [1, 0, 0, 1, 0, 0];\n\n\ttimeSetSpanLabel();\n\tstatemapsUpdate();\n\ttimebarShow(g_timebar);\n\tstateselUpdate();\n};\n"
  },
  {
    "path": "src/statemap.rs",
    "content": "/*\n * Copyright 2020 Joyent, Inc. and other contributors\n */ \n\nextern crate memmap;\nextern crate serde;\nextern crate serde_json;\nextern crate natord;\nextern crate palette;\nextern crate rand;\n\n/*\n * The StatemapInput* types denote the structure of the concatenated JSON\n * in the input file.\n */\n#[derive(Deserialize, Debug)]\n#[serde(deny_unknown_fields)]\nstruct StatemapInputState {\n    color: Option<String>,                  // color for state, if any\n    value: usize,                           // value for state\n}\n\n#[derive(Deserialize, Debug)]\n#[serde(deny_unknown_fields)]\nstruct StatemapInputDatum {\n    #[serde(deserialize_with = \"datum_time_from_string\")]\n    time: u64,                              // time of this datum\n    entity: String,                         // name of entity\n    state: u32,                             // state entity is in at time\n    tag: Option<String>,                    // tag for this state, if any\n}\n\n#[derive(Deserialize, Debug)]\n#[serde(deny_unknown_fields)]\nstruct StatemapInputDescription {\n    entity: String,                         // name of entity\n    description: String,                    // description of entity\n}\n\n#[derive(Deserialize, Debug)]\n#[allow(non_snake_case)]\n#[serde(deny_unknown_fields)]\nstruct StatemapInputMetadata {\n    start: Vec<u64>,\n    title: String,\n    host: Option<String>,\n    entityKind: Option<String>,\n    states: HashMap<String, StatemapInputState>,\n}\n\n#[derive(Deserialize, Debug)]\n#[serde(deny_unknown_fields)]\nstruct StatemapInputEvent {\n    time: String,                           // time of this datum\n    entity: String,                         // name of entity\n    event: String,                          // type of event\n    target: Option<String>,                 // target for event, if any\n}\n\n#[derive(Deserialize, Debug)]\nstruct StatemapInputTag {\n    state: u32,                             // state for this tag\n    tag: String,                            // tag itself\n}\n\n#[derive(Copy,Clone,Debug)]\npub struct Config {\n    pub maxrect: u64,                       // maximum number of rectangles\n    pub abstime: bool,                      // time is absolute, not relative\n    pub begin: i64,                         // absolute/relative time to begin\n    pub end: i64,                           // absolute/relative time to end\n    pub notags: bool,                       // do not include tags\n}\n\n/*\n * These fields are dropped directly into the SVG.\n */\n#[derive(Debug,Serialize)]\n#[allow(non_snake_case)]\npub struct StatemapSVGConfig {\n    pub stripHeight: u32,\n    pub legendWidth: u32,\n    pub tagWidth: u32,\n    pub stripWidth: u32,\n    pub background: String,\n    pub sortby: Option<String>,\n    pub stacksortby: Option<String>,\n}\n\n#[derive(Copy,Clone,Debug)]\nstruct StatemapColor {\n    color: Color,                           // underlying color\n}\n\n#[derive(Debug)]\nstruct StatemapRect {\n    start: u64,                             // nanosecond offset\n    duration: u64,                          // nanosecond duration\n    weight: u64,                            // my weight + neighbors\n    states: Vec<u64>,                       // time spent in each state\n    prev: Option<u64>,                      // previous rectangle\n    next: Option<u64>,                      // next rectangle\n    tags: Option<HashMap<usize, u64>>,      // tags, if any\n}\n\n#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]\nstruct StatemapRectWeight {\n    weight: u64,                            // weight for this rect\n    start: u64,                             // start time for this rect\n    entity: usize,                          // entity for this rect\n}\n\n#[derive(Default,Clone,PartialEq,Eq,Debug,Serialize)]\nstruct StatemapState {\n    name: String,                           // name of this state\n    value: usize,                           // value for this state\n    color: Option<String>,                  // color of this state, if any\n}\n\n#[derive(Debug)]\nstruct StatemapEntity {\n    name: String,                           // name of this entity\n    id: usize,                              // identifier\n    description: Option<String>,            // description, if any\n    last: Option<u64>,                      // last start time\n    start: Option<u64>,                     // current start time\n    state: Option<u32>,                     // current state\n    tag: Option<usize>,                     // current tag, if any\n    rects: HashMap<u64, RefCell<StatemapRect>>, // rectangles for this entity\n}\n\n#[derive(Debug)]\npub struct Statemap {\n    config: Config,                         // configuration\n    metadata: Option<StatemapInputMetadata>, // in-stream metadata\n    nrecs: u64,                             // number of records\n    nevents: u64,                           // number of events\n    entities: HashMap<String, StatemapEntity>, // hash of entities\n    states: Vec<StatemapState>,             // vector of valid states\n    byid: Vec<String>,                      // entities by ID\n    byweight: BTreeSet<StatemapRectWeight>, // rectangles by weight\n    tags: HashMap<(u32, String), (Value, usize)>, // tags, if any\n    begin: u64,                             // begin time, as ns since epoch\n    end: u64,                               // end time, as ns since epoch\n    last: u64,                              // last time seen\n}\n\n#[derive(Debug)]\npub struct StatemapError {\n    errmsg: String\n}\n\n#[derive(Serialize)]\n#[allow(non_snake_case)]\nstruct StatemapSVGGlobals<'a> {\n    begin: i64,\n    end: i64,\n    entityPrefix: String,\n    pixelHeight: u32,\n    pixelWidth: u32,\n    totalHeight: u32,\n    timeWidth: u64,\n    lmargin: u32,\n    tmargin: u32,\n    smargin: u32,\n    states: &'a Vec<StatemapState>,\n    start: &'a Vec<u64>,\n    entityKind: &'a str,\n}\n\n#[derive(Serialize)]\n#[allow(non_snake_case)]\nstruct StatemapSVGLocals<'a> {\n    offset: i64,\n    states: &'a Vec<StatemapState>,\n    entityKind: &'a str,\n    title: String,\n}\n\npub struct StatemapSVG<'a> {\n    config: &'a StatemapSVGConfig,\n}\n\nuse std::fs::File;\nuse std::str;\nuse std::error::Error;\nuse std::fmt;\nuse std::collections::HashMap;\nuse std::collections::HashSet;\nuse std::collections::BTreeSet;\nuse std::str::FromStr;\nuse std::cell::RefCell;\nuse std::cmp;\nuse std::path::Path;\n\nuse self::memmap::MmapOptions;\nuse self::palette::{Srgb, Color, Mix};\nuse self::serde_json::Value;\n\nimpl Default for Config {\n    fn default() -> Config {\n        Config { \n            maxrect: 25000,\n            begin: 0,\n            end: 0,\n            notags: false,\n            abstime: false,\n        }\n    }\n}\n\nimpl Default for StatemapSVGConfig {\n    fn default() -> StatemapSVGConfig {\n        StatemapSVGConfig {\n            stripHeight: 10,\n            legendWidth: 138,\n            stripWidth: 862,\n            tagWidth: 250,\n            background: \"#f0f0f0\".to_string(),\n            sortby: None,\n            stacksortby: None,\n        }\n    }\n}\n\nimpl StatemapError {\n    fn new(msg: &str) -> StatemapError {\n        StatemapError { errmsg: msg.to_string() }\n    }\n}\n\nimpl fmt::Display for StatemapError {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        write!(f, \"{}\", self.errmsg)\n    }\n}\n\nimpl Error for StatemapError {\n    fn description(&self) -> &str {\n        &self.errmsg\n    }\n}\n\nimpl FromStr for StatemapColor {\n    type Err = StatemapError;\n\n    fn from_str(name: &str) -> Result<StatemapColor, StatemapError> {\n        let named = palette::named::from_str(name);\n\n        match named {\n            Some(color) => {\n                let rgb = Srgb::<f32>::from_format(color);\n\n                return Ok(StatemapColor {\n                    color: rgb.into_format().into_linear().into()\n                });\n            }\n            None => {}\n        }\n\n        if name.len() == 7 && name.chars().next().unwrap() == '#' {\n            let r = u8::from_str_radix(&name[1..3], 16);\n            let g = u8::from_str_radix(&name[3..5], 16);\n            let b = u8::from_str_radix(&name[5..7], 16);\n\n            if r.is_ok() && g.is_ok() && b.is_ok() {\n                let rgb = Srgb::new(r.unwrap(), g.unwrap(), b.unwrap());\n\n                return Ok(StatemapColor {\n                    color: rgb.into_format().into_linear().into()\n                });\n            }\n        }\n\n        return Err(StatemapError { \n            errmsg: format!(\"\\\"{}\\\" is not a valid color\", name)\n        });\n    }\n}\n\nimpl fmt::Display for StatemapColor {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        let rgb = Srgb::from_linear(self.color.into()).into_components();\n\n        write!(f, \"rgb({}, {}, {})\", (rgb.0 * 256.0) as u8,\n            (rgb.1 * 256.0) as u8, (rgb.2 * 256.0) as u8)\n    }\n}\n\nimpl StatemapColor {\n    fn random() -> Self {\n        let rgb = Srgb::new(rand::random::<u8>(), rand::random::<u8>(),\n            rand::random::<u8>());\n\n        StatemapColor {\n            color: rgb.into_format().into_linear().into()\n        }\n    }\n\n    fn _mix(&self, other: &Self, ratio: f32) -> Self {\n        StatemapColor {\n            color: self.color.mix(&other.color, ratio)\n        }\n    }\n\n    fn mix_nonlinear(&self, other: &Self, ratio: f32) -> Self {\n        let lhs = Srgb::from_linear(self.color.into()).into_components();\n        let rhs = Srgb::from_linear(other.color.into()).into_components();\n\n        let recip = 1.0 - ratio;\n\n        let rgb = Srgb::<f32>::new(lhs.0 as f32 * recip + rhs.0 as f32 * ratio,\n            lhs.1 as f32 * recip + rhs.1 as f32 * ratio,\n            lhs.2 as f32 * recip + rhs.2 as f32 * ratio);\n\n        StatemapColor {\n            color: rgb.into_format().into_linear().into()\n        }\n    }\n}\n\nimpl StatemapRect {\n    fn new(start: u64, duration: u64, state: u32, nstates: u32) -> Self {\n        let mut r = StatemapRect {\n            start: start,\n            duration: duration,\n            states: vec![0; nstates as usize],\n            prev: None,\n            next: None,\n            weight: duration,\n            tags: None,\n        };\n\n        r.states[state as usize] = duration;\n        r\n    }\n}\n\nfn subsume_tags(stags: &mut HashMap<usize, u64>,\n    vtags: &mut HashMap<usize, u64>)\n{\n    for (id, duration) in vtags.drain() {\n        if let Some(d) = stags.get_mut(&id) {\n            *d += duration;\n            continue;\n        }\n\n        stags.insert(id, duration);\n    }\n}\n\nimpl StatemapEntity {\n    fn new(name: &str, id: usize) -> Self {\n        StatemapEntity {\n            name: name.to_string(),\n            start: None,\n            description: None,\n            last: None,\n            state: None,\n            tag: None,\n            rects: HashMap::new(),\n            id: id,\n        }\n    }\n\n    fn newrect(&mut self, end: u64, nstates: u32)\n        -> (Option<(u64, u64, u64)>, (u64, u64))\n    {\n        let start = self.start.unwrap();\n        let state = self.state.unwrap();\n        let lhs: Option<(u64, u64, u64)>;\n        let rhs: (u64, u64);\n        let mut rect = StatemapRect::new(start, end - start, state, nstates);\n\n        match self.tag {\n            Some(id) => {\n                let mut hash: HashMap<usize, u64> = HashMap::new();\n                hash.insert(id, end - start);\n                rect.tags = Some(hash);\n            }\n            _ => {}\n        }\n\n        rect.prev = self.last;\n\n        match self.last {\n            Some(last) => {\n                let mut lrect = self.rects.get(&last).unwrap().borrow_mut();\n                let old = lrect.weight;\n\n                lrect.next = Some(start);\n                rect.weight += lrect.duration;\n                lrect.weight += rect.duration;\n\n                lhs = Some((lrect.start, old, lrect.weight));\n            }\n            _ => { lhs = None; }\n        }\n\n        rhs = (rect.start, rect.weight);\n        self.rects.insert(start, RefCell::new(rect));\n        (lhs, rhs)\n    }\n\n    fn addto(&mut self, rect: u64, delta: u64) -> u64 {\n        let mut r = self.rects.get(&rect).unwrap().borrow_mut();\n        let old = r.weight;\n\n        r.weight += delta;\n        old\n    }\n\n    fn subsume(&mut self, victim: u64)\n        -> ((Option<u64>, u64), (u64, u64), (u64, u64), (Option<u64>, u64))\n    {\n        let mut last = self.last;\n        let subsumed: u64;\n        let rval;\n\n        /*\n         * We return three weights that need to be adjusted: that of the\n         * rectangle to the left (post-subsume), that of the rectangle to\n         * the right (post-subsume) and that of the center rectangle.  Each\n         * of these adjustments is described as a start plus a weight to be\n         * added -- and all three are returned as a tuple that also includes\n         * the subsumed rectangle that needs to be removed.\n         */\n        let ldelta: (Option<u64>, u64);\n        let cdelta: (u64, u64);\n        let rdelta: (Option<u64>, u64);\n\n        /*\n         * We create a scope here to help out the borrow checker in terms of\n         * knowing that our immutable borrow of self.rects is being dropped\n         * before our mutable borrow of it, below.\n         */\n        {\n            let left: &RefCell<StatemapRect>;\n            let right: &RefCell<StatemapRect>;\n\n            /*\n             * We create a scope here to allow the borrow of the victim\n             * cell fall out of scope as we may need it to be mutable, below.\n             */\n            {\n                let vcell = self.rects.get(&victim).unwrap();\n                let v = vcell.borrow();\n\n                match (v.prev, v.next) {\n                    (None, None) => panic!(\"nothing to subsume\"),\n                    (Some(prev), None) => {\n                        left = self.rects.get(&prev).unwrap();\n                        right = vcell;\n\n                        let lref = left.borrow();\n                        ldelta = (lref.prev, v.duration);\n                        cdelta = (lref.start, 0);\n                        rdelta = (None, 0);\n                    }\n                    (None, Some(next)) => {\n                        left = vcell;\n                        right = self.rects.get(&next).unwrap();\n\n                        /*\n                         * We want the weight of the remaining (center)\n                         * rectangle to be the weight of our right rectangle;\n                         * to express this as a delta, we express it as the\n                         * difference between the two.\n                         */\n                        let rref = right.borrow();\n                        ldelta = (None, 0);\n                        cdelta = (v.start, rref.weight - v.weight);\n                        rdelta = (rref.next, v.duration);\n                    }\n                    (Some(prev), Some(next)) => {\n                        /*\n                         * We want whichever of our neighboring rectangles is\n                         * shorter to subsume us.\n                         */\n                        let l = self.rects.get(&prev).unwrap();\n                        let r = self.rects.get(&next).unwrap();\n\n                        let lref = l.borrow();\n                        let rref = r.borrow();\n\n                        if lref.duration < rref.duration {\n                            left = l;\n                            right = vcell;\n\n                            ldelta = (lref.prev, v.duration);\n                            cdelta = (lref.start, v.weight -\n                                (lref.duration + v.duration));\n                            rdelta = (Some(rref.start), lref.duration);\n                        } else {\n                            left = vcell;\n                            right = r;\n\n                            ldelta = (Some(lref.start), rref.duration);\n                            cdelta = (v.start, rref.weight -\n                                (rref.duration + v.duration));\n                            rdelta = (rref.next, v.duration);\n                        }\n                    }\n                }\n            }\n\n            let mut s = left.borrow_mut();\n            let mut v = right.borrow_mut();\n\n            s.next = v.next;\n\n            /*\n             * Set our subsumed next rectangle's previous to point back to us\n             * rather than the subsumed rectangle.\n             */\n            match s.next {\n                Some(next) => {\n                    self.rects.get(&next).unwrap()\n                        .borrow_mut().prev = Some(s.start);\n                }\n                None => {\n                    last = Some(s.start);\n                }\n            }\n\n            /*\n             * Add our duration, and then sum the value in each of the states.\n             */\n            s.duration += v.duration;\n\n            for i in 0..v.states.len() {\n                s.states[i] += v.states[i];\n            }\n\n            /*\n             * If our victim has tags, we need to fold them in.\n             */\n            if v.tags.is_some() && s.tags.is_none() {\n                s.tags = Some(HashMap::new());\n            }\n\n            match s.tags {\n                Some(ref mut stags) => {\n                    match v.tags {\n                        Some(ref mut vtags) => { subsume_tags(stags, vtags); },\n                        None => {}\n                    }\n                },\n                None => {}\n            }\n\n            subsumed = v.start;\n            rval = (v.start, v.weight);\n        }\n\n        /*\n         * Okay, we're done subsuming! We can remove the subsumed rectangle.\n         */\n        self.rects.remove(&subsumed);\n        self.last = last;\n\n        (ldelta, cdelta, rval, rdelta)\n    }\n\n    #[must_use]\n    fn apply(&mut self, deltas: ((Option<u64>, u64),\n        (u64, u64), (u64, u64), (Option<u64>, u64))) ->\n        Vec<(u64, u64, Option<u64>)>\n    {\n        let mut updates: Vec<(u64, u64, Option<u64>)> = vec![];\n\n        /*\n         * Handle the left delta.\n         */\n        match (deltas.0).0 {\n            Some(rect) => {\n                let delta = (deltas.0).1;\n                updates.push((rect, self.addto(rect, delta), Some(delta)));\n            }\n            None => {}\n        }\n\n        /*\n         * Handle the center delta.\n         */\n        let rect = (deltas.1).0;\n        let delta = (deltas.1).1;\n        updates.push((rect, self.addto(rect, delta), Some(delta)));\n\n        /*\n         * Handle the subsumed rectangle by pushing a delta update of None.\n         */\n        updates.push(((deltas.2).0, (deltas.2).1, None));\n\n        /*\n         * And finally, the right delta.\n         */\n        match (deltas.3).0 {\n            Some(rect) => {\n                let delta = (deltas.3).1;\n                updates.push((rect, self.addto(rect, delta), Some(delta)));\n            }\n            None => {}\n        }\n\n        updates\n    }\n\n    fn output_svg(&self, id: usize, begin: i64, config: &StatemapSVGConfig,\n        globals: &StatemapSVGGlobals, locals: &StatemapSVGLocals,\n        colors: &Vec<StatemapColor>, y: u32) -> Vec<String>\n    {\n        let rect_width = |rect: &StatemapRect| -> f64 {\n            /*\n             * We add a fuzz factor to our width to assure it will always be\n             * nearly (but not quite!) half a pixel wider than it should be.\n             * This assures that none of the background (which is deliberately a\n             * bright color) comes through at the border of rectangles, without\n             * losing any accuracy (the next rectangle will tile over ours at\n             * an unadjusted offset).\n             */\n            ((rect.duration as f64 / globals.timeWidth as f64) *\n                globals.pixelWidth as f64) + 0.4 as f64\n        };\n\n        let output_tags = |rect: &StatemapRect, datum: &mut String| {\n            /*\n             * If we have tags, we emit them in ID order.\n             */\n            if let Some(ref tags) = rect.tags {\n                let mut g: Vec<(usize, u64)>;\n\n                datum.push_str(\", g: {\");\n\n                g = tags.iter()\n                    .map(|(&id, &duration)| { (id, duration) })\n                    .collect();\n\n                g.sort_unstable();\n\n                for j in 0..g.len() {\n                    let ratio = g[j].1 as f64 / rect.duration as f64;\n                    datum.push_str(&format!(\"'{}': {:.3}{}\", g[j].0, ratio,\n                        if j < g.len() - 1 { \",\" } else { \"\" }));\n                }\n\n                datum.push_str(\"}\");\n            }\n        };\n\n        let background = |x: f64, width: f64| {\n            if width > 0.0 {\n                println!(r##\"<rect x=\"{}\" y=\"{}\" width=\"{}\"\n                    height=\"{}\" style=\"fill:{}\" />\"##, x, y, width,\n                    config.stripHeight, config.background);\n            }\n        };\n\n        let mut x: f64 = 0.0;\n        let mut map: Vec<i64>;\n        let mut data: Vec<String> = vec![];\n\n        map = self.rects.values().map(|r| r.borrow().start as i64).collect();\n        map.sort();\n\n        if map.len() >= 1 && map[0] > begin {\n            background(0.0, ((map[0] - begin) as f64 /\n                globals.timeWidth as f64) * globals.pixelWidth as f64);\n        }\n\n        println!(r##\"<g id=\"{}{}-{}\"><title>{} {}</title>\"##,\n            globals.entityPrefix, id, self.name, locals.entityKind, self.name);\n\n        for i in 0..map.len() {\n            let rect = self.rects.get(&(map[i] as u64)).unwrap().borrow();\n            let mut state = None;\n            let mut blended = false;\n            let w = rect_width(&rect);\n\n            x = ((map[i] - begin) as f64 /\n                globals.timeWidth as f64) * globals.pixelWidth as f64;\n\n            for j in 0..rect.states.len() {\n                if rect.states[j] != 0 {\n                    match state {\n                        None => { state = Some(j) },\n                        Some(_s) => {\n                            blended = true;\n                            break;\n                        }\n                    }\n                }\n            }\n\n            if !blended {\n                assert!(state.is_some());\n\n                let mut datum = format!(\"{{ \\\"t\\\": {}, \\\"s\\\": {}\", rect.start,\n                    state.unwrap());\n\n                output_tags(&rect, &mut datum);\n                datum.push_str(\"}\");\n                data.push(datum);\n\n                println!(concat!(r##\"<rect x=\"{}\" y=\"{}\" width=\"{}\" \"##,\n                    r##\"height=\"{}\" onclick=\"mapclick(evt, {})\" \"##,\n                    r##\"style=\"fill:{}\" />\"##), x, y, w, config.stripHeight,\n                    data.len() - 1, colors[state.unwrap()]);\n                x += w;\n\n                continue;\n            }\n\n            let max = rect.states.iter().enumerate()\n                .max_by(|&(_, lhs), &(_, rhs)| lhs.cmp(rhs)).unwrap().0;\n\n            let mut color = colors[max];\n            let mut datum = format!(\"{{ t: {}, s: {{ \", rect.start);\n            let mut comma = \"\";\n            \n            for j in 0..rect.states.len() {\n                if rect.states[j] == 0 {\n                    continue;\n                }\n\n                let ratio = rect.states[j] as f64 / rect.duration as f64;\n\n                datum.push_str(&format!(\"{}'{}': {:.3}\", comma, j, ratio));\n                comma = \", \";\n\n                if j != max {\n                    color = color.mix_nonlinear(&colors[j], ratio as f32);\n                }\n            }\n\n            datum.push_str(\"}\");\n\n            output_tags(&rect, &mut datum);\n            datum.push_str(\"}\");\n            data.push(datum);\n\n            println!(concat!(r##\"<rect x=\"{}\" y=\"{}\" width=\"{}\" \"##,\n                r##\"height=\"{}\" onclick=\"mapclick(evt, {})\" \"##,\n                r##\"style=\"fill:{}\" />\"##), x, y, w,\n                config.stripHeight, data.len() - 1, color);\n            x += w;\n        }\n\n        println!(\"</g>\");\n\n        /*\n         * Finally, add a background rectangle that covers whatever remains\n         * of our width.\n         */\n        background(x, globals.pixelWidth as f64 - x);\n\n        data\n    }\n\n    #[cfg(test)]\n    fn print(&self, header: &str) {\n        let mut v: Vec<u64>;\n        let l: usize;\n        \n        v = self.rects.values().map(|r| r.borrow().start).collect();\n        v.sort();\n        l = v.len();\n\n        for i in 0..l {\n            let me = self.rects.get(&v[i]).unwrap().borrow();\n            println!(\"{}: entity={}: [{}] {:?}: {:?}\",\n                header, self.id, i, v[i], me);\n        }\n\n        println!(\"{}: entity={}: last is {:?}\", header, self.id, self.last);\n    }\n\n    #[cfg(test)]\n    fn verify(&self) {\n        let mut v: Vec<u64>;\n        let l: usize;\n        \n        v = self.rects.values().map(|r| r.borrow().start).collect();\n        v.sort();\n        l = v.len();\n\n        for i in 0..l {\n            let me = self.rects.get(&v[i]).unwrap().borrow();\n            let mut weight = me.duration;\n\n            if i < l - 1 {\n                let next = self.rects.get(&v[i + 1]).unwrap().borrow();\n                assert_eq!(me.next, Some(next.start));\n                assert!(me.start < next.start);\n                weight += next.duration;\n            } else {\n                assert_eq!(me.next, None);\n                assert_eq!(self.last, Some(me.start));\n            }\n\n            if i > 0 {\n                let prev = self.rects.get(&v[i - 1]).unwrap().borrow();\n                assert_eq!(me.prev, Some(prev.start));\n                assert!(me.start > prev.start);\n                weight += prev.duration;\n            } else {\n                assert_eq!(me.prev, None);\n            }\n\n            assert_eq!(me.weight, weight);\n\n            if let Some(ref tags) = me.tags {\n                let duration = tags.iter().fold(0,\n                    |i, (_id, duration)| { i + duration });\n\n                /*\n                 * This is technically a more vigorous assertion than we can\n                 * make:  we actually allow for partial tagging in that not\n                 * all states must by tagged all of the time.  For the moment,\n                 * though, we assert that if any states have been tagged, all\n                 * have been.\n                 */\n                assert_eq!(duration, me.duration);\n            }\n        }\n    }\n\n    #[cfg(test)]\n    fn subsume_apply_and_verify(&mut self, victim: u64) ->\n        Vec<(u64, u64, Option<u64>)>\n    {\n        println!(\"=== Subsuming {}\", victim);\n        self.print(&format!(\"Before subsuming {}\", victim));\n        self.verify();\n\n        let tup = self.subsume(victim);\n        println!(\"Weight delta from subsuming {}: {:?}\", victim, tup);\n\n        self.print(&format!(\"After subsuming {}, before applying\", victim));\n        let updates = self.apply(tup);\n\n        self.print(&format!(\"After subsuming {}, after applying\", victim));\n        self.verify();\n        updates\n    }\n}\n\nenum Ingest {\n    Success,\n    EndOfFile,\n}\n\nfn try_parse<'de, T>(content: &mut &'de str)\n    -> Result<Option<T>, serde_json::Error>\nwhere\n    T: serde::Deserialize<'de>\n{\n    let mut de = serde_json::Deserializer::from_str(*content).into_iter();\n    match de.next() {\n        Some(Ok(value)) => {\n            *content = &content[de.byte_offset()..];\n            Ok(Some(value))\n        }\n        Some(Err(err)) => Err(err),\n        None => Ok(None),\n    }\n}\n\nfn try_parse_raw<'de, T>(content: &mut &'de str)\n    -> Result<Option<(T, serde_json::Value)>, serde_json::Error>\nwhere\n    T: serde::Deserialize<'de>\n{\n    let mut de = serde_json::Deserializer::from_str(*content).into_iter();\n    let offset = de.byte_offset();\n\n    match de.next() {\n        Some(Ok(value)) => {\n            let v: serde_json::Value =\n                serde_json::from_str(&content[offset..de.byte_offset()])?;\n\n            *content = &content[de.byte_offset()..];\n\n            Ok(Some((value, v)))\n        }\n        Some(Err(err)) => Err(err),\n        None => Ok(None),\n    }\n}\n\nfn line_number(mmap: &[u8], byte_offset: usize) -> usize {\n    let mut nls = mmap[..byte_offset].iter().filter(|&&b| b == b'\\n').count();\n\n    /*\n     * We report the line number of the first non-whitespace character after\n     * byte_offset.\n     */\n    for b in mmap[byte_offset..].iter() {\n        if *b == b'\\n' {\n            nls += 1;\n        }\n\n        if !((*b as char).is_whitespace()) {\n            break;\n        }\n    }\n\n    nls + 1\n}\n\n/*\n * The time value is written in the input as a JSON string containing a number.\n * Deserialize just the number here without allocating memory for a String.\n */\nfn datum_time_from_string<'de, D>(deserializer: D) -> Result<u64, D::Error>\nwhere\n    D: serde::Deserializer<'de>,\n{\n    let s: &str = serde::Deserialize::deserialize(deserializer)?;\n    match u64::from_str(s) {\n        Ok(time) => Ok(time),\n        Err(_) => Err(serde::de::Error::custom(\"illegal time value\")),\n    }\n}\n\nimpl Statemap {\n    pub fn new(config: &Config) -> Self {\n        Statemap {\n            config: *config,\n            nrecs: 0,\n            nevents: 0,\n            entities: HashMap::new(),\n            states: Vec::new(),\n            byid: Vec::new(),\n            byweight: BTreeSet::new(),\n            metadata: None,\n            tags: HashMap::new(),\n            begin: 0,\n            end: 0,\n            last: 0,\n        }\n    }\n\n    fn err<T>(&self, msg: &str) -> Result<T, Box<dyn Error>>  {\n        Err(Box::new(StatemapError::new(msg)))\n    }\n\n    fn entity_lookup(&mut self, name: &str) -> &mut StatemapEntity {\n        /*\n         * The lack of non-lexical lifetimes causes this code to be a bit\n         * gnarlier than it should really have to be.\n         */\n        if self.entities.contains_key(name) {\n            return match self.entities.get_mut(name) {\n                Some(entity) => { entity },\n                None => unreachable!()\n            };\n        }\n\n        let entity = StatemapEntity::new(name, self.byid.len());\n        self.byid.push(name.to_string());\n\n        self.entities.insert(name.to_string(), entity);\n        self.entities.get_mut(name).unwrap()\n    }\n\n    fn tag_lookup(&mut self, state: u32, tagr: &Option<String>)\n        -> Option<usize>\n    {\n        if self.config.notags {\n            return None;\n        }\n\n        match *tagr {\n            Some(ref tag) => {\n                let id;\n\n                match self.tags.get(&(state, tag.to_string())) {\n                    Some(( _value, idr)) => { return Some(*idr); },\n                    None => { id = self.tags.len(); }\n                }\n\n                let value = json!({ \"state\": state, \"tag\": tag.to_string() });\n\n                self.tags.insert((state, tag.to_string()), (value, id));\n                Some(id)\n            },\n            None => None\n        }\n    }\n\n    /*\n     * Takes a vector of updates to apply to our byweight tree as well as a\n     * template rectangle weight and applies the updates.\n     */\n    fn apply(&mut self, updates: Vec<(u64, u64, Option<u64>)>,\n        rweight: &mut StatemapRectWeight)\n    {\n        for i in 0..updates.len() {\n            rweight.start = updates[i].0;\n            rweight.weight = updates[i].1;\n\n            self.byweight.remove(rweight);\n\n            match updates[i].2 {\n                Some(delta) => {\n                    rweight.weight += delta;\n                    self.byweight.insert(*rweight);\n                }\n                None => {}\n            }\n        }\n    }\n\n    /*\n     * Subsumes the rectangle of least weight, applies the deltas to the\n     * entity corresponding to that rectangle, and then applies the\n     * resulting rectangle weight updates.\n     */\n    fn trim(&mut self) {\n        let mut remove: StatemapRectWeight;\n        let updates;\n\n        remove = *self.byweight.iter().next().unwrap();\n        self.byweight.remove(&remove);\n        \n        /*\n         * We need a scope here to help the compiler out with respect to\n         * our use of entity.\n         */\n        {\n            let name = &self.byid[remove.entity];\n            let entity = self.entities.get_mut(name).unwrap();\n\n            if entity.rects.len() == 1 {\n                /*\n                 * If this entity only has one rectangle, than there is\n                 * nothing to subsume; we simply return.  (This weight has\n                 * already been removed, so we won't find it again until\n                 * another rectangle is added for this entity.)\n                 */\n                return;\n            }\n\n            let deltas = entity.subsume(remove.start);\n            updates = entity.apply(deltas);\n        }\n\n        self.apply(updates, &mut remove);\n    }\n\n    #[must_use]\n    fn sort(&self, sortby: Option<usize>) -> Vec<usize>\n    {\n        let mut v: Vec<(u64, &String, usize)>;\n\n        let values = self.entities.values();\n\n        match sortby {\n            None => { v = values.map(|e| (0, &e.name, e.id)).collect(); },\n            Some(state) => {\n                v = values.map(|e| {\n                    let ttl = e.rects.values().fold(0, |i, r| {\n                        i + r.borrow().states[state]\n                    });\n\n                    (ttl, &e.name, e.id)\n                }).collect();\n            }\n        }\n\n        v.sort_by(|&a, &b| {\n            let result = b.0.cmp(&a.0);\n\n            if result == cmp::Ordering::Equal {\n                natord::compare(a.1, b.1)\n            } else {\n                result\n            }\n        });\n\n        v.iter().map(|e| e.2).collect()\n    }\n\n    /*\n     * Return the total time spent across all entities and all rectangles\n     * in a particular state, for purposes of assigning a weight to the\n     * statemap itself.\n     */\n    fn weight(&self, state: usize) -> u64\n    {\n        self.entities.values().fold(0, |ttl, e| {\n            ttl + e.rects.values().fold(0, |i, r| {\n                i + r.borrow().states[state]\n            })\n        })\n    }\n\n    #[cfg(test)]\n    fn verify(&self) {\n        /*\n         * First, verify each of the entities.\n         */\n        for entity in self.entities.values() {\n            entity.verify();\n        }\n\n        /*\n         * Verify that each rectangle in each entity can be found in our\n         * byweight set -- and that the weights match.\n         */\n        for entity in self.entities.values() {\n            for cell in entity.rects.values() {\n                let rect = cell.borrow();\n\n                let rweight = StatemapRectWeight {\n                    entity: entity.id,\n                    weight: rect.weight,\n                    start: rect.start\n                };\n\n                assert!(self.byweight.contains(&rweight) ||\n                    entity.rects.len() == 1 ||\n                    Some(rect.start) == entity.last ||\n                    rect.next == entity.last);\n            }\n        }\n\n        let mut present = HashSet::new();\n\n        /*\n         * Verify that each entity is valid that each entity/start tuple is\n         * present exactly once.\n         */\n        for rweight in self.byweight.iter() {\n            let name = &self.byid[rweight.entity];\n            let tup = (rweight.entity, rweight.start);\n\n            assert!(self.entities.get(name).is_some());\n\n            let entity = self.entities.get(name).unwrap();\n\n            assert!(entity.rects.get(&rweight.start).is_some());\n            assert!(!present.contains(&tup));\n            present.insert(tup);\n        }\n    }\n\n    #[cfg(test)]\n    fn subsume_apply_and_verify(&mut self, what: &str, victim: u64) {\n        let id: usize;\n        let mut weight: Option<u64> = None;\n        let updates;\n\n    {\n        let entity = self.entity_lookup(what);\n            updates = entity.subsume_apply_and_verify(victim);\n            id = entity.id;\n        }\n\n        /*\n         * Before we verify, remove the victim -- if it wasn't actually\n         * to be removed, we'll add it back when we apply the updates.\n         */\n        for rweight in self.byweight.iter() {\n            if rweight.entity == id && rweight.start == victim {\n                assert!(weight.is_none());\n                weight = Some(rweight.weight);\n            }\n        }\n\n        assert!(weight.is_some());\n\n        let mut rweight = StatemapRectWeight {\n            entity: id, weight: 0, start: 0\n        };\n\n        self.apply(updates, &mut rweight);\n        self.print(&format!(\"After subsuming {} from {}\", victim, what)); \n        self.verify();\n    }\n\n    #[cfg(test)]\n    fn print(&self, header: &str) {\n        println!(\"{}: by weight: {:?}\", header, self.byweight);\n\n        for entity in self.entities.values() {\n            entity.print(header);\n        }\n\n        println!(\"\");\n    }\n\n    #[cfg(test)]\n    fn get_rects(&self, entity: &str) -> Vec<(u64, u64, Vec<u64>)> {\n        let mut rval: Vec<(u64, u64, Vec<u64>)>;\n\n        let e = self.entities.get(entity);\n\n        match e {\n            Some(entity) => {\n                rval = entity.rects.values().map(|r| {\n                    let rect = r.borrow();\n\n                    (rect.start, rect.duration, rect.states.clone())\n                }).collect();\n\n                rval.sort();\n            },\n            None => { rval = vec![]; }\n        }\n\n        rval\n    }\n\n    /*\n     * Ingest and advance `payload` past the metadata JSON object.\n     */\n    fn ingest_metadata(&mut self, payload: &mut &str)\n        -> Result<(), Box<dyn Error>>\n    {\n        let metadata: StatemapInputMetadata = match try_parse(payload)? {\n            None => return self.err(\"missing metadata payload\"),\n            Some(metadata) => metadata,\n        };\n\n        let nstates = metadata.states.len();\n        let mut states: Vec<Option<StatemapState>> = vec![None; nstates];\n\n        if metadata.start.len() != 2 {\n            return self.err(concat!(\"\\\"start\\\" property must be a \",\n                \"two element array\"));\n        }\n\n        for (key, value) in &metadata.states {\n            let ndx = value.value;\n\n            if ndx >= nstates {\n                let errmsg = format!(concat!(\"state \\\"{}\\\" has value ({}) \",\n                    \"that exceeds maximum allowed value ({})\"),\n                    key, ndx, nstates - 1);\n                return self.err(&errmsg);\n            }\n\n            if ndx < states.len() && states[ndx].is_some() {\n                let errmsg = format!(concat!(\"state \\\"{}\\\" has value \",\n                    \"({}) that conflicts with state \\\"{}\\\"\"), key,\n                    ndx, states[ndx].as_ref().unwrap().name);\n\n                return self.err(&errmsg);\n            }\n\n            states[ndx] = Some(StatemapState {\n                name: key.to_string(),\n                value: ndx,\n                color: match value.color {\n                    Some(ref str) => { Some(str.to_string()) },\n                    None => { None }\n                }\n            });\n        }\n\n        assert_eq!(self.states.len(), 0);\n\n        /*\n         * We have verified our states; now pull them into our array.\n         */\n        for _i in 0..nstates {\n            self.states.push(states.remove(0).unwrap());\n        }\n\n        self.metadata = Some(metadata);\n\n        Ok(())\n    }\n\n    fn ingest_end(&mut self) {\n        assert!(!self.config.abstime);\n\n        if self.config.end < 0 {\n            return;\n        }\n\n        let mut end = self.last;\n        let begin = self.config.begin;\n\n        /*\n         * If we've been given an ending time and it's less than the last\n         * rectangle for which we have state, we'll use that.\n         */\n        if self.config.end != 0 && self.config.end < end as i64 {\n            end = self.config.end as u64;\n        }\n\n        let nstates = self.states.len() as u32;\n\n        for entity in self.entities.values_mut() {\n            match entity.start {\n                Some(start) if start < end => {\n                    /*\n                     * If our start time is less than our begin time then\n                     * this entity must be in a single state for our entire\n                     * specified time -- and we move our start time up to our\n                     * begin time (and assert that we have no rectangles).\n                     */\n                    if begin != 0 && (start as i64) < begin {\n                        assert!(entity.rects.is_empty());\n                        entity.start = Some(begin as u64);\n                    }\n\n                    /*\n                     * We are adding a rectangle, but because we are now done\n                     * with ingestion, we are not updating the rectangle weight\n                     * tree and we are not going to subsume any rectangles; we\n                     * can safely ignore the return value.\n                     */\n                    entity.newrect(end, nstates);\n\n                    /*\n                     * Even though we expect no other ingestion, we set our\n                     * last to allow for state to be verified.\n                     */\n                    entity.last = entity.start;\n                },\n                _ => {}\n            }\n        }\n\n        let metadata = self.metadata.as_ref().unwrap();\n        let start = (metadata.start[0] * 1_000_000_000) + metadata.start[1];\n        self.begin = (self.config.begin + start as i64) as u64;\n        self.end = cmp::max(end, self.config.end as u64) + start;\n    }\n\n    /*\n     * Ingest and advance `payload` past one JSON object datum.\n     */\n    fn ingest_datum(&mut self, payload: &mut &str)\n        -> Result<Ingest, Box<dyn Error>>\n    {\n        match try_parse::<StatemapInputDatum>(payload) {\n            Ok(None) => return Ok(Ingest::EndOfFile),\n            Ok(Some(datum)) => {\n                let time: u64 = datum.time;\n                let nstates: u32 = self.states.len() as u32;\n\n                self.last = time;\n\n                /*\n                 * If the time of this datum is after our specified end time,\n                 * we have nothing further to do to process it.\n                 */\n                if self.config.end != 0 && time as i64 > self.config.end {\n                    return Ok(Ingest::Success);\n                }\n\n                if datum.state >= nstates {\n                    return self.err(\"illegal state value\");\n                }\n\n                let begin = self.config.begin;\n                let mut errmsg: Option<String> = None;\n                let mut insert: Option<StatemapRectWeight> = None;\n                let mut update: Option<(StatemapRectWeight, u64)> = None;\n                let tag = self.tag_lookup(datum.state, &datum.tag);\n\n                /*\n                 * We are going to do a lookup of our entity, but this will\n                 * cause us to lose our reference on self (mutable or\n                 * otherwise) -- which we need to fully record any error.  To\n                 * implement this absent non-lexical lifetimes, we put the\n                 * entity in a lexical scope implemented with \"loop\" so we\n                 * can break out of it on an error condition.\n                 */\n                loop {\n                    let name = &datum.entity;\n                    let entity = self.entity_lookup(name);\n\n                    match entity.start {\n                        Some(start) => {\n                            if time < start {\n                                errmsg = Some(format!(concat!(\"time {} is out\",\n                                    \" of order with respect to prior time {}\"),\n                                    time, start));\n                                break;\n                            }\n\n                            if (time as i64) > begin {\n                                /*\n                                 * We can now create a new rectangle for this\n                                 * entity's past state.\n                                 */\n                                if begin > 0 && start < (begin as u64) {\n                                    entity.start = Some(begin as u64);\n                                }\n\n                                let rval = entity.newrect(time, nstates);\n                                entity.last = entity.start;\n\n                                match rval.0 {\n                                    Some(rect) => {\n                                        update = Some((StatemapRectWeight {\n                                            weight: rect.1,\n                                            start: rect.0,\n                                            entity: entity.id\n                                        }, rect.2));\n                                    }\n                                    None => {}\n                                }\n\n                                insert = Some(StatemapRectWeight {\n                                    weight: (rval.1).1,\n                                    start: (rval.1).0,\n                                    entity: entity.id\n                                });\n                            }\n                        }\n                        None => {}\n                    }\n\n                    entity.start = Some(time);\n                    entity.state = Some(datum.state);\n                    entity.tag = tag;\n                    break;\n                }\n\n                if errmsg.is_some() {\n                    return self.err(&errmsg.unwrap());\n                }\n\n                if update.is_some() {\n                    let mut rweight = update.unwrap().0;\n                    self.byweight.remove(&rweight);\n                    rweight.weight = update.unwrap().1;\n                    self.byweight.insert(rweight);\n                }\n\n                if insert.is_some() {\n                    self.byweight.insert(insert.unwrap());\n                }\n\n                return Ok(Ingest::Success);\n            }\n            Err(_) => {}\n        }\n\n        match try_parse::<StatemapInputDescription>(payload) {\n            Ok(None) => return Ok(Ingest::EndOfFile),\n            Ok(Some(datum)) => {\n                let entity = self.entity_lookup(&datum.entity);\n                entity.description = Some(datum.description.to_string());\n\n                return Ok(Ingest::Success);\n            }\n            Err(_) => {}\n        }\n\n        match try_parse::<StatemapInputEvent>(payload) {\n            Ok(None) => return Ok(Ingest::EndOfFile),\n            Ok(Some(_datum)) => {\n                /*\n                 * Right now, we don't do anything with events -- but the\n                 * intent is to be able to render these in the statemap, so\n                 * we also don't reject them.\n                 */\n                self.nevents += 1;\n\n                return Ok(Ingest::Success);\n            }\n            Err(_) => {}\n        }\n\n        match try_parse_raw::<StatemapInputTag>(payload) {\n            Ok(None) => return Ok(Ingest::EndOfFile),\n            Ok(Some((datum, value))) => {\n                if self.config.notags {\n                    return Ok(Ingest::Success);\n                }\n\n                /*\n                 * We allow tags to be redefined, so we need to first lookup\n                 * our tag to see if it exists -- and if it does, we need\n                 * to use the existing ID.\n                 */\n                let id;\n\n                match self.tags.get(&(datum.state, datum.tag.to_string())) {\n                    Some((_value, idr)) => { id = *idr }\n                    None => { id = self.tags.len() }\n                };\n\n                self.tags.insert((datum.state, datum.tag), (value, id));\n\n                return Ok(Ingest::Success);\n\n            }\n            Err(_) => {}\n        }\n\n        self.err(\"unrecognized payload\")\n    }\n\n    pub fn ingest(&mut self, filename: &str) -> Result<(), Box<dyn Error>> {\n        let file = File::open(filename)?;\n        let mut nrecs = 0;\n\n        /*\n         * Unsafe because Rust cannot enforce that the underlying data on\n         * filesystem is not mutated while our program contains a &[u8]\n         * reference to it. Mutating the file would result in undefined\n         * behavior.\n         */\n        let mmap = unsafe { MmapOptions::new().map(&file)? };\n        let mut contents = str::from_utf8(&mmap[..])?;\n        let len = contents.len();\n\n        self.ingest_metadata(&mut contents)?;\n\n        /*\n         * If our time was presented as absolute time, we will now convert it\n         * to be relative to our (now known) start time.\n         */\n        if self.config.abstime {\n            let metadata = self.metadata.as_ref().unwrap();\n            let start = (metadata.start[0] * 1_000_000_000 +\n                metadata.start[1]) as i64;\n\n            self.config.begin -= start;\n            self.config.end -= start;\n            self.config.abstime = false;\n        }\n\n        /*\n         * Now rip through our data pulling out concatenated JSON payloads.\n         */\n        loop {\n            match self.ingest_datum(&mut contents) {\n                Ok(Ingest::Success) => nrecs += 1,\n                Ok(Ingest::EndOfFile) => break,\n                Err(err) => {\n                    /*\n                     * Lazily compute the line number for our error message.\n                     */\n                    let remaining_len = contents.len();\n                    let byte_offset = len - remaining_len;\n                    let line = line_number(&mmap, byte_offset);\n                    let message =\n                        format!(\"illegal datum on line {}: {}\", line, err);\n                    return self.err(&message);\n                }\n            }\n\n            while self.byweight.len() >= self.config.maxrect as usize {\n                self.trim();\n            }\n        }\n        \n        self.ingest_end();\n\n        eprintln!(\"{}: {} records processed, {} rectangles\",\n            Path::new(filename).file_name().unwrap().to_string_lossy(),\n            nrecs, self.byweight.len());\n        Ok(())\n    }\n\n    pub fn timebounds(&self) -> (u64, u64) {\n        (self.begin, self.end)\n    }\n\n    fn output_defs(&self) {\n        /*\n         * Provide an \"entities\" member that has the descriptions for each\n         * entity, if they have one.  Yes, this is a little goofy -- it\n         * would make much more sense to have a \"descriptions\" member that\n         * consists of strings named by entity -- but we're doing this for\n         * the sake of compatibility with the legacy implementation, however\n         * dubious..\n         */\n        println!(\"entities: {{\");\n\n        let mut comma = \"\";\n\n        for entity in self.entities.values() {\n            let val = match entity.description {\n                Some(ref description) => {\n                    format!(\"description: \\\"{}\\\"\", description)\n                }\n                _ => { \"\".to_string() }\n            };\n\n            println!(\"    {} \\\"{}\\\": {{ {} }}\", comma, entity.name, val);\n            comma = \",\";\n        }\n\n        println!(\"}}\");\n\n        if self.tags.len() > 0 {\n            /*\n             * Pull our tags into a Vec so we can sort them and emit them in\n             * array order.\n             */\n            let mut tags: Vec<(usize, u32, &str)> = vec![];\n\n            for ((state, tag), (_value, id)) in self.tags.iter() {\n                tags.push((*id, *state, tag));\n            }\n\n            tags.sort_unstable();\n\n            println!(\", tags: [\");\n\n            for i in 0..tags.len() {\n                let (value, id) =\n                    self.tags.get(&(tags[i].1, tags[i].2.to_string())).unwrap();\n\n                assert_eq!(i, *id);\n                println!(\"{}{}\", serde_json::to_string_pretty(value).unwrap(),\n                    if i < tags.len() - 1 { \",\" } else { \"\" });\n            }\n\n            println!(\"]\");\n        }\n    }\n\n    fn output_svg(&self, id: usize, config: &StatemapSVGConfig,\n        globals: &StatemapSVGGlobals,\n        colors: &Vec<StatemapColor>) -> Result<(), Box<dyn Error>>\n    {\n        let output_data = |data: &HashMap<&String, Vec<String>>| {\n            println!(\"\\\"data\\\": {{ \");\n            let mut comma = \"\";\n\n            for entity in data.keys() {\n                println!(\"{}\\\"{}\\\": [\", comma, entity);\n\n                let datum = data.get(entity).unwrap();\n\n                if datum.len() > 0 {\n                    for i in 0..datum.len() - 1 {\n                        println!(\"{},\", datum[i]);\n                    }\n\n                    println!(\"{}\", datum[datum.len() - 1]);\n                }\n\n                println!(\"]\");\n                comma = \",\";\n            }\n\n            println!(r##\"}},\"##);\n        };\n\n        let metadata = match self.metadata {\n            Some(ref metadata) => { metadata }\n            _ => { return self.err(\"metadata not found in data stream\"); }\n        };\n\n        /*\n         * Sort our entities, by whatever criteria has been specified.\n         */\n        let sort = match config.sortby {\n            None => None,\n            Some(ref sortby) => {\n                if metadata.states.contains_key(sortby) {\n                    Some(metadata.states.get(sortby).unwrap().value)\n                } else {\n                    if sortby == \"entity\" {\n                        /*\n                         * A state of \"entity\" denotes that we should sort\n                         * by entity name.\n                         */\n                        None\n                    } else {\n                        return self.err(&format!(concat!(\"cannot sort by \",\n                            \"state \\\"{}\\\": no such state\"), sortby));\n                    }\n                }\n            }\n        };\n\n        let entities = self.sort(sort);\n\n        println!(r##\"<g id=\"statemap-{}\" transform=\"matrix(1 0 0 1 0 0)\">\"##,\n            id);\n\n        let mut y = 0;\n        let mut data = HashMap::new();\n        let mut title = metadata.title.clone();\n\n        if let Some(ref host) = metadata.host {\n            title.push_str(&format!(\" on {}\", host));\n        }\n\n        let locals = StatemapSVGLocals {\n            offset: self.config.begin - globals.begin,\n            states: &self.states,\n            entityKind: match metadata.entityKind {\n                Some(ref kind) => { kind }\n                None => { \"Entity\" }\n            },\n            title: title,\n        };\n\n        for e in entities {\n            let entity = self.entities.get(self.byid.get(e).unwrap()).unwrap();\n            data.insert(&entity.name, entity.output_svg(id,\n                self.config.begin, config, globals, &locals, &colors, y));\n            y += config.stripHeight;\n        }\n\n        println!(\"</g>\");\n\n        /*\n         * Finally, output our element in the global statemaps array.\n         */\n        println!(\"<defs>\");\n        println!(r##\"<script type=\"application/ecmascript\"><![CDATA[\"##);\n\n        let str = serde_json::to_string_pretty(&locals).unwrap();\n\n        println!(\"g_statemaps[{}] = {{\\n{},\", id, &str[2..str.len() - 2]);\n\n        output_data(&data);\n        self.output_defs();\n\n        println!(r##\"}} ]]></script></defs>\"##);\n\n        Ok(())\n    }\n}\n\nimpl<'a> StatemapSVG<'a> {\n    pub fn new(config: &'a StatemapSVGConfig) -> Self {\n        StatemapSVG {\n            config: config\n        }\n    }\n\n    fn output_defs(&self, globals: &StatemapSVGGlobals)\n    {\n        println!(\"<defs>\");\n\n        println!(\"<script type=\\\"application/ecmascript\\\"><![CDATA[\");\n\n        println!(\"var globals = {{\");\n        let str = serde_json::to_string_pretty(&self.config).unwrap();\n        println!(\"{},\", &str[2..str.len() - 2]);\n\n        let str = serde_json::to_string_pretty(&globals).unwrap();\n        println!(\"{},\", &str[2..str.len() - 2]);\n        println!(\"}}\");\n\n        /*\n         * Now drop in our in-SVG code.\n         */\n        let lib = include_str!(\"statemap-svg.js\");\n\n        println!(\"{}\\n]]></script>\", lib);\n\n        /*\n         * Next up: CSS.\n         */\n        let css = include_str!(\"statemap-svg.css\");\n\n        println!(\"<style type=\\\"text/css\\\"><![CDATA[\\n{}\\n]]></style>\", css);\n\n        /*\n         * And now other definitions.\n         */\n        let defs = include_str!(\"statemap-svg.defs\");\n        println!(\"{}\", defs);\n\n        println!(\"</defs>\");\n    }\n\n    fn title(&self, statemaps: &Vec<Statemap>) -> String\n    {\n        /*\n         * A little helper routine to generate an Oxford comma-separated\n         * list.\n         */\n        let oxford = |v: &Vec<String>| {\n            let map: HashSet<_> = v.iter().collect();\n\n            if map.len() == 1 {\n                v[0].clone()\n            } else if v.len() == 2 {\n                v.join(\" and \")\n            } else {\n                (&v[0..v.len() - 1]).join(\", \") + \", and \" + &v[v.len() - 1]\n            }\n        };\n\n        /*\n         * If we have \"statemap\" anywhere in the title of the first statemap,\n         * we assume it's a legacy title and just use that.\n         */\n        let metadata = statemaps[0].metadata.as_ref().unwrap();\n\n        if metadata.title.find(\"tatemap\").is_some() {\n            return metadata.title.clone();\n        }\n\n        /*\n         * Gather our titles.\n         */\n        let titles = statemaps.iter()\n            .filter_map(|s| s.metadata.as_ref())\n            .map(|m| m.title.to_string())\n            .collect::<Vec<String>>();\n\n        let mut title = vec![\"Statemap of\".to_string(),\n            oxford(&titles), \"activity\".to_string()];\n\n        let hosts = statemaps.iter()\n            .filter_map(|s| s.metadata.as_ref())\n            .filter_map(|m| m.host.as_ref())\n            .map(|r| r.to_string())\n            .collect::<Vec<String>>();\n\n        if hosts.len() > 0 {\n            title.push(\"on\".to_string());\n\n            if hosts.iter().collect::<HashSet<_>>().len() > 5 {\n                title.push(format!(\"{} hosts\", hosts.len()));\n            } else {\n                title.push(oxford(&hosts));\n            }\n        }\n\n        title.join(\" \")\n    }\n\n    pub fn output(&self, statemaps: &Vec<Statemap>) ->\n        Result<(), Box<dyn Error>>\n    {\n        struct Props {\n            x: u32,\n            y: u32,\n            height: u32,\n            width: u32,\n            lheight: u32,\n            spacing: u32\n        };\n\n        let base = &statemaps[0];\n\n        let output_controls = |props: &Props| {\n            let width = props.width / 4;\n            let mut x = 0;\n            let y = 0;\n\n            let icons = vec![\n                (include_str!(\"./icons/arrow-left-l.svg\"), \"panclick(50, 0)\"),\n                (include_str!(\"./icons/zoom-in.svg\"), \"zoomclick(1.25)\"),\n                (include_str!(\"./icons/zoom-out.svg\"), \"zoomclick(0.8)\"),\n                (include_str!(\"./icons/arrow-right-l.svg\"), \"panclick(-50, 0)\")\n            ];\n\n            println!(r##\"<svg x=\"{}px\" y=\"{}px\" width=\"{}px\" height=\"{}px\">\"##,\n                props.x, props.y, props.width, props.height);\n\n            for i in 0..icons.len() {\n                println!(r##\"<svg x=\"{}px\" y=\"{}px\" width=\"{}px\" height=\"{}px\"\n                    onclick=\"{}\"><rect x=\"0px\" y=\"0px\" width=\"{}px\" \n                    height=\"{}px\" onclick=\"{}\" class=\"button\" />{}</svg>\"##,\n                    x, y, width, width, icons[i].1,\n                    width, width, icons[i].1, icons[i].0);\n                x += width;\n            }\n\n            println!(\"</svg>\");\n        };\n\n        let output_legend = |statemap: &Statemap, id: usize,\n            props: &mut Props, colors: &Vec<StatemapColor>|\n        {\n            let x = props.x;\n            let mut y = props.y;\n            let height = props.lheight;\n            let width = props.width;\n\n            for state in 0..statemap.states.len() {\n                println!(concat!(r##\"<rect x=\"{}\" y=\"{}\" width=\"{}\" \"##,\n                    r##\"height=\"{}\" id=\"statemap-legend-{}-{}\" \"##,\n                    r##\"onclick=\"legendclick(evt, {}, {})\" \"##,\n                    r##\"class=\"statemap-legend\" style=\"fill:{}\" />\"##),\n                    x, y, width, height, id, state, id, state, colors[state]);\n                y += height + props.spacing;\n\n                println!(concat!(r##\"<text x=\"{}\" y=\"{}\" \"##,\n                    r##\"class=\"statemap-legendlabel sansserif\">{}</text>\"##),\n                    x + (width / 2), y, statemap.states[state].name);\n                y += props.spacing;\n            }\n\n            props.y = y;\n        };\n\n        let output_tagbox = || {\n            if !base.config.notags {\n                println!(r##\"<g id=\"statemap-tagbox\"></g>\"##);\n                println!(r##\"<g id=\"statemap-tagbox-select\"></g>\"##);\n            }\n        };\n\n        let metadata = match base.metadata {\n            Some(ref metadata) => { metadata }\n            _ => { return base.err(\"metadata not found in data stream\"); }\n        };\n\n        #[allow(non_snake_case)]\n        let timeWidth = base.entities.values().fold(base.config.end,\n            |latest, e| {\n                match e.start {\n                    Some(start) => cmp::max(latest, start as i64),\n                    None => latest\n               }\n            }) - base.config.begin;\n\n        assert!(timeWidth >= 0);\n\n        let lmargin = self.config.legendWidth;\n        let tmargin = 60;\n        let rmargin = self.config.tagWidth;\n        let smargin = self.config.stripHeight;\n        let height: u32;\n\n        let stacked = true;\n\n        if stacked || statemaps.len() == 1 {\n            let nentities = statemaps.iter().fold(0,\n                |total, statemap| { total + statemap.entities.len() });\n\n            height = nentities as u32 * self.config.stripHeight +\n                tmargin + ((statemaps.len() as u32) - 1) * smargin;\n        } else {\n            panic!(\"tabbed statemaps not yet supported\");\n        }\n\n        let width = self.config.stripWidth + lmargin + rmargin;\n\n        let mut props = Props { x: 20, y: tmargin, height: 45,\n            width: lmargin, lheight: 15, spacing: 10 };\n\n        let mut sharedlegend = true;\n        let mut lheight = tmargin + props.height;\n\n        /*\n         * We need to add in our legend height, but to determine this, we\n         * need to see to what degree we will be sharing legends.\n         */\n        for i in 0..statemaps.len() {\n            if i == 0 || statemaps[i].states != statemaps[i - 1].states {\n                lheight += statemaps[i].states.len() as u32 *\n                    (props.lheight + (props.spacing * 2));\n\n                if i > 0 {\n                    lheight += props.spacing * 2;\n                    sharedlegend = false;\n                }\n            }\n        }\n\n        let globals = StatemapSVGGlobals {\n            begin: base.config.begin,\n            end: base.config.end,\n            pixelWidth: self.config.stripWidth,\n            pixelHeight: height - tmargin,\n            totalHeight: cmp::max(height, lheight),\n            timeWidth: timeWidth as u64,\n            lmargin: lmargin,\n            tmargin: tmargin,\n            smargin: smargin,\n            entityPrefix: \"statemap-entity-\".to_string(),\n            states: &base.states,\n            start: &metadata.start,\n            entityKind: match metadata.entityKind {\n                Some(ref kind) => { kind }\n                None => { \"Entity\" }\n            }\n        };\n\n        /*\n         * Make sure that all of our colors are valid.\n         */\n        let mut colors: Vec<Vec<StatemapColor>> = vec![];\n\n        for i in 0..statemaps.len() {\n            for j in 0..statemaps[i].states.len() {\n                colors.push(vec![]);\n\n                match statemaps[i].states[j].color {\n                    Some(ref name) => {\n                        match StatemapColor::from_str(name) {\n                            Ok(color) => colors[i].push(color),\n                            Err(_err) => {\n                                return base.err(&format!(concat!(\"illegal \",\n                                    \"color \\\"{}\\\" for state \\\"{}\\\"\"), name,\n                                    statemaps[i].states[j].name));\n                            }\n                        }\n                    }\n                    None => colors[i].push(StatemapColor::random())\n                }\n            }\n        }\n\n        let sorted: Vec<usize>;\n\n        match self.config.stacksortby {\n            None => { sorted = (0..statemaps.len()).collect(); }\n            Some(ref stacksortby) => {\n                /*\n                 * If we aren't all sharing a legend, this doesn't make sense.\n                 */\n                if !sharedlegend {\n                    return base.err(\"can only stack sort like statemaps\");\n                }\n\n                if !metadata.states.contains_key(stacksortby) {\n                    return base.err(&format!(concat!(\"unknown stack sorting \",\n                        \"state \\\"{}\\\"\"), stacksortby));\n                }\n\n                let sort = metadata.states.get(stacksortby).unwrap().value;\n\n                let mut weights = statemaps.iter()\n                    .map(|s| s.weight(sort))\n                    .enumerate()\n                    .collect::<Vec<(usize, _)>>();\n\n                weights.sort_by(|&(_, l), &(_, r)| r.cmp(&l));\n\n                sorted = weights.iter().map(|&(e, _)| e).collect();\n            }\n        }\n\n        println!(r##\"<?xml version=\"1.0\"?>\n            <!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n                \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n            <svg width=\"{}\" height=\"{}\"\n                xmlns=\"http://www.w3.org/2000/svg\"\n                version=\"1.1\"\n                onload=\"init(evt)\">\"##, width, globals.totalHeight);\n\n        self.output_defs(&globals);\n\n        let mut y = tmargin;\n\n        for i in 0..statemaps.len() {\n            let statemap = &statemaps[sorted[i]];\n\n            let height = statemap.entities.len() as u32 *\n                self.config.stripHeight;\n\n            println!(r##\"<svg x=\"{}px\" y=\"{}px\" width=\"{}px\" height=\"{}px\">\"##,\n                lmargin, y, globals.pixelWidth, height);\n\n            /*\n             * First, we drop down a background rectangle as big as our SVG.\n             * This color will be changed dynamically to be a highlight color,\n             * and then rectangles can be made transparent to become\n             * highlighted.\n             */\n            println!(concat!(r##\"<rect x=\"0px\" y=\"0px\" width=\"{}px\" \"##,\n                r##\"height=\"{}px\" fill=\"{}\" id=\"statemap-{}-highlight\" />\"##),\n                globals.pixelWidth, height, self.config.background, i);\n\n            statemap.output_svg(i, &self.config, &globals, &colors[i])?;\n\n            println!(\"</svg>\");\n\n            /*\n             * The border around this statemap.\n             */\n            println!(r##\"<polygon class=\"statemap-border\"\"##);\n            println!(r##\"  points=\"{} {}, {} {}, {} {}, {} {}\"/>\"##,\n                lmargin, y, lmargin + globals.pixelWidth, y,\n                lmargin + globals.pixelWidth, y + height, lmargin, y + height);\n\n            y += height + smargin;\n        }\n\n        println!(concat!(r##\"<text x=\"{}\" y=\"{}\" \"##,\n            r##\"class=\"statemap-title sansserif\">{}</text>\"##),\n            lmargin + (globals.pixelWidth / 2), 16,\n            self.title(statemaps));\n\n        println!(concat!(r##\"<text x=\"{}\" y=\"{}\" class=\"statemap-timelabel\"##,\n            r##\" sansserif\" id=\"statemap-timelabel\"></text>\"##),\n            lmargin + (globals.pixelWidth / 2), 34);\n\n        println!(r##\"<line x1=\"{}\" y1=\"{}\" x2=\"{}\" y2=\"{}\"\"##,\n            lmargin + 10, 40, lmargin + globals.pixelWidth - 10, 40);\n        println!(r##\"class=\"statemap-timeline\" />\"##);\n\n        props.width -= (2 * props.x) + 10;\n\n        output_controls(&props);\n\n        props.y += props.height;\n\n        for i in 0..statemaps.len() {\n            if i == 0 || statemaps[i].states != statemaps[i - 1].states {\n                output_legend(&statemaps[i], i, &mut props, &colors[i]);\n            }\n\n            if !sharedlegend {\n                props.y += props.spacing * 2;\n            }\n        }\n\n        output_tagbox();\n\n        println!(\"</svg>\");\n\n        Ok(())\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use std::env;\n    use std::process;\n    use std::fs;\n    use std::io::Write;\n\n    fn metadata(config: Option<&Config>, mut metadata: &str) -> Statemap {\n        let mut statemap;\n\n        match config {\n            Some(config) => { statemap = Statemap::new(&config); },\n            None => {\n                let config: Config = Default::default();\n                statemap = Statemap::new(&config);\n            }\n        }\n\n        match statemap.ingest_metadata(&mut metadata) {\n            Err(err) => { panic!(\"metadata incorrectly failed: {:?}\", err); }\n            Ok(_) => { statemap }\n        }\n    }\n\n    fn minimal(config: Option<&Config>) -> Statemap {\n        metadata(config, r##\"{\n            \"start\": [ 0, 0 ],\n            \"title\": \"Foo\",\n            \"states\": {\n                \"zero\": {\"value\": 0 },\n                \"one\": {\"value\": 1 }\n            }\n        }\"##)\n    }\n\n    fn data(config: Option<&Config>, data: Vec<&str>) -> Statemap {\n        let mut statemap = minimal(config);\n\n        for mut datum in data {\n            match statemap.ingest_datum(&mut datum) {\n                Err(err) => { panic!(\"data incorrectly failed: {:?}\", err); }\n                Ok(_) => {}\n            }\n        }\n\n        statemap.ingest_end();\n        statemap\n    }\n\n    fn bad_metadata(mut metadata: &str, expected: &str) {\n        let config: Config = Default::default();\n        let mut statemap = Statemap::new(&config);\n\n        match statemap.ingest_metadata(&mut metadata) {\n            Err(err) => {\n                let errmsg = format!(\"{}\", err);\n\n                if errmsg.find(expected).is_none() {\n                    panic!(\"error ('{}') did not contain '{}' as expected\",\n                        errmsg, expected);\n                }\n            },\n            Ok(_) => { panic!(\"bad metadata succeeded!\"); }\n        }\n    }\n\n    fn bad_datum(operand: Option<Statemap>, mut datum: &str, expected: &str) {\n        let mut statemap = match operand {\n            Some(statemap) => statemap,\n            None => {\n                metadata(None, r##\"{\n                    \"start\": [ 0, 0 ],\n                    \"title\": \"Foo\",\n                    \"states\": {\n                        \"zero\": {\"value\": 0 },\n                        \"one\": {\"value\": 1 }\n                    }\n                }\"##)\n            }\n        };\n\n        match statemap.ingest_datum(&mut datum) {\n            Err(err) => {\n                let errmsg = format!(\"{}\", err);\n\n                if errmsg.find(expected).is_none() {\n                    panic!(\"error ('{}') did not contain '{}' as expected\",\n                        errmsg, expected);\n                }\n            },\n            Ok(_) => { panic!(\"bad datum succeeded!\"); }\n        }\n    }\n\n    fn statemap_ingest(statemap: &mut Statemap, raw: &str)\n        -> Result<(), Box<Error>>\n    {\n        let mut path = env::temp_dir();\n        path.push(format!(\"statemap.test.{}.{:p}\", process::id(), statemap));\n\n        let filename = path.to_str().unwrap();\n        let mut file = File::create(filename)?;\n        file.write_all(raw.as_bytes())?;\n\n        let result = statemap.ingest(filename);\n\n        fs::remove_file(filename)?;\n\n        result\n    }\n\n    fn bad_statemap(raw: &str, expected: &str) {\n        let config: Config = Default::default();\n        let mut statemap = Statemap::new(&config);\n\n        match statemap_ingest(&mut statemap, raw) {\n            Err(err) => {\n                let errmsg = format!(\"{}\\n\", err);\n\n                if errmsg.find(expected).is_none() {\n                    panic!(\"error ('{}') did not contain '{}' as expected\",\n                        errmsg, expected);\n                }\n            },\n            Ok(_) => { panic!(\"bad statemap succeeded!\"); }\n        }\n    }\n\n    macro_rules! bad_statemap {\n        ($what:expr) => ({\n            bad_statemap(include_str!(concat!(\"../tst/tst.\", $what, \".in\")),\n                include_str!(concat!(\"../tst/tst.\", $what, \".err\")));\n        });\n    }\n\n    fn good_statemap(config: &Config, raw: &str) -> Statemap {\n        let mut statemap = Statemap::new(&config);\n\n        match statemap_ingest(&mut statemap, raw) {\n            Err(err) => {\n                panic!(\"statemap failed: {}\", err);\n            },\n            Ok(_) => { statemap }\n        }\n    }\n\n    macro_rules! good_statemap {\n        ($what:expr) => ({\n            let mut config: Config = Default::default();\n            config.notags = false;\n\n            good_statemap(&config,\n                include_str!(concat!(\"../tst/tst.\", $what, \".in\")))\n        });\n\n        ($what:expr, $conf:expr) => ({\n            good_statemap($conf,\n                include_str!(concat!(\"../tst/tst.\", $what, \".in\")))\n        });\n    }\n\n    #[test]\n    fn good_minimal() {\n        metadata(None, r##\"{\n            \"start\": [ 0, 0 ],\n            \"title\": \"Foo\",\n            \"states\": {\n                \"zero\": {\"value\": 0 }\n            }\n        }\"##);\n    }\n\n    #[test]\n    fn bad_title_missing() {\n        bad_metadata(r##\"{\n            \"start\": [ 0, 0 ],\n            \"states\": {\n                \"zero\": {\"value\": 0 }\n            }\n        }\"##, \"missing field `title`\");\n    }\n\n    #[test]\n    fn bad_start_missing() {\n        bad_metadata(r##\"{\n            \"title\": \"Foo\",\n            \"states\": {\n                \"zero\": {\"value\": 0 }\n            }\n        }\"##, \"missing field `start`\");\n    }\n\n    #[test]\n    fn bad_start_badval() {\n        bad_metadata(r##\"{\n            \"start\": [ -1, 0 ],\n            \"title\": \"Foo\",\n            \"states\": {\n                \"zero\": {\"value\": 0 }\n            }\n        }\"##, \"invalid value: integer `-1`\");\n    }\n\n    #[test]\n    fn bad_start_tooshort() {\n        bad_metadata(r##\"{\n            \"start\": [ 0 ],\n            \"title\": \"Foo\",\n            \"states\": {\n                \"zero\": {\"value\": 0 }\n            }\n        }\"##, \"\\\"start\\\" property must be a two element array\");\n    }\n\n    #[test]\n    fn bad_start_toolong() {\n        bad_metadata(r##\"{\n            \"start\": [ 0, 0, 3 ],\n            \"title\": \"Foo\",\n            \"states\": {\n                \"zero\": {\"value\": 0 }\n            }\n        }\"##, \"\\\"start\\\" property must be a two element array\");\n    }\n\n    #[test]\n    fn bad_states_missing() {\n        bad_metadata(r##\"{\n            \"start\": [ 0, 0 ],\n            \"title\": \"Foo\"\n        }\"##, \"missing field `states`\");\n    }\n\n    #[test]\n    fn bad_states_badmap() {\n        bad_metadata(r##\"{\n            \"start\": [ 0, 0 ],\n            \"title\": \"Foo\",\n            \"states\": 123\n        }\"##, \"expected a map\");\n    }\n\n    #[test]\n    fn bad_states_value_missing() {\n        bad_metadata(r##\"{\n            \"start\": [ 0, 0 ],\n            \"title\": \"Foo\",\n            \"states\": {\n                \"zero\": {}\n            }\n        }\"##, \"missing field `value`\");\n    }\n\n    #[test]\n    fn bad_states_value_bad() {\n        bad_metadata(r##\"{\n            \"start\": [ 0, 0 ],\n            \"title\": \"Foo\",\n            \"states\": {\n                \"zero\": {\"value\": -1 }\n            }\n        }\"##, \"invalid value: integer `-1`\");\n    }\n\n    #[test]\n    fn bad_states_value_skipped1() {\n        bad_metadata(r##\"{\n            \"start\": [ 0, 0 ],\n            \"title\": \"Foo\",\n            \"states\": {\n                \"zero\": {\"value\": 0 },\n                \"one\": {\"value\": 2 }\n            }\n        }\"##, \"state \\\"one\\\" has value (2) that exceeds maximum\");\n    }\n\n    #[test]\n    fn bad_states_value_toohigh() {\n        bad_metadata(r##\"{\n            \"start\": [ 0, 0 ],\n            \"title\": \"Foo\",\n            \"states\": {\n                \"zero\": {\"value\": 1 },\n                \"one\": {\"value\": 2 }\n            }\n        }\"##, \"state \\\"one\\\" has value (2) that exceeds maximum\");\n    }\n\n    #[test]\n    fn bad_states_value_duplicate() {\n        bad_metadata(r##\"{\n            \"start\": [ 0, 0 ],\n            \"title\": \"Foo\",\n            \"states\": {\n                \"zero\": {\"value\": 1 },\n                \"one\": {\"value\": 1 }\n            }\n        }\"##, \"has value (1) that conflicts\");\n    }\n\n    #[test]\n    fn bad_line_basic() {\n        bad_statemap!(\"bad_line_basic\");\n    }\n\n    #[test]\n    fn bad_line_whitespace() {\n        bad_statemap!(\"bad_line_whitespace\");\n    }\n\n    #[test]\n    fn bad_line_newline() {\n        bad_statemap!(\"bad_line_newline\");\n    }\n\n    #[test]\n    fn basic() {\n        let statemap = metadata(None, r##\"{\n            \"start\": [ 1528417173, 255882937 ],\n            \"title\": \"Foo\",\n            \"host\": \"HA8S7MRD2\",\n            \"entityKind\": \"Process\",\n            \"states\": {\n                \"on-cpu\": {\"value\": 0, \"color\": \"#2e9107\" },\n                \"off-cpu-waiting\": {\"value\": 1, \"color\": \"#f9f9f9\" },\n                \"off-cpu-semop\": {\"value\": 2, \"color\": \"#FF5733\" },\n                \"off-cpu-blocked\": {\"value\": 3, \"color\": \"#C70039\" },\n                \"off-cpu-zfs-read\": {\"value\": 4, \"color\": \"#FFC300\" },\n                \"off-cpu-zfs-write\": {\"value\": 5, \"color\": \"#338AFF\" },\n                \"off-cpu-zil-commit\": {\"value\": 6, \"color\": \"#66FFCC\" },\n                \"off-cpu-tx-delay\": {\"value\": 7, \"color\": \"#e1ff00\" },\n                \"off-cpu-dead\": {\"value\": 8, \"color\": \"#E0E0E0\" }\n            }\n        }\"##);\n        assert_eq!(statemap.states.len(), 9);\n        assert_eq!(statemap.states[0].name, \"on-cpu\");\n        assert_eq!(statemap.states[0].color, Some(\"#2e9107\".to_string()));\n        assert_eq!(statemap.states[1].name, \"off-cpu-waiting\");\n        assert_eq!(statemap.states[1].color, Some(\"#f9f9f9\".to_string()));\n        assert_eq!(statemap.states[8].name, \"off-cpu-dead\");\n    }\n\n    #[test]\n    fn basic_datum() {\n        let mut _statemap = data(None, vec![\n            r##\"{ \"time\": \"156683\", \"entity\": \"foo\", \"state\": 0 }\"##\n        ]);\n    }\n\n    #[test]\n    fn basic_description() {\n        let mut statemap = data(None, vec![\n            r##\"{ \"time\": \"156683\", \"entity\": \"foo\", \"state\": 0 }\"##,\n            r##\"{ \"entity\": \"foo\", \"description\": \"This is a foo!\" }\"##\n        ]);\n\n        assert_eq!(statemap.entity_lookup(\"foo\").description,\n            Some(\"This is a foo!\".to_string()));\n    }\n\n    #[test]\n    fn bad_datum_badtime() {\n        bad_datum(None, r##\"\n            { \"time\": 156683, \"entity\": \"foo\", \"state\": 0 }\n        \"##, \"unrecognized payload\");\n    }\n\n    #[test]\n    fn bad_datum_badtime_float() {\n        bad_datum(None, r##\"\n            { \"time\": \"156683.12\", \"entity\": \"foo\", \"state\": 0 }\n        \"##, \"unrecognized payload\");\n    }\n\n    #[test]\n    fn bad_datum_nostate() {\n        bad_datum(None, r##\"\n            { \"time\": \"156683\", \"entity\": \"foo\" }\n        \"##, \"unrecognized payload\");\n    }\n\n    #[test]\n    fn bad_datum_badstate() {\n        bad_datum(None, r##\"\n            { \"time\": \"156683\", \"entity\": \"foo\", \"state\": 200 }\n        \"##, \"illegal state value\");\n    }\n\n    #[test]\n    fn bad_datum_backwards() {\n        let statemap = data(None, vec![\n            r##\"{ \"time\": \"156683\", \"entity\": \"foo\", \"state\": 0 }\"##\n        ]);\n\n        bad_datum(Some(statemap), r##\"\n            { \"time\": \"156682\", \"entity\": \"foo\", \"state\": 1 }\n        \"##, \"out of order with respect to prior time\");\n    }\n\n    #[test]\n    fn basic_data() {\n        let statemap = data(None, vec![\n            r##\"{ \"time\": \"100000\", \"entity\": \"foo\", \"state\": 0 }\"##,\n            r##\"{ \"time\": \"200000\", \"entity\": \"foo\", \"state\": 1 }\"##,\n            r##\"{ \"time\": \"300000\", \"entity\": \"foo\", \"state\": 0 }\"##,\n            r##\"{ \"time\": \"400000\", \"entity\": \"foo\", \"state\": 1 }\"##,\n            r##\"{ \"time\": \"500000\", \"entity\": \"foo\", \"state\": 0 }\"##,\n            r##\"{ \"time\": \"600000\", \"entity\": \"foo\", \"state\": 1 }\"##\n        ]);\n\n        statemap.verify();\n    }\n\n    #[test]\n    fn subsume() {\n        let mut statemap = data(None, vec![\n            r##\"{ \"time\": \"100000\", \"entity\": \"foo\", \"state\": 0 }\"##,\n            r##\"{ \"time\": \"200000\", \"entity\": \"foo\", \"state\": 1 }\"##,\n            r##\"{ \"time\": \"300000\", \"entity\": \"foo\", \"state\": 0 }\"##,\n            r##\"{ \"time\": \"400000\", \"entity\": \"foo\", \"state\": 1 }\"##,\n            r##\"{ \"time\": \"500000\", \"entity\": \"foo\", \"state\": 0 }\"##,\n            r##\"{ \"time\": \"600000\", \"entity\": \"foo\", \"state\": 1 }\"##\n        ]);\n\n        statemap.print(\"Initial load\");\n        statemap.verify();\n        statemap.subsume_apply_and_verify(\"foo\", 100000);\n        statemap.subsume_apply_and_verify(\"foo\", 300000);\n        statemap.subsume_apply_and_verify(\"foo\", 100000);\n    }\n\n    #[test]\n    fn subsume_right() {\n        let mut statemap = data(None, vec![\n            r##\"{ \"time\": \"100000\", \"entity\": \"foo\", \"state\": 0 }\"##,\n            r##\"{ \"time\": \"200000\", \"entity\": \"foo\", \"state\": 1 }\"##,\n            r##\"{ \"time\": \"300000\", \"entity\": \"foo\", \"state\": 0 }\"##,\n            r##\"{ \"time\": \"400000\", \"entity\": \"foo\", \"state\": 1 }\"##,\n            r##\"{ \"time\": \"500000\", \"entity\": \"foo\", \"state\": 0 }\"##,\n            r##\"{ \"time\": \"600000\", \"entity\": \"foo\", \"state\": 1 }\"##\n        ]);\n\n        statemap.print(\"Initial load\");\n        statemap.verify();\n\n        statemap.subsume_apply_and_verify(\"foo\", 500000);\n        statemap.subsume_apply_and_verify(\"foo\", 400000);\n        statemap.subsume_apply_and_verify(\"foo\", 300000);\n        statemap.subsume_apply_and_verify(\"foo\", 200000);\n    }\n\n    #[test]\n    fn subsume_middle() {\n        let mut statemap = data(None, vec![\n            r##\"{ \"time\": \"100000\", \"entity\": \"foo\", \"state\": 0 }\"##,\n            r##\"{ \"time\": \"200000\", \"entity\": \"foo\", \"state\": 1 }\"##,\n            r##\"{ \"time\": \"300000\", \"entity\": \"foo\", \"state\": 0 }\"##,\n            r##\"{ \"time\": \"400000\", \"entity\": \"foo\", \"state\": 1 }\"##,\n            r##\"{ \"time\": \"500000\", \"entity\": \"foo\", \"state\": 0 }\"##,\n            r##\"{ \"time\": \"600000\", \"entity\": \"foo\", \"state\": 1 }\"##\n        ]);\n\n        statemap.print(\"Initial load\");\n        statemap.verify();\n        statemap.subsume_apply_and_verify(\"foo\", 300000);\n        statemap.subsume_apply_and_verify(\"foo\", 300000);\n        statemap.subsume_apply_and_verify(\"foo\", 200000);\n    }\n\n    #[test]\n    fn subsume_tagged() {\n        let mut statemap = data(None, vec![\n            r##\"{ \"time\": \"100\", \"entity\": \"foo\", \"state\": 0, \"tag\": \"a\" }\"##,\n            r##\"{ \"time\": \"200\", \"entity\": \"foo\", \"state\": 1, \"tag\": \"b\" }\"##,\n            r##\"{ \"time\": \"300\", \"entity\": \"foo\", \"state\": 0, \"tag\": \"c\" }\"##,\n            r##\"{ \"time\": \"400\", \"entity\": \"foo\", \"state\": 1, \"tag\": \"b\" }\"##,\n            r##\"{ \"time\": \"500\", \"entity\": \"foo\", \"state\": 0, \"tag\": \"a\" }\"##,\n            r##\"{ \"time\": \"600\", \"entity\": \"foo\", \"state\": 1, \"tag\": \"b\" }\"##\n        ]);\n\n        statemap.print(\"Initial load\");\n        statemap.verify();\n        statemap.subsume_apply_and_verify(\"foo\", 100);\n        statemap.subsume_apply_and_verify(\"foo\", 300);\n        statemap.subsume_apply_and_verify(\"foo\", 100);\n    }\n\n    #[test]\n    fn trim() {\n        let mut statemap = data(None, vec![\n            r##\"{ \"time\": \"0\", \"entity\": \"foo\", \"state\": 0 }\"##,\n            r##\"{ \"time\": \"100\", \"entity\": \"foo\", \"state\": 1 }\"##,\n            r##\"{ \"time\": \"101\", \"entity\": \"foo\", \"state\": 0 }\"##,\n            r##\"{ \"time\": \"104\", \"entity\": \"foo\", \"state\": 1 }\"##,\n            r##\"{ \"time\": \"106\", \"entity\": \"foo\", \"state\": 0 }\"##,\n            r##\"{ \"time\": \"206\", \"entity\": \"foo\", \"state\": 1 }\"##,\n            r##\"{ \"time\": \"207\", \"entity\": \"foo\", \"state\": 0 }\"##\n        ]);\n\n        statemap.print(\"Initial\");\n\n        statemap.trim();\n        statemap.verify();\n        statemap.print(\"After first trim\");\n\n        statemap.trim();\n        statemap.verify();\n        statemap.print(\"After second trim\");\n\n        statemap.trim();\n        statemap.verify();\n        statemap.print(\"After third trim\");\n    }\n\n    #[test]\n    fn trim_insert() {\n        let mut statemap = data(None, vec![\n            r##\"{ \"time\": \"0\", \"entity\": \"foo\", \"state\": 0 }\"##,\n            r##\"{ \"time\": \"100\", \"entity\": \"foo\", \"state\": 1 }\"##,\n            r##\"{ \"time\": \"101\", \"entity\": \"foo\", \"state\": 0 }\"##,\n            r##\"{ \"time\": \"104\", \"entity\": \"foo\", \"state\": 1 }\"##,\n            r##\"{ \"time\": \"106\", \"entity\": \"foo\", \"state\": 0 }\"##,\n            r##\"{ \"time\": \"206\", \"entity\": \"foo\", \"state\": 1 }\"##,\n            r##\"{ \"time\": \"207\", \"entity\": \"foo\", \"state\": 0 }\"##\n        ]);\n\n        statemap.print(\"Initial\");\n\n        statemap.trim();\n        statemap.verify();\n        statemap.print(\"After first trim\");\n\n        let mut datum = r##\"{ \"time\": \"210\", \"entity\": \"foo\", \"state\": 1 }\"##;\n\n        assert!(statemap.ingest_datum(&mut datum).is_ok());\n        statemap.verify();\n        statemap.print(\"After insert\");\n\n        statemap.trim();\n        statemap.verify();\n        statemap.print(\"After second trim\");\n    }\n\n    #[test]\n    fn trim_multient() {\n        let mut statemap = data(None, vec![\n            r##\"{ \"time\": \"0\", \"entity\": \"foo\", \"state\": 0 }\"##,\n            r##\"{ \"time\": \"1000\", \"entity\": \"foo\", \"state\": 1 }\"##,\n            r##\"{ \"time\": \"1010\", \"entity\": \"foo\", \"state\": 0 }\"##,\n            r##\"{ \"time\": \"1040\", \"entity\": \"foo\", \"state\": 1 }\"##,\n            r##\"{ \"time\": \"1060\", \"entity\": \"foo\", \"state\": 0 }\"##,\n            r##\"{ \"time\": \"2060\", \"entity\": \"foo\", \"state\": 1 }\"##,\n            r##\"{ \"time\": \"2070\", \"entity\": \"foo\", \"state\": 0 }\"##,\n            r##\"{ \"time\": \"0\", \"entity\": \"bar\", \"state\": 0 }\"##,\n            r##\"{ \"time\": \"10\", \"entity\": \"bar\", \"state\": 1 }\"##,\n        ]);\n\n        statemap.print(\"Initial\");\n\n        statemap.trim();\n        statemap.verify();\n        statemap.print(\"After trim\");\n    }\n\n    #[test]\n    fn data_begin_time() {\n        let mut config: Config = Default::default();\n        config.begin = 200000;\n\n        let statemap = data(Some(&config), vec![\n            r##\"{ \"time\": \"100000\", \"entity\": \"foo\", \"state\": 0 }\"##,\n            r##\"{ \"time\": \"200000\", \"entity\": \"foo\", \"state\": 1 }\"##,\n            r##\"{ \"time\": \"300000\", \"entity\": \"foo\", \"state\": 0 }\"##,\n            r##\"{ \"time\": \"400000\", \"entity\": \"foo\", \"state\": 1 }\"##,\n            r##\"{ \"time\": \"500000\", \"entity\": \"foo\", \"state\": 0 }\"##,\n            r##\"{ \"time\": \"600000\", \"entity\": \"foo\", \"state\": 1 }\"##\n        ]);\n\n        statemap.verify();\n        statemap.print(\"Begin at 200000\");\n\n        let rects = statemap.get_rects(\"foo\");\n        assert_eq!(rects.len(), 4);\n        assert_eq!(rects[0].0, 200000);\n        assert_eq!(rects[0].1, 300000 - 200000);\n    }\n\n    #[test]\n    fn data_begin_time_later() {\n        let mut config: Config = Default::default();\n        config.begin = 200001;\n\n        let statemap = data(Some(&config), vec![\n            r##\"{ \"time\": \"100000\", \"entity\": \"foo\", \"state\": 0 }\"##,\n            r##\"{ \"time\": \"200000\", \"entity\": \"foo\", \"state\": 1 }\"##,\n            r##\"{ \"time\": \"300000\", \"entity\": \"foo\", \"state\": 0 }\"##,\n            r##\"{ \"time\": \"400000\", \"entity\": \"foo\", \"state\": 1 }\"##,\n            r##\"{ \"time\": \"500000\", \"entity\": \"foo\", \"state\": 0 }\"##,\n            r##\"{ \"time\": \"600000\", \"entity\": \"foo\", \"state\": 1 }\"##\n        ]);\n\n        statemap.verify();\n        statemap.print(\"Begin at 200001\");\n\n        let rects = statemap.get_rects(\"foo\");\n        assert_eq!(rects.len(), 4);\n        assert_eq!(rects[0].0, 200001);\n        assert_eq!(rects[0].1, 300000 - 200001);\n        assert_eq!((rects[0].2)[0], 0);\n        assert_eq!((rects[0].2)[1], 300000 - 200001);\n    }\n\n    #[test]\n    fn data_begin_end_time() {\n        let mut config: Config = Default::default();\n        config.begin = 250000;\n        config.end = 310000;\n\n        let statemap = data(Some(&config), vec![\n            r##\"{ \"time\": \"100000\", \"entity\": \"foo\", \"state\": 0 }\"##,\n            r##\"{ \"time\": \"200000\", \"entity\": \"foo\", \"state\": 1 }\"##,\n            r##\"{ \"time\": \"300000\", \"entity\": \"foo\", \"state\": 0 }\"##,\n            r##\"{ \"time\": \"400000\", \"entity\": \"foo\", \"state\": 1 }\"##,\n            r##\"{ \"time\": \"500000\", \"entity\": \"foo\", \"state\": 0 }\"##,\n            r##\"{ \"time\": \"600000\", \"entity\": \"foo\", \"state\": 1 }\"##\n        ]);\n\n        statemap.verify();\n        statemap.print(\"Begin at 250000, end at 310000\");\n\n        let rects = statemap.get_rects(\"foo\");\n        assert_eq!(rects.len(), 2);\n        assert_eq!(rects[0].0, 250000);\n        assert_eq!(rects[0].1, 250000 - 200000);\n        assert_eq!((rects[0].2)[0], 0);\n        assert_eq!((rects[0].2)[1], 250000 - 200000);\n\n        assert_eq!(rects[1].0, 300000);\n        assert_eq!(rects[1].1, 310000 - 300000);\n        assert_eq!((rects[1].2)[0], 310000 - 300000);\n        assert_eq!((rects[1].2)[1], 0);\n    }\n\n    #[test]\n    fn data_wrapped_time() {\n        let mut config: Config = Default::default();\n        config.begin = 250000;\n        config.end = 260000;\n\n        let statemap = data(Some(&config), vec![\n            r##\"{ \"time\": \"100000\", \"entity\": \"foo\", \"state\": 0 }\"##,\n            r##\"{ \"time\": \"200000\", \"entity\": \"foo\", \"state\": 1 }\"##,\n            r##\"{ \"time\": \"300000\", \"entity\": \"foo\", \"state\": 0 }\"##,\n            r##\"{ \"time\": \"400000\", \"entity\": \"foo\", \"state\": 1 }\"##,\n            r##\"{ \"time\": \"500000\", \"entity\": \"foo\", \"state\": 0 }\"##,\n            r##\"{ \"time\": \"600000\", \"entity\": \"foo\", \"state\": 1 }\"##\n        ]);\n\n        statemap.verify();\n        statemap.print(\"Begin at 250000, end at 260000\");\n\n        let rects = statemap.get_rects(\"foo\");\n        assert_eq!(rects.len(), 1);\n        assert_eq!(rects[0].0, 250000);\n        assert_eq!(rects[0].1, 260000 - 250000);\n        assert_eq!((rects[0].2)[0], 0);\n        assert_eq!((rects[0].2)[1], 260000 - 250000);\n    }\n\n    #[test]\n    fn color_named() {\n        let colors = vec![\n            (\"aliceblue\", (240, 248, 255)),\n            (\"antiquewhite\", (250, 235, 215)),\n            (\"aqua\", (0, 255, 255)),\n            (\"aquamarine\", (127, 255, 212)),\n            (\"azure\", (240, 255, 255)),\n            (\"beige\", (245, 245, 220)),\n            (\"bisque\", (255, 228, 196)),\n            (\"black\", (0, 0, 0)),\n            (\"blanchedalmond\", (255, 235, 205)),\n            (\"blue\", (0, 0, 255)),\n            (\"blueviolet\", (138, 43, 226)),\n            (\"brown\", (165, 42, 42)),\n            (\"burlywood\", (222, 184, 135)),\n            (\"cadetblue\", (95, 158, 160)),\n            (\"chartreuse\", (127, 255, 0)),\n            (\"chocolate\", (210, 105, 30)),\n            (\"coral\", (255, 127, 80)),\n            (\"cornflowerblue\", (100, 149, 237)),\n            (\"cornsilk\", (255, 248, 220)),\n            (\"crimson\", (220, 20, 60)),\n            (\"cyan\", (0, 255, 255)),\n            (\"darkblue\", (0, 0, 139)),\n            (\"darkcyan\", (0, 139, 139)),\n            (\"darkgoldenrod\", (184, 134, 11)),\n            (\"darkgray\", (169, 169, 169)),\n            (\"darkgreen\", (0, 100, 0)),\n            (\"darkgrey\", (169, 169, 169)),\n            (\"darkkhaki\", (189, 183, 107)),\n            (\"darkmagenta\", (139, 0, 139)),\n            (\"darkolivegreen\", (85, 107, 47)),\n            (\"darkorange\", (255, 140, 0)),\n            (\"darkorchid\", (153, 50, 204)),\n            (\"darkred\", (139, 0, 0)),\n            (\"darksalmon\", (233, 150, 122)),\n            (\"darkseagreen\", (143, 188, 143)),\n            (\"darkslateblue\", (72, 61, 139)),\n            (\"darkslategray\", (47, 79, 79)),\n            (\"darkslategrey\", (47, 79, 79)),\n            (\"darkturquoise\", (0, 206, 209)),\n            (\"darkviolet\", (148, 0, 211)),\n            (\"deeppink\", (255, 20, 147)),\n            (\"deepskyblue\", (0, 191, 255)),\n            (\"dimgray\", (105, 105, 105)),\n            (\"dimgrey\", (105, 105, 105)),\n            (\"dodgerblue\", (30, 144, 255)),\n            (\"firebrick\", (178, 34, 34)),\n            (\"floralwhite\", (255, 250, 240)),\n            (\"forestgreen\", (34, 139, 34)),\n            (\"fuchsia\", (255, 0, 255)),\n            (\"gainsboro\", (220, 220, 220)),\n            (\"ghostwhite\", (248, 248, 255)),\n            (\"gold\", (255, 215, 0)),\n            (\"goldenrod\", (218, 165, 32)),\n            (\"gray\", (128, 128, 128)),\n            (\"green\", (0, 128, 0)),\n            (\"greenyellow\", (173, 255, 47)),\n            (\"grey\", (128, 128, 128)),\n            (\"honeydew\", (240, 255, 240)),\n            (\"hotpink\", (255, 105, 180)),\n            (\"indianred\", (205, 92, 92)),\n            (\"indigo\", (75, 0, 130)),\n            (\"ivory\", (255, 255, 240)),\n            (\"khaki\", (240, 230, 140)),\n            (\"lavender\", (230, 230, 250)),\n            (\"lavenderblush\", (255, 240, 245)),\n            (\"lawngreen\", (124, 252, 0)),\n            (\"lemonchiffon\", (255, 250, 205)),\n            (\"lightblue\", (173, 216, 230)),\n            (\"lightcoral\", (240, 128, 128)),\n            (\"lightcyan\", (224, 255, 255)),\n            (\"lightgoldenrodyellow\", (250, 250, 210)),\n            (\"lightgray\", (211, 211, 211)),\n            (\"lightgreen\", (144, 238, 144)),\n            (\"lightgrey\", (211, 211, 211)),\n            (\"lightpink\", (255, 182, 193)),\n            (\"lightsalmon\", (255, 160, 122)),\n            (\"lightseagreen\", (32, 178, 170)),\n            (\"lightskyblue\", (135, 206, 250)),\n            (\"lightslategray\", (119, 136, 153)),\n            (\"lightslategrey\", (119, 136, 153)),\n            (\"lightsteelblue\", (176, 196, 222)),\n            (\"lightyellow\", (255, 255, 224)),\n            (\"lime\", (0, 255, 0)),\n            (\"limegreen\", (50, 205, 50)),\n            (\"linen\", (250, 240, 230)),\n            (\"magenta\", (255, 0, 255)),\n            (\"maroon\", (128, 0, 0)),\n            (\"mediumaquamarine\", (102, 205, 170)),\n            (\"mediumblue\", (0, 0, 205)),\n            (\"mediumorchid\", (186, 85, 211)),\n            (\"mediumpurple\", (147, 112, 219)),\n            (\"mediumseagreen\", (60, 179, 113)),\n            (\"mediumslateblue\", (123, 104, 238)),\n            (\"mediumspringgreen\", (0, 250, 154)),\n            (\"mediumturquoise\", (72, 209, 204)),\n            (\"mediumvioletred\", (199, 21, 133)),\n            (\"midnightblue\", (25, 25, 112)),\n            (\"mintcream\", (245, 255, 250)),\n            (\"mistyrose\", (255, 228, 225)),\n            (\"moccasin\", (255, 228, 181)),\n            (\"navajowhite\", (255, 222, 173)),\n            (\"navy\", (0, 0, 128)),\n            (\"oldlace\", (253, 245, 230)),\n            (\"olive\", (128, 128, 0)),\n            (\"olivedrab\", (107, 142, 35)),\n            (\"orange\", (255, 165, 0)),\n            (\"orangered\", (255, 69, 0)),\n            (\"orchid\", (218, 112, 214)),\n            (\"palegoldenrod\", (238, 232, 170)),\n            (\"palegreen\", (152, 251, 152)),\n            (\"paleturquoise\", (175, 238, 238)),\n            (\"palevioletred\", (219, 112, 147)),\n            (\"papayawhip\", (255, 239, 213)),\n            (\"peachpuff\", (255, 218, 185)),\n            (\"peru\", (205, 133, 63)),\n            (\"pink\", (255, 192, 203)),\n            (\"plum\", (221, 160, 221)),\n            (\"powderblue\", (176, 224, 230)),\n            (\"purple\", (128, 0, 128)),\n            (\"rebeccapurple\", (102, 51, 153)),\n            (\"red\", (255, 0, 0)),\n            (\"rosybrown\", (188, 143, 143)),\n            (\"royalblue\", (65, 105, 225)),\n            (\"saddlebrown\", (139, 69, 19)),\n            (\"salmon\", (250, 128, 114)),\n            (\"sandybrown\", (244, 164, 96)),\n            (\"seagreen\", (46, 139, 87)),\n            (\"seashell\", (255, 245, 238)),\n            (\"sienna\", (160, 82, 45)),\n            (\"silver\", (192, 192, 192)),\n            (\"skyblue\", (135, 206, 235)),\n            (\"slateblue\", (106, 90, 205)),\n            (\"slategray\", (112, 128, 144)),\n            (\"slategrey\", (112, 128, 144)),\n            (\"snow\", (255, 250, 250)),\n            (\"springgreen\", (0, 255, 127)),\n            (\"steelblue\", (70, 130, 180)),\n            (\"tan\", (210, 180, 140)),\n            (\"teal\", (0, 128, 128)),\n            (\"thistle\", (216, 191, 216)),\n            (\"tomato\", (255, 99, 71)),\n            (\"turquoise\", (64, 224, 208)),\n            (\"violet\", (238, 130, 238)),\n            (\"wheat\", (245, 222, 179)),\n            (\"white\", (255, 255, 255)),\n            (\"whitesmoke\", (245, 245, 245)),\n            (\"yellow\", (255, 255, 0)),\n            (\"yellowgreen\", (154, 205, 50)),\n        ];\n\n        let notcolors = vec![\"nixon\", \"yellowgreenybeeny\", \"#1234567\",\n            \"1234567\", \"$123456\", \"#123456#\" ];\n\n        for i in 0..notcolors.len() {\n            match StatemapColor::from_str(notcolors[i]) {\n                Ok(color) => {\n                    panic!(\"lookup of {} succeeded with {:?}!\",\n                        notcolors[i], color);\n                },\n                Err(err) => {\n                    println!(\"lookup of {} failed with {}\", notcolors[i], err);\n                }\n            }\n        }\n\n        for i in 0..colors.len() {\n            match StatemapColor::from_str(colors[i].0) {\n                Ok(color) => {\n                    let out = format!(\"rgb({}, {}, {})\",\n                        (colors[i].1).0, (colors[i].1).1, (colors[i].1).2);\n                    assert_eq!(out, color.to_string());\n                },\n                Err(err) => {\n                    panic!(\"lookup of {} failed with {}!\", colors[i].0, err);\n                }\n            }\n        }\n    }\n\n    #[test]\n    fn color_mix() {\n        let red = StatemapColor::from_str(\"red\").unwrap();\n        let white = StatemapColor::from_str(\"white\").unwrap();\n\n        let tests = vec![\n            (0.0, \"rgb(255, 0, 0)\"),\n            (0.25, \"rgb(255, 137, 137)\"),\n            (0.5, \"rgb(255, 188, 188)\"),\n            (0.75, \"rgb(255, 225, 225)\"),\n            (1.0, \"rgb(255, 255, 255)\"),\n        ];\n\n        for i in 0..tests.len() {\n            assert_eq!(red._mix(&white, tests[i].0).to_string(), tests[i].1);\n            assert_eq!(red._mix(&white, tests[i].0).to_string(),\n                white._mix(&red, 1.0 - tests[i].0).to_string());\n        }\n    }\n\n    #[test]\n    fn color_mix_linear() {\n        let color = StatemapColor::from_str(\"#2e9107\").unwrap();\n        let other = StatemapColor::from_str(\"#f9f9f9\").unwrap();\n        let ratio = 351500 as f64 / 840108 as f64;\n        let mix = color._mix(&other, ratio as f32);\n\n        println!(\"color={}, other={}, mix={}\", color, other, mix);\n    }\n\n    #[test]\n    fn color_mix_nonlinear() {\n        let color = StatemapColor::from_str(\"#2e9107\").unwrap();\n        let other = StatemapColor::from_str(\"#f9f9f9\").unwrap();\n        let ratio = 351500 as f64 / 840108 as f64;\n        let mix = color.mix_nonlinear(&other, ratio as f32);\n\n        println!(\"color={}, other={}, mix={}\", color, other, mix);\n    }\n\n    #[test]\n    fn tag_basic() {\n        let statemap = good_statemap!(\"tag_basic\");\n        println!(\"{:?}\", statemap.tags);\n        statemap.verify();\n    }\n\n    #[test]\n    fn tag_redefined() {\n        let statemap = good_statemap!(\"tag_redefined\");\n        println!(\"{:?}\", statemap.tags);\n        statemap.verify();\n    }\n\n    #[test]\n    fn timebounds() {\n        let statemap = good_statemap!(\"io\");\n        let _timebounds = statemap.timebounds();\n\n        let mut config: Config = Default::default();\n        config.begin = 100000;\n\n        let bounded = good_statemap!(\"io\", &config);\n        println!(\"{:?}\", bounded.timebounds());\n\n        config.begin = -100000;\n        config.end = 10000;\n\n        let bounded = good_statemap!(\"io\", &config);\n        println!(\"{:?}\", bounded.timebounds());\n\n        statemap.verify();\n    }\n\n    #[test]\n    fn weight() {\n        let statemap = good_statemap!(\"io\");\n\n        assert_eq!(statemap.weight(0), 737063);\n        assert_eq!(statemap.weight(1), 2290450);\n        assert_eq!(statemap.weight(2), 934399);\n        assert_eq!(statemap.weight(3), 1082403);\n    }\n}\n"
  },
  {
    "path": "tst/tst.bad_line_basic.err",
    "content": "illegal datum on line 23: unrecognized payload\n"
  },
  {
    "path": "tst/tst.bad_line_basic.in",
    "content": "{\n        \"start\": [ 1527898727, 987783377 ],\n        \"title\": \"PostgreSQL statemap on HA8SDNRD2, by process ID\",\n        \"host\": \"HA8SDNRD2\",\n        \"entityKind\": \"Process\",\n        \"states\": {\n                \"on-cpu\": {\"value\": 0, \"color\": \"#DAF7A6\" },\n                \"off-cpu-waiting\": {\"value\": 1, \"color\": \"#f9f9f9\" },\n                \"off-cpu-semop\": {\"value\": 2, \"color\": \"#FF5733\" },\n                \"off-cpu-blocked\": {\"value\": 3, \"color\": \"#C70039\" },\n                \"off-cpu-zfs-read\": {\"value\": 4, \"color\": \"#FFC300\" },\n                \"off-cpu-zfs-write\": {\"value\": 5, \"color\": \"#338AFF\" },\n                \"off-cpu-zil-commit\": {\"value\": 6, \"color\": \"#66FFCC\" },\n                \"off-cpu-tx-wait\": {\"value\": 7, \"color\": \"#CCFF00\" },\n                \"off-cpu-dead\": {\"value\": 8, \"color\": \"#E0E0E0\" }\n        }\n}\n{ \"time\": \"90774\", \"entity\": \"586684\", \"state\": 0 }\n{ \"time\": \"129359\", \"entity\": \"586680\", \"state\": 1 }\n{ \"time\": \"184733\", \"entity\": \"586661\", \"state\": 7 }\n{ \"time\": \"189017\", \"entity\": \"586816\", \"state\": 0 }\n{ \"time\": \"273768\", \"entity\": \"586696\", \"state\": 4 }\n{ \"badrecord\": \"273835\", \"entity\": \"586677\", \"state\": 0 }\n{ \"time\": \"301002\", \"entity\": \"586680\", \"state\": 0 }\n{ \"time\": \"310276\", \"entity\": \"586654\", \"state\": 0 }\n{ \"time\": \"321186\", \"entity\": \"587470\", \"state\": 0 }\n{ \"time\": \"397567\", \"entity\": \"586818\", \"state\": 0 }\n{ \"time\": \"422987\", \"entity\": \"586680\", \"state\": 1 }\n{ \"time\": \"475881\", \"entity\": \"586688\", \"state\": 0 }\n{ \"time\": \"480090\", \"entity\": \"586818\", \"state\": 1 }\n{ \"time\": \"488177\", \"entity\": \"586684\", \"state\": 7 }\n{ \"time\": \"508238\", \"entity\": \"586749\", \"state\": 0 }\n{ \"time\": \"572155\", \"entity\": \"586677\", \"state\": 1 }\n{ \"time\": \"585023\", \"entity\": \"587481\", \"state\": 7 }\n{ \"time\": \"607816\", \"entity\": \"586749\", \"state\": 1 }\n{ \"time\": \"616968\", \"entity\": \"586818\", \"state\": 0 }\n{ \"time\": \"642186\", \"entity\": \"586680\", \"state\": 0 }\n"
  },
  {
    "path": "tst/tst.bad_line_newline.err",
    "content": "illegal datum on line 31: unrecognized payload\n"
  },
  {
    "path": "tst/tst.bad_line_newline.in",
    "content": "{\n        \"start\": [ 1527898727, 987783377 ],\n        \"title\": \"PostgreSQL statemap on HA8SDNRD2, by process ID\",\n        \"host\": \"HA8SDNRD2\",\n        \"entityKind\": \"Process\",\n        \"states\": {\n                \"on-cpu\": {\"value\": 0, \"color\": \"#DAF7A6\" },\n                \"off-cpu-waiting\": {\"value\": 1, \"color\": \"#f9f9f9\" },\n                \"off-cpu-semop\": {\"value\": 2, \"color\": \"#FF5733\" },\n                \"off-cpu-blocked\": {\"value\": 3, \"color\": \"#C70039\" },\n                \"off-cpu-zfs-read\": {\"value\": 4, \"color\": \"#FFC300\" },\n                \"off-cpu-zfs-write\": {\"value\": 5, \"color\": \"#338AFF\" },\n                \"off-cpu-zil-commit\": {\"value\": 6, \"color\": \"#66FFCC\" },\n                \"off-cpu-tx-wait\": {\"value\": 7, \"color\": \"#CCFF00\" },\n                \"off-cpu-dead\": {\"value\": 8, \"color\": \"#E0E0E0\" }\n        }\n}\n{ \"time\": \"90774\", \"entity\": \"586684\", \"state\": 0 }\n{ \"time\": \"129359\", \"entity\": \"586680\", \"state\": 1 }\n{ \"time\": \"184733\", \"entity\": \"586661\", \"state\": 7 }\n{ \"time\": \"189017\", \"entity\": \"586816\", \"state\": 0 }\n{ \"time\": \"273768\", \"entity\": \"586696\", \"state\": 4 }\n{ \"time\": \"301002\", \"entity\": \"586680\", \"state\": 0 }\n{ \"time\": \"310276\", \"entity\": \"586654\", \"state\": 0 }\n{ \"time\": \"321186\", \"entity\": \"587470\", \"state\": 0 }\n{ \"time\": \"397567\", \"entity\": \"586818\", \"state\": 0 }\n{ \"time\": \"422987\", \"entity\": \"586680\", \"state\": 1 }\n{ \"time\": \"475881\", \"entity\": \"586688\", \"state\": 0 }\n\n\n{ \"badrecord\": \"480090\", \"entity\": \"586818\", \"state\": 1 }\n\n{ \"time\": \"488177\", \"entity\": \"586684\", \"state\": 7 }\n{ \"time\": \"508238\", \"entity\": \"586749\", \"state\": 0 }\n{ \"time\": \"572155\", \"entity\": \"586677\", \"state\": 1 }\n{ \"time\": \"585023\", \"entity\": \"587481\", \"state\": 7 }\n{ \"time\": \"607816\", \"entity\": \"586749\", \"state\": 1 }\n{ \"time\": \"616968\", \"entity\": \"586818\", \"state\": 0 }\n{ \"time\": \"642186\", \"entity\": \"586680\", \"state\": 0 }\n"
  },
  {
    "path": "tst/tst.bad_line_whitespace.err",
    "content": "illegal datum on line 29: unrecognized payload\n"
  },
  {
    "path": "tst/tst.bad_line_whitespace.in",
    "content": "{\n        \"start\": [ 1527898727, 987783377 ],\n        \"title\": \"PostgreSQL statemap on HA8SDNRD2, by process ID\",\n        \"host\": \"HA8SDNRD2\",\n        \"entityKind\": \"Process\",\n        \"states\": {\n                \"on-cpu\": {\"value\": 0, \"color\": \"#DAF7A6\" },\n                \"off-cpu-waiting\": {\"value\": 1, \"color\": \"#f9f9f9\" },\n                \"off-cpu-semop\": {\"value\": 2, \"color\": \"#FF5733\" },\n                \"off-cpu-blocked\": {\"value\": 3, \"color\": \"#C70039\" },\n                \"off-cpu-zfs-read\": {\"value\": 4, \"color\": \"#FFC300\" },\n                \"off-cpu-zfs-write\": {\"value\": 5, \"color\": \"#338AFF\" },\n                \"off-cpu-zil-commit\": {\"value\": 6, \"color\": \"#66FFCC\" },\n                \"off-cpu-tx-wait\": {\"value\": 7, \"color\": \"#CCFF00\" },\n                \"off-cpu-dead\": {\"value\": 8, \"color\": \"#E0E0E0\" }\n        }\n}\n{ \"time\": \"90774\", \"entity\": \"586684\", \"state\": 0 }\n{ \"time\": \"129359\", \"entity\": \"586680\", \"state\": 1 }\n{ \"time\": \"184733\", \"entity\": \"586661\", \"state\": 7 }\n{ \"time\": \"189017\", \"entity\": \"586816\", \"state\": 0 }\n{ \"time\": \"273768\", \"entity\": \"586696\", \"state\": 4 }\n{ \"time\": \"301002\", \"entity\": \"586680\", \"state\": 0 }\n{ \"time\": \"310276\", \"entity\": \"586654\", \"state\": 0 }\n{ \"time\": \"321186\", \"entity\": \"587470\", \"state\": 0 }\n{ \"time\": \"397567\", \"entity\": \"586818\", \"state\": 0 }\n{ \"time\": \"422987\", \"entity\": \"586680\", \"state\": 1 }\n{ \"time\": \"475881\", \"entity\": \"586688\", \"state\": 0 }   \n{ \"badrecord\": \"480090\", \"entity\": \"586818\", \"state\": 1 }\n\n{ \"time\": \"488177\", \"entity\": \"586684\", \"state\": 7 }\n{ \"time\": \"508238\", \"entity\": \"586749\", \"state\": 0 }\n{ \"time\": \"572155\", \"entity\": \"586677\", \"state\": 1 }\n{ \"time\": \"585023\", \"entity\": \"587481\", \"state\": 7 }\n{ \"time\": \"607816\", \"entity\": \"586749\", \"state\": 1 }\n{ \"time\": \"616968\", \"entity\": \"586818\", \"state\": 0 }\n{ \"time\": \"642186\", \"entity\": \"586680\", \"state\": 0 }\n"
  },
  {
    "path": "tst/tst.io.in",
    "content": "{\n\t\"start\": [ 1515712765, 175059957 ],\n\t\"title\": \"Statemap for device I/O on HCFHM2TD2\",\n\t\"host\": \"HCFHM2TD2\",\n\t\"states\": {\n\t\t\"no I/O\": {\"value\": 0, \"color\": \"#e0e0e0\" },\n\t\t\"1 I/O\": {\"value\": 1, \"color\": \"#ffffcc\" },\n\t\t\"2 I/Os\": {\"value\": 2, \"color\": \"#ffeda0\" },\n\t\t\"3 I/Os\": {\"value\": 3, \"color\": \"#fed976\" },\n\t\t\"4 I/Os\": {\"value\": 4, \"color\": \"#feb24c\" },\n\t\t\"5 I/Os\": {\"value\": 5, \"color\": \"#fd8d3c\" },\n\t\t\"6 I/Os\": {\"value\": 6, \"color\": \"#fc4e2a\" },\n\t\t\"7 I/Os\": {\"value\": 7, \"color\": \"#e31a1c\" },\n\t\t\"8 I/Os\": {\"value\": 8, \"color\": \"#bd0026\" },\n\t\t\">8 I/Os\": {\"value\": 9, \"color\": \"#800026\" }\n\t}\n}\n{ \"time\": \"122523\", \"entity\": \"sd3\", \"state\": 0 }\n{ \"time\": \"136559\", \"entity\": \"sd4\", \"state\": 0 }\n{ \"time\": \"144007\", \"entity\": \"sd6\", \"state\": 0 }\n{ \"time\": \"197064\", \"entity\": \"sd6\", \"state\": 1 }\n{ \"time\": \"204699\", \"entity\": \"sd8\", \"state\": 4 }\n{ \"time\": \"217980\", \"entity\": \"sd8\", \"state\": 3 }\n{ \"time\": \"219042\", \"entity\": \"sd4\", \"state\": 1 }\n{ \"time\": \"226112\", \"entity\": \"sd8\", \"state\": 2 }\n{ \"time\": \"233987\", \"entity\": \"sd2\", \"state\": 3 }\n{ \"time\": \"245080\", \"entity\": \"sd8\", \"state\": 3 }\n{ \"time\": \"258479\", \"entity\": \"sd5\", \"state\": 2 }\n{ \"time\": \"271165\", \"entity\": \"sd1\", \"state\": 1 }\n{ \"time\": \"286441\", \"entity\": \"sd8\", \"state\": 2 }\n{ \"time\": \"304154\", \"entity\": \"sd7\", \"state\": 7 }\n{ \"time\": \"324614\", \"entity\": \"sd7\", \"state\": 6 }\n{ \"time\": \"341445\", \"entity\": \"sd8\", \"state\": 1 }\n{ \"time\": \"354628\", \"entity\": \"sd3\", \"state\": 1 }\n{ \"time\": \"370011\", \"entity\": \"sd7\", \"state\": 7 }\n{ \"time\": \"446175\", \"entity\": \"sd7\", \"state\": 6 }\n{ \"time\": \"468920\", \"entity\": \"sd4\", \"state\": 1 }\n{ \"time\": \"475701\", \"entity\": \"sd4\", \"state\": 1 }\n{ \"time\": \"488966\", \"entity\": \"sd3\", \"state\": 0 }\n{ \"time\": \"495868\", \"entity\": \"sd2\", \"state\": 4 }\n{ \"time\": \"499196\", \"entity\": \"sd7\", \"state\": 7 }\n{ \"time\": \"505590\", \"entity\": \"sd8\", \"state\": 0 }\n{ \"time\": \"510634\", \"entity\": \"sd6\", \"state\": 2 }\n{ \"time\": \"518170\", \"entity\": \"sd8\", \"state\": 1 }\n{ \"time\": \"519923\", \"entity\": \"sd1\", \"state\": 0 }\n{ \"time\": \"533632\", \"entity\": \"sd5\", \"state\": 3 }\n{ \"time\": \"547899\", \"entity\": \"sd1\", \"state\": 1 }\n{ \"time\": \"561853\", \"entity\": \"sd7\", \"state\": 6 }\n{ \"time\": \"573397\", \"entity\": \"sd3\", \"state\": 1 }\n{ \"time\": \"573456\", \"entity\": \"sd2\", \"state\": 3 }\n{ \"time\": \"582845\", \"entity\": \"sd7\", \"state\": 7 }\n{ \"time\": \"592933\", \"entity\": \"sd6\", \"state\": 3 }\n{ \"time\": \"611640\", \"entity\": \"sd7\", \"state\": 6 }\n{ \"time\": \"617899\", \"entity\": \"sd7\", \"state\": 5 }\n{ \"time\": \"638869\", \"entity\": \"sd6\", \"state\": 2 }\n{ \"time\": \"651313\", \"entity\": \"sd7\", \"state\": 4 }\n{ \"time\": \"668226\", \"entity\": \"sd7\", \"state\": 3 }\n{ \"time\": \"688325\", \"entity\": \"sd8\", \"state\": 2 }\n{ \"time\": \"702999\", \"entity\": \"sd5\", \"state\": 4 }\n{ \"time\": \"704915\", \"entity\": \"sd6\", \"state\": 1 }\n{ \"time\": \"731014\", \"entity\": \"sd7\", \"state\": 2 }\n{ \"time\": \"740876\", \"entity\": \"sd7\", \"state\": 1 }\n{ \"time\": \"747430\", \"entity\": \"sd7\", \"state\": 0 }\n{ \"time\": \"764305\", \"entity\": \"sd8\", \"state\": 3 }\n{ \"time\": \"765171\", \"entity\": \"sd4\", \"state\": 0 }\n{ \"time\": \"775917\", \"entity\": \"sd5\", \"state\": 5 }\n{ \"time\": \"784865\", \"entity\": \"sd1\", \"state\": 0 }\n{ \"time\": \"794219\", \"entity\": \"sd6\", \"state\": 2 }\n{ \"time\": \"802379\", \"entity\": \"sd5\", \"state\": 4 }\n{ \"time\": \"804071\", \"entity\": \"sd3\", \"state\": 2 }\n{ \"time\": \"814227\", \"entity\": \"sd7\", \"state\": 1 }\n{ \"time\": \"817592\", \"entity\": \"sd4\", \"state\": 1 }\n{ \"time\": \"822131\", \"entity\": \"sd8\", \"state\": 2 }\n{ \"time\": \"824538\", \"entity\": \"sd7\", \"state\": 2 }\n{ \"time\": \"827469\", \"entity\": \"sd6\", \"state\": 3 }\n{ \"time\": \"829852\", \"entity\": \"sd8\", \"state\": 1 }\n{ \"time\": \"836807\", \"entity\": \"sd2\", \"state\": 4 }\n{ \"time\": \"848386\", \"entity\": \"sd4\", \"state\": 2 }\n{ \"time\": \"858331\", \"entity\": \"sd5\", \"state\": 3 }\n{ \"time\": \"867636\", \"entity\": \"sd8\", \"state\": 2 }\n{ \"time\": \"869196\", \"entity\": \"sd7\", \"state\": 3 }\n{ \"time\": \"879278\", \"entity\": \"sd7\", \"state\": 4 }\n{ \"time\": \"881291\", \"entity\": \"sd5\", \"state\": 4 }\n{ \"time\": \"893179\", \"entity\": \"sd1\", \"state\": 1 }\n{ \"time\": \"898015\", \"entity\": \"sd6\", \"state\": 4 }\n{ \"time\": \"902098\", \"entity\": \"sd6\", \"state\": 5 }\n{ \"time\": \"909303\", \"entity\": \"sd3\", \"state\": 1 }\n{ \"time\": \"913168\", \"entity\": \"sd4\", \"state\": 3 }\n{ \"time\": \"923748\", \"entity\": \"sd7\", \"state\": 5 }\n{ \"time\": \"925732\", \"entity\": \"sd5\", \"state\": 3 }\n{ \"time\": \"926853\", \"entity\": \"sd2\", \"state\": 5 }\n{ \"time\": \"936067\", \"entity\": \"sd3\", \"state\": 0 }\n{ \"time\": \"936716\", \"entity\": \"sd1\", \"state\": 2 }\n{ \"time\": \"939044\", \"entity\": \"sd8\", \"state\": 3 }\n{ \"time\": \"943174\", \"entity\": \"sd7\", \"state\": 6 }\n{ \"time\": \"944707\", \"entity\": \"sd6\", \"state\": 6 }\n{ \"time\": \"945970\", \"entity\": \"sd5\", \"state\": 4 }\n{ \"time\": \"946514\", \"entity\": \"sd8\", \"state\": 2 }\n{ \"time\": \"952966\", \"entity\": \"sd3\", \"state\": 1 }\n{ \"time\": \"953633\", \"entity\": \"sd8\", \"state\": 3 }\n"
  },
  {
    "path": "tst/tst.tag_basic.in",
    "content": "{\n\t\"start\": [ 1528482355, 856625707 ],\n\t\"title\": \"Statemap for CPU activity on HA8S7MRD2\",\n\t\"host\": \"HA8S7MRD2\",\n\t\"entityKind\": \"CPU\",\n\t\"states\": {\n\t\t\"uthread\": {\"value\": 0, \"color\": \"#9BC362\" },\n\t\t\"kthread\": {\"value\": 1, \"color\": \"#2E4E00\" },\n\t\t\"level-1\": {\"value\": 2, \"color\": \"#689D99\" },\n\t\t\"level-2\": {\"value\": 3, \"color\": \"#41837E\" },\n\t\t\"level-3\": {\"value\": 4, \"color\": \"#236863\" },\n\t\t\"level-4\": {\"value\": 5, \"color\": \"#0D4E4A\" },\n\t\t\"level-5\": {\"value\": 6, \"color\": \"#003430\" },\n\t\t\"level-6\": {\"value\": 7, \"color\": \"#817FB2\" },\n\t\t\"level-7\": {\"value\": 8, \"color\": \"#575594\" },\n\t\t\"level-8\": {\"value\": 9, \"color\": \"#363377\" },\n\t\t\"level-9\": {\"value\": 10, \"color\": \"#1C1A59\" },\n\t\t\"level-10\": {\"value\": 11, \"color\": \"#0A093B\" },\n\t\t\"level-11\": {\"value\": 12, \"color\": \"#FFAAAA\" },\n\t\t\"level-12\": {\"value\": 13, \"color\": \"#D46A6A\" },\n\t\t\"level-13\": {\"value\": 14, \"color\": \"#AA3939\" },\n\t\t\"level-14\": {\"value\": 15, \"color\": \"#801515\" },\n\t\t\"level-15\": {\"value\": 16, \"color\": \"#550000\" },\n\t\t\"idle\": {\"value\": 17, \"color\": \"#e0e0e0\" }\n\t}\n}\n{ \"time\": \"133694\", \"entity\": \"14\", \"state\": 17 }\n{ \"time\": \"133726\", \"entity\": \"0\", \"state\": 17 }\n{ \"time\": \"133731\", \"entity\": \"8\", \"state\": 17 }\n{ \"time\": \"133776\", \"entity\": \"12\", \"state\": 17 }\n{ \"time\": \"133779\", \"entity\": \"28\", \"state\": 17 }\n{ \"time\": \"133783\", \"entity\": \"20\", \"state\": 17 }\n{ \"time\": \"133819\", \"entity\": \"18\", \"state\": 17 }\n{ \"time\": \"133859\", \"entity\": \"5\", \"state\": 17 }\n{ \"time\": \"133863\", \"entity\": \"22\", \"state\": 17 }\n{ \"time\": \"133888\", \"entity\": \"11\", \"state\": 17 }\n{ \"time\": \"133917\", \"entity\": \"7\", \"state\": 17 }\n{ \"time\": \"133961\", \"entity\": \"3\", \"state\": 17 }\n{ \"time\": \"133979\", \"entity\": \"21\", \"state\": 17 }\n{ \"time\": \"134574\", \"entity\": \"9\", \"state\": 17 }\n{ \"time\": \"135203\", \"entity\": \"35\", \"state\": 17 }\n{ \"time\": \"136037\", \"entity\": \"4\", \"state\": 0, \"tag\": \"49a7f49\" }\n{ \"time\": \"136389\", \"entity\": \"31\", \"state\": 17 }\n{ \"time\": \"136724\", \"entity\": \"17\", \"state\": 17 }\n{ \"time\": \"137094\", \"entity\": \"40\", \"state\": 17 }\n{ \"time\": \"137133\", \"entity\": \"46\", \"state\": 17 }\n{ \"time\": \"137348\", \"entity\": \"13\", \"state\": 17 }\n{ \"time\": \"137701\", \"entity\": \"6\", \"state\": 17 }\n{ \"time\": \"138148\", \"entity\": \"29\", \"state\": 17 }\n{ \"time\": \"138234\", \"entity\": \"1\", \"state\": 17 }\n{ \"time\": \"138244\", \"entity\": \"44\", \"state\": 17 }\n{ \"time\": \"139739\", \"entity\": \"41\", \"state\": 0, \"tag\": \"49a7f3e\" }\n{ \"time\": \"139979\", \"entity\": \"37\", \"state\": 17 }\n{ \"time\": \"141144\", \"entity\": \"25\", \"state\": 17 }\n{ \"time\": \"141240\", \"entity\": \"53\", \"state\": 17 }\n{ \"time\": \"141384\", \"entity\": \"32\", \"state\": 17 }\n{ \"time\": \"141553\", \"entity\": \"39\", \"state\": 17 }\n{ \"time\": \"141598\", \"entity\": \"45\", \"state\": 0, \"tag\": \"49a7f2e\" }\n{ \"time\": \"141960\", \"entity\": \"55\", \"state\": 17 }\n{ \"time\": \"141978\", \"entity\": \"27\", \"state\": 17 }\n{ \"time\": \"142181\", \"entity\": \"10\", \"state\": 17 }\n{ \"time\": \"142336\", \"entity\": \"28\", \"state\": 15 }\n{ \"time\": \"142496\", \"entity\": \"51\", \"state\": 17 }\n{ \"time\": \"142744\", \"entity\": \"23\", \"state\": 17 }\n{ \"time\": \"143454\", \"entity\": \"19\", \"state\": 17 }\n{ \"time\": \"143551\", \"entity\": \"47\", \"state\": 17 }\n{ \"time\": \"143638\", \"entity\": \"30\", \"state\": 17 }\n{ \"time\": \"144457\", \"entity\": \"33\", \"state\": 17 }\n{ \"time\": \"144680\", \"entity\": \"43\", \"state\": 17 }\n{ \"time\": \"144739\", \"entity\": \"15\", \"state\": 17 }\n{ \"time\": \"144784\", \"entity\": \"36\", \"state\": 17 }\n{ \"time\": \"145279\", \"entity\": \"50\", \"state\": 17 }\n{ \"time\": \"145292\", \"entity\": \"49\", \"state\": 0, \"tag\": \"497cdd3\" }\n{ \"time\": \"145567\", \"entity\": \"42\", \"state\": 17 }\n{ \"time\": \"146407\", \"entity\": \"48\", \"state\": 1, \"tag\": \"3c4\" }\n{ \"time\": \"148558\", \"entity\": \"34\", \"state\": 17 }\n{ \"time\": \"148758\", \"entity\": \"38\", \"state\": 17 }\n{ \"time\": \"149461\", \"entity\": \"26\", \"state\": 17 }\n{ \"time\": \"149464\", \"entity\": \"54\", \"state\": 17 }\n{ \"time\": \"149917\", \"entity\": \"28\", \"state\": 17 }\n{ \"time\": \"151111\", \"entity\": \"24\", \"state\": 17 }  \n{ \"state\": 2, \"tag\": \"3\", \"driver\": \"softint\", \"instance\": 0 }\n{ \"time\": \"151161\", \"entity\": \"52\", \"state\": 17 }\n{ \"time\": \"158287\", \"entity\": \"28\", \"state\": 3, \"tag\": \"2\" }\n{ \"time\": \"159063\", \"entity\": \"49\", \"state\": 17 }\n{ \"state\": 0, \"tag\": \"4a0e384\", \"pid\": \"50378\", \"tid\": \"1\", \"execname\": \"dtrace\", \"psargs\": \"/usr/sbin/dtrace -Cs ./postgres-statemap-zfs.d\" }\n{ \"time\": \"170534\", \"entity\": \"28\", \"state\": 17 }\n{ \"time\": \"173279\", \"entity\": \"0\", \"state\": 0, \"tag\": \"4a0e384\" }\n{ \"state\": 0, \"tag\": \"49a7f42\", \"pid\": \"565192\", \"tid\": \"66\", \"execname\": \"pg_prefaulter\", \"psargs\": \"/opt/smartdc/manatee/bin/pg_prefaulter run --config=/opt/smartdc/manatee/etc/pg\" }\n{ \"time\": \"184732\", \"entity\": \"28\", \"state\": 0, \"tag\": \"49a7f42\" }\n{ \"time\": \"198289\", \"entity\": \"4\", \"state\": 17 }\n{ \"state\": 0, \"tag\": \"49a7f49\", \"pid\": \"565192\", \"tid\": \"74\", \"execname\": \"pg_prefaulter\", \"psargs\": \"/opt/smartdc/manatee/bin/pg_prefaulter run --config=/opt/smartdc/manatee/etc/pg\" }\n{ \"time\": \"215317\", \"entity\": \"4\", \"state\": 0, \"tag\": \"49a7f49\" }\n{ \"state\": 0, \"tag\": \"497cdd3\", \"pid\": \"565192\", \"tid\": \"19\", \"execname\": \"pg_prefaulter\", \"psargs\": \"/opt/smartdc/manatee/bin/pg_prefaulter run --config=/opt/smartdc/manatee/etc/pg\" }\n{ \"time\": \"236759\", \"entity\": \"28\", \"state\": 17 }\n{ \"time\": \"240371\", \"entity\": \"36\", \"state\": 0, \"tag\": \"49a7f42\" }\n{ \"time\": \"245952\", \"entity\": \"49\", \"state\": 0, \"tag\": \"497cdd3\" }\n{ \"time\": \"251572\", \"entity\": \"52\", \"state\": 15 }\n{ \"time\": \"256407\", \"entity\": \"4\", \"state\": 17 }\n{ \"time\": \"257895\", \"entity\": \"52\", \"state\": 17 }\n{ \"time\": \"263286\", \"entity\": \"52\", \"state\": 3, \"tag\": \"2\" }\n{ \"time\": \"273170\", \"entity\": \"4\", \"state\": 0, \"tag\": \"49a7f49\" }\n{ \"time\": \"275226\", \"entity\": \"52\", \"state\": 17 }\n{ \"state\": 0, \"tag\": \"49a7f45\", \"pid\": \"565192\", \"tid\": \"70\", \"execname\": \"pg_prefaulter\", \"psargs\": \"/opt/smartdc/manatee/bin/pg_prefaulter run --config=/opt/smartdc/manatee/etc/pg\" }\n{ \"state\": 0, \"tag\": \"49a7f32\", \"pid\": \"565192\", \"tid\": \"51\", \"execname\": \"pg_prefaulter\", \"psargs\": \"/opt/smartdc/manatee/bin/pg_prefaulter run --config=/opt/smartdc/manatee/etc/pg\" }\n{ \"time\": \"296823\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"298706\", \"entity\": \"0\", \"state\": 16 }\n{ \"time\": \"299990\", \"entity\": \"19\", \"state\": 0, \"tag\": \"49a7f32\" }\n{ \"state\": 0, \"tag\": \"49a7f46\", \"pid\": \"565192\", \"tid\": \"71\", \"execname\": \"pg_prefaulter\", \"psargs\": \"/opt/smartdc/manatee/bin/pg_prefaulter run --config=/opt/smartdc/manatee/etc/pg\" }\n{ \"time\": \"303706\", \"entity\": \"0\", \"state\": 0, \"tag\": \"4a0e384\" }\n{ \"time\": \"307335\", \"entity\": \"31\", \"state\": 0, \"tag\": \"49a7f46\" }\n{ \"state\": 0, \"tag\": \"497cdd0\", \"pid\": \"565192\", \"tid\": \"16\", \"execname\": \"pg_prefaulter\", \"psargs\": \"/opt/smartdc/manatee/bin/pg_prefaulter run --config=/opt/smartdc/manatee/etc/pg\" }\n{ \"state\": 0, \"tag\": \"4a0e388\", \"pid\": \"50380\", \"tid\": \"1\", \"execname\": \"pg_xlogdump\", \"psargs\": \"/opt/postgresql/current/bin/pg_xlogdump -f /manatee/pg/data/pg_xlog/00000001000\" }\n{ \"time\": \"311412\", \"entity\": \"4\", \"state\": 17 }\n{ \"time\": \"312858\", \"entity\": \"36\", \"state\": 17 }\n{ \"time\": \"315103\", \"entity\": \"1\", \"state\": 16 }\n{ \"time\": \"315435\", \"entity\": \"14\", \"state\": 0, \"tag\": \"4a0e388\" }\n{ \"time\": \"320596\", \"entity\": \"10\", \"state\": 0, \"tag\": \"497cdd0\" }\n{ \"time\": \"323738\", \"entity\": \"1\", \"state\": 17 }\n{ \"time\": \"324471\", \"entity\": \"41\", \"state\": 17 }\n{ \"time\": \"327464\", \"entity\": \"2\", \"state\": 16 }\n{ \"state\": 0, \"tag\": \"49a7f3e\", \"pid\": \"565192\", \"tid\": \"63\", \"execname\": \"pg_prefaulter\", \"psargs\": \"/opt/smartdc/manatee/bin/pg_prefaulter run --config=/opt/smartdc/manatee/etc/pg\" }\n{ \"time\": \"330894\", \"entity\": \"2\", \"state\": 17 }\n{ \"time\": \"333404\", \"entity\": \"41\", \"state\": 0, \"tag\": \"49a7f3e\" }\n{ \"time\": \"335503\", \"entity\": \"3\", \"state\": 16 }\n{ \"time\": \"341680\", \"entity\": \"3\", \"state\": 17 }\n{ \"time\": \"344099\", \"entity\": \"4\", \"state\": 16 }\n{ \"time\": \"347527\", \"entity\": \"45\", \"state\": 17 }\n{ \"time\": \"347942\", \"entity\": \"4\", \"state\": 17 }\n{ \"time\": \"351280\", \"entity\": \"5\", \"state\": 16 }\n{ \"state\": 0, \"tag\": \"49a7f2e\", \"pid\": \"565192\", \"tid\": \"47\", \"execname\": \"pg_prefaulter\", \"psargs\": \"/opt/smartdc/manatee/bin/pg_prefaulter run --config=/opt/smartdc/manatee/etc/pg\" }\n{ \"time\": \"355510\", \"entity\": \"5\", \"state\": 17 }\n{ \"time\": \"357571\", \"entity\": \"19\", \"state\": 17 }\n{ \"time\": \"359891\", \"entity\": \"6\", \"state\": 16 }\n{ \"time\": \"360586\", \"entity\": \"49\", \"state\": 17 }\n{ \"time\": \"365971\", \"entity\": \"6\", \"state\": 17 }\n{ \"time\": \"367461\", \"entity\": \"45\", \"state\": 0, \"tag\": \"49a7f2e\" }\n{ \"time\": \"368755\", \"entity\": \"7\", \"state\": 16 }\n{ \"time\": \"368815\", \"entity\": \"31\", \"state\": 16 }\n{ \"time\": \"369961\", \"entity\": \"10\", \"state\": 16 }\n{ \"time\": \"370707\", \"entity\": \"52\", \"state\": 16 }\n{ \"time\": \"371639\", \"entity\": \"31\", \"state\": 0, \"tag\": \"49a7f46\" }\n{ \"time\": \"372586\", \"entity\": \"7\", \"state\": 17 }\n{ \"time\": \"372850\", \"entity\": \"14\", \"state\": 17 }\n{ \"time\": \"373621\", \"entity\": \"45\", \"state\": 16 }\n{ \"time\": \"375707\", \"entity\": \"8\", \"state\": 16 }\n{ \"time\": \"377134\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"377401\", \"entity\": \"10\", \"state\": 0, \"tag\": \"497cdd0\" }\n{ \"time\": \"379466\", \"entity\": \"8\", \"state\": 17 }\n{ \"time\": \"380914\", \"entity\": \"45\", \"state\": 0, \"tag\": \"49a7f2e\" }\n{ \"time\": \"413422\", \"entity\": \"31\", \"state\": 17 }\n{ \"time\": \"449800\", \"entity\": \"31\", \"state\": 0, \"tag\": \"49a7f46\" }\n{ \"time\": \"450431\", \"entity\": \"49\", \"state\": 0, \"tag\": \"497cdd3\" }\n{ \"state\": 7, \"tag\": \"ffffd062dbcb7d58\", \"driver\": \"ixgbe\", \"instance\": 2 }\n{ \"time\": \"468924\", \"entity\": \"36\", \"state\": 0, \"tag\": \"49a7f42\" }\n{ \"time\": \"469468\", \"entity\": \"30\", \"state\": 7, \"tag\": \"ffffd062dbcb7d58\" }\n{ \"time\": \"470025\", \"entity\": \"19\", \"state\": 0, \"tag\": \"49a7f32\" }\n{ \"time\": \"471607\", \"entity\": \"4\", \"state\": 0, \"tag\": \"49a7f49\" }\n{ \"time\": \"477875\", \"entity\": \"10\", \"state\": 17 }\n{ \"time\": \"484799\", \"entity\": \"10\", \"state\": 0, \"tag\": \"497cdd0\" }\n{ \"state\": 0, \"tag\": \"497cdd1\", \"pid\": \"565192\", \"tid\": \"17\", \"execname\": \"pg_prefaulter\", \"psargs\": \"/opt/smartdc/manatee/bin/pg_prefaulter run --config=/opt/smartdc/manatee/etc/pg\" }\n{ \"time\": \"485897\", \"entity\": \"4\", \"state\": 17 }\n{ \"time\": \"491362\", \"entity\": \"31\", \"state\": 17 }\n{ \"time\": \"491825\", \"entity\": \"11\", \"state\": 0, \"tag\": \"497cdd1\" }\n{ \"time\": \"492884\", \"entity\": \"30\", \"state\": 17 }\n{ \"time\": \"496488\", \"entity\": \"31\", \"state\": 0, \"tag\": \"49a7f46\" }\n{ \"state\": 0, \"tag\": \"48d4b6d\", \"pid\": \"5447\", \"tid\": \"1\", \"execname\": \"node\", \"psargs\": \"node --abort-on-uncaught-exception main.js -f etc/config.json -p 2021 -k 3021\" }\n{ \"time\": \"503227\", \"entity\": \"4\", \"state\": 0, \"tag\": \"49a7f49\" }\n{ \"time\": \"503832\", \"entity\": \"29\", \"state\": 0, \"tag\": \"48d4b6d\" }\n{ \"time\": \"506328\", \"entity\": \"11\", \"state\": 17 }\n{ \"time\": \"509977\", \"entity\": \"11\", \"state\": 0, \"tag\": \"497cdd1\" }\n{ \"state\": 0, \"tag\": \"497cdd4\", \"pid\": \"565192\", \"tid\": \"20\", \"execname\": \"pg_prefaulter\", \"psargs\": \"/opt/smartdc/manatee/bin/pg_prefaulter run --config=/opt/smartdc/manatee/etc/pg\" }\n{ \"time\": \"523775\", \"entity\": \"22\", \"state\": 0, \"tag\": \"497cdd4\" }\n{ \"state\": 0, \"tag\": \"497cd9f\", \"pid\": \"565192\", \"tid\": \"1\", \"execname\": \"pg_prefaulter\", \"psargs\": \"/opt/smartdc/manatee/bin/pg_prefaulter run --config=/opt/smartdc/manatee/etc/pg\" }\n{ \"time\": \"532235\", \"entity\": \"53\", \"state\": 0, \"tag\": \"497cd9f\" }\n{ \"state\": 0, \"tag\": \"4980fc2\", \"pid\": \"565192\", \"tid\": \"27\", \"execname\": \"pg_prefaulter\", \"psargs\": \"/opt/smartdc/manatee/bin/pg_prefaulter run --config=/opt/smartdc/manatee/etc/pg\" }\n{ \"state\": 0, \"tag\": \"497cdd9\", \"pid\": \"565192\", \"tid\": \"24\", \"execname\": \"pg_prefaulter\", \"psargs\": \"/opt/smartdc/manatee/bin/pg_prefaulter run --config=/opt/smartdc/manatee/etc/pg\" }\n{ \"time\": \"542614\", \"entity\": \"9\", \"state\": 0, \"tag\": \"4980fc2\" }\n{ \"time\": \"546541\", \"entity\": \"46\", \"state\": 0, \"tag\": \"497cdd9\" }\n{ \"time\": \"547085\", \"entity\": \"41\", \"state\": 17 }\n{ \"time\": \"549434\", \"entity\": \"11\", \"state\": 17 }\n{ \"time\": \"555295\", \"entity\": \"49\", \"state\": 17 }\n{ \"state\": 0, \"tag\": \"48d4b75\", \"pid\": \"5447\", \"tid\": \"2\", \"execname\": \"node\", \"psargs\": \"node --abort-on-uncaught-exception main.js -f etc/config.json -p 2021 -k 3021\" }\n{ \"time\": \"557568\", \"entity\": \"4\", \"state\": 17 }\n{ \"time\": \"558415\", \"entity\": \"49\", \"state\": 0, \"tag\": \"497cdd3\" }\n{ \"time\": \"559789\", \"entity\": \"53\", \"state\": 17 }\n{ \"time\": \"564353\", \"entity\": \"8\", \"state\": 0, \"tag\": \"48d4b75\" }\n{ \"time\": \"573039\", \"entity\": \"9\", \"state\": 17 }\n{ \"time\": \"576830\", \"entity\": \"53\", \"state\": 0, \"tag\": \"497cd9f\" }\n{ \"time\": \"578248\", \"entity\": \"46\", \"state\": 17 }\n{ \"time\": \"586259\", \"entity\": \"8\", \"state\": 17 }\n{ \"time\": \"586378\", \"entity\": \"36\", \"state\": 17 }\n{ \"time\": \"591726\", \"entity\": \"49\", \"state\": 17 }\n{ \"time\": \"594180\", \"entity\": \"49\", \"state\": 0, \"tag\": \"497cdd3\" }\n{ \"time\": \"606345\", \"entity\": \"31\", \"state\": 17 }\n{ \"time\": \"609029\", \"entity\": \"31\", \"state\": 0, \"tag\": \"49a7f46\" }\n{ \"time\": \"615014\", \"entity\": \"53\", \"state\": 17 }\n{ \"time\": \"623515\", \"entity\": \"53\", \"state\": 0, \"tag\": \"497cd9f\" }\n{ \"time\": \"635285\", \"entity\": \"45\", \"state\": 17 }\n{ \"time\": \"641951\", \"entity\": \"45\", \"state\": 0, \"tag\": \"49a7f2e\" }\n{ \"time\": \"642296\", \"entity\": \"31\", \"state\": 17 }\n{ \"time\": \"657898\", \"entity\": \"53\", \"state\": 17 }\n{ \"time\": \"658525\", \"entity\": \"52\", \"state\": 17 }\n{ \"time\": \"664378\", \"entity\": \"53\", \"state\": 0, \"tag\": \"497cd9f\" }\n{ \"time\": \"668175\", \"entity\": \"14\", \"state\": 0, \"tag\": \"4a0e388\" }\n{ \"time\": \"669848\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"671815\", \"entity\": \"22\", \"state\": 17 }\n{ \"time\": \"689085\", \"entity\": \"10\", \"state\": 17 }\n{ \"time\": \"696634\", \"entity\": \"49\", \"state\": 17 }\n{ \"time\": \"697889\", \"entity\": \"10\", \"state\": 0, \"tag\": \"497cdd0\" }\n{ \"time\": \"699569\", \"entity\": \"19\", \"state\": 17 }\n{ \"time\": \"703265\", \"entity\": \"14\", \"state\": 17 }\n{ \"time\": \"718505\", \"entity\": \"49\", \"state\": 0, \"tag\": \"497cdd3\" }\n{ \"time\": \"728522\", \"entity\": \"52\", \"state\": 17 }\n{ \"time\": \"735026\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"736636\", \"entity\": \"19\", \"state\": 0, \"tag\": \"49a7f32\" }\n{ \"time\": \"739400\", \"entity\": \"0\", \"state\": 15 }\n{ \"time\": \"743280\", \"entity\": \"0\", \"state\": 0, \"tag\": \"4a0e384\" }\n{ \"state\": 10, \"tag\": \"b\", \"driver\": \"softint\", \"instance\": 0 }\n{ \"time\": \"747031\", \"entity\": \"0\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"752452\", \"entity\": \"10\", \"state\": 17 }\n{ \"time\": \"752901\", \"entity\": \"53\", \"state\": 17 }\n{ \"time\": \"753787\", \"entity\": \"49\", \"state\": 17 }\n{ \"time\": \"754077\", \"entity\": \"16\", \"state\": 17 }\n{ \"time\": \"762849\", \"entity\": \"0\", \"state\": 0, \"tag\": \"4a0e384\" }\n{ \"time\": \"767901\", \"entity\": \"49\", \"state\": 0, \"tag\": \"497cdd3\" }\n{ \"time\": \"775953\", \"entity\": \"19\", \"state\": 17 }\n{ \"time\": \"785696\", \"entity\": \"49\", \"state\": 17 }\n{ \"time\": \"786067\", \"entity\": \"19\", \"state\": 0, \"tag\": \"49a7f32\" }\n{ \"time\": \"838177\", \"entity\": \"45\", \"state\": 17 }\n{ \"time\": \"901231\", \"entity\": \"45\", \"state\": 0, \"tag\": \"49a7f2e\" }\n{ \"time\": \"923069\", \"entity\": \"49\", \"state\": 0, \"tag\": \"497cdd3\" }\n{ \"time\": \"927589\", \"entity\": \"19\", \"state\": 17 }\n{ \"time\": \"938479\", \"entity\": \"19\", \"state\": 0, \"tag\": \"49a7f32\" }\n{ \"time\": \"947220\", \"entity\": \"31\", \"state\": 7, \"tag\": \"ffffd062dbcb7d58\" }\n{ \"time\": \"961419\", \"entity\": \"45\", \"state\": 17 }\n{ \"time\": \"966595\", \"entity\": \"45\", \"state\": 0, \"tag\": \"49a7f2e\" }\n{ \"time\": \"975225\", \"entity\": \"31\", \"state\": 17 }\n{ \"state\": 0, \"tag\": \"48d4ade\", \"pid\": \"5336\", \"tid\": \"1\", \"execname\": \"node\", \"psargs\": \"node --abort-on-uncaught-exception main.js -f etc/config.json -p 2021 -k 3021\" }\n{ \"time\": \"983732\", \"entity\": \"27\", \"state\": 0, \"tag\": \"48d4ade\" }\n{ \"time\": \"988698\", \"entity\": \"53\", \"state\": 0, \"tag\": \"497cd9f\" }\n{ \"time\": \"1006460\", \"entity\": \"10\", \"state\": 0, \"tag\": \"497cdd0\" }\n{ \"time\": \"1018551\", \"entity\": \"49\", \"state\": 17 }\n{ \"time\": \"1020723\", \"entity\": \"53\", \"state\": 17 }\n{ \"time\": \"1025056\", \"entity\": \"53\", \"state\": 0, \"tag\": \"497cd9f\" }\n{ \"time\": \"1029210\", \"entity\": \"49\", \"state\": 0, \"tag\": \"497cdd3\" }\n{ \"time\": \"1031701\", \"entity\": \"14\", \"state\": 0, \"tag\": \"4a0e388\" }\n{ \"state\": 0, \"tag\": \"48d4ae8\", \"pid\": \"5336\", \"tid\": \"2\", \"execname\": \"node\", \"psargs\": \"node --abort-on-uncaught-exception main.js -f etc/config.json -p 2021 -k 3021\" }\n{ \"time\": \"1040160\", \"entity\": \"52\", \"state\": 17 }\n{ \"time\": \"1045495\", \"entity\": \"21\", \"state\": 0, \"tag\": \"48d4ae8\" }\n{ \"time\": \"1053860\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"1056323\", \"entity\": \"22\", \"state\": 0, \"tag\": \"497cdd4\" }\n{ \"time\": \"1063767\", \"entity\": \"21\", \"state\": 17 }\n{ \"time\": \"1064227\", \"entity\": \"10\", \"state\": 17 }\n{ \"time\": \"1070591\", \"entity\": \"14\", \"state\": 17 }\n{ \"time\": \"1076581\", \"entity\": \"49\", \"state\": 17 }\n{ \"time\": \"1076899\", \"entity\": \"53\", \"state\": 17 }\n{ \"time\": \"1079487\", \"entity\": \"10\", \"state\": 0, \"tag\": \"497cdd0\" }\n{ \"time\": \"1085729\", \"entity\": \"49\", \"state\": 0, \"tag\": \"497cdd3\" }\n{ \"time\": \"1104374\", \"entity\": \"53\", \"state\": 0, \"tag\": \"497cd9f\" }\n{ \"time\": \"1113664\", \"entity\": \"52\", \"state\": 17 }\n{ \"time\": \"1117162\", \"entity\": \"53\", \"state\": 17 }\n{ \"time\": \"1119151\", \"entity\": \"31\", \"state\": 0, \"tag\": \"49a7f46\" }\n{ \"time\": \"1119914\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"1123006\", \"entity\": \"49\", \"state\": 17 }\n{ \"state\": 0, \"tag\": \"4a0e383\", \"pid\": \"50377\", \"tid\": \"1\", \"execname\": \"dtrace\", \"psargs\": \"/usr/sbin/dtrace -Cs ./cpu-statemap-tagged.d\" }\n{ \"time\": \"1128525\", \"entity\": \"16\", \"state\": 0, \"tag\": \"4a0e383\" }\n{ \"time\": \"1133011\", \"entity\": \"9\", \"state\": 16 }\n{ \"time\": \"1137190\", \"entity\": \"9\", \"state\": 17 }\n{ \"time\": \"1137845\", \"entity\": \"10\", \"state\": 17 }\n{ \"time\": \"1143092\", \"entity\": \"10\", \"state\": 16 }\n{ \"time\": \"1149172\", \"entity\": \"10\", \"state\": 17 }\n{ \"time\": \"1151888\", \"entity\": \"11\", \"state\": 16 }\n{ \"time\": \"1153362\", \"entity\": \"45\", \"state\": 17 }\n{ \"time\": \"1154832\", \"entity\": \"52\", \"state\": 17 }\n{ \"time\": \"1156133\", \"entity\": \"11\", \"state\": 17 }\n{ \"time\": \"1156908\", \"entity\": \"10\", \"state\": 0, \"tag\": \"497cdd0\" }\n{ \"time\": \"1159816\", \"entity\": \"12\", \"state\": 16 }\n{ \"time\": \"1160547\", \"entity\": \"30\", \"state\": 7, \"tag\": \"ffffd062dbcb7d58\" }\n{ \"time\": \"1162840\", \"entity\": \"12\", \"state\": 17 }\n{ \"time\": \"1166278\", \"entity\": \"19\", \"state\": 17 }\n{ \"time\": \"1166405\", \"entity\": \"13\", \"state\": 16 }\n{ \"time\": \"1170340\", \"entity\": \"22\", \"state\": 17 }\n{ \"time\": \"1171318\", \"entity\": \"13\", \"state\": 17 }\n{ \"time\": \"1173640\", \"entity\": \"30\", \"state\": 17 }\n{ \"time\": \"1173786\", \"entity\": \"14\", \"state\": 16 }\n{ \"time\": \"1177357\", \"entity\": \"14\", \"state\": 17 }\n{ \"state\": 0, \"tag\": \"48d4ced\", \"pid\": \"5737\", \"tid\": \"1\", \"execname\": \"node\", \"psargs\": \"node --abort-on-uncaught-exception main.js -f etc/config.json -p 2023 -k 3023\" }\n{ \"time\": \"1184808\", \"entity\": \"15\", \"state\": 0, \"tag\": \"48d4ced\" }\n{ \"time\": \"1188092\", \"entity\": \"15\", \"state\": 16 }\n{ \"time\": \"1192735\", \"entity\": \"15\", \"state\": 0, \"tag\": \"48d4ced\" }\n{ \"time\": \"1201969\", \"entity\": \"22\", \"state\": 0, \"tag\": \"497cdd4\" }\n{ \"time\": \"1205236\", \"entity\": \"17\", \"state\": 16 }\n{ \"time\": \"1213509\", \"entity\": \"17\", \"state\": 17 }\n{ \"time\": \"1214693\", \"entity\": \"18\", \"state\": 16 }\n{ \"time\": \"1217933\", \"entity\": \"31\", \"state\": 17 }\n{ \"time\": \"1218025\", \"entity\": \"18\", \"state\": 17 }\n{ \"time\": \"1222783\", \"entity\": \"19\", \"state\": 16 }\n{ \"time\": \"1223052\", \"entity\": \"31\", \"state\": 0, \"tag\": \"49a7f46\" }\n{ \"time\": \"1231369\", \"entity\": \"19\", \"state\": 17 }\n{ \"time\": \"1234496\", \"entity\": \"20\", \"state\": 16 }\n{ \"state\": 0, \"tag\": \"48d4d00\", \"pid\": \"5737\", \"tid\": \"2\", \"execname\": \"node\", \"psargs\": \"node --abort-on-uncaught-exception main.js -f etc/config.json -p 2023 -k 3023\" }\n{ \"time\": \"1239245\", \"entity\": \"20\", \"state\": 17 }\n{ \"time\": \"1239831\", \"entity\": \"22\", \"state\": 17 }\n{ \"time\": \"1240063\", \"entity\": \"19\", \"state\": 0, \"tag\": \"49a7f32\" }\n{ \"time\": \"1241645\", \"entity\": \"21\", \"state\": 16 }\n{ \"time\": \"1242848\", \"entity\": \"41\", \"state\": 0, \"tag\": \"48d4d00\" }\n{ \"time\": \"1247578\", \"entity\": \"21\", \"state\": 17 }\n{ \"time\": \"1250339\", \"entity\": \"22\", \"state\": 16 }\n{ \"time\": \"1254272\", \"entity\": \"22\", \"state\": 17 }\n{ \"time\": \"1254559\", \"entity\": \"41\", \"state\": 17 }\n{ \"time\": \"1256915\", \"entity\": \"23\", \"state\": 16 }\n{ \"time\": \"1261109\", \"entity\": \"23\", \"state\": 17 }\n{ \"time\": \"1264991\", \"entity\": \"22\", \"state\": 0, \"tag\": \"497cdd4\" }\n{ \"time\": \"1265886\", \"entity\": \"24\", \"state\": 16 }\n{ \"state\": 0, \"tag\": \"497d20a\", \"pid\": \"566150\", \"tid\": \"1\", \"execname\": \"postgres\", \"psargs\": \"/opt/postgresql/9.6.3/bin/postgres -D /manatee/pg/data\" }\n{ \"time\": \"1274130\", \"entity\": \"24\", \"state\": 17 }\n{ \"time\": \"1275439\", \"entity\": \"25\", \"state\": 16 }\n{ \"time\": \"1278104\", \"entity\": \"2\", \"state\": 0, \"tag\": \"497d20a\" }\n{ \"time\": \"1280783\", \"entity\": \"25\", \"state\": 17 }\n{ \"time\": \"1284410\", \"entity\": \"26\", \"state\": 16 }\n{ \"time\": \"1285340\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"1290577\", \"entity\": \"26\", \"state\": 17 }\n{ \"time\": \"1293829\", \"entity\": \"27\", \"state\": 16 }\n{ \"time\": \"1299840\", \"entity\": \"27\", \"state\": 0, \"tag\": \"48d4ade\" }\n{ \"time\": \"1301420\", \"entity\": \"22\", \"state\": 17 }\n{ \"time\": \"1302605\", \"entity\": \"28\", \"state\": 16 }\n{ \"time\": \"1305409\", \"entity\": \"22\", \"state\": 0, \"tag\": \"497cdd4\" }\n{ \"time\": \"1307933\", \"entity\": \"28\", \"state\": 17 }\n{ \"time\": \"1311223\", \"entity\": \"29\", \"state\": 16 }\n{ \"time\": \"1318349\", \"entity\": \"29\", \"state\": 0, \"tag\": \"48d4b6d\" }\n{ \"time\": \"1320548\", \"entity\": \"30\", \"state\": 16 }\n{ \"time\": \"1324450\", \"entity\": \"30\", \"state\": 17 }\n{ \"time\": \"1326355\", \"entity\": \"31\", \"state\": 17 }\n{ \"time\": \"1328330\", \"entity\": \"45\", \"state\": 0, \"tag\": \"49a7f2e\" }\n{ \"time\": \"1328586\", \"entity\": \"22\", \"state\": 17 }\n{ \"time\": \"1328695\", \"entity\": \"31\", \"state\": 16 }\n{ \"time\": \"1332677\", \"entity\": \"31\", \"state\": 17 }\n{ \"time\": \"1336344\", \"entity\": \"32\", \"state\": 16 }\n{ \"time\": \"1340039\", \"entity\": \"32\", \"state\": 17 }\n{ \"time\": \"1342203\", \"entity\": \"33\", \"state\": 16 }\n{ \"time\": \"1345521\", \"entity\": \"33\", \"state\": 17 }\n{ \"time\": \"1349615\", \"entity\": \"34\", \"state\": 16 }\n{ \"time\": \"1354008\", \"entity\": \"34\", \"state\": 17 }\n{ \"time\": \"1356043\", \"entity\": \"35\", \"state\": 16 }\n{ \"time\": \"1359384\", \"entity\": \"35\", \"state\": 17 }\n{ \"time\": \"1361625\", \"entity\": \"22\", \"state\": 0, \"tag\": \"497cdd4\" }\n{ \"time\": \"1362681\", \"entity\": \"36\", \"state\": 16 }\n{ \"time\": \"1366323\", \"entity\": \"36\", \"state\": 17 }\n{ \"time\": \"1367733\", \"entity\": \"30\", \"state\": 7, \"tag\": \"ffffd062dbcb7d58\" }\n{ \"time\": \"1369031\", \"entity\": \"45\", \"state\": 17 }\n{ \"time\": \"1369266\", \"entity\": \"37\", \"state\": 16 }\n{ \"time\": \"1372514\", \"entity\": \"37\", \"state\": 17 }\n{ \"time\": \"1378625\", \"entity\": \"38\", \"state\": 16 }\n{ \"time\": \"1379993\", \"entity\": \"2\", \"state\": 17 }\n{ \"time\": \"1386771\", \"entity\": \"30\", \"state\": 17 }\n{ \"time\": \"1387798\", \"entity\": \"38\", \"state\": 17 }\n{ \"time\": \"1387821\", \"entity\": \"22\", \"state\": 17 }\n{ \"time\": \"1388067\", \"entity\": \"39\", \"state\": 16 }\n{ \"time\": \"1388228\", \"entity\": \"45\", \"state\": 0, \"tag\": \"49a7f2e\" }\n{ \"time\": \"1391467\", \"entity\": \"39\", \"state\": 17 }\n{ \"time\": \"1393949\", \"entity\": \"40\", \"state\": 16 }\n{ \"time\": \"1395988\", \"entity\": \"40\", \"state\": 17 }\n{ \"time\": \"1399028\", \"entity\": \"41\", \"state\": 16 }\n{ \"time\": \"1402723\", \"entity\": \"41\", \"state\": 17 }\n{ \"time\": \"1406240\", \"entity\": \"42\", \"state\": 16 }\n{ \"time\": \"1408563\", \"entity\": \"42\", \"state\": 17 }\n{ \"time\": \"1412926\", \"entity\": \"43\", \"state\": 16 }\n{ \"time\": \"1418481\", \"entity\": \"22\", \"state\": 0, \"tag\": \"497cdd4\" }\n{ \"time\": \"1418781\", \"entity\": \"43\", \"state\": 17 }\n{ \"time\": \"1421034\", \"entity\": \"44\", \"state\": 16 }\n{ \"time\": \"1424874\", \"entity\": \"14\", \"state\": 0, \"tag\": \"4a0e388\" }\n{ \"time\": \"1424927\", \"entity\": \"44\", \"state\": 17 }\n{ \"time\": \"1428749\", \"entity\": \"45\", \"state\": 16 }\n{ \"time\": \"1431809\", \"entity\": \"10\", \"state\": 17 }\n{ \"time\": \"1436972\", \"entity\": \"45\", \"state\": 0, \"tag\": \"49a7f2e\" }\n{ \"time\": \"1438380\", \"entity\": \"46\", \"state\": 16 }\n{ \"time\": \"1440527\", \"entity\": \"46\", \"state\": 17 }\n{ \"time\": \"1444400\", \"entity\": \"31\", \"state\": 0, \"tag\": \"49a7f46\" }\n{ \"time\": \"1448049\", \"entity\": \"47\", \"state\": 16 }\n{ \"time\": \"1449582\", \"entity\": \"10\", \"state\": 0, \"tag\": \"497cdd0\" }\n{ \"state\": 0, \"tag\": \"497d212\", \"pid\": \"566158\", \"tid\": \"1\", \"execname\": \"postgres\", \"psargs\": \"/opt/postgresql/9.6.3/bin/postgres -D /manatee/pg/data\" }\n{ \"time\": \"1456559\", \"entity\": \"37\", \"state\": 0, \"tag\": \"497d212\" }\n{ \"time\": \"1458812\", \"entity\": \"47\", \"state\": 17 }\n{ \"time\": \"1459196\", \"entity\": \"19\", \"state\": 17 }\n{ \"time\": \"1459808\", \"entity\": \"48\", \"state\": 16 }\n{ \"time\": \"1460858\", \"entity\": \"14\", \"state\": 17 }\n{ \"time\": \"1462700\", \"entity\": \"22\", \"state\": 17 }\n{ \"time\": \"1463447\", \"entity\": \"48\", \"state\": 1, \"tag\": \"3c4\" }\n{ \"time\": \"1466417\", \"entity\": \"49\", \"state\": 16 }\n{ \"time\": \"1469928\", \"entity\": \"49\", \"state\": 17 }\n{ \"time\": \"1475559\", \"entity\": \"50\", \"state\": 16 }\n{ \"time\": \"1476464\", \"entity\": \"22\", \"state\": 0, \"tag\": \"497cdd4\" }\n{ \"time\": \"1480197\", \"entity\": \"50\", \"state\": 17 }\n{ \"state\": 0, \"tag\": \"48d4e10\", \"pid\": \"5958\", \"tid\": \"1\", \"execname\": \"node\", \"psargs\": \"node --abort-on-uncaught-exception main.js -f etc/config.json -p 2024 -k 3024\" }\n{ \"time\": \"1481808\", \"entity\": \"51\", \"state\": 16 }\n{ \"time\": \"1484985\", \"entity\": \"51\", \"state\": 17 }\n{ \"time\": \"1490063\", \"entity\": \"52\", \"state\": 16 }\n{ \"time\": \"1491640\", \"entity\": \"45\", \"state\": 0, \"tag\": \"48d4e10\" }\n{ \"time\": \"1498337\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"1499681\", \"entity\": \"53\", \"state\": 16 }\n{ \"time\": \"1503542\", \"entity\": \"53\", \"state\": 17 }\n{ \"time\": \"1507553\", \"entity\": \"54\", \"state\": 16 }\n{ \"time\": \"1507610\", \"entity\": \"45\", \"state\": 0, \"tag\": \"49a7f2e\" }\n{ \"time\": \"1511913\", \"entity\": \"54\", \"state\": 17 }\n{ \"time\": \"1514247\", \"entity\": \"10\", \"state\": 17 }\n{ \"time\": \"1515873\", \"entity\": \"55\", \"state\": 16 }\n{ \"time\": \"1520140\", \"entity\": \"22\", \"state\": 17 }\n{ \"time\": \"1522315\", \"entity\": \"55\", \"state\": 17 }\n{ \"time\": \"1527856\", \"entity\": \"27\", \"state\": 17 }\n{ \"time\": \"1531660\", \"entity\": \"22\", \"state\": 0, \"tag\": \"497cdd4\" }\n{ \"time\": \"1540257\", \"entity\": \"10\", \"state\": 0, \"tag\": \"497cdd0\" }\n{ \"time\": \"1550117\", \"entity\": \"19\", \"state\": 0, \"tag\": \"49a7f32\" }\n{ \"time\": \"1557017\", \"entity\": \"31\", \"state\": 17 }\n{ \"time\": \"1563796\", \"entity\": \"27\", \"state\": 0, \"tag\": \"48d4ade\" }\n{ \"time\": \"1566090\", \"entity\": \"22\", \"state\": 17 }\n{ \"time\": \"1566148\", \"entity\": \"45\", \"state\": 0, \"tag\": \"48d4e10\" }\n{ \"time\": \"1566354\", \"entity\": \"52\", \"state\": 17 }\n{ \"time\": \"1568814\", \"entity\": \"2\", \"state\": 0, \"tag\": \"497d20a\" }\n{ \"time\": \"1570616\", \"entity\": \"9\", \"state\": 15 }\n{ \"time\": \"1571878\", \"entity\": \"46\", \"state\": 15 }\n{ \"time\": \"1573357\", \"entity\": \"22\", \"state\": 0, \"tag\": \"497cdd4\" }\n{ \"time\": \"1573496\", \"entity\": \"46\", \"state\": 17 }\n{ \"time\": \"1574862\", \"entity\": \"9\", \"state\": 17 }\n{ \"time\": \"1576428\", \"entity\": \"46\", \"state\": 3, \"tag\": \"2\" }\n{ \"time\": \"1576608\", \"entity\": \"37\", \"state\": 17 }\n{ \"time\": \"1578950\", \"entity\": \"8\", \"state\": 15 }\n{ \"time\": \"1579862\", \"entity\": \"9\", \"state\": 3, \"tag\": \"2\" }\n{ \"time\": \"1581274\", \"entity\": \"8\", \"state\": 17 }\n{ \"time\": \"1582362\", \"entity\": \"46\", \"state\": 17 }\n{ \"time\": \"1584227\", \"entity\": \"8\", \"state\": 3, \"tag\": \"2\" }\n{ \"time\": \"1586328\", \"entity\": \"46\", \"state\": 0, \"tag\": \"497cdd9\" }\n{ \"time\": \"1590277\", \"entity\": \"8\", \"state\": 17 }\n{ \"time\": \"1590464\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"1590591\", \"entity\": \"45\", \"state\": 0, \"tag\": \"49a7f2e\" }\n{ \"time\": \"1591543\", \"entity\": \"9\", \"state\": 17 }\n{ \"time\": \"1594956\", \"entity\": \"8\", \"state\": 0, \"tag\": \"48d4b75\" }\n{ \"time\": \"1600794\", \"entity\": \"29\", \"state\": 17 }\n{ \"time\": \"1601223\", \"entity\": \"9\", \"state\": 0, \"tag\": \"4980fc2\" }\n{ \"time\": \"1601876\", \"entity\": \"8\", \"state\": 17 }\n{ \"time\": \"1602851\", \"entity\": \"22\", \"state\": 17 }\n{ \"time\": \"1612606\", \"entity\": \"22\", \"state\": 0, \"tag\": \"497cdd4\" }\n{ \"time\": \"1619928\", \"entity\": \"10\", \"state\": 17 }\n{ \"time\": \"1621241\", \"entity\": \"31\", \"state\": 0, \"tag\": \"49a7f46\" }\n{ \"time\": \"1622825\", \"entity\": \"9\", \"state\": 17 }\n{ \"time\": \"1625312\", \"entity\": \"10\", \"state\": 0, \"tag\": \"497cdd0\" }\n{ \"time\": \"1639370\", \"entity\": \"9\", \"state\": 0, \"tag\": \"4980fc2\" }\n{ \"time\": \"1640702\", \"entity\": \"31\", \"state\": 17 }\n{ \"time\": \"1678850\", \"entity\": \"31\", \"state\": 0, \"tag\": \"49a7f46\" }\n{ \"time\": \"1680520\", \"entity\": \"49\", \"state\": 0, \"tag\": \"497cdd3\" }\n{ \"time\": \"1692340\", \"entity\": \"53\", \"state\": 0, \"tag\": \"497cd9f\" }\n{ \"time\": \"1694963\", \"entity\": \"36\", \"state\": 0, \"tag\": \"49a7f42\" }\n{ \"time\": \"1700982\", \"entity\": \"4\", \"state\": 0, \"tag\": \"49a7f49\" }\n{ \"time\": \"1706068\", \"entity\": \"46\", \"state\": 0, \"tag\": \"48d4e10\" }\n{ \"time\": \"1713100\", \"entity\": \"46\", \"state\": 0, \"tag\": \"497cdd9\" }\n{ \"time\": \"1717396\", \"entity\": \"31\", \"state\": 17 }\n{ \"time\": \"1718374\", \"entity\": \"1\", \"state\": 0, \"tag\": \"48d4e10\" }\n{ \"time\": \"1721948\", \"entity\": \"9\", \"state\": 16 }\n{ \"time\": \"1722376\", \"entity\": \"22\", \"state\": 16 }\n{ \"time\": \"1722398\", \"entity\": \"36\", \"state\": 16 }\n{ \"time\": \"1722545\", \"entity\": \"46\", \"state\": 16 }\n{ \"time\": \"1723026\", \"entity\": \"10\", \"state\": 16 }\n{ \"time\": \"1723152\", \"entity\": \"49\", \"state\": 16 }\n{ \"time\": \"1723829\", \"entity\": \"53\", \"state\": 16 }\n{ \"time\": \"1723893\", \"entity\": \"19\", \"state\": 16 }\n{ \"time\": \"1724110\", \"entity\": \"45\", \"state\": 16 }\n{ \"time\": \"1724830\", \"entity\": \"52\", \"state\": 16 }\n{ \"time\": \"1725469\", \"entity\": \"46\", \"state\": 0, \"tag\": \"497cdd9\" }\n{ \"time\": \"1725641\", \"entity\": \"49\", \"state\": 17 }\n{ \"time\": \"1725958\", \"entity\": \"36\", \"state\": 0, \"tag\": \"49a7f42\" }\n{ \"time\": \"1726469\", \"entity\": \"9\", \"state\": 0, \"tag\": \"4980fc2\" }\n{ \"time\": \"1726734\", \"entity\": \"22\", \"state\": 0, \"tag\": \"497cdd4\" }\n{ \"time\": \"1727245\", \"entity\": \"53\", \"state\": 0, \"tag\": \"497cd9f\" }\n{ \"time\": \"1727648\", \"entity\": \"37\", \"state\": 0, \"tag\": \"497d212\" }\n{ \"time\": \"1727681\", \"entity\": \"49\", \"state\": 17 }\n{ \"time\": \"1730123\", \"entity\": \"10\", \"state\": 0, \"tag\": \"497cdd0\" }\n{ \"time\": \"1730633\", \"entity\": \"19\", \"state\": 0, \"tag\": \"49a7f32\" }\n{ \"time\": \"1731250\", \"entity\": \"45\", \"state\": 0, \"tag\": \"49a7f2e\" }\n{ \"time\": \"1731403\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"1732151\", \"entity\": \"49\", \"state\": 0, \"tag\": \"497cdd3\" }\n{ \"time\": \"1739845\", \"entity\": \"0\", \"state\": 15 }\n{ \"time\": \"1746589\", \"entity\": \"0\", \"state\": 0, \"tag\": \"4a0e384\" }\n{ \"time\": \"1749918\", \"entity\": \"0\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"1751913\", \"entity\": \"31\", \"state\": 0, \"tag\": \"49a7f46\" }\n{ \"time\": \"1752389\", \"entity\": \"27\", \"state\": 17 }\n{ \"state\": 0, \"tag\": \"497d4e2\", \"pid\": \"566865\", \"tid\": \"1\", \"execname\": \"postgres\", \"psargs\": \"/opt/postgresql/9.6.3/bin/postgres -D /manatee/pg/data\" }\n{ \"time\": \"1755671\", \"entity\": \"36\", \"state\": 17 }\n{ \"time\": \"1758552\", \"entity\": \"36\", \"state\": 0, \"tag\": \"49a7f42\" }\n{ \"state\": 0, \"tag\": \"48d4e18\", \"pid\": \"5958\", \"tid\": \"2\", \"execname\": \"node\", \"psargs\": \"node --abort-on-uncaught-exception main.js -f etc/config.json -p 2024 -k 3024\" }\n{ \"time\": \"1767581\", \"entity\": \"50\", \"state\": 0, \"tag\": \"48d4e18\" }\n{ \"time\": \"1767920\", \"entity\": \"26\", \"state\": 0, \"tag\": \"497d4e2\" }\n{ \"time\": \"1768630\", \"entity\": \"19\", \"state\": 17 }\n{ \"time\": \"1774944\", \"entity\": \"47\", \"state\": 0, \"tag\": \"49a7f32\" }\n{ \"time\": \"1776434\", \"entity\": \"11\", \"state\": 0, \"tag\": \"497cdd1\" }\n{ \"time\": \"1778474\", \"entity\": \"0\", \"state\": 0, \"tag\": \"4a0e384\" }\n{ \"time\": \"1783434\", \"entity\": \"11\", \"state\": 17 }\n{ \"time\": \"1785617\", \"entity\": \"15\", \"state\": 17 }\n{ \"time\": \"1789972\", \"entity\": \"50\", \"state\": 17 }\n{ \"time\": \"1790371\", \"entity\": \"31\", \"state\": 17 }\n{ \"time\": \"1798662\", \"entity\": \"22\", \"state\": 17 }\n{ \"time\": \"1799659\", \"entity\": \"53\", \"state\": 17 }\n{ \"time\": \"1799775\", \"entity\": \"49\", \"state\": 17 }\n{ \"time\": \"1800147\", \"entity\": \"45\", \"state\": 17 }\n{ \"time\": \"1802644\", \"entity\": \"49\", \"state\": 0, \"tag\": \"497cdd3\" }\n{ \"time\": \"1804234\", \"entity\": \"9\", \"state\": 17 }\n{ \"time\": \"1804314\", \"entity\": \"17\", \"state\": 0, \"tag\": \"49a7f2e\" }\n{ \"time\": \"1815421\", \"entity\": \"52\", \"state\": 17 }\n{ \"time\": \"1831927\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"1842650\", \"entity\": \"49\", \"state\": 17 }\n{ \"time\": \"1853453\", \"entity\": \"46\", \"state\": 17 }\n{ \"time\": \"1854478\", \"entity\": \"47\", \"state\": 17 }\n{ \"time\": \"1857286\", \"entity\": \"46\", \"state\": 0, \"tag\": \"497cdd9\" }\n{ \"time\": \"1857662\", \"entity\": \"14\", \"state\": 0, \"tag\": \"4a0e388\" }\n{ \"time\": \"1860962\", \"entity\": \"47\", \"state\": 0, \"tag\": \"49a7f32\" }\n{ \"time\": \"1861543\", \"entity\": \"36\", \"state\": 17 }\n{ \"time\": \"1863742\", \"entity\": \"4\", \"state\": 17 }\n{ \"time\": \"1865505\", \"entity\": \"17\", \"state\": 17 }\n{ \"time\": \"1866888\", \"entity\": \"4\", \"state\": 0, \"tag\": \"49a7f49\" }\n{ \"time\": \"1868188\", \"entity\": \"46\", \"state\": 17 }\n{ \"time\": \"1885355\", \"entity\": \"10\", \"state\": 17 }\n{ \"time\": \"1891052\", \"entity\": \"10\", \"state\": 0, \"tag\": \"497cdd0\" }\n{ \"time\": \"1908947\", \"entity\": \"14\", \"state\": 17 }\n{ \"time\": \"1928141\", \"entity\": \"46\", \"state\": 0, \"tag\": \"497cdd9\" }\n{ \"time\": \"1973538\", \"entity\": \"4\", \"state\": 17 }\n{ \"time\": \"2013125\", \"entity\": \"4\", \"state\": 0, \"tag\": \"49a7f49\" }\n{ \"time\": \"2027694\", \"entity\": \"36\", \"state\": 0, \"tag\": \"49a7f42\" }\n{ \"time\": \"2034820\", \"entity\": \"17\", \"state\": 0, \"tag\": \"49a7f2e\" }\n{ \"time\": \"2051826\", \"entity\": \"46\", \"state\": 17 }\n{ \"time\": \"2057896\", \"entity\": \"21\", \"state\": 15 }\n{ \"time\": \"2060651\", \"entity\": \"36\", \"state\": 17 }\n{ \"time\": \"2061335\", \"entity\": \"21\", \"state\": 17 }\n{ \"time\": \"2063578\", \"entity\": \"36\", \"state\": 0, \"tag\": \"49a7f42\" }\n{ \"time\": \"2064235\", \"entity\": \"21\", \"state\": 3, \"tag\": \"2\" }\n{ \"time\": \"2068218\", \"entity\": \"4\", \"state\": 17 }\n{ \"time\": \"2070666\", \"entity\": \"21\", \"state\": 17 }\n{ \"time\": \"2076440\", \"entity\": \"21\", \"state\": 0, \"tag\": \"48d4ae8\" }\n{ \"time\": \"2084643\", \"entity\": \"21\", \"state\": 17 }\n{ \"time\": \"2088885\", \"entity\": \"47\", \"state\": 17 }\n{ \"time\": \"2095628\", \"entity\": \"47\", \"state\": 0, \"tag\": \"49a7f32\" }\n{ \"time\": \"2105539\", \"entity\": \"36\", \"state\": 17 }\n{ \"time\": \"2166276\", \"entity\": \"36\", \"state\": 0, \"tag\": \"49a7f42\" }\n{ \"time\": \"2201863\", \"entity\": \"4\", \"state\": 0, \"tag\": \"49a7f49\" }\n{ \"time\": \"2228637\", \"entity\": \"4\", \"state\": 17 }\n{ \"time\": \"2231212\", \"entity\": \"4\", \"state\": 0, \"tag\": \"49a7f49\" }\n{ \"time\": \"2249903\", \"entity\": \"4\", \"state\": 17 }\n{ \"time\": \"2251762\", \"entity\": \"41\", \"state\": 15 }\n{ \"time\": \"2253203\", \"entity\": \"41\", \"state\": 17 }\n{ \"time\": \"2255393\", \"entity\": \"41\", \"state\": 3, \"tag\": \"2\" }\n{ \"time\": \"2260551\", \"entity\": \"41\", \"state\": 17 }\n{ \"time\": \"2264500\", \"entity\": \"41\", \"state\": 0, \"tag\": \"48d4d00\" }\n{ \"time\": \"2269824\", \"entity\": \"41\", \"state\": 17 }\n{ \"time\": \"2284834\", \"entity\": \"10\", \"state\": 17 }\n{ \"time\": \"2291061\", \"entity\": \"52\", \"state\": 17 }\n{ \"time\": \"2301592\", \"entity\": \"29\", \"state\": 0, \"tag\": \"48d4b6d\" }\n{ \"time\": \"2305757\", \"entity\": \"2\", \"state\": 17 }\n{ \"state\": 0, \"tag\": \"497e0d4\", \"pid\": \"569380\", \"tid\": \"1\", \"execname\": \"postgres\", \"psargs\": \"/opt/postgresql/9.6.3/bin/postgres -D /manatee/pg/data\" }\n{ \"time\": \"2322704\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"2323720\", \"entity\": \"14\", \"state\": 0, \"tag\": \"4a0e388\" }\n{ \"time\": \"2327364\", \"entity\": \"19\", \"state\": 0, \"tag\": \"497e0d4\" }\n{ \"time\": \"2327891\", \"entity\": \"36\", \"state\": 17 }\n{ \"time\": \"2336478\", \"entity\": \"38\", \"state\": 0, \"tag\": \"48d4b75\" }\n{ \"time\": \"2350895\", \"entity\": \"1\", \"state\": 17 }\n{ \"time\": \"2360872\", \"entity\": \"38\", \"state\": 17 }\n{ \"time\": \"2362577\", \"entity\": \"14\", \"state\": 17 }\n{ \"time\": \"2373219\", \"entity\": \"36\", \"state\": 0, \"tag\": \"49a7f42\" }\n{ \"time\": \"2401842\", \"entity\": \"10\", \"state\": 0, \"tag\": \"497cdd0\" }\n{ \"time\": \"2410496\", \"entity\": \"52\", \"state\": 17 }\n{ \"time\": \"2410586\", \"entity\": \"47\", \"state\": 17 }\n{ \"time\": \"2445800\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"2446541\", \"entity\": \"27\", \"state\": 0, \"tag\": \"48d4ade\" }\n{ \"time\": \"2447611\", \"entity\": \"16\", \"state\": 17 }\n{ \"time\": \"2458415\", \"entity\": \"37\", \"state\": 17 }\n{ \"time\": \"2461516\", \"entity\": \"21\", \"state\": 0, \"tag\": \"48d4ae8\" }\n{ \"time\": \"2467039\", \"entity\": \"21\", \"state\": 17 }\n{ \"time\": \"2484067\", \"entity\": \"36\", \"state\": 17 }\n{ \"time\": \"2484984\", \"entity\": \"47\", \"state\": 0, \"tag\": \"49a7f32\" }\n{ \"time\": \"2487284\", \"entity\": \"52\", \"state\": 17 }\n{ \"time\": \"2491074\", \"entity\": \"2\", \"state\": 0, \"tag\": \"497d20a\" }\n{ \"time\": \"2511956\", \"entity\": \"2\", \"state\": 17 }\n{ \"time\": \"2530247\", \"entity\": \"15\", \"state\": 0, \"tag\": \"48d4ced\" }\n{ \"time\": \"2546597\", \"entity\": \"41\", \"state\": 0, \"tag\": \"48d4d00\" }\n{ \"time\": \"2551849\", \"entity\": \"41\", \"state\": 17 }\n{ \"time\": \"2553991\", \"entity\": \"26\", \"state\": 17 }\n{ \"time\": \"2598265\", \"entity\": \"37\", \"state\": 0, \"tag\": \"497d212\" }\n{ \"time\": \"2612822\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"2616846\", \"entity\": \"14\", \"state\": 0, \"tag\": \"4a0e388\" }\n{ \"time\": \"2618688\", \"entity\": \"37\", \"state\": 17 }\n{ \"time\": \"2624719\", \"entity\": \"10\", \"state\": 17 }\n{ \"time\": \"2628302\", \"entity\": \"17\", \"state\": 17 }\n{ \"time\": \"2652173\", \"entity\": \"14\", \"state\": 17 }\n{ \"time\": \"2698733\", \"entity\": \"26\", \"state\": 0, \"tag\": \"497d4e2\" }\n{ \"time\": \"2713062\", \"entity\": \"15\", \"state\": 17 }\n{ \"time\": \"2718744\", \"entity\": \"17\", \"state\": 0, \"tag\": \"49a7f2e\" }\n{ \"time\": \"2738856\", \"entity\": \"11\", \"state\": 15 }\n{ \"time\": \"2739184\", \"entity\": \"53\", \"state\": 15 }\n{ \"time\": \"2739223\", \"entity\": \"13\", \"state\": 15 }\n{ \"time\": \"2739227\", \"entity\": \"33\", \"state\": 15 }\n{ \"time\": \"2739356\", \"entity\": \"35\", \"state\": 15 }\n{ \"time\": \"2739437\", \"entity\": \"0\", \"state\": 15 }\n{ \"time\": \"2739444\", \"entity\": \"22\", \"state\": 15 }\n{ \"time\": \"2739524\", \"entity\": \"23\", \"state\": 15 }\n{ \"time\": \"2739527\", \"entity\": \"12\", \"state\": 15 }\n{ \"time\": \"2739800\", \"entity\": \"21\", \"state\": 15 }\n{ \"time\": \"2739816\", \"entity\": \"36\", \"state\": 15 }\n{ \"time\": \"2739819\", \"entity\": \"49\", \"state\": 15 }\n{ \"time\": \"2739830\", \"entity\": \"14\", \"state\": 15 }\n{ \"time\": \"2739847\", \"entity\": \"48\", \"state\": 15 }\n{ \"time\": \"2739980\", \"entity\": \"15\", \"state\": 15 }\n{ \"time\": \"2740110\", \"entity\": \"16\", \"state\": 15 }\n{ \"time\": \"2740137\", \"entity\": \"37\", \"state\": 15 }\n{ \"time\": \"2740149\", \"entity\": \"4\", \"state\": 15 }\n{ \"time\": \"2740488\", \"entity\": \"30\", \"state\": 15 }\n{ \"time\": \"2740512\", \"entity\": \"32\", \"state\": 15 }\n{ \"time\": \"2740623\", \"entity\": \"11\", \"state\": 17 }\n{ \"time\": \"2740924\", \"entity\": \"52\", \"state\": 15 }\n{ \"time\": \"2741143\", \"entity\": \"1\", \"state\": 15 }\n{ \"time\": \"2741149\", \"entity\": \"29\", \"state\": 15 }\n{ \"time\": \"2741154\", \"entity\": \"10\", \"state\": 15 }\n{ \"time\": \"2741427\", \"entity\": \"26\", \"state\": 15 }\n{ \"time\": \"2741623\", \"entity\": \"33\", \"state\": 17 }\n{ \"time\": \"2741668\", \"entity\": \"53\", \"state\": 17 }\n{ \"time\": \"2741898\", \"entity\": \"12\", \"state\": 17 }\n{ \"time\": \"2742244\", \"entity\": \"13\", \"state\": 17 }\n{ \"time\": \"2742964\", \"entity\": \"21\", \"state\": 17 }\n{ \"time\": \"2743620\", \"entity\": \"23\", \"state\": 17 }\n{ \"time\": \"2743646\", \"entity\": \"49\", \"state\": 17 }\n{ \"time\": \"2743658\", \"entity\": \"35\", \"state\": 17 }\n{ \"time\": \"2743684\", \"entity\": \"11\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2743960\", \"entity\": \"22\", \"state\": 17 }\n{ \"time\": \"2744663\", \"entity\": \"33\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2744680\", \"entity\": \"53\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2744789\", \"entity\": \"14\", \"state\": 17 }\n{ \"time\": \"2744980\", \"entity\": \"47\", \"state\": 15 }\n{ \"time\": \"2745068\", \"entity\": \"12\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2745110\", \"entity\": \"36\", \"state\": 17 }\n{ \"time\": \"2745119\", \"entity\": \"15\", \"state\": 17 }\n{ \"time\": \"2745444\", \"entity\": \"21\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2745609\", \"entity\": \"13\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2745804\", \"entity\": \"48\", \"state\": 1, \"tag\": \"3c4\" }\n{ \"time\": \"2746183\", \"entity\": \"0\", \"state\": 0, \"tag\": \"4a0e384\" }\n{ \"time\": \"2746302\", \"entity\": \"37\", \"state\": 17 }\n{ \"time\": \"2746306\", \"entity\": \"49\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2746344\", \"entity\": \"16\", \"state\": 17 }\n{ \"time\": \"2746428\", \"entity\": \"23\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2746493\", \"entity\": \"4\", \"state\": 17 }\n{ \"time\": \"2746496\", \"entity\": \"30\", \"state\": 17 }\n{ \"time\": \"2746569\", \"entity\": \"35\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2746608\", \"entity\": \"32\", \"state\": 17 }\n{ \"time\": \"2747310\", \"entity\": \"22\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2747848\", \"entity\": \"14\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2748202\", \"entity\": \"1\", \"state\": 17 }\n{ \"time\": \"2748519\", \"entity\": \"0\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2748767\", \"entity\": \"15\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2748842\", \"entity\": \"36\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2748989\", \"entity\": \"29\", \"state\": 0, \"tag\": \"48d4b6d\" }\n{ \"time\": \"2749477\", \"entity\": \"10\", \"state\": 17 }\n{ \"time\": \"2749892\", \"entity\": \"30\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2749933\", \"entity\": \"16\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2750103\", \"entity\": \"48\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2750214\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"2750477\", \"entity\": \"4\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2750480\", \"entity\": \"32\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2750619\", \"entity\": \"37\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2751894\", \"entity\": \"26\", \"state\": 0, \"tag\": \"497d4e2\" }\n{ \"time\": \"2752222\", \"entity\": \"12\", \"state\": 17 }\n{ \"time\": \"2753033\", \"entity\": \"29\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2753036\", \"entity\": \"1\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2753619\", \"entity\": \"33\", \"state\": 17 }\n{ \"time\": \"2754750\", \"entity\": \"11\", \"state\": 17 }\n{ \"time\": \"2756235\", \"entity\": \"14\", \"state\": 17 }\n{ \"time\": \"2756564\", \"entity\": \"52\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2756724\", \"entity\": \"10\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2757240\", \"entity\": \"37\", \"state\": 17 }\n{ \"time\": \"2757510\", \"entity\": \"47\", \"state\": 0, \"tag\": \"49a7f32\" }\n{ \"time\": \"2758979\", \"entity\": \"16\", \"state\": 17 }\n{ \"time\": \"2758984\", \"entity\": \"26\", \"state\": 11, \"tag\": \"a\" }\n{ \"state\": 1, \"tag\": \"508\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"time\": \"2762129\", \"entity\": \"0\", \"state\": 0, \"tag\": \"4a0e384\" }\n{ \"time\": \"2763958\", \"entity\": \"29\", \"state\": 0, \"tag\": \"48d4b6d\" }\n{ \"time\": \"2763992\", \"entity\": \"0\", \"state\": 3, \"tag\": \"2\" }\n{ \"time\": \"2764529\", \"entity\": \"48\", \"state\": 1, \"tag\": \"3c4\" }\n{ \"state\": 1, \"tag\": \"506\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"state\": 1, \"tag\": \"56b\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"time\": \"2765826\", \"entity\": \"0\", \"state\": 0, \"tag\": \"4a0e384\" }\n{ \"state\": 1, \"tag\": \"50c\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"time\": \"2766634\", \"entity\": \"47\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2769168\", \"entity\": \"8\", \"state\": 1, \"tag\": \"508\" }\n{ \"time\": \"2769369\", \"entity\": \"15\", \"state\": 17 }\n{ \"time\": \"2769781\", \"entity\": \"16\", \"state\": 1, \"tag\": \"56b\" }\n{ \"time\": \"2770167\", \"entity\": \"50\", \"state\": 1, \"tag\": \"50c\" }\n{ \"time\": \"2770906\", \"entity\": \"11\", \"state\": 1, \"tag\": \"506\" }\n{ \"state\": 1, \"tag\": \"572\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"time\": \"2775305\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"2775728\", \"entity\": \"10\", \"state\": 17 }\n{ \"state\": 1, \"tag\": \"589\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"state\": 1, \"tag\": \"511\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"time\": \"2778446\", \"entity\": \"32\", \"state\": 17 }\n{ \"state\": 1, \"tag\": \"563\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"state\": 1, \"tag\": \"588\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"time\": \"2779948\", \"entity\": \"6\", \"state\": 1, \"tag\": \"572\" }\n{ \"time\": \"2781106\", \"entity\": \"11\", \"state\": 15 }\n{ \"state\": 1, \"tag\": \"50f\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"state\": 1, \"tag\": \"591\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"time\": \"2781550\", \"entity\": \"18\", \"state\": 1, \"tag\": \"589\" }\n{ \"time\": \"2782610\", \"entity\": \"31\", \"state\": 1, \"tag\": \"563\" }\n{ \"time\": \"2782633\", \"entity\": \"8\", \"state\": 1, \"tag\": \"588\" }\n{ \"time\": \"2783057\", \"entity\": \"11\", \"state\": 1, \"tag\": \"506\" }\n{ \"time\": \"2783200\", \"entity\": \"20\", \"state\": 1, \"tag\": \"511\" }\n{ \"time\": \"2784164\", \"entity\": \"50\", \"state\": 1, \"tag\": \"591\" }\n{ \"state\": 1, \"tag\": \"568\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"time\": \"2785196\", \"entity\": \"11\", \"state\": 3, \"tag\": \"2\" }\n{ \"state\": 1, \"tag\": \"505\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"time\": \"2786380\", \"entity\": \"43\", \"state\": 1, \"tag\": \"50f\" }\n{ \"time\": \"2786979\", \"entity\": \"50\", \"state\": 15 }\n{ \"time\": \"2787490\", \"entity\": \"13\", \"state\": 17 }\n{ \"time\": \"2787981\", \"entity\": \"10\", \"state\": 0, \"tag\": \"497cdd0\" }\n{ \"state\": 1, \"tag\": \"494\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"time\": \"2789225\", \"entity\": \"32\", \"state\": 1, \"tag\": \"568\" }\n{ \"state\": 1, \"tag\": \"50b\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"time\": \"2789603\", \"entity\": \"11\", \"state\": 1, \"tag\": \"506\" }\n{ \"time\": \"2790250\", \"entity\": \"8\", \"state\": 17 }\n{ \"time\": \"2791044\", \"entity\": \"50\", \"state\": 1, \"tag\": \"591\" }\n{ \"state\": 1, \"tag\": \"50a\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"time\": \"2791330\", \"entity\": \"18\", \"state\": 17 }\n{ \"state\": 1, \"tag\": \"3a3\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"time\": \"2793174\", \"entity\": \"12\", \"state\": 1, \"tag\": \"50b\" }\n{ \"time\": \"2794514\", \"entity\": \"15\", \"state\": 1, \"tag\": \"50a\" }\n{ \"state\": 1, \"tag\": \"586\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"state\": 1, \"tag\": \"332\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"state\": 1, \"tag\": \"1a1\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"state\": 1, \"tag\": \"431\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"time\": \"2795661\", \"entity\": \"52\", \"state\": 1, \"tag\": \"494\" }\n{ \"time\": \"2795818\", \"entity\": \"24\", \"state\": 1, \"tag\": \"505\" }\n{ \"time\": \"2795870\", \"entity\": \"50\", \"state\": 3, \"tag\": \"2\" }\n{ \"time\": \"2796195\", \"entity\": \"32\", \"state\": 17 }\n{ \"state\": 1, \"tag\": \"149\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"time\": \"2796791\", \"entity\": \"6\", \"state\": 17 }\n{ \"time\": \"2796948\", \"entity\": \"31\", \"state\": 1, \"tag\": \"332\" }\n{ \"time\": \"2796998\", \"entity\": \"47\", \"state\": 0, \"tag\": \"49a7f32\" }\n{ \"state\": 1, \"tag\": \"2fc\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"time\": \"2797170\", \"entity\": \"20\", \"state\": 17 }\n{ \"time\": \"2797844\", \"entity\": \"22\", \"state\": 17 }\n{ \"time\": \"2798008\", \"entity\": \"13\", \"state\": 1, \"tag\": \"1a1\" }\n{ \"time\": \"2798180\", \"entity\": \"46\", \"state\": 1, \"tag\": \"431\" }\n{ \"state\": 1, \"tag\": \"53d\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"time\": \"2799503\", \"entity\": \"8\", \"state\": 1, \"tag\": \"149\" }\n{ \"time\": \"2799946\", \"entity\": \"9\", \"state\": 1, \"tag\": \"586\" }\n{ \"time\": \"2800495\", \"entity\": \"38\", \"state\": 1, \"tag\": \"3a3\" }\n{ \"time\": \"2801241\", \"entity\": \"43\", \"state\": 1, \"tag\": \"53d\" }\n{ \"time\": \"2801891\", \"entity\": \"50\", \"state\": 1, \"tag\": \"591\" }\n{ \"time\": \"2802030\", \"entity\": \"28\", \"state\": 1, \"tag\": \"2fc\" }\n{ \"time\": \"2802203\", \"entity\": \"11\", \"state\": 17 }\n{ \"time\": \"2802513\", \"entity\": \"15\", \"state\": 17 }\n{ \"time\": \"2804148\", \"entity\": \"22\", \"state\": 0, \"tag\": \"48d4e18\" }\n{ \"time\": \"2804983\", \"entity\": \"12\", \"state\": 17 }\n{ \"state\": 1, \"tag\": \"159\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"state\": 1, \"tag\": \"3c4\", \"thread\": \"zfs`dbuf_evict_thread\", \"taskq\": \"<none>\" }\n{ \"state\": 1, \"tag\": \"454\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"time\": \"2807716\", \"entity\": \"21\", \"state\": 17 }\n{ \"state\": 1, \"tag\": \"532\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"time\": \"2809330\", \"entity\": \"46\", \"state\": 1, \"tag\": \"3c4\" }\n{ \"time\": \"2809907\", \"entity\": \"9\", \"state\": 1, \"tag\": \"159\" }\n{ \"time\": \"2809959\", \"entity\": \"48\", \"state\": 1, \"tag\": \"454\" }\n{ \"state\": 1, \"tag\": \"401\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"time\": \"2812244\", \"entity\": \"22\", \"state\": 17 }\n{ \"time\": \"2812381\", \"entity\": \"38\", \"state\": 17 }\n{ \"time\": \"2812838\", \"entity\": \"50\", \"state\": 1, \"tag\": \"532\" }\n{ \"state\": 1, \"tag\": \"441\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"time\": \"2813618\", \"entity\": \"43\", \"state\": 1, \"tag\": \"401\" }\n{ \"time\": \"2813635\", \"entity\": \"24\", \"state\": 17 }\n{ \"time\": \"2813655\", \"entity\": \"4\", \"state\": 17 }\n{ \"state\": 1, \"tag\": \"201\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"time\": \"2816419\", \"entity\": \"31\", \"state\": 17 }\n{ \"state\": 1, \"tag\": \"109\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"state\": 1, \"tag\": \"4f0\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"state\": 7, \"tag\": \"ffffd062dbd3caa0\", \"driver\": \"ixgbe\", \"instance\": 0 }\n{ \"time\": \"2817983\", \"entity\": \"13\", \"state\": 17 }\n{ \"time\": \"2818893\", \"entity\": \"4\", \"state\": 1, \"tag\": \"109\" }\n{ \"time\": \"2819739\", \"entity\": \"35\", \"state\": 17 }\n{ \"state\": 1, \"tag\": \"56f\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"time\": \"2820521\", \"entity\": \"44\", \"state\": 1, \"tag\": \"4f0\" }\n{ \"state\": 1, \"tag\": \"474\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"time\": \"2820846\", \"entity\": \"31\", \"state\": 7, \"tag\": \"ffffd062dbcb7d58\" }\n{ \"time\": \"2821964\", \"entity\": \"4\", \"state\": 17 }\n{ \"time\": \"2822271\", \"entity\": \"47\", \"state\": 1, \"tag\": \"441\" }\n{ \"time\": \"2823215\", \"entity\": \"19\", \"state\": 1, \"tag\": \"201\" }\n{ \"time\": \"2823281\", \"entity\": \"28\", \"state\": 17 }\n{ \"time\": \"2823339\", \"entity\": \"50\", \"state\": 1, \"tag\": \"474\" }\n{ \"time\": \"2824040\", \"entity\": \"22\", \"state\": 1, \"tag\": \"56f\" }\n{ \"time\": \"2824727\", \"entity\": \"8\", \"state\": 17 }\n{ \"time\": \"2825090\", \"entity\": \"20\", \"state\": 7, \"tag\": \"ffffd062dbd3caa0\" }\n{ \"time\": \"2826403\", \"entity\": \"35\", \"state\": 7, \"tag\": \"ffffd062dbcb7d58\" }\n{ \"time\": \"2827341\", \"entity\": \"15\", \"state\": 7, \"tag\": \"ffffd062dbd3caa0\" }\n{ \"time\": \"2827641\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"2828147\", \"entity\": \"31\", \"state\": 17 }\n{ \"time\": \"2828240\", \"entity\": \"44\", \"state\": 17 }\n{ \"time\": \"2828434\", \"entity\": \"48\", \"state\": 17 }\n{ \"time\": \"2828810\", \"entity\": \"13\", \"state\": 7, \"tag\": \"ffffd062dbd3caa0\" }\n{ \"time\": \"2828928\", \"entity\": \"18\", \"state\": 7, \"tag\": \"ffffd062dbd3caa0\" }\n{ \"state\": 1, \"tag\": \"231\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"time\": \"2831848\", \"entity\": \"32\", \"state\": 7, \"tag\": \"ffffd062dbcb7d58\" }\n{ \"state\": 1, \"tag\": \"3b3\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"time\": \"2832759\", \"entity\": \"9\", \"state\": 17 }\n{ \"time\": \"2833726\", \"entity\": \"22\", \"state\": 1, \"tag\": \"231\" }\n{ \"time\": \"2834743\", \"entity\": \"39\", \"state\": 1, \"tag\": \"3b3\" }\n{ \"time\": \"2834868\", \"entity\": \"52\", \"state\": 17 }\n{ \"time\": \"2835340\", \"entity\": \"41\", \"state\": 0, \"tag\": \"497d212\" }\n{ \"time\": \"2836018\", \"entity\": \"20\", \"state\": 17 }\n{ \"time\": \"2836192\", \"entity\": \"15\", \"state\": 17 }\n{ \"time\": \"2836248\", \"entity\": \"35\", \"state\": 17 }\n{ \"time\": \"2836415\", \"entity\": \"19\", \"state\": 0, \"tag\": \"497e0d4\" }\n{ \"time\": \"2837835\", \"entity\": \"22\", \"state\": 17 }\n{ \"time\": \"2838427\", \"entity\": \"13\", \"state\": 17 }\n{ \"state\": 1, \"tag\": \"55c\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"state\": 1, \"tag\": \"421\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"time\": \"2841934\", \"entity\": \"50\", \"state\": 17 }\n{ \"time\": \"2842485\", \"entity\": \"16\", \"state\": 17 }\n{ \"time\": \"2842632\", \"entity\": \"43\", \"state\": 17 }\n{ \"time\": \"2842769\", \"entity\": \"26\", \"state\": 0, \"tag\": \"497d4e2\" }\n{ \"time\": \"2843248\", \"entity\": \"32\", \"state\": 17 }\n{ \"time\": \"2843749\", \"entity\": \"15\", \"state\": 1, \"tag\": \"55c\" }\n{ \"time\": \"2844586\", \"entity\": \"18\", \"state\": 17 }\n{ \"time\": \"2849706\", \"entity\": \"47\", \"state\": 0, \"tag\": \"49a7f32\" }\n{ \"time\": \"2850475\", \"entity\": \"23\", \"state\": 17 }\n{ \"state\": 1, \"tag\": \"547\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"time\": \"2851926\", \"entity\": \"45\", \"state\": 1, \"tag\": \"421\" }\n{ \"time\": \"2853387\", \"entity\": \"15\", \"state\": 17 }\n{ \"state\": 1, \"tag\": \"139\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"time\": \"2854482\", \"entity\": \"18\", \"state\": 1, \"tag\": \"547\" }\n{ \"time\": \"2857892\", \"entity\": \"27\", \"state\": 17 }\n{ \"time\": \"2858407\", \"entity\": \"7\", \"state\": 1, \"tag\": \"139\" }\n{ \"time\": \"2858890\", \"entity\": \"39\", \"state\": 17 }\n{ \"time\": \"2861162\", \"entity\": \"18\", \"state\": 17 }\n{ \"time\": \"2865228\", \"entity\": \"15\", \"state\": 0, \"tag\": \"49a7f32\" }\n{ \"time\": \"2865239\", \"entity\": \"47\", \"state\": 17 }\n{ \"time\": \"2874241\", \"entity\": \"20\", \"state\": 7, \"tag\": \"ffffd062dbd3caa0\" }\n{ \"time\": \"2877147\", \"entity\": \"20\", \"state\": 17 }\n{ \"time\": \"2878100\", \"entity\": \"18\", \"state\": 7, \"tag\": \"ffffd062dbd3caa0\" }\n{ \"time\": \"2878417\", \"entity\": \"49\", \"state\": 17 }\n{ \"time\": \"2880266\", \"entity\": \"13\", \"state\": 7, \"tag\": \"ffffd062dbd3caa0\" }\n{ \"state\": 1, \"tag\": \"58a\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"state\": 1, \"tag\": \"48c0687\", \"thread\": \"mac`mac_srs_worker\", \"taskq\": \"<none>\" }\n{ \"time\": \"2881471\", \"entity\": \"7\", \"state\": 17 }\n{ \"time\": \"2882394\", \"entity\": \"4\", \"state\": 1, \"tag\": \"58a\" }\n{ \"time\": \"2882699\", \"entity\": \"18\", \"state\": 17 }\n{ \"time\": \"2884819\", \"entity\": \"21\", \"state\": 1, \"tag\": \"48c0687\" }\n{ \"time\": \"2885368\", \"entity\": \"13\", \"state\": 17 }\n{ \"time\": \"2892650\", \"entity\": \"4\", \"state\": 17 }\n{ \"state\": 0, \"tag\": \"497cdc5\", \"pid\": \"565220\", \"tid\": \"1\", \"execname\": \"postgres\", \"psargs\": \"/opt/postgresql/9.6.3/bin/postgres -D /manatee/pg/data\" }\n{ \"state\": 1, \"tag\": \"119\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"time\": \"2895882\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"2896922\", \"entity\": \"21\", \"state\": 17 }\n{ \"time\": \"2898855\", \"entity\": \"23\", \"state\": 0, \"tag\": \"497cdc5\" }\n{ \"time\": \"2899081\", \"entity\": \"5\", \"state\": 1, \"tag\": \"119\" }\n{ \"state\": 1, \"tag\": \"2\", \"driver\": \"softint\", \"instance\": 0 }\n{ \"time\": \"2904722\", \"entity\": \"23\", \"state\": 2, \"tag\": \"1\" }\n{ \"time\": \"2905416\", \"entity\": \"45\", \"state\": 17 }\n{ \"state\": 1, \"tag\": \"353\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"time\": \"2908478\", \"entity\": \"23\", \"state\": 0, \"tag\": \"497cdc5\" }\n{ \"time\": \"2909051\", \"entity\": \"53\", \"state\": 17 }\n{ \"state\": 1, \"tag\": \"592\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"time\": \"2910797\", \"entity\": \"33\", \"state\": 1, \"tag\": \"353\" }\n{ \"time\": \"2912119\", \"entity\": \"11\", \"state\": 0, \"tag\": \"497cdd1\" }\n{ \"time\": \"2913138\", \"entity\": \"15\", \"state\": 1, \"tag\": \"592\" }\n{ \"time\": \"2914211\", \"entity\": \"29\", \"state\": 17 }\n{ \"time\": \"2918243\", \"entity\": \"1\", \"state\": 17 }\n{ \"time\": \"2918569\", \"entity\": \"33\", \"state\": 17 }\n{ \"state\": 1, \"tag\": \"4e9\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"state\": 1, \"tag\": \"245\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"time\": \"2921512\", \"entity\": \"15\", \"state\": 17 }\n{ \"time\": \"2921746\", \"entity\": \"5\", \"state\": 17 }\n{ \"time\": \"2923567\", \"entity\": \"52\", \"state\": 2, \"tag\": \"1\" }\n{ \"time\": \"2923665\", \"entity\": \"23\", \"state\": 1, \"tag\": \"245\" }\n{ \"time\": \"2923828\", \"entity\": \"29\", \"state\": 1, \"tag\": \"4e9\" }\n{ \"time\": \"2924126\", \"entity\": \"36\", \"state\": 17 }\n{ \"state\": 1, \"tag\": \"570\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"time\": \"2926812\", \"entity\": \"43\", \"state\": 0, \"tag\": \"48d4ced\" }\n{ \"time\": \"2927055\", \"entity\": \"15\", \"state\": 0, \"tag\": \"49a7f32\" }\n{ \"time\": \"2927485\", \"entity\": \"5\", \"state\": 1, \"tag\": \"570\" }\n{ \"state\": 1, \"tag\": \"1b1\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"state\": 1, \"tag\": \"ae\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"time\": \"2930823\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"2931655\", \"entity\": \"14\", \"state\": 1, \"tag\": \"1b1\" }\n{ \"time\": \"2932169\", \"entity\": \"29\", \"state\": 17 }\n{ \"time\": \"2933048\", \"entity\": \"15\", \"state\": 17 }\n{ \"time\": \"2933676\", \"entity\": \"5\", \"state\": 17 }\n{ \"state\": 1, \"tag\": \"343\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"time\": \"2934343\", \"entity\": \"1\", \"state\": 1, \"tag\": \"ae\" }\n{ \"time\": \"2934772\", \"entity\": \"14\", \"state\": 17 }\n{ \"time\": \"2936066\", \"entity\": \"32\", \"state\": 1, \"tag\": \"343\" }\n{ \"time\": \"2936210\", \"entity\": \"26\", \"state\": 17 }\n{ \"time\": \"2939460\", \"entity\": \"52\", \"state\": 1, \"tag\": \"494\" }\n{ \"time\": \"2939597\", \"entity\": \"1\", \"state\": 17 }\n{ \"time\": \"2940588\", \"entity\": \"32\", \"state\": 17 }\n{ \"time\": \"2943613\", \"entity\": \"23\", \"state\": 0, \"tag\": \"497cdc5\" }\n{ \"time\": \"2946897\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"2954837\", \"entity\": \"30\", \"state\": 17 }\n{ \"state\": 1, \"tag\": \"565\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"time\": \"2959792\", \"entity\": \"15\", \"state\": 1, \"tag\": \"565\" }\n{ \"time\": \"2968711\", \"entity\": \"28\", \"state\": 1, \"tag\": \"2fc\" }\n{ \"time\": \"2971712\", \"entity\": \"15\", \"state\": 0, \"tag\": \"49a7f32\" }\n{ \"time\": \"2971952\", \"entity\": \"13\", \"state\": 1, \"tag\": \"1a1\" }\n{ \"time\": \"2974959\", \"entity\": \"36\", \"state\": 0, \"tag\": \"49a7f42\" }\n{ \"time\": \"2982979\", \"entity\": \"14\", \"state\": 0, \"tag\": \"4a0e388\" }\n{ \"time\": \"2983981\", \"entity\": \"34\", \"state\": 7, \"tag\": \"ffffd062dbcb7d58\" }\n{ \"time\": \"2986129\", \"entity\": \"28\", \"state\": 17 }\n{ \"time\": \"2990466\", \"entity\": \"16\", \"state\": 7, \"tag\": \"ffffd062dbd3caa0\" }\n{ \"time\": \"2994684\", \"entity\": \"34\", \"state\": 17 }\n{ \"time\": \"2998520\", \"entity\": \"16\", \"state\": 17 }\n{ \"time\": \"2999276\", \"entity\": \"18\", \"state\": 0, \"tag\": \"497cdd9\" }\n{ \"time\": \"3000587\", \"entity\": \"13\", \"state\": 17 }\n{ \"state\": 1, \"tag\": \"d7\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"time\": \"3004848\", \"entity\": \"16\", \"state\": 0, \"tag\": \"497d20a\" }\n{ \"time\": \"3004920\", \"entity\": \"2\", \"state\": 1, \"tag\": \"d7\" }\n{ \"time\": \"3005728\", \"entity\": \"49\", \"state\": 0, \"tag\": \"497cdd3\" }\n{ \"time\": \"3018074\", \"entity\": \"23\", \"state\": 17 }\n{ \"time\": \"3019107\", \"entity\": \"2\", \"state\": 17 }\n{ \"time\": \"3023591\", \"entity\": \"15\", \"state\": 7, \"tag\": \"ffffd062dbd3caa0\" }\n{ \"time\": \"3023621\", \"entity\": \"10\", \"state\": 17 }\n{ \"time\": \"3026750\", \"entity\": \"14\", \"state\": 17 }\n{ \"time\": \"3029498\", \"entity\": \"38\", \"state\": 0, \"tag\": \"497cdd0\" }\n{ \"time\": \"3029791\", \"entity\": \"11\", \"state\": 17 }\n{ \"time\": \"3033399\", \"entity\": \"15\", \"state\": 0, \"tag\": \"49a7f32\" }\n{ \"time\": \"3034832\", \"entity\": \"11\", \"state\": 0, \"tag\": \"497cdd1\" }\n{ \"time\": \"3042504\", \"entity\": \"14\", \"state\": 0, \"tag\": \"4a0e388\" }\n{ \"time\": \"3050698\", \"entity\": \"15\", \"state\": 17 }\n{ \"time\": \"3059843\", \"entity\": \"15\", \"state\": 0, \"tag\": \"49a7f32\" }\n{ \"time\": \"3067142\", \"entity\": \"14\", \"state\": 17 }\n{ \"time\": \"3087009\", \"entity\": \"9\", \"state\": 0, \"tag\": \"4980fc2\" }\n{ \"time\": \"3091275\", \"entity\": \"36\", \"state\": 17 }\n{ \"time\": \"3100875\", \"entity\": \"26\", \"state\": 0, \"tag\": \"497d4e2\" }\n{ \"time\": \"3103179\", \"entity\": \"38\", \"state\": 17 }\n{ \"time\": \"3112559\", \"entity\": \"38\", \"state\": 0, \"tag\": \"497cdd0\" }\n{ \"time\": \"3130384\", \"entity\": \"49\", \"state\": 17 }\n{ \"time\": \"3130852\", \"entity\": \"36\", \"state\": 0, \"tag\": \"49a7f42\" }\n{ \"time\": \"3144079\", \"entity\": \"52\", \"state\": 17 }\n{ \"time\": \"3148229\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"3148920\", \"entity\": \"9\", \"state\": 17 }\n{ \"time\": \"3152479\", \"entity\": \"43\", \"state\": 17 }\n{ \"time\": \"3159520\", \"entity\": \"18\", \"state\": 17 }\n{ \"time\": \"3163635\", \"entity\": \"18\", \"state\": 0, \"tag\": \"497cdd9\" }\n{ \"time\": \"3164268\", \"entity\": \"9\", \"state\": 0, \"tag\": \"4980fc2\" }\n{ \"time\": \"3165294\", \"entity\": \"43\", \"state\": 0, \"tag\": \"48d4ced\" }\n{ \"time\": \"3168555\", \"entity\": \"14\", \"state\": 0, \"tag\": \"4a0e388\" }\n{ \"time\": \"3171006\", \"entity\": \"11\", \"state\": 17 }\n{ \"state\": 1, \"tag\": \"3ecbe54\", \"thread\": \"mac`mac_srs_worker\", \"taskq\": \"<none>\" }\n{ \"time\": \"3183242\", \"entity\": \"52\", \"state\": 17 }\n{ \"time\": \"3183692\", \"entity\": \"11\", \"state\": 0, \"tag\": \"497cdd1\" }\n{ \"time\": \"3183796\", \"entity\": \"33\", \"state\": 1, \"tag\": \"3ecbe54\" }\n{ \"time\": \"3186062\", \"entity\": \"26\", \"state\": 17 }\n{ \"time\": \"3191125\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"3193820\", \"entity\": \"33\", \"state\": 17 }\n{ \"time\": \"3203137\", \"entity\": \"49\", \"state\": 0, \"tag\": \"497cdd3\" }\n{ \"time\": \"3207620\", \"entity\": \"14\", \"state\": 17 }\n{ \"time\": \"3208377\", \"entity\": \"11\", \"state\": 17 }\n{ \"time\": \"3209779\", \"entity\": \"9\", \"state\": 17 }\n{ \"time\": \"3228662\", \"entity\": \"15\", \"state\": 17 }\n{ \"time\": \"3233904\", \"entity\": \"15\", \"state\": 0, \"tag\": \"49a7f32\" }\n{ \"time\": \"3239573\", \"entity\": \"1\", \"state\": 0, \"tag\": \"48d4e10\" }\n{ \"time\": \"3242310\", \"entity\": \"9\", \"state\": 0, \"tag\": \"4980fc2\" }\n{ \"time\": \"3247045\", \"entity\": \"4\", \"state\": 15 }\n{ \"time\": \"3249062\", \"entity\": \"4\", \"state\": 17 }\n{ \"time\": \"3250489\", \"entity\": \"4\", \"state\": 3, \"tag\": \"2\" }\n{ \"time\": \"3254343\", \"entity\": \"52\", \"state\": 17 }\n{ \"time\": \"3254565\", \"entity\": \"4\", \"state\": 17 }\n{ \"time\": \"3257853\", \"entity\": \"4\", \"state\": 0, \"tag\": \"49a7f49\" }\n{ \"time\": \"3260479\", \"entity\": \"22\", \"state\": 0, \"tag\": \"48d4e18\" }\n{ \"time\": \"3261954\", \"entity\": \"19\", \"state\": 17 }\n{ \"time\": \"3266829\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"3267804\", \"entity\": \"22\", \"state\": 17 }\n{ \"time\": \"3270503\", \"entity\": \"4\", \"state\": 16 }\n{ \"time\": \"3271940\", \"entity\": \"9\", \"state\": 16 }\n{ \"time\": \"3272354\", \"entity\": \"15\", \"state\": 16 }\n{ \"time\": \"3272791\", \"entity\": \"18\", \"state\": 16 }\n{ \"time\": \"3272865\", \"entity\": \"4\", \"state\": 0, \"tag\": \"49a7f49\" }\n{ \"time\": \"3273096\", \"entity\": \"52\", \"state\": 16 }\n{ \"time\": \"3273281\", \"entity\": \"49\", \"state\": 16 }\n{ \"time\": \"3274285\", \"entity\": \"17\", \"state\": 16 }\n{ \"time\": \"3274728\", \"entity\": \"38\", \"state\": 16 }\n{ \"time\": \"3277012\", \"entity\": \"9\", \"state\": 0, \"tag\": \"4980fc2\" }\n{ \"time\": \"3277370\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"3277741\", \"entity\": \"49\", \"state\": 0, \"tag\": \"497cdd3\" }\n{ \"time\": \"3278500\", \"entity\": \"15\", \"state\": 0, \"tag\": \"49a7f32\" }\n{ \"time\": \"3278837\", \"entity\": \"18\", \"state\": 0, \"tag\": \"497cdd9\" }\n{ \"time\": \"3282801\", \"entity\": \"15\", \"state\": 17 }\n{ \"time\": \"3283385\", \"entity\": \"17\", \"state\": 0, \"tag\": \"49a7f2e\" }\n{ \"time\": \"3284342\", \"entity\": \"38\", \"state\": 0, \"tag\": \"497cdd0\" }\n{ \"time\": \"3296061\", \"entity\": \"9\", \"state\": 17 }\n{ \"time\": \"3297797\", \"entity\": \"4\", \"state\": 17 }\n{ \"time\": \"3306163\", \"entity\": \"18\", \"state\": 17 }\n{ \"time\": \"3309408\", \"entity\": \"6\", \"state\": 0, \"tag\": \"497cdd9\" }\n{ \"time\": \"3316172\", \"entity\": \"4\", \"state\": 0, \"tag\": \"49a7f49\" }\n{ \"time\": \"3331918\", \"entity\": \"17\", \"state\": 17 }\n{ \"time\": \"3339615\", \"entity\": \"17\", \"state\": 0, \"tag\": \"49a7f2e\" }\n{ \"time\": \"3340029\", \"entity\": \"15\", \"state\": 0, \"tag\": \"49a7f32\" }\n{ \"time\": \"3343966\", \"entity\": \"38\", \"state\": 17 }\n{ \"time\": \"3347924\", \"entity\": \"49\", \"state\": 17 }\n{ \"time\": \"3352143\", \"entity\": \"38\", \"state\": 15 }\n{ \"time\": \"3352954\", \"entity\": \"4\", \"state\": 17 }\n"
  },
  {
    "path": "tst/tst.tag_redefined.in",
    "content": "{\n\t\"start\": [ 1528482355, 856625707 ],\n\t\"title\": \"Statemap for CPU activity on HA8S7MRD2\",\n\t\"host\": \"HA8S7MRD2\",\n\t\"entityKind\": \"CPU\",\n\t\"states\": {\n\t\t\"uthread\": {\"value\": 0, \"color\": \"#9BC362\" },\n\t\t\"kthread\": {\"value\": 1, \"color\": \"#2E4E00\" },\n\t\t\"level-1\": {\"value\": 2, \"color\": \"#689D99\" },\n\t\t\"level-2\": {\"value\": 3, \"color\": \"#41837E\" },\n\t\t\"level-3\": {\"value\": 4, \"color\": \"#236863\" },\n\t\t\"level-4\": {\"value\": 5, \"color\": \"#0D4E4A\" },\n\t\t\"level-5\": {\"value\": 6, \"color\": \"#003430\" },\n\t\t\"level-6\": {\"value\": 7, \"color\": \"#817FB2\" },\n\t\t\"level-7\": {\"value\": 8, \"color\": \"#575594\" },\n\t\t\"level-8\": {\"value\": 9, \"color\": \"#363377\" },\n\t\t\"level-9\": {\"value\": 10, \"color\": \"#1C1A59\" },\n\t\t\"level-10\": {\"value\": 11, \"color\": \"#0A093B\" },\n\t\t\"level-11\": {\"value\": 12, \"color\": \"#FFAAAA\" },\n\t\t\"level-12\": {\"value\": 13, \"color\": \"#D46A6A\" },\n\t\t\"level-13\": {\"value\": 14, \"color\": \"#AA3939\" },\n\t\t\"level-14\": {\"value\": 15, \"color\": \"#801515\" },\n\t\t\"level-15\": {\"value\": 16, \"color\": \"#550000\" },\n\t\t\"idle\": {\"value\": 17, \"color\": \"#e0e0e0\" }\n\t}\n}\n{ \"time\": \"133694\", \"entity\": \"14\", \"state\": 17 }\n{ \"time\": \"133726\", \"entity\": \"0\", \"state\": 17 }\n{ \"time\": \"133731\", \"entity\": \"8\", \"state\": 17 }\n{ \"time\": \"133776\", \"entity\": \"12\", \"state\": 17 }\n{ \"time\": \"133779\", \"entity\": \"28\", \"state\": 17 }\n{ \"time\": \"133783\", \"entity\": \"20\", \"state\": 17 }\n{ \"time\": \"133819\", \"entity\": \"18\", \"state\": 17 }\n{ \"time\": \"133859\", \"entity\": \"5\", \"state\": 17 }\n{ \"time\": \"133863\", \"entity\": \"22\", \"state\": 17 }\n{ \"time\": \"133888\", \"entity\": \"11\", \"state\": 17 }\n{ \"time\": \"133917\", \"entity\": \"7\", \"state\": 17 }\n{ \"time\": \"133961\", \"entity\": \"3\", \"state\": 17 }\n{ \"time\": \"133979\", \"entity\": \"21\", \"state\": 17 }\n{ \"time\": \"134574\", \"entity\": \"9\", \"state\": 17 }\n{ \"time\": \"135203\", \"entity\": \"35\", \"state\": 17 }\n{ \"time\": \"136037\", \"entity\": \"4\", \"state\": 0, \"tag\": \"49a7f49\" }\n{ \"time\": \"136389\", \"entity\": \"31\", \"state\": 17 }\n{ \"time\": \"136724\", \"entity\": \"17\", \"state\": 17 }\n{ \"time\": \"137094\", \"entity\": \"40\", \"state\": 17 }\n{ \"time\": \"137133\", \"entity\": \"46\", \"state\": 17 }\n{ \"time\": \"137348\", \"entity\": \"13\", \"state\": 17 }\n{ \"time\": \"137701\", \"entity\": \"6\", \"state\": 17 }\n{ \"time\": \"138148\", \"entity\": \"29\", \"state\": 17 }\n{ \"time\": \"138234\", \"entity\": \"1\", \"state\": 17 }\n{ \"time\": \"138244\", \"entity\": \"44\", \"state\": 17 }\n{ \"time\": \"139739\", \"entity\": \"41\", \"state\": 0, \"tag\": \"49a7f3e\" }\n{ \"time\": \"139979\", \"entity\": \"37\", \"state\": 17 }\n{ \"time\": \"141144\", \"entity\": \"25\", \"state\": 17 }\n{ \"time\": \"141240\", \"entity\": \"53\", \"state\": 17 }\n{ \"time\": \"141384\", \"entity\": \"32\", \"state\": 17 }\n{ \"time\": \"141553\", \"entity\": \"39\", \"state\": 17 }\n{ \"time\": \"141598\", \"entity\": \"45\", \"state\": 0, \"tag\": \"49a7f2e\" }\n{ \"time\": \"141960\", \"entity\": \"55\", \"state\": 17 }\n{ \"time\": \"141978\", \"entity\": \"27\", \"state\": 17 }\n{ \"time\": \"142181\", \"entity\": \"10\", \"state\": 17 }\n{ \"time\": \"142336\", \"entity\": \"28\", \"state\": 15 }\n{ \"time\": \"142496\", \"entity\": \"51\", \"state\": 17 }\n{ \"time\": \"142744\", \"entity\": \"23\", \"state\": 17 }\n{ \"time\": \"143454\", \"entity\": \"19\", \"state\": 17 }\n{ \"time\": \"143551\", \"entity\": \"47\", \"state\": 17 }\n{ \"time\": \"143638\", \"entity\": \"30\", \"state\": 17 }\n{ \"time\": \"144457\", \"entity\": \"33\", \"state\": 17 }\n{ \"time\": \"144680\", \"entity\": \"43\", \"state\": 17 }\n{ \"time\": \"144739\", \"entity\": \"15\", \"state\": 17 }\n{ \"time\": \"144784\", \"entity\": \"36\", \"state\": 17 }\n{ \"time\": \"145279\", \"entity\": \"50\", \"state\": 17 }\n{ \"time\": \"145292\", \"entity\": \"49\", \"state\": 0, \"tag\": \"497cdd3\" }\n{ \"time\": \"145567\", \"entity\": \"42\", \"state\": 17 }\n{ \"time\": \"146407\", \"entity\": \"48\", \"state\": 1, \"tag\": \"3c4\" }\n{ \"time\": \"148558\", \"entity\": \"34\", \"state\": 17 }\n{ \"time\": \"148758\", \"entity\": \"38\", \"state\": 17 }\n{ \"time\": \"149461\", \"entity\": \"26\", \"state\": 17 }\n{ \"time\": \"149464\", \"entity\": \"54\", \"state\": 17 }\n{ \"time\": \"149917\", \"entity\": \"28\", \"state\": 17 }\n{ \"time\": \"151111\", \"entity\": \"24\", \"state\": 17 }  \n{ \"state\": 2, \"tag\": \"3\", \"driver\": \"softint\", \"instance\": 0 }\n{ \"time\": \"151161\", \"entity\": \"52\", \"state\": 17 }\n{ \"time\": \"158287\", \"entity\": \"28\", \"state\": 3, \"tag\": \"2\" }\n{ \"time\": \"159063\", \"entity\": \"49\", \"state\": 17 }\n{ \"state\": 0, \"tag\": \"4a0e384\", \"pid\": \"50378\", \"tid\": \"1\", \"execname\": \"dtrace\", \"psargs\": \"/usr/sbin/dtrace -Cs ./postgres-statemap-zfs.d\" }\n{ \"time\": \"170534\", \"entity\": \"28\", \"state\": 17 }\n{ \"time\": \"173279\", \"entity\": \"0\", \"state\": 0, \"tag\": \"4a0e384\" }\n{ \"state\": 0, \"tag\": \"49a7f42\", \"pid\": \"565192\", \"tid\": \"66\", \"execname\": \"pg_prefaulter\", \"psargs\": \"/opt/smartdc/manatee/bin/pg_prefaulter run --config=/opt/smartdc/manatee/etc/pg\" }\n{ \"time\": \"184732\", \"entity\": \"28\", \"state\": 0, \"tag\": \"49a7f42\" }\n{ \"time\": \"198289\", \"entity\": \"4\", \"state\": 17 }\n{ \"state\": 0, \"tag\": \"49a7f49\", \"pid\": \"565192\", \"tid\": \"74\", \"execname\": \"pg_prefaulter\", \"psargs\": \"/opt/smartdc/manatee/bin/pg_prefaulter run --config=/opt/smartdc/manatee/etc/pg\" }\n{ \"time\": \"215317\", \"entity\": \"4\", \"state\": 0, \"tag\": \"49a7f49\" }\n{ \"state\": 0, \"tag\": \"497cdd3\", \"pid\": \"565192\", \"tid\": \"19\", \"execname\": \"pg_prefaulter\", \"psargs\": \"/opt/smartdc/manatee/bin/pg_prefaulter run --config=/opt/smartdc/manatee/etc/pg\" }\n{ \"time\": \"236759\", \"entity\": \"28\", \"state\": 17 }\n{ \"time\": \"240371\", \"entity\": \"36\", \"state\": 0, \"tag\": \"49a7f42\" }\n{ \"time\": \"245952\", \"entity\": \"49\", \"state\": 0, \"tag\": \"497cdd3\" }\n{ \"time\": \"251572\", \"entity\": \"52\", \"state\": 15 }\n{ \"time\": \"256407\", \"entity\": \"4\", \"state\": 17 }\n{ \"time\": \"257895\", \"entity\": \"52\", \"state\": 17 }\n{ \"time\": \"263286\", \"entity\": \"52\", \"state\": 3, \"tag\": \"2\" }\n{ \"time\": \"273170\", \"entity\": \"4\", \"state\": 0, \"tag\": \"49a7f49\" }\n{ \"time\": \"275226\", \"entity\": \"52\", \"state\": 17 }\n{ \"state\": 0, \"tag\": \"49a7f45\", \"pid\": \"565192\", \"tid\": \"70\", \"execname\": \"pg_prefaulter\", \"psargs\": \"/opt/smartdc/manatee/bin/pg_prefaulter run --config=/opt/smartdc/manatee/etc/pg\" }\n{ \"state\": 0, \"tag\": \"49a7f32\", \"pid\": \"565192\", \"tid\": \"51\", \"execname\": \"pg_prefaulter\", \"psargs\": \"/opt/smartdc/manatee/bin/pg_prefaulter run --config=/opt/smartdc/manatee/etc/pg\" }\n{ \"time\": \"296823\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"298706\", \"entity\": \"0\", \"state\": 16 }\n{ \"time\": \"299990\", \"entity\": \"19\", \"state\": 0, \"tag\": \"49a7f32\" }\n{ \"state\": 0, \"tag\": \"49a7f46\", \"pid\": \"565192\", \"tid\": \"71\", \"execname\": \"pg_prefaulter\", \"psargs\": \"/opt/smartdc/manatee/bin/pg_prefaulter run --config=/opt/smartdc/manatee/etc/pg\" }\n{ \"time\": \"303706\", \"entity\": \"0\", \"state\": 0, \"tag\": \"4a0e384\" }\n{ \"time\": \"307335\", \"entity\": \"31\", \"state\": 0, \"tag\": \"49a7f46\" }\n{ \"state\": 0, \"tag\": \"497cdd0\", \"pid\": \"565192\", \"tid\": \"16\", \"execname\": \"pg_prefaulter\", \"psargs\": \"/opt/smartdc/manatee/bin/pg_prefaulter run --config=/opt/smartdc/manatee/etc/pg\" }\n{ \"state\": 0, \"tag\": \"4a0e388\", \"pid\": \"50380\", \"tid\": \"1\", \"execname\": \"pg_xlogdump\", \"psargs\": \"/opt/postgresql/current/bin/pg_xlogdump -f /manatee/pg/data/pg_xlog/00000001000\" }\n{ \"time\": \"311412\", \"entity\": \"4\", \"state\": 17 }\n{ \"time\": \"312858\", \"entity\": \"36\", \"state\": 17 }\n{ \"time\": \"315103\", \"entity\": \"1\", \"state\": 16 }\n{ \"time\": \"315435\", \"entity\": \"14\", \"state\": 0, \"tag\": \"4a0e388\" }\n{ \"time\": \"320596\", \"entity\": \"10\", \"state\": 0, \"tag\": \"497cdd0\" }\n{ \"time\": \"323738\", \"entity\": \"1\", \"state\": 17 }\n{ \"time\": \"324471\", \"entity\": \"41\", \"state\": 17 }\n{ \"time\": \"327464\", \"entity\": \"2\", \"state\": 16 }\n{ \"state\": 0, \"tag\": \"49a7f3e\", \"pid\": \"565192\", \"tid\": \"63\", \"execname\": \"pg_prefaulter\", \"psargs\": \"/opt/smartdc/manatee/bin/pg_prefaulter run --config=/opt/smartdc/manatee/etc/pg\" }\n{ \"time\": \"330894\", \"entity\": \"2\", \"state\": 17 }\n{ \"time\": \"333404\", \"entity\": \"41\", \"state\": 0, \"tag\": \"49a7f3e\" }\n{ \"time\": \"335503\", \"entity\": \"3\", \"state\": 16 }\n{ \"time\": \"341680\", \"entity\": \"3\", \"state\": 17 }\n{ \"time\": \"344099\", \"entity\": \"4\", \"state\": 16 }\n{ \"time\": \"347527\", \"entity\": \"45\", \"state\": 17 }\n{ \"time\": \"347942\", \"entity\": \"4\", \"state\": 17 }\n{ \"time\": \"351280\", \"entity\": \"5\", \"state\": 16 }\n{ \"state\": 0, \"tag\": \"49a7f2e\", \"pid\": \"565192\", \"tid\": \"47\", \"execname\": \"pg_prefaulter\", \"psargs\": \"/opt/smartdc/manatee/bin/pg_prefaulter run --config=/opt/smartdc/manatee/etc/pg\" }\n{ \"time\": \"355510\", \"entity\": \"5\", \"state\": 17 }\n{ \"time\": \"357571\", \"entity\": \"19\", \"state\": 17 }\n{ \"time\": \"359891\", \"entity\": \"6\", \"state\": 16 }\n{ \"time\": \"360586\", \"entity\": \"49\", \"state\": 17 }\n{ \"time\": \"365971\", \"entity\": \"6\", \"state\": 17 }\n{ \"time\": \"367461\", \"entity\": \"45\", \"state\": 0, \"tag\": \"49a7f2e\" }\n{ \"time\": \"368755\", \"entity\": \"7\", \"state\": 16 }\n{ \"time\": \"368815\", \"entity\": \"31\", \"state\": 16 }\n{ \"time\": \"369961\", \"entity\": \"10\", \"state\": 16 }\n{ \"time\": \"370707\", \"entity\": \"52\", \"state\": 16 }\n{ \"time\": \"371639\", \"entity\": \"31\", \"state\": 0, \"tag\": \"49a7f46\" }\n{ \"time\": \"372586\", \"entity\": \"7\", \"state\": 17 }\n{ \"time\": \"372850\", \"entity\": \"14\", \"state\": 17 }\n{ \"time\": \"373621\", \"entity\": \"45\", \"state\": 16 }\n{ \"time\": \"375707\", \"entity\": \"8\", \"state\": 16 }\n{ \"time\": \"377134\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"377401\", \"entity\": \"10\", \"state\": 0, \"tag\": \"497cdd0\" }\n{ \"time\": \"379466\", \"entity\": \"8\", \"state\": 17 }\n{ \"time\": \"380914\", \"entity\": \"45\", \"state\": 0, \"tag\": \"49a7f2e\" }\n{ \"time\": \"413422\", \"entity\": \"31\", \"state\": 17 }\n{ \"time\": \"449800\", \"entity\": \"31\", \"state\": 0, \"tag\": \"49a7f46\" }\n{ \"time\": \"450431\", \"entity\": \"49\", \"state\": 0, \"tag\": \"497cdd3\" }\n{ \"state\": 7, \"tag\": \"ffffd062dbcb7d58\", \"driver\": \"ixgbe\", \"instance\": 2 }\n{ \"time\": \"468924\", \"entity\": \"36\", \"state\": 0, \"tag\": \"49a7f42\" }\n{ \"time\": \"469468\", \"entity\": \"30\", \"state\": 7, \"tag\": \"ffffd062dbcb7d58\" }\n{ \"time\": \"470025\", \"entity\": \"19\", \"state\": 0, \"tag\": \"49a7f32\" }\n{ \"time\": \"471607\", \"entity\": \"4\", \"state\": 0, \"tag\": \"49a7f49\" }\n{ \"time\": \"477875\", \"entity\": \"10\", \"state\": 17 }\n{ \"time\": \"484799\", \"entity\": \"10\", \"state\": 0, \"tag\": \"497cdd0\" }\n{ \"state\": 0, \"tag\": \"497cdd1\", \"pid\": \"565192\", \"tid\": \"17\", \"execname\": \"pg_prefaulter\", \"psargs\": \"/opt/smartdc/manatee/bin/pg_prefaulter run --config=/opt/smartdc/manatee/etc/pg\" }\n{ \"time\": \"485897\", \"entity\": \"4\", \"state\": 17 }\n{ \"time\": \"491362\", \"entity\": \"31\", \"state\": 17 }\n{ \"time\": \"491825\", \"entity\": \"11\", \"state\": 0, \"tag\": \"497cdd1\" }\n{ \"time\": \"492884\", \"entity\": \"30\", \"state\": 17 }\n{ \"time\": \"496488\", \"entity\": \"31\", \"state\": 0, \"tag\": \"49a7f46\" }\n{ \"state\": 0, \"tag\": \"48d4b6d\", \"pid\": \"5447\", \"tid\": \"1\", \"execname\": \"node\", \"psargs\": \"node --abort-on-uncaught-exception main.js -f etc/config.json -p 2021 -k 3021\" }\n{ \"time\": \"503227\", \"entity\": \"4\", \"state\": 0, \"tag\": \"49a7f49\" }\n{ \"time\": \"503832\", \"entity\": \"29\", \"state\": 0, \"tag\": \"48d4b6d\" }\n{ \"time\": \"506328\", \"entity\": \"11\", \"state\": 17 }\n{ \"time\": \"509977\", \"entity\": \"11\", \"state\": 0, \"tag\": \"497cdd1\" }\n{ \"state\": 0, \"tag\": \"497cdd4\", \"pid\": \"565192\", \"tid\": \"20\", \"execname\": \"pg_prefaulter\", \"psargs\": \"/opt/smartdc/manatee/bin/pg_prefaulter run --config=/opt/smartdc/manatee/etc/pg\" }\n{ \"time\": \"523775\", \"entity\": \"22\", \"state\": 0, \"tag\": \"497cdd4\" }\n{ \"state\": 0, \"tag\": \"497cd9f\", \"pid\": \"565192\", \"tid\": \"1\", \"execname\": \"pg_prefaulter\", \"psargs\": \"/opt/smartdc/manatee/bin/pg_prefaulter run --config=/opt/smartdc/manatee/etc/pg\" }\n{ \"time\": \"532235\", \"entity\": \"53\", \"state\": 0, \"tag\": \"497cd9f\" }\n{ \"state\": 0, \"tag\": \"4980fc2\", \"pid\": \"565192\", \"tid\": \"27\", \"execname\": \"pg_prefaulter\", \"psargs\": \"/opt/smartdc/manatee/bin/pg_prefaulter run --config=/opt/smartdc/manatee/etc/pg\" }\n{ \"state\": 0, \"tag\": \"497cdd9\", \"pid\": \"565192\", \"tid\": \"24\", \"execname\": \"pg_prefaulter\", \"psargs\": \"/opt/smartdc/manatee/bin/pg_prefaulter run --config=/opt/smartdc/manatee/etc/pg\" }\n{ \"time\": \"542614\", \"entity\": \"9\", \"state\": 0, \"tag\": \"4980fc2\" }\n{ \"time\": \"546541\", \"entity\": \"46\", \"state\": 0, \"tag\": \"497cdd9\" }\n{ \"time\": \"547085\", \"entity\": \"41\", \"state\": 17 }\n{ \"time\": \"549434\", \"entity\": \"11\", \"state\": 17 }\n{ \"time\": \"555295\", \"entity\": \"49\", \"state\": 17 }\n{ \"state\": 0, \"tag\": \"48d4b75\", \"pid\": \"5447\", \"tid\": \"2\", \"execname\": \"node\", \"psargs\": \"node --abort-on-uncaught-exception main.js -f etc/config.json -p 2021 -k 3021\" }\n{ \"time\": \"557568\", \"entity\": \"4\", \"state\": 17 }\n{ \"time\": \"558415\", \"entity\": \"49\", \"state\": 0, \"tag\": \"497cdd3\" }\n{ \"time\": \"559789\", \"entity\": \"53\", \"state\": 17 }\n{ \"time\": \"564353\", \"entity\": \"8\", \"state\": 0, \"tag\": \"48d4b75\" }\n{ \"time\": \"573039\", \"entity\": \"9\", \"state\": 17 }\n{ \"time\": \"576830\", \"entity\": \"53\", \"state\": 0, \"tag\": \"497cd9f\" }\n{ \"time\": \"578248\", \"entity\": \"46\", \"state\": 17 }\n{ \"time\": \"586259\", \"entity\": \"8\", \"state\": 17 }\n{ \"time\": \"586378\", \"entity\": \"36\", \"state\": 17 }\n{ \"time\": \"591726\", \"entity\": \"49\", \"state\": 17 }\n{ \"time\": \"594180\", \"entity\": \"49\", \"state\": 0, \"tag\": \"497cdd3\" }\n{ \"time\": \"606345\", \"entity\": \"31\", \"state\": 17 }\n{ \"time\": \"609029\", \"entity\": \"31\", \"state\": 0, \"tag\": \"49a7f46\" }\n{ \"time\": \"615014\", \"entity\": \"53\", \"state\": 17 }\n{ \"time\": \"623515\", \"entity\": \"53\", \"state\": 0, \"tag\": \"497cd9f\" }\n{ \"time\": \"635285\", \"entity\": \"45\", \"state\": 17 }\n{ \"time\": \"641951\", \"entity\": \"45\", \"state\": 0, \"tag\": \"49a7f2e\" }\n{ \"time\": \"642296\", \"entity\": \"31\", \"state\": 17 }\n{ \"time\": \"657898\", \"entity\": \"53\", \"state\": 17 }\n{ \"time\": \"658525\", \"entity\": \"52\", \"state\": 17 }\n{ \"time\": \"664378\", \"entity\": \"53\", \"state\": 0, \"tag\": \"497cd9f\" }\n{ \"time\": \"668175\", \"entity\": \"14\", \"state\": 0, \"tag\": \"4a0e388\" }\n{ \"time\": \"669848\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"671815\", \"entity\": \"22\", \"state\": 17 }\n{ \"time\": \"689085\", \"entity\": \"10\", \"state\": 17 }\n{ \"time\": \"696634\", \"entity\": \"49\", \"state\": 17 }\n{ \"time\": \"697889\", \"entity\": \"10\", \"state\": 0, \"tag\": \"497cdd0\" }\n{ \"time\": \"699569\", \"entity\": \"19\", \"state\": 17 }\n{ \"time\": \"703265\", \"entity\": \"14\", \"state\": 17 }\n{ \"time\": \"718505\", \"entity\": \"49\", \"state\": 0, \"tag\": \"497cdd3\" }\n{ \"time\": \"728522\", \"entity\": \"52\", \"state\": 17 }\n{ \"time\": \"735026\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"736636\", \"entity\": \"19\", \"state\": 0, \"tag\": \"49a7f32\" }\n{ \"time\": \"739400\", \"entity\": \"0\", \"state\": 15 }\n{ \"time\": \"743280\", \"entity\": \"0\", \"state\": 0, \"tag\": \"4a0e384\" }\n{ \"state\": 10, \"tag\": \"b\", \"driver\": \"softint\", \"instance\": 0 }\n{ \"time\": \"747031\", \"entity\": \"0\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"752452\", \"entity\": \"10\", \"state\": 17 }\n{ \"time\": \"752901\", \"entity\": \"53\", \"state\": 17 }\n{ \"time\": \"753787\", \"entity\": \"49\", \"state\": 17 }\n{ \"time\": \"754077\", \"entity\": \"16\", \"state\": 17 }\n{ \"time\": \"762849\", \"entity\": \"0\", \"state\": 0, \"tag\": \"4a0e384\" }\n{ \"time\": \"767901\", \"entity\": \"49\", \"state\": 0, \"tag\": \"497cdd3\" }\n{ \"time\": \"775953\", \"entity\": \"19\", \"state\": 17 }\n{ \"time\": \"785696\", \"entity\": \"49\", \"state\": 17 }\n{ \"time\": \"786067\", \"entity\": \"19\", \"state\": 0, \"tag\": \"49a7f32\" }\n{ \"time\": \"838177\", \"entity\": \"45\", \"state\": 17 }\n{ \"time\": \"901231\", \"entity\": \"45\", \"state\": 0, \"tag\": \"49a7f2e\" }\n{ \"time\": \"923069\", \"entity\": \"49\", \"state\": 0, \"tag\": \"497cdd3\" }\n{ \"time\": \"927589\", \"entity\": \"19\", \"state\": 17 }\n{ \"time\": \"938479\", \"entity\": \"19\", \"state\": 0, \"tag\": \"49a7f32\" }\n{ \"time\": \"947220\", \"entity\": \"31\", \"state\": 7, \"tag\": \"ffffd062dbcb7d58\" }\n{ \"time\": \"961419\", \"entity\": \"45\", \"state\": 17 }\n{ \"time\": \"966595\", \"entity\": \"45\", \"state\": 0, \"tag\": \"49a7f2e\" }\n{ \"time\": \"975225\", \"entity\": \"31\", \"state\": 17 }\n{ \"state\": 0, \"tag\": \"48d4ade\", \"pid\": \"5336\", \"tid\": \"1\", \"execname\": \"node\", \"psargs\": \"node --abort-on-uncaught-exception main.js -f etc/config.json -p 2021 -k 3021\" }\n{ \"time\": \"983732\", \"entity\": \"27\", \"state\": 0, \"tag\": \"48d4ade\" }\n{ \"time\": \"988698\", \"entity\": \"53\", \"state\": 0, \"tag\": \"497cd9f\" }\n{ \"time\": \"1006460\", \"entity\": \"10\", \"state\": 0, \"tag\": \"497cdd0\" }\n{ \"time\": \"1018551\", \"entity\": \"49\", \"state\": 17 }\n{ \"time\": \"1020723\", \"entity\": \"53\", \"state\": 17 }\n{ \"time\": \"1025056\", \"entity\": \"53\", \"state\": 0, \"tag\": \"497cd9f\" }\n{ \"time\": \"1029210\", \"entity\": \"49\", \"state\": 0, \"tag\": \"497cdd3\" }\n{ \"time\": \"1031701\", \"entity\": \"14\", \"state\": 0, \"tag\": \"4a0e388\" }\n{ \"state\": 0, \"tag\": \"48d4ae8\", \"pid\": \"5336\", \"tid\": \"2\", \"execname\": \"node\", \"psargs\": \"node --abort-on-uncaught-exception main.js -f etc/config.json -p 2021 -k 3021\" }\n{ \"time\": \"1040160\", \"entity\": \"52\", \"state\": 17 }\n{ \"time\": \"1045495\", \"entity\": \"21\", \"state\": 0, \"tag\": \"48d4ae8\" }\n{ \"time\": \"1053860\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"1056323\", \"entity\": \"22\", \"state\": 0, \"tag\": \"497cdd4\" }\n{ \"time\": \"1063767\", \"entity\": \"21\", \"state\": 17 }\n{ \"time\": \"1064227\", \"entity\": \"10\", \"state\": 17 }\n{ \"time\": \"1070591\", \"entity\": \"14\", \"state\": 17 }\n{ \"time\": \"1076581\", \"entity\": \"49\", \"state\": 17 }\n{ \"time\": \"1076899\", \"entity\": \"53\", \"state\": 17 }\n{ \"time\": \"1079487\", \"entity\": \"10\", \"state\": 0, \"tag\": \"497cdd0\" }\n{ \"time\": \"1085729\", \"entity\": \"49\", \"state\": 0, \"tag\": \"497cdd3\" }\n{ \"time\": \"1104374\", \"entity\": \"53\", \"state\": 0, \"tag\": \"497cd9f\" }\n{ \"time\": \"1113664\", \"entity\": \"52\", \"state\": 17 }\n{ \"time\": \"1117162\", \"entity\": \"53\", \"state\": 17 }\n{ \"time\": \"1119151\", \"entity\": \"31\", \"state\": 0, \"tag\": \"49a7f46\" }\n{ \"time\": \"1119914\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"1123006\", \"entity\": \"49\", \"state\": 17 }\n{ \"state\": 0, \"tag\": \"4a0e383\", \"pid\": \"50377\", \"tid\": \"1\", \"execname\": \"dtrace\", \"psargs\": \"/usr/sbin/dtrace -Cs ./cpu-statemap-tagged.d\" }\n{ \"time\": \"1128525\", \"entity\": \"16\", \"state\": 0, \"tag\": \"4a0e383\" }\n{ \"time\": \"1133011\", \"entity\": \"9\", \"state\": 16 }\n{ \"time\": \"1137190\", \"entity\": \"9\", \"state\": 17 }\n{ \"time\": \"1137845\", \"entity\": \"10\", \"state\": 17 }\n{ \"time\": \"1143092\", \"entity\": \"10\", \"state\": 16 }\n{ \"time\": \"1149172\", \"entity\": \"10\", \"state\": 17 }\n{ \"time\": \"1151888\", \"entity\": \"11\", \"state\": 16 }\n{ \"time\": \"1153362\", \"entity\": \"45\", \"state\": 17 }\n{ \"time\": \"1154832\", \"entity\": \"52\", \"state\": 17 }\n{ \"time\": \"1156133\", \"entity\": \"11\", \"state\": 17 }\n{ \"time\": \"1156908\", \"entity\": \"10\", \"state\": 0, \"tag\": \"497cdd0\" }\n{ \"time\": \"1159816\", \"entity\": \"12\", \"state\": 16 }\n{ \"time\": \"1160547\", \"entity\": \"30\", \"state\": 7, \"tag\": \"ffffd062dbcb7d58\" }\n{ \"time\": \"1162840\", \"entity\": \"12\", \"state\": 17 }\n{ \"time\": \"1166278\", \"entity\": \"19\", \"state\": 17 }\n{ \"time\": \"1166405\", \"entity\": \"13\", \"state\": 16 }\n{ \"time\": \"1170340\", \"entity\": \"22\", \"state\": 17 }\n{ \"time\": \"1171318\", \"entity\": \"13\", \"state\": 17 }\n{ \"time\": \"1173640\", \"entity\": \"30\", \"state\": 17 }\n{ \"time\": \"1173786\", \"entity\": \"14\", \"state\": 16 }\n{ \"time\": \"1177357\", \"entity\": \"14\", \"state\": 17 }\n{ \"state\": 0, \"tag\": \"48d4ced\", \"pid\": \"5737\", \"tid\": \"1\", \"execname\": \"node\", \"psargs\": \"node --abort-on-uncaught-exception main.js -f etc/config.json -p 2023 -k 3023\" }\n{ \"time\": \"1184808\", \"entity\": \"15\", \"state\": 0, \"tag\": \"48d4ced\" }\n{ \"time\": \"1188092\", \"entity\": \"15\", \"state\": 16 }\n{ \"time\": \"1192735\", \"entity\": \"15\", \"state\": 0, \"tag\": \"48d4ced\" }\n{ \"time\": \"1201969\", \"entity\": \"22\", \"state\": 0, \"tag\": \"497cdd4\" }\n{ \"time\": \"1205236\", \"entity\": \"17\", \"state\": 16 }\n{ \"time\": \"1213509\", \"entity\": \"17\", \"state\": 17 }\n{ \"time\": \"1214693\", \"entity\": \"18\", \"state\": 16 }\n{ \"time\": \"1217933\", \"entity\": \"31\", \"state\": 17 }\n{ \"time\": \"1218025\", \"entity\": \"18\", \"state\": 17 }\n{ \"time\": \"1222783\", \"entity\": \"19\", \"state\": 16 }\n{ \"time\": \"1223052\", \"entity\": \"31\", \"state\": 0, \"tag\": \"49a7f46\" }\n{ \"time\": \"1231369\", \"entity\": \"19\", \"state\": 17 }\n{ \"time\": \"1234496\", \"entity\": \"20\", \"state\": 16 }\n{ \"state\": 0, \"tag\": \"48d4d00\", \"pid\": \"5737\", \"tid\": \"2\", \"execname\": \"node\", \"psargs\": \"node --abort-on-uncaught-exception main.js -f etc/config.json -p 2023 -k 3023\" }\n{ \"time\": \"1239245\", \"entity\": \"20\", \"state\": 17 }\n{ \"time\": \"1239831\", \"entity\": \"22\", \"state\": 17 }\n{ \"time\": \"1240063\", \"entity\": \"19\", \"state\": 0, \"tag\": \"49a7f32\" }\n{ \"time\": \"1241645\", \"entity\": \"21\", \"state\": 16 }\n{ \"time\": \"1242848\", \"entity\": \"41\", \"state\": 0, \"tag\": \"48d4d00\" }\n{ \"time\": \"1247578\", \"entity\": \"21\", \"state\": 17 }\n{ \"time\": \"1250339\", \"entity\": \"22\", \"state\": 16 }\n{ \"time\": \"1254272\", \"entity\": \"22\", \"state\": 17 }\n{ \"time\": \"1254559\", \"entity\": \"41\", \"state\": 17 }\n{ \"time\": \"1256915\", \"entity\": \"23\", \"state\": 16 }\n{ \"time\": \"1261109\", \"entity\": \"23\", \"state\": 17 }\n{ \"time\": \"1264991\", \"entity\": \"22\", \"state\": 0, \"tag\": \"497cdd4\" }\n{ \"time\": \"1265886\", \"entity\": \"24\", \"state\": 16 }\n{ \"state\": 0, \"tag\": \"497d20a\", \"pid\": \"566150\", \"tid\": \"1\", \"execname\": \"postgres\", \"psargs\": \"/opt/postgresql/9.6.3/bin/postgres -D /manatee/pg/data\" }\n{ \"time\": \"1274130\", \"entity\": \"24\", \"state\": 17 }\n{ \"time\": \"1275439\", \"entity\": \"25\", \"state\": 16 }\n{ \"time\": \"1278104\", \"entity\": \"2\", \"state\": 0, \"tag\": \"497d20a\" }\n{ \"time\": \"1280783\", \"entity\": \"25\", \"state\": 17 }\n{ \"time\": \"1284410\", \"entity\": \"26\", \"state\": 16 }\n{ \"time\": \"1285340\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"1290577\", \"entity\": \"26\", \"state\": 17 }\n{ \"time\": \"1293829\", \"entity\": \"27\", \"state\": 16 }\n{ \"time\": \"1299840\", \"entity\": \"27\", \"state\": 0, \"tag\": \"48d4ade\" }\n{ \"time\": \"1301420\", \"entity\": \"22\", \"state\": 17 }\n{ \"time\": \"1302605\", \"entity\": \"28\", \"state\": 16 }\n{ \"time\": \"1305409\", \"entity\": \"22\", \"state\": 0, \"tag\": \"497cdd4\" }\n{ \"time\": \"1307933\", \"entity\": \"28\", \"state\": 17 }\n{ \"time\": \"1311223\", \"entity\": \"29\", \"state\": 16 }\n{ \"time\": \"1318349\", \"entity\": \"29\", \"state\": 0, \"tag\": \"48d4b6d\" }\n{ \"time\": \"1320548\", \"entity\": \"30\", \"state\": 16 }\n{ \"time\": \"1324450\", \"entity\": \"30\", \"state\": 17 }\n{ \"time\": \"1326355\", \"entity\": \"31\", \"state\": 17 }\n{ \"time\": \"1328330\", \"entity\": \"45\", \"state\": 0, \"tag\": \"49a7f2e\" }\n{ \"time\": \"1328586\", \"entity\": \"22\", \"state\": 17 }\n{ \"time\": \"1328695\", \"entity\": \"31\", \"state\": 16 }\n{ \"time\": \"1332677\", \"entity\": \"31\", \"state\": 17 }\n{ \"time\": \"1336344\", \"entity\": \"32\", \"state\": 16 }\n{ \"time\": \"1340039\", \"entity\": \"32\", \"state\": 17 }\n{ \"time\": \"1342203\", \"entity\": \"33\", \"state\": 16 }\n{ \"time\": \"1345521\", \"entity\": \"33\", \"state\": 17 }\n{ \"time\": \"1349615\", \"entity\": \"34\", \"state\": 16 }\n{ \"time\": \"1354008\", \"entity\": \"34\", \"state\": 17 }\n{ \"time\": \"1356043\", \"entity\": \"35\", \"state\": 16 }\n{ \"time\": \"1359384\", \"entity\": \"35\", \"state\": 17 }\n{ \"time\": \"1361625\", \"entity\": \"22\", \"state\": 0, \"tag\": \"497cdd4\" }\n{ \"time\": \"1362681\", \"entity\": \"36\", \"state\": 16 }\n{ \"time\": \"1366323\", \"entity\": \"36\", \"state\": 17 }\n{ \"time\": \"1367733\", \"entity\": \"30\", \"state\": 7, \"tag\": \"ffffd062dbcb7d58\" }\n{ \"time\": \"1369031\", \"entity\": \"45\", \"state\": 17 }\n{ \"time\": \"1369266\", \"entity\": \"37\", \"state\": 16 }\n{ \"time\": \"1372514\", \"entity\": \"37\", \"state\": 17 }\n{ \"time\": \"1378625\", \"entity\": \"38\", \"state\": 16 }\n{ \"time\": \"1379993\", \"entity\": \"2\", \"state\": 17 }\n{ \"time\": \"1386771\", \"entity\": \"30\", \"state\": 17 }\n{ \"time\": \"1387798\", \"entity\": \"38\", \"state\": 17 }\n{ \"time\": \"1387821\", \"entity\": \"22\", \"state\": 17 }\n{ \"time\": \"1388067\", \"entity\": \"39\", \"state\": 16 }\n{ \"time\": \"1388228\", \"entity\": \"45\", \"state\": 0, \"tag\": \"49a7f2e\" }\n{ \"time\": \"1391467\", \"entity\": \"39\", \"state\": 17 }\n{ \"time\": \"1393949\", \"entity\": \"40\", \"state\": 16 }\n{ \"time\": \"1395988\", \"entity\": \"40\", \"state\": 17 }\n{ \"time\": \"1399028\", \"entity\": \"41\", \"state\": 16 }\n{ \"time\": \"1402723\", \"entity\": \"41\", \"state\": 17 }\n{ \"time\": \"1406240\", \"entity\": \"42\", \"state\": 16 }\n{ \"time\": \"1408563\", \"entity\": \"42\", \"state\": 17 }\n{ \"time\": \"1412926\", \"entity\": \"43\", \"state\": 16 }\n{ \"time\": \"1418481\", \"entity\": \"22\", \"state\": 0, \"tag\": \"497cdd4\" }\n{ \"time\": \"1418781\", \"entity\": \"43\", \"state\": 17 }\n{ \"time\": \"1421034\", \"entity\": \"44\", \"state\": 16 }\n{ \"time\": \"1424874\", \"entity\": \"14\", \"state\": 0, \"tag\": \"4a0e388\" }\n{ \"time\": \"1424927\", \"entity\": \"44\", \"state\": 17 }\n{ \"time\": \"1428749\", \"entity\": \"45\", \"state\": 16 }\n{ \"time\": \"1431809\", \"entity\": \"10\", \"state\": 17 }\n{ \"time\": \"1436972\", \"entity\": \"45\", \"state\": 0, \"tag\": \"49a7f2e\" }\n{ \"time\": \"1438380\", \"entity\": \"46\", \"state\": 16 }\n{ \"time\": \"1440527\", \"entity\": \"46\", \"state\": 17 }\n{ \"time\": \"1444400\", \"entity\": \"31\", \"state\": 0, \"tag\": \"49a7f46\" }\n{ \"time\": \"1448049\", \"entity\": \"47\", \"state\": 16 }\n{ \"time\": \"1449582\", \"entity\": \"10\", \"state\": 0, \"tag\": \"497cdd0\" }\n{ \"state\": 0, \"tag\": \"497d212\", \"pid\": \"566158\", \"tid\": \"1\", \"execname\": \"postgres\", \"psargs\": \"/opt/postgresql/9.6.3/bin/postgres -D /manatee/pg/data\" }\n{ \"time\": \"1456559\", \"entity\": \"37\", \"state\": 0, \"tag\": \"497d212\" }\n{ \"time\": \"1458812\", \"entity\": \"47\", \"state\": 17 }\n{ \"time\": \"1459196\", \"entity\": \"19\", \"state\": 17 }\n{ \"time\": \"1459808\", \"entity\": \"48\", \"state\": 16 }\n{ \"time\": \"1460858\", \"entity\": \"14\", \"state\": 17 }\n{ \"time\": \"1462700\", \"entity\": \"22\", \"state\": 17 }\n{ \"time\": \"1463447\", \"entity\": \"48\", \"state\": 1, \"tag\": \"3c4\" }\n{ \"time\": \"1466417\", \"entity\": \"49\", \"state\": 16 }\n{ \"time\": \"1469928\", \"entity\": \"49\", \"state\": 17 }\n{ \"time\": \"1475559\", \"entity\": \"50\", \"state\": 16 }\n{ \"time\": \"1476464\", \"entity\": \"22\", \"state\": 0, \"tag\": \"497cdd4\" }\n{ \"time\": \"1480197\", \"entity\": \"50\", \"state\": 17 }\n{ \"state\": 0, \"tag\": \"48d4e10\", \"pid\": \"5958\", \"tid\": \"1\", \"execname\": \"node\", \"psargs\": \"node --abort-on-uncaught-exception main.js -f etc/config.json -p 2024 -k 3024\" }\n{ \"time\": \"1481808\", \"entity\": \"51\", \"state\": 16 }\n{ \"time\": \"1484985\", \"entity\": \"51\", \"state\": 17 }\n{ \"time\": \"1490063\", \"entity\": \"52\", \"state\": 16 }\n{ \"time\": \"1491640\", \"entity\": \"45\", \"state\": 0, \"tag\": \"48d4e10\" }\n{ \"time\": \"1498337\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"1499681\", \"entity\": \"53\", \"state\": 16 }\n{ \"time\": \"1503542\", \"entity\": \"53\", \"state\": 17 }\n{ \"time\": \"1507553\", \"entity\": \"54\", \"state\": 16 }\n{ \"time\": \"1507610\", \"entity\": \"45\", \"state\": 0, \"tag\": \"49a7f2e\" }\n{ \"time\": \"1511913\", \"entity\": \"54\", \"state\": 17 }\n{ \"time\": \"1514247\", \"entity\": \"10\", \"state\": 17 }\n{ \"time\": \"1515873\", \"entity\": \"55\", \"state\": 16 }\n{ \"time\": \"1520140\", \"entity\": \"22\", \"state\": 17 }\n{ \"time\": \"1522315\", \"entity\": \"55\", \"state\": 17 }\n{ \"time\": \"1527856\", \"entity\": \"27\", \"state\": 17 }\n{ \"time\": \"1531660\", \"entity\": \"22\", \"state\": 0, \"tag\": \"497cdd4\" }\n{ \"time\": \"1540257\", \"entity\": \"10\", \"state\": 0, \"tag\": \"497cdd0\" }\n{ \"time\": \"1550117\", \"entity\": \"19\", \"state\": 0, \"tag\": \"49a7f32\" }\n{ \"time\": \"1557017\", \"entity\": \"31\", \"state\": 17 }\n{ \"time\": \"1563796\", \"entity\": \"27\", \"state\": 0, \"tag\": \"48d4ade\" }\n{ \"time\": \"1566090\", \"entity\": \"22\", \"state\": 17 }\n{ \"time\": \"1566148\", \"entity\": \"45\", \"state\": 0, \"tag\": \"48d4e10\" }\n{ \"time\": \"1566354\", \"entity\": \"52\", \"state\": 17 }\n{ \"time\": \"1568814\", \"entity\": \"2\", \"state\": 0, \"tag\": \"497d20a\" }\n{ \"time\": \"1570616\", \"entity\": \"9\", \"state\": 15 }\n{ \"time\": \"1571878\", \"entity\": \"46\", \"state\": 15 }\n{ \"time\": \"1573357\", \"entity\": \"22\", \"state\": 0, \"tag\": \"497cdd4\" }\n{ \"time\": \"1573496\", \"entity\": \"46\", \"state\": 17 }\n{ \"time\": \"1574862\", \"entity\": \"9\", \"state\": 17 }\n{ \"time\": \"1576428\", \"entity\": \"46\", \"state\": 3, \"tag\": \"2\" }\n{ \"time\": \"1576608\", \"entity\": \"37\", \"state\": 17 }\n{ \"time\": \"1578950\", \"entity\": \"8\", \"state\": 15 }\n{ \"time\": \"1579862\", \"entity\": \"9\", \"state\": 3, \"tag\": \"2\" }\n{ \"time\": \"1581274\", \"entity\": \"8\", \"state\": 17 }\n{ \"time\": \"1582362\", \"entity\": \"46\", \"state\": 17 }\n{ \"time\": \"1584227\", \"entity\": \"8\", \"state\": 3, \"tag\": \"2\" }\n{ \"time\": \"1586328\", \"entity\": \"46\", \"state\": 0, \"tag\": \"497cdd9\" }\n{ \"time\": \"1590277\", \"entity\": \"8\", \"state\": 17 }\n{ \"time\": \"1590464\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"1590591\", \"entity\": \"45\", \"state\": 0, \"tag\": \"49a7f2e\" }\n{ \"time\": \"1591543\", \"entity\": \"9\", \"state\": 17 }\n{ \"time\": \"1594956\", \"entity\": \"8\", \"state\": 0, \"tag\": \"48d4b75\" }\n{ \"time\": \"1600794\", \"entity\": \"29\", \"state\": 17 }\n{ \"time\": \"1601223\", \"entity\": \"9\", \"state\": 0, \"tag\": \"4980fc2\" }\n{ \"time\": \"1601876\", \"entity\": \"8\", \"state\": 17 }\n{ \"time\": \"1602851\", \"entity\": \"22\", \"state\": 17 }\n{ \"time\": \"1612606\", \"entity\": \"22\", \"state\": 0, \"tag\": \"497cdd4\" }\n{ \"time\": \"1619928\", \"entity\": \"10\", \"state\": 17 }\n{ \"time\": \"1621241\", \"entity\": \"31\", \"state\": 0, \"tag\": \"49a7f46\" }\n{ \"time\": \"1622825\", \"entity\": \"9\", \"state\": 17 }\n{ \"time\": \"1625312\", \"entity\": \"10\", \"state\": 0, \"tag\": \"497cdd0\" }\n{ \"time\": \"1639370\", \"entity\": \"9\", \"state\": 0, \"tag\": \"4980fc2\" }\n{ \"time\": \"1640702\", \"entity\": \"31\", \"state\": 17 }\n{ \"time\": \"1678850\", \"entity\": \"31\", \"state\": 0, \"tag\": \"49a7f46\" }\n{ \"time\": \"1680520\", \"entity\": \"49\", \"state\": 0, \"tag\": \"497cdd3\" }\n{ \"time\": \"1692340\", \"entity\": \"53\", \"state\": 0, \"tag\": \"497cd9f\" }\n{ \"time\": \"1694963\", \"entity\": \"36\", \"state\": 0, \"tag\": \"49a7f42\" }\n{ \"time\": \"1700982\", \"entity\": \"4\", \"state\": 0, \"tag\": \"49a7f49\" }\n{ \"time\": \"1706068\", \"entity\": \"46\", \"state\": 0, \"tag\": \"48d4e10\" }\n{ \"time\": \"1713100\", \"entity\": \"46\", \"state\": 0, \"tag\": \"497cdd9\" }\n{ \"time\": \"1717396\", \"entity\": \"31\", \"state\": 17 }\n{ \"time\": \"1718374\", \"entity\": \"1\", \"state\": 0, \"tag\": \"48d4e10\" }\n{ \"time\": \"1721948\", \"entity\": \"9\", \"state\": 16 }\n{ \"time\": \"1722376\", \"entity\": \"22\", \"state\": 16 }\n{ \"time\": \"1722398\", \"entity\": \"36\", \"state\": 16 }\n{ \"time\": \"1722545\", \"entity\": \"46\", \"state\": 16 }\n{ \"time\": \"1723026\", \"entity\": \"10\", \"state\": 16 }\n{ \"time\": \"1723152\", \"entity\": \"49\", \"state\": 16 }\n{ \"time\": \"1723829\", \"entity\": \"53\", \"state\": 16 }\n{ \"time\": \"1723893\", \"entity\": \"19\", \"state\": 16 }\n{ \"time\": \"1724110\", \"entity\": \"45\", \"state\": 16 }\n{ \"time\": \"1724830\", \"entity\": \"52\", \"state\": 16 }\n{ \"time\": \"1725469\", \"entity\": \"46\", \"state\": 0, \"tag\": \"497cdd9\" }\n{ \"time\": \"1725641\", \"entity\": \"49\", \"state\": 17 }\n{ \"time\": \"1725958\", \"entity\": \"36\", \"state\": 0, \"tag\": \"49a7f42\" }\n{ \"time\": \"1726469\", \"entity\": \"9\", \"state\": 0, \"tag\": \"4980fc2\" }\n{ \"time\": \"1726734\", \"entity\": \"22\", \"state\": 0, \"tag\": \"497cdd4\" }\n{ \"time\": \"1727245\", \"entity\": \"53\", \"state\": 0, \"tag\": \"497cd9f\" }\n{ \"time\": \"1727648\", \"entity\": \"37\", \"state\": 0, \"tag\": \"497d212\" }\n{ \"time\": \"1727681\", \"entity\": \"49\", \"state\": 17 }\n{ \"time\": \"1730123\", \"entity\": \"10\", \"state\": 0, \"tag\": \"497cdd0\" }\n{ \"time\": \"1730633\", \"entity\": \"19\", \"state\": 0, \"tag\": \"49a7f32\" }\n{ \"time\": \"1731250\", \"entity\": \"45\", \"state\": 0, \"tag\": \"49a7f2e\" }\n{ \"time\": \"1731403\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"1732151\", \"entity\": \"49\", \"state\": 0, \"tag\": \"497cdd3\" }\n{ \"time\": \"1739845\", \"entity\": \"0\", \"state\": 15 }\n{ \"time\": \"1746589\", \"entity\": \"0\", \"state\": 0, \"tag\": \"4a0e384\" }\n{ \"time\": \"1749918\", \"entity\": \"0\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"1751913\", \"entity\": \"31\", \"state\": 0, \"tag\": \"49a7f46\" }\n{ \"time\": \"1752389\", \"entity\": \"27\", \"state\": 17 }\n{ \"state\": 0, \"tag\": \"497d4e2\", \"pid\": \"566865\", \"tid\": \"1\", \"execname\": \"postgres\", \"psargs\": \"/opt/postgresql/9.6.3/bin/postgres -D /manatee/pg/data\" }\n{ \"time\": \"1755671\", \"entity\": \"36\", \"state\": 17 }\n{ \"time\": \"1758552\", \"entity\": \"36\", \"state\": 0, \"tag\": \"49a7f42\" }\n{ \"state\": 0, \"tag\": \"48d4e18\", \"pid\": \"5958\", \"tid\": \"2\", \"execname\": \"node\", \"psargs\": \"node --abort-on-uncaught-exception main.js -f etc/config.json -p 2024 -k 3024\" }\n{ \"time\": \"1767581\", \"entity\": \"50\", \"state\": 0, \"tag\": \"48d4e18\" }\n{ \"time\": \"1767920\", \"entity\": \"26\", \"state\": 0, \"tag\": \"497d4e2\" }\n{ \"time\": \"1768630\", \"entity\": \"19\", \"state\": 17 }\n{ \"time\": \"1774944\", \"entity\": \"47\", \"state\": 0, \"tag\": \"49a7f32\" }\n{ \"time\": \"1776434\", \"entity\": \"11\", \"state\": 0, \"tag\": \"497cdd1\" }\n{ \"time\": \"1778474\", \"entity\": \"0\", \"state\": 0, \"tag\": \"4a0e384\" }\n{ \"time\": \"1783434\", \"entity\": \"11\", \"state\": 17 }\n{ \"time\": \"1785617\", \"entity\": \"15\", \"state\": 17 }\n{ \"time\": \"1789972\", \"entity\": \"50\", \"state\": 17 }\n{ \"time\": \"1790371\", \"entity\": \"31\", \"state\": 17 }\n{ \"time\": \"1798662\", \"entity\": \"22\", \"state\": 17 }\n{ \"time\": \"1799659\", \"entity\": \"53\", \"state\": 17 }\n{ \"time\": \"1799775\", \"entity\": \"49\", \"state\": 17 }\n{ \"time\": \"1800147\", \"entity\": \"45\", \"state\": 17 }\n{ \"time\": \"1802644\", \"entity\": \"49\", \"state\": 0, \"tag\": \"497cdd3\" }\n{ \"time\": \"1804234\", \"entity\": \"9\", \"state\": 17 }\n{ \"time\": \"1804314\", \"entity\": \"17\", \"state\": 0, \"tag\": \"49a7f2e\" }\n{ \"time\": \"1815421\", \"entity\": \"52\", \"state\": 17 }\n{ \"time\": \"1831927\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"1842650\", \"entity\": \"49\", \"state\": 17 }\n{ \"time\": \"1853453\", \"entity\": \"46\", \"state\": 17 }\n{ \"time\": \"1854478\", \"entity\": \"47\", \"state\": 17 }\n{ \"time\": \"1857286\", \"entity\": \"46\", \"state\": 0, \"tag\": \"497cdd9\" }\n{ \"time\": \"1857662\", \"entity\": \"14\", \"state\": 0, \"tag\": \"4a0e388\" }\n{ \"time\": \"1860962\", \"entity\": \"47\", \"state\": 0, \"tag\": \"49a7f32\" }\n{ \"time\": \"1861543\", \"entity\": \"36\", \"state\": 17 }\n{ \"time\": \"1863742\", \"entity\": \"4\", \"state\": 17 }\n{ \"time\": \"1865505\", \"entity\": \"17\", \"state\": 17 }\n{ \"time\": \"1866888\", \"entity\": \"4\", \"state\": 0, \"tag\": \"49a7f49\" }\n{ \"time\": \"1868188\", \"entity\": \"46\", \"state\": 17 }\n{ \"time\": \"1885355\", \"entity\": \"10\", \"state\": 17 }\n{ \"time\": \"1891052\", \"entity\": \"10\", \"state\": 0, \"tag\": \"497cdd0\" }\n{ \"time\": \"1908947\", \"entity\": \"14\", \"state\": 17 }\n{ \"time\": \"1928141\", \"entity\": \"46\", \"state\": 0, \"tag\": \"497cdd9\" }\n{ \"time\": \"1973538\", \"entity\": \"4\", \"state\": 17 }\n{ \"time\": \"2013125\", \"entity\": \"4\", \"state\": 0, \"tag\": \"49a7f49\" }\n{ \"time\": \"2027694\", \"entity\": \"36\", \"state\": 0, \"tag\": \"49a7f42\" }\n{ \"time\": \"2034820\", \"entity\": \"17\", \"state\": 0, \"tag\": \"49a7f2e\" }\n{ \"time\": \"2051826\", \"entity\": \"46\", \"state\": 17 }\n{ \"time\": \"2057896\", \"entity\": \"21\", \"state\": 15 }\n{ \"time\": \"2060651\", \"entity\": \"36\", \"state\": 17 }\n{ \"time\": \"2061335\", \"entity\": \"21\", \"state\": 17 }\n{ \"time\": \"2063578\", \"entity\": \"36\", \"state\": 0, \"tag\": \"49a7f42\" }\n{ \"time\": \"2064235\", \"entity\": \"21\", \"state\": 3, \"tag\": \"2\" }\n{ \"time\": \"2068218\", \"entity\": \"4\", \"state\": 17 }\n{ \"time\": \"2070666\", \"entity\": \"21\", \"state\": 17 }\n{ \"time\": \"2076440\", \"entity\": \"21\", \"state\": 0, \"tag\": \"48d4ae8\" }\n{ \"time\": \"2084643\", \"entity\": \"21\", \"state\": 17 }\n{ \"time\": \"2088885\", \"entity\": \"47\", \"state\": 17 }\n{ \"time\": \"2095628\", \"entity\": \"47\", \"state\": 0, \"tag\": \"49a7f32\" }\n{ \"time\": \"2105539\", \"entity\": \"36\", \"state\": 17 }\n{ \"time\": \"2166276\", \"entity\": \"36\", \"state\": 0, \"tag\": \"49a7f42\" }\n{ \"time\": \"2201863\", \"entity\": \"4\", \"state\": 0, \"tag\": \"49a7f49\" }\n{ \"time\": \"2228637\", \"entity\": \"4\", \"state\": 17 }\n{ \"time\": \"2231212\", \"entity\": \"4\", \"state\": 0, \"tag\": \"49a7f49\" }\n{ \"time\": \"2249903\", \"entity\": \"4\", \"state\": 17 }\n{ \"time\": \"2251762\", \"entity\": \"41\", \"state\": 15 }\n{ \"time\": \"2253203\", \"entity\": \"41\", \"state\": 17 }\n{ \"time\": \"2255393\", \"entity\": \"41\", \"state\": 3, \"tag\": \"2\" }\n{ \"time\": \"2260551\", \"entity\": \"41\", \"state\": 17 }\n{ \"time\": \"2264500\", \"entity\": \"41\", \"state\": 0, \"tag\": \"48d4d00\" }\n{ \"time\": \"2269824\", \"entity\": \"41\", \"state\": 17 }\n{ \"time\": \"2284834\", \"entity\": \"10\", \"state\": 17 }\n{ \"time\": \"2291061\", \"entity\": \"52\", \"state\": 17 }\n{ \"time\": \"2301592\", \"entity\": \"29\", \"state\": 0, \"tag\": \"48d4b6d\" }\n{ \"time\": \"2305757\", \"entity\": \"2\", \"state\": 17 }\n{ \"state\": 0, \"tag\": \"497e0d4\", \"pid\": \"569380\", \"tid\": \"1\", \"execname\": \"postgres\", \"psargs\": \"/opt/postgresql/9.6.3/bin/postgres -D /manatee/pg/data\" }\n{ \"time\": \"2322704\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"2323720\", \"entity\": \"14\", \"state\": 0, \"tag\": \"4a0e388\" }\n{ \"time\": \"2327364\", \"entity\": \"19\", \"state\": 0, \"tag\": \"497e0d4\" }\n{ \"time\": \"2327891\", \"entity\": \"36\", \"state\": 17 }\n{ \"time\": \"2336478\", \"entity\": \"38\", \"state\": 0, \"tag\": \"48d4b75\" }\n{ \"time\": \"2350895\", \"entity\": \"1\", \"state\": 17 }\n{ \"time\": \"2360872\", \"entity\": \"38\", \"state\": 17 }\n{ \"time\": \"2362577\", \"entity\": \"14\", \"state\": 17 }\n{ \"time\": \"2373219\", \"entity\": \"36\", \"state\": 0, \"tag\": \"49a7f42\" }\n{ \"time\": \"2401842\", \"entity\": \"10\", \"state\": 0, \"tag\": \"497cdd0\" }\n{ \"time\": \"2410496\", \"entity\": \"52\", \"state\": 17 }\n{ \"time\": \"2410586\", \"entity\": \"47\", \"state\": 17 }\n{ \"time\": \"2445800\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"2446541\", \"entity\": \"27\", \"state\": 0, \"tag\": \"48d4ade\" }\n{ \"time\": \"2447611\", \"entity\": \"16\", \"state\": 17 }\n{ \"time\": \"2458415\", \"entity\": \"37\", \"state\": 17 }\n{ \"time\": \"2461516\", \"entity\": \"21\", \"state\": 0, \"tag\": \"48d4ae8\" }\n{ \"time\": \"2467039\", \"entity\": \"21\", \"state\": 17 }\n{ \"time\": \"2484067\", \"entity\": \"36\", \"state\": 17 }\n{ \"time\": \"2484984\", \"entity\": \"47\", \"state\": 0, \"tag\": \"49a7f32\" }\n{ \"time\": \"2487284\", \"entity\": \"52\", \"state\": 17 }\n{ \"time\": \"2491074\", \"entity\": \"2\", \"state\": 0, \"tag\": \"497d20a\" }\n{ \"time\": \"2511956\", \"entity\": \"2\", \"state\": 17 }\n{ \"time\": \"2530247\", \"entity\": \"15\", \"state\": 0, \"tag\": \"48d4ced\" }\n{ \"time\": \"2546597\", \"entity\": \"41\", \"state\": 0, \"tag\": \"48d4d00\" }\n{ \"time\": \"2551849\", \"entity\": \"41\", \"state\": 17 }\n{ \"time\": \"2553991\", \"entity\": \"26\", \"state\": 17 }\n{ \"time\": \"2598265\", \"entity\": \"37\", \"state\": 0, \"tag\": \"497d212\" }\n{ \"time\": \"2612822\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"2616846\", \"entity\": \"14\", \"state\": 0, \"tag\": \"4a0e388\" }\n{ \"time\": \"2618688\", \"entity\": \"37\", \"state\": 17 }\n{ \"time\": \"2624719\", \"entity\": \"10\", \"state\": 17 }\n{ \"time\": \"2628302\", \"entity\": \"17\", \"state\": 17 }\n{ \"time\": \"2652173\", \"entity\": \"14\", \"state\": 17 }\n{ \"time\": \"2698733\", \"entity\": \"26\", \"state\": 0, \"tag\": \"497d4e2\" }\n{ \"time\": \"2713062\", \"entity\": \"15\", \"state\": 17 }\n{ \"time\": \"2718744\", \"entity\": \"17\", \"state\": 0, \"tag\": \"49a7f2e\" }\n{ \"time\": \"2738856\", \"entity\": \"11\", \"state\": 15 }\n{ \"time\": \"2739184\", \"entity\": \"53\", \"state\": 15 }\n{ \"time\": \"2739223\", \"entity\": \"13\", \"state\": 15 }\n{ \"time\": \"2739227\", \"entity\": \"33\", \"state\": 15 }\n{ \"time\": \"2739356\", \"entity\": \"35\", \"state\": 15 }\n{ \"time\": \"2739437\", \"entity\": \"0\", \"state\": 15 }\n{ \"time\": \"2739444\", \"entity\": \"22\", \"state\": 15 }\n{ \"time\": \"2739524\", \"entity\": \"23\", \"state\": 15 }\n{ \"time\": \"2739527\", \"entity\": \"12\", \"state\": 15 }\n{ \"time\": \"2739800\", \"entity\": \"21\", \"state\": 15 }\n{ \"time\": \"2739816\", \"entity\": \"36\", \"state\": 15 }\n{ \"time\": \"2739819\", \"entity\": \"49\", \"state\": 15 }\n{ \"time\": \"2739830\", \"entity\": \"14\", \"state\": 15 }\n{ \"time\": \"2739847\", \"entity\": \"48\", \"state\": 15 }\n{ \"time\": \"2739980\", \"entity\": \"15\", \"state\": 15 }\n{ \"time\": \"2740110\", \"entity\": \"16\", \"state\": 15 }\n{ \"time\": \"2740137\", \"entity\": \"37\", \"state\": 15 }\n{ \"time\": \"2740149\", \"entity\": \"4\", \"state\": 15 }\n{ \"time\": \"2740488\", \"entity\": \"30\", \"state\": 15 }\n{ \"time\": \"2740512\", \"entity\": \"32\", \"state\": 15 }\n{ \"time\": \"2740623\", \"entity\": \"11\", \"state\": 17 }\n{ \"time\": \"2740924\", \"entity\": \"52\", \"state\": 15 }\n{ \"time\": \"2741143\", \"entity\": \"1\", \"state\": 15 }\n{ \"time\": \"2741149\", \"entity\": \"29\", \"state\": 15 }\n{ \"time\": \"2741154\", \"entity\": \"10\", \"state\": 15 }\n{ \"time\": \"2741427\", \"entity\": \"26\", \"state\": 15 }\n{ \"time\": \"2741623\", \"entity\": \"33\", \"state\": 17 }\n{ \"time\": \"2741668\", \"entity\": \"53\", \"state\": 17 }\n{ \"time\": \"2741898\", \"entity\": \"12\", \"state\": 17 }\n{ \"time\": \"2742244\", \"entity\": \"13\", \"state\": 17 }\n{ \"time\": \"2742964\", \"entity\": \"21\", \"state\": 17 }\n{ \"time\": \"2743620\", \"entity\": \"23\", \"state\": 17 }\n{ \"time\": \"2743646\", \"entity\": \"49\", \"state\": 17 }\n{ \"time\": \"2743658\", \"entity\": \"35\", \"state\": 17 }\n{ \"time\": \"2743684\", \"entity\": \"11\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2743960\", \"entity\": \"22\", \"state\": 17 }\n{ \"time\": \"2744663\", \"entity\": \"33\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2744680\", \"entity\": \"53\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2744789\", \"entity\": \"14\", \"state\": 17 }\n{ \"time\": \"2744980\", \"entity\": \"47\", \"state\": 15 }\n{ \"time\": \"2745068\", \"entity\": \"12\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2745110\", \"entity\": \"36\", \"state\": 17 }\n{ \"time\": \"2745119\", \"entity\": \"15\", \"state\": 17 }\n{ \"time\": \"2745444\", \"entity\": \"21\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2745609\", \"entity\": \"13\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2745804\", \"entity\": \"48\", \"state\": 1, \"tag\": \"3c4\" }\n{ \"time\": \"2746183\", \"entity\": \"0\", \"state\": 0, \"tag\": \"4a0e384\" }\n{ \"time\": \"2746302\", \"entity\": \"37\", \"state\": 17 }\n{ \"time\": \"2746306\", \"entity\": \"49\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2746344\", \"entity\": \"16\", \"state\": 17 }\n{ \"time\": \"2746428\", \"entity\": \"23\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2746493\", \"entity\": \"4\", \"state\": 17 }\n{ \"time\": \"2746496\", \"entity\": \"30\", \"state\": 17 }\n{ \"time\": \"2746569\", \"entity\": \"35\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2746608\", \"entity\": \"32\", \"state\": 17 }\n{ \"time\": \"2747310\", \"entity\": \"22\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2747848\", \"entity\": \"14\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2748202\", \"entity\": \"1\", \"state\": 17 }\n{ \"time\": \"2748519\", \"entity\": \"0\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2748767\", \"entity\": \"15\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2748842\", \"entity\": \"36\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2748989\", \"entity\": \"29\", \"state\": 0, \"tag\": \"48d4b6d\" }\n{ \"time\": \"2749477\", \"entity\": \"10\", \"state\": 17 }\n{ \"time\": \"2749892\", \"entity\": \"30\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2749933\", \"entity\": \"16\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2750103\", \"entity\": \"48\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2750214\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"2750477\", \"entity\": \"4\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2750480\", \"entity\": \"32\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2750619\", \"entity\": \"37\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2751894\", \"entity\": \"26\", \"state\": 0, \"tag\": \"497d4e2\" }\n{ \"time\": \"2752222\", \"entity\": \"12\", \"state\": 17 }\n{ \"time\": \"2753033\", \"entity\": \"29\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2753036\", \"entity\": \"1\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2753619\", \"entity\": \"33\", \"state\": 17 }\n{ \"time\": \"2754750\", \"entity\": \"11\", \"state\": 17 }\n{ \"time\": \"2756235\", \"entity\": \"14\", \"state\": 17 }\n{ \"time\": \"2756564\", \"entity\": \"52\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2756724\", \"entity\": \"10\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2757240\", \"entity\": \"37\", \"state\": 17 }\n{ \"time\": \"2757510\", \"entity\": \"47\", \"state\": 0, \"tag\": \"49a7f32\" }\n{ \"time\": \"2758979\", \"entity\": \"16\", \"state\": 17 }\n{ \"time\": \"2758984\", \"entity\": \"26\", \"state\": 11, \"tag\": \"a\" }\n{ \"state\": 1, \"tag\": \"508\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"time\": \"2762129\", \"entity\": \"0\", \"state\": 0, \"tag\": \"4a0e384\" }\n{ \"time\": \"2763958\", \"entity\": \"29\", \"state\": 0, \"tag\": \"48d4b6d\" }\n{ \"time\": \"2763992\", \"entity\": \"0\", \"state\": 3, \"tag\": \"2\" }\n{ \"time\": \"2764529\", \"entity\": \"48\", \"state\": 1, \"tag\": \"3c4\" }\n{ \"state\": 1, \"tag\": \"506\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"state\": 1, \"tag\": \"56b\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"time\": \"2765826\", \"entity\": \"0\", \"state\": 0, \"tag\": \"4a0e384\" }\n{ \"state\": 1, \"tag\": \"50c\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"time\": \"2766634\", \"entity\": \"47\", \"state\": 11, \"tag\": \"a\" }\n{ \"time\": \"2769168\", \"entity\": \"8\", \"state\": 1, \"tag\": \"508\" }\n{ \"time\": \"2769369\", \"entity\": \"15\", \"state\": 17 }\n{ \"time\": \"2769781\", \"entity\": \"16\", \"state\": 1, \"tag\": \"56b\" }\n{ \"time\": \"2770167\", \"entity\": \"50\", \"state\": 1, \"tag\": \"50c\" }\n{ \"time\": \"2770906\", \"entity\": \"11\", \"state\": 1, \"tag\": \"506\" }\n{ \"state\": 1, \"tag\": \"572\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"time\": \"2775305\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"2775728\", \"entity\": \"10\", \"state\": 17 }\n{ \"state\": 1, \"tag\": \"589\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"state\": 1, \"tag\": \"511\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"time\": \"2778446\", \"entity\": \"32\", \"state\": 17 }\n{ \"state\": 1, \"tag\": \"563\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"state\": 1, \"tag\": \"588\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"time\": \"2779948\", \"entity\": \"6\", \"state\": 1, \"tag\": \"572\" }\n{ \"time\": \"2781106\", \"entity\": \"11\", \"state\": 15 }\n{ \"state\": 1, \"tag\": \"50f\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"state\": 1, \"tag\": \"591\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"time\": \"2781550\", \"entity\": \"18\", \"state\": 1, \"tag\": \"589\" }\n{ \"time\": \"2782610\", \"entity\": \"31\", \"state\": 1, \"tag\": \"563\" }\n{ \"time\": \"2782633\", \"entity\": \"8\", \"state\": 1, \"tag\": \"588\" }\n{ \"time\": \"2783057\", \"entity\": \"11\", \"state\": 1, \"tag\": \"506\" }\n{ \"time\": \"2783200\", \"entity\": \"20\", \"state\": 1, \"tag\": \"511\" }\n{ \"time\": \"2784164\", \"entity\": \"50\", \"state\": 1, \"tag\": \"591\" }\n{ \"state\": 1, \"tag\": \"568\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"time\": \"2785196\", \"entity\": \"11\", \"state\": 3, \"tag\": \"2\" }\n{ \"state\": 1, \"tag\": \"505\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"time\": \"2786380\", \"entity\": \"43\", \"state\": 1, \"tag\": \"50f\" }\n{ \"time\": \"2786979\", \"entity\": \"50\", \"state\": 15 }\n{ \"time\": \"2787490\", \"entity\": \"13\", \"state\": 17 }\n{ \"time\": \"2787981\", \"entity\": \"10\", \"state\": 0, \"tag\": \"497cdd0\" }\n{ \"state\": 1, \"tag\": \"494\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"time\": \"2789225\", \"entity\": \"32\", \"state\": 1, \"tag\": \"568\" }\n{ \"state\": 1, \"tag\": \"50b\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"time\": \"2789603\", \"entity\": \"11\", \"state\": 1, \"tag\": \"506\" }\n{ \"time\": \"2790250\", \"entity\": \"8\", \"state\": 17 }\n{ \"time\": \"2791044\", \"entity\": \"50\", \"state\": 1, \"tag\": \"591\" }\n{ \"state\": 1, \"tag\": \"50a\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"time\": \"2791330\", \"entity\": \"18\", \"state\": 17 }\n{ \"state\": 1, \"tag\": \"3a3\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"time\": \"2793174\", \"entity\": \"12\", \"state\": 1, \"tag\": \"50b\" }\n{ \"time\": \"2794514\", \"entity\": \"15\", \"state\": 1, \"tag\": \"50a\" }\n{ \"state\": 1, \"tag\": \"586\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"state\": 1, \"tag\": \"332\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"state\": 1, \"tag\": \"1a1\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"state\": 1, \"tag\": \"431\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"time\": \"2795661\", \"entity\": \"52\", \"state\": 1, \"tag\": \"494\" }\n{ \"time\": \"2795818\", \"entity\": \"24\", \"state\": 1, \"tag\": \"505\" }\n{ \"time\": \"2795870\", \"entity\": \"50\", \"state\": 3, \"tag\": \"2\" }\n{ \"time\": \"2796195\", \"entity\": \"32\", \"state\": 17 }\n{ \"state\": 1, \"tag\": \"149\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"time\": \"2796791\", \"entity\": \"6\", \"state\": 17 }\n{ \"time\": \"2796948\", \"entity\": \"31\", \"state\": 1, \"tag\": \"332\" }\n{ \"time\": \"2796998\", \"entity\": \"47\", \"state\": 0, \"tag\": \"49a7f32\" }\n{ \"state\": 1, \"tag\": \"2fc\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"time\": \"2797170\", \"entity\": \"20\", \"state\": 17 }\n{ \"time\": \"2797844\", \"entity\": \"22\", \"state\": 17 }\n{ \"time\": \"2798008\", \"entity\": \"13\", \"state\": 1, \"tag\": \"1a1\" }\n{ \"time\": \"2798180\", \"entity\": \"46\", \"state\": 1, \"tag\": \"431\" }\n{ \"state\": 1, \"tag\": \"53d\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"time\": \"2799503\", \"entity\": \"8\", \"state\": 1, \"tag\": \"149\" }\n{ \"time\": \"2799946\", \"entity\": \"9\", \"state\": 1, \"tag\": \"586\" }\n{ \"time\": \"2800495\", \"entity\": \"38\", \"state\": 1, \"tag\": \"3a3\" }\n{ \"time\": \"2801241\", \"entity\": \"43\", \"state\": 1, \"tag\": \"53d\" }\n{ \"time\": \"2801891\", \"entity\": \"50\", \"state\": 1, \"tag\": \"591\" }\n{ \"time\": \"2802030\", \"entity\": \"28\", \"state\": 1, \"tag\": \"2fc\" }\n{ \"time\": \"2802203\", \"entity\": \"11\", \"state\": 17 }\n{ \"time\": \"2802513\", \"entity\": \"15\", \"state\": 17 }\n{ \"time\": \"2804148\", \"entity\": \"22\", \"state\": 0, \"tag\": \"48d4e18\" }\n{ \"time\": \"2804983\", \"entity\": \"12\", \"state\": 17 }\n{ \"state\": 1, \"tag\": \"159\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"state\": 1, \"tag\": \"3c4\", \"thread\": \"zfs`dbuf_evict_thread\", \"taskq\": \"<none>\" }\n{ \"state\": 1, \"tag\": \"454\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"time\": \"2807716\", \"entity\": \"21\", \"state\": 17 }\n{ \"state\": 1, \"tag\": \"532\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"time\": \"2809330\", \"entity\": \"46\", \"state\": 1, \"tag\": \"3c4\" }\n{ \"time\": \"2809907\", \"entity\": \"9\", \"state\": 1, \"tag\": \"159\" }\n{ \"time\": \"2809959\", \"entity\": \"48\", \"state\": 1, \"tag\": \"454\" }\n{ \"state\": 1, \"tag\": \"401\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"time\": \"2812244\", \"entity\": \"22\", \"state\": 17 }\n{ \"time\": \"2812381\", \"entity\": \"38\", \"state\": 17 }\n{ \"time\": \"2812838\", \"entity\": \"50\", \"state\": 1, \"tag\": \"532\" }\n{ \"state\": 1, \"tag\": \"441\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"time\": \"2813618\", \"entity\": \"43\", \"state\": 1, \"tag\": \"401\" }\n{ \"time\": \"2813635\", \"entity\": \"24\", \"state\": 17 }\n{ \"time\": \"2813655\", \"entity\": \"4\", \"state\": 17 }\n{ \"state\": 1, \"tag\": \"201\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"time\": \"2816419\", \"entity\": \"31\", \"state\": 17 }\n{ \"state\": 1, \"tag\": \"109\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"state\": 1, \"tag\": \"4f0\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"state\": 7, \"tag\": \"ffffd062dbd3caa0\", \"driver\": \"ixgbe\", \"instance\": 0 }\n{ \"time\": \"2817983\", \"entity\": \"13\", \"state\": 17 }\n{ \"time\": \"2818893\", \"entity\": \"4\", \"state\": 1, \"tag\": \"109\" }\n{ \"time\": \"2819739\", \"entity\": \"35\", \"state\": 17 }\n{ \"state\": 1, \"tag\": \"56f\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"time\": \"2820521\", \"entity\": \"44\", \"state\": 1, \"tag\": \"4f0\" }\n{ \"state\": 1, \"tag\": \"474\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"time\": \"2820846\", \"entity\": \"31\", \"state\": 7, \"tag\": \"ffffd062dbcb7d58\" }\n{ \"time\": \"2821964\", \"entity\": \"4\", \"state\": 17 }\n{ \"time\": \"2822271\", \"entity\": \"47\", \"state\": 1, \"tag\": \"441\" }\n{ \"time\": \"2823215\", \"entity\": \"19\", \"state\": 1, \"tag\": \"201\" }\n{ \"time\": \"2823281\", \"entity\": \"28\", \"state\": 17 }\n{ \"time\": \"2823339\", \"entity\": \"50\", \"state\": 1, \"tag\": \"474\" }\n{ \"time\": \"2824040\", \"entity\": \"22\", \"state\": 1, \"tag\": \"56f\" }\n{ \"time\": \"2824727\", \"entity\": \"8\", \"state\": 17 }\n{ \"time\": \"2825090\", \"entity\": \"20\", \"state\": 7, \"tag\": \"ffffd062dbd3caa0\" }\n{ \"time\": \"2826403\", \"entity\": \"35\", \"state\": 7, \"tag\": \"ffffd062dbcb7d58\" }\n{ \"time\": \"2827341\", \"entity\": \"15\", \"state\": 7, \"tag\": \"ffffd062dbd3caa0\" }\n{ \"time\": \"2827641\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"2828147\", \"entity\": \"31\", \"state\": 17 }\n{ \"time\": \"2828240\", \"entity\": \"44\", \"state\": 17 }\n{ \"time\": \"2828434\", \"entity\": \"48\", \"state\": 17 }\n{ \"time\": \"2828810\", \"entity\": \"13\", \"state\": 7, \"tag\": \"ffffd062dbd3caa0\" }\n{ \"time\": \"2828928\", \"entity\": \"18\", \"state\": 7, \"tag\": \"ffffd062dbd3caa0\" }\n{ \"state\": 1, \"tag\": \"231\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"time\": \"2831848\", \"entity\": \"32\", \"state\": 7, \"tag\": \"ffffd062dbcb7d58\" }\n{ \"state\": 1, \"tag\": \"3b3\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"time\": \"2832759\", \"entity\": \"9\", \"state\": 17 }\n{ \"time\": \"2833726\", \"entity\": \"22\", \"state\": 1, \"tag\": \"231\" }\n{ \"time\": \"2834743\", \"entity\": \"39\", \"state\": 1, \"tag\": \"3b3\" }\n{ \"time\": \"2834868\", \"entity\": \"52\", \"state\": 17 }\n{ \"time\": \"2835340\", \"entity\": \"41\", \"state\": 0, \"tag\": \"497d212\" }\n{ \"time\": \"2836018\", \"entity\": \"20\", \"state\": 17 }\n{ \"time\": \"2836192\", \"entity\": \"15\", \"state\": 17 }\n{ \"time\": \"2836248\", \"entity\": \"35\", \"state\": 17 }\n{ \"time\": \"2836415\", \"entity\": \"19\", \"state\": 0, \"tag\": \"497e0d4\" }\n{ \"time\": \"2837835\", \"entity\": \"22\", \"state\": 17 }\n{ \"time\": \"2838427\", \"entity\": \"13\", \"state\": 17 }\n{ \"state\": 1, \"tag\": \"55c\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"state\": 1, \"tag\": \"421\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"time\": \"2841934\", \"entity\": \"50\", \"state\": 17 }\n{ \"time\": \"2842485\", \"entity\": \"16\", \"state\": 17 }\n{ \"time\": \"2842632\", \"entity\": \"43\", \"state\": 17 }\n{ \"time\": \"2842769\", \"entity\": \"26\", \"state\": 0, \"tag\": \"497d4e2\" }\n{ \"time\": \"2843248\", \"entity\": \"32\", \"state\": 17 }\n{ \"time\": \"2843749\", \"entity\": \"15\", \"state\": 1, \"tag\": \"55c\" }\n{ \"time\": \"2844586\", \"entity\": \"18\", \"state\": 17 }\n{ \"time\": \"2849706\", \"entity\": \"47\", \"state\": 0, \"tag\": \"49a7f32\" }\n{ \"time\": \"2850475\", \"entity\": \"23\", \"state\": 17 }\n{ \"state\": 1, \"tag\": \"547\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"time\": \"2851926\", \"entity\": \"45\", \"state\": 1, \"tag\": \"421\" }\n{ \"time\": \"2853387\", \"entity\": \"15\", \"state\": 17 }\n{ \"state\": 1, \"tag\": \"139\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"time\": \"2854482\", \"entity\": \"18\", \"state\": 1, \"tag\": \"547\" }\n{ \"time\": \"2857892\", \"entity\": \"27\", \"state\": 17 }\n{ \"time\": \"2858407\", \"entity\": \"7\", \"state\": 1, \"tag\": \"139\" }\n{ \"time\": \"2858890\", \"entity\": \"39\", \"state\": 17 }\n{ \"time\": \"2861162\", \"entity\": \"18\", \"state\": 17 }\n{ \"time\": \"2865228\", \"entity\": \"15\", \"state\": 0, \"tag\": \"49a7f32\" }\n{ \"time\": \"2865239\", \"entity\": \"47\", \"state\": 17 }\n{ \"time\": \"2874241\", \"entity\": \"20\", \"state\": 7, \"tag\": \"ffffd062dbd3caa0\" }\n{ \"time\": \"2877147\", \"entity\": \"20\", \"state\": 17 }\n{ \"time\": \"2878100\", \"entity\": \"18\", \"state\": 7, \"tag\": \"ffffd062dbd3caa0\" }\n{ \"time\": \"2878417\", \"entity\": \"49\", \"state\": 17 }\n{ \"time\": \"2880266\", \"entity\": \"13\", \"state\": 7, \"tag\": \"ffffd062dbd3caa0\" }\n{ \"state\": 1, \"tag\": \"58a\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"state\": 1, \"tag\": \"48c0687\", \"thread\": \"mac`mac_srs_worker\", \"taskq\": \"<none>\" }\n{ \"time\": \"2881471\", \"entity\": \"7\", \"state\": 17 }\n{ \"time\": \"2882394\", \"entity\": \"4\", \"state\": 1, \"tag\": \"58a\" }\n{ \"time\": \"2882699\", \"entity\": \"18\", \"state\": 17 }\n{ \"time\": \"2884819\", \"entity\": \"21\", \"state\": 1, \"tag\": \"48c0687\" }\n{ \"time\": \"2885368\", \"entity\": \"13\", \"state\": 17 }\n{ \"time\": \"2892650\", \"entity\": \"4\", \"state\": 17 }\n{ \"state\": 0, \"tag\": \"497cdc5\", \"pid\": \"565220\", \"tid\": \"1\", \"execname\": \"postgres\", \"psargs\": \"/opt/postgresql/9.6.3/bin/postgres -D /manatee/pg/data\" }\n{ \"state\": 1, \"tag\": \"119\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"time\": \"2895882\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"2896922\", \"entity\": \"21\", \"state\": 17 }\n{ \"time\": \"2898855\", \"entity\": \"23\", \"state\": 0, \"tag\": \"497cdc5\" }\n{ \"time\": \"2899081\", \"entity\": \"5\", \"state\": 1, \"tag\": \"119\" }\n{ \"state\": 1, \"tag\": \"2\", \"driver\": \"softint\", \"instance\": 0 }\n{ \"time\": \"2904722\", \"entity\": \"23\", \"state\": 2, \"tag\": \"1\" }\n{ \"time\": \"2905416\", \"entity\": \"45\", \"state\": 17 }\n{ \"state\": 1, \"tag\": \"353\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"time\": \"2908478\", \"entity\": \"23\", \"state\": 0, \"tag\": \"497cdc5\" }\n{ \"time\": \"2909051\", \"entity\": \"53\", \"state\": 17 }\n{ \"state\": 1, \"tag\": \"592\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"time\": \"2910797\", \"entity\": \"33\", \"state\": 1, \"tag\": \"353\" }\n{ \"time\": \"2912119\", \"entity\": \"11\", \"state\": 0, \"tag\": \"497cdd1\" }\n{ \"time\": \"2913138\", \"entity\": \"15\", \"state\": 1, \"tag\": \"592\" }\n{ \"time\": \"2914211\", \"entity\": \"29\", \"state\": 17 }\n{ \"time\": \"2918243\", \"entity\": \"1\", \"state\": 17 }\n{ \"time\": \"2918569\", \"entity\": \"33\", \"state\": 17 }\n{ \"state\": 1, \"tag\": \"4e9\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"state\": 1, \"tag\": \"245\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"time\": \"2921512\", \"entity\": \"15\", \"state\": 17 }\n{ \"time\": \"2921746\", \"entity\": \"5\", \"state\": 17 }\n{ \"time\": \"2923567\", \"entity\": \"52\", \"state\": 2, \"tag\": \"1\" }\n{ \"time\": \"2923665\", \"entity\": \"23\", \"state\": 1, \"tag\": \"245\" }\n{ \"time\": \"2923828\", \"entity\": \"29\", \"state\": 1, \"tag\": \"4e9\" }\n{ \"time\": \"2924126\", \"entity\": \"36\", \"state\": 17 }\n{ \"state\": 1, \"tag\": \"570\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"time\": \"2926812\", \"entity\": \"43\", \"state\": 0, \"tag\": \"48d4ced\" }\n{ \"time\": \"2927055\", \"entity\": \"15\", \"state\": 0, \"tag\": \"49a7f32\" }\n{ \"time\": \"2927485\", \"entity\": \"5\", \"state\": 1, \"tag\": \"570\" }\n{ \"state\": 1, \"tag\": \"1b1\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"state\": 1, \"tag\": \"ae\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"time\": \"2930823\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"2931655\", \"entity\": \"14\", \"state\": 1, \"tag\": \"1b1\" }\n{ \"time\": \"2932169\", \"entity\": \"29\", \"state\": 17 }\n{ \"time\": \"2933048\", \"entity\": \"15\", \"state\": 17 }\n{ \"time\": \"2933676\", \"entity\": \"5\", \"state\": 17 }\n{ \"state\": 1, \"tag\": \"343\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"time\": \"2934343\", \"entity\": \"1\", \"state\": 1, \"tag\": \"ae\" }\n{ \"time\": \"2934772\", \"entity\": \"14\", \"state\": 17 }\n{ \"time\": \"2936066\", \"entity\": \"32\", \"state\": 1, \"tag\": \"343\" }\n{ \"time\": \"2936210\", \"entity\": \"26\", \"state\": 17 }\n{ \"time\": \"2939460\", \"entity\": \"52\", \"state\": 1, \"tag\": \"494\" }\n{ \"time\": \"2939597\", \"entity\": \"1\", \"state\": 17 }\n{ \"time\": \"2940588\", \"entity\": \"32\", \"state\": 17 }\n{ \"time\": \"2943613\", \"entity\": \"23\", \"state\": 0, \"tag\": \"497cdc5\" }\n{ \"time\": \"2946897\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"2954837\", \"entity\": \"30\", \"state\": 17 }\n{ \"state\": 1, \"tag\": \"565\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"time\": \"2959792\", \"entity\": \"15\", \"state\": 1, \"tag\": \"565\" }\n{ \"time\": \"2968711\", \"entity\": \"28\", \"state\": 1, \"tag\": \"2fc\" }\n{ \"time\": \"2971712\", \"entity\": \"15\", \"state\": 0, \"tag\": \"49a7f32\" }\n{ \"time\": \"2971952\", \"entity\": \"13\", \"state\": 1, \"tag\": \"1a1\" }\n{ \"time\": \"2974959\", \"entity\": \"36\", \"state\": 0, \"tag\": \"49a7f42\" }\n{ \"time\": \"2982979\", \"entity\": \"14\", \"state\": 0, \"tag\": \"4a0e388\" }\n{ \"time\": \"2983981\", \"entity\": \"34\", \"state\": 7, \"tag\": \"ffffd062dbcb7d58\" }\n{ \"time\": \"2986129\", \"entity\": \"28\", \"state\": 17 }\n{ \"time\": \"2990466\", \"entity\": \"16\", \"state\": 7, \"tag\": \"ffffd062dbd3caa0\" }\n{ \"time\": \"2994684\", \"entity\": \"34\", \"state\": 17 }\n{ \"time\": \"2998520\", \"entity\": \"16\", \"state\": 17 }\n{ \"time\": \"2999276\", \"entity\": \"18\", \"state\": 0, \"tag\": \"497cdd9\" }\n{ \"time\": \"3000587\", \"entity\": \"13\", \"state\": 17 }\n{ \"state\": 1, \"tag\": \"d7\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"time\": \"3004848\", \"entity\": \"16\", \"state\": 0, \"tag\": \"497d20a\" }\n{ \"time\": \"3004920\", \"entity\": \"2\", \"state\": 1, \"tag\": \"d7\" }\n{ \"time\": \"3005728\", \"entity\": \"49\", \"state\": 0, \"tag\": \"497cdd3\" }\n{ \"time\": \"3018074\", \"entity\": \"23\", \"state\": 17 }\n{ \"time\": \"3019107\", \"entity\": \"2\", \"state\": 17 }\n{ \"time\": \"3023591\", \"entity\": \"15\", \"state\": 7, \"tag\": \"ffffd062dbd3caa0\" }\n{ \"time\": \"3023621\", \"entity\": \"10\", \"state\": 17 }\n{ \"time\": \"3026750\", \"entity\": \"14\", \"state\": 17 }\n{ \"time\": \"3029498\", \"entity\": \"38\", \"state\": 0, \"tag\": \"497cdd0\" }\n{ \"time\": \"3029791\", \"entity\": \"11\", \"state\": 17 }\n{ \"time\": \"3033399\", \"entity\": \"15\", \"state\": 0, \"tag\": \"49a7f32\" }\n{ \"time\": \"3034832\", \"entity\": \"11\", \"state\": 0, \"tag\": \"497cdd1\" }\n{ \"time\": \"3042504\", \"entity\": \"14\", \"state\": 0, \"tag\": \"4a0e388\" }\n{ \"time\": \"3050698\", \"entity\": \"15\", \"state\": 17 }\n{ \"time\": \"3059843\", \"entity\": \"15\", \"state\": 0, \"tag\": \"49a7f32\" }\n{ \"time\": \"3067142\", \"entity\": \"14\", \"state\": 17 }\n{ \"time\": \"3087009\", \"entity\": \"9\", \"state\": 0, \"tag\": \"4980fc2\" }\n{ \"time\": \"3091275\", \"entity\": \"36\", \"state\": 17 }\n{ \"time\": \"3100875\", \"entity\": \"26\", \"state\": 0, \"tag\": \"497d4e2\" }\n{ \"time\": \"3103179\", \"entity\": \"38\", \"state\": 17 }\n{ \"time\": \"3112559\", \"entity\": \"38\", \"state\": 0, \"tag\": \"497cdd0\" }\n{ \"time\": \"3130384\", \"entity\": \"49\", \"state\": 17 }\n{ \"time\": \"3130852\", \"entity\": \"36\", \"state\": 0, \"tag\": \"49a7f42\" }\n{ \"time\": \"3144079\", \"entity\": \"52\", \"state\": 17 }\n{ \"time\": \"3148229\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"3148920\", \"entity\": \"9\", \"state\": 17 }\n{ \"time\": \"3152479\", \"entity\": \"43\", \"state\": 17 }\n{ \"time\": \"3159520\", \"entity\": \"18\", \"state\": 17 }\n{ \"time\": \"3163635\", \"entity\": \"18\", \"state\": 0, \"tag\": \"497cdd9\" }\n{ \"time\": \"3164268\", \"entity\": \"9\", \"state\": 0, \"tag\": \"4980fc2\" }\n{ \"time\": \"3165294\", \"entity\": \"43\", \"state\": 0, \"tag\": \"48d4ced\" }\n{ \"time\": \"3168555\", \"entity\": \"14\", \"state\": 0, \"tag\": \"4a0e388\" }\n{ \"time\": \"3171006\", \"entity\": \"11\", \"state\": 17 }\n{ \"state\": 1, \"tag\": \"3ecbe54\", \"thread\": \"mac`mac_srs_worker\", \"taskq\": \"<none>\" }\n{ \"time\": \"3183242\", \"entity\": \"52\", \"state\": 17 }\n{ \"time\": \"3183692\", \"entity\": \"11\", \"state\": 0, \"tag\": \"497cdd1\" }\n{ \"time\": \"3183796\", \"entity\": \"33\", \"state\": 1, \"tag\": \"3ecbe54\" }\n{ \"time\": \"3186062\", \"entity\": \"26\", \"state\": 17 }\n{ \"time\": \"3191125\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"3193820\", \"entity\": \"33\", \"state\": 17 }\n{ \"time\": \"3203137\", \"entity\": \"49\", \"state\": 0, \"tag\": \"497cdd3\" }\n{ \"time\": \"3207620\", \"entity\": \"14\", \"state\": 17 }\n{ \"time\": \"3208377\", \"entity\": \"11\", \"state\": 17 }\n{ \"time\": \"3209779\", \"entity\": \"9\", \"state\": 17 }\n{ \"time\": \"3228662\", \"entity\": \"15\", \"state\": 17 }\n{ \"time\": \"3233904\", \"entity\": \"15\", \"state\": 0, \"tag\": \"49a7f32\" }\n{ \"time\": \"3239573\", \"entity\": \"1\", \"state\": 0, \"tag\": \"48d4e10\" }\n{ \"time\": \"3242310\", \"entity\": \"9\", \"state\": 0, \"tag\": \"4980fc2\" }\n{ \"time\": \"3247045\", \"entity\": \"4\", \"state\": 15 }\n{ \"time\": \"3249062\", \"entity\": \"4\", \"state\": 17 }\n{ \"time\": \"3250489\", \"entity\": \"4\", \"state\": 3, \"tag\": \"2\" }\n{ \"time\": \"3254343\", \"entity\": \"52\", \"state\": 17 }\n{ \"time\": \"3254565\", \"entity\": \"4\", \"state\": 17 }\n{ \"time\": \"3257853\", \"entity\": \"4\", \"state\": 0, \"tag\": \"49a7f49\" }\n{ \"time\": \"3260479\", \"entity\": \"22\", \"state\": 0, \"tag\": \"48d4e18\" }\n{ \"time\": \"3261954\", \"entity\": \"19\", \"state\": 17 }\n{ \"time\": \"3266829\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"3267804\", \"entity\": \"22\", \"state\": 17 }\n{ \"time\": \"3270503\", \"entity\": \"4\", \"state\": 16 }\n{ \"time\": \"3271940\", \"entity\": \"9\", \"state\": 16 }\n{ \"time\": \"3272354\", \"entity\": \"15\", \"state\": 16 }\n{ \"time\": \"3272791\", \"entity\": \"18\", \"state\": 16 }\n{ \"time\": \"3272865\", \"entity\": \"4\", \"state\": 0, \"tag\": \"49a7f49\" }\n{ \"time\": \"3273096\", \"entity\": \"52\", \"state\": 16 }\n{ \"time\": \"3273281\", \"entity\": \"49\", \"state\": 16 }\n{ \"time\": \"3274285\", \"entity\": \"17\", \"state\": 16 }\n{ \"time\": \"3274728\", \"entity\": \"38\", \"state\": 16 }\n{ \"time\": \"3277012\", \"entity\": \"9\", \"state\": 0, \"tag\": \"4980fc2\" }\n{ \"time\": \"3277370\", \"entity\": \"52\", \"state\": 0, \"tag\": \"49a7f45\" }\n{ \"time\": \"3277741\", \"entity\": \"49\", \"state\": 0, \"tag\": \"497cdd3\" }\n{ \"time\": \"3278500\", \"entity\": \"15\", \"state\": 0, \"tag\": \"49a7f32\" }\n{ \"time\": \"3278837\", \"entity\": \"18\", \"state\": 0, \"tag\": \"497cdd9\" }\n{ \"time\": \"3282801\", \"entity\": \"15\", \"state\": 17 }\n{ \"time\": \"3283385\", \"entity\": \"17\", \"state\": 0, \"tag\": \"49a7f2e\" }\n{ \"time\": \"3284342\", \"entity\": \"38\", \"state\": 0, \"tag\": \"497cdd0\" }\n{ \"time\": \"3296061\", \"entity\": \"9\", \"state\": 17 }\n{ \"time\": \"3297797\", \"entity\": \"4\", \"state\": 17 }\n{ \"time\": \"3306163\", \"entity\": \"18\", \"state\": 17 }\n{ \"time\": \"3309408\", \"entity\": \"6\", \"state\": 0, \"tag\": \"497cdd9\" }\n{ \"time\": \"3316172\", \"entity\": \"4\", \"state\": 0, \"tag\": \"49a7f49\" }\n{ \"time\": \"3331918\", \"entity\": \"17\", \"state\": 17 }\n{ \"time\": \"3339615\", \"entity\": \"17\", \"state\": 0, \"tag\": \"49a7f2e\" }\n{ \"time\": \"3340029\", \"entity\": \"15\", \"state\": 0, \"tag\": \"49a7f32\" }\n{ \"time\": \"3343966\", \"entity\": \"38\", \"state\": 17 }\n{ \"time\": \"3347924\", \"entity\": \"49\", \"state\": 17 }\n{ \"time\": \"3352143\", \"entity\": \"38\", \"state\": 15 }\n{ \"time\": \"3352954\", \"entity\": \"4\", \"state\": 17 }\n{ \"state\": 2, \"tag\": \"3\", \"driver\": \"softint\", \"instance\": 0 }\n{ \"state\": 0, \"tag\": \"4a0e384\", \"pid\": \"50378\", \"tid\": \"1\", \"execname\": \"dtrace\", \"psargs\": \"/usr/sbin/dtrace -Cs ./postgres-statemap-zfs.d\" }\n{ \"state\": 0, \"tag\": \"49a7f42\", \"pid\": \"565192\", \"tid\": \"66\", \"execname\": \"pg_prefaulter\", \"psargs\": \"/opt/smartdc/manatee/bin/pg_prefaulter run --config=/opt/smartdc/manatee/etc/pg\" }\n{ \"state\": 0, \"tag\": \"49a7f49\", \"pid\": \"565192\", \"tid\": \"74\", \"execname\": \"pg_prefaulter\", \"psargs\": \"/opt/smartdc/manatee/bin/pg_prefaulter run --config=/opt/smartdc/manatee/etc/pg\" }\n{ \"state\": 0, \"tag\": \"497cdd3\", \"pid\": \"565192\", \"tid\": \"19\", \"execname\": \"pg_prefaulter\", \"psargs\": \"/opt/smartdc/manatee/bin/pg_prefaulter run --config=/opt/smartdc/manatee/etc/pg\" }\n{ \"state\": 0, \"tag\": \"49a7f45\", \"pid\": \"565192\", \"tid\": \"70\", \"execname\": \"pg_prefaulter\", \"psargs\": \"/opt/smartdc/manatee/bin/pg_prefaulter run --config=/opt/smartdc/manatee/etc/pg\" }\n{ \"state\": 0, \"tag\": \"49a7f32\", \"pid\": \"565192\", \"tid\": \"51\", \"execname\": \"pg_prefaulter\", \"psargs\": \"/opt/smartdc/manatee/bin/pg_prefaulter run --config=/opt/smartdc/manatee/etc/pg\" }\n{ \"state\": 0, \"tag\": \"49a7f46\", \"pid\": \"565192\", \"tid\": \"71\", \"execname\": \"pg_prefaulter\", \"psargs\": \"/opt/smartdc/manatee/bin/pg_prefaulter run --config=/opt/smartdc/manatee/etc/pg\" }\n{ \"state\": 0, \"tag\": \"497cdd0\", \"pid\": \"565192\", \"tid\": \"16\", \"execname\": \"pg_prefaulter\", \"psargs\": \"/opt/smartdc/manatee/bin/pg_prefaulter run --config=/opt/smartdc/manatee/etc/pg\" }\n{ \"state\": 0, \"tag\": \"4a0e388\", \"pid\": \"50380\", \"tid\": \"1\", \"execname\": \"pg_xlogdump\", \"psargs\": \"/opt/postgresql/current/bin/pg_xlogdump -f /manatee/pg/data/pg_xlog/00000001000\" }\n{ \"state\": 0, \"tag\": \"49a7f3e\", \"pid\": \"565192\", \"tid\": \"63\", \"execname\": \"pg_prefaulter\", \"psargs\": \"/opt/smartdc/manatee/bin/pg_prefaulter run --config=/opt/smartdc/manatee/etc/pg\" }\n{ \"state\": 0, \"tag\": \"49a7f2e\", \"pid\": \"565192\", \"tid\": \"47\", \"execname\": \"pg_prefaulter\", \"psargs\": \"/opt/smartdc/manatee/bin/pg_prefaulter run --config=/opt/smartdc/manatee/etc/pg\" }\n{ \"state\": 7, \"tag\": \"ffffd062dbcb7d58\", \"driver\": \"ixgbe\", \"instance\": 2 }\n{ \"state\": 0, \"tag\": \"497cdd1\", \"pid\": \"565192\", \"tid\": \"17\", \"execname\": \"pg_prefaulter\", \"psargs\": \"/opt/smartdc/manatee/bin/pg_prefaulter run --config=/opt/smartdc/manatee/etc/pg\" }\n{ \"state\": 0, \"tag\": \"48d4b6d\", \"pid\": \"5447\", \"tid\": \"1\", \"execname\": \"node\", \"psargs\": \"node --abort-on-uncaught-exception main.js -f etc/config.json -p 2021 -k 3021\" }\n{ \"state\": 0, \"tag\": \"497cdd4\", \"pid\": \"565192\", \"tid\": \"20\", \"execname\": \"pg_prefaulter\", \"psargs\": \"/opt/smartdc/manatee/bin/pg_prefaulter run --config=/opt/smartdc/manatee/etc/pg\" }\n{ \"state\": 0, \"tag\": \"497cd9f\", \"pid\": \"565192\", \"tid\": \"1\", \"execname\": \"pg_prefaulter\", \"psargs\": \"/opt/smartdc/manatee/bin/pg_prefaulter run --config=/opt/smartdc/manatee/etc/pg\" }\n{ \"state\": 0, \"tag\": \"4980fc2\", \"pid\": \"565192\", \"tid\": \"27\", \"execname\": \"pg_prefaulter\", \"psargs\": \"/opt/smartdc/manatee/bin/pg_prefaulter run --config=/opt/smartdc/manatee/etc/pg\" }\n{ \"state\": 0, \"tag\": \"497cdd9\", \"pid\": \"565192\", \"tid\": \"24\", \"execname\": \"pg_prefaulter\", \"psargs\": \"/opt/smartdc/manatee/bin/pg_prefaulter run --config=/opt/smartdc/manatee/etc/pg\" }\n{ \"state\": 0, \"tag\": \"48d4b75\", \"pid\": \"5447\", \"tid\": \"2\", \"execname\": \"node\", \"psargs\": \"node --abort-on-uncaught-exception main.js -f etc/config.json -p 2021 -k 3021\" }\n{ \"state\": 10, \"tag\": \"b\", \"driver\": \"softint\", \"instance\": 0 }\n{ \"state\": 0, \"tag\": \"48d4ade\", \"pid\": \"5336\", \"tid\": \"1\", \"execname\": \"node\", \"psargs\": \"node --abort-on-uncaught-exception main.js -f etc/config.json -p 2021 -k 3021\" }\n{ \"state\": 0, \"tag\": \"48d4ae8\", \"pid\": \"5336\", \"tid\": \"2\", \"execname\": \"node\", \"psargs\": \"node --abort-on-uncaught-exception main.js -f etc/config.json -p 2021 -k 3021\" }\n{ \"state\": 0, \"tag\": \"4a0e383\", \"pid\": \"50377\", \"tid\": \"1\", \"execname\": \"dtrace\", \"psargs\": \"/usr/sbin/dtrace -Cs ./cpu-statemap-tagged.d\" }\n{ \"state\": 0, \"tag\": \"48d4ced\", \"pid\": \"5737\", \"tid\": \"1\", \"execname\": \"node\", \"psargs\": \"node --abort-on-uncaught-exception main.js -f etc/config.json -p 2023 -k 3023\" }\n{ \"state\": 0, \"tag\": \"48d4d00\", \"pid\": \"5737\", \"tid\": \"2\", \"execname\": \"node\", \"psargs\": \"node --abort-on-uncaught-exception main.js -f etc/config.json -p 2023 -k 3023\" }\n{ \"state\": 0, \"tag\": \"497d20a\", \"pid\": \"566150\", \"tid\": \"1\", \"execname\": \"postgres\", \"psargs\": \"/opt/postgresql/9.6.3/bin/postgres -D /manatee/pg/data\" }\n{ \"state\": 0, \"tag\": \"497d212\", \"pid\": \"566158\", \"tid\": \"1\", \"execname\": \"postgres\", \"psargs\": \"/opt/postgresql/9.6.3/bin/postgres -D /manatee/pg/data\" }\n{ \"state\": 0, \"tag\": \"48d4e10\", \"pid\": \"5958\", \"tid\": \"1\", \"execname\": \"node\", \"psargs\": \"node --abort-on-uncaught-exception main.js -f etc/config.json -p 2024 -k 3024\" }\n{ \"state\": 0, \"tag\": \"497d4e2\", \"pid\": \"566865\", \"tid\": \"1\", \"execname\": \"postgres\", \"psargs\": \"/opt/postgresql/9.6.3/bin/postgres -D /manatee/pg/data\" }\n{ \"state\": 0, \"tag\": \"48d4e18\", \"pid\": \"5958\", \"tid\": \"2\", \"execname\": \"node\", \"psargs\": \"node --abort-on-uncaught-exception main.js -f etc/config.json -p 2024 -k 3024\" }\n{ \"state\": 0, \"tag\": \"497e0d4\", \"pid\": \"569380\", \"tid\": \"1\", \"execname\": \"postgres\", \"psargs\": \"/opt/postgresql/9.6.3/bin/postgres -D /manatee/pg/data\" }\n{ \"state\": 1, \"tag\": \"508\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"state\": 1, \"tag\": \"506\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"state\": 1, \"tag\": \"56b\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"state\": 1, \"tag\": \"50c\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"state\": 1, \"tag\": \"572\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"state\": 1, \"tag\": \"589\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"state\": 1, \"tag\": \"511\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"state\": 1, \"tag\": \"563\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"state\": 1, \"tag\": \"588\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"state\": 1, \"tag\": \"50f\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"state\": 1, \"tag\": \"591\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"state\": 1, \"tag\": \"568\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"state\": 1, \"tag\": \"505\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"state\": 1, \"tag\": \"494\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"state\": 1, \"tag\": \"50b\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"state\": 1, \"tag\": \"50a\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"state\": 1, \"tag\": \"3a3\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"state\": 1, \"tag\": \"586\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"state\": 1, \"tag\": \"332\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"state\": 1, \"tag\": \"1a1\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"state\": 1, \"tag\": \"431\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"state\": 1, \"tag\": \"149\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"state\": 1, \"tag\": \"2fc\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"state\": 1, \"tag\": \"53d\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"state\": 1, \"tag\": \"159\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"state\": 1, \"tag\": \"3c4\", \"thread\": \"zfs`dbuf_evict_thread\", \"taskq\": \"<none>\" }\n{ \"state\": 1, \"tag\": \"454\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"state\": 1, \"tag\": \"532\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"state\": 1, \"tag\": \"401\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"state\": 1, \"tag\": \"441\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"state\": 1, \"tag\": \"201\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"state\": 1, \"tag\": \"109\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"state\": 1, \"tag\": \"4f0\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"state\": 7, \"tag\": \"ffffd062dbd3caa0\", \"driver\": \"ixgbe\", \"instance\": 0 }\n{ \"state\": 1, \"tag\": \"56f\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"state\": 1, \"tag\": \"474\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"state\": 1, \"tag\": \"231\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"state\": 1, \"tag\": \"3b3\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"state\": 1, \"tag\": \"55c\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"state\": 1, \"tag\": \"421\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"state\": 1, \"tag\": \"547\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"state\": 1, \"tag\": \"139\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"state\": 1, \"tag\": \"58a\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"state\": 1, \"tag\": \"48c0687\", \"thread\": \"mac`mac_srs_worker\", \"taskq\": \"<none>\" }\n{ \"state\": 0, \"tag\": \"497cdc5\", \"pid\": \"565220\", \"tid\": \"1\", \"execname\": \"postgres\", \"psargs\": \"/opt/postgresql/9.6.3/bin/postgres -D /manatee/pg/data\" }\n{ \"state\": 1, \"tag\": \"119\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"state\": 1, \"tag\": \"2\", \"driver\": \"softint\", \"instance\": 0 }\n{ \"state\": 1, \"tag\": \"353\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"state\": 1, \"tag\": \"592\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"state\": 1, \"tag\": \"4e9\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"state\": 1, \"tag\": \"245\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"state\": 1, \"tag\": \"570\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"state\": 1, \"tag\": \"1b1\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"state\": 1, \"tag\": \"ae\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"state\": 1, \"tag\": \"343\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"state\": 1, \"tag\": \"565\", \"thread\": \"genunix`taskq_thread\", \"taskq\": \"callout_taskq\" }\n{ \"state\": 1, \"tag\": \"d7\", \"thread\": \"ip`squeue_worker\", \"taskq\": \"<none>\" }\n{ \"state\": 1, \"tag\": \"3ecbe54\", \"thread\": \"mac`mac_srs_worker\", \"taskq\": \"<none>\" }\n"
  }
]