[
  {
    "path": ".editorconfig",
    "content": "[*.{sh,md,cfg,sample}]\nindent_style = tab\nindent_size = 4\n\n[bashtop]\nindent_style = tab\nindent_size = 4"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: aristocratos\npatreon: # Replace with a single Patreon username\nopen_collective: # Replace with a single Open Collective username\nko_fi: # Replace with a single Ko-fi username\ntidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel\ncommunity_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry\nliberapay: # Replace with a single Liberapay username\nissuehunt: # Replace with a single IssueHunt username\notechie: # Replace with a single Otechie username\ncustom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: \"[BUG]\"\nlabels: bug\nassignees: aristocratos\n\n---\n\n**Describe the bug**\n\n[A clear and concise description of what the bug is.]\n\n**To Reproduce**\n\n[Steps to reproduce the behavior:]\n\n**Expected behavior**\n\n[A clear and concise description of what you expected to happen.]\n\n**Screenshots**\n\n[If applicable, add screenshots to help explain your problem.]\n\n**Info (please complete the following information):**\n - Bashtop version:\n - (Linux) Linux distribution and version:\n - (Linux) Data collection type (/proc or psutil):\n - Psutil version: `python3 -c \"import psutil; print(psutil.version_info)\"` (version 5.7.0 or above is required):\n - (OSX/FreeBSD) Os release version:\n - Terminal used:\n - Font used:\n - Bash version, `bash --version` (version 4.4 or above is required):\n - Locales: output of `locale -v`\n\n**Additional context**\n\ncontents of `$HOME/.config/bashtop/error.log`\n\n(enable error-logging in \"$HOME/.config/bashtop/bashtop.cfg\" if missing)\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: \"[REQUEST]\"\nlabels: enhancement\nassignees: aristocratos\n\n---\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\nAdd any other context or screenshots about the feature request here.\n"
  },
  {
    "path": ".gitignore",
    "content": "DEB/bashtop_*\nDEB/usr/*"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"test/libs/bats\"]\n\tpath = test/libs/bats\n\turl = https://github.com/sstephenson/bats\n[submodule \"test/libs/bats-assert\"]\n\tpath = test/libs/bats-assert\n\turl = https://github.com/ztombol/bats-assert\n[submodule \"test/libs/bats-support\"]\n\tpath = test/libs/bats-support\n\turl = https://github.com/ztombol/bats-support\n"
  },
  {
    "path": ".travis.yml",
    "content": "# travis does not offer python container for OSX or Windows, not sure if we can get automated testing?\nos: linux\nlanguage: python\npython:\n  - \"3.6\"\ndist: bionic\ninstall:\n  - pip install -r requirements.txt\nscript: ./test.sh\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\n\n## v0.9.25\n\n* Fixed: Crash when using \"/proc\" data collection and filesystem type is 9p, by @bolapara\n\n## v0.9.24\n\n* Fixed: Psutil script crash on OSX\n* Fixed: Error handling for malformed osx-cpu-temp output\n\n## v0.9.23\n\n* Fixed: kill/terminate/interrupt process not working in OsX and FreeBSD\n\n## v0.9.22\n\n* Added: Added handler for mktemp failure for psutil script\n* Removed: Secondary mktemp command for psutil script\n* Fixed: Insecure test import of psutil changed\n\n## v0.9.21\n\n* Changed: Config file comments for theme locations\n* Added: Check for correct theme file path prefix\n* Added: Support for application cursor mode input\n* Fixed: Incorrect value calculation for reversed proc gradient\n\n## v0.9.20\n\n* Fixed: Psutil script security issue when placed directly in temp folder\n\n## v0.9.19\n\n* Added: Option for timestamps with python on bash < 5\n* Changed: Reverted \"date\" command timestamps to not using fifo\n* Added missing # from hex value in monokai theme\n\n## v0.9.18\n\n* Fixed: Errors caused by process scroll change\n* Fixed: Process graph creation ignored for process below 0.5%\n\n## v0.9.17\n\n* Changed: Process list now scrolls instead of \"page jump\" and shows number of processes instead of number of pages\n* Fixed: Inverted gradient on dark text in processes box\n\n## v0.9.16\n\n* Fixed: Errors in v0.9.15 psutil disk collection fix\n* Added: Additional graph creation error checks\n\n## v0.9.15\n\n* Fixed: Psutil error on disk collection now fallback to df and iostat\n\n## v0.9.14\n\n* Added: Additional processes error checking\n* Added: Additional sensors error checking\n* Added: Additional psutil error checking\n\n## v0.9.13\n\n* Added: More robust psutil error handling\n\n## v0.9.12\n\n* Changed: Psutil data collection now runs a python script in a coprocess taking commands and sending output over coproc pipes\n* Added: Psutil data collection now replaces most external calls including sensors, cpu info, disks info and io collection\n* Changed: Tree view is now a toggle instead of sorting option\n* Fixed: Cpu temp check not using vcgencmd when sensors is available\n\n## v0.9.11\n\n* Fixed: Processes text color now sets RGB instead of RBB...\n\n## v0.9.10\n\n* Fixed: Humanizer function now round values 1000-1023 up to 1024 to fit size constraints.\n* Added: More error checks for psutil\n* Changed: Terminal title now includes original title if $TERMINAL_TITLE is set, suggested by @theytaz\n\n## v0.9.9\n\n* Fixed: Fixed theme downloader not reporting new themes and corrected comment in config\n\n## v0.9.8\n\n* Added: Nord theme by Justin Zobel\n* Changed: Theme downloader now overwrites default themes, folder user_themes (safe from overwrites) added\n* Changed: Cleaned up monokai theme variants\n* Added: Base for testing with BATS by Maciek Swiech\n\n## v0.9.7\n\n* Changed: UTF-8 locale check, try to find UTF-8 for current language if LANG is set but not with \"UTF-8\" suffix\n\n## v0.9.6\n\n* Fixed: UTF-8 locale check\n\n## v0.9.5\n\n* Added: UTF-8 locale check and automatic LANG variable set if not UTF-8\n* Fixed: Filter out zero sized disks and added some psutil error checks\n\n## v0.9.4\n\n* Fixed: Missing path for OSX df and correct swap usage reporting for OSX\n\n## v0.9.3\n\n* Fixed: Resizing problems in iTerm2\n* Changed: Removed redundant error checking in print function for lower cpu usage\n* Fixed: Memory in OSX now shows active memory usage and /private/var/vm as swap memory\n* Fixed: Disks in OSX changed from using \"GNU df\" to \"BSD df\" for better compatibility\n\n## v0.9.2\n\n* Fixed: Correct prefixes for some missed GNU tools\n* Added: Startup progress screen\n* Changed: replaced tput commands with escape sequence commands\n\n## v0.9.1\n\n* Added: FreeBSD support with python3 psutil data collection\n* Added: Check for gnu tools on non Linux platforms\n* Fixed: Increased graph history to avoid cut off on high resolution graphs\n\n## v0.9.0\n\n* Added: Mac OS X support with python3 psutil data collection\n* Added: Ability to switch between all available network devices\n\n## v0.8.32\n\n* Fixed: Error in theme error checking corrupting default theme\n\n## v0.8.31\n\n* Fixed: Theme 2-color gradient generation\n* Fixed: Theme file error checking\n\n## v0.8.30\n\n* Fixed: Crash on missing net device\n\n## v0.8.29\n\n* Fixed: Cpu temperature colors not working when above high temp value\n* Fixed: Unescaped \"\\\" in process list and indent fixes\n* Changed: Changes to net graph rescaling parameters\n\n## v0.8.28\n\n* Fixed: Ctrl-C and Ctrl-Z not registering after change to \"dd\"\n* Added: Option to switch to high resolution graphs\n* Added: Current peak value for download/upload graphs\n\n## v0.8.27\n\n* Fixed: Use value for \"Inactive\"+\"MemFree\" if \"MemAvailable\" is missing in /proc/meminfo\n* Added: Option to toggle update check at start\n\n## v0.8.26\n\n* Fixed: Escaped delimiter for sed to fix config not saving \"/\" character\n* Fixed: Detailed process view missing info and slowdown in certain cases\n* Optimization: Fork cleanup\n\n## v0.8.25\n\n* Fixed: Backspace not registering when not set to send ascii delete\n* Fixed: Broken cpu temperature graph when is value over cpu high temp\n* Added: Possibility to run date through background fifo for bash <5\n\n## v0.8.24\n\n* Fixed: Input error freezes, by changing from using \"read\" command to using \"dd\" for reading keyboard input.\n\n## v0.8.23\n\n* Added: Support for Raspberry Pi cpu temperature reporting\n* Fixed: Decreased chance of read command stalling on lower spec systems\n* Added: Failover to nproc if lscpu are reporting 0 cpu cores\n* Changed: Moved page display for options and help to bottom and changed to Page Up/Down for changing page\n\n## v0.8.22\n\n* Added: Sorting option \"tree\", shows processes in a tree structure\n* Added: Option to toggle process cpu usage per core instead of total available cpu power\n* Fixed: Possible fix for stalling read command\n* Added: Multiple while loop fail safes\n\n## v0.8.21\n\n* Fixed: iostat flag compatibility for older iostat versions\n* Fixed: possible fix for script stall on bash 4\n\n## v0.8.20\n\n* Fixed: Update slowdown when not sorting by cpu\n* Added: New version desktop notification\n\n## v0.8.19\n\n* Added: Disks read and write stats, requires new optional dependency \"iostat (part of sysstat)\"\n* Fixed: Ctrl-C not working when showing resize error message\n* Fixed: Network download/upload offset auto switched off if /proc/net/dev resets\n* Fixed: Removed trailing whitespace in script\n\n## v0.8.18\n\n* Added: Pagination for help and options windows if items don't fit\n* Added: Option to turn off color gradient in process list\n* Changed: bash version check to use $BASH_VERSINFO array\n* Added: Filter for shown disks\n* Added: Option to reset network totals in options menu\n\n## v0.8.17\n\n* Fixed: Not showing CPU temperatures when \"Package\" temp is missing\n* Added: CPU temperature support for AMD Ryzen\n* Changed: Minimum size changed from 80x25 to 80x24\n* Fixed: High cpu usage on systems with a lot of mounted disks\n\n## v0.8.16\n\n* Added: Bash version check, by Calinou\n* Added: OS check, by kpucynski\n* Fixed: number of themes reported in options when theme folder is empty, by deluxe\n* Fixed: README.md typos, by lucaskim1233\n* Added: CHANGELOG.md\n\n## v0.8.15\n\n* Added: deb build script by Jukoo\n* Fixed: load average and uptime not showing\n* Fixed: freeze on reverse process order when showing detailed information\n* Fixed: single quotes on associative arrays\n\n## v0.8.14\n\n* Fixed: disks usage runaway array\n* Fixed: disks used not reporting new values\n* Changed: memory and disks update frequency increased\n\n## v0.8.13\n\n* Fixed: get_value() regex\n* Added: 2 new themes, flat-remix and flat-remix-light, by Daniel Ruiz de Alegría\n* Other: general cleanup and formatting\n\n## v0.8.12\n\n* Fixed: changed remaining ps thcount flags to nlwp\n\n## v0.8.11\n\n* Fixed: ps flag thcount changed to nlwp for greater compability\n* Fixed: regex and float to int rounding in get_value()\n\n## v0.8.10\n\n* Fixed: erroneous regular expressions\n\n## v0.8.9\n\n* Added: functions is_int, is_float, is_hex\n* Fixes: error checking on internal functions\n\n## v0.8.8\n\n* Fixed: load average max length\n\n## v0.8.7\n\n* Fixed: load average clipping\n* Fixed: cpu box calculations error\n\n## v0.8.6\n\n* Added: load average and uptime\n* Fixed: cohesive window size representation\n* Added: unset LC_ALL to not override wanted locale\n* Fixed: cpu box calculation errors\n\n## v0.8.5\n\n* Fixed: cpu frequency and /proc/stat error checks\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as\ncontributors and maintainers pledge to making participation in our project and\nour community a harassment-free experience for everyone, regardless of age, body\nsize, disability, ethnicity, sex characteristics, gender identity and expression,\nlevel of experience, education, socio-economic status, nationality, personal\nappearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment\ninclude:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or\n advances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic\n address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable\nbehavior and are expected to take appropriate and fair corrective action in\nresponse to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or\nreject comments, commits, code, wiki edits, issues, and other contributions\nthat are not aligned to this Code of Conduct, or to ban temporarily or\npermanently any contributor for other behaviors that they deem inappropriate,\nthreatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces\nwhen an individual is representing the project or its community. Examples of\nrepresenting a project or community include using an official project e-mail\naddress, posting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event. Representation of a project may be\nfurther defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported by contacting the project team at admin@qvantnet.com. All\ncomplaints will be reviewed and investigated and will result in a response that\nis deemed necessary and appropriate to the circumstances. The project team is\nobligated to maintain confidentiality with regard to the reporter of an incident.\nFurther details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good\nfaith may face temporary or permanent repercussions as determined by other\nmembers of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,\navailable at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html\n\n[homepage]: https://www.contributor-covenant.org\n\nFor answers to common questions about this code of conduct, see\nhttps://www.contributor-covenant.org/faq"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing guidelines\n\n## When submitting pull requests\n\n* Explain your thinking in why a change or addition is needed.\n  * Is it a requested change or feature?\n  * If not, open a feature request to get feedback before making a pull request.\n\n* If it's a fix for a unreported bug, make a bug report and link the pull request.\n\n* Split up multiple unrelated changes in multiple pull requests.\n\n* [Shellcheck](https://github.com/koalaman/shellcheck) your work. Current shellsheck exceptions at the beginning of [bashtop](bashtop).\n\n* Purely cosmetic changes won't be accepted without a very good explanation of its value.\n  * (Some design choices are for better configurability of syntax highlighting.)\n\n## Formatting\n\n### Follow the current syntax design\n\n* Indent type: Tabs\n\n* Tab size: 4\n\n* Use the longer \"if, elif, then, else, fi\" statements and indent conditionals, loops etc.\n\n* Use \"[[ ]]\", \"(( ))\" for conditions and \"$( ), <( )\" for command substitution.\n\n* Create functions instead of repeating blocks of code.\n\n* Don't stack unrelated blocks of code, leave blank lines for better readability.\n\n* Comment new code that isn't very obvious in it's function.\n\n* Name new variables and functions in lower-case and after what purpose they serve.\n  * (Exception arithmetic with many variables, make sure to comment what's happening instead.)\n\n## Optimization\n\n* Avoid forks if possible.\n\n* Avoid writing to disk if possible.\n\n* Make sure variables/arrays are cleaned up if not reused.\n\n* Compare cpu and memory usage with and without your code and look for alternatives if they cause a noticeable negative impact.\n\nFor questions contact Aristocratos at admin@qvantnet.com\n\nFor proposing changes to this document create a [new issue](https://github.com/aristocratos/bashtop/issues/new/choose).\n"
  },
  {
    "path": "DEB/DEBIAN/control",
    "content": "Package: bashtop \nVersion: 0.0.0\nSection: base\nPriority: optional\nArchitecture: all\nDepends: bash (>= 4.4),curl (>= 7.16.2), coreutils, sed, awk, grep\nMaintainer: your_name  <xxx@xxx.xxx> \nDescription: Resource monitor that shows usage \n    and stats for processor, memory, disks, network and processes\nHomepage: https://github.com/aristocratos/bashtop\n"
  },
  {
    "path": "DEB/DEBIAN/postinst",
    "content": "#!/bin/bash  \n\n\necho -e \"[\\033[1;32m done \\033[0m]\"\n"
  },
  {
    "path": "DEB/DEBIAN/postrm",
    "content": "#!/bin/bash  \n\n\necho -e \"[\\033[1;32m successfully removed \\033[0m]\"\n"
  },
  {
    "path": "DEB/DEBIAN/preinst",
    "content": "#!/bin/bash  \n\n\necho -e \"[\\033[1;32m starting installation \\033[0m]\"\n"
  },
  {
    "path": "DEB/DEBIAN/prerm",
    "content": "#!/bin/bash  \n\n\necho -e \"[\\033[1;33m removing packet from the system \\033[0m]\"\n"
  },
  {
    "path": "DEB/build",
    "content": "#!/bin/bash  \n\n\n# this little script is just to automate the creation of the .deb package under debian and also the automatic installation of the bashtop program in the system. \n# How does it work? \n# ----\n# It parses the bashtop file to retrieve the last version specified in the script to allow a fresh creation of the .deb package \n# +by also retrieving the most recent version of the script then it proceeds to the installation ... \n\nset  -o errexit \n#set  -x   # just  for debuging  \n\nreadonly   file_src_location=../bashtop             #  bashtop location  ^ \nreadonly   ubin=usr/bin/\nreadonly   file_name=${file_src_location##*/}         \nreadonly   ctrl_file=DEBIAN/control \nreadonly   architecture=`dpkg --print-architecture` # for all architectures \nreadonly   root_uid=0\ndeclare    version  build_version  \n\n[[  ROOT::PERMISSION ]] \n{\n    [[ $UID -ne ${root_uid} ]]  && {\n        echo -e  \"require root user\"\n        exit  $UID\n    }\n}\n\n[[  ARGUMENTS::HANDLER ]] \n{ \n    if [[ -n $1 ]] ; then\n        case $1 in  \n            \"--remove\")\n                [[  -x  /${ubin}/${file_name} ]] && {\n                    dpkg --remove  ${file_name}\n                    test $? -eq 0 && exit 0   \n                }||{\n                    echo -e  \"~ nothing  todo:  bashtop is removed \" \n                    exit 0        \n                } \n                ;;\n        esac \n    fi \n}\n\necho -e \"+ building package ...\"\nsleep 1   \n[[ FILECHECK ]]  \n{\n    #+ require  bashtop file to read inside  \n    [[ !  -f  ${file_src_location} ]]  &&   {\n        echo  -e  \"undefine  ${file_name}\"\n        exit  3  #  just a basic exit   \n    }|| {\n        echo  -e \"+ populate   DEB folder \"\n        [[  -d  $ubin  ]] || mkdir -p  $ubin\n        `cp  $file_src_location  $ubin`\n    }\n\n    #+ require  control file  to write  inside  \n    [[ ! -f  ${ctrl_file}  ]]  && {\n      echo -e  \"undefined ${ctrl_file##*/}\"  \n      exit  3   \n    } \n} \n[[ IO::SEMVERS ]]  \n{\n    echo -e \"+ fetching the lastest  version of  ${file_name}\"\n    \n    get_current_version  () {\n        local watch_version=`grep  -i \"declare version\"  ${file_src_location}`\n        local semvers=${watch_version##*=}\n        echo  ${semvers:1:-1}  \n    }\n\n    set_new_version_ctrl() {\n        local catch_package_version=`grep -i  version  ${ctrl_file}` \n        version=${catch_package_version%%:*}\n        build_version=${catch_package_version##*:} \n        [[  -n $1  ]] && build_version=$1 \n        version+=\": ${build_version}\"  \n     \n        echo -e  \"+ set  new version control\"\n        `sed -i \"s/$catch_package_version/${version}/g\" ${ctrl_file}`\n    }\n\nset_new_version_ctrl $(get_current_version)  \n} \n\n[[ PACKAGER_BUILD::DEB ]] \n{\n    build_for_debian_base (){ \n        local debian_package_name=${file_name}_${build_version}-${architecture}.deb  \n        #echo  ${debian_package_name}\n        dpkg-deb --build   ../DEB   ${debian_package_name} \n        test  $?  -eq 0  &&  {\n           if [[ -f   ${debian_package_name} ]] ;then\n               dpkg -i ${debian_package_name}\n               [[ $? -eq 0 ]] &&  {\n                 exit $?\n               }||{ \n                    echo -e  \"Installation failed\" \n                    exit $?  \n               }\n           fi\n        }||{\n           echo -e \"build failed\"\n           exit 5 \n        }\n    }\n\nbuild_for_debian_base\n}\n\n\n"
  },
  {
    "path": "LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "Makefile",
    "content": "PREFIX ?= /usr/local\nDOCDIR ?= $(PREFIX)/share/doc/bashtop\n\nall:\n\t@echo Run \\'make install\\' to install bashtop.\n\ninstall:\n\t@mkdir -p $(DESTDIR)$(PREFIX)/bin\n\t@cp -p bashtop $(DESTDIR)$(PREFIX)/bin/bashtop\n\t@mkdir -p $(DESTDIR)$(DOCDIR)\n\t@cp -p README.md $(DESTDIR)$(DOCDIR)\n\t@chmod 755 $(DESTDIR)$(PREFIX)/bin/bashtop\n\nuninstall:\n\t@rm -rf $(DESTDIR)$(PREFIX)/bin/bashtop\n\t@rm -rf $(DESTDIR)$(DOCDIR)\n"
  },
  {
    "path": "README.md",
    "content": "# ![bashtop](Imgs/logo-t.png)\n\n![Linux](https://img.shields.io/badge/-Linux-grey?logo=linux)\n![OSX](https://img.shields.io/badge/-OSX-black?logo=apple)\n![FreeBSD](https://img.shields.io/badge/-FreeBSD-red?logo=freebsd)\n![Usage](https://img.shields.io/badge/Usage-System%20resource%20monitor-blue)\n![Bash](https://img.shields.io/badge/Bash-v4.4%5E-green?logo=GNU%20bash)\n![Python](https://img.shields.io/badge/Python-v3.6%5E-orange?logo=python)\n![bashtop_version](https://img.shields.io/github/v/tag/aristocratos/bashtop?label=version)\n[![Build Status](https://travis-ci.com/aristocratos/bashtop.svg?branch=master)](https://travis-ci.com/aristocratos/bashtop)\n[![Donate](https://img.shields.io/badge/-Donate-yellow?logo=paypal)](https://paypal.me/aristocratos)\n[![Sponsor](https://img.shields.io/badge/-Sponsor-red?logo=github)](https://github.com/sponsors/aristocratos)\n[![Coffee](https://img.shields.io/badge/-Buy%20me%20a%20Coffee-grey?logo=Ko-fi)](https://ko-fi.com/aristocratos)\n\n### C++ Version\n\n##### 18 September 2021\n\n![btop++](https://raw.githubusercontent.com/aristocratos/btop/main/Img/logo.png)\n\nThe C++ version of bashtop - btop++ is available.\n\nGet it at https://github.com/aristocratos/btop\n\n#\n\n## Index\n\n* [Documents](#documents)\n* [Description](#description)\n* [Features](#features)\n* [Themes](#themes)\n* [Support and funding](#support-and-funding)\n* [Prerequisites](#prerequisites)\n* [Dependencies](#dependencies)\n* [Screenshots](#screenshots)\n* [Installation](#installation)\n* [Configurability](#configurability)\n* [TODO](#todo)\n* [License](#license)\n\n\n## Documents\n\n#### [CHANGELOG.md](CHANGELOG.md)\n\n#### [CONTRIBUTING.md](CONTRIBUTING.md)\n\n#### [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)\n\n## Description\n\nResource monitor that shows usage and stats for processor, memory, disks, network and processes.\n\n## Features\n\n* Easy to use, with a game inspired menu system.\n* Fast and \"mostly\" responsive UI with UP, DOWN keys process selection.\n* Function for showing detailed stats for selected process.\n* Ability to filter processes.\n* Easy switching between sorting options.\n* Send SIGTERM, SIGKILL, SIGINT to selected process.\n* UI menu for changing all config file options.\n* Auto scaling graph for network usage.\n* Shows message in menu if new version is available\n* Shows current read and write speeds for disks\n* Multiple data collection methods which can be switched if running on Linux\n\n## Themes\n\nBashtop now has theme support and a function to download missing local themes from repository.\n\nSee [themes](themes) folder for available themes.\n\nThe builtin theme downloader places the default themes in `$HOME/.config/bashtop/themes`.\nUser created themes should be placed in `$HOME/.config/bashtop/user_themes` to be safe from overwrites.\n\nLet me know if you want to contribute with new themes.\n\n## Support and funding\n\nBug fixes and updates might be slow during normal workdays since I work full time as an industrial worker and don't have much time or energy left during the week.\nI'm looking into ways of funding this project that would allow me to take off time from my day job to work on this.\n\nAny advice on how to get funding for open source projects is very welcome!\n\n#### Update\n\nYou can now sponsor this project through github, see [my sponsors page](https://github.com/sponsors/aristocratos) for options.\n\nAlso added donation links for [paypal](https://paypal.me/aristocratos) and [ko-fi](https://ko-fi.com/aristocratos).\n\nAny support is greatly appreciated!\n\n## Prerequisites\n\n#### Mac Os X\n\nWill not display correctly in the standard terminal!\nRecommended alternative [iTerm2](https://www.iterm2.com/)\n\nWill also need to be run as superuser to display stats for processes not owned by user.\n\n#### Linux, Mac Os X and FreeBSD\n\nFor correct display, a terminal with support for:\n\n* 24-bit truecolor ([See list of terminals with truecolor support](https://gist.github.com/XVilka/8346728))\n* Wide characters (Are sometimes problematic in web-based terminals)\n\nAlso needs a UTF8 locale and a font that covers:\n\n* Unicode Block “Braille Patterns” U+2800 - U+28FF\n* Unicode Block “Geometric Shapes” U+25A0 - U+25FF\n* Unicode Block \"Box Drawing\" and \"Block Elements\" U+2500 - U+259F\n\n#### Notice\n\nDropbear seems to not be able to set correct locale. So if accessing bashtop over ssh, OpenSSH is recommended.\n\n## Dependencies\n\n## Linux, OSX and FreeBSD\n\n**[bash](https://www.gnu.org/software/bash/)** (v4.4 or later) Script functionality will most probably break with earlier versions.\nBash version 5 is highly recommended to make use of $EPOCHREALTIME variable instead of a lot of external date command calls.\n\n**[GNU coreutils](https://www.gnu.org/software/coreutils/)**\n\n**[GNU sed](https://www.gnu.org/software/sed/)**\n\n## Linux using /proc for data collection\n\n**[GNU grep](https://www.gnu.org/software/grep/)**\n\n**[ps from procps-ng](https://gitlab.com/procps-ng/procps)** (v3.1.15 or later)\n\n**[GNU awk](https://www.gnu.org/software/gawk/)**\n\n## OSX and FreeBSD or Linux using psutil for data collection\n\n**[Python3](https://www.python.org/downloads/)** (v3.6 or later)\n\n**[psutil python module](https://github.com/giampaolo/psutil)** (v5.7.0 or later)\n\n## Optionals for additional stats\n\n(Optional OSX) **[osx-cpu-temp](https://github.com/lavoiesl/osx-cpu-temp)** Needed to show CPU temperatures.\n\n(Optional Linux) **[lm-sensors](https://github.com/lm-sensors/lm-sensors)** Needed to show CPU temperatures.\n\n(Optional Linux) **[iostat (part of sysstat)](https://github.com/sysstat/sysstat)** Needed if you want disk read/write stats and are not using psutil data collection.\n\n(Optional OSX/Linux/FreeBSD) **[curl](https://curl.haxx.se/download.html)** (v7.16.2 or later) Needed if you want messages about updates and the ability to download themes.\n\n## Screenshots\n\nMain UI showing details for a selected process.\n![Screenshot 1](Imgs/main.png)\n\nMain menu.\n![Screenshot 2](Imgs/menu.png)\n\nOptions menu.\n![Screenshot 3](Imgs/options.png)\n\n## Installation\n\n#### Dependencies installation OSX\n\n>Install homebrew if not already installed\n\n``` bash\n/bin/bash -c \"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)\"\n```\n\n\n\n>If you got python 3.6 or later installed outside of brew:\n\n``` bash\nsudo python3 -m ensurepip\nsudo python3 -m pip install psutil\n```\n\n>If you haven't got python3 installed:\n\n```\nbrew install python3\npython3 -m pip install psutil\n```\n\n>Install dependencies\n\n\n``` bash\nbrew install bash coreutils gnu-sed git\n```\n\n>Install optional dependency osx-cpu-temp\n\n``` bash\nbrew install osx-cpu-temp\n```\n\n#### Dependencies installation FreeBSD\n\n>Install with pkg and pip\n\n``` bash\nsudo pkg install coreutils gsed git py37-psutil\n```\n\n#### Manual installation Linux, OSX and FreeBSD\n\n>Clone and install\n\n``` bash\ngit clone https://github.com/aristocratos/bashtop.git\ncd bashtop\nsudo make install\n```\n\n>to uninstall it\n\n``` bash\nsudo make uninstall\n```\n\n#### FreeBSD package\n\nAvailable in [FreeBSD ports](https://www.freshports.org/sysutils/bashtop/)\n\nInstall pre-built pacakge\n\n``` bash\nsudo pkg install bashtop\n```\n\n#### Arch based\n\nAvailable in the AUR as [bashtop-git](https://aur.archlinux.org/packages/bashtop-git/)\n\nAvailable in the Arch Linux repository as [bashtop](https://www.archlinux.org/packages/community/any/bashtop/)\n\n#### Debian based\n\nAvailable in [official Debian repository](https://tracker.debian.org/pkg/bashtop) since Debian 11\n\nAvailable for debian/ubuntu from [Azlux's repository](http://packages.azlux.fr/)\n\nOr use quick installation:\n\n>Quick install go to DEB  folder  and type\n\n``` bash\n sudo ./build\n```\n\n>to uninstall it   go to DEB  folder  and type\n\n``` bash\n sudo ./build --remove\n```\n\n#### Guix based\n\nAvailable in [official Guix repository](https://git.savannah.gnu.org/cgit/guix.git/tree/gnu/packages/admin.scm) since 6bbd0fd2\n\n>Installation\n\n``` bash\nguix install bashtop\n```\n\n#### Ubuntu based\n\nAvailable in [official Ubuntu repository](https://launchpad.net/ubuntu/+source/bashtop) since Ubuntu 20.10\n\nAvailable for Ubuntu from [PPA repository](https://code.launchpad.net/~bashtop-monitor/+archive/ubuntu/bashtop)\n\n>Add PPA repository and install bashtop\n\n``` bash\n sudo add-apt-repository ppa:bashtop-monitor/bashtop\n sudo apt update\n sudo apt install bashtop\n```\n\n#### Fedora\n\nAvailable in the Fedora repository.\n\n>Installation\n\n``` bash\nsudo dnf install bashtop\n```\n\n#### CentOS 8\n\n>Installation\n\n``` bash\ndnf config-manager --set-enabled PowerTools\ndnf install epel-release\ndnf install bashtop\n```\n\n#### RHEL 8\n\n>Installation\n\n``` bash\nARCH=$( /bin/arch )\nsubscription-manager repos --enable\n\"codeready-builder-for-rhel-8-${ARCH}-rpms\"\ndnf install epel-release\ndnf install bashtop\n```\n\n## Configurability\n\nAll options changeable from within UI.\nConfig files stored in \"$HOME/.config/bashtop\" folder\n\n#### bashtop.cfg: (auto generated if not found)\n\n```bash\n#? Config file for bashtop v. 0.9.21\n\n#* Color theme, looks for a .theme file in \"$HOME/.config/bashtop/themes\" and \"$HOME/.config/bashtop/user_themes\"\n#* Should be prefixed with either \"themes/\" or \"user_themes/\" depending on location, \"Default\" for builtin default theme\ncolor_theme=\"Default\"\n\n#* Update time in milliseconds, increases automatically if set below internal loops processing time, recommended 2000 ms or above for better sample times for graphs\nupdate_ms=\"2500\"\n\n#* Processes sorting, \"pid\" \"program\" \"arguments\" \"threads\" \"user\" \"memory\" \"cpu lazy\" \"cpu responsive\"\n#* \"cpu lazy\" updates sorting over time, \"cpu responsive\" updates sorting directly\nproc_sorting=\"cpu lazy\"\n\n#* Reverse sorting order, \"true\" or \"false\"\nproc_reversed=\"false\"\n\n#* Show processes as a tree\nproc_tree=\"false\"\n\n#* Check cpu temperature, only works if \"sensors\", \"vcgencmd\" or \"osx-cpu-temp\" commands is available\ncheck_temp=\"true\"\n\n#* Draw a clock at top of screen, formatting according to strftime, empty string to disable\ndraw_clock=\"%X\"\n\n#* Update main ui when menus are showing, set this to false if the menus is flickering too much for comfort\nbackground_update=\"true\"\n\n#* Custom cpu model name, empty string to disable\ncustom_cpu_name=\"\"\n\n#* Enable error logging to \"$HOME/.config/bashtop/error.log\", \"true\" or \"false\"\nerror_logging=\"true\"\n\n#* Show color gradient in process list, \"true\" or \"false\"\nproc_gradient=\"true\"\n\n#* If process cpu usage should be of the core it's running on or usage of the total available cpu power\nproc_per_core=\"false\"\n\n#* Optional filter for shown disks, should be names of mountpoints, \"root\" replaces \"/\", separate multiple values with space\ndisks_filter=\"\"\n\n#* Enable check for new version from github.com/aristocratos/bashtop at start\nupdate_check=\"true\"\n\n#* Enable graphs with double the horizontal resolution, increases cpu usage\nhires_graphs=\"false\"\n\n#* Enable the use of psutil python3 module for data collection, default on OSX\nuse_psutil=\"true\"\n```\n\n#### Command line options: (not yet implemented)\n\n``` bash\nUSAGE: bashtop\n\n```\n\n## TODO\n\nMight finish off items out of order since I usually work on multiple at a time.\n\n- [x] Add options to change colors for text, graphs and meters.\n- [x] Fix cross platform compatibility for Mac OSX and *BSD: Working on OSX, and FreeBSD.\n- [x] Add support for showing AMD cpu temperatures.\n- [x] Add option to show tree view of processes.\n- [x] Add option to reset network download/upload totals.\n- [x] Add option to turn of gradient in processes list.\n- [ ] Add gpu temp and usage. (If feasible)\n- [x] Add io stats for disks.\n- [ ] Add cpu and mem stats for docker containers. (If feasible)\n- [x] Change process list to line scroll instead of page change.\n- [ ] Add optional window for tailing log files.\n- [ ] Add options for resizing all boxes.\n- [ ] Add command line argument parsing.\n- [ ] Builtin updater. Relevant PR #96 by Jukoo\n- [ ] Add support for zram in memory box. Relevant PR #122 by perkinslr\n\n- [ ] Miscellaneous optimizations and code cleanup.\n- [ ] Add more commenting where it's sparse.\n\n- [ ] Python port. (Porting started)\n\n## LICENSE\n\n[Apache License 2.0](LICENSE)\n"
  },
  {
    "path": "bashtop",
    "content": "#!/usr/bin/env bash\n# indent type=tab\n# tab size=4\n# shellcheck disable=SC2034 #Unused variables\n# shellcheck disable=SC2068 #Double quote array warning\n# shellcheck disable=SC2086 # Double quote warning\n# shellcheck disable=SC2140 # Word form warning\n# shellcheck disable=SC2162 #Read without -r\n# shellcheck disable=SC2206 #Word split warning\n# shellcheck disable=SC2178 #Array to string warning\n# shellcheck disable=SC2102 #Ranges only match single\n# shellcheck disable=SC2004 #arithmetic brackets warning\n# shellcheck disable=SC2017 #arithmetic precision warning\n# shellcheck disable=SC2207 #split array warning\n# shellcheck disable=SC2154 #variable referenced but not assigned\n# shellcheck disable=SC1003 #info: single quote escape\n# shellcheck disable=SC2179 # array append warning\n# shellcheck disable=SC2128 # expanding array without index warning\n\n\n# Copyright 2020 Aristocratos (jakob@qvantnet.com)\n\n#    Licensed under the Apache License, Version 2.0 (the \"License\");\n#    you may not use this file except in compliance with the License.\n#    You may obtain a copy of the License at\n\n#        http://www.apache.org/licenses/LICENSE-2.0\n\n#    Unless required by applicable law or agreed to in writing, software\n#    distributed under the License is distributed on an \"AS IS\" BASIS,\n#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#    See the License for the specific language governing permissions and\n#    limitations under the License.\n\ndeclare -x LC_MESSAGES=\"C\" LC_NUMERIC=\"C\" LC_ALL=\"\"\n\n#* Fail if running on unsupported OS\ncase \"$(uname -s)\" in\n\tLinux*)  system=Linux;;\n\t*BSD)\t system=BSD;;\n\tDarwin*) system=MacOS;;\n\tCYGWIN*) system=Cygwin;;\n\tMINGW*)  system=MinGw;;\n\t*)       system=\"Other\"\nesac\nif [[ ! $system =~ Linux|MacOS|BSD ]]; then\n\techo \"This version of bashtop does not support $system platform.\"\n\texit 1\nfi\n\n#* Fail if Bash version is below 4.4\nbash_version_major=${BASH_VERSINFO[0]}\nbash_version_minor=${BASH_VERSINFO[1]}\nif [[ \"$bash_version_major\" -lt 4 ]] || [[ \"$bash_version_major\" == 4 && \"$bash_version_minor\" -lt 4 ]]; then\n\techo \"ERROR: Bash 4.4 or later is required (you are using Bash $bash_version_major.$bash_version_minor).\"\n\texit 1\nfi\n\nshopt -qu failglob nullglob\nshopt -qs extglob globasciiranges globstar\n\n#* Check for UTF-8 locale and set LANG variable if not set\nif [[ ! $LANG =~ UTF-8 ]]; then\n\tif [[ -n $LANG && ${LANG::1} != \"C\" ]]; then old_lang=\"${LANG%.*}\"; fi\n\tfor set_lang in $(locale -a); do\n\t\tif [[ $set_lang =~ utf8|UTF-8 ]]; then\n\t\t\tif [[ -n $old_lang && $set_lang =~ ${old_lang} ]]; then\n\t\t\t\tdeclare -x LANG=\"${set_lang/utf8/UTF-8}\"\n\t\t\t\tset_lang_search=\"found\"\n\t\t\t\tbreak\n\t\t\telif [[ -z $first_lang ]]; then\n\t\t\t\tfirst_lang=\"${set_lang/utf8/UTF-8}\"\n\t\t\t\tset_lang_first=\"found\"\n\t\t\tfi\n\t\t\tif [[ -z $old_lang ]]; then break; fi\n\t\tfi\n\tdone\n\tif [[ $set_lang_search != \"found\" && $set_lang_first != \"found\" ]]; then\n\t\techo \"ERROR: No UTF-8 locale found!\"\n\t\texit 1\n\telif [[ $set_lang_search != \"found\" ]]; then\n\t\t\tdeclare -x LANG=\"${first_lang/utf8/UTF-8}\"\n\tfi\n\tunset old_lang set_lang first_lang set_lang_search set_lang_first\nfi\n\ndeclare -a banner banner_colors\n\nbanner=(\n\"██████╗  █████╗ ███████╗██╗  ██╗████████╗ ██████╗ ██████╗ \"\n\"██╔══██╗██╔══██╗██╔════╝██║  ██║╚══██╔══╝██╔═══██╗██╔══██╗\"\n\"██████╔╝███████║███████╗███████║   ██║   ██║   ██║██████╔╝\"\n\"██╔══██╗██╔══██║╚════██║██╔══██║   ██║   ██║   ██║██╔═══╝ \"\n\"██████╔╝██║  ██║███████║██║  ██║   ██║   ╚██████╔╝██║     \"\n\"╚═════╝ ╚═╝  ╚═╝╚══════╝╚═╝  ╚═╝   ╚═╝    ╚═════╝ ╚═╝     \")\ndeclare version=\"0.9.25\"\n\n#* Get latest version of BashTOP from https://github.com/aristocratos/bashtop\n\ndeclare banner_width=${#banner[0]}\nbanner_colors=(\"#E62525\" \"#CD2121\" \"#B31D1D\" \"#9A1919\" \"#801414\")\n\n#* Set correct names for GNU tools depending on OS\nif [[ $system != \"Linux\" ]]; then tool_prefix=\"g\"; fi\nfor tool in \"dd\" \"df\" \"stty\" \"tail\" \"realpath\" \"wc\" \"rm\" \"mv\" \"sleep\" \"stdbuf\" \"mkfifo\" \"date\" \"kill\" \"sed\"; do\n\tdeclare -n set_tool=\"${tool}\"\n\tset_tool=\"${tool_prefix}${tool}\"\ndone\n\nif ! command -v ${dd} >/dev/null 2>&1; then\n\techo \"ERROR: Missing GNU coreutils!\"\n\texit 1\nelif ! command -v ${sed} >/dev/null 2>&1; then\n\techo \"ERROR: Missing GNU sed!\"\n\texit 1\nfi\n\nread tty_height tty_width < <(${stty} size)\n\n#? Start default variables------------------------------------------------------------------------------>\n#? These values are used to create \"$HOME/.config/bashtop/bashtop.cfg\"\n#? Any changes made here will be ignored if config file exists\naaa_config() { : ; } #! Do not remove this line!\n\n#* Color theme, looks for a .theme file in \"$HOME/.config/bashtop/themes\" and \"$HOME/.config/bashtop/user_themes\"\n#* Should be prefixed with either \"themes/\" or \"user_themes/\" depending on location, \"Default\" for builtin default theme\ncolor_theme=\"Default\"\n\n#* Update time in milliseconds, increases automatically if set below internal loops processing time, recommended 2000 ms or above for better sample times for graphs\nupdate_ms=\"2500\"\n\n#* Processes sorting, \"pid\" \"program\" \"arguments\" \"threads\" \"user\" \"memory\" \"cpu lazy\" \"cpu responsive\"\n#* \"cpu lazy\" updates sorting over time, \"cpu responsive\" updates sorting directly\nproc_sorting=\"cpu lazy\"\n\n#* Reverse sorting order, \"true\" or \"false\"\nproc_reversed=\"false\"\n\n#* Show processes as a tree\nproc_tree=\"false\"\n\n#* Check cpu temperature, only works if \"sensors\", \"vcgencmd\" or \"osx-cpu-temp\" commands is available\ncheck_temp=\"true\"\n\n#* Draw a clock at top of screen, formatting according to strftime, empty string to disable\ndraw_clock=\"%X\"\n\n#* Update main ui when menus are showing, set this to false if the menus is flickering too much for comfort\nbackground_update=\"true\"\n\n#* Custom cpu model name, empty string to disable\ncustom_cpu_name=\"\"\n\n#* Enable error logging to \"$HOME/.config/bashtop/error.log\", \"true\" or \"false\"\nerror_logging=\"true\"\n\n#* Show color gradient in process list, \"true\" or \"false\"\nproc_gradient=\"true\"\n\n#* If process cpu usage should be of the core it's running on or usage of the total available cpu power\nproc_per_core=\"false\"\n\n#* Optional filter for shown disks, should be names of mountpoints, \"root\" replaces \"/\", separate multiple values with space\ndisks_filter=\"\"\n\n#* Enable check for new version from github.com/aristocratos/bashtop at start\nupdate_check=\"true\"\n\n#* Enable graphs with double the horizontal resolution, increases cpu usage\nhires_graphs=\"false\"\n\n#* Enable the use of psutil python3 module for data collection, default on OSX\nuse_psutil=\"true\"\n\naaz_config() { : ; } #! Do not remove this line!\n#? End default variables-------------------------------------------------------------------------------->\n\ndeclare -a menu_options menu_help menu_quit\n\nmenu_options=(\n\"┌─┐┌─┐┌┬┐┬┌─┐┌┐┌┌─┐\"\n\"│ │├─┘ │ ││ ││││└─┐\"\n\"└─┘┴   ┴ ┴└─┘┘└┘└─┘\")\nmenu_help=(\n\"┬ ┬┌─┐┬  ┌─┐\"\n\"├─┤├┤ │  ├─┘\"\n\"┴ ┴└─┘┴─┘┴  \")\nmenu_quit=(\n\"┌─┐ ┬ ┬ ┬┌┬┐\"\n\"│─┼┐│ │ │ │ \"\n\"└─┘└└─┘ ┴ ┴ \")\n\nmenu_options_selected=(\n\"╔═╗╔═╗╔╦╗╦╔═╗╔╗╔╔═╗\"\n\"║ ║╠═╝ ║ ║║ ║║║║╚═╗\"\n\"╚═╝╩   ╩ ╩╚═╝╝╚╝╚═╝\")\nmenu_help_selected=(\n\"╦ ╦╔═╗╦  ╔═╗\"\n\"╠═╣║╣ ║  ╠═╝\"\n\"╩ ╩╚═╝╩═╝╩  \")\nmenu_quit_selected=(\n\"╔═╗ ╦ ╦ ╦╔╦╗ \"\n\"║═╬╗║ ║ ║ ║  \"\n\"╚═╝╚╚═╝ ╩ ╩  \")\n\ndeclare -A cpu mem swap proc net box theme disks\ndeclare -a cpu_usage cpu_graph_a cpu_graph_b color_meter color_temp_graph color_cpu color_cpu_graph cpu_history color_mem_graph color_swap_graph\ndeclare -a mem_history swap_history net_history_download net_history_upload mem_graph swap_graph proc_array download_graph upload_graph trace_array\ndeclare resized=1 size_error clock tty_width tty_height hex=\"16#\" cpu_p_box swap_on=1 draw_out esc_character boxes_out last_screen clock_out update_string\ndeclare -a options_array=(\"color_theme\" \"update_ms\" \"use_psutil\" \"proc_sorting\" \"proc_tree\" \"check_temp\" \"draw_clock\" \"background_update\" \"custom_cpu_name\"\n\t\"proc_per_core\" \"proc_reversed\" \"proc_gradient\" \"disks_filter\" \"hires_graphs\" \"net_totals_reset\" \"update_check\" \"error_logging\")\ndeclare -a save_array=(${options_array[*]/net_totals_reset/})\ndeclare -a sorting=( \"pid\" \"program\" \"arguments\" \"threads\" \"user\" \"memory\" \"cpu lazy\" \"cpu responsive\")\ndeclare -a detail_graph detail_history detail_mem_history disks_io\ndeclare -A pid_history\ndeclare time_left timestamp_start timestamp_end timestamp_input_start timestamp_input_end time_string mem_out proc_misc prev_screen pause_screen filter input_to_filter\ndeclare no_epoch proc_det proc_misc2 sleeping=0 detail_mem_graph proc_det2 proc_out curled git_version has_iostat sensor_comm failed_pipes=0 py_error\ndeclare esc_character tab backspace sleepy late_update skip_process_draw winches quitting theme_int notifier saved_stty nic_int net_misc skip_net_draw\ndeclare psutil_disk_fail\ndeclare -a disks_free disks_total disks_name disks_free_percent saved_key themes nic_list old_procs\nprintf -v esc_character \"\\u1b\"\nprintf -v tab \"\\u09\"\nprintf -v backspace \"\\u7F\" #? Backspace set to DELETE\nprintf -v backspace_real \"\\u08\" #? Real backspace\n#printf -v enter_key \"\\uA\"\nprintf -v enter_key \"\\uD\"\nprintf -v ctrl_c \"\\u03\"\nprintf -v ctrl_z \"\\u1A\"\n\nhide_cursor='\\033[?25l'\t\t#* Hide terminal cursor\nshow_cursor='\\033[?25h'\t\t#* Show terminal cursor\nalt_screen='\\033[?1049h'\t#* Switch to alternate screen\nnormal_screen='\\033[?1049l'\t#* Switch to normal screen\nclear_screen='\\033[2J'\t\t#* Clear screen\n\n#* Symbols for graphs\ndeclare -a graph_symbol\ngraph_symbol=(\" \" \"⡀\" \"⣀\" \"⣄\" \"⣤\" \"⣦\" \"⣴\" \"⣶\" \"⣷\" \"⣾\" \"⣿\")\ngraph_symbol+=( \" \" \"⣿\" \"⢿\" \"⡿\" \"⠿\" \"⠻\" \"⠟\"  \"⠛\" \"⠙\" \"⠉\" \"⠈\")\ndeclare -A graph_symbol_up='(\n\t[0_0]=⠀ [0_1]=⢀ [0_2]=⢠ [0_3]=⢰ [0_4]=⢸\n\t[1_0]=⡀ [1_1]=⣀ [1_2]=⣠ [1_3]=⣰ [1_4]=⣸\n\t[2_0]=⡄ [2_1]=⣄ [2_2]=⣤ [2_3]=⣴ [2_4]=⣼\n\t[3_0]=⡆ [3_1]=⣆ [3_2]=⣦ [3_3]=⣶ [3_4]=⣾\n\t[4_0]=⡇ [4_1]=⣇ [4_2]=⣧ [4_3]=⣷ [4_4]=⣿\n)'\ndeclare -A graph_symbol_down='(\n\t[0_0]=⠀ [0_1]=⠈ [0_2]=⠘ [0_3]=⠸ [0_4]=⢸\n\t[1_0]=⠁ [1_1]=⠉ [1_2]=⠙ [1_3]=⠹ [1_4]=⢹\n\t[2_0]=⠃ [2_1]=⠋ [2_2]=⠛ [2_3]=⠻ [2_4]=⢻\n\t[3_0]=⠇ [3_1]=⠏ [3_2]=⠟ [3_3]=⠿ [3_4]=⢿\n\t[4_0]=⡇ [4_1]=⡏ [4_2]=⡟ [4_3]=⡿ [4_4]=⣿\n)'\ndeclare -A graph\nbox[boxes]=\"cpu mem net processes\"\n\ncpu[threads]=0\n\n#* Symbols for subscript function\nsubscript=(\"₀\" \"₁\" \"₂\" \"₃\" \"₄\" \"₅\" \"₆\" \"₇\" \"₈\" \"₉\")\n\n#* Symbols for create_box function\nbox[single_hor_line]=\"─\"\nbox[single_vert_line]=\"│\"\nbox[single_left_corner_up]=\"┌\"\nbox[single_right_corner_up]=\"┐\"\nbox[single_left_corner_down]=\"└\"\nbox[single_right_corner_down]=\"┘\"\nbox[single_title_left]=\"├\"\nbox[single_title_right]=\"┤\"\n\nbox[double_hor_line]=\"═\"\nbox[double_vert_line]=\"║\"\nbox[double_left_corner_up]=\"╔\"\nbox[double_right_corner_up]=\"╗\"\nbox[double_left_corner_down]=\"╚\"\nbox[double_right_corner_down]=\"╝\"\nbox[double_title_left]=\"╟\"\nbox[double_title_right]=\"╢\"\n\ninit_() { #? Collect needed information and set options before startig main loop\n\tif [[ -z $1 ]]; then\n\t\tlocal i stx=0\n\t\t#* Set terminal options, save and clear screen\n\t\tsaved_stty=\"$(${stty} -g)\"\n\t\techo -en \"${alt_screen}${hide_cursor}${clear_screen}\"\n\t\techo -en \"\\033]0;${TERMINAL_TITLE} BashTOP\\a\"\n\t\t${stty} -echo\n\n\t\t#* Wait for resize if terminal size is smaller then 80x24\n\t\tif (($tty_width<80 | $tty_height<24)); then resized; echo -en \"${clear_screen}\"; fi\n\n\t\t#* Draw banner to banner array\n\t\tlocal letter b_color banner_line y=0\n\t\tlocal -a banner_out\n\t\t#print -v banner_out[0] -t \"\\e[0m\"\n\t\tfor banner_line in \"${banner[@]}\"; do\n\t\t\t#* Read banner array letter by letter to set correct color for filled vs outline characters\n\t\t\twhile read -rN1 letter; do\n\t\t\t\tif [[ $letter == \"█\" ]]; then b_color=\"${banner_colors[$y]}\"\n\t\t\t\telse b_color=\"#$((80-y*6))\"; fi\n\t\t\t\tif [[ $letter == \" \" ]]; then\n\t\t\t\t\tprint -v banner_out[y] -r 1\n\t\t\t\telse\n\t\t\t\t\tprint -v banner_out[y] -fg ${b_color} \"${letter}\"\n\t\t\t\tfi\n\t\t\tdone <<<\"$banner_line\"\n\t\t\t((++y))\n\t\tdone\n\t\tbanner=(\"${banner_out[@]}\")\n\n\t\t#* Draw banner to screen and show status while running init\n\t\tdraw_banner $((tty_height/2-10))\n\n\t\t#* Start psutil coprocess if enabled\n\t\tif [[ $use_psutil == true ]]; then\n\t\t\tprint -m $(( (tty_height/2-3)+stx++ )) 0 -bg \"#00\" -fg \"#cc\" -b -c \"Creating psutil coprocess...\"\n\t\t\treturn\n\t\tfi\n\tfi\n\n\tif [[ -n $1 ]]; then local i stx=1; print -bg \"#00\" -fg \"#30ff50\" -r 1 -t \"√\"; fi\n\n\t#* Check if \"sensors\", \"osx-cpu-temp\" or \"vcgencmd\" commands is available, if not, disable temperature collection\n\tprint -m $(( (tty_height/2-3)+stx++ )) 0 -bg \"#00\" -fg \"#cc\" -b -c \"Checking available tools...\"\n\tif [[ $check_temp == true ]]; then\n\t\tlocal has_temp\n\t\tsensor_comm=\"\"\n\t\tif [[ $use_psutil == true ]]; then\n\t\t\tpy_command -v has_temp \"get_sensors_check()\"\n\t\t\tif [[ $has_temp == true ]]; then sensor_comm=\"psutil\"; fi\n\t\tfi\n\t\tif [[ -z $sensor_comm ]]; then\n\t\t\tlocal checker\n\t\t\tfor checker in \"vcgencmd\" \"sensors\" \"osx-cpu-temp\"; do\n\t\t\t\tif command -v \"${checker}\" >/dev/null 2>&1; then sensor_comm=\"${checker}\"; break; fi\n\t\t\tdone\n\t\tfi\n\t\tif [[ -z $sensor_comm ]]; then check_temp=\"false\"; fi\n\tfi\n\n\t#* Check if \"curl\" command is available, if not, disable update check and theme downloads\n\tif command -v curl >/dev/null 2>&1; then curled=1; else unset curled; fi\n\n\t#* Check if \"notify-send\" command is available, if not, disable update notifier\n\tif [[ -n $curled ]] && command -v notify-send >/dev/null 2>&1; then notifier=1; else unset notifier; fi\n\n\t#* Check if \"iostat\" command is available, if not, disable disk io stat collection\n\tif command -v iostat >/dev/null 2>&1; then has_iostat=1; else unset has_iostat; fi\n\n\t#* Get number of cores and cpu threads\n\tprint -bg \"#00\" -fg \"#30ff50\" -r 1 -t \"√\"\n\tprint -m $(( (tty_height/2-3)+stx++ )) 0 -bg \"#00\" -fg \"#cc\" -c -b \"Checking cpu...\"\n\tget_cpu_info\n\n\t#* Set graph resolution\n\tgraph[hires]=\"${hires_graphs}\"\n\n\t#* Get processor BCLK\n\tlocal param_var\n\tif [[ $use_psutil == false ]] && [[ -e /usr/include/asm-generic/param.h ]]; then\n\t\tparam_var=\"$(</usr/include/asm-generic/param.h)\"\n\t\tget_value -v 'cpu[hz]' -sv \"param_var\" -k \"define HZ\" -i\n\telse\n\t\tcpu[hz]=\"100\"\n\tfi\n\n\t#* Get max pid value and length\n\tif [[ $use_psutil == false ]];  then\n\t\tproc[pid_max]=\"$(</proc/sys/kernel/pid_max)\"\n\t\tproc[pid_len]=${#proc[pid_max]}\n\t\tif [[ ${proc[pid_len]} -lt 5 ]]; then proc[pid_len]=5; fi\n\telse\n\t\tproc[pid_len]=\"7\"\n\tfi\n\n\t#* Calculate sizes of boxes\n\tprint -bg \"#00\" -fg \"#30ff50\" -r 1 -t \"√\"\n\tprint -m $(( (tty_height/2-3)+stx++ )) 0 -bg \"#00\" -fg \"#cc\" -c -b \"Calculating sizes...\"\n\tcalc_sizes\n\n\t#* Call init for cpu data collection\n\tprint -bg \"#00\" -fg \"#30ff50\" -r 1 -t \"√\"\n\tprint -m $(( (tty_height/2-3)+stx++ )) 0 -bg \"#00\" -fg \"#cc\" -c -b \"Running cpu collection init...\"\n\tcollect_cpu init\n\n\t#* Call init for memory data collection and check if swap is available\n\tprint -bg \"#00\" -fg \"#30ff50\" -r 1 -t \"√\"\n\tprint -m $(( (tty_height/2-3)+stx++ )) 0 -bg \"#00\" -fg \"#cc\" -c -b \"Running mem collection init...\"\n\tmem[counter]=10\n\tcollect_mem init\n\n\t#* Get default network device from \"ip route\" command and call init for net collection if device is found\n\tprint -bg \"#00\" -fg \"#30ff50\" -r 1 -t \"√\"\n\tprint -m $(( (tty_height/2-3)+stx++ )) 0 -bg \"#00\" -fg \"#cc\" -c -b \"Checking network devices...\"\n\tget_net_device\n\n\t#* Check if newer version of bashtop is available from https://github.com/aristocratos/bashtop\n\tif [[ -n $curled && $update_check == \"true\" ]]; then\n\t\tprint -bg \"#00\" -fg \"#30ff50\" -r 1 -t \"√\"\n\t\tprint -m $(( (tty_height/2-3)+stx++ )) 0 -bg \"#00\" -fg \"#cc\" -c -b \"Checking for updates...\"\n\t\tif ! get_value -v git_version -ss \"$(curl -m 4 --raw -r 0-5000 https://raw.githubusercontent.com/aristocratos/bashtop/master/bashtop 2>/dev/null)\" -k \"version=\" -r \"[^0-9.]\"; then unset git_version; fi\n\tfi\n\n\t#* Add update notification to banner if new version is available\n\tlocal banner_out_up\n\tprint -v banner_out_up -rs -fg \"#cc\" -b \"← esc\"\n\tif [[ -n $git_version && $git_version != \"$version\" ]]; then\n\t\tprint -v banner_out_up -rs -fg \"#80cc80\" -r 15 \"[${git_version} available!]\" -r $((9-${#git_version}))\n\t\tif [[ -n $notifier ]]; then\n\t\t\tnotify-send -u normal\\\n\t\t\t\"Bashtop Update!\" \"New version of Bashtop available\\!\\nCurrent version: ${version}\\n\\New version: ${git_version}\\nDownload at github.com/aristocratos/bashtop\"\\\n\t\t\t-i face-glasses -t 10000\n\t\tfi\n\telse\n\t\tprint -v banner_out_up -r 37\n\tfi\n\tprint -v banner_out_up -fg \"#cc\" -i -b \"Version: ${version}\" -rs\n\tbanner+=(\"${banner_out_up}\")\n\n\t#* Get theme and set colors\n\tprint -bg \"#00\" -fg \"#30ff50\" -r 1 -t \"√\"\n\tprint -m $(( (tty_height/2-3)+stx++ )) 0 -bg \"#00\" -fg \"#cc\" -c -b \"Generating colors for theme...\"\n\tcolor_init_\n\n\t#* Set up internals for quick processes sorting switching\n\tfor((i=0;i<${#sorting[@]};i++)); do\n\t\tif [[ ${sorting[i]} == \"${proc_sorting}\" ]]; then\n\t\t\tproc[sorting_int]=$i\n\t\t\tbreak\n\t\tfi\n\tdone\n\tif [[ -z ${proc[sorting_int]} ]]; then\n\t\tproc[sorting_int]=0\n\t\tproc_sorting=\"${sorting[0]}\"\n\tfi\n\n\tif [[ ${proc_reversed} == true ]]; then\n\t\tproc[reverse]=\"+\"\n\telse\n\t\tunset 'proc[reverse]'\n\tfi\n\n\tif [[ ${proc_tree} == true ]]; then\n\t\tproc[tree]=\"+\"\n\telse\n\t\tunset 'proc[tree]'\n\tfi\n\n\t#* Call init for processes data collection\n\tprint -bg \"#00\" -fg \"#30ff50\" -r 1 -t \"√\"\n\tprint -m $(( (tty_height/2-3)+stx++ )) 0 -bg \"#00\" -fg \"#cc\" -c -b \"Running process collection init...\"\n\tproc[selected]=0\n\tproc[start]=1\n\tcollect_processes init\n\n\t#* Draw first screen\n\tprint -bg \"#00\" -fg \"#30ff50\" -r 1 -t \"√\"\n\tprint -m $(( (tty_height/2-3)+stx++ )) 0 -bg \"#00\" -fg \"#cc\" -c -b \"Drawing screen...\"\n\n\tdraw_bg quiet\n\tget_ms timestamp_start\n\n\tfor task in processes cpu mem net; do\n\t\tcollect_${task}\n\t\tdraw_${task}\n\tdone\n\tlast_screen=\"${draw_out}\"\n\n\tprint -bg \"#00\" -fg \"#30ff50\" -r 1 -t \"√\" -rs\n\tsleep 0.5\n\n\tdraw_clock\n\techo -en \"${clear_screen}${draw_out}${proc_out}${clock_out}\"\n\tresized=0\n\tunset draw_out\n}\n\ncolor_init_() { #? Check for theme file and set colors\n\tlocal main_bg=\"\" main_fg=\"#cc\" title=\"#ee\" hi_fg=\"#90\" inactive_fg=\"#40\" cpu_box=\"#3d7b46\" mem_box=\"#8a882e\" net_box=\"#423ba5\" proc_box=\"#923535\" proc_misc=\"#0de756\" selected_bg=\"#7e2626\" selected_fg=\"#ee\"\n\tlocal temp_start=\"#4897d4\" temp_mid=\"#5474e8\" temp_end=\"#ff40b6\" cpu_start=\"#50f095\" cpu_mid=\"#f2e266\" cpu_end=\"#fa1e1e\" div_line=\"#30\"\n\tlocal free_start=\"#223014\" free_mid=\"#b5e685\" free_end=\"#dcff85\" cached_start=\"#0b1a29\" cached_mid=\"#74e6fc\" cached_end=\"#26c5ff\" available_start=\"#292107\" available_mid=\"#ffd77a\" available_end=\"#ffb814\"\n\tlocal used_start=\"#3b1f1c\" used_mid=\"#d9626d\" used_end=\"#ff4769\" download_start=\"#231a63\" download_mid=\"#4f43a3\" download_end=\"#b0a9de\" upload_start=\"#510554\" upload_mid=\"#7d4180\" upload_end=\"#dcafde\"\n\tlocal hex2rgb color_name array_name this_color main_fg_dec sourced theme_unset\n\tlocal -i i y\n\tlocal -A rgb\n\tlocal -a dec_test\n\tlocal -a convert_color=(\"main_bg\" \"temp_start\" \"temp_mid\" \"temp_end\" \"cpu_start\" \"cpu_mid\" \"cpu_end\" \"upload_start\" \"upload_mid\" \"upload_end\" \"download_start\" \"download_mid\" \"download_end\" \"used_start\" \"used_mid\" \"used_end\" \"available_start\" \"available_mid\" \"available_end\" \"cached_start\" \"cached_mid\" \"cached_end\" \"free_start\" \"free_mid\" \"free_end\" \"proc_misc\" \"main_fg_dec\")\n\tlocal -a set_color=(\"main_fg\" \"title\" \"hi_fg\" \"div_line\" \"inactive_fg\" \"selected_fg\" \"selected_bg\" \"cpu_box\" \"mem_box\" \"net_box\" \"proc_box\")\n\n\tfor theme_unset in ${!theme[@]}; do\n\t\tunset 'theme[${theme_unset}]'\n\tdone\n\n\t#* Check if theme set in config exists and source it if it does\n\tif [[ -n ${color_theme} && ${color_theme} != \"Default\" && ${color_theme} =~ (themes/)|(user_themes/) && -e \"${config_dir}/${color_theme%.theme}.theme\" ]]; then\n\t\t# shellcheck source=/dev/null\n\t\tsource \"${config_dir}/${color_theme%.theme}.theme\"\n\t\tsourced=1\n\telse\n\t\tcolor_theme=\"Default\"\n\tfi\n\n\tmain_fg_dec=\"${theme[main_fg]:-$main_fg}\"\n\ttheme[main_fg_dec]=\"${main_fg_dec}\"\n\n\t#* Convert colors for graphs and meters from rgb hexadecimal to rgb decimal if needed\n\tfor color_name in ${convert_color[@]}; do\n\t\tif [[ -n $sourced ]]; then hex2rgb=\"${theme[${color_name}]}\"\n\t\telse hex2rgb=\"${!color_name}\"; fi\n\n\t\thex2rgb=${hex2rgb//#/}\n\n\t\tif [[ ${#hex2rgb} == 6 ]] && is_hex \"$hex2rgb\"; then hex2rgb=\"$((${hex}${hex2rgb:0:2})) $((${hex}${hex2rgb:2:2})) $((${hex}${hex2rgb:4:2}))\"\n\t\telif [[ ${#hex2rgb} == 2 ]] && is_hex \"$hex2rgb\"; then hex2rgb=\"$((${hex}${hex2rgb:0:2})) $((${hex}${hex2rgb:0:2})) $((${hex}${hex2rgb:0:2}))\"\n\t\telse\n\t\t\tdec_test=(${hex2rgb})\n\t\t\tif [[ ${#dec_test[@]} -eq 3 ]] && is_int \"${dec_test[@]}\"; then hex2rgb=\"${dec_test[*]}\"\n\t\t\telse unset hex2rgb; fi\n\t\tfi\n\n\t\ttheme[${color_name}]=\"${hex2rgb}\"\n\tdone\n\n\t#* Set background color if set, otherwise use terminal default\n\tif [[ -n ${theme[main_bg]} ]]; then theme[main_bg_dec]=\"${theme[main_bg]}\"; theme[main_bg]=\";48;2;${theme[main_bg]// /;}\"; fi\n\n\t#* Set colors from theme file if found and valid hexadecimal or integers, otherwise use default values\n\tfor color_name in \"${set_color[@]}\"; do\n\t\tif [[ -z ${theme[$color_name]} ]] || ! is_hex \"${theme[$color_name]}\" && ! is_int \"${theme[$color_name]}\"; then theme[${color_name}]=\"${!color_name}\"; fi\n\tdone\n\n\tbox[cpu_color]=\"${theme[cpu_box]}\"\n\tbox[mem_color]=\"${theme[mem_box]}\"\n\tbox[net_color]=\"${theme[net_box]}\"\n\tbox[processes_color]=\"${theme[proc_box]}\"\n\n\t#* Create color arrays from one, two or three color gradient, 100 values in each\n\tfor array_name in \"temp\" \"cpu\" \"upload\" \"download\" \"used\" \"available\" \"cached\" \"free\"; do\n\t\tlocal -n color_array=\"color_${array_name}_graph\"\n\t\tlocal -a rgb_start=(${theme[${array_name}_start]}) rgb_mid=(${theme[${array_name}_mid]}) rgb_end=(${theme[${array_name}_end]})\n\t\tlocal pf_calc middle=1\n\n\t\trgb[red]=${rgb_start[0]}; rgb[green]=${rgb_start[1]}; rgb[blue]=${rgb_start[2]}\n\n\t\tif [[ -z ${rgb_mid[*]} ]] && ((rgb_end[0]+rgb_end[1]+rgb_end[2]>rgb_start[0]+rgb_start[1]+rgb_start[2])); then\n\t\t\trgb_mid=( $(( rgb_start[0]+( (rgb_end[0]-rgb_start[0])/2) )) $((rgb_start[1]+( (rgb_end[1]-rgb_start[1])/2) )) $((rgb_start[2]+( (rgb_end[2]-rgb_start[2])/2) )) )\n\t\telif [[ -z ${rgb_mid[*]} ]]; then\n\t\t\trgb_mid=( $(( rgb_end[0]+( (rgb_start[0]-rgb_end[0])/2) )) $(( rgb_end[1]+( (rgb_start[1]-rgb_end[1])/2) )) $(( rgb_end[2]+( (rgb_start[2]-rgb_end[2])/2) )) )\n\t\tfi\n\n\t\tfor((i=0;i<=100;i++,y=0)); do\n\n\t\t\tif [[ -n ${rgb_end[*]} ]]; then\n\t\t\t\tfor this_color in \"red\" \"green\" \"blue\"; do\n\t\t\t\t\tif ((i==50)); then rgb_start[y]=${rgb[$this_color]}; fi\n\n\t\t\t\t\tif ((middle==1 & rgb[$this_color]<rgb_mid[y])); then\n\t\t\t\t\t\tprintf -v pf_calc \"%.0f\" \"$(( i*( (rgb_mid[y]-rgb_start[y])*100/50*100) ))e-4\"\n\n\t\t\t\t\telif ((middle==1 & rgb[$this_color]>rgb_mid[y])); then\n\t\t\t\t\t\tprintf -v pf_calc \"%.0f\" \"-$(( i*( (rgb_start[y]-rgb_mid[y])*100/50*100) ))e-4\"\n\n\t\t\t\t\telif ((middle==0 & rgb[$this_color]<rgb_end[y])); then\n\t\t\t\t\t\tprintf -v pf_calc \"%.0f\" \"$(( (i-50)*( (rgb_end[y]-rgb_start[y])*100/50*100) ))e-4\"\n\n\t\t\t\t\telif ((middle==0 & rgb[$this_color]>rgb_end[y])); then\n\t\t\t\t\t\tprintf -v pf_calc \"%.0f\" \"-$(( (i-50)*( (rgb_start[y]-rgb_end[y])*100/50*100) ))e-4\"\n\n\t\t\t\t\telse\n\t\t\t\t\t\tpf_calc=0\n\t\t\t\t\tfi\n\n\t\t\t\t\trgb[$this_color]=$((rgb_start[y]+pf_calc))\n\t\t\t\t\tif ((rgb[$this_color]<0)); then rgb[$this_color]=0\n\t\t\t\t\telif ((rgb[$this_color]>255)); then rgb[$this_color]=255; fi\n\n\t\t\t\t\ty+=1\n\t\t\t\t\tif ((i==49 & y==3 & middle==1)); then middle=0; fi\n\t\t\t\tdone\n\t\t\tfi\n\t\t\tcolor_array[i]=\"${rgb[red]} ${rgb[green]} ${rgb[blue]}\"\n\t\tdone\n\n\tdone\n}\n\nquit_() { #? Clean exit\n\t#* Restore terminal options and screen\n\tif [[ $use_psutil == true && $2 != \"psutil\" ]]; then\n\t\tpy_command quit\n\t\tsleep 0.1\n\t\trm -rf \"${pytmpdir}\"\n\tfi\n\techo -en \"${clear_screen}${normal_screen}${show_cursor}\"\n\t${stty} \"${saved_stty}\"\n\techo -en \"\\033]0;\\a\"\n\n\t#* Save any changed values to config file\n\tif [[ $config_file != \"/dev/null\" ]]; then\n\t\tsave_config \"${save_array[@]}\"\n\tfi\n\n\tif [[ $1 == \"restart\" ]]; then exec \"$(${realpath} \"$0\")\"; fi\n\n\texit ${1:-0}\n}\n\nsleep_() { #? Restore terminal options, stop and send to background if caught SIGTSTP (ctrl+z)\n\techo -en \"${clear_screen}${normal_screen}${show_cursor}\"\n\t${stty} \"${saved_stty}\"\n\techo -en \"\\033]0;\\a\"\n\n\tif [[ $use_psutil == true ]]; then\n\t\tif ((failed_pipes>1)); then ((failed_pipes--)); fi\n\t\tpy_command quit\n\t\tfailed_pipe=1\n\t\twait ${pycoproc_PID}\n\tfi\n\n\t${kill} -s SIGSTOP $$\n}\n\nresume_() { #? Set terminal options and resume if caught SIGCONT ('fg' from terminal)\n\tsleepy=0\n\techo -en \"${alt_screen}${hide_cursor}${clear_screen}\"\n\techo -en \"\\033]0;${TERMINAL_TITLE} BashTOP\\a\"\n\t${stty} -echo\n\n\tif [[ -n $pause_screen ]]; then\n\t\techo -en \"$pause_screen\"\n\telse\n\t\techo -en \"${boxes_out}${proc_det}${last_screen}${mem_out}${proc_misc}${proc_misc2}${update_string}${clock_out}\"\n\tfi\n}\n\ntraperr() { #? Function for reporting error line numbers\n\tlocal match len trap_muted err=\"${BASH_LINENO[0]}\"\n\n\tlen=$((${#trace_array[@]}))\n\tif ((len-->=1)); then\n\t\twhile ((len>=${#trace_array[@]}-2)); do\n\t\t\tif [[ $err == \"${trace_array[$((len--))]}\" ]]; then ((++match)) ; fi\n\t\tdone\n\t\tif ((match==2 & len != -2)); then return\n\t\telif ((match>=1)); then trap_muted=\"(MUTED!)\"\n\t\tfi\n\tfi\n\tif ((len>100)); then unset 'trace_array[@]'; fi\n\ttrace_array+=(\"$err\")\n\tprintf \"%(%X)T ERROR: On line %s %s\\n\" -1 \"$err\" \"$trap_muted\" >> \"${config_dir}/error.log\"\n\n}\n\nresized() { #? Get new terminal size if terminal is resized\n\tresized=1\n\tunset winches\n\twhile ((++winches<5)); do\n\t\tread tty_height tty_width < <(${stty} size)\n\t\tif (($tty_width<80 | $tty_height<24)); then\n\t\t\tsize_error_msg\n\t\t\twinches=0\n\t\telse\n\t\t\techo -en \"${clear_screen}\"\n\t\t\tcreate_box -w 30 -h 3 -c 1 -l 1 -lc \"#EE2020\" -title \"resizing\"\n\t\t\tprint -jc 28 -fg ${theme[title]} \"New size: ${tty_width}x${tty_height}\"\n\t\t\t${sleep} 0.2\n\t\t\tif [[ $(${stty} size) != \"$tty_height $tty_width\" ]]; then winches=0; fi\n\t\tfi\n\tdone\n}\n\nsize_error_msg() { #? Shows error message if terminal size is below 80x25\n\tlocal width=$tty_width\n\tlocal height=$tty_height\n\techo -en \"${clear_screen}\"\n\tcreate_box -full -lc \"#EE2020\" -title \"resize window\"\n\tprint -rs -m $((tty_height/2-1)) 2 -fg ${theme[title]} -c -l 11 \"Current size: \" -bg \"#00\" -fg \"#dd2020\" -d 1 -c \"${tty_width}x${tty_height}\" -rs\n\tprint -d 1 -fg ${theme[title]} -c -l 15 \"Need to be atleast:\" -bg \"#00\" -fg \"#30dd50\" -d 1 -c \"80x24\" -rs\n\twhile [[ $(${stty} size) == \"$tty_height $tty_width\" ]]; do ${sleep} 0.2; if [[ -n $quitting ]]; then quit_; fi ; done\n}\n\ndraw_banner() { #? Draw banner, usage: draw_banner <line> [output variable]\n\tlocal y letter b_color x_color xpos ypos=$1 banner_out\n\tif [[ -n $2 ]]; then local -n banner_out=$2; fi\n\txpos=$(( (tty_width/2)-(banner_width/2) ))\n\n\tfor banner_line in \"${banner[@]}\"; do\n\t\tprint -v banner_out -rs -move $((ypos+++y)) $xpos -t \"${banner_line}\"\n\tdone\n\n\tif [[ -z $2 ]]; then echo -en \"${banner_out}\"; fi\n}\n\ncreate_config() { #? Creates a new config file with default values from above\n\tlocal c_line c_read this_file\n\tthis_file=\"$(${realpath} \"$0\")\"\n\techo \"#? Config file for bashtop v. ${version}\" > \"$config_file\"\n\twhile IFS= read -r c_line; do\n\t\tif [[ $c_line =~ aaz_config() ]]; then break\n\t\telif [[ $c_read == \"1\" ]]; then echo \"$c_line\" >> \"$config_file\"\n\t\telif [[ $c_line =~ aaa_config() ]]; then c_read=1; fi\n\tdone < \"$this_file\"\n}\n\nsave_config() { #? Saves variables to config file if not same, usage: save_config \"var1\" [\"var2\"] [\"var3\"]...\n\tif [[ -z $1 || $config_file == \"/dev/null\" ]]; then return; fi\n\tlocal var tmp_conf tmp_value quote original new\n\ttmp_conf=\"$(<\"$config_file\")\"\n\tfor var in \"$@\"; do\n\t\tif [[ ${tmp_conf} =~ ${var} ]]; then\n\t\t\tget_value -v \"tmp_value\" -sv \"tmp_conf\" -k \"${var}=\"\n\t\t\tif [[ ${tmp_value//\\\"/} != \"${!var}\" ]]; then\n\t\t\t\toriginal=\"${var}=${tmp_value}\"\n\t\t\t\tnew=\"${var}=\\\"${!var}\\\"\"\n\t\t\t\toriginal=\"${original//'/'/'\\/'}\"\n\t\t\t\tnew=\"${new//'/'/'\\/'}\"\n\t\t\t\t${sed} -i \"s/${original}/${new}/\" \"${config_file}\"\n\t\t\tfi\n\t\telse\n\t\t\techo \"${var}=\\\"${!var}\\\"\" >> \"$config_file\"\n\t\tfi\n\tdone\n}\n\nset_font() { #? Take a string and generate a string of unicode characters of given font, usage; set_font \"font-name [bold] [italic]\" \"string\"\n\tlocal i letter letter_hex new_hex add_hex start font=\"$1\" string_in=\"$2\" string_out hex=\"16#\"\n\tif [[ -z $font || -z $string_in ]]; then return; fi\n\tcase \"$font\" in\n\t\t\"sans-serif\") lower_start=\"1D5BA\"; upper_start=\"1D5A0\"; digit_start=\"1D7E2\";;\n\t\t\"sans-serif bold\") lower_start=\"1D5EE\"; upper_start=\"1D5D4\"; digit_start=\"1D7EC\";;\n\t\t\"sans-serif italic\") lower_start=\"1D622\"; upper_start=\"1D608\"; digit_start=\"1D7E2\";;\n\t\t#\"sans-serif bold italic\") start=\"1D656\"; upper_start=\"1D63C\"; digit_start=\"1D7EC\";;\n\t\t\"script\") lower_start=\"1D4B6\"; upper_start=\"1D49C\"; digit_start=\"1D7E2\";;\n\t\t\"script bold\") lower_start=\"1D4EA\"; upper_start=\"1D4D0\"; digit_start=\"1D7EC\";;\n\t\t\"fraktur\") lower_start=\"1D51E\"; upper_start=\"1D504\"; digit_start=\"1D7E2\";;\n\t\t\"fraktur bold\") lower_start=\"1D586\"; upper_start=\"1D56C\"; digit_start=\"1D7EC\";;\n\t\t\"monospace\") lower_start=\"1D68A\"; upper_start=\"1D670\"; digit_start=\"1D7F6\";;\n\t\t\"double-struck\") lower_start=\"1D552\"; upper_start=\"1D538\"; digit_start=\"1D7D8\";;\n\t\t*) echo -n \"${string_in}\"; return;;\n\tesac\n\n\tfor((i=0;i<${#string_in};i++)); do\n\t\tletter=${string_in:i:1}\n\t\tif [[ $letter =~ [a-z] ]]; then #61\n\t\t\tprintf -v letter_hex '%X\\n' \"'$letter\"\n\t\t\tprintf -v add_hex '%X' \"$((${hex}${letter_hex}-${hex}61))\"\n\t\t\tprintf -v new_hex '%X' \"$((${hex}${lower_start}+${hex}${add_hex}))\"\n\t\t\tstring_out=\"${string_out}\\U${new_hex}\"\n\t\t\t#if [[ $font =~ sans-serif && $letter =~ m|w ]]; then string_out=\"${string_out} \"; fi\n\t\t\t#\\U205F\n\t\telif [[ $letter =~ [A-Z] ]]; then #41\n\t\t\tprintf -v letter_hex '%X\\n' \"'$letter\"\n\t\t\tprintf -v add_hex '%X' \"$((${hex}${letter_hex}-${hex}41))\"\n\t\t\tprintf -v new_hex '%X' \"$((${hex}${upper_start}+${hex}${add_hex}))\"\n\t\t\tstring_out=\"${string_out}\\U${new_hex}\"\n\t\t\t#if [[ $font =~ sans-serif && $letter =~ M|W ]]; then string_out=\"${string_out} \"; fi\n\t\telif [[ $letter =~ [0-9] ]]; then #30\n\t\t\tprintf -v letter_hex '%X\\n' \"'$letter\"\n\t\t\tprintf -v add_hex '%X' \"$((${hex}${letter_hex}-${hex}30))\"\n\t\t\tprintf -v new_hex '%X' \"$((${hex}${digit_start}+${hex}${add_hex}))\"\n\t\t\tstring_out=\"${string_out}\\U${new_hex}\"\n\t\telse\n\t\t\tstring_out=\"${string_out} \\e[1D${letter}\"\n\t\tfi\n\tdone\n\n\techo -en \"${string_out}\"\n}\n\nsort_array_int() {\t#? Copy and sort an array of integers from largest to smallest value, usage: sort_array_int \"input array\" \"output array\"\n\t#* Return if given array has no values\n\tif [[ -z ${!1} ]]; then return; fi\n\tlocal start_n search_n tmp_array\n\n\t#* Create pointers to arrays\n\tlocal -n in_arr=\"$1\"\n\tlocal -n out_arr=\"$2\"\n\n\t#* Create local copy of array\n\tlocal array=(\"${in_arr[@]}\")\n\n\t#* Start sorting\n\tfor ((start_n=0;start_n<=${#array[@]}-1;++start_n)); do\n\t\tfor ((search_n=start_n+1;search_n<=${#array[@]}-1;++search_n)); do\n\t\t\tif ((array[start_n]<array[search_n])); then\n\t\t\t\ttmp_array=${array[start_n]}\n\t\t\t\tarray[start_n]=${array[search_n]}\n\t\t\t\tarray[search_n]=$tmp_array\n\t\t\tfi\n\t\tdone\n\tdone\n\n\t#* Write the sorted array to output array\n\tout_arr=(\"${array[@]}\")\n}\n\nsubscript() { #? Convert an integer to a string of subscript numbers\n\tlocal i out int=$1\n\tfor((i=0;i<${#int};i++)); do\n\t\tout=\"${out}${subscript[${int:$i:1}]}\"\n\tdone\n\techo -n \"${out}\"\n}\n\nspaces() { #? Prints back spaces, usage: spaces \"number of spaces\"\n\tprintf \"%${1}s\" \"\"\n}\n\nis_int() { #? Check if value(s) is integer\n\tlocal param\n\tfor param; do\n\t\tif [[ ! $param =~ ^[\\-]?[0-9]+$ ]]; then return 1; fi\n\tdone\n}\n\nis_float() { #? Check if value(s) is floating point\n\tlocal param\n\tfor param; do\n\t\tif [[ ! $param =~ ^[\\-]?[0-9]*[,.][0-9]+$ ]]; then return 1; fi\n\tdone\n}\n\nis_hex() { #? Check if value(s) is hexadecimal\n\tlocal param\n\tfor param; do\n\t\tif [[ ! ${param//#/} =~ ^[0-9a-fA-F]*$ ]]; then return 1; fi\n\tdone\n}\n\nfloating_humanizer() { \t#? Convert integer to floating point and scale up in steps of 1024 to highest positive unit\n\t\t\t\t\t\t#? Usage: floating_humanizer <-b,-bit|-B,-Byte> [-ps,-per-second] [-s,-start \"1024 multiplier start\"] [-v,-variable-output] <input>\n\tlocal value selector per_second unit_mult decimals out_var ext_var short sep=\" \"\n\tlocal -a unit\n\tuntil (($#==0)); do\n\t\tcase \"$1\" in\n\t\t\t-b|-bit) unit=(bit Kib Mib Gib Tib Pib); unit_mult=8;;\n\t\t\t-B|-Byte) unit=(Byte KiB MiB GiB TiB PiB); unit_mult=1;;\n\t\t\t-ps|-per-second) per_second=1;;\n\t\t\t-short) short=1; sep=\"\";;\n\t\t\t-s|-start) selector=\"$2\"; shift;;\n\t\t\t-v|-variable-output) local -n out_var=\"$2\"; ext_var=1; shift;;\n\t\t\t*) if is_int \"$1\"; then value=$1; break; fi;;\n\t\tesac\n\t\tshift\n\tdone\n\n\tif [[ -z $value || $value -lt 0 || -z $unit_mult ]]; then return; fi\n\n\tif ((per_second==1 & unit_mult==1)); then per_second=\"/s\"\n\telif ((per_second==1)); then per_second=\"ps\"; fi\n\n\tif ((value>0)); then\n\t\tvalue=$((value*100*unit_mult))\n\n\t\tuntil ((${#value}<6)); do\n\t\t\tvalue=$((value>>10))\n\t\t\tif ((value<100)); then value=100; fi\n\t\t\t((++selector))\n\t\tdone\n\n\t\tif ((${#value}<5 & ${#value}>=2 & selector>0)); then\n\t\t\tdecimals=$((5-${#value}))\n\t\t\tvalue=\"${value::-2}.${value:(-${decimals})}\"\n\t\telif ((${#value}>=2)); then\n\t\t\tvalue=\"${value::-2}\"\n\t\tfi\n\tfi\n\n\tif [[ -n $short ]]; then value=\"${value%.*}\"; fi\n\n\tout_var=\"${value}${sep}${unit[$selector]::${short:-${#unit[$selector]}}}${per_second}\"\n\tif [[ -z $ext_var ]]; then echo -n \"${out_var}\"; fi\n}\n\nget_cpu_info() {\n\tlocal lscpu_var pyin\n\tif [[ $use_psutil == true ]]; then\n\t\tif [[ -z ${cpu[threads]} || -z ${cpu[cores]} ]]; then\n\t\t\tpy_command -v pyin \"get_cpu_cores()\"\n\t\t\tread cpu[cores] cpu[threads] <<<\"${pyin}\"\n\t\tfi\n\n\telse\n\t\tif command -v lscpu >/dev/null 2>&1; then lscpu_var=\"$(lscpu)\"; fi\n\t\tif [[ -z ${cpu[threads]} || -z ${cpu[cores]} ]]; then\n\t\t\tif ! get_value -v 'cpu[threads]' -sv \"lscpu_var\" -k \"CPU(s):\" -i || [[ ${cpu[threads]} == \"0\" ]]; then\n\t\t\t\tcpu[threads]=\"$(nproc 2>/dev/null ||true)\"\n\t\t\t\tif [[ -z ${cpu[threads]} ]]; then cpu[threads]=\"1\"; fi\n\t\t\t\tcpu[cores]=${cpu[threads]}\n\t\t\telse\n\t\t\tget_value -v 'cpu[cores]' -sv \"lscpu_var\" -k \"Core(s)\" -i\n\t\t\tfi\n\t\tfi\n\tfi\n\n\tif [[ $use_psutil == false && -z $custom_cpu_name ]]; then\n\t\tif ! get_value -v 'cpu[model]' -sv \"lscpu_var\" -k \"Model name:\" -a -b -k \"CPU\" -mk -1; then\n\t\t\tif ! get_value -v 'cpu[model]' -sv \"lscpu_var\" -k \"Model name:\" -r \"  \"; then\n\t\t\t\tcpu[model]=\"cpu\"\n\t\t\tfi\n\t\tfi\n\telif [[ $use_psutil == true && -z $custom_cpu_name ]]; then\n\t\tpy_command -v cpu[model] \"get_cpu_name()\"\n\telse\n\t\tcpu[model]=\"${custom_cpu_name}\"\n\tfi\n}\n\nget_value() { #? Get a value from a file, variable or array by searching for a non spaced \"key name\" on the same line\n\tlocal match line_pos=1 int reg key all tmp_array input found input_line line_array line_val ext_var line_nr current_line match_key math removing ext_arr\n\tlocal -a remove\n\tuntil (($#==0)); do\n\t\tuntil (($#==0)); do\n\t\t\tcase \"$1\" in\n\t\t\t\t-k|-key) key=\"$2\"; shift;;\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Key \"string\" on the same line as target value\n\t\t\t\t-m|-match) match=\"$2\"; shift;;\t\t\t\t\t\t\t\t\t\t\t\t\t#? If multiple matches on a line, match occurrence \"x\"\n\t\t\t\t-mk|-match-key) match_key=$2; line_pos=0; shift;;\t\t\t\t\t\t\t\t#? Match in relation to key position, -1 for previous value, 1 for next value\n\t\t\t\t-b|-break) shift; break;;\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Break up arguments for multiple searches\n\t\t\t\t-a|-all) all=1;;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Prints back found line including key\n\t\t\t\t-l|-line) line_nr=\"$2\"; shift;;\t\t\t\t\t\t\t\t\t\t\t\t\t#? Set target line if no key is available\n\t\t\t\t-ss|-source-string) input=\"$2\"; shift;;\t\t\t\t\t\t\t\t\t\t\t#? Argument string as source\n\t\t\t\t-sf|-source-file) input=\"$(<\"$2\")\"; shift;;  \t\t\t\t\t\t\t\t\t#? File as source\n\t\t\t\t-sv|-source-var) input=\"${!2}\"; shift;;\t\t\t\t\t\t\t\t\t\t\t#? Variable as source\n\t\t\t\t-sa|-source-array) local -n tmp_array=$2; input=\"${tmp_array[*]}\"; shift;;\t\t#? Array as source\n\t\t\t\t-fp|-floating-point) reg=\"[\\-]?[0-9]*[.,][0-9]+\"; match=1;;\t\t\t\t\t\t#? Match floating point value\n\t\t\t\t-math) math=\"$2\"; shift;;\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Perform math on a integer value, \"x\" represents value, only works if \"integer\" argument is given\n\t\t\t\t-i|-integer) reg=\"[\\-]?[0-9]+[.,]?[0-9]*\"; int=1; match=1;;\t\t\t\t\t\t#? Match integer value or float and convert to int\n\t\t\t\t-r|-remove) remove+=(\"$2\"); shift;;\t\t\t\t\t\t\t\t\t\t\t\t#? Format output by removing entered regex, can be used multiple times\n\t\t\t\t-v|-variable-out) local -n found=\"$2\"; ext_var=1; shift;;\t\t\t\t\t\t#? Output to variable\n\t\t\t\t-map|-map-array) local -n array_out=\"$2\"; ext_var=1; ext_arr=1; shift;;\t\t\t#? Map output to array\n\t\t\tesac\n\t\t\tshift\n\t\tdone\n\n\t\tfound=\"\"\n\n\t\tif [[ -z $input ]]; then return 1; fi\n\t\tif [[ -z $line_nr && -z $key ]]; then line_nr=1; fi\n\n\t\twhile IFS='' read -r input_line; do\n\t\t\t((++current_line))\n\t\t\tif [[ -n $line_nr && $current_line -eq $line_nr || -z $line_nr && -n $key && ${input_line/${key}/} != \"$input_line\" ]]; then\n\t\t\t\tif [[ -n $all ]]; then\n\t\t\t\t\tfound=\"${input_line}\"\n\t\t\t\t\tbreak\n\n\t\t\t\telif [[ -z $match && -z $match_key && -z $reg ]]; then\n\t\t\t\t\tfound=\"${input_line/${key}/}\"\n\t\t\t\t\tbreak\n\n\t\t\t\telse\n\t\t\t\t\tline_array=(${input_line/${key}/${key// /}})\n\n\t\t\t\tfi\n\n\t\t\t\tfor line_val in \"${line_array[@]}\"; do\n\t\t\t\t\tif [[ -n $match_key && $line_val == \"${key// /}\" ]]; then\n\t\t\t\t\t\tif ((match_key<0 & line_pos+match_key>=0)) || ((match_key>=0 & line_pos+match_key<${#line_array[@]})); then\n\t\t\t\t\t\t\tfound=\"${line_array[$((line_pos+match_key))]}\"\n\t\t\t\t\t\t\tbreak 2\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\treturn 1\n\t\t\t\t\t\tfi\n\n\t\t\t\t\telif [[ -n $match_key ]]; then\n\t\t\t\t\t\t((++line_pos))\n\n\t\t\t\t\telif [[ -n $reg && $line_val =~ ^${reg}$ || -z $reg && -n $match ]]; then\n\t\t\t\t\t\tif ((line_pos==match)); then\n\t\t\t\t\t\t\tfound=${line_val}\n\t\t\t\t\t\t\tbreak 2\n\t\t\t\t\t\tfi\n\t\t\t\t\t\t((++line_pos))\n\t\t\t\t\tfi\n\t\t\t\tdone\n\t\t\tfi\n\t\tdone <<<\"${input}\"\n\n\t\tif [[ -z $found ]]; then return 1; fi\n\n\t\tif [[ -n ${remove[*]} ]]; then\n\t\t\tfor removing in \"${remove[@]}\"; do\n\t\t\t\tfound=\"${found//${removing}/}\"\n\t\t\tdone\n\t\tfi\n\n\t\tif [[ -n $int && $found =~ [.,] ]]; then\n\t\t\tfound=\"${found/,/.}\"\n\t\t\tprintf -v found \"%.0f\" \"${found}\"\n\t\tfi\n\n\t\tif [[ -n $math && -n $int ]]; then\n\t\t\tmath=\"${math//x/$found}\"\n\t\t\tfound=$((${math}))\n\t\tfi\n\n\t\tif (($#>0)); then\n\t\t\tinput=\"${found}\"\n\t\t\tunset key match match_key all reg found int 'remove[@]' current_line\n\t\t\tline_pos=1\n\t\tfi\n\n\tdone\n\n\tif [[ -z $ext_var ]]; then echo \"${found}\"; fi\n\tif [[ -n $ext_arr ]]; then array_out=(${found}); fi\n}\n\nget_themes() {\n\tlocal file\n\ttheme_int=0\n\tthemes=(\"Default\")\n\tfor file in \"${config_dir}/themes\"/*.theme; do\n\t\tfile=\"${file##*/}\"\n\t\tif [[ ${file} != \"*.theme\" ]]; then themes+=(\"themes/${file%.theme}\"); fi\n\t\tif [[ ${themes[-1]} == \"${color_theme}\" ]]; then theme_int=${#themes[@]}-1; fi\n\tdone\n\tfor file in \"${config_dir}/user_themes\"/*.theme; do\n\t\tfile=\"${file##*/}\"\n\t\tif [[ ${file} != \"*.theme\" ]]; then themes+=(\"user_themes/${file%.theme}\"); fi\n\t\tif [[ ${themes[-1]} == \"${color_theme}\" ]]; then theme_int=${#themes[@]}-1; fi\n\tdone\n}\n\nget_net_device() { #? Check for internet connection, name of default network device and create list of all devices\n\tif [[ $use_psutil == true ]]; then get_net_device_psutil; return; fi\n\tlocal -a netdev\n\tlocal ndline\n\tif ! get_value -v 'net[device]' -ss \"$(ip route get 1.1.1.1 2>/dev/null)\" -k \"dev\" -mk 1; then\n\t\tnet[no_device]=1\n\telse\n\t\tunset 'net[no_device]' 'nic_list[@]' nic_int\n\t\treadarray -t netdev </proc/net/dev\n\t\tfor ndline in \"${netdev[@]:2}\"; do\n\t\t\tndline=\"${ndline%:*}\"; ndline=\"${ndline// /}\"\n\t\t\tnic_list+=(\"${ndline}\")\n\t\t\tif [[ ${ndline} == \"${net[device]}\" ]]; then\n\t\t\t\tnic_int=$((${#nic_list[@]}-1))\n\t\t\tfi\n\t\tdone\n\t\tcollect_net init\n\tfi\n}\n\nget_net_device_psutil() {\n\tunset 'nic_list[@]'\n\tpy_command -a nic_list \"get_nics()\"\n\tnet[device]=\"${nic_list[0]}\"\n\tnic_int=0\n\tif [[ -z ${net[device]} ]]; then\n\t\tnet[no_device]=1\n\telse\n\t\tunset 'net[no_device]'\n\t\tcollect_net init\n\tfi\n}\n\ncur_pos() { #? Get cursor postion, argument \"line\" prints current line, argument \"col\" prints current column, no argument prints both in format \"line column\"\n\tlocal line col\n\tIFS=';' read -sdR -p $'\\E[6n' line col\n\tif [[ -z $1 || $1 == \"line\" ]]; then echo -n \"${line#*[}${1:-\" \"}\"; fi\n\tif [[ -z $1 || $1 == \"col\" ]]; then echo -n \"$col\"; fi\n}\n\ncreate_box() { #? Draw a box with an optional title at given location\n\tlocal width height col line title ltype hpos vpos i hlines vlines color line_color c_rev=0 box_out ext_var fill\n\tuntil (($#==0)); do\n\t\tcase $1 in\n\t\t\t-f|-full) col=1; line=1; width=$((tty_width)); height=$((tty_height));;\t\t\t\t\t\t\t#? Use full terminal size for box\n\t\t\t-c|-col) if is_int \"$2\"; then col=$2; shift; fi;; \t\t\t\t\t\t\t\t\t\t\t\t#? Column position to start box\n\t\t\t-l|-line) if is_int \"$2\"; then line=$2; shift; fi;; \t\t\t\t\t\t\t\t\t\t\t#? Line position to start box\n\t\t\t-w|-width) if is_int \"$2\"; then width=$2; shift; fi;; \t\t\t\t\t\t\t\t\t\t\t#? Width of box\n\t\t\t-h|-height) if is_int \"$2\"; then height=$2; shift; fi;; \t\t\t\t\t\t\t\t\t\t#? Height of box\n\t\t\t-t|-title) if [[ -n $2 ]]; then title=\"$2\"; shift; fi;;\t\t\t\t\t\t\t\t\t\t\t#? Draw title without titlebar\n\t\t\t-s|-single) ltype=\"single\";;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Use single lines\n\t\t\t-d|-double) ltype=\"double\";;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Use double lines\n\t\t\t-lc|-line-color) line_color=\"$2\"; shift;;\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Color of the lines\n\t\t\t-fill) fill=1;;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Fill background of box\n\t\t\t-v|-variable) local -n box_out=$2; ext_var=1; shift;;\t\t\t\t\t\t\t\t\t\t\t#? Output box to a variable\n\t\tesac\n\t\tshift\n\tdone\n\tif [[ -z $col || -z $line || -z $width || -z $height ]]; then return; fi\n\n\tltype=${ltype:-\"single\"}\n\tvlines+=(\"$col\" \"$((col+width-1))\")\n\thlines+=(\"$line\" \"$((line+height-1))\")\n\n\tprint -v box_out -rs\n\n\t#* Fill box if enabled\n\tif [[ -n $fill ]]; then\n\t\tfor((i=line+1;i<line+height-1;i++)); do\n\t\t\tprint -v box_out -m $i $((col+1)) -rp $((width-2)) -t \" \"\n\t\tdone\n\tfi\n\n\t#* Draw all horizontal lines\n\tprint -v box_out -fg ${line_color:-${theme[div_line]}}\n\tfor hpos in \"${hlines[@]}\"; do\n\t\tprint -v box_out -m $hpos $col -rp $((width-1)) -t \"${box[${ltype}_hor_line]}\"\n\tdone\n\n\t#* Draw all vertical lines\n\tfor vpos in \"${vlines[@]}\"; do\n\t\tprint -v box_out -m $line $vpos\n\t\tfor((hpos=line;hpos<=line+height-1;hpos++)); do\n\t\t\tprint -v box_out -m $hpos $vpos -t \"${box[${ltype}_vert_line]}\"\n\t\tdone\n\tdone\n\n\t#* Draw corners\n\tprint -v box_out -m $line $col -t \"${box[${ltype}_left_corner_up]}\"\n\tprint -v box_out -m $line $((col+width-1)) -t \"${box[${ltype}_right_corner_up]}\"\n\tprint -v box_out -m $((line+height-1)) $col -t \"${box[${ltype}_left_corner_down]}\"\n\tprint -v box_out -m $((line+height-1)) $((col+width-1)) -t \"${box[${ltype}_right_corner_down]}\"\n\n\t#* Draw small title without titlebar\n\tif [[ -n $title ]]; then\n\t\tprint -v box_out -m $line $((col+2)) -t \"┤\" -fg ${theme[title]} -b -t \"$title\" -rs -fg ${line_color:-${theme[div_line]}} -t \"├\"\n\tfi\n\n\tprint -v box_out -rs -m $((line+1)) $((col+1))\n\n\tif [[ -z $ext_var ]]; then echo -en \"${box_out}\"; fi\n\n\n}\n\ncreate_meter() { \t#? Create a horizontal percentage meter, usage; create_meter <value 0-100>\n\t\t\t\t\t#? Optional arguments: [-p, -place <line> <col>] [-w, -width <columns>] [-f, -fill-empty]\n\t\t\t\t\t#? [-c, -color \"array-name\"] [-i, -invert-color] [-v, -variable \"variable-name\"]\n\tif [[ -z $1 ]]; then return; fi\n\tlocal val width colors color block=\"■\" i fill_empty col line var ext_var out meter_var print_var invert bg_color=${theme[inactive_fg]}\n\n\t#* Argument parsing\n\tuntil (($#==0)); do\n\t\tcase $1 in\n\t\t\t-p|-place) if is_int \"${@:2:2}\"; then line=$2; col=$3; shift 2; fi;;\t\t\t\t\t\t\t\t#? Placement for meter\n\t\t\t-w|-width) width=$2; shift;;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Width of meter in columns\n\t\t\t-c|-color) local -n colors=$2; shift;;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Name of an array containing colors from index 0-100\n\t\t\t-i|-invert) invert=1;;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Invert meter\n\t\t\t-f|-fill-empty) fill_empty=1;;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Fill unused space with dark blocks\n\t\t\t-v|-variable) local -n meter_var=$2; ext_var=1; shift;;\t\t\t\t\t\t\t\t\t\t\t\t#? Output meter to a variable\n\t\t\t*) if is_int \"$1\"; then val=$1; fi;;\n\t\tesac\n\t\tshift\n\tdone\n\n\tif [[ -z $val ]]; then return; fi\n\n\t#* Set default width if not given\n\twidth=${width:-10}\n\n\t#* If no color array was given, create a simple greyscale array\n\tif [[ -z $colors ]]; then\n\t\tfor ((i=0,ic=50;i<=100;i++,ic=ic+2)); do\n\t\t\tcolors[i]=\"${ic} ${ic} ${ic}\"\n\t\tdone\n\tfi\n\n\t#* Create the meter\n\tmeter_var=\"\"\n\tif [[ -n $line && -n $col ]]; then print -v meter_var -rs -m $line $col\n\telse print -v meter_var -rs; fi\n\n\tif [[ -n $invert ]]; then print -v meter_var -r $((width+1)); fi\n\tfor((i=1;i<=width;i++)); do\n\t\tif [[ -n $invert ]]; then print -v meter_var -l 2; fi\n\n\t\tif ((val>=i*100/width)); then\n\t\t\tprint -v meter_var -fg ${colors[$((i*100/width))]} -t \"${block}\"\n\t\telif ((fill_empty==1)); then\n\t\t\tif [[ -n $invert ]]; then print -v meter_var -l $((width-i)); fi\n\t\t\tprint -v meter_var -fg $bg_color -rp $((1+width-i)) -t \"${block}\"; break\n\t\telse\n\t\t\tif [[ -n $invert ]]; then break; print -v meter_var -l $((1+width-i))\n\t\t\telse print -v meter_var -r $((1+width-i)); break; fi\n\t\tfi\n\tdone\n\tif [[ -z $ext_var ]]; then echo -en \"${meter_var}\"; fi\n}\n\ncreate_graph() { \t#? Create a graph from an array of percentage values, usage; \tcreate_graph <options> <value-array>\n\t\t\t\t\t#? Create a graph from an array of non percentage values:       create_graph <options> <-max \"max value\"> <value-array>\n\t\t\t\t\t#? Add a value to existing graph; \t\t\t\t\t\t\t\tcreate_graph [-i, -invert] [-max \"max value\"] -add-value \"graph_array\" <value>\n\t\t\t\t\t#? Add last value from an array to existing graph; \t\t\t\tcreate_graph [-i, -invert] [-max \"max value\"] -add-last \"graph_array\" \"value-array\"\n\t\t\t\t\t#? Options: < -d, -dimensions <line> <col> <height> <width> > [-i, -invert] [-n, -no-guide] [-c, -color \"array-name\"] [-o, -output-array \"variable-name\"]\n\tif [[ -z $1 ]]; then return; fi\n\tif [[ ${graph[hires]} == true ]]; then create_graph_hires \"$@\"; return; fi\n\n\tlocal val col s_col line s_line height s_height width s_width colors color i var ext_var out side_num side_nums=1 add add_array invert no_guide max\n\tlocal -a graph_array input_array\n\n\t#* Argument parsing\n\tuntil (($#==0)); do\n\t\tcase $1 in\n\t\t\t-d|-dimensions) if is_int \"${@:2:4}\"; then line=$2; col=$3; height=$4; width=$5; shift 4; fi;;\t\t\t\t\t\t#? Graph dimensions\n\t\t\t-c|-color) local -n colors=$2; shift;;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Name of an array containing colors from index 0-100\n\t\t\t-o|-output-array) local -n output_array=$2; ext_var=1; shift;;\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Output meter to an array\n\t\t\t-add-value) if is_int \"$3\"; then local -n output_array=$2; add=$3; break; else return; fi;;\t\t\t\t\t\t\t#? Add a value to existing graph\n\t\t\t-add-last) local -n output_array=$2; local -n add_array=$3; add=${add_array[-1]}; break;;\t\t\t\t\t\t\t#? Add last value from array to existing graph\n\t\t\t-i|-invert) invert=1;;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Invert graph, drawing from top to bottom\n\t\t\t-n|-no-guide) no_guide=1;;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Don't print side and bottom guide lines\n\t\t\t-max) if is_int \"$2\"; then max=$2; shift; fi;;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Needed max value for non percentage arrays\n\t\t\t*) local -n tmp_in_array=$1; input_array=(\"${tmp_in_array[@]}\");;\n\t\tesac\n\t\tshift\n\tdone\n\n\tif [[ -z $no_guide ]]; then\n\t\t((--height))\n\telse\n\t\tif [[ -n $invert ]]; then ((line--)); fi\n\tfi\n\n\n\tif ((width<3)); then width=3; fi\n\tif ((height<1)); then height=1; fi\n\n\n\t#* If argument \"add\" was passed check for existing graph and make room for new value(s)\n\tlocal add_start add_end\n\tif [[ -n $add ]]; then\n\t\tlocal cut_left search\n\t\tif [[ -n ${input_array[0]} ]]; then return; fi\n\t\tif [[ -n $output_array ]]; then\n\t\t\tgraph_array=(\"${output_array[@]}\")\n\t\t\tif [[ -z ${graph_array[0]} ]]; then return; fi\n\t\telse\n\t\t\treturn\n\t\tfi\n\t\theight=$((${#graph_array[@]}-1))\n\t\tinput_array[0]=${add}\n\n\t\t#* Remove last value in current graph\n\n\t\tfor ((i=0;i<height;i++)); do\n\t\t\tcut_left=\"${graph_array[i]%m*}\"\n\t\t\tsearch=$((${#cut_left}+1))\n\t\t\tgraph_array[i]=\"${graph_array[i]::$search}${graph_array[i]:$((search+1))}\"\n\t\tdone\n\n\tfi\n\n\t#* Initialize graph if no \"add\" argument was given\n\tif [[ -z $add ]]; then\n\t\t#* Scale down graph one line if height is even\n\t\tlocal inv_offset h_inv normal_vals=1\n\t\tlocal -a side_num=(100 0) g_char=(\" ⡇\" \" ⠓\" \"⠒\") g_index\n\n\t\tif [[ -n $invert ]]; then\n\t\t\tfor((i=height;i>=0;i--)); do\n\t\t\t\tg_index+=($i)\n\t\t\tdone\n\n\t\telse\n\t\t\tfor((i=0;i<=height;i++)); do\n\t\t\t\tg_index+=($i)\n\t\t\tdone\n\t\tfi\n\n\t\tif [[ -n $no_guide ]]; then unset normal_vals\n\t\telif [[ -n $invert ]]; then g_char=(\" ⡇\" \" ⡤\" \"⠤\")\n\t\tfi\n\n\t\t#* Set up graph array print side numbers and lines\n\t\tprint -v graph_array[0] -rs\n\t\tprint -v graph_array[0] -m $((line+g_index[0])) ${col} ${normal_vals:+-jr 3 -fg \"#ee\" -b -t \"${side_num[0]}\" -rs -fg ${theme[main_fg]} -t \"${g_char[0]}\"} -fg ${colors[100]}\n\t\tfor((i=1;i<height;i++)); do\n\t\t\tprint -v graph_array[i] -m $((line+g_index[i])) ${col} ${normal_vals:+-r 3 -fg ${theme[main_fg]} -t \"${g_char[0]}\"} -fg ${colors[$((100-i*100/height))]}\n\t\tdone\n\n\t\tif [[ -z $no_guide ]]; then width=$((width-5)); fi\n\n\t\tgraph_array[height]=\"\"\n\t\tif [[ -z $no_guide ]]; then\n\t\t\tprint -v graph_array[$height] -m $((line+g_index[(-1)])) ${col} -jr 3 -fg \"#ee\" -b -t \"${side_num[1]}\" -rs -fg ${theme[main_fg]} -t \"${g_char[1]}\" -rp ${width} -t \"${g_char[2]}\"\n\t\tfi\n\n\t\t#* If no color array was given, create a simple greyscale array\n\t\tif [[ -z $colors ]]; then\n\t\t\tfor ((i=0,ic=50;i<=100;i++,ic=ic+2)); do\n\t\t\t\tcolors[i]=\"${ic} ${ic} ${ic}\"\n\t\t\tdone\n\t\tfi\n\tfi\n\n\t#* Create the graph\n\tlocal value_width x y a cur_value prev_value=100 symbol tmp_out compare found count virt_height=$((height*10))\n\tif [[ -n $add ]]; then\n\t\tvalue_width=1\n\telif ((${#input_array[@]}<=width)); then\n\t\tvalue_width=${#input_array[@]};\n\telse\n\t\tvalue_width=${width}\n\t\tinput_array=(\"${input_array[@]:(-$width)}\")\n\tfi\n\n\tif [[ -n $invert ]]; then\n\t\ty=$((height-1))\n\t\tdone_val=\"-1\"\n\telse\n\t\ty=0\n\t\tdone_val=$height\n\tfi\n\n\t#* Convert input array to percentage values of max if a max value was given\n\tif [[ -n $max ]]; then\n\t\tfor((i=0;i<${#input_array[@]};i++)); do\n\t\t\tif ((input_array[i]>=max)); then\n\t\t\t\tinput_array[i]=100\n\t\t\telse\n\t\t\t\tinput_array[i]=$((input_array[i]*100/max))\n\t\t\tfi\n\t\tdone\n\tfi\n\n\tuntil ((y==done_val)); do\n\n\t\t#* Print spaces to right-justify graph if number of values is less than graph width\n\t\tif [[ -z $add ]] && ((value_width<width)); then print -v graph_array[y] -rp $((width-value_width)) -t \" \"; fi\n\n\t\tcur_value=$(( virt_height-(y*10) ))\n\t\tnext_value=$(( virt_height-((y+1)*10) ))\n\n\t\tcount=0\n\t\tx=0\n\n\t\t#* Create graph by walking through all values for each line, speed up by counting similar values and print once, when difference is met\n\t\twhile ((x<value_width)); do\n\n\t\t\tif [[ -z ${input_array[x]} ]] || ((input_array[x]<1)) || ((${#input_array[x]}>3)); then input_array[x]=0; fi\n\n\t\t\t#* Print empty space if current value is less than percentage for current line\n\t\t\twhile ((x<value_width & input_array[x]*virt_height/100<next_value)); do\n\t\t\t\t((++count))\n\t\t\t\t((++x))\n\t\t\tdone\n\t\t\tif ((count>0)); then\n\t\t\t\tprint -v graph_array[y] -rp ${count} -t \" \"\n\t\t\t\tcount=0\n\t\t\tfi\n\n\t\t\t#* Print current value in percent relative to graph size if current value is less than line percentage but greater than next line percentage\n\t\t\twhile ((x<value_width & input_array[x]*virt_height/100<cur_value & input_array[x]*virt_height/100>=next_value)); do\n\t\t\t\tprint -v graph_array[y] -t \"${graph_symbol[${invert:+-}$(( (input_array[x]*virt_height/100)-next_value ))]}\"\n\t\t\t\t((++x))\n\t\t\tdone\n\n\t\t\t#* Print full block if current value is greater than percentage for current line\n\t\t\twhile ((x<value_width & input_array[x]*virt_height/100>=cur_value)); do\n\t\t\t\t((++count))\n\t\t\t\t((++x))\n\t\t\tdone\n\t\t\tif ((count>0)); then\n\t\t\t\tprint -v graph_array[y] -rp ${count} -t \"${graph_symbol[10]}\"\n\t\t\t\tcount=0\n\t\t\tfi\n\t\tdone\n\n\tif [[ -n $invert ]]; then\n\t\t((y--)) || true\n\telse\n\t\t((++y))\n\tfi\n\tdone\n\n\t#* Echo out graph if no argument for a output array was given\n\tif [[ -z $ext_var && -z $add ]]; then echo -en \"${graph_array[*]}\"\n\telse output_array=(\"${graph_array[@]}\"); fi\n}\n\ncreate_mini_graph() { \t#? Create a one line high graph from an array of percentage values, usage; \tcreate_mini_graph <options> <value-array>\n\t\t\t\t\t\t#? Add a value to existing graph; \t\t\t\t\t\tcreate_mini_graph [-i, -invert] [-nc, -no-color] [-c, -color \"array-name\"] -add-value \"graph_variable\" <value>\n\t\t\t\t\t\t#? Add last value from an array to existing graph; \t\tcreate_mini_graph [-i, -invert] [-nc, -no-color] [-c, -color \"array-name\"] -add-last \"graph_variable\" \"value-array\"\n\t\t\t\t\t\t#? Options: [-w, -width <width>] [-i, -invert] [-nc, -no-color] [-c, -color \"array-name\"] [-o, -output-variable \"variable-name\"]\n\tif [[ -z $1 ]]; then return; fi\n\n\tif [[ ${graph[hires]} == true ]]; then create_mini_graph_hires \"$@\"; return; fi\n\n\tlocal val col s_col line s_line height s_height width s_width colors color i var ext_var out side_num side_nums=1 add invert no_guide graph_var no_color color_value\n\n\t#* Argument parsing\n\tuntil (($#==0)); do\n\t\tcase $1 in\n\t\t\t-w|-width) if is_int \"$2\"; then width=$2; shift; fi;;\t\t\t\t\t\t\t\t\t \t\t\t\t\t\t#? Graph width\n\t\t\t-c|-color) local -n colors=$2; shift;;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Name of an array containing colors from index 0-100\n\t\t\t-nc|-no-color) no_color=1;;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Set no color\n\t\t\t-o|-output-variable) local -n output_var=$2; ext_var=1; shift;;\t\t\t\t\t\t\t\t\t\t\t\t\t#? Output graph to a variable\n\t\t\t-add-value) if is_int \"$3\"; then local -n output_var=$2; add=$3; break; else return; fi;;\t\t\t\t\t\t#? Add a value to existing graph\n\t\t\t-add-last) local -n output_var=$2 add_array=$3; add=\"${add_array[-1]}\"; break;; \t\t\t\t\t\t\t\t#? Add last value from array to existing graph\n\t\t\t-i|-invert) invert=1;;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Invert graph, drawing from top to bottom\n\t\t\t*) local -n input_array=$1;;\n\t\tesac\n\t\tshift\n\tdone\n\n\tif ((width<1)); then width=1; fi\n\n\t#* If argument \"add\" was passed check for existing graph and make room for new value(s)\n\tlocal add_start add_end\n\tif [[ -n $add ]]; then\n\t\tlocal cut_left search\n\t\t#if [[ -n ${input_array[0]} ]]; then return; fi\n\t\tif [[ -n $output_var ]]; then\n\t\t\tgraph_var=\"${output_var}\"\n\t\t\tif [[ -z ${graph_var} ]]; then return; fi\n\t\telse\n\t\t\treturn\n\t\tfi\n\n\t\tdeclare -a input_array\n\t\tinput_array[0]=${add}\n\n\t\t#* Remove last value in current graph\n\t\tif [[ -n ${graph_var} && -z $no_color ]]; then\n\t\t\tif [[ ${graph_var::5} == \"\\e[1C\" ]]; then\n\t\t\t\tgraph_var=\"${graph_var#'\\e[1C'}\"\n\t\t\telse\n\t\t\t\tcut_left=\"${graph_var%%m*}\"\n\t\t\t\tsearch=$((${#cut_left}+1))\n\t\t\t\tgraph_var=\"${graph_var:$((search+1))}\"\n\t\t\tfi\n\t\telif [[ -n ${graph_var} && -n $no_color ]]; then\n\t\t\tif [[ ${graph_var::5} == \"\\e[1C\" ]]; then\n\t\t\t\t#cut_left=\"${graph_var%%C*}\"\n\t\t\t\t#search=$((${#cut_left}+1))\n\t\t\t\t#graph_var=\"${graph_var:$((search))}\"\n\t\t\t\tgraph_var=\"${graph_var#'\\e[1C'}\"\n\t\t\telse\n\t\t\t\tgraph_var=\"${graph_var:1}\"\n\t\t\tfi\n\t\tfi\n\tfi\n\n\n\t#* If no color array was given, create a simple greyscale array\n\tif [[ -z $colors && -z $no_color ]]; then\n\t\tfor ((i=0,ic=50;i<=100;i++,ic=ic+2)); do\n\t\t\tcolors[i]=\"${ic} ${ic} ${ic}\"\n\t\tdone\n\tfi\n\n\n\t#* Create the graph\n\tlocal value_width x=0 y a cur_value virt_height=$((height*10)) offset=0 org_value\n\tif [[ -n $add ]]; then\n\t\tvalue_width=1\n\telif ((${#input_array[@]}<=width)); then\n\t\tvalue_width=${#input_array[@]};\n\telse\n\t\tvalue_width=${width}\n\t\toffset=$((${#input_array[@]}-width))\n\tfi\n\n\t#* Print spaces to right-justify graph if number of values is less than graph width\n\t\tif [[ -z $add && -z $no_color ]] && ((value_width<width)); then print -v graph_var -rp $((width-value_width)) -t \"\\e[1C\"\n\t\telif [[ -z $add && -n $no_color ]] && ((value_width<width)); then print -v graph_var -rp $((width-value_width)) -t \"\\e[1C\"; fi\n\t\t#* Create graph\n\t\twhile ((x<value_width)); do\n\t\t\t#* Round current input_array value divided by 10 to closest whole number\n\t\t\torg_value=${input_array[offset+x]}\n\t\t\tif ((org_value<=0)); then org_value=0; fi\n\t\t\tif ((org_value>=100)); then cur_value=10; org_value=100\n\t\t\telif [[ ${#org_value} -gt 1 && ${org_value:(-1)} -ge 5 ]]; then cur_value=$((${org_value::1}+1))\n\t\t\telif [[ ${#org_value} -gt 1 && ${org_value:(-1)} -lt 5 ]]; then cur_value=$((${org_value::1}))\n\t\t\telif [[ ${org_value:(-1)} -ge 5 ]]; then cur_value=1\n\t\t\telse cur_value=0\n\t\t\tfi\n\t\t\tif [[ -z $no_color ]]; then\n\t\t\t\tcolor=\"-fg ${colors[$org_value]} \"\n\t\t\telse\n\t\t\t\tcolor=\"\"\n\t\t\tfi\n\n\t\t\tif [[ $cur_value == 0 ]]; then\n\t\t\t\tprint -v graph_var -t \"\\e[1C\"\n\t\t\telse\n\t\t\t\tprint -v graph_var ${color}-t \"${graph_symbol[${invert:+-}$cur_value]}\"\n\t\t\tfi\n\t\t\t((++x))\n\t\tdone\n\n\t#* Echo out graph if no argument for a output array was given\n\tif [[ -z $ext_var && -z $add ]]; then echo -en \"${graph_var}\"\n\telse output_var=\"${graph_var}\"; fi\n}\n\ncreate_graph_hires() { \t#? Create a graph from an array of percentage values, usage; \tcreate_graph <options> <value-array>\n\t\t\t\t\t#? Create a graph from an array of non percentage values:       create_graph <options> <-max \"max value\"> <value-array>\n\t\t\t\t\t#? Add a value to existing graph; \t\t\t\t\t\t\t\tcreate_graph [-i, -invert] [-max \"max value\"] -add-value \"graph_array\" <value>\n\t\t\t\t\t#? Add last value from an array to existing graph; \t\t\t\tcreate_graph [-i, -invert] [-max \"max value\"] -add-last \"graph_array\" \"value-array\"\n\t\t\t\t\t#? Options: < -d, -dimensions <line> <col> <height> <width> > [-i, -invert] [-n, -no-guide] [-c, -color \"array-name\"] [-o, -output-array \"variable-name\"]\n\tif [[ -z $1 ]]; then return; fi\n\tlocal val col s_col line s_line height s_height width s_width colors color var ext_var out side_num side_nums=1 add add_array invert no_guide max graph_name offset=0 last_val\n\tlocal -a input_array\n\tlocal -i i\n\n\t#* Argument parsing\n\tuntil (($#==0)); do\n\t\tcase $1 in\n\t\t\t-d|-dimensions) if is_int \"${@:2:4}\"; then line=$2; col=$3; height=$4; width=$5; shift 4; fi;;\t\t\t\t\t\t#? Graph dimensions\n\t\t\t-c|-color) local -n colors=$2; shift;;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Name of an array containing colors from index 0-100\n\t\t\t-o|-output-array) local -n output_array=$2; graph_name=$2; ext_var=1; shift;;\t\t\t\t\t\t\t\t\t\t#? Output meter to an array\n\t\t\t-add-value) if is_int \"$3\"; then local -n output_array=$2; graph_name=$2; add=$3; break; else return; fi;;\t\t\t#? Add a value to existing graph\n\t\t\t-add-last) local -n output_array=$2; graph_name=$2; local -n add_array=$3; add=${add_array[-1]}; break;;\t\t\t#? Add last value from array to existing graph\n\t\t\t-i|-invert) invert=1;;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Invert graph, drawing from top to bottom\n\t\t\t-n|-no-guide) no_guide=1;;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Don't print side and bottom guide lines\n\t\t\t-max) if is_int \"$2\"; then max=$2; shift; fi;;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Needed max value for non percentage arrays\n\t\t\t*) local -n tmp_in_array=\"$1\"; input_array=(\"${tmp_in_array[@]}\");;\n\t\tesac\n\t\tshift\n\tdone\n\n\tlocal -n last_val=\"graph[${graph_name}_last_val]\"\n\tlocal -n last_type=\"graph[${graph_name}_last_type]\"\n\n\n\tif [[ -z $add ]]; then\n\t\tlast_type=\"even\"\n\t\tlast_val=0\n\t\tlocal -n graph_array=\"${graph_name}_odd\"\n\t\tlocal -n graph_even=\"${graph_name}_even\"\n\t\tgraph_even=(\"\")\n\t\tgraph_array=(\"\")\n\telif [[ ${last_type} == \"even\" ]]; then\n\t\tlocal -n graph_array=\"${graph_name}_odd\"\n\t\tlast_type=\"odd\"\n\telif [[ ${last_type} == \"odd\" ]]; then\n\t\tlocal -n graph_array=\"${graph_name}_even\"\n\t\tlast_type=\"even\"\n\tfi\n\n\tif [[ -z $no_guide ]]; then ((--height))\n\telif [[ -n $invert ]]; then ((line--))\n\tfi\n\n\tif ((width<3)); then width=3; fi\n\tif ((height<1)); then height=1; fi\n\n\n\t#* If argument \"add\" was passed check for existing graph and make room for new value(s)\n\tlocal add_start add_end\n\tif [[ -n $add ]]; then\n\t\tlocal cut_left search\n\t\tif [[ -n ${input_array[*]} || -z ${graph_array[0]} ]]; then return; fi\n\n\t\theight=$((${#graph_array[@]}-1))\n\t\tinput_array=(\"${add}\")\n\n\t\t#* Remove last value in current graph\n\n\t\tfor ((i=0;i<height;i++)); do\n\t\t\tcut_left=\"${graph_array[i]%m*}\"\n\t\t\tsearch=$((${#cut_left}+1))\n\t\t\tgraph_array[i]=\"${graph_array[i]::$search}${graph_array[i]:$((search+1))}\"\n\t\tdone\n\n\tfi\n\n\t#* Initialize graph if no \"add\" argument was given\n\tif [[ -z $add ]]; then\n\t\t#* Scale down graph one line if height is even\n\t\tlocal inv_offset h_inv normal_vals=1\n\t\tlocal -a side_num=(100 0) g_char=(\" ⡇\" \" ⠓\" \"⠒\") g_index\n\n\t\tif [[ -n $invert ]]; then\n\t\t\tfor((i=height;i>=0;i--)); do\n\t\t\t\tg_index+=($i)\n\t\t\tdone\n\n\t\telse\n\t\t\tfor((i=0;i<=height;i++)); do\n\t\t\t\tg_index+=($i)\n\t\t\tdone\n\t\tfi\n\n\t\tif [[ -n $no_guide ]]; then unset normal_vals\n\t\telif [[ -n $invert ]]; then g_char=(\" ⡇\" \" ⡤\" \"⠤\")\n\t\tfi\n\n\t\t#* Set up graph array print side numbers and lines\n\t\tprint -v graph_array[0] -rs -m $((line+g_index[0])) ${col} ${normal_vals:+-jr 3 -fg \"#ee\" -b -t \"${side_num[0]}\" -rs -fg ${theme[main_fg]} -t \"${g_char[0]}\"} -fg ${colors[100]}\n\t\tfor((i=1;i<height;i++)); do\n\t\t\tprint -v graph_array[i] -m $((line+g_index[i])) ${col} ${normal_vals:+-r 3 -fg ${theme[main_fg]} -t \"${g_char[0]}\"} -fg ${colors[$((100-i*100/height))]}\n\t\tdone\n\n\t\tif [[ -z $no_guide ]]; then width=$((width-5)); fi\n\n\t\tgraph_array[$height]=\"\"\n\t\tif [[ -z $no_guide ]]; then\n\t\t\tprint -v graph_array[$height] -m $((line+g_index[(-1)])) ${col} -jr 3 -fg \"#ee\" -b -t \"${side_num[1]}\" -rs -fg ${theme[main_fg]} -t \"${g_char[1]}\" -rp ${width} -t \"${g_char[2]}\"\n\t\tfi\n\n\t\tgraph_even=(\"${graph_array[@]}\")\n\n\t\t#* If no color array was given, create a simple greyscale array\n\t\tif [[ -z $colors ]]; then\n\t\t\tfor ((i=0,ic=50;i<=100;i++,ic=ic+2)); do\n\t\t\t\tcolors[i]=\"${ic} ${ic} ${ic}\"\n\t\t\tdone\n\t\tfi\n\tfi\n\n\t#* Create the graph\n\tlocal value_width next_line prev_value cur_value virt_height=$((height*4)) converted\n\tlocal -i x y c_val p_val l_val\n\tif [[ -n $add ]]; then\n\t\tvalue_width=1\n\telif ((${#input_array[@]}<=width*2)); then\n\t\tvalue_width=$((${#input_array[@]}*2))\n\telse\n\t\tvalue_width=$((width*2))\n\t\tinput_array=(\"${input_array[@]:(-${value_width})}\")\n\tfi\n\n\tif [[ -z $add ]] && ! ((${#input_array[@]}%2)); then last_val=${input_array[0]}; input_array=(\"${input_array[@]:1}\"); converted=1; fi\n\n\t#* Print spaces to right-justify graph if number of values is less than graph width\n\tif [[ -z $add ]] && ((${#input_array[@]}/2<width)); then\n\t\tfor((i=0;i<height;i++)); do\n\t\t\tprint -v graph_array[i] -rp $((width-1-${#input_array[@]}/2)) -t \" \"\n\t\tdone\n\t\tgraph_even=(\"${graph_array[@]}\")\n\tfi\n\n\tif [[ -n $invert ]]; then\n\t\ty=$((height-1))\n\t\tdone_val=\"-1\"\n\telse\n\t\ty=0\n\t\tdone_val=$height\n\tfi\n\n\t#* Convert input array to percentage values of max if a max value was given\n\tif [[ -n $max ]]; then\n\t\tfor((i=0;i<${#input_array[@]};i++)); do\n\t\t\tif ((input_array[i]>=max)); then\n\t\t\t\tinput_array[i]=100\n\t\t\telse\n\t\t\t\tinput_array[i]=$((input_array[i]*100/max))\n\t\t\tfi\n\t\tdone\n\t\tif [[ -n $converted ]]; then\n\t\t\tlast_val=$((${last_val}*100/max))\n\t\t\tif ((${last_val}>100)); then last_val=100; fi\n\t\tfi\n\tfi\n\n\tif [[ -n $invert ]]; then local -n symbols=graph_symbol_down\n\telse local -n symbols=graph_symbol_up\n\tfi\n\n\tuntil ((y==done_val)); do\n\n\t\tnext_line=$(( virt_height-((y+1)*4) ))\n\t\tunset p_val\n\n\t\t#* Create graph by walking through all values for each line\n\t\tfor ((x=0;x<${#input_array[@]};x++)); do\n\t\t\tc_val=${input_array[x]}\n\t\t\tp_val=${p_val:-${last_val}}\n\t\t\tcur_value=\"$((c_val*virt_height/100-next_line))\"\n\t\t\tprev_value=$((p_val*virt_height/100-next_line))\n\n\t\t\tif ((cur_value<0)); then cur_value=0\n\t\t\telif ((cur_value>4)); then cur_value=4; fi\n\t\t\tif ((prev_value<0)); then prev_value=0\n\t\t\telif ((prev_value>4)); then prev_value=4; fi\n\n\t\t\tif [[ -z $add ]] && ((x==0)); then\n\t\t\t\tprint -v graph_even[y] -t \"${symbols[${prev_value}_${cur_value}]}\"\n\t\t\t\tprint -v graph_array[y] -t \"${symbols[0_${prev_value}]}\"\n\t\t\telif [[ -z $add ]] && ! ((x%2)); then\n\t\t\t\tprint -v graph_even[y] -t \"${symbols[${prev_value}_${cur_value}]}\"\n\t\t\telse\n\t\t\t\tprint -v graph_array[y] -t \"${symbols[${prev_value}_${cur_value}]}\"\n\t\t\tfi\n\n\t\t\tif [[ -z $add ]]; then p_val=${input_array[x]}; else unset p_val; fi\n\n\t\tdone\n\n\t\tif [[ -n $invert ]]; then\n\t\t\t((y--)) || true\n\t\telse\n\t\t\t((++y))\n\t\tfi\n\n\tdone\n\n\tif [[ -z $add && ${last_type} == \"even\" ]]; then\n\t\tdeclare -n graph_array=\"${graph_name}_even\"\n\tfi\n\n\tlast_val=$c_val\n\n\toutput_array=(\"${graph_array[@]}\")\n}\n\n\ncreate_mini_graph_hires() { \t#? Create a one line high graph from an array of percentage values, usage; \tcreate_mini_graph <options> <value-array>\n\t\t\t\t\t\t#? Add a value to existing graph; \t\t\t\t\t\tcreate_mini_graph [-i, -invert] [-nc, -no-color] [-c, -color \"array-name\"] -add-value \"graph_variable\" <value>\n\t\t\t\t\t\t#? Add last value from an array to existing graph; \t\tcreate_mini_graph [-i, -invert] [-nc, -no-color] [-c, -color \"array-name\"] -add-last \"graph_variable\" \"value-array\"\n\t\t\t\t\t\t#? Options: [-w, -width <width>] [-i, -invert] [-nc, -no-color] [-c, -color \"array-name\"] [-o, -output-variable \"variable-name\"]\n\tif [[ -z $1 ]]; then return; fi\n\tlocal val col s_col line s_line height s_height width s_width colors color var ext_var out side_num side_nums=1 add invert no_guide graph_var no_color color_value graph_name\n\tlocal -a input_array\n\tlocal -i i\n\n\t#* Argument parsing\n\tuntil (($#==0)); do\n\t\tcase $1 in\n\t\t\t-w|-width) if is_int \"$2\"; then width=$2; shift; fi;;\t\t\t\t\t\t\t\t\t \t\t\t\t\t\t#? Graph width\n\t\t\t-c|-color) local -n colors=$2; shift;;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Name of an array containing colors from index 0-100\n\t\t\t-nc|-no-color) no_color=1;;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Set no color\n\t\t\t-o|-output-variable) local -n output_var=$2; graph_name=$2; ext_var=1; shift;;\t\t\t\t\t\t\t\t\t#? Output graph to a variable\n\t\t\t-add-value) if is_int \"$3\"; then local -n output_var=$2; graph_name=$2; add=$3; break; else return; fi;;\t\t#? Add a value to existing graph\n\t\t\t-add-last) local -n output_var=$2; local -n add_array=$3; graph_name=$2; add=\"${add_array[-1]:-0}\"; break;; \t\t#? Add last value from array to existing graph\n\t\t\t-i|-invert) invert=1;;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Invert graph, drawing from top to bottom\n\t\t\t*) local -n tmp_in_arr=$1; input_array=(\"${tmp_in_arr[@]}\");;\n\t\tesac\n\t\tshift\n\tdone\n\n\tlocal -n last_val=\"${graph_name}_last_val\"\n\tlocal -n last_type=\"${graph_name}_last_type\"\n\n\tif [[ -z $add ]]; then\n\t\tlast_type=\"even\"\n\t\tlast_val=0\n\t\tlocal -n graph_var=\"${graph_name}_odd\"\n\t\tlocal -n graph_other=\"${graph_name}_even\"\n\t\tgraph_var=\"\"; graph_other=\"\"\n\telif [[ ${last_type} == \"even\" ]]; then\n\t\tlocal -n graph_var=\"${graph_name}_odd\"\n\t\tlast_type=\"odd\"\n\telif [[ ${last_type} == \"odd\" ]]; then\n\t\tlocal -n graph_var=\"${graph_name}_even\"\n\t\tlast_type=\"even\"\n\tfi\n\n\tif ((width<1)); then width=1; fi\n\n\t#* If argument \"add\" was passed check for existing graph and make room for new value(s)\n\tlocal add_start add_end\n\tif [[ -n $add ]]; then\n\t\tlocal cut_left search\n\t\tinput_array[0]=${add}\n\n\t\t#* Remove last value in current graph\n\t\tif [[ -n ${graph_var} && -z $no_color ]]; then\n\t\t\tif [[ ${graph_var::5} == '\\e[1C' ]]; then\n\t\t\t\tgraph_var=\"${graph_var#'\\e[1C'}\"\n\t\t\telse\n\t\t\t\tcut_left=\"${graph_var%m*}\"\n\t\t\t\tsearch=$((${#cut_left}+1))\n\t\t\t\tgraph_var=\"${graph_var::$search}${graph_var:$((search+1))}\"\n\t\t\tfi\n\t\telif [[ -n ${graph_var} && -n $no_color ]]; then\n\t\t\tif [[ ${graph_var::5} == \"\\e[1C\" ]]; then\n\t\t\t\t#cut_left=\"${graph_var%%C*}\"\n\t\t\t\t#search=$((${#cut_left}+1))\n\t\t\t\t#graph_var=\"${graph_var:$((search))}\"\n\t\t\t\tgraph_var=\"${graph_var#'\\e[1C'}\"\n\t\t\telse\n\t\t\t\tgraph_var=\"${graph_var:1}\"\n\t\t\tfi\n\t\tfi\n\tfi\n\n\n\t#* If no color array was given, create a simple greyscale array\n\tif [[ -z $colors && -z $no_color ]]; then\n\t\tfor ((i=0,ic=50;i<=100;i++,ic=ic+2)); do\n\t\t\tcolors[i]=\"${ic} ${ic} ${ic}\"\n\t\tdone\n\tfi\n\n\n\t#* Create the graph\n\tlocal value_width x=0 y a cur_value prev_value p_val c_val acolor jump odd offset=0\n\tif [[ -n $add ]]; then\n\t\tvalue_width=1\n\telif ((${#input_array[@]}<=width*2)); then\n\t\tvalue_width=$((${#input_array[@]}*2))\n\telse\n\t\tvalue_width=$((width*2))\n\t\tinput_array=(\"${input_array[@]:(-${value_width})}\")\n\tfi\n\n\tif [[ -z $add ]] && ! ((${#input_array[@]}%2)); then last_val=${input_array[0]}; input_array=(\"${input_array[@]:1}\"); fi\n\n\t#* Print spaces to right-justify graph if number of values is less than graph width\n\tif [[ -z $add ]] && ((${#input_array[@]}/2<width)); then print -v graph_var -rp $((width-1-${#input_array[@]}/2)) -t \"\\e[1C\"; graph_other=\"${graph_var}\"; fi\n\n\tif [[ -n $invert ]]; then local -n symbols=graph_symbol_down\n\telse local -n symbols=graph_symbol_up\n\tfi\n\n\tunset p_val\n\n\t#* Create graph\n\tfor((i=0;i<${#input_array[@]};i++)); do\n\n\t\tc_val=${input_array[i]}\n\t\tp_val=${p_val:-${last_val}}\n\n\t\tif ((c_val>=85)); then cur_value=4\n\t\telif ((c_val>=60)); then cur_value=3\n\t\telif ((c_val>=30)); then cur_value=2\n\t\telif ((c_val>=10)); then cur_value=1\n\t\telif ((c_val<10)); then cur_value=0; fi\n\n\t\tif ((p_val>=85)); then prev_value=4\n\t\telif ((p_val>=60)); then prev_value=3\n\t\telif ((p_val>=30)); then prev_value=2\n\t\telif ((p_val>=10)); then prev_value=1\n\t\telif ((p_val<10)); then prev_value=0; fi\n\n\t\tif [[ -z $no_color ]]; then\n\t\t\tif ((c_val>p_val)); then acolor=$((c_val-p_val))\n\t\t\telse acolor=$((p_val-c_val)); fi\n\t\t\tif ((acolor>100)); then acolor=100; elif ((acolor<0)); then acolor=0; fi\n\t\t\tcolor=\"-fg ${colors[${acolor:-0}]} \"\n\t\telse\n\t\t\tunset color\n\t\tfi\n\n\t\tif ((cur_value==0 & prev_value==0)); then jump=\"\\e[1C\"; else unset jump; fi\n\n\t\tif [[ -z $add ]] && ((i==0)); then\n\t\t\tprint -v graph_other ${color}-t \"${jump:-${symbols[${prev_value}_${cur_value}]}}\"\n\t\t\tprint -v graph_var ${color}-t \"${jump:-${symbols[0_${prev_value}]}}\"\n\t\telif [[ -z $add ]] && ((i%2)); then\n\t\t\tprint -v graph_other ${color}-t \"${jump:-${symbols[${prev_value}_${cur_value}]}}\"\n\t\telse\n\t\t\tprint -v graph_var ${color}-t \"${jump:-${symbols[${prev_value}_${cur_value}]}}\"\n\t\tfi\n\n\t\tif [[ -z $add ]]; then p_val=$c_val; else unset p_val; fi\n\tdone\n\n\t#if [[ -z $add ]]; then\n\t#\tdeclare -n graph_var=\"${graph_name}_even\"\n\t# \t#echo \"yup\" >&2\n\t#fi\n\n\tlast_val=$c_val\n\n\toutput_var=\"${graph_var}\"\n}\n\nprint() {\t#? Print text, set true-color foreground/background color, add effects, center text, move cursor, save cursor position and restore cursor postion\n\t\t\t#? Effects: [-fg, -foreground <RGB Hex>|<R Dec> <G Dec> <B Dec>] [-bg, -background <RGB Hex>|<R Dec> <G Dec> <B Dec>] [-rs, -reset] [-/+b, -/+bold] [-/+da, -/+dark]\n\t\t\t#? [-/+ul, -/+underline] [-/+i, -/+italic] [-/+bl, -/+blink] [-f, -font \"sans-serif|script|fraktur|monospace|double-struck\"]\n\t\t\t#? Manipulation: [-m, -move <line> <column>] [-l, -left <x>] [-r, -right <x>] [-u, -up <x>] [-d, -down <x>] [-c, -center] [-sc, -save] [-rc, -restore]\n\t\t\t#? [-jl, -justify-left <width>] [-jr, -justify-right <width>] [-jc, -justify-center <width>] [-rp, -repeat <x>]\n\t\t\t#? Text: [-v, -variable \"variable-name\"] [-stdin] [-t, -text \"string\"] [\"string\"]\n\n\t#* Return if no arguments is given\n\tif [[ -z $1 ]]; then return; fi\n\n\t#* Just echo and return if only one argument and not a valid option\n\tif [[ $# -eq 1 && ${1::1} != \"-\"  ]]; then echo -en \"$1\"; return; fi\n\n\tlocal effect color add_command text text2 esc center clear fgc bgc fg_bg_div tmp tmp_len bold italic custom_font val var out ext_var hex=\"16#\"\n\tlocal justify_left justify_right justify_center repeat r_tmp trans\n\n\n\t#* Loop function until we are out of arguments\n\tuntil (($#==0)); do\n\n\t\t#* Argument parsing\n\t\tuntil (($#==0)); do\n\t\t\tcase $1 in\n\t\t\t\t-t|-text) text=\"$2\"; shift 2; break;;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? String to print\n\t\t\t\t-stdin) text=\"$(</dev/stdin)\"; shift; break;;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Print from stdin\n\t\t\t\t-fg|-foreground)\t#? Set text foreground color, accepts either 6 digit hexadecimal \"#RRGGBB\", 2 digit hex (greyscale) or decimal RGB \"<0-255> <0-255> <0-255>\"\n\t\t\t\t\tif [[ ${2::1} == \"#\" ]]; then\n\t\t\t\t\t\tval=${2//#/}\n\t\t\t\t\t\tif [[ ${#val} == 6 ]]; then fgc=\"\\e[38;2;$((${hex}${val:0:2}));$((${hex}${val:2:2}));$((${hex}${val:4:2}))m\"; shift\n\t\t\t\t\t\telif [[ ${#val} == 2 ]]; then fgc=\"\\e[38;2;$((${hex}${val:0:2}));$((${hex}${val:0:2}));$((${hex}${val:0:2}))m\"; shift\n\t\t\t\t\t\tfi\n\t\t\t\t\telif is_int \"${@:2:3}\"; then fgc=\"\\e[38;2;$2;$3;$4m\"; shift 3\n\t\t\t\t\tfi\n\t\t\t\t\t;;\n\t\t\t\t-bg|-background)\t#? Set text background color, accepts either 6 digit hexadecimal \"#RRGGBB\", 2 digit hex (greyscale) or decimal RGB \"<0-255> <0-255> <0-255>\"\n\t\t\t\t\tif [[ ${2::1} == \"#\" ]]; then\n\t\t\t\t\t\tval=${2//#/}\n\t\t\t\t\t\tif [[ ${#val} == 6 ]]; then bgc=\"\\e[48;2;$((${hex}${val:0:2}));$((${hex}${val:2:2}));$((${hex}${val:4:2}))m\"; shift\n\t\t\t\t\t\telif [[ ${#val} == 2 ]]; then bgc=\"\\e[48;2;$((${hex}${val:0:2}));$((${hex}${val:0:2}));$((${hex}${val:0:2}))m\"; shift\n\t\t\t\t\t\tfi\n\t\t\t\t\telif is_int \"${@:2:3}\"; then bgc=\"\\e[48;2;$2;$3;$4m\"; shift 3\n\t\t\t\t\tfi\n\t\t\t\t\t;;\n\t\t\t\t-c|-center) center=1;;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Center text horizontally on screen\n\t\t\t\t-rs|-reset) effect=\"0${effect}${theme[main_bg]}\";;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Reset text colors and effects\n\t\t\t\t-b|-bold) effect=\"${effect}${effect:+;}1\"; bold=1;;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Enable bold text\n\t\t\t\t+b|+bold) effect=\"${effect}${effect:+;}21\"; bold=0;;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Disable bold text\n\t\t\t\t-da|-dark) effect=\"${effect}${effect:+;}2\";;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Enable dark text\n\t\t\t\t+da|+dark) effect=\"${effect}${effect:+;}22\";;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Disable dark text\n\t\t\t\t-i|-italic) effect=\"${effect}${effect:+;}3\"; italic=1;;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Enable italic text\n\t\t\t\t+i|+italic) effect=\"${effect}${effect:+;}23\"; italic=0;;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Disable italic text\n\t\t\t\t-ul|-underline) effect=\"${effect}${effect:+;}4\";;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Enable underlined text\n\t\t\t\t+ul|+underline) effect=\"${effect}${effect:+;}24\";;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Disable underlined text\n\t\t\t\t-bl|-blink) effect=\"${effect}${effect:+;}5\";;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Enable blinking text\n\t\t\t\t+bl|+blink) effect=\"${effect}${effect:+;}25\";;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Disable blinking text\n\t\t\t\t-f|-font) if [[ $2 =~ ^(sans-serif|script|fraktur|monospace|double-struck)$ ]]; then custom_font=\"$2\"; shift; fi;;\t\t\t#? Set custom font\n\t\t\t\t-m|-move) add_command=\"${add_command}\\e[${2};${3}f\"; shift 2;;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Move to postion \"LINE\" \"COLUMN\"\n\t\t\t\t-l|-left) add_command=\"${add_command}\\e[${2}D\"; shift;;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Move left x columns\n\t\t\t\t-r|-right) add_command=\"${add_command}\\e[${2}C\"; shift;;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Move right x columns\n\t\t\t\t-u|-up) add_command=\"${add_command}\\e[${2}A\"; shift;;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Move up x lines\n\t\t\t\t-d|-down) add_command=\"${add_command}\\e[${2}B\"; shift;;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Move down x lines\n\t\t\t\t-jl|-justify-left) justify_left=\"${2}\"; shift;;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Justify string left within given width\n\t\t\t\t-jr|-justify-right) justify_right=\"${2}\"; shift;;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Justify string right within given width\n\t\t\t\t-jc|-justify-center) justify_center=\"${2}\"; shift;;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Justify string center within given width\n\t\t\t\t-rp|-repeat) repeat=${2}; shift;;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Repeat next string x number of times\n\t\t\t\t-sc|-save) add_command=\"\\e[s${add_command}\";;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Save cursor position\n\t\t\t\t-rc|-restore) add_command=\"${add_command}\\e[u\";;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Restore cursor position\n\t\t\t\t-trans) trans=1;;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Make whitespace transparent\n\t\t\t\t-v|-variable) local -n var=$2; ext_var=1; shift;;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Send output to a variable, appending if not unset\n\t\t\t\t*) text=\"$1\"; shift; break;;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t#? Assumes text string if no argument is found\n\t\t\tesac\n\t\t\tshift\n\t\tdone\n\n\t\t#* Repeat string if repeat is enabled\n\t\tif [[ -n $repeat ]]; then\n\t\t\tprintf -v r_tmp \"%${repeat}s\" \"\"\n\t\t\ttext=\"${r_tmp// /$text}\"\n\t\tfi\n\n\t\t#* Set correct placement for screen centered text\n\t\tif ((center==1 & ${#text}>0 & ${#text}<tty_width-4)); then\n\t\t\tadd_command=\"${add_command}\\e[${tty_width}D\\e[$(( (tty_width/2)-(${#text}/2) ))C\"\n\t\tfi\n\n\t\t#* Convert text string to custom font if set and remove non working effects\n\t\tif [[ -n $custom_font ]]; then\n\t\t\tunset effect\n\t\t\ttext=$(set_font \"${custom_font}${bold:+\" bold\"}${italic:+\" italic\"}\" \"${text}\")\n\t\tfi\n\n\t\t#* Set text justification if set\n\t\tif [[ -n $justify_left ]] && ((${#text}<justify_left)); then\n\t\t\tprintf -v text \"%s%$((justify_left-${#text}))s\" \"${text}\" \"\"\n\t\telif [[ -n $justify_right ]] && ((${#text}<justify_right)); then\n\t\t\tprintf -v text \"%$((justify_right-${#text}))s%s\" \"\" \"${text}\"\n\t\telif [[ -n $justify_center ]] && ((${#text}<justify_center)); then\n\t\t\tprintf -v text \"%$(( (justify_center/2)-(${#text}/2) ))s%s\" \"\" \"${text}\"\n\t\t\tprintf -v text \"%s%-$((justify_center-${#text}))s\" \"${text}\" \"\"\n\t\tfi\n\n\t\tif [[ -n $trans ]]; then\n\t\t\ttext=\"${text// /'\\e[1C'}\"\n\t\tfi\n\n\t\t#* Create text string\n\t\tif [[ -n $effect ]]; then effect=\"\\e[${effect}m\"; fi\n\t\tout=\"${out}${add_command}${effect}${bgc}${fgc}${text}\"\n\t\tunset add_command effect fgc bgc center justify_left justify_right justify_center custom_font text repeat trans justify\n\tdone\n\n\t#* Print the string to stdout if variable out hasn't been set\n\tif [[ -z $ext_var ]]; then echo -en \"$out\"\n\telse var=\"${var}${out}\"; fi\n\n}\n\ncollect_cpu() { #? Collects cpu stats from /proc/stat and compares with previously collected sample to get cpu usage\n\t\t\t\t#? Returns cpu usage in array \"cpu_usage\", index 0 is usage for all threads, following indices corresponds to thread usage in multicore/hyperthreading cpus\n\tlocal freq thread i threads=${cpu[threads]}\n\tlocal -a stat_array stat_input\n\n\t#* Get values from /proc/stat or psutil, compare to get cpu usage\n\tif [[ $use_psutil == true ]]; then\n\t\tlocal -a usage_arr\n\t\tlocal x=1\n\t\tpy_command -a usage_arr \"get_cpu_usage()\"\n\t\tcpu_usage[0]=${usage_arr[0]}\n\t\tfor thread in ${usage_arr[@]:1}; do\n\t\t\tcpu_usage[$((x++))]=$thread\n\t\tdone\n\t\tpy_command -v cpu[freq] \"get_cpu_freq()\"\n\t\tpy_command -v cpu[uptime] \"get_uptime()\"\n\t\tpy_command -v cpu[load_avg] \"get_load_avg()\"\n\telse\n\t\treadarray -t stat_input </proc/stat\n\t\tthread=0\n\t\twhile ((thread<threads+1)); do\n\t\t\tstat_array=(${stat_input[thread]})\n\t\t\tcpu[new_${thread}]=$((stat_array[1]+stat_array[2]+stat_array[3]+stat_array[4]))\n\t\t\tcpu[idle_new_${thread}]=${stat_array[4]}\n\t\t\tif [[ -n ${cpu[old_${thread}]} && -n ${cpu[idle_new_${thread}]} && ${cpu[old_${thread}]} -ne ${cpu[new_${thread}]} ]]; then\n\t\t\t\tcpu_usage[${thread}]=\"$(( ( 100*(${cpu[old_${thread}]}-${cpu[new_${thread}]}-${cpu[idle_old_${thread}]}+${cpu[idle_new_${thread}]}) ) / (${cpu[old_${thread}]}-${cpu[new_${thread}]}) ))\"\n\t\t\tfi\n\t\t\tcpu[old_${thread}]=${cpu[new_${thread}]}\n\t\t\tcpu[idle_old_${thread}]=${cpu[idle_new_${thread}]}\n\t\t\t((++thread))\n\t\tdone\n\tfi\n\n\t#* Copy cpu usage for cpu package and cores to cpu history arrays and trim earlier entries\n\tif ((${#cpu_history[@]}>tty_width*4)); then\n\t\tcpu_history=( \"${cpu_history[@]:$((tty_width*2))}\" \"${cpu_usage[0]}\")\n\telse\n\t\tcpu_history+=(\"${cpu_usage[0]}\")\n\tfi\n\n\tfor((i=1;i<=threads;i++)); do\n\t\tlocal -n cpu_core_history=\"cpu_core_history_$i\"\n\t\tif ((${#cpu_core_history[@]}>40)); then\n\t\t\tcpu_core_history=( \"${cpu_core_history[@]:20}\" \"${cpu_usage[$i]}\")\n\t\telse\n\t\t\tcpu_core_history+=(\"${cpu_usage[$i]}\")\n\t\tfi\n\tdone\n\n\t#* Get current cpu frequency from \"/proc/cpuinfo\" and convert to appropriate unit\n\tif [[ $use_psutil == false && -z ${cpu[no_cpu_info]} ]] && ! get_value -v 'cpu[freq]' -sf \"/proc/cpuinfo\" -k \"cpu MHz\" -i; then\n\t\tcpu[no_cpu_info]=1\n\tfi\n\n\t#* If getting cpu frequency from \"proc/cpuinfo\" was unsuccessfull try \"/sys/devices/../../scaling_cur_freq\"\n\tif [[ $use_psutil == false && -n ${cpu[no_cpu_info]} && -e \"/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq\" ]]; then\n\t\tget_value -v 'cpu[freq]' -sf \"/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq\" -i\n\t\tprintf -v 'cpu[freq]' \"%.0f0\" \"${cpu[freq]}e-4\"\n\tfi\n\n\tif ((${#cpu[freq]}>3)); then cpu[freq_string]=\"${cpu[freq]::-3}.${cpu[freq]:(-3):1} GHz\"\n\telif ((${#cpu[freq]}>1)); then cpu[freq_string]=\"${cpu[freq]} MHz\"\n\telse cpu[freq_string]=\"\"; fi\n\n\t#* Get load average and uptime from uptime command\n\tif [[ $use_psutil == false ]]; then\n\t\tlocal uptime_var\n\t\tread -r uptime_var < <(uptime 2>/dev/null || true)\n\t\tcpu[load_avg]=\"${uptime_var#*average: }\"\n\t\tcpu[load_avg]=\"${cpu[load_avg]//,/}\"\n\t\tcpu[uptime]=\"${uptime_var#*up }\"\n\t\tcpu[uptime]=\"${cpu[uptime]%%,  *}\"\n\tfi\n\n\t#* Collect cpu temps if enabled\n\tif [[ $check_temp == true ]]; then collect_cpu_temps; fi\n}\n\ncollect_cpu_temps() { #? Collect cpu temperatures\n\tlocal unit c div threads=${cpu[threads]} sens_var i it ccd_value breaking core_value misc_var\n\tlocal -a ccd_array core_array\n\n\t#* Fetch output from \"sensors\" command or psutil to a variable\n\tif [[ $sensor_comm == \"psutil\" ]]; then\n\t\tif ! py_command -vn sens_var \"get_sensors()\"; then\n\t\t\tif command -v sensors >/dev/null 2>&1; then sensor_comm=\"sensors\"\n\t\t\telse sensor_comm=\"\"; check_temp=\"false\"; resized=1; return; fi\n\t\tfi\n\tfi\n\tif [[ $sensor_comm == \"sensors\" ]]; then\n\t\tif [[ $use_psutil == true ]]; then\n\t\t\tpy_command -vn sens_var \"get_cmd_out('sensors 2>/dev/null')\"\n\t\telse\n\t\t\tread -rd '' sens_var < <(sensors 2>/dev/null || true) || true\n\t\tfi\n\telif [[ $sensor_comm != \"sensors\" && $sensor_comm != \"psutil\" ]]; then\n\t\tif [[ $use_psutil == true ]]; then\n\t\t\tpy_command -v misc_var \"get_cmd_out('${sensor_comm} measure_temp 2>/dev/null')\"\n\t\telse\n\t\t\tread -r misc_var < <(${sensor_comm} measure_temp 2>/dev/null ||true)\n\t\tfi\n\tfi\n\n\t#* Get CPU package temp for intel cpus\n\tif get_value -v 'cpu[temp_0]' -sv \"sens_var\" -k \"Package*:\" -mk 1 || get_value -v 'cpu[temp_0]' -sv \"sens_var\" -k \"Core 0:\" -mk 1; then\n\t\t#* If successful get temperature unit, convert temp to integer and get high and crit\n\t\tcpu[temp_unit]=\"${cpu[temp_0]:(-2)}\"; cpu[temp_0]=\"${cpu[temp_0]%.*}\"; if [[ ${cpu[temp_0]::1} == \"+\" ]]; then cpu[temp_0]=\"${cpu[temp_0]#+}\"; fi\n\t\tif [[ -z ${cpu[temp_high]} ]]; then\n\t\t\tif ! get_value -v 'cpu[temp_high]' -sv \"sens_var\" -k \"Package*high =\" -m 2 -r \"[^0-9.]\" -b -i; then cpu[temp_high]=\"85\"; cpu[temp_crit]=$((cpu[temp_high]+10))\n\t\t\telse get_value -v 'cpu[temp_crit]' -sv \"sens_var\" -k \"Package*crit =\" -m 2 -r \"[^0-9.]\" -b -i; fi\n\t\tfi\n\n\t\t#* Get core temps\n\t\ti=0\n\t\twhile get_value -v \"core_value\" -sv \"sens_var\" -k \"Core ${i}:\" -mk 1 -r \"[^0-9.]\" -b -i && ((i<=threads)); do core_array+=(\"$core_value\"); ((++i)) ; done\n\n\t\tif [[ -z ${core_array[0]} ]]; then core_array=(\"${cpu[temp_0]}\"); fi\n\n\t\tif ((${#core_array[@]}<threads/2)); then\n\t\t\tfor((i=${#core_array[@]};i<threads/2;i++)); do\n\t\t\t\tcore_array+=(\"${cpu[temp_0]}\")\n\t\t\tdone\n\t\tfi\n\n\t\t#* Copy core values to hyperthreading cores\n\t\ti=1\n\t\tfor core_value in \"${core_array[@]}\"; do\n\t\t\tcpu[temp_$((i))]=\"${core_value}\"\n\t\t\tcpu[temp_$((threads/2+i))]=\"${core_value}\"\n\t\t\t((i++))\n\t\tdone\n\n\t#* Get CPU package temp for amd ryzen cpus\n\telif get_value -v 'cpu[temp_0]' -sv \"sens_var\" -k \"Tdie:\" -mk 1; then\n\t\t#* If successful get temperature unit, convert temp to integer and get high\n\t\tcpu[temp_unit]=\"${cpu[temp_0]:(-2)}\"; cpu[temp_0]=\"${cpu[temp_0]%.*}\"; if [[ ${cpu[temp_0]::1} == \"+\" ]]; then cpu[temp_0]=\"${cpu[temp_0]#+}\"; fi\n\t\tif [[ -z ${cpu[temp_high]} ]]; then\n\t\t\tif ! get_value -v 'cpu[temp_high]' -sv \"sens_var\" -k \"Tdie*high =\" -m 2 -r \"[^0-9.]\" -b -i; then cpu[temp_high]=\"85\"; fi\n\t\t\tcpu[temp_crit]=$((cpu[temp_high]+10))\n\t\tfi\n\n\t\t#* Get ccd module temps\n\t\ti=1\n\t\twhile get_value -v \"ccd_value\" -sv \"sens_var\" -k \"Tccd${i}:\" -mk 1 -r \"[^0-9.]\" -b -i && ((i<=threads)); do ccd_array+=(\"$ccd_value\"); ((i++)) ; done\n\n\t\tif [[ -z ${ccd_array[0]} ]]; then ccd_array=(\"${cpu[temp_0]}\"); fi\n\n\t\t#* Copy ccd values to cores in each ccd\n\t\tz=1\n\t\tfor ccd_value in \"${ccd_array[@]}\"; do\n\t\t\tfor((i=0;i<threads/${#ccd_array[@]};i++)); do\n\t\t\t\tcpu[temp_$((z+i))]=\"${ccd_value}\"\n\t\t\tdone\n\t\t\tz=$((z+i))\n\t\tdone\n\n\t#* Get CPU package temp for Rapberry Pi cpus and for OSX\n\telif [[ $sensor_comm != \"sensors\" && -n ${misc_var} ]]; then\n\t\tcpu[temp_0]=\"${misc_var#temp=}\"\n\t\tcpu[temp_unit]=\"°${cpu[temp_0]:(-1)}\"; cpu[temp_0]=${cpu[temp_0]%%.*}; if [[ ${cpu[temp_0]::1} == \"+\" ]]; then cpu[temp_0]=${cpu[temp_0]#+}; fi\n\t\tif [[ -z ${cpu[temp_high]} ]]; then\n\t\t\tcpu[temp_high]=\"75\"; cpu[temp_crit]=$((cpu[temp_high]+10))\n\t\tfi\n\n\t\t#* Copy cpu temp to cores\n\t\tfor((i=1;i<=threads;i++)); do\n\t\t\tcpu[temp_${i}]=\"${cpu[temp_0]}\"\n\t\tdone\n\n\t#* If unsuccessful turn off temperature checking\n\telse\n\t\tcheck_temp=\"false\"\n\t\tresized=1\n\tfi\n\n\tif [[ $check_temp == true ]]; then\n\t\tlocal tmp_temp\n\t\tfor((i=0;i<=threads;i++)); do\n\t\t\ttmp_temp=\"$(( (${cpu[temp_${i}]}-20)*100/(cpu[temp_high]-20) ))\"\n\t\t\tif ((tmp_temp>100)); then tmp_temp=100; elif ((tmp_temp<0)); then tmp_temp=0; fi\n\t\t\tlocal -n cpu_temp_history=\"cpu_temp_history_$i\"\n\t\t\tif ((${#cpu_temp_history[@]}>20)); then\n\t\t\t\tcpu_temp_history=( \"${cpu_temp_history[@]:10}\" \"${tmp_temp}\")\n\t\t\telse\n\t\t\t\tcpu_temp_history+=(\"${tmp_temp}\")\n\t\t\tfi\n\t\tdone\n\tfi\n}\n\ncollect_mem() { #? Collect memory information from \"/proc/meminfo\"\n\t((++mem[counter]))\n\n\t#if [[ $use_psutil == false ]] && ((mem[counter]<4)); then return; fi\n\tif ((mem[counter]<4)); then return; fi\n\tmem[counter]=0\n\n\tlocal i tmp value array mem_info height=$((box[mem_height]-2)) skip filter_value\n\tlocal -a mem_array swap_array available=(\"mem\")\n\tunset 'mem[total]'\n\n\t#* Get memory and swap information from \"/proc/meminfo\" or psutil and calculate percentages\n\tif [[ $use_psutil == true ]]; then\n\t\tlocal pymemout\n\n\t\tpy_command -v pymemout \"get_mem()\" || return\n\t\tread mem[total] mem[free] mem[available] mem[cached] swap[total] swap[free] <<<\"$pymemout\"\n\n\t\tif [[ -z ${mem[total]} ]]; then return; fi\n\t\tif [[ -n ${swap[total]} ]] && ((swap[total]>0)); then\n\t\t\tswap[free_percent]=$((swap[free]*100/swap[total]))\n\t\t\tswap[used]=$((swap[total]-swap[free]))\n\t\t\tswap[used_percent]=$((swap[used]*100/swap[total]))\n\t\t\tavailable+=(\"swap\")\n\t\telse\n\t\t\tunset swap_on\n\t\tfi\n\telse\n\t\tread -rd '' mem_info </proc/meminfo ||true\n\t\tget_value -v 'mem[total]' -sv \"mem_info\" -k \"MemTotal:\" -i\n\t\tget_value -v 'mem[free]' -sv \"mem_info\" -k \"MemFree:\" -i\n\t\tif ! get_value -v 'mem[available]' -sv \"mem_info\" -k \"MemAvailable:\" -i; then\n\t\t\tget_value -v 'mem[available]' -sv \"mem_info\" -k \"Inactive:\" -i\n\t\t\tmem[available]=$((mem[available]+mem[free]))\n\t\tfi\n\t\tget_value -v 'mem[cached]' -sv \"mem_info\" -k \"Cached:\" -i\n\tfi\n\n\tmem[available_percent]=$((mem[available]*100/mem[total]))\n\tmem[used]=$((mem[total]-mem[available]))\n\tmem[used_percent]=$((mem[used]*100/mem[total]))\n\tmem[free_percent]=$((mem[free]*100/mem[total]))\n\tmem[cached_percent]=$((mem[cached]*100/mem[total]))\n\n\tif [[ $use_psutil == false ]] && get_value -v swap[total] -sv \"mem_info\" -k \"SwapTotal:\" -i && ((swap[total]>0)); then\n\t\tget_value -v 'swap[free]' -sv \"mem_info\" -k \"SwapFree:\" -i\n\t\tswap[free_percent]=$((swap[free]*100/swap[total]))\n\n\t\tswap[used]=$((swap[total]-swap[free]))\n\t\tswap[used_percent]=$((swap[used]*100/swap[total]))\n\n\t\tavailable+=(\"swap\")\n\telif [[ $use_psutil == false ]]; then\n\t\tunset swap_on\n\tfi\n\n\t#* Convert values to floating point and humanize\n\tfor array in ${available[@]}; do\n\t\tfor value in total used free available cached; do\n\t\t\tif [[ $array == \"swap\" && $value == \"available\" ]]; then break 2; fi\n\t\t\tlocal -n this_value=\"${array}[${value}]\" this_string=\"${array}[${value}_string]\"\n\t\t\tfloating_humanizer -v this_string -s 1 -B \"${this_value}\"\n\t\tdone\n\tdone\n\n\t#* Get disk information\n\tlocal df_line line_array dev_path dev_name iostat_var disk_read disk_write disk_io_string df_count=0 filtering psutil_on\n\tlocal -a device_array iostat_array df_array\n\tunset 'disks_free[@]' 'disks_used[@]' 'disks_used_percent[@]' 'disks_total[@]' 'disks_name[@]' 'disks_free_percent[@]' 'disks_io[@]'\n\tif [[ -n $psutil_disk_fail ]]; then psutil_on=\"false\"; else psutil_on=\"$use_psutil\"; fi\n\tif [[ $psutil_on == true ]]; then\n\t\tif [[ -n $disks_filter ]]; then filtering=\", filtering='${disks_filter}'\"; fi\n\t\tif ! py_command -a df_array \"get_disks(exclude='squashfs'${filtering})\"; then psutil_disk_fail=1; psutil_on=\"false\"; fi\n\tfi\n\tif [[ $psutil_on == false ]]; then\n\t\treadarray -t df_array < <(${df} -x squashfs -x tmpfs -x devtmpfs -x overlay -x 9p 2>/dev/null || true)\n\tfi\n\tfor df_line in \"${df_array[@]:1}\"; do\n\t\tline_array=(${df_line})\n\t\tif ! is_int \"${line_array[1]}\" || ((line_array[1]<=0)); then continue; fi\n\n\t\tif [[ $psutil_on == false && ${line_array[5]} == \"/\" ]]; then disks_name+=(\"root\")\n\t\telif [[ $psutil_on == false ]]; then disks_name+=(\"${line_array[5]##*/}\")\n\t\telif [[ $psutil_on == true ]]; then disks_name+=(\"${line_array[*]:7}\"); fi\n\n\t\t#* Filter disks showed if $disks_filter is set\n\t\tif [[ $psutil_on == false && -n $disks_filter ]]; then\n\t\t\tunset found\n\t\t\tfor filter_value in ${disks_filter}; do\n\t\t\t\tif [[ $filter_value == \"${disks_name[-1]}\" ]]; then found=1; fi\n\t\t\tdone\n\t\tfi\n\n\t\tif [[ $psutil_on == true || -z $disks_filter || -n $found ]]; then\n\t\t\tdisks_total+=(\"$(floating_humanizer -s 1 -B ${line_array[1]})\")\n\t\t\tdisks_used+=(\"$(floating_humanizer -s 1 -B ${line_array[2]})\")\n\t\t\tdisks_used_percent+=(\"${line_array[4]%'%'}\")\n\t\t\tdisks_free+=(\"$(floating_humanizer -s 1 -B ${line_array[3]})\")\n\t\t\tdisks_free_percent+=(\"$((100-${line_array[4]%'%'}))\")\n\n\t\t\t#* Get read/write stats for disk from iostat or psutil if available\n\t\t\tif [[ $psutil_on == true || -n $has_iostat ]]; then\n\t\t\t\tunset disk_io_string\n\t\t\t\tdev_name=\"${line_array[0]##*/}\"\n\t\t\t\tif [[ $psutil_on == false && ${dev_name::2} == \"md\" ]]; then dev_name=\"${dev_name::3}\"; fi\n\t\t\t\tif [[ $psutil_on == false ]]; then\n\t\t\t\t\tunset iostat_var 'iostat_array[@]'\n\t\t\t\t\tdev_path=\"${line_array[0]%${dev_name}}\"\n\t\t\t\t\tread -r iostat_var < <(iostat -dkz \"${dev_path}${dev_name}\" | tail -n +4)\n\t\t\t\t\tiostat_array=(${iostat_var})\n\t\t\t\tfi\n\t\t\t\tif [[ $psutil_on == true || -n ${iostat_var} ]]; then\n\n\t\t\t\t\tif [[ $psutil_on == true ]]; then\n\t\t\t\t\t\tdisk_read=${line_array[5]}\n\t\t\t\t\t\tdisk_write=${line_array[6]}\n\t\t\t\t\telse\n\t\t\t\t\t\tdisk_read=$((iostat_array[-2]-${disks[${dev_name}_read]:-${iostat_array[-2]}}))\n\t\t\t\t\t\tdisk_write=$((iostat_array[-1]-${disks[${dev_name}_write]:-${iostat_array[-1]}}))\n\t\t\t\t\tfi\n\n\t\t\t\t\tif ((box[m_width2]>25)); then\n\t\t\t\t\t\tif ((disk_read>0)); then disk_io_string=\"▲$(floating_humanizer -s 1 -short -B ${disk_read}) \"; fi\n\t\t\t\t\t\tif ((disk_write>0)); then disk_io_string+=\"▼$(floating_humanizer -s 1 -short -B ${disk_write})\"; fi\n\t\t\t\t\telif ((disk_read+disk_write>0)); then\n\t\t\t\t\t\tdisk_io_string+=\"▼▲$(floating_humanizer -s 1 -short -B $((disk_read+disk_write)))\"\n\t\t\t\t\tfi\n\n\t\t\t\t\tif [[ $psutil_on == false ]]; then\n\t\t\t\t\t\tdisks[${dev_name}_read]=\"${iostat_array[-2]}\"\n\t\t\t\t\t\tdisks[${dev_name}_write]=\"${iostat_array[-1]}\"\n\t\t\t\t\tfi\n\t\t\t\tfi\n\t\t\t\tdisks_io+=(\"${disk_io_string:-0}\")\n\t\t\tfi\n\t\telse\n\t\t\tunset 'disks_name[-1]'\n\t\t\tdisks_name=(\"${disks_name[@]}\")\n\t\tfi\n\n\t\tif ((${#disks_name[@]}>=height/2)); then break; fi\n\n\tdone\n\n\n}\n\ncollect_processes() { #? Collect process information and calculate accurate cpu usage\n\tif [[ $use_psutil == true ]]; then collect_processes_psutil $1; return; fi\n\tlocal argument=\"$1\"\n\tif [[ -n $skip_process_draw && $argument != \"now\" ]]; then return; fi\n\tlocal width=${box[processes_width]} height=${box[processes_height]} format_args format_cmd readline sort symbol=\"▼\" cpu_title options pid_string tmp selected\n\tlocal tree tree_compare1 tree_compare2 tree_compare3 no_core_divide pids\n\tlocal -a grep_array saved_proc_array\n\n\tif [[ $argument == \"now\" ]]; then skip_process_draw=1; fi\n\n\tif [[ -n ${proc[reverse]} ]]; then symbol=\"▲\"; fi\n\tcase ${proc_sorting} in\n\t\t\"pid\") selected=\"Pid:\"; sort=\"pid\";;\n\t\t\"program\") selected=\"Program:\"; sort=\"comm\";;\n\t\t\"arguments\") selected=\"Arguments:\"; sort=\"args\";;\n\t\t\"threads\") selected=\"Threads:\"; sort=\"nlwp\";;\n\t\t\"user\") selected=\"User:\"; sort=\"euser\";;\n\t\t\"memory\") selected=\"Mem%\"; sort=\"pmem\";;\n\t\t\"cpu lazy\"|\"cpu responsive\") sort=\"pcpu\"; selected=\"Cpu%\";;\n\tesac\n\n\tif [[ $proc_tree == true ]]; then tree=\"Tree:\"; fi\n\tif [[ $proc_per_core == true ]]; then no_core_divide=\"1\"; fi\n\n\t#* Collect output from ps command to array\n\tif ((width>60)) && [[ $proc_tree != true ]] ; then format_args=\",args:$(( width-(47+proc[pid_len]) ))=Arguments:\"; format_cmd=15\n\telse format_cmd=$(( width-(31+proc[pid_len]) )); fi\n\tsaved_proc_array=(\"${proc_array[@]}\")\n\tunset 'proc_array[@]' 'pid_array[@]'\n\n\tif ((proc[detailed]==0)) && [[ -n ${proc[detailed_name]} ]]; then\n\t\tunset 'proc[detailed_name]' 'proc[detailed_killed]' 'proc[detailed_cpu_int]' 'proc[detailed_cmd]'\n\t\tunset 'proc[detailed_mem]' 'proc[detailed_mem_int]' 'proc[detailed_user]' 'proc[detailed_threads]'\n\t\tunset 'detail_graph[@]' 'detail_mem_graph' 'detail_history[@]' 'detail_mem_history[@]'\n\t\tunset 'proc[detailed_runtime]' 'proc[detailed_mem_string]' 'proc[detailed_parent_pid]' 'proc[detailed_parent_name]'\n\tfi\n\n\tunset 'proc[detailed_cpu]'\n\n\tif [[ -z $filter ]]; then\n\t\toptions=\"-t\"\n\tfi\n\n\treadarray ${options} proc_array < <(ps ax${tree:+f} -o pid:${proc[pid_len]}=Pid:,comm:${format_cmd}=${tree:-Program:}${format_args},nlwp:3=Tr:,euser:6=User:,pmem=Mem%,pcpu:10=Cpu% --sort ${proc[reverse]:--}${sort})\n\n\tproc_array[0]=\"${proc_array[0]/      Tr:/ Threads:}\"\n\tproc_array[0]=\"${proc_array[0]/ ${selected}/${symbol}${selected}}\"\n\n\tif [[ -n $filter ]]; then\n\t\tgrep_array[0]=\"${proc_array[0]}\"\n\t\treadarray -O 1 -t grep_array < <(echo -e \" ${proc_array[*]:1}\" | grep -e \"${filter}\" ${proc[detailed_pid]:+-e ${proc[detailed_pid]}} | cut -c 2- || true)\n\t\tproc_array=(\"${grep_array[@]}\")\n\tfi\n\n\n\t#* Get accurate cpu usage by fetching and comparing values in /proc/\"pid\"/stat\n\tlocal operations operation utime stime count time_elapsed cpu_percent_string rgb=231 step add proc_out tmp_value_array i pcpu_usage cpu_int tmp_percent breaking\n\tlocal -a cpu_percent statfile work_array\n\n\t#* Timestamp the values in milliseconds to accurately calculate cpu usage\n\tget_ms proc[new_timestamp]\n\n\tfor readline in \"${proc_array[@]:1}\"; do\n\t\t((++count))\n\n\t\tif ((count==height-3 & breaking==0)); then\n\t\t\tif [[ -n $filter || $proc_sorting != \"cpu lazy\" || ${proc[selected]} -gt 0 || ${proc[start]} -gt 1 || ${proc_reversed} == true ]]; then :\n\t\t\telse breaking=1; fi\n\t\tfi\n\n\t\t#if get_key -save && [[ ${#saved_key[@]} -gt 0 ]]; then proc_array=(\"${saved_proc_array[@]}\"); return; fi\n\n\t\tif ((breaking==2)); then\n\t\t\twork_array=(${proc_array[-1]})\n\t\telse\n\t\t\twork_array=(${readline})\n\t\tfi\n\n\t\tpid=\"${work_array[0]}\"\n\t\tpcpu_usage=\"${work_array[-1]}\"\n\n\t\t#* If showing tree structure replace slashes and pipes with actual lines and terminate them at the correct places\n\t\tif [[ $proc_tree == true ]]; then\n\t\t\ttree_compare1=\"${proc_array[$((count+1))]%'\\_'*}\"\n\t\t\ttree_compare2=\"${proc_array[count]%'\\_'*}\"\n\t\t\ttree_compare3=\"${proc_array[$((count+1))]%'|'*}\"\n\t\t\tproc_array[count]=\"${proc_array[count]//'|'/│}\"\n\t\t\tproc_array[count]=\"${proc_array[count]//'\\_'/└─}\"\n\t\t\tif ((count<${#proc_array[@]}-1)) && [[ ${#tree_compare1} -eq ${#tree_compare2} || ${#tree_compare2} -eq ${#tree_compare3} ]]; then\n\t\t\t\tproc_array[count]=\"${proc_array[count]//'└'/├}\"\n\t\t\tfi\n\t\tfi\n\n\t\tpid_history[${pid}]=\"1\"\n\n\t\tif [[ -n $filter || $proc_sorting == \"cpu responsive\" ]] && [[ ${proc_array[count]:${proc[pid_len]}:1} != \" \" ]]; then\n\t\t\tunset pid_string\n\t\t\tprintf -v pid_string \"%${proc[pid_len]}s\" \"${pid}\"\n\t\t\tproc_array[count]=\"${pid_string}${proc_array[count]#*${pid}}\"\n\t\tfi\n\n\t\tif [[ -r \"/proc/${pid}/stat\" ]] && read -ra statfile </proc/${pid}/stat 2>/dev/null; then\n\n\t\t\tutime=${statfile[13]}\n\t\t\tstime=${statfile[14]}\n\n\t\t\tproc[new_${pid}_ticks]=$((utime+stime))\n\n\n\t\t\tif [[ -n ${proc[old_${pid}_ticks]} ]]; then\n\n\t\t\t\ttime_elapsed=$((proc[new_timestamp]-proc[old_timestamp]))\n\n\t\t\t\t#* Calculate current cpu usage for process, * 1000 (for conversion from ms to seconds) * 1000 (for conversion to floating point)\n\t\t\t\tcpu_percent[count]=$(( ( ( ${proc[new_${pid}_ticks]}-${proc[old_${pid}_ticks]} ) * 1000 * 1000 ) / ( cpu[hz]*time_elapsed*${no_core_divide:-${cpu[threads]}} ) ))\n\n\t\t\t\tif ((cpu_percent[count]<0)); then cpu_percent[count]=0\n\t\t\t\telif [[ -z $no_core_divide ]] && ((cpu_percent[count]>1000)); then cpu_percent[count]=1000; fi\n\n\t\t\t\tif ((${#cpu_percent[count]}<=3)); then\n\t\t\t\t\tprintf -v cpu_percent_string \"%01d%s\" \"${cpu_percent[count]::-1}\" \".${cpu_percent[count]:(-1)}\"\n\t\t\t\telse\n\t\t\t\t\tcpu_percent_string=${cpu_percent[count]::-1}\n\t\t\t\tfi\n\n\t\t\t\tprintf -v cpu_percent_string \"%5s\" \"${cpu_percent_string::4}\"\n\n\t\t\t\tproc_array[count]=\"${proc_array[count]::-5}${cpu_percent_string}\"\n\n\n\t\t\t\tpid_graph=\"pid_${pid}_graph\"\n\t\t\t\tlocal -n pid_count=\"pid_${pid}_count\"\n\n\t\t\t\tprintf -v cpu_int \"%01d\" \"${cpu_percent[count]::-1}\"\n\n\t\t\t\t#* Get info for detailed box if enabled\n\t\t\t\tif [[ ${pid} == \"${proc[detailed_pid]}\" ]]; then\n\t\t\t\t\tif [[ -z ${proc[detailed_name]} ]]; then\n\t\t\t\t\t\tlocal get_mem mem_string cmdline=\"\"\n\t\t\t\t\t\tlocal -a det_array\n\t\t\t\t\t\tread -r proc[detailed_name] </proc/${pid}/comm ||true\n\t\t\t\t\t\tmapfile -d $'\\0' -n 0 cmdline </proc/${pid}/cmdline ||true\n\t\t\t\t\t\tproc[detailed_cmd]=\"${cmdline[*]}\"\n\t\t\t\t\t\tproc[detailed_name]=\"${proc[detailed_name]::15}\"\n\t\t\t\t\t\tread -ra det_array < <(ps -o ppid:4,euser:15 --no-headers -p $pid || true)\n\t\t\t\t\t\tproc[detailed_parent_pid]=\"${det_array[0]}\"\n\t\t\t\t\t\tproc[detailed_user]=\"${det_array[*]:1}\"\n\t\t\t\t\t\tread -r proc[detailed_parent_name] < <(ps -o comm --no-headers -p ${det_array[0]} || true)\n\t\t\t\t\t\tget_mem=1\n\t\t\t\t\tfi\n\t\t\t\t\tproc[detailed_cpu]=\"${cpu_percent_string// /}\"\n\t\t\t\t\tproc[detailed_cpu_int]=\"${cpu_int}\"\n\t\t\t\t\tproc[detailed_threads]=\"${work_array[-4]}\"\n\t\t\t\t\tread -r proc[detailed_runtime] < <(ps -o etime:4 --no-headers -p $pid || true)\n\n\t\t\t\t\tif [[ ${proc[detailed_mem]} != \"${work_array[-2]}\" || -n $get_mem ]] || ((++proc[detailed_mem_count]>5)); then\n\t\t\t\t\t\tproc[detailed_mem_count]=0\n\t\t\t\t\t\tproc[detailed_mem]=\"${work_array[-2]}\"\n\t\t\t\t\t\tproc[detailed_mem_int]=\"${proc[detailed_mem]/./}\"\n\t\t\t\t\t\tif [[ ${proc[detailed_mem_int]::1} == \"0\" ]]; then proc[detailed_mem_int]=\"${proc[detailed_mem_int]:1}0\"; fi\n\t\t\t\t\t\t#* Scale up low mem values to see any changes on mini graph\n\t\t\t\t\t\tif ((proc[detailed_mem_int]>900)); then proc[detailed_mem_int]=$((proc[detailed_mem_int]/10))\n\t\t\t\t\t\telif ((proc[detailed_mem_int]>600)); then proc[detailed_mem_int]=$((proc[detailed_mem_int]/8))\n\t\t\t\t\t\telif ((proc[detailed_mem_int]>300)); then proc[detailed_mem_int]=$((proc[detailed_mem_int]/5))\n\t\t\t\t\t\telif ((proc[detailed_mem_int]>100)); then proc[detailed_mem_int]=$((proc[detailed_mem_int]/2))\n\t\t\t\t\t\telif ((proc[detailed_mem_int]<50)); then proc[detailed_mem_int]=$((proc[detailed_mem_int]*2)); fi\n\t\t\t\t\t\tunset 'proc[detailed_mem_string]'\n\t\t\t\t\t\tread -r mem_string < <(ps -o rss:1 --no-headers -p ${pid} || true)\n\t\t\t\t\t\tfloating_humanizer -v proc[detailed_mem_string] -B -s 1 $mem_string\n\t\t\t\t\t\tif [[ -z ${proc[detailed_mem_string]} ]]; then proc[detailed_mem_string]=\"? Byte\"; fi\n\t\t\t\t\tfi\n\n\t\t\t\t\t#* Copy process cpu usage to history array and trim earlier entries\n\t\t\t\t\tif ((${#detail_history[@]}>box[details_width]*2)); then\n\t\t\t\t\t\tdetail_history=( \"${detail_history[@]:${box[details_width]}}\" \"$((cpu_int+4))\")\n\t\t\t\t\telse\n\t\t\t\t\t\tdetail_history+=(\"$((cpu_int+4))\")\n\t\t\t\t\tfi\n\n\t\t\t\t\t#* Copy process mem usage to history array and trim earlier entries\n\t\t\t\t\tif ((${#detail_mem_history[@]}>box[details_width])); then\n\t\t\t\t\t\tdetail_mem_history=( \"${detail_mem_history[@]:$((box[details_width]/2))}\" \"${proc[detailed_mem_int]}\")\n\t\t\t\t\telse\n\t\t\t\t\t\tdetail_mem_history+=(\"${proc[detailed_mem_int]}\")\n\t\t\t\t\tfi\n\n\t\t\t\t\t#* Remove selected process from array if process is excluded by filtering or not on first page\n\t\t\t\t\tif [[ -n $filter && ! ${proc[detailed_name]} =~ $filter ]]; then\n\t\t\t\t\t\tunset 'proc_array[count]'\n\t\t\t\t\t\tcpu_int=0; pid_count=0\n\t\t\t\t\tfi\n\t\t\t\tfi\n\n\t\t\t\t#* Create small graphs for all visible processes using more than 1% cpu time\n\t\t\t\tif [[ ${cpu_int} -gt 0 ]]; then pid_count=5; fi\n\n\t\t\t\tif [[ -z ${!pid_graph} && ${cpu_int} -gt 0 ]]; then\n\t\t\t\t\ttmp_value_array=(\"$((cpu_int+4))\")\n\t\t\t\t\tcreate_mini_graph -o \"pid_${pid}_graph\" -nc -w 5 \"tmp_value_array\"\n\t\t\t\telif [[ ${pid_count} -gt 0 ]]; then\n\t\t\t\t\tif [[ ${cpu_int} -gt 9 ]]; then\n\t\t\t\t\t\tcreate_mini_graph -nc -add-value \"pid_${pid}_graph\" \"$((cpu_int+15))\"\n\t\t\t\t\telse\n\t\t\t\t\t\tcreate_mini_graph -nc -add-value \"pid_${pid}_graph\" \"$((cpu_int+9))\"\n\t\t\t\t\tfi\n\n\t\t\t\t\tpid_count=$((${pid_count}-1))\n\t\t\t\telif [[ ${pid_count} == \"0\" ]]; then\n\t\t\t\t\tunset \"pid_${pid}_graph\" \"pid_${pid}_graph_even\" \"pid_${pid}_graph_odd\" \"pid_${pid}_graph_last_type\" \"pid_${pid}_graph_last_val\"\n\t\t\t\t\tunset \"pid_${pid}_count\"\n\t\t\t\tfi\n\t\t\telse\n\t\t\t\ttmp_percent=\"${proc_array[count]:(-5)}\"; tmp_percent=\"${tmp_percent// /}\"; if [[ ${tmp_percent//./} != \"$tmp_percent\" ]]; then tmp_percent=\"${tmp_percent::-2}\"; fi\n\t\t\t\tif ((tmp_percent>100)); then\n\t\t\t\t\tproc_array[count]=\"${proc_array[count]::-5}  100\"\n\t\t\t\tfi\n\t\t\tfi\n\n\t\t\tproc[old_${pid}_ticks]=${proc[new_${pid}_ticks]}\n\n\t\tfi\n\n\t\tif ((breaking==1)); then\n\t\t\tif [[ ${proc[detailed]} == \"1\" && -z ${proc[detailed_cpu]} ]] && ps ${proc[detailed_pid]} >/dev/null 2>&1; then\n\t\t\t\treadarray ${options} -O ${#proc_array[@]} proc_array < <(ps -o pid:${proc[pid_len]}=Pid:,comm:${format_cmd}=${tree:-Program:}${format_args},nlwp:3=Tr:,euser:6=User:,pmem=Mem%,pcpu:10=Cpu% --no-headers -p ${proc[detailed_pid]} || true)\n\t\t\t\t((++breaking))\n\t\t\telse\n\t\t\t\tbreak\n\t\t\tfi\n\t\telif ((breaking==2)); then\n\t\t\tunset 'proc_array[-1]'\n\t\t\tbreak\n\t\tfi\n\n\tdone\n\n\n\tproc[old_timestamp]=${proc[new_timestamp]}\n\n\tif ((proc[detailed]==1)) && [[ -z ${proc[detailed_cpu]} && -z ${proc[detailed_killed]} ]]; then proc[detailed_killed]=1; proc[detailed_change]=1\n\telif [[ -n ${proc[detailed_cpu]} ]]; then unset 'proc[detailed_killed]'; fi\n\n\t#* Sort output array based on cpu usage if \"cpu responsive\" is selected\n\tif [[ ${proc_sorting} == \"cpu responsive\" && ${proc_tree} != true ]]; then\n\t\tlocal -a sort_array\n\t\tif [[ -z ${proc[reverse]} ]]; then local sort_rev=\"-r\"; fi\n\t\tsort_array[0]=\"${proc_array[0]}\"\n\t\treadarray -O 1 -t sort_array < <(printf \"%s\\n\" \"${proc_array[@]:1}\" | awk '{ print $NF, $0 }' | sort -n -k1 ${sort_rev}| sed 's/^[0-9\\.]* //')\n\t\tproc_array=(\"${sort_array[@]}\")\n\tfi\n\n\t#* Clear up memory by removing variables and graphs of no longer running processes\n\t((++proc[general_counter]))\n\tif ((proc[general_counter]>100)); then\n\t\tproc[general_counter]=0\n\t\tfor pids in ${!pid_history[@]}; do\n\t\t\tif [[ ! -e /proc/${pids} ]]; then\n\t\t\t\tunset \"pid_${pids}_graph\" \"pid_${pids}_graph_even\" \"pid_${pids}_graph_odd\" \"pid_${pids}_graph_last_type\" \"pid_${pids}_graph_last_val\"\n\t\t\t\tunset \"pid_${pids}_count\"\n\t\t\t\tunset \"proc[new_${pids}_ticks]\"\n\t\t\t\tunset \"proc[old_${pids}_ticks]\"\n\t\t\t\tunset \"pid_history[${pids}]\"\n\t\t\tfi\n\t\tdone\n\tfi\n\n}\n\ncollect_processes_psutil() {\n\tlocal argument=$1\n\tif [[ -n $skip_process_draw && $argument != \"now\" ]]; then return; fi\n\tif [[ $argument == \"now\" ]]; then skip_process_draw=1; fi\n\tlocal prog_len arg_len symbol=\"▼\" selected width=${box[processes_width]} height=${box[processes_height]}\n\tlocal pcpu_usage pids p_count cpu_int pids max_lines i pi\n\n\tcase ${proc_sorting} in\n\t\t\"pid\") selected=\"Pid:\";;\n\t\t\"program\") selected=\"Program:\";;\n\t\t\"arguments\") selected=\"Arguments:\";;\n\t\t\"threads\") selected=\"Threads:\";;\n\t\t\"user\") selected=\"User:\";;\n\t\t\"memory\") selected=\"Mem%\";;\n\t\t\"cpu lazy\"|\"cpu responsive\") selected=\"Cpu%\";;\n\tesac\n\n\tif [[ ${proc_tree} == true && ${proc_sorting} =~ pid|program|arguments ]]; then selected=\"Tree:\"; fi\n\n\tif [[ -n ${proc[reverse]} ]]; then symbol=\"▲\"; fi\n\n\tif ((proc[detailed]==0)) && [[ -n ${proc[detailed_name]} ]]; then\n\t\tunset 'proc[detailed_name]' 'proc[detailed_killed]' 'proc[detailed_cpu_int]' 'proc[detailed_cmd]'\n\t\tunset 'proc[detailed_mem]' 'proc[detailed_mem_int]' 'proc[detailed_user]' 'proc[detailed_threads]'\n\t\tunset 'detail_graph[@]' 'detail_mem_graph' 'detail_history[@]' 'detail_mem_history[@]'\n\t\tunset 'proc[detailed_runtime]' 'proc[detailed_mem_string]' 'proc[detailed_parent_pid]' 'proc[detailed_parent_name]'\n\tfi\n\n\tunset 'proc[detailed_cpu]'\n\n\n\tif ((width>60)); then\n\t\targ_len=$((width-55))\n\t\tprog_len=15\n\telse\n\t\tprog_len=$((width-40))\n\t\targ_len=0\n\t\tif [[ $proc_sorting == \"threads\" ]]; then selected=\"Tr:\"; fi\n\tfi\n\n\n\tunset 'proc_array[@]'\n\tif ! py_command -a proc_array \"get_proc(sorting='${proc_sorting}', tree=${proc_tree^}, prog_len=${prog_len}, arg_len=${arg_len}, search='${filter}', reverse=${proc_reversed^}, proc_per_cpu=${proc_per_core^})\"; then\n\t\tproc_array=(\"\"); return\n\tfi\n\n\tproc_array[0]=\"${proc_array[0]/ ${selected}/${symbol}${selected}}\"\n\n\tfor((i=1;i<${#proc_array[@]};i++)); do\n\t\tif [[ -z ${proc_array[i]} ]]; then continue; fi\n\n\t\tout_arr=(${proc_array[i]})\n\n\t\tpi=0\n\t\tif [[ $proc_tree == true ]]; then\n\t\t\twhile ! is_int \"${out_arr[pi]}\" && ((pi<${#out_arr[@]}-1)); do ((++pi)); done\n\t\tfi\n\t\tpid=\"${out_arr[pi]}\"\n\t\tif ! is_int \"${pid}\"; then continue; fi\n\n\t\tpcpu_usage=\"${out_arr[-1]}\"\n\n\t\tif ! printf -v cpu_int \"%.0f\" \"${pcpu_usage}\" 2>/dev/null; then continue; fi\n\n\t\tpid_history[${pid}]=\"1\"\n\n\t\t#* Create small graphs for all visible processes using more than 1% rounded cpu time\n\t\tpid_graph=\"pid_${pid}_graph\"\n\t\tif ! local -n pid_count=\"pid_${pid}_count\" 2>/dev/null; then continue; fi\n\n\t\tif [[ ${cpu_int} -gt 0 ]]; then pid_count=5; fi\n\n\t\tif [[ -z ${!pid_graph} && ${cpu_int} -gt 0 ]]; then\n\t\t\ttmp_value_array=(\"$((cpu_int+4))\")\n\t\t\tcreate_mini_graph -o \"pid_${pid}_graph\" -nc -w 5 \"tmp_value_array\"\n\t\telif [[ ${pid_count} -gt 0 ]]; then\n\t\t\tif [[ ${cpu_int} -gt 9 ]]; then\n\t\t\t\tcreate_mini_graph -nc -add-value \"pid_${pid}_graph\" \"$((cpu_int+15))\"\n\t\t\telif [[ ${cpu_int} -gt 0 ]]; then\n\t\t\t\tcreate_mini_graph -nc -add-value \"pid_${pid}_graph\" \"$((cpu_int+9))\"\n\t\t\telse\n\t\t\t\tcreate_mini_graph -nc -add-value \"pid_${pid}_graph\" \"0\"\n\t\t\tfi\n\t\t\tpid_count=$((${pid_count}-1))\n\t\telif [[ ${pid_count} == \"0\" ]]; then\n\t\t\tunset \"pid_${pid}_graph\" \"pid_${pid}_graph_even\" \"pid_${pid}_graph_odd\" \"pid_${pid}_graph_last_type\" \"pid_${pid}_graph_last_val\"\n\t\t\tunset \"pid_${pid}_count\"\n\t\tfi\n\n\t\t#* Get info for detailed box if enabled\n\t\tif [[ ${pid} == \"${proc[detailed_pid]}\" ]]; then\n\t\t\tlocal -a det_array\n\t\t\tif [[ -z ${proc[detailed_name]} ]]; then\n\t\t\t\tlocal get_mem mem_string cmdline=\"\"\n\n\t\t\t\tpy_command -a det_array \"get_detailed_names_cmd(${pid})\"\n\n\t\t\t\tif [[ -z ${det_array[0]} ]]; then continue; fi\n\t\t\t\tproc[detailed_name]=\"${det_array[0]::15}\"\n\t\t\t\tproc[detailed_parent_name]=\"${det_array[1]}\"\n\t\t\t\tproc[detailed_user]=\"${det_array[2]}\"\n\t\t\t\tproc[detailed_cmd]=\"${det_array[3]}\"\n\t\t\tfi\n\t\t\tproc[detailed_cpu]=\"${out_arr[-1]}\"\n\t\t\tproc[detailed_cpu_int]=\"${cpu_int}\"\n\t\t\tproc[detailed_threads]=\"${out_arr[-4]}\"\n\n\t\t\tunset 'det_array[@]'\n\t\t\tpy_command -a det_array \"get_detailed_mem_time(${pid})\"\n\n\t\t\tif [[ -z ${det_array[0]} ]]; then continue; fi\n\t\t\tunset 'proc[detailed_mem_string]'\n\t\t\tfloating_humanizer -v proc[detailed_mem_string] -B ${det_array[0]}\n\t\t\tif [[ -z ${proc[detailed_mem_string]} ]]; then proc[detailed_mem_string]=\"? Byte\"; fi\n\t\t\tif ((${#det_array[1]}>8)); then proc[detailed_runtime]=\"${det_array[1]/ days, /-}\"\n\t\t\telse proc[detailed_runtime]=\"${det_array[1]}\"; fi\n\n\t\t\tproc[detailed_mem_count]=0\n\t\t\tproc[detailed_mem]=\"${out_arr[-2]}\"\n\t\t\tproc[detailed_mem_int]=\"${proc[detailed_mem]/./}\"\n\t\t\tif [[ ${proc[detailed_mem_int]::1} == \"0\" ]]; then proc[detailed_mem_int]=\"${proc[detailed_mem_int]:1}0\"; fi\n\t\t\t#* Scale up low mem values to see any changes on mini graph\n\t\t\tif ((proc[detailed_mem_int]>900)); then proc[detailed_mem_int]=$((proc[detailed_mem_int]/10))\n\t\t\telif ((proc[detailed_mem_int]>600)); then proc[detailed_mem_int]=$((proc[detailed_mem_int]/8))\n\t\t\telif ((proc[detailed_mem_int]>300)); then proc[detailed_mem_int]=$((proc[detailed_mem_int]/5))\n\t\t\telif ((proc[detailed_mem_int]>100)); then proc[detailed_mem_int]=$((proc[detailed_mem_int]/2))\n\t\t\telif ((proc[detailed_mem_int]<50)); then proc[detailed_mem_int]=$((proc[detailed_mem_int]*2)); fi\n\n\t\t\t#* Copy process cpu usage to history array and trim earlier entries\n\t\t\tif ((${#detail_history[@]}>box[details_width]*2)); then\n\t\t\t\tdetail_history=( \"${detail_history[@]:${box[details_width]}}\" \"$((cpu_int+4))\")\n\t\t\telse\n\t\t\t\tdetail_history+=(\"$((cpu_int+4))\")\n\t\t\tfi\n\n\t\t\t#* Copy process mem usage to history array and trim earlier entries\n\t\t\tif ((${#detail_mem_history[@]}>box[details_width])); then\n\t\t\t\tdetail_mem_history=( \"${detail_mem_history[@]:$((box[details_width]/2))}\" \"${proc[detailed_mem_int]}\")\n\t\t\telse\n\t\t\t\tdetail_mem_history+=(\"${proc[detailed_mem_int]}\")\n\t\t\tfi\n\t\tfi\n\n\t\tif ((i==height-2)); then\n\t\t\tif [[ ${proc[selected]} -gt 0 || -n $filter || ${proc[start]} -gt 1 ]] || [[ ${proc[detailed]} -eq 1 && -z ${proc[detailed_cpu]} && -z ${proc[detailed_killed]} ]]; then :\n\t\t\telse break; fi\n\t\tfi\n\n\tdone\n\n\tif ((proc[detailed]==1)) && [[ -z ${proc[detailed_cpu]} && -z ${proc[detailed_killed]} ]]; then proc[detailed_killed]=1; proc[detailed_change]=1\n\telif [[ -n ${proc[detailed_cpu]} ]]; then unset 'proc[detailed_killed]'; fi\n\n\n\n\t#* Clear up memory\n\t((++proc[general_counter]))\n\tif ((proc[general_counter]>100)); then\n\t\tproc[general_counter]=0\n\t\tfor pids in ${!pid_history[@]}; do\n\t\t\tunset \"pid_${pids}_graph\" \"pid_${pids}_graph_even\" \"pid_${pids}_graph_odd\" \"pid_${pids}_graph_last_type\" \"pid_${pids}_graph_last_val\"\n\t\t\tunset \"pid_${pids}_count\"\n\t\t\tunset \"pid_history[${pids}]\"\n\t\tdone\n\tfi\n\n}\n\ncollect_net() { #? Collect information from \"/proc/net/dev\"\n\tlocal operations operation direction index unit_selector speed speed_B total\n\tlocal -a net_dev history_sorted history_last\n\n\tif [[ -n ${net[no_device]} ]]; then return; fi\n\n\tif [[ $1 == \"init\" ]]; then\n\t\tfor direction in \"download\" \"upload\"; do\n\t\tnet[${direction}_max]=0\n\t\tnet[${direction}_new_low]=0\n\t\tnet[${direction}_new_max]=0\n\t\tnet[${direction}_max_current]=0\n\t\tnet[${direction}_graph_max]=$((50<<10))\n\t\tdone\n\t\tunset 'download_graph[@]' 'upload_graph[@]' 'net_history_download[@]' 'net_history_upload[@]'\n\tfi\n\n\t#* Get the line with relevant net device from /proc/net/dev or psutil into array net_dev, index 1 is download, index 9 is upload\n\tif [[ $use_psutil == true ]]; then\n\t\tpy_command -v net_dev \"get_net('${net[device]}')\" || return\n\t\tnet_dev=(${net_dev})\n\t\tif ! is_int \"${net_dev[0]}\"; then net[no_device]=1; return; fi\n\telse\n\t\tif ! get_value -map net_dev -sf \"/proc/net/dev\" -k \"${net[device]}\" -a; then net[no_device]=1; return; fi\n\tfi\n\n\t#* Timestamp the values to accurately calculate values in seconds\n\tget_ms net[new_timestamp]\n\tfor direction in \"download\" \"upload\"; do\n\t\tif [[ $direction == \"download\" ]]; then index=1\n\t\telse index=9; fi\n\n\t\tnet[new_${direction}]=${net_dev[index]}\n\n\t\tif [[ -n ${net[old_${direction}]} ]]; then\n\t\t\t#* Get total, convert to floating point and format string to best fitting unit in Bytes\n\t\t\tif ((net[nic_change]==1 & net[reset]==1)); then unset \"net[total_offset_${direction}]\"; net[reset]=0; fi\n\t\t\tif ((net[reset]==1)) && [[ -z ${net[total_offset_${direction}]} || ${net[total_offset_${direction}]} -gt ${net[new_${direction}]} ]]; then net[total_offset_${direction}]=${net[new_${direction}]}\n\t\t\telif ((net[reset]==0)) && [[ -n ${net[total_offset_${direction}]} ]]; then unset \"net[total_offset_${direction}]\"; fi\n\n\t\t\tfloating_humanizer -Byte -v net[total_${direction}] $((${net[new_${direction}]}-${net[total_offset_${direction}]:-0}))\n\n\t\t\t#* Calculate current speeds: (\"New value\" - \"Old value\") * 1000(for ms to seconds) / (\"new_timestamp\" - \"old_timestamp\")\n\t\t\tnet[speed_${direction}]=$(( (${net[new_${direction}]}-${net[old_${direction}]})*1000/(net[new_timestamp]-net[old_timestamp]) ))\n\n\t\t\t#* Convert to floating point and format string to best fitting unit in Bytes and Bits per second\n\t\t\tfloating_humanizer -Byte -per-second -v net[speed_${direction}_byteps] ${net[speed_${direction}]}\n\t\t\tfloating_humanizer -bit -per-second -v net[speed_${direction}_bitps] ${net[speed_${direction}]}\n\n\t\t\t#* Update download and upload max values for graph\n\t\t\tif ((${net[speed_${direction}]}>${net[${direction}_max]})); then\n\t\t\t\tnet[${direction}_max]=${net[speed_${direction}]}\n\t\t\tfi\n\n\t\t\tif ((${net[speed_${direction}]}>${net[${direction}_graph_max]})); then\n\t\t\t\t\t((++net[${direction}_new_max]))\n\t\t\t\t\tif ((net[${direction}_new_low]>0)); then ((net[${direction}_new_low]--)); fi\n\t\t\telif ((${net[${direction}_graph_max]}>10<<10 & ${net[speed_${direction}]}<${net[${direction}_graph_max]}/10)); then\n\t\t\t\t((++net[${direction}_new_low]))\n\t\t\t\tif ((net[${direction}_new_max]>0)); then ((net[${direction}_new_max]--)); fi\n\t\t\tfi\n\n\t\t\t#* Copy download and upload speed to history arrays and trim earlier entries\n\t\t\tlocal -n history=\"net_history_${direction}\"\n\t\t\tif ((${#history[@]}>box[net_width]*4)); then\n\t\t\t\thistory=( \"${history[@]:$((box[net_width]*2))}\" \"${net[speed_${direction}]}\")\n\t\t\telse\n\t\t\t\thistory+=(\"${net[speed_${direction}]}\")\n\t\t\tfi\n\n\t\t\t#* Check for new max value and set flag to adjust resolution of graph if needed\n\t\t\tif ((${net[${direction}_new_max]}>=5)); then\n\t\t\t\tnet[${direction}_graph_max]=$((${net[${direction}_max]}+(${net[${direction}_max]}/3) ))\n\t\t\t\tnet[${direction}_redraw]=1\n\t\t\t\tnet[${direction}_new_max]=0\n\n\t\t\t#* If current max value isn't relevant, sort array to get the next largest value to set graph resolution\n\t\t\telif ((${net[${direction}_new_low]}>=5 & ${#history[@]}>5)); then\n\t\t\t\thistory_last=(\"${history[@]:(-5)}\")\n\t\t\t\tsort_array_int \"history_last\" \"history_sorted\"\n\t\t\t\tnet[${direction}_max]=${history_sorted[0]}\n\t\t\t\tnet[${direction}_graph_max]=$(( ${net[${direction}_max]}*3 ))\n\t\t\t\tif ((${net[${direction}_graph_max]}<10<<10)); then net[${direction}_graph_max]=$((10<<10)); fi\n\t\t\t\tnet[${direction}_redraw]=1\n\t\t\t\tnet[${direction}_new_low]=0\n\t\t\tfi\n\t\tfi\n\n\t\tfloating_humanizer -Byte -short -v net[${direction}_max_string] ${net[${direction}_graph_max]}\n\n\t\tnet[old_${direction}]=${net[new_${direction}]}\n\tdone\n\n\tnet[old_timestamp]=${net[new_timestamp]}\n\n}\n\ncalc_sizes() { #? Calculate width and height of all boxes\n\tlocal pos calc_size calc_total percent threads=${cpu[threads]}\n\n\t#* Calculate heights\n\tfor pos in ${box[boxes]/processes/}; do\n\t\tif [[ $pos = \"cpu\" ]]; then percent=32;\n\t\telif [[ $pos = \"mem\" ]]; then percent=40;\n\t\telse percent=28; fi\n\n\t\t#* Multiplying with 10 to convert to floating point\n\t\tcalc_size=$(( (tty_height*10)*(percent*10)/100 ))\n\n\t\t#* Round down if last 2 digits of value is below \"50\" and round up if above\n\t\tif ((${calc_size:(-2):1}==0)); then calc_size=$((calc_size+10)); fi\n\t\tif ((${calc_size:(-2)}<50)); then\n\t\t\tcalc_size=$((${calc_size::-2}))\n\t\telse\n\t\t\tcalc_size=$((${calc_size::-2}+1))\n\t\tfi\n\n\t\t#* Subtract from last value if the total of all rounded numbers is larger then terminal height\n\t\twhile ((calc_total+calc_size>tty_height)); do ((--calc_size)); done\n\t\tcalc_total=$((calc_total+calc_size))\n\n\t\t#* Set calculated values in box array\n\t\tbox[${pos}_line]=$((calc_total-calc_size+1))\n\t\tbox[${pos}_col]=1\n\t\tbox[${pos}_height]=$calc_size\n\t\tbox[${pos}_width]=$tty_width\n\tdone\n\n\n\t#* Calculate widths\n\tunset calc_total\n\tfor pos in net processes; do\n\t\tif [[ $pos = \"net\" ]]; then percent=45; else percent=55; fi\n\n\t\t#* Multiplying with 10 to convert to floating point\n\t\tcalc_size=$(( (tty_width*10)*(percent*10)/100 ))\n\n\t\t#* Round down if last 2 digits of value is below \"50\" and round up if above\n\t\tif ((${calc_size:(-2)}<50)); then\n\t\t\tcalc_size=$((${calc_size::-2}))\n\t\telse\n\t\t\tcalc_size=$((${calc_size::-2}+1))\n\t\tfi\n\n\t\t#* Subtract from last value if the total of all rounded numbers is larger then terminal width\n\t\twhile ((calc_total+calc_size>tty_width)); do ((--calc_size)); done\n\t\tcalc_total=$((calc_total+calc_size))\n\n\t\t#* Set calculated values in box array\n\t\tbox[${pos}_col]=$((calc_total-calc_size+1))\n\t\tbox[${pos}_width]=$calc_size\n\tdone\n\n\t#* Copy numbers around to get target layout\n\tbox[mem_width]=${box[net_width]}\n\tbox[processes_line]=${box[mem_line]}\n\tbox[processes_height]=$((box[mem_height]+box[net_height]))\n\n\t#  threads=${box[testing]} #! For testing, remove <--------------\n\n\t#* Recalculate size of process box if currently showing detailed process information\n\tif ((proc[detailed]==1)); then\n\t\tbox[details_line]=${box[processes_line]}\n\t\tbox[details_col]=${box[processes_col]}\n\t\tbox[details_width]=${box[processes_width]}\n\t\tbox[details_height]=8\n\t\tbox[processes_line]=$((box[processes_line]+box[details_height]))\n\t\tbox[processes_height]=$((box[processes_height]-box[details_height]))\n\tfi\n\n\t#* Calculate number of columns and placement of cpu meter box\n\tlocal cpu_line=$((box[cpu_line]+1)) cpu_width=$((box[cpu_width]-2)) cpu_height=$((box[cpu_height]-2)) box_cols\n\tif ((threads>(cpu_height-3)*3 && tty_width>=200)); then box[p_width]=$((24*4)); box[p_height]=$((threads/4+4)); box_cols=4\n\telif ((threads>(cpu_height-3)*2 && tty_width>=150)); then box[p_width]=$((24*3)); box[p_height]=$((threads/3+5)); box_cols=3\n\telif ((threads>cpu_height-3 && tty_width>=100)); then box[p_width]=$((24*2)); box[p_height]=$((threads/2+4)); box_cols=2\n\telse box[p_width]=24; box[p_height]=$((threads+4)); box_cols=1\n\tfi\n\n\tif [[ $check_temp == true ]]; then\n\t\tbox[p_width]=$(( box[p_width]+13*box_cols))\n\tfi\n\n\tif ((box[p_height]>cpu_height)); then box[p_height]=$cpu_height; fi\n\tbox[p_col]=\"$((cpu_width-box[p_width]+2))\"\n\tbox[p_line]=\"$((cpu_line+(cpu_height/2)-(box[p_height]/2)+1))\"\n\n\t#* Calculate placement of mem divider\n\tlocal mem_line=$((box[mem_line]+1)) mem_width=$((box[mem_width]-2)) mem_height=$((box[mem_height]-2)) mem_col=$((box[mem_col]+1))\n\tbox[m_width]=$((mem_width/2))\n\tbox[m_width2]=${box[m_width]}\n\tif ((box[m_width]+box[m_width2]<mem_width)); then ((box[m_width]++)); fi\n\tbox[m_height]=$mem_height\n\tbox[m_col]=$((mem_col+1))\n\tbox[m_line]=$mem_line\n\n\t#* Calculate placement of net value box\n\tlocal net_line=$((box[net_line]+1)) net_width=$((box[net_width]-2)) net_height=$((box[net_height]-2))\n\tbox[n_width]=24\n\tif ((net_height>9)); then box[n_height]=9\n\telse box[n_height]=$net_height; fi\n\tbox[n_col]=\"$((net_width-box[n_width]+2))\"\n\tbox[n_line]=\"$((net_line+(net_height/2)-(box[n_height]/2)+1))\"\n\n\n}\n\ndraw_bg() { #? Draw all box outlines\n\tlocal this_box cpu_p_width i cpu_model_len\n\n\tunset boxes_out\n\tfor this_box in ${box[boxes]}; do\n\t\tcreate_box -v boxes_out -col ${box[${this_box}_col]} -line ${box[${this_box}_line]} -width ${box[${this_box}_width]} -height ${box[${this_box}_height]} -fill -lc \"${box[${this_box}_color]}\" -title ${this_box}\n\tdone\n\n\t#* Misc cpu box\n\tif [[ $check_temp == true ]]; then cpu_model_len=18; else cpu_model_len=9; fi\n\tcreate_box -v boxes_out -col $((box[p_col]-1)) -line $((box[p_line]-1)) -width ${box[p_width]} -height ${box[p_height]} -lc ${theme[div_line]} -t \"${cpu[model]:0:${cpu_model_len}}\"\n\tprint -v boxes_out -m ${box[cpu_line]} $((box[cpu_col]+10)) -rs \\\n\t-fg ${box[cpu_color]} -t \"┤\" -b -fg ${theme[hi_fg]} -t \"m\" -fg ${theme[title]} -t \"enu\" -rs -fg ${box[cpu_color]} -t \"├\"\n\n\t#* Misc mem\n\tprint -v boxes_out -m ${box[mem_line]} $((box[mem_col]+box[m_width]+2)) -rs -fg ${box[mem_color]} -t \"┤\" -fg ${theme[title]} -b -t \"disks\" -rs -fg ${box[mem_color]} -t \"├\"\n\tprint -v boxes_out -m ${box[mem_line]} $((box[mem_col]+box[m_width])) -rs -fg ${box[mem_color]} -t \"┬\"\n\tprint -v boxes_out -m $((box[mem_line]+box[mem_height]-1)) $((box[mem_col]+box[m_width])) -fg ${box[mem_color]} -t \"┴\"\n\tfor((i=1;i<=box[mem_height]-2;i++)); do\n\t\tprint -v boxes_out -m $((box[mem_line]+i)) $((box[mem_col]+box[m_width])) -fg ${theme[div_line]} -t \"│\"\n\tdone\n\n\n\t#* Misc net box\n\tcreate_box -v boxes_out -col $((box[n_col]-1)) -line $((box[n_line]-1)) -width ${box[n_width]} -height ${box[n_height]} -lc ${theme[div_line]} -t \"Download\"\n\tprint -v boxes_out -m $((box[n_line]+box[n_height]-2)) $((box[n_col]+1)) -rs -fg ${theme[div_line]} -t \"┤\" -fg ${theme[title]} -b -t \"Upload\" -rs -fg ${theme[div_line]} -t \"├\"\n\n\n\tif [[ $1 == \"quiet\" ]]; then draw_out=\"${boxes_out}\"\n\telse echo -en \"${boxes_out}\"; fi\n\tdraw_update_string $1\n}\n\ndraw_cpu() { #? Draw cpu and core graphs and print percentages\n\tlocal cpu_out i name cpu_p_color temp_color y pt_line pt_col p_normal_color=\"${theme[main_fg]}\" threads=${cpu[threads]}\n\tlocal meter meter_size meter_width temp_var cpu_out_var core_name temp_name temp_width\n\n\t#* Get variables from previous calculations\n\tlocal col=$((box[cpu_col]+1)) line=$((box[cpu_line]+1)) width=$((box[cpu_width]-2)) height=$((box[cpu_height]-2))\n\tlocal p_width=${box[p_width]} p_height=${box[p_height]} p_col=${box[p_col]} p_line=${box[p_line]}\n\n\t#* If resized recreate cpu meter/graph box, cpu graph and core graphs\n\tif ((resized>0)); then\n\t\tlocal graph_a_size graph_b_size\n\t\tgraph_a_size=$((height/2)); graph_b_size=${graph_a_size}\n\n\t\tif ((graph_a_size*2<height)); then ((graph_a_size++)); fi\n\t\tcreate_graph -o cpu_graph_a -d ${line} ${col} ${graph_a_size} $((width-p_width-2)) -c color_cpu_graph -n cpu_history\n\t\tcreate_graph -o cpu_graph_b -d $((line+graph_a_size)) ${col} ${graph_b_size} $((width-p_width-2)) -c color_cpu_graph -i -n cpu_history\n\n\t\tif [[ -z ${cpu_core_1_graph} ]]; then\n\t\t\tfor((i=1;i<=threads;i++)); do\n\t\t\t\tcreate_mini_graph -o \"cpu_core_${i}_graph\" -w 10 -nc \"cpu_core_history_${i}\"\n\t\t\tdone\n\t\tfi\n\n\t\tif [[ $check_temp == true && -z ${cpu_temp_0_graph} ]]; then\n\t\t\tfor((i=0;i<=threads;i++)); do\n\t\t\t\tif [[ -n ${cpu[temp_${i}]} ]]; then create_mini_graph -o \"cpu_temp_${i}_graph\" -w 5 -nc \"cpu_temp_history_${i}\"; fi\n\t\t\tdone\n\t\tfi\n\t\t((resized++))\n\tfi\n\n\t#* Add new values to cpu and core graphs unless just resized\n\tif ((resized==0)); then\n\t\tcreate_graph -add-last cpu_graph_a cpu_history\n\t\tcreate_graph -i -add-last cpu_graph_b cpu_history\n\t\tfor((i=1;i<=threads;i++)); do\n\t\t\tcreate_mini_graph -w 10 -nc -add-last \"cpu_core_${i}_graph\" \"cpu_core_history_${i}\"\n\t\tdone\n\t\tif [[ $check_temp == true ]]; then\n\t\t\tfor((i=0;i<=threads;i++)); do\n\t\t\t\tif [[ -n ${cpu[temp_${i}]} ]]; then\n\t\t\t\t\tcreate_mini_graph -w 5 -nc -add-last \"cpu_temp_${i}_graph\" \"cpu_temp_history_${i}\"\n\t\t\t\tfi\n\t\t\tdone\n\t\tfi\n\tfi\n\n\t#* Print CPU total and all cpu core percentage meters in box\n\tfor((i=0;i<=threads;i++)); do\n\t\tif ((i==0)); then name=\"CPU\"; else name=\"Core${i}\"; fi\n\n\t\t#* Get color of cpu text depending on current usage\n\t\tcpu_p_color=\"${color_cpu_graph[cpu_usage[i]]}\"\n\n\t\tpt_col=$p_col; pt_line=$p_line; meter_size=\"small\"; meter_width=10\n\n\t\t#* Set temperature string if \"sensors\" is available\n\t\tif [[ $check_temp == true ]]; then\n\t\t\t#* Get color of temperature text depending on current temp vs factory high temp\n\t\t\tdeclare -n temp_hist=\"cpu_temp_history_${i}[-1]\"\n\t\t\ttemp_color=\"${color_temp_graph[${temp_hist}]}\"\n\t\t\ttemp_name=\"cpu_temp_${i}_graph\"\n\t\t\ttemp_width=13\n\t\tfi\n\n\t\tif ((i==0 & p_width>24+temp_width)); then\n\t\t\tname=\"CPU Total \"; meter_width=$((p_width-17-temp_width))\n\t\tfi\n\n\n\t\t#* Create cpu usage meter\n\t\tif ((i==0)); then\n\t\t\tcreate_meter -v meter -w $meter_width -f -c color_cpu_graph ${cpu_usage[i]}\n\t\telse\n\t\t\tcore_name=\"cpu_core_${i}_graph\"\n\t\t\tmeter=\"${!core_name}\"\n\t\tfi\n\n\t\tif ((p_width>84+temp_width & i>=(p_height-2)*3-2)); then pt_line=$((p_line+i-y*4)); pt_col=$((p_col+72+temp_width*3))\n\t\telif ((p_width>54+temp_width & i>=(p_height-2)*2-1)); then pt_line=$((p_line+i-y*3)); pt_col=$((p_col+48+temp_width*2))\n\t\telif ((p_width>24+temp_width & i>=p_height-2)); then pt_line=$((p_line+i-y*2)); pt_col=$((p_col+24+temp_width))\n\t\telse y=$i; fi\n\n\t\tprint -v cpu_out_var -m $((pt_line+y)) $pt_col -rs -fg $p_normal_color -jl 7 -t \"$name\" -fg ${theme[inactive_fg]} \"⡀⡀⡀⡀⡀⡀⡀⡀⡀⡀\" -l 10 -fg $cpu_p_color -t \"$meter\"\\\n\t\t-jr 4 -fg $cpu_p_color -t \"${cpu_usage[i]}\" -fg $p_normal_color -t \"%\"\n\t\tif [[ $check_temp == true && -n ${cpu[temp_${i}]} ]]; then\n\t\t\tprint -v cpu_out_var -fg ${theme[inactive_fg]} \"  ⡀⡀⡀⡀⡀\" -l 7 -fg $temp_color -jl 7 -t \"  ${!temp_name}\" -jr 4 -t ${cpu[temp_${i}]} -fg $p_normal_color -t ${cpu[temp_unit]}\n\t\tfi\n\n\t\tif (( i>(p_height-2)*( p_width/(24+temp_width) )-( p_width/(24+temp_width) )-1 )); then break; fi\n\tdone\n\n\t#* Print load average and uptime\n\tif ((pt_line+y+3<p_line+p_height)); then\n\t\tlocal avg_string avg_width\n\t\tif [[ $check_temp == true ]]; then avg_string=\"Load Average: \"; avg_width=7; else avg_string=\"L AVG: \"; avg_width=5; fi\n\t\tprint -v cpu_out_var -m $((pt_line+y+1)) $pt_col -fg ${theme[main_fg]} -t \"${avg_string}\"\n\t\tfor avg_string in ${cpu[load_avg]}; do\n\t\t\tprint -v cpu_out_var -jc $avg_width -t \"${avg_string::4}\"\n\t\tdone\n\tfi\n\tprint -v cpu_out_var -m $((line+height-1)) $((col+1)) -fg ${theme[inactive_fg]} -trans -t \"up ${cpu[uptime]}\"\n\n\t#* Print current CPU frequency right of the title in the meter box\n\tif [[ -n ${cpu[freq_string]} ]]; then print -v cpu_out_var -m $((p_line-1)) $((p_col+p_width-5-${#cpu[freq_string]})) -fg ${theme[div_line]} -t \"┤\" -fg ${theme[title]} -b -t \"${cpu[freq_string]}\" -rs -fg ${theme[div_line]} -t \"├\"; fi\n\n\t#* Print created text, graph and meters to output variable\n\tdraw_out+=\"${cpu_graph_a[*]}${cpu_graph_b[*]}${cpu_out_var}\"\n\n}\n\ndraw_mem() { #? Draw mem, swap and disk statistics\n\n\tif ((mem[counter]>0 & resized==0)); then return; fi\n\n\tlocal i swap_used_meter swap_free_meter mem_available_meter mem_free_meter mem_used_meter mem_cached_meter normal_color=\"${theme[main_fg]}\" value_text\n\tlocal meter_mod_w meter_mod_pos value type m_title meter_options values=\"used available cached free\"\n\tlocal -a types=(\"mem\")\n\tunset mem_out\n\n\tif [[ -n ${swap[total]} && ${swap[total]} -gt 0 ]]; then types+=(\"swap\"); fi\n\n\t#* Get variables from previous calculations\n\tlocal col=$((box[mem_col]+1)) line=$((box[mem_line]+1)) width=$((box[mem_width]-2)) height=$((box[mem_height]-2))\n\tlocal m_width=${box[m_width]} m_height=${box[m_height]} m_col=${box[m_col]} m_line=${box[m_line]} mem_line=$((box[mem_col]+box[m_width]))\n\n\t#* Create text and meters for memory and swap and adapt sizes based on available height\n\tlocal y_pos=$m_line v_height=8 list value meter inv_meter\n\n\tfor type in ${types[@]}; do\n\t\tlocal -n type_name=\"$type\"\n\t\tif [[ $type == \"mem\" ]]; then\n\t\t\tm_title=\"memory\"\n\t\telse\n\t\t\tm_title=\"$type\"\n\t\t\tif ((height>14)); then ((y_pos++)); fi\n\t\tfi\n\n\t\t#* Print name of type and total amount in humanized base 2 bytes\n\t\tprint -v mem_out -m $y_pos $m_col -rs -fg ${theme[title]} -b -jl 9 -t \"${m_title^}:\" -m $((y_pos++)) $((mem_line-10)) -jr 9 -t \" ${type_name[total_string]::$((m_width-11))}\"\n\n\t\tfor value in ${values}; do\n\t\t\tif [[ $type == \"swap\" && $value =~ available|cached ]]; then continue; fi\n\n\t\t\tif [[ $system == \"MacOS\" && $value == \"cached\" ]]; then value_text=\"active\"\n\t\t\telse value_text=\"${value::$((m_width-12))}\"; fi\n\t\t\tif ((height<14)); then value_text=\"${value_text::5}\"; fi\n\n\t\t\t#* Print name of value and value amount in humanized base 2 bytes\n\t\t\tprint -v mem_out -m $y_pos $m_col -rs -fg $normal_color -jl 9 -t \"${value_text^}:\" -m $((y_pos++)) $((mem_line-10)) -jr 9 -t \" ${type_name[${value}_string]::$((m_width-11))}\"\n\n\t\t\t#* Create meter for value and calculate size and placement depending on terminal size\n\t\t\tif ((height>v_height++ | tty_width>100)); then\n\t\t\t\tif ((height<=v_height & tty_width<150)); then\n\t\t\t\t\tmeter_mod_w=12\n\t\t\t\t\tmeter_mod_pos=7\n\t\t\t\t\t((y_pos--))\n\t\t\t\telif ((height<=v_height)); then\n\t\t\t\t\tprint -v mem_out -m $((--y_pos)) $((m_col+5)) -jr 4 -t \"${type_name[${value}_percent]}%\"\n\t\t\t\t\tmeter_mod_w=14\n\t\t\t\t\tmeter_mod_pos=10\n\t\t\t\tfi\n\t\t\t\tcreate_meter -v ${type}_${value}_meter -w $((m_width-7-meter_mod_w)) -f -c color_${value}_graph ${type_name[${value}_percent]}\n\n\t\t\t\tmeter=\"${type}_${value}_meter\"\n\t\t\t\tprint -v mem_out -m $((y_pos++)) $((m_col+meter_mod_pos)) -t \"${!meter}\" -rs -fg $normal_color\n\n\t\t\t\tif [[ -z $meter_mod_w ]]; then print -v mem_out  -jr 4 -t \"${type_name[${value}_percent]}%\"; fi\n\t\t\tfi\n\t\t#if [[ $system == \"MacOS\" && -z $swap_on ]] && ((height>14)); then ((y_pos++)); fi\n\t\tdone\n\tdone\n\n\n\t#* Create text and meters for disks and adapt sizes based on available height\n\tlocal disk_num disk_name disk_value v_height2 just_val name_len\n\ty_pos=$m_line\n\tm_col=$((m_col+m_width))\n\tm_width=${box[m_width2]}\n\tv_height=$((${#disks_name[@]}))\n\tunset meter_mod_w meter_mod_pos\n\n\tfor disk_name in \"${disks_name[@]}\"; do\n\t\tif ((y_pos>m_line+height-2)); then break; fi\n\n\t\t#* Print folder disk is mounted on, total size in humanized base 2 bytes and io stats if enabled\n\t\tprint -v mem_out -m $((y_pos++)) $m_col -rs -fg ${theme[title]} -b -t \"${disks_name[disk_num]::10}\"\n\t\tname_len=${#disks_name[disk_num]}; if ((name_len>10)); then name_len=10; fi\n\t\tif [[ -n ${disks_io[disk_num]} && ${disks_io[disk_num]} != \"0\" ]] && ((m_width-11-name_len>6)); then\n\t\t\tprint -v mem_out -jc $((m_width-name_len-10)) -rs -fg ${theme[main_fg]} -t \"${disks_io[disk_num]::$((m_width-10-name_len))}\"\n\t\t\tjust_val=8\n\t\telse\n\t\t\tjust_val=$((m_width-name_len-2))\n\t\tfi\n\t\tprint -v mem_out -jr ${just_val} -fg ${theme[title]} -b -t \"${disks_total[disk_num]::$((m_width-11))}\"\n\n\t\tfor value in \"used\" \"free\"; do\n\t\t\tif ((height<v_height*3)) && [[ $value == \"free\" ]]; then break; fi\n\t\t\tlocal -n disk_value=\"disks_${value}\"\n\n\t\t\t#* Print name of value and value amount in humanized base 2 bytes\n\t\t\tprint -v mem_out -m $((y_pos++)) $m_col -rs -fg $normal_color -jl 9 -t \"${value^}:\" -jr $((m_width-11)) -t \"${disk_value[disk_num]::$((m_width-11))}\"\n\n\t\t\t#* Create meter for value and calculate size and placement depending on terminal size\n\t\t\tif ((height>=v_height*5 | tty_width>100)); then\n\t\t\t\tlocal -n disk_value_percent=\"disks_${value}_percent\"\n\t\t\t\tif ((height<=v_height*5 & tty_width<150)); then\n\t\t\t\t\tmeter_mod_w=12\n\t\t\t\t\tmeter_mod_pos=7\n\t\t\t\t\t((y_pos--))\n\t\t\t\telif ((height<=v_height*5)); then\n\t\t\t\t\tprint -v mem_out -m $((--y_pos)) $((m_col+5)) -jr 4 -t \"${disk_value_percent[disk_num]}%\"\n\t\t\t\t\tmeter_mod_w=14\n\t\t\t\t\tmeter_mod_pos=10\n\t\t\t\tfi\n\t\t\t\tcreate_meter -v disk_${disk_num}_${value}_meter -w $((m_width-7-meter_mod_w)) -f -c color_${value}_graph ${disk_value_percent[disk_num]}\n\n\t\t\t\tmeter=\"disk_${disk_num}_${value}_meter\"\n\t\t\t\tprint -v mem_out -m $((y_pos++)) $((m_col+meter_mod_pos)) -t \"${!meter}\" -rs -fg $normal_color\n\n\t\t\t\tif [[ -z $meter_mod_w ]]; then print -v mem_out -jr 4 -t \"${disk_value_percent[disk_num]}%\"; fi\n\t\t\tfi\n\t\t\tif ((y_pos>m_line+height-1)); then break; fi\n\t\tdone\n\t\tif ((height>=v_height*4 & height<v_height*5 | height>=v_height*6)); then ((y_pos++)); fi\n\t\t((++disk_num))\n\tdone\n\n\tif ((resized>0)); then ((resized++)); fi\n\t#* Print created text, graph and meters to output variable\n\tdraw_out+=\"${mem_graph[*]}${swap_graph[*]}${mem_out}\"\n\n}\n\ndraw_processes() { #? Draw processes and values to screen\n\tlocal argument=\"$1\"\n\tif [[ -n $skip_process_draw && $argument != \"now\" ]]; then return; fi\n\tlocal line=${box[processes_line]} col=${box[processes_col]} width=${box[processes_width]} height=${box[processes_height]} out_line y=1 fg_step_r=0 fg_step_g=0 fg_step_b=0 checker=2 page_string sel_string\n\tlocal reverse_string reverse_pos order_left=\"───────────┤\" filter_string current_num detail_location det_no_add com_fg pg_arrow_up_fg pg_arrow_down_fg p_height=$((height-3))\n\tlocal pid=0 pid_graph pid_step_r pid_step_g pid_step_b pid_add_r pid_add_g pid_add_b bg_add bg_step proc_start up_fg down_fg page_up_fg page_down_fg this_box=processes\n\tlocal d_width=${box[details_width]} d_height=${box[details_height]} d_line=${box[details_line]} d_col=${box[details_col]}\n\tlocal detail_graph_width=$((d_width/3+2)) detail_graph_height=$((d_height-1)) kill_fg det_mod fg_add_r fg_add_g fg_add_b\n\tlocal right_width=$((d_width-detail_graph_width-2))\n\tlocal right_col=$((d_col+detail_graph_width+4))\n\tlocal -a pid_rgb=(${theme[proc_misc]}) fg_rgb=(${theme[main_fg_dec]})\n\tlocal pid_r=${pid_rgb[0]} pid_g=${pid_rgb[1]} pid_b=${pid_rgb[2]} fg_r=${fg_rgb[0]} fg_g=${fg_rgb[1]} fg_b=${fg_rgb[2]}\n\n\tif [[ $argument == \"now\" ]]; then skip_process_draw=1; fi\n\n\tif [[ $proc_gradient == true ]]; then\n\t\tif ((fg_r+fg_g+fg_b<(255*3)/2)); then\n\t\t\tfg_add_r=\"$(( (fg_r-255-((fg_r-255)/6) )/height))\"\n\t\t\tfg_add_g=\"$(( (fg_g-255-((fg_g-255)/6) )/height))\"\n\t\t\tfg_add_b=\"$(( (fg_b-255-((fg_b-255)/6) )/height))\"\n\n\t\t\tpid_add_r=\"$(( (pid_r-255-((pid_r-255)/6) )/height))\"\n\t\t\tpid_add_g=\"$(( (pid_g-255-((pid_g-255)/6) )/height))\"\n\t\t\tpid_add_b=\"$(( (pid_b-255-((pid_b-255)/6) )/height))\"\n\t\telse\n\t\t\tfg_add_r=\"$(( (fg_r-(fg_r/6) )/height))\"\n\t\t\tfg_add_g=\"$(( (fg_g-(fg_g/6) )/height))\"\n\t\t\tfg_add_b=\"$(( (fg_b-(fg_b/6) )/height))\"\n\n\t\t\tpid_add_r=\"$(( (pid_r-(pid_r/6) )/height))\"\n\t\t\tpid_add_g=\"$(( (pid_g-(pid_g/6) )/height))\"\n\t\t\tpid_add_b=\"$(( (pid_b-(pid_b/6) )/height))\"\n\t\tfi\n\tfi\n\n\tunset proc_out\n\n\t#* Details box\n\tif ((proc[detailed_change]>0)) || ((proc[detailed]>0 & resized>0)); then\n\t\tproc[detailed_change]=0\n\t\tproc[order_change]=1\n\t\tproc[page_change]=1\n\t\tif ((proc[detailed]==1)); then\n\t\t\tunset proc_det\n\t\t\tlocal enter_fg enter_a_fg misc_fg misc_a_fg i det_y=6 dets cmd_y\n\n\t\t\tif [[ ${#detail_history[@]} -eq 1 ]] || ((resized>0)); then\n\t\t\t\tunset proc_det2\n\t\t\t\tcreate_graph -o detail_graph -d $((d_line+1)) $((d_col+1)) ${detail_graph_height} ${detail_graph_width} -c color_cpu_graph -n detail_history\n\t\t\t\tif ((tty_width>120)); then create_mini_graph -o detail_mem_graph -w $((right_width/3-3)) -nc detail_mem_history; fi\n\t\t\t\tdet_no_add=1\n\n\t\t\t\tfor detail_location in \"${d_line}\" \"$((d_line+d_height))\"; do\n\t\t\t\t\tprint -v proc_det2 -m ${detail_location} $((d_col+1)) -rs -fg ${box[processes_color]} -rp $((d_width-2)) -t \"─\"\n\t\t\t\tdone\n\t\t\t\tfor((i=1;i<d_height;i++)); do\n\t\t\t\t\tprint -v proc_det2 -m $((d_line+i)) $((d_col+3+detail_graph_width)) -rp $((right_width-1)) -t \" \"\n\t\t\t\t\tprint -v proc_det2 -m $((d_line+i)) ${d_col} -fg ${box[processes_color]} -t \"│\" -r $((detail_graph_width+1)) -fg ${theme[div_line]} -t \"│\" -r $((right_width+1)) -fg ${box[processes_color]} -t \"│\"\n\t\t\t\tdone\n\n\t\t\t\tprint -v proc_det2 -m ${d_line} ${d_col} -t \"┌\" -m ${d_line} $((d_col+d_width-1)) -t \"┐\"\n\t\t\t\tprint -v proc_det2 -m ${d_line} $((d_col+2+detail_graph_width)) -t \"┬\" -m $((d_line+d_height)) $((d_col+detail_graph_width+2)) -t \"┴\"\n\t\t\t\tprint -v proc_det2 -m $((d_line+d_height)) ${d_col} -t \"├\" -r 1 -t \"┤\" -fg ${theme[title]} -b -t \"${this_box}\" -rs -fg ${box[processes_color]} -t \"├\" -r $((d_width-5-${#this_box})) -t \"┤\"\n\t\t\t\tprint -v proc_det2 -m ${d_line} $((d_col+2)) -t \"┤\" -fg ${theme[title]} -b -t \"${proc[detailed_name],,}\" -rs -fg ${box[processes_color]} -t \"├\"\n\t\t\t\tif ((tty_width>128)); then print -v proc_det2 -r 1 -t \"┤\" -fg ${theme[title]} -b -t \"${proc[detailed_pid]}\" -rs -fg ${box[processes_color]} -t \"├\"; fi\n\n\n\n\t\t\t\tif ((${#proc[detailed_cmd]}>(right_width-6)*2)); then ((det_y--)); dets=2\n\t\t\t\telif ((${#proc[detailed_cmd]}>right_width-6)); then dets=1; fi\n\n\t\t\t\tprint -v proc_det2 -fg ${theme[title]} -b\n\t\t\t\tfor i in C M D; do\n\t\t\t\t\tprint -v proc_det2 -m $((d_line+5+cmd_y++)) $right_col -t \"$i\"\n\t\t\t\tdone\n\n\n\t\t\t\tprint -v proc_det2 -m $((d_line+det_y++)) $((right_col+1)) -jc $((right_width-4)) -rs -fg ${theme[main_fg]} -t \"${proc[detailed_cmd]::$((right_width-6))}\"\n\t\t\t\tif ((dets>0)); then print -v proc_det2 -m $((d_line+det_y++)) $((right_col+2)) -jl $((right_width-6)) -t \"${proc[detailed_cmd]:$((right_width-6)):$((right_width-6))}\"; fi\n\t\t\t\tif ((dets>1)); then print -v proc_det2 -m $((d_line+det_y)) $((right_col+2)) -jl $((right_width-6)) -t \"${proc[detailed_cmd]:$(( (right_width-6)*2 )):$((right_width-6))}\"; fi\n\n\t\t\tfi\n\n\n\t\t\tif ((proc[selected]>0)); then enter_fg=\"${theme[inactive_fg]}\"; enter_a_fg=\"${theme[inactive_fg]}\"; else enter_fg=\"${theme[title]}\"; enter_a_fg=\"${theme[hi_fg]}\"; fi\n\t\t\tif [[ -n ${proc[detailed_killed]} ]]; then misc_fg=\"${theme[title]}\"; misc_a_fg=\"${theme[hi_fg]}\"\n\t\t\telse misc_fg=$enter_fg; misc_a_fg=$enter_a_fg; fi\n\t\t\tprint -v proc_det -m ${d_line} $((d_col+d_width-11)) -fg ${box[processes_color]} -t \"┤\" -fg $enter_fg -b -t \"close \" -fg $enter_a_fg -t \"↲\" -rs -fg ${box[processes_color]} -t \"├\"\n\t\t\tif ((tty_width<129)); then det_mod=\"-8\"; fi\n\n\t\t\tprint -v proc_det -m ${d_line} $((d_col+detail_graph_width+4+det_mod)) -t \"┤\" -fg $misc_a_fg -b -t \"t\" -fg $misc_fg -t \"erminate\" -rs -fg ${box[processes_color]} -t \"├\"\n\t\t\tprint -v proc_det -r 1 -t \"┤\" -fg $misc_a_fg -b -t \"k\" -fg $misc_fg -t \"ill\" -rs -fg ${box[processes_color]} -t \"├\"\n\t\t\tif ((tty_width>104)); then print -v proc_det -r 1 -t \"┤\" -fg $misc_a_fg -b -t \"i\" -fg $misc_fg -t \"nterrupt\" -rs -fg ${box[processes_color]} -t \"├\"; fi\n\n\n\t\t\tproc_det=\"${proc_det2}${proc_det}\"\n\t\t\tproc_out=\"${proc_det}\"\n\n\t\telif ((resized==0)); then\n\t\t\tunset proc_det\n\t\t\tcreate_box -v proc_out -col ${box[${this_box}_col]} -line ${box[${this_box}_line]} -width ${box[${this_box}_width]} -height ${box[${this_box}_height]} -fill -lc \"${box[${this_box}_color]}\" -title ${this_box}\n\t\tfi\n\tfi\n\n\tif [[ ${proc[detailed]} -eq 1 ]]; then\n\t\tlocal det_status status_color det_columns=3\n\t\tif ((tty_width>140)); then ((det_columns++)); fi\n\t\tif ((tty_width>150)); then ((det_columns++)); fi\n\t\tif [[ -z $det_no_add && $1 != \"now\" && -z ${proc[detailed_killed]} ]]; then\n\t\t\tcreate_graph -add-last detail_graph detail_history\n\t\t\tif ((tty_width>120)); then create_mini_graph -w $((right_width/3-3)) -nc -add-last detail_mem_graph detail_mem_history; fi\n\t\tfi\n\n\t\tprint -v proc_out -fg ${theme[title]} -b\n\t\tcmd_y=0\n\t\tfor i in C P U; do\n\t\t\tprint -v proc_out -m $((d_line+3+cmd_y++)) $((d_col+1)) -t \"$i\"\n\t\tdone\n\t\tprint -v proc_out -m $((d_line+1)) $((d_col+1)) -fg ${theme[title]} -t \"${proc[detailed_cpu]}%\"\n\n\t\tif [[ -n ${proc[detailed_killed]} ]]; then det_status=\"stopped\"; status_color=\"${theme[inactive_fg]}\"\n\t\telse det_status=\"running\"; status_color=\"${theme[proc_misc]}\"; fi\n\t\tprint -v proc_out -m $((d_line+1)) ${right_col} -fg ${theme[title]} -b -jc $((right_width/det_columns-1)) -t \"Status:\" -jc $((right_width/det_columns)) -t \"Elapsed:\" -jc $((right_width/det_columns)) -t \"Parent:\"\n\t\tif ((det_columns>=4)); then print -v proc_out -jc $((right_width/det_columns-1)) -t \"User:\"; fi\n\t\tif ((det_columns>=5)); then print -v proc_out -jc $((right_width/det_columns-1)) -t \"Threads:\"; fi\n\t\tprint -v proc_out -m $((d_line+2)) ${right_col} -rs -fg ${status_color} -jc $((right_width/det_columns-1)) -t \"${det_status}\" -jc $((right_width/det_columns)) -fg ${theme[main_fg]} -t \"${proc[detailed_runtime]::$((right_width/det_columns-1))}\" -jc $((right_width/det_columns)) -t \"${proc[detailed_parent_name]::$((right_width/det_columns-2))}\"\n\t\tif ((det_columns>=4)); then print -v proc_out -jc $((right_width/det_columns-1)) -t \"${proc[detailed_user]::$((right_width/det_columns-2))}\"; fi\n\t\tif ((det_columns>=5)); then print -v proc_out -jc $((right_width/det_columns-1)) -t \"${proc[detailed_threads]}\"; fi\n\n\t\tprint -v proc_out -m $((d_line+4)) ${right_col} -fg ${theme[title]} -b -jr $((right_width/3+2)) -t \"Memory: ${proc[detailed_mem]}%\" -t \" \"\n\t\tif ((tty_width>120)); then print -v proc_out -rs -fg ${theme[inactive_fg]} -rp $((right_width/3-3)) \"⡀\" -l $((right_width/3-3)) -fg ${theme[proc_misc]} -t \"${detail_mem_graph}\" -t \" \"; fi\n\t\tprint -v proc_out -fg ${theme[title]} -b -t \"${proc[detailed_mem_string]}\"\n\tfi\n\n\t#* Print processes\n\tif ((${#proc_array[@]}<=p_height)); then\n\t\tproc[start]=1\n\telif (( proc[start]>(${#proc_array[@]}-1)-p_height )); then\n\t\tproc[start]=$(( (${#proc_array[@]}-1)-p_height ))\n\tfi\n\n\tif ((proc[selected]>${#proc_array[@]}-1)); then proc[selected]=$((${#proc_array[@]}-1)); fi\n\n\tif [[ $proc_gradient == true ]] && ((proc[selected]>1)); then\n\t\tfg_r=\"$(( fg_r-( fg_add_r*(proc[selected]-1) ) ))\"\n\t\tfg_g=\"$(( fg_g-( fg_add_g*(proc[selected]-1) ) ))\"\n\t\tfg_b=\"$(( fg_b-( fg_add_b*(proc[selected]-1) ) ))\"\n\n\t\tpid_r=\"$(( pid_r-( pid_add_r*(proc[selected]-1) ) ))\"\n\t\tpid_g=\"$(( pid_g-( pid_add_g*(proc[selected]-1) ) ))\"\n\t\tpid_b=\"$(( pid_b-( pid_add_b*(proc[selected]-1) ) ))\"\n\tfi\n\n\tcurrent_num=1\n\n\tprint -v proc_out -rs -m $((line+y++)) $((col+1)) -fg ${theme[title]} -b -t \"${proc_array[0]::$((width-3))} \" -rs\n\n\tlocal -a out_arr\n\tfor out_line in \"${proc_array[@]:${proc[start]}}\"; do\n\n\t\tif [[ $use_psutil == true ]]; then\n\t\t\tout_arr=(${out_line})\n\t\t\tpi=0\n\t\t\tif [[ $proc_tree == true ]]; then\n\t\t\t\twhile [[ ! ${out_arr[pi]} =~ ^[0-9]+$ ]]; do ((++pi)); done\n\t\t\tfi\n\t\t\tpid=\"${out_arr[pi]}\"\n\n\t\telse\n\t\t\tpid=\"${out_line::$((proc[pid_len]+1))}\"; pid=\"${pid// /}\"\n\t\t\tout_line=\"${out_line//'\\'/'\\\\'}\"\n\t\t\tout_line=\"${out_line//'$'/'\\$'}\"\n\t\t\tout_line=\"${out_line//'\"'/'\\\"'}\"\n\t\tfi\n\n\t\tpid_graph=\"pid_${pid}_graph\"\n\n\t\tif ((current_num==proc[selected])); then print -v proc_out -bg ${theme[selected_bg]} -fg ${theme[selected_fg]} -b; proc[selected_pid]=\"$pid\"\n\t\telse print -v proc_out -rs -fg $((fg_r-fg_step_r)) $((fg_g-fg_step_g)) $((fg_b-fg_step_b)); fi\n\n\t\tprint -v proc_out -m $((line+y)) $((col+1)) -t \"${out_line::$((width-3))} \"\n\n\t\tif ((current_num==proc[selected])); then print -v proc_out -rs -bg ${theme[selected_bg]}; fi\n\n\t\tprint -v proc_out -m $((line+y)) $((col+width-12)) -fg ${theme[inactive_fg]} -t \"⡀⡀⡀⡀⡀\"\n\n\t\tif [[ -n ${!pid_graph} ]]; then\n\t\t\tprint -v proc_out -m $((line+y)) $((col+width-12)) -fg $((pid_r-pid_step_r)) $((pid_g-pid_step_g)) $((pid_b-pid_step_b)) -t \"${!pid_graph}\"\n\t\tfi\n\n\t\t((y++))\n\t\t((current_num++))\n\t\tif ((y>height-2)); then break; fi\n\t\tif [[ $proc_gradient == false ]]; then :\n\t\telif ((current_num<proc[selected]+1)); then\n\t\t\tfg_step_r=$((fg_step_r-fg_add_r)); fg_step_g=$((fg_step_g-fg_add_g)); fg_step_b=$((fg_step_b-fg_add_b))\n\t\t\tpid_step_r=$((pid_step_r-pid_add_r)); pid_step_g=$((pid_step_g-pid_add_g)); pid_step_b=$((pid_step_b-pid_add_b))\n\t\telif ((current_num>=proc[selected])); then\n\t\t\tfg_step_r=$((fg_step_r+fg_add_r)); fg_step_g=$((fg_step_g+fg_add_g)); fg_step_b=$((fg_step_b+fg_add_b))\n\t\t\tpid_step_r=$((pid_step_r+pid_add_r)); pid_step_g=$((pid_step_g+pid_add_g)); pid_step_b=$((pid_step_b+pid_add_b))\n\t\tfi\n\n\tdone\n\t\tprint -v proc_out -rs\n\t\twhile ((y<=height-2)); do\n\t\t\tprint -v proc_out -m $((line+y++)) $((col+1)) -rp $((width-2)) -t \" \"\n\t\tdone\n\n\t\tif ((proc[selected]>0)); then sel_string=$((proc[start]-1+proc[selected])); else sel_string=0; fi\n\t\tpage_string=\"${sel_string}/$((${#proc_array[@]}-2${filter:++1}))\"\n\t\tprint -v proc_out -m $((line+height-1)) $((col+width-20)) -fg ${box[processes_color]} -rp 19 -t \"─\"\n\t\tprint -v proc_out -m $((line+height-1)) $((col+width-${#page_string}-4)) -fg ${box[processes_color]} -t \"┤\" -b -fg ${theme[title]} -t \"$page_string\" -rs -fg ${box[processes_color]} -t \"├\"\n\n\n\tif ((proc[order_change]==1 | proc[filter_change]==1 | resized>0)); then\n\t\tunset proc_misc\n\t\tproc[order_change]=0\n\t\tproc[filter_change]=0\n\t\tproc[page_change]=1\n\t\tprint -v proc_misc -m $line $((col+13)) -fg ${box[processes_color]} -rp $((box[processes_width]-14)) -t \"─\" -rs\n\n\t\tif ((proc[detailed]==1)); then\n\t\t\tprint -v proc_misc -m $((d_line+d_height)) $((d_col+detail_graph_width+2)) -fg ${box[processes_color]} -t \"┴\" -rs\n\t\tfi\n\n\t\tif ((tty_width>100)); then\n\t\t\treverse_string=\"-fg ${box[processes_color]} -t ┤ -fg ${theme[hi_fg]}${proc[reverse]:+ -ul} -b -t r -fg ${theme[title]} -t everse -rs -fg ${box[processes_color]} -t ├\"\n\t\t\treverse_pos=9\n\t\tfi\n\t\tprint -v proc_misc -m $line $((col+width-${#proc_sorting}-14-reverse_pos)) -rs\\\n\t\t${reverse_string}\\\n\t\t-fg ${box[processes_color]} -t ┤ -fg ${theme[title]}${proc[tree]:+ -ul} -b -t \"tre\" -fg ${theme[hi_fg]} -t \"e\" -rs -fg ${box[processes_color]} -t ├\\\n\t\t-fg ${box[processes_color]} -t \"┤\" -fg ${theme[hi_fg]} -b -t \"‹\" -fg ${theme[title]} -t \" ${proc_sorting} \"  -fg ${theme[hi_fg]} -t \"›\" -rs -fg ${box[processes_color]} -t \"├\"\n\n\t\tif [[ -z $filter && -z $input_to_filter ]]; then\n\t\t\tprint -v proc_misc -m $line $((col+14)) -fg ${box[processes_color]} -t \"┤\" -fg ${theme[hi_fg]} -b -t \"f\" -fg ${theme[title]} -t \"ilter\" -rs -fg ${box[processes_color]} -t \"├\"\n\t\telif [[ -n $input_to_filter ]]; then\n\t\t\tif [[ ${#filter} -le $((width-35-reverse_pos)) ]]; then filter_string=\"${filter}\"\n\t\t\telif [[ ${#filter} -gt $((width-35-reverse_pos)) ]]; then filter_string=\"${filter: (-$((width-35-reverse_pos)))}\"\n\t\t\tfi\n\t\t\tprint -v proc_misc -m $line $((col+14)) -fg ${box[processes_color]} -t \"┤\" -fg ${theme[title]} -b -t \"${filter_string}\" -fg ${theme[proc_misc]} -bl -t \"█\" -rs -fg ${box[processes_color]} -t \"├\"\n\t\telif [[ -n $filter ]]; then\n\t\t\tif [[ ${#filter} -le $((width-35-reverse_pos-4)) ]]; then filter_string=\"${filter}\"\n\t\t\telif [[ ${#filter} -gt $((width-35-reverse_pos-4)) ]]; then filter_string=\"${filter::$((width-35-reverse_pos-4))}\"\n\t\t\tfi\n\t\t\tprint -v proc_misc -m $line $((col+14)) -fg ${box[processes_color]} -t \"┤\" -fg ${theme[hi_fg]} -b -t \"f\" -fg ${theme[title]} -t \" ${filter_string} \" -fg ${theme[hi_fg]} -t \"c\" -rs -fg ${box[processes_color]} -t \"├\"\n\t\tfi\n\n\t\tproc_out+=\"${proc_misc}\"\n\tfi\n\n\tif ((proc[page_change]==1 | resized>0)); then\n\t\tunset proc_misc2\n\t\tproc[page_change]=0\n\t\tif ((proc[selected]>0)); then kill_fg=\"${theme[hi_fg]}\"; com_fg=\"${theme[title]}\"; else kill_fg=\"${theme[inactive_fg]}\"; com_fg=\"${theme[inactive_fg]}\"; fi\n\t\tif ((proc[selected]==(${#proc_array[@]}-1${filter:++1})-proc[start])); then down_fg=\"${theme[inactive_fg]}\"; else down_fg=\"${theme[hi_fg]}\"; fi\n\t\tif ((proc[selected]>0 | proc[start]>1)); then up_fg=\"${theme[hi_fg]}\"; else up_fg=\"${theme[inactive_fg]}\"; fi\n\n\t\tprint -v proc_misc2 -m $((line+height-1)) $((col+2)) -fg ${box[processes_color]} -t \"┤\" -fg $up_fg -b -t \"↑\" -fg ${theme[title]} -t \" select \" -fg $down_fg -t \"↓\" -rs -fg ${box[processes_color]} -t \"├\"\n\t\tprint -v proc_misc2 -r 1 -fg ${box[processes_color]} -t \"┤\" -fg $com_fg -b -t \"info \" -fg $kill_fg \"↲\" -rs -fg ${box[processes_color]} -t \"├\"\n\t\tif ((tty_width>100)); then print -v proc_misc2 -r 1 -t \"┤\" -fg $kill_fg -b -t \"t\" -fg $com_fg -t \"erminate\" -rs -fg ${box[processes_color]} -t \"├\"; fi\n\t\tif ((tty_width>111)); then print -v proc_misc2 -r 1 -t \"┤\" -fg $kill_fg -b -t \"k\" -fg $com_fg -t \"ill\" -rs -fg ${box[processes_color]} -t \"├\"; fi\n\t\tif ((tty_width>126)); then print -v proc_misc2 -r 1 -t \"┤\" -fg $kill_fg -b -t \"i\" -fg $com_fg -t \"nterrupt\" -rs -fg ${box[processes_color]} -t \"├\"; fi\n\n\t\tproc_out+=\"${proc_misc2}\"\n\tfi\n\n\tproc_out=\"${detail_graph[*]}${proc_out}\"\n\n\tif ((resized>0)); then ((resized++)); fi\n\n\tif [[ $argument == \"now\" ]]; then\n\t\techo -en \"${proc_out}\"\n\tfi\n\n}\n\ndraw_net() { #? Draw net information and graphs to screen\n\tlocal net_out argument=$1\n\tif [[ -n ${net[no_device]} ]]; then return; fi\n\tif [[ -n $skip_net_draw && $argument != \"now\" ]]; then return; fi\n\tif [[ $argument == \"now\" ]]; then skip_net_draw=1; fi\n\n\t#* Get variables from previous calculations\n\tlocal col=$((box[net_col]+1)) line=$((box[net_line]+1)) width=$((box[net_width]-2)) height=$((box[net_height]-2))\n\tlocal n_width=${box[n_width]} n_height=${box[n_height]} n_col=${box[n_col]} n_line=${box[n_line]} main_fg=\"${theme[main_fg]}\"\n\n\t#* If resized recreate net meter box and net graphs\n\tif ((resized>0)); then\n\t\tlocal graph_a_size graph_b_size\n\t\tgraph_a_size=$(( (height)/2 )); graph_b_size=${graph_a_size}\n\t\tif ((graph_a_size*2<height)); then ((graph_a_size++)); fi\n\t\tnet[graph_a_size]=$graph_a_size\n\t\tnet[graph_b_size]=$graph_b_size\n\t\tnet[download_redraw]=0\n\t\tnet[upload_redraw]=0\n\t\t((resized++))\n\tfi\n\n\t#* Update graphs if graph resolution update is needed or just resized, otherwise just add new values\n\tif ((net[download_redraw]==1 | net[nic_change]==1 | resized>0)); then\n\t\tcreate_graph -o download_graph -d $line $col ${net[graph_a_size]} $((width-n_width-2)) -c color_download_graph -n -max \"${net[download_graph_max]}\" net_history_download\n\telse\n\t\tcreate_graph -max \"${net[download_graph_max]}\" -add-last download_graph net_history_download\n\tfi\n\tif ((net[upload_redraw]==1 | net[nic_change]==1 | resized>0)); then\n\t\tcreate_graph -o upload_graph -d $((line+net[graph_a_size])) $col ${net[graph_b_size]} $((width-n_width-2)) -c color_upload_graph -i -n -max \"${net[upload_graph_max]}\" net_history_upload\n\telse\n\t\tcreate_graph -max \"${net[upload_graph_max]}\" -i -add-last upload_graph net_history_upload\n\tfi\n\n\tif ((net[nic_change]==1 | resized>0)); then\n\t\tlocal dev_len=${#net[device]}\n\t\tif ((dev_len>15)); then dev_len=15; fi\n\t\tunset net_misc 'net[nic_change]'\n\t\tprint -v net_out -m $((line-1)) $((width-23)) -rs -fg ${box[net_color]} -rp 23 -t \"─\"\n\t\tprint -v net_misc -m $((line-1)) $((width-7-dev_len)) -rs -fg ${box[net_color]} -t \"┤\" -fg ${theme[hi_fg]} -b -t \"‹b \" -fg ${theme[title]} -t \"${net[device]::15}\" -fg ${theme[hi_fg]} -t \" n›\" -rs -fg ${box[net_color]} -t \"├\"\n\t\tnet_out+=\"${net_misc}\"\n\tfi\n\n\t#* Create text depening on box height\n\tlocal ypos=$n_line\n\n\tprint -v net_out -fg ${main_fg} -m $((ypos++)) $n_col -jl 10 -t \"▼ Byte:\" -jr 12 -t \"${net[speed_download_byteps]}\"\n\tif ((height>4)); then print -v net_out -fg ${main_fg} -m $((ypos++)) $n_col -jl 10 -t \"▼ Bit:\" -jr 12 -t \"${net[speed_download_bitps]}\"; fi\n\tif ((height>6)); then print -v net_out -fg ${main_fg} -m $((ypos++)) $n_col -jl 10 -t \"▼ Total:\" -jr 12 -t \"${net[total_download]}\"; fi\n\n\tif ((height>8)); then ((ypos++)); fi\n\tprint -v net_out -fg ${main_fg} -m $((ypos++)) $n_col -jl 10 -t \"▲ Byte:\" -jr 12 -t \"${net[speed_upload_byteps]}\"\n\tif ((height>7)); then print -v net_out -fg ${main_fg} -m $((ypos++)) $n_col -jl 10 -t \"▲ Bit:\" -jr 12 -t \"${net[speed_upload_bitps]}\"; fi\n\tif ((height>5)); then print -v net_out -fg ${main_fg} -m $((ypos++)) $n_col -jl 10 -t \"▲ Total:\" -jr 12 -t \"${net[total_upload]}\"; fi\n\n\tprint -v net_out -fg ${theme[inactive_fg]} -m $line $col -t \"${net[download_max_string]}\"\n\tprint -v net_out -fg ${theme[inactive_fg]} -m $((line+height-1)) $col -t \"${net[upload_max_string]}\"\n\n\n\t#* Print graphs and text to output variable\n\tdraw_out+=\"${download_graph[*]}${upload_graph[*]}${net_out}\"\n\tif [[ $argument == \"now\" ]]; then echo -en \"${download_graph[*]}${upload_graph[*]}${net_out}\"; fi\n}\n\ndraw_clock() { #? Draw a clock at top of screen\n\tif [[ -z $draw_clock ]]; then return; fi\n\tif [[ $resized -gt 0 && $resized -lt 5 ]]; then unset clock_out; return; fi\n\tlocal width=${box[cpu_width]} color=${box[cpu_color]} old_time_string=\"${time_string}\"\n\t#time_string=\"$(date ${draw_clock})\"\n\tprintf -v time_string \"%(${draw_clock})T\"\n\tif [[ $old_time_string != \"$time_string\" || -z $clock_out ]]; then\n\t\tunset clock_out\n\t\tprint -v clock_out -m 1 $((width/2-${#time_string}/2)) -rs -fg ${color} -t \"┤\" -fg ${theme[title]} -b -t \"${time_string}\" -fg ${color} -t \"├\"\n\tfi\n\tif [[ $1 == \"now\" ]]; then echo -en \"${clock_out}\"; fi\n}\n\ndraw_update_string() {\n\tunset update_string\n\tprint -v update_string -m ${box[cpu_line]} $((box[cpu_col]+box[cpu_width]-${#update_ms}-14)) -rs -fg ${box[cpu_color]} -t \"────┤\"  -fg ${theme[hi_fg]} -b -t \"+\" -fg ${theme[title]} -b -t \" ${update_ms}ms \"  -fg ${theme[hi_fg]} -b -t \"-\" -rs -fg ${box[cpu_color]} -t \"├\"\n\tif [[ $1 == \"quiet\" ]]; then draw_out+=\"${update_string}\"\n\telse echo -en \"${update_string}\"; fi\n}\n\npause_() { #? Pause input and draw a darkened version of main ui\n\tlocal pause_out ext_var\n\tif [[ -n $1 && $1 != \"off\" ]]; then local -n pause_out=${1}; ext_var=1; fi\n\tif [[ $1 != \"off\" ]]; then\n\t\tprev_screen=\"${boxes_out}${proc_det}${last_screen}${net_misc}${mem_out}${detail_graph[*]}${proc_out}${proc_misc}${proc_misc2}${update_string}${clock_out}\"\n\t\tif [[ -n $skip_process_draw ]]; then\n\t\t\tprev_screen+=\"${proc_out}\"\n\t\t\tunset skip_process_draw proc_out\n\t\tfi\n\n\t\tunset pause_screen\n\t\tprint -v pause_screen -rs -b -fg ${theme[inactive_fg]}\n\t\tpause_screen+=\"${theme[main_bg]}m$(${sed} -E 's/\\\\e\\[[0-9;\\-]*m//g' <<< \"${prev_screen}\")\\e[0m\" #\\e[1;38;5;236\n\n\t\tif [[ -z $ext_var ]]; then echo -en \"${pause_screen}\"\n\t\telse pause_out=\"${pause_screen}\"; fi\n\n\telif [[ $1 == \"off\" ]]; then\n\t\techo -en \"${prev_screen}\"\n\t\tunset pause_screen prev_screen\n\tfi\n}\n\nunpause_() { #? Unpause\n\tpause_ off\n}\n\nmenu_() { #? Shows the main menu overlay\n\tlocal menu i count keypress selected_int=0 selected up local_rez d_banner=1 menu_out bannerd skipped menu_pause out_out wait_string trans\n\tlocal -a menus=(\"options\" \"help\" \"quit\") color\n\tunset bannerd menu_out\n\tuntil false; do\n\n\t\t#* Put program to sleep if caught ctrl-z\n\t\tif ((sleepy==1)); then sleep_; fi\n\n\t\tif [[ $background_update == true || -z $menu_out ]]; then\n\t\t\tdraw_clock\n\t\t\tpause_ menu_pause\n\t\telse\n\t\t\tunset menu_pause\n\t\tfi\n\n\t\tunset draw_out\n\n\t\tif [[ -z ${bannerd} ]]; then\n\t\t\tdraw_banner \"$((tty_height/2-10))\" bannerd\n\t\t\tunset d_banner\n\t\tfi\n\t\tif [[ -n ${keypress} || -z ${menu_out} ]]; then\n\t\t\tunset menu_out\n\t\t\tprint -v menu_out -t \"${bannerd}\"\n\t\t\tprint -v menu_out -d 1 -rs\n\t\t\tselected=\"${menus[selected_int]}\"\n\t\t\tunset up\n\t\t\tif [[ -n ${theme[main_bg_dec]} ]] && ((${theme[main_bg_dec]// /*}>255**3/2)); then print -v menu_out -bg \"#00\"; unset trans; else trans=\" -trans\"; fi\n\t\t\tfor menu in \"${menus[@]}\"; do\n\t\t\t\tif [[ $menu == \"$selected\" ]]; then\n\t\t\t\t\tlocal -n menu_array=\"menu_${menu}_selected\"\n\t\t\t\t\tcolor=(\"#c55e5e\" \"#c23d3d\" \"#a13030\" \"#8c2626\")\n\t\t\t\telse\n\t\t\t\t\tlocal -n menu_array=\"menu_${menu}\"\n\t\t\t\t\tcolor=(\"#bb\" \"#aa\" \"#99\" \"#88\")\n\t\t\t\tfi\n\t\t\t\tup=$((up+${#menu_array[@]}))\n\t\t\t\tfor((i=0;i<${#menu_array[@]};i++)); do\n\t\t\t\t\tprint -v menu_out -d 1 -fg ${color[i]} -c${trans} -t \"${menu_array[i]}\"\n\t\t\t\tdone\n\t\t\tdone\n\t\t\tprint -v menu_out -rs -u ${up}\n\t\tfi\n\t\tunset out_out\n\t\tout_out=\"${menu_pause}${menu_out}\"\n\t\techo -e \"${out_out}\"\n\n\n\t\tget_ms timestamp_end\n\t\ttime_left=$((timestamp_start+update_ms-timestamp_end))\n\n\t\tif ((time_left>1000)); then wait_string=10; time_left=$((time_left-1000))\n\t\telif ((time_left>100)); then wait_string=$((time_left/100)); time_left=0\n\t\telse wait_string=\"0\"; time_left=0; fi\n\n\t\tget_key -v keypress -w ${wait_string}\n\t\tif [[ $(${stty} size) != \"$tty_height $tty_width\" ]]; then resized; fi\n\t\tif ((resized>0)); then\n\t\t\tcalc_sizes; draw_bg quiet; time_left=0; unset menu_out\n\t\t\tunset bannerd\n\t\t\techo -en \"${clear_screen}\"\n\t\tfi\n\n\t\tcase \"$keypress\" in\n\t\t\tup|shift_tab) if ((selected_int>0)); then ((selected_int--)); else selected_int=$((${#menus[@]}-1)); fi ;;\n\t\t\tdown|tab) if ((selected_int<${#menus[@]}-1)); then ((++selected_int)); else selected_int=0; fi ;;\n\t\t\tenter|space)\n\t\t\t\tcase \"$selected\" in\n\t\t\t\t\toptions) options_ ;;\n\t\t\t\t\thelp) help_ ;;\n\t\t\t\t\tquit) quit_ ;;\n\t\t\t\tesac\n\t\t\t;;\n\t\t\tm|M|escape|backspace) break ;;\n\t\t\tq|Q) quit_ ;;\n\t\tesac\n\n\t\tif ((time_left==0)) && [[ -z $keypress ]]; then get_ms timestamp_start; collect_and_draw; fi\n\t\tif ((resized>=5)); then resized=0; fi\n\n\tdone\n\tunpause_\n\n}\n\nhelp_() { #? Shows the help overlay\n\tlocal help_key from_menu col line y i help_out help_pause redraw=1 wait_string pages page=1 height\n\tlocal -a shortcuts descriptions\n\n\tshortcuts=(\n\t\t\"(Esc, M, m)\"\n\t\t\"(F2, O, o)\"\n\t\t\"(F1, H, h)\"\n\t\t\"(Ctrl-C, Q, q)\"\n\t\t\"(+, A, a) (-, S, s)\"\n\t\t\"(Up) (Down)\"\n\t\t\"(Enter)\"\n\t\t\"(Pg Up) (Pg Down)\"\n\t\t\"(Home) (End)\"\n\t\t\"(Left) (Right)\"\n\t\t\"(b, B) (n, N)\"\n\t\t\"(E, e)\"\n\t\t\"(R, r)\"\n\t\t\"(F, f)\"\n\t\t\"(C, c)\"\n\t\t\"Selected (T, t)\"\n\t\t\"Selected (K, k)\"\n\t\t\"Selected (I, i)\"\n\t\t\" \"\n\t\t\" \"\n\t\t\" \"\n\t)\n\tdescriptions=(\n\t\t\"Shows main menu.\"\n\t\t\"Shows options.\"\n\t\t\"Shows this window.\"\n\t\t\"Quits program.\"\n\t\t\"Add/Subtract 100ms to/from update timer.\"\n\t\t\"Select in process list.\"\n\t\t\"Show detailed information for selected process.\"\n\t\t\"Jump 1 page in process list.\"\n\t\t\"Jump to first or last page in process list.\"\n\t\t\"Select previous/next sorting column.\"\n\t\t\"Select previous/next network device.\"\n\t\t\"Toggle processes tree view\"\n\t\t\"Reverse sorting order in processes box.\"\n\t\t\"Input a string to filter processes with.\"\n\t\t\"Clear any entered filter.\"\n\t\t\"Terminate selected process with SIGTERM - 15.\"\n\t\t\"Kill selected process with SIGKILL - 9.\"\n\t\t\"Interrupt selected process with SIGINT - 2.\"\n\t\t\" \"\n\t\t\"For bug reporting and project updates, visit:\"\n\t\t\"\\e[1mhttps://github.com/aristocratos/bashtop\"\n\t)\n\n\tif [[ -n $pause_screen ]]; then from_menu=1; fi\n\n\tuntil [[ -n $help_key ]]; do\n\n\t\t#* Put program to sleep if caught ctrl-z\n\t\tif ((sleepy==1)); then sleep_; redraw=1; fi\n\n\t\tif [[ $background_update == true || -n $redraw ]]; then\n\t\t\tdraw_clock\n\t\t\tpause_ help_pause\n\t\telse\n\t\t\tunset help_pause\n\t\tfi\n\n\n\t\tif [[ -n $redraw ]]; then\n\t\t\tcol=$((tty_width/2-36)); line=$((tty_height/2-4)); y=1; height=$((tty_height-2-line))\n\t\t\tif ((${#shortcuts[@]}>height)); then pages=$(( (${#shortcuts[@]}/height)+1 )); else height=${#shortcuts[@]}; unset pages; fi\n\t\t\tunset redraw help_out\n\t\t\tdraw_banner \"$((tty_height/2-11))\" help_out\n\t\t\tprint -d 1\n\t\t\tcreate_box -v help_out -w 72 -h $((height+3)) -l $((line++)) -c $((col++)) -fill -lc ${theme[div_line]} -title \"help\"\n\n\t\t\tif [[ -n $pages ]]; then\n\t\t\t\tprint -v help_out -m $((line+height+1)) $((col+72-16)) -rs -fg ${theme[div_line]} -t \"┤\" -fg ${theme[title]} -b -t \"pg\" -fg ${theme[hi_fg]} -t \"↑\"\\\n\t\t\t\t-fg ${theme[title]} -t \" ${page}/${pages} \" -fg ${theme[title]} -t \"pg\" -fg ${theme[hi_fg]} -t \"↓\" -rs -fg ${theme[div_line]} -t \"├\"\n\t\t\tfi\n\t\t\t((++col))\n\n\t\t\tprint -v help_out -m $line $col -fg ${theme[title]} -b -jl 20 -t \"Key:\" -jl 48 -t \"Description:\" -m $((line+y++)) $col\n\n\t\t\tfor((i=(page-1)*height;i<page*height;i++)); do\n\t\t\t\tprint -v help_out -fg ${theme[main_fg]} -b -jl 20 -t \"${shortcuts[i]}\" -rs -fg ${theme[main_fg]} -jl 48 -t \"${descriptions[i]}\" -m $((line+y++)) $col\n\t\t\tdone\n\t\tfi\n\n\n\t\tunset draw_out\n\t\techo -en \"${help_pause}${help_out}\"\n\n\t\tget_ms timestamp_end\n\t\ttime_left=$((timestamp_start+update_ms-timestamp_end))\n\n\t\tif ((time_left>1000)); then wait_string=10; time_left=$((time_left-1000))\n\t\telif ((time_left>100)); then wait_string=$((time_left/100)); time_left=0\n\t\telse wait_string=\"0\"; time_left=0; fi\n\n\t\tget_key -v help_key -w \"${wait_string}\"\n\n\t\tif [[ -n $pages ]]; then\n\t\t\tcase $help_key in\n\t\t\t\tdown|page_down) if ((page<pages)); then ((page++)); else page=1; fi; redraw=1; unset help_key ;;\n\t\t\t\tup|page_up) if ((page>1)); then ((page--)); else page=${pages}; fi; redraw=1; unset help_key ;;\n\t\t\tesac\n\t\tfi\n\n\t\tif [[ $(${stty} size) != \"$tty_height $tty_width\" ]]; then resized; fi\n\t\tif ((resized>0)); then\n\t\t\t${sleep} 0.5\n\t\t\tcalc_sizes; draw_bg quiet; redraw=1\n\t\t\td_banner=1\n\t\t\tunset bannerd menu_out\n\t\tfi\n\t\tif ((time_left==0)); then get_ms timestamp_start; collect_and_draw; fi\n\t\tif ((resized>0)); then resized=0; fi\n\tdone\n\n\tif [[ -n $from_menu ]]; then pause_\n\telse unpause_; fi\n}\n\noptions_() { #? Shows the options overlay\n\tlocal keypress from_menu col line y=1 i=1 options_out selected_int=0 ypos option_string options_misc option_value bg fg skipped start_t end_t left_t changed_cpu_name theme_int=0 page=1 pages height\n\tlocal desc_col right left enter lr inp valid updated_ms local_rez redraw_misc=1 desc_pos desc_height options_pause updated_proc inputting inputting_value inputting_key file theme_check net_totals_reset\n\n\tif ((net[reset]==1)); then net_totals_reset=\"On\"; else net_totals_reset=\"Off\"; fi\n\n\t#* Check theme folder for theme files\n\tget_themes\n\n\tdesc_color_theme=(\t\"Set bashtop color theme.\"\n\t\t\t\t\t\t\" \"\n\t\t\t\t\t\t\"Choose between theme files located in\"\n\t\t\t\t\t\t\"\\\"\\$HOME/.config/bashtop/themes\\\" &\"\n\t\t\t\t\t\t\"\\\"\\$HOME/.config/bashtop/user_themes\"\n\t\t\t\t\t\t\" \"\n\t\t\t\t\t\t\"User themes are prefixed with \\\"*\\\".\"\n\t\t\t\t\t\t\"\\\"Default\\\" for builtin default.\"\n\t\t\t\t\t\t\" \")\n\tif [[ -z $curled ]]; then desc_color_theme+=(\"Get more themes at:\"\n\t\t\t\t\t\t\"https://github.com/aristocratos/bashtop\")\n\telse desc_color_theme+=(\"\\e[1mPress ENTER to download the default themes.\"\n\t\t\t\t\t\t\t\"Will overwrite changes made to the default\"\n\t\t\t\t\t\t\t\"themes if not copied to user_themes folder.\"); fi\n\n\tdesc_update_ms=(\t\"Update time in milliseconds.\"\n\t\t\t\t\t\t\"Recommended 2000 ms or above for better sample\"\n\t\t\t\t\t\t\"times for graphs.\"\n\t\t\t\t\t\t\" \"\n\t\t\t\t\t\t\"Increases automatically if set below internal\"\n\t\t\t\t\t\t\"loops processing time.\"\n\t\t\t\t\t\t\" \"\n\t\t\t\t\t\t\"Max value: 86400000 ms = 24 hours.\")\n\tdesc_use_psutil=(\t\"Enable the use of psutil python3 module for\"\n\t\t\t\t\t\t\"data collection. Default on non Linux.\"\n\t\t\t\t\t\t\"\"\n\t\t\t\t\t\t\"Program will automatically restart if changing\"\n\t\t\t\t\t\t\"this setting to check for compatibility.\"\n\t\t\t\t\t\t\" \"\n\t\t\t\t\t\t\"True or false.\"\n\t\t\t\t\t\t\" \"\n\t\t\t\t\t\t\"Can only be switched off when on Linux.\")\n\tdesc_proc_sorting=(\t\"Processes sorting.\"\n\t\t\t\t\t\t\"Valid values are \\\"pid\\\", \\\"program\\\", \\\"arguments\\\",\"\n\t\t\t\t\t\t\"\\\"threads\\\", \\\"user\\\", \\\"memory\\\", \\\"cpu lazy\\\"\"\n\t\t\t\t\t\t\"\\\"cpu responsive\\\" and \\\"tree\\\".\"\n\t\t\t\t\t\t\" \"\n\t\t\t\t\t\t\"\\\"cpu lazy\\\" shows cpu usage over the lifetime\"\n\t\t\t\t\t\t\"of a process.\"\n\t\t\t\t\t\t\" \"\n\t\t\t\t\t\t\"\\\"cpu responsive\\\" updates sorting directly at a\"\n\t\t\t\t\t\t\"cost of cpu time (unless using psutil).\"\n\t\t\t\t\t\t\" \"\n\t\t\t\t\t\t\"\\\"tree\\\" shows a tree structure of running\"\n\t\t\t\t\t\t\"processes. (not available with psutil)\")\n\tdesc_proc_tree=(\t\"Processes tree view.\"\n\t\t\t\t\t\t\" \"\n\t\t\t\t\t\t\"Set true to show processes grouped by parents,\"\n\t\t\t\t\t\t\"with lines drawn between parent and child\"\n\t\t\t\t\t\t\"process.\"\n\t\t\t\t\t\t\" \"\n\t\t\t\t\t\t\"True or false.\")\n\tdesc_check_temp=(\t\"Check cpu temperature.\"\n\t\t\t\t\t\t\" \"\n\t\t\t\t\t\t\"True or false.\"\n\t\t\t\t\t\t\" \"\n\t\t\t\t\t\t\"Only works if sensors, vcgencmd or osx-cpu-temp\"\n\t\t\t\t\t\t\"commands is available.\")\n\tdesc_draw_clock=(\t\"Draw a clock at top of screen.\"\n\t\t\t\t\t\t\" \"\n\t\t\t\t\t\t\"Formatting according to strftime, empty\"\n\t\t\t\t\t\t\"string to disable.\"\n\t\t\t\t\t\t\" \"\n\t\t\t\t\t\t\"\\\"%X\\\" locale HH:MM:SS\"\n\t\t\t\t\t\t\"\\\"%H\\\" 24h hour, \\\"%I\\\" 12h hour\"\n\t\t\t\t\t\t\"\\\"%M\\\" minute, \\\"%S\\\" second\"\n\t\t\t\t\t\t\"\\\"%d\\\" day, \\\"%m\\\" month, \\\"%y\\\" year\")\n\tdesc_background_update=( \"Update main ui when menus are showing.\"\n\t\t\t\t\t\t\t\" \"\n\t\t\t\t\t\t\t\"True or false.\"\n\t\t\t\t\t\t\t\" \"\n\t\t\t\t\t\t\t\"Set this to false if the menus is flickering\"\n\t\t\t\t\t\t\t\"too much for a comfortable experience.\")\n\tdesc_custom_cpu_name=(\t\"Custom cpu model name in cpu percentage box.\"\n\t\t\t\t\t\t\t\" \"\n\t\t\t\t\t\t\t\"Empty string to disable.\")\n\tdesc_error_logging=(\"Enable error logging to\"\n\t\t\t\t\t\t\"\\\"\\$HOME/.config/bashtop/error.log\\\"\"\n\t\t\t\t\t\t\" \"\n\t\t\t\t\t\t\"Program will be automatically restarted if\"\n\t\t\t\t\t\t\"changing this option.\"\n\t\t\t\t\t\t\" \"\n\t\t\t\t\t\t\"True or false.\")\n\tdesc_proc_reversed=(\"Reverse sorting order.\"\n\t\t\t\t\t\t\" \"\n\t\t\t\t\t\t\"True or false.\")\n\tdesc_proc_gradient=(\"Show color gradient in process list.\"\n\t\t\t\t\t\t\" \"\n\t\t\t\t\t\t\"True or False.\")\n\tdesc_disks_filter=(\"Optional filter for shown disks.\"\n\t\t\t\t\t\t\" \"\n\t\t\t\t\t\t\"Should be names of mountpoints.\"\n\t\t\t\t\t\t\"\\\"root\\\" replaces \\\"/\\\"\"\n\t\t\t\t\t\t\" \"\n\t\t\t\t\t\t\"Separate multiple values with space.\"\n\t\t\t\t\t\t\"Example: \\\"root home external\\\"\")\n\tdesc_net_totals_reset=(\"Press ENTER to toggle network upload\"\n\t\t\t\t\t\t\t\"and download totals reset.\"\n\t\t\t\t\t\t\t\" \"\n\t\t\t\t\t\t\t\"Shows totals since system start or\"\n\t\t\t\t\t\t\t\"network adapter reset when Off.\")\n\tdesc_proc_per_core=(\"Process usage per core.\"\n\t\t\t\t\t\t\" \"\n\t\t\t\t\t\t\"If process cpu usage should be of the core\"\n\t\t\t\t\t\t\"it's running on or usage of the total\"\n\t\t\t\t\t\t\"available cpu power.\"\n\t\t\t\t\t\t\"\"\n\t\t\t\t\t\t\"If true and process is multithreaded\"\n\t\t\t\t\t\t\"cpu usage can reach over 100%.\")\n\tdesc_update_check=( \"Check for updates.\"\n\t\t\t\t\t\t\" \"\n\t\t\t\t\t\t\"Enable check for new version from\"\n\t\t\t\t\t\t\"github.com/aristocratos/bashtop at start.\"\n\t\t\t\t\t\t\" \"\n\t\t\t\t\t\t\"True or False.\")\n\tdesc_hires_graphs=(\"Enable high resolution graphs.\"\n\t\t\t\t\t\t\" \"\n\t\t\t\t\t\t\"Doubles the horizontal resolution of all\"\n\t\t\t\t\t\t\"graphs. At a cpu usage cost.\"\n\t\t\t\t\t\t\"Needs restart to take effect.\"\n\t\t\t\t\t\t\" \"\n\t\t\t\t\t\t\"True or False.\")\n\n\tif [[ -n $pause_screen ]]; then from_menu=1; fi\n\n\tuntil false; do\n\n\t\t#* Put program to sleep if caught ctrl-z\n\t\tif ((sleepy==1)); then sleep_; fi\n\n\n\t\tif [[ $background_update == true || -n $redraw_misc ]]; then\n\t\t\tdraw_clock\n\t\t\tif [[ -z $inputting ]]; then pause_ options_pause; fi\n\t\telse\n\t\t\tunset options_pause\n\t\tfi\n\n\t\tif [[ -n $redraw_misc ]]; then\n\t\t\tunset options_misc redraw_misc\n\t\t\tcol=$((tty_width/2-39))\n\t\t\tline=$((tty_height/2-4))\n\t\t\theight=$(( (tty_height-2-line)/2 ))\n\t\t\tif ((${#options_array[@]}>height)); then pages=$(( (${#options_array[@]}/height)+1 )); else height=${#options_array[@]}; unset pages; fi\n\t\t\tdesc_col=$((col+30))\n\t\t\tdraw_banner \"$((tty_height/2-11))\" options_misc\n\t\t\tcreate_box -v options_misc -w 29 -h $((height*2+2)) -l $line -c $((col-1)) -fill -lc ${theme[div_line]} -title \"options\"\n\t\t\tif [[ -n $pages ]]; then\n\t\t\t\tprint -v options_misc -m $((line+height*2+1)) $((col+29-16)) -rs -fg ${theme[div_line]} -t \"┤\" -fg ${theme[title]} -b -t \"pg\" -fg ${theme[hi_fg]} -t \"↑\"\\\n\t\t\t\t-fg ${theme[title]} -t \" ${page}/${pages} \" -fg ${theme[title]} -t \"pg\" -fg ${theme[hi_fg]} -t \"↓\" -rs -fg ${theme[div_line]} -t \"├\"\n\t\t\tfi\n\t\tfi\n\n\t\tif [[ -n $keypress || -z $options_out ]]; then\n\t\t\tunset options_out desc_height lr inp valid\n\t\t\tselected=\"${options_array[selected_int]}\"\n\t\t\tlocal -n selected_desc=\"desc_${selected}\"\n\t\t\tif [[ $background_update == false ]]; then desc_pos=$line; desc_height=$((height*2+2))\n\t\t\telif (( (selected_int-( (page-1)*height) )*2+${#selected_desc[@]}<height*2 )); then desc_pos=$((line+(selected_int-( (page-1)*height) )*2))\n\t\t\telse desc_pos=$((line+height*2-${#selected_desc[@]})); fi\n\t\t\tcreate_box -v options_out -w 50 -h ${desc_height:-$((${#selected_desc[@]}+2))} -l $desc_pos -c $((desc_col-1)) -fill -lc ${theme[div_line]} -title \"description\"\n\t\t\tfor((i=(page-1)*height,ypos=1;i<page*height;i++,ypos=ypos+2)); do\n\t\t\t\tif [[ -z ${options_array[i]} ]]; then break; fi\n\t\t\t\toption_string=\"${options_array[i]}\"\n\t\t\t\tif [[ -n $inputting && ${option_string} == \"${selected}\" ]]; then\n\t\t\t\t\tif [[ ${#inputting_value} -gt 14 ]]; then option_value=\"${inputting_value:(-14)}_\"\n\t\t\t\t\telse option_value=\"${inputting_value}_\"; fi\n\t\t\t\telse\n\t\t\t\t\toption_value=\"${!option_string}\"\n\t\t\t\tfi\n\n\t\t\t\tif [[ ${option_string} == \"${selected}\" ]]; then\n\t\t\t\t\tif is_int \"$option_value\" || [[ $selected == \"color_theme\" && -n $curled ]]; then\n\t\t\t\t\t\tenter=\"↲\"; inp=1\n\t\t\t\t\tfi\n\t\t\t\t\tif is_int \"$option_value\" || [[ $option_value =~ true|false || $selected =~ proc_sorting|color_theme ]] && [[ -z $inputting ]]; then\n\t\t\t\t\t\tleft=\"←\"; right=\"→\"; lr=1\n\t\t\t\t\telse\n\t\t\t\t\t\tenter=\"↲\"; inp=1\n\t\t\t\t\tfi\n\t\t\t\t\tbg=\" -bg ${theme[selected_bg]}\"\n\t\t\t\t\tfg=\"${theme[selected_fg]}\"\n\t\t\t\tfi\n\t\t\t\toption_string=\"${option_string//_/ }:\"\n\t\t\t\tif [[ $option_string == \"proc sorting:\" ]]; then\n\t\t\t\t\toption_string+=\" $((proc[sorting_int]+1))/${#sorting[@]}\"\n\t\t\t\telif [[ $option_string == \"color theme:\" ]]; then\n\t\t\t\t\toption_string+=\" $((theme_int+1))/${#themes[@]}\"\n\t\t\t\t\tif [[ ${option_value::12} == \"user_themes/\" ]]; then option_value=\"*${option_value#*/}\"\n\t\t\t\t\telse option_value=\"${option_value#*/}\"; fi\n\t\t\t\tfi\n\t\t\t\tprint -v options_out -m $((line+ypos)) $((col+1)) -rs -fg ${fg:-${theme[title]}}${bg} -b -jc 25 -t \"${option_string^}\"\n\t\t\t\tprint -v options_out -m $((line+ypos+1)) $((col+1)) -rs -fg ${fg:-${theme[main_fg]}}${bg} -jc 25 -t \"${enter:+ } ${left} \\\"${option_value::15}\\\" ${right} ${enter}\"\n\t\t\t\tunset right left enter bg fg\n\t\t\tdone\n\n\t\t\tfor((i=0,ypos=1;i<${#selected_desc[@]};i++,ypos++)); do\n\t\t\t\tprint -v options_out -m $((desc_pos+ypos)) $((desc_col+1)) -rs -fg ${theme[main_fg]} -jl 46 -t \"${selected_desc[i]}\"\n\t\t\tdone\n\t\tfi\n\n\t\techo -en \"${options_pause}${options_misc}${options_out}\"\n\t\tunset draw_out keypress\n\n\t\tif [[ -n $theme_check ]]; then\n\t\t\tlocal -a theme_index\n\t\t\tlocal git_theme new_themes=0 down_themes=0 new_theme\n\t\t\tunset 'theme_index[@]' 'desc_color_theme[-1]' 'desc_color_theme[-1]' 'desc_color_theme[-1]' options_out\n\t\t\ttheme_index=($(curl -m 3 --raw https://raw.githubusercontent.com/aristocratos/bashtop/master/themes/index.txt 2>/dev/null))\n\t\t\tif [[ ${theme_index[*]} =~ .theme ]]; then\n\t\t\t\tfor git_theme in ${theme_index[@]}; do\n\t\t\t\t\tunset new_theme\n\t\t\t\t\tif [[ ! -e \"${config_dir}/themes/${git_theme}\" ]]; then new_theme=1; fi\n\t\t\t\t\tif curl -m 3 --raw \"https://raw.githubusercontent.com/aristocratos/bashtop/master/themes/${git_theme}\" >\"${config_dir}/themes/${git_theme}\" 2>/dev/null; then\n\t\t\t\t\t\t((++down_themes))\n\t\t\t\t\t\tif [[ -n $new_theme ]]; then\n\t\t\t\t\t\t\t((++new_themes))\n\t\t\t\t\t\t\tthemes+=(\"themes/${git_theme%.theme}\")\n\t\t\t\t\t\tfi\n\t\t\t\t\tfi\n\t\t\t\tdone\n\t\t\t\tdesc_color_theme+=(\"Downloaded ${down_themes} theme(s).\")\n\t\t\t\tdesc_color_theme+=(\"Found ${new_themes} new theme(s)!\")\n\t\t\telse\n\t\t\t\tdesc_color_theme+=(\"ERROR: Couldn't get theme index!\")\n\t\t\tfi\n\t\tfi\n\n\n\t\tget_ms timestamp_end\n\t\tif [[ -z $theme_check ]]; then time_left=$((timestamp_start+update_ms-timestamp_end))\n\t\telse unset theme_check; time_left=0; fi\n\n\t\tif ((time_left>500)); then wait_string=5; time_left=$((time_left-500))\n\t\telif ((time_left>100)); then wait_string=$((time_left/100)); time_left=0\n\t\telse wait_string=\"0\"; time_left=0; fi\n\n\t\tget_key -v keypress -w ${wait_string}\n\n\t\tif [[ -n $inputting ]]; then\n\t\t\tcase \"$keypress\" in\n\t\t\t\tescape) unset inputting inputting_value ;;\n\t\t\t\tenter|backspace) valid=1 ;;\n\t\t\t\t*) if [[ ${#keypress} -eq 1 ]]; then valid=1; fi ;;\n\t\t\tesac\n\t\telse\n\t\t\tcase \"$keypress\" in\n\t\t\t\tescape|q|backspace) break 1 ;;\n\t\t\t\tdown|tab) if ((selected_int<${#options_array[@]}-1)); then ((++selected_int)); else selected_int=0; fi ;;\n\t\t\t\tup|shift_tab) if ((selected_int>0)); then ((selected_int--)); else selected_int=$((${#options_array[@]}-1)); fi ;;\n\t\t\t\tleft|right) if [[ -n $lr && -z $inputting ]]; then valid=1; fi ;;\n\t\t\t\tenter) if [[ -n $inp ]]; then valid=1; fi ;;\n\t\t\t\tpage_down) if ((page<pages)); then ((page++)); else page=1; selected_int=0; fi; redraw_misc=1; selected_int=$(( (page-1)*height )) ;;\n\t\t\t\tpage_up) if ((page>1)); then ((page--)); else page=${pages}; fi; redraw_misc=1; selected_int=$(( (page-1)*height )) ;;\n\t\t\tesac\n\t\t\tif (( selected_int<(page-1)*height | selected_int>=page*height )); then page=$(( (selected_int/height)+1 )); redraw_misc=1; fi\n\t\tfi\n\n\t\tif [[ ${selected} == \"color_theme\" && ${keypress} =~ left|right && ${#themes} -lt 2 ]]; then unset valid; fi\n\n\t\tif [[ -n $valid ]]; then\n\t\t\tcase \"${selected} ${keypress}\" in\n\t\t\t\t\"update_ms right\")\n\t\t\t\t\t\tif ((update_ms<86399900)); then\n\t\t\t\t\t\t\tupdate_ms=$((update_ms+100))\n\t\t\t\t\t\t\tupdated_ms=1\n\t\t\t\t\t\tfi\n\t\t\t\t\t;;\n\t\t\t\t\"update_ms left\")\n\t\t\t\t\t\tif ((update_ms>100)); then\n\t\t\t\t\t\t\tupdate_ms=$((update_ms-100))\n\t\t\t\t\t\t\tupdated_ms=1\n\t\t\t\t\t\tfi\n\t\t\t\t\t;;\n\t\t\t\t\"update_ms enter\")\n\t\t\t\t\t\tif [[ -z $inputting ]]; then inputting=1; inputting_value=\"${update_ms}\"\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tif ((inputting_value<86400000)); then update_ms=\"${inputting_value:-0}\"; updated_ms=1; fi\n\t\t\t\t\t\t\tunset inputting inputting_value\n\t\t\t\t\t\tfi\n\t\t\t\t\t;;\n\t\t\t\t\"update_ms backspace\"|\"draw_clock backspace\"|\"custom_cpu_name backspace\"|\"disks_filter backspace\")\n\t\t\t\t\t\tif [[ ${#inputting_value} -gt 0 ]]; then\n\t\t\t\t\t\t\tinputting_value=\"${inputting_value::-1}\"\n\t\t\t\t\t\tfi\n\t\t\t\t\t;;\n\t\t\t\t\"update_ms\"*)\n\t\t\t\t\t\tinputting_value+=\"${keypress//[^0-9]/}\"\n\t\t\t\t\t;;\n\t\t\t\t\"draw_clock enter\")\n\t\t\t\t\t\tif [[ -z $inputting ]]; then inputting=1; inputting_value=\"${draw_clock}\"\n\t\t\t\t\t\telse draw_clock=\"${inputting_value}\"; unset inputting inputting_value clock_out; fi\n\t\t\t\t\t;;\n\t\t\t\t\"custom_cpu_name enter\")\n\t\t\t\t\t\tif [[ -z $inputting ]]; then inputting=1; inputting_value=\"${custom_cpu_name}\"\n\t\t\t\t\t\telse custom_cpu_name=\"${inputting_value}\"; changed_cpu_name=1; unset inputting inputting_value; fi\n\t\t\t\t\t;;\n\t\t\t\t\"disks_filter enter\")\n\t\t\t\t\t\tif [[ -z $inputting ]]; then inputting=1; inputting_value=\"${disks_filter}\"\n\t\t\t\t\t\telse disks_filter=\"${inputting_value}\"; mem[counter]=10; resized=1; unset inputting inputting_value; fi\n\t\t\t\t\t;;\n\t\t\t\t\"net_totals_reset enter\")\n\t\t\t\t\t\tif ((net[reset]==1)); then net_totals_reset=\"Off\"; net[reset]=0\n\t\t\t\t\t\telse net_totals_reset=\"On\"; net[reset]=1; fi\n\t\t\t\t\t;;\n\t\t\t\t\"check_temp\"*|\"error_logging\"*|\"background_update\"*|\"proc_reversed\"*|\"proc_gradient\"*|\"proc_per_core\"*|\"update_check\"*|\"hires_graphs\"*|\"use_psutil\"*|\"proc_tree\"*)\n\t\t\t\t\t\tlocal -n selected_var=${selected}\n\t\t\t\t\t\tif [[ ${selected_var} == \"true\" ]]; then\n\t\t\t\t\t\t\tselected_var=\"false\"\n\t\t\t\t\t\t\tif [[ $selected == \"proc_reversed\" ]]; then proc[order_change]=1; unset 'proc[reverse]'\n\t\t\t\t\t\t\telif [[ $selected == \"proc_tree\" ]]; then proc[order_change]=1; unset 'proc[tree]'; fi\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tselected_var=\"true\"\n\t\t\t\t\t\t\tif [[ $selected == \"proc_reversed\" ]]; then proc[order_change]=1; proc[reverse]=\"+\"\n\t\t\t\t\t\t\telif [[ $selected == \"proc_tree\" ]]; then proc[order_change]=1; proc[tree]=\"+\"; fi\n\t\t\t\t\t\tfi\n\t\t\t\t\t\tif [[ $selected == \"check_temp\" && $check_temp == true ]]; then\n\t\t\t\t\t\t\tlocal has_temp\n\t\t\t\t\t\t\tsensor_comm=\"\"\n\t\t\t\t\t\t\tif [[ $use_psutil == true ]]; then\n\t\t\t\t\t\t\t\tpy_command -v has_temp \"get_sensors_check()\"\n\t\t\t\t\t\t\t\tif [[ $has_temp == true ]]; then sensor_comm=\"psutil\"; fi\n\t\t\t\t\t\t\tfi\n\t\t\t\t\t\t\tif [[ -z $sensor_comm ]]; then\n\t\t\t\t\t\t\t\tlocal checker\n\t\t\t\t\t\t\t\tfor checker in \"vcgencmd\" \"sensors\" \"osx-cpu-temp\"; do\n\t\t\t\t\t\t\t\t\tif command -v \"${checker}\" >/dev/null 2>&1; then sensor_comm=\"${checker}\"; break; fi\n\t\t\t\t\t\t\t\tdone\n\t\t\t\t\t\t\tfi\n\t\t\t\t\t\t\tif [[ -z $sensor_comm ]]; then check_temp=\"false\"\n\t\t\t\t\t\t\telse resized=1; fi\n\t\t\t\t\t\telif [[ $selected == \"check_temp\" ]]; then\n\t\t\t\t\t\t\tresized=1\n\t\t\t\t\t\tfi\n\t\t\t\t\t\tif [[ $selected == \"use_psutil\" && $system != \"Linux\" ]]; then use_psutil=\"true\"\n\t\t\t\t\t\telif [[ $selected == \"use_psutil\" ]]; then quit_ restart psutil; fi\n\t\t\t\t\t\tif [[ $selected == \"error_logging\" ]]; then quit_ restart; fi\n\n\t\t\t\t\t;;\n\t\t\t\t\"proc_sorting right\")\n\t\t\t\t\t\tif ((proc[sorting_int]<${#sorting[@]}-1)); then ((++proc[sorting_int]))\n\t\t\t\t\t\telse proc[sorting_int]=0; fi\n\t\t\t\t\t\tproc_sorting=\"${sorting[proc[sorting_int]]}\"\n\t\t\t\t\t\tproc[order_change]=1\n\t\t\t\t\t;;\n\t\t\t\t\"proc_sorting left\")\n\t\t\t\t\t\tif ((proc[sorting_int]>0)); then ((proc[sorting_int]--))\n\t\t\t\t\t\telse proc[sorting_int]=$((${#sorting[@]}-1)); fi\n\t\t\t\t\t\tproc_sorting=\"${sorting[proc[sorting_int]]}\"\n\t\t\t\t\t\tproc[order_change]=1\n\t\t\t\t\t;;\n\t\t\t\t\"color_theme right\")\n\t\t\t\t\t\tif ((theme_int<${#themes[@]}-1)); then ((++theme_int))\n\t\t\t\t\t\telse theme_int=0; fi\n\t\t\t\t\t\tcolor_theme=\"${themes[$theme_int]}\"\n\t\t\t\t\t\tcolor_init_\n\t\t\t\t\t\tresized=1\n\t\t\t\t\t;;\n\t\t\t\t\"color_theme left\")\n\t\t\t\t\t\tif ((theme_int>0)); then ((theme_int--))\n\t\t\t\t\t\telse theme_int=$((${#themes[@]}-1)); fi\n\t\t\t\t\t\tcolor_theme=\"${themes[$theme_int]}\"\n\t\t\t\t\t\tcolor_init_\n\t\t\t\t\t\tresized=1\n\t\t\t\t\t;;\n\t\t\t\t\"color_theme enter\")\n\t\t\t\t\t\ttheme_check=1\n\t\t\t\t\t\tif ((${#desc_color_theme[@]}>8)); then unset 'desc_color_theme[-1]'; fi\n\t\t\t\t\t\tdesc_color_theme+=(\"Checking for new themes...\")\n\t\t\t\t\t;;\n\t\t\t\t\"draw_clock\"*|\"custom_cpu_name\"*|\"disks_filter\"*)\n\t\t\t\t\t\tinputting_value+=\"${keypress//[\\\\\\$\\\"\\']/}\"\n\t\t\t\t\t;;\n\n\t\t\tesac\n\n\t\tfi\n\n\t\tif [[ -n $changed_cpu_name ]]; then\n\t\t\tchanged_cpu_name=0\n\t\t\tget_cpu_info\n\t\t\tcalc_sizes\n\t\t\tdraw_bg quiet\n\t\tfi\n\n\t\tif [[ $(${stty} size) != \"$tty_height $tty_width\" ]]; then resized; fi\n\n\t\tif ((resized>0)); then\n\t\t\tcalc_sizes; draw_bg quiet\n\t\t\tredraw_misc=1\n\t\t\tunset options_out bannerd menu_out\n\t\tfi\n\n\t\tget_ms timestamp_end\n\t\ttime_left=$((timestamp_start+update_ms-timestamp_end))\n\t\tif ((time_left<=0 | resized>0)); then get_ms timestamp_start; if [[ -z $inputting ]]; then collect_and_draw; fi; fi\n\t\tif ((resized>0)); then resized=0; page=1; selected_int=0; fi\n\n\t\tif [[ -n $updated_ms ]] && ((updated_ms++==2)); then\n\t\t\tunset updated_ms\n\t\t\tdraw_update_string quiet\n\t\tfi\n\n\tdone\n\n\tif [[ -n $from_menu ]]; then pause_\n\telif [[ -n ${pause_screen} ]]; then unpause_; draw_update_string; fi\n}\n\nkiller_() { #? Kill process with selected signal\n\tlocal kill_op=\"$1\" kill_pid=\"$2\" killer_out killer_box col line program keypress selected selected_int=0 sig confirmed=0 option killer_pause status msg\n\tlocal -a options=(\"yes\" \"no\")\n\n\tif ! program=\"$(ps -o comm -p ${kill_pid})\"; then return\n\telse program=\"$(tail -n1 <<<\"$program\")\"; fi\n\n\tcase $kill_op in\n\t\tt|T) kill_op=\"terminate\"; sig=\"SIGTERM\" ;;\n\t\tk|K) kill_op=\"kill\"; sig=\"SIGKILL\" ;;\n\t\ti|I) kill_op=\"interrupt\"; sig=\"SIGINT\" ;;\n\tesac\n\n\tuntil false; do\n\n\t\t#* Put program to sleep if caught ctrl-z\n\t\tif ((sleepy==1)); then sleep_; fi\n\n\t\tif [[ $background_update == true || -z $killer_box ]]; then\n\t\t\tdraw_clock\n\t\t\tpause_ killer_pause\n\t\telse\n\t\t\tunset killer_pause\n\t\tfi\n\n\t\tif [[ -z $killer_box ]]; then\n\t\t\tcol=$((tty_width/2-15)); line=$((tty_height/2-4)); y=1\n\t\t\tunset redraw killer_box\n\t\t\tcreate_box -v killer_box -w 40 -h 9 -l $line -c $((col++)) -fill -lc \"${theme[proc_box]}\" -title \"${kill_op}\"\n\t\tfi\n\n\t\tif ((confirmed==0)); then\n\t\t\tselected=\"${options[selected_int]}\"\n\t\t\tprint -v killer_out -m $((line+2)) $col -fg ${theme[title]} -b -jc 38 -t \"${kill_op^} ${program::20}?\" -m $((line+4)) $((col+3))\n\t\t\tfor option in \"${options[@]}\"; do\n\t\t\t\tif [[ $option == \"${selected}\" ]]; then print -v killer_out -bg ${theme[selected_bg]} -fg ${theme[selected_fg]}; else print -v killer_out -fg ${theme[title]}; fi\n\t\t\t\tprint -v killer_out -b -r 5 -t \"[  ${option^}  ]\" -rs\n\t\t\tdone\n\n\t\telif ((confirmed==1)); then\n\t\t\tselected=\"ok\"\n\t\t\tprint -v killer_out -m $((line+2)) $col -fg ${theme[title]} -b -jc 38 -t \"Sending signal ${sig} to pid ${kill_pid}!\"\n\t\t\tprint -v killer_out -m $((line+4)) $col -fg ${theme[main_fg]} -jc 38 -t \"${status^}!\" -m $((line+6)) $col\n\t\t\tif [[ -n $msg ]]; then print -v killer_out -m $((line+5)) $col -fg ${theme[main_fg]} -jc 38 -t \"${msg}\" -m $((line+7)) $col; fi\n\t\t\tprint -v killer_out -fg ${theme[selected_fg]} -bg ${theme[selected_bg]} -b -r 15 -t \"[  Ok  ]\" -rs\n\t\tfi\n\n\t\techo -en \"${killer_pause}${killer_box}${killer_out}\"\n\t\tunset killer_out draw_out\n\n\n\t\tget_ms timestamp_end\n\t\ttime_left=$((timestamp_start+update_ms-timestamp_end))\n\n\t\tif ((time_left>1000)); then wait_string=10; time_left=$((time_left-1000))\n\t\telif ((time_left>100)); then wait_string=$((time_left/100)); time_left=0\n\t\telse wait_string=\"0\"; time_left=0; fi\n\n\t\tget_key -v keypress -w ${wait_string}\n\t\tif [[ $(${stty} size) != \"$tty_height $tty_width\" ]]; then resized; fi\n\t\tif ((resized>0)); then\n\t\t\tcalc_sizes; draw_bg quiet; time_left=0; unset killer_out killer_box\n\t\tfi\n\n\t\tcase \"$keypress\" in\n\t\t\tright|shift_tab) if ((selected_int>0)); then ((selected_int--)); else selected_int=$((${#options[@]}-1)); fi ;;\n\t\t\tleft|tab) if ((selected_int<${#options[@]}-1)); then ((++selected_int)); else selected_int=0; fi ;;\n\t\t\tenter)\n\t\t\t\tcase \"$selected\" in\n\t\t\t\t\tyes) confirmed=1 ;;\n\t\t\t\t\tno|ok) confirmed=-1 ;;\n\t\t\t\tesac\n\t\t\t;;\n\t\t\tq|Q) quit_ ;;\n\t\tesac\n\n\t\tif ((confirmed<0)); then\n\t\t\tunpause_\n\t\t\tbreak\n\t\telif ((confirmed>0)) && [[ -z $status ]]; then\n\t\t\tif ${kill} -${sig} ${kill_pid} >/dev/null 2>&1; then\n\t\t\t\tstatus=\"success\"\n\t\t\telse\n\t\t\t\tif ! ps -p ${kill_pid} >/dev/null 2>&1; then\n\t\t\t\t\tmsg=\"Process not running.\"\n\t\t\t\telif [[ $UID != 0 ]]; then\n\t\t\t\t\tmsg=\"Try restarting with sudo.\"\n\t\t\t\telse\n\t\t\t\t\tmsg=\"Unknown error.\"\n\t\t\t\tfi\n\t\t\t\tstatus=\"failed\"; fi\n\t\tfi\n\n\n\t\tif ((time_left==0)); then get_ms timestamp_start; unset draw_out; collect_and_draw; fi\n\t\tif ((resized>=5)); then resized=0; fi\n\n\tdone\n\n\n}\n\nget_key() { #? Get one key from standard input and translate key code to readable format\n\tlocal key key_out wait_time esc ext_out save\n\n\tif ((quitting==1)); then quit_; fi\n\n\tuntil (($#==0)); do\n\t\tcase \"$1\" in\n\t\t\t-v|-variable) local -n key_out=$2; ext_out=1; shift;;\t\t\t#* Output variable\n\t\t\t-w|-wait) wait_time=\"$2\"; shift;;\t\t\t\t\t\t\t\t#* Time to wait for key\n\t\t\t-s|-save) save=1;;\t\t\t\t\t\t\t\t\t\t\t\t#* Save key for later processing\n\t\tesac\n\t\tshift\n\tdone\n\n\tif [[ -z $save && -n ${saved_key[0]} ]]; then key=\"${saved_key[0]}\"; unset 'saved_key[0]'; saved_key=(\"${saved_key[@]}\")\n\telse\n\t\tunset key\n\n\t\tkey=$(${stty} -cooked min 0 time ${wait_time:-0} 2>/dev/null; ${dd} bs=1 count=1 2>/dev/null)\n\t\tif [[ -z ${key:+s} ]]; then\n\t\t\tkey_out=\"\"\n\t\t\t${stty} isig\n\t\t\tif [[ -z $save ]]; then return 0\n\t\t\telse return 1; fi\n\t\tfi\n\n\t\t#* Read 3 more characters if a leading escape character is detected\n\t\tif [[ $key == \"${enter_key}\" ]]; then key=\"enter\"\n\t\telif [[ $key == \"${ctrl_c}\" ]]; then quitting=1; time_left=0\n\t\telif [[ $key == \"${ctrl_z}\" ]]; then sleepy=1; time_left=0\n\t\telif [[ $key == \"${backspace}\" || $key == \"${backspace_real}\" ]]; then key=\"backspace\"\n\t\telif [[ $key == \"${tab}\" ]]; then key=\"tab\"\n\t\telif [[ $key == \"$esc_character\" ]]; then\n\t\t\tesc=1; key=$(${stty} -cooked min 0 time 0 2>/dev/null; ${dd} bs=1 count=3 2>/dev/null); fi\n\t\tif [[ -z $key && $esc -eq 1 ]]; then key=\"escape\"\n\t\telif [[ $esc -eq 1 ]]; then\n\t\t\tcase \"${key}\" in\n\t\t\t\t'[A'*|'OA'*) key=\"up\" ;;\n\t\t\t\t'[B'*|'OB'*) key=\"down\" ;;\n\t\t\t\t'[D'*|'OD'*) key=\"left\" ;;\n\t\t\t\t'[C'*|'OC'*) key=\"right\" ;;\n\t\t\t\t'[2~') key=\"insert\" ;;\n\t\t\t\t'[3~') key=\"delete\" ;;\n\t\t\t\t'[H'*) key=\"home\" ;;\n\t\t\t\t'[F'*) key=\"end\" ;;\n\t\t\t\t'[5~') key=\"page_up\" ;;\n\t\t\t\t'[6~') key=\"page_down\" ;;\n\t\t\t\t'[Z'*) key=\"shift_tab\" ;;\n\t\t\t\t'OP'*) key=\"f1\";;\n\t\t\t\t'OQ'*) key=\"f2\";;\n\t\t\t\t'OR'*) key=\"f3\";;\n\t\t\t\t'OS'*) key=\"f4\";;\n\t\t\t\t'[15') key=\"f5\";;\n\t\t\t\t'[17') key=\"f6\";;\n\t\t\t\t'[18') key=\"f7\";;\n\t\t\t\t'[19') key=\"f8\";;\n\t\t\t\t'[20') key=\"f9\";;\n\t\t\t\t'[21') key=\"f10\";;\n\t\t\t\t'[23') key=\"f11\";;\n\t\t\t\t'[24') key=\"f12\";;\n\t\t\t\t*) key=\"\" ;;\n\t\t\tesac\n\t\tfi\n\n\tfi\n\n\t${stty} -cooked min 0 time 0 >/dev/null 2>&1; ${dd} bs=512 count=1 >/dev/null 2>&1\n\t${stty} isig\n\tif [[ -n $save && -n $key ]]; then saved_key+=(\"${key}\"); return 0; fi\n\n\tif [[ -n $ext_out ]]; then key_out=\"${key}\"\n\telse echo -n \"${key}\"; fi\n}\n\nprocess_input() { #? Process keypresses for main ui\n\tlocal wait_time=\"$1\" keypress esc prev_screen anykey filter_change p_height=$((box[processes_height]-3))\n\tlate_update=0\n\t#* Wait while reading input\n\tget_key -v keypress -w \"${wait_time}\"\n\tif [[ -z $keypress ]] || [[ -n $failed_pipe ]]; then return; fi\n\n\tif [[ -n $input_to_filter ]]; then\n\t\tfilter_change=1\n\t\tcase \"$keypress\" in\n\t\t\t\"enter\") unset input_to_filter ;;\n\t\t\t\"backspace\") if [[ ${#filter} -gt 0 ]]; then filter=\"${filter:: (-1)}\"; else unset filter_change; fi ;;\n\t\t\t\"escape\") unset input_to_filter filter ;;\n\t\t\t*) if [[ ${#keypress} -eq 1 && $keypress =~ ^[A-Za-z0-9\\!\\@\\#\\%\\&\\/\\(\\)\\[\\+\\-\\_\\*\\,\\;\\.\\:]$ ]]; then filter+=\"${keypress//[\\\\\\$\\\"\\']/}\"; else unset filter_change; fi ;;\n\t\tesac\n\n\telse\n\t\tcase \"$keypress\" in\n\t\t\tleft) #* Move left in processes sorting column\n\t\t\t\tif ((proc[sorting_int]>0)); then ((proc[sorting_int]--))\n\t\t\t\telse proc[sorting_int]=$((${#sorting[@]}-1)); fi\n\t\t\t\tproc_sorting=\"${sorting[proc[sorting_int]]}\"\n\t\t\t\tif [[ $proc_sorting == \"tree\" && $use_psutil == true ]]; then\n\t\t\t\t\t((proc[sorting_int]--))\n\t\t\t\t\tproc_sorting=\"${sorting[proc[sorting_int]]}\"\n\t\t\t\tfi\n\t\t\t\tfilter_change=1\n\t\t\t;;\n\t\t\tright) #* Move right in processes sorting column\n\t\t\t\tif ((proc[sorting_int]<${#sorting[@]}-1)); then ((++proc[sorting_int]))\n\t\t\t\telse proc[sorting_int]=0; fi\n\t\t\t\tproc_sorting=\"${sorting[proc[sorting_int]]}\"\n\t\t\t\tif [[ $proc_sorting == \"tree\" && $use_psutil == true ]]; then\n\t\t\t\t\tproc[sorting_int]=0\n\t\t\t\t\tproc_sorting=\"${sorting[proc[sorting_int]]}\"\n\t\t\t\tfi\n\t\t\t\tfilter_change=1\n\t\t\t;;\n\t\t\tn|N) #* Switch to next network device\n\t\t\t\tif ((${#nic_list[@]}>1)); then\n\t\t\t\t\tif ((nic_int<${#nic_list[@]}-1)); then ((++nic_int))\n\t\t\t\t\telse nic_int=0; fi\n\t\t\t\t\tnet[device]=\"${nic_list[nic_int]}\"\n\t\t\t\t\tnet[nic_change]=1\n\t\t\t\t\tcollect_net init\n\t\t\t\t\tcollect_net\n\t\t\t\t\tdraw_net now\n\t\t\t\tfi\n\t\t\t;;\n\t\t\tb|B) #* Switch to previous network device\n\t\t\t\tif ((${#nic_list[@]}>1)); then\n\t\t\t\t\tif ((nic_int>0)); then ((nic_int--))\n\t\t\t\t\telse nic_int=$((${#nic_list[@]}-1)); fi\n\t\t\t\t\tnet[device]=\"${nic_list[nic_int]}\"\n\t\t\t\t\tnet[nic_change]=1\n\t\t\t\t\tcollect_net init\n\t\t\t\t\tcollect_net\n\t\t\t\t\tdraw_net now\n\t\t\t\tfi\n\t\t\t;;\n\t\t\tup|shift_tab) #* Move process selector up one\n\t\t\t\tif ((proc[selected]>1)); then\n\t\t\t\t\t((proc[selected]--))\n\t\t\t\t\tproc[page_change]=1\n\t\t\t\telif ((proc[start]>1)); then\n\t\t\t\t\tif ((proc[selected]==0)); then proc[selected]=${p_height}; fi\n\t\t\t\t\t((proc[start]--))\n\t\t\t\t\tproc[page_change]=1\n\t\t\t\telif ((proc[start]==1 & proc[selected]==1)); then\n\t\t\t\t\tproc[selected]=0\n\t\t\t\t\tproc[page_change]=1\n\t\t\t\tfi\n\t\t\t;;\n\t\t\tdown|tab) #* Move process selector down one\n\t\t\t\tif ((proc[selected]<p_height & proc[start]+proc[selected]<(${#proc_array[@]}) )); then\n\t\t\t\t\t((++proc[selected]))\n\t\t\t\t\tproc[page_change]=1\n\t\t\t\telif ((proc[start]+proc[selected]<(${#proc_array[@]}) )); then\n\t\t\t\t\t((++proc[start]))\n\t\t\t\t\tproc[page_change]=1\n\t\t\t\tfi\n\t\t\t;;\n\t\t\tenter) #* Show detailed info for selected process or close detailed info if no new process is selected\n\t\t\t\tif ((proc[selected]>0 & proc[detailed_pid]!=proc[selected_pid])) && ps -p ${proc[selected_pid]} > /dev/null 2>&1; then\n\t\t\t\t\tproc[detailed]=1\n\t\t\t\t\tproc[detailed_change]=1\n\t\t\t\t\tproc[detailed_pid]=${proc[selected_pid]}\n\t\t\t\t\tproc[selected]=0\n\t\t\t\t\tunset 'proc[detailed_name]' 'detail_history[@]' 'detail_mem_history[@]' 'proc[detailed_killed]'\n\t\t\t\t\tcalc_sizes\n\t\t\t\t\tcollect_processes now\n\t\t\t\telif ((proc[detailed]==1 & proc[detailed_pid]!=proc[selected_pid])); then\n\t\t\t\t\tproc[detailed]=0\n\t\t\t\t\tproc[detailed_change]=1\n\t\t\t\t\tunset 'proc[detailed_pid]'\n\t\t\t\t\tcalc_sizes\n\t\t\t\tfi\n\t\t\t;;\n\t\t\tpage_up) #* Move up one page in process box\n\t\t\t\tif ((proc[start]>1)); then\n\t\t\t\t\tproc[start]=$(( proc[start]-p_height ))\n\t\t\t\t\tif ((proc[start]<1)); then proc[start]=1; fi\n\t\t\t\t\tproc[page_change]=1\n\t\t\t\telif ((proc[selected]>0)); then\n\t\t\t\t\tproc[selected]=0\n\t\t\t\t\tproc[start]=1\n\t\t\t\t\tproc[page_change]=1\n\t\t\t\tfi\n\t\t\t;;\n\t\t\tpage_down) #* Move down one page in process box\n\t\t\t\tif ((proc[start]<(${#proc_array[@]}-1)-p_height)); then\n\t\t\t\t\tif ((proc[start]==1)) && [[ $use_psutil == false ]]; then collect_processes now; fi\n\t\t\t\t\tproc[start]=$(( proc[start]+p_height ))\n\t\t\t\t\tif (( proc[start]>(${#proc_array[@]})-p_height )); then proc[start]=$(( (${#proc_array[@]})-p_height )); fi\n\t\t\t\t\tproc[page_change]=1\n\t\t\t\telif ((proc[selected]>0)); then\n\t\t\t\t\tproc[selected]=$((p_height))\n\t\t\t\t\tproc[page_change]=1\n\t\t\t\tfi\n\t\t\t;;\n\t\t\thome) #* Go to first page in process box\n\t\t\t\t\tproc[start]=1\n\t\t\t\t\tproc[page_change]=1\n\t\t\t;;\n\t\t\tend) #* Go to last page in process box\n\t\t\t\t\tif ((proc[selected]==0)) && [[ $use_psutil == false ]]; then collect_processes now; fi\n\t\t\t\t\tproc[start]=$(((${#proc_array[@]}-1)-p_height))\n\t\t\t\t\tproc[page_change]=1\n\t\t\t;;\n\t\t\tr|R) #* Reverse order of processes sorting column\n\t\t\t\tif [[ -z ${proc[reverse]} ]]; then\n\t\t\t\t\tproc[reverse]=\"+\"\n\t\t\t\t\tproc_reversed=\"true\"\n\t\t\t\telse\n\t\t\t\t\tproc_reversed=\"false\"\n\t\t\t\t\tunset 'proc[reverse]'\n\t\t\t\tfi\n\t\t\t\tfilter_change=1\n\t\t\t;;\n\t\t\te|E) #* Show processes as a tree\n\t\t\t\tif [[ -z ${proc[tree]} ]]; then\n\t\t\t\t\tproc[tree]=\"+\"\n\t\t\t\t\tproc_tree=\"true\"\n\t\t\t\telse\n\t\t\t\t\tproc_tree=\"false\"\n\t\t\t\t\tunset 'proc[tree]'\n\t\t\t\tfi\n\t\t\t\tfilter_change=1\n\t\t\t;;\n\t\t\to|O|f2) #* Options\n\t\t\t\toptions_\n\t\t\t;;\n\t\t\t+|A|a) #* Add 100ms to update timer\n\t\t\t\tif ((update_ms<86399900)); then\n\t\t\t\t\tupdate_ms=$((update_ms+100))\n\t\t\t\t\tdraw_update_string\n\t\t\t\tfi\n\t\t\t;;\n\t\t\t-|S|s) #* Subtract 100ms from update timer\n\t\t\t\tif ((update_ms>100)); then\n\t\t\t\t\tupdate_ms=$((update_ms-100))\n\t\t\t\t\tdraw_update_string\n\t\t\t\tfi\n\t\t\t;;\n\t\t\th|H|f1) #* Show help\n\t\t\t\thelp_\n\t\t\t;;\n\t\t\tq|Q) #* Quit\n\t\t\t\tquit_\n\t\t\t;;\n\t\t\tm|M|escape) #* Show main menu\n\t\t\t\tmenu_\n\t\t\t;;\n\t\t\tf|F) #* Start process filtering input\n\t\t\t\tinput_to_filter=1\n\t\t\t\tfilter_change=1\n\t\t\t\tif ((proc[selected]>1)); then proc[selected]=1; fi\n\t\t\t\tproc[start]=1\n\t\t\t;;\n\t\t\tc|C) #* Clear process filter\n\t\t\t\tif [[ -n $filter ]]; then\n\t\t\t\t\tunset input_to_filter filter\n\t\t\t\t\tfilter_change=1\n\t\t\t\tfi\n\t\t\t;;\n\t\t\tt|T|k|K|i|I) #* Send terminate, kill or interrupt signal\n\t\t\t\tif [[ ${proc[selected]} -gt 0 ]]; then\n\t\t\t\t\tkiller_ \"$keypress\" \"${proc[selected_pid]}\"\n\t\t\t\telif [[ ${proc[detailed]} -eq 1 && -z ${proc[detailed_killed]} ]]; then\n\t\t\t\t\tkiller_ \"$keypress\" \"${proc[detailed_pid]}\"\n\t\t\t\tfi\n\t\t\t;;\n\t\tesac\n\tfi\n\n\tif [[ -n $filter_change ]]; then\n\t\tunset filter_change\n\t\tcollect_processes now\n\t\tproc[filter_change]=1\n\t\tdraw_processes now\n\telif [[ ${proc[page_change]} -eq 1 || ${proc[detailed_change]} == 1 ]]; then\n\t\tif ((proc[selected]==0)); then unset 'proc[selected_pid]'; proc[detailed_change]=1; fi\n\t\tdraw_processes now\n\tfi\n\n\t#* Subtract time since input start from time left if timer is interrupted\n\tget_ms timestamp_input_end\n\ttime_left=$(( (timestamp_start+update_ms)-timestamp_input_end ))\n\n\treturn 0\n}\n\ncollect_and_draw() { #? Run all collect and draw functions\n\tlocal task_int=0 input_runs\n\tfor task in processes cpu mem net; do\n\t\t((++task_int))\n\t\tif [[ -n $pause_screen && -n ${saved_key[0]} ]]; then\n\t\t\treturn\n\t\telif [[ -z $pause_screen ]]; then\n\t\t\tinput_runs=0\n\t\t\twhile [[ -n ${saved_key[0]} ]] && ((time_left>0)) && ((++input_runs<=5)); do\n\t\t\t\tprocess_input\n\t\t\t\tunset late_update\n\t\t\tdone\n\t\tfi\n\t\tcollect_${task}\n\t\tif get_key -save && [[ -z $pause_screen ]]; then process_input; fi\n\t\tdraw_${task}\n\t\tif get_key -save && [[ -z $pause_screen ]]; then process_input; fi\n\t\tdraw_clock \"$1\"\n\t\tif ((resized>0 & resized<task_int)) || [[ -n $failed_pipe || -n $py_error ]]; then return; fi\n\tdone\n\n\tlast_screen=\"${draw_out}\"\n}\n\n#? ----------------------------------------------------------------------------------------------------------------------- ?#\n\nmain_loop() { #? main loop...\n\tlocal wait_time wait_string input_runs\n\n\t#* Put program to sleep if caught ctrl-z\n\tif ((sleepy==1)); then sleep_; fi\n\n\t#* Timestamp for accurate timer\n\tget_ms timestamp_start\n\n\tif [[ $(${stty} size) != \"$tty_height $tty_width\" ]]; then resized; fi\n\n\tif ((resized>0)); then\n\t\tcalc_sizes\n\t\tdraw_bg\n\tfi\n\n\t#* Run all collect and draw functions\n\tcollect_and_draw now\n\n\t#* Reset resized variable if resized and all functions have finished redrawing\n\tif ((resized>=5)); then resized=0\n\telif ((resized>0)); then unset draw_out proc_out clock_out; return; fi\n\n\t#* Echo everyting out to screen in one command to get a smooth transition between updates\n\techo -en \"${draw_out}${proc_out}${clock_out}\"\n\tunset draw_out\n\n\t#* Periodically check for new network device if non was found at start or was removed\n\tif ((net[device_check]>10)); then\n\t\tnet[device_check]=0\n\t\tget_net_device\n\telif [[ -n ${net[no_device]} ]]; then\n\t\t((++net[device_check]))\n\tfi\n\n\t#* Compare timestamps to get exact time needed to wait until next loop\n\tget_ms timestamp_end\n\ttime_left=$((timestamp_start+update_ms-timestamp_end))\n\tif ((time_left>update_ms)); then time_left=$update_ms; fi\n\tif ((time_left>0)); then\n\n\t\tlate_update=0\n\n\t\t#* Divide waiting time in chunks of 500ms and below to keep program responsive while reading input\n\t\twhile ((time_left>0 & resized==0)); do\n\n\t\t\t#* If NOT waiting for input and time left is greater than 500ms, wait 500ms and loop\n\t\t\tif [[ -z $input_to_filter ]] && ((time_left>=500)); then\n\t\t\t\twait_string=\"5\"\n\t\t\t\ttime_left=$((time_left-500))\n\n\t\t\t#* If waiting for input and time left is greater than \"50 ms\", wait 50ms and loop\n\t\t\telif [[ -n $input_to_filter ]] && ((time_left>=100)); then\n\t\t\t\twait_string=\"1\"\n\t\t\t\ttime_left=$((time_left-100))\n\n\t\t\t#* Else format wait string with padded zeroes if needed and break loop\n\t\t\telse\n\t\t\t\tif ((time_left>=100)); then wait_string=$((time_left/100)); else wait_string=0; fi\n\t\t\t\ttime_left=0\n\t\t\tfi\n\n\t\t\t#* Wait while reading input\n\t\t\tprocess_input \"${wait_string}\"\n\t\t\tif [[ -n $failed_pipe || -n $py_error ]]; then return; fi\n\n\t\t\t#* Draw clock if set\n\t\t\tdraw_clock now\n\n\t\tdone\n\n\t#* If time left is too low to process any input more than five times in succession, add 100ms to update timer\n\telif ((++late_update==5)); then\n\t\tupdate_ms=$((update_ms+100))\n\t\tdraw_update_string\n\tfi\n\n\tunset skip_process_draw skip_net_draw\n}\n\n#? Pre main loop\n\n#* Read config file or create if non existant\nconfig_dir=\"${XDG_CONFIG_HOME:-$HOME/.config}/bashtop\"\nif [[ -d \"${config_dir}\" && -w \"${config_dir}\" ]] || mkdir -p \"${config_dir}\"; then\n\tif [[ ! -d \"${config_dir}/themes\" ]]; then mkdir -p \"${config_dir}/themes\"; fi\n\tif [[ ! -d \"${config_dir}/user_themes\" ]]; then mkdir -p \"${config_dir}/user_themes\"; fi\n\tconfig_file=\"${config_dir}/bashtop.cfg\"\n\t# shellcheck source=/dev/null\n\tif [[ -e \"$config_file\" ]]; then\n\t\tsource \"$config_file\"\n\n\t\t#* If current config is from an older version recreate config file and save user changes\n\t\tif [[ $(get_value -sf \"${config_file}\" -k \"bashtop v.\" -mk 1) != \"${version}\" ]]; then\n\t\t\tcreate_config\n\t\t\tsave_config \"${save_array[@]}\"\n\t\tfi\n\telse create_config; fi\nelse\n\t#* If anything goes wrong turn off all writing to filesystem\n\techo \"ERROR: Could not set config dir!\"\n\tconfig_dir=\"/dev/null\"\n\tconfig_file=\"/dev/null\"\n\terror_logging=\"false\"\n\tunset 'save_array[@]'\nfi\n\n#* Force the use of python psutil if not on Linux\nif [[ $system != \"Linux\" ]]; then use_psutil=\"true\"; fi\n\n#* Check for python3 and psutil if \"use_psutil\" is true\nif [[ $use_psutil == true ]]; then\n\tif ! command -v python3 >/dev/null 2>&1; then\n\t\techo \"Error: Missing python3!\"\n\t\tif [[ $system == \"Linux\" ]]; then\n\t\t\tuse_psutil=\"false\"\n\t\telse\n\t\t\texit 1\n\t\tfi\n\telif [[ $use_psutil == true ]] && ! (cd / && python3 -c \"import psutil\") >/dev/null 2>&1; then\n\t\techo \"Error: Missing python3 psutil module!\"\n\t\tif [[ $system == \"Linux\" ]]; then\n\t\t\tuse_psutil=\"false\"\n\t\telse\n\t\t\texit 1\n\t\tfi\n\tfi\nfi\n\n#* If using bash version 5, set timestamps with EPOCHREALTIME variable\nif [[ -n $EPOCHREALTIME ]]; then\n\tget_ms() { #? Set given variable to current epoch millisecond with EPOCHREALTIME varialble\n\t\tlocal -n ms_out=$1\n\t\tms_out=$((${EPOCHREALTIME/[.,]/}/1000))\n\t}\n\n#* If not, but using psutil, set timestamps with python\nelif [[ $use_psutil == true ]]; then\n\tget_ms() {\n\t\tlocal -n ms_out=$1\n\t\tpy_command -v ms_out \"get_ms()\"\n\t}\n\n#* Else use date command\nelse\n\tget_ms() { #? Set given variable to current epoch millisecond with date command\n\t\tlocal -n ms_out=$1\n\t\tms_out=\"\"\n\t\tread ms_out < <(${date} +%s%3N)\n\t}\nfi\n\n#* Setup psutil script\nif [[ $use_psutil == true ]]; then\n\tpy_command() {\n\t\tif [[ -n $failed_pipe ]]; then return; fi\n\t\tlocal arr var output cmd pyerr=${py_error} ln\n\t\tcase $1 in\n\t\t\t\"quit\")\n\t\t\t\techo \"quit\" >&${pycoproc[1]} 2>/dev/null || true\n\t\t\t\treturn\n\t\t\t\t;;\n\t\t\t\"-v\") var=1;;\n\t\t\t\"-vn\") var=1; ln=1;;\n\t\t\t\"-a\") arr=1;;\n\t\t\t*) return;;\n\t\tesac\n\t\tlocal -n pyout=$2\n\t\tcmd=\"$3\"\n\n\t\techo \"${cmd}\" >&${pycoproc[1]} #2>/dev/null || true\n\t\tif [[ -n $var ]]; then pyout=\"\"\n\t\telse pyout=(); fi\n\t\twhile IFS= read -r -u ${pycoproc[0]} -t 1 output; do #2>/dev/null\n\t\t\tif [[ $output == '/EOL' ]]; then break; fi\n\t\t\tif [[ -n $failed_pipe ]]; then py_out=\"\"; return 1; fi\n\t\t\tif [[ $output == '/ERROR' ]]; then ((++py_error)); unset arr var; fi\n\t\t\tif [[ -n $arr ]]; then pyout+=(\"${output}\")\n\t\t\telif [[ -n $var ]]; then pyout+=\"${output}${ln:+\\n}\"; fi\n\t\tdone\n\t\tif ((py_error>pyerr)); then py_out=\"\"; return 1; fi\n\t\tif [[ -n $ln ]]; then printf -v pyout \"%b\" \"${pyout}\"; fi\n\t\treturn 0\n\t}\n\n\tif ! pytmpdir=$(mktemp -d \"${TMPDIR:-/tmp}\"/XXXXXXXXXXXX); then\n\t\tif [[ $system == \"Linux\" ]]; then\n\t\t\tuse_psutil=\"false\"\n\t\telse\n\t\t\techo \"ERROR: Failed setting up temp directory for psutil script!\"\n\t\t\texit 1\n\t\tfi\n\telse\n\t\tpywrapper=\"${pytmpdir}/bashtop.psutil\"\n\ncat << 'EOF' > \"${pywrapper}\"\nimport os, sys, subprocess, re, time, psutil\nfrom datetime import timedelta\nfrom collections import defaultdict\nfrom typing import List, Set, Dict, Tuple, Optional, Union\n\nsystem: str\nif \"linux\" in sys.platform: system = \"Linux\"\nelif \"bsd\" in sys.platform: system = \"BSD\"\nelif \"darwin\" in sys.platform: system = \"MacOS\"\nelse: system = \"Other\"\n\nparent_pid: int = psutil.Process(os.getpid()).ppid()\n\nallowed_commands: Tuple[str] = (\n\t'get_proc',\n\t'get_disks',\n\t'get_cpu_name',\n\t'get_cpu_cores',\n\t'get_nics',\n\t'get_cpu_cores',\n\t'get_cpu_usage',\n\t'get_cpu_freq',\n\t'get_uptime',\n\t'get_load_avg',\n\t'get_mem',\n\t'get_detailed_names_cmd',\n\t'get_detailed_mem_time',\n\t'get_net',\n\t'get_cmd_out',\n\t'get_sensors',\n\t'get_sensors_check',\n\t'get_ms'\n\t)\ncommand: str = ''\ncpu_count: int = psutil.cpu_count()\ndisk_hist: Dict = {}\n\ndef cleaned(string: str) -> str:\n\t'''Escape characters not suitable for \"echo -e\" in bash'''\n\treturn string.replace(\"\\\\\", \"\\\\\\\\\").replace(\"$\", \"\\\\$\").replace(\"\\n\", \"\\\\n\").replace(\"\\t\", \"\\\\t\").replace(\"\\\"\", \"\\\\\\\"\").replace(\"\\'\", \"\\\\\\'\")\n\ndef get_cmd_out(cmd: str):\n\t'''Save bash the trouble of creating child processes by running through python instead'''\n\tprint(subprocess.check_output(cmd, shell=True, universal_newlines=True).rstrip())\n\ndef get_ms():\n\t'''Get current epoch millisecond'''\n\tt = str(time.time()).split(\".\")\n\tprint(f'{t[0]}{t[1][:3]}')\n\ndef get_sensors():\n\t'''A clone of \"sensors\" but using psutil'''\n\ttemps = psutil.sensors_temperatures()\n\tif not temps:\n\t\treturn\n\ttry:\n\t\tfor name, entries in temps.items():\n\t\t\tprint(name)\n\t\t\tfor entry in entries:\n\t\t\t\tprint(f'{entry.label or name}: {entry.current}°C (high = {entry.high}°C, crit = {entry.critical}°C)')\n\t\t\tprint()\n\texcept:\n\t\tpass\n\ndef get_sensors_check():\n\t'''Check if get_sensors() output contains accepted CPU temperature values'''\n\tif not hasattr(psutil, \"sensors_temperatures\"): print(\"false\"); return\n\ttry:\n\t\ttemps = psutil.sensors_temperatures()\n\texcept:\n\t\tpass\n\t\tprint(\"false\"); return\n\tif not temps: print(\"false\"); return\n\ttry:\n\t\tfor _, entries in temps.items():\n\t\t\tfor entry in entries:\n\t\t\t\tif entry.label.startswith(('Package', 'Core 0', 'Tdie')):\n\t\t\t\t\tprint(\"true\")\n\t\t\t\t\treturn\n\texcept:\n\t\tpass\n\tprint(\"false\")\n\ndef get_cpu_name():\n\t'''Fetch a suitable CPU identifier from the CPU model name string'''\n\tname: str = \"\"\n\tcommand: str = \"\"\n\tall_info: str = \"\"\n\trem_line: str = \"\"\n\tif system == \"Linux\":\n\t\tcommand = \"cat /proc/cpuinfo\"\n\t\trem_line = \"model name\"\n\telif system == \"MacOS\":\n\t\tcommand =\"sysctl -n machdep.cpu.brand_string\"\n\telif system == \"BSD\":\n\t\tcommand =\"sysctl hw.model\"\n\t\trem_line = \"hw.model\"\n\n\tall_info = subprocess.check_output(\"LANG=C \" + command, shell=True, universal_newlines=True)\n\tif rem_line:\n\t\tfor line in all_info.split(\"\\n\"):\n\t\t\tif rem_line in line:\n\t\t\t\tname = re.sub( \".*\" + rem_line + \".*:\", \"\", line,1).lstrip()\n\telse:\n\t\tname = all_info\n\tif \"Xeon\" in name:\n\t\tname = name.split(\" \")\n\t\tname = name[name.index(\"CPU\")+1]\n\telif \"Ryzen\" in name:\n\t\tname = name.split(\" \")\n\t\tname = \" \".join(name[name.index(\"Ryzen\"):name.index(\"Ryzen\")+3])\n\telif \"CPU\" in name:\n\t\tname = name.split(\" \")\n\t\tname = name[name.index(\"CPU\")-1]\n\n\tprint(name)\n\ndef get_cpu_cores():\n\t'''Get number of CPU cores and threads'''\n\tcores: int = psutil.cpu_count(logical=False)\n\tthreads: int = psutil.cpu_count(logical=True)\n\tprint(f'{cores} {threads if threads else cores}')\n\ndef get_cpu_usage():\n\tcpu: float = psutil.cpu_percent(percpu=False)\n\tthreads: List[float] = psutil.cpu_percent(percpu=True)\n\tprint(f'{cpu:.0f}')\n\tfor thread in threads:\n\t\tprint(f'{thread:.0f}')\n\ndef get_cpu_freq():\n\t'''Get current CPU frequency'''\n\ttry:\n\t\tprint(f'{psutil.cpu_freq().current:.0f}')\n\texcept:\n\t\tprint(0)\n\ndef get_uptime():\n\t'''Get current system uptime'''\n\tprint(str(timedelta(seconds=round(time.time()-psutil.boot_time(),0)))[:-3])\n\ndef get_load_avg():\n\t'''Get CPU load average'''\n\tfor lavg in os.getloadavg():\n\t\tprint(round(lavg, 2), ' ', end='')\n\tprint()\n\ndef get_mem():\n\t'''Get current system memory and swap usage'''\n\tmem = psutil.virtual_memory()\n\tswap = psutil.swap_memory()\n\ttry:\n\t\tcmem = mem.cached>>10\n\texcept:\n\t\tcmem = mem.active>>10\n\tprint(mem.total>>10, mem.free>>10, mem.available>>10, cmem, swap.total>>10, swap.free>>10)\n\ndef get_nics():\n\t'''Get a list of all network devices sorted by highest throughput'''\n\tio_all = psutil.net_io_counters(pernic=True)\n\tup_stat = psutil.net_if_stats()\n\n\tfor nic in sorted(psutil.net_if_addrs(), key=lambda nic: (io_all[nic].bytes_recv + io_all[nic].bytes_sent), reverse=True):\n\t\tif up_stat[nic].isup is False:\n\t\t\tcontinue\n\t\tprint(nic)\n\ndef get_net(net_dev: str):\n\t'''Emulated /proc/net/dev for selected network device'''\n\tnet = psutil.net_io_counters(pernic=True)[net_dev]\n\tprint(0,net.bytes_recv,0,0,0,0,0,0,0,net.bytes_sent)\n\ndef get_detailed_names_cmd(pid: int):\n\t'''Get name, parent name, username and arguments for selected pid'''\n\tp = psutil.Process(pid)\n\tpa = psutil.Process(p.ppid())\n\twith p.oneshot():\n\t\tprint(p.name())\n\t\tprint(pa.name())\n\t\tprint(p.username())\n\t\tcmd = ' '.join(p.cmdline()) or '[' + p.name() + ']'\n\t\tprint(cleaned(cmd))\n\ndef get_detailed_mem_time(pid: int):\n\t'''Get memory usage and runtime for selected pid'''\n\tp = psutil.Process(pid)\n\twith p.oneshot():\n\t\tprint(p.memory_info().rss)\n\t\tprint(timedelta(seconds=round(time.time()-p.create_time(),0)))\n\ndef get_proc(sorting='cpu lazy', tree=False, prog_len=0, arg_len=0, search='', reverse=True, proc_per_cpu=True, max_lines=0):\n\t'''List all processess with pid, name, arguments, threads, username, memory percent and cpu percent'''\n\tline_count: int = 0\n\terr: float = 0.0\n\treverse = not reverse\n\n\tif sorting == 'pid':\n\t\tsort_cmd = \"p.info['pid']\"\n\telif sorting == 'program' or tree and sorting == \"arguments\":\n\t\tsort_cmd = \"p.info['name']\"\n\t\treverse = not reverse\n\telif sorting == 'arguments':\n\t\tsort_cmd = \"' '.join(str(p.info['cmdline'])) or p.info['name']\"\n\t\treverse = not reverse\n\telif sorting == 'threads':\n\t\tsort_cmd = \"str(p.info['num_threads'])\"\n\telif sorting == 'user':\n\t\tsort_cmd = \"p.info['username']\"\n\t\treverse = not reverse\n\telif sorting == 'memory':\n\t\tsort_cmd = \"str(p.info['memory_percent'])\"\n\telif sorting == 'cpu responsive':\n\t\tsort_cmd = \"p.info['cpu_percent']\" if proc_per_cpu else \"(p.info['cpu_percent'] / cpu_count)\"\n\telse:\n\t\tsort_cmd = \"(sum(p.info['cpu_times'][:2] if not p.info['cpu_times'] == 0.0 else [0.0, 0.0]) * 1000 / (time.time() - p.info['create_time']))\"\n\n\tif tree:\n\t\tproc_tree(width=prog_len + arg_len, sorting=sort_cmd, reverse=reverse, max_lines=max_lines, proc_per_cpu=proc_per_cpu, search=search)\n\t\treturn\n\n\n\tprint(f\"{'Pid:':>7} {'Program:':<{prog_len}}\", f\"{'Arguments:':<{arg_len-4}}\" if arg_len else '', f\"{'Threads:' if arg_len else ' Tr:'} {'User:':<9}Mem%{'Cpu%':>11}\", sep='')\n\n\tfor p in sorted(psutil.process_iter(['pid', 'name', 'cmdline', 'num_threads', 'username', 'memory_percent', 'cpu_percent', 'cpu_times', 'create_time'], err), key=lambda p: eval(sort_cmd), reverse=reverse):\n\t\tif p.info['name'] == 'idle' or p.info['name'] == err or p.info['pid'] == err:\n\t\t\tcontinue\n\t\tif p.info['cmdline'] == err:\n\t\t\tp.info['cmdline'] = \"\"\n\t\tif p.info['username'] == err:\n\t\t\tp.info['username'] = \"?\"\n\t\tif p.info['num_threads'] == err:\n\t\t\tp.info['num_threads'] = 0\n\t\tif search:\n\t\t\tfound = False\n\t\t\tfor value in [ p.info['name'], ' '.join(p.info['cmdline']), str(p.info['pid']), p.info['username'] ]:\n\t\t\t\tif search in value:\n\t\t\t\t\tfound = True\n\t\t\t\t\tbreak\n\t\t\tif not found:\n\t\t\t\tcontinue\n\n\t\tcpu = p.info['cpu_percent'] if proc_per_cpu else (p.info['cpu_percent'] / psutil.cpu_count())\n\t\tmem = p.info['memory_percent']\n\t\tcmd = ' '.join(p.info['cmdline']) or '[' + p.info['name'] + ']'\n\t\tprint(f\"{p.info['pid']:>7} \",\n\t\t\tf\"{cleaned(p.info['name']):<{prog_len}.{prog_len-1}}\",\n\t\t\tf\"{cleaned(cmd):<{arg_len}.{arg_len-1}}\" if arg_len else '',\n\t\t\tf\"{p.info['num_threads']:>4} \" if p.info['num_threads'] < 1000 else '999> ',\n\t\t\tf\"{p.info['username']:<9.9}\" if len(p.info['username']) < 10 else f\"{p.info['username'][:8]:<8}+\",\n\t\t\tf\"{mem:>4.1f}\" if mem < 100 else f\"{mem:>4.0f} \",\n\t\t\tf\"{cpu:>11.1f} \" if cpu < 100 else f\"{cpu:>11.0f} \",\n\t\t\tsep='')\n\t\tline_count += 1\n\t\tif max_lines and line_count == max_lines:\n\t\t\tbreak\n\ndef proc_tree(width: int, sorting: str = 'cpu lazy', reverse: bool = True, max_lines: int = 0, proc_per_cpu=True, search=''):\n\t'''List all processess in a tree view with pid, name, threads, username, memory percent and cpu percent'''\n\ttree_line_count: int = 0\n\terr: float = 0.0\n\n\tdef create_tree(parent: int, tree, indent: str = '', inindent: str = ' ', found: bool = False):\n\t\tnonlocal infolist, tree_line_count, max_lines, tree_width, proc_per_cpu, search\n\t\tcont: bool = True\n\t\tif max_lines and tree_line_count >= max_lines:\n\t\t\treturn\n\t\ttry:\n\t\t\tname: str = psutil.Process(parent).name()\n\t\t\tif name == \"idle\": return\n\t\texcept psutil.Error:\n\t\t\tpass\n\t\t\tname: str = ''\n\t\ttry:\n\t\t\tgetinfo: Dict = infolist[parent]\n\t\texcept:\n\t\t\tpass\n\t\t\tgetinfo: bool = False\n\t\tif search and not found:\n\t\t\tfor value in [ name, str(parent), getinfo['username'] if getinfo else '' ]:\n\t\t\t\tif search in value:\n\t\t\t\t\tfound = True\n\t\t\t\t\tbreak\n\t\t\tif not found:\n\t\t\t\tcont = False\n\t\tif cont: print(f\"{f'{inindent}{parent} {cleaned(name)}':<{tree_width}.{tree_width-1}}\", sep='', end='')\n\t\tif getinfo and cont:\n\t\t\tif getinfo['cpu_times'] == err:\n\t\t\t\tgetinfo['num_threads'] = 0\n\t\t\tif p.info['username'] == err:\n\t\t\t\t\tp.info['username'] = \"?\"\n\t\t\tcpu = getinfo['cpu_percent'] if proc_per_cpu else (getinfo['cpu_percent'] / psutil.cpu_count())\n\t\t\tprint(f\"{getinfo['num_threads']:>4} \" if getinfo['num_threads'] < 1000 else '999> ',\n\t\t\t\tf\"{getinfo['username']:<9.9}\" if len(getinfo['username']) < 10 else f\"{getinfo['username'][:8]:<8}+\",\n\t\t\t\tf\"{getinfo['memory_percent']:>4.1f}\" if getinfo['memory_percent'] < 100 else f\"{getinfo['memory_percent']:>4.0f} \",\n\t\t\t\tf\"{cpu:>11.1f} \" if cpu < 100 else f\"{cpu:>11.0f} \",\n\t\t\t\tsep='')\n\t\telif cont:\n\t\t\tprint(f\"{'':>14}{'0.0':>4}{'0.0':>11} \", sep='')\n\t\ttree_line_count += 1\n\t\tif parent not in tree:\n\t\t\treturn\n\t\tchildren = tree[parent][:-1]\n\t\tfor child in children:\n\t\t\tcreate_tree(child, tree, indent + \" │ \", indent + \" ├─ \", found=found)\n\t\t\tif max_lines and tree_line_count >= max_lines:\n\t\t\t\tbreak\n\t\tchild = tree[parent][-1]\n\t\tcreate_tree(child, tree, indent + \"  \", indent + \" └─ \")\n\n\tinfolist: Dict = {}\n\ttree: List = defaultdict(list)\n\tfor p in sorted(psutil.process_iter(['pid', 'name', 'num_threads', 'username', 'memory_percent', 'cpu_percent', 'cpu_times', 'create_time'], err), key=lambda p: eval(sorting), reverse=reverse):\n\t\ttry:\n\t\t\ttree[p.ppid()].append(p.pid)\n\t\texcept (psutil.NoSuchProcess, psutil.ZombieProcess):\n\t\t\tpass\n\t\telse:\n\t\t\tinfolist[p.pid] = p.info\n\tif 0 in tree and 0 in tree[0]:\n\t\ttree[0].remove(0)\n\n\ttree_width: int = width + 8\n\n\tprint(f\"{' Tree:':<{tree_width-4}}\", 'Threads: ', f\"{'User:':<9}Mem%{'Cpu%':>11}\", sep='')\n\tcreate_tree(min(tree), tree)\n\ndef get_disks(exclude: str = None, filtering: str = None):\n\t'''Get stats, current read and current write for all disks'''\n\tglobal disk_hist\n\tdisk_read: int = 0\n\tdisk_write: int = 0\n\tdev_name: str\n\tdisk_name: str\n\tdisk_list: List[str] = []\n\texcludes: List[str] = []\n\tif exclude: excludes = exclude.split(' ')\n\tif system == \"BSD\": excludes += [\"devfs\", \"tmpfs\", \"procfs\", \"linprocfs\", \"gvfs\", \"fusefs\"]\n\tif filtering: filtering: Tuple[str] = tuple(filtering.split(' '))\n\tio_counters = psutil.disk_io_counters(perdisk=True if system == \"Linux\" else False, nowrap=True)\n\tprint(\"Ignored line\")\n\tfor disk in psutil.disk_partitions():\n\t\tdisk_io = None\n\t\tdisk_name = disk.mountpoint.rsplit('/', 1)[-1] if not disk.mountpoint == \"/\" else \"root\"\n\t\twhile disk_name in disk_list: disk_name += \"_\"\n\t\tdisk_list += [disk_name]\n\t\tif excludes and disk.fstype in excludes or filtering and not disk_name.endswith(filtering):\n\t\t\tcontinue\n\t\tif system == \"MacOS\" and disk.mountpoint == \"/private/var/vm\":\n\t\t\tcontinue\n\t\ttry:\n\t\t\tdisk_u = psutil.disk_usage(disk.mountpoint)\n\t\texcept:\n\t\t\tpass\n\t\tprint(f'{disk.device} {disk_u.total >> 10} {disk_u.used >> 10} {disk_u.free >> 10} {disk_u.percent:.0f} ', end='')\n\t\ttry:\n\t\t\tif system == \"Linux\":\n\t\t\t\tdev_name = os.path.realpath(disk.device).rsplit('/', 1)[-1]\n\t\t\t\tif dev_name.startswith(\"md\"):\n\t\t\t\t\ttry:\n\t\t\t\t\t\tdev_name = dev_name[:dev_name.index(\"p\")]\n\t\t\t\t\texcept:\n\t\t\t\t\t\tpass\n\t\t\t\tdisk_io = io_counters[dev_name]\n\t\t\telif disk.mountpoint == \"/\":\n\t\t\t\tdisk_io = io_counters\n\t\t\telse:\n\t\t\t\traise Exception\n\t\t\tdisk_read = disk_io.read_bytes\n\t\t\tdisk_write = disk_io.write_bytes\n\n\t\t\tdisk_read -= disk_hist[disk.device][0]\n\t\t\tdisk_write -= disk_hist[disk.device][1]\n\t\texcept:\n\t\t\tpass\n\t\t\tdisk_read = 0\n\t\t\tdisk_write = 0\n\n\t\tif disk_io: disk_hist[disk.device] = (disk_io.read_bytes, disk_io.write_bytes)\n\t\tprint(f'{disk_read >> 10} {disk_write >> 10} {disk_name}')\n\n#* The script takes input over coproc pipes and runs command if in the accepted commands list\nwhile command != 'quit':\n\tif not psutil.pid_exists(parent_pid):\n\t\tquit()\n\ttry:\n\t\tcommand = input()\n\texcept:\n\t\tpass\n\t\tquit()\n\n\tif not command or command == 'test':\n\t\tcontinue\n\telif command.startswith(allowed_commands):\n\t\ttry:\n\t\t\texec(command)\n\t\texcept Exception as e:\n\t\t\tpass\n\t\t\tprint()\n\t\t\tprint('/ERROR')\n\t\t\tprint(f'PSUTIL ERROR! Command: {command}\\n{e}', file=sys.stderr)\n\telse:\n\t\tcontinue\n\tprint('/EOL')\n\t#print(f'{command}', file=sys.stderr)\nEOF\n\tfi\nfi\n\n#* Set up traps for ctrl-c, soft kill, window resize, ctrl-z and resume from ctrl-z\ntrap 'quitting=1; time_left=0' SIGINT SIGQUIT SIGTERM\ntrap 'resized=1; time_left=0' SIGWINCH\ntrap 'sleepy=1; time_left=0' SIGTSTP\ntrap 'resume_' SIGCONT\ntrap 'failed_pipe=1; time_left=0' PIPE\n\n#* Set up error logging to file if enabled\nif [[ $error_logging == true ]]; then\n\tset -o errtrace\n\ttrap 'traperr' ERR\n\n\t#* Remove everything but the last 500 lines of error log if larger than 500 lines\n\tif [[ -e \"${config_dir}/error.log\" && $(${wc} -l <\"${config_dir}/error.log\") -gt 500 ]]; then\n\t\t${tail} -n 500 \"${config_dir}/error.log\" > \"${config_dir}/tmp\"\n\t\t${rm} -f \"${config_dir}/error.log\"\n\t\t${mv} -f \"${config_dir}/tmp\" \"${config_dir}/error.log\"\n\tfi\n\t( echo \" \" ; echo \"New instance of bashtop version: ${version} Pid: $$\" ) >> \"${config_dir}/error.log\"\n\texec 2>>\"${config_dir}/error.log\"\n\tif [[ $1 == \"--debug\" ]]; then\n\t\texec 19>\"${config_dir}/tracing.log\"\n\t\tBASH_XTRACEFD=19\n\t\tset -x\n\tfi\nelse\n\texec 2>/dev/null\nfi\n\n#* If we have been sourced by another shell, quit. Allows sourcing only function definition.\n[[ \"${#BASH_SOURCE[@]}\" -gt 1 ]] && { return 0; }\n\n#* Call init function\ninit_\n\nif [[ $use_psutil == true ]]; then\n\tcoproc pycoproc (python3 ${pywrapper})\n\tsleep 0.1\n\tinit_ cont\nfi\n\n#* Start infinite loop\nuntil false; do\n\tif [[ $use_psutil == true ]] && [[ -n $failed_pipe ]]; then\n\t\tif ((++failed_pipes>10)); then\n\t\t\tif [[ $system == \"Linux\" ]]; then\n\t\t\t\tuse_psutil=\"false\"\n\t\t\telse\n\t\t\t\tquit_ 1\n\t\t\tfi\n\t\tfi\n\t\tcoproc pycoproc (python3 ${pywrapper})\n\t\tsleep 0.1\n\t\tunset failed_pipe\n\tfi\n\tif [[ -n $py_error ]]; then\n\t\tif ((++py_errors>10)); then\n\t\t\tif [[ $system == \"Linux\" ]]; then\n\t\t\t\tuse_psutil=\"false\"\n\t\t\telse\n\t\t\t\tquit_ 1\n\t\t\tfi\n\t\tfi\n\t\tunset py_error\n\tfi\n\tmain_loop\ndone\n\n#* Quit cleanly even if false starts being true...\nquit_\n"
  },
  {
    "path": "requirements.txt",
    "content": "psutil==5.7.0\n"
  },
  {
    "path": "src/bashtop.psutil.py",
    "content": "#!/usr/bin/env python3\n\n'''This is a copy of the python script that bashtop starts in a coprocess when using psutil for data collection'''\n\nimport os, sys, subprocess, re, time, psutil\nfrom datetime import timedelta\nfrom collections import defaultdict\nfrom typing import List, Set, Dict, Tuple, Optional, Union\n\nsystem: str\nif \"linux\" in sys.platform: system = \"Linux\"\nelif \"bsd\" in sys.platform: system = \"BSD\"\nelif \"darwin\" in sys.platform: system = \"MacOS\"\nelse: system = \"Other\"\n\nparent_pid: int = psutil.Process(os.getpid()).ppid()\n\nallowed_commands: Tuple[str] = (\n\t'get_proc',\n\t'get_disks',\n\t'get_cpu_name',\n\t'get_cpu_cores',\n\t'get_nics',\n\t'get_cpu_cores',\n\t'get_cpu_usage',\n\t'get_cpu_freq',\n\t'get_uptime',\n\t'get_load_avg',\n\t'get_mem',\n\t'get_detailed_names_cmd',\n\t'get_detailed_mem_time',\n\t'get_net',\n\t'get_cmd_out',\n\t'get_sensors',\n\t'get_sensors_check',\n\t'get_ms'\n\t)\ncommand: str = ''\ncpu_count: int = psutil.cpu_count()\ndisk_hist: Dict = {}\n\ndef cleaned(string: str) -> str:\n\t'''Escape characters not suitable for \"echo -e\" in bash'''\n\treturn string.replace(\"\\\\\", \"\\\\\\\\\").replace(\"$\", \"\\\\$\").replace(\"\\n\", \"\\\\n\").replace(\"\\t\", \"\\\\t\").replace(\"\\\"\", \"\\\\\\\"\").replace(\"\\'\", \"\\\\\\'\")\n\ndef get_cmd_out(cmd: str):\n\t'''Save bash the trouble of creating child processes by running through python instead'''\n\tprint(subprocess.check_output(cmd, shell=True, universal_newlines=True).rstrip())\n\ndef get_ms():\n\t'''Get current epoch millisecond'''\n\tt = str(time.time()).split(\".\")\n\tprint(f'{t[0]}{t[1][:3]}')\n\ndef get_sensors():\n\t'''A clone of \"sensors\" but using psutil'''\n\ttemps = psutil.sensors_temperatures()\n\tif not temps:\n\t\treturn\n\ttry:\n\t\tfor name, entries in temps.items():\n\t\t\tprint(name)\n\t\t\tfor entry in entries:\n\t\t\t\tprint(f'{entry.label or name}: {entry.current}°C (high = {entry.high}°C, crit = {entry.critical}°C)')\n\t\t\tprint()\n\texcept:\n\t\tpass\n\ndef get_sensors_check():\n\t'''Check if get_sensors() output contains accepted CPU temperature values'''\n\tif not hasattr(psutil, \"sensors_temperatures\"): print(\"false\"); return\n\ttry:\n\t\ttemps = psutil.sensors_temperatures()\n\texcept:\n\t\tpass\n\t\tprint(\"false\"); return\n\tif not temps: print(\"false\"); return\n\ttry:\n\t\tfor _, entries in temps.items():\n\t\t\tfor entry in entries:\n\t\t\t\tif entry.label.startswith(('Package', 'Core 0', 'Tdie')):\n\t\t\t\t\tprint(\"true\")\n\t\t\t\t\treturn\n\texcept:\n\t\tpass\n\tprint(\"false\")\n\ndef get_cpu_name():\n\t'''Fetch a suitable CPU identifier from the CPU model name string'''\n\tname: str = \"\"\n\tcommand: str = \"\"\n\tall_info: str = \"\"\n\trem_line: str = \"\"\n\tif system == \"Linux\":\n\t\tcommand = \"cat /proc/cpuinfo\"\n\t\trem_line = \"model name\"\n\telif system == \"MacOS\":\n\t\tcommand =\"sysctl -n machdep.cpu.brand_string\"\n\telif system == \"BSD\":\n\t\tcommand =\"sysctl hw.model\"\n\t\trem_line = \"hw.model\"\n\n\tall_info = subprocess.check_output(\"LANG=C \" + command, shell=True, universal_newlines=True)\n\tif rem_line:\n\t\tfor line in all_info.split(\"\\n\"):\n\t\t\tif rem_line in line:\n\t\t\t\tname = re.sub( \".*\" + rem_line + \".*:\", \"\", line,1).lstrip()\n\telse:\n\t\tname = all_info\n\tif \"Xeon\" in name:\n\t\tname = name.split(\" \")\n\t\tname = name[name.index(\"CPU\")+1]\n\telif \"Ryzen\" in name:\n\t\tname = name.split(\" \")\n\t\tname = \" \".join(name[name.index(\"Ryzen\"):name.index(\"Ryzen\")+3])\n\telif \"CPU\" in name:\n\t\tname = name.split(\" \")\n\t\tname = name[name.index(\"CPU\")-1]\n\n\tprint(name)\n\ndef get_cpu_cores():\n\t'''Get number of CPU cores and threads'''\n\tcores: int = psutil.cpu_count(logical=False)\n\tthreads: int = psutil.cpu_count(logical=True)\n\tprint(f'{cores} {threads if threads else cores}')\n\ndef get_cpu_usage():\n\tcpu: float = psutil.cpu_percent(percpu=False)\n\tthreads: List[float] = psutil.cpu_percent(percpu=True)\n\tprint(f'{cpu:.0f}')\n\tfor thread in threads:\n\t\tprint(f'{thread:.0f}')\n\ndef get_cpu_freq():\n\t'''Get current CPU frequency'''\n\ttry:\n\t\tprint(f'{psutil.cpu_freq().current:.0f}')\n\texcept:\n\t\tprint(0)\n\ndef get_uptime():\n\t'''Get current system uptime'''\n\tprint(str(timedelta(seconds=round(time.time()-psutil.boot_time(),0)))[:-3])\n\ndef get_load_avg():\n\t'''Get CPU load average'''\n\tfor lavg in os.getloadavg():\n\t\tprint(round(lavg, 2), ' ', end='')\n\tprint()\n\ndef get_mem():\n\t'''Get current system memory and swap usage'''\n\tmem = psutil.virtual_memory()\n\tswap = psutil.swap_memory()\n\ttry:\n\t\tcmem = mem.cached>>10\n\texcept:\n\t\tcmem = mem.active>>10\n\tprint(mem.total>>10, mem.free>>10, mem.available>>10, cmem, swap.total>>10, swap.free>>10)\n\ndef get_nics():\n\t'''Get a list of all network devices sorted by highest throughput'''\n\tio_all = psutil.net_io_counters(pernic=True)\n\tup_stat = psutil.net_if_stats()\n\n\tfor nic in sorted(psutil.net_if_addrs(), key=lambda nic: (io_all[nic].bytes_recv + io_all[nic].bytes_sent), reverse=True):\n\t\tif up_stat[nic].isup is False:\n\t\t\tcontinue\n\t\tprint(nic)\n\ndef get_net(net_dev: str):\n\t'''Emulated /proc/net/dev for selected network device'''\n\tnet = psutil.net_io_counters(pernic=True)[net_dev]\n\tprint(0,net.bytes_recv,0,0,0,0,0,0,0,net.bytes_sent)\n\ndef get_detailed_names_cmd(pid: int):\n\t'''Get name, parent name, username and arguments for selected pid'''\n\tp = psutil.Process(pid)\n\tpa = psutil.Process(p.ppid())\n\twith p.oneshot():\n\t\tprint(p.name())\n\t\tprint(pa.name())\n\t\tprint(p.username())\n\t\tcmd = ' '.join(p.cmdline()) or '[' + p.name() + ']'\n\t\tprint(cleaned(cmd))\n\ndef get_detailed_mem_time(pid: int):\n\t'''Get memory usage and runtime for selected pid'''\n\tp = psutil.Process(pid)\n\twith p.oneshot():\n\t\tprint(p.memory_info().rss)\n\t\tprint(timedelta(seconds=round(time.time()-p.create_time(),0)))\n\ndef get_proc(sorting='cpu lazy', tree=False, prog_len=0, arg_len=0, search='', reverse=True, proc_per_cpu=True, max_lines=0):\n\t'''List all processess with pid, name, arguments, threads, username, memory percent and cpu percent'''\n\tline_count: int = 0\n\terr: float = 0.0\n\treverse = not reverse\n\n\tif sorting == 'pid':\n\t\tsort_cmd = \"p.info['pid']\"\n\telif sorting == 'program' or tree and sorting == \"arguments\":\n\t\tsort_cmd = \"p.info['name']\"\n\t\treverse = not reverse\n\telif sorting == 'arguments':\n\t\tsort_cmd = \"' '.join(str(p.info['cmdline'])) or p.info['name']\"\n\t\treverse = not reverse\n\telif sorting == 'threads':\n\t\tsort_cmd = \"str(p.info['num_threads'])\"\n\telif sorting == 'user':\n\t\tsort_cmd = \"p.info['username']\"\n\t\treverse = not reverse\n\telif sorting == 'memory':\n\t\tsort_cmd = \"str(p.info['memory_percent'])\"\n\telif sorting == 'cpu responsive':\n\t\tsort_cmd = \"p.info['cpu_percent']\" if proc_per_cpu else \"(p.info['cpu_percent'] / cpu_count)\"\n\telse:\n\t\tsort_cmd = \"(sum(p.info['cpu_times'][:2] if not p.info['cpu_times'] == 0.0 else [0.0, 0.0]) * 1000 / (time.time() - p.info['create_time']))\"\n\n\tif tree:\n\t\tproc_tree(width=prog_len + arg_len, sorting=sort_cmd, reverse=reverse, max_lines=max_lines, proc_per_cpu=proc_per_cpu, search=search)\n\t\treturn\n\n\n\tprint(f\"{'Pid:':>7} {'Program:':<{prog_len}}\", f\"{'Arguments:':<{arg_len-4}}\" if arg_len else '', f\"{'Threads:' if arg_len else ' Tr:'} {'User:':<9}Mem%{'Cpu%':>11}\", sep='')\n\n\tfor p in sorted(psutil.process_iter(['pid', 'name', 'cmdline', 'num_threads', 'username', 'memory_percent', 'cpu_percent', 'cpu_times', 'create_time'], err), key=lambda p: eval(sort_cmd), reverse=reverse):\n\t\tif p.info['name'] == 'idle' or p.info['name'] == err or p.info['pid'] == err:\n\t\t\tcontinue\n\t\tif p.info['cmdline'] == err:\n\t\t\tp.info['cmdline'] = \"\"\n\t\tif p.info['username'] == err:\n\t\t\tp.info['username'] = \"?\"\n\t\tif p.info['num_threads'] == err:\n\t\t\tp.info['num_threads'] = 0\n\t\tif search:\n\t\t\tfound = False\n\t\t\tfor value in [ p.info['name'], ' '.join(p.info['cmdline']), str(p.info['pid']), p.info['username'] ]:\n\t\t\t\tif search in value:\n\t\t\t\t\tfound = True\n\t\t\t\t\tbreak\n\t\t\tif not found:\n\t\t\t\tcontinue\n\n\t\tcpu = p.info['cpu_percent'] if proc_per_cpu else (p.info['cpu_percent'] / psutil.cpu_count())\n\t\tmem = p.info['memory_percent']\n\t\tcmd = ' '.join(p.info['cmdline']) or '[' + p.info['name'] + ']'\n\t\tprint(f\"{p.info['pid']:>7} \",\n\t\t\tf\"{cleaned(p.info['name']):<{prog_len}.{prog_len-1}}\",\n\t\t\tf\"{cleaned(cmd):<{arg_len}.{arg_len-1}}\" if arg_len else '',\n\t\t\tf\"{p.info['num_threads']:>4} \" if p.info['num_threads'] < 1000 else '999> ',\n\t\t\tf\"{p.info['username']:<9.9}\" if len(p.info['username']) < 10 else f\"{p.info['username'][:8]:<8}+\",\n\t\t\tf\"{mem:>4.1f}\" if mem < 100 else f\"{mem:>4.0f} \",\n\t\t\tf\"{cpu:>11.1f} \" if cpu < 100 else f\"{cpu:>11.0f} \",\n\t\t\tsep='')\n\t\tline_count += 1\n\t\tif max_lines and line_count == max_lines:\n\t\t\tbreak\n\ndef proc_tree(width: int, sorting: str = 'cpu lazy', reverse: bool = True, max_lines: int = 0, proc_per_cpu=True, search=''):\n\t'''List all processess in a tree view with pid, name, threads, username, memory percent and cpu percent'''\n\ttree_line_count: int = 0\n\terr: float = 0.0\n\n\tdef create_tree(parent: int, tree, indent: str = '', inindent: str = ' ', found: bool = False):\n\t\tnonlocal infolist, tree_line_count, max_lines, tree_width, proc_per_cpu, search\n\t\tcont: bool = True\n\t\tif max_lines and tree_line_count >= max_lines:\n\t\t\treturn\n\t\ttry:\n\t\t\tname: str = psutil.Process(parent).name()\n\t\t\tif name == \"idle\": return\n\t\texcept psutil.Error:\n\t\t\tpass\n\t\t\tname: str = ''\n\t\ttry:\n\t\t\tgetinfo: Dict = infolist[parent]\n\t\texcept:\n\t\t\tpass\n\t\t\tgetinfo: bool = False\n\t\tif search and not found:\n\t\t\tfor value in [ name, str(parent), getinfo['username'] if getinfo else '' ]:\n\t\t\t\tif search in value:\n\t\t\t\t\tfound = True\n\t\t\t\t\tbreak\n\t\t\tif not found:\n\t\t\t\tcont = False\n\t\tif cont: print(f\"{f'{inindent}{parent} {cleaned(name)}':<{tree_width}.{tree_width-1}}\", sep='', end='')\n\t\tif getinfo and cont:\n\t\t\tif getinfo['cpu_times'] == err:\n\t\t\t\tgetinfo['num_threads'] = 0\n\t\t\tif p.info['username'] == err:\n\t\t\t\t\tp.info['username'] = \"?\"\n\t\t\tcpu = getinfo['cpu_percent'] if proc_per_cpu else (getinfo['cpu_percent'] / psutil.cpu_count())\n\t\t\tprint(f\"{getinfo['num_threads']:>4} \" if getinfo['num_threads'] < 1000 else '999> ',\n\t\t\t\tf\"{getinfo['username']:<9.9}\" if len(getinfo['username']) < 10 else f\"{getinfo['username'][:8]:<8}+\",\n\t\t\t\tf\"{getinfo['memory_percent']:>4.1f}\" if getinfo['memory_percent'] < 100 else f\"{getinfo['memory_percent']:>4.0f} \",\n\t\t\t\tf\"{cpu:>11.1f} \" if cpu < 100 else f\"{cpu:>11.0f} \",\n\t\t\t\tsep='')\n\t\telif cont:\n\t\t\tprint(f\"{'':>14}{'0.0':>4}{'0.0':>11} \", sep='')\n\t\ttree_line_count += 1\n\t\tif parent not in tree:\n\t\t\treturn\n\t\tchildren = tree[parent][:-1]\n\t\tfor child in children:\n\t\t\tcreate_tree(child, tree, indent + \" │ \", indent + \" ├─ \", found=found)\n\t\t\tif max_lines and tree_line_count >= max_lines:\n\t\t\t\tbreak\n\t\tchild = tree[parent][-1]\n\t\tcreate_tree(child, tree, indent + \"  \", indent + \" └─ \")\n\n\tinfolist: Dict = {}\n\ttree: List = defaultdict(list)\n\tfor p in sorted(psutil.process_iter(['pid', 'name', 'num_threads', 'username', 'memory_percent', 'cpu_percent', 'cpu_times', 'create_time'], err), key=lambda p: eval(sorting), reverse=reverse):\n\t\ttry:\n\t\t\ttree[p.ppid()].append(p.pid)\n\t\texcept (psutil.NoSuchProcess, psutil.ZombieProcess):\n\t\t\tpass\n\t\telse:\n\t\t\tinfolist[p.pid] = p.info\n\tif 0 in tree and 0 in tree[0]:\n\t\ttree[0].remove(0)\n\n\ttree_width: int = width + 8\n\n\tprint(f\"{' Tree:':<{tree_width-4}}\", 'Threads: ', f\"{'User:':<9}Mem%{'Cpu%':>11}\", sep='')\n\tcreate_tree(min(tree), tree)\n\ndef get_disks(exclude: str = None, filtering: str = None):\n\t'''Get stats, current read and current write for all disks'''\n\tglobal disk_hist\n\tdisk_read: int = 0\n\tdisk_write: int = 0\n\tdev_name: str\n\tdisk_name: str\n\tdisk_list: List[str] = []\n\texcludes: List[str] = []\n\tif exclude: excludes = exclude.split(' ')\n\tif system == \"BSD\": excludes += [\"devfs\", \"tmpfs\", \"procfs\", \"linprocfs\", \"gvfs\", \"fusefs\"]\n\tif filtering: filtering: Tuple[str] = tuple(filtering.split(' '))\n\tio_counters = psutil.disk_io_counters(perdisk=True if system == \"Linux\" else False, nowrap=True)\n\tprint(\"Ignored line\")\n\tfor disk in psutil.disk_partitions():\n\t\tdisk_io = None\n\t\tdisk_name = disk.mountpoint.rsplit('/', 1)[-1] if not disk.mountpoint == \"/\" else \"root\"\n\t\twhile disk_name in disk_list: disk_name += \"_\"\n\t\tdisk_list += [disk_name]\n\t\tif excludes and disk.fstype in excludes or filtering and not disk_name.endswith(filtering):\n\t\t\tcontinue\n\t\tif system == \"MacOS\" and disk.mountpoint == \"/private/var/vm\":\n\t\t\tcontinue\n\t\ttry:\n\t\t\tdisk_u = psutil.disk_usage(disk.mountpoint)\n\t\texcept:\n\t\t\tpass\n\t\tprint(f'{disk.device} {disk_u.total >> 10} {disk_u.used >> 10} {disk_u.free >> 10} {disk_u.percent:.0f} ', end='')\n\t\ttry:\n\t\t\tif system == \"Linux\":\n\t\t\t\tdev_name = os.path.realpath(disk.device).rsplit('/', 1)[-1]\n\t\t\t\tif dev_name.startswith(\"md\"):\n\t\t\t\t\ttry:\n\t\t\t\t\t\tdev_name = dev_name[:dev_name.index(\"p\")]\n\t\t\t\t\texcept:\n\t\t\t\t\t\tpass\n\t\t\t\tdisk_io = io_counters[dev_name]\n\t\t\telif disk.mountpoint == \"/\":\n\t\t\t\tdisk_io = io_counters\n\t\t\telse:\n\t\t\t\traise Exception\n\t\t\tdisk_read = disk_io.read_bytes\n\t\t\tdisk_write = disk_io.write_bytes\n\n\t\t\tdisk_read -= disk_hist[disk.device][0]\n\t\t\tdisk_write -= disk_hist[disk.device][1]\n\t\texcept:\n\t\t\tpass\n\t\t\tdisk_read = 0\n\t\t\tdisk_write = 0\n\n\t\tif disk_io: disk_hist[disk.device] = (disk_io.read_bytes, disk_io.write_bytes)\n\t\tprint(f'{disk_read >> 10} {disk_write >> 10} {disk_name}')\n\n#* The script takes input over coproc pipes and runs command if in the accepted commands list\nwhile command != 'quit':\n\tif not psutil.pid_exists(parent_pid):\n\t\tquit()\n\ttry:\n\t\tcommand = input()\n\texcept:\n\t\tpass\n\t\tquit()\n\n\tif not command or command == 'test':\n\t\tcontinue\n\telif command.startswith(allowed_commands):\n\t\ttry:\n\t\t\texec(command)\n\t\texcept Exception as e:\n\t\t\tpass\n\t\t\tprint()\n\t\t\tprint('/ERROR')\n\t\t\tprint(f'PSUTIL ERROR! Command: {command}\\n{e}', file=sys.stderr)\n\telse:\n\t\tcontinue\n\tprint('/EOL')\n\t#print(f'{command}', file=sys.stderr)"
  },
  {
    "path": "test/basic_test.bats",
    "content": "#!/usr/bin/env bats\n\nload 'libs/bats-support/load'\nload 'libs/bats-assert/load'\n\nload test_helper\n\n@test \"Sourcing works, by checking if \\$system is set\" {\n    run echo $system\n    refute_output \"\"\n}\n\n@test \"#get_themes populates themes\" {\n  get_themes\n  assert_success\n  assert [ ${#themes[@]} -gt 0 ]\n}\n"
  },
  {
    "path": "test/test_helper.bash",
    "content": "source bashtop\n"
  },
  {
    "path": "test.sh",
    "content": "#!/usr/bin/env bash\n\n./test/libs/bats/bin/bats test/*.bats\n"
  },
  {
    "path": "themes/default_black.theme",
    "content": "#Bashtop theme with default colors and black background\n#by aristocratos\n\n# Colors should be in 6 or 2 character hexadecimal or single spaced rgb decimal: \"#RRGGBB\", \"#BW\" or \"0-255 0-255 0-255\"\n# example for white: \"#FFFFFF\", \"#ff\" or \"255 255 255\".\n\n# All graphs and meters can be gradients\n# For single color graphs leave \"mid\" and \"end\" variable empty.\n# Use \"start\" and \"end\" variables for two color gradient\n# Use \"start\", \"mid\" and \"end\" for three color gradient\n\n# Main background, empty for terminal default, need to be empty if you want transparent background\ntheme[main_bg]=\"#00\"\n\n# Main text color\ntheme[main_fg]=\"#cc\"\n\n# Title color for boxes\ntheme[title]=\"#ee\"\n\n# Higlight color for keyboard shortcuts\ntheme[hi_fg]=\"#90\"\n\n# Background color of selected item in processes box\ntheme[selected_bg]=\"#7e2626\" \n\n# Foreground color of selected item in processes box\ntheme[selected_fg]=\"#ee\"\n\n# Color of inactive/disabled text\ntheme[inactive_fg]=\"#40\"\n\n# Misc colors for processes box including mini cpu graphs, details memory graph and details status text\ntheme[proc_misc]=\"#0de756\"\n\n# Cpu box outline color\ntheme[cpu_box]=\"#3d7b46\"\n\n# Memory/disks box outline color\ntheme[mem_box]=\"#8a882e\"\n\n# Net up/down box outline color\ntheme[net_box]=\"#423ba5\"\n\n# Processes box outline color\ntheme[proc_box]=\"#923535\"\n\n# Box divider line and small boxes line color\ntheme[div_line]=\"#30\"\n\n# Temperature graph colors\ntheme[temp_start]=\"#4897d4\"\ntheme[temp_mid]=\"#5474e8\"\ntheme[temp_end]=\"#ff40b6\"\n\n# CPU graph colors\ntheme[cpu_start]=\"#50f095\"\ntheme[cpu_mid]=\"#f2e266\"\ntheme[cpu_end]=\"#fa1e1e\"\n\n# Mem/Disk free meter\ntheme[free_start]=\"#223014\"\ntheme[free_mid]=\"#b5e685\"\ntheme[free_end]=\"#dcff85\"\n\n# Mem/Disk cached meter\ntheme[cached_start]=\"#0b1a29\"\ntheme[cached_mid]=\"#74e6fc\"\ntheme[cached_end]=\"#26c5ff\"\n\n# Mem/Disk available meter\ntheme[available_start]=\"#292107\"\ntheme[available_mid]=\"#ffd77a\"\ntheme[available_end]=\"#ffb814\"\n\n# Mem/Disk used meter\ntheme[used_start]=\"#3b1f1c\"\ntheme[used_mid]=\"#d9626d\"\ntheme[used_end]=\"#ff4769\"\n\n# Download graph colors\ntheme[download_start]=\"#231a63\"\ntheme[download_mid]=\"#4f43a3\"\ntheme[download_end]=\"#b0a9de\"\n\n# Upload graph colors\ntheme[upload_start]=\"#510554\"\ntheme[upload_mid]=\"#7d4180\"\ntheme[upload_end]=\"#dcafde\""
  },
  {
    "path": "themes/flat-remix-light.theme",
    "content": "#Bashtop theme with flat-remix colors\n#by Daniel Ruiz de Alegría <daniel@drasite.com>\n\n# Colors should be in 6 or 2 character hexadecimal or single spaced rgb decimal: \"#RRGGBB\", \"#BW\" or \"0-255 0-255 0-255\"\n# example for white: \"#ffffff\", \"#ff\" or \"255 255 255\".\n\n# All graphs and meters can be gradients\n# For single color graphs leave \"mid\" and \"end\" variable empty.\n# Use \"start\" and \"end\" variables for two color gradient\n# Use \"start\", \"mid\" and \"end\" for three color gradient\n\n# Main background, empty for terminal default, need to be empty if you want transparent background\ntheme[main_bg]=\"#e4e4e7\"\n\n# Main text color\ntheme[main_fg]=\"#737680\"\n\n# Title color for boxes\ntheme[title]=\"#272a34\"\n\n# Higlight color for keyboard shortcuts\ntheme[hi_fg]=\"#90\"\n\n# Background color of selected item in processes box\ntheme[selected_bg]=\"#b8174c\"\n\n# Foreground color of selected item in processes box\ntheme[selected_fg]=\"#ff\"\n\n# Color of inactive/disabled text\ntheme[inactive_fg]=\"#40\"\n\n# Misc colors for processes box including mini cpu graphs, details memory graph and details status text\ntheme[proc_misc]=\"#367bf0\"\n\n# Cpu box outline color\ntheme[cpu_box]=\"#367bf0\"\n\n# Memory/disks box outline color\ntheme[mem_box]=\"#19a187\"\n\n# Net up/down box outline color\ntheme[net_box]=\"#fd3535\"\n\n# Processes box outline color\ntheme[proc_box]=\"#4aaee6\"\n\n# Box divider line and small boxes line color\ntheme[div_line]=\"#50\"\n\n# Temperature graph colors\ntheme[temp_start]=\"#367bf0\"\ntheme[temp_mid]=\"#b8174c\"\ntheme[temp_end]=\"#d41919\"\n\n# CPU graph colors\ntheme[cpu_start]=\"#367bf0\"\ntheme[cpu_mid]=\"#4aaee6\"\ntheme[cpu_end]=\"#54bd8e\"\n\n# Mem/Disk free meter\ntheme[free_start]=\"#811035\"\ntheme[free_mid]=\"#b8174c\"\ntheme[free_end]=\"#d41919\"\n\n# Mem/Disk cached meter\ntheme[cached_start]=\"#2656a8\"\ntheme[cached_mid]=\"#4aaee6\"\ntheme[cached_end]=\"#23bac2\"\n\n# Mem/Disk available meter\ntheme[available_start]=\"#fea44c\"\ntheme[available_mid]=\"#fd7d00\"\ntheme[available_end]=\"#fe7171\"\n\n# Mem/Disk used meter\ntheme[used_start]=\"#12715f\"\ntheme[used_mid]=\"#19a187\"\ntheme[used_end]=\"#23bac2\"\n\n# Download graph colors\ntheme[download_start]=\"#367bf0\"\ntheme[download_mid]=\"#19a187\"\ntheme[download_end]=\"#4aaee6\"\n\n# Upload graph colors\ntheme[upload_start]=\"#8c42ab\"\ntheme[upload_mid]=\"#b8174c\"\ntheme[upload_end]=\"#d41919\"\n"
  },
  {
    "path": "themes/flat-remix.theme",
    "content": "#Bashtop theme with flat-remix colors\n#by Daniel Ruiz de Alegría <daniel@drasite.com>\n\n# Colors should be in 6 or 2 character hexadecimal or single spaced rgb decimal: \"#RRGGBB\", \"#BW\" or \"0-255 0-255 0-255\"\n# example for white: \"#ffffff\", \"#ff\" or \"255 255 255\".\n\n# All graphs and meters can be gradients\n# For single color graphs leave \"mid\" and \"end\" variable empty.\n# Use \"start\" and \"end\" variables for two color gradient\n# Use \"start\", \"mid\" and \"end\" for three color gradient\n\n# Main background, empty for terminal default, need to be empty if you want transparent background\ntheme[main_bg]=\"\"\n\n# Main text color\ntheme[main_fg]=\"#E6E6E6\"\n\n# Title color for boxes\ntheme[title]=\"#ff\"\n\n# Higlight color for keyboard shortcuts\ntheme[hi_fg]=\"#90\"\n\n# Background color of selected item in processes box\ntheme[selected_bg]=\"#b8174c\"\n\n# Foreground color of selected item in processes box\ntheme[selected_fg]=\"#ff\"\n\n# Color of inactive/disabled text\ntheme[inactive_fg]=\"#40\"\n\n# Misc colors for processes box including mini cpu graphs, details memory graph and details status text\ntheme[proc_misc]=\"#367bf0\"\n\n# Cpu box outline color\ntheme[cpu_box]=\"#367bf0\"\n\n# Memory/disks box outline color\ntheme[mem_box]=\"#19a187\"\n\n# Net up/down box outline color\ntheme[net_box]=\"#fd3535\"\n\n# Processes box outline color\ntheme[proc_box]=\"#4aaee6\"\n\n# Box divider line and small boxes line color\ntheme[div_line]=\"#50\"\n\n# Temperature graph colors\ntheme[temp_start]=\"#367bf0\"\ntheme[temp_mid]=\"#b8174c\"\ntheme[temp_end]=\"#d41919\"\n\n# CPU graph colors\ntheme[cpu_start]=\"#367bf0\"\ntheme[cpu_mid]=\"#4aaee6\"\ntheme[cpu_end]=\"#54bd8e\"\n\n# Mem/Disk free meter\ntheme[free_start]=\"#811035\"\ntheme[free_mid]=\"#b8174c\"\ntheme[free_end]=\"#d41919\"\n\n# Mem/Disk cached meter\ntheme[cached_start]=\"#2656a8\"\ntheme[cached_mid]=\"#4aaee6\"\ntheme[cached_end]=\"#23bac2\"\n\n# Mem/Disk available meter\ntheme[available_start]=\"#fea44c\"\ntheme[available_mid]=\"#fd7d00\"\ntheme[available_end]=\"#fe7171\"\n\n# Mem/Disk used meter\ntheme[used_start]=\"#12715f\"\ntheme[used_mid]=\"#19a187\"\ntheme[used_end]=\"#23bac2\"\n\n# Download graph colors\ntheme[download_start]=\"#367bf0\"\ntheme[download_mid]=\"#19a187\"\ntheme[download_end]=\"#4aaee6\"\n\n# Upload graph colors\ntheme[upload_start]=\"#8c42ab\"\ntheme[upload_mid]=\"#b8174c\"\ntheme[upload_end]=\"#d41919\"\n"
  },
  {
    "path": "themes/greyscale.theme",
    "content": "#Bashtop grayscale theme\n#by aristocratos\n\n# Colors should be in 6 or 2 character hexadecimal or single spaced rgb decimal: \"#RRGGBB\", \"#BW\" or \"0-255 0-255 0-255\"\n# example for white: \"#FFFFFF\", \"#ff\" or \"255 255 255\".\n\n# All graphs and meters can be gradients\n# For single color graphs leave \"mid\" and \"end\" variable empty.\n# Use \"start\" and \"end\" variables for two color gradient\n# Use \"start\", \"mid\" and \"end\" for three color gradient\n\n# Main background, empty for terminal default, need to be empty if you want transparent background\ntheme[main_bg]=\"#00\"\n\n# Main text color\ntheme[main_fg]=\"#bb\"\n\n# Title color for boxes\ntheme[title]=\"#cc\"\n\n# Higlight color for keyboard shortcuts\ntheme[hi_fg]=\"#90\"\n\n# Background color of selected item in processes box\ntheme[selected_bg]=\"#ff\" \n\n# Foreground color of selected item in processes box\ntheme[selected_fg]=\"#00\"\n\n# Color of inactive/disabled text\ntheme[inactive_fg]=\"#30\"\n\n# Misc colors for processes box including mini cpu graphs, details memory graph and details status text\ntheme[proc_misc]=\"#90\"\n\n# Cpu box outline color\ntheme[cpu_box]=\"#90\"\n\n# Memory/disks box outline color\ntheme[mem_box]=\"#90\"\n\n# Net up/down box outline color\ntheme[net_box]=\"#90\"\n\n# Processes box outline color\ntheme[proc_box]=\"#90\"\n\n# Box divider line and small boxes line color\ntheme[div_line]=\"#30\"\n\n# Temperature graph colors\ntheme[temp_start]=\"#50\"\ntheme[temp_mid]=\"\"\ntheme[temp_end]=\"#ff\"\n\n# CPU graph colors\ntheme[cpu_start]=\"#50\"\ntheme[cpu_mid]=\"\"\ntheme[cpu_end]=\"#ff\"\n\n# Mem/Disk free meter\ntheme[free_start]=\"#50\"\ntheme[free_mid]=\"\"\ntheme[free_end]=\"#ff\"\n\n# Mem/Disk cached meter\ntheme[cached_start]=\"#50\"\ntheme[cached_mid]=\"\"\ntheme[cached_end]=\"#ff\"\n\n# Mem/Disk available meter\ntheme[available_start]=\"#50\"\ntheme[available_mid]=\"\"\ntheme[available_end]=\"#ff\"\n\n# Mem/Disk used meter\ntheme[used_start]=\"#50\"\ntheme[used_mid]=\"\"\ntheme[used_end]=\"#ff\"\n\n# Download graph colors\ntheme[download_start]=\"#30\"\ntheme[download_mid]=\"\"\ntheme[download_end]=\"#ff\"\n\n# Upload graph colors\ntheme[upload_start]=\"#30\"\ntheme[upload_mid]=\"\"\ntheme[upload_end]=\"#ff\""
  },
  {
    "path": "themes/gruvbox_dark.theme",
    "content": "#Bashtop gruvbox (https://github.com/morhetz/gruvbox) theme\n#by BachoSeven\n\n# Colors should be in 6 or 2 character hexadecimal or single spaced rgb decimal: \"#RRGGBB\", \"#BW\" or \"0-255 0-255 0-255\"\n# example for white: \"#FFFFFF\", \"#ff\" or \"255 255 255\".\n\n# All graphs and meters can be gradients\n# For single color graphs leave \"mid\" and \"end\" variable empty.\n# Use \"start\" and \"end\" variables for two color gradient\n# Use \"start\", \"mid\" and \"end\" for three color gradient\n\n# Main background, empty for terminal default, need to be empty if you want transparent background\ntheme[main_bg]=\"#1d2021\"\n\n# Main text color\ntheme[main_fg]=\"#a89984\"\n\n# Title color for boxes\ntheme[title]=\"#ebdbb2\"\n\n# Higlight color for keyboard shortcuts\ntheme[hi_fg]=\"#d79921\"\n\n# Background color of selected items\ntheme[selected_bg]=\"#282828\"\n\n# Foreground color of selected items\ntheme[selected_fg]=\"#fabd2f\"\n\n# Color of inactive/disabled text\ntheme[inactive_fg]=\"#282828\"\n\n# Misc colors for processes box including mini cpu graphs, details memory graph and details status text\ntheme[proc_misc]=\"#98971a\"\n\n# Cpu box outline color\ntheme[cpu_box]=\"#a89984\"\n\n# Memory/disks box outline color\ntheme[mem_box]=\"#a89984\"\n\n# Net up/down box outline color\ntheme[net_box]=\"#a89984\"\n\n# Processes box outline color\ntheme[proc_box]=\"#a89984\"\n\n# Box divider line and small boxes line color\ntheme[div_line]=\"#a89984\"\n\n# Temperature graph colors\ntheme[temp_start]=\"#458588\"\ntheme[temp_mid]=\"#d3869b\"\ntheme[temp_end]=\"#fb4394\"\n\n# CPU graph colors\ntheme[cpu_start]=\"#b8bb26\"\ntheme[cpu_mid]=\"#d79921\"\ntheme[cpu_end]=\"#fb4934\"\n\n# Mem/Disk free meter\ntheme[free_start]=\"#4e5900\"\ntheme[free_mid]=\"\"\ntheme[free_end]=\"#98971a\"\n\n# Mem/Disk cached meter\ntheme[cached_start]=\"#458588\"\ntheme[cached_mid]=\"\"\ntheme[cached_end]=\"#83a598\"\n\n# Mem/Disk available meter\ntheme[available_start]=\"#d79921\"\ntheme[available_mid]=\"\"\ntheme[available_end]=\"#fabd2f\"\n\n# Mem/Disk used meter\ntheme[used_start]=\"#cc241d\"\ntheme[used_mid]=\"\"\ntheme[used_end]=\"#fb4934\"\n\n# Download graph colors\ntheme[download_start]=\"#3d4070\"\ntheme[download_mid]=\"#6c71c4\"\ntheme[download_end]=\"#a3a8f7\"\n\n# Upload graph colors\ntheme[upload_start]=\"#701c45\"\ntheme[upload_mid]=\"#b16286\"\ntheme[upload_end]=\"#d3869b\"\n"
  },
  {
    "path": "themes/index.txt",
    "content": "default_black.theme\nflat-remix-light.theme\nflat-remix.theme\ngreyscale.theme\ngruvbox_dark.theme\nmonokai.theme\nnord.theme\nsolarized_dark.theme\nwhiteout.theme\n"
  },
  {
    "path": "themes/monokai.theme",
    "content": "#Bashtop monokai theme\n#by aristocratos\n\n# Colors should be in 6 or 2 character hexadecimal or single spaced rgb decimal: \"#RRGGBB\", \"#BW\" or \"0-255 0-255 0-255\"\n# example for white: \"#FFFFFF\", \"#ff\" or \"255 255 255\".\n\n# All graphs and meters can be gradients\n# For single color graphs leave \"mid\" and \"end\" variable empty.\n# Use \"start\" and \"end\" variables for two color gradient\n# Use \"start\", \"mid\" and \"end\" for three color gradient\n\n# Main background, empty for terminal default, need to be empty if you want transparent background\ntheme[main_bg]=\"\"\n\n# Main text color\ntheme[main_fg]=\"#F8F8F2\"\n\n# Title color for boxes\ntheme[title]=\"#F8F8F2\"\n\n# Higlight color for keyboard shortcuts\ntheme[hi_fg]=\"#F92672\"\n\n# Background color of selected item in processes box\ntheme[selected_bg]=\"#7a1137\"\n\n# Foreground color of selected item in processes box\ntheme[selected_fg]=\"#F8F8F2\"\n\n# Color of inactive/disabled text\ntheme[inactive_fg]=\"#595647\"\n\n# Misc colors for processes box including mini cpu graphs, details memory graph and details status text\ntheme[proc_misc]=\"#A6E22E\"\n\n# Cpu box outline color\ntheme[cpu_box]=\"#75715E\"\n\n# Memory/disks box outline color\ntheme[mem_box]=\"#75715E\"\n\n# Net up/down box outline color\ntheme[net_box]=\"#75715E\"\n\n# Processes box outline color\ntheme[proc_box]=\"#75715E\"\n\n# Box divider line and small boxes line color\ntheme[div_line]=\"#595647\"\n\n# Temperature graph colors\ntheme[temp_start]=\"#7976B7\"\ntheme[temp_mid]=\"#D8B8B2\"\ntheme[temp_end]=\"#F92672\"\n\n# CPU graph colors\ntheme[cpu_start]=\"#A6E22E\"\ntheme[cpu_mid]=\"#F8F8F2\" #b05475\"\ntheme[cpu_end]=\"#F92672\"\n\n# Mem/Disk free meter\ntheme[free_start]=\"#75715E\"\ntheme[free_mid]=\"#a9c474\"\ntheme[free_end]=\"#e2f5bc\"\n\n# Mem/Disk cached meter\ntheme[cached_start]=\"#75715E\"\ntheme[cached_mid]=\"#66D9EF\"\ntheme[cached_end]=\"#aae7f2\"\n\n# Mem/Disk available meter\ntheme[available_start]=\"#75715E\"\ntheme[available_mid]=\"#E6DB74\"\ntheme[available_end]=\"#f2ecb6\"\n\n# Mem/Disk used meter\ntheme[used_start]=\"#75715E\"\ntheme[used_mid]=\"#F92672\"\ntheme[used_end]=\"#ff87b2\"\n\n# Download graph colors\ntheme[download_start]=\"#2d2042\"\ntheme[download_mid]=\"#7352a8\"\ntheme[download_end]=\"#ccaefc\"\n\n# Upload graph colors\ntheme[upload_start]=\"#570d33\"\ntheme[upload_mid]=\"#cf277d\"\ntheme[upload_end]=\"#fa91c7\"\n"
  },
  {
    "path": "themes/nord.theme",
    "content": "#Bashtop theme with nord palette (https://www.nordtheme.com)\n#by Justin Zobel <justin.zobel@gmail.com>\n\n# Colors should be in 6 or 2 character hexadecimal or single spaced rgb decimal: \"#RRGGBB\", \"#BW\" or \"0-255 0-255 0-255\"\n# example for white: \"#ffffff\", \"#ff\" or \"255 255 255\".\n\n# All graphs and meters can be gradients\n# For single color graphs leave \"mid\" and \"end\" variable empty.\n# Use \"start\" and \"end\" variables for two color gradient\n# Use \"start\", \"mid\" and \"end\" for three color gradient\n\n# Main background, empty for terminal default, need to be empty if you want transparent background\ntheme[main_bg]=\"#2E3440\"\n\n# Main text color\ntheme[main_fg]=\"#D8DEE9\"\n\n# Title color for boxes\ntheme[title]=\"#8FBCBB\"\n\n# Higlight color for keyboard shortcuts\ntheme[hi_fg]=\"#5E81AC\"\n\n# Background color of selected item in processes box\ntheme[selected_bg]=\"#4C566A\"\n\n# Foreground color of selected item in processes box\ntheme[selected_fg]=\"#ECEFF4\"\n\n# Color of inactive/disabled text\ntheme[inactive_fg]=\"#4C566A\"\n\n# Misc colors for processes box including mini cpu graphs, details memory graph and details status text\ntheme[proc_misc]=\"#5E81AC\"\n\n# Cpu box outline color\ntheme[cpu_box]=\"#4C566A\"\n\n# Memory/disks box outline color\ntheme[mem_box]=\"#4C566A\"\n\n# Net up/down box outline color\ntheme[net_box]=\"#4C566A\"\n\n# Processes box outline color\ntheme[proc_box]=\"#4C566A\"\n\n# Box divider line and small boxes line color\ntheme[div_line]=\"#4C566A\"\n\n# Temperature graph colors\ntheme[temp_start]=\"#81A1C1\"\ntheme[temp_mid]=\"#88C0D0\"\ntheme[temp_end]=\"#ECEFF4\"\n\n# CPU graph colors\ntheme[cpu_start]=\"#81A1C1\"\ntheme[cpu_mid]=\"#88C0D0\"\ntheme[cpu_end]=\"#ECEFF4\"\n\n# Mem/Disk free meter\ntheme[free_start]=\"#81A1C1\"\ntheme[free_mid]=\"#88C0D0\"\ntheme[free_end]=\"#ECEFF4\"\n\n# Mem/Disk cached meter\ntheme[cached_start]=\"#81A1C1\"\ntheme[cached_mid]=\"#88C0D0\"\ntheme[cached_end]=\"#ECEFF4\"\n\n# Mem/Disk available meter\ntheme[available_start]=\"#81A1C1\"\ntheme[available_mid]=\"#88C0D0\"\ntheme[available_end]=\"#ECEFF4\"\n\n# Mem/Disk used meter\ntheme[used_start]=\"#81A1C1\"\ntheme[used_mid]=\"#88C0D0\"\ntheme[used_end]=\"#ECEFF4\"\n\n# Download graph colors\ntheme[download_start]=\"#81A1C1\"\ntheme[download_mid]=\"#88C0D0\"\ntheme[download_end]=\"#ECEFF4\"\n\n# Upload graph colors\ntheme[upload_start]=\"#81A1C1\"\ntheme[upload_mid]=\"#88C0D0\"\ntheme[upload_end]=\"#ECEFF4\"\n"
  },
  {
    "path": "themes/solarized_dark.theme",
    "content": "#Bashtop solarized theme\n#by aristocratos\n\n# Colors should be in 6 or 2 character hexadecimal or single spaced rgb decimal: \"#RRGGBB\", \"#BW\" or \"0-255 0-255 0-255\"\n# example for white: \"#FFFFFF\", \"#ff\" or \"255 255 255\".\n\n# All graphs and meters can be gradients\n# For single color graphs leave \"mid\" and \"end\" variable empty.\n# Use \"start\" and \"end\" variables for two color gradient\n# Use \"start\", \"mid\" and \"end\" for three color gradient\n\n# Main background, empty for terminal default, need to be empty if you want transparent background\ntheme[main_bg]=\"#002b36\"\n\n# Main text color\ntheme[main_fg]=\"#eee8d5\"\n\n# Title color for boxes\ntheme[title]=\"#fdf6e3\"\n\n# Higlight color for keyboard shortcuts\ntheme[hi_fg]=\"#b58900\"\n\n# Background color of selected items\ntheme[selected_bg]=\"#073642\" \n\n# Foreground color of selected items\ntheme[selected_fg]=\"#d6a200\"\n\n# Color of inactive/disabled text\ntheme[inactive_fg]=\"#073642\"\n\n# Misc colors for processes box including mini cpu graphs, details memory graph and details status text\ntheme[proc_misc]=\"#bad600\"\n\n# Cpu box outline color\ntheme[cpu_box]=\"#586e75\"\n\n# Memory/disks box outline color\ntheme[mem_box]=\"#586e75\"\n\n# Net up/down box outline color\ntheme[net_box]=\"#586e75\"\n\n# Processes box outline color\ntheme[proc_box]=\"#586e75\"\n\n# Box divider line and small boxes line color\ntheme[div_line]=\"#586e75\"\n\n# Temperature graph colors\ntheme[temp_start]=\"#268bd2\"\ntheme[temp_mid]=\"#ccb5f7\"\ntheme[temp_end]=\"#fc5378\"\n\n# CPU graph colors\ntheme[cpu_start]=\"#adc700\"\ntheme[cpu_mid]=\"#d6a200\"\ntheme[cpu_end]=\"#e65317\"\n\n# Mem/Disk free meter\ntheme[free_start]=\"#4e5900\"\ntheme[free_mid]=\"\"\ntheme[free_end]=\"#bad600\"\n\n# Mem/Disk cached meter\ntheme[cached_start]=\"#114061\"\ntheme[cached_mid]=\"\"\ntheme[cached_end]=\"#268bd2\"\n\n# Mem/Disk available meter\ntheme[available_start]=\"#705500\"\ntheme[available_mid]=\"\"\ntheme[available_end]=\"#edb400\"\n\n# Mem/Disk used meter\ntheme[used_start]=\"#6e1718\"\ntheme[used_mid]=\"\"\ntheme[used_end]=\"#e02f30\"\n\n# Download graph colors\ntheme[download_start]=\"#3d4070\"\ntheme[download_mid]=\"#6c71c4\"\ntheme[download_end]=\"#a3a8f7\"\n\n# Upload graph colors\ntheme[upload_start]=\"#701c45\"\ntheme[upload_mid]=\"#d33682\"\ntheme[upload_end]=\"#f56caf\""
  },
  {
    "path": "themes/whiteout.theme",
    "content": "#Bashtop \"whiteout\" theme\n#by aristocratos\n\n# Colors should be in 6 or 2 character hexadecimal or single spaced rgb decimal: \"#RRGGBB\", \"#BW\" or \"0-255 0-255 0-255\"\n# example for white: \"#FFFFFF\", \"#ff\" or \"255 255 255\".\n\n# All graphs and meters can be gradients\n# For single color graphs leave \"mid\" and \"end\" variable empty.\n# Use \"start\" and \"end\" variables for two color gradient\n# Use \"start\", \"mid\" and \"end\" for three color gradient\n\n# Main background, empty for terminal default, need to be empty if you want transparent background\ntheme[main_bg]=\"#ff\"\n\n# Main text color\ntheme[main_fg]=\"#30\"\n\n# Title color for boxes\ntheme[title]=\"#10\"\n\n# Higlight color for keyboard shortcuts\ntheme[hi_fg]=\"#284d75\"\n\n# Background color of selected item in processes box\ntheme[selected_bg]=\"#15283d\" \n\n# Foreground color of selected item in processes box\ntheme[selected_fg]=\"#ff\"\n\n# Color of inactive/disabled text\ntheme[inactive_fg]=\"#dd\"\n\n# Misc colors for processes box including mini cpu graphs, details memory graph and details status text\ntheme[proc_misc]=\"#03521d\"\n\n# Cpu box outline color\ntheme[cpu_box]=\"#1a361e\"\n\n# Memory/disks box outline color\ntheme[mem_box]=\"#3d3c14\"\n\n# Net up/down box outline color\ntheme[net_box]=\"#1a1742\"\n\n# Processes box outline color\ntheme[proc_box]=\"#3b1515\"\n\n# Box divider line and small boxes line color\ntheme[div_line]=\"#80\"\n\n# Temperature graph colors\ntheme[temp_start]=\"#184567\"\ntheme[temp_mid]=\"#122c87\"\ntheme[temp_end]=\"#9e0061\"\n\n# CPU graph colors\ntheme[cpu_start]=\"#0b8e44\"\ntheme[cpu_mid]=\"#a49104\"\ntheme[cpu_end]=\"#8d0202\"\n\n# Mem/Disk free meter\ntheme[free_start]=\"#b0d090\"\ntheme[free_mid]=\"#70ba26\"\ntheme[free_end]=\"#496600\"\n\n# Mem/Disk cached meter\ntheme[cached_start]=\"#26c5ff\"\ntheme[cached_mid]=\"#74e6fc\"\ntheme[cached_end]=\"#0b1a29\"\n\n# Mem/Disk available meter\ntheme[available_start]=\"#ffb814\"\ntheme[available_mid]=\"#ffd77a\"\ntheme[available_end]=\"#292107\"\n\n# Mem/Disk used meter\ntheme[used_start]=\"#ff4769\"\ntheme[used_mid]=\"#d9626d\"\ntheme[used_end]=\"#3b1f1c\"\n\n# Download graph colors\ntheme[download_start]=\"#8d82de\"\ntheme[download_mid]=\"#413786\"\ntheme[download_end]=\"#130f29\"\n\n# Upload graph colors\ntheme[upload_start]=\"#f590f9\"\ntheme[upload_mid]=\"#722e76\"\ntheme[upload_end]=\"#2b062d\""
  }
]