diff options
Diffstat (limited to '')
292 files changed, 20556 insertions, 8744 deletions
diff --git a/.codeclimate.yml b/.codeclimate.yml index c3d4daa4..f53287ad 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -1,15 +1,53 @@ ---- -engines: +version: "2" +checks: + argument-count: + enabled: false + config: + threshold: 10 + complex-logic: + enabled: false + config: + threshold: 10 + file-lines: + enabled: false + config: + threshold: 5000 + method-complexity: + enabled: false + config: + threshold: 20 + method-count: + enabled: false + config: + threshold: 50 + method-lines: + enabled: false + config: + threshold: 250 + nested-control-flow: + enabled: false + config: + threshold: 4 + return-statements: + enabled: false + config: + threshold: 4 + similar-code: + enabled: false + identical-code: + enabled: false +plugins: csslint: enabled: true duplication: - enabled: true + enabled: false config: languages: - - ruby - - javascript - - python - - php + - javascript: + mass_threshold: 100 + - python: + python_version: 3 + mass_threshold: 100 checks: Similar code: enabled: false @@ -41,31 +79,22 @@ engines: checks: Complexity: enabled: false -ratings: - paths: - - "**.css" - - "**.inc" - - "**.js" - - "**.jsx" - - "**.module" - - "**.php" - - "**.py" - - "**.rb" -exclude_paths: -- .gitignore -- conf.d/ -- hooks/ -- tests/ -- m4/ -- web/css/ -- web/lib/ -- web/fonts/ -- web/old/ -- python.d/python_modules/pyyaml2/ -- python.d/python_modules/pyyaml3/ -- python.d/python_modules/urllib3/ -- node.d/node_modules/lib/ -- node.d/node_modules/asn1-ber.js -- node.d/node_modules/extend.js -- node.d/node_modules/pixl-xml.js -- node.d/node_modules/net-snmp.js +exclude_patterns: + - ".gitignore" + - "conf.d/" + - "hooks/" + - "tests/" + - "m4/" + - "web/css/" + - "web/lib/" + - "web/fonts/" + - "web/old/" + - "python.d/python_modules/pyyaml2/" + - "python.d/python_modules/pyyaml3/" + - "python.d/python_modules/urllib3/" + - "node.d/node_modules/lib/" + - "node.d/node_modules/asn1-ber.js" + - "node.d/node_modules/extend.js" + - "node.d/node_modules/pixl-xml.js" + - "node.d/node_modules/net-snmp.js" + @@ -1,3 +1,9 @@ +netdata (1.9.0) - 2017-12-17 + + Please check full changelog at github. + https://github.com/firehol/netdata/releases + + netdata (1.8.0) - 2017-09-17 This is mainly a bugfix release. @@ -5,6 +5,9 @@ FROM debian:jessie ADD . /netdata.git +RUN echo "deb http://ftp.nl.debian.org/debian/ jessie main" > /etc/apt/sources.list +RUN echo "deb http://security.debian.org/debian-security jessie/updates main" >> /etc/apt/sources.list + RUN cd ./netdata.git && chmod +x ./docker-build.sh && sync && sleep 1 && ./docker-build.sh WORKDIR / diff --git a/Dockerfile.armv7hf b/Dockerfile.armv7hf new file mode 100644 index 00000000..2591748a --- /dev/null +++ b/Dockerfile.armv7hf @@ -0,0 +1,19 @@ +# author : titpetric +# original: https://github.com/titpetric/netdata + +FROM resin/armv7hf-debian:jessie + +RUN [ "cross-build-start"] + +ADD . /netdata.git + +RUN cd ./netdata.git && chmod +x ./docker-build.sh && sync && sleep 1 && ./docker-build.sh + +WORKDIR / + +ENV NETDATA_PORT 19999 +EXPOSE $NETDATA_PORT + +CMD /usr/sbin/netdata -D -s /host -p ${NETDATA_PORT} + +RUN [ "cross-build-end"] diff --git a/LICENSE-REDISTRIBUTED.md b/LICENSE-REDISTRIBUTED.md index 513d53f5..b67c5acc 100644 --- a/LICENSE-REDISTRIBUTED.md +++ b/LICENSE-REDISTRIBUTED.md @@ -54,6 +54,10 @@ connectivity is not available. Copyright 2015, Twitter [MIT License](http://getbootstrap.com/getting-started/#license-faqs) +- [Bootstrap-slider](http://seiyria.com/bootstrap-slider/) + + Copyright 2017 Kyle Kemp, Rohit Kalkur, and contributors + [MIT License](https://github.com/seiyria/bootstrap-slider/blob/master/LICENSE.md) - [Bootstrap Toggle](http://www.bootstraptoggle.com/) @@ -154,3 +158,12 @@ connectivity is not available. Copyright 2008-2016 Andrey Petrov and [contributors](https://github.com/shazow/urllib3/blob/master/CONTRIBUTORS.txt) [MIT License](https://github.com/shazow/urllib3/blob/master/LICENSE.txt) +- [lz-string](http://pieroxy.net/blog/pages/lz-string/index.html) + + Copyright 2013 Pieroxy + [WTFPL License](http://pieroxy.net/blog/pages/lz-string/index.html#inline_menu_10) + +- [pako](http://nodeca.github.io/pako/) + + Copyright 2014-2017 Vitaly Puzrin and Andrei Tuputcyn + [MIT License](https://github.com/nodeca/pako/blob/master/LICENSE) diff --git a/Makefile.am b/Makefile.am index 2ea9e40f..f87a6bb3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -63,6 +63,7 @@ SUBDIRS = \ dist_noinst_DATA= \ configs.signatures \ Dockerfile \ + Dockerfile.armv7hf \ netdata.spec \ package.json \ $(NULL) diff --git a/Makefile.in b/Makefile.in index 5abcfe6f..a93c84ba 100644 --- a/Makefile.in +++ b/Makefile.in @@ -412,6 +412,7 @@ SUBDIRS = \ dist_noinst_DATA = \ configs.signatures \ Dockerfile \ + Dockerfile.armv7hf \ netdata.spec \ package.json \ $(NULL) @@ -29,26 +29,12 @@ netdata runs on **Linux**, **FreeBSD**, and **MacOS**. ## News -<p align="center"> -Netdata is featured at <b><a href="https://octoverse.github.com/" target="_blank">GitHub's State Of The Octoverse 2016</a></b><br/> -<a href="https://octoverse.github.com/" target="_blank"><img src="https://cloud.githubusercontent.com/assets/2662304/21743260/23ebe62c-d507-11e6-80c0-76b95f53e464.png"/></a> -</p> +`Sep 17th, 2017` - **[netdata v1.8.0 released!](https://github.com/firehol/netdata/releases)** -`Jul 16th, 2017` - **[netdata v1.7.0 released!](https://github.com/firehol/netdata/releases)** - - - netdata is now a fully featured **statsd** server - [read more here](https://github.com/firehol/netdata/wiki/statsd) - - netdata now monitors **ZFS** of Linux and FreeBSD - - netdata now monitors **ElasticSearch** - - netdata now monitors **RabbitMQ** - - netdata now monitors **Go applications** (via `expvar`) - [read more here](https://github.com/firehol/netdata/wiki/Monitoring-Go-Applications) - - netdata now monitors **squid logs** - - netdata now monitors **samba** - - several **backends** improvements and enhancements, including **metrics filtering** - - **prometheus** backend support has been rewritten - - alarm notifications now support **custom hooks** to execute shell commands in parallel with all other notification methods - - dozens of new and improved plugins - - dozens of new and improved alarms - - dozens more improvements and performance optimizations + - mainly a bug fix release - all users are advised to update this release + - better support for containers (`veth` interfaces are now visualized at their containers section, container sections now provide a summary view for each container) + - netdata can now listen on UNIX domain sockets + - dozens of more improvements, compatibility fixes and enhancements --- @@ -69,11 +55,11 @@ Netdata is featured at <b><a href="https://octoverse.github.com/" target="_blank collects thousands of metrics per server per second, with just 1% CPU utilization of a single core, a few MB of RAM and no disk I/O at all - - **Sophisticated alarming**<br/> + - **Sophisticated alerting**<br/> hundreds of alarms, **out of the box**!<br/> supports dynamic thresholds, hysteresis, alarm templates, - multiple role-based notification methods (such as email, slack.com, - pushover.net, pushbullet.com, telegram.org, twilio.com, messagebird.com) + multiple role-based notification methods (such as email, slack.com, flock.com, + pushover.net, pushbullet.com, telegram.org, twilio.com, messagebird.com, kavenegar.com) - **Extensible**<br/> you can monitor anything you can get a metric for, @@ -219,6 +205,9 @@ This is a list of what it currently monitors: - **Redis databases**<br/> multiple servers, each showing: operations, hit rate, memory, keys, clients, slaves +- **couchdb**<br/> + reads/writes, request methods, status codes, tasks, replication, per-db, etc + - **mongodb**<br/> operations, clients, transactions, cursors, connections, asserts, locks, etc @@ -234,6 +223,9 @@ This is a list of what it currently monitors: - **NSD name servers**<br/> queries, zones, protocols, query types, transfers, etc. +- **PowerDNS**</br> + queries, answers, cache, latency, etc. + - **Postfix email servers**<br/> message queue (entries, size) @@ -278,6 +270,12 @@ This is a list of what it currently monitors: - **SNMP devices**<br/> can be monitored too (although you will need to configure these) +- **chrony**</br> + frequencies, offsets, delays, etc. + +- **beanstalkd**</br> + global and per tube monitoring + - **statsd**<br/> [netdata is a fully featured statsd server](https://github.com/firehol/netdata/wiki/statsd) @@ -290,7 +288,7 @@ And you can extend it, by writing plugins that collect data from any source, usi This is a high level overview of netdata feature set and architecture. Click it to to interact with it (it has direct links to documentation). -[![netdata-overview](https://cloud.githubusercontent.com/assets/2662304/26529478/104652ac-43c9-11e7-903f-edb9bb2ced24.png)](https://my-netdata.io/infographic.html) +[![netdata-overview](https://user-images.githubusercontent.com/2662304/32415725-a4779606-c246-11e7-8985-2b350181aa27.png)](https://my-netdata.io/infographic.html) --- diff --git a/charts.d/apache.chart.sh b/charts.d/apache.chart.sh index b503e74e..a8ac0801 100644 --- a/charts.d/apache.chart.sh +++ b/charts.d/apache.chart.sh @@ -114,7 +114,7 @@ apache_get() { apache_accesses="${apache_response[${apache_key_accesses}]}" apache_kbytes="${apache_response[${apache_key_kbytes}]}" - + float2int "${apache_response[${apache_key_reqpersec}]}" ${apache_decimal_detail} apache_reqpersec=${FLOAT2INT_RESULT} @@ -201,7 +201,7 @@ EOF2 return 0 } -# _update is called continiously, to collect the values +# _update is called continuously, to collect the values apache_update() { local reqs net # the first argument to this function is the microseconds since last update diff --git a/charts.d/cpufreq.chart.sh b/charts.d/cpufreq.chart.sh index b21504a0..1c41c38f 100644 --- a/charts.d/cpufreq.chart.sh +++ b/charts.d/cpufreq.chart.sh @@ -72,7 +72,7 @@ cpufreq_create() { return 0 } -# _update is called continiously, to collect the values +# _update is called continuously, to collect the values cpufreq_update() { # the first argument to this function is the microseconds since last update # pass this parameter to the BEGIN statement (see bellow). diff --git a/charts.d/example.chart.sh b/charts.d/example.chart.sh index 86fde490..ffc98712 100644 --- a/charts.d/example.chart.sh +++ b/charts.d/example.chart.sh @@ -96,7 +96,7 @@ EOF return 0 } -# _update is called continiously, to collect the values +# _update is called continuously, to collect the values example_update() { # the first argument to this function is the microseconds since last update # pass this parameter to the BEGIN statement (see bellow). diff --git a/charts.d/hddtemp.chart.sh b/charts.d/hddtemp.chart.sh index 15895c5e..3aada175 100644 --- a/charts.d/hddtemp.chart.sh +++ b/charts.d/hddtemp.chart.sh @@ -43,7 +43,7 @@ hddtemp_create() { return 0 } -# _update is called continiously, to collect the values +# _update is called continuously, to collect the values hddtemp_last=0 hddtemp_count=0 hddtemp_update() { @@ -56,7 +56,7 @@ hddtemp_update() { IFS=$OLD_IFS # check if there is some data - if [ -z "${all[3]}" ]; then + if [ -z "${all[3]}" ]; then return 1 fi diff --git a/charts.d/nginx.chart.sh b/charts.d/nginx.chart.sh index 0ae7d630..d0df460a 100644 --- a/charts.d/nginx.chart.sh +++ b/charts.d/nginx.chart.sh @@ -107,7 +107,7 @@ EOF return 0 } -# _update is called continiously, to collect the values +# _update is called continuously, to collect the values nginx_update() { # the first argument to this function is the microseconds since last update # pass this parameter to the BEGIN statement (see bellow). diff --git a/charts.d/phpfpm.chart.sh b/charts.d/phpfpm.chart.sh index a5ee0ad5..a3c69b6f 100644 --- a/charts.d/phpfpm.chart.sh +++ b/charts.d/phpfpm.chart.sh @@ -72,7 +72,7 @@ phpfpm_get() { else phpfpm_slow_requests="-1" fi - + if [[ -z "${phpfpm_pool}" \ || -z "${phpfpm_start_time}" \ || -z "${phpfpm_start_since}" \ @@ -99,7 +99,7 @@ phpfpm_check() { if [ ${#phpfpm_urls[@]} -eq 0 ]; then phpfpm_urls[local]="http://localhost/status" fi - + local m for m in "${!phpfpm_urls[@]}" do @@ -110,12 +110,12 @@ phpfpm_check() { continue fi done - + if [ ${#phpfpm_urls[@]} -eq 0 ]; then error "no phpfpm servers found. Please set phpfpm_urls[name]='url' to whatever needed to get status to the phpfpm server, in $confd/phpfpm.conf" return 1 fi - + # this should return: # - 0 to enable the chart # - 1 to disable the chart @@ -145,11 +145,11 @@ EOF echo "DIMENSION slow 'slow requests' absolute 1 1" fi done - + return 0 } -# _update is called continiously, to collect the values +# _update is called continuously, to collect the values phpfpm_update() { # the first argument to this function is the microseconds since last update # pass this parameter to the BEGIN statement (see bellow). @@ -165,7 +165,7 @@ phpfpm_update() { if [ $? -ne 0 ]; then continue fi - + # write the result of the work. cat <<EOF BEGIN phpfpm_$m.connections $1 @@ -185,7 +185,7 @@ EOF fi echo "END" done - + return 0 } diff --git a/charts.d/sensors.chart.sh b/charts.d/sensors.chart.sh index 125c925d..f21248da 100644 --- a/charts.d/sensors.chart.sh +++ b/charts.d/sensors.chart.sh @@ -234,7 +234,7 @@ sensors_create() { return 0 } -# _update is called continiously, to collect the values +# _update is called continuously, to collect the values sensors_update() { # the first argument to this function is the microseconds since last update # pass this parameter to the BEGIN statement (see bellow). diff --git a/charts.d/tomcat.chart.sh b/charts.d/tomcat.chart.sh index 44a92c86..4ea6ae68 100644 --- a/charts.d/tomcat.chart.sh +++ b/charts.d/tomcat.chart.sh @@ -46,7 +46,7 @@ tomcat_check() { fi if [ -z "${tomcat_user}" ]; then # check backwards compatibility - if [ -z "${tomcatUser}" ]; then + if [ -z "${tomcatUser}" ]; then error "tomcat user is unset or set to the empty string" return 1 else @@ -114,7 +114,7 @@ EOF return 0 } -# _update is called continiously, to collect the values +# _update is called continuously, to collect the values tomcat_update() { local reqs net # the first argument to this function is the microseconds since last update diff --git a/conf.d/Makefile.am b/conf.d/Makefile.am index 7a078667..095e891a 100644 --- a/conf.d/Makefile.am +++ b/conf.d/Makefile.am @@ -27,11 +27,13 @@ dist_nodeconfig_DATA = \ pythonconfigdir=$(configdir)/python.d dist_pythonconfig_DATA = \ python.d/apache.conf \ - python.d/apache_cache.conf \ + python.d/beanstalk.conf \ python.d/bind_rndc.conf \ python.d/chrony.conf \ + python.d/couchdb.conf \ python.d/cpufreq.conf \ python.d/dns_query_time.conf \ + python.d/dnsdist.conf \ python.d/dovecot.conf \ python.d/elasticsearch.conf \ python.d/example.conf \ @@ -53,6 +55,7 @@ dist_pythonconfig_DATA = \ python.d/phpfpm.conf \ python.d/postfix.conf \ python.d/postgres.conf \ + python.d/powerdns.conf \ python.d/rabbitmq.conf \ python.d/redis.conf \ python.d/retroshare.conf \ @@ -70,8 +73,10 @@ healthconfigdir=$(configdir)/health.d dist_healthconfig_DATA = \ health.d/apache.conf \ health.d/backend.conf \ + health.d/beanstalkd.conf \ health.d/bind_rndc.conf \ health.d/cpu.conf \ + health.d/couchdb.conf \ health.d/disks.conf \ health.d/elasticsearch.conf \ health.d/entropy.conf \ @@ -99,6 +104,10 @@ dist_healthconfig_DATA = \ health.d/softnet.conf \ health.d/squid.conf \ health.d/swap.conf \ + health.d/tcp_conn.conf \ + health.d/tcp_listen.conf \ + health.d/tcp_mem.conf \ + health.d/tcp_orphans.conf \ health.d/tcp_resets.conf \ health.d/udp_errors.conf \ health.d/varnish.conf \ diff --git a/conf.d/Makefile.in b/conf.d/Makefile.in index 3d7084ed..c1c291bc 100644 --- a/conf.d/Makefile.in +++ b/conf.d/Makefile.in @@ -326,11 +326,13 @@ dist_nodeconfig_DATA = \ pythonconfigdir = $(configdir)/python.d dist_pythonconfig_DATA = \ python.d/apache.conf \ - python.d/apache_cache.conf \ + python.d/beanstalk.conf \ python.d/bind_rndc.conf \ python.d/chrony.conf \ + python.d/couchdb.conf \ python.d/cpufreq.conf \ python.d/dns_query_time.conf \ + python.d/dnsdist.conf \ python.d/dovecot.conf \ python.d/elasticsearch.conf \ python.d/example.conf \ @@ -352,6 +354,7 @@ dist_pythonconfig_DATA = \ python.d/phpfpm.conf \ python.d/postfix.conf \ python.d/postgres.conf \ + python.d/powerdns.conf \ python.d/rabbitmq.conf \ python.d/redis.conf \ python.d/retroshare.conf \ @@ -368,8 +371,10 @@ healthconfigdir = $(configdir)/health.d dist_healthconfig_DATA = \ health.d/apache.conf \ health.d/backend.conf \ + health.d/beanstalkd.conf \ health.d/bind_rndc.conf \ health.d/cpu.conf \ + health.d/couchdb.conf \ health.d/disks.conf \ health.d/elasticsearch.conf \ health.d/entropy.conf \ @@ -397,6 +402,10 @@ dist_healthconfig_DATA = \ health.d/softnet.conf \ health.d/squid.conf \ health.d/swap.conf \ + health.d/tcp_conn.conf \ + health.d/tcp_listen.conf \ + health.d/tcp_mem.conf \ + health.d/tcp_orphans.conf \ health.d/tcp_resets.conf \ health.d/udp_errors.conf \ health.d/varnish.conf \ diff --git a/conf.d/apps_groups.conf b/conf.d/apps_groups.conf index 43bf1352..4356e491 100644 --- a/conf.d/apps_groups.conf +++ b/conf.d/apps_groups.conf @@ -100,14 +100,14 @@ puma: *puma* # ----------------------------------------------------------------------------- # database servers -sql: mysqld* mariad* postgres* oracle_* ora_* -nosql: mongod redis* memcached +sql: mysqld* mariad* postgres* postmaster* oracle_* ora_* +nosql: mongod redis* memcached *couchdb* timedb: prometheus *carbon-cache.py* *carbon-aggregator.py* *graphite/manage.py* *net.opentsdb.tools.TSDMain* # ----------------------------------------------------------------------------- # email servers -email: dovecot imapd pop3d amavis* master zmstat* zmmailboxdmgr qmgr oqmgr +email: dovecot imapd pop3d amavis* master zmstat* zmmailboxdmgr qmgr oqmgr saslauthd opendkim clamd freshclam unbound tlsmgr postfwd2 postscreen postfix smtp* lmtp* # ----------------------------------------------------------------------------- # network, routing, VPN @@ -138,14 +138,15 @@ chat: irssi *vines* *prosody* murmurd # ----------------------------------------------------------------------------- # monitoring -logs: ulogd* syslog* rsyslog* logrotate systemd-journald +logs: ulogd* syslog* rsyslog* logrotate systemd-journald rotatelogs nms: snmpd vnstatd smokeping zabbix* monit munin* mon openhpid watchdog tailon nrpe splunk: splunkd -azure: mdsd *waagent* *omiserver* *omiagent* hv_kvp_daemon hv_vss_daemon +azure: mdsd *waagent* *omiserver* *omiagent* hv_kvp_daemon hv_vss_daemon *auoms* *omsagent* # ----------------------------------------------------------------------------- -# file systems and file servers +# storage, file systems and file servers +ceph: ceph-mds ceph-mgr ceph-mon ceph-osd radosgw* rbd-* samba: smbd nmbd winbindd nfs: rpcbind rpc.* nfs* zfs: spl_* z_* txg_* zil_* arc_* l2arc* @@ -182,11 +183,12 @@ dhcp: *dhcp* # name servers and clients named: named rncd dig +dnsdist: dnsdist # ----------------------------------------------------------------------------- # installation / compilation / debugging -build: cc1 cc1plus as gcc* cppcheck ld make cmake automake autoconf autoreconf +build: cc1 cc1plus as gcc* cppcheck ld make cmake automake autoconf autoreconf build: git gdb valgrind* # ----------------------------------------------------------------------------- @@ -273,6 +275,8 @@ kernel: fsnotify_mark kthrotld deferwq scsi_* kafka: *kafka.Kafka* +rabbitmq: *rabbitmq* + sidekiq: *sidekiq* java: java ipfs: ipfs diff --git a/conf.d/health.d/beanstalkd.conf b/conf.d/health.d/beanstalkd.conf new file mode 100644 index 00000000..30dc2732 --- /dev/null +++ b/conf.d/health.d/beanstalkd.conf @@ -0,0 +1,36 @@ +# get the number of buried jobs in all queues + +template: server_buried_jobs + on: beanstalk.current_jobs + calc: $buried + units: jobs + every: 10s + warn: $this > 0 + crit: $this > 10 + delay: up 0 down 5m multiplier 1.2 max 1h + info: the number of buried jobs aggregated across all tubes + to: sysadmin + +# get the number of buried jobs per queue + +#template: tube_buried_jobs +# on: beanstalk.jobs +# calc: $buried +# units: jobs +# every: 10s +# warn: $this > 0 +# crit: $this > 10 +# delay: up 0 down 5m multiplier 1.2 max 1h +# info: the number of jobs buried per tube +# to: sysadmin + +# get the current number of tubes + +#template: number_of_tubes +# on: beanstalk.current_tubes +# calc: $tubes +# every: 10s +# warn: $this < 5 +# delay: up 0 down 5m multiplier 1.2 max 1h +# info: the current number of tubes on the server +# to: sysadmin diff --git a/conf.d/health.d/bind_rndc.conf b/conf.d/health.d/bind_rndc.conf index 028bc9d0..4145e77c 100644 --- a/conf.d/health.d/bind_rndc.conf +++ b/conf.d/health.d/bind_rndc.conf @@ -1,4 +1,4 @@ - alarm: bind_rndc_stats_file_size + template: bind_rndc_stats_file_size on: bind_rndc.stats_size units: megabytes every: 60 diff --git a/conf.d/health.d/couchdb.conf b/conf.d/health.d/couchdb.conf new file mode 100644 index 00000000..4a289528 --- /dev/null +++ b/conf.d/health.d/couchdb.conf @@ -0,0 +1,13 @@ + +# make sure couchdb is running + +template: couchdb_last_collected_secs + on: couchdb.request_methods + calc: $now - $last_collected_t + units: seconds ago + every: 10s + warn: $this > (($status >= $WARNING) ? ($update_every) : ( 5 * $update_every)) + crit: $this > (($status == $CRITICAL) ? ($update_every) : (60 * $update_every)) + delay: down 5m multiplier 1.5 max 1h + info: number of seconds since the last successful data collection + to: dba diff --git a/conf.d/health.d/redis.conf b/conf.d/health.d/redis.conf index 5f6d397e..c08a884a 100644 --- a/conf.d/health.d/redis.conf +++ b/conf.d/health.d/redis.conf @@ -12,3 +12,23 @@ template: redis_last_collected_secs info: number of seconds since the last successful data collection to: dba +template: redis_bgsave_broken +families: * + on: redis.bgsave_health + every: 10s + crit: $rdb_last_bgsave_status != 0 + units: ok/failed + info: states if redis bgsave is working + delay: down 5m multiplier 1.5 max 1h + to: dba + +template: redis_bgsave_slow +families: * + on: redis.bgsave_now + every: 10s + warn: $rdb_bgsave_in_progress > 600 + crit: $rdb_bgsave_in_progress > 1200 + units: seconds + info: the time redis needs to save its database + delay: down 5m multiplier 1.5 max 1h + to: dba diff --git a/conf.d/health.d/tcp_conn.conf b/conf.d/health.d/tcp_conn.conf new file mode 100644 index 00000000..7aa9a980 --- /dev/null +++ b/conf.d/health.d/tcp_conn.conf @@ -0,0 +1,19 @@ + +# +# ${tcp_max_connections} may be nan or -1 if the system +# supports dynamic threshold for TCP connections. +# In this case, the alarm will always be zero. +# + + alarm: tcp_connections + on: ipv4.tcpsock + os: linux + hosts: * + calc: (${tcp_max_connections} > 0) ? ( ${connections} * 100 / ${tcp_max_connections} ) : 0 + units: % + every: 10s + warn: $this > (($status >= $WARNING ) ? ( 60 ) : ( 80 )) + crit: $this > (($status >= $CRITICAL) ? ( 80 ) : ( 90 )) + delay: up 0 down 5m multiplier 1.5 max 1h + info: the percentage of IPv4 TCP connections over the max allowed + to: sysadmin diff --git a/conf.d/health.d/tcp_listen.conf b/conf.d/health.d/tcp_listen.conf new file mode 100644 index 00000000..957964ae --- /dev/null +++ b/conf.d/health.d/tcp_listen.conf @@ -0,0 +1,27 @@ +# ----------------------------------------------------------------------------- +# tcp listen sockets issues + + alarm: 1m_ipv4_tcp_listen_overflows + on: ipv4.tcplistenissues + os: linux freebsd + hosts: * + lookup: sum -60s unaligned absolute of ListenOverflows + units: overflows + every: 10s + crit: $this > 0 + delay: up 0 down 5m multiplier 1.5 max 1h + info: the number of TCP listen socket overflows during the last minute + to: sysadmin + + alarm: 1m_ipv4_tcp_listen_drops + on: ipv4.tcplistenissues + os: linux + hosts: * + lookup: sum -60s unaligned absolute of ListenDrops + units: drops + every: 10s + crit: $this > 0 + delay: up 0 down 5m multiplier 1.5 max 1h + info: the number of TCP listen socket drops during the last minute + to: sysadmin + diff --git a/conf.d/health.d/tcp_mem.conf b/conf.d/health.d/tcp_mem.conf new file mode 100644 index 00000000..6927d576 --- /dev/null +++ b/conf.d/health.d/tcp_mem.conf @@ -0,0 +1,20 @@ +# +# check +# http://blog.tsunanet.net/2011/03/out-of-socket-memory.html +# +# We give a warning when TCP is under memory pressure +# and a critical when TCP is 90% of its upper memory limit +# + + alarm: tcp_memory + on: ipv4.sockstat_tcp_mem + os: linux + hosts: * + calc: ${mem} * 100 / ${tcp_mem_high} + units: % + every: 10s + warn: ${mem} > (($status >= $WARNING ) ? ( ${tcp_mem_pressure} * 0.8 ) : ( ${tcp_mem_pressure} )) + crit: ${mem} > (($status >= $CRITICAL ) ? ( ${tcp_mem_pressure} ) : ( ${tcp_mem_high} * 0.9 )) + delay: up 0 down 5m multiplier 1.5 max 1h + info: the amount of TCP memory as a percentage of its max memory limit + to: sysadmin diff --git a/conf.d/health.d/tcp_orphans.conf b/conf.d/health.d/tcp_orphans.conf new file mode 100644 index 00000000..280d6590 --- /dev/null +++ b/conf.d/health.d/tcp_orphans.conf @@ -0,0 +1,21 @@ + +# +# check +# http://blog.tsunanet.net/2011/03/out-of-socket-memory.html +# +# The kernel may penalize orphans by 2x or even 4x +# so we alarm warning at 25% and critical at 50% +# + + alarm: tcp_orphans + on: ipv4.sockstat_tcp_sockets + os: linux + hosts: * + calc: ${orphan} * 100 / ${tcp_max_orphans} + units: % + every: 10s + warn: $this > (($status >= $WARNING ) ? ( 20 ) : ( 25 )) + crit: $this > (($status >= $CRITICAL) ? ( 25 ) : ( 50 )) + delay: up 0 down 5m multiplier 1.5 max 1h + info: the percentage of orphan IPv4 TCP sockets over the max allowed (this may lead to too-many-orphans errors) + to: sysadmin diff --git a/conf.d/health.d/tcp_resets.conf b/conf.d/health.d/tcp_resets.conf index fec124ac..e6cfd39a 100644 --- a/conf.d/health.d/tcp_resets.conf +++ b/conf.d/health.d/tcp_resets.conf @@ -37,7 +37,7 @@ every: 10s warn: $this > ((($1m_ipv4_tcp_resets_sent < 5)?(5):($1m_ipv4_tcp_resets_sent)) * (($status >= $WARNING) ? (1) : (20))) delay: up 0 down 60m multiplier 1.2 max 2h -options: no-clear-notification + options: no-clear-notification info: average TCP RESETS this host is sending, over the last 10 seconds (this can be an indication that a port scan is made, or that a service running on this host has crashed; clear notification for this alarm will not be sent) to: sysadmin @@ -62,6 +62,6 @@ options: no-clear-notification every: 10s warn: $this > ((($1m_ipv4_tcp_resets_received < 5)?(5):($1m_ipv4_tcp_resets_received)) * (($status >= $WARNING) ? (1) : (10))) delay: up 0 down 60m multiplier 1.2 max 2h -options: no-clear-notification + options: no-clear-notification info: average TCP RESETS this host is receiving, over the last 10 seconds (this can be an indication that a service this host needs, has crashed; clear notification for this alarm will not be sent) to: sysadmin diff --git a/conf.d/health_alarm_notify.conf b/conf.d/health_alarm_notify.conf index 641272ce..eb01e2bb 100644 --- a/conf.d/health_alarm_notify.conf +++ b/conf.d/health_alarm_notify.conf @@ -7,6 +7,7 @@ # - e-mails (using the sendmail command), # - push notifications to your mobile phone (pushover.net), # - messages to your slack team (slack.com), +# - messages to your flock team (flock.com), # - messages to your discord guild (discordapp.com), # - messages to your telegram chat / group chat (telegram.org) # - sms messages to your cell phone or any sms enabled device (twilio.com) @@ -23,7 +24,7 @@ # proxy configuration # # If you need to send curl based notifications (pushover, pushbullet, slack, -# discord, telegram) via a proxy, set these to your proxy address: +# flock, discord, telegram) via a proxy, set these to your proxy address: #export http_proxy="http://10.0.0.1:3128/" #export https_proxy="http://10.0.0.1:3128/" @@ -63,6 +64,7 @@ curl="" # - pushover user tokens # - telegram chat ids # - slack channels +# - flock rooms # - discord channels # - hipchat rooms # - sms phone numbers @@ -77,9 +79,11 @@ curl="" # pushover : "2987343...9437837 8756278...2362736|critical" # telegram : "111827421 112746832|critical" # slack : "alarms disasters|critical" +# flock : "alarms disasters|critical" # discord : "alarms disasters|critical" # twilio : "+15555555555 +17777777777|critical" # messagebird: "+15555555555 +17777777777|critical" +# kavenegar : "09155555555 09177777777|critical" # pd : "<pd_service_key_1> <pd_service_key_2>|critical" # # If a recipient is set to empty string, the default recipient of the given @@ -160,6 +164,9 @@ SEND_PUSHBULLET="YES" PUSHBULLET_ACCESS_TOKEN="" DEFAULT_RECIPIENT_PUSHBULLET="" +# Device iden of the sending device. Optional. +PUSHBULLET_SOURCE_DEVICE="" + #------------------------------------------------------------------------------ # Twilio (twilio.com) SMS options @@ -205,6 +212,28 @@ DEFAULT_RECIPIENT_MESSAGEBIRD="" #------------------------------------------------------------------------------ +# Kavenegar (Kavenegar.com) SMS options + +# multiple recipients can be given like this: +# "09155555555 09177777777" + +# enable/disable sending kavenegar SMS +SEND_KAVENEGAR="YES" + +# to get an access key, after selecting and purchasing your desired service +# at http://kavenegar.com/pricing.html +# login to your account, go to your dashboard and my account are +# https://panel.kavenegar.com/Client/setting/account from API Key +# copy your api key. You can generate new API Key too. +# You can find and select kevenegar sender number from this place. + +# Without an API key, netdata cannot send KAVENEGAR text messages. +KAVENEGAR_API_KEY="" +KAVENEGAR_SENDER="" +DEFAULT_RECIPIENT_KAVENEGAR="" + + +#------------------------------------------------------------------------------ # telegram (telegram.org) global notification options # To get your chat ID send the command /my_id to telegram bot @get_id. @@ -247,6 +276,21 @@ DEFAULT_RECIPIENT_SLACK="" #------------------------------------------------------------------------------ +# flock (flock.com) global notification options + +# enable/disable sending flock notifications +SEND_FLOCK="YES" + +# Login to flock.com and create an incoming webhook. You need only one for all +# your netdata servers (or you can have one for each of your netdata). +# Without it, netdata cannot send flock notifications. +FLOCK_WEBHOOK_URL="" + +# if a role recipient is not configured, no notification will be sent +DEFAULT_RECIPIENT_FLOCK="" + + +#------------------------------------------------------------------------------ # discord (discordapp.com) global notification options # multiple recipients can be given like this: @@ -398,6 +442,8 @@ role_recipients_telegram[sysadmin]="${DEFAULT_RECIPIENT_TELEGRAM}" role_recipients_slack[sysadmin]="${DEFAULT_RECIPIENT_SLACK}" +role_recipients_flock[sysadmin]="${DEFAULT_RECIPIENT_FLOCK}" + role_recipients_discord[sysadmin]="${DEFAULT_RECIPIENT_DISCORD}" role_recipients_hipchat[sysadmin]="${DEFAULT_RECIPIENT_HIPCHAT}" @@ -406,6 +452,8 @@ role_recipients_twilio[sysadmin]="${DEFAULT_RECIPIENT_TWILIO}" role_recipients_messagebird[sysadmin]="${DEFAULT_RECIPIENT_MESSAGEBIRD}" +role_recipients_kavenegar[sysadmin]="${DEFAULT_RECIPIENT_KAVENEGAR}" + role_recipients_pd[sysadmin]="${DEFAULT_RECIPIENT_PD}" role_recipients_custom[sysadmin]="${DEFAULT_RECIPIENT_CUSTOM}" @@ -423,6 +471,8 @@ role_recipients_telegram[domainadmin]="${DEFAULT_RECIPIENT_TELEGRAM}" role_recipients_slack[domainadmin]="${DEFAULT_RECIPIENT_SLACK}" +role_recipients_flock[domainadmin]="${DEFAULT_RECIPIENT_FLOCK}" + role_recipients_discord[domainadmin]="${DEFAULT_RECIPIENT_DISCORD}" role_recipients_hipchat[domainadmin]="${DEFAULT_RECIPIENT_HIPCHAT}" @@ -431,6 +481,8 @@ role_recipients_twilio[domainadmin]="${DEFAULT_RECIPIENT_TWILIO}" role_recipients_messagebird[domainadmin]="${DEFAULT_RECIPIENT_MESSAGEBIRD}" +role_recipients_kavenegar[domainadmin]="${DEFAULT_RECIPIENT_KAVENEGAR}" + role_recipients_pd[domainadmin]="${DEFAULT_RECIPIENT_PD}" role_recipients_custom[domainadmin]="${DEFAULT_RECIPIENT_CUSTOM}" @@ -449,6 +501,8 @@ role_recipients_telegram[dba]="${DEFAULT_RECIPIENT_TELEGRAM}" role_recipients_slack[dba]="${DEFAULT_RECIPIENT_SLACK}" +role_recipients_flock[dba]="${DEFAULT_RECIPIENT_FLOCK}" + role_recipients_discord[dba]="${DEFAULT_RECIPIENT_DISCORD}" role_recipients_hipchat[dba]="${DEFAULT_RECIPIENT_HIPCHAT}" @@ -457,6 +511,8 @@ role_recipients_twilio[dba]="${DEFAULT_RECIPIENT_TWILIO}" role_recipients_messagebird[dba]="${DEFAULT_RECIPIENT_MESSAGEBIRD}" +role_recipients_kavenegar[dba]="${DEFAULT_RECIPIENT_KAVENEGAR}" + role_recipients_pd[dba]="${DEFAULT_RECIPIENT_PD}" role_recipients_custom[dba]="${DEFAULT_RECIPIENT_CUSTOM}" @@ -475,6 +531,8 @@ role_recipients_telegram[webmaster]="${DEFAULT_RECIPIENT_TELEGRAM}" role_recipients_slack[webmaster]="${DEFAULT_RECIPIENT_SLACK}" +role_recipients_flock[webmaster]="${DEFAULT_RECIPIENT_FLOCK}" + role_recipients_discord[webmaster]="${DEFAULT_RECIPIENT_DISCORD}" role_recipients_hipchat[webmaster]="${DEFAULT_RECIPIENT_HIPCHAT}" @@ -483,6 +541,8 @@ role_recipients_twilio[webmaster]="${DEFAULT_RECIPIENT_TWILIO}" role_recipients_messagebird[webmaster]="${DEFAULT_RECIPIENT_MESSAGEBIRD}" +role_recipients_kavenegar[webmaster]="${DEFAULT_RECIPIENT_KAVENEGAR}" + role_recipients_pd[webmaster]="${DEFAULT_RECIPIENT_PD}" role_recipients_custom[webmaster]="${DEFAULT_RECIPIENT_CUSTOM}" @@ -501,6 +561,8 @@ role_recipients_telegram[proxyadmin]="${DEFAULT_RECIPIENT_TELEGRAM}" role_recipients_slack[proxyadmin]="${DEFAULT_RECIPIENT_SLACK}" +role_recipients_flock[proxyadmin]="${DEFAULT_RECIPIENT_FLOCK}" + role_recipients_discord[proxyadmin]="${DEFAULT_RECIPIENT_DISCORD}" role_recipients_hipchat[proxyadmin]="${DEFAULT_RECIPIENT_HIPCHAT}" @@ -509,6 +571,8 @@ role_recipients_twilio[proxyadmin]="${DEFAULT_RECIPIENT_TWILIO}" role_recipients_messagebird[proxyadmin]="${DEFAULT_RECIPIENT_MESSAGEBIRD}" +role_recipients_kavenegar[proxyadmin]="${DEFAULT_RECIPIENT_KAVENEGAR}" + role_recipients_pd[proxyadmin]="${DEFAULT_RECIPIENT_PD}" role_recipients_custom[proxyadmin]="${DEFAULT_RECIPIENT_CUSTOM}" diff --git a/conf.d/python.d.conf b/conf.d/python.d.conf index 741d4991..2c3d400c 100644 --- a/conf.d/python.d.conf +++ b/conf.d/python.d.conf @@ -9,13 +9,6 @@ # Enable / disable the whole python.d.plugin (all its modules) enabled: yes -# Prevent log flood -# Define how many log messages can be written to log file in one log_interval -logs_per_interval: 200 - -# Define how long is one logging interval (in seconds) -log_interval: 3600 - # ---------------------------------------------------------------------- # Enable / Disable python.d.plugin modules #default_run: yes @@ -29,11 +22,14 @@ log_interval: 3600 # apache_cache has been replaced by web_log apache_cache: no # apache: yes +# beanstalk: yes # bind_rndc: yes -# chrony: yes +chrony: no +# couchdb: yes # cpufreq: yes # cpuidle: yes # dns_query_time: yes +# dnsdist: yes # dovecot: yes # elasticsearch: yes @@ -53,6 +49,7 @@ go_expvar: no # isc_dhcpd: yes # mdstat: yes # memcached: yes +# mongodb: yes # mysql: yes # nginx: yes # nsd: yes @@ -64,6 +61,7 @@ nginx_log: no # phpfpm: yes # postfix: yes # postgres: yes +# powerdns: yes # rabbitmq: yes # redis: yes # retroshare: yes diff --git a/conf.d/python.d/apache.conf b/conf.d/python.d/apache.conf index 5b151ef7..3bbc3f78 100644 --- a/conf.d/python.d/apache.conf +++ b/conf.d/python.d/apache.conf @@ -31,7 +31,13 @@ # If unset, the default for python.d.plugin is used. # Attempts to restore the service are made once every update_every # and only if the module has collected values in the past. -# retries: 5 +# retries: 60 + +# autodetection_retry sets the job re-check interval in seconds. +# The job is not deleted if check fails. +# Attempts to start the job are made once every autodetection_retry. +# This feature is disabled by default. +# autodetection_retry: 0 # ---------------------------------------------------------------------- # JOBS (data collection sources) @@ -47,12 +53,13 @@ # predefined parameters. These are: # # job_name: -# name: myname # the JOB's name as it will appear at the -# # dashboard (by default is the job_name) -# # JOBs sharing a name are mutually exclusive -# update_every: 1 # the JOB's data collection frequency -# priority: 60000 # the JOB's order on the dashboard -# retries: 5 # the JOB's number of restoration attempts +# name: myname # the JOB's name as it will appear at the +# # dashboard (by default is the job_name) +# # JOBs sharing a name are mutually exclusive +# update_every: 1 # the JOB's data collection frequency +# priority: 60000 # the JOB's order on the dashboard +# retries: 60 # the JOB's number of restoration attempts +# autodetection_retry: 0 # the JOB's re-check interval in seconds # # Additionally to the above, apache also supports the following: # diff --git a/conf.d/python.d/beanstalk.conf b/conf.d/python.d/beanstalk.conf new file mode 100644 index 00000000..94080187 --- /dev/null +++ b/conf.d/python.d/beanstalk.conf @@ -0,0 +1,80 @@ +# netdata python.d.plugin configuration for beanstalk +# +# This file is in YaML format. Generally the format is: +# +# name: value +# +# There are 2 sections: +# - global variables +# - one or more JOBS +# +# JOBS allow you to collect values from multiple sources. +# Each source will have its own set of charts. +# +# JOB parameters have to be indented (using spaces only, example below). + +# ---------------------------------------------------------------------- +# Global Variables +# These variables set the defaults for all JOBs, however each JOB +# may define its own, overriding the defaults. + +# update_every sets the default data collection frequency. +# If unset, the python.d.plugin default is used. +# update_every: 1 + +# priority controls the order of charts at the netdata dashboard. +# Lower numbers move the charts towards the top of the page. +# If unset, the default for python.d.plugin is used. +# priority: 60000 + +# retries sets the number of retries to be made in case of failures. +# If unset, the default for python.d.plugin is used. +# Attempts to restore the service are made once every update_every +# and only if the module has collected values in the past. +# retries: 60 + +# autodetection_retry sets the job re-check interval in seconds. +# The job is not deleted if check fails. +# Attempts to start the job are made once every autodetection_retry. +# This feature is disabled by default. +# autodetection_retry: 0 + +# chart_cleanup sets the default chart cleanup interval in iterations. +# A chart is marked as obsolete if it has not been updated +# 'chart_cleanup' iterations in a row. +# When a plugin sends the obsolete flag, the charts are not deleted +# from netdata immediately. +# They will be hidden immediately (not offered to dashboard viewer, +# streamed upstream and archived to backends) and deleted one hour +# later (configurable from netdata.conf). +# chart_cleanup: 10 + +# ---------------------------------------------------------------------- +# JOBS (data collection sources) +# +# The default JOBS share the same *name*. JOBS with the same name +# are mutually exclusive. Only one of them will be allowed running at +# any time. This allows autodetection to try several alternatives and +# pick the one that works. +# +# Any number of jobs is supported. +# +# All python.d.plugin JOBS (for all its modules) support a set of +# predefined parameters. These are: +# +# job_name: +# name: myname # the JOB's name as it will appear at the +# # dashboard (by default is the job_name) +# # JOBs sharing a name are mutually exclusive +# update_every: 1 # the JOB's data collection frequency +# priority: 60000 # the JOB's order on the dashboard +# retries: 60 # the JOB's number of restoration attempts +# autodetection_retry: 0 # the JOB's re-check interval in seconds +# chart_cleanup: 10 # the JOB's chart cleanup interval in iterations +# +# Additionally to the above, apache also supports the following: +# +# host: 'host' # Server ip address or hostname. Default: 127.0.0.1 +# port: port # Beanstalkd port. Default: +# +# ---------------------------------------------------------------------- diff --git a/conf.d/python.d/bind_rndc.conf b/conf.d/python.d/bind_rndc.conf index e4f7ac82..71958ff9 100644 --- a/conf.d/python.d/bind_rndc.conf +++ b/conf.d/python.d/bind_rndc.conf @@ -31,7 +31,13 @@ # If unset, the default for python.d.plugin is used. # Attempts to restore the service are made once every update_every # and only if the module has collected values in the past. -# retries: 5 +# retries: 60 + +# autodetection_retry sets the job re-check interval in seconds. +# The job is not deleted if check fails. +# Attempts to start the job are made once every autodetection_retry. +# This feature is disabled by default. +# autodetection_retry: 0 # ---------------------------------------------------------------------- # JOBS (data collection sources) @@ -47,12 +53,13 @@ # predefined parameters. These are: # # job_name: -# name: myname # the JOB's name as it will appear at the -# # dashboard (by default is the job_name) -# # JOBs sharing a name are mutually exclusive -# update_every: 1 # the JOB's data collection frequency -# priority: 60000 # the JOB's order on the dashboard -# retries: 5 # the JOB's number of restoration attempts +# name: myname # the JOB's name as it will appear at the +# # dashboard (by default is the job_name) +# # JOBs sharing a name are mutually exclusive +# update_every: 1 # the JOB's data collection frequency +# priority: 60000 # the JOB's order on the dashboard +# retries: 60 # the JOB's number of restoration attempts +# autodetection_retry: 0 # the JOB's re-check interval in seconds # # Additionally to the above, bind_rndc also supports the following: # @@ -75,7 +82,7 @@ # chown bind bind/ # # 4. RELOAD (NOT restart) BIND -# systemctl reload bind9.serice +# systemctl reload bind9.service # # 5. Run as a root 'rndc stats' to dump (BIND will create named.stats in new directory) # @@ -101,9 +108,5 @@ # To test your logrotate conf file run as root: # # logrotate /etc/logrotate.d/bind-rndc -d (debug dry-run mode) -# ------------------------------------------------------------------------------------------------------------------ -# AUTO-DETECTION JOBS -# only one of them will run (they have the same name) # -#local: -# named_stats_path: '/var/log/bind/named.stats' +# ---------------------------------------------------------------------- diff --git a/conf.d/python.d/chrony.conf b/conf.d/python.d/chrony.conf index 46229687..9ac906b5 100644 --- a/conf.d/python.d/chrony.conf +++ b/conf.d/python.d/chrony.conf @@ -31,7 +31,13 @@ update_every: 5 # If unset, the default for python.d.plugin is used. # Attempts to restore the service are made once every update_every # and only if the module has collected values in the past. -# retries: 5 +# retries: 60 + +# autodetection_retry sets the job re-check interval in seconds. +# The job is not deleted if check fails. +# Attempts to start the job are made once every autodetection_retry. +# This feature is disabled by default. +# autodetection_retry: 0 # ---------------------------------------------------------------------- # JOBS (data collection sources) @@ -47,12 +53,13 @@ update_every: 5 # predefined parameters. These are: # # job_name: -# name: myname # the JOB's name as it will appear at the -# # dashboard (by default is the job_name) -# # JOBs sharing a name are mutually exclusive -# update_every: 1 # the JOB's data collection frequency -# priority: 60000 # the JOB's order on the dashboard -# retries: 5 # the JOB's number of restoration attempts +# name: myname # the JOB's name as it will appear at the +# # dashboard (by default is the job_name) +# # JOBs sharing a name are mutually exclusive +# update_every: 1 # the JOB's data collection frequency +# priority: 60000 # the JOB's order on the dashboard +# retries: 60 # the JOB's number of restoration attempts +# autodetection_retry: 0 # the JOB's re-check interval in seconds # # Additionally to the above, chrony also supports the following: # diff --git a/conf.d/python.d/couchdb.conf b/conf.d/python.d/couchdb.conf new file mode 100644 index 00000000..5f6e75cf --- /dev/null +++ b/conf.d/python.d/couchdb.conf @@ -0,0 +1,91 @@ +# netdata python.d.plugin configuration for couchdb +# +# This file is in YaML format. Generally the format is: +# +# name: value +# +# There are 2 sections: +# - global variables +# - one or more JOBS +# +# JOBS allow you to collect values from multiple sources. +# Each source will have its own set of charts. +# +# JOB parameters have to be indented (using spaces only, example below). + +# ---------------------------------------------------------------------- +# Global Variables +# These variables set the defaults for all JOBs, however each JOB +# may define its own, overriding the defaults. + +# update_every sets the default data collection frequency. +# If unset, the python.d.plugin default is used. +# By default, CouchDB only updates its stats every 10 seconds. +update_every: 10 + +# priority controls the order of charts at the netdata dashboard. +# Lower numbers move the charts towards the top of the page. +# If unset, the default for python.d.plugin is used. +# priority: 60000 + +# retries sets the number of retries to be made in case of failures. +# If unset, the default for python.d.plugin is used. +# Attempts to restore the service are made once every update_every +# and only if the module has collected values in the past. +# retries: 60 + +# autodetection_retry sets the job re-check interval in seconds. +# The job is not deleted if check fails. +# Attempts to start the job are made once every autodetection_retry. +# This feature is disabled by default. +# autodetection_retry: 0 + +# ---------------------------------------------------------------------- +# JOBS (data collection sources) +# +# The default JOBS share the same *name*. JOBS with the same name +# are mutually exclusive. Only one of them will be allowed running at +# any time. This allows autodetection to try several alternatives and +# pick the one that works. +# +# Any number of jobs is supported. +# +# All python.d.plugin JOBS (for all its modules) support a set of +# predefined parameters. These are: +# +# job_name: +# name: myname # the JOB's name as it will appear at the +# # dashboard (by default is the job_name) +# # JOBs sharing a name are mutually exclusive +# update_every: 1 # the JOB's data collection frequency +# priority: 60000 # the JOB's order on the dashboard +# retries: 60 # the JOB's number of restoration attempts +# autodetection_retry: 0 # the JOB's re-check interval in seconds +# +# Additionally to the above, the couchdb plugin also supports the following: +# +# host: 'ipaddress' # Server ip address or hostname. Default: 127.0.0.1 +# port: 'port' # CouchDB port. Default: 15672 +# scheme: 'scheme' # http or https. Default: http +# node: 'couchdb@127.0.0.1' # CouchDB node name. Same as -name vm.args argument. +# +# if the URL is password protected, the following are supported: +# +# user: 'username' +# pass: 'password' +# +# if db-specific stats are desired, place their names in databases: +# databases: 'npm-registry animaldb' +# +# ---------------------------------------------------------------------- +# AUTO-DETECTION JOBS +# only one of them will run (they have the same name) +# +localhost: + name: 'local' + host: '127.0.0.1' + port: '5984' + node: 'couchdb@127.0.0.1' + scheme: 'http' +# user: 'admin' +# pass: 'password' diff --git a/conf.d/python.d/cpufreq.conf b/conf.d/python.d/cpufreq.conf index 10c96917..0890245d 100644 --- a/conf.d/python.d/cpufreq.conf +++ b/conf.d/python.d/cpufreq.conf @@ -31,7 +31,13 @@ # If unset, the default for python.d.plugin is used. # Attempts to restore the service are made once every update_every # and only if the module has collected values in the past. -# retries: 5 +# retries: 60 + +# autodetection_retry sets the job re-check interval in seconds. +# The job is not deleted if check fails. +# Attempts to start the job are made once every autodetection_retry. +# This feature is disabled by default. +# autodetection_retry: 0 # The directory to search for the file scaling_cur_freq sys_dir: "/sys/devices" diff --git a/conf.d/python.d/dns_query_time.conf b/conf.d/python.d/dns_query_time.conf index f4d4dbf9..d32c6db8 100644 --- a/conf.d/python.d/dns_query_time.conf +++ b/conf.d/python.d/dns_query_time.conf @@ -31,7 +31,13 @@ # If unset, the default for python.d.plugin is used. # Attempts to restore the service are made once every update_every # and only if the module has collected values in the past. -# retries: 5 +# retries: 60 + +# autodetection_retry sets the job re-check interval in seconds. +# The job is not deleted if check fails. +# Attempts to start the job are made once every autodetection_retry. +# This feature is disabled by default. +# autodetection_retry: 0 # ---------------------------------------------------------------------- # JOBS (data collection sources) @@ -47,26 +53,19 @@ # predefined parameters. These are: # # job_name: -# name: myname # the JOB's name as it will appear at the -# # dashboard (by default is the job_name) -# # JOBs sharing a name are mutually exclusive -# update_every: 1 # the JOB's data collection frequency -# priority: 60000 # the JOB's order on the dashboard -# retries: 5 # the JOB's number of restoration attempts +# name: myname # the JOB's name as it will appear at the +# # dashboard (by default is the job_name) +# # JOBs sharing a name are mutually exclusive +# update_every: 1 # the JOB's data collection frequency +# priority: 60000 # the JOB's order on the dashboard +# retries: 60 # the JOB's number of restoration attempts +# autodetection_retry: 0 # the JOB's re-check interval in seconds # # Additionally to the above, dns_query_time also supports the following: # -# dns_servers: 'dns servers' # list of dns servers to query -# domains: 'domains' # list of domains -# aggregate: yes/no # Default: yes. Aggregate all servers in one chart or not -# response_timeout: 4 # Defalt: 4. Dns query response timeout (query = -100 if response time > response_time) -# -# -# ---------------------------------------------------------------------- -# AUTO-DETECTION JOBS -# only one of them will run (they have the same name) -# +# dns_servers: 'dns servers' # List of dns servers to query +# domains: 'domains' # List of domains +# aggregate: yes/no # Aggregate all servers in one chart or not +# response_timeout: 4 # Dns query response timeout (query = -100 if response time > response_time) # -#aggregate: yes -#dns_servers: '8.8.8.8 8.8.4.4' -#domains: 'python.org distrowatch.com linuxmint.com linux.com rsyslog.com liblognorm.com archlinux.org cisco.com debian.org kernel.org gns3.com opera.com github.com youtube.com amazon.co.uk kde.org netdata.firehol.org ubuntu.com redhat.com opensuse.org wireshark.org vmware.com microsoft.com elastic.co' +# ----------------------------------------------------------------------
\ No newline at end of file diff --git a/conf.d/python.d/dnsdist.conf b/conf.d/python.d/dnsdist.conf new file mode 100644 index 00000000..aec58b8e --- /dev/null +++ b/conf.d/python.d/dnsdist.conf @@ -0,0 +1,85 @@ +# netdata python.d.plugin configuration for dnsdist +# +# This file is in YaML format. Generally the format is: +# +# name: value +# +# There are 2 sections: +# - global variables +# - one or more JOBS +# +# JOBS allow you to collect values from multiple sources. +# Each source will have its own set of charts. +# +# JOB parameters have to be indented (using spaces only, example below). + +# ---------------------------------------------------------------------- +# Global Variables +# These variables set the defaults for all JOBs, however each JOB +# may define its own, overriding the defaults. + +# update_every sets the default data collection frequency. +# If unset, the python.d.plugin default is used. +#update_every: 1 + +# priority controls the order of charts at the netdata dashboard. +# Lower numbers move the charts towards the top of the page. +# If unset, the default for python.d.plugin is used. +# priority: 60000 + +# retries sets the number of retries to be made in case of failures. +# If unset, the default for python.d.plugin is used. +# Attempts to restore the service are made once every update_every +# and only if the module has collected values in the past. +#retries: 600000 + +# autodetection_retry sets the job re-check interval in seconds. +# The job is not deleted if check fails. +# Attempts to start the job are made once every autodetection_retry. +# This feature is disabled by default. +#autodetection_retry: 1 + +# ---------------------------------------------------------------------- +# JOBS (data collection sources) +# +# The default JOBS share the same *name*. JOBS with the same name +# are mutually exclusive. Only one of them will be allowed running at +# any time. This allows autodetection to try several alternatives and +# pick the one that works. +# +# Any number of jobs is supported. +# +# All python.d.plugin JOBS (for all its modules) support a set of +# predefined parameters. These are: +# +# job_name: +# name: myname # the JOB's name as it will appear at the +# # dashboard (by default is the job_name) +# # JOBs sharing a name are mutually exclusive +# update_every: 1 # the JOB's data collection frequency +# priority: 60000 # the JOB's order on the dashboard +# retries: 60 # the JOB's number of restoration attempts +# autodetection_retry: 0 # the JOB's re-check interval in seconds +# +# +# Additionally to the above, dnsdist also supports the following: +# +# url: 'URL' # the URL to fetch dnsdist performance statistics +# user: 'username' # username for basic auth +# pass: 'password' # password for basic auth +# header: +# X-API-Key: 'Key' # API key +# +# ---------------------------------------------------------------------- +# AUTO-DETECTION JOBS +# only one of them will run (they have the same name) + +# localhost: +# name : 'local' +# url : 'http://127.0.0.1:5053/jsonstat?command=stats' +# user : 'username' +# pass : 'password' +# header: +# X-API-Key: 'dnsdist-api-key' + + diff --git a/conf.d/python.d/dovecot.conf b/conf.d/python.d/dovecot.conf index 917c5272..56c39499 100644 --- a/conf.d/python.d/dovecot.conf +++ b/conf.d/python.d/dovecot.conf @@ -31,7 +31,13 @@ # If unset, the default for python.d.plugin is used. # Attempts to restore the service are made once every update_every # and only if the module has collected values in the past. -# retries: 5 +# retries: 60 + +# autodetection_retry sets the job re-check interval in seconds. +# The job is not deleted if check fails. +# Attempts to start the job are made once every autodetection_retry. +# This feature is disabled by default. +# autodetection_retry: 0 # ---------------------------------------------------------------------- # JOBS (data collection sources) @@ -47,12 +53,13 @@ # predefined parameters. These are: # # job_name: -# name: myname # the JOB's name as it will appear at the -# # dashboard (by default is the job_name) -# # JOBs sharing a name are mutually exclusive -# update_every: 1 # the JOB's data collection frequency -# priority: 60000 # the JOB's order on the dashboard -# retries: 5 # the JOB's number of restoration attempts +# name: myname # the JOB's name as it will appear at the +# # dashboard (by default is the job_name) +# # JOBs sharing a name are mutually exclusive +# update_every: 1 # the JOB's data collection frequency +# priority: 60000 # the JOB's order on the dashboard +# retries: 60 # the JOB's number of restoration attempts +# autodetection_retry: 0 # the JOB's re-check interval in seconds # # Additionally to the above, dovecot also supports the following: # diff --git a/conf.d/python.d/elasticsearch.conf b/conf.d/python.d/elasticsearch.conf index 7c35df22..213843bf 100644 --- a/conf.d/python.d/elasticsearch.conf +++ b/conf.d/python.d/elasticsearch.conf @@ -31,7 +31,13 @@ # If unset, the default for python.d.plugin is used. # Attempts to restore the service are made once every update_every # and only if the module has collected values in the past. -# retries: 5 +# retries: 60 + +# autodetection_retry sets the job re-check interval in seconds. +# The job is not deleted if check fails. +# Attempts to start the job are made once every autodetection_retry. +# This feature is disabled by default. +# autodetection_retry: 0 # ---------------------------------------------------------------------- # JOBS (data collection sources) @@ -47,12 +53,13 @@ # predefined parameters. These are: # # job_name: -# name: myname # the JOB's name as it will appear at the -# # dashboard (by default is the job_name) -# # JOBs sharing a name are mutually exclusive -# update_every: 1 # the JOB's data collection frequency -# priority: 60000 # the JOB's order on the dashboard -# retries: 5 # the JOB's number of restoration attempts +# name: myname # the JOB's name as it will appear at the +# # dashboard (by default is the job_name) +# # JOBs sharing a name are mutually exclusive +# update_every: 1 # the JOB's data collection frequency +# priority: 60000 # the JOB's order on the dashboard +# retries: 60 # the JOB's number of restoration attempts +# autodetection_retry: 0 # the JOB's re-check interval in seconds # # Additionally to the above, elasticsearch plugin also supports the following: # diff --git a/conf.d/python.d/example.conf b/conf.d/python.d/example.conf index 31f9a49a..e7fed9b5 100644 --- a/conf.d/python.d/example.conf +++ b/conf.d/python.d/example.conf @@ -31,7 +31,13 @@ # If unset, the default for python.d.plugin is used. # Attempts to restore the service are made once every update_every # and only if the module has collected values in the past. -# retries: 5 +# retries: 60 + +# autodetection_retry sets the job re-check interval in seconds. +# The job is not deleted if check fails. +# Attempts to start the job are made once every autodetection_retry. +# This feature is disabled by default. +# autodetection_retry: 0 # ---------------------------------------------------------------------- # JOBS (data collection sources) @@ -47,12 +53,13 @@ # predefined parameters. These are: # # job_name: -# name: myname # the JOB's name as it will appear at the -# # dashboard (by default is the job_name) -# # JOBs sharing a name are mutually exclusive -# update_every: 1 # the JOB's data collection frequency -# priority: 60000 # the JOB's order on the dashboard -# retries: 5 # the JOB's number of restoration attempts +# name: myname # the JOB's name as it will appear at the +# # dashboard (by default is the job_name) +# # JOBs sharing a name are mutually exclusive +# update_every: 1 # the JOB's data collection frequency +# priority: 60000 # the JOB's order on the dashboard +# retries: 60 # the JOB's number of restoration attempts +# autodetection_retry: 0 # the JOB's re-check interval in seconds # # Additionally to the above, example also supports the following: # diff --git a/conf.d/python.d/exim.conf b/conf.d/python.d/exim.conf index 07d72c5a..2add7b2c 100644 --- a/conf.d/python.d/exim.conf +++ b/conf.d/python.d/exim.conf @@ -32,7 +32,13 @@ update_every: 10 # If unset, the default for python.d.plugin is used. # Attempts to restore the service are made once every update_every # and only if the module has collected values in the past. -# retries: 5 +# retries: 60 + +# autodetection_retry sets the job re-check interval in seconds. +# The job is not deleted if check fails. +# Attempts to start the job are made once every autodetection_retry. +# This feature is disabled by default. +# autodetection_retry: 0 # ---------------------------------------------------------------------- # JOBS (data collection sources) @@ -48,12 +54,13 @@ update_every: 10 # predefined parameters. These are: # # job_name: -# name: myname # the JOB's name as it will appear at the -# # dashboard (by default is the job_name) -# # JOBs sharing a name are mutually exclusive -# update_every: 1 # the JOB's data collection frequency -# priority: 60000 # the JOB's order on the dashboard -# retries: 5 # the JOB's number of restoration attempts +# name: myname # the JOB's name as it will appear at the +# # dashboard (by default is the job_name) +# # JOBs sharing a name are mutually exclusive +# update_every: 1 # the JOB's data collection frequency +# priority: 60000 # the JOB's order on the dashboard +# retries: 60 # the JOB's number of restoration attempts +# autodetection_retry: 0 # the JOB's re-check interval in seconds # # Additionally to the above, exim also supports the following: # diff --git a/conf.d/python.d/fail2ban.conf b/conf.d/python.d/fail2ban.conf index 76277108..60ca8723 100644 --- a/conf.d/python.d/fail2ban.conf +++ b/conf.d/python.d/fail2ban.conf @@ -31,7 +31,13 @@ # If unset, the default for python.d.plugin is used. # Attempts to restore the service are made once every update_every # and only if the module has collected values in the past. -# retries: 5 +# retries: 60 + +# autodetection_retry sets the job re-check interval in seconds. +# The job is not deleted if check fails. +# Attempts to start the job are made once every autodetection_retry. +# This feature is disabled by default. +# autodetection_retry: 0 # ---------------------------------------------------------------------- # JOBS (data collection sources) @@ -47,17 +53,18 @@ # predefined parameters. These are: # # job_name: -# name: myname # the JOB's name as it will appear at the -# # dashboard (by default is the job_name) -# # JOBs sharing a name are mutually exclusive -# update_every: 1 # the JOB's data collection frequency -# priority: 60000 # the JOB's order on the dashboard -# retries: 5 # the JOB's number of restoration attempts +# name: myname # the JOB's name as it will appear at the +# # dashboard (by default is the job_name) +# # JOBs sharing a name are mutually exclusive +# update_every: 1 # the JOB's data collection frequency +# priority: 60000 # the JOB's order on the dashboard +# retries: 60 # the JOB's number of restoration attempts +# autodetection_retry: 0 # the JOB's re-check interval in seconds # # Additionally to the above, fail2ban also supports the following: # -# log_path: 'path to fail2ban.log' # Default: '/var/log/fail2ban.log' -# conf_path: 'path to jail.local/jail.conf' # Default: '/etc/fail2ban/jail.local' -# conf_dir: 'path to jail.d/' # Default: '/etc/fail2ban/jail.d/' -# exclude: 'jails you want to exclude from autodetection' # Default: '[]' empty list +# log_path: 'path to fail2ban.log' # Default: '/var/log/fail2ban.log' +# conf_path: 'path to jail.local/jail.conf' # Default: '/etc/fail2ban/jail.local' +# conf_dir: 'path to jail.d/' # Default: '/etc/fail2ban/jail.d/' +# exclude: 'jails you want to exclude from autodetection' # Default: none #------------------------------------------------------------------------------------------------------------------ diff --git a/conf.d/python.d/freeradius.conf b/conf.d/python.d/freeradius.conf index b2c8abf6..3336d4c4 100644 --- a/conf.d/python.d/freeradius.conf +++ b/conf.d/python.d/freeradius.conf @@ -31,7 +31,13 @@ # If unset, the default for python.d.plugin is used. # Attempts to restore the service are made once every update_every # and only if the module has collected values in the past. -# retries: 5 +# retries: 60 + +# autodetection_retry sets the job re-check interval in seconds. +# The job is not deleted if check fails. +# Attempts to start the job are made once every autodetection_retry. +# This feature is disabled by default. +# autodetection_retry: 0 # ---------------------------------------------------------------------- # JOBS (data collection sources) @@ -47,21 +53,22 @@ # predefined parameters. These are: # # job_name: -# name: myname # the JOB's name as it will appear at the -# # dashboard (by default is the job_name) -# # JOBs sharing a name are mutually exclusive -# update_every: 1 # the JOB's data collection frequency -# priority: 60000 # the JOB's order on the dashboard -# retries: 5 # the JOB's number of restoration attempts +# name: myname # the JOB's name as it will appear at the +# # dashboard (by default is the job_name) +# # JOBs sharing a name are mutually exclusive +# update_every: 1 # the JOB's data collection frequency +# priority: 60000 # the JOB's order on the dashboard +# retries: 60 # the JOB's number of restoration attempts +# autodetection_retry: 0 # the JOB's re-check interval in seconds # # Additionally to the above, freeradius also supports the following: # -# host: 'host' # Default: 'localhost'. Server ip address or hostname. -# port: 'port' # Default: '18121'. Port on which freeradius server listen (type = status). +# host: 'host' # Default: 'localhost'. Server ip address or hostname. +# port: 'port' # Default: '18121'. Port on which freeradius server listen (type = status). # secret: 'secret' # Default: 'adminsecret'. -# acct: True/False # Defalt: False. Freeradius accounting statistics. -# proxy_auth: True/False # Default: False. Freeradius proxy authentication statistics. -# proxy_acct: True/False # Default: False. Freeradius proxy accounting statistics. +# acct: yes/no # Default: no. Freeradius accounting statistics. +# proxy_auth: yes/no # Default: no. Freeradius proxy authentication statistics. +# proxy_acct: yes/no # Default: no. Freeradius proxy accounting statistics. # # ------------------------------------------------------------------------------------------------------------------ # Freeradius server configuration: @@ -73,14 +80,3 @@ # ln -s ../sites-available/status status # and restart/reload your FREERADIUS server. # ------------------------------------------------------------------------------------------------------------------ -# -# AUTO-DETECTION JOBS -# only one of them will run (they have the same name) - -local: - host: 'localhost' - port: '18121' - secret: 'adminsecret' -#acct: False -#proxy_auth: False -#proxy_acct: False diff --git a/conf.d/python.d/go_expvar.conf b/conf.d/python.d/go_expvar.conf index 5be4890d..c352b167 100644 --- a/conf.d/python.d/go_expvar.conf +++ b/conf.d/python.d/go_expvar.conf @@ -31,7 +31,13 @@ # If unset, the default for python.d.plugin is used. # Attempts to restore the service are made once every update_every # and only if the module has collected values in the past. -# retries: 5 +# retries: 60 + +# autodetection_retry sets the job re-check interval in seconds. +# The job is not deleted if check fails. +# Attempts to start the job are made once every autodetection_retry. +# This feature is disabled by default. +# autodetection_retry: 0 # ---------------------------------------------------------------------- # JOBS (data collection sources) @@ -42,19 +48,17 @@ # predefined parameters. These are: # # job_name: -# name: my_name # the JOB's name as it will appear at the -# # dashboard. If name: is not supplied the -# # job_name: will be used (use _ for spaces) -# # JOBs sharing a name are mutually exclusive -# update_every: 1 # the JOB's data collection frequency -# priority: 60000 # the JOB's order on the dashboard -# retries: 5 # the JOB's number of restoration attempts +# name: myname # the JOB's name as it will appear at the +# # dashboard (by default is the job_name) +# # JOBs sharing a name are mutually exclusive +# update_every: 1 # the JOB's data collection frequency +# priority: 60000 # the JOB's order on the dashboard +# retries: 60 # the JOB's number of restoration attempts +# autodetection_retry: 0 # the JOB's re-check interval in seconds # # Additionally to the above, this plugin also supports the following: # # url: 'http://127.0.0.1/debug/vars' # the URL of the expvar endpoint -# ss_cert: # ignore HTTPS self-signed certificate -# proxy: # use HTTP proxy # # As the plugin cannot possibly know the port your application listens on, there is no default value. Please include # the whole path of the endpoint, as the expvar handler can be installed in a non-standard location. diff --git a/conf.d/python.d/haproxy.conf b/conf.d/python.d/haproxy.conf index a9e04879..a40dd76a 100644 --- a/conf.d/python.d/haproxy.conf +++ b/conf.d/python.d/haproxy.conf @@ -31,7 +31,13 @@ # If unset, the default for python.d.plugin is used. # Attempts to restore the service are made once every update_every # and only if the module has collected values in the past. -# retries: 5 +# retries: 60 + +# autodetection_retry sets the job re-check interval in seconds. +# The job is not deleted if check fails. +# Attempts to start the job are made once every autodetection_retry. +# This feature is disabled by default. +# autodetection_retry: 0 # ---------------------------------------------------------------------- # JOBS (data collection sources) @@ -47,12 +53,13 @@ # predefined parameters. These are: # # job_name: -# name: myname # the JOB's name as it will appear at the -# # dashboard (by default is the job_name) -# # JOBs sharing a name are mutually exclusive -# update_every: 1 # the JOB's data collection frequency -# priority: 60000 # the JOB's order on the dashboard -# retries: 5 # the JOB's number of restoration attempts +# name: myname # the JOB's name as it will appear at the +# # dashboard (by default is the job_name) +# # JOBs sharing a name are mutually exclusive +# update_every: 1 # the JOB's data collection frequency +# priority: 60000 # the JOB's order on the dashboard +# retries: 60 # the JOB's number of restoration attempts +# autodetection_retry: 0 # the JOB's re-check interval in seconds # # Additionally to the above, haproxy also supports the following: # diff --git a/conf.d/python.d/hddtemp.conf b/conf.d/python.d/hddtemp.conf index f74a0980..9165798a 100644 --- a/conf.d/python.d/hddtemp.conf +++ b/conf.d/python.d/hddtemp.conf @@ -31,7 +31,13 @@ # If unset, the default for python.d.plugin is used. # Attempts to restore the service are made once every update_every # and only if the module has collected values in the past. -# retries: 5 +# retries: 60 + +# autodetection_retry sets the job re-check interval in seconds. +# The job is not deleted if check fails. +# Attempts to start the job are made once every autodetection_retry. +# This feature is disabled by default. +# autodetection_retry: 0 # ---------------------------------------------------------------------- # JOBS (data collection sources) @@ -47,18 +53,18 @@ # predefined parameters. These are: # # job_name: -# name: myname # the JOB's name as it will appear at the -# # dashboard (by default is the job_name) -# # JOBs sharing a name are mutually exclusive -# update_every: 1 # the JOB's data collection frequency -# priority: 60000 # the JOB's order on the dashboard -# retries: 5 # the JOB's number of restoration attempts +# name: myname # the JOB's name as it will appear at the +# # dashboard (by default is the job_name) +# # JOBs sharing a name are mutually exclusive +# update_every: 1 # the JOB's data collection frequency +# priority: 60000 # the JOB's order on the dashboard +# retries: 60 # the JOB's number of restoration attempts +# autodetection_retry: 0 # the JOB's re-check interval in seconds # # Additionally to the above, hddtemp also supports the following: # # host: 'IP or HOSTNAME' # the host to connect to # port: PORT # the port to connect to -# fahrenheit: True/False # fahrenheit instead of celsius. Default is False # # By default this module will try to autodetect disks @@ -78,13 +84,11 @@ localhost: name: 'local' host: 'localhost' - fahrenheit: False port: 7634 localipv4: name: 'local' host: '127.0.0.1' - fahrenheit: False port: 7634 localipv6: diff --git a/conf.d/python.d/ipfs.conf b/conf.d/python.d/ipfs.conf index e039026c..c247c1b7 100644 --- a/conf.d/python.d/ipfs.conf +++ b/conf.d/python.d/ipfs.conf @@ -31,7 +31,13 @@ # If unset, the default for python.d.plugin is used. # Attempts to restore the service are made once every update_every # and only if the module has collected values in the past. -# retries: 5 +# retries: 60 + +# autodetection_retry sets the job re-check interval in seconds. +# The job is not deleted if check fails. +# Attempts to start the job are made once every autodetection_retry. +# This feature is disabled by default. +# autodetection_retry: 0 # ---------------------------------------------------------------------- # JOBS (data collection sources) @@ -47,12 +53,13 @@ # predefined parameters. These are: # # job_name: -# name: myname # the JOB's name as it will appear at the -# # dashboard (by default is the job_name) -# # JOBs sharing a name are mutually exclusive -# update_every: 1 # the JOB's data collection frequency -# priority: 60000 # the JOB's order on the dashboard -# retries: 5 # the JOB's number of restoration attempts +# name: myname # the JOB's name as it will appear at the +# # dashboard (by default is the job_name) +# # JOBs sharing a name are mutually exclusive +# update_every: 1 # the JOB's data collection frequency +# priority: 60000 # the JOB's order on the dashboard +# retries: 60 # the JOB's number of restoration attempts +# autodetection_retry: 0 # the JOB's re-check interval in seconds # # Additionally to the above, ipfs also supports the following: # diff --git a/conf.d/python.d/isc_dhcpd.conf b/conf.d/python.d/isc_dhcpd.conf index 938ca6e7..4a4c4a5e 100644 --- a/conf.d/python.d/isc_dhcpd.conf +++ b/conf.d/python.d/isc_dhcpd.conf @@ -31,7 +31,13 @@ # If unset, the default for python.d.plugin is used. # Attempts to restore the service are made once every update_every # and only if the module has collected values in the past. -# retries: 5 +# retries: 60 + +# autodetection_retry sets the job re-check interval in seconds. +# The job is not deleted if check fails. +# Attempts to start the job are made once every autodetection_retry. +# This feature is disabled by default. +# autodetection_retry: 0 # ---------------------------------------------------------------------- # JOBS (data collection sources) @@ -47,12 +53,13 @@ # predefined parameters. These are: # # job_name: -# name: myname # the JOB's name as it will appear at the -# # dashboard (by default is the job_name) -# # JOBs sharing a name are mutually exclusive -# update_every: 1 # the JOB's data collection frequency -# priority: 60000 # the JOB's order on the dashboard -# retries: 5 # the JOB's number of restoration attempts +# name: myname # the JOB's name as it will appear at the +# # dashboard (by default is the job_name) +# # JOBs sharing a name are mutually exclusive +# update_every: 1 # the JOB's data collection frequency +# priority: 60000 # the JOB's order on the dashboard +# retries: 60 # the JOB's number of restoration attempts +# autodetection_retry: 0 # the JOB's re-check interval in seconds # # Additionally to the above, isc_dhcpd supports the following: # @@ -71,13 +78,4 @@ # This is the default, so it will work in most cases. # 3. Pools MUST BE in CIDR format. # -#----------------------------------------------------------------------- -# AUTO-DETECTION JOBS -# This is disabled by default. -# To enable it, uncomment the following. -# -#leases: -# leases_path : '/var/lib/dhcp/dhcpd.leases' -# pools: -# office: '192.168.2.0/24' -# wifi: '192.168.3.0/24' +# ---------------------------------------------------------------------- diff --git a/conf.d/python.d/mdstat.conf b/conf.d/python.d/mdstat.conf index c89d463b..66a2f153 100644 --- a/conf.d/python.d/mdstat.conf +++ b/conf.d/python.d/mdstat.conf @@ -23,4 +23,10 @@ # If unset, the default for python.d.plugin is used. # Attempts to restore the service are made once every update_every # and only if the module has collected values in the past. -# retries: 5 +# retries: 60 + +# autodetection_retry sets the job re-check interval in seconds. +# The job is not deleted if check fails. +# Attempts to start the job are made once every autodetection_retry. +# This feature is disabled by default. +# autodetection_retry: 0 diff --git a/conf.d/python.d/memcached.conf b/conf.d/python.d/memcached.conf index f1723dc8..85c3daf6 100644 --- a/conf.d/python.d/memcached.conf +++ b/conf.d/python.d/memcached.conf @@ -31,7 +31,13 @@ # If unset, the default for python.d.plugin is used. # Attempts to restore the service are made once every update_every # and only if the module has collected values in the past. -# retries: 5 +# retries: 60 + +# autodetection_retry sets the job re-check interval in seconds. +# The job is not deleted if check fails. +# Attempts to start the job are made once every autodetection_retry. +# This feature is disabled by default. +# autodetection_retry: 0 # ---------------------------------------------------------------------- # JOBS (data collection sources) @@ -47,12 +53,13 @@ # predefined parameters. These are: # # job_name: -# name: myname # the JOB's name as it will appear at the -# # dashboard (by default is the job_name) -# # JOBs sharing a name are mutually exclusive -# update_every: 1 # the JOB's data collection frequency -# priority: 60000 # the JOB's order on the dashboard -# retries: 5 # the JOB's number of restoration attempts +# name: myname # the JOB's name as it will appear at the +# # dashboard (by default is the job_name) +# # JOBs sharing a name are mutually exclusive +# update_every: 1 # the JOB's data collection frequency +# priority: 60000 # the JOB's order on the dashboard +# retries: 60 # the JOB's number of restoration attempts +# autodetection_retry: 0 # the JOB's re-check interval in seconds # # Additionally to the above, memcached also supports the following: # diff --git a/conf.d/python.d/mongodb.conf b/conf.d/python.d/mongodb.conf index a19b6570..62faef68 100644 --- a/conf.d/python.d/mongodb.conf +++ b/conf.d/python.d/mongodb.conf @@ -31,7 +31,13 @@ # If unset, the default for python.d.plugin is used. # Attempts to restore the service are made once every update_every # and only if the module has collected values in the past. -# retries: 5 +# retries: 60 + +# autodetection_retry sets the job re-check interval in seconds. +# The job is not deleted if check fails. +# Attempts to start the job are made once every autodetection_retry. +# This feature is disabled by default. +# autodetection_retry: 0 # ---------------------------------------------------------------------- # JOBS (data collection sources) @@ -47,12 +53,13 @@ # predefined parameters. These are: # # job_name: -# name: myname # the JOB's name as it will appear at the -# # dashboard (by default is the job_name) -# # JOBs sharing a name are mutually exclusive -# update_every: 1 # the JOB's data collection frequency -# priority: 60000 # the JOB's order on the dashboard -# retries: 5 # the JOB's number of restoration attempts +# name: myname # the JOB's name as it will appear at the +# # dashboard (by default is the job_name) +# # JOBs sharing a name are mutually exclusive +# update_every: 1 # the JOB's data collection frequency +# priority: 60000 # the JOB's order on the dashboard +# retries: 60 # the JOB's number of restoration attempts +# autodetection_retry: 0 # the JOB's re-check interval in seconds # # Additionally to the above, mongodb also supports the following: # diff --git a/conf.d/python.d/mysql.conf b/conf.d/python.d/mysql.conf index 63d63517..def9f7e9 100644 --- a/conf.d/python.d/mysql.conf +++ b/conf.d/python.d/mysql.conf @@ -31,7 +31,13 @@ # If unset, the default for python.d.plugin is used. # Attempts to restore the service are made once every update_every # and only if the module has collected values in the past. -# retries: 5 +# retries: 60 + +# autodetection_retry sets the job re-check interval in seconds. +# The job is not deleted if check fails. +# Attempts to start the job are made once every autodetection_retry. +# This feature is disabled by default. +# autodetection_retry: 0 # ---------------------------------------------------------------------- # JOBS (data collection sources) @@ -47,12 +53,13 @@ # predefined parameters. These are: # # job_name: -# name: myname # the JOB's name as it will appear at the -# # dashboard (by default is the job_name) -# # JOBs sharing a name are mutually exclusive -# update_every: 1 # the JOB's data collection frequency -# priority: 60000 # the JOB's order on the dashboard -# retries: 5 # the JOB's number of restoration attempts +# name: myname # the JOB's name as it will appear at the +# # dashboard (by default is the job_name) +# # JOBs sharing a name are mutually exclusive +# update_every: 1 # the JOB's data collection frequency +# priority: 60000 # the JOB's order on the dashboard +# retries: 60 # the JOB's number of restoration attempts +# autodetection_retry: 0 # the JOB's re-check interval in seconds # # Additionally to the above, mysql also supports the following: # diff --git a/conf.d/python.d/nginx.conf b/conf.d/python.d/nginx.conf index 645925a5..71c52106 100644 --- a/conf.d/python.d/nginx.conf +++ b/conf.d/python.d/nginx.conf @@ -43,7 +43,13 @@ # If unset, the default for python.d.plugin is used. # Attempts to restore the service are made once every update_every # and only if the module has collected values in the past. -# retries: 5 +# retries: 60 + +# autodetection_retry sets the job re-check interval in seconds. +# The job is not deleted if check fails. +# Attempts to start the job are made once every autodetection_retry. +# This feature is disabled by default. +# autodetection_retry: 0 # ---------------------------------------------------------------------- # JOBS (data collection sources) @@ -59,13 +65,13 @@ # predefined parameters. These are: # # job_name: -# name: my_name # the JOB's name as it will appear at the -# # dashboard. If name: is not supplied the -# # job_name: will be used (use _ for spaces) -# # JOBs sharing a name are mutually exclusive -# update_every: 1 # the JOB's data collection frequency -# priority: 60000 # the JOB's order on the dashboard -# retries: 5 # the JOB's number of restoration attempts +# name: myname # the JOB's name as it will appear at the +# # dashboard (by default is the job_name) +# # JOBs sharing a name are mutually exclusive +# update_every: 1 # the JOB's data collection frequency +# priority: 60000 # the JOB's order on the dashboard +# retries: 60 # the JOB's number of restoration attempts +# autodetection_retry: 0 # the JOB's re-check interval in seconds # # Additionally to the above, this plugin also supports the following: # @@ -99,5 +105,5 @@ localipv4: localipv6: name : 'local' - url : 'http://::1/stub_status' + url : 'http://[::1]/stub_status' diff --git a/conf.d/python.d/nsd.conf b/conf.d/python.d/nsd.conf index 7566fe85..078e9721 100644 --- a/conf.d/python.d/nsd.conf +++ b/conf.d/python.d/nsd.conf @@ -32,7 +32,13 @@ # If unset, the default for python.d.plugin is used. # Attempts to restore the service are made once every update_every # and only if the module has collected values in the past. -# retries: 5 +# retries: 60 + +# autodetection_retry sets the job re-check interval in seconds. +# The job is not deleted if check fails. +# Attempts to start the job are made once every autodetection_retry. +# This feature is disabled by default. +# autodetection_retry: 0 # ---------------------------------------------------------------------- # JOBS (data collection sources) @@ -48,12 +54,13 @@ # predefined parameters. These are: # # job_name: -# name: myname # the JOB's name as it will appear at the -# # dashboard (by default is the job_name) -# # JOBs sharing a name are mutually exclusive -# update_every: 1 # the JOB's data collection frequency -# priority: 60000 # the JOB's order on the dashboard -# retries: 5 # the JOB's number of restoration attempts +# name: myname # the JOB's name as it will appear at the +# # dashboard (by default is the job_name) +# # JOBs sharing a name are mutually exclusive +# update_every: 1 # the JOB's data collection frequency +# priority: 60000 # the JOB's order on the dashboard +# retries: 60 # the JOB's number of restoration attempts +# autodetection_retry: 0 # the JOB's re-check interval in seconds # # Additionally to the above, nsd also supports the following: # diff --git a/conf.d/python.d/ovpn_status_log.conf b/conf.d/python.d/ovpn_status_log.conf index 39bc8e9d..907f014f 100644 --- a/conf.d/python.d/ovpn_status_log.conf +++ b/conf.d/python.d/ovpn_status_log.conf @@ -31,7 +31,13 @@ # If unset, the default for python.d.plugin is used. # Attempts to restore the service are made once every update_every # and only if the module has collected values in the past. -# retries: 5 +# retries: 60 + +# autodetection_retry sets the job re-check interval in seconds. +# The job is not deleted if check fails. +# Attempts to start the job are made once every autodetection_retry. +# This feature is disabled by default. +# autodetection_retry: 0 # ---------------------------------------------------------------------- # JOBS (data collection sources) @@ -47,12 +53,13 @@ # predefined parameters. These are: # # job_name: -# name: myname # the JOB's name as it will appear at the -# # dashboard (by default is the job_name) -# # JOBs sharing a name are mutually exclusive -# update_every: 1 # the JOB's data collection frequency -# priority: 60000 # the JOB's order on the dashboard -# retries: 5 # the JOB's number of restoration attempts +# name: myname # the JOB's name as it will appear at the +# # dashboard (by default is the job_name) +# # JOBs sharing a name are mutually exclusive +# update_every: 1 # the JOB's data collection frequency +# priority: 60000 # the JOB's order on the dashboard +# retries: 60 # the JOB's number of restoration attempts +# autodetection_retry: 0 # the JOB's re-check interval in seconds # # Additionally to the above, openvpn status log also supports the following: # @@ -84,3 +91,5 @@ # #default: # log_path: '/var/log/openvpn-status.log' +# +# ----------------------------------------------------------------------
\ No newline at end of file diff --git a/conf.d/python.d/phpfpm.conf b/conf.d/python.d/phpfpm.conf index f5d067cc..08688e2f 100644 --- a/conf.d/python.d/phpfpm.conf +++ b/conf.d/python.d/phpfpm.conf @@ -31,7 +31,13 @@ # If unset, the default for python.d.plugin is used. # Attempts to restore the service are made once every update_every # and only if the module has collected values in the past. -# retries: 5 +# retries: 60 + +# autodetection_retry sets the job re-check interval in seconds. +# The job is not deleted if check fails. +# Attempts to start the job are made once every autodetection_retry. +# This feature is disabled by default. +# autodetection_retry: 0 # ---------------------------------------------------------------------- # JOBS (data collection sources) @@ -47,12 +53,13 @@ # predefined parameters. These are: # # job_name: -# name: myname # the JOB's name as it will appear at the -# # dashboard (by default is the job_name) -# # JOBs sharing a name are mutually exclusive -# update_every: 1 # the JOB's data collection frequency -# priority: 60000 # the JOB's order on the dashboard -# retries: 5 # the JOB's number of restoration attempts +# name: myname # the JOB's name as it will appear at the +# # dashboard (by default is the job_name) +# # JOBs sharing a name are mutually exclusive +# update_every: 1 # the JOB's data collection frequency +# priority: 60000 # the JOB's order on the dashboard +# retries: 60 # the JOB's number of restoration attempts +# autodetection_retry: 0 # the JOB's re-check interval in seconds # # Additionally to the above, PHP-FPM also supports the following: # diff --git a/conf.d/python.d/postfix.conf b/conf.d/python.d/postfix.conf index ca9d8fad..e0d5a5f8 100644 --- a/conf.d/python.d/postfix.conf +++ b/conf.d/python.d/postfix.conf @@ -32,7 +32,13 @@ update_every: 10 # If unset, the default for python.d.plugin is used. # Attempts to restore the service are made once every update_every # and only if the module has collected values in the past. -# retries: 5 +# retries: 60 + +# autodetection_retry sets the job re-check interval in seconds. +# The job is not deleted if check fails. +# Attempts to start the job are made once every autodetection_retry. +# This feature is disabled by default. +# autodetection_retry: 0 # ---------------------------------------------------------------------- # JOBS (data collection sources) @@ -48,12 +54,13 @@ update_every: 10 # predefined parameters. These are: # # job_name: -# name: myname # the JOB's name as it will appear at the -# # dashboard (by default is the job_name) -# # JOBs sharing a name are mutually exclusive -# update_every: 1 # the JOB's data collection frequency -# priority: 60000 # the JOB's order on the dashboard -# retries: 5 # the JOB's number of restoration attempts +# name: myname # the JOB's name as it will appear at the +# # dashboard (by default is the job_name) +# # JOBs sharing a name are mutually exclusive +# update_every: 1 # the JOB's data collection frequency +# priority: 60000 # the JOB's order on the dashboard +# retries: 60 # the JOB's number of restoration attempts +# autodetection_retry: 0 # the JOB's re-check interval in seconds # # Additionally to the above, postfix also supports the following: # diff --git a/conf.d/python.d/postgres.conf b/conf.d/python.d/postgres.conf index 1dbb64f4..3a70a718 100644 --- a/conf.d/python.d/postgres.conf +++ b/conf.d/python.d/postgres.conf @@ -31,7 +31,13 @@ # If unset, the default for python.d.plugin is used. # Attempts to restore the service are made once every update_every # and only if the module has collected values in the past. -# retries: 5 +# retries: 60 + +# autodetection_retry sets the job re-check interval in seconds. +# The job is not deleted if check fails. +# Attempts to start the job are made once every autodetection_retry. +# This feature is disabled by default. +# autodetection_retry: 0 # ---------------------------------------------------------------------- # JOBS (data collection sources) @@ -47,12 +53,13 @@ # predefined parameters. These are: # # job_name: -# name: myname # the JOB's name as it will appear at the -# # dashboard (by default is the job_name) -# # JOBs sharing a name are mutually exclusive -# update_every: 1 # the JOB's data collection frequency -# priority: 60000 # the JOB's order on the dashboard -# retries: 5 # the JOB's number of restoration attempts +# name: myname # the JOB's name as it will appear at the +# # dashboard (by default is the job_name) +# # JOBs sharing a name are mutually exclusive +# update_every: 1 # the JOB's data collection frequency +# priority: 60000 # the JOB's order on the dashboard +# retries: 60 # the JOB's number of restoration attempts +# autodetection_retry: 0 # the JOB's re-check interval in seconds # # A single connection is required in order to pull statistics. # @@ -70,7 +77,7 @@ # index_stats : false # database_poll : 'dbase_name1 dbase_name2' # poll only specified databases (all other will be excluded from charts) # -# Postfix permissions are configured at its pg_hba.conf file. You can +# Postgres permissions are configured at its pg_hba.conf file. You can # "trust" local clients to allow netdata to connect, or you can create # a postgres user for netdata and add its password below to allow # netdata connect. diff --git a/conf.d/python.d/apache_cache.conf b/conf.d/python.d/powerdns.conf index 98eecd0e..ca6200df 100644 --- a/conf.d/python.d/apache_cache.conf +++ b/conf.d/python.d/powerdns.conf @@ -1,4 +1,4 @@ -# netdata python.d.plugin configuration for apache cache +# netdata python.d.plugin configuration for powerdns # # This file is in YaML format. Generally the format is: # @@ -31,7 +31,13 @@ # If unset, the default for python.d.plugin is used. # Attempts to restore the service are made once every update_every # and only if the module has collected values in the past. -# retries: 5 +# retries: 60 + +# autodetection_retry sets the job re-check interval in seconds. +# The job is not deleted if check fails. +# Attempts to start the job are made once every autodetection_retry. +# This feature is disabled by default. +# autodetection_retry: 0 # ---------------------------------------------------------------------- # JOBS (data collection sources) @@ -47,30 +53,26 @@ # predefined parameters. These are: # # job_name: -# name: myname # the JOB's name as it will appear at the -# # dashboard (by default is the job_name) -# # JOBs sharing a name are mutually exclusive -# update_every: 1 # the JOB's data collection frequency -# priority: 60000 # the JOB's order on the dashboard -# retries: 5 # the JOB's number of restoration attempts +# name: myname # the JOB's name as it will appear at the +# # dashboard (by default is the job_name) +# # JOBs sharing a name are mutually exclusive +# update_every: 1 # the JOB's data collection frequency +# priority: 60000 # the JOB's order on the dashboard +# retries: 60 # the JOB's number of restoration attempts +# autodetection_retry: 0 # the JOB's re-check interval in seconds # -# Additionally to the above, apache_cache also supports the following: +# Additionally to the above, apache also supports the following: # -# path: 'PATH' # the path to apache's cache.log +# url: 'URL' # the URL to fetch powerdns performance statistics +# header: +# X-API-Key: 'Key' # API key # - # ---------------------------------------------------------------------- # AUTO-DETECTION JOBS # only one of them will run (they have the same name) -apache: - name: 'local' - path: '/var/log/apache/cache.log' - -apache2: - name: 'local' - path: '/var/log/apache2/cache.log' - -httpd: - name: 'local' - path: '/var/log/httpd/cache.log' +# localhost: +# name : 'local' +# url : 'http://127.0.0.1:8081/api/v1/servers/localhost/statistics' +# header: +# X-API-Key: 'change_me' diff --git a/conf.d/python.d/rabbitmq.conf b/conf.d/python.d/rabbitmq.conf index eccf65df..3f90da8a 100644 --- a/conf.d/python.d/rabbitmq.conf +++ b/conf.d/python.d/rabbitmq.conf @@ -31,7 +31,13 @@ # If unset, the default for python.d.plugin is used. # Attempts to restore the service are made once every update_every # and only if the module has collected values in the past. -# retries: 5 +# retries: 60 + +# autodetection_retry sets the job re-check interval in seconds. +# The job is not deleted if check fails. +# Attempts to start the job are made once every autodetection_retry. +# This feature is disabled by default. +# autodetection_retry: 0 # ---------------------------------------------------------------------- # JOBS (data collection sources) @@ -47,12 +53,13 @@ # predefined parameters. These are: # # job_name: -# name: myname # the JOB's name as it will appear at the -# # dashboard (by default is the job_name) -# # JOBs sharing a name are mutually exclusive -# update_every: 1 # the JOB's data collection frequency -# priority: 60000 # the JOB's order on the dashboard -# retries: 5 # the JOB's number of restoration attempts +# name: myname # the JOB's name as it will appear at the +# # dashboard (by default is the job_name) +# # JOBs sharing a name are mutually exclusive +# update_every: 1 # the JOB's data collection frequency +# priority: 60000 # the JOB's order on the dashboard +# retries: 60 # the JOB's number of restoration attempts +# autodetection_retry: 0 # the JOB's re-check interval in seconds # # Additionally to the above, rabbitmq plugin also supports the following: # diff --git a/conf.d/python.d/redis.conf b/conf.d/python.d/redis.conf index 983fbfbd..6363f6da 100644 --- a/conf.d/python.d/redis.conf +++ b/conf.d/python.d/redis.conf @@ -31,7 +31,13 @@ # If unset, the default for python.d.plugin is used. # Attempts to restore the service are made once every update_every # and only if the module has collected values in the past. -# retries: 5 +# retries: 60 + +# autodetection_retry sets the job re-check interval in seconds. +# The job is not deleted if check fails. +# Attempts to start the job are made once every autodetection_retry. +# This feature is disabled by default. +# autodetection_retry: 0 # ---------------------------------------------------------------------- # JOBS (data collection sources) @@ -47,12 +53,13 @@ # predefined parameters. These are: # # job_name: -# name: myname # the JOB's name as it will appear at the -# # dashboard (by default is the job_name) -# # JOBs sharing a name are mutually exclusive -# update_every: 1 # the JOB's data collection frequency -# priority: 60000 # the JOB's order on the dashboard -# retries: 5 # the JOB's number of restoration attempts +# name: myname # the JOB's name as it will appear at the +# # dashboard (by default is the job_name) +# # JOBs sharing a name are mutually exclusive +# update_every: 1 # the JOB's data collection frequency +# priority: 60000 # the JOB's order on the dashboard +# retries: 60 # the JOB's number of restoration attempts +# autodetection_retry: 0 # the JOB's re-check interval in seconds # # Additionally to the above, redis also supports the following: # diff --git a/conf.d/python.d/retroshare.conf b/conf.d/python.d/retroshare.conf index 79614373..9c92583f 100644 --- a/conf.d/python.d/retroshare.conf +++ b/conf.d/python.d/retroshare.conf @@ -31,7 +31,13 @@ # If unset, the default for python.d.plugin is used. # Attempts to restore the service are made once every update_every # and only if the module has collected values in the past. -# retries: 5 +# retries: 60 + +# autodetection_retry sets the job re-check interval in seconds. +# The job is not deleted if check fails. +# Attempts to start the job are made once every autodetection_retry. +# This feature is disabled by default. +# autodetection_retry: 0 # ---------------------------------------------------------------------- # JOBS (data collection sources) @@ -47,12 +53,13 @@ # predefined parameters. These are: # # job_name: -# name: myname # the JOB's name as it will appear at the -# # dashboard (by default is the job_name) -# # JOBs sharing a name are mutually exclusive -# update_every: 1 # the JOB's data collection frequency -# priority: 60000 # the JOB's order on the dashboard -# retries: 5 # the JOB's number of restoration attempts +# name: myname # the JOB's name as it will appear at the +# # dashboard (by default is the job_name) +# # JOBs sharing a name are mutually exclusive +# update_every: 1 # the JOB's data collection frequency +# priority: 60000 # the JOB's order on the dashboard +# retries: 60 # the JOB's number of restoration attempts +# autodetection_retry: 0 # the JOB's re-check interval in seconds # # Additionally to the above, RetroShare also supports the following: # diff --git a/conf.d/python.d/samba.conf b/conf.d/python.d/samba.conf index 865281cd..ee513c60 100644 --- a/conf.d/python.d/samba.conf +++ b/conf.d/python.d/samba.conf @@ -31,7 +31,13 @@ update_every: 5 # If unset, the default for python.d.plugin is used. # Attempts to restore the service are made once every update_every # and only if the module has collected values in the past. -# retries: 5 +# retries: 60 + +# autodetection_retry sets the job re-check interval in seconds. +# The job is not deleted if check fails. +# Attempts to start the job are made once every autodetection_retry. +# This feature is disabled by default. +# autodetection_retry: 0 # ---------------------------------------------------------------------- # JOBS (data collection sources) @@ -47,12 +53,10 @@ update_every: 5 # predefined parameters. These are: # # job_name: -# name: myname # the JOB's name as it will appear at the -# # dashboard (by default is the job_name) -# # JOBs sharing a name are mutually exclusive -# update_every: 1 # the JOB's data collection frequency -# priority: 60000 # the JOB's order on the dashboard -# retries: 5 # the JOB's number of restoration attempts -# -# - +# name: myname # the JOB's name as it will appear at the +# # dashboard (by default is the job_name) +# # JOBs sharing a name are mutually exclusive +# update_every: 1 # the JOB's data collection frequency +# priority: 60000 # the JOB's order on the dashboard +# retries: 60 # the JOB's number of restoration attempts +# autodetection_retry: 0 # the JOB's re-check interval in seconds
\ No newline at end of file diff --git a/conf.d/python.d/sensors.conf b/conf.d/python.d/sensors.conf index 2e9a4133..83bbffd7 100644 --- a/conf.d/python.d/sensors.conf +++ b/conf.d/python.d/sensors.conf @@ -23,7 +23,13 @@ # If unset, the default for python.d.plugin is used. # Attempts to restore the service are made once every update_every # and only if the module has collected values in the past. -# retries: 5 +# retries: 60 + +# autodetection_retry sets the job re-check interval in seconds. +# The job is not deleted if check fails. +# Attempts to start the job are made once every autodetection_retry. +# This feature is disabled by default. +# autodetection_retry: 0 # ---------------------------------------------------------------------- # Limit the number of sensors types. @@ -54,5 +60,4 @@ types: # the prefix is matched (anything that starts like that) # #---------------------------------------------------------------------- -# To change celsius to fahrenheit uncomment line below -#fahrenheit: True + diff --git a/conf.d/python.d/smartd_log.conf b/conf.d/python.d/smartd_log.conf index 8764ffd3..3fab3f1c 100644 --- a/conf.d/python.d/smartd_log.conf +++ b/conf.d/python.d/smartd_log.conf @@ -31,7 +31,13 @@ # If unset, the default for python.d.plugin is used. # Attempts to restore the service are made once every update_every # and only if the module has collected values in the past. -# retries: 5 +# retries: 60 + +# autodetection_retry sets the job re-check interval in seconds. +# The job is not deleted if check fails. +# Attempts to start the job are made once every autodetection_retry. +# This feature is disabled by default. +# autodetection_retry: 0 # ---------------------------------------------------------------------- # JOBS (data collection sources) @@ -47,18 +53,20 @@ # predefined parameters. These are: # # job_name: -# name: myname # the JOB's name as it will appear at the -# # dashboard (by default is the job_name) -# # JOBs sharing a name are mutually exclusive -# update_every: 1 # the JOB's data collection frequency -# priority: 60000 # the JOB's order on the dashboard -# retries: 5 # the JOB's number of restoration attempts +# name: myname # the JOB's name as it will appear at the +# # dashboard (by default is the job_name) +# # JOBs sharing a name are mutually exclusive +# update_every: 1 # the JOB's data collection frequency +# priority: 60000 # the JOB's order on the dashboard +# retries: 60 # the JOB's number of restoration attempts +# autodetection_retry: 0 # the JOB's re-check interval in seconds # # Additionally to the above, smartd_log also supports the following: # -# log_path: '/path/to/smartdlogs' # path to smartd log files. Default is /var/log/smartd -# raw_values: no # raw or normalized values on charts. Default is normalized. -# smart_attributes: '1 2 3 4 44' # smart attributes charts. Default are ['1', '4', '5', '7', '9', '12', '193', '194', '197', '198', '200']. +# log_path: '/path/to/smartdlogs' # path to smartd log files. Default is /var/log/smartd +# raw_values: yes # enable/disable raw values charts. Enabled by default. +# smart_attributes: '1 2 3 4 44' # smart attributes charts. Default are ['1', '4', '5', '7', '9', '12', '193', '194', '197', '198', '200']. +# exclude_disks: 'PATTERN1 PATTERN2' # space separated patterns. If the pattern is in the drive name, the module will not collect data for it. # # ---------------------------------------------------------------------- # Additional information @@ -79,7 +87,4 @@ # Some raw numbers provide valuable insight when properly interpreted. These cases will be discussed later on. # Raw values are typically listed in hexadecimal numbers. The raw value has different structure for different vendors and is often not meaningful as a decimal number. # -# -# JOB configuration -# -log_path: '/var/log/smartd' +# ---------------------------------------------------------------------- diff --git a/conf.d/python.d/squid.conf b/conf.d/python.d/squid.conf index 27800bde..564187f0 100644 --- a/conf.d/python.d/squid.conf +++ b/conf.d/python.d/squid.conf @@ -31,7 +31,13 @@ # If unset, the default for python.d.plugin is used. # Attempts to restore the service are made once every update_every # and only if the module has collected values in the past. -# retries: 5 +# retries: 60 + +# autodetection_retry sets the job re-check interval in seconds. +# The job is not deleted if check fails. +# Attempts to start the job are made once every autodetection_retry. +# This feature is disabled by default. +# autodetection_retry: 0 # ---------------------------------------------------------------------- # JOBS (data collection sources) @@ -47,12 +53,13 @@ # predefined parameters. These are: # # job_name: -# name: myname # the JOB's name as it will appear at the -# # dashboard (by default is the job_name) -# # JOBs sharing a name are mutually exclusive -# update_every: 1 # the JOB's data collection frequency -# priority: 60000 # the JOB's order on the dashboard -# retries: 5 # the JOB's number of restoration attempts +# name: myname # the JOB's name as it will appear at the +# # dashboard (by default is the job_name) +# # JOBs sharing a name are mutually exclusive +# update_every: 1 # the JOB's data collection frequency +# priority: 60000 # the JOB's order on the dashboard +# retries: 60 # the JOB's number of restoration attempts +# autodetection_retry: 0 # the JOB's re-check interval in seconds # # Additionally to the above, squid also supports the following: # diff --git a/conf.d/python.d/tomcat.conf b/conf.d/python.d/tomcat.conf index ce89175f..c63f06cf 100644 --- a/conf.d/python.d/tomcat.conf +++ b/conf.d/python.d/tomcat.conf @@ -31,7 +31,13 @@ # If unset, the default for python.d.plugin is used. # Attempts to restore the service are made once every update_every # and only if the module has collected values in the past. -# retries: 5 +# retries: 60 + +# autodetection_retry sets the job re-check interval in seconds. +# The job is not deleted if check fails. +# Attempts to start the job are made once every autodetection_retry. +# This feature is disabled by default. +# autodetection_retry: 0 # ---------------------------------------------------------------------- # JOBS (data collection sources) @@ -47,12 +53,13 @@ # predefined parameters. These are: # # job_name: -# name: myname # the JOB's name as it will appear at the -# # dashboard (by default is the job_name) -# # JOBs sharing a name are mutually exclusive -# update_every: 1 # the JOB's data collection frequency -# priority: 60000 # the JOB's order on the dashboard -# retries: 5 # the JOB's number of restoration attempts +# name: myname # the JOB's name as it will appear at the +# # dashboard (by default is the job_name) +# # JOBs sharing a name are mutually exclusive +# update_every: 1 # the JOB's data collection frequency +# priority: 60000 # the JOB's order on the dashboard +# retries: 60 # the JOB's number of restoration attempts +# autodetection_retry: 0 # the JOB's re-check interval in seconds # # Additionally to the above, tomcat also supports the following: # diff --git a/conf.d/python.d/varnish.conf b/conf.d/python.d/varnish.conf index c25f3010..4b069d51 100644 --- a/conf.d/python.d/varnish.conf +++ b/conf.d/python.d/varnish.conf @@ -31,7 +31,13 @@ # If unset, the default for python.d.plugin is used. # Attempts to restore the service are made once every update_every # and only if the module has collected values in the past. -# retries: 5 +# retries: 60 + +# autodetection_retry sets the job re-check interval in seconds. +# The job is not deleted if check fails. +# Attempts to start the job are made once every autodetection_retry. +# This feature is disabled by default. +# autodetection_retry: 0 # ---------------------------------------------------------------------- # JOBS (data collection sources) @@ -47,11 +53,12 @@ # predefined parameters. These are: # # job_name: -# name: myname # the JOB's name as it will appear at the -# # dashboard (by default is the job_name) -# # JOBs sharing a name are mutually exclusive -# update_every: 1 # the JOB's data collection frequency -# priority: 60000 # the JOB's order on the dashboard -# retries: 5 # the JOB's number of restoration attempts -# +# name: myname # the JOB's name as it will appear at the +# # dashboard (by default is the job_name) +# # JOBs sharing a name are mutually exclusive +# update_every: 1 # the JOB's data collection frequency +# priority: 60000 # the JOB's order on the dashboard +# retries: 60 # the JOB's number of restoration attempts +# autodetection_retry: 0 # the JOB's re-check interval in seconds # +# ---------------------------------------------------------------------- diff --git a/conf.d/python.d/web_log.conf b/conf.d/python.d/web_log.conf index cd1f1af0..dd1fff07 100644 --- a/conf.d/python.d/web_log.conf +++ b/conf.d/python.d/web_log.conf @@ -31,7 +31,13 @@ # If unset, the default for python.d.plugin is used. # Attempts to restore the service are made once every update_every # and only if the module has collected values in the past. -# retries: 5 +# retries: 60 + +# autodetection_retry sets the job re-check interval in seconds. +# The job is not deleted if check fails. +# Attempts to start the job are made once every autodetection_retry. +# This feature is disabled by default. +# autodetection_retry: 0 # ---------------------------------------------------------------------- # JOBS (data collection sources) @@ -50,12 +56,13 @@ # predefined parameters. These are: # # job_name: -# name: myname # the JOB's name as it will appear at the -# # dashboard (by default is the job_name) -# # JOBs sharing a name are mutually exclusive -# update_every: 1 # the JOB's data collection frequency -# priority: 60000 # the JOB's order on the dashboard -# retries: 5 # the JOB's number of restoration attempts +# name: myname # the JOB's name as it will appear at the +# # dashboard (by default is the job_name) +# # JOBs sharing a name are mutually exclusive +# update_every: 1 # the JOB's data collection frequency +# priority: 60000 # the JOB's order on the dashboard +# retries: 60 # the JOB's number of restoration attempts +# autodetection_retry: 0 # the JOB's re-check interval in seconds # # Additionally to the above, web_log also supports the following: # diff --git a/conf.d/stream.conf b/conf.d/stream.conf index 0ae5ba67..8945529e 100644 --- a/conf.d/stream.conf +++ b/conf.d/stream.conf @@ -21,13 +21,13 @@ # # If many are given, the first available will get the metrics. # - # PROTOCOL = tcp or udp (only tcp is supported by masters) - # HOST = an IPv4, IPv6 IP, or a hostname. + # PROTOCOL = tcp, udp, or unix (only tcp and unix are supported by masters) + # HOST = an IPv4, IPv6 IP, or a hostname, or a unix domain socket path. # IPv6 IPs should be given with brackets [ip:address] - # INTERFACE = the network interface to use + # INTERFACE = the network interface to use (only for IPv6) # PORT = the port number or service name (/etc/services) # - # This communication is not HTTP (cannot be proxied by web proxies). + # This communication is not HTTP (it cannot be proxied by web proxies). destination = # The API_KEY to use (as the sender) @@ -56,26 +56,34 @@ # ----------------------------------------------------------------------------- # 2. ON MASTER NETDATA - THE ONE THAT WILL BE RECEIVING METRICS -# You can have one API key per slave, or the same API key for all slaves. +# You can have one API key per slave, +# or the same API key for all slaves. # # netdata searches for options in this order: # -# a) [MACHINE_GUID] section (settings for each machine) -# b) [API_KEY] section (settings for the API key) -# c) master netdata settings (netdata.conf) +# a) master netdata settings (netdata.conf) +# b) [API_KEY] section (below, settings for the API key) +# c) [MACHINE_GUID] section (below, settings for each machine) # # You can combine the above (the more specific setting will be used). # API key authentication -# If the key is not listed here, it will not be able to connect. +# If the key is not listed here, it will not be able to push metrics. +# [API_KEY] is [YOUR-API-KEY], i.e [11111111-2222-3333-4444-555555555555] [API_KEY] - # Default settings for the API key + # Default settings for this API key # You can disable the API key, by setting this to: no # The default (for unknown API keys) is: no enabled = no + # A list of simple patterns matching the IPs of the servers that + # will be pushing metrics using this API key. + # The metrics are received via the API port, so the same IPs + # should also be matched at netdata.conf [web].allow connections from + allow from = * + # The default history in entries, for all hosts using this API key. # You can also set it per host below. # If you don't set it here, the history size of the central netdata @@ -132,6 +140,13 @@ # Use only the API key for security. enabled = no + # A list of simple patterns matching the IPs of the servers that + # will be pushing metrics using this MACHINE GUID. + # The metrics are received via the API port, so the same IPs + # should also be matched at netdata.conf [web].allow connections from + # and at stream.conf [API_KEY].allow from + allow from = * + # The number of entries in the database history = 3600 diff --git a/configs.signatures b/configs.signatures index f22431c2..c23950c9 100644 --- a/configs.signatures +++ b/configs.signatures @@ -1,31 +1,40 @@ declare -A configs_signatures=( + ['00403e687213f3b7db9bf4563a5a92cc']='python.d/isc_dhcpd.conf' ['0056936ce99788ed9ae1c611c87aa6d8']='apps_groups.conf' + ['007fc019fb32e952b509d455c016a002']='health.d/tcp_resets.conf' ['0102351817595a85d01ebd54a5f2f36b']='python.d/ovpn_status_log.conf' ['01302e01162d465614276de43fad7546']='python.d.conf' + ['0147c7e8f8f57e37c5dade4e8aacacf9']='python.d/example.conf' + ['017036c1dc32c9312b2704b839bd078f']='python.d/haproxy.conf' ['01c54057e0ca55b5bb49df1662d6b8c3']='python.d/web_log.conf' ['02fa10fa85ab88e9723998de48d1aca0']='health.d/disks.conf' + ['0314f0f1f88773c0ed9e9a908335e7ca']='health.d/tcp_mem.conf' ['036dc300bd7b0e0ef229b9822686d63e']='python.d/isc_dhcpd.conf' ['0388b873d0d7e47c19005b7241db77d8']='python.d/tomcat.conf' ['04138a3d8e907c75329fe60ce2e27c1c']='health.d/tcp_resets.conf' ['0433d98a19d3b08e6f13884e46d39b47']='health.d/disks.conf' ['043f0a35dde85837fabeb85b990a41c1']='health.d/swap.conf' + ['044496086420b531487d3c57600ca673']='apps_groups.conf' ['0529b679d3c0e7e6332753c7f6484731']='health.d/net.conf' ['057d12aaff0467e64529e839a258806b']='health.d/entropy.conf' ['059d98d0c562e1c81653d1e64673deab']='python.d/web_log.conf' ['05a8f39f134850c1e8d6267dbe706273']='health.d/web_log.conf' ['061c45b0e34170d357e47883166ecf40']='python.d/nginx.conf' + ['074d618a7e9c72f9bdfda7611e01e0ca']='python.d/redis.conf' ['074df527cc70b5f38c0714f08f20e57c']='health.d/apache.conf' ['0787e67357804b934d2866f1b7c60b14']='health.d/ipc.conf' ['08042325ab27256b938575deafee8ecf']='python.d/nginx.conf' ['0847d54a7a0c7e0381c52e9d4d3fa7db']='health.d/mdstat.conf' ['084ee72d64760f2641b0720e79c922f3']='health.d/cpu.conf' ['0856124b1eecf01681b4fdf4e21efb3f']='health.d/net.conf' + ['0862e7cf3d32ef48795702c6aefd27e0']='python.d/fail2ban.conf' ['08ff5218f938fc48e09e718821169d14']='health.d/redis.conf' ['091572888425bc3b8b559c3c53367ec7']='apps_groups.conf' ['09225283977a6584f8063016091cc4f2']='health.d/tcp_resets.conf' ['09264cec953ae1c4c2985e6446abb386']='health.d/mysql.conf' ['093540fdc2a228e976ce5d48a3adf9fc']='health.d/disks.conf' ['09e030d26be08a13fa3560e47fa27825']='apps_groups.conf' + ['0a7039ecc7a86b480d9d499b12b02763']='python.d/freeradius.conf' ['0ad10fa896346202aee99384b0ec968d']='health.d/cpu.conf' ['0c5e0fa364d7bdf7c16e8459a0544572']='health.d/netfilter.conf' ['0cd4e1fb57497e4d4c2451a9e58f724d']='python.d/redis.conf' @@ -49,6 +58,7 @@ declare -A configs_signatures=( ['18710ef6523cef8630d644ab270bfe02']='health.d/varnish.conf' ['18ee1c6197a4381b1c1631ef6129824f']='apps_groups.conf' ['1972e48345e6c3f0d65f94a03317622b']='health_alarm_notify.conf' + ['1bc518219377499d1d05d6ee770f1a87']='python.d/go_expvar.conf' ['1c12b678ab65f271a96da1bbd0a1ab1c']='health.d/softnet.conf' ['1c3168c95b53e999df3d45162b3f50b8']='health.d/fping.conf' ['1c71a8792c5c0ed035dd97af93a04838']='health_alarm_notify.conf' @@ -57,6 +67,7 @@ declare -A configs_signatures=( ['1ea8e8ef1fa8a3a0fcdfba236f4cb195']='python.d/mysql.conf' ['1eb0bc80934a3166fcde4d153c476d14']='health.d/fping.conf' ['1ef0fd38e7969c023bc3fa6d89eaf6d6']='python.d/mdstat.conf' + ['1f43a9a820c02e0525de594299b55b15']='python.d.conf' ['1f5545b3ff52b3eb75ee05401f67a9bc']='fping.conf' ['1fa47f32ab52a22f8e7087cae85dd25e']='health.d/net.conf' ['203678a5be09d65993dcb3a9d475d187']='health.d/ipfs.conf' @@ -80,22 +91,31 @@ declare -A configs_signatures=( ['298504f331c55dff4055321ff3a7b5cc']='health.d/web_log.conf' ['29f97e10b92333790fbe0d2a3617b736']='health_alarm_notify.conf' ['2a0794fd43eadf30a51805bc9ba2c64d']='python.d/hddtemp.conf' + ['2acae80dbdbe536a160f5b216bac84bc']='python.d/samba.conf' ['2ad55a5d1e885cf142849a78d4b00401']='health.d/net.conf' ['2bbbebf52f84fd27fbefecd2a8a8076f']='health.d/memcached.conf' ['2c2b7e8df922b2bf121fb7db32bbc3bd']='health.d/udp_errors.conf' ['2d1d7498c72f4245cf32902c2b7e71e0']='health.d/entropy.conf' + ['2da0a2e7117292ece11d69723a294bd7']='python.d/mongodb.conf' + ['2ee5df033fe9c65a45566b6760b856e3']='python.d/web_log.conf' + ['2f05e09b69ea20cda56d8f8b6fd3e86d']='health.d/couchdb.conf' ['2f3a8e33df83f14e0af8ca2465697215']='python.d/exim.conf' ['2f4a85fedecce1bf425fa1039f6b021e']='apps_groups.conf' ['2fa8fb929fd597f2ab97b6efc540a043']='health_alarm_notify.conf' ['307ac41f6c67fcf007d6f7135fac314c']='stream.conf' ['312b4b8e2805e19cf9be554b319567d6']='health.d/softnet.conf' ['318bb45755726a25120bb33413d4b582']='health.d/net.conf' + ['318db50a701442890c269ab547041e97']='health.d/tcp_orphans.conf' ['325617412a628e3bc776e3fbb777a2a6']='health.d/redis.conf' ['326e1477131e0f73304711135f70a2a5']='health.d/memcached.conf' ['32fde0057c790964f2c743cb3c9aad29']='health.d/nginx.conf' + ['33486497112127badc4c47ed2008969c']='python.d/freeradius.conf' ['33b135e28aeaef2b8224ba69a0fde245']='health.d/cpu.conf' ['343bc919a2fbc93f687f9d1339ec5f79']='health.d/net.conf' + ['34f6cf10f8da18ddd7edd2a28a4fe5f9']='python.d/sensors.conf' ['35024ebd94542484c0866e6ee6b950cb']='health.d/net.conf' + ['35ac63a2f08b2c6dd901c542629ae5df']='python.d/postgres.conf' + ['35eb9785c844afd43fa7931915e2d566']='python.d/elasticsearch.conf' ['3634d5eddc46fb0d50cf47f370670c2c']='health.d/redis.conf' ['364b6e0081b116c9ec073b4d329a6dcc']='health_alarm_notify.conf' ['367d1463e520eb9dc89223bab161c6d1']='python.d/postgres.conf' @@ -108,11 +128,14 @@ declare -A configs_signatures=( ['3866efafd38e161136428d0f818cac43']='health.d/net.conf' ['38d1bf04fe9901481dd6febcc0404a86']='python.d.conf' ['39304b2570611c3acb35b72762b46778']='charts.d/sensors.conf' + ['394b7e91c97b7adb776460d309b335ff']='python.d/nginx.conf' ['39571e9fad9b759200c5d5b2ee13feb4']='python.d/redis.conf' + ['39b65042cafdd9b849a44ec81aa66cac']='health_alarm_notify.conf' ['39f9422b0f0c3eec11a31aff79d89514']='health.d/retroshare.conf' ['3a04a3bc66c49d0c24f65a44fd9caa80']='python.d/postgres.conf' ['3af522d65b50a5e447607ffb28c81ff5']='apps_groups.conf' ['3b1bfa40a4ff6a200bb2fc00bc51a664']='apps_groups.conf' + ['3b535da82cf2ff53e03d735d02fb2357']='python.d/squid.conf' ['3bc2776623889744a98178bad6fb3b79']='health.d/disks.conf' ['3bc65e997ab59b9de390fdf63d77f5e1']='python.d/postgres.conf' ['3c9c47163e9d4dbcb0079b6232398f2f']='apps_groups.conf' @@ -120,9 +143,11 @@ declare -A configs_signatures=( ['3cc6255457d4cba881ae0554ae5d9190']='health.d/squid.conf' ['3d974ac9fdaa44d4527d6503bec35e34']='stream.conf' ['3f170e3343cd784983b019163393f5af']='health.d/nginx.conf' + ['3fbe85671efd5d07e51584ab8262b48b']='health.d/tcp_listen.conf' ['3fc45cc18e884c22482524dff6d27833']='python.d/hddtemp.conf' ['3fcc3c449ce8e0388f9c23ca07cab608']='health.d/backend.conf' ['4063a01bffb43b0423425d1ba3004967']='health.d/tcp_resets.conf' + ['41fa6bb109763561be59d7bcd07bbe82']='python.d/dnsdist.conf' ['421d5dc6c2fce22d0816b6e6363bea57']='python.d/hddtemp.conf' ['42ad0e70b1365b6e7244cc305dbaa529']='health_alarm_notify.conf' ['42bf1c7c64ed77038a0aa094d792a9e2']='python.d/mysql.conf' @@ -140,6 +165,7 @@ declare -A configs_signatures=( ['48eef63bcf744bae114b502b6dacb4a1']='charts.d/phpfpm.conf' ['4960852f8951b54ca2fe10065752143e']='python.d.conf' ['4a448831776de8acf2e0bdc4cc994cb4']='apps_groups.conf' + ['4aba3b6a28ccd75faf5326aca997ee0d']='health_alarm_notify.conf' ['4b775fb31342f1478b3773d041a72911']='python.d.conf' ['4ccb06fff1ce06dc5bc80e0a9f568f6e']='charts.d.conf' ['4cd585f5dfdacaf287413ad037b4e60a']='apps_groups.conf' @@ -157,6 +183,7 @@ declare -A configs_signatures=( ['5120492fa26be3749192607f62dc05f8']='health.d/mdstat.conf' ['5271cf9fc0fd10915a9759add70f7d78']='health.d/swap.conf' ['5278ebbae19c60db600f0a119cb3664e']='python.d/apache.conf' + ['52d230aff57850a5aacc4e0420fcd8f5']='python.d.conf' ['52d4131cf9df84e2550b1a5d899ec61d']='health.d/swap.conf' ['53160707fdc6ce46c195b1b55bb0bcb1']='health.d/swap.conf' ['535e5113b07b0fc6f3abd59546c276f6']='charts.d.conf' @@ -164,12 +191,14 @@ declare -A configs_signatures=( ['5452eccad2f220d1191411737f6f4b2b']='python.d/isc_dhcpd.conf' ['54614490a14e1a4b7b3d9fecb6b4cfa5']='python.d/exim.conf' ['547779cdc460a926980de1590294b96b']='health.d/softnet.conf' + ['54c3934a03453453b8d7d0e8b84a7cd8']='health_alarm_notify.conf' ['55608bdd908a3806df1468f6ee318b2b']='health.d/qos.conf' ['5598b83e915e31f68027afe324a427cd']='apps_groups.conf' ['565f11c38ae6bd5cc9d3c2adb542bc1b']='health.d/softnet.conf' ['5664a814f9351b55da76edd472169a73']='health_alarm_notify.conf' ['56b689031cdcf138064825f31474b37d']='apps_groups.conf' ['573398335c0c71c075fa57f702bce287']='health.d/disks.conf' + ['57be306944cb09b7f024079728fd04b9']='apps_groups.conf' ['5829812db29598db5857c9f433e96fef']='python.d/apache.conf' ['5855dd70d71c8497e5591b0690162c9c']='health.d/tcp_resets.conf' ['58e835b7176865ec5a6f59f7aba832bf']='health.d/named.conf' @@ -179,6 +208,7 @@ declare -A configs_signatures=( ['5bbef0708f5eff4d4a53aaf35fc48a62']='health.d/disks.conf' ['5bf51bb24fb41db9b1e448bd060d3f8c']='apps_groups.conf' ['5da15d6e17a15213a720749045e5d419']='health.d/disks.conf' + ['5dddb6c9670f4aa605abe4b0d901acc4']='python.d/bind_rndc.conf' ['5e6fd588ef6934cf04ddb5e662aa02ea']='health.d/postgres.conf' ['5eb670b6fe39da5fec2523d910b0dd1e']='health.d/cpu.conf' ['5f05d4b248ab2637ada319b4e8c4e4c3']='python.d/varnish.conf' @@ -205,12 +235,12 @@ declare -A configs_signatures=( ['669ebef43ee341f6889d382e86d0e200']='health.d/named.conf' ['66dfe138058ca26a31a118007eb31f35']='health.d/nginx.conf' ['6814b9bc84483db428f6a479ba221855']='python.d/mysql.conf' + ['68607aef1802ed3dc0cd593bf6073beb']='python.d/postfix.conf' ['6a18f61a595c0d48c3363bcc0dbfa6b9']='health_alarm_notify.conf' ['6a47af861ad3dd112124c37fbf09672b']='apps_groups.conf' ['6aa4507f86657383917a0407f2a9cc0d']='python.d.conf' ['6acad8ce5c33e642742825db0eb9bb56']='python.d/web_log.conf' ['6b39de5d85db45115db236347a6896d4']='health.d/named.conf' - ['6b917300747e7e8314844237e2462261']='python.d/apache_cache.conf' ['6bb278bd9e171c4cb5c0fe639231288b']='python.d/web_log.conf' ['6bf0de6e3b251b765b10a71d8c5c319d']='python.d/apache.conf' ['6c9f2f0abe49a6f1a69db052ebcef1bf']='python.d/elasticsearch.conf' @@ -222,6 +252,7 @@ declare -A configs_signatures=( ['707a63f53f4b32e01d134ae90ba94aad']='health_alarm_notify.conf' ['707a63f53f4b32e01d134ae90ba94aad']='health_email_recipients.conf' ['70d82dabecb09a1da4684f293abef0c9']='health_alarm_notify.conf' + ['7117b7067ac2b712aa4c9e92a6cdbf5a']='python.d/couchdb.conf' ['7120cba2f55b1c0a97a0e10d4f6ef751']='health.d/ipmi.conf' ['729b3e24a72f7d566fd429617d51a21b']='health.d/web_log.conf' ['73125ae64d5c6e9361944cd9bd14844e']='python.d/exim.conf' @@ -229,10 +260,13 @@ declare -A configs_signatures=( ['73a8e10dfe4183aca751e9e2a80dabe3']='node.d.conf' ['7454ed74511d7b9819dfe173f9020786']='python.d/redis.conf' ['749fe31362969d75f1ea66d15231d98d']='python.d/retroshare.conf' + ['74e5e8d3a4b324f1770f61f78ee4b0e6']='health.d/beanstalkd.conf' ['7502c931aa9acbb92f54c67978d75983']='stream.conf' + ['751f15371d0987018abc4d4ad60819f5']='apps_groups.conf' ['7596ae54d46ce199ac599429ef753caf']='health.d/cpu.conf' ['75a9c4b0b1c73956df55585eb0619f6c']='charts.d/ap.conf' ['769aa4cdcdc3d78d0328d1f9e4edcdf9']='python.d/mysql.conf' + ['76a0c1b21e49850442a43efddb15a81e']='health.d/tcp_orphans.conf' ['777f4da70f461ef675bde07fb3644312']='python.d/redis.conf' ['777f55a95c5c25cf6176fece1ebbf4b8']='apps_groups.conf' ['7808ba2ca26bd0642270740cf6a8ee59']='charts.d/mem_apps.conf' @@ -256,6 +290,7 @@ declare -A configs_signatures=( ['80f109ff293ac94222bf3959432751bd']='health.d/qos.conf' ['81255035f6d53534938085df72cdef23']='health.d/nginx.conf' ['8170ba3ae507cf9322bd60350348552e']='health.d/net.conf' + ['81af92c7050873c7de2fb42e0c3f04f4']='python.d/tomcat.conf' ['81fd16f29d5f3d422fe1cee82dc8ed9d']='health.d/cpu.conf' ['8213d921b6a8382e27052fb42d81db3d']='python.d/freeradius.conf' ['8214bb8f4b005aa4691fcd38f7331e8f']='health.d/swap.conf' @@ -266,8 +301,10 @@ declare -A configs_signatures=( ['845023f9b4a526aa0e6493756dbe6034']='health.d/squid.conf' ['846ce94bfeeb90c0dc6a89e8d25f1a68']='health.d/named.conf' ['8490f690d97adacc4e2096df82e7e8a5']='charts.d/cpufreq.conf' + ['87155bea7383028b0c1846c802cfdd81']='python.d/mdstat.conf' ['871bbeea33b83ea9755600b6d574919c']='python.d/web_log.conf' ['87224d2f2b87646f3c0d38cc1eb30112']='python.d/nsd.conf' + ['87615ae5ac2412d853c717383fa53781']='python.d/chrony.conf' ['87642c568093daf3b2c30c5beffe2225']='python.d/elasticsearch.conf' ['8810140ce9c09af1d18b9602c4003904']='health_alarm_notify.conf' ['88f77865f75c9fb61c97d700bd4561ee']='python.d/mysql.conf' @@ -276,21 +313,30 @@ declare -A configs_signatures=( ['89fb3cbb223be4fa0cb676cfa3b07055']='health.d/backend.conf' ['8a1b95d375992d7b11330a0ac46f369c']='health.d/disks.conf' ['8a66a3085ad8892a002ff39b18b2cb07']='python.d/fail2ban.conf' + ['8abc7f66746b201b5b0af45c419d53bc']='health.d/bind_rndc.conf' ['8c1d41e2c88aeca78bc319ed74c8748c']='python.d/phpfpm.conf' ['8d0552371a7c9725a04196fa560813d1']='health.d/cpu.conf' ['8d24873bb25c195026918f15626310ea']='health.d/softnet.conf' ['8dc0bd0a70b5117454bd5f5b98f91c2c']='health.d/disks.conf' + ['8ec636a4f96158044d2cec0fd1ff8452']='python.d/rabbitmq.conf' ['8f4f925c1e97dd164007495ec5135ffc']='health.d/fping.conf' ['8f7b734ea0f89abf8acbb47c50234477']='health.d/web_log.conf' ['8fd472a854b0996327e8ed3562161182']='health_alarm_notify.conf' ['919911d13901d60a7580f5dfd7fc87bb']='health.d/ram.conf' + ['91c377e7d26a1120cfbbd488332f0398']='python.d/dns_query_time.conf' ['91c757ef6be3abdb86906d9dbb9c217a']='fping.conf' ['91cf3b3d42cac969b8b3fd4f531ecfb3']='python.d/squid.conf' ['91e1a9703debbdc64edf124419fdc14b']='python.d/elasticsearch.conf' + ['91f0a626c19f76241cadf9dbf28fb5a7']='health.d/beanstalkd.conf' + ['92024bbe088e55251665fb666305ff66']='python.d/mysql.conf' + ['920574fcfe56d5c9c11a583905e9db62']='health.d/tcp_conn.conf' ['9347bcce0b3574ac5193d43248d2e3cc']='python.d/chrony.conf' + ['94bb961f83ec724cf86239328f73a3db']='health.d/redis.conf' ['9542f80def48ba105190f6cdaa18248e']='health.d/mysql.conf' + ['978daf0777ffe774e5a9576d33972e97']='python.d/smartd_log.conf' ['97eee7a30e6419df4537242e9d4a719d']='health.d/mysql.conf' ['97f337eb96213f3ede05e522e3743a6c']='python.d/memcached.conf' + ['98e4dd6ba71bf76767bc59c63a51b617']='apps_groups.conf' ['99a3de85d1e7826ed64a5f8576712e5d']='python.d.conf' ['99b06e68f1da5917ae4cf60e901439f6']='health.d/ram.conf' ['99b6030ce25c8fee4598179c0f95fb0b']='health.d/redis.conf' @@ -300,6 +346,7 @@ declare -A configs_signatures=( ['9c0185ceff15415bc59b2ce2c1f04367']='apps_groups.conf' ['9c8ddfa810d83ae58c8614ee5229e66b']='health.d/disks.conf' ['9c981c75bdf4b1637f7113e7e45eb2bf']='health.d/memcached.conf' + ['9d304e41e32721224a743f25534263d9']='python.d/retroshare.conf' ['9e0553ebdc21b64295873fc104cfa79d']='python.d.conf' ['9eb3326ae2ee9badeaad31d8dd2eaa2b']='python.d/isc_dhcpd.conf' ['a02d14124b19c635c1426cee2e98bac5']='charts.d.conf' @@ -308,7 +355,10 @@ declare -A configs_signatures=( ['a0b3a12389c9c56dfe35964b20b59836']='health.d/bind_rndc.conf' ['a0c0ef7ca9671f4b5e797d4276e5c0dd']='health.d/disks.conf' ['a0ee8f351f213c0e8af9eb7a4a09cb95']='apps_groups.conf' + ['a1b53a225f225911cd8ac892bba8118b']='python.d/powerdns.conf' ['a1b6dfe312b896b0b1ba471e8ac07f95']='python.d/isc_dhcpd.conf' + ['a1bb5823c4926b65ef4b2dae467fc847']='python.d/couchdb.conf' + ['a250e12f1ab4c18796fdaff5b0ba8968']='python.d/varnish.conf' ['a2944a309f8ce1a3195451856478d6ae']='python.d.conf' ['a2a647dc492dc2d6ed1f5c0fdc97a96e']='python.d/mongodb.conf' ['a305b400378d6492efd15f9940c2779b']='health.d/softnet.conf' @@ -321,6 +371,7 @@ declare -A configs_signatures=( ['a5134d7cfbe27f5791e788c2add51abb']='apps_groups.conf' ['a55133f1b0be0a4255057849dd451b09']='health_alarm_notify.conf' ['a6d5ce2572bf7a1dce9e545fcd29273e']='health.d/apache.conf' + ['a70e14bda17b076d2486232355652ae6']='apps_groups.conf' ['a71d9082410200bf92e823675d78121c']='python.d/retroshare.conf' ['a731b7b164f42717c1c9a778ee637ff3']='health.d/memcached.conf' ['a7320c6f26191b9599ec3bc4be007a93']='health.d/swap.conf' @@ -331,6 +382,7 @@ declare -A configs_signatures=( ['a89c516a1144435a88decf25509318ac']='health_alarm_notify.conf' ['a8bb4e1d0525f59692778ad8f675a77a']='python.d/example.conf' ['a8feb36776005bf419c90278787a1be8']='health.d/entropy.conf' + ['a9150a0c61e1b360cf8c265ea2413d02']='python.d/couchdb.conf' ['a94af1c808aafdf00537d85ff2197ec8']='python.d/exim.conf' ['a9ab68845db2fb695b7060273a6ac68e']='health_alarm_notify.conf' ['a9cd91675467c5426f5b51c47602c889']='apps_groups.conf' @@ -345,6 +397,7 @@ declare -A configs_signatures=( ['ad15b251b93f8b16bb33ec508f44a598']='health.d/netfilter.conf' ['ade389c1b6efe0cff47c33e662731f0a']='python.d/squid.conf' ['ae5ac0a3521e50aa6f6eda2a330b4075']='python.d/example.conf' + ['aee501b7f9b122b962521c45893371bb']='python.d/smartd_log.conf' ['af12051cf57dd4e484ef8e64502b7549']='health.d/net.conf' ['af14667ee7993acea810f6d50923bdc9']='health.d/web_log.conf' ['af44cc53aa2bc5cc8935667119567522']='python.d.conf' @@ -354,11 +407,14 @@ declare -A configs_signatures=( ['b0f0a0ac415e4b1a82187b80d211e83b']='python.d/mysql.conf' ['b181dcca01a258d9792ad703583baed2']='statsd.d/example.conf' ['b185914d4f795e1732273dc4c7a35845']='health.d/memory.conf' + ['b210982cac9accfe43173cef5f46b361']='health.d/beanstalkd.conf' ['b27f10a38a95edbbec20f44a4728b7c4']='python.d.conf' + ['b28c77dceeb398ca4ceec44c646f5431']='stream.conf' ['b32164929eda7449a9677044e11151bf']='python.d.conf' ['b3d48935ab7f44a57d40ad349df0033d']='python.d/postgres.conf' ['b3fc4749b132e55ac0d3a0f92859237e']='health.d/tcp_resets.conf' ['b4825f731cc7eb03b374eade14a453c1']='health.d/net.conf' + ['b5246eed059e33e0903a819fa5460ce0']='python.d/ipfs.conf' ['b5b5a8d6d991fb1cef8d80afa23ba114']='python.d/cpufreq.conf' ['b636e5e603f9d93e52c7577ac8c6bf0c']='health.d/entropy.conf' ['b68706bb8101ef85192db92f865a5d80']='health_alarm_notify.conf' @@ -368,11 +424,13 @@ declare -A configs_signatures=( ['b81b8f331161b0d48e03f6fbf6b6d062']='health.d/memcached.conf' ['b846ca1f99fa6a65303b58186f47d7a4']='python.d/squid.conf' ['b8969be5b3ceb4a99477937119bd4323']='python.d.conf' + ['b8aff60806fb6829a4e72a824e655375']='health.d/beanstalkd.conf' ['b8b87574fd496a66ede884c5336493bd']='python.d/phpfpm.conf' ['b915126262d08aa9da81de539a58a3fb']='python.d/redis.conf' ['ba11ea2d2f632b2de4b1224bcdc54f07']='python.d/smartd_log.conf' ['bb51112d01ff20053196a57632df8962']='apps_groups.conf' ['bba2f3886587f137ea08a6e63dd3d376']='python.d.conf' + ['bcaba2347951b301127fd502a219b26a']='python.d/apache.conf' ['bcd94c4fa2f89c710ff807de061ab11c']='health.d/net.conf' ['bda5517ea01640cfdfa0a27549619d6a']='health.d/memcached.conf' ['bf66f113b2dd8d8fb444cbd5650f284c']='health_alarm_notify.conf' @@ -380,8 +438,11 @@ declare -A configs_signatures=( ['c080e006f544c949baca33cc24a9c126']='health_alarm_notify.conf' ['c132d2e257fc4df2925be7ad75100d5b']='health.d/entropy.conf' ['c1a7e634b5b8aad523a0d115a93379cd']='health.d/memcached.conf' + ['c1d014ffaebfa0952968aeaf330e5337']='python.d.conf' + ['c30ee008173ba9f77adfcacbf138143e']='python.d/ovpn_status_log.conf' ['c3296c08260bcd556e74711c820817be']='health.d/cpu.conf' ['c3661b68232e06de90bb5e63e725b8b6']='health_alarm_notify.conf' + ['c45ab106725e94615bccf8be4b136d0f']='python.d.conf' ['c61948101e0e6846679682794ee48c5b']='python.d/nginx.conf' ['c6403d8b1bcfa52d3abb941be155fc03']='python.d.conf' ['c6b9f31e14adca433f82054f62388c47']='python.d/web_log.conf' @@ -399,23 +460,31 @@ declare -A configs_signatures=( ['cb60badf376d246ad8ec9d3f524db430']='health.d/disks.conf' ['cb7f80cd2768c649d7448e01f8aa6579']='python.d.conf' ['cc4d31a0d1ff9c339892c1f8a0c5fcd3']='charts.d/load_average.conf' + ['cca26b4d2384043f1737e0ed4a995600']='python.d/bind_rndc.conf' ['ccde91d209aeb02c4a6be0e43a8d92b3']='health.d/apache.conf' ['cd08e5534c94bf1f2cd28396c76b8bbc']='health.d/ram.conf' + ['cd9a7de356d6424c4a71d87053726c86']='python.d/bind_rndc.conf' ['cdd504812ff93073c57d02209d4d0f69']='health.d/cpu.conf' ['ce2e8768964a936f58c4c2144aee8a01']='health_alarm_notify.conf' ['ce3b65eac6c472b21905f7f72104f4c9']='python.d/nginx.conf' ['cf48dfd828af70bea04db7a809f94358']='health.d/haproxy.conf' + ['cf8b87ede2d3233b6f55f4690af7fb08']='python.d/smartd_log.conf' ['cfecf298bdafaa7e0a3a263548e82132']='python.d/sensors.conf' ['d11711b3647bc2bdd0292dd7deebbeb1']='health.d/net.conf' ['d1596fe068c8674efade49a4a8e22b5d']='health.d/isc_dhcpd.conf' ['d162b7465a56151312e60151c1d74fba']='health.d/squid.conf' ['d1e79707cd9b51a14288e8dd40694fcc']='fping.conf' + ['d297104e43ce2b544003271181e26ff6']='python.d/cpufreq.conf' ['d29c5fa5faf74b86d01c2270a79388d8']='health.d/disks.conf' ['d2b2ad30e277a69d8713e620dabc18bc']='python.d/phpfpm.conf' + ['d3f397ead7f2ac8f88a99d7c5b8cff1d']='python.d/dovecot.conf' + ['d4adcebadc4c86332df247922b85aadc']='python.d/freeradius.conf' ['d55bdb83b9ff606852f6a97c1430258c']='health.d/ram.conf' ['d55be5bb5e108da1e7645da007c53cd4']='python.d.conf' + ['d56c28ece8354850011f213d94d02fe0']='python.d/hddtemp.conf' ['d5dab509d8792f795bece27de39dd476']='health.d/mysql.conf' ['d69eba15d3e968187a938a7b98e22dda']='python.d.conf' + ['d712df81b17971884443a4a9bc996c9e']='health_alarm_notify.conf' ['d74dc63fbe631dab9a2ff1b0f5d71719']='python.d/hddtemp.conf' ['d7e0bd12d4a60a761dcab3531a841711']='python.d/phpfpm.conf' ['d8dc489e32f7114c6298fce94e86a8ef']='health.d/entropy.conf' @@ -426,6 +495,7 @@ declare -A configs_signatures=( ['dad303c5cca7a69345811a01a74f5892']='health.d/net.conf' ['dc0d2b96378f290eec3fcf98b89ad824']='python.d/cpufreq.conf' ['dc9c2a66778623a759706c14c3d91983']='health.d/net.conf' + ['dd220677c42c487549952048ee1f7750']='python.d/postgres.conf' ['dd7764507804a2296bfd091a58ad4ad7']='health.d/memcached.conf' ['dd8254ef74509a3e38cb2838e30f7e63']='health.d/disks.conf' ['ddda2bb1c88be03b637d3285406f7910']='health.d/named.conf' @@ -438,9 +508,10 @@ declare -A configs_signatures=( ['dfd5431b11cf2f3852a40d390c1d5a92']='python.d/varnish.conf' ['e0242003fd2e3f9ac1b9314e802ada79']='python.d/hddtemp.conf' ['e0ba3bc216ffc9933b4741dbb6b1f8c8']='health.d/web_log.conf' - ['e0e96cc47ed61d6492416be5236cd4d3']='python.d/apache_cache.conf' ['e0ffc0c34424b35666fddf7f61e05def']='health.d/tcp_resets.conf' + ['e100d98f3ed1eff59678f035b3b8daf2']='python.d/beanstalk.conf' ['e1a8bf99d36683c10225100f207a2b59']='python.d/web_log.conf' + ['e22f30680148a29d9738bd4bfe8b252c']='health_alarm_notify.conf' ['e2f3388c06726154c10ec22bad5bc7ec']='fping.conf' ['e3023092e3b2bbb5351e0fe6682f4fe9']='health_alarm_notify.conf' ['e3112d8e06fa77888aab02e8fcd22e25']='apps_groups.conf' @@ -451,8 +522,10 @@ declare -A configs_signatures=( ['e449e5582279742496550df14b6fca95']='health.d/entropy.conf' ['e4ed13f996434ac17b40a2228c96283b']='python.d/tomcat.conf' ['e5f32f54d6d6728f21f9ac26f37d6573']='python.d/example.conf' + ['e70a7ee4999f30c6ceb75f31088a3a34']='python.d/powerdns.conf' ['e734c5951a8764d4d9de046dd7cf7407']='health.d/softnet.conf' ['e7bc22a1942cffbd2b1b0cfd119ee328']='health.d/ipfs.conf' + ['e8656d72dbd3b6fe603048ded751499a']='python.d/memcached.conf' ['e8ec8046c7007af6ca3e8c51e62c99f8']='health.d/disks.conf' ['ea031c1c0c36edee3bd08fae559c4203']='health_alarm_notify.conf' ['ea1a96c42ad464c354fb250e3408c3e8']='stream.conf' @@ -461,9 +534,11 @@ declare -A configs_signatures=( ['eb748d6fb69d11b0d29c5794657e206c']='health.d/qos.conf' ['eb9fedc3c1dface77312d9bf48f673a8']='stream.conf' ['ebd0612ccc5807524ebb2b647e3e56c9']='apps_groups.conf' + ['ecb6c01fae255d369748406945a50435']='apps_groups.conf' ['ecd3aa97e2581f88eb466d6612690ef2']='charts.d/nginx.conf' ['ed43efac299c31f8fd5e2abccff30071']='python.d/samba.conf' ['ed80e6b2cfc8b08adea7027fc03daa68']='python.d.conf' + ['edb48efc8f446624001e07d04f6cad1a']='apps_groups.conf' ['ee5343881744e6a97e6ee5cdd329cfb8']='health.d/retroshare.conf' ['ef1861bf5725d91e773cbdba05687597']='python.d.conf' ['ef9916ea144878a9f37cbb6b1b29da10']='health.d/squid.conf' @@ -471,26 +546,34 @@ declare -A configs_signatures=( ['f0a86c5bae3c4b32b266dacbf74ca4a3']='python.d/web_log.conf' ['f1446cb3f1a905ee06defa2aa15ee806']='python.d/web_log.conf' ['f1682835e3414f60284c13bf1662e50f']='health.d/web_log.conf' + ['f1f114647ed185c4812c361b1d870b44']='python.d/sensors.conf' ['f2f1b8656f5011e965ac45b818cf668d']='apps_groups.conf' + ['f42389e5497a28205ba6fef4f716db4f']='python.d/nginx.conf' ['f42df9f13abfae2426519c6728b34882']='charts.d/example.conf' ['f4c5d88c34d3fb853498124177cc77f1']='python.d.conf' ['f5736e0b2945182cb659cb0713eff923']='apps_groups.conf' ['f66e5236ba1245bb2e5fd99191f114c6']='charts.d/hddtemp.conf' + ['f68ac0fca6b4ffc96097779344cabac6']='health.d/tcp_listen.conf' ['f6c6656f900ff52d159dca12d624016a']='python.d/postgres.conf' ['f7401a6e7c7d4fe2e0e2be7f7f523275']='health.d/web_log.conf' ['f7a99e94231beda85c6254912d8d31c1']='python.d/tomcat.conf' ['f82924563e41d99cdae5431f0af69155']='python.d.conf' ['f8c30f22df92765e2c0fab3c8174e2fc']='health.d/memcached.conf' ['f8dade4484f1b6a48655388502df7d5a']='health_alarm_notify.conf' + ['f8e7d23a83fc8ee58f403da7bdbe7f8a']='python.d/phpfpm.conf' ['f96acba4b14b0c1b50d0187a04416151']='health_alarm_notify.conf' ['f9be549a849d023595d19d5d74263e0f']='health.d/tcp_resets.conf' ['fa4396513b358d6ec6a7f5bfb08439b8']='health.d/net.conf' + ['fb1c75159f855f4b4671835f5bca1ef6']='python.d.conf' ['fbdb6f5d3906d3d8ea4e28f6ba6965a6']='python.d/go_expvar.conf' + ['fc11bd9255ac382f442f31c1f1a32532']='health_alarm_notify.conf' ['fc40b83f173bc4676d686867a8369a62']='python.d/dns_query_time.conf' + ['fc987459f82e251e31c41d822e5e8202']='python.d/nsd.conf' ['fd3164e6e8cb6726706267eae49aa082']='health_alarm_notify.conf' ['fdd11640ba626cc2064c2fe3ea3eee4c']='health.d/cpu.conf' ['fde44f62c8d7e52f09705cd273fae6b1']='charts.d/tomcat.conf' ['fdea185e0e52b459b48852aa37f20e0f']='apps_groups.conf' + ['fe069e4d6579ecdda7f36ac2318ffefc']='python.d/exim.conf' ['fe478efe2e721724edb1fe2ef1addf93']='health_alarm_notify.conf' ['feb8bcf828aa2529a7ee4a140feeb12d']='health.d/net.conf' ['ff1b3d8ae8b2149c711d8da9b7a9c4bd']='health_alarm_notify.conf' @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for netdata 1.8.0. +# Generated by GNU Autoconf 2.69 for netdata 1.9.0. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. @@ -577,8 +577,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='netdata' PACKAGE_TARNAME='netdata' -PACKAGE_VERSION='1.8.0' -PACKAGE_STRING='netdata 1.8.0' +PACKAGE_VERSION='1.9.0' +PACKAGE_STRING='netdata 1.9.0' PACKAGE_BUGREPORT='' PACKAGE_URL='' @@ -1374,7 +1374,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures netdata 1.8.0 to adapt to many kinds of systems. +\`configure' configures netdata 1.9.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1444,7 +1444,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of netdata 1.8.0:";; + short | recursive ) echo "Configuration of netdata 1.9.0:";; esac cat <<\_ACEOF @@ -1587,7 +1587,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -netdata configure 1.8.0 +netdata configure 1.9.0 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2365,7 +2365,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by netdata $as_me 1.8.0, which was +It was created by netdata $as_me 1.9.0, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2746,7 +2746,7 @@ $as_echo "$as_me: ***************** MAINTAINER MODE *****************" >&6;} PACKAGE_BUILT_DATE=$(date '+%d %b %Y') fi -PACKAGE_RPM_VERSION="1.8.0" +PACKAGE_RPM_VERSION="1.9.0" @@ -3273,7 +3273,7 @@ fi # Define the identity of the package. PACKAGE='netdata' - VERSION='1.8.0' + VERSION='1.9.0' cat >>confdefs.h <<_ACEOF @@ -8525,7 +8525,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by netdata $as_me 1.8.0, which was +This file was extended by netdata $as_me 1.9.0, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -8591,7 +8591,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -netdata config.status 1.8.0 +netdata config.status 1.9.0 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index 16381f8d..b8a0699b 100644 --- a/configure.ac +++ b/configure.ac @@ -4,7 +4,7 @@ AC_PREREQ(2.60) define([VERSION_MAJOR], [1]) -define([VERSION_MINOR], [8]) +define([VERSION_MINOR], [9]) define([VERSION_FIX], [0]) define([VERSION_NUMBER], VERSION_MAJOR[.]VERSION_MINOR[.]VERSION_FIX) define([VERSION_SUFFIX], []) diff --git a/contrib/debian/changelog b/contrib/debian/changelog deleted file mode 100644 index 479a2020..00000000 --- a/contrib/debian/changelog +++ /dev/null @@ -1,3 +0,0 @@ -netdata (1.8.0) UNRELEASED; urgency=medium - * Latest release - -- Netdata Team <> Sun, 17 Sep 2017 17:00:08 +0000 diff --git a/contrib/debian/compat b/contrib/debian/compat deleted file mode 100644 index ec635144..00000000 --- a/contrib/debian/compat +++ /dev/null @@ -1 +0,0 @@ -9 diff --git a/contrib/debian/control b/contrib/debian/control deleted file mode 100644 index 24c5f4c4..00000000 --- a/contrib/debian/control +++ /dev/null @@ -1,25 +0,0 @@ -Source: netdata -Build-Depends: debhelper (>= 9), - dh-autoreconf, - dh-systemd (>= 1.5), - dpkg-dev (>= 1.13.19), - zlib1g-dev, - uuid-dev -Section: net -Priority: optional -Maintainer: Costa Tsaousis <costa@tsaousis.gr> -Standards-Version: 3.9.6 -Homepage: https://github.com/firehol/netdata/wiki - -Package: netdata -Architecture: any -Depends: adduser, - libcap2-bin (>= 1:2.0), - lsb-base (>= 3.1-23.2), - ${misc:Depends}, - ${shlibs:Depends} -Description: real-time charts for system monitoring - Netdata is a daemon that collects data in realtime (per second) - and presents a web site to view and analyze them. The presentation - is also real-time and full of interactive charts that precisely - render all collected values. diff --git a/contrib/debian/control.wheezy b/contrib/debian/control.wheezy deleted file mode 100644 index 4103908a..00000000 --- a/contrib/debian/control.wheezy +++ /dev/null @@ -1,25 +0,0 @@ -Source: netdata -Build-Depends: debhelper (>= 9), - dh-autoreconf, - pkg-config, - dpkg-dev (>= 1.13.19), - zlib1g-dev, - uuid-dev -Section: net -Priority: optional -Maintainer: Costa Tsaousis <costa@tsaousis.gr> -Standards-Version: 3.9.6 -Homepage: https://github.com/firehol/netdata/wiki - -Package: netdata -Architecture: any -Depends: adduser, - libcap2-bin (>= 1:2.0), - lsb-base (>= 3.1-23.2), - ${misc:Depends}, - ${shlibs:Depends} -Description: real-time charts for system monitoring - Netdata is a daemon that collects data in realtime (per second) - and presents a web site to view and analyze them. The presentation - is also real-time and full of interactive charts that precisely - render all collected values. diff --git a/contrib/debian/copyright b/contrib/debian/copyright deleted file mode 100644 index 11a3d639..00000000 --- a/contrib/debian/copyright +++ /dev/null @@ -1,10 +0,0 @@ -Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ -Upstream-Name: Netdata -Upstream-Contact: Costa Tsaousis <costa@tsaousis.gr> -Source: https://github.com/firehol/netdata - -Files: * -Copyright: 2014-2016, Costa Tsaousis -License: GPL-3+ - On Debian systems, the complete text of the GNU General Public - License version 3 can be found in /usr/share/common-licenses/GPL-3. diff --git a/contrib/debian/netdata.conf b/contrib/debian/netdata.conf deleted file mode 100644 index a963d80b..00000000 --- a/contrib/debian/netdata.conf +++ /dev/null @@ -1,16 +0,0 @@ -# NetData Configuration - -# The current full configuration can be retrieved from the running -# server at the URL -# -# http://localhost:19999/netdata.conf -# -# for example: -# -# wget -O /etc/netdata/netdata.conf http://localhost:19999/netdata.conf -# - -[global] - run as user = netdata - web files owner = root - web files group = netdata diff --git a/contrib/debian/netdata.default b/contrib/debian/netdata.default deleted file mode 100644 index 9e7f8ae6..00000000 --- a/contrib/debian/netdata.default +++ /dev/null @@ -1,5 +0,0 @@ -# Extra arguments to pass to netdata -# -#EXTRA_OPTS="" -#uncomment following line if you are building a wheezy-package -#EXTRA_OPTS="-P /var/run/netdata.pid" diff --git a/contrib/debian/netdata.docs b/contrib/debian/netdata.docs deleted file mode 100644 index 56631abf..00000000 --- a/contrib/debian/netdata.docs +++ /dev/null @@ -1 +0,0 @@ -ChangeLog diff --git a/contrib/debian/netdata.init b/contrib/debian/netdata.init deleted file mode 100755 index c1b2b74d..00000000 --- a/contrib/debian/netdata.init +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/sh -# Start/stop the netdata daemon. -# -### BEGIN INIT INFO -# Provides: netdata -# Required-Start: $remote_fs -# Required-Stop: $remote_fs -# Should-Start: $network -# Should-Stop: $network -# Default-Start: 2 3 4 5 -# Default-Stop: -# Short-Description: Real-time charts for system monitoring -# Description: Netdata is a daemon that collects data in realtime (per second) -# and presents a web site to view and analyze them. The presentation -# is also real-time and full of interactive charts that precisely -# render all collected values. -### END INIT INFO - -PATH=/bin:/usr/bin:/sbin:/usr/sbin -DESC="netdata daemon" -NAME=netdata -DAEMON=/usr/sbin/netdata -PIDFILE=/var/run/netdata/netdata.pid -SCRIPTNAME=/etc/init.d/"$NAME" - -test -f $DAEMON || exit 0 - -. /lib/lsb/init-functions - -[ -r /etc/default/netdata ] && . /etc/default/netdata - -case "$1" in -start) log_daemon_msg "Starting real-time system monitoring" "netdata" - start_daemon -p $PIDFILE $DAEMON $EXTRA_OPTS - log_end_msg $? - ;; -stop) log_daemon_msg "Stopping real-time system monitoring" "netdata" - killproc -p $PIDFILE $DAEMON - RETVAL=$? - [ $RETVAL -eq 0 ] && [ -e "$PIDFILE" ] && rm -f $PIDFILE - log_end_msg $RETVAL - # wait for plugins to exit - sleep 1 - ;; -restart|force-reload) log_daemon_msg "Restarting real-time system monitoring" "netdata" - $0 stop - $0 start - ;; -status) - status_of_proc -p $PIDFILE $DAEMON $NAME && exit 0 || exit $? - ;; -*) log_action_msg "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" - exit 2 - ;; -esac -exit 0 diff --git a/contrib/debian/netdata.install b/contrib/debian/netdata.install deleted file mode 100644 index 45d42b63..00000000 --- a/contrib/debian/netdata.install +++ /dev/null @@ -1 +0,0 @@ -debian/netdata.conf /etc/netdata/ diff --git a/contrib/debian/netdata.lintian-overrides b/contrib/debian/netdata.lintian-overrides deleted file mode 100644 index 45b2d868..00000000 --- a/contrib/debian/netdata.lintian-overrides +++ /dev/null @@ -1,16 +0,0 @@ - -# See Debian policy 10.9. apps.plugin has extra capabilities, so don't let -# normal users run it. -netdata: non-standard-executable-perm usr/lib/*/netdata/plugins.d/apps.plugin 0754 != 0755 - - -# FontAwesome is at least in the fonts-font-awesome package, but this is -# not available in wheezy. glyphicons-halflings-regular isn't currently in -# a Debian package. Therefore don't complain about shipping them with netdata -# for the time being. -netdata: duplicate-font-file usr/share/netdata/fonts/* -netdata: font-in-non-font-package usr/share/netdata/fonts/* - -# Files here are marked as conffiles so that local updates to the html files -# isn't clobbered on upgrade. -netdata: non-etc-file-marked-as-conffile var/lib/netdata/www/* diff --git a/contrib/debian/netdata.postinst.in b/contrib/debian/netdata.postinst.in deleted file mode 100644 index 29615f54..00000000 --- a/contrib/debian/netdata.postinst.in +++ /dev/null @@ -1,41 +0,0 @@ -#! /bin/sh - -set -e - -case "$1" in - configure) - if [ -z "$2" ]; then - if ! getent group netdata >/dev/null; then - addgroup --quiet --system netdata - fi - - if ! getent passwd netdata >/dev/null; then - adduser --quiet --system --ingroup netdata --home /var/lib/netdata --no-create-home netdata - fi - - if ! dpkg-statoverride --list /var/lib/netdata >/dev/null 2>&1; then - dpkg-statoverride --update --add netdata netdata 0755 /var/lib/netdata - fi - - if ! dpkg-statoverride --list /var/lib/netdata/www >/dev/null 2>&1; then - dpkg-statoverride --update --add root netdata 0755 /var/lib/netdata/www - fi - - if ! dpkg-statoverride --list /var/cache/netdata >/dev/null 2>&1; then - dpkg-statoverride --update --add netdata netdata 0755 /var/cache/netdata - fi - - fi - - dpkg-statoverride --update --add --force root netdata 0775 /var/lib/netdata/registry - chown -R root:netdata /usr/share/netdata/* - chown -R root:netdata /usr/lib/@DEB_HOST_MULTIARCH@/netdata/plugins.d - setcap cap_dac_read_search,cap_sys_ptrace+ep /usr/lib/@DEB_HOST_MULTIARCH@/netdata/plugins.d/apps.plugin - -#PERMS# - ;; -esac - -#DEBHELPER# - -exit 0 diff --git a/contrib/debian/netdata.postrm b/contrib/debian/netdata.postrm deleted file mode 100644 index 4ab4eead..00000000 --- a/contrib/debian/netdata.postrm +++ /dev/null @@ -1,43 +0,0 @@ -#! /bin/sh - -set -e - -case "$1" in - remove) - ;; - - purge) - if dpkg-statoverride --list | grep -qw /var/cache/netdata; then - dpkg-statoverride --remove /var/cache/netdata - fi - - if dpkg-statoverride --list | grep -qw /var/lib/netdata/www; then - dpkg-statoverride --remove /var/lib/netdata/www - fi - - if dpkg-statoverride --list | grep -qw /var/lib/netdata; then - dpkg-statoverride --remove /var/lib/netdata - fi - - if getent passwd netdata >/dev/null; then - if [ -x /usr/sbin/deluser ]; then - deluser --quiet --system netdata || echo "Unable to remove netdata user" - fi - fi - - if getent group netdata >/dev/null; then - if [ -x /usr/sbin/delgroup ]; then - delgroup --quiet --system netdata || echo "Unable to remove netdata group" - fi - fi - - ;; - - *) - ;; -esac - -#DEBHELPER# - -exit 0 - diff --git a/contrib/debian/netdata.service b/contrib/debian/netdata.service deleted file mode 100644 index e5d3a386..00000000 --- a/contrib/debian/netdata.service +++ /dev/null @@ -1,14 +0,0 @@ -[Unit] -Description=netdata real-time system monitoring -After=network.target - -[Service] -Type=simple -EnvironmentFile=-/etc/default/netdata -ExecStart=/usr/sbin/netdata -D $EXTRA_OPTS -TimeoutStopSec=30 -Restart=always -RestartSec=5 - -[Install] -WantedBy=multi-user.target diff --git a/contrib/debian/rules b/contrib/debian/rules deleted file mode 100755 index ec4ec418..00000000 --- a/contrib/debian/rules +++ /dev/null @@ -1,87 +0,0 @@ -#!/usr/bin/make -f - -# Find the arch we are building for, as this determines -# the location of plugins in /usr/lib -DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH) -TOP = $(CURDIR)/debian/netdata - -%: - # For jessie and beyond - # - dh $@ --with autoreconf,systemd - - # For wheezy or other non-systemd distributions use the following. You - # should also see contrib/README.md which gives details of updates to - # make to debian/control. - # - #dh $@ --with autoreconf - -override_dh_auto_configure: - dh_auto_configure -- --with-math --with-webdir=/var/lib/netdata/www - -debian/%.postinst: debian/%.postinst.in - sed 's/@DEB_HOST_MULTIARCH@/$(DEB_HOST_MULTIARCH)/g' $< > $@ - -override_dh_install: debian/netdata.postinst - dh_install - - # Remove unneeded .keep files - # - find "$(TOP)" -name .keep -exec rm '{}' ';' - - # Move files that local user shouldn't be editing to /usr/share/netdata - # - mkdir -p "$(TOP)/usr/share/netdata" - for D in $$(find "$(TOP)/var/lib/netdata/www/" -maxdepth 1 -type d -printf '%f '); do \ - echo Relocating $$D; \ - mv "$(TOP)/var/lib/netdata/www/$$D" "$(TOP)/usr/share/netdata/$$D"; \ - ln -s "/usr/share/netdata/$$D" "$(TOP)/var/lib/netdata/www/$$D"; \ - done - - # Update postinst to set correct group for www files on installation. - # Should probably be dpkg-statoverride really, but that gets *really* - # messy. We also set all web files in /var as conffiles so an upgrade - # doesn't splat them. - # - for D in $$(find "$(TOP)/var/lib/netdata/www/" -maxdepth 1 -type f -printf '%f '); do \ - echo Updating postinst for $$D; \ - sed -i "s/^#PERMS#/chgrp netdata \/var\/lib\/netdata\/www\/$$D\n#PERMS#/g" \ - $(CURDIR)/debian/netdata.postinst; \ - echo "/var/lib/netdata/www/$$D" >> $(CURDIR)/debian/netdata.conffiles; \ - done - sed -i "/^#PERMS#/d" $(CURDIR)/debian/netdata.postinst - -override_dh_installdocs: - dh_installdocs - - # Docs should not be under /usr/lib - # - mv $(TOP)/usr/lib/$(DEB_HOST_MULTIARCH)/netdata/plugins.d/README.md \ - $(TOP)/usr/share/doc/netdata/README.plugins.md - mv $(TOP)/usr/lib/$(DEB_HOST_MULTIARCH)/netdata/charts.d/README.md \ - $(TOP)/usr/share/doc/netdata/README.charts.md - - # This doc is currently empty, so no point installing it. - # - rm $(TOP)/usr/lib/$(DEB_HOST_MULTIARCH)/netdata/node.d/README.md - -override_dh_fixperms: - dh_fixperms - - # apps.plugin should only be runnable by the netdata user. It will be - # given extra capabilities in the postinst script. - # - chmod 0754 $(TOP)/usr/lib/$(DEB_HOST_MULTIARCH)/netdata/plugins.d/apps.plugin - -override_dh_installlogrotate: - cp system/netdata.logrotate debian/netdata.logrotate - dh_installlogrotate - -override_dh_clean: - dh_clean - - # Tidy up copied/generated files - # - -[ -r $(CURDIR)/debian/netdata.logrotate ] && rm $(CURDIR)/debian/netdata.logrotate - -[ -r $(CURDIR)/debian/netdata.postinst ] && rm $(CURDIR)/debian/netdata.postinst - -[ -r $(CURDIR)/debian/netdata.conffiles ] && rm $(CURDIR)/debian/netdata.conffiles diff --git a/contrib/debian/source/format b/contrib/debian/source/format deleted file mode 100644 index 89ae9db8..00000000 --- a/contrib/debian/source/format +++ /dev/null @@ -1 +0,0 @@ -3.0 (native) diff --git a/diagrams/netdata-overview.xml b/diagrams/netdata-overview.xml index d06950b4..fa7b6479 100644 --- a/diagrams/netdata-overview.xml +++ b/diagrams/netdata-overview.xml @@ -1 +1 @@ -<mxfile userAgent="Mozilla/5.0 (Windows NT 10.0; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0" version="6.8.15" editor="www.draw.io" type="github"><diagram name="Page-1" id="6533187f-1b6b-8515-a257-c05e29b4d991">7X1Zk9s2uvZvORddlVywC/ty6SWdpGo84xN7vvnmKgWCYDcTSVRIyXbn1x+AItVcIIlSQ0urbVfZEiVxwfvg3Zcb/G767edCzR8+5ImZ3CCQfLvB728QQoAD+5878rg6AiFAqyP3RZbUx54OfMr+NvXB+of3yywxZeeLizyfLLJ596DOZzOjF51jqijyr92vpfmke9W5ujeDA5+0mgyP/idLFg/1UQzA0we/mOz+YdE8cvNJrPSf90W+nNUXvEE4rf6sPp6q5mT198sHleRfW4fwTzf4XZHni9Wr6bd3ZuJWt1m31e/uNny6vvHCzBaeH/y7NMW/4j/cmiEwUbElXH2b7meTbPbn6v3DYuGW+o37Ibq7zxYPy/hW51P7Js0K85Dbi97NzCJRC2VfxZM8tv9NVbkwhX1h6ZLeJvbF/HHxkM+ql4VZFLl93MLcuo9XV2zum8r1s6+fqVw8NvSwP5u7l9m0Itzb6v835XxFe2CPqOZNmn0z9qRvv5hikVmK/sM95Me8zBZZPrOfx/liYZ/j6QtvJtm9+2CRz5sz23fdBdCTfJncrpZhaZfQPsDCLnC9IqoszaK0LxBjCANSvaJIMIrtS4GFkoSwiOBYRBAaHklq4gghLXDMqOBM385n9/biQ+LV9HT3ar61DtUr9bPJp3ZZH+1X6k/ZaiURaLYeRWx14GsLyLI+9tDCMKlBoOq9c78+9xN8HI1X5GnetgB1TIB9zf7Mng5EaV5Ev+afexhie2FoJ0Cqu3+73s/v8kleVKdqdvQmDA2wOIRrUJgB5mAGOOIi0W2YKZBGGCKUEKCQ5HE4mEHYMLAGZ0LCAc4EGsJMsMuH2dSUpaVPnBVJNMsXWWpp7NBR9gAnDIxjGccpUYTyOCLwtSKQrxDIMUWghUABIIio5Tea0zQ2MiACKYYdAOIGbC382W95+BwJAcCB5BX1pb6oydK0wdgCwNeHbGE+zZV2779a3ckuxcNi6rAL7cvSCsg/TYvK7/h7+JMjVppNJs3xWT5z4LkvVJLZ5Wt//d2d/eO+bqlWK1UQOzjU4ND2+1Y+47eJKh8cLqrLzk2R2RUwhbuzzNGnAkju3i3c6mL3tkJg9Rv3bq22uDf3EwuM+rUFSqabL1XP0yhQuL7uR7Ww15pVF0cAhkEDZh0wUDQEA4QcetDQHNwDDkdiPovCmLYS9aQ74fnDPJ1Pd3Afvh/3eSE6VPVSAJYkWJm2cAM6iYym0nAjcRKLgKylJ9oI4UM0Ie4BEz6ubGOTRb277ev7RfW0q2Nxc+DNxw/rY8X64Hw+qUWYPeUHe0uZLpuvOfW9fzqHUM9VkuxLc6hcqEWZuJUu8kWuHZTXP219zfPLHz6/+2h/Z5kWAv9+//HHTT8MIcibu9y6b/B2vdEesGanWTG9agdVSLbv92XnTAsTpz12bo8nyohU9/g28fHtbUw/APCF7CJfCjKUqcAjU9fa4HGRP8DpCqQtarG/lnnzQVRWS/nGSRk2//b0YXOWT5bjqqmTeNth79shLai+t5CLlUUIAr+Z1kY7Hqxbl4n+Zcn7JTNfuyDHKWQsJRhCSBXEkRBbMb4vkgWKMWMeJFMjEjIGySFskLXTpYYrY8ADV48NIvkF2yBb1IAvqphl5UOklX4w2wnO93OoXI8pAmGlL2iOgFBtfQFzEkGSImgESTEM6HOBsGeLQALpAInCwzebYy8NiKnKJihWsx0YfK3mMEQrDMYcJaSNQaRRFDMYawYFjw0LiUHIuxhEcOj4kx4McnEK0e3RCQ+X5sQnzdO5leS388nyPpsdINB36q3NoXLucH/oXdrt9TUv/qwWyUJJP7auvzrzWW5rms+yRV50daEx9xNCnakoF32sKbeNo6wMsUPVmLZSgobKi+UgSGufupOwmFEWZqMSCm4xxkQyYEUS7e5ZAIZOVNgExdqblp1E3z7BprUyJptPs4vft5XeOi+ySs1/cNj9vnHvni4e/frxw6877Gz0LBvkIjYvRPKiN2yb8J9zd7lZvnhw2ttWbLSAsabxqa1XnM+rEEsV27P3HJVmljhkzfJkh60DIdqKrHAeHMk4Vh6710Br+fKT2b207+32+CepB4RHd9OEgMe/S0f1f9aR3q/2V9HHwt3mg1mWO4AAtgPhpbrARWVOSG6AaUfXpFQwSkGsU21t3UTjcOaEBXoHYoR6PIHEY03QSw7vbrFozbdsuh1cfLvu+VKxJVfYEpgb0caWRZVVt0nMEsHTWNOApirom6q4cdK10MU98RV6ZFP1WOBK8i9GW7VtK77YdvXoheLL6UIWXzGDIm7npgiO0yjGSGEmJIhxGtIVAmgfX0N3HAS+HKgjB/CeBbCNSXZOQ1q9UFOTVNl1t9NkB9r242ZX5JurhKlz2UrS8Q/rGEWpITpJrD6ZmpD+YYC6Chu0kBwAsom1dfzDQXJVTs/w1Hx3hILRV4rAinYCYpoQ2ha5gkAZKbdOiaYKJSBgRgPqMUQ6jJTBhvl1nMNBAhSDZKmBX6/eH89IngqwSrxn3K9d6kcw7ncvyfPzyQIsCesvCTjnkpBLWBK7ly9pTfAlrAmB/TVpHGVnWRN0EWsC+msCz7km8BLWBMvB3jnnmoCLWBPRWxMgz7gm+CIkMYP9JfEYcCdbkouQxKhfcAHkML5/tDWBzxcz/YANdX99TnZW/QkEJNJdNUGHsppSj6sJ4v1XbVzi7u5In31mX6SvSdsFyTrhcGy27rhY49f6+d09zPJiqibDu9g77Et9z/JDXtyrmf1S4jDmbukhL52xZJcU6AdVuNdAzdzHSTY1s9KFhn7c8cAnjHx+MNO8eIx+M38t7ZfsDS56oQnUguWzYp2ieV//2reVUsM2xD65jAE4DgPyZVty7uE/8iRZ8R60Py87eJDxsEpRKJ2DY+/M+T4Gj3KD5psrrHG7FtT3al+9+fjrAff7nJv15ilYkLlfp46tLFb7PP/i3EZgns1NuefyhdjCP9WrVSce9UOLofavJ1p8GtE3RvIJz3Y9RPKN8fn4jPc9kSVGbYNs1mwDpqaOMrO4nHfBNNgG6wMrjACdTyb2UVYFM6ffQt79/oOLhTu6JEmUzyaO1EprU7pdvnDJHgvncl1rByOk5WBPXbg214M0Zz4NmHkwzfdP+A+lzI3k3f/IZstvYVD2vIQyzwa4hDy3H6YqW2HeRRqKXP+4532FEBm/zraJjO3xjBMYzb26RcE8fklfWD1MbtqA4fs8CUfIK/Xur7vCmLef3u9mgefKJ734bVY+lnoxOWSXnRT0AvPdoD+WV4SfEeEflP7Xp+/4vnZ8S3pGfEsPvnsr0M6WbfeEWHeYqDKT+lmw/UD8NEsSd8Z1gu70271rLXa7auaFVv+707plALfUXa/qNwblLeUVUooaZ65DRuGW5u0sX+iH+hb2Txf31FqnaSJD6bIYd5OUBB6mhPi8KQdYZ0Nv7mZbrEK7Z3c5+z2q6ei2V03KjYqtbzMF5oBr9Qw8WXxPjo9DGOOejGnEMk1MuvBwoWI5m1UlG46MznArjErK6knKzKW7g/rhtnZHaG3Dyr3S4T2Fseun4uoLbgPM88w5Ke236dsb+t7tyuUiL2svxZhNusqWKVdNYj67N+8jcjPMeQ8h1Uk370DiIddb74ROAl94r31IUe737DddKi5Vlv+wTOYu30vPz2F0+Xp4wGfZWpvab2xu2BEA0hDwAyX5+uClNtfwgmYVxbk9BNbhARxbbeRJOJwDxT+bmSnUJPp1luZRFD2tTidotL1gfk+X3Ekq4mg/Ui+OF6kPExUKjPMm+fpimXd1g3+UFwX/ZtE64H9eyPQc4Ef9tDcgfB7pK0b/U873xeJ/dYtngv/mHPkO9J8XbTwH9DEfQP94WWvP0WYKM80XLYvKLa0p7INubYDXQsBTtg0o2u293lVEWncQA0/5OVVCi/1gssim6ySdp258ddy7aoN39irrwmiTffHXWaPtjfFeQhCccXjLpT0lIAJy3lNWfNmnBHkwK44TIfE6kM/jYPtjOZ3/OnvTdrNBapfupvazIbbys1Xf/8Uod2VKPWT2OeI2dYnb3FfO43yTPHEmVBittce9JPf4F4DPFgvhVkXiwsmO1u5VjJ5D9kk2/2WDkBLa+IVULCihgVLWIOiFROVomxsEoDPTjFmgI0aoohrAqPFYnSVgpF1d3PxAz+h5gyC8l/ghPQ0vhK9efP/MwxFEHFFJ8T0qciilwfmiIkNKo++UPhqlRT+weVZKjyhv+E7pAykt+47vs1J6RA3pd0ofrG/JSyL1iLqtl0BqcUuwj9o6QcJL7abow0ttRTufvW9d2KhyEQYI/eQGTs6JgxEljd9xcBQcMHhJOLiSdCYIXh4QIOCoh4RhQ7mTIWFM4fdLQAK9RXIIhPO718gI99rpiH0l9rq4UGL3+6GMJfYhzUjPH/BU83l58c2qXX1MXRdWxR8vIfP6rI2q31iqjWowj7aPTXkJPapRv8fKiXtUj+DIV+JXu1Txi+H5xO+gecqV0PpSpW+/o9Ixpe9uYm8uiHqe8BgI8//NP+2Qszv63AdKLlpo+5l280/NQYlFZy0Q9YbRPFgJEUYb9N66nBj4VcoA2K+gOJ4MOH172elj+ddkuyJHr7Obtt2JdwIkMibdOdspTyNhiNZaqoTAgN20WeOyW/cuZmioTjZ9Qrt1Cy+0e3H519LCaju89huv+FLgtZq1bCjFoj1rWTACIvv0SuOEg5SGbNY+GAZAfG0yGxMmfG/i08OrMEm2Y5DJyhK7OnixCl6pBCjtNL52YxFZgklKklSrkGMRERBddGFfs17pa4pxyaMAto2Kz8vFfWF2AQztBbDrab7uAlIOgyxmuINBpliUiBTomDKQ6oDN19dzctYSFA1rpBD2jeaULxODxhpEltalUYVVkrcCkV8hp5NVEZx9mcSaW1gRbPnbCmXGqm0JBEkMRYxSHnDIBJE9TkfwMMK2Rt4zm2NdBMrc7EhnRO2aCsZfLa/jjtdBIFPKOrOdUmJfEYNTLBONQ6pzognrNiikntFOkPtG77xQbc6ip8i/Pe6A4PYCr+uFYNWuTUBEiZLdWSfMTWPnRCksaMqScBDsJ4tbRjgsylyrd9eg8mXzdBcLJK8Vf3CFPwFp12GieRxJmGodC80kDGhy9Jys7sJDDog89uwBbtaLgF/+ZT773XXpWJa/T/L7HUjcb+rTi9D3rKSVNZuDKew4TlKpI0mFNTENJLGRASd09osZsae2CWHhkbQvFGfOsrVE34Gv7TWrLxJf0j6cfZkgps3Kc9LYEzJOVAQSRmViJEoJDIgv1NPk1nkF7WiRR5E7dn33seBlianVjhmdfL+owhXJ0RWDk5qguCtHkzTSUiJoEg5RzMMBsJ/FYPW4YfIw5J6pieyFGrSz+2y2g72x/djbFQGwinxBrDGKUduWpdoaEhQrRU2aJNQE9Nv1BzNh7unu4qs7PaAL3ekAuHGM7FNPqrt87kauzMtqlux2RIordOBZuFWhCshRbDBr87tY00jF3MnHlFs4hoyE9Q1X6htb7PWdwOPi7Sj16I7rmFlySEF6K43mw7rryptCP1SdTI6ZSFofiOL1zW/dG8/KJt3cGGVTK5V+J85BbkwAmPLeLFnqa52BPUyRH5kpnqpb55uJKqbPb6Pwi+sP5JoSfmglRoeA6EN14mjaO+0mjMpn9Rzc3DJzU5PNU2CU9roInBijO5PfZL2FWslv71etqX4zybJul46eR4h1otmm1LRTEKI/M8xLCO6LSYWvDQksvn75/PnjTX820G5WEGKH//bTp8+RvXD0Be7Y28/qK3eZkOopSdSbwxqmM/T5daSbwQgrMO7QP/NFltbt3/aTVSEAqpyIjGbde9gK1O3xiRcphBjpOmgJ8cQBfGGoMPH43ULoctojeLuQ3TQtyFxN86D/2OYSqk1FV32at7uT+TK8Q0CgFwsi0pN85m0zF7Q28vSGj3ydbipZ9Qy8o0hhYKWQc9ST2m9ANYtiITCCisiEBXTUi6avQQ0y5JmKh7zxRnFciXgG2PG9YPdSfFFVVjYkaQKVars+IaIRNVRjzThXJmAaj2xKNGtMYeHR25lHb6eXnMVzGKZea8jHVW5a2Gkk00R3XKCpiVJtWVkCYcxRwNQdCGQPdw3NO7kTvk6P18fL9qswuR7coSpDGzIgU9PNpcAgAmmcJMh+h8YioAjtww57YNd8p2NUBqlw2qmqr3XE16qrh6BxL5yMPa4ob1eEdWZ+yPLXdUHTd4o+Q1r0vYueDCjhMbAh3J+ilyQaIHit6cR4FZY1UHDYyQIgsYwwNwrqlGmsAqZzDjqXITasq4DYY18RdiLhcDlTBEK3ND1/HT3tqQbMM4nwVL1UILiSpgng1jeG7+y0Fk2hwEXQ+oV2q6x7Rl70ppa9zC7Gh5mF3nrMcF7ZtQpwqvEPhbnPyupej9e17nmt9aaP0dOMpqmZLXffavD8nuljo4q5G4iyhZnu0MXg9vy3F5nj04+x+kwlb1MpfiKVB16O9bT4mv9HPb7psUjUsEgEb8PE0ts8tsyXoUJUshs8oGRIauahND2GyIPXO4Xh/DIPo24fH0pP14B5SOnrncJwfkpTQc9GaSoMjGMZxylRhPK4bqj68il9qf0fWZd/S0+JwtHaPw6I7Z1v1iN2Qx29LCaPbwvn8HLq2w49qfJLVVjwa01vJKTenvi1+8pDhbu7O3Qnx2hURxK9/dHZ0JMdwpv90/FIHzE58tM/P3zcZgu0NO5qeeZFVprRhoJVrr/mxZ9H0eA31rU0w6bvytl0XlW03E6TrlY/RPL2rGh7IJuXbWZTOTR34/gIqWo+aIM7eXcXyBbooRT5GmhRL4s5jTFwQbO7rnyaZr8+CXr8YxD7oBDCXBjuUTQg/INd00nV+b4HAPuIi55EMWX2t4qrL7gFmufZbFHdHn17Q987Ki0XeVkTZQw8ViGR0u79bHb/2b15H/ksuRCkGIxTYWKU3D+O2B/uwHKRF25i9jo1efWvRySkefFVFcnIJslXRkcJu+obk8NW/T7zO2iX3nYj7JomhZOyQFnl98HJ0rFNtXtOzWM46AKMNR/id3v2eThhLxnHyuP0MdAaEnyMsA/CO3qtoSHwZPdtEOnHqY8aUmREbro1IL6sLQIzS2qx+97qgfrPm41zOchKcy0e/79jGLeC8ObAf6sDqEpjqA58NEVmH88tfMVayoUqFs1lcntvzbG7bDJ5upHWu7V+8QSH/9Rr7LNWGh/vADjv+Hv4U6OwfFQLe0+z6qwI1BetH89la5hv2aJ+uPrdfzvv+o+1EVPW1im08WtdENYUsc9/bxab6Fh7Hkxyb7Zis4U8H/CaY4WZ2K3/xXRu0wfG+gofnTBoQR/1CgMZ7J1j9cj1z54wPTwT7k09YrJXtbFal8GZLHzUY+trtbjacsv9C9XvN95Zv+ZO8D1/YPlB5xf2xequn7b3mnKnT5UpJ0r/ua22aAjC/bLCryVbRmJnut2ZWMeaJlUxAquzZQBlUZIKaYCGwDAVsvlZF0trJbRT9ORpSnWAhXDyBN75snyIl5OJWeyHv1ebybvqPyogNmknWwtzGMkk1WkMU8TTgJm8pDcOB+OhQo2or2XLJTdFq/GXZKXOi2Qv8JHrbM8iKmRJqpAg7RxxKlBkJDEUpyaGOmQ7qmbsRcPZoIez+bJNXwRns7QpkuXicT9soWvEFl61rFXYYNwutxJSgYhiLRMrOFOUBMwxxbxnkTU9Vtpcq4mZnrLxTwhsLczE3Bdqaz34EFr7ZTi/CGhZhcx10bMGJoG8Eoia19ACmEVSKWqBZQADNCC0ZLeNo08h87Uwa3520cj6mk2yfD9c7dcI+UXgyrKsVZdjDVIZt7uVSSBExLllWDSlAJOQXY5ZN50EAU9WvM91SYJU6u12ITVi91LDQuuY0InbG4Sb6c54N13aa+t5uxvIY0QhmnB6i+D/zZcDmgeMIExMujgsfoBA876+MRiAHrAJiK011GH7QHKqmBAdkeHV57YtmvjXNIRpPIKlh+XNq+p9rZSBHd6s3UwOGjMZQyORimvePDq35d27u7sqyO9JAFh/1sfcUZp89RJZWKPNtnHn60O+vyQYgbsRkYPNvH5j8GaWz0yDrxbwBjJhTy2gLzGmpVbmdoU0Nc9+n6qZheK0ok2f/gBw+Z6diMaNy6RJKfQUSPsKJo4Qp6wiip4SA8fXo/rRXY1BUd3F7knCezeF9NYuDCOfAYorDn/KMpvOJ+bWfsGkqRP9X6o36qspLQH+56jXHqxwl40+VXncZvnJF6Yb7X72OOqiOfLDux/tt9/l88f6wgBVgy33Ggh9QU/4Li+rMpzPpcqXZVa+3Cf5YcetP+/sulonAhb1Ot3eF4eMAd9kCfc2y1bTlm7vuXU5em8AcSRZL2TJALlljHEiAGGCe+Yr+mxRKE6Uz0B9Jdp7yh1vVd+DfRiHH/PFuBtIjVosq8Qrq42655ol7l/XGXthb3f1UZ7eVIlZXS49lGA+juyTap6d38b94qG66NzMojqhAL1zm96oSbTIpvXbuSnSvLD6jvu8vu+HpkVyu5fx3nvr8rLHQu0CLPuB+wHsqdiSTRFW8R5Rm97K0qkV6hYpOrky/jyXzXkxntyaset9IbkpuB8CkL0mJaNTUwb5HINTbchNudmZ2jECBiPqfQ63vzaZQMe2y9TflnXervjR7y1udCLjC/YKuuTQ10p81tf+Cfi7CcxG+FVfh2NnNZFGSxqjTgwaiCRiFCogjTRaqxfr2GE9xw5hQwHja3zT1CyFxd2Iku/LdezkaZppc+vgVa7+HdIdAY7eipPxlA5puWfUTNO/6JkB5xGkRSeUGRS4v6cjuaX1F0f01f+/p6qYDm/q/RtiFfwTkR72jCfuqehqtJGOODnKth5RvfU6xMmq7WVCNO9OqqVcRABoaRIGNILyxYqTQb8+xod6jNeLHKAB4xB44wIF1w88UgEPcapcY99WgCpBMMKAqVgQkvL45QaoZDdVQYJhtyfmUWOOw+9G2EffzeTWFXrWba8cmdNbyiGBEGLk5i93TzfeZO6rQ1tPe0Tzmfusq811dsB55oHy+fPaPjNg2UXltxu69irf4qPLkwDZrFyo1e25tXEzqMDqvf28cBB9LBdmumI44zuDdUbTRO40y/k8LxwvGt6187ZFiVnU6Sp+Z2TnjCtX4eBEf5sit8ddtX92vyzU2NOleVE5HMvKfTpfFxuWa69kswqblmDwvJn3SVv+z01kMZbFuZ01rWYcNmeq6FJTxO3/OK/KZy357D9/LKsbh1Fp7KO7wz/ofDJplhMs3KJ8ycql5bN/Vw/240iq+Z8iddlEGx9gtZgOnqmr0gSLh3xZrlZxup7bODcVtur7fdfAb2aM64O7fqIbtwvBu4//vqk92O60pYX3xFR0LsZ3ofA9XnVX/TFKvYc1TqPPtu6kzq0/PfiHt81d//bmwxpJM0eMJCv/tP/9as/1L/fJYr3rvj5k1bNV5yyWs82QG/WAkzJvLW8V0tvxuNPYJEnlHPdunHc+QJhvCzc6duuPxqx1J16we9v+8PPHfzhkW8n+9sd91qkXxx3909vb25qIa168ItFq1359MIXZwiiPF5g4PDgHRRh1q+/JZp48NB4qHHf6Kd1fTfz7JO9N1USvtcaLVF5Quxu1/aBtPRhBI6hRarWbRGGGA3bkFl19Hq7jYJ1W/sgDsH6570VltW/BnFXm7vMk7mIO71fadT2Yw1X1l8VBIpKOxeo8JzhmiloBDGHIdHciUA9z1OM0Ax6PaQPWlwa5WZn04La9Jda1wk1aA9C+NBRQomJXEKZp7ZnTVEQ8YVAZppUOWWwoZDffEiI0lKHQ1xsuzJjTYdOtEd4yR8f5+IevjLOZvWSt5dzUceuNi8J7pUwQN86UTt8ST5ncAVPJTr/hslL/njzoeX/boVe57axmQWq/pN2BncR5iOOIGGZATBJqaLxx261Bu3vfNZDyNcLxAAofp4jJ28ouxMz697+8a3d17GZxXaIt8hQM21wgswd5G7Y61BMDNcI9PbsorZmdF/1JQa+z1YlVCWXFLJBGmoCOSkhphLggAsSKpyagjIZiULTtkdHUE1gg+4uj06mEG9uo6gdVLMpVR9Xlouqj2gXfjlYTx1YPMCV9eow0C5tq+yujB95vcunLqHWWVQ09jlMUa1CpBWnjcKAq4gYQZRUEofHmnd6oyCO2ejumdXLg/LPbLLnlP/z3x0+jHZWf83yy0XN8LmRu95ZdhAYC8W4NZA8kfesi5vGmzel2dPsMY9OdkT+puV7Oy8QnM/ZzKrwMHsVI1UIGYU0I0t3UUBhRHlMqjFQoBgEdVLznFPVqI77+REeaYducdp/8muvRR6vWewIRJiTsJgdDEakUwDhhXMcKhUMA6uujAgzZi2+IMd/fQzmk9gHZVFdEbVRRmzIUd4IggqY0wlDzlAMD7MYP2NdHsD61fVG2IbUbn9mzqM32p/ZLYd1Vz0KUxNTwDuvG3EQxSgxXSRwLHrJnYa+XO+Ry2MxdeHy9B0xbG5JyxPDYl0rKalgwkhomRLRJiTiNpCSaC6phnKYBuyL1pTCXQxc196S48gAprmREBd618mBZ9WO+i4kG9rVuN7vlFEYxY6lKCGfWPAzoAeK9KI3wUFt6VC4eoPNJ08T9NVLb7u2Vvy9lIGWdJo2JZdNKxQJb5UsKEjDtQDQVrmtqNx0Z29T27G22v/k2TBQ9oOrueqhNK3sKQxhL0qE2sZycAckMUDEHKGDfxEGHAR+1IfRI5QOCjUNyjyt2u1ZyV8YTRoamsJ3fIay9FEGpDUepxCgOyMrJQJv27G1PIPCAidBDYqPXTGyySuZJDNVxR+EmMI2U5Z6xEvYzKgPKbdKT2z4tzeeICyG36QEFb9dDbVoF9bGkypi2X0TGII4ETw1SmgoIdThqM0Z2U9unpR2QjTqk9qv2gtGqtAwrSUnSrWm0Onkaa2NZfSoTEtAC42xggQ0novoaHvMAfhFvm5/XQ222orZJqep4wRxjpwQbEHMsrUgPqJP397bEHi3N5wY7YN7DcZtZ1weqCWa/5p9XJ32qE2stw9WESWjlNsXU5U6CrjAgETCY0tQQFpOQaj3utlKxJvvQSQ6bZN8OYNDegPGESc6QOv5Y/jXpoold5UwQWrkEsE5VIjruPoVxBLCVMiDGUKuAqoXojW+EiHsSCH0tsOX+7GdM0G1kk5RrFUBihQBNNOvwE4v4yCQsoSnAMUxJyHlDPQEk5DAMw3zKZYCg28i+KddK7SpSg2MZG92pAqE6iSBPlcQJ5ipkFYhAXReg9ARqmmBOxwMYIFAzplGKZwpmp11Ar43AsHOAy3e5U9Ns4h7wFzP5YhyhNyTGdBqxuT+tvJt1+4Z9ehF05mvWnQ/a8zXdr7rzNZ9GXdKb1qjLbdRuD7VsNlB7hmVNqgtpdyBozw0JUG/O5NgeB7I3mU/y4wys7N+xrI2iA4dJDvfBCIt62EBjv21wYAOName0ZsvSm/Zk2RZcYRust5z2sd9s3v5w2VGgph5Mo4sCNe/71iE8ENQC9rcHG4fqQ4A3IsXlRANlVHuUjMVZhWS3JFDeUjfPuD3wZZYXjqZvZ/lCP9S30OvUk1AjEuIDvkAxZq4Ww9PDR/IEcB5GsmLUddswPFSkA5VqDAl7vdksrHK3EgpBNzFJShBHLNZAGmoUIwGd62u36dol4wul+LJZArQWZNeazSIxdIX2HMTGhbbb+Q2WqhHSwGjCtOYiYEZhP0wigafeEnp8qY2MfpYv9VVnFLLKNUYQ5xJ3R+ciFCUxMATSRCYgoCnbH+dlTVlPn7RjmbKvOHfJUrsyZYlQadrNVKNGRzC2HNRggggL6DnHjd9zG7V9SYcyBJt+1blLbJXNknIYi47jAhEQpYRgwoGSSgUUypQPqO0Ryh7PRYi97e1p93qoXSWzECufMWXdSgAYpQIxQLHUKUpCxkB7mWqceNzSvgSHEJ1W+av2QTO8Etwp17DNymWawkhxlkJt0gQjGDCmRegIcmPP7sY8ALnRqyY3WxlYMQdc9UMOjEqSxDIVMQyolbO+S5A3Nc2doJOn7jxEvQAf4X67YnLTmtwg1Z1kNUmp/QcQTBExImS3M057arnPCpM+IywEta/VNWJJ5VbBCjwkUuUYtYaNPR0nUQLsy8QkEomAchmCvm9EoJGc+oCWEbsGaY7tKAOFr6PMqgtuc65lczhpVZovPU01h51nnps389TnOFrdUxK5UQuZNr3eKHx7b5QXU3S+Pwfpx6hBo6K1Tb0wg6HHJCnwgyaFnSWCQxDsxHBuoYRjgzXVrz6aIrNr5tz8e4QlNWMiIYgRqqgGrgv/6kvtmE4TvruQmI7AXWehbIi6d0iH97RZ0B8nFC6kw1+xH+IsFXMc9ON1ZKjMUE8NFQmgzIgD/BAvQpk5S5xnoJcCPJQq1OMuPqB33pCUB/gYXgQpzxLnGViUoFnOHXlNISakNLm2L0AbGORzhEvaGCXyGwZ2KSK/N5ZSyp6+OD6Lo89KGlCEF/livzS6c8KNnxtvjXp0IXjr2zEH442LvkHUVy8C4u3lpKudHW+NVL8UvOG+WAQHpqlxgntnokdLUxM+l13H46PXQHly6mDDEpCYoZ/nabxJosy0M0Pp8rsI+1KVf2Lur7uffKFq/U5uNc33cPDBpgCjmdTMhkF1CMO4Wnb59zxtIe1izUa5/IjP5TeY0bOehOKdz9McW110z/E6Ye64NWML2Ju9qYZNpXkxVbPOWCHfLe6eCRTCe/n5wUSVFaL0xJRRnkYqsncarabFRnZ1o7SaAtX2ZIrtnsyvD9nCfLL7wr3/Wqh5dx/2cj/TNEVa+6RIwmJX0xkmAaHnHoLr4QWdgQaenXFA95QxTkgxwgl5omzeP5bT+a+zN+2cXkhvrfJVJ/Uitkrqrb7/i1HuypT2OB278Wf9XlymLxkkf/tiID4eSUN0X+gPXDykjdKFj4FNZvA2qwYfzhJT1DyoZjvuuPM6GHt0aqzyEqlZEsXLMpuZsozcx5b3WIlyB12t051zXBx77iskvm2UTrL5L7tUzD18HB3QkaGrCkoP5GDfxDjIw7EHxPSymDy+LSwyTCVht7PyCjxrO2E0gdYY8xDIUgfdyTEEanMbqwhX3CYAoURPV17nJLUHLXFPvPsAFWpAKnmAi/haAgKiSgC+ExTSODGddh2CqUgTljCgJINJQC+y7DdeIsOKSuiLTfbrfJ6hMFuDdpasZqi25qlu0+4m+SzJZ7fTx6hW6G6zvPqkraWtvBUbtbSrhZF0mt2djo0gxFT5raaGkRW9ERdSJpAgDVXT1qHPaUIoGV0zDAnf9CxPhhTsW/ihuzzsadWwUXbYGrW3f5QHGGMes2t0bshOs+vJf7DqB7/Rf7CnYfi8O1zNtp49PtmFDv/73Vpnr9PnWGRDwV398Qhu6v6OEc7h9xBpphC09tC6CWkny/A4/eTliFS0F1p+eRoTfD3GvvFNeeryjjwNSy9LJ8tacrbcLmjHulHeVSeO3vdOu8bOKx2LJd1AuTsj4wSKmLREsTRYRxxRTFAc60Sr44liyLv2/h6y+DhD9uTleH5eJiNhfVt62GDvWKXacoQp/Z1223ajpGcj3rom4Tv1DqRev0sCBcPw0pFF+Kf/97M9EKvk3uVXg7So5Lk7W6YDCfOfzcwUauEyut/W10EdGKFXKs1X1SdS4hhUqWHN6DuR0DjCxigIeRwndJNh3Y2V4kBmQq+jIqEe+c488h0FmYLp4TIjMny+c5mtbR+65aNnMBTCMBI1v62cDrflQ5+FvFLfHGNVk0wSgzSBnXpFA2HEiIk1xZwxHXBSlQC95Jc1UHaUn9Agkd8zdFw1U6204yM90LFXCjoOVqCDiqWd7PQYgwhLCIkEnCIcsM9v1Q22AzrPOETm8V4dMB5tD9DZRWtrSxYQ+Jtrr5g5f+RjviwcJHSRzReBdCkrXkz2xalSTX/p+uKR09wiK+0mk6hzxSe47tdz+orgiiq4JsgkqtONBQsaMZVwERuScK23q1n2LRooXaG8Khh2ZTQBnk6kYYqCRyld8FU3feCrpg8JSXuNhylEEU1iwLHhyMiAcw7WP3maczBMo2kyZjru+XCB0zAsykxVNoms1pullpIOA31OBLdHV15Yes6BEFt1HkjtFk46MjQxLGKWG1k5qpRal6s/pYaAvpFzP7FX6Rs8m7PL7Y1lujnPPpnmLdulTmvfJyFoU9ruMUJdvJka0fiofdzUN/0pSKjr9BpqoeI4W0z/6u+zVxomYXxVPplCwTttPSTC0r5VQCCqlEQhB46hXkLsOveok5Pm0VCbmsqLBF3N0+fL8iF3Ccxb2fprVTBBxcsBB9gk3RnDMokQ4ymD2EAacjw86wV/YTN0ruOl88zJOaAj2CiFER2QaXeVgp1UYECcqjjtdANMkKuSYioWhKQ8jo+dhou8Ps8A2JNd/w/3BIB9/uEDiotPL0nv89/Nt/kXVfR4W2dJXgtv44wK9+B3EhKUxKmKiBS6aSohUARFQplmiZAk5Px02asoQGgYFoO+VgT0qM6ewKib5YmpMJcW+Sxb9qUp2i8qdupuCA5CUfVRuRFUdtdQCZxX7M7VhAOOQES1MIhDETHedOgSwL7lVHLGjdScBRzwQlEPSpgM4+Ow6bfXaVDykkyBNZTKRWbsRczECpVZH1D4ygBFJaU4kjGkVCJiARUnjR/aqmGxs7FTBjTnIYMfsueHpmQYTIPY46nDQQDlXMB5vmh9/WcXofxgAeB+9H8=</diagram></mxfile>
\ No newline at end of file +<mxfile userAgent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36" version="7.6.7" editor="www.draw.io" type="github"><diagram name="Page-1" id="6533187f-1b6b-8515-a257-c05e29b4d991">7X1Zk9pI2u5vORcV0X2hityXSy9d3R3x9YzP2HPmzFVHKpWqUjcgRlC2a379lykkSkolIKiEAqrtCBsEaMn3yXdfbvCH6fefKzV/+K3MzOQGgez7Df54gxAkhNn/3JGn1REh+OrAfVVkzZeeD3wu/muag6A5+lhkZtH74rIsJ8ti3j+oy9nM6GXvmKqq8lv/a3k56V91ru7N4MBnrSbDo/8qsuVDcxQD8PzBL6a4f2gujUD7Sar0n/dV+ThrLniDcF7/WX08Ve3Jmu8vHlRWfuscwj/d4A9VWS5Xr6bfP5iJW9x23Va/u9vw6frGKzNbBn7wz4Wp/p7+4dYMgYlKLd2a23Q/mxSzP1fvH5ZLt9Tv3A/R3X2xfHhMb3U5tW/yojIPpb3o3cwsM7VU9lU6KVP731QtlqayLyxd8tvMvXhQ1XJRvyznZrawBLx1H66u1941ziFjOcEQQqogTsTzSqyfcLF8aqlj12zuXhbTmozv6//fLeYrJAB7RLVv8uK7sRd5/9VUy8LS93/cI38qF8WyKGf287RcLu1TPX/h3aS4dx8sy3l7Zvuuvxx6Uj5mt6tFebQLah9oaZe7WR+1WJjlwr5AjCEMSP2KIsGQ3RR3AnKUGswSglORQGh4IlJNE5VyhCTKOcT6dj67txcfkrKhrrtX871zqFmpn005NcvqyX6l+VTIBmbNPoQUk9WBb8+wtrheHXvoIJo2P1TNTrpfn/sZTI7iK/K0bzvwOibclpUxXbjNn5YP5cyhDOvyUT9kaR9fEPG9ALUTLfWjvF9v9Q/lpKzqU7WbfROgBsAcYjeMOYezpP5osRF5z4DDEGAGOUw0Q4YBiBJFOV7BTaIUJhkWVELIKcvTBm71yd932desnJk4OCSA9XGIYQCHBAxxyNgZ43Aj23sG5F1l77a0AKtMgPFReY2MjmLH6LBQ0ioCHUYnqUkThLTAKaOCs4iMjjHSBxiRPMDo2BBghJ8xwL4VfxbPB5K8rJJfyy8ehtil87YDYQZqeQo44iLTXZgpkCcYIpQRoJDkaTyYQYg8gSokHOBMoCHMxDnzsQZmU7NYWPqkRZUls3JZ5JbGDh0LD3DCwDSVaZoTRShPEwLfKgL5CoEcUwS6Gh2AIKEISs1pnhoZEYEUwx4AcQu2Lp9DNMDnSAwADgwO0Vzqq5o8mi4YOwD49lAszee50u79N2sx2qV4WE4ddqF9ubAC8k/TofIH/hH+5IiVF5NJe7xRRu4rlRV2+bpf/3Bn/7ivW6o1tqRVaS0cGnBo+30rn/H7TC0eHC7qy85NVdgVMJW7s8LRpwZI6d4t3epi97ZGYP0b925trbk39xMLjOa1BUqh2y/Vz9Pajbi57ie1tNea1RdHAMZBA+6rVRQNwWCVPBiSenBvOJxemZ8/zPP5dAf34ftxnwvRoeqXArAsw8p0hRvQWWI0lYYbibNUxGMtxNPRCaZDNCEeABM+rmxjk2Wzu+3r+2X9tKtjaXvg3aff1seq9cH5fNKIMHvK3+wtFXrRfs2p7/7pHEIDV8mKr+2hxVItF5lb6apcltpBef3TztcCv/zhy4dP9neWaSHwz4+fftz0wxiCvL3LrfsGb9cb7YFivjArplfvoBrJ9v2+7JxpYdLcY+f2eKaMyLXHt0mIb29j+hGA73tJpAgYpyAgU9fa4HGRP8DpCqQdarH/PJbtB8miXsp3Tsqw+ffnD9uzfLYcV02dxNsO+9AO6UD1o4VcqixCEPiH6Wy048G6c5nk75a8XwvzrQ/ygSNRbMX4vkgWKMWMBZBMjcjIGCTHsEHWvuan1vYFAbgGbBB5zqbuFjXgq6pmxeIh0Uo/mO0E5/s5VK7HFIGw1hc0R0Corr6AOUkgyRE0guQYRvS5QOjZIpDAocYgAnyzPXZpQMxVMUGpmu3A4Fs1hyFaYTDlKCNdDCKNkpTBVDMoeGpYTAxC3sfg2snXwaAMYJCLU4jugE54uDQnIWmez60kv51PHu+L2QECfafe2h5azB3uD71Lu72+ldWf9SJZKOmnzvVXZ36V25qWs2JZVn1daMz9xFBnasolnxrKbeMoZHv4aoca01VK0FB5sRwEaR1SdzKWMsoiGZcU3GKMiWTAiiTa37MADJ2oEIaiQSfRt0+waa2MKebT4uz3ba23zquiVvMfHHb/2rh3zxdPfv3026877Gz0IhvkLDYvRPKsN2yX8F9Kd7lZuXxw2ttWbHSAsabxqa1XXM7rEEsd27P3nCzMLHPImpXZDlsHQrQVWfE8OJJxrAJ2r4HW8uUns3up7+0ehnghDYDw6G6aGPD458JR/W9NpPeb/VXyqXK3+WAeFzuAALYD4VJd4KI2JyQ3wHSja1IqmOQg1bm2tm6mcTxzwgK9BzFCQ2kqAWuCnnN4d4tFa74X0+3g4vulTl0KtuQKWwJzI7rYsqiy6jZJWSZ4nmoaEVttmGSdAxXw2/FAeIUe2VI9Fray8qvRVmvbCi+2XTu6UHg5VcjCK2VQpN3UFMFxnqQYKcyEBCnOY3pCgGdVYRCI34FQCtSR43cvAtjGHDunIK1eqKnJ6uS622m2A20Xnwd6KCBrWeo8tpL03MM6RUluiM4yq07mJqZ7GCAvoLxONO66h8kQj+2xs8TjFoan5rsDFIy+UQTWtBMQ04zQrsQVBMpEuXXKNFUoAxFzpZDHEOlQ4EISSH7nUeITg1ypgVuv2R8vyJ2KsErcs+3XHvUj2Pa7l+Tl6WQRloT5SwJec0nIOSyJ3cvntCb4HNaEQH9NWj/Zq6wJOos1Af6awNdcE3gOa4L9KiwIXnNNwFmsifDWBMhXXBN8FpKYQX9JAgbcyZbkLCQx8ustgByG94+2JvDlYsaP11D3N+RjZ/WfSEAi/VUTdCirKQ24miDef9XG5e3uDvTZZw4F+tqsXZCt8w3HJuuOCzV+a57f3cOsrKZqMryLvaO+NPQsP5TVvZrZL2UOY+6WHsqFM5bskoJVpbRb+pn7OCumrly6nC1+3PHAJwx8/mamZfWU/MP859F+yd7g0otMoA4sXxTqFO375tehrZQbtiH0yWUKwHEYUCjZkvMA/5EnSYoPoP1lycGDhIdVhkJdwr934ryPwaPcoPnu6mrcrgXNvdpX7z79esD9vuRmg2kKFmTu17ljK8vVPi+/OrcRmBdzs9hz+WJs4Z+a1WryjvzIYqz9GwgWn0b0jZF8IrBdD5F8Y3w+IeN9T2SJUdugmLXbgKmpo8wsXcz7YBpsg/WBFUaALicT+yirepnTb6Hgfv/BhcIdXbIsKWcTR2qltVm4Xb50uR5L53JdawcjpOVgT525NudBmrOQBswCmOb75/vHUuZG8u7/KWaP3+Og7GX5ZIENcA5pbj9MVbHCvIs0VKX+cc/7iiEyfp1tExnb4xknMJqpx/FZwC8ZCqvHSU0bMPyQJ+EIaaXB/XVXGfP+88fdLPC10knPfpstnhZ6OTlkl50U9ALz3aA/lleEvyLCf1P675//wve141vSV8S3DODbW4Fusmy3JcS6wUSdmeQnwfqB+GmRZe6M6/zc6fd710/xdtXCEK3+d6d1ywBuqbte3WQRylvKa6RUDc5cg4zKLc37WbnUD80t7J8tHii1zvNMxtJlMe4nKQk8TAkJeVMOsM6G3tzNtliN9sDucvZ70tDRba+GlBsV29BmiswB1+oZeLb4nh0fhzDGPRnTiGWamHwZ4ELV42xWV2w4MjrDrTIqW9RPsihctjtoHm5rc4TONqzdKz3eUxm7fiqtv+A2wLwsnJPSfpu+v6Ef3a58XJaLxksxZpOusmUWqx4xX9ybjwm5Gaa8x5DqpJ93IHGghxkO7A4S32sfU5SHPfttk4pzleU/PGZzl++l569hdIVaeMAX2Vqbum9s7tcRAdIQ8AMl+frgufbWCILmud/t3rCOD+DUaiPPwuE1UPyzmZlKTZJfZ3mZJMnz6vSCRtvr5fd0yZ2kII76kXpxvEh9nKhQZJy3yddny7zrG/xjcVbwbxetB/6XhUxfA/zIT3sDIuSRvmL0P+d8ny3+V7f4SvDfnCPfg/7Loo2vAX3MB9A/XtbaS7SZykzLZceicktrKvugW/vfdRDwnG0Dqm53rw81kdYNxMBzfk6d0GI/mCyL6TpJ57kZXxP3rrvgvXqRdWW0Kb6Gy6zR9r54lxAEZxzecmlPCYiAnHvKSij7lKAAZsVxIiRBB/LrONj+eJzOf52967rZILVLd9P42RBb+dnq7/9ilLsypQEyhxxxm5rEbW4rF3C+SZ45EyqO1upxL8kD/gUQssViuFWROHOyo7V7FaOXkH1SzH/ZIKSENmEhlQpKaKSUNQi8kKgcbXODCHRmmjELdMQIVVQDmLQeq1cJGGlXFzc/0DP6ukEQ7iV+yEC/CxGqF98/83AEEUdUUvwVFTmU0uD1oiJDSqO/KH00Sgs/sPmqlB5R3vAXpQ+ktPQd369K6RE1pH9R+mB9S54TqUfUbV0CqcUtwSFq6wyJILXboo8gtRXtffaxc2GjFss4QPCTGzh5TRyMKGn8CwdHwQGD54SDK0lnguDygAABRx4Shv3kToaEMYXfl4AEeovkEAiv714jI9xrpyP2ldjr4kyJ7fdDGUvsQ3qRvn7AU83ni7PvVe3qY5q6sDr+eA6Z16/ap/qdpdqo/vJo+9SUS2hRjfweKyduUT2CI1+JX+1cxS+Gryd+B81TroTW5yp9/Y5Kx5S+u4m9uSDqZcJjIMz/b/l5h5zd0eY+UnLRUtvPtBt/ag5KLHrVAtFgGC2AlRhhtEHvrfOJgV+lDIB+BcXxZMDp28tOnxb/mWxX5Oh1dtO2O/FOgEympD9mO+d5IgzRWkuVERixm7Yfe4frlO9eWTkKiJh2/tildS9e/OfRwmo7vPabrngp8FqNWjaUYtEdtSwYAYl9eqVxxkFOozZr93OoaaglZGvCxO9NfHp4VSYrdswxWVliVwcvVsMrlwDlvcbXbioiyzDJSZZrFXMqIgL+qIl2HGwXXUIM0XXsNOVjoWteLpb3ldkFMLQXwK6n+boLSDkMspThHgaZYkkmcqBTykCuIzZfX4/JWUvQ1vbqZpuGxjVdavt/Yw0iS+uFUZVVkrcCkV8hp5N1EZx9maWaW1gRbPnbCmXGqm0ZBFkKRYpyHnHIBPH1NBLo8Y/aWHj85PZXmEFsP3JG1K6hYPzN8jrueB0EMqesN9opJ/YVMTjHMtM4pjonW3/f8yDsQMa1DFgLrb16aSi06KnK7087ILi9wOt6IVi3axPWZiRK9medMDeMnROlsKA5y+JBkAlP3K45Y5cRwoDK105JuTQIFvN8FwskbxV/cIU/AWnfYaJ5mkiYa50KzSSMaHL4FfFEDuEHUcCePcDNehbwK7/OZ7+7Lh2Pi98n5f0OJO439eki9D0raWXD5mAOe46TXOpEUmFFnoEkNTLmUDFf4VsPE+8CrR3g80If71kAzZm2luo7ALa9aPUiASbtw9mXGWLarFwnrUEh00wlIGNUZkainMB4ABMY7saXCNgTl+o5scTUaseQTr5fWOGKBOmKw0lNUNoXpFmeaCkRNBmHKOUR/SZeMQEkKNBdg4QUuf3bPZ8FAmf3xWwHe2P7sbcrAmAd+oJYY5SirjFLtbUkKFaKmjzLqIkIQOhzQCYCEjYAQHzkyNdRCoQdCswsO6RCuJPX8Nu6Dca7Sj/UrSWOmdnXHEjS9c1v2z3iRel9mztVbOpt4bdGHCQrREAp94Z70lAvAxyojuZHltOnap/4bqKq6cvr2n9xDVtcl7jfOpmqMSD6UJ84mXqn3YRR+aImcJt7GG7qengKjFKvrPvEGN2ZjdQ6JDvZSB9XvYL+YbLHpn81ehkh1pk/m3KFTkEIf4hTkBCtnv9CQpxYfP3y5cunG39Yy25WEGOH/+Onz18Se+HkK9yxt1/U6Os8IeW5IWgwqTBOq97X15FuBjOFwLhDfyuXRd7049pPVsUAqHIiMpn172ErULc7jC9SCDHSV+dDcQHIQkPQo5iTu4XQ+dSrB9tC3bQ9oVyR6aAh1Oaalk1VMD7Nu+2iQim3MSDgZUATGYhOBvt+RS1WO73hI9+m20DWTdzuKFIYWCnkHKek8VtRzZJUCIygIjJjUR2n/dRrFBhThoIBIHFcifgKsON7we4inPGCoTpNFpI8g0p1XVEQ0YQaqrFmnCsTM6+irZlrMIVFQG9nAb2dnnOS7GGYeqsueJdaY2Gnkcwz3XXBp7lJcm1ZWQZhylHEXAoIpIe7lua9YHao9d718bL9Uv6vB3eoTpmFDMjc9IPbGCQgT7MM2e/QVEQUoT7scAB2wSyyKBmzO1X1tY74VnX1GDT2Cj9wwBUVLFNHeH+ZNoKi59Mm5FIpCoHvXQy02xUBAxvC/Sl6TqIBgrea34nrkh5ooOCwF5UlqUwwNwrqnGmsIubXDVpJITZsJQVxwL4iUaKyI1jJ+bR1j91j8vULm6mnGrDAaLhTNbeA4Eqq2MFtaC7aq9NatHkUZ0HrC20f2DTxO+tNLUVfcWB82CcSHzcquVYBTtWPvzL3xaK+1+O1EXtZr7PpU/I8NGdqZo+7bzV6fs/0qVXF3A0kxdJMd+hicHtF4UXm+Pgx1pCpFOzyw0+k8sDzsZ6W38p/qad3HotELYtE8DZOLL3LYxflY6wQlewHDygZkpoFKE2PIfLg9bbFf32Zh1G/NQGlp+uIO6T09bbFf31KU68i8ZSUpsLANJVpmhNFKE+bDpeXT+lzbcjH+vxb8mHw92j9+AbEDg6c8ojdUkc/VpOn95VzeDn1bYeeVPulaiyEtaZ3EtJgk/LGfRWgwt3dHbqTYzSqI4lev3IThrJDIA1U1B2hlfFa6f/8t98+bTMGOip3vT7zqliY0ZaC1a6/ldWfR1Hh00mZ3nQqXXQ5y12dy107/vduMZvOb+vD06yv1g+hvD0t2h4o5osut6k9mruBfIRctRC2wZ28u4tkDHgwRSAA01A7GYhOYw2c0TSlK59v6JcAw4CDDOIQFGLYC8M9igaEf7BrOql7kXsAsI+49ESKWRT/VWn9BbdA87KYLevbo+9v6EdHpcdluWiIMgYeq5jIwu79Ynb/xb35mIRMuRikGAy4CNSKhQT/ceT+cAculmXlZhivc5NX/wZEQl5W31SVjWxbe2V0lLCvvzE57HYZsr+j9k3ttiZuaFI5KQuU1X4fnCwd2+bY82oew0MXYdD0EL/b08/jCXvJOFYBr4+B1pLgY4R9FN7hNeuFIJDet0GkH6dAakiREcnp1oL4ujYJzCxrxO5HqwfqP282TkogK821evr/jmHcCsLbA/+uD6A6j6E+8MlUhX08t/A1a1ksVbVsL1Pae2uP3RWTyfONdN6t9YtnOPyrWeOQubJxSPkH/hH+1Cosn9TS3tOsPisCzUWbx3PpGuZ7sWwernn37947/7E2YsoaO5U2Ya0LwoYi9vnvzXITHRvXg8nuzVZsdpAXAl57rDITu/W/mt5thsDYXOGTEwYd6COvMpBB7xyrR25+9ozp4ZmwN4eGSa9sY7UugzNZ+KinztcacbXllv0LNe833plfdCf4nj+w/KD3C/tiddfP23tNudPnyiwmSv+5rbhoCML90sKvJV1GYme63ZlUp5pmdTUCa9JlAGVJlgtpgIbAMBWxHRXoY2mthO7qYXCAhXDyDN754+IhfZxMzHI//L3ZVN5VR0gBscl76VqYw0Rmuc5TmCOeR0zlJd6AEoyHCvW6YUsvW+uc26E1+MuKhS6rbC/wkSvseGuRJWpkSaqQIN0kcSpQYiQxFOcmhTpifyDM+hY3ggHOFko3vQjOZmlTZY/Lp/2wha4RW3jVRFRhg3G33kpIBRKKtcys4MxRFjHJFHPPImubrPR6iJIA19qiAp8LtpZmYu4rtbUgfAit/VKcLwJaViFzbc2sgUkgrwWi5g20AGaJVIpaYBnAAI0oED2LB6NhWz0ekIfiAuTh8lsxKcr9cLVfa9qLwJVlWau+sxrkMmVdRQsIkXBuGRbNKcAkZt9Z1s8nQSCQFh9yXZIopXq7XUh0RDD6mitsNvU3iDhunffzpYO2XrC9gTxGFKKNp3cI/u/ycUDziBGEicmXh8UPEGjfNzcGI9ADet3wERyyenKqmBAdkeLlc9sOTcJrGsM0HsHS4/LmVfm+VsrAHm/WbkoCTZlMoZFIpQ1vHp3c8uHD3V0d5A8kAKw/8zF3lC5fXiYLa7XZLu4CLp8DJMEI3I2IHGzm9RuDN7NyZlp8dYA3kAl7agG+xJgutDK3K6SpefH7VM0sFKc1bXz6A8DlR3YiGtN+c1waqJAOVUwcIU5ZRxQDNQaOryfNo7sig6q+i92zXffuChksXhhGPiNUVxz+lItiOp+YW/sFk+dO9H+t36hvZmEJ8H+Oeu3BCvfZ6HOZx21Rnnxh+tHuFw8IrtojP3z40X77Qzl/ai4M7G/5jsj5GT/hh3JR1+F8WajycVEsLvdJfthx6y87u67XiYBls06399Uhg5k3WcLeZtlq2tLtTbfOR++NII4k80KWDJBbxhgnAhAmAqMDgmk0MM4wshFayeZR5aPlTrCs78E+jMOP+WrcDeRGLR/rxCurjbrnmmXuX9cae2lvd/VRmd/UiVl9Lj2UYCGOHJJqG+ecr44tH+qLzs0saRIK0Ae36Y2aJMti2rydmyovK6vvuM+b+35oeyR3mxm/ZOj5mWSPxdoFWPqB+wHsaXDC+lEMvhHF6Z0snUah7pCilysTznPZnBcTyK0Zu95nkpuC/RCA9LqUjE5NGeRzDE61ITflZmdqxwgYjCj4Odz+2mQCHdsuU/+1rPN2xY9+73CjExlf0KvokkNfKwlZX/sn4O8mMBvhV30bjp3ViBAtaYp6MWggsoRRqIA00mitLtaxwzzHDmFDARPqfNMW/cXF3Yia7/N17JR5Xmhz6+C1WP07pDsCHL0XJ+MpPdJyEPAVB6ZtHRBwHkFadEKZQYH7ezqSW1p/dURf/f97rqrp8KY+viNWwT8R6aFnPPFARVerjfTEyVG29YjqrbchTlZ9LzOieX92KOUiAUBLkzGgEZQXK04GDfsYH+oxQS9yhA6MQ+CNCxRcP/BIDTzEqXKdfTsBqgzBBAOmUkFIztPLDVDJfqqCBMN2TyygxhyH342wj/4ykztX8KxbrxyZ01vKIYEQYuQm4vZPN95k9tWhrac9ovnMQ9bV5jo74DzzQIX8eV2fGbDsovbbDV17tW/xyeVJgGK2WKrV7bm1cUOowOq9/bxyEH1aLM10xXDGtwbrzaZJ3Gke5/OycrxoeNfO25ZkZtmkq4Sdkb0zrlyFgxP911SlPe6q/Yv7x0qNPV1eVrXDcVG7T+frYsPF2ivZrsKmJRg8bxF80o7/cxNZjGVxbmdN6yGH7ZlqujQUcfs/LevyWUs++88fj/WNw2Rh7KO7wz/ocjJplxMs3aJ8LRaPls/+t36wH0dSLfwUucsm2vgAq8V08MxdlSZYPpSPi9UqTteDG+emxlZzvx9a+M2McY1w109043Yh+PDpnzeNB9uddmHhPTE1navxXShCj1fflT9HyXtY4zT6YutO6t3684P/9r6963+8+22NpJkjRlYs/rT//WrP9Xf3yXK96749FPWz1eesHmebITfqASeLsrO8dUhvx+NOU5NltXM8uHE+hABhvludY1Fs/dGYte7FC3Zv2x9+/vQ/DtlWsr//cZ918uK4o396e3vbEHHNi1ckWu3abw+mMlsY5fECE4cH56CIo275nmwWyEPjscJxpx+b/M2kv09Kb6wmeqs1XqT2gtrdqO0HXevBCJpAjfLUDY3HDEdsyS28ljSkreLtdU5CAYD55b5nldW+BXNWmbsvs7SPObxfadf1YA7X1V8WB5nIehar85zglClqBTCEMdPdsWdDQsyGRmRwJFLbqOXSIDdbZB7ctrfEula4SSTqMmoKKFGpKwjTtPHMaSoSnjGoDNNKxyw2FLKfbwlRoGwHooCTNs6c02HTrRHeMkfH+fiHr42zmb1ko+XcNHHrzeEoP+kHt3ur17ckUCZ3wFiy02+4YqF/zx703N926E1uO6tZkMYvaXdgL3Ee4jQhhhmQkowamm7cdmvQ7t53LaRCjXACgMLHKWIKtrKLMbT+4y8ful0d+1lc52iLPAfDNhfI7EHelq0O49eROuGenl0srJldVv6ooLfZ6sSqhLJmFkgjTUBPJaQ0QVwQAVLFcxNRRkPhp1nhIbwgDwQW6DlbIRvbqOoHVS0Xq46qj8u6j2offDtaTRxbPcB+Q93QbPigWdhW218ZPfB+o0svo9ZZ1jX0OM1RqkGtFuStw4GqhBtAlFUQhMabd3qrIo/Y6t2Y1smB87d+s+SO//Cfnz6PdlR+KcvJRs/xayFzu7fsLDQQiHdrIHsg6XsfMU83XU63o9tnHJvuFfmTmuvH+SILyYz9nAqXwaMYqVvIIKwJQbqfGgoTylNKhZEKpSBinw860EaGyTXr9oc9dO2f5jDGlmln4+6TX3M9+mjdek8gwoSE/eRgKBKVA5hmjOtUoXgIsLKxjwABhuwlNMW4nX72kjwXckA21RVRG9XUpgylvSCIoDlNMNQ858AAu/EjOqQF86kdirINqc323+5DarP9qX0prLvuWYiylBreY92YmyRFmeEqS1PBY/Ys9Hq5Qy6HzdxFwNd7wLi1ISlHTI+9VFLW04KR1DAjoktKxGkiJdFcUA3TPI/YFYljn5TDXhg8FCWKkOJKRlTgXSsPlnU/5ruUaGBf626zW05hkjKWq4xwZs3DiB4g7kVpRIDabeCwR+0InU9ate0tUtvu7ZW/L2cgZ70mjZll00qlAlvlSwoSMe1AtBWua2rDoYYtA3ub7W++DRNFD6i6ux5q09qewhCmkvSoTSwnZ0AyA1TKAYrYN3HQYSBEbQgDUvmAYOOQ3OOK3a6V3LXxhJGhOezmdwhrLyVQasNRLjFKI7JyMtCmA3s7EAg8YCT0kNjoLRObrJJ5MkN12lO4CcwTZblnqoT9jMqIcpt4cjukpYUccTHkNj2g4O16qE3roD6WVBnT9YvIFKSJ4LlBSlMBoY5HbcbIbmqHtLQDslGH1H7TXjBal5ZhJSnJ+jWNVifPU20sq89lRiJaYJwNLLDhSFQRaHjMI/hFgm1+3g612YraJqeq5wVzjJ0SbEDKsbQiPaJO7u9tGfB6w5Ab7IB5D8dtZt0cqCeY/Vp+WZ30uU6sswxXEyahtdsUU5c7CfrCgCTAYEpzQ1hKYqr1uN9KxZrsgdxxEfCSE7Q3YAJhkldIHX9a/GfSRxO7ypkgtHYJYJ2rTPTcfQrjBGArZUCKoVYRVQvpd1pCbSuLXS2w5f7sZ0zQbWSTlGsVQGKFAE006/ETi/jEZCyjOcApzEnMeUOeABJyGIZhIeUyQtBtZN+Ua6V2HanBqUyN7lWBUJ0lkOdK4gxzFbMKRKC+C1AGAjVtMKfnAYwQqBnTKCUwBbPXLsBrIzDsHODyXe7UtJi4B/zFTL4aR+gNiTG9RmzuTyfvZt2+YZ9eBL35mk3ng+58Tfer/nzN51GX9KYz6nIbtbtDLdsN1J1h2ZDqTNodCD+tAyBvzuTYHgfSm8wn+XEGVvp3LBuj6MBhksN9MMKiHjbQ2G8bHNhAo94Zndmy9KY7WbYDV9gF6y2nPvbbzesPlx0FahrANDorUHPftw7hgaAW0N8ebByqDwHeiBSXEw2UUd1RMhZnNZLdkkB5S9084+7Al1lZOZq+n5VL/dDcgtepJ6NGZCQEfIFSzFwtRqCHj+QZ4DyOZMWo77ZheJi7HalUY0jY681mYbW7lVAI+olJUoI0YakG0lCjGInoXEd+WYQMhVJC2SwRWguya81mkRi6QnsOUuNC2938BkvVBGlgNGFacxExo9APk0gwdJyvWXdP3yUvJ+XIQS5Xatyw2jVGEOcS90fnIpRkKTAE0kxmIKIp64/zsqZsoE/asUzZN5y7ZKldm7JEqDzvZ6pRoxOYWg5qMEGERfSc49bvuY3aoaRDGYNNv+ncJbbKZsk5TEXPcYEISHJCMOFASaUiCmXKB9QOCOWA5yLG3g72tHs71K6TWYiVz5iyfiUATHKBGKBY6hxlMWOgXqYaJ4FKyFCCQ4xOq/xN+6AZXgnunGvYZeUyz2GiOMuhNnmGEYwYhSB0BLlxYHdjHoHc6E2Tm60MrJQDrvyQA6OSZKnMRQojauXMdwnytqa5F3QK1J3HqBfgI9xvV0xu2pAb5LqXrCYptf8AgikiRsTsdsapp5aHrDAZMsJiUPtaXSOWVG4VrMBDIleOUWvY2tNplmTAvsxMJpGIKJch8H0jItSiIMSpScwORvt1lIEi1FFm1QW3PddjezjrVJo/BppqDjvPvDRv5rnPcbK6pyxxoxYKbbzeKHx7b5SLKTrfn4P4MWrQqmhdUy/OYOgxSQr8oElhrxLBIQj2Yji3UMKxwZr6V59MVdg1c27+PcKSmjGREcQIVVQD14V/9aVuTKcN351JTEfgvrNQtkTdO6TDPW0W+OOE4oV0+Bv2Q7xKxRwHfryODJUZGmpSEEGZEQf4IS5CmXmVOM9ALwV4KFVowF18QO+8ISkP8DFcBClfJc4zsChBu5w78ppiTEhpc20vQBsY5HPES9oYJfJbBnYuIt8bSymlpy+Oz+LwWUkLivgiX+yXRveacOOvjbdWPToTvPl2zMF448I3iHz1IiLeLidd7dXx1kr1c8Eb9sUiODBNjRPsnYkeLU1NhFx2PY+PXgPl2amDDctAZoZ+nufxJpky094MpfPvIhxKVf6Jub/ufsqlavQ7udU038PBB9sCjHZSc2BKAIRxXC27/HuBtpB2sWajXH4k5PIbzOhZT0IJzudpj60uuud4nTh33JmxBezN3tTDpvKymqpZb6xQ6BZ3zwSK4b388mCS2gpRemIWSZknKrF3mqymxSZ2dZO8ngLV9WSK7Z7Mbw/F0ny2+8K9/1apeX8fermfeZ4jrUNSJGOpq+mMk4DguYfgenhBb6BBYGcc0D1ljBNSjHBCniib94/H6fzX2btuTi+kt1b5apJ6EVsl9dbf/8Uod2VKPU7HbsJZv2eX6UsGyd/BNs0hsR6j+4I/cPGQNkpnPgY2m8Hboh58OMtM1fCghu24487rYOzRqbHKS6JmWZI+LoqZWSwS97HlPVai3EFX63TnHBfHnvsKSWgb5ZNi/ssuFXMPH0cPdGToqoIyADnomxgHeTj2gJh+rCZP7yuLDFNL2O2svAbP2k4YTaA1xgIEstRBd3IMgbrcxirCNbeJQCjh6crrnKTukGgeiHcfoEINSCUPcBFfS0BA1AnAd4JCmmam165DMJVowjIGlGQwi+hFln7jJTKsqISh2KRf5/MChdkatLNsNUO1M091m3Y3KWdZObudPiWNQndblPUnXS1t5a3YqKVdLYyk0+zudGoEIabObzUNjKzoTbiQMoMEaajatg4+p4mhZPTNMCRC07MCGVLQt/Bjd3nY06pho+ywNWpv/1gcYIwFzK7RuSE7za5n/8GqH/xG/8GehuHL7nA123r29GwXOvzvd2u9vU5fYpENBXf9JyC4qfs7RjjH30OknULQ7Sffas+9LMP9i3/GGGxyRCrahZZfnsYEX4+xb31Tgbq8I0/D0o8LJ8s6cnaxXdCOdaN8qE+cfPROu8bOGx2LJd1AuTsj0wyKlHREsTRYJxxRTFCa6kyr44liyPv2/h6y+DhD9uT5eH4uk5Ew35YeNtg7Vqm2HGFK/0W7bbtR0lcj3rom4S/qHUg9v0sCBcPw0pFF+Of/97M9kKrs3uVXg7yq5bk7W6EjCfOfzcxUaukyut8310E9GKE3Ks1X1SdS4hTUqWHt6DuR0TTBxigIeZpmdJNh3Y+V4khmgtdRkdCAfGcB+Y72L2kYI94hGJHh8xeX2dr2oV8++gqGQhxGoua3tdPhdvHgs5A36ptjrG6SSVKQZ7BXr2ggTBgxqaaYM6YjTqqy/Nqf2w7QAFAhHy+NEvp9hZarZqqVdozEQx17o6jjYIU6qFjeS09PMUiwhJBIwCnCERv9Mkp80A39V22dfC+wEMXq3AQ6u2hddckCAsN6uZ1D8ql8rBwkdFXMl5GUKStfTPHV6VJtg+nm4olT3RIr7iaTpHfFZ7ju13T6iuCKarhmyGSq144FC5owlXGRGpJxrbfrWfYtGmhdsdwqGPaFNAGBVqRxqoJHaV3wTXd94KuuDxnJvc7DFKKEZing2HBkZMRBB+ufPA86GObR0ACD8/t+vrqaZqaqmCRW7S1yS0mHAZ8Twe3hlQvLzzkQYqvWA7ndwllPhmaGJcxyIytHlVLrevXn3BDgWzn3E3sV3+LZnF5ub6zQ7Xn2STXvGC9NXvs+GUGb8naPEeviuK8toBA3DY1/ihLrOr2GWqk0LZbT//j77I3GSRhf1U/mUPBeXw+JsLRvFRCIKiVRxFJYhr0mTajt+9BLSgsw8Lao8ixB1/D0+ePioXQZzFvZ+ltVMEHNywEH2GT9IcMySxDjOYPYQBpzPjzzor+QBtDWKocvbAk2SmFEB6TaXaVgJzUYEKcqzXvtADPkyqSYSgUhOU/TY+fhoqDTMwL2ZD9qwQMR4JCD+IDq4tNL0vvyd/N9/lVVHm/rLclb4W2cUeEe/E5CgrI0VwmRQrddJQRKoMgo0ywTksQcoO5VXcH1/NQecwv0ImDnLEp91M3KzNSYy6tyVjz60hTtFxY7dTsEB6Gk/mixEVR211AJnFfszhWFA45AQrUwiEORMN626BLAvuVUcsaN1JxFnPCCfV81EcMQK2wb7vU6lFySKbCG0mJZGHsRM7FCZeYDCl8ZoKikFCcyhZRKRCyg0qz1Q1s1LHU2ds6A5jxi9EP6EyoID8RHRZyWN2dhW87Lb6bKBso+2s+Hc4YCcQzgnqUhBoJLgUFCBINWHopEYSAbvLFcJwISyRW2DIZEbAbL2t7aaz2fDDN8EAzgDV8o3vSDZV1PPtouPtS2N9qsVEQywTkAeSaYQ5tqJ2kLbg2J3BCIudE4Incjng+D0mGQDaKA4nXWYGt8GLlreLHVgYEu3oGxJ8oQppRbVkYhyjLFSKIBbniagJAnqcZQAZ1TYCKiDON+xum6F1UXZSTkKUNnjLItLC01arZYqsmfPt7kW8MbgZRRkiiRS5VhnWhEaCNDAcoTA0ia5YAxaPpGwABcAQhuxBvlvs4WaG0XarmMo9gA9lBVlsvO1392WWW/WZ3d/eh/AQ==</diagram></mxfile>
\ No newline at end of file diff --git a/docker-build.sh b/docker-build.sh index 1112ccb6..fd056c39 100644 --- a/docker-build.sh +++ b/docker-build.sh @@ -8,9 +8,6 @@ DEBIAN_FRONTEND=noninteractive # some mirrors have issues, i skipped httpredir in favor of an eu mirror -echo "deb http://ftp.nl.debian.org/debian/ jessie main" > /etc/apt/sources.list -echo "deb http://security.debian.org/debian-security jessie/updates main" >> /etc/apt/sources.list - # install dependencies for build apt-get -qq update diff --git a/installer/functions.sh b/installer/functions.sh index cfc2d7ea..d403bfe5 100644 --- a/installer/functions.sh +++ b/installer/functions.sh @@ -120,6 +120,7 @@ netdata_banner() { # portable service command service_cmd="$(which_cmd service)" +rcservice_cmd="$(which_cmd rc-service)" systemctl_cmd="$(which_cmd systemctl)" service() { local cmd="${1}" action="${2}" @@ -132,6 +133,10 @@ service() { then run "${service_cmd}" "${cmd}" "${action}" return $? + elif [ ! -z "${rcservice_cmd}" ] + then + run "${rcservice_cmd}" "${cmd}" "${action}" + return $? fi return 1 } @@ -437,7 +442,7 @@ install_non_systemd_init() { run update-rc.d netdata defaults && \ run update-rc.d netdata enable && \ return 0 - elif [[ "${key}" =~ ^(amzn-201[567]|ol|CentOS release 6|Red Hat Enterprise Linux Server release 6).* ]] + elif [[ "${key}" =~ ^(amzn-201[567]|ol|CentOS release 6|Red Hat Enterprise Linux Server release 6|Scientific Linux CERN SLC release 6|CloudLinux Server release 6).* ]] then echo >&2 "Installing init.d file..." run cp system/netdata-init-d /etc/init.d/netdata && \ @@ -488,8 +493,15 @@ install_netdata_service() { if [ ${ret} -eq 0 ] then - NETDATA_START_CMD="service netdata start" - NETDATA_STOP_CMD="service netdata stop" + if [ ! -z "${service_cmd}" ] + then + NETDATA_START_CMD="service netdata start" + NETDATA_STOP_CMD="service netdata stop" + elif [ ! -z "${rcservice_cmd}" ] + then + NETDATA_START_CMD="rc-service netdata start" + NETDATA_STOP_CMD="rc-service netdata stop" + fi fi return ${ret} @@ -628,6 +640,84 @@ install_netdata_logrotate() { } # ----------------------------------------------------------------------------- +# download netdata.conf + +fix_netdata_conf() { + local owner="${1}" + + if [ "${UID}" -eq 0 ] + then + run chown "${owner}" "${filename}" + fi + run chmod 0664 "${filename}" +} + +generate_netdata_conf() { + local owner="${1}" filename="${2}" url="${3}" + + if [ ! -s "${filename}" ] + then + cat >"${filename}" <<EOFCONF +# netdata can generate its own config. +# Get it with: +# +# wget -O ${filename} "${url}" +# +# or +# +# curl -s -o ${filename} "${url}" +# +EOFCONF + fix_netdata_conf "${owner}" + fi +} + +download_netdata_conf() { + local owner="${1}" filename="${2}" url="${3}" + + if [ ! -s "${filename}" ] + then + echo >&2 + echo >&2 "-------------------------------------------------------------------------------" + echo >&2 + echo >&2 "Downloading default configuration from netdata..." + sleep 5 + + # remove a possibly obsolete download + [ -f "${filename}.new" ] && rm "${filename}.new" + + # disable a proxy to get data from the local netdata + export http_proxy= + export https_proxy= + + # try curl + run curl -s -o "${filename}.new" "${url}" + ret=$? + + if [ ${ret} -ne 0 -o ! -s "${filename}.new" ] + then + # try wget + run wget -O "${filename}.new" "${url}" + ret=$? + fi + + if [ ${ret} -eq 0 -a -s "${filename}.new" ] + then + run mv "${filename}.new" "${filename}" + run_ok "New configuration saved for you to edit at ${filename}" + else + [ -f "${filename}.new" ] && rm "${filename}.new" + run_failed "Cannnot download configuration from netdata daemon using url '${url}'" + + generate_netdata_conf "${owner}" "${filename}" "${url}" + fi + + fix_netdata_conf "${owner}" + fi +} + + +# ----------------------------------------------------------------------------- # add netdata user and group NETDATA_ADDED_TO_DOCKER=0 @@ -642,15 +732,15 @@ add_netdata_user_and_group() { if [ ${UID} -eq 0 ] then portable_add_group netdata || return 1 - portable_add_user netdata || return 1 + portable_add_user netdata || return 1 portable_add_user_to_group docker netdata && NETDATA_ADDED_TO_DOCKER=1 portable_add_user_to_group nginx netdata && NETDATA_ADDED_TO_NGINX=1 portable_add_user_to_group varnish netdata && NETDATA_ADDED_TO_VARNISH=1 portable_add_user_to_group haproxy netdata && NETDATA_ADDED_TO_HAPROXY=1 portable_add_user_to_group adm netdata && NETDATA_ADDED_TO_ADM=1 portable_add_user_to_group nsd netdata && NETDATA_ADDED_TO_NSD=1 - portable_add_user_to_group proxy netdata && NETDATA_ADDED_TO_PROXY=1 - portable_add_user_to_group squid netdata && NETDATA_ADDED_TO_SQUID=1 + portable_add_user_to_group proxy netdata && NETDATA_ADDED_TO_PROXY=1 + portable_add_user_to_group squid netdata && NETDATA_ADDED_TO_SQUID=1 return 0 fi diff --git a/makeself/install-or-update.sh b/makeself/install-or-update.sh index b64e7be3..34630cf1 100755 --- a/makeself/install-or-update.sh +++ b/makeself/install-or-update.sh @@ -162,7 +162,9 @@ progress "starting netdata" restart_netdata "/opt/netdata/bin/netdata" if [ $? -eq 0 ] then + download_netdata_conf "${NETDATA_USER}:${NETDATA_GROUP}" "/opt/netdata/etc/netdata/netdata.conf" "http://localhost:19999/netdata.conf" netdata_banner "is installed and running now!" else + generate_netdata_conf "${NETDATA_USER}:${NETDATA_GROUP}" "/opt/netdata/etc/netdata/netdata.conf" "http://localhost:19999/netdata.conf" netdata_banner "is installed now!" fi diff --git a/makeself/jobs/70-netdata-git.install.sh b/makeself/jobs/70-netdata-git.install.sh index 0486ce11..b8548149 100755 --- a/makeself/jobs/70-netdata-git.install.sh +++ b/makeself/jobs/70-netdata-git.install.sh @@ -11,6 +11,13 @@ else export CFLAGS="-static -O1 -ggdb -Wall -Wextra -Wformat-signedness -fstack-protector-all -D_FORTIFY_SOURCE=2 -DNETDATA_INTERNAL_CHECKS=1" fi +if [ ! -z "${NETDATA_INSTALL_PATH}" -a -d "${NETDATA_INSTALL_PATH}/etc" ] + then + # make sure we don't have an old etc path, so that the installer + # will install all files without examining changes + run mv "${NETDATA_INSTALL_PATH}/etc" "${NETDATA_INSTALL_PATH}/etc.new" +fi + run ./netdata-installer.sh --install "${NETDATA_INSTALL_PARENT}" \ --dont-wait \ --dont-start-it \ @@ -20,4 +27,5 @@ if [ ${NETDATA_BUILD_WITH_DEBUG} -eq 0 ] then run strip ${NETDATA_INSTALL_PATH}/bin/netdata run strip ${NETDATA_INSTALL_PATH}/usr/libexec/netdata/plugins.d/apps.plugin + run strip ${NETDATA_INSTALL_PATH}/usr/libexec/netdata/plugins.d/cgroup-network fi diff --git a/makeself/jobs/99-makeself.install.sh b/makeself/jobs/99-makeself.install.sh index 465a3195..698f2f92 100755 --- a/makeself/jobs/99-makeself.install.sh +++ b/makeself/jobs/99-makeself.install.sh @@ -2,14 +2,46 @@ . $(dirname "${0}")/../functions.sh "${@}" || exit 1 +run cd "${NETDATA_SOURCE_PATH}" || exit 1 + +# ----------------------------------------------------------------------------- +# find the netdata version + +NOWNER="unknown" +ORIGIN="$(git config --get remote.origin.url || echo "unknown")" +if [[ "${ORIGIN}" =~ ^git@github.com:.*/netdata.*$ ]] + then + NOWNER="${ORIGIN/git@github.com:/}" + NOWNER="${NOWNER/\/netdata*/}" + +elif [[ "${ORIGIN}" =~ ^https://github.com/.*/netdata.*$ ]] + then + NOWNER="${ORIGIN/https:\/\/github.com\//}" + NOWNER="${NOWNER/\/netdata*/}" +fi + +# make sure it does not have any slashes in it +NOWNER="${NOWNER//\//_}" + +if [ "${NOWNER}" = "firehol" ] + then + NOWNER= +else + NOWNER="-${NOWNER}" +fi + +VERSION="$(git describe || echo "undefined")" +[ -z "${VERSION}" ] && VERSION="undefined" + +FILE_VERSION="${VERSION}-$(uname -m)-$(date +"%Y%m%d-%H%M%S")${NOWNER}" + # ----------------------------------------------------------------------------- # copy the files needed by makeself installation run mkdir -p "${NETDATA_INSTALL_PATH}/system" -run cd "${NETDATA_SOURCE_PATH}" || exit 1 -cp \ +run cp \ makeself/post-installer.sh \ makeself/install-or-update.sh \ installer/functions.sh \ @@ -25,9 +57,9 @@ cp \ # ----------------------------------------------------------------------------- # create a wrapper to start our netdata with a modified path -mkdir -p "${NETDATA_INSTALL_PATH}/bin/srv" +run mkdir -p "${NETDATA_INSTALL_PATH}/bin/srv" -mv "${NETDATA_INSTALL_PATH}/bin/netdata" \ +run mv "${NETDATA_INSTALL_PATH}/bin/netdata" \ "${NETDATA_INSTALL_PATH}/bin/srv/netdata" || exit 1 cat >"${NETDATA_INSTALL_PATH}/bin/netdata" <<EOF @@ -35,28 +67,34 @@ cat >"${NETDATA_INSTALL_PATH}/bin/netdata" <<EOF export PATH="${NETDATA_INSTALL_PATH}/bin:\${PATH}" exec "${NETDATA_INSTALL_PATH}/bin/srv/netdata" "\${@}" EOF -chmod 755 "${NETDATA_INSTALL_PATH}/bin/netdata" +run chmod 755 "${NETDATA_INSTALL_PATH}/bin/netdata" # ----------------------------------------------------------------------------- # move etc to protect the destination when unpacked -if [ -d "${NETDATA_INSTALL_PATH}/etc" ] +if [ ! -z "${NETDATA_INSTALL_PATH}" -a -d "${NETDATA_INSTALL_PATH}/etc" ] then if [ -d "${NETDATA_INSTALL_PATH}/etc.new" ] then - rm -rf "${NETDATA_INSTALL_PATH}/etc.new" || exit 1 + run rm -rf "${NETDATA_INSTALL_PATH}/etc.new" || exit 1 fi - mv "${NETDATA_INSTALL_PATH}/etc" \ + run mv "${NETDATA_INSTALL_PATH}/etc" \ "${NETDATA_INSTALL_PATH}/etc.new" || exit 1 + + if [ -f "${NETDATA_INSTALL_PATH}/etc.new/netdata/netdata.conf" ] + then + # delete the generated netdata.conf, so that the static installer will generate a new one + run rm "${NETDATA_INSTALL_PATH}/etc.new/netdata/netdata.conf" + fi fi # ----------------------------------------------------------------------------- # remove the links to allow untaring the archive -rm "${NETDATA_INSTALL_PATH}/sbin" \ +run rm "${NETDATA_INSTALL_PATH}/sbin" \ "${NETDATA_INSTALL_PATH}/usr/bin" \ "${NETDATA_INSTALL_PATH}/usr/sbin" \ "${NETDATA_INSTALL_PATH}/usr/local" @@ -65,14 +103,16 @@ rm "${NETDATA_INSTALL_PATH}/sbin" \ # ----------------------------------------------------------------------------- # create the makeself archive -"${NETDATA_MAKESELF_PATH}/makeself.sh" \ +run sed "s|NETDATA_VERSION|${FILE_VERSION}|g" <"${NETDATA_MAKESELF_PATH}/makeself.lsm" >"${NETDATA_MAKESELF_PATH}/makeself.lsm.tmp" + +run "${NETDATA_MAKESELF_PATH}/makeself.sh" \ --gzip \ --complevel 9 \ --notemp \ --needroot \ --target "${NETDATA_INSTALL_PATH}" \ --header "${NETDATA_MAKESELF_PATH}/makeself-header.sh" \ - --lsm "${NETDATA_MAKESELF_PATH}/makeself.lsm" \ + --lsm "${NETDATA_MAKESELF_PATH}/makeself.lsm.tmp" \ --license "${NETDATA_MAKESELF_PATH}/makeself-license.txt" \ --help-header "${NETDATA_MAKESELF_PATH}/makeself-help-header.txt" \ "${NETDATA_INSTALL_PATH}" \ @@ -81,41 +121,16 @@ rm "${NETDATA_INSTALL_PATH}/sbin" \ ./system/post-installer.sh \ ${NULL} +run rm "${NETDATA_MAKESELF_PATH}/makeself.lsm.tmp" # ----------------------------------------------------------------------------- # copy it to the netdata build dir -NOWNER="unknown" -ORIGIN="$(git config --get remote.origin.url || echo "unknown")" -if [[ "${ORIGIN}" =~ ^git@github.com:.*/netdata.*$ ]] - then - NOWNER="${ORIGIN/git@github.com:/}" - NOWNER="${NOWNER/\/netdata*/}" - -elif [[ "${ORIGIN}" =~ ^https://github.com/.*/netdata.*$ ]] - then - NOWNER="${ORIGIN/https:\/\/github.com\//}" - NOWNER="${NOWNER/\/netdata*/}" -fi - -# make sure it does not have any slashes in it -NOWNER="${NOWNER//\//_}" - -if [ "${NOWNER}" = "firehol" ] - then - NOWNER= -else - NOWNER="-${NOWNER}" -fi - -VERSION="$(git describe || echo "undefined")" -[ -z "${VERSION}" ] && VERSION="undefined" - -FILE="netdata-${VERSION}-$(uname -m)-$(date +"%Y%m%d-%H%M%S")${NOWNER}.gz.run" +FILE="netdata-${FILE_VERSION}.gz.run" -cp "${NETDATA_INSTALL_PATH}.gz.run" "${FILE}" +run cp "${NETDATA_INSTALL_PATH}.gz.run" "${FILE}" echo >&2 "Self-extracting installer copied to '${FILE}'" [ -f netdata-latest.gz.run ] && rm netdata-latest.gz.run -ln -s "${FILE}" netdata-latest.gz.run +run ln -s "${FILE}" netdata-latest.gz.run echo >&2 "Self-extracting installer linked to 'netdata-latest.gz.run'" diff --git a/makeself/makeself-header.sh b/makeself/makeself-header.sh index 93d937b3..83131a17 100755 --- a/makeself/makeself-header.sh +++ b/makeself/makeself-header.sh @@ -218,10 +218,9 @@ MS_Check() UnTAR() { if test x"\$quiet" = xn; then - tar \$1 "$UNTAR_EXTRA" -vf - 2>&1 || { echo Extraction failed. > /dev/tty; kill -15 \$$; } + tar \$1vf - $UNTAR_EXTRA 2>&1 || { echo " ... Extraction failed." > /dev/tty; kill -15 \$$; } else - - tar \$1 "$UNTAR_EXTRA" -f - 2>&1 || { echo Extraction failed. > /dev/tty; kill -15 \$$; } + tar \$1f - $UNTAR_EXTRA 2>&1 || { echo Extraction failed. > /dev/tty; kill -15 \$$; } fi } diff --git a/makeself/makeself.lsm b/makeself/makeself.lsm index 02679629..6bd4703d 100644 --- a/makeself/makeself.lsm +++ b/makeself/makeself.lsm @@ -1,6 +1,6 @@ Begin3 Title: netdata -Version: 1.6.0 +Version: NETDATA_VERSION Description: netdata is a system for distributed real-time performance and health monitoring. It provides unparalleled insights, in real-time, of everything happening on the system it runs (including applications such as web and database servers), using diff --git a/makeself/makeself.sh b/makeself/makeself.sh index 709473aa..2ce37a24 100755 --- a/makeself/makeself.sh +++ b/makeself/makeself.sh @@ -470,8 +470,8 @@ gpg-asymmetric) GUNZIP_CMD="gpg --yes -d" ;; openssl) - GZIP_CMD="openssl aes-256-cbc -a -salt" - GUNZIP_CMD="openssl aes-256-cbc -d -a" + GZIP_CMD="openssl aes-256-cbc -a -salt -md sha256" + GUNZIP_CMD="openssl aes-256-cbc -d -a -md sha256" ;; Unix) GZIP_CMD="compress -cf" @@ -529,7 +529,8 @@ if test "$QUIET" = "n";then echo Adding files to archive named \"$archname\"... fi exec 3<> "$tmpfile" -(cd "$archdir" && ( tar "$TAR_EXTRA" -$TAR_ARGS - . | eval "$GZIP_CMD" >&3 ) ) || { echo Aborting: Archive directory not found or temporary file: "$tmpfile" could not be created.; exec 3>&-; rm -f "$tmpfile"; exit 1; } +( cd "$archdir" && ( tar $TAR_EXTRA -$TAR_ARGS - . | eval "$GZIP_CMD" >&3 ) ) || \ + { echo Aborting: archive directory not found or temporary file: "$tmpfile" could not be created.; exec 3>&-; rm -f "$tmpfile"; exit 1; } exec 3>&- # try to close the archive fsize=`cat "$tmpfile" | wc -c | tr -d " "` @@ -617,4 +618,3 @@ else fi fi rm -f "$tmpfile" - diff --git a/netdata-installer.sh b/netdata-installer.sh index f3f444f6..356eb4e4 100755 --- a/netdata-installer.sh +++ b/netdata-installer.sh @@ -817,16 +817,7 @@ install_netdata_service || run_failed "Cannot install netdata init service." started=0 if [ ${DONOTSTART} -eq 1 ] then - if [ ! -s "${NETDATA_PREFIX}/etc/netdata/netdata.conf" ] - then - echo "# Get config from http://127.0.0.1:${NETDATA_PORT}/netdata.conf" >"${NETDATA_PREFIX}/etc/netdata/netdata.conf" - - if [ "${UID}" -eq 0 ] - then - chown "${NETDATA_USER}" "${NETDATA_PREFIX}/etc/netdata/netdata.conf" - fi - chmod 0644 "${NETDATA_PREFIX}/etc/netdata/netdata.conf" - fi + generate_netdata_conf "${NETDATA_USER}" "${NETDATA_PREFIX}/etc/netdata/netdata.conf" "http://localhost:${NETDATA_PORT}/netdata.conf" else restart_netdata ${NETDATA_PREFIX}/usr/sbin/netdata "${@}" @@ -845,47 +836,7 @@ else # ----------------------------------------------------------------------------- # save a config file, if it is not already there - if [ ! -s "${NETDATA_PREFIX}/etc/netdata/netdata.conf" ] - then - echo >&2 - echo >&2 "-------------------------------------------------------------------------------" - echo >&2 - echo >&2 "Downloading default configuration from netdata..." - sleep 5 - - # remove a possibly obsolete download - [ -f "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" ] && rm "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" - - # disable a proxy to get data from the local netdata - export http_proxy= - export https_proxy= - - # try wget - wget 2>/dev/null -O "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" "http://localhost:${NETDATA_PORT}/netdata.conf" - ret=$? - - # try curl - if [ ${ret} -ne 0 -o ! -s "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" ] - then - curl -s -o "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" "http://localhost:${NETDATA_PORT}/netdata.conf" - ret=$? - fi - - if [ ${ret} -eq 0 -a -s "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" ] - then - mv "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" "${NETDATA_PREFIX}/etc/netdata/netdata.conf" - echo >&2 "New configuration saved for you to edit at ${NETDATA_PREFIX}/etc/netdata/netdata.conf" - - if [ "${UID}" -eq 0 ] - then - chown "${NETDATA_USER}" "${NETDATA_PREFIX}/etc/netdata/netdata.conf" - fi - chmod 0664 "${NETDATA_PREFIX}/etc/netdata/netdata.conf" - else - echo >&2 "Cannnot download configuration from netdata daemon using url 'http://localhost:${NETDATA_PORT}/netdata.conf'" - [ -f "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" ] && rm "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" - fi - fi + download_netdata_conf "${NETDATA_USER}" "${NETDATA_PREFIX}/etc/netdata/netdata.conf" "http://localhost:${NETDATA_PORT}/netdata.conf" fi # ----------------------------------------------------------------------------- diff --git a/netdata.spec b/netdata.spec index bb817135..b614e212 100644 --- a/netdata.spec +++ b/netdata.spec @@ -9,6 +9,7 @@ # Conditional build: %bcond_without systemd # systemd %bcond_with nfacct # build with nfacct plugin +%bcond_with freeipmi # build with freeipmi plugin %if 0%{?fedora} || 0%{?rhel} >= 7 || 0%{?suse_version} >= 1140 %else @@ -77,11 +78,11 @@ Recommends: python2-psycopg2 \ Summary: Real-time performance monitoring, done right Name: netdata -Version: 1.8.0 +Version: 1.9.0 Release: 1%{?dist} License: GPLv3+ Group: Applications/System -Source0: https://github.com/firehol/%{name}/releases/download/v1.8.0/%{name}-1.8.0.tar.xz +Source0: https://github.com/firehol/%{name}/releases/download/v1.9.0/%{name}-1.9.0.tar.xz URL: http://my-netdata.io BuildRequires: pkgconfig BuildRequires: xz @@ -98,6 +99,11 @@ Requires: libmnl Requires: libnetfilter_acct %endif +%if %{with freeipmi} +BuildRequires: freeipmi-devel +Requires: freeipmi +%endif + Requires(pre): /usr/sbin/groupadd Requires(pre): /usr/sbin/useradd Requires(post): libcap @@ -117,13 +123,14 @@ so that you can get insights of what is happening now and what just happened, on your systems and applications. %prep -%setup -q -n netdata-1.8.0 +%setup -q -n netdata-1.9.0 %build %configure \ --with-zlib \ --with-math \ %{?with_nfacct:--enable-plugin-nfacct} \ + %{?with_freeipmi:--enable-plugin-freeipmi} \ --with-user=netdata %{__make} %{?_smp_mflags} @@ -187,6 +194,16 @@ rm -rf "${RPM_BUILD_ROOT}" %caps(cap_dac_read_search,cap_sys_ptrace=ep) %attr(0555,root,root) %{_libexecdir}/%{name}/plugins.d/apps.plugin +# cgroup-network detects the network interfaces of CGROUPs +# it must be able to use setns() and run cgroup-network-helper.sh as root +# the helper script reads /proc/PID/fdinfo/* files, runs virsh, etc. +%caps(cap_setuid=ep) %attr(4555,root,root) %{_libexecdir}/%{name}/plugins.d/cgroup-network +%attr(0555,root,root) %{_libexecdir}/%{name}/plugins.d/cgroup-network-helper.sh + +%if %{with freeipmi} +%caps(cap_setuid=ep) %attr(4555,root,root) %{_libexecdir}/%{name}/plugins.d/freeipmi.plugin +%endif + %attr(0700,netdata,netdata) %dir %{_localstatedir}/cache/%{name} %attr(0700,netdata,netdata) %dir %{_localstatedir}/log/%{name} %attr(0700,netdata,netdata) %dir %{_localstatedir}/lib/%{name} @@ -207,6 +224,9 @@ rm -rf "${RPM_BUILD_ROOT}" %{_datadir}/%{name}/web %changelog +* Sun Dec 17 2017 Costa Tsaousis <costa@tsaousis.gr> - 1.9.0-1 + Please check full changelog at github. + https://github.com/firehol/netdata/releases * Mon Sep 17 2017 Costa Tsaousis <costa@tsaousis.gr> - 1.8.0-1 This is mainly a bugfix release. Please check full changelog at github. diff --git a/netdata.spec.in b/netdata.spec.in index eef2a089..cd8ef6d3 100644 --- a/netdata.spec.in +++ b/netdata.spec.in @@ -9,6 +9,7 @@ # Conditional build: %bcond_without systemd # systemd %bcond_with nfacct # build with nfacct plugin +%bcond_with freeipmi # build with freeipmi plugin %if 0%{?fedora} || 0%{?rhel} >= 7 || 0%{?suse_version} >= 1140 %else @@ -98,6 +99,11 @@ Requires: libmnl Requires: libnetfilter_acct %endif +%if %{with freeipmi} +BuildRequires: freeipmi-devel +Requires: freeipmi +%endif + Requires(pre): /usr/sbin/groupadd Requires(pre): /usr/sbin/useradd Requires(post): libcap @@ -124,6 +130,7 @@ happened, on your systems and applications. --with-zlib \ --with-math \ %{?with_nfacct:--enable-plugin-nfacct} \ + %{?with_freeipmi:--enable-plugin-freeipmi} \ --with-user=netdata %{__make} %{?_smp_mflags} @@ -187,6 +194,16 @@ rm -rf "${RPM_BUILD_ROOT}" %caps(cap_dac_read_search,cap_sys_ptrace=ep) %attr(0555,root,root) %{_libexecdir}/%{name}/plugins.d/apps.plugin +# cgroup-network detects the network interfaces of CGROUPs +# it must be able to use setns() and run cgroup-network-helper.sh as root +# the helper script reads /proc/PID/fdinfo/* files, runs virsh, etc. +%caps(cap_setuid=ep) %attr(4555,root,root) %{_libexecdir}/%{name}/plugins.d/cgroup-network +%attr(0555,root,root) %{_libexecdir}/%{name}/plugins.d/cgroup-network-helper.sh + +%if %{with freeipmi} +%caps(cap_setuid=ep) %attr(4555,root,root) %{_libexecdir}/%{name}/plugins.d/freeipmi.plugin +%endif + %attr(0700,netdata,netdata) %dir %{_localstatedir}/cache/%{name} %attr(0700,netdata,netdata) %dir %{_localstatedir}/log/%{name} %attr(0700,netdata,netdata) %dir %{_localstatedir}/lib/%{name} @@ -207,6 +224,9 @@ rm -rf "${RPM_BUILD_ROOT}" %{_datadir}/%{name}/web %changelog +* Sun Dec 17 2017 Costa Tsaousis <costa@tsaousis.gr> - 1.9.0-1 + Please check full changelog at github. + https://github.com/firehol/netdata/releases * Mon Sep 17 2017 Costa Tsaousis <costa@tsaousis.gr> - 1.8.0-1 This is mainly a bugfix release. Please check full changelog at github. diff --git a/node.d/named.node.js b/node.d/named.node.js index 3d794655..02c890c6 100644 --- a/node.d/named.node.js +++ b/node.d/named.node.js @@ -201,7 +201,7 @@ var named = { r = JSON.parse(data); if(typeof r === 'undefined' || r === null) { - netdata.serviceError(service, "Cannot parse these data: " + data); + service.error("Cannot parse these data: " + data.toString()); return; } diff --git a/node.d/node_modules/netdata.js b/node.d/node_modules/netdata.js index 143255d9..4ab8308c 100644 --- a/node.d/node_modules/netdata.js +++ b/node.d/node_modules/netdata.js @@ -68,7 +68,6 @@ var netdata = { modules_configuring: 0, charts: {}, - processors: { http: { name: 'http', @@ -245,7 +244,13 @@ var netdata = { if(__DEBUG === true) netdata.debug(service.module.name + ': ' + service.name + ': processing ' + service.processor.name + ' response (received in ' + (service.ended - service.started).toString() + ' ms)'); - responseProcessor(service, response); + try { + responseProcessor(service, response); + } + catch(e) { + netdata.error(e); + service.error("responseProcessor failed process response data."); + } service.running = false; service.module.active--; diff --git a/plugins.d/Makefile.am b/plugins.d/Makefile.am index 7d3bc44f..41e6d536 100644 --- a/plugins.d/Makefile.am +++ b/plugins.d/Makefile.am @@ -12,6 +12,7 @@ dist_plugins_SCRIPTS = \ alarm-notify.sh \ alarm-test.sh \ cgroup-name.sh \ + cgroup-network-helper.sh \ charts.d.dryrun-helper.sh \ charts.d.plugin \ fping.plugin \ diff --git a/plugins.d/Makefile.in b/plugins.d/Makefile.in index 256605f5..059d68f6 100644 --- a/plugins.d/Makefile.in +++ b/plugins.d/Makefile.in @@ -306,6 +306,7 @@ dist_plugins_SCRIPTS = \ alarm-notify.sh \ alarm-test.sh \ cgroup-name.sh \ + cgroup-network-helper.sh \ charts.d.dryrun-helper.sh \ charts.d.plugin \ fping.plugin \ diff --git a/plugins.d/alarm-notify.sh b/plugins.d/alarm-notify.sh index 9b7f6c8d..0af98095 100755 --- a/plugins.d/alarm-notify.sh +++ b/plugins.d/alarm-notify.sh @@ -219,11 +219,13 @@ sendmail= # enable / disable features SEND_SLACK="YES" +SEND_FLOCK="YES" SEND_DISCORD="YES" SEND_PUSHOVER="YES" SEND_TWILIO="YES" SEND_HIPCHAT="YES" SEND_MESSAGEBIRD="YES" +SEND_KAVENEGAR="YES" SEND_TELEGRAM="YES" SEND_EMAIL="YES" SEND_PUSHBULLET="YES" @@ -236,6 +238,11 @@ SLACK_WEBHOOK_URL= DEFAULT_RECIPIENT_SLACK= declare -A role_recipients_slack=() +# flock configs +FLOCK_WEBHOOK_URL= +DEFAULT_RECIPIENT_FLOCK= +declare -A role_recipients_flock=() + # discord configs DISCORD_WEBHOOK_URL= DEFAULT_RECIPIENT_DISCORD= @@ -248,6 +255,7 @@ declare -A role_recipients_pushover=() # pushbullet configs PUSHBULLET_ACCESS_TOKEN= +PUSHBULLET_SOURCE_DEVICE= DEFAULT_RECIPIENT_PUSHBULLET= declare -A role_recipients_pushbullet=() @@ -270,6 +278,12 @@ MESSAGEBIRD_NUMBER= DEFAULT_RECIPIENT_MESSAGEBIRD= declare -A role_recipients_messagebird=() +# kavenegar configs +KAVENEGAR_API_KEY="" +KAVENEGAR_SENDER="" +DEFAULT_RECIPIENT_KAVENEGAR=() +declare -A role_recipients_kavenegar="" + # telegram configs TELEGRAM_BOT_TOKEN= DEFAULT_RECIPIENT_TELEGRAM= @@ -372,6 +386,7 @@ filter_recipient_by_criticality() { # find the recipients' addresses per method declare -A arr_slack=() +declare -A arr_flock=() declare -A arr_discord=() declare -A arr_pushover=() declare -A arr_pushbullet=() @@ -382,6 +397,7 @@ declare -A arr_pd=() declare -A arr_email=() declare -A arr_custom=() declare -A arr_messagebird=() +declare -A arr_kavenegar=() # netdata may call us with multiple roles, and roles may have multiple but # overlapping recipients - so, here we find the unique recipients. @@ -439,6 +455,14 @@ do [ "${r}" != "disabled" ] && filter_recipient_by_criticality messagebird "${r}" && arr_messagebird[${r/|*/}]="1" done + # kavenegar + a="${role_recipients_kavenegar[${x}]}" + [ -z "${a}" ] && a="${DEFAULT_RECIPIENT_KAVENEGAR}" + for r in ${a//,/ } + do + [ "${r}" != "disabled" ] && filter_recipient_by_criticality kavenegar "${r}" && arr_kavenegar[${r/|*/}]="1" + done + # telegram a="${role_recipients_telegram[${x}]}" [ -z "${a}" ] && a="${DEFAULT_RECIPIENT_TELEGRAM}" @@ -455,6 +479,14 @@ do [ "${r}" != "disabled" ] && filter_recipient_by_criticality slack "${r}" && arr_slack[${r/|*/}]="1" done + # flock + a="${role_recipients_flock[${x}]}" + [ -z "${a}" ] && a="${DEFAULT_RECIPIENT_FLOCK}" + for r in ${a//,/ } + do + [ "${r}" != "disabled" ] && filter_recipient_by_criticality flock "${r}" && arr_flock[${r/|*/}]="1" + done + # discord a="${role_recipients_discord[${x}]}" [ -z "${a}" ] && a="${DEFAULT_RECIPIENT_DISCORD}" @@ -485,6 +517,10 @@ done to_slack="${!arr_slack[*]}" [ -z "${to_slack}" ] && SEND_SLACK="NO" +# build the list of flock recipients (channels) +to_flock="${!arr_flock[*]}" +[ -z "${to_flock}" ] && SEND_FLOCK="NO" + # build the list of discord recipients (channels) to_discord="${!arr_discord[*]}" [ -z "${to_discord}" ] && SEND_DISCORD="NO" @@ -509,6 +545,10 @@ to_hipchat="${!arr_hipchat[*]}" to_messagebird="${!arr_messagebird[*]}" [ -z "${to_messagebird}" ] && SEND_MESSAGEBIRD="NO" +# build the list of kavenegar recipients (phone numbers) +to_kavenegar="${!arr_kavenegar[*]}" +[ -z "${to_kavenegar}" ] && SEND_KAVENEGAR="NO" + # check array of telegram recipients (chat ids) to_telegram="${!arr_telegram[*]}" [ -z "${to_telegram}" ] && SEND_TELEGRAM="NO" @@ -537,6 +577,9 @@ done # check slack [ -z "${SLACK_WEBHOOK_URL}" ] && SEND_SLACK="NO" +# check flock +[ -z "${FLOCK_WEBHOOK_URL}" ] && SEND_FLOCK="NO" + # check discord [ -z "${DISCORD_WEBHOOK_URL}" ] && SEND_DISCORD="NO" @@ -555,6 +598,9 @@ done # check messagebird [ -z "${MESSAGEBIRD_ACCESS_KEY}" -o -z "${MESSAGEBIRD_NUMBER}" ] && SEND_MESSAGEBIRD="NO" +# check kavenegar +[ -z "${KAVENEGAR_API_KEY}" -o -z "${KAVENEGAR_SENDER}" ] && SEND_KAVENEGAR="NO" + # check telegram [ -z "${TELEGRAM_BOT_TOKEN}" ] && SEND_TELEGRAM="NO" @@ -578,13 +624,16 @@ fi if [ \( \ "${SEND_PUSHOVER}" = "YES" \ -o "${SEND_SLACK}" = "YES" \ + -o "${SEND_FLOCK}" = "YES" \ -o "${SEND_DISCORD}" = "YES" \ -o "${SEND_HIPCHAT}" = "YES" \ -o "${SEND_TWILIO}" = "YES" \ -o "${SEND_MESSAGEBIRD}" = "YES" \ + -o "${SEND_KAVENEGAR}" = "YES" \ -o "${SEND_TELEGRAM}" = "YES" \ -o "${SEND_PUSHBULLET}" = "YES" \ -o "${SEND_KAFKA}" = "YES" \ + -o "${SEND_CUSTOM}" = "YES" \ \) -a -z "${curl}" ] then curl="$(which curl 2>/dev/null || command -v curl 2>/dev/null)" @@ -595,11 +644,14 @@ if [ \( \ SEND_PUSHBULLET="NO" SEND_TELEGRAM="NO" SEND_SLACK="NO" + SEND_FLOCK="NO" SEND_DISCORD="NO" SEND_TWILIO="NO" SEND_HIPCHAT="NO" SEND_MESSAGEBIRD="NO" + SEND_KAVENEGAR="NO" SEND_KAFKA="NO" + SEND_CUSTOM="NO" fi fi @@ -619,10 +671,12 @@ if [ "${SEND_EMAIL}" != "YES" \ -a "${SEND_PUSHOVER}" != "YES" \ -a "${SEND_TELEGRAM}" != "YES" \ -a "${SEND_SLACK}" != "YES" \ + -a "${SEND_FLOCK}" != "YES" \ -a "${SEND_DISCORD}" != "YES" \ -a "${SEND_TWILIO}" != "YES" \ -a "${SEND_HIPCHAT}" != "YES" \ -a "${SEND_MESSAGEBIRD}" != "YES" \ + -a "${SEND_KAVENEGAR}" != "YES" \ -a "${SEND_PUSHBULLET}" != "YES" \ -a "${SEND_KAFKA}" != "YES" \ -a "${SEND_PD}" != "YES" \ @@ -783,7 +837,7 @@ send_pushover() { priority=-2 case "${status}" in CLEAR) priority=-1;; # low priority: no sound or vibration - WARNING) priotity=0;; # normal priority: respect quiet hours + WARNING) priority=0;; # normal priority: respect quiet hours CRITICAL) priority=1;; # high priority: bypass quiet hours *) priority=-2;; # lowest priority: no notification at all esac @@ -802,7 +856,7 @@ send_pushover() { --form-string "priority=${priority}" \ https://api.pushover.net/1/messages.json) - if [ "${httpcode}" == "200" ] + if [ "${httpcode}" = "200" ] then info "sent pushover notification for: ${host} ${chart}.${name} is ${status} to '${user}'" sent=$((sent + 1)) @@ -821,7 +875,7 @@ send_pushover() { # pushbullet sender send_pushbullet() { - local userapikey="${1}" recipients="${2}" title="${3}" message="${4}" httpcode sent=0 user + local userapikey="${1}" source_device="${2}" recipients="${3}" url="${4}" title="${5}" message="${6}" httpcode sent=0 user if [ "${SEND_PUSHBULLET}" = "YES" -a ! -z "${userapikey}" -a ! -z "${recipients}" -a ! -z "${message}" -a ! -z "${title}" ] then #https://docs.pushbullet.com/#create-push @@ -832,13 +886,15 @@ send_pushbullet() { --header 'Content-Type: application/json' \ --data-binary @<(cat <<EOF {"title": "${title}", - "type": "note", + "type": "link", "email": "${user}", - "body": "$( echo -n ${message})"} + "body": "$( echo -n ${message})", + "url": "${url}", + "source_device_iden": "${source_device}"} EOF ) "https://api.pushbullet.com/v2/pushes" -X POST) - if [ "${httpcode}" == "200" ] + if [ "${httpcode}" = "200" ] then info "sent pushbullet notification for: ${host} ${chart}.${name} is ${status} to '${user}'" sent=$((sent + 1)) @@ -864,7 +920,7 @@ send_kafka() { --data "{host_ip:\"${KAFKA_SENDER_IP}\",when:${when},name:\"${name}\",chart:\"${chart}\",family:\"${family}\",status:\"${status}\",old_status:\"${old_status}\",value:${value},old_value:${old_value},duration:${duration},non_clear_duration:${non_clear_duration},units:\"${units}\",info:\"${info}\"}" \ "${KAFKA_URL}") - if [ "${httpcode}" == "204" ] + if [ "${httpcode}" = "204" ] then info "sent kafka data for: ${host} ${chart}.${name} is ${status} and ip '${KAFKA_SENDER_IP}'" sent=$((sent + 1)) @@ -951,7 +1007,7 @@ send_twilio() { -u "${accountsid}:${accounttoken}" \ "https://api.twilio.com/2010-04-01/Accounts/${accountsid}/Messages.json") - if [ "${httpcode}" == "201" ] + if [ "${httpcode}" = "201" ] then info "sent Twilio SMS for: ${host} ${chart}.${name} is ${status} to '${user}'" sent=$((sent + 1)) @@ -1004,7 +1060,7 @@ send_hipchat() { -d "{\"color\": \"${color}\", \"from\": \"${host}\", \"message_format\": \"${msg_format}\", \"message\": \"${message}\", \"notify\": \"${notify}\"}" \ "https://${HIPCHAT_SERVER}/v2/room/${room}/notification") - if [ "${httpcode}" == "204" ] + if [ "${httpcode}" = "204" ] then info "sent HipChat notification for: ${host} ${chart}.${name} is ${status} to '${room}'" sent=$((sent + 1)) @@ -1038,7 +1094,7 @@ send_messagebird() { -H "Authorization: AccessKey ${accesskey}" \ "https://rest.messagebird.com/messages") - if [ "${httpcode}" == "201" ] + if [ "${httpcode}" = "201" ] then info "sent Messagebird SMS for: ${host} ${chart}.${name} is ${status} to '${user}'" sent=$((sent + 1)) @@ -1054,6 +1110,36 @@ send_messagebird() { } # ----------------------------------------------------------------------------- +# kavenegar sender + +send_kavenegar() { + local API_KEY="${1}" kavenegarsender="${2}" recipients="${3}" title="${4}" message="${5}" httpcode sent=0 user + if [ "${SEND_KAVENEGAR}" = "YES" -a ! -z "${API_KEY}" -a ! -z "${kavenegarsender}" -a ! -z "${recipients}" -a ! -z "${message}" -a ! -z "${title}" ] + then + # http://api.kavenegar.com/v1/{API-KEY}/sms/send.json + for user in ${recipients} + do + httpcode=$(docurl -X POST http://api.kavenegar.com/v1/${API_KEY}/sms/send.json \ + --data-urlencode "sender=${kavenegarsender}" \ + --data-urlencode "receptor=${user}" \ + --data-urlencode "message=${title} ${message}") + + if [ "${httpcode}" = "201" ] + then + info "sent Kavenegar SMS for: ${host} ${chart}.${name} is ${status} to '${user}'" + sent=$((sent + 1)) + else + error "failed to send Kavenegar SMS for: ${host} ${chart}.${name} is ${status} to '${user}' with HTTP error code ${httpcode}." + fi + done + + [ ${sent} -gt 0 ] && return 0 + fi + + return 1 +} + +# ----------------------------------------------------------------------------- # telegram sender send_telegram() { @@ -1079,11 +1165,11 @@ send_telegram() { --data-urlencode "text=${emoji} ${message}" \ "https://api.telegram.org/bot${bottoken}/sendMessage?chat_id=${chatid}") - if [ "${httpcode}" == "200" ] + if [ "${httpcode}" = "200" ] then info "sent telegram notification for: ${host} ${chart}.${name} is ${status} to '${chatid}'" sent=$((sent + 1)) - elif [ "${httpcode}" == "401" ] + elif [ "${httpcode}" = "401" ] then error "failed to send telegram notification for: ${host} ${chart}.${name} is ${status} to '${chatid}': Wrong bot token." else @@ -1147,7 +1233,7 @@ EOF )" httpcode=$(docurl -X POST --data-urlencode "payload=${payload}" "${webhook}") - if [ "${httpcode}" == "200" ] + if [ "${httpcode}" = "200" ] then info "sent slack notification for: ${host} ${chart}.${name} is ${status} to '${channel}'" sent=$((sent + 1)) @@ -1162,6 +1248,61 @@ EOF } # ----------------------------------------------------------------------------- +# flock sender + +send_flock() { + local webhook="${1}" channels="${2}" httpcode sent=0 channel color payload + + [ "${SEND_FLOCK}" != "YES" ] && return 1 + + case "${status}" in + WARNING) color="warning" ;; + CRITICAL) color="danger" ;; + CLEAR) color="good" ;; + *) color="#777777" ;; + esac + + for channel in ${channels} + do + httpcode=$(docurl -X POST "${webhook}" -H "Content-Type: application/json" -d "{ + \"sendAs\": { + \"name\" : \"netdata on ${host}\", + \"profileImage\" : \"${images_base_url}/images/seo-performance-128.png\" + }, + \"text\": \"${host} *${status_message}*\", + \"timestamp\": \"${when}\", + \"attachments\": [ + { + \"description\": \"${chart} (${family}) - ${info}\", + \"color\": \"${color}\", + \"title\": \"${alarm}\", + \"url\": \"${goto_url}\", + \"text\": \"${info}\", + \"views\": { + \"image\": { + \"original\": { \"src\": \"${image}\", \"width\": 400, \"height\": 400 }, + \"thumbnail\": { \"src\": \"${image}\", \"width\": 50, \"height\": 50 }, + \"filename\": \"${image}\" + } + } + } + ] + }" ) + if [ "${httpcode}" = "200" ] + then + info "sent flock notification for: ${host} ${chart}.${name} is ${status} to '${channel}'" + sent=$((sent + 1)) + else + error "failed to send flock notification for: ${host} ${chart}.${name} is ${status} to '${channel}', with HTTP error code ${httpcode}." + fi + done + + [ ${sent} -gt 0 ] && return 0 + + return 1 +} + +# ----------------------------------------------------------------------------- # discord sender send_discord() { @@ -1210,7 +1351,7 @@ EOF )" httpcode=$(docurl -X POST --data-urlencode "payload=${payload}" "${webhook}") - if [ "${httpcode}" == "200" ] + if [ "${httpcode}" = "200" ] then info "sent discord notification for: ${host} ${chart}.${name} is ${status} to '${channel}'" sent=$((sent + 1)) @@ -1266,7 +1407,7 @@ case "${status}" in WARNING) image="${images_base_url}/images/alert-128-orange.png" status_message="needs attention" - color="#caca4b" + color="#ffc107" ;; CLEAR) @@ -1325,6 +1466,15 @@ send_slack "${SLACK_WEBHOOK_URL}" "${to_slack}" SENT_SLACK=$? # ----------------------------------------------------------------------------- +# send the flock notification + +# flock aggregates posts from the same username +# so we use "${host} ${status}" as the bot username, to make them diff + +send_flock "${FLOCK_WEBHOOK_URL}" "${to_flock}" +SENT_FLOCK=$? + +# ----------------------------------------------------------------------------- # send the discord notification # discord aggregates posts from the same username @@ -1351,11 +1501,11 @@ SENT_PUSHOVER=$? # ----------------------------------------------------------------------------- # send the pushbullet notification -send_pushbullet "${PUSHBULLET_ACCESS_TOKEN}" "${to_pushbullet}" "${host} ${status_message} - ${name//_/ } - ${chart}" "${alarm}\n +send_pushbullet "${PUSHBULLET_ACCESS_TOKEN}" "${PUSHBULLET_SOURCE_DEVICE}" "${to_pushbullet}" "${goto_url}" "${host} ${status_message} - ${name//_/ } - ${chart}" "${alarm}\n Severity: ${severity}\n Chart: ${chart}\n Family: ${family}\n -To View Netdata go to: ${goto_url}\n +$(date -d @${when})\n The source of this alarm is line ${src}" SENT_PUSHBULLET=$? @@ -1384,6 +1534,18 @@ SENT_MESSAGEBIRD=$? # ----------------------------------------------------------------------------- +# send the kavenegar SMS + +send_kavenegar "${KAVENEGAR_API_KEY}" "${KAVENEGAR_SENDER}" "${to_kavenegar}" "${host} ${status_message} - ${name//_/ } - ${chart}" "${alarm} +Severity: ${severity} +Chart: ${chart} +Family: ${family} +${info}" + +SENT_KAVENEGAR=$? + + +# ----------------------------------------------------------------------------- # send the telegram.org message # https://core.telegram.org/bots/api#formatting-options @@ -1559,6 +1721,7 @@ Content-Transfer-Encoding: 8bit </table> </body> </html> +--multipart-boundary-- EOF SENT_EMAIL=$? @@ -1570,10 +1733,12 @@ if [ ${SENT_EMAIL} -eq 0 \ -o ${SENT_PUSHOVER} -eq 0 \ -o ${SENT_TELEGRAM} -eq 0 \ -o ${SENT_SLACK} -eq 0 \ + -o ${SENT_FLOCK} -eq 0 \ -o ${SENT_DISCORD} -eq 0 \ -o ${SENT_TWILIO} -eq 0 \ -o ${SENT_HIPCHAT} -eq 0 \ -o ${SENT_MESSAGEBIRD} -eq 0 \ + -o ${SENT_KAVENEGAR} -eq 0 \ -o ${SENT_PUSHBULLET} -eq 0 \ -o ${SENT_KAFKA} -eq 0 \ -o ${SENT_PD} -eq 0 \ @@ -1586,4 +1751,3 @@ fi # we did not send anything exit 1 - diff --git a/plugins.d/cgroup-name.sh b/plugins.d/cgroup-name.sh index dc0bf755..acdd6f4f 100755 --- a/plugins.d/cgroup-name.sh +++ b/plugins.d/cgroup-name.sh @@ -126,6 +126,11 @@ if [ -z "${NAME}" ] # NAME="$(echo ${CGROUP} | sed 's/machine.slice_machine.*-qemu//; s/\/x2d//; s/\/x2d/\-/g; s/\.scope//g')" NAME="qemu_$(echo ${CGROUP} | sed 's/machine.slice_machine.*-qemu//; s/\/x2d[[:digit:]]*//; s/\/x2d//g; s/\.scope//g')" + elif [[ "${CGROUP}" =~ machine_.*\.libvirt-qemu ]] + then + # libvirtd / qemu virtual machines + NAME="qemu_$(echo ${CGROUP} | sed 's/^machine_//; s/\.libvirt-qemu$//; s/-/_/;')" + elif [[ "${CGROUP}" =~ qemu.slice_([0-9]+).scope && -d /etc/pve ]] then # Proxmox VMs diff --git a/plugins.d/cgroup-network-helper.sh b/plugins.d/cgroup-network-helper.sh new file mode 100755 index 00000000..d93fe356 --- /dev/null +++ b/plugins.d/cgroup-network-helper.sh @@ -0,0 +1,256 @@ +#!/usr/bin/env bash + +# cgroup-network-helper.sh +# detect container and virtual machine interfaces +# +# (C) 2017 Costa Tsaousis +# GPL v3+ +# +# This script is called as root (by cgroup-network), with either a pid, or a cgroup path. +# It tries to find all the network interfaces that belong to the same cgroup. +# +# It supports several method for this detection: +# +# 1. cgroup-network (the binary father of this script) detects veth network interfaces, +# by examining iflink and ifindex IDs and switching namespaces +# (it also detects the interface name as it is used by the container). +# +# 2. this script, uses /proc/PID/fdinfo to find tun/tap network interfaces. +# +# 3. this script, calls virsh to find libvirt network interfaces. +# + +# ----------------------------------------------------------------------------- + +export PATH="${PATH}:/sbin:/usr/sbin:/usr/local/sbin" +export LC_ALL=C + +PROGRAM_NAME="$(basename "${0}")" + +logdate() { + date "+%Y-%m-%d %H:%M:%S" +} + +log() { + local status="${1}" + shift + + echo >&2 "$(logdate): ${PROGRAM_NAME}: ${status}: ${*}" + +} + +warning() { + log WARNING "${@}" +} + +error() { + log ERROR "${@}" +} + +info() { + log INFO "${@}" +} + +fatal() { + log FATAL "${@}" + exit 1 +} + +debug=0 +debug() { + [ "${debug}" = "1" ] && log DEBUG "${@}" +} + +# ----------------------------------------------------------------------------- +# check for BASH v4+ (required for associative arrays) + +[ $(( ${BASH_VERSINFO[0]} )) -lt 4 ] && \ + fatal "BASH version 4 or later is required (this is ${BASH_VERSION})." + +# ----------------------------------------------------------------------------- +# defaults to allow running this script by hand + +[ -z "${NETDATA_PLUGINS_DIR}" ] && NETDATA_PLUGINS_DIR="$(dirname "${0}")" +[ -z "${NETDATA_CONFIG_DIR}" ] && NETDATA_CONFIG_DIR="$(dirname "${0}")/../../../../etc/netdata" +[ -z "${NETDATA_CACHE_DIR}" ] && NETDATA_CACHE_DIR="$(dirname "${0}")/../../../../var/cache/netdata" + +# ----------------------------------------------------------------------------- +# parse the arguments + +pid= +cgroup= +while [ ! -z "${1}" ] +do + case "${1}" in + --cgroup) cgroup="${2}"; shift 1;; + --pid|-p) pid="${2}"; shift 1;; + --debug|debug) debug=1;; + *) fatal "Cannot understand argument '${1}'";; + esac + + shift +done + +if [ -z "${pid}" -a -z "${cgroup}" ] +then + fatal "Either --pid or --cgroup is required" +fi + +# ----------------------------------------------------------------------------- + +set_source() { + [ ${debug} -eq 1 ] && echo "SRC ${*}" +} + + +# ----------------------------------------------------------------------------- +# veth interfaces via cgroup + +# cgroup-network can detect veth interfaces by itself (written in C). +# If you seek for a shell version of what it does, check this: +# https://github.com/firehol/netdata/issues/474#issuecomment-317866709 + + +# ----------------------------------------------------------------------------- +# tun/tap interfaces via /proc/PID/fdinfo + +# find any tun/tap devices linked to a pid +proc_pid_fdinfo_iff() { + local p="${1}" # the pid + + debug "Searching for tun/tap interfaces for pid ${p}..." + set_source "fdinfo" + grep ^iff:.* "${NETDATA_HOST_PREFIX}/proc/${p}/fdinfo"/* 2>/dev/null | cut -f 2 +} + +find_tun_tap_interfaces_for_cgroup() { + local c="${1}" # the cgroup path + + # for each pid of the cgroup + # find any tun/tap devices linked to the pid + if [ -f "${c}/emulator/cgroup.procs" ] + then + local p + for p in $(< "${c}/emulator/cgroup.procs" ) + do + proc_pid_fdinfo_iff ${p} + done + fi +} + + +# ----------------------------------------------------------------------------- +# virsh domain network interfaces + +virsh_cgroup_to_domain_name() { + local c="${1}" # the cgroup path + + debug "extracting a possible virsh domain from cgroup ${c}..." + + # extract for the cgroup path + sed -n -e "s|.*/machine-qemu\\\\x2d[0-9]\+\\\\x2d\(.*\)\.scope$|\1|p" \ + -e "s|.*/machine/\(.*\)\.libvirt-qemu$|\1|p" \ + <<EOF +${c} +EOF +} + +virsh_find_all_interfaces_for_cgroup() { + local c="${1}" # the cgroup path + + # the virsh command + local virsh="$(which virsh 2>/dev/null || command -v virsh 2>/dev/null)" + + if [ ! -z "${virsh}" ] + then + local d="$(virsh_cgroup_to_domain_name "${c}")" + + if [ ! -z "${d}" ] + then + debug "running: virsh domiflist ${d}; to find the network interfaces" + + # match only 'network' interfaces from virsh output + + set_source "virsh" + "${virsh}" domiflist ${d} |\ + sed -n \ + -e "s|^\([^[:space:]]\+\)[[:space:]]\+network[[:space:]]\+\([^[:space:]]\+\)[[:space:]]\+[^[:space:]]\+[[:space:]]\+[^[:space:]]\+$|\1 \1_\2|p" \ + -e "s|^\([^[:space:]]\+\)[[:space:]]\+bridge[[:space:]]\+\([^[:space:]]\+\)[[:space:]]\+[^[:space:]]\+[[:space:]]\+[^[:space:]]\+$|\1 \1_\2|p" + else + debug "no virsh domain extracted from cgroup ${c}" + fi + else + debug "virsh command is not available" + fi +} + +# ----------------------------------------------------------------------------- + +find_all_interfaces_of_pid_or_cgroup() { + local p="${1}" c="${2}" # the pid and the cgroup path + + if [ ! -z "${pid}" ] + then + # we have been called with a pid + + proc_pid_fdinfo_iff ${p} + + elif [ ! -z "${c}" ] + then + # we have been called with a cgroup + + info "searching for network interfaces of cgroup '${c}'" + + find_tun_tap_interfaces_for_cgroup "${c}" + virsh_find_all_interfaces_for_cgroup "${c}" + + else + + error "Either a pid or a cgroup path is needed" + return 1 + + fi + + return 0 +} + +# ----------------------------------------------------------------------------- + +# an associative array to store the interfaces +# the index is the interface name as seen by the host +# the value is the interface name as seen by the guest / container +declare -A devs=() + +# store all interfaces found in the associative array +# this will also give the unique devices, as seen by the host +last_src= +while read host_device guest_device +do + [ -z "${host_device}" ] && continue + + [ "${host_device}" = "SRC" ] && last_src="${guest_device}" && continue + + # the default guest_device is the host_device + [ -z "${guest_device}" ] && guest_device="${host_device}" + + # when we run in debug, show the source + debug "Found host device '${host_device}', guest device '${guest_device}', detected via '${last_src}'" + + [ -z "${devs[${host_device}]}" -o "${devs[${host_device}]}" = "${host_device}" ] && \ + devs[${host_device}]="${guest_device}" + +done < <( find_all_interfaces_of_pid_or_cgroup "${pid}" "${cgroup}" ) + +# print the interfaces found, in the format netdata expects them +found=0 +for x in "${!devs[@]}" +do + found=$((found + 1)) + echo "${x} ${devs[${x}]}" +done + +debug "found ${found} network interfaces for pid '${pid}', cgroup '${cgroup}', run as ${USER}, ${UID}" + +# let netdata know if we found any +[ ${found} -eq 0 ] && exit 1 +exit 0 diff --git a/plugins.d/python.d.plugin b/plugins.d/python.d.plugin index 03c156f4..855080e8 100755 --- a/plugins.d/python.d.plugin +++ b/plugins.d/python.d.plugin @@ -1,599 +1,382 @@ #!/usr/bin/env bash -'''':; exec "$(command -v python || command -v python3 || command -v python2 || echo "ERROR python IS NOT AVAILABLE IN THIS SYSTEM")" "$0" "$@" # ''' -# -*- coding: utf-8 -*- +'''':; exec "$(command -v python || command -v python3 || command -v python2 || +echo "ERROR python IS NOT AVAILABLE IN THIS SYSTEM")" "$0" "$@" # ''' -# Description: netdata python modules supervisor +# -*- coding: utf-8 -*- +# Description: # Author: Pawel Krupa (paulfantom) +# Author: Ilya Mashchenko (l2isbad) import os import sys -import time import threading + from re import sub +from sys import version_info, argv +from time import sleep + +try: + from time import monotonic as time +except ImportError: + from time import time + +PY_VERSION = version_info[:2] +PLUGIN_CONFIG_DIR = os.getenv('NETDATA_CONFIG_DIR', os.path.dirname(__file__) + '/../../../../etc/netdata') + '/' +CHARTS_PY_DIR = os.path.abspath(os.getenv('NETDATA_PLUGINS_DIR', os.path.dirname(__file__)) + '/../python.d') + '/' +CHARTS_PY_CONFIG_DIR = PLUGIN_CONFIG_DIR + 'python.d/' +PYTHON_MODULES_DIR = CHARTS_PY_DIR + 'python_modules' + +sys.path.append(PYTHON_MODULES_DIR) + +from bases.loaders import ModuleAndConfigLoader +from bases.loggers import PythonDLogger +from bases.collection import setdefault_values, run_and_exit + +try: + from collections import OrderedDict +except ImportError: + from third_party.ordereddict import OrderedDict -# ----------------------------------------------------------------------------- -# globals & environment setup -# https://github.com/firehol/netdata/wiki/External-Plugins#environment-variables -MODULE_EXTENSION = ".chart.py" BASE_CONFIG = {'update_every': os.getenv('NETDATA_UPDATE_EVERY', 1), - 'priority': 90000, - 'retries': 10} + 'retries': 60, + 'priority': 60000, + 'autodetection_retry': 0, + 'chart_cleanup': 10, + 'name': str()} -MODULES_DIR = os.path.abspath(os.getenv('NETDATA_PLUGINS_DIR', - os.path.dirname(__file__)) + "/../python.d") + "/" -CONFIG_DIR = os.getenv('NETDATA_CONFIG_DIR', - os.path.dirname(__file__) + "/../../../../etc/netdata") +MODULE_EXTENSION = '.chart.py' +OBSOLETE_MODULES = ['apache_cache', 'gunicorn_log', 'nginx_log'] -# directories should end with '/' -if CONFIG_DIR[-1] != "/": - CONFIG_DIR += "/" -sys.path.append(MODULES_DIR + "python_modules") -PROGRAM = os.path.basename(__file__).replace(".plugin", "") -DEBUG_FLAG = False -TRACE_FLAG = False -OVERRIDE_UPDATE_EVERY = False +def module_ok(m): + return m.endswith(MODULE_EXTENSION) and m[:-len(MODULE_EXTENSION)] not in OBSOLETE_MODULES -# ----------------------------------------------------------------------------- -# custom, third party and version specific python modules management -import msg -try: - assert sys.version_info >= (3, 1) - import importlib.machinery - PY_VERSION = 3 - # change this hack below if we want PY_VERSION to be used in modules - # import builtins - # builtins.PY_VERSION = 3 - msg.info('Using python v3') -except (AssertionError, ImportError): - try: - import imp - - # change this hack below if we want PY_VERSION to be used in modules - # import __builtin__ - # __builtin__.PY_VERSION = 2 - PY_VERSION = 2 - msg.info('Using python v2') - except ImportError: - msg.fatal('Cannot start. No importlib.machinery on python3 or lack of imp on python2') -# try: -# import yaml -# except ImportError: -# msg.fatal('Cannot find yaml library') -try: - if PY_VERSION == 3: - import pyyaml3 as yaml - else: - import pyyaml2 as yaml -except ImportError: - msg.fatal('Cannot find yaml library') +ALL_MODULES = [m for m in sorted(os.listdir(CHARTS_PY_DIR)) if module_ok(m)] -try: - from collections import OrderedDict - ORDERED = True - DICT = OrderedDict - msg.info('YAML output is ordered') -except ImportError: - try: - from ordereddict import OrderedDict - ORDERED = True - DICT = OrderedDict - msg.info('YAML output is ordered') - except ImportError: - ORDERED = False - DICT = dict - msg.info('YAML output is unordered') -if ORDERED: - def ordered_load(stream, Loader=yaml.Loader, object_pairs_hook=OrderedDict): - class OrderedLoader(Loader): - pass - - def construct_mapping(loader, node): - loader.flatten_mapping(node) - return object_pairs_hook(loader.construct_pairs(node)) - OrderedLoader.add_constructor( - yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG, - construct_mapping) - return yaml.load(stream, OrderedLoader) - - -class PythonCharts(object): - """ - Main class used to control every python module. - """ - - def __init__(self, - modules=None, - modules_path='../python.d/', - modules_configs='../conf.d/', - modules_disabled=None, - modules_enabled=None, - default_run=None): + +def parse_cmd(): + debug = 'debug' in argv[1:] + trace = 'trace' in argv[1:] + override_update_every = next((arg for arg in argv[1:] if arg.isdigit() and int(arg) > 1), False) + modules = [''.join([m, MODULE_EXTENSION]) for m in argv[1:] if ''.join([m, MODULE_EXTENSION]) in ALL_MODULES] + return debug, trace, override_update_every, modules or ALL_MODULES + + +def multi_job_check(config): + return next((True for key in config if isinstance(config[key], dict)), False) + + +class Job(object): + def __init__(self, initialized_job, job_id): """ - :param modules: list - :param modules_path: str - :param modules_configs: str - :param modules_disabled: list - :param modules_enabled: list - :param default_run: bool + :param initialized_job: instance of <Class Service> + :param job_id: <str> """ + self.job = initialized_job + self.id = job_id # key in Modules.jobs() + self.module_name = self.job.__module__ # used in Plugin.delete_job() + self.recheck_every = self.job.configuration.pop('autodetection_retry') + self.checked = False # used in Plugin.check_job() + self.created = False # used in Plugin.create_job_charts() + if OVERRIDE_UPDATE_EVERY: + self.job.update_every = int(OVERRIDE_UPDATE_EVERY) - if modules is None: - modules = [] - if modules_disabled is None: - modules_disabled = [] + def __getattr__(self, item): + return getattr(self.job, item) - self.first_run = True - # set configuration directory - self.configs = modules_configs + def __repr__(self): + return self.job.__repr__() - # load modules - loaded_modules = self._load_modules(modules_path, modules, modules_disabled, modules_enabled, default_run) + def is_dead(self): + return bool(self.ident) and not self.is_alive() - # load configuration files - configured_modules = self._load_configs(loaded_modules) + def not_launched(self): + return not bool(self.ident) - # good economy and prosperity: - self.jobs = self._create_jobs(configured_modules) # type <list> + def is_autodetect(self): + return self.recheck_every - # enable timetable override like `python.d.plugin mysql debug 1` - if DEBUG_FLAG and OVERRIDE_UPDATE_EVERY: - for job in self.jobs: - job.create_timetable(BASE_CONFIG['update_every']) - @staticmethod - def _import_module(path, name=None): +class Module(object): + def __init__(self, service, config): """ - Try to import module using only its path. - :param path: str - :param name: str - :return: object + :param service: <Module> + :param config: <dict> """ + self.service = service + self.name = service.__name__ + self.config = self.jobs_configurations_builder(config) + self.jobs = OrderedDict() + self.counter = 1 - if name is None: - name = path.split('/')[-1] - if name[-len(MODULE_EXTENSION):] != MODULE_EXTENSION: - return None - name = name[:-len(MODULE_EXTENSION)] - try: - if PY_VERSION == 3: - return importlib.machinery.SourceFileLoader(name, path).load_module() - else: - return imp.load_source(name, path) - except Exception as e: - msg.error("Problem loading", name, str(e)) - return None + self.initialize_jobs() + + def __repr__(self): + return "<Class Module '{name}'>".format(name=self.name) + + def __iter__(self): + return iter(OrderedDict(self.jobs).values()) + + def __getitem__(self, item): + return self.jobs[item] + + def __delitem__(self, key): + del self.jobs[key] + + def __len__(self): + return len(self.jobs) + + def __bool__(self): + return bool(self.jobs) - def _load_modules(self, path, modules, disabled, enabled, default_run): + def __nonzero__(self): + return self.__bool__() + + def jobs_configurations_builder(self, config): """ - Load modules from 'modules' list or dynamically every file from 'path' (only .chart.py files) - :param path: str - :param modules: list - :param disabled: list - :return: list + :param config: <dict> + :return: """ + counter = 0 + job_base_config = dict() - # check if plugin directory exists - if not os.path.isdir(path): - msg.fatal("cannot find charts directory ", path) - - # load modules - loaded = [] - if len(modules) > 0: - for m in modules: - if m in disabled: - continue - mod = self._import_module(path + m + MODULE_EXTENSION) - if mod is not None: - loaded.append(mod) - else: # exit if plugin is not found - msg.fatal('no modules found.') - else: - # scan directory specified in path and load all modules from there - if default_run is False: - names = [module for module in os.listdir(path) if module[:-9] in enabled] - else: - names = os.listdir(path) - for mod in names: - if mod.replace(MODULE_EXTENSION, "") in disabled: - msg.error(mod + ": disabled module ", mod.replace(MODULE_EXTENSION, "")) - continue - m = self._import_module(path + mod) - if m is not None: - msg.debug(mod + ": loading module '" + path + mod + "'") - loaded.append(m) - return loaded - - def _load_configs(self, modules): + for attr in BASE_CONFIG: + job_base_config[attr] = config.pop(attr, getattr(self.service, attr, BASE_CONFIG[attr])) + + if not config: + config = {str(): dict()} + elif not multi_job_check(config): + config = {str(): config} + + for job_name in config: + if not isinstance(config[job_name], dict): + continue + + job_config = setdefault_values(config[job_name], base_dict=job_base_config) + job_name = sub(r'\s+', '_', job_name) + config[job_name]['name'] = sub(r'\s+', '_', config[job_name]['name']) + counter += 1 + job_id = 'job' + str(counter).zfill(3) + + yield job_id, job_name, job_config + + def initialize_jobs(self): """ - Append configuration in list named `config` to every module. - For multi-job modules `config` list is created in _parse_config, - otherwise it is created here based on BASE_CONFIG prototype with None as identifier. - :param modules: list - :return: list + :return: """ - for mod in modules: - configfile = self.configs + mod.__name__ + ".conf" - if os.path.isfile(configfile): - msg.debug(mod.__name__ + ": loading module configuration: '" + configfile + "'") - try: - if not hasattr(mod, 'config'): - mod.config = {} - setattr(mod, - 'config', - self._parse_config(mod, read_config(configfile))) - except Exception as e: - msg.error(mod.__name__ + ": cannot parse configuration file '" + configfile + "':", str(e)) + for job_id, job_name, job_config in self.config: + job_config['job_name'] = job_name + job_config['override_name'] = job_config.pop('name') + + try: + initialized_job = self.service.Service(configuration=job_config) + except Exception as error: + Logger.error("job initialization: '{module_name} {job_name}' " + "=> ['FAILED'] ({error})".format(module_name=self.name, + job_name=job_name, + error=error)) + continue + else: + Logger.debug("job initialization: '{module_name} {job_name}' " + "=> ['OK']".format(module_name=self.name, + job_name=job_name or self.name)) + self.jobs[job_id] = Job(initialized_job=initialized_job, + job_id=job_id) + del self.config + del self.service + + +class Plugin(object): + def __init__(self): + self.loader = ModuleAndConfigLoader() + self.modules = OrderedDict() + self.sleep_time = 1 + self.runs_counter = 0 + self.config, error = self.loader.load_config_from_file(PLUGIN_CONFIG_DIR + 'python.d.conf') + if error: + run_and_exit(Logger.error)(error) + + if not self.config.get('enabled', True): + run_and_exit(Logger.info)('DISABLED in configuration file.') + + self.load_and_initialize_modules() + if not self.modules: + run_and_exit(Logger.info)('No modules to run. Exit...') + + def __iter__(self): + return iter(OrderedDict(self.modules).values()) + + @property + def jobs(self): + return (job for mod in self for job in mod) + + @property + def dead_jobs(self): + return (job for job in self.jobs if job.is_dead()) + + @property + def autodetect_jobs(self): + return [job for job in self.jobs if job.not_launched()] + + def enabled_modules(self): + for mod in MODULES_TO_RUN: + mod_name = mod[:-len(MODULE_EXTENSION)] + mod_path = CHARTS_PY_DIR + mod + conf_path = ''.join([CHARTS_PY_CONFIG_DIR, mod_name, '.conf']) + + if DEBUG: + yield mod, mod_name, mod_path, conf_path else: - msg.error(mod.__name__ + ": configuration file '" + configfile + "' not found. Using defaults.") - # set config if not found - if not hasattr(mod, 'config'): - msg.debug(mod.__name__ + ": setting configuration for only one job") - mod.config = {None: {}} - for var in BASE_CONFIG: - try: - mod.config[None][var] = getattr(mod, var) - except AttributeError: - mod.config[None][var] = BASE_CONFIG[var] - return modules + if all([self.config.get('default_run', True), + self.config.get(mod_name, True)]): + yield mod, mod_name, mod_path, conf_path + + elif all([not self.config.get('default_run'), + self.config.get(mod_name)]): + yield mod, mod_name, mod_path, conf_path + + def load_and_initialize_modules(self): + for mod, mod_name, mod_path, conf_path in self.enabled_modules(): + + # Load module from file ------------------------------------------------------------ + loaded_module, error = self.loader.load_module_from_file(mod_name, mod_path) + log = Logger.error if error else Logger.debug + log("module load source: '{module_name}' => [{status}]".format(status='FAILED' if error else 'OK', + module_name=mod_name)) + if error: + Logger.error("load source error : {0}".format(error)) + continue + + # Load module config from file ------------------------------------------------------ + loaded_config, error = self.loader.load_config_from_file(conf_path) + log = Logger.error if error else Logger.debug + log("module load config: '{module_name}' => [{status}]".format(status='FAILED' if error else 'OK', + module_name=mod_name)) + if error: + Logger.error('load config error : {0}'.format(error)) + + # Service instance initialization --------------------------------------------------- + initialized_module = Module(service=loaded_module, config=loaded_config) + Logger.debug("module status: '{module_name}' => [{status}] " + "(jobs: {jobs_number})".format(status='OK' if initialized_module else 'FAILED', + module_name=initialized_module.name, + jobs_number=len(initialized_module))) + + if initialized_module: + self.modules[initialized_module.name] = initialized_module @staticmethod - def _parse_config(module, config): + def check_job(job): """ - Parse configuration file or extract configuration from module file. - Example of returned dictionary: - config = {'name': { - 'update_every': 2, - 'retries': 3, - 'priority': 30000 - 'other_val': 123}} - :param module: object - :param config: dict - :return: dict + :param job: <Job> + :return: """ - if config is None: - config = {} - # get default values - defaults = {} - msg.debug(module.__name__ + ": reading configuration") - for key in BASE_CONFIG: - try: - # get defaults from module config - defaults[key] = int(config.pop(key)) - except (KeyError, ValueError): - try: - # get defaults from module source code - defaults[key] = getattr(module, key) - except (KeyError, ValueError, AttributeError): - # if above failed, get defaults from global dict - defaults[key] = BASE_CONFIG[key] - - # check if there are dict in config dict - many_jobs = False - for name in config: - if isinstance(config[name], DICT): - many_jobs = True - break - - # assign variables needed by supervisor to every job configuration - if many_jobs: - for name in config: - for key in defaults: - if key not in config[name]: - config[name][key] = defaults[key] - # if only one job is needed, values doesn't have to be in dict (in YAML) + try: + check_ok = bool(job.check()) + except Exception as error: + job.error('check() unhandled exception: {error}'.format(error=error)) + return None else: - config = {None: config.copy()} - config[None].update(defaults) - - # return dictionary of jobs where every job has BASE_CONFIG variables - return config + return check_ok @staticmethod - def _create_jobs(modules): - """ - Create jobs based on module.config dictionary and module.Service class definition. - :param modules: list - :return: list + def create_job_charts(job): """ - jobs = [] - for module in modules: - for name in module.config: - # register a new job - conf = module.config[name] - try: - job = module.Service(configuration=conf, name=name) - except Exception as e: - msg.error(module.__name__ + - ("/" + str(name) if name is not None else "") + - ": cannot start job: '" + - str(e)) - continue - else: - # set chart_name (needed to plot run time graphs) - job.chart_name = module.__name__ - if name is not None: - job.chart_name += "_" + name - jobs.append(job) - msg.debug(module.__name__ + ("/" + str(name) if name is not None else "") + ": job added") - - return [j for j in jobs if j is not None] - - def _stop(self, job, reason=None): + :param job: <Job> + :return: """ - Stop specified job and remove it from self.jobs list - Also notifies user about job failure if DEBUG_FLAG is set - :param job: object - :param reason: str - """ - prefix = job.__module__ - if job.name is not None and len(job.name) != 0: - prefix += "/" + job.name try: - msg.error("DISABLED:", prefix) - self.jobs.remove(job) - except Exception as e: - msg.debug("This shouldn't happen. NO " + prefix + " IN LIST:" + str(self.jobs) + " ERROR: " + str(e)) - - # TODO remove section below and remove `reason`. - prefix += ": " - if reason is None: - return - elif reason[:3] == "no ": - msg.error(prefix + - "does not seem to have " + - reason[3:] + - "() function. Disabling it.") - elif reason[:7] == "failed ": - msg.error(prefix + - reason[7:] + - "() function reports failure.") - elif reason[:13] == "configuration": - msg.error(prefix + - "configuration file '" + - self.configs + - job.__module__ + - ".conf' not found. Using defaults.") - elif reason[:11] == "misbehaving": - msg.error(prefix + "is " + reason) - - def check(self): - """ - Tries to execute check() on every job. - This cannot fail thus it is catching every exception - If job.check() fails job is stopped - """ - i = 0 - overridden = [] - msg.debug("all job objects", str(self.jobs)) - while i < len(self.jobs): - job = self.jobs[i] - try: - if not job.check(): - msg.error(job.chart_name, "check() failed - disabling job") - self._stop(job) - else: - msg.info("CHECKED OK:", job.chart_name) - i += 1 - try: - if job.override_name is not None: - new_name = job.__module__ + '_' + sub(r'\s+', '_', job.override_name) - if new_name in overridden: - msg.info("DROPPED:", job.name, ", job '" + job.override_name + - "' is already served by another job.") - self._stop(job) - i -= 1 - else: - job.name = job.override_name - msg.info("RENAMED:", new_name, ", from " + job.chart_name) - job.chart_name = new_name - overridden.append(job.chart_name) - except Exception: - pass - except AttributeError as e: - self._stop(job) - msg.error(job.chart_name, "cannot find check() function or it thrown unhandled exception.") - msg.debug(str(e)) - except (UnboundLocalError, Exception) as e: - msg.error(job.chart_name, str(e)) - self._stop(job) - msg.debug("overridden job names:", str(overridden)) - msg.debug("all remaining job objects:", str(self.jobs)) - - def create(self): - """ - Tries to execute create() on every job. - This cannot fail thus it is catching every exception. - If job.create() fails job is stopped. - This is also creating job run time chart. - """ - i = 0 - while i < len(self.jobs): - job = self.jobs[i] - try: - if not job.create(): - msg.error(job.chart_name, "create function failed.") - self._stop(job) - else: - chart = job.chart_name - sys.stdout.write( - "CHART netdata.plugin_pythond_" + - chart + - " '' 'Execution time for " + - chart + - " plugin' 'milliseconds / run' python.d netdata.plugin_python area 145000 " + - str(job.timetable['freq']) + - '\n') - sys.stdout.write("DIMENSION run_time 'run time' absolute 1 1\n\n") - msg.debug("created charts for", job.chart_name) - # sys.stdout.flush() - i += 1 - except AttributeError: - msg.error(job.chart_name, "cannot find create() function or it thrown unhandled exception.") - self._stop(job) - except (UnboundLocalError, Exception) as e: - msg.error(job.chart_name, str(e)) - self._stop(job) - - def update(self): + create_ok = job.create() + except Exception as error: + job.error('create() unhandled exception: {error}'.format(error=error)) + return False + else: + return create_ok + + def delete_job(self, job): """ - Creates and supervises every job thread. - This will stay forever and ever and ever forever and ever it'll be the one... + :param job: <Job> + :return: """ - for job in self.jobs: - job.start() + del self.modules[job.module_name][job.id] - while True: - if threading.active_count() <= 1: - msg.fatal("no more jobs") - time.sleep(1) - - -def read_config(path): - """ - Read YAML configuration from specified file - :param path: str - :return: dict - """ - try: - with open(path, 'r') as stream: - if ORDERED: - config = ordered_load(stream, yaml.SafeLoader) + def run_check(self): + checked = list() + for job in self.jobs: + if job.name in checked: + job.info('check() => [DROPPED] (already served by another job)') + self.delete_job(job) + continue + ok = self.check_job(job) + if ok: + job.info('check() => [OK]') + checked.append(job.name) + job.checked = True + continue + if not job.is_autodetect() or ok is None: + job.error('check() => [FAILED]') + self.delete_job(job) else: - config = yaml.load(stream) - except (OSError, IOError) as error: - msg.error(str(path), 'reading error:', str(error)) - return None - except yaml.YAMLError as error: - msg.error(str(path), "is malformed:", str(error)) - return None - return config - - -def parse_cmdline(directory, *commands): - """ - Parse parameters from command line. - :param directory: str - :param commands: list of str - :return: dict - """ - global DEBUG_FLAG, TRACE_FLAG - global OVERRIDE_UPDATE_EVERY - global BASE_CONFIG - - changed_update = False - mods = [] - for cmd in commands[1:]: - if cmd == "check": - pass - elif cmd == "debug" or cmd == "all": - DEBUG_FLAG = True - # redirect stderr to stdout? - elif cmd == "trace" or cmd == "all": - TRACE_FLAG = True - elif os.path.isfile(directory + cmd + ".chart.py") or os.path.isfile(directory + cmd): - # DEBUG_FLAG = True - mods.append(cmd.replace(".chart.py", "")) - else: - try: - BASE_CONFIG['update_every'] = int(cmd) - changed_update = True - except ValueError: - pass - if changed_update and DEBUG_FLAG: - OVERRIDE_UPDATE_EVERY = True - msg.debug(PROGRAM, "overriding update interval to", str(BASE_CONFIG['update_every'])) - - msg.debug("started from", commands[0], "with options:", *commands[1:]) - - return mods - - -# if __name__ == '__main__': -def run(): - """ - Main program. - """ - global DEBUG_FLAG, TRACE_FLAG, BASE_CONFIG - - # read configuration file - disabled = ['nginx_log', 'gunicorn_log', 'apache_cache'] - enabled = list() - default_run = True - configfile = CONFIG_DIR + "python.d.conf" - msg.PROGRAM = PROGRAM - msg.info("reading configuration file:", configfile) - log_throttle = 200 - log_interval = 3600 - - conf = read_config(configfile) - if conf is not None: - try: - # exit the whole plugin when 'enabled: no' is set in 'python.d.conf' - if conf['enabled'] is False: - msg.fatal('disabled in configuration file.\n') - except (KeyError, TypeError): - pass - - try: - for param in BASE_CONFIG: - BASE_CONFIG[param] = conf[param] - except (KeyError, TypeError): - pass # use default update_every from NETDATA_UPDATE_EVERY - - try: - DEBUG_FLAG = conf['debug'] - except (KeyError, TypeError): - pass - - try: - TRACE_FLAG = conf['trace'] - except (KeyError, TypeError): - pass - - try: - log_throttle = conf['logs_per_interval'] - except (KeyError, TypeError): - pass + job.error('check() => [RECHECK] (autodetection_retry: {0})'.format(job.recheck_every)) - try: - log_interval = conf['log_interval'] - except (KeyError, TypeError): - pass + def run_create(self): + for job in self.jobs: + if not job.checked: + # skip autodetection_retry jobs + continue + ok = self.create_job_charts(job) + if ok: + job.debug('create() => [OK] (charts: {0})'.format(len(job.charts))) + job.created = True + continue + job.error('create() => [FAILED] (charts: {0})'.format(len(job.charts))) + self.delete_job(job) - default_run = True if ('default_run' not in conf or conf.get('default_run')) else False + def start(self): + self.run_check() + self.run_create() + for job in self.jobs: + if job.created: + job.start() - for k, v in conf.items(): - if k in ("update_every", "debug", "enabled", "default_run"): - continue - if default_run: - if v is False: - disabled.append(k) - else: - if v is True: - enabled.append(k) - # parse passed command line arguments - modules = parse_cmdline(MODULES_DIR, *sys.argv) - msg.DEBUG_FLAG = DEBUG_FLAG - msg.TRACE_FLAG = TRACE_FLAG - msg.LOG_THROTTLE = log_throttle - msg.LOG_INTERVAL = log_interval - msg.LOG_COUNTER = 0 - msg.LOG_NEXT_CHECK = 0 - msg.info("MODULES_DIR='" + MODULES_DIR + - "', CONFIG_DIR='" + CONFIG_DIR + - "', UPDATE_EVERY=" + str(BASE_CONFIG['update_every']) + - ", ONLY_MODULES=" + str(modules)) - - # run plugins - charts = PythonCharts(modules, MODULES_DIR, CONFIG_DIR + "python.d/", disabled, enabled, default_run) - charts.check() - charts.create() - charts.update() - msg.fatal("finished") + while True: + if threading.active_count() <= 1 and not self.autodetect_jobs: + run_and_exit(Logger.info)('FINISHED') + + sleep(self.sleep_time) + self.cleanup() + self.autodetect_retry() + + def cleanup(self): + for job in self.dead_jobs: + self.delete_job(job) + for mod in self: + if not mod: + del self.modules[mod.name] + + def autodetect_retry(self): + self.runs_counter += self.sleep_time + for job in self.autodetect_jobs: + if self.runs_counter % job.recheck_every == 0: + checked = self.check_job(job) + if checked: + created = self.create_job_charts(job) + if not created: + self.delete_job(job) + continue + job.start() if __name__ == '__main__': - run() + DEBUG, TRACE, OVERRIDE_UPDATE_EVERY, MODULES_TO_RUN = parse_cmd() + Logger = PythonDLogger() + if DEBUG: + Logger.logger.severity = 'DEBUG' + if TRACE: + Logger.log_traceback = True + Logger.info('Using python {version}'.format(version=PY_VERSION[0])) + + plugin = Plugin() + plugin.start() diff --git a/python.d/Makefile.am b/python.d/Makefile.am index 84c2aead..1c84cddb 100644 --- a/python.d/Makefile.am +++ b/python.d/Makefile.am @@ -14,12 +14,14 @@ dist_python_SCRIPTS = \ dist_python_DATA = \ README.md \ apache.chart.py \ - apache_cache.chart.py \ + beanstalk.chart.py \ bind_rndc.chart.py \ chrony.chart.py \ + couchdb.chart.py \ cpufreq.chart.py \ cpuidle.chart.py \ dns_query_time.chart.py \ + dnsdist.chart.py \ dovecot.chart.py \ elasticsearch.chart.py \ example.chart.py \ @@ -41,6 +43,7 @@ dist_python_DATA = \ phpfpm.chart.py \ postfix.chart.py \ postgres.chart.py \ + powerdns.chart.py \ rabbitmq.chart.py \ redis.chart.py \ retroshare.chart.py \ @@ -57,8 +60,33 @@ pythonmodulesdir=$(pythondir)/python_modules dist_pythonmodules_DATA = \ python_modules/__init__.py \ python_modules/base.py \ - python_modules/msg.py \ - python_modules/lm_sensors.py \ + $(NULL) + +basesdir=$(pythonmodulesdir)/bases +dist_bases_DATA = \ + python_modules/bases/__init__.py \ + python_modules/bases/charts.py \ + python_modules/bases/collection.py \ + python_modules/bases/loaders.py \ + python_modules/bases/loggers.py \ + $(NULL) + +bases_framework_servicesdir=$(basesdir)/FrameworkServices +dist_bases_framework_services_DATA = \ + python_modules/bases/FrameworkServices/__init__.py \ + python_modules/bases/FrameworkServices/ExecutableService.py \ + python_modules/bases/FrameworkServices/LogService.py \ + python_modules/bases/FrameworkServices/MySQLService.py \ + python_modules/bases/FrameworkServices/SimpleService.py \ + python_modules/bases/FrameworkServices/SocketService.py \ + python_modules/bases/FrameworkServices/UrlService.py \ + $(NULL) + +third_partydir=$(pythonmodulesdir)/third_party +dist_third_party_DATA = \ + python_modules/third_party/__init__.py \ + python_modules/third_party/ordereddict.py \ + python_modules/third_party/lm_sensors.py \ $(NULL) pythonyaml2dir=$(pythonmodulesdir)/pyyaml2 diff --git a/python.d/Makefile.in b/python.d/Makefile.in index 104f4f1c..dda54e1a 100644 --- a/python.d/Makefile.in +++ b/python.d/Makefile.in @@ -81,6 +81,7 @@ build_triplet = @build@ host_triplet = @host@ DIST_COMMON = $(top_srcdir)/build/subst.inc $(srcdir)/Makefile.in \ $(srcdir)/Makefile.am $(dist_python_SCRIPTS) \ + $(dist_bases_DATA) $(dist_bases_framework_services_DATA) \ $(dist_python_DATA) $(dist_python_urllib3_DATA) \ $(dist_python_urllib3_backports_DATA) \ $(dist_python_urllib3_contrib_DATA) \ @@ -88,7 +89,8 @@ DIST_COMMON = $(top_srcdir)/build/subst.inc $(srcdir)/Makefile.in \ $(dist_python_urllib3_securetransport_DATA) \ $(dist_python_urllib3_ssl_match_hostname_DATA) \ $(dist_python_urllib3_util_DATA) $(dist_pythonmodules_DATA) \ - $(dist_pythonyaml2_DATA) $(dist_pythonyaml3_DATA) + $(dist_pythonyaml2_DATA) $(dist_pythonyaml3_DATA) \ + $(dist_third_party_DATA) subdir = python.d ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___atomic.m4 \ @@ -132,8 +134,9 @@ am__uninstall_files_from_dir = { \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } -am__installdirs = "$(DESTDIR)$(pythondir)" "$(DESTDIR)$(pythondir)" \ - "$(DESTDIR)$(python_urllib3dir)" \ +am__installdirs = "$(DESTDIR)$(pythondir)" "$(DESTDIR)$(basesdir)" \ + "$(DESTDIR)$(bases_framework_servicesdir)" \ + "$(DESTDIR)$(pythondir)" "$(DESTDIR)$(python_urllib3dir)" \ "$(DESTDIR)$(python_urllib3_backportsdir)" \ "$(DESTDIR)$(python_urllib3_contribdir)" \ "$(DESTDIR)$(python_urllib3_packagesdir)" \ @@ -141,7 +144,7 @@ am__installdirs = "$(DESTDIR)$(pythondir)" "$(DESTDIR)$(pythondir)" \ "$(DESTDIR)$(python_urllib3_ssl_match_hostnamedir)" \ "$(DESTDIR)$(python_urllib3_utildir)" \ "$(DESTDIR)$(pythonmodulesdir)" "$(DESTDIR)$(pythonyaml2dir)" \ - "$(DESTDIR)$(pythonyaml3dir)" + "$(DESTDIR)$(pythonyaml3dir)" "$(DESTDIR)$(third_partydir)" SCRIPTS = $(dist_python_SCRIPTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) @@ -162,14 +165,16 @@ am__can_run_installinfo = \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac -DATA = $(dist_python_DATA) $(dist_python_urllib3_DATA) \ +DATA = $(dist_bases_DATA) $(dist_bases_framework_services_DATA) \ + $(dist_python_DATA) $(dist_python_urllib3_DATA) \ $(dist_python_urllib3_backports_DATA) \ $(dist_python_urllib3_contrib_DATA) \ $(dist_python_urllib3_packages_DATA) \ $(dist_python_urllib3_securetransport_DATA) \ $(dist_python_urllib3_ssl_match_hostname_DATA) \ $(dist_python_urllib3_util_DATA) $(dist_pythonmodules_DATA) \ - $(dist_pythonyaml2_DATA) $(dist_pythonyaml3_DATA) + $(dist_pythonyaml2_DATA) $(dist_pythonyaml3_DATA) \ + $(dist_third_party_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ @@ -329,12 +334,14 @@ dist_python_SCRIPTS = \ dist_python_DATA = \ README.md \ apache.chart.py \ - apache_cache.chart.py \ + beanstalk.chart.py \ bind_rndc.chart.py \ chrony.chart.py \ + couchdb.chart.py \ cpufreq.chart.py \ cpuidle.chart.py \ dns_query_time.chart.py \ + dnsdist.chart.py \ dovecot.chart.py \ elasticsearch.chart.py \ example.chart.py \ @@ -356,6 +363,7 @@ dist_python_DATA = \ phpfpm.chart.py \ postfix.chart.py \ postgres.chart.py \ + powerdns.chart.py \ rabbitmq.chart.py \ redis.chart.py \ retroshare.chart.py \ @@ -372,8 +380,33 @@ pythonmodulesdir = $(pythondir)/python_modules dist_pythonmodules_DATA = \ python_modules/__init__.py \ python_modules/base.py \ - python_modules/msg.py \ - python_modules/lm_sensors.py \ + $(NULL) + +basesdir = $(pythonmodulesdir)/bases +dist_bases_DATA = \ + python_modules/bases/__init__.py \ + python_modules/bases/charts.py \ + python_modules/bases/collection.py \ + python_modules/bases/loaders.py \ + python_modules/bases/loggers.py \ + $(NULL) + +bases_framework_servicesdir = $(basesdir)/FrameworkServices +dist_bases_framework_services_DATA = \ + python_modules/bases/FrameworkServices/__init__.py \ + python_modules/bases/FrameworkServices/ExecutableService.py \ + python_modules/bases/FrameworkServices/LogService.py \ + python_modules/bases/FrameworkServices/MySQLService.py \ + python_modules/bases/FrameworkServices/SimpleService.py \ + python_modules/bases/FrameworkServices/SocketService.py \ + python_modules/bases/FrameworkServices/UrlService.py \ + $(NULL) + +third_partydir = $(pythonmodulesdir)/third_party +dist_third_party_DATA = \ + python_modules/third_party/__init__.py \ + python_modules/third_party/ordereddict.py \ + python_modules/third_party/lm_sensors.py \ $(NULL) pythonyaml2dir = $(pythonmodulesdir)/pyyaml2 @@ -552,6 +585,48 @@ uninstall-dist_pythonSCRIPTS: files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(pythondir)'; $(am__uninstall_files_from_dir) +install-dist_basesDATA: $(dist_bases_DATA) + @$(NORMAL_INSTALL) + @list='$(dist_bases_DATA)'; test -n "$(basesdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(basesdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(basesdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(basesdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(basesdir)" || exit $$?; \ + done + +uninstall-dist_basesDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_bases_DATA)'; test -n "$(basesdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(basesdir)'; $(am__uninstall_files_from_dir) +install-dist_bases_framework_servicesDATA: $(dist_bases_framework_services_DATA) + @$(NORMAL_INSTALL) + @list='$(dist_bases_framework_services_DATA)'; test -n "$(bases_framework_servicesdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(bases_framework_servicesdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(bases_framework_servicesdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(bases_framework_servicesdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(bases_framework_servicesdir)" || exit $$?; \ + done + +uninstall-dist_bases_framework_servicesDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_bases_framework_services_DATA)'; test -n "$(bases_framework_servicesdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(bases_framework_servicesdir)'; $(am__uninstall_files_from_dir) install-dist_pythonDATA: $(dist_python_DATA) @$(NORMAL_INSTALL) @list='$(dist_python_DATA)'; test -n "$(pythondir)" || list=; \ @@ -783,6 +858,27 @@ uninstall-dist_pythonyaml3DATA: @list='$(dist_pythonyaml3_DATA)'; test -n "$(pythonyaml3dir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(pythonyaml3dir)'; $(am__uninstall_files_from_dir) +install-dist_third_partyDATA: $(dist_third_party_DATA) + @$(NORMAL_INSTALL) + @list='$(dist_third_party_DATA)'; test -n "$(third_partydir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(third_partydir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(third_partydir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(third_partydir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(third_partydir)" || exit $$?; \ + done + +uninstall-dist_third_partyDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_third_party_DATA)'; test -n "$(third_partydir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(third_partydir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: @@ -824,7 +920,7 @@ check-am: all-am check: check-am all-am: Makefile $(SCRIPTS) $(DATA) installdirs: - for dir in "$(DESTDIR)$(pythondir)" "$(DESTDIR)$(pythondir)" "$(DESTDIR)$(python_urllib3dir)" "$(DESTDIR)$(python_urllib3_backportsdir)" "$(DESTDIR)$(python_urllib3_contribdir)" "$(DESTDIR)$(python_urllib3_packagesdir)" "$(DESTDIR)$(python_urllib3_securetransportdir)" "$(DESTDIR)$(python_urllib3_ssl_match_hostnamedir)" "$(DESTDIR)$(python_urllib3_utildir)" "$(DESTDIR)$(pythonmodulesdir)" "$(DESTDIR)$(pythonyaml2dir)" "$(DESTDIR)$(pythonyaml3dir)"; do \ + for dir in "$(DESTDIR)$(pythondir)" "$(DESTDIR)$(basesdir)" "$(DESTDIR)$(bases_framework_servicesdir)" "$(DESTDIR)$(pythondir)" "$(DESTDIR)$(python_urllib3dir)" "$(DESTDIR)$(python_urllib3_backportsdir)" "$(DESTDIR)$(python_urllib3_contribdir)" "$(DESTDIR)$(python_urllib3_packagesdir)" "$(DESTDIR)$(python_urllib3_securetransportdir)" "$(DESTDIR)$(python_urllib3_ssl_match_hostnamedir)" "$(DESTDIR)$(python_urllib3_utildir)" "$(DESTDIR)$(pythonmodulesdir)" "$(DESTDIR)$(pythonyaml2dir)" "$(DESTDIR)$(pythonyaml3dir)" "$(DESTDIR)$(third_partydir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am @@ -879,7 +975,9 @@ info: info-am info-am: -install-data-am: install-dist_pythonDATA install-dist_pythonSCRIPTS \ +install-data-am: install-dist_basesDATA \ + install-dist_bases_framework_servicesDATA \ + install-dist_pythonDATA install-dist_pythonSCRIPTS \ install-dist_python_urllib3DATA \ install-dist_python_urllib3_backportsDATA \ install-dist_python_urllib3_contribDATA \ @@ -888,7 +986,7 @@ install-data-am: install-dist_pythonDATA install-dist_pythonSCRIPTS \ install-dist_python_urllib3_ssl_match_hostnameDATA \ install-dist_python_urllib3_utilDATA \ install-dist_pythonmodulesDATA install-dist_pythonyaml2DATA \ - install-dist_pythonyaml3DATA + install-dist_pythonyaml3DATA install-dist_third_partyDATA install-dvi: install-dvi-am @@ -932,7 +1030,9 @@ ps: ps-am ps-am: -uninstall-am: uninstall-dist_pythonDATA uninstall-dist_pythonSCRIPTS \ +uninstall-am: uninstall-dist_basesDATA \ + uninstall-dist_bases_framework_servicesDATA \ + uninstall-dist_pythonDATA uninstall-dist_pythonSCRIPTS \ uninstall-dist_python_urllib3DATA \ uninstall-dist_python_urllib3_backportsDATA \ uninstall-dist_python_urllib3_contribDATA \ @@ -941,15 +1041,18 @@ uninstall-am: uninstall-dist_pythonDATA uninstall-dist_pythonSCRIPTS \ uninstall-dist_python_urllib3_ssl_match_hostnameDATA \ uninstall-dist_python_urllib3_utilDATA \ uninstall-dist_pythonmodulesDATA \ - uninstall-dist_pythonyaml2DATA uninstall-dist_pythonyaml3DATA + uninstall-dist_pythonyaml2DATA uninstall-dist_pythonyaml3DATA \ + uninstall-dist_third_partyDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic cscopelist-am \ ctags-am distclean distclean-generic distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ - install-data-am install-dist_pythonDATA \ - install-dist_pythonSCRIPTS install-dist_python_urllib3DATA \ + install-data-am install-dist_basesDATA \ + install-dist_bases_framework_servicesDATA \ + install-dist_pythonDATA install-dist_pythonSCRIPTS \ + install-dist_python_urllib3DATA \ install-dist_python_urllib3_backportsDATA \ install-dist_python_urllib3_contribDATA \ install-dist_python_urllib3_packagesDATA \ @@ -957,13 +1060,15 @@ uninstall-am: uninstall-dist_pythonDATA uninstall-dist_pythonSCRIPTS \ install-dist_python_urllib3_ssl_match_hostnameDATA \ install-dist_python_urllib3_utilDATA \ install-dist_pythonmodulesDATA install-dist_pythonyaml2DATA \ - install-dist_pythonyaml3DATA install-dvi install-dvi-am \ - install-exec install-exec-am install-html install-html-am \ - install-info install-info-am install-man install-pdf \ - install-pdf-am install-ps install-ps-am install-strip \ - installcheck installcheck-am installdirs maintainer-clean \ - maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ - pdf-am ps ps-am tags-am uninstall uninstall-am \ + install-dist_pythonyaml3DATA install-dist_third_partyDATA \ + install-dvi install-dvi-am install-exec install-exec-am \ + install-html install-html-am install-info install-info-am \ + install-man install-pdf install-pdf-am install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-generic pdf pdf-am ps ps-am tags-am \ + uninstall uninstall-am uninstall-dist_basesDATA \ + uninstall-dist_bases_framework_servicesDATA \ uninstall-dist_pythonDATA uninstall-dist_pythonSCRIPTS \ uninstall-dist_python_urllib3DATA \ uninstall-dist_python_urllib3_backportsDATA \ @@ -973,7 +1078,8 @@ uninstall-am: uninstall-dist_pythonDATA uninstall-dist_pythonSCRIPTS \ uninstall-dist_python_urllib3_ssl_match_hostnameDATA \ uninstall-dist_python_urllib3_utilDATA \ uninstall-dist_pythonmodulesDATA \ - uninstall-dist_pythonyaml2DATA uninstall-dist_pythonyaml3DATA + uninstall-dist_pythonyaml2DATA uninstall-dist_pythonyaml3DATA \ + uninstall-dist_third_partyDATA .in: if sed \ diff --git a/python.d/README.md b/python.d/README.md index 1b04ccdf..009265f7 100644 --- a/python.d/README.md +++ b/python.d/README.md @@ -125,13 +125,118 @@ If no configuration is given, module will attempt to read log file at `/var/log/ --- +# beanstalk + +Module provides server and tube level statistics: + +**Requirements:** + * `python-beanstalkc` + * `python-yaml` + +**Server statistics:** + +1. **Cpu usage** in cpu time + * user + * system + +2. **Jobs rate** in jobs/s + * total + * timeouts + +3. **Connections rate** in connections/s + * connections + +4. **Commands rate** in commands/s + * put + * peek + * peek-ready + * peek-delayed + * peek-buried + * reserve + * use + * watch + * ignore + * delete + * release + * bury + * kick + * stats + * stats-job + * stats-tube + * list-tubes + * list-tube-used + * list-tubes-watched + * pause-tube + +5. **Current tubes** in tubes + * tubes + +6. **Current jobs** in jobs + * urgent + * ready + * reserved + * delayed + * buried + +7. **Current connections** in connections + * written + * producers + * workers + * waiting + +8. **Binlog** in records/s + * written + * migrated + +9. **Uptime** in seconds + * uptime + +**Per tube statistics:** + +1. **Jobs rate** in jobs/s + * jobs + +2. **Jobs** in jobs + * using + * ready + * reserved + * delayed + * buried + +3. **Connections** in connections + * using + * waiting + * watching + +4. **Commands** in commands/s + * deletes + * pauses + +5. **Pause** in seconds + * since + * left + + +### configuration + +Sample: + +```yaml +host : '127.0.0.1' +port : 11300 +``` + +If no configuration is given, module will attempt to connect to beanstalkd on `127.0.0.1:11300` address + +--- + # bind_rndc Module parses bind dump file to collect real-time performance metrics **Requirements:** * Version of bind must be 9.6 + - * Netdata must have permissions to run `rndc status` + * Netdata must have permissions to run `rndc stats` It produces: @@ -218,6 +323,42 @@ local: --- +# couchdb + +This module monitors vital statistics of a local Apache CouchDB 2.x server, including: + +* Overall server reads/writes +* HTTP traffic breakdown + * Request methods (`GET`, `PUT`, `POST`, etc.) + * Response status codes (`200`, `201`, `4xx`, etc.) +* Active server tasks +* Replication status (CouchDB 2.1 and up only) +* Erlang VM stats +* Optional per-database statistics: sizes, # of docs, # of deleted docs + +### Configuration + +Sample for a local server running on port 5984: +```yaml +local: + user: 'admin' + pass: 'password' + node: 'couchdb@127.0.0.1' +``` + +Be sure to specify a correct admin-level username and password. + +You may also need to change the `node` name; this should match the value of `-name NODENAME` in your CouchDB's `etc/vm.args` file. Typically this is of the form `couchdb@fully.qualified.domain.name` in a cluster, or `couchdb@127.0.0.1` / `couchdb@localhost` for a single-node server. + +If you want per-database statistics, these need to be added to the configuration, separated by spaces: +```yaml +local: + ... + databases: 'db1 db2 db3 ...' +``` + +--- + # cpufreq This module shows the current CPU frequency as set by the cpufreq kernel @@ -271,6 +412,59 @@ It produces one aggregate chart or one chart per dns server, showing the query t --- +# dnsdist + +Module monitor dnsdist performance and health metrics. + +Following charts are drawn: + +1. **Response latency** + * latency-slow + * latency100-1000 + * latency50-100 + * latency10-50 + * latency1-10 + * latency0-1 + +2. **Cache performance** + * cache-hits + * cache-misses + +3. **ACL events** + * acl-drops + * rule-drop + * rule-nxdomain + * rule-refused + +4. **Noncompliant data** + * empty-queries + * no-policy + * noncompliant-queries + * noncompliant-responses + +5. **Queries** + * queries + * rdqueries + * rdqueries + +6. **Health** + * downstream-send-errors + * downstream-timeouts + * servfail-responses + * trunc-failures + +### configuration + +```yaml +localhost: + name : 'local' + url : 'http://127.0.0.1:5053/jsonstat?command=stats' + user : 'username' + pass : 'password' + header: + X-API-Key: 'dnsdist-api-key' +``` + # dovecot This module provides statistics information from dovecot server. @@ -1278,6 +1472,45 @@ When no configuration file is found, module tries to connect to TCP/IP socket: ` --- +# powerdns + +Module monitor powerdns performance and health metrics. + +Following charts are drawn: + +1. **Queries and Answers** + * udp-queries + * udp-answers + * tcp-queries + * tcp-answers + +2. **Cache Usage** + * query-cache-hit + * query-cache-miss + * packetcache-hit + * packetcache-miss + +3. **Cache Size** + * query-cache-size + * packetcache-size + * key-cache-size + * meta-cache-size + +4. **Latency** + * latency + +### configuration + +```yaml +local: + name : 'local' + url : 'http://127.0.0.1:8081/api/v1/servers/localhost/statistics' + header : + X-API-Key: 'change_me' +``` + +--- + # rabbitmq Module monitor rabbitmq performance and health metrics. @@ -1321,10 +1554,10 @@ Following charts are drawn: ```yaml socket: name : 'local' - host : '127.0.0.1' - port : 15672 - user : 'guest' - pass : 'guest' + host : '127.0.0.1' + port : 15672 + user : 'guest' + pass : 'guest' ``` @@ -1573,60 +1806,64 @@ Module uses the `varnishstat` command to provide varnish cache statistics. It produces: -1. **Client metrics** - * session accepted - * session dropped - * good client requests received - -2. **All history hit rate ratio** - * cache hits in percent - * cache miss in percent - * cache hits for pass percent - -3. **Curent poll hit rate ratio** - * cache hits in percent - * cache miss in percent - * cache hits for pass percent - -4. **Thread-related metrics** (only for varnish version 4+) - * total number of threads - * threads created - * threads creation failed - * threads hit max - * length os session queue - * sessions queued for thread - -5. **Backend health** - * backend conn. success - * backend conn. not attempted - * backend conn. too many - * backend conn. failures - * backend conn. reuses - * backend conn. recycles - * backend conn. retry - * backend requests made - -6. **Memory usage** - * memory available in megabytes - * memory allocated in megabytes - -7. **Problems summary** - * session dropped - * session accept failures - * session pipe overflow - * backend conn. not attempted - * fetch failed (all causes) - * backend conn. too many - * threads hit max - * threads destroyed - * length of session queue - * HTTP header overflows - * ESI parse errors - * ESI parse warnings - -8. **Uptime** - * varnish instance uptime in seconds +1. **Connections Statistics** in connections/s + * accepted + * dropped + +2. **Client Requests** in requests/s + * received + +3. **All History Hit Rate Ratio** in percent + * hit + * miss + * hitpass + +4. **Current Poll Hit Rate Ratio** in percent + * hit + * miss + * hitpass +5. **Expired Objects** in expired/s + * objects + +6. **Least Recently Used Nuked Objects** in nuked/s + * objects + + +7. **Number Of Threads In All Pools** in threads + * threads + +8. **Threads Statistics** in threads/s + * created + * failed + * limited + +9. **Current Queue Length** in requests + * in queue + +10. **Backend Connections Statistics** in connections/s + * successful + * unhealthy + * reused + * closed + * resycled + * failed + +10. **Requests To The Backend** in requests/s + * received + +11. **ESI Statistics** in problems/s + * errors + * warnings + +12. **Memory Usage** in MB + * free + * allocated + +13. **Uptime** in seconds + * uptime + + ### configuration No configuration is needed. diff --git a/python.d/apache.chart.py b/python.d/apache.chart.py index 71fe0300..789b3c09 100644 --- a/python.d/apache.chart.py +++ b/python.d/apache.chart.py @@ -2,7 +2,7 @@ # Description: apache netdata python.d module # Author: Pawel Krupa (paulfantom) -from base import UrlService +from bases.FrameworkServices.UrlService import UrlService # default module values (can be overridden per job in `config`) # update_every = 2 @@ -31,9 +31,7 @@ CHARTS = { 'options': [None, 'apache Workers', 'workers', 'workers', 'apache.workers', 'stacked'], 'lines': [ ["idle"], - ["idle_servers", 'idle'], ["busy"], - ["busy_servers", 'busy'] ]}, 'reqpersec': { 'options': [None, 'apache Lifetime Avg. Requests/s', 'requests/s', 'statistics', @@ -42,10 +40,10 @@ CHARTS = { ["requests_sec"] ]}, 'bytespersec': { - 'options': [None, 'apache Lifetime Avg. Bandwidth/s', 'kilobytes/s', 'statistics', + 'options': [None, 'apache Lifetime Avg. Bandwidth/s', 'kilobits/s', 'statistics', 'apache.bytesperreq', 'area'], 'lines': [ - ["size_sec", None, 'absolute', 1, 1000] + ["size_sec", None, 'absolute', 8, 1000] ]}, 'requests': { 'options': [None, 'apache Requests', 'requests/s', 'requests', 'apache.requests', 'line'], @@ -53,9 +51,9 @@ CHARTS = { ["requests", None, 'incremental'] ]}, 'net': { - 'options': [None, 'apache Bandwidth', 'kilobytes/s', 'bandwidth', 'apache.net', 'area'], + 'options': [None, 'apache Bandwidth', 'kilobits/s', 'bandwidth', 'apache.net', 'area'], 'lines': [ - ["sent", None, 'incremental'] + ["sent", None, 'incremental', 8, 1] ]}, 'connections': { 'options': [None, 'apache Connections', 'connections', 'connections', 'apache.connections', 'line'], @@ -94,15 +92,22 @@ class Service(UrlService): self.url = self.configuration.get('url', 'http://localhost/server-status?auto') def check(self): - if UrlService.check(self): - if 'idle_servers' in self._data_from_check: - self.__module__ = 'lighttpd' - for chart in self.definitions: - opts = self.definitions[chart]['options'] - opts[1] = opts[1].replace('apache', 'lighttpd') - opts[4] = opts[4].replace('apache', 'lighttpd') - return True - return False + self._manager = self._build_manager() + data = self._get_data() + if not data: + return None + + if 'idle_servers' in data: + self.module_name = 'lighttpd' + for chart in self.definitions: + if chart == 'workers': + lines = self.definitions[chart]['lines'] + lines[0] = ["idle_servers", 'idle'] + lines[1] = ["busy_servers", 'busy'] + opts = self.definitions[chart]['options'] + opts[1] = opts[1].replace('apache', 'lighttpd') + opts[4] = opts[4].replace('apache', 'lighttpd') + return True def _get_data(self): """ diff --git a/python.d/apache_cache.chart.py b/python.d/apache_cache.chart.py deleted file mode 100644 index 3681a851..00000000 --- a/python.d/apache_cache.chart.py +++ /dev/null @@ -1,60 +0,0 @@ -# -*- coding: utf-8 -*- -# Description: apache cache netdata python.d module -# Author: Pawel Krupa (paulfantom) - -from base import LogService - -priority = 60000 -retries = 60 -# update_every = 3 - -ORDER = ['cache'] -CHARTS = { - 'cache': { - 'options': [None, 'apache cached responses', 'percent cached', 'cached', 'apache_cache.cache', 'stacked'], - 'lines': [ - ["hit", 'cache', "percentage-of-absolute-row"], - ["miss", None, "percentage-of-absolute-row"], - ["other", None, "percentage-of-absolute-row"] - ]} -} - - -class Service(LogService): - def __init__(self, configuration=None, name=None): - LogService.__init__(self, configuration=configuration, name=name) - if len(self.log_path) == 0: - self.log_path = "/var/log/apache2/cache.log" - self.order = ORDER - self.definitions = CHARTS - - def _get_data(self): - """ - Parse new log lines - :return: dict - """ - try: - raw = self._get_raw_data() - if raw is None: - return None - elif not raw: - return {'hit': 0, - 'miss': 0, - 'other': 0} - except (ValueError, AttributeError): - return None - - hit = 0 - miss = 0 - other = 0 - for line in raw: - if "cache hit" in line: - hit += 1 - elif "cache miss" in line: - miss += 1 - else: - other += 1 - - return {'hit': hit, - 'miss': miss, - 'other': other} diff --git a/python.d/beanstalk.chart.py b/python.d/beanstalk.chart.py new file mode 100644 index 00000000..8880afdd --- /dev/null +++ b/python.d/beanstalk.chart.py @@ -0,0 +1,250 @@ +# -*- coding: utf-8 -*- +# Description: beanstalk netdata python.d module +# Author: l2isbad + +try: + import beanstalkc + BEANSTALKC = True +except ImportError: + BEANSTALKC = False + +try: + import yaml + YAML = True +except ImportError: + YAML = False + +from bases.FrameworkServices.SimpleService import SimpleService + +# default module values (can be overridden per job in `config`) +# update_every = 2 +priority = 60000 +retries = 60 + +ORDER = ['cpu_usage', 'jobs_rate', 'connections_rate', 'commands_rate', 'current_tubes', 'current_jobs', + 'current_connections', 'binlog', 'uptime'] + +CHARTS = { + 'cpu_usage': { + 'options': [None, 'Cpu Usage', 'cpu time', 'server statistics', 'beanstalk.cpu_usage', 'area'], + 'lines': [ + ['rusage-utime', 'user', 'incremental'], + ['rusage-stime', 'system', 'incremental'] + ] + }, + 'jobs_rate': { + 'options': [None, 'Jobs Rate', 'jobs/s', 'server statistics', 'beanstalk.jobs_rate', 'line'], + 'lines': [ + ['total-jobs', 'total', 'incremental'], + ['job-timeouts', 'timeouts', 'incremental'] + ] + }, + 'connections_rate': { + 'options': [None, 'Connections Rate', 'connections/s', 'server statistics', 'beanstalk.connections_rate', + 'area'], + 'lines': [ + ['total-connections', 'connections', 'incremental'] + ] + }, + 'commands_rate': { + 'options': [None, 'Commands Rate', 'commands/s', 'server statistics', 'beanstalk.commands_rate', 'stacked'], + 'lines': [ + ['cmd-put', 'put', 'incremental'], + ['cmd-peek', 'peek', 'incremental'], + ['cmd-peek-ready', 'peek-ready', 'incremental'], + ['cmd-peek-delayed', 'peek-delayed', 'incremental'], + ['cmd-peek-buried', 'peek-buried', 'incremental'], + ['cmd-reserve', 'reserve', 'incremental'], + ['cmd-use', 'use', 'incremental'], + ['cmd-watch', 'watch', 'incremental'], + ['cmd-ignore', 'ignore', 'incremental'], + ['cmd-delete', 'delete', 'incremental'], + ['cmd-release', 'release', 'incremental'], + ['cmd-bury', 'bury', 'incremental'], + ['cmd-kick', 'kick', 'incremental'], + ['cmd-stats', 'stats', 'incremental'], + ['cmd-stats-job', 'stats-job', 'incremental'], + ['cmd-stats-tube', 'stats-tube', 'incremental'], + ['cmd-list-tubes', 'list-tubes', 'incremental'], + ['cmd-list-tube-used', 'list-tube-used', 'incremental'], + ['cmd-list-tubes-watched', 'list-tubes-watched', 'incremental'], + ['cmd-pause-tube', 'pause-tube', 'incremental'] + ] + }, + 'current_tubes': { + 'options': [None, 'Current Tubes', 'tubes', 'server statistics', 'beanstalk.current_tubes', 'area'], + 'lines': [ + ['current-tubes', 'tubes'] + ] + }, + 'current_jobs': { + 'options': [None, 'Current Jobs', 'jobs', 'server statistics', 'beanstalk.current_jobs', 'stacked'], + 'lines': [ + ['current-jobs-urgent', 'urgent'], + ['current-jobs-ready', 'ready'], + ['current-jobs-reserved', 'reserved'], + ['current-jobs-delayed', 'delayed'], + ['current-jobs-buried', 'buried'] + ] + }, + 'current_connections': { + 'options': [None, 'Current Connections', 'connections', 'server statistics', + 'beanstalk.current_connections', 'line'], + 'lines': [ + ['current-connections', 'written'], + ['current-producers', 'producers'], + ['current-workers', 'workers'], + ['current-waiting', 'waiting'] + ] + }, + 'binlog': { + 'options': [None, 'Binlog', 'records/s', 'server statistics', 'beanstalk.binlog', 'line'], + 'lines': [ + ['binlog-records-written', 'written', 'incremental'], + ['binlog-records-migrated', 'migrated', 'incremental'] + ] + }, + 'uptime': { + 'options': [None, 'Uptime', 'seconds', 'server statistics', 'beanstalk.uptime', 'line'], + 'lines': [ + ['uptime'], + ] + } +} + + +def tube_chart_template(name): + order = ['{0}_jobs_rate'.format(name), + '{0}_jobs'.format(name), + '{0}_connections'.format(name), + '{0}_commands'.format(name), + '{0}_pause'.format(name) + ] + family = 'tube {0}'.format(name) + + charts = { + order[0]: { + 'options': [None, 'Job Rate', 'jobs/s', family, 'beanstalk.jobs_rate', 'area'], + 'lines': [ + ['_'.join([name, 'total-jobs']), 'jobs', 'incremental'] + ]}, + order[1]: { + 'options': [None, 'Jobs', 'jobs', family, 'beanstalk.jobs', 'stacked'], + 'lines': [ + ['_'.join([name, 'current-jobs-urgent']), 'urgent'], + ['_'.join([name, 'current-jobs-ready']), 'ready'], + ['_'.join([name, 'current-jobs-reserved']), 'reserved'], + ['_'.join([name, 'current-jobs-delayed']), 'delayed'], + ['_'.join([name, 'current-jobs-buried']), 'buried'] + ]}, + order[2]: { + 'options': [None, 'Connections', 'connections', family, 'beanstalk.connections', 'stacked'], + 'lines': [ + ['_'.join([name, 'current-using']), 'using'], + ['_'.join([name, 'current-waiting']), 'waiting'], + ['_'.join([name, 'current-watching']), 'watching'] + ]}, + order[3]: { + 'options': [None, 'Commands', 'commands/s', family, 'beanstalk.commands', 'stacked'], + 'lines': [ + ['_'.join([name, 'cmd-delete']), 'deletes', 'incremental'], + ['_'.join([name, 'cmd-pause-tube']), 'pauses', 'incremental'] + ]}, + order[4]: { + 'options': [None, 'Pause', 'seconds', family, 'beanstalk.pause', 'stacked'], + 'lines': [ + ['_'.join([name, 'pause']), 'since'], + ['_'.join([name, 'pause-time-left']), 'left'] + ]} + + } + + return order, charts + + +class Service(SimpleService): + def __init__(self, configuration=None, name=None): + SimpleService.__init__(self, configuration=configuration, name=name) + self.configuration = configuration + self.order = list(ORDER) + self.definitions = dict(CHARTS) + self.conn = None + self.alive = True + + def check(self): + if not BEANSTALKC: + self.error("'beanstalkc' module is needed to use beanstalk.chart.py") + return False + + if not YAML: + self.error("'yaml' module is needed to use beanstalk.chart.py") + return False + + self.conn = self.connect() + + return True if self.conn else False + + def get_data(self): + """ + :return: dict + """ + if not self.is_alive(): + return None + + active_charts = self.charts.active_charts() + data = dict() + + try: + data.update(self.conn.stats()) + + for tube in self.conn.tubes(): + stats = self.conn.stats_tube(tube) + + if tube + '_jobs_rate' not in active_charts: + self.create_new_tube_charts(tube) + + for stat in stats: + data['_'.join([tube, stat])] = stats[stat] + + except beanstalkc.SocketError: + self.alive = False + return None + + return data or None + + def create_new_tube_charts(self, tube): + order, charts = tube_chart_template(tube) + + for chart_name in order: + params = [chart_name] + charts[chart_name]['options'] + dimensions = charts[chart_name]['lines'] + + new_chart = self.charts.add_chart(params) + for dimension in dimensions: + new_chart.add_dimension(dimension) + + def connect(self): + host = self.configuration.get('host', '127.0.0.1') + port = self.configuration.get('port', 11300) + timeout = self.configuration.get('timeout', 1) + try: + return beanstalkc.Connection(host=host, + port=port, + connect_timeout=timeout, + parse_yaml=yaml.load) + except beanstalkc.SocketError as error: + self.error('Connection to {0}:{1} failed: {2}'.format(host, port, error)) + return None + + def reconnect(self): + try: + self.conn.reconnect() + self.alive = True + return True + except beanstalkc.SocketError: + return False + + def is_alive(self): + if not self.alive: + return self.reconnect() + return True diff --git a/python.d/bind_rndc.chart.py b/python.d/bind_rndc.chart.py index 5a974928..cc96659b 100644 --- a/python.d/bind_rndc.chart.py +++ b/python.d/bind_rndc.chart.py @@ -2,11 +2,13 @@ # Description: bind rndc netdata python.d module # Author: l2isbad -from os.path import getsize -from os import access, R_OK -from subprocess import Popen +import os + from collections import defaultdict -from base import SimpleService +from subprocess import Popen + +from bases.collection import find_binary +from bases.FrameworkServices.SimpleService import SimpleService priority = 60000 retries = 60 @@ -94,7 +96,7 @@ class Service(SimpleService): self.order = ORDER self.definitions = CHARTS self.named_stats_path = self.configuration.get('named_stats_path', '/var/log/bind/named.stats') - self.rndc = self.find_binary('rndc') + self.rndc = find_binary('rndc') self.data = dict(nms_requests=0, nms_responses=0, nms_failure=0, nms_auth=0, nms_non_auth=0, nms_nxrrset=0, nms_success=0, nms_nxdomain=0, nms_recursion=0, nms_duplicate=0, nms_rejected_queries=0, @@ -102,10 +104,10 @@ class Service(SimpleService): def check(self): if not self.rndc: - self.error('Can\'t locate \'rndc\' binary or binary is not executable by netdata') + self.error('Can\'t locate "rndc" binary or binary is not executable by netdata') return False - if not access(self.named_stats_path, R_OK): + if not (os.path.isfile(self.named_stats_path) and os.access(self.named_stats_path, os.R_OK)): self.error('Cannot access file %s' % self.named_stats_path) return False @@ -124,7 +126,7 @@ class Service(SimpleService): """ result = dict() try: - current_size = getsize(self.named_stats_path) + current_size = os.path.getsize(self.named_stats_path) run_rndc = Popen([self.rndc, 'stats'], shell=False) run_rndc.wait() @@ -159,12 +161,12 @@ class Service(SimpleService): parsed_key, chart_name = elem[0], elem[1] for dimension_id, value in queries_mapper(data=parsed[parsed_key], add=chart_name[:9]).items(): + if dimension_id not in self.data: dimension = dimension_id.replace(chart_name[:9], '') - self._add_new_dimension(dimension_id=dimension_id, - dimension=dimension, - chart_name=chart_name, - priority=self.priority + self.order.index(chart_name)) + if dimension_id not in self.charts[chart_name]: + self.charts[chart_name].add_dimension([dimension_id, dimension, 'incremental']) + self.data[dimension_id] = value self.data['stats_size'] = raw_data['size'] diff --git a/python.d/chrony.chart.py b/python.d/chrony.chart.py index 96d7e696..8f331fa5 100644 --- a/python.d/chrony.chart.py +++ b/python.d/chrony.chart.py @@ -2,10 +2,10 @@ # Description: chrony netdata python.d module # Author: Dominik Schloesser (domschl) -from base import ExecutableService +from bases.FrameworkServices.ExecutableService import ExecutableService # default module values (can be overridden per job in `config`) -# update_every = 10 +update_every = 5 priority = 60000 retries = 10 diff --git a/python.d/couchdb.chart.py b/python.d/couchdb.chart.py new file mode 100644 index 00000000..558bac58 --- /dev/null +++ b/python.d/couchdb.chart.py @@ -0,0 +1,410 @@ +# -*- coding: utf-8 -*- +# Description: couchdb netdata python.d module +# Author: wohali <wohali@apache.org> +# Thanks to l2isbad for good examples :) + +from collections import namedtuple, defaultdict +from json import loads +from threading import Thread +from socket import gethostbyname, gaierror +try: + from queue import Queue +except ImportError: + from Queue import Queue + +from bases.FrameworkServices.UrlService import UrlService + +# default module values (can be overridden per job in `config`) +update_every = 1 +priority = 60000 +retries = 60 + +METHODS = namedtuple('METHODS', ['get_data', 'url', 'stats']) + +OVERVIEW_STATS = [ + 'couchdb.database_reads.value', + 'couchdb.database_writes.value', + 'couchdb.httpd.view_reads.value' + 'couchdb.httpd_request_methods.COPY.value', + 'couchdb.httpd_request_methods.DELETE.value', + 'couchdb.httpd_request_methods.GET.value', + 'couchdb.httpd_request_methods.HEAD.value', + 'couchdb.httpd_request_methods.OPTIONS.value', + 'couchdb.httpd_request_methods.POST.value', + 'couchdb.httpd_request_methods.PUT.value', + 'couchdb.httpd_status_codes.200.value', + 'couchdb.httpd_status_codes.201.value', + 'couchdb.httpd_status_codes.202.value', + 'couchdb.httpd_status_codes.204.value', + 'couchdb.httpd_status_codes.206.value', + 'couchdb.httpd_status_codes.301.value', + 'couchdb.httpd_status_codes.302.value', + 'couchdb.httpd_status_codes.304.value', + 'couchdb.httpd_status_codes.400.value', + 'couchdb.httpd_status_codes.401.value', + 'couchdb.httpd_status_codes.403.value', + 'couchdb.httpd_status_codes.404.value', + 'couchdb.httpd_status_codes.405.value', + 'couchdb.httpd_status_codes.406.value', + 'couchdb.httpd_status_codes.409.value', + 'couchdb.httpd_status_codes.412.value', + 'couchdb.httpd_status_codes.413.value', + 'couchdb.httpd_status_codes.414.value', + 'couchdb.httpd_status_codes.415.value', + 'couchdb.httpd_status_codes.416.value', + 'couchdb.httpd_status_codes.417.value', + 'couchdb.httpd_status_codes.500.value', + 'couchdb.httpd_status_codes.501.value', + 'couchdb.open_os_files.value', + 'couch_replicator.jobs.running.value', + 'couch_replicator.jobs.pending.value', + 'couch_replicator.jobs.crashed.value', +] + +SYSTEM_STATS = [ + 'context_switches', + 'run_queue', + 'ets_table_count', + 'reductions', + 'memory.atom', + 'memory.atom_used', + 'memory.binary', + 'memory.code', + 'memory.ets', + 'memory.other', + 'memory.processes', + 'io_input', + 'io_output', + 'os_proc_count', + 'process_count', + 'internal_replication_jobs' +] + +DB_STATS = [ + 'doc_count', + 'doc_del_count', + 'sizes.file', + 'sizes.external', + 'sizes.active' +] + +ORDER = [ + 'activity', + 'request_methods', + 'response_codes', + 'active_tasks', + 'replicator_jobs', + 'open_files', + 'db_sizes_file', + 'db_sizes_external', + 'db_sizes_active', + 'db_doc_counts', + 'db_doc_del_counts', + 'erlang_memory', + 'erlang_proc_counts', + 'erlang_peak_msg_queue', + 'erlang_reductions' +] + +CHARTS = { + 'activity': { + 'options': [None, 'Overall Activity', 'req/s', + 'dbactivity', 'couchdb.activity', 'stacked'], + 'lines': [ + ['couchdb_database_reads', 'DB reads', 'incremental'], + ['couchdb_database_writes', 'DB writes', 'incremental'], + ['couchdb_httpd_view_reads', 'View reads', 'incremental'] + ] + }, + 'request_methods': { + 'options': [None, 'HTTP request methods', 'req/s', + 'httptraffic', 'couchdb.request_methods', + 'stacked'], + 'lines': [ + ['couchdb_httpd_request_methods_COPY', 'COPY', 'incremental'], + ['couchdb_httpd_request_methods_DELETE', 'DELETE', 'incremental'], + ['couchdb_httpd_request_methods_GET', 'GET', 'incremental'], + ['couchdb_httpd_request_methods_HEAD', 'HEAD', 'incremental'], + ['couchdb_httpd_request_methods_OPTIONS', 'OPTIONS', + 'incremental'], + ['couchdb_httpd_request_methods_POST', 'POST', 'incremental'], + ['couchdb_httpd_request_methods_PUT', 'PUT', 'incremental'] + ] + }, + 'response_codes': { + 'options': [None, 'HTTP response status codes', 'resp/s', + 'httptraffic', 'couchdb.response_codes', + 'stacked'], + 'lines': [ + ['couchdb_httpd_status_codes_200', '200 OK', 'incremental'], + ['couchdb_httpd_status_codes_201', '201 Created', 'incremental'], + ['couchdb_httpd_status_codes_202', '202 Accepted', 'incremental'], + ['couchdb_httpd_status_codes_2xx', 'Other 2xx Success', + 'incremental'], + ['couchdb_httpd_status_codes_3xx', '3xx Redirection', + 'incremental'], + ['couchdb_httpd_status_codes_4xx', '4xx Client error', + 'incremental'], + ['couchdb_httpd_status_codes_5xx', '5xx Server error', + 'incremental'] + ] + }, + 'open_files': { + 'options': [None, 'Open files', 'files', + 'ops', 'couchdb.open_files', 'line'], + 'lines': [ + ['couchdb_open_os_files', '# files', 'absolute'] + ] + }, + 'active_tasks': { + 'options': [None, 'Active task breakdown', 'tasks', + 'ops', 'couchdb.active_tasks', 'stacked'], + 'lines': [ + ['activetasks_indexer', 'Indexer', 'absolute'], + ['activetasks_database_compaction', 'DB Compaction', 'absolute'], + ['activetasks_replication', 'Replication', 'absolute'], + ['activetasks_view_compaction', 'View Compaction', 'absolute'] + ] + }, + 'replicator_jobs': { + 'options': [None, 'Replicator job breakdown', 'jobs', + 'ops', 'couchdb.replicator_jobs', 'stacked'], + 'lines': [ + ['couch_replicator_jobs_running', 'Running', 'absolute'], + ['couch_replicator_jobs_pending', 'Pending', 'absolute'], + ['couch_replicator_jobs_crashed', 'Crashed', 'absolute'], + ['internal_replication_jobs', 'Internal replication jobs', + 'absolute'] + ] + }, + 'erlang_memory': { + 'options': [None, 'Erlang VM memory usage', 'bytes', + 'erlang', 'couchdb.erlang_vm_memory', 'stacked'], + 'lines': [ + ['memory_atom', 'atom', 'absolute'], + ['memory_binary', 'binaries', 'absolute'], + ['memory_code', 'code', 'absolute'], + ['memory_ets', 'ets', 'absolute'], + ['memory_processes', 'procs', 'absolute'], + ['memory_other', 'other', 'absolute'] + ] + }, + 'erlang_reductions': { + 'options': [None, 'Erlang reductions', 'count', + 'erlang', 'couchdb.reductions', 'line'], + 'lines': [ + ['reductions', 'reductions', 'incremental'] + ] + }, + 'erlang_proc_counts': { + 'options': [None, 'Process counts', 'count', + 'erlang', 'couchdb.proccounts', 'line'], + 'lines': [ + ['os_proc_count', 'OS procs', 'absolute'], + ['process_count', 'erl procs', 'absolute'] + ] + }, + 'erlang_peak_msg_queue': { + 'options': [None, 'Peak message queue size', 'count', + 'erlang', 'couchdb.peakmsgqueue', + 'line'], + 'lines': [ + ['peak_msg_queue', 'peak size', 'absolute'] + ] + }, + # Lines for the following are added as part of check() + 'db_sizes_file': { + 'options': [None, 'Database sizes (file)', 'KB', + 'perdbstats', 'couchdb.db_sizes_file', 'line'], + 'lines': [] + }, + 'db_sizes_external': { + 'options': [None, 'Database sizes (external)', 'KB', + 'perdbstats', 'couchdb.db_sizes_external', 'line'], + 'lines': [] + }, + 'db_sizes_active': { + 'options': [None, 'Database sizes (active)', 'KB', + 'perdbstats', 'couchdb.db_sizes_active', 'line'], + 'lines': [] + }, + 'db_doc_counts': { + 'options': [None, 'Database # of docs', 'docs', + 'perdbstats', 'couchdb_db_doc_count', 'line'], + 'lines': [] + }, + 'db_doc_del_counts': { + 'options': [None, 'Database # of deleted docs', 'docs', + 'perdbstats', 'couchdb_db_doc_del_count', 'line'], + 'lines': [] + } +} + + +class Service(UrlService): + def __init__(self, configuration=None, name=None): + UrlService.__init__(self, configuration=configuration, name=name) + self.order = ORDER + self.definitions = CHARTS + self.host = self.configuration.get('host', '127.0.0.1') + self.port = self.configuration.get('port', 5984) + self.node = self.configuration.get('node', 'couchdb@127.0.0.1') + self.scheme = self.configuration.get('scheme', 'http') + self.user = self.configuration.get('user') + self.password = self.configuration.get('pass') + try: + self.dbs = self.configuration.get('databases').split(' ') + except (KeyError, AttributeError): + self.dbs = [] + + def check(self): + if not (self.host and self.port): + self.error('Host is not defined in the module configuration file') + return False + try: + self.host = gethostbyname(self.host) + except gaierror as error: + self.error(str(error)) + return False + self.url = '{scheme}://{host}:{port}'.format(scheme=self.scheme, + host=self.host, + port=self.port) + stats = self.url + '/_node/{node}/_stats'.format(node=self.node) + active_tasks = self.url + '/_active_tasks' + system = self.url + '/_node/{node}/_system'.format(node=self.node) + self.methods = [METHODS(get_data=self._get_overview_stats, + url=stats, + stats=OVERVIEW_STATS), + METHODS(get_data=self._get_active_tasks_stats, + url=active_tasks, + stats=None), + METHODS(get_data=self._get_overview_stats, + url=system, + stats=SYSTEM_STATS), + METHODS(get_data=self._get_dbs_stats, + url=self.url, + stats=DB_STATS)] + # must initialise manager before using _get_raw_data + self._manager = self._build_manager() + self.dbs = [db for db in self.dbs + if self._get_raw_data(self.url + '/' + db)] + for db in self.dbs: + self.definitions['db_sizes_file']['lines'].append( + ['db_'+db+'_sizes_file', db, 'absolute', 1, 1000] + ) + self.definitions['db_sizes_external']['lines'].append( + ['db_'+db+'_sizes_external', db, 'absolute', 1, 1000] + ) + self.definitions['db_sizes_active']['lines'].append( + ['db_'+db+'_sizes_active', db, 'absolute', 1, 1000] + ) + self.definitions['db_doc_counts']['lines'].append( + ['db_'+db+'_doc_count', db, 'absolute'] + ) + self.definitions['db_doc_del_counts']['lines'].append( + ['db_'+db+'_doc_del_count', db, 'absolute'] + ) + return UrlService.check(self) + + def _get_data(self): + threads = list() + queue = Queue() + result = dict() + + for method in self.methods: + th = Thread(target=method.get_data, + args=(queue, method.url, method.stats)) + th.start() + threads.append(th) + + for thread in threads: + thread.join() + result.update(queue.get()) + + # self.info('couchdb result = ' + str(result)) + return result or None + + def _get_overview_stats(self, queue, url, stats): + raw_data = self._get_raw_data(url) + if not raw_data: + return queue.put(dict()) + data = loads(raw_data) + to_netdata = self._fetch_data(raw_data=data, metrics=stats) + if 'message_queues' in data: + to_netdata['peak_msg_queue'] = get_peak_msg_queue(data) + return queue.put(to_netdata) + + def _get_active_tasks_stats(self, queue, url, _): + taskdict = defaultdict(int) + taskdict["activetasks_indexer"] = 0 + taskdict["activetasks_database_compaction"] = 0 + taskdict["activetasks_replication"] = 0 + taskdict["activetasks_view_compaction"] = 0 + raw_data = self._get_raw_data(url) + if not raw_data: + return queue.put(dict()) + data = loads(raw_data) + for task in data: + taskdict["activetasks_" + task["type"]] += 1 + return queue.put(dict(taskdict)) + + def _get_dbs_stats(self, queue, url, stats): + to_netdata = {} + for db in self.dbs: + raw_data = self._get_raw_data(url + '/' + db) + if not raw_data: + continue + data = loads(raw_data) + for metric in stats: + value = data + metrics_list = metric.split('.') + try: + for m in metrics_list: + value = value[m] + except KeyError as e: + self.debug('cannot process ' + metric + ' for ' + db + + ": " + str(e)) + continue + metric_name = 'db_{0}_{1}'.format(db, '_'.join(metrics_list)) + to_netdata[metric_name] = value + return queue.put(to_netdata) + + def _fetch_data(self, raw_data, metrics): + data = dict() + for metric in metrics: + value = raw_data + metrics_list = metric.split('.') + try: + for m in metrics_list: + value = value[m] + except KeyError as e: + self.debug('cannot process ' + metric + ': ' + str(e)) + continue + # strip off .value from end of stat + if metrics_list[-1] == 'value': + metrics_list = metrics_list[:-1] + # sum up 3xx/4xx/5xx + if metrics_list[0:2] == ['couchdb', 'httpd_status_codes'] and \ + int(metrics_list[2]) > 202: + metrics_list[2] = '{0}xx'.format(int(metrics_list[2]) // 100) + if '_'.join(metrics_list) in data: + data['_'.join(metrics_list)] += value + else: + data['_'.join(metrics_list)] = value + else: + data['_'.join(metrics_list)] = value + return data + + +def get_peak_msg_queue(data): + maxsize = 0 + queues = data['message_queues'] + for queue in iter(queues.values()): + if isinstance(queue, dict) and 'count' in queue: + value = queue['count'] + elif isinstance(queue, int): + value = queue + else: + continue + maxsize = max(maxsize, value) + return maxsize diff --git a/python.d/cpufreq.chart.py b/python.d/cpufreq.chart.py index 01cc22b0..3abde736 100644 --- a/python.d/cpufreq.chart.py +++ b/python.d/cpufreq.chart.py @@ -4,8 +4,8 @@ import glob import os -import time -from base import SimpleService + +from bases.FrameworkServices.SimpleService import SimpleService # default module values (can be overridden per job in `config`) # update_every = 2 @@ -14,12 +14,13 @@ ORDER = ['cpufreq'] CHARTS = { 'cpufreq': { - 'options': [None, 'CPU Clock', 'MHz', 'cpufreq', None, 'line'], + 'options': [None, 'CPU Clock', 'MHz', 'cpufreq', 'cpufreq.cpufreq', 'line'], 'lines': [ # lines are created dynamically in `check()` method ]} } + class Service(SimpleService): def __init__(self, configuration=None, name=None): prefix = os.getenv('NETDATA_HOST_PREFIX', "") @@ -29,7 +30,7 @@ class Service(SimpleService): SimpleService.__init__(self, configuration=configuration, name=name) self.order = ORDER self.definitions = CHARTS - self._orig_name = "" + self.fake_name = 'cpu' self.assignment = {} self.accurate_exists = True self.accurate_last = {} @@ -72,7 +73,6 @@ class Service(SimpleService): if accurate_ok: return data - for name, paths in self.assignment.items(): data[name] = open(paths['inaccurate'], 'r').read() @@ -84,8 +84,6 @@ class Service(SimpleService): except (KeyError, TypeError): self.error("No path specified. Using: '" + self.sys_dir + "'") - self._orig_name = self.chart_name - for path in glob.glob(self.sys_dir + '/system/cpu/cpu*/cpufreq/stats/time_in_state'): path_elem = path.split('/') cpu = path_elem[-4] @@ -113,14 +111,3 @@ class Service(SimpleService): return True - def create(self): - self.chart_name = "cpu" - status = SimpleService.create(self) - self.chart_name = self._orig_name - return status - - def update(self, interval): - self.chart_name = "cpu" - status = SimpleService.update(self, interval=interval) - self.chart_name = self._orig_name - return status diff --git a/python.d/cpuidle.chart.py b/python.d/cpuidle.chart.py index e5ed49bd..d14c6aaf 100644 --- a/python.d/cpuidle.chart.py +++ b/python.d/cpuidle.chart.py @@ -5,8 +5,8 @@ import glob import os import platform -import time -from base import SimpleService + +from bases.FrameworkServices.SimpleService import SimpleService import ctypes syscall = ctypes.CDLL('libc.so.6').syscall @@ -14,6 +14,7 @@ syscall = ctypes.CDLL('libc.so.6').syscall # default module values (can be overridden per job in `config`) # update_every = 2 + class Service(SimpleService): def __init__(self, configuration=None, name=None): prefix = os.getenv('NETDATA_HOST_PREFIX', "") @@ -24,11 +25,12 @@ class Service(SimpleService): SimpleService.__init__(self, configuration=configuration, name=name) self.order = [] self.definitions = {} - self._orig_name = "" + self.fake_name = 'cpu' self.assignment = {} self.last_schedstat = None - def __gettid(self): + @staticmethod + def __gettid(): # This is horrendous. We need the *thread id* (not the *process id*), # but there's no Python standard library way of doing that. If you need # to enable this module on a non-x86 machine type, you'll have to find @@ -108,8 +110,6 @@ class Service(SimpleService): self.error("Cannot get thread ID. Stats would be completely broken.") return False - self._orig_name = self.chart_name - for path in sorted(glob.glob(self.sys_dir + '/cpu*/cpuidle/state*/name')): # ['', 'sys', 'devices', 'system', 'cpu', 'cpu0', 'cpuidle', 'state3', 'name'] path_elem = path.split('/') @@ -122,7 +122,7 @@ class Service(SimpleService): self.order.append(orderid) active_name = '%s_active_time' % (cpu,) self.definitions[orderid] = { - 'options': [None, 'C-state residency', 'time%', 'cpuidle', None, 'stacked'], + 'options': [None, 'C-state residency', 'time%', 'cpuidle', 'cpuidle.cpuidle', 'stacked'], 'lines': [ [active_name, 'C0 (active)', 'percentage-of-incremental-row', 1, 1], ], @@ -146,16 +146,3 @@ class Service(SimpleService): return True - def create(self): - self.chart_name = "cpu" - status = SimpleService.create(self) - self.chart_name = self._orig_name - return status - - def update(self, interval): - self.chart_name = "cpu" - status = SimpleService.update(self, interval=interval) - self.chart_name = self._orig_name - return status - -# vim: set ts=4 sts=4 sw=4 et: diff --git a/python.d/dns_query_time.chart.py b/python.d/dns_query_time.chart.py index 9053d9a1..9a794a9c 100644 --- a/python.d/dns_query_time.chart.py +++ b/python.d/dns_query_time.chart.py @@ -2,6 +2,10 @@ # Description: dns_query_time netdata python.d module # Author: l2isbad +from random import choice +from threading import Thread +from socket import getaddrinfo, gaierror + try: from time import monotonic as time except ImportError: @@ -15,10 +19,8 @@ try: from queue import Queue except ImportError: from Queue import Queue -from random import choice -from threading import Thread -from socket import gethostbyname, gaierror -from base import SimpleService + +from bases.FrameworkServices.SimpleService import SimpleService # default module values (can be overridden per job in `config`) @@ -43,7 +45,6 @@ class Service(SimpleService): return False self.timeout = self.timeout if isinstance(self.timeout, int) else 4 - self.update_every = self.timeout + 1 if self.update_every <= self.timeout else self.update_every if not all([self.domains, self.server_list, isinstance(self.server_list, str), isinstance(self.domains, str)]): @@ -69,9 +70,7 @@ class Service(SimpleService): if not self.server_list: return False - self._data_from_check = data self.order, self.definitions = create_charts(aggregate=self.aggregate, server_list=self.server_list) - self.info(str({'domains': len(self.domains), 'servers': self.server_list})) return True def _get_data(self, timeout=None): @@ -110,7 +109,7 @@ def dns_request(server_list, timeout, domains): def check_ns(ns): try: - return gethostbyname(ns) + return getaddrinfo(ns, 'domain')[0][4][0] except gaierror: return False diff --git a/python.d/dnsdist.chart.py b/python.d/dnsdist.chart.py new file mode 100644 index 00000000..b40112cb --- /dev/null +++ b/python.d/dnsdist.chart.py @@ -0,0 +1,101 @@ +# -*- coding: utf-8 -*- +from json import loads +from bases.FrameworkServices.UrlService import UrlService + +ORDER = ['queries', 'queries_dropped', 'packets_dropped', 'answers', 'backend_responses', 'backend_commerrors', 'backend_errors', 'cache', 'servercpu', 'servermem', 'query_latency', 'query_latency_avg'] +CHARTS = { + 'queries': { + 'options': [None, 'Client queries received', 'queries/s', 'queries', 'dnsdist.queries', 'line'], + 'lines': [ + ['queries', 'all', 'incremental'], + ['rdqueries', 'recursive', 'incremental'], + ['empty-queries', 'empty', 'incremental'] + ]}, + 'queries_dropped': { + 'options': [None, 'Client queries dropped', 'queries/s', 'queries', 'dnsdist.queries_dropped', 'line'], + 'lines': [ + ['rule-drop', 'rule drop', 'incremental'], + ['dyn-blocked', 'dynamic block', 'incremental'], + ['no-policy', 'no policy', 'incremental'], + ['noncompliant-queries', 'non compliant', 'incremental'] + ]}, + 'packets_dropped': { + 'options': [None, 'Packets dropped', 'packets/s', 'packets', 'dnsdist.packets_dropped', 'line'], + 'lines': [ + ['acl-drops', 'acl', 'incremental'] + ]}, + 'answers': { + 'options': [None, 'Answers statistics', 'answers/s', 'answers', 'dnsdist.answers', 'line'], + 'lines': [ + ['self-answered', 'self answered', 'incremental'], + ['rule-nxdomain', 'nxdomain', 'incremental', -1], + ['rule-refused', 'refused', 'incremental', -1], + ['trunc-failures', 'trunc failures', 'incremental', -1] + ]}, + 'backend_responses': { + 'options': [None, 'Backend responses', 'responses/s', 'backends', 'dnsdist.backend_responses', 'line'], + 'lines': [ + ['responses', 'responses', 'incremental'] + ]}, + 'backend_commerrors': { + 'options': [None, 'Backend Communication Errors', 'errors/s', 'backends', 'dnsdist.backend_commerrors', 'line'], + 'lines': [ + ['downstream-send-errors', 'send errors', 'incremental'] + ]}, + 'backend_errors': { + 'options': [None, 'Backend error responses', 'responses/s', 'backends', 'dnsdist.backend_errors', 'line'], + 'lines': [ + ['downstream-timeouts', 'timeout', 'incremental'], + ['servfail-responses', 'servfail', 'incremental'], + ['noncompliant-responses', 'non compliant', 'incremental'] + ]}, + 'cache': { + 'options': [None, 'Cache performance', 'answers/s', 'cache', 'dnsdist.cache', 'area'], + 'lines': [ + ['cache-hits', 'hits', 'incremental'], + ['cache-misses', 'misses', 'incremental', -1] + ]}, + 'servercpu': { + 'options': [None, 'DNSDIST server CPU utilization', 'ms/s', 'server', 'dnsdist.servercpu', 'stacked'], + 'lines': [ + ['cpu-sys-msec', 'system state', 'incremental'], + ['cpu-user-msec', 'user state', 'incremental'] + ]}, + 'servermem': { + 'options': [None, 'DNSDIST server memory utilization', 'MB', 'server', 'dnsdist.servermem', 'area'], + 'lines': [ + ['real-memory-usage', 'memory usage', 'absolute', 1, 1048576] + ]}, + 'query_latency': { + 'options': [None, 'Query latency', 'queries/s', 'latency', 'dnsdist.query_latency', 'stacked'], + 'lines': [ + ['latency0-1', '1ms', 'incremental'], + ['latency1-10', '10ms', 'incremental'], + ['latency10-50', '50ms', 'incremental'], + ['latency50-100', '100ms', 'incremental'], + ['latency100-1000', '1sec', 'incremental'], + ['latency-slow', 'slow', 'incremental'] + ]}, + 'query_latency_avg': { + 'options': [None, 'Average latency for the last N queries', 'ms/query', 'latency', 'dnsdist.query_latency_avg', 'line'], + 'lines': [ + ['latency-avg100', '100', 'absolute'], + ['latency-avg1000', '1k', 'absolute'], + ['latency-avg10000', '10k', 'absolute'], + ['latency-avg1000000', '1000k', 'absolute'] + ]} +} + +class Service(UrlService): + def __init__(self, configuration=None, name=None): + UrlService.__init__(self, configuration=configuration, name=name) + self.order = ORDER + self.definitions = CHARTS + + def _get_data(self): + data = self._get_raw_data() + if not data: + return None + + return loads(data) + diff --git a/python.d/dovecot.chart.py b/python.d/dovecot.chart.py index b2bef495..5689f2ec 100644 --- a/python.d/dovecot.chart.py +++ b/python.d/dovecot.chart.py @@ -2,7 +2,7 @@ # Description: dovecot netdata python.d module # Author: Pawel Krupa (paulfantom) -from base import SocketService +from bases.FrameworkServices.SocketService import SocketService # default module values (can be overridden per job in `config`) # update_every = 2 @@ -117,19 +117,10 @@ class Service(SocketService): data = raw.split('\n')[:2] desc = data[0].split('\t') vals = data[1].split('\t') - # ret = dict(zip(desc, vals)) - ret = {} - for i in range(len(desc)): + ret = dict() + for i, _ in enumerate(desc): try: - #d = str(desc[i]) - #if d in ('user_cpu', 'sys_cpu', 'clock_time'): - # val = float(vals[i]) - #else: - # val = int(vals[i]) - #ret[d] = val ret[str(desc[i])] = int(vals[i]) except ValueError: - pass - if len(ret) == 0: - return None - return ret + continue + return ret or None diff --git a/python.d/elasticsearch.chart.py b/python.d/elasticsearch.chart.py index 2e0f18c0..afdf0f1b 100644 --- a/python.d/elasticsearch.chart.py +++ b/python.d/elasticsearch.chart.py @@ -11,10 +11,9 @@ try: except ImportError: from Queue import Queue -from base import UrlService +from bases.FrameworkServices.UrlService import UrlService # default module values (can be overridden per job in `config`) -# update_every = 2 update_every = 5 priority = 60000 retries = 60 diff --git a/python.d/example.chart.py b/python.d/example.chart.py index adf97a92..ee7ff62f 100644 --- a/python.d/example.chart.py +++ b/python.d/example.chart.py @@ -2,35 +2,46 @@ # Description: example netdata python.d module # Author: Pawel Krupa (paulfantom) -import os -import random -from base import SimpleService +from random import SystemRandom -NAME = os.path.basename(__file__).replace(".chart.py", "") +from bases.FrameworkServices.SimpleService import SimpleService # default module values # update_every = 4 priority = 90000 retries = 60 +ORDER = ['random'] +CHARTS = { + 'random': { + 'options': [None, 'A random number', 'random number', 'random', 'random', 'line'], + 'lines': [ + ['random1'] + ] + } +} + class Service(SimpleService): def __init__(self, configuration=None, name=None): - super(self.__class__,self).__init__(configuration=configuration, name=name) + SimpleService.__init__(self, configuration=configuration, name=name) + self.order = ORDER + self.definitions = CHARTS + self.random = SystemRandom() - def check(self): - return True - - def create(self): - self.chart("example.python_random", '', 'A random number', 'random number', - 'random', 'random', 'line', self.priority, self.update_every) - self.dimension('random1') - self.commit() - return True - - def update(self, interval): - self.begin("example.python_random", interval) - self.set("random1", random.randint(0, 100)) - self.end() - self.commit() + @staticmethod + def check(): return True + + def get_data(self): + data = dict() + + for i in range(1, 4): + dimension_id = ''.join(['random', str(i)]) + + if dimension_id not in self.charts['random']: + self.charts['random'].add_dimension([dimension_id]) + + data[dimension_id] = self.random.randint(0, 100) + + return data diff --git a/python.d/exim.chart.py b/python.d/exim.chart.py index 1858cbc7..2e5b924b 100644 --- a/python.d/exim.chart.py +++ b/python.d/exim.chart.py @@ -2,7 +2,7 @@ # Description: exim netdata python.d module # Author: Pawel Krupa (paulfantom) -from base import ExecutableService +from bases.FrameworkServices.ExecutableService import ExecutableService # default module values (can be overridden per job in `config`) # update_every = 2 diff --git a/python.d/fail2ban.chart.py b/python.d/fail2ban.chart.py index 5238fa16..895833f8 100644 --- a/python.d/fail2ban.chart.py +++ b/python.d/fail2ban.chart.py @@ -2,12 +2,15 @@ # Description: fail2ban log netdata python.d module # Author: l2isbad +import bisect + +from glob import glob from re import compile as r_compile from os import access as is_accessible, R_OK from os.path import isdir, getsize -from glob import glob -import bisect -from base import LogService + + +from bases.FrameworkServices.LogService import LogService priority = 60000 retries = 60 @@ -180,8 +183,8 @@ def find_jails_in_files(list_of_files, print_error): jails_list = list() for conf in list_of_files: if is_accessible(conf, R_OK): - with open(conf, 'rt') as conf: - raw_data = conf.readlines() + with open(conf, 'rt') as f: + raw_data = f.readlines() data = ' '.join(line for line in raw_data if line.startswith(('[', 'enabled'))) jails_list.extend(REGEX_JAILS.findall(data)) else: diff --git a/python.d/freeradius.chart.py b/python.d/freeradius.chart.py index f3de1573..3acc58d1 100644 --- a/python.d/freeradius.chart.py +++ b/python.d/freeradius.chart.py @@ -2,15 +2,19 @@ # Description: freeradius netdata python.d module # Author: l2isbad -from base import SimpleService from re import findall from subprocess import Popen, PIPE +from bases.collection import find_binary +from bases.FrameworkServices.SimpleService import SimpleService + # default module values (can be overridden per job in `config`) priority = 60000 retries = 60 update_every = 15 +RADIUS_MSG = 'Message-Authenticator = 0x00, FreeRADIUS-Statistics-Type = 15, Response-Packet-Type = Access-Accept' + # charts order (can be overridden if you want less charts, or different order) ORDER = ['authentication', 'accounting', 'proxy-auth', 'proxy-acct'] @@ -18,34 +22,46 @@ CHARTS = { 'authentication': { 'options': [None, "Authentication", "packets/s", 'Authentication', 'freerad.auth', 'line'], 'lines': [ - ['access-accepts', None, 'incremental'], ['access-rejects', None, 'incremental'], - ['auth-dropped-requests', None, 'incremental'], ['auth-duplicate-requests', None, 'incremental'], - ['auth-invalid-requests', None, 'incremental'], ['auth-malformed-requests', None, 'incremental'], - ['auth-unknown-types', None, 'incremental'] - ]}, - 'accounting': { + ['access-accepts', None, 'incremental'], + ['access-rejects', None, 'incremental'], + ['auth-dropped-requests', 'dropped-requests', 'incremental'], + ['auth-duplicate-requests', 'duplicate-requests', 'incremental'], + ['auth-invalid-requests', 'invalid-requests', 'incremental'], + ['auth-malformed-requests', 'malformed-requests', 'incremental'], + ['auth-unknown-types', 'unknown-types', 'incremental'] + ]}, + 'accounting': { 'options': [None, "Accounting", "packets/s", 'Accounting', 'freerad.acct', 'line'], 'lines': [ - ['accounting-requests', None, 'incremental'], ['accounting-responses', None, 'incremental'], - ['acct-dropped-requests', None, 'incremental'], ['acct-duplicate-requests', None, 'incremental'], - ['acct-invalid-requests', None, 'incremental'], ['acct-malformed-requests', None, 'incremental'], - ['acct-unknown-types', None, 'incremental'] + ['accounting-requests', 'requests', 'incremental'], + ['accounting-responses', 'responses', 'incremental'], + ['acct-dropped-requests', 'dropped-requests', 'incremental'], + ['acct-duplicate-requests', 'duplicate-requests', 'incremental'], + ['acct-invalid-requests', 'invalid-requests', 'incremental'], + ['acct-malformed-requests', 'malformed-requests', 'incremental'], + ['acct-unknown-types', 'unknown-types', 'incremental'] ]}, 'proxy-auth': { 'options': [None, "Proxy Authentication", "packets/s", 'Authentication', 'freerad.proxy.auth', 'line'], 'lines': [ - ['proxy-access-accepts', None, 'incremental'], ['proxy-access-rejects', None, 'incremental'], - ['proxy-auth-dropped-requests', None, 'incremental'], ['proxy-auth-duplicate-requests', None, 'incremental'], - ['proxy-auth-invalid-requests', None, 'incremental'], ['proxy-auth-malformed-requests', None, 'incremental'], - ['proxy-auth-unknown-types', None, 'incremental'] + ['proxy-access-accepts', 'access-accepts', 'incremental'], + ['proxy-access-rejects', 'access-rejects', 'incremental'], + ['proxy-auth-dropped-requests', 'dropped-requests', 'incremental'], + ['proxy-auth-duplicate-requests', 'duplicate-requests', 'incremental'], + ['proxy-auth-invalid-requests', 'invalid-requests', 'incremental'], + ['proxy-auth-malformed-requests', 'malformed-requests', 'incremental'], + ['proxy-auth-unknown-types', 'unknown-types', 'incremental'] ]}, - 'proxy-acct': { + 'proxy-acct': { 'options': [None, "Proxy Accounting", "packets/s", 'Accounting', 'freerad.proxy.acct', 'line'], 'lines': [ - ['proxy-accounting-requests', None, 'incremental'], ['proxy-accounting-responses', None, 'incremental'], - ['proxy-acct-dropped-requests', None, 'incremental'], ['proxy-acct-duplicate-requests', None, 'incremental'], - ['proxy-acct-invalid-requests', None, 'incremental'], ['proxy-acct-malformed-requests', None, 'incremental'], - ['proxy-acct-unknown-types', None, 'incremental'] + ['proxy-accounting-requests', 'requests', 'incremental'], + ['proxy-accounting-responses', 'responses', 'incremental'], + ['proxy-acct-dropped-requests', 'dropped-requests', 'incremental'], + ['proxy-acct-duplicate-requests', 'duplicate-requests', 'incremental'], + ['proxy-acct-invalid-requests', 'invalid-requests', 'incremental'], + ['proxy-acct-malformed-requests', 'malformed-requests', 'incremental'], + ['proxy-acct-unknown-types', 'unknown-types', 'incremental'] ]} } @@ -54,31 +70,33 @@ CHARTS = { class Service(SimpleService): def __init__(self, configuration=None, name=None): SimpleService.__init__(self, configuration=configuration, name=name) + self.definitions = CHARTS self.host = self.configuration.get('host', 'localhost') self.port = self.configuration.get('port', '18121') - self.secret = self.configuration.get('secret', 'adminsecret') + self.secret = self.configuration.get('secret') self.acct = self.configuration.get('acct', False) self.proxy_auth = self.configuration.get('proxy_auth', False) self.proxy_acct = self.configuration.get('proxy_acct', False) - self.echo = self.find_binary('echo') - self.radclient = self.find_binary('radclient') - self.sub_echo = [self.echo, 'Message-Authenticator = 0x00, FreeRADIUS-Statistics-Type = 15, Response-Packet-Type = Access-Accept'] - self.sub_radclient = [self.radclient, '-r', '1', '-t', '1', ':'.join([self.host, self.port]), 'status', self.secret] - + chart_choice = [True, bool(self.acct), bool(self.proxy_auth), bool(self.proxy_acct)] + self.order = [chart for chart, choice in zip(ORDER, chart_choice) if choice] + self.echo = find_binary('echo') + self.radclient = find_binary('radclient') + self.sub_echo = [self.echo, RADIUS_MSG] + self.sub_radclient = [self.radclient, '-r', '1', '-t', '1', '-x', + ':'.join([self.host, self.port]), 'status', self.secret] + def check(self): if not all([self.echo, self.radclient]): - self.error('Can\'t locate \'radclient\' binary or binary is not executable by netdata') + self.error('Can\'t locate "radclient" binary or binary is not executable by netdata') return False + if not self.secret: + self.error('"secret" not set') + return None + if self._get_raw_data(): - chart_choice = [True, bool(self.acct), bool(self.proxy_auth), bool(self.proxy_acct)] - self.order = [chart for chart, choice in zip(ORDER, chart_choice) if choice] - self.definitions = dict([chart for chart in CHARTS.items() if chart[0] in self.order]) - self.info('Plugin was started succesfully') return True - else: - self.error('Request returned no data. Is server alive? Used options: host {0}, port {1}, secret {2}'.format(self.host, self.port, self.secret)) - return False - + self.error('Request returned no data. Is server alive?') + return False def _get_data(self): """ @@ -91,7 +109,8 @@ class Service(SimpleService): def _get_raw_data(self): """ The following code is equivalent to - 'echo "Message-Authenticator = 0x00, FreeRADIUS-Statistics-Type = 15, Response-Packet-Type = Access-Accept" | radclient -t 1 -r 1 host:port status secret' + 'echo "Message-Authenticator = 0x00, FreeRADIUS-Statistics-Type = 15, Response-Packet-Type = Access-Accept" + | radclient -t 1 -r 1 host:port status secret' :return: str """ try: @@ -99,10 +118,8 @@ class Service(SimpleService): process_rad = Popen(self.sub_radclient, stdin=process_echo.stdout, stdout=PIPE, stderr=PIPE, shell=False) process_echo.stdout.close() raw_result = process_rad.communicate()[0] - except Exception: + except OSError: return None - else: - if process_rad.returncode is 0: - return raw_result.decode() - else: - return None + if process_rad.returncode is 0: + return raw_result.decode() + return None diff --git a/python.d/go_expvar.chart.py b/python.d/go_expvar.chart.py index e1a334cc..cbd46257 100644 --- a/python.d/go_expvar.chart.py +++ b/python.d/go_expvar.chart.py @@ -3,9 +3,10 @@ # Author: Jan Kral (kralewitz) from __future__ import division -from base import UrlService import json +from bases.FrameworkServices.UrlService import UrlService + # default module values (can be overridden per job in `config`) # update_every = 2 priority = 60000 @@ -14,44 +15,52 @@ retries = 60 MEMSTATS_CHARTS = { 'memstats_heap': { - 'options': ['heap', 'memory: size of heap memory structures', 'kB', 'memstats', 'expvar.memstats.heap', 'line'], + 'options': ['heap', 'memory: size of heap memory structures', 'kB', 'memstats', + 'expvar.memstats.heap', 'line'], 'lines': [ ['memstats_heap_alloc', 'alloc', 'absolute', 1, 1024], ['memstats_heap_inuse', 'inuse', 'absolute', 1, 1024] ]}, 'memstats_stack': { - 'options': ['stack', 'memory: size of stack memory structures', 'kB', 'memstats', 'expvar.memstats.stack', 'line'], + 'options': ['stack', 'memory: size of stack memory structures', 'kB', 'memstats', + 'expvar.memstats.stack', 'line'], 'lines': [ ['memstats_stack_inuse', 'inuse', 'absolute', 1, 1024] ]}, 'memstats_mspan': { - 'options': ['mspan', 'memory: size of mspan memory structures', 'kB', 'memstats', 'expvar.memstats.mspan', 'line'], + 'options': ['mspan', 'memory: size of mspan memory structures', 'kB', 'memstats', + 'expvar.memstats.mspan', 'line'], 'lines': [ ['memstats_mspan_inuse', 'inuse', 'absolute', 1, 1024] ]}, 'memstats_mcache': { - 'options': ['mcache', 'memory: size of mcache memory structures', 'kB', 'memstats', 'expvar.memstats.mcache', 'line'], + 'options': ['mcache', 'memory: size of mcache memory structures', 'kB', 'memstats', + 'expvar.memstats.mcache', 'line'], 'lines': [ ['memstats_mcache_inuse', 'inuse', 'absolute', 1, 1024] ]}, 'memstats_live_objects': { - 'options': ['live_objects', 'memory: number of live objects', 'objects', 'memstats', 'expvar.memstats.live_objects', 'line'], + 'options': ['live_objects', 'memory: number of live objects', 'objects', 'memstats', + 'expvar.memstats.live_objects', 'line'], 'lines': [ ['memstats_live_objects', 'live'] ]}, 'memstats_sys': { - 'options': ['sys', 'memory: size of reserved virtual address space', 'kB', 'memstats', 'expvar.memstats.sys', 'line'], + 'options': ['sys', 'memory: size of reserved virtual address space', 'kB', 'memstats', + 'expvar.memstats.sys', 'line'], 'lines': [ ['memstats_sys', 'sys', 'absolute', 1, 1024] ]}, 'memstats_gc_pauses': { - 'options': ['gc_pauses', 'memory: average duration of GC pauses', 'ns', 'memstats', 'expvar.memstats.gc_pauses', 'line'], + 'options': ['gc_pauses', 'memory: average duration of GC pauses', 'ns', 'memstats', + 'expvar.memstats.gc_pauses', 'line'], 'lines': [ ['memstats_gc_pauses', 'avg'] ]}, } -MEMSTATS_ORDER = ['memstats_heap', 'memstats_stack', 'memstats_mspan', 'memstats_mcache', 'memstats_sys', 'memstats_live_objects', 'memstats_gc_pauses'] +MEMSTATS_ORDER = ['memstats_heap', 'memstats_stack', 'memstats_mspan', 'memstats_mcache', + 'memstats_sys', 'memstats_live_objects', 'memstats_gc_pauses'] def flatten(d, top='', sep='.'): @@ -71,8 +80,8 @@ class Service(UrlService): # if memstats collection is enabled, add the charts and their order if self.configuration.get('collect_memstats'): - self.definitions = MEMSTATS_CHARTS - self.order = MEMSTATS_ORDER + self.definitions = dict(MEMSTATS_CHARTS) + self.order = list(MEMSTATS_ORDER) else: self.definitions = dict() self.order = list() diff --git a/python.d/haproxy.chart.py b/python.d/haproxy.chart.py index a9ee6665..e72698d1 100644 --- a/python.d/haproxy.chart.py +++ b/python.d/haproxy.chart.py @@ -10,7 +10,9 @@ try: except ImportError: from urllib.parse import urlparse -from base import UrlService, SocketService +from bases.FrameworkServices.SocketService import SocketService +from bases.FrameworkServices.UrlService import UrlService + # default module values (can be overridden per job in `config`) # update_every = 2 diff --git a/python.d/hddtemp.chart.py b/python.d/hddtemp.chart.py index 8a98995b..577cab09 100644 --- a/python.d/hddtemp.chart.py +++ b/python.d/hddtemp.chart.py @@ -1,10 +1,12 @@ # -*- coding: utf-8 -*- # Description: hddtemp netdata python.d module # Author: Pawel Krupa (paulfantom) -# Modified by l2isbad + import os -from base import SocketService +from copy import deepcopy + +from bases.FrameworkServices.SocketService import SocketService # default module values (can be overridden per job in `config`) #update_every = 2 @@ -22,34 +24,39 @@ retries = 60 ORDER = ['temperatures'] +CHARTS = { + 'temperatures': { + 'options': ['disks_temp', 'Disks Temperatures', 'Celsius', 'temperatures', 'hddtemp.temperatures', 'line'], + 'lines': [ + # lines are created dynamically in `check()` method + ]}} + + class Service(SocketService): def __init__(self, configuration=None, name=None): SocketService.__init__(self, configuration=configuration, name=name) + self.order = ORDER + self.definitions = deepcopy(CHARTS) self._keep_alive = False self.request = "" self.host = "127.0.0.1" self.port = 7634 - self.order = ORDER - self.fahrenheit = ('Fahrenheit', lambda x: x * 9 / 5 + 32) if self.configuration.get('fahrenheit') else False - self.whatever = ('Whatever', lambda x: x * 33 / 22 + 11) if self.configuration.get('whatever') else False - self.choice = (choice for choice in [self.fahrenheit, self.whatever] if choice) - self.calc = lambda x: x - self.disks = [] + self.disks = list() - def _get_disks(self): + def get_disks(self): try: disks = self.configuration['devices'] - self.info("Using configured disks" + str(disks)) - except (KeyError, TypeError) as e: + self.info("Using configured disks {0}".format(disks)) + except (KeyError, TypeError): self.info("Autodetecting disks") return ["/dev/" + f for f in os.listdir("/dev") if len(f) == 3 and f.startswith("sd")] - ret = [] + ret = list() for disk in disks: if not disk.startswith('/dev/'): disk = "/dev/" + disk ret.append(disk) - if len(ret) == 0: + if not ret: self.error("Provided disks cannot be found in /dev directory.") return ret @@ -59,10 +66,9 @@ class Service(SocketService): if all(disk in data for disk in self.disks): return True - return False - def _get_data(self): + def get_data(self): """ Get data from TCP/IP socket :return: dict @@ -72,21 +78,20 @@ class Service(SocketService): except AttributeError: self.error("no data received") return None - data = {} + data = dict() for i in range(len(raw) // 5): if not raw[i*5+1] in self.disks: continue try: - val = self.calc(int(raw[i*5+3])) + val = int(raw[i*5+3]) except ValueError: val = 0 data[raw[i*5+1].replace("/dev/", "")] = val - if len(data) == 0: + if not data: self.error("received data doesn't have needed records") return None - else: - return data + return data def check(self): """ @@ -94,27 +99,12 @@ class Service(SocketService): :return: boolean """ self._parse_config() - self.disks = self._get_disks() + self.disks = self.get_disks() - data = self._get_data() + data = self.get_data() if data is None: return False - self.definitions = { - 'temperatures': { - 'options': ['disks_temp', 'Disks Temperatures', 'temperatures', 'hddtemp.temperatures', 'line'], - 'lines': [ - # lines are created dynamically in `check()` method - ]} - } - try: - self.choice = next(self.choice) - except StopIteration: - self.definitions[ORDER[0]]['options'].insert(2, 'Celsius') - else: - self.calc = self.choice[1] - self.definitions[ORDER[0]]['options'].insert(2, self.choice[0]) - for name in data: - self.definitions[ORDER[0]]['lines'].append([name]) + self.definitions['temperatures']['lines'].append([name]) return True diff --git a/python.d/ipfs.chart.py b/python.d/ipfs.chart.py index eaea3c5e..43500dfb 100644 --- a/python.d/ipfs.chart.py +++ b/python.d/ipfs.chart.py @@ -2,9 +2,10 @@ # Description: IPFS netdata python.d module # Authors: Pawel Krupa (paulfantom), davidak -from base import UrlService import json +from bases.FrameworkServices.UrlService import UrlService + # default module values (can be overridden per job in `config`) # update_every = 2 priority = 60000 @@ -49,75 +50,75 @@ CHARTS = { } SI_zeroes = {'k': 3, 'm': 6, 'g': 9, 't': 12, - 'p': 15, 'e': 18, 'z': 21, 'y': 24 } + 'p': 15, 'e': 18, 'z': 21, 'y': 24} class Service(UrlService): def __init__(self, configuration=None, name=None): UrlService.__init__(self, configuration=configuration, name=name) - try: - self.baseurl = str(self.configuration['url']) - except (KeyError, TypeError): - self.baseurl = "http://localhost:5001" + self.baseurl = self.configuration.get('url', 'http://localhost:5001') self.order = ORDER self.definitions = CHARTS - self.__storagemax = None + self.__storage_max = None - def _get_json(self, suburl): + def _get_json(self, sub_url): """ :return: json decoding of the specified url """ - self.url = self.baseurl + suburl + self.url = self.baseurl + sub_url try: return json.loads(self._get_raw_data()) - except: - return {} + except (TypeError, ValueError): + return dict() - def _recursive_pins(self, keys): + @staticmethod + def _recursive_pins(keys): return len([k for k in keys if keys[k]["Type"] == b"recursive"]) - def _dehumanize(self, storemax): + @staticmethod + def _dehumanize(store_max): # convert from '10Gb' to 10000000000 - if type(storemax) != int: - storemax = storemax.lower() - if storemax.endswith('b'): - val, units = storemax[:-2], storemax[-2] + if not isinstance(store_max, int): + store_max = store_max.lower() + if store_max.endswith('b'): + val, units = store_max[:-2], store_max[-2] if units in SI_zeroes: val += '0'*SI_zeroes[units] - storemax = val + store_max = val try: - storemax = int(storemax) - except: - storemax = None - return storemax + store_max = int(store_max) + except (TypeError, ValueError): + store_max = None + return store_max - def _storagemax(self, storecfg): - if self.__storagemax is None: - self.__storagemax = self._dehumanize(storecfg['StorageMax']) - return self.__storagemax + def _storagemax(self, store_cfg): + if self.__storage_max is None: + self.__storage_max = self._dehumanize(store_cfg['StorageMax']) + return self.__storage_max def _get_data(self): """ Get data from API :return: dict """ - cfg = { # suburl : List of (result-key, original-key, transform-func) - '/api/v0/stats/bw' :[('in', 'RateIn', int ), - ('out', 'RateOut', int )], - '/api/v0/swarm/peers':[('peers', 'Strings', len )], - '/api/v0/stats/repo' :[('size', 'RepoSize', int), - ('objects', 'NumObjects', int)], - '/api/v0/pin/ls': [('pinned', 'Keys', len), - ('recursive_pins', 'Keys', self._recursive_pins)], - '/api/v0/config/show': [('avail', 'Datastore', self._storagemax)] + # suburl : List of (result-key, original-key, transform-func) + cfg = { + '/api/v0/stats/bw': + [('in', 'RateIn', int), ('out', 'RateOut', int)], + '/api/v0/swarm/peers': + [('peers', 'Strings', len)], + '/api/v0/stats/repo': + [('size', 'RepoSize', int), ('objects', 'NumObjects', int)], + '/api/v0/pin/ls': + [('pinned', 'Keys', len), ('recursive_pins', 'Keys', self._recursive_pins)], + '/api/v0/config/show': [('avail', 'Datastore', self._storagemax)] } - r = {} + r = dict() for suburl in cfg: - json = self._get_json(suburl) - for newkey, origkey, xmute in cfg[suburl]: + in_json = self._get_json(suburl) + for new_key, orig_key, xmute in cfg[suburl]: try: - r[newkey] = xmute(json[origkey]) - except: pass + r[new_key] = xmute(in_json[orig_key]) + except Exception: + continue return r or None - - diff --git a/python.d/isc_dhcpd.chart.py b/python.d/isc_dhcpd.chart.py index a437f803..60995342 100644 --- a/python.d/isc_dhcpd.chart.py +++ b/python.d/isc_dhcpd.chart.py @@ -7,14 +7,15 @@ from os import stat, access, R_OK from os.path import isfile try: from ipaddress import ip_network, ip_address - have_ipaddress = True + HAVE_IPADDRESS = True except ImportError: - have_ipaddress = False + HAVE_IPADDRESS = False try: from itertools import filterfalse except ImportError: from itertools import ifilterfalse as filterfalse -from base import SimpleService + +from bases.FrameworkServices.SimpleService import SimpleService priority = 60000 retries = 60 @@ -55,11 +56,10 @@ class Service(SimpleService): # Will work only with 'default' db-time-format (weekday year/month/day hour:minute:second) # TODO: update algorithm to parse correctly 'local' db-time-format - # (epoch <seconds-since-epoch>; # <day-name> <month-name> <day-number> <hours>:<minutes>:<seconds> <year>) # Also only ipv4 supported def check(self): - if not have_ipaddress: + if not HAVE_IPADDRESS: self.error('\'python-ipaddress\' module is needed') return False if not (isfile(self.leases_path) and access(self.leases_path, R_OK)): @@ -146,7 +146,16 @@ class Service(SimpleService): def binding_active(lease_end_time, current_time): - return mktime(strptime(lease_end_time, '%w %Y/%m/%d %H:%M:%S')) - current_time > 0 + # lease_end_time might be epoch + if lease_end_time.startswith('epoch'): + epoch = int(lease_end_time.split()[1].replace(';','')) + return epoch - current_time > 0 + # max. int for lease-time causes lease to expire in year 2038. + # dhcpd puts 'never' in the ends section of active lease + elif lease_end_time == 'never': + return True + else: + return mktime(strptime(lease_end_time, '%w %Y/%m/%d %H:%M:%S')) - current_time > 0 def find_lease(value): @@ -155,4 +164,3 @@ def find_lease(value): def find_ends(value): return value[2:6] != 'ends' - diff --git a/python.d/mdstat.chart.py b/python.d/mdstat.chart.py index 7ce7b193..794d2564 100644 --- a/python.d/mdstat.chart.py +++ b/python.d/mdstat.chart.py @@ -2,9 +2,10 @@ # Description: mdstat netdata python.d module # Author: l2isbad -from re import compile as re_compile from collections import defaultdict -from base import SimpleService +from re import compile as re_compile + +from bases.FrameworkServices.SimpleService import SimpleService priority = 60000 retries = 60 @@ -18,7 +19,7 @@ class Service(SimpleService): SimpleService.__init__(self, configuration=configuration, name=name) self.regex = dict(disks=re_compile(r' (?P<array>[a-zA-Z_0-9]+) : active .+\[' r'(?P<total_disks>[0-9]+)/' - r'(?P<inuse_disks>[0-9])\]'), + r'(?P<inuse_disks>[0-9]+)\]'), status=re_compile(r' (?P<array>[a-zA-Z_0-9]+) : active .+ ' r'(?P<operation>[a-z]+) =[ ]{1,2}' r'(?P<operation_status>[0-9.]+).+finish=' diff --git a/python.d/memcached.chart.py b/python.d/memcached.chart.py index 0d6807ba..4f7adfa2 100644 --- a/python.d/memcached.chart.py +++ b/python.d/memcached.chart.py @@ -2,7 +2,7 @@ # Description: memcached netdata python.d module # Author: Pawel Krupa (paulfantom) -from base import SocketService +from bases.FrameworkServices.SocketService import SocketService # default module values (can be overridden per job in `config`) #update_every = 2 @@ -149,9 +149,8 @@ class Service(SocketService): data[t[0]] = t[1] except (IndexError, ValueError): self.debug("invalid line received: " + str(line)) - pass - if len(data) == 0: + if not data: self.error("received data doesn't have any records") return None @@ -159,7 +158,7 @@ class Service(SocketService): try: data['avail'] = int(data['limit_maxbytes']) - int(data['bytes']) data['used'] = int(data['bytes']) - except: + except (KeyError, ValueError, TypeError): pass return data @@ -178,11 +177,7 @@ class Service(SocketService): :return: boolean """ self._parse_config() - if self.name == "": - self.name = "local" - self.chart_name += "_" + self.name data = self._get_data() if data is None: return False - return True diff --git a/python.d/mongodb.chart.py b/python.d/mongodb.chart.py index bb4c44b0..909a419d 100644 --- a/python.d/mongodb.chart.py +++ b/python.d/mongodb.chart.py @@ -2,7 +2,6 @@ # Description: mongodb netdata python.d module # Author: l2isbad -from base import SimpleService from copy import deepcopy from datetime import datetime from sys import exc_info @@ -14,6 +13,8 @@ try: except ImportError: PYMONGO = False +from bases.FrameworkServices.SimpleService import SimpleService + # default module values (can be overridden per job in `config`) # update_every = 2 priority = 60000 @@ -36,6 +37,7 @@ REPL_SET_STATES = [ def multiply_by_100(value): return value * 100 + DEFAULT_METRICS = [ ('opcounters.delete', None, None), ('opcounters.update', None, None), diff --git a/python.d/mysql.chart.py b/python.d/mysql.chart.py index 6118f79f..4c7058b2 100644 --- a/python.d/mysql.chart.py +++ b/python.d/mysql.chart.py @@ -2,11 +2,11 @@ # Description: MySQL netdata python.d module # Author: Pawel Krupa (paulfantom) -from base import MySQLService +from bases.FrameworkServices.MySQLService import MySQLService # default module values (can be overridden per job in `config`) # update_every = 3 -priority = 90000 +priority = 60000 retries = 60 # query executed on MySQL server @@ -114,7 +114,16 @@ GLOBAL_STATS = [ 'Connection_errors_max_connections', 'Connection_errors_peer_address', 'Connection_errors_select', - 'Connection_errors_tcpwrap'] + 'Connection_errors_tcpwrap', + 'wsrep_local_recv_queue', + 'wsrep_local_send_queue', + 'wsrep_received', + 'wsrep_replicated', + 'wsrep_received_bytes', + 'wsrep_replicated_bytes', + 'wsrep_local_bf_aborts', + 'wsrep_local_cert_failures', + 'wsrep_flow_control_paused_ns'] def slave_seconds(value): try: @@ -122,6 +131,7 @@ def slave_seconds(value): except (TypeError, ValueError): return -1 + def slave_running(value): return 1 if value == 'Yes' else -1 @@ -146,7 +156,8 @@ ORDER = ['net', 'innodb_buffer_pool_read_ahead', 'innodb_buffer_pool_reqs', 'innodb_buffer_pool_ops', 'qcache_ops', 'qcache', 'qcache_freemem', 'qcache_memblocks', 'key_blocks', 'key_requests', 'key_disk_ops', - 'files', 'files_rate', 'slave_behind', 'slave_status'] + 'files', 'files_rate', 'slave_behind', 'slave_status', + 'galera_writesets', 'galera_bytes', 'galera_queue', 'galera_conflicts', 'galera_flow_control'] CHARTS = { 'net': { @@ -248,7 +259,8 @@ CHARTS = { ['Innodb_data_fsyncs', 'fsyncs', 'incremental'] ]}, 'innodb_io_pending_ops': { - 'options': [None, 'mysql InnoDB Pending I/O Operations', 'operations', 'innodb', 'mysql.innodb_io_pending_ops', 'line'], + 'options': [None, 'mysql InnoDB Pending I/O Operations', 'operations', 'innodb', + 'mysql.innodb_io_pending_ops', 'line'], 'lines': [ ['Innodb_data_pending_reads', 'reads', 'absolute'], ['Innodb_data_pending_writes', 'writes', 'absolute', -1, 1], @@ -274,7 +286,8 @@ CHARTS = { ['Innodb_os_log_written', 'write', 'incremental', -1, 1024], ]}, 'innodb_cur_row_lock': { - 'options': [None, 'mysql InnoDB Current Row Locks', 'operations', 'innodb', 'mysql.innodb_cur_row_lock', 'area'], + 'options': [None, 'mysql InnoDB Current Row Locks', 'operations', 'innodb', + 'mysql.innodb_cur_row_lock', 'area'], 'lines': [ ['Innodb_row_lock_current_waits', 'current_waits', 'absolute'] ]}, @@ -287,7 +300,8 @@ CHARTS = { ['Innodb_rows_deleted', 'deleted', 'incremental', -1, 1], ]}, 'innodb_buffer_pool_pages': { - 'options': [None, 'mysql InnoDB Buffer Pool Pages', 'pages', 'innodb', 'mysql.innodb_buffer_pool_pages', 'line'], + 'options': [None, 'mysql InnoDB Buffer Pool Pages', 'pages', 'innodb', + 'mysql.innodb_buffer_pool_pages', 'line'], 'lines': [ ['Innodb_buffer_pool_pages_data', 'data', 'absolute'], ['Innodb_buffer_pool_pages_dirty', 'dirty', 'absolute', -1, 1], @@ -303,20 +317,23 @@ CHARTS = { ['Innodb_buffer_pool_bytes_dirty', 'dirty', 'absolute', -1, 1024 * 1024] ]}, 'innodb_buffer_pool_read_ahead': { - 'options': [None, 'mysql InnoDB Buffer Pool Read Ahead', 'operations/s', 'innodb', 'mysql.innodb_buffer_pool_read_ahead', 'area'], + 'options': [None, 'mysql InnoDB Buffer Pool Read Ahead', 'operations/s', 'innodb', + 'mysql.innodb_buffer_pool_read_ahead', 'area'], 'lines': [ ['Innodb_buffer_pool_read_ahead', 'all', 'incremental'], ['Innodb_buffer_pool_read_ahead_evicted', 'evicted', 'incremental', -1, 1], ['Innodb_buffer_pool_read_ahead_rnd', 'random', 'incremental'] ]}, 'innodb_buffer_pool_reqs': { - 'options': [None, 'mysql InnoDB Buffer Pool Requests', 'requests/s', 'innodb', 'mysql.innodb_buffer_pool_reqs', 'area'], + 'options': [None, 'mysql InnoDB Buffer Pool Requests', 'requests/s', 'innodb', + 'mysql.innodb_buffer_pool_reqs', 'area'], 'lines': [ ['Innodb_buffer_pool_read_requests', 'reads', 'incremental'], ['Innodb_buffer_pool_write_requests', 'writes', 'incremental', -1, 1] ]}, 'innodb_buffer_pool_ops': { - 'options': [None, 'mysql InnoDB Buffer Pool Operations', 'operations/s', 'innodb', 'mysql.innodb_buffer_pool_ops', 'area'], + 'options': [None, 'mysql InnoDB Buffer Pool Operations', 'operations/s', 'innodb', + 'mysql.innodb_buffer_pool_ops', 'area'], 'lines': [ ['Innodb_buffer_pool_reads', 'disk reads', 'incremental'], ['Innodb_buffer_pool_wait_free', 'wait free', 'incremental', -1, 1] @@ -359,7 +376,8 @@ CHARTS = { ['Key_write_requests', 'writes', 'incremental', -1, 1] ]}, 'key_disk_ops': { - 'options': [None, 'mysql MyISAM Key Cache Disk Operations', 'operations/s', 'myisam', 'mysql.key_disk_ops', 'area'], + 'options': [None, 'mysql MyISAM Key Cache Disk Operations', 'operations/s', + 'myisam', 'mysql.key_disk_ops', 'area'], 'lines': [ ['Key_reads', 'reads', 'incremental'], ['Key_writes', 'writes', 'incremental', -1, 1] @@ -375,13 +393,15 @@ CHARTS = { ['Opened_files', 'files', 'incremental'] ]}, 'binlog_stmt_cache': { - 'options': [None, 'mysql Binlog Statement Cache', 'statements/s', 'binlog', 'mysql.binlog_stmt_cache', 'line'], + 'options': [None, 'mysql Binlog Statement Cache', 'statements/s', 'binlog', + 'mysql.binlog_stmt_cache', 'line'], 'lines': [ ['Binlog_stmt_cache_disk_use', 'disk', 'incremental'], ['Binlog_stmt_cache_use', 'all', 'incremental'] ]}, 'connection_errors': { - 'options': [None, 'mysql Connection Errors', 'connections/s', 'connections', 'mysql.connection_errors', 'line'], + 'options': [None, 'mysql Connection Errors', 'connections/s', 'connections', + 'mysql.connection_errors', 'line'], 'lines': [ ['Connection_errors_accept', 'accept', 'incremental'], ['Connection_errors_internal', 'internal', 'incremental'], @@ -400,6 +420,35 @@ CHARTS = { 'lines': [ ['Slave_SQL_Running', 'sql_running', 'absolute'], ['Slave_IO_Running', 'io_running', 'absolute'] + ]}, + 'galera_writesets': { + 'options': [None, 'Replicated writesets', 'writesets/s', 'galera', 'mysql.galera_writesets', 'line'], + 'lines': [ + ['wsrep_received', 'rx', 'incremental'], + ['wsrep_replicated', 'tx', 'incremental', -1, 1], + ]}, + 'galera_bytes': { + 'options': [None, 'Replicated bytes', 'KB/s', 'galera', 'mysql.galera_bytes', 'area'], + 'lines': [ + ['wsrep_received_bytes', 'rx', 'incremental', 1, 1024], + ['wsrep_replicated_bytes', 'tx', 'incremental', -1, 1024], + ]}, + 'galera_queue': { + 'options': [None, 'Galera queue', 'writesets', 'galera', 'mysql.galera_queue', 'line'], + 'lines': [ + ['wsrep_local_recv_queue', 'rx', 'absolute'], + ['wsrep_local_send_queue', 'tx', 'absolute', -1, 1], + ]}, + 'galera_conflicts': { + 'options': [None, 'Replication conflicts', 'transactions', 'galera', 'mysql.galera_conflicts', 'area'], + 'lines': [ + ['wsrep_local_bf_aborts', 'bf_aborts', 'incremental'], + ['wsrep_local_cert_failures', 'cert_fails', 'incremental', -1, 1], + ]}, + 'galera_flow_control': { + 'options': [None, 'Flow control', 'millisec', 'galera', 'mysql.galera_flow_control', 'area'], + 'lines': [ + ['wsrep_flow_control_paused_ns', 'paused', 'incremental', 1, 1000000], ]} } @@ -416,7 +465,7 @@ class Service(MySQLService): raw_data = self._get_raw_data(description=True) if not raw_data: - return None + return None to_netdata = dict() @@ -426,14 +475,15 @@ class Service(MySQLService): if key in global_status: to_netdata[key] = global_status[key] if 'Threads_created' in to_netdata and 'Connections' in to_netdata: - to_netdata['Thread_cache_misses'] = round(int(to_netdata['Threads_created']) / float(to_netdata['Connections']) * 10000) + to_netdata['Thread_cache_misses'] = round(int(to_netdata['Threads_created']) + / float(to_netdata['Connections']) * 10000) if 'slave_status' in raw_data: if raw_data['slave_status'][0]: slave_raw_data = dict(zip([e[0] for e in raw_data['slave_status'][1]], raw_data['slave_status'][0][0])) - for key, function in SLAVE_STATS: + for key, func in SLAVE_STATS: if key in slave_raw_data: - to_netdata[key] = function(slave_raw_data[key]) + to_netdata[key] = func(slave_raw_data[key]) else: self.queries.pop('slave_status') diff --git a/python.d/nginx.chart.py b/python.d/nginx.chart.py index 88849a92..2e4f0d1b 100644 --- a/python.d/nginx.chart.py +++ b/python.d/nginx.chart.py @@ -2,7 +2,7 @@ # Description: nginx netdata python.d module # Author: Pawel Krupa (paulfantom) -from base import UrlService +from bases.FrameworkServices.UrlService import UrlService # default module values (can be overridden per job in `config`) # update_every = 2 @@ -22,7 +22,8 @@ ORDER = ['connections', 'requests', 'connection_status', 'connect_rate'] CHARTS = { 'connections': { - 'options': [None, 'nginx Active Connections', 'connections', 'active connections', 'nginx.connections', 'line'], + 'options': [None, 'nginx Active Connections', 'connections', 'active connections', + 'nginx.connections', 'line'], 'lines': [ ["active"] ]}, @@ -32,14 +33,16 @@ CHARTS = { ["requests", None, 'incremental'] ]}, 'connection_status': { - 'options': [None, 'nginx Active Connections by Status', 'connections', 'status', 'nginx.connection_status', 'line'], + 'options': [None, 'nginx Active Connections by Status', 'connections', 'status', + 'nginx.connection_status', 'line'], 'lines': [ ["reading"], ["writing"], ["waiting", "idle"] ]}, 'connect_rate': { - 'options': [None, 'nginx Connections Rate', 'connections/s', 'connections rate', 'nginx.connect_rate', 'line'], + 'options': [None, 'nginx Connections Rate', 'connections/s', 'connections rate', + 'nginx.connect_rate', 'line'], 'lines': [ ["accepts", "accepted", "incremental"], ["handled", None, "incremental"] @@ -50,8 +53,7 @@ CHARTS = { class Service(UrlService): def __init__(self, configuration=None, name=None): UrlService.__init__(self, configuration=configuration, name=name) - if len(self.url) == 0: - self.url = "http://localhost/stub_status" + self.url = self.configuration.get('url', 'http://localhost/stub_status') self.order = ORDER self.definitions = CHARTS diff --git a/python.d/nsd.chart.py b/python.d/nsd.chart.py index 68bb4f23..499dfda2 100644 --- a/python.d/nsd.chart.py +++ b/python.d/nsd.chart.py @@ -2,10 +2,10 @@ # Description: NSD `nsd-control stats_noreset` netdata python.d module # Author: <383c57 at gmail.com> - -from base import ExecutableService import re +from bases.FrameworkServices.ExecutableService import ExecutableService + # default module values (can be overridden per job in `config`) priority = 60000 retries = 5 diff --git a/python.d/ovpn_status_log.chart.py b/python.d/ovpn_status_log.chart.py index 3a7e8200..519c77fa 100644 --- a/python.d/ovpn_status_log.chart.py +++ b/python.d/ovpn_status_log.chart.py @@ -3,8 +3,8 @@ # Author: l2isbad from re import compile as r_compile -from collections import defaultdict -from base import SimpleService + +from bases.FrameworkServices.SimpleService import SimpleService priority = 60000 retries = 60 @@ -34,24 +34,30 @@ class Service(SimpleService): self.log_path = self.configuration.get('log_path') self.regex = dict(tls=r_compile(r'\d{1,3}(?:\.\d{1,3}){3}(?::\d+)? (?P<bytes_in>\d+) (?P<bytes_out>\d+)'), static_key=r_compile(r'TCP/[A-Z]+ (?P<direction>(?:read|write)) bytes,(?P<bytes>\d+)')) - self.to_netdata = dict(bytes_in=0, bytes_out=0) def check(self): if not (self.log_path and isinstance(self.log_path, str)): - self.error('\'log_path\' is not defined') + self.error("'log_path' is not defined") return False - data = False - for method in (self._get_data_tls, self._get_data_static_key): - data = method() - if data: - self._get_data = method - self._data_from_check = data - break + data = self._get_raw_data() + if not data: + self.error('Make sure that the openvpn status log file exists and netdata has permission to read it') + return None - if data: + found = None + for row in data: + if 'ROUTING' in row: + self.get_data = self.get_data_tls + found = True + break + elif 'STATISTICS' in row: + self.get_data = self.get_data_static_key + found = True + break + if found: return True - self.error('Make sure that the openvpn status log file exists and netdata has permission to read it') + self.error("Failed to parse ovpenvpn log file") return False def _get_raw_data(self): @@ -68,7 +74,7 @@ class Service(SimpleService): else: return raw_data - def _get_data_static_key(self): + def get_data_static_key(self): """ Parse openvpn-status log file. """ @@ -77,7 +83,7 @@ class Service(SimpleService): if not raw_data: return None - data = defaultdict(lambda: 0) + data = dict(bytes_in=0, bytes_out=0) for row in raw_data: match = self.regex['static_key'].search(row) @@ -90,7 +96,7 @@ class Service(SimpleService): return data or None - def _get_data_tls(self): + def get_data_tls(self): """ Parse openvpn-status log file. """ @@ -99,7 +105,7 @@ class Service(SimpleService): if not raw_data: return None - data = defaultdict(lambda: 0) + data = dict(users=0, bytes_in=0, bytes_out=0) for row in raw_data: row = ' '.join(row.split(',')) if ',' in row else ' '.join(row.split()) match = self.regex['tls'].search(row) @@ -110,4 +116,3 @@ class Service(SimpleService): data['bytes_out'] += int(match['bytes_out']) return data or None - diff --git a/python.d/phpfpm.chart.py b/python.d/phpfpm.chart.py index 7a983521..ea7a9a7e 100644 --- a/python.d/phpfpm.chart.py +++ b/python.d/phpfpm.chart.py @@ -2,10 +2,11 @@ # Description: PHP-FPM netdata python.d module # Author: Pawel Krupa (paulfantom) -from base import UrlService import json import re +from bases.FrameworkServices.UrlService import UrlService + # default module values (can be overridden per job in `config`) # update_every = 2 priority = 60000 @@ -40,6 +41,7 @@ PER_PROCESS_INFO = [ def average(collection): return sum(collection, 0.0) / max(len(collection), 1) + CALC = [ ('min', min), ('max', max), @@ -130,8 +132,8 @@ class Service(UrlService): if p_info: for new_name in PER_PROCESS_INFO: - for name, function in CALC: - to_netdata[name + new_name[1]] = function([p_info[k] for k in p_info if new_name[1] in k]) + for name, func in CALC: + to_netdata[name + new_name[1]] = func([p_info[k] for k in p_info if new_name[1] in k]) return to_netdata or None @@ -165,4 +167,3 @@ def parse_raw_data_(is_json, regex, raw_data): else: raw_data = ' '.join(raw_data.split()) return dict(regex.findall(raw_data)) - diff --git a/python.d/postfix.chart.py b/python.d/postfix.chart.py index ee4142aa..a2129e4b 100644 --- a/python.d/postfix.chart.py +++ b/python.d/postfix.chart.py @@ -2,7 +2,7 @@ # Description: postfix netdata python.d module # Author: Pawel Krupa (paulfantom) -from base import ExecutableService +from bases.FrameworkServices.ExecutableService import ExecutableService # default module values (can be overridden per job in `config`) # update_every = 2 diff --git a/python.d/postgres.chart.py b/python.d/postgres.chart.py index b17565e9..ef69a9c7 100644 --- a/python.d/postgres.chart.py +++ b/python.d/postgres.chart.py @@ -13,11 +13,11 @@ try: except ImportError: PSYCOPG2 = False -from base import SimpleService +from bases.FrameworkServices.SimpleService import SimpleService # default module values update_every = 1 -priority = 90000 +priority = 60000 retries = 60 METRICS = dict( @@ -62,7 +62,7 @@ SELECT CAST(COALESCE(SUM(CAST(archive_file ~ $r$\.ready$$r$ as INT)), 0) AS INT) AS ready_count, CAST(COALESCE(SUM(CAST(archive_file ~ $r$\.done$$r$ AS INT)), 0) AS INT) AS done_count FROM - pg_catalog.pg_ls_dir('pg_xlog/archive_status') AS archive_files (archive_file); + pg_catalog.pg_ls_dir('{0}/archive_status') AS archive_files (archive_file); """, BACKENDS=""" SELECT @@ -125,7 +125,11 @@ AND NOT datname ~* '^template\d+'; """, IF_SUPERUSER=""" SELECT current_setting('is_superuser') = 'on' AS is_superuser; - """) + """, + DETECT_SERVER_VERSION=""" +SHOW server_version_num; + """ +) QUERY_STATS = { @@ -221,7 +225,7 @@ CHARTS = { class Service(SimpleService): def __init__(self, configuration=None, name=None): - super(self.__class__, self).__init__(configuration=configuration, name=name) + SimpleService.__init__(self, configuration=configuration, name=name) self.order = ORDER[:] self.definitions = deepcopy(CHARTS) self.table_stats = configuration.pop('table_stats', False) @@ -229,6 +233,7 @@ class Service(SimpleService): self.database_poll = configuration.pop('database_poll', None) self.configuration = configuration self.connection = False + self.server_version = None self.data = dict() self.locks_zeroed = dict() self.databases = list() @@ -257,17 +262,20 @@ class Service(SimpleService): return False result, error = self._connect() if not result: - conf = dict([(k, (lambda k, v: v if k != 'password' else '*****')(k, v)) for k, v in self.configuration.items()]) + conf = dict((k, (lambda k, v: v if k != 'password' else '*****')(k, v)) + for k, v in self.configuration.items()) self.error('Failed to connect to %s. Error: %s' % (str(conf), error)) return False try: cursor = self.connection.cursor() self.databases = discover_databases_(cursor, QUERIES['FIND_DATABASES']) is_superuser = check_if_superuser_(cursor, QUERIES['IF_SUPERUSER']) + self.server_version = detect_server_version(cursor, QUERIES['DETECT_SERVER_VERSION']) cursor.close() - if (self.database_poll and isinstance(self.database_poll, str)): - self.databases = [dbase for dbase in self.databases if dbase in self.database_poll.split()] or self.databases + if self.database_poll and isinstance(self.database_poll, str): + self.databases = [dbase for dbase in self.databases if dbase in self.database_poll.split()]\ + or self.databases self.locks_zeroed = populate_lock_types(self.databases) self.add_additional_queries_(is_superuser) @@ -284,7 +292,11 @@ class Service(SimpleService): self.queries[QUERIES['TABLE_STATS']] = METRICS['TABLE_STATS'] if is_superuser: self.queries[QUERIES['BGWRITER']] = METRICS['BGWRITER'] - self.queries[QUERIES['ARCHIVE']] = METRICS['ARCHIVE'] + if self.server_version >= 100000: + wal_dir_name = 'pg_wal' + else: + wal_dir_name = 'pg_xlog' + self.queries[QUERIES['ARCHIVE'].format(wal_dir_name)] = METRICS['ARCHIVE'] def create_dynamic_charts_(self): @@ -340,6 +352,9 @@ def check_if_superuser_(cursor, query): cursor.execute(query) return cursor.fetchone()[0] +def detect_server_version(cursor, query): + cursor.execute(query) + return int(cursor.fetchone()[0]) def populate_lock_types(databases): result = dict() diff --git a/python.d/powerdns.chart.py b/python.d/powerdns.chart.py new file mode 100644 index 00000000..a8d2f399 --- /dev/null +++ b/python.d/powerdns.chart.py @@ -0,0 +1,58 @@ +# -*- coding: utf-8 -*- +# Description: powerdns netdata python.d module +# Author: l2isbad + +from json import loads + +from bases.FrameworkServices.UrlService import UrlService + +priority = 60000 +retries = 60 +# update_every = 3 + +ORDER = ['questions', 'cache_usage', 'cache_size', 'latency'] +CHARTS = { + 'questions': { + 'options': [None, 'PowerDNS Queries and Answers', 'count', 'questions', 'powerdns.questions', 'line'], + 'lines': [ + ['udp-queries', None, 'incremental'], + ['udp-answers', None, 'incremental'], + ['tcp-queries', None, 'incremental'], + ['tcp-answers', None, 'incremental'] + ]}, + 'cache_usage': { + 'options': [None, 'PowerDNS Cache Usage', 'count', 'cache', 'powerdns.cache_usage', 'line'], + 'lines': [ + ['query-cache-hit', None, 'incremental'], + ['query-cache-miss', None, 'incremental'], + ['packetcache-hit', 'packet-cache-hit', 'incremental'], + ['packetcache-miss', 'packet-cache-miss', 'incremental'] + ]}, + 'cache_size': { + 'options': [None, 'PowerDNS Cache Size', 'count', 'cache', 'powerdns.cache_size', 'line'], + 'lines': [ + ['query-cache-size', None, 'absolute'], + ['packetcache-size', 'packet-cache-size', 'absolute'], + ['key-cache-size', None, 'absolute'], + ['meta-cache-size', None, 'absolute'] + ]}, + 'latency': { + 'options': [None, 'PowerDNS Latency', 'microseconds', 'latency', 'powerdns.latency', 'line'], + 'lines': [ + ['latency', None, 'absolute'] + ]} + +} + + +class Service(UrlService): + def __init__(self, configuration=None, name=None): + UrlService.__init__(self, configuration=configuration, name=name) + self.order = ORDER + self.definitions = CHARTS + + def _get_data(self): + data = self._get_raw_data() + if not data: + return None + return dict((d['name'], d['value']) for d in loads(data)) diff --git a/python.d/python_modules/base.py b/python.d/python_modules/base.py index 1d5417ec..7c6e1d2f 100644 --- a/python.d/python_modules/base.py +++ b/python.d/python_modules/base.py @@ -1,1119 +1,9 @@ # -*- coding: utf-8 -*- -# Description: netdata python modules framework -# Author: Pawel Krupa (paulfantom) - -# Remember: -# ALL CODE NEEDS TO BE COMPATIBLE WITH Python > 2.7 and Python > 3.1 -# Follow PEP8 as much as it is possible -# "check" and "create" CANNOT be blocking. -# "update" CAN be blocking -# "update" function needs to be fast, so follow: -# https://wiki.python.org/moin/PythonSpeed/PerformanceTips -# basically: -# - use local variables wherever it is possible -# - avoid dots in expressions that are executed many times -# - use "join()" instead of "+" -# - use "import" only at the beginning -# -# using ".encode()" in one thread can block other threads as well (only in python2) - -import os -import re -import socket -import time -import threading - -import urllib3 - -from glob import glob -from subprocess import Popen, PIPE -from sys import exc_info - -try: - import MySQLdb - PY_MYSQL = True -except ImportError: - try: - import pymysql as MySQLdb - PY_MYSQL = True - except ImportError: - PY_MYSQL = False - -import msg - - -PATH = os.getenv('PATH', '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin').split(':') -try: - urllib3.disable_warnings() -except AttributeError: - msg.error('urllib3: warnings were not disabled') - - -# class BaseService(threading.Thread): -class SimpleService(threading.Thread): - """ - Prototype of Service class. - Implemented basic functionality to run jobs by `python.d.plugin` - """ - def __init__(self, configuration=None, name=None): - """ - This needs to be initialized in child classes - :param configuration: dict - :param name: str - """ - threading.Thread.__init__(self) - self._data_stream = "" - self.daemon = True - self.retries = 0 - self.retries_left = 0 - self.priority = 140000 - self.update_every = 1 - self.name = name - self.override_name = None - self.chart_name = "" - self._dimensions = [] - self._charts = [] - self.__chart_set = False - self.__first_run = True - self.order = [] - self.definitions = {} - self._data_from_check = dict() - if configuration is None: - self.error("BaseService: no configuration parameters supplied. Cannot create Service.") - raise RuntimeError - else: - self._extract_base_config(configuration) - self.timetable = {} - self.create_timetable() - - # --- BASIC SERVICE CONFIGURATION --- - - def _extract_base_config(self, config): - """ - Get basic parameters to run service - Minimum config: - config = {'update_every':1, - 'priority':100000, - 'retries':0} - :param config: dict - """ - pop = config.pop - try: - self.override_name = pop('name') - except KeyError: - pass - self.update_every = int(pop('update_every')) - self.priority = int(pop('priority')) - self.retries = int(pop('retries')) - self.retries_left = self.retries - self.configuration = config - - def create_timetable(self, freq=None): - """ - Create service timetable. - `freq` is optional - Example: - timetable = {'last': 1466370091.3767564, - 'next': 1466370092, - 'freq': 1} - :param freq: int - """ - if freq is None: - freq = self.update_every - now = time.time() - self.timetable = {'last': now, - 'next': now - (now % freq) + freq, - 'freq': freq} - - # --- THREAD CONFIGURATION --- - - def _run_once(self): - """ - Executes self.update(interval) and draws run time chart. - Return value presents exit status of update() - :return: boolean - """ - t_start = float(time.time()) - chart_name = self.chart_name - - since_last = int((t_start - self.timetable['last']) * 1000000) - if self.__first_run: - since_last = 0 - - if not self.update(since_last): - self.error("update function failed.") - return False - - # draw performance graph - run_time = int((time.time() - t_start) * 1000) - print("BEGIN netdata.plugin_pythond_%s %s\nSET run_time = %s\nEND\n" % - (self.chart_name, str(since_last), str(run_time))) - - self.debug(chart_name, "updated in", str(run_time), "ms") - self.timetable['last'] = t_start - self.__first_run = False - return True - - def run(self): - """ - Runs job in thread. Handles retries. - Exits when job failed or timed out. - :return: None - """ - step = float(self.timetable['freq']) - penalty = 0 - self.timetable['last'] = float(time.time() - step) - self.debug("starting data collection - update frequency:", str(step), " retries allowed:", str(self.retries)) - while True: # run forever, unless something is wrong - now = float(time.time()) - next = self.timetable['next'] = now - (now % step) + step + penalty - - # it is important to do this in a loop - # sleep() is interruptable - while now < next: - self.debug("sleeping for", str(next - now), "secs to reach frequency of", - str(step), "secs, now:", str(now), " next:", str(next), " penalty:", str(penalty)) - time.sleep(next - now) - now = float(time.time()) - - # do the job - try: - status = self._run_once() - except Exception: - status = False - - if status: - # it is good - self.retries_left = self.retries - penalty = 0 - else: - # it failed - self.retries_left -= 1 - if self.retries_left <= 0: - if penalty == 0: - penalty = float(self.retries * step) / 2 - else: - penalty *= 1.5 - - if penalty > 600: - penalty = 600 - - self.retries_left = self.retries - self.alert("failed to collect data for " + str(self.retries) + - " times - increasing penalty to " + str(penalty) + " sec and trying again") - - else: - self.error("failed to collect data - " + str(self.retries_left) - + " retries left - penalty: " + str(penalty) + " sec") - - # --- CHART --- - - @staticmethod - def _format(*args): - """ - Escape and convert passed arguments. - :param args: anything - :return: list - """ - params = [] - append = params.append - for p in args: - if p is None: - append(p) - continue - if type(p) is not str: - p = str(p) - if ' ' in p: - p = "'" + p + "'" - append(p) - return params - - def _line(self, instruction, *params): - """ - Converts *params to string and joins them with one space between every one. - Result is appended to self._data_stream - :param params: str/int/float - """ - tmp = list(map((lambda x: "''" if x is None or len(x) == 0 else x), params)) - self._data_stream += "%s %s\n" % (instruction, str(" ".join(tmp))) - - def chart(self, type_id, name="", title="", units="", family="", - category="", chart_type="line", priority="", update_every=""): - """ - Defines a new chart. - :param type_id: str - :param name: str - :param title: str - :param units: str - :param family: str - :param category: str - :param chart_type: str - :param priority: int/str - :param update_every: int/str - """ - self._charts.append(type_id) - - p = self._format(type_id, name, title, units, family, category, chart_type, priority, update_every) - self._line("CHART", *p) - - def dimension(self, id, name=None, algorithm="absolute", multiplier=1, divisor=1, hidden=False): - """ - Defines a new dimension for the chart - :param id: str - :param name: str - :param algorithm: str - :param multiplier: int/str - :param divisor: int/str - :param hidden: boolean - :return: - """ - try: - int(multiplier) - except TypeError: - self.error("malformed dimension: multiplier is not a number:", multiplier) - multiplier = 1 - try: - int(divisor) - except TypeError: - self.error("malformed dimension: divisor is not a number:", divisor) - divisor = 1 - if name is None: - name = id - if algorithm not in ("absolute", "incremental", "percentage-of-absolute-row", "percentage-of-incremental-row"): - algorithm = "absolute" - - self._dimensions.append(str(id)) - if hidden: - p = self._format(id, name, algorithm, multiplier, divisor, "hidden") - else: - p = self._format(id, name, algorithm, multiplier, divisor) - - self._line("DIMENSION", *p) - - def begin(self, type_id, microseconds=0): - """ - Begin data set - :param type_id: str - :param microseconds: int - :return: boolean - """ - if type_id not in self._charts: - self.error("wrong chart type_id:", type_id) - return False - try: - int(microseconds) - except TypeError: - self.error("malformed begin statement: microseconds are not a number:", microseconds) - microseconds = "" - - self._line("BEGIN", type_id, str(microseconds)) - return True - - def set(self, id, value): - """ - Set value to dimension - :param id: str - :param value: int/float - :return: boolean - """ - if id not in self._dimensions: - self.error("wrong dimension id:", id, "Available dimensions are:", *self._dimensions) - return False - try: - value = str(int(value)) - except TypeError: - self.error("cannot set non-numeric value:", str(value)) - return False - self._line("SET", id, "=", str(value)) - self.__chart_set = True - return True - - def end(self): - if self.__chart_set: - self._line("END") - self.__chart_set = False - else: - pos = self._data_stream.rfind("BEGIN") - self._data_stream = self._data_stream[:pos] - - def commit(self): - """ - Upload new data to netdata. - """ - try: - print(self._data_stream) - except Exception as e: - msg.fatal('cannot send data to netdata:', str(e)) - self._data_stream = "" - - # --- ERROR HANDLING --- - - def error(self, *params): - """ - Show error message on stderr - """ - msg.error(self.chart_name, *params) - - def alert(self, *params): - """ - Show error message on stderr - """ - msg.alert(self.chart_name, *params) - - def debug(self, *params): - """ - Show debug message on stderr - """ - msg.debug(self.chart_name, *params) - - def info(self, *params): - """ - Show information message on stderr - """ - msg.info(self.chart_name, *params) - - # --- MAIN METHODS --- - - def _get_data(self): - """ - Get some data - :return: dict - """ - return {} - - def check(self): - """ - check() prototype - :return: boolean - """ - self.debug("Module", str(self.__module__), "doesn't implement check() function. Using default.") - data = self._get_data() - - if data is None: - self.debug("failed to receive data during check().") - return False - - if len(data) == 0: - self.debug("empty data during check().") - return False - - self.debug("successfully received data during check(): '" + str(data) + "'") - return True - - def create(self): - """ - Create charts - :return: boolean - """ - data = self._data_from_check or self._get_data() - if data is None: - self.debug("failed to receive data during create().") - return False - - idx = 0 - for name in self.order: - options = self.definitions[name]['options'] + [self.priority + idx, self.update_every] - self.chart(self.chart_name + "." + name, *options) - # check if server has this datapoint - for line in self.definitions[name]['lines']: - if line[0] in data: - self.dimension(*line) - idx += 1 - - self.commit() - return True - - def update(self, interval): - """ - Update charts - :param interval: int - :return: boolean - """ - data = self._get_data() - if data is None: - self.debug("failed to receive data during update().") - return False - - updated = False - for chart in self.order: - if self.begin(self.chart_name + "." + chart, interval): - updated = True - for dim in self.definitions[chart]['lines']: - try: - self.set(dim[0], data[dim[0]]) - except KeyError: - pass - self.end() - - self.commit() - if not updated: - self.error("no charts to update") - - return updated - - @staticmethod - def find_binary(binary): - try: - if isinstance(binary, str): - binary = os.path.basename(binary) - return next(('/'.join([p, binary]) for p in PATH - if os.path.isfile('/'.join([p, binary])) - and os.access('/'.join([p, binary]), os.X_OK))) - return None - except StopIteration: - return None - - def _add_new_dimension(self, dimension_id, chart_name, dimension=None, algorithm='incremental', - multiplier=1, divisor=1, priority=65000): - """ - :param dimension_id: - :param chart_name: - :param dimension: - :param algorithm: - :param multiplier: - :param divisor: - :param priority: - :return: - """ - if not all([dimension_id not in self._dimensions, - chart_name in self.order, - chart_name in self.definitions]): - return - self._dimensions.append(dimension_id) - dimension_list = list(map(str, [dimension_id, - dimension if dimension else dimension_id, - algorithm, - multiplier, - divisor])) - self.definitions[chart_name]['lines'].append(dimension_list) - add_to_name = self.override_name or self.name - job_name = ('_'.join([self.__module__, re.sub('\s+', '_', add_to_name)]) - if add_to_name != 'None' else self.__module__) - chart = 'CHART {0}.{1} '.format(job_name, chart_name) - options = '"" "{0}" {1} "{2}" {3} {4} '.format(*self.definitions[chart_name]['options'][1:6]) - other = '{0} {1}\n'.format(priority, self.update_every) - new_dimension = "DIMENSION {0}\n".format(' '.join(dimension_list)) - print(chart + options + other + new_dimension) - - -class UrlService(SimpleService): - def __init__(self, configuration=None, name=None): - SimpleService.__init__(self, configuration=configuration, name=name) - self.url = self.configuration.get('url') - self.user = self.configuration.get('user') - self.password = self.configuration.get('pass') - self.proxy_user = self.configuration.get('proxy_user') - self.proxy_password = self.configuration.get('proxy_pass') - self.proxy_url = self.configuration.get('proxy_url') - self._manager = None - - def __make_headers(self, **header_kw): - user = header_kw.get('user') or self.user - password = header_kw.get('pass') or self.password - proxy_user = header_kw.get('proxy_user') or self.proxy_user - proxy_password = header_kw.get('proxy_pass') or self.proxy_password - header_params = dict(keep_alive=True) - proxy_header_params = dict() - if user and password: - header_params['basic_auth'] = '{user}:{password}'.format(user=user, - password=password) - if proxy_user and proxy_password: - proxy_header_params['proxy_basic_auth'] = '{user}:{password}'.format(user=proxy_user, - password=proxy_password) - try: - return urllib3.make_headers(**header_params), urllib3.make_headers(**proxy_header_params) - except TypeError as error: - self.error('build_header() error: {error}'.format(error=error)) - return None, None - - def _build_manager(self, **header_kw): - header, proxy_header = self.__make_headers(**header_kw) - if header is None or proxy_header is None: - return None - proxy_url = header_kw.get('proxy_url') or self.proxy_url - if proxy_url: - manager = urllib3.ProxyManager - params = dict(proxy_url=proxy_url, headers=header, proxy_headers=proxy_header) - else: - manager = urllib3.PoolManager - params = dict(headers=header) - try: - return manager(**params) - except (urllib3.exceptions.ProxySchemeUnknown, TypeError) as error: - self.error('build_manager() error:', str(error)) - return None - - def _get_raw_data(self, url=None, manager=None): - """ - Get raw data from http request - :return: str - """ - try: - url = url or self.url - manager = manager or self._manager - # TODO: timeout, retries and method hardcoded.. - response = manager.request(method='GET', - url=url, - timeout=1, - retries=1, - headers=manager.headers) - except (urllib3.exceptions.HTTPError, TypeError, AttributeError) as error: - self.error('Url: {url}. Error: {error}'.format(url=url, error=error)) - return None - if response.status == 200: - return response.data.decode() - self.debug('Url: {url}. Http response status code: {code}'.format(url=url, code=response.status)) - return None - - def check(self): - """ - Format configuration data and try to connect to server - :return: boolean - """ - if not (self.url and isinstance(self.url, str)): - self.error('URL is not defined or type is not <str>') - return False - - self._manager = self._build_manager() - if not self._manager: - return False - - try: - data = self._get_data() - except Exception as error: - self.error('_get_data() failed. Url: {url}. Error: {error}'.format(url=self.url, error=error)) - return False - - if isinstance(data, dict) and data: - self._data_from_check = data - return True - self.error('_get_data() returned no data or type is not <dict>') - return False - - -class SocketService(SimpleService): - def __init__(self, configuration=None, name=None): - self._sock = None - self._keep_alive = False - self.host = "localhost" - self.port = None - self.unix_socket = None - self.request = "" - self.__socket_config = None - self.__empty_request = "".encode() - SimpleService.__init__(self, configuration=configuration, name=name) - - def _socketerror(self, message=None): - if self.unix_socket is not None: - self.error("unix socket '" + self.unix_socket + "':", message) - else: - if self.__socket_config is not None: - af, socktype, proto, canonname, sa = self.__socket_config - self.error("socket to '" + str(sa[0]) + "' port " + str(sa[1]) + ":", message) - else: - self.error("unknown socket:", message) - - def _connect2socket(self, res=None): - """ - Connect to a socket, passing the result of getaddrinfo() - :return: boolean - """ - if res is None: - res = self.__socket_config - if res is None: - self.error("Cannot create socket to 'None':") - return False - - af, socktype, proto, canonname, sa = res - try: - self.debug("creating socket to '" + str(sa[0]) + "', port " + str(sa[1])) - self._sock = socket.socket(af, socktype, proto) - except socket.error as e: - self.error("Failed to create socket to '" + str(sa[0]) + "', port " + str(sa[1]) + ":", str(e)) - self._sock = None - self.__socket_config = None - return False - - try: - self.debug("connecting socket to '" + str(sa[0]) + "', port " + str(sa[1])) - self._sock.connect(sa) - except socket.error as e: - self.error("Failed to connect to '" + str(sa[0]) + "', port " + str(sa[1]) + ":", str(e)) - self._disconnect() - self.__socket_config = None - return False - - self.debug("connected to '" + str(sa[0]) + "', port " + str(sa[1])) - self.__socket_config = res - return True - - def _connect2unixsocket(self): - """ - Connect to a unix socket, given its filename - :return: boolean - """ - if self.unix_socket is None: - self.error("cannot connect to unix socket 'None'") - return False - - try: - self.debug("attempting DGRAM unix socket '" + str(self.unix_socket) + "'") - self._sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM) - self._sock.connect(self.unix_socket) - self.debug("connected DGRAM unix socket '" + str(self.unix_socket) + "'") - return True - except socket.error as e: - self.debug("Failed to connect DGRAM unix socket '" + str(self.unix_socket) + "':", str(e)) - - try: - self.debug("attempting STREAM unix socket '" + str(self.unix_socket) + "'") - self._sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - self._sock.connect(self.unix_socket) - self.debug("connected STREAM unix socket '" + str(self.unix_socket) + "'") - return True - except socket.error as e: - self.debug("Failed to connect STREAM unix socket '" + str(self.unix_socket) + "':", str(e)) - self.error("Failed to connect to unix socket '" + str(self.unix_socket) + "':", str(e)) - self._sock = None - return False - - def _connect(self): - """ - Recreate socket and connect to it since sockets cannot be reused after closing - Available configurations are IPv6, IPv4 or UNIX socket - :return: - """ - try: - if self.unix_socket is not None: - self._connect2unixsocket() - - else: - if self.__socket_config is not None: - self._connect2socket() - else: - for res in socket.getaddrinfo(self.host, self.port, socket.AF_UNSPEC, socket.SOCK_STREAM): - if self._connect2socket(res): break - - except Exception as e: - self._sock = None - self.__socket_config = None - - if self._sock is not None: - self._sock.setblocking(0) - self._sock.settimeout(5) - self.debug("set socket timeout to: " + str(self._sock.gettimeout())) - - def _disconnect(self): - """ - Close socket connection - :return: - """ - if self._sock is not None: - try: - self.debug("closing socket") - self._sock.shutdown(2) # 0 - read, 1 - write, 2 - all - self._sock.close() - except Exception: - pass - self._sock = None - - def _send(self): - """ - Send request. - :return: boolean - """ - # Send request if it is needed - if self.request != self.__empty_request: - try: - self.debug("sending request:", str(self.request)) - self._sock.send(self.request) - except Exception as e: - self._socketerror("error sending request:" + str(e)) - self._disconnect() - return False - return True - - def _receive(self): - """ - Receive data from socket - :return: str - """ - data = "" - while True: - self.debug("receiving response") - try: - buf = self._sock.recv(4096) - except Exception as e: - self._socketerror("failed to receive response:" + str(e)) - self._disconnect() - break - - if buf is None or len(buf) == 0: # handle server disconnect - if data == "": - self._socketerror("unexpectedly disconnected") - else: - self.debug("server closed the connection") - self._disconnect() - break - - self.debug("received data:", str(buf)) - data += buf.decode('utf-8', 'ignore') - if self._check_raw_data(data): - break - - self.debug("final response:", str(data)) - return data - - def _get_raw_data(self): - """ - Get raw data with low-level "socket" module. - :return: str - """ - if self._sock is None: - self._connect() - if self._sock is None: - return None - - # Send request if it is needed - if not self._send(): - return None - - data = self._receive() - - if not self._keep_alive: - self._disconnect() - - return data - - def _check_raw_data(self, data): - """ - Check if all data has been gathered from socket - :param data: str - :return: boolean - """ - return True - - def _parse_config(self): - """ - Parse configuration data - :return: boolean - """ - if self.name is None or self.name == str(None): - self.name = "" - else: - self.name = str(self.name) - - try: - self.unix_socket = str(self.configuration['socket']) - except (KeyError, TypeError): - self.debug("No unix socket specified. Trying TCP/IP socket.") - self.unix_socket = None - try: - self.host = str(self.configuration['host']) - except (KeyError, TypeError): - self.debug("No host specified. Using: '" + self.host + "'") - try: - self.port = int(self.configuration['port']) - except (KeyError, TypeError): - self.debug("No port specified. Using: '" + str(self.port) + "'") - - try: - self.request = str(self.configuration['request']) - except (KeyError, TypeError): - self.debug("No request specified. Using: '" + str(self.request) + "'") - - self.request = self.request.encode() - - def check(self): - self._parse_config() - return SimpleService.check(self) - - -class LogService(SimpleService): - def __init__(self, configuration=None, name=None): - SimpleService.__init__(self, configuration=configuration, name=name) - self.log_path = self.configuration.get('path') - self.__glob_path = self.log_path - self._last_position = 0 - self.retries = 100000 # basically always retry - self.__re_find = dict(current=0, run=0, maximum=60) - - def _get_raw_data(self): - """ - Get log lines since last poll - :return: list - """ - lines = list() - try: - if self.__re_find['current'] == self.__re_find['run']: - self._find_recent_log_file() - size = os.path.getsize(self.log_path) - if size == self._last_position: - self.__re_find['current'] += 1 - return list() # return empty list if nothing has changed - elif size < self._last_position: - self._last_position = 0 # read from beginning if file has shrunk - - with open(self.log_path) as fp: - fp.seek(self._last_position) - for line in fp: - lines.append(line) - self._last_position = fp.tell() - self.__re_find['current'] = 0 - except (OSError, IOError) as error: - self.__re_find['current'] += 1 - self.error(str(error)) - - return lines or None - - def _find_recent_log_file(self): - """ - :return: - """ - self.__re_find['run'] = self.__re_find['maximum'] - self.__re_find['current'] = 0 - self.__glob_path = self.__glob_path or self.log_path # workaround for modules w/o config files - path_list = glob(self.__glob_path) - if path_list: - self.log_path = max(path_list) - return True - return False - - def check(self): - """ - Parse basic configuration and check if log file exists - :return: boolean - """ - if not self.log_path: - self.error("No path to log specified") - return None - - if all([self._find_recent_log_file(), - os.access(self.log_path, os.R_OK), - os.path.isfile(self.log_path)]): - return True - self.error("Cannot access %s" % self.log_path) - return False - - def create(self): - # set cursor at last byte of log file - self._last_position = os.path.getsize(self.log_path) - status = SimpleService.create(self) - # self._last_position = 0 - return status - - -class ExecutableService(SimpleService): - - def __init__(self, configuration=None, name=None): - SimpleService.__init__(self, configuration=configuration, name=name) - self.command = None - - def _get_raw_data(self, stderr=False): - """ - Get raw data from executed command - :return: <list> - """ - try: - p = Popen(self.command, stdout=PIPE, stderr=PIPE) - except Exception as error: - self.error("Executing command", " ".join(self.command), "resulted in error:", str(error)) - return None - data = list() - std = p.stderr if stderr else p.stdout - for line in std.readlines(): - data.append(line.decode()) - - return data or None - - def check(self): - """ - Parse basic configuration, check if command is whitelisted and is returning values - :return: <boolean> - """ - # Preference: 1. "command" from configuration file 2. "command" from plugin (if specified) - if 'command' in self.configuration: - self.command = self.configuration['command'] - - # "command" must be: 1.not None 2. type <str> - if not (self.command and isinstance(self.command, str)): - self.error('Command is not defined or command type is not <str>') - return False - - # Split "command" into: 1. command <str> 2. options <list> - command, opts = self.command.split()[0], self.command.split()[1:] - - # Check for "bad" symbols in options. No pipes, redirects etc. TODO: what is missing? - bad_opts = set(''.join(opts)) & set(['&', '|', ';', '>', '<']) - if bad_opts: - self.error("Bad command argument(s): %s" % bad_opts) - return False - - # Find absolute path ('echo' => '/bin/echo') - if '/' not in command: - command = self.find_binary(command) - if not command: - self.error('Can\'t locate "%s" binary in PATH(%s)' % (self.command, PATH)) - return False - # Check if binary exist and executable - else: - if not (os.path.isfile(command) and os.access(command, os.X_OK)): - self.error('"%s" is not a file or not executable' % command) - return False - - self.command = [command] + opts if opts else [command] - - try: - data = self._get_data() - except Exception as error: - self.error('_get_data() failed. Command: %s. Error: %s' % (self.command, error)) - return False - - if isinstance(data, dict) and data: - # We need this for create() method. No reason to execute get_data() again if result is not empty dict() - self._data_from_check = data - return True - else: - self.error("Command", str(self.command), "returned no data") - return False - - -class MySQLService(SimpleService): - - def __init__(self, configuration=None, name=None): - SimpleService.__init__(self, configuration=configuration, name=name) - self.__connection = None - self.__conn_properties = dict() - self.extra_conn_properties = dict() - self.__queries = self.configuration.get('queries', dict()) - self.queries = dict() - - def __connect(self): - try: - connection = MySQLdb.connect(connect_timeout=self.update_every, **self.__conn_properties) - except (MySQLdb.MySQLError, TypeError, AttributeError) as error: - return None, str(error) - else: - return connection, None - - def check(self): - def get_connection_properties(conf, extra_conf): - properties = dict() - if conf.get('user'): - properties['user'] = conf['user'] - if conf.get('pass'): - properties['passwd'] = conf['pass'] - if conf.get('socket'): - properties['unix_socket'] = conf['socket'] - elif conf.get('host'): - properties['host'] = conf['host'] - properties['port'] = int(conf.get('port', 3306)) - elif conf.get('my.cnf'): - if MySQLdb.__name__ == 'pymysql': - self.error('"my.cnf" parsing is not working for pymysql') - else: - properties['read_default_file'] = conf['my.cnf'] - if isinstance(extra_conf, dict) and extra_conf: - properties.update(extra_conf) - - return properties or None - - def is_valid_queries_dict(raw_queries, log_error): - """ - :param raw_queries: dict: - :param log_error: function: - :return: dict or None - - raw_queries is valid when: type <dict> and not empty after is_valid_query(for all queries) - """ - def is_valid_query(query): - return all([isinstance(query, str), - query.startswith(('SELECT', 'select', 'SHOW', 'show'))]) - - if hasattr(raw_queries, 'keys') and raw_queries: - valid_queries = dict([(n, q) for n, q in raw_queries.items() if is_valid_query(q)]) - bad_queries = set(raw_queries) - set(valid_queries) - - if bad_queries: - log_error('Removed query(s): %s' % bad_queries) - return valid_queries - else: - log_error('Unsupported "queries" format. Must be not empty <dict>') - return None - - if not PY_MYSQL: - self.error('MySQLdb or PyMySQL module is needed to use mysql.chart.py plugin') - return False - - # Preference: 1. "queries" from the configuration file 2. "queries" from the module - self.queries = self.__queries or self.queries - # Check if "self.queries" exist, not empty and all queries are in valid format - self.queries = is_valid_queries_dict(self.queries, self.error) - if not self.queries: - return None - - # Get connection properties - self.__conn_properties = get_connection_properties(self.configuration, self.extra_conn_properties) - if not self.__conn_properties: - self.error('Connection properties are missing') - return False - - # Create connection to the database - self.__connection, error = self.__connect() - if error: - self.error('Can\'t establish connection to MySQL: %s' % error) - return False - - try: - data = self._get_data() - except Exception as error: - self.error('_get_data() failed. Error: %s' % error) - return False - - if isinstance(data, dict) and data: - # We need this for create() method - self._data_from_check = data - return True - else: - self.error("_get_data() returned no data or type is not <dict>") - return False - - def _get_raw_data(self, description=None): - """ - Get raw data from MySQL server - :return: dict: fetchall() or (fetchall(), description) - """ - - if not self.__connection: - self.__connection, error = self.__connect() - if error: - return None - - raw_data = dict() - queries = dict(self.queries) - try: - with self.__connection as cursor: - for name, query in queries.items(): - try: - cursor.execute(query) - except (MySQLdb.ProgrammingError, MySQLdb.OperationalError) as error: - if self.__is_error_critical(err_class=exc_info()[0], err_text=str(error)): - raise RuntimeError - self.error('Removed query: %s[%s]. Error: %s' - % (name, query, error)) - self.queries.pop(name) - continue - else: - raw_data[name] = (cursor.fetchall(), cursor.description) if description else cursor.fetchall() - self.__connection.commit() - except (MySQLdb.MySQLError, RuntimeError, TypeError, AttributeError): - self.__connection.close() - self.__connection = None - return None - else: - return raw_data or None - - @staticmethod - def __is_error_critical(err_class, err_text): - return err_class == MySQLdb.OperationalError and all(['denied' not in err_text, - 'Unknown column' not in err_text]) +# Description: backward compatibility with old version + +from bases.FrameworkServices.SimpleService import SimpleService +from bases.FrameworkServices.UrlService import UrlService +from bases.FrameworkServices.SocketService import SocketService +from bases.FrameworkServices.LogService import LogService +from bases.FrameworkServices.ExecutableService import ExecutableService +from bases.FrameworkServices.MySQLService import MySQLService diff --git a/python.d/python_modules/bases/FrameworkServices/ExecutableService.py b/python.d/python_modules/bases/FrameworkServices/ExecutableService.py new file mode 100644 index 00000000..b6d7871f --- /dev/null +++ b/python.d/python_modules/bases/FrameworkServices/ExecutableService.py @@ -0,0 +1,85 @@ +# -*- coding: utf-8 -*- +# Description: +# Author: Pawel Krupa (paulfantom) +# Author: Ilya Mashchenko (l2isbad) + +import os + +from subprocess import Popen, PIPE + +from bases.FrameworkServices.SimpleService import SimpleService +from bases.collection import find_binary + + +class ExecutableService(SimpleService): + def __init__(self, configuration=None, name=None): + SimpleService.__init__(self, configuration=configuration, name=name) + self.command = None + + def _get_raw_data(self, stderr=False): + """ + Get raw data from executed command + :return: <list> + """ + try: + p = Popen(self.command, stdout=PIPE, stderr=PIPE) + except Exception as error: + self.error('Executing command {command} resulted in error: {error}'.format(command=self.command, + error=error)) + return None + data = list() + std = p.stderr if stderr else p.stdout + for line in std: + data.append(line.decode()) + + return data or None + + def check(self): + """ + Parse basic configuration, check if command is whitelisted and is returning values + :return: <boolean> + """ + # Preference: 1. "command" from configuration file 2. "command" from plugin (if specified) + if 'command' in self.configuration: + self.command = self.configuration['command'] + + # "command" must be: 1.not None 2. type <str> + if not (self.command and isinstance(self.command, str)): + self.error('Command is not defined or command type is not <str>') + return False + + # Split "command" into: 1. command <str> 2. options <list> + command, opts = self.command.split()[0], self.command.split()[1:] + + # Check for "bad" symbols in options. No pipes, redirects etc. + opts_list = ['&', '|', ';', '>', '<'] + bad_opts = set(''.join(opts)) & set(opts_list) + if bad_opts: + self.error("Bad command argument(s): {opts}".format(opts=bad_opts)) + return False + + # Find absolute path ('echo' => '/bin/echo') + if '/' not in command: + command = find_binary(command) + if not command: + self.error('Can\'t locate "{command}" binary'.format(command=self.command)) + return False + # Check if binary exist and executable + else: + if not os.access(command, os.X_OK): + self.error('"{binary}" is not executable'.format(binary=command)) + return False + + self.command = [command] + opts if opts else [command] + + try: + data = self._get_data() + except Exception as error: + self.error('_get_data() failed. Command: {command}. Error: {error}'.format(command=self.command, + error=error)) + return False + + if isinstance(data, dict) and data: + return True + self.error('Command "{command}" returned no data'.format(command=self.command)) + return False diff --git a/python.d/python_modules/bases/FrameworkServices/LogService.py b/python.d/python_modules/bases/FrameworkServices/LogService.py new file mode 100644 index 00000000..45daa244 --- /dev/null +++ b/python.d/python_modules/bases/FrameworkServices/LogService.py @@ -0,0 +1,78 @@ +# -*- coding: utf-8 -*- +# Description: +# Author: Pawel Krupa (paulfantom) + +from glob import glob +import os + +from bases.FrameworkServices.SimpleService import SimpleService + + +class LogService(SimpleService): + def __init__(self, configuration=None, name=None): + SimpleService.__init__(self, configuration=configuration, name=name) + self.log_path = self.configuration.get('path') + self.__glob_path = self.log_path + self._last_position = 0 + self.__re_find = dict(current=0, run=0, maximum=60) + + def _get_raw_data(self): + """ + Get log lines since last poll + :return: list + """ + lines = list() + try: + if self.__re_find['current'] == self.__re_find['run']: + self._find_recent_log_file() + size = os.path.getsize(self.log_path) + if size == self._last_position: + self.__re_find['current'] += 1 + return list() # return empty list if nothing has changed + elif size < self._last_position: + self._last_position = 0 # read from beginning if file has shrunk + + with open(self.log_path) as fp: + fp.seek(self._last_position) + for line in fp: + lines.append(line) + self._last_position = fp.tell() + self.__re_find['current'] = 0 + except (OSError, IOError) as error: + self.__re_find['current'] += 1 + self.error(str(error)) + + return lines or None + + def _find_recent_log_file(self): + """ + :return: + """ + self.__re_find['run'] = self.__re_find['maximum'] + self.__re_find['current'] = 0 + self.__glob_path = self.__glob_path or self.log_path # workaround for modules w/o config files + path_list = glob(self.__glob_path) + if path_list: + self.log_path = max(path_list) + return True + return False + + def check(self): + """ + Parse basic configuration and check if log file exists + :return: boolean + """ + if not self.log_path: + self.error('No path to log specified') + return None + + if self._find_recent_log_file() and os.access(self.log_path, os.R_OK) and os.path.isfile(self.log_path): + return True + self.error('Cannot access {0}'.format(self.log_path)) + return False + + def create(self): + # set cursor at last byte of log file + self._last_position = os.path.getsize(self.log_path) + status = SimpleService.create(self) + return status diff --git a/python.d/python_modules/bases/FrameworkServices/MySQLService.py b/python.d/python_modules/bases/FrameworkServices/MySQLService.py new file mode 100644 index 00000000..3acc5b10 --- /dev/null +++ b/python.d/python_modules/bases/FrameworkServices/MySQLService.py @@ -0,0 +1,158 @@ +# -*- coding: utf-8 -*- +# Description: +# Author: Ilya Mashchenko (l2isbad) + +from sys import exc_info + +try: + import MySQLdb + + PY_MYSQL = True +except ImportError: + try: + import pymysql as MySQLdb + + PY_MYSQL = True + except ImportError: + PY_MYSQL = False + +from bases.FrameworkServices.SimpleService import SimpleService + + +class MySQLService(SimpleService): + def __init__(self, configuration=None, name=None): + SimpleService.__init__(self, configuration=configuration, name=name) + self.__connection = None + self.__conn_properties = dict() + self.extra_conn_properties = dict() + self.__queries = self.configuration.get('queries', dict()) + self.queries = dict() + + def __connect(self): + try: + connection = MySQLdb.connect(connect_timeout=self.update_every, **self.__conn_properties) + except (MySQLdb.MySQLError, TypeError, AttributeError) as error: + return None, str(error) + else: + return connection, None + + def check(self): + def get_connection_properties(conf, extra_conf): + properties = dict() + if conf.get('user'): + properties['user'] = conf['user'] + if conf.get('pass'): + properties['passwd'] = conf['pass'] + if conf.get('socket'): + properties['unix_socket'] = conf['socket'] + elif conf.get('host'): + properties['host'] = conf['host'] + properties['port'] = int(conf.get('port', 3306)) + elif conf.get('my.cnf'): + if MySQLdb.__name__ == 'pymysql': + self.error('"my.cnf" parsing is not working for pymysql') + else: + properties['read_default_file'] = conf['my.cnf'] + if isinstance(extra_conf, dict) and extra_conf: + properties.update(extra_conf) + + return properties or None + + def is_valid_queries_dict(raw_queries, log_error): + """ + :param raw_queries: dict: + :param log_error: function: + :return: dict or None + + raw_queries is valid when: type <dict> and not empty after is_valid_query(for all queries) + """ + + def is_valid_query(query): + return all([isinstance(query, str), + query.startswith(('SELECT', 'select', 'SHOW', 'show'))]) + + if hasattr(raw_queries, 'keys') and raw_queries: + valid_queries = dict([(n, q) for n, q in raw_queries.items() if is_valid_query(q)]) + bad_queries = set(raw_queries) - set(valid_queries) + + if bad_queries: + log_error('Removed query(s): {queries}'.format(queries=bad_queries)) + return valid_queries + else: + log_error('Unsupported "queries" format. Must be not empty <dict>') + return None + + if not PY_MYSQL: + self.error('MySQLdb or PyMySQL module is needed to use mysql.chart.py plugin') + return False + + # Preference: 1. "queries" from the configuration file 2. "queries" from the module + self.queries = self.__queries or self.queries + # Check if "self.queries" exist, not empty and all queries are in valid format + self.queries = is_valid_queries_dict(self.queries, self.error) + if not self.queries: + return None + + # Get connection properties + self.__conn_properties = get_connection_properties(self.configuration, self.extra_conn_properties) + if not self.__conn_properties: + self.error('Connection properties are missing') + return False + + # Create connection to the database + self.__connection, error = self.__connect() + if error: + self.error('Can\'t establish connection to MySQL: {error}'.format(error=error)) + return False + + try: + data = self._get_data() + except Exception as error: + self.error('_get_data() failed. Error: {error}'.format(error=error)) + return False + + if isinstance(data, dict) and data: + return True + self.error("_get_data() returned no data or type is not <dict>") + return False + + def _get_raw_data(self, description=None): + """ + Get raw data from MySQL server + :return: dict: fetchall() or (fetchall(), description) + """ + + if not self.__connection: + self.__connection, error = self.__connect() + if error: + return None + + raw_data = dict() + queries = dict(self.queries) + try: + with self.__connection as cursor: + for name, query in queries.items(): + try: + cursor.execute(query) + except (MySQLdb.ProgrammingError, MySQLdb.OperationalError) as error: + if self.__is_error_critical(err_class=exc_info()[0], err_text=str(error)): + raise RuntimeError + self.error('Removed query: {name}[{query}]. Error: error'.format(name=name, + query=query, + error=error)) + self.queries.pop(name) + continue + else: + raw_data[name] = (cursor.fetchall(), cursor.description) if description else cursor.fetchall() + self.__connection.commit() + except (MySQLdb.MySQLError, RuntimeError, TypeError, AttributeError): + self.__connection.close() + self.__connection = None + return None + else: + return raw_data or None + + @staticmethod + def __is_error_critical(err_class, err_text): + return err_class == MySQLdb.OperationalError and all(['denied' not in err_text, + 'Unknown column' not in err_text]) diff --git a/python.d/python_modules/bases/FrameworkServices/SimpleService.py b/python.d/python_modules/bases/FrameworkServices/SimpleService.py new file mode 100644 index 00000000..14c83910 --- /dev/null +++ b/python.d/python_modules/bases/FrameworkServices/SimpleService.py @@ -0,0 +1,252 @@ +# -*- coding: utf-8 -*- +# Description: +# Author: Pawel Krupa (paulfantom) +# Author: Ilya Mashchenko (l2isbad) + +from threading import Thread + +try: + from time import sleep, monotonic as time +except ImportError: + from time import sleep, time + +from bases.charts import Charts, ChartError, create_runtime_chart +from bases.collection import OldVersionCompatibility, safe_print +from bases.loggers import PythonDLimitedLogger + +RUNTIME_CHART_UPDATE = 'BEGIN netdata.runtime_{job_name} {since_last}\n' \ + 'SET run_time = {elapsed}\n' \ + 'END\n' + + +class RuntimeCounters: + def __init__(self, configuration): + """ + :param configuration: <dict> + """ + self.FREQ = int(configuration.pop('update_every')) + self.START_RUN = 0 + self.NEXT_RUN = 0 + self.PREV_UPDATE = 0 + self.SINCE_UPDATE = 0 + self.ELAPSED = 0 + self.RETRIES = 0 + self.RETRIES_MAX = configuration.pop('retries') + self.PENALTY = 0 + + def is_sleep_time(self): + return self.START_RUN < self.NEXT_RUN + + +class SimpleService(Thread, PythonDLimitedLogger, OldVersionCompatibility, object): + """ + Prototype of Service class. + Implemented basic functionality to run jobs by `python.d.plugin` + """ + def __init__(self, configuration, name=''): + """ + :param configuration: <dict> + :param name: <str> + """ + Thread.__init__(self) + self.daemon = True + PythonDLimitedLogger.__init__(self) + OldVersionCompatibility.__init__(self) + self.configuration = configuration + self.order = list() + self.definitions = dict() + + self.module_name = self.__module__ + self.job_name = configuration.pop('job_name') + self.override_name = configuration.pop('override_name') + self.fake_name = None + + self._runtime_counters = RuntimeCounters(configuration=configuration) + self.charts = Charts(job_name=self.actual_name, + priority=configuration.pop('priority'), + cleanup=configuration.pop('chart_cleanup'), + get_update_every=self.get_update_every, + module_name=self.module_name) + + def __repr__(self): + return '<{cls_bases}: {name}>'.format(cls_bases=', '.join(c.__name__ for c in self.__class__.__bases__), + name=self.name) + + @property + def name(self): + if self.job_name: + return '_'.join([self.module_name, self.override_name or self.job_name]) + return self.module_name + + def actual_name(self): + return self.fake_name or self.name + + @property + def update_every(self): + return self._runtime_counters.FREQ + + @update_every.setter + def update_every(self, value): + """ + :param value: <int> + :return: + """ + self._runtime_counters.FREQ = value + + def get_update_every(self): + return self.update_every + + def check(self): + """ + check() prototype + :return: boolean + """ + self.debug("job doesn't implement check() method. Using default which simply invokes get_data().") + data = self.get_data() + if data and isinstance(data, dict): + return True + self.debug('returned value is wrong: {0}'.format(data)) + return False + + @create_runtime_chart + def create(self): + for chart_name in self.order: + chart_config = self.definitions.get(chart_name) + + if not chart_config: + self.debug("create() => [NOT ADDED] chart '{chart_name}' not in definitions. " + "Skipping it.".format(chart_name=chart_name)) + continue + + # create chart + chart_params = [chart_name] + chart_config['options'] + try: + self.charts.add_chart(params=chart_params) + except ChartError as error: + self.error("create() => [NOT ADDED] (chart '{chart}': {error})".format(chart=chart_name, + error=error)) + continue + + # add dimensions to chart + for dimension in chart_config['lines']: + try: + self.charts[chart_name].add_dimension(dimension) + except ChartError as error: + self.error("create() => [NOT ADDED] (dimension '{dimension}': {error})".format(dimension=dimension, + error=error)) + continue + + # add variables to chart + if 'variables' in chart_config: + for variable in chart_config['variables']: + try: + self.charts[chart_name].add_variable(variable) + except ChartError as error: + self.error("create() => [NOT ADDED] (variable '{var}': {error})".format(var=variable, + error=error)) + continue + + del self.order + del self.definitions + + # True if job has at least 1 chart else False + return bool(self.charts) + + def run(self): + """ + Runs job in thread. Handles retries. + Exits when job failed or timed out. + :return: None + """ + job = self._runtime_counters + self.debug('started, update frequency: {freq}, ' + 'retries: {retries}'.format(freq=job.FREQ, retries=job.RETRIES_MAX - job.RETRIES)) + + while True: + job.START_RUN = time() + + job.NEXT_RUN = job.START_RUN - (job.START_RUN % job.FREQ) + job.FREQ + job.PENALTY + + self.sleep_until_next_run() + + if job.PREV_UPDATE: + job.SINCE_UPDATE = int((job.START_RUN - job.PREV_UPDATE) * 1e6) + + try: + updated = self.update(interval=job.SINCE_UPDATE) + except Exception as error: + self.error('update() unhandled exception: {error}'.format(error=error)) + updated = False + + if not updated: + if not self.manage_retries(): + return + else: + job.ELAPSED = int((time() - job.START_RUN) * 1e3) + job.PREV_UPDATE = job.START_RUN + job.RETRIES, job.PENALTY = 0, 0 + safe_print(RUNTIME_CHART_UPDATE.format(job_name=self.name, + since_last=job.SINCE_UPDATE, + elapsed=job.ELAPSED)) + self.debug('update => [{status}] (elapsed time: {elapsed}, ' + 'retries left: {retries})'.format(status='OK' if updated else 'FAILED', + elapsed=job.ELAPSED if updated else '-', + retries=job.RETRIES_MAX - job.RETRIES)) + + def update(self, interval): + """ + :return: + """ + data = self.get_data() + if not data: + self.debug('get_data() returned no data') + return False + elif not isinstance(data, dict): + self.debug('get_data() returned incorrect type data') + return False + + updated = False + + for chart in self.charts: + if chart.flags.obsoleted: + continue + elif self.charts.cleanup and chart.penalty >= self.charts.cleanup: + chart.obsolete() + self.error("chart '{0}' was suppressed due to non updating".format(chart.name)) + continue + + ok = chart.update(data, interval) + if ok: + updated = True + + if not updated: + self.debug('none of the charts has been updated') + + return updated + + def manage_retries(self): + rc = self._runtime_counters + rc.RETRIES += 1 + if rc.RETRIES % 5 == 0: + rc.PENALTY = int(rc.RETRIES * self.update_every / 2) + if rc.RETRIES >= rc.RETRIES_MAX: + self.error('stopped after {0} data collection failures in a row'.format(rc.RETRIES_MAX)) + return False + return True + + def sleep_until_next_run(self): + job = self._runtime_counters + + # sleep() is interruptable + while job.is_sleep_time(): + sleep_time = job.NEXT_RUN - job.START_RUN + self.debug('sleeping for {sleep_time} to reach frequency of {freq} sec'.format(sleep_time=sleep_time, + freq=job.FREQ + job.PENALTY)) + sleep(sleep_time) + job.START_RUN = time() + + def get_data(self): + return self._get_data() + + def _get_data(self): + raise NotImplementedError diff --git a/python.d/python_modules/bases/FrameworkServices/SocketService.py b/python.d/python_modules/bases/FrameworkServices/SocketService.py new file mode 100644 index 00000000..90631df1 --- /dev/null +++ b/python.d/python_modules/bases/FrameworkServices/SocketService.py @@ -0,0 +1,250 @@ +# -*- coding: utf-8 -*- +# Description: +# Author: Pawel Krupa (paulfantom) + +import socket + +from bases.FrameworkServices.SimpleService import SimpleService + + +class SocketService(SimpleService): + def __init__(self, configuration=None, name=None): + self._sock = None + self._keep_alive = False + self.host = 'localhost' + self.port = None + self.unix_socket = None + self.request = '' + self.__socket_config = None + self.__empty_request = "".encode() + SimpleService.__init__(self, configuration=configuration, name=name) + + def _socket_error(self, message=None): + if self.unix_socket is not None: + self.error('unix socket "{socket}": {message}'.format(socket=self.unix_socket, + message=message)) + else: + if self.__socket_config is not None: + af, sock_type, proto, canon_name, sa = self.__socket_config + self.error('socket to "{address}" port {port}: {message}'.format(address=sa[0], + port=sa[1], + message=message)) + else: + self.error('unknown socket: {0}'.format(message)) + + def _connect2socket(self, res=None): + """ + Connect to a socket, passing the result of getaddrinfo() + :return: boolean + """ + if res is None: + res = self.__socket_config + if res is None: + self.error("Cannot create socket to 'None':") + return False + + af, sock_type, proto, canon_name, sa = res + try: + self.debug('Creating socket to "{address}", port {port}'.format(address=sa[0], port=sa[1])) + self._sock = socket.socket(af, sock_type, proto) + except socket.error as error: + self.error('Failed to create socket "{address}", port {port}, error: {error}'.format(address=sa[0], + port=sa[1], + error=error)) + self._sock = None + self.__socket_config = None + return False + + try: + self.debug('connecting socket to "{address}", port {port}'.format(address=sa[0], port=sa[1])) + self._sock.connect(sa) + except socket.error as error: + self.error('Failed to connect to "{address}", port {port}, error: {error}'.format(address=sa[0], + port=sa[1], + error=error)) + self._disconnect() + self.__socket_config = None + return False + + self.debug('connected to "{address}", port {port}'.format(address=sa[0], port=sa[1])) + self.__socket_config = res + return True + + def _connect2unixsocket(self): + """ + Connect to a unix socket, given its filename + :return: boolean + """ + if self.unix_socket is None: + self.error("cannot connect to unix socket 'None'") + return False + + try: + self.debug('attempting DGRAM unix socket "{0}"'.format(self.unix_socket)) + self._sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM) + self._sock.connect(self.unix_socket) + self.debug('connected DGRAM unix socket "{0}"'.format(self.unix_socket)) + return True + except socket.error as error: + self.debug('Failed to connect DGRAM unix socket "{socket}": {error}'.format(socket=self.unix_socket, + error=error)) + + try: + self.debug('attempting STREAM unix socket "{0}"'.format(self.unix_socket)) + self._sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + self._sock.connect(self.unix_socket) + self.debug('connected STREAM unix socket "{0}"'.format(self.unix_socket)) + return True + except socket.error as error: + self.debug('Failed to connect STREAM unix socket "{socket}": {error}'.format(socket=self.unix_socket, + error=error)) + self._sock = None + return False + + def _connect(self): + """ + Recreate socket and connect to it since sockets cannot be reused after closing + Available configurations are IPv6, IPv4 or UNIX socket + :return: + """ + try: + if self.unix_socket is not None: + self._connect2unixsocket() + + else: + if self.__socket_config is not None: + self._connect2socket() + else: + for res in socket.getaddrinfo(self.host, self.port, socket.AF_UNSPEC, socket.SOCK_STREAM): + if self._connect2socket(res): + break + + except Exception: + self._sock = None + self.__socket_config = None + + if self._sock is not None: + self._sock.setblocking(0) + self._sock.settimeout(5) + self.debug('set socket timeout to: {0}'.format(self._sock.gettimeout())) + + def _disconnect(self): + """ + Close socket connection + :return: + """ + if self._sock is not None: + try: + self.debug('closing socket') + self._sock.shutdown(2) # 0 - read, 1 - write, 2 - all + self._sock.close() + except Exception: + pass + self._sock = None + + def _send(self): + """ + Send request. + :return: boolean + """ + # Send request if it is needed + if self.request != self.__empty_request: + try: + self.debug('sending request: {0}'.format(self.request)) + self._sock.send(self.request) + except Exception as error: + self._socket_error('error sending request: {0}'.format(error)) + self._disconnect() + return False + return True + + def _receive(self): + """ + Receive data from socket + :return: str + """ + data = "" + while True: + self.debug('receiving response') + try: + buf = self._sock.recv(4096) + except Exception as error: + self._socket_error('failed to receive response: {0}'.format(error)) + self._disconnect() + break + + if buf is None or len(buf) == 0: # handle server disconnect + if data == "": + self._socket_error('unexpectedly disconnected') + else: + self.debug('server closed the connection') + self._disconnect() + break + + self.debug('received data') + data += buf.decode('utf-8', 'ignore') + if self._check_raw_data(data): + break + + self.debug('final response: {0}'.format(data)) + return data + + def _get_raw_data(self): + """ + Get raw data with low-level "socket" module. + :return: str + """ + if self._sock is None: + self._connect() + if self._sock is None: + return None + + # Send request if it is needed + if not self._send(): + return None + + data = self._receive() + + if not self._keep_alive: + self._disconnect() + + return data + + @staticmethod + def _check_raw_data(data): + """ + Check if all data has been gathered from socket + :param data: str + :return: boolean + """ + return bool(data) + + def _parse_config(self): + """ + Parse configuration data + :return: boolean + """ + try: + self.unix_socket = str(self.configuration['socket']) + except (KeyError, TypeError): + self.debug('No unix socket specified. Trying TCP/IP socket.') + self.unix_socket = None + try: + self.host = str(self.configuration['host']) + except (KeyError, TypeError): + self.debug('No host specified. Using: "{0}"'.format(self.host)) + try: + self.port = int(self.configuration['port']) + except (KeyError, TypeError): + self.debug('No port specified. Using: "{0}"'.format(self.port)) + + try: + self.request = str(self.configuration['request']) + except (KeyError, TypeError): + self.debug('No request specified. Using: "{0}"'.format(self.request)) + + self.request = self.request.encode() + + def check(self): + self._parse_config() + return SimpleService.check(self) diff --git a/python.d/python_modules/bases/FrameworkServices/UrlService.py b/python.d/python_modules/bases/FrameworkServices/UrlService.py new file mode 100644 index 00000000..0941ab16 --- /dev/null +++ b/python.d/python_modules/bases/FrameworkServices/UrlService.py @@ -0,0 +1,115 @@ +# -*- coding: utf-8 -*- +# Description: +# Author: Pawel Krupa (paulfantom) +# Author: Ilya Mashchenko (l2isbad) + +import urllib3 + +from bases.FrameworkServices.SimpleService import SimpleService + +try: + urllib3.disable_warnings() +except AttributeError: + pass + + +class UrlService(SimpleService): + def __init__(self, configuration=None, name=None): + SimpleService.__init__(self, configuration=configuration, name=name) + self.url = self.configuration.get('url') + self.user = self.configuration.get('user') + self.password = self.configuration.get('pass') + self.proxy_user = self.configuration.get('proxy_user') + self.proxy_password = self.configuration.get('proxy_pass') + self.proxy_url = self.configuration.get('proxy_url') + self.header = self.configuration.get('header') + self.request_timeout = self.configuration.get('timeout', 1) + self._manager = None + + def __make_headers(self, **header_kw): + user = header_kw.get('user') or self.user + password = header_kw.get('pass') or self.password + proxy_user = header_kw.get('proxy_user') or self.proxy_user + proxy_password = header_kw.get('proxy_pass') or self.proxy_password + custom_header = header_kw.get('header') or self.header + header_params = dict(keep_alive=True) + proxy_header_params = dict() + if user and password: + header_params['basic_auth'] = '{user}:{password}'.format(user=user, + password=password) + if proxy_user and proxy_password: + proxy_header_params['proxy_basic_auth'] = '{user}:{password}'.format(user=proxy_user, + password=proxy_password) + try: + header, proxy_header = urllib3.make_headers(**header_params), urllib3.make_headers(**proxy_header_params) + except TypeError as error: + self.error('build_header() error: {error}'.format(error=error)) + return None, None + else: + header.update(custom_header or dict()) + return header, proxy_header + + def _build_manager(self, **header_kw): + header, proxy_header = self.__make_headers(**header_kw) + if header is None or proxy_header is None: + return None + proxy_url = header_kw.get('proxy_url') or self.proxy_url + if proxy_url: + manager = urllib3.ProxyManager + params = dict(proxy_url=proxy_url, headers=header, proxy_headers=proxy_header) + else: + manager = urllib3.PoolManager + params = dict(headers=header) + try: + url = header_kw.get('url') or self.url + if url.startswith('https'): + return manager(assert_hostname=False, cert_reqs='CERT_NONE', **params) + return manager(**params) + except (urllib3.exceptions.ProxySchemeUnknown, TypeError) as error: + self.error('build_manager() error:', str(error)) + return None + + def _get_raw_data(self, url=None, manager=None): + """ + Get raw data from http request + :return: str + """ + try: + url = url or self.url + manager = manager or self._manager + response = manager.request(method='GET', + url=url, + timeout=self.request_timeout, + retries=1, + headers=manager.headers) + except (urllib3.exceptions.HTTPError, TypeError, AttributeError) as error: + self.error('Url: {url}. Error: {error}'.format(url=url, error=error)) + return None + if response.status == 200: + return response.data.decode() + self.debug('Url: {url}. Http response status code: {code}'.format(url=url, code=response.status)) + return None + + def check(self): + """ + Format configuration data and try to connect to server + :return: boolean + """ + if not (self.url and isinstance(self.url, str)): + self.error('URL is not defined or type is not <str>') + return False + + self._manager = self._build_manager() + if not self._manager: + return False + + try: + data = self._get_data() + except Exception as error: + self.error('_get_data() failed. Url: {url}. Error: {error}'.format(url=self.url, error=error)) + return False + + if isinstance(data, dict) and data: + return True + self.error('_get_data() returned no data or type is not <dict>') + return False diff --git a/python.d/python_modules/bases/FrameworkServices/__init__.py b/python.d/python_modules/bases/FrameworkServices/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/python.d/python_modules/bases/FrameworkServices/__init__.py diff --git a/python.d/python_modules/bases/__init__.py b/python.d/python_modules/bases/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/python.d/python_modules/bases/__init__.py diff --git a/python.d/python_modules/bases/charts.py b/python.d/python_modules/bases/charts.py new file mode 100644 index 00000000..1e9348e5 --- /dev/null +++ b/python.d/python_modules/bases/charts.py @@ -0,0 +1,376 @@ +# -*- coding: utf-8 -*- +# Description: +# Author: Ilya Mashchenko (l2isbad) + +from bases.collection import safe_print + +CHART_PARAMS = ['type', 'id', 'name', 'title', 'units', 'family', 'context', 'chart_type'] +DIMENSION_PARAMS = ['id', 'name', 'algorithm', 'multiplier', 'divisor', 'hidden'] +VARIABLE_PARAMS = ['id', 'value'] + +CHART_TYPES = ['line', 'area', 'stacked'] +DIMENSION_ALGORITHMS = ['absolute', 'incremental', 'percentage-of-absolute-row', 'percentage-of-incremental-row'] + +CHART_BEGIN = 'BEGIN {type}.{id} {since_last}\n' +CHART_CREATE = "CHART {type}.{id} '{name}' '{title}' '{units}' '{family}' '{context}' " \ + "{chart_type} {priority} {update_every} '' 'python.d.plugin' '{module_name}'\n" +CHART_OBSOLETE = "CHART {type}.{id} '{name}' '{title}' '{units}' '{family}' '{context}' " \ + "{chart_type} {priority} {update_every} 'obsolete'\n" + + +DIMENSION_CREATE = "DIMENSION '{id}' '{name}' {algorithm} {multiplier} {divisor} '{hidden}'\n" +DIMENSION_SET = "SET '{id}' = {value}\n" + +CHART_VARIABLE_SET = "VARIABLE CHART '{id}' = {value}\n" + +RUNTIME_CHART_CREATE = "CHART netdata.runtime_{job_name} '' 'Execution time for {job_name}' 'ms' 'python.d' " \ + "netdata.pythond_runtime line 145000 {update_every}\n" \ + "DIMENSION run_time 'run time' absolute 1 1\n" + + +def create_runtime_chart(func): + """ + Calls a wrapped function, then prints runtime chart to stdout. + + Used as a decorator for SimpleService.create() method. + The whole point of making 'create runtime chart' functionality as a decorator was + to help users who re-implements create() in theirs classes. + + :param func: class method + :return: + """ + def wrapper(*args, **kwargs): + self = args[0] + ok = func(*args, **kwargs) + if ok: + safe_print(RUNTIME_CHART_CREATE.format(job_name=self.name, + update_every=self._runtime_counters.FREQ)) + return ok + return wrapper + + +class ChartError(Exception): + """Base-class for all exceptions raised by this module""" + + +class DuplicateItemError(ChartError): + """Occurs when user re-adds a chart or a dimension that has already been added""" + + +class ItemTypeError(ChartError): + """Occurs when user passes value of wrong type to Chart, Dimension or ChartVariable class""" + + +class ItemValueError(ChartError): + """Occurs when user passes inappropriate value to Chart, Dimension or ChartVariable class""" + + +class Charts: + """Represent a collection of charts + + All charts stored in a dict. + Chart is a instance of Chart class. + Charts adding must be done using Charts.add_chart() method only""" + def __init__(self, job_name, priority, cleanup, get_update_every, module_name): + """ + :param job_name: <bound method> + :param priority: <int> + :param get_update_every: <bound method> + """ + self.job_name = job_name + self.priority = priority + self.cleanup = cleanup + self.get_update_every = get_update_every + self.module_name = module_name + self.charts = dict() + + def __len__(self): + return len(self.charts) + + def __iter__(self): + return iter(self.charts.values()) + + def __repr__(self): + return 'Charts({0})'.format(self) + + def __str__(self): + return str([chart for chart in self.charts]) + + def __contains__(self, item): + return item in self.charts + + def __getitem__(self, item): + return self.charts[item] + + def __delitem__(self, key): + del self.charts[key] + + def __bool__(self): + return bool(self.charts) + + def __nonzero__(self): + return self.__bool__() + + def add_chart(self, params): + """ + Create Chart instance and add it to the dict + + Manually adds job name, priority and update_every to params. + :param params: <list> + :return: + """ + params = [self.job_name()] + params + new_chart = Chart(params) + + new_chart.params['update_every'] = self.get_update_every() + new_chart.params['priority'] = self.priority + new_chart.params['module_name'] = self.module_name + + self.priority += 1 + self.charts[new_chart.id] = new_chart + + return new_chart + + def active_charts(self): + return [chart.id for chart in self if not chart.flags.obsoleted] + + +class Chart: + """Represent a chart""" + def __init__(self, params): + """ + :param params: <list> + """ + if not isinstance(params, list): + raise ItemTypeError("'chart' must be a list type") + if not len(params) >= 8: + raise ItemValueError("invalid value for 'chart', must be {0}".format(CHART_PARAMS)) + + self.params = dict(zip(CHART_PARAMS, (p or str() for p in params))) + self.name = '{type}.{id}'.format(type=self.params['type'], + id=self.params['id']) + if self.params.get('chart_type') not in CHART_TYPES: + self.params['chart_type'] = 'absolute' + + self.dimensions = list() + self.variables = set() + self.flags = ChartFlags() + self.penalty = 0 + + def __getattr__(self, item): + try: + return self.params[item] + except KeyError: + raise AttributeError("'{instance}' has no attribute '{attr}'".format(instance=repr(self), + attr=item)) + + def __repr__(self): + return 'Chart({0})'.format(self.id) + + def __str__(self): + return self.id + + def __iter__(self): + return iter(self.dimensions) + + def __contains__(self, item): + return item in [dimension.id for dimension in self.dimensions] + + def add_variable(self, variable): + """ + :param variable: <list> + :return: + """ + self.variables.add(ChartVariable(variable)) + + def add_dimension(self, dimension): + """ + :param dimension: <list> + :return: + """ + dim = Dimension(dimension) + + if dim.id in self: + raise DuplicateItemError("'{dimension}' already in '{chart}' dimensions".format(dimension=dim.id, + chart=self.name)) + self.refresh() + self.dimensions.append(dim) + return dim + + def hide_dimension(self, dimension_id, reverse=False): + if dimension_id in self: + idx = self.dimensions.index(dimension_id) + dimension = self.dimensions[idx] + dimension.params['hidden'] = 'hidden' if not reverse else str() + self.refresh() + + def create(self): + """ + :return: + """ + chart = CHART_CREATE.format(**self.params) + dimensions = ''.join([dimension.create() for dimension in self.dimensions]) + variables = ''.join([var.set(var.value) for var in self.variables if var]) + + self.flags.push = False + self.flags.created = True + + safe_print(chart + dimensions + variables) + + def update(self, data, interval): + updated_dimensions, updated_variables = str(), str() + + for dim in self.dimensions: + value = dim.get_value(data) + if value is not None: + updated_dimensions += dim.set(value) + + for var in self.variables: + value = var.get_value(data) + if value is not None: + updated_variables += var.set(value) + + if updated_dimensions: + since_last = interval if self.flags.updated else 0 + + if self.flags.push: + self.create() + + chart_begin = CHART_BEGIN.format(type=self.type, id=self.id, since_last=since_last) + safe_print(chart_begin, updated_dimensions, updated_variables, 'END\n') + + self.flags.updated = True + self.penalty = 0 + else: + self.penalty += 1 + self.flags.updated = False + + return bool(updated_dimensions) + + def obsolete(self): + self.flags.obsoleted = True + if self.flags.created: + safe_print(CHART_OBSOLETE.format(**self.params)) + + def refresh(self): + self.penalty = 0 + self.flags.push = True + self.flags.obsoleted = False + + +class Dimension: + """Represent a dimension""" + def __init__(self, params): + """ + :param params: <list> + """ + if not isinstance(params, list): + raise ItemTypeError("'dimension' must be a list type") + if not params: + raise ItemValueError("invalid value for 'dimension', must be {0}".format(DIMENSION_PARAMS)) + + self.params = dict(zip(DIMENSION_PARAMS, (p or str() for p in params))) + self.params['name'] = self.params.get('name') or self.params['id'] + + if self.params.get('algorithm') not in DIMENSION_ALGORITHMS: + self.params['algorithm'] = 'absolute' + if not isinstance(self.params.get('multiplier'), int): + self.params['multiplier'] = 1 + if not isinstance(self.params.get('divisor'), int): + self.params['divisor'] = 1 + self.params.setdefault('hidden', '') + + def __getattr__(self, item): + try: + return self.params[item] + except KeyError: + raise AttributeError("'{instance}' has no attribute '{attr}'".format(instance=repr(self), + attr=item)) + + def __repr__(self): + return 'Dimension({0})'.format(self.id) + + def __str__(self): + return self.id + + def __eq__(self, other): + if not isinstance(other, Dimension): + return self.id == other + return self.id == other.id + + def create(self): + return DIMENSION_CREATE.format(**self.params) + + def set(self, value): + """ + :param value: <str>: must be a digit + :return: + """ + return DIMENSION_SET.format(id=self.id, + value=value) + + def get_value(self, data): + try: + return int(data[self.id]) + except (KeyError, TypeError): + return None + + +class ChartVariable: + """Represent a chart variable""" + def __init__(self, params): + """ + :param params: <list> + """ + if not isinstance(params, list): + raise ItemTypeError("'variable' must be a list type") + if not params: + raise ItemValueError("invalid value for 'variable' must be: {0}".format(VARIABLE_PARAMS)) + + self.params = dict(zip(VARIABLE_PARAMS, params)) + self.params.setdefault('value', None) + + def __getattr__(self, item): + try: + return self.params[item] + except KeyError: + raise AttributeError("'{instance}' has no attribute '{attr}'".format(instance=repr(self), + attr=item)) + + def __bool__(self): + return self.value is not None + + def __nonzero__(self): + return self.__bool__() + + def __repr__(self): + return 'ChartVariable({0})'.format(self.id) + + def __str__(self): + return self.id + + def __eq__(self, other): + if isinstance(other, ChartVariable): + return self.id == other.id + return False + + def __hash__(self): + return hash(repr(self)) + + def set(self, value): + return CHART_VARIABLE_SET.format(id=self.id, + value=value) + + def get_value(self, data): + try: + return int(data[self.id]) + except (KeyError, TypeError): + return None + + +class ChartFlags: + def __init__(self): + self.push = True + self.created = False + self.updated = False + self.obsoleted = False diff --git a/python.d/python_modules/bases/collection.py b/python.d/python_modules/bases/collection.py new file mode 100644 index 00000000..e03b4f58 --- /dev/null +++ b/python.d/python_modules/bases/collection.py @@ -0,0 +1,144 @@ +# -*- coding: utf-8 -*- +# Description: +# Author: Ilya Mashchenko (l2isbad) + +import os + +PATH = os.getenv('PATH', '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin').split(':') + +CHART_BEGIN = 'BEGIN {0} {1}\n' +CHART_CREATE = "CHART {0} '{1}' '{2}' '{3}' '{4}' '{5}' {6} {7} {8}\n" +DIMENSION_CREATE = "DIMENSION '{0}' '{1}' {2} {3} {4} '{5}'\n" +DIMENSION_SET = "SET '{0}' = {1}\n" + + +def setdefault_values(config, base_dict): + for key, value in base_dict.items(): + config.setdefault(key, value) + return config + + +def run_and_exit(func): + def wrapper(*args, **kwargs): + func(*args, **kwargs) + exit(1) + return wrapper + + +def on_try_except_finally(on_except=(None, ), on_finally=(None, )): + except_func = on_except[0] + finally_func = on_finally[0] + + def decorator(func): + def wrapper(*args, **kwargs): + try: + func(*args, **kwargs) + except Exception: + if except_func: + except_func(*on_except[1:]) + finally: + if finally_func: + finally_func(*on_finally[1:]) + return wrapper + return decorator + + +def static_vars(**kwargs): + def decorate(func): + for k in kwargs: + setattr(func, k, kwargs[k]) + return func + return decorate + + +@on_try_except_finally(on_except=(exit, 1)) +def safe_print(*msg): + """ + :param msg: + :return: + """ + print(''.join(msg)) + + +def find_binary(binary): + """ + :param binary: <str> + :return: + """ + for directory in PATH: + binary_name = '/'.join([directory, binary]) + if os.path.isfile(binary_name) and os.access(binary_name, os.X_OK): + return binary_name + return None + + +def read_last_line(f): + with open(f, 'rb') as opened: + opened.seek(-2, 2) + while opened.read(1) != b'\n': + opened.seek(-2, 1) + if opened.tell() == 0: + break + result = opened.readline() + return result.decode() + + +class OldVersionCompatibility: + + def __init__(self): + self._data_stream = str() + + def begin(self, type_id, microseconds=0): + """ + :param type_id: <str> + :param microseconds: <str> or <int>: must be a digit + :return: + """ + self._data_stream += CHART_BEGIN.format(type_id, microseconds) + + def set(self, dim_id, value): + """ + :param dim_id: <str> + :param value: <int> or <str>: must be a digit + :return: + """ + self._data_stream += DIMENSION_SET.format(dim_id, value) + + def end(self): + self._data_stream += 'END\n' + + def chart(self, type_id, name='', title='', units='', family='', category='', chart_type='line', + priority='', update_every=''): + """ + :param type_id: <str> + :param name: <str> + :param title: <str> + :param units: <str> + :param family: <str> + :param category: <str> + :param chart_type: <str> + :param priority: <str> or <int> + :param update_every: <str> or <int> + :return: + """ + self._data_stream += CHART_CREATE.format(type_id, name, title, units, + family, category, chart_type, + priority, update_every) + + def dimension(self, dim_id, name=None, algorithm="absolute", multiplier=1, divisor=1, hidden=False): + """ + :param dim_id: <str> + :param name: <str> or None + :param algorithm: <str> + :param multiplier: <str> or <int>: must be a digit + :param divisor: <str> or <int>: must be a digit + :param hidden: <str>: literally "hidden" or "" + :return: + """ + self._data_stream += DIMENSION_CREATE.format(dim_id, name or dim_id, algorithm, + multiplier, divisor, hidden or str()) + + @on_try_except_finally(on_except=(exit, 1)) + def commit(self): + print(self._data_stream) + self._data_stream = str() diff --git a/python.d/python_modules/bases/loaders.py b/python.d/python_modules/bases/loaders.py new file mode 100644 index 00000000..d18b9dcd --- /dev/null +++ b/python.d/python_modules/bases/loaders.py @@ -0,0 +1,66 @@ +# -*- coding: utf-8 -*- +# Description: +# Author: Ilya Mashchenko (l2isbad) + +import types +from sys import version_info + +PY_VERSION = version_info[:2] + +if PY_VERSION > (3, 1): + from pyyaml3 import SafeLoader as YamlSafeLoader + from importlib.machinery import SourceFileLoader + DEFAULT_MAPPING_TAG = 'tag:yaml.org,2002:map' +else: + from pyyaml2 import SafeLoader as YamlSafeLoader + from imp import load_source as SourceFileLoader + DEFAULT_MAPPING_TAG = u'tag:yaml.org,2002:map' + +try: + from collections import OrderedDict +except ImportError: + from third_party.ordereddict import OrderedDict + + +def dict_constructor(loader, node): + return OrderedDict(loader.construct_pairs(node)) + + +YamlSafeLoader.add_constructor(DEFAULT_MAPPING_TAG, dict_constructor) + + +class YamlOrderedLoader: + @staticmethod + def load_config_from_file(file_name): + opened, loaded = False, False + try: + stream = open(file_name, 'r') + opened = True + loader = YamlSafeLoader(stream) + loaded = True + parsed = loader.get_single_data() or dict() + except Exception as error: + return dict(), error + else: + return parsed, None + finally: + if opened: + stream.close() + if loaded: + loader.dispose() + + +class SourceLoader: + @staticmethod + def load_module_from_file(name, path): + try: + loaded = SourceFileLoader(name, path) + if isinstance(loaded, types.ModuleType): + return loaded, None + return loaded.load_module(), None + except Exception as error: + return None, error + + +class ModuleAndConfigLoader(YamlOrderedLoader, SourceLoader): + pass diff --git a/python.d/python_modules/bases/loggers.py b/python.d/python_modules/bases/loggers.py new file mode 100644 index 00000000..fc40b83d --- /dev/null +++ b/python.d/python_modules/bases/loggers.py @@ -0,0 +1,205 @@ +# -*- coding: utf-8 -*- +# Description: +# Author: Ilya Mashchenko (l2isbad) + +import logging +import traceback + +from sys import exc_info + +try: + from time import monotonic as time +except ImportError: + from time import time + +from bases.collection import on_try_except_finally + + +LOGGING_LEVELS = {'CRITICAL': 50, + 'ERROR': 40, + 'WARNING': 30, + 'INFO': 20, + 'DEBUG': 10, + 'NOTSET': 0} + +DEFAULT_LOG_LINE_FORMAT = '%(asctime)s: %(name)s %(levelname)s : %(message)s' +DEFAULT_LOG_TIME_FORMAT = '%Y-%m-%d %H:%M:%S' + +PYTHON_D_LOG_LINE_FORMAT = '%(asctime)s: %(name)s %(levelname)s: %(module_name)s: %(job_name)s: %(message)s' +PYTHON_D_LOG_NAME = 'python.d' + + +def limiter(log_max_count=30, allowed_in_seconds=60): + def on_decorator(func): + + def on_call(*args): + current_time = args[0]._runtime_counters.START_RUN + lc = args[0]._logger_counters + + if lc.logged and lc.logged % log_max_count == 0: + if current_time - lc.time_to_compare <= allowed_in_seconds: + lc.dropped += 1 + return + lc.time_to_compare = current_time + + lc.logged += 1 + func(*args) + + return on_call + return on_decorator + + +def add_traceback(func): + def on_call(*args): + self = args[0] + + if not self.log_traceback: + func(*args) + else: + if exc_info()[0]: + func(*args) + func(self, traceback.format_exc()) + else: + func(*args) + + return on_call + + +class LoggerCounters: + def __init__(self): + self.logged = 0 + self.dropped = 0 + self.time_to_compare = time() + + def __repr__(self): + return 'LoggerCounter(logged: {logged}, dropped: {dropped})'.format(logged=self.logged, + dropped=self.dropped) + + +class BaseLogger(object): + def __init__(self, logger_name, log_fmt=DEFAULT_LOG_LINE_FORMAT, date_fmt=DEFAULT_LOG_TIME_FORMAT, + handler=logging.StreamHandler): + """ + :param logger_name: <str> + :param log_fmt: <str> + :param date_fmt: <str> + :param handler: <logging handler> + """ + self.logger = logging.getLogger(logger_name) + if not self.has_handlers(): + self.severity = 'INFO' + self.logger.addHandler(handler()) + self.set_formatter(fmt=log_fmt, date_fmt=date_fmt) + + def __repr__(self): + return '<Logger: {name})>'.format(name=self.logger.name) + + def set_formatter(self, fmt, date_fmt=DEFAULT_LOG_TIME_FORMAT): + """ + :param fmt: <str> + :param date_fmt: <str> + :return: + """ + if self.has_handlers(): + self.logger.handlers[0].setFormatter(logging.Formatter(fmt=fmt, datefmt=date_fmt)) + + def has_handlers(self): + return self.logger.handlers + + @property + def severity(self): + return self.logger.getEffectiveLevel() + + @severity.setter + def severity(self, level): + """ + :param level: <str> or <int> + :return: + """ + if level in LOGGING_LEVELS: + self.logger.setLevel(LOGGING_LEVELS[level]) + + def debug(self, *msg, **kwargs): + self.logger.debug(' '.join(map(str, msg)), **kwargs) + + def info(self, *msg, **kwargs): + self.logger.info(' '.join(map(str, msg)), **kwargs) + + def warning(self, *msg, **kwargs): + self.logger.warning(' '.join(map(str, msg)), **kwargs) + + def error(self, *msg, **kwargs): + self.logger.error(' '.join(map(str, msg)), **kwargs) + + def alert(self, *msg, **kwargs): + self.logger.critical(' '.join(map(str, msg)), **kwargs) + + @on_try_except_finally(on_finally=(exit, 1)) + def fatal(self, *msg, **kwargs): + self.logger.critical(' '.join(map(str, msg)), **kwargs) + + +class PythonDLogger(object): + def __init__(self, logger_name=PYTHON_D_LOG_NAME, log_fmt=PYTHON_D_LOG_LINE_FORMAT): + """ + :param logger_name: <str> + :param log_fmt: <str> + """ + self.logger = BaseLogger(logger_name, log_fmt=log_fmt) + self.module_name = 'plugin' + self.job_name = 'main' + self._logger_counters = LoggerCounters() + + _LOG_TRACEBACK = False + + @property + def log_traceback(self): + return PythonDLogger._LOG_TRACEBACK + + @log_traceback.setter + def log_traceback(self, value): + PythonDLogger._LOG_TRACEBACK = value + + def debug(self, *msg): + self.logger.debug(*msg, extra={'module_name': self.module_name, + 'job_name': self.job_name or self.module_name}) + + def info(self, *msg): + self.logger.info(*msg, extra={'module_name': self.module_name, + 'job_name': self.job_name or self.module_name}) + + def warning(self, *msg): + self.logger.warning(*msg, extra={'module_name': self.module_name, + 'job_name': self.job_name or self.module_name}) + + @add_traceback + def error(self, *msg): + self.logger.error(*msg, extra={'module_name': self.module_name, + 'job_name': self.job_name or self.module_name}) + + @add_traceback + def alert(self, *msg): + self.logger.alert(*msg, extra={'module_name': self.module_name, + 'job_name': self.job_name or self.module_name}) + + def fatal(self, *msg): + self.logger.fatal(*msg, extra={'module_name': self.module_name, + 'job_name': self.job_name or self.module_name}) + + +class PythonDLimitedLogger(PythonDLogger): + @limiter() + def info(self, *msg): + PythonDLogger.info(self, *msg) + + @limiter() + def warning(self, *msg): + PythonDLogger.warning(self, *msg) + + @limiter() + def error(self, *msg): + PythonDLogger.error(self, *msg) + + @limiter() + def alert(self, *msg): + PythonDLogger.alert(self, *msg) diff --git a/python.d/python_modules/msg.py b/python.d/python_modules/msg.py deleted file mode 100644 index 74716770..00000000 --- a/python.d/python_modules/msg.py +++ /dev/null @@ -1,101 +0,0 @@ -# -*- coding: utf-8 -*- -# Description: logging for netdata python.d modules - -import traceback -import sys -from time import time, strftime - -DEBUG_FLAG = False -TRACE_FLAG = False -PROGRAM = "" -LOG_COUNTER = 0 -LOG_THROTTLE = 10000 # has to be too big during init -LOG_INTERVAL = 1 # has to be too low during init -LOG_NEXT_CHECK = 0 - -WRITE = sys.stderr.write -FLUSH = sys.stderr.flush - - -def log_msg(msg_type, *args): - """ - Print message on stderr. - :param msg_type: str - """ - global LOG_COUNTER - global LOG_THROTTLE - global LOG_INTERVAL - global LOG_NEXT_CHECK - now = time() - - if not DEBUG_FLAG: - LOG_COUNTER += 1 - - # WRITE("COUNTER " + str(LOG_COUNTER) + " THROTTLE " + str(LOG_THROTTLE) + " INTERVAL " + str(LOG_INTERVAL) + " NOW " + str(now) + " NEXT " + str(LOG_NEXT_CHECK) + "\n") - - if LOG_COUNTER <= LOG_THROTTLE or msg_type == "FATAL" or msg_type == "ALERT": - timestamp = strftime('%Y-%m-%d %X') - msg = "%s: %s %s: %s" % (timestamp, PROGRAM, str(msg_type), " ".join(args)) - WRITE(msg + "\n") - FLUSH() - elif LOG_COUNTER == LOG_THROTTLE + 1: - timestamp = strftime('%Y-%m-%d %X') - msg = "%s: python.d.plugin: throttling further log messages for %s seconds" % (timestamp, str(int(LOG_NEXT_CHECK + 0.5) - int(now))) - WRITE(msg + "\n") - FLUSH() - - if LOG_NEXT_CHECK <= now: - if LOG_COUNTER >= LOG_THROTTLE: - timestamp = strftime('%Y-%m-%d %X') - msg = "%s: python.d.plugin: Prevented %s log messages from displaying" % (timestamp, str(LOG_COUNTER - LOG_THROTTLE)) - WRITE(msg + "\n") - FLUSH() - LOG_NEXT_CHECK = now - (now % LOG_INTERVAL) + LOG_INTERVAL - LOG_COUNTER = 0 - - if TRACE_FLAG: - if msg_type == "FATAL" or msg_type == "ERROR" or msg_type == "ALERT": - traceback.print_exc() - - -def debug(*args): - """ - Print debug message on stderr. - """ - if not DEBUG_FLAG: - return - - log_msg("DEBUG", *args) - - -def error(*args): - """ - Print message on stderr. - """ - log_msg("ERROR", *args) - - -def alert(*args): - """ - Print message on stderr. - """ - log_msg("ALERT", *args) - - -def info(*args): - """ - Print message on stderr. - """ - log_msg("INFO", *args) - - -def fatal(*args): - """ - Print message on stderr and exit. - """ - try: - log_msg("FATAL", *args) - print('DISABLE') - except: - pass - sys.exit(1) diff --git a/python.d/python_modules/third_party/__init__.py b/python.d/python_modules/third_party/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/python.d/python_modules/third_party/__init__.py diff --git a/python.d/python_modules/lm_sensors.py b/python.d/python_modules/third_party/lm_sensors.py index 1d868f0e..1d868f0e 100644 --- a/python.d/python_modules/lm_sensors.py +++ b/python.d/python_modules/third_party/lm_sensors.py diff --git a/python.d/python_modules/third_party/ordereddict.py b/python.d/python_modules/third_party/ordereddict.py new file mode 100644 index 00000000..d0b97d47 --- /dev/null +++ b/python.d/python_modules/third_party/ordereddict.py @@ -0,0 +1,128 @@ +# Copyright (c) 2009 Raymond Hettinger +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. + +from UserDict import DictMixin + + +class OrderedDict(dict, DictMixin): + + def __init__(self, *args, **kwds): + if len(args) > 1: + raise TypeError('expected at most 1 arguments, got %d' % len(args)) + try: + self.__end + except AttributeError: + self.clear() + self.update(*args, **kwds) + + def clear(self): + self.__end = end = [] + end += [None, end, end] # sentinel node for doubly linked list + self.__map = {} # key --> [key, prev, next] + dict.clear(self) + + def __setitem__(self, key, value): + if key not in self: + end = self.__end + curr = end[1] + curr[2] = end[1] = self.__map[key] = [key, curr, end] + dict.__setitem__(self, key, value) + + def __delitem__(self, key): + dict.__delitem__(self, key) + key, prev, next = self.__map.pop(key) + prev[2] = next + next[1] = prev + + def __iter__(self): + end = self.__end + curr = end[2] + while curr is not end: + yield curr[0] + curr = curr[2] + + def __reversed__(self): + end = self.__end + curr = end[1] + while curr is not end: + yield curr[0] + curr = curr[1] + + def popitem(self, last=True): + if not self: + raise KeyError('dictionary is empty') + if last: + key = reversed(self).next() + else: + key = iter(self).next() + value = self.pop(key) + return key, value + + def __reduce__(self): + items = [[k, self[k]] for k in self] + tmp = self.__map, self.__end + del self.__map, self.__end + inst_dict = vars(self).copy() + self.__map, self.__end = tmp + if inst_dict: + return self.__class__, (items,), inst_dict + return self.__class__, (items,) + + def keys(self): + return list(self) + + setdefault = DictMixin.setdefault + update = DictMixin.update + pop = DictMixin.pop + values = DictMixin.values + items = DictMixin.items + iterkeys = DictMixin.iterkeys + itervalues = DictMixin.itervalues + iteritems = DictMixin.iteritems + + def __repr__(self): + if not self: + return '%s()' % (self.__class__.__name__,) + return '%s(%r)' % (self.__class__.__name__, self.items()) + + def copy(self): + return self.__class__(self) + + @classmethod + def fromkeys(cls, iterable, value=None): + d = cls() + for key in iterable: + d[key] = value + return d + + def __eq__(self, other): + if isinstance(other, OrderedDict): + if len(self) != len(other): + return False + for p, q in zip(self.items(), other.items()): + if p != q: + return False + return True + return dict.__eq__(self, other) + + def __ne__(self, other): + return not self == other diff --git a/python.d/rabbitmq.chart.py b/python.d/rabbitmq.chart.py index 76391203..eef472bf 100644 --- a/python.d/rabbitmq.chart.py +++ b/python.d/rabbitmq.chart.py @@ -11,7 +11,7 @@ try: except ImportError: from Queue import Queue -from base import UrlService +from bases.FrameworkServices.UrlService import UrlService # default module values (can be overridden per job in `config`) update_every = 1 diff --git a/python.d/redis.chart.py b/python.d/redis.chart.py index 7c3c43f5..bcfcf16a 100644 --- a/python.d/redis.chart.py +++ b/python.d/redis.chart.py @@ -2,10 +2,9 @@ # Description: redis netdata python.d module # Author: Pawel Krupa (paulfantom) -from base import SocketService +from bases.FrameworkServices.SocketService import SocketService # default module values (can be overridden per job in `config`) -#update_every = 2 priority = 60000 retries = 60 @@ -19,7 +18,8 @@ retries = 60 # 'unix_socket': None # }} -ORDER = ['operations', 'hit_rate', 'memory', 'keys', 'net', 'connections', 'clients', 'slaves', 'persistence'] +ORDER = ['operations', 'hit_rate', 'memory', 'keys', 'net', 'connections', 'clients', 'slaves', 'persistence', + 'bgsave_now', 'bgsave_health'] CHARTS = { 'operations': { @@ -72,6 +72,18 @@ CHARTS = { 'redis.rdb_changes', 'line'], 'lines': [ ['rdb_changes_since_last_save', 'changes', 'absolute'] + ]}, + 'bgsave_now': { + 'options': [None, 'Duration of the RDB Save Operation', 'seconds', 'persistence', + 'redis.bgsave_now', 'absolute'], + 'lines': [ + ['rdb_bgsave_in_progress', 'rdb save', 'absolute'] + ]}, + 'bgsave_health': { + 'options': [None, 'Status of the Last RDB Save Operation', 'status', 'persistence', + 'redis.bgsave_health', 'line'], + 'lines': [ + ['rdb_last_bgsave_status', 'rdb save', 'absolute'] ]} } @@ -87,6 +99,7 @@ class Service(SocketService): self.port = self.configuration.get('port', 6379) self.unix_socket = self.configuration.get('socket') password = self.configuration.get('pass', str()) + self.bgsave_time = 0 self.requests = dict(request='INFO\r\n'.encode(), password=' '.join(['AUTH', password, '\r\n']).encode() if password else None) self.request = self.requests['request'] @@ -130,9 +143,8 @@ class Service(SocketService): data[t[0]] = t[1] except (IndexError, ValueError): self.debug("invalid line received: " + str(line)) - pass - if len(data) == 0: + if not data: self.error("received data doesn't have any records") return None @@ -142,6 +154,14 @@ class Service(SocketService): except (KeyError, ZeroDivisionError, TypeError): data['hit_rate'] = 0 + if data['rdb_bgsave_in_progress'] != '0\r': + self.bgsave_time += self.update_every + else: + self.bgsave_time = 0 + + data['rdb_last_bgsave_status'] = 0 if data['rdb_last_bgsave_status'] == 'ok\r' else 1 + data['rdb_bgsave_in_progress'] = self.bgsave_time + return data def _check_raw_data(self, data): @@ -170,9 +190,6 @@ class Service(SocketService): Parse configuration, check if redis is available, and dynamically create chart lines data :return: boolean """ - if self.name == "": - self.name = "local" - self.chart_name += "_" + self.name data = self._get_data() if data is None: return False diff --git a/python.d/retroshare.chart.py b/python.d/retroshare.chart.py index 0c97973f..8c0330ec 100644 --- a/python.d/retroshare.chart.py +++ b/python.d/retroshare.chart.py @@ -2,9 +2,10 @@ # Description: RetroShare netdata python.d module # Authors: sehraf -from base import UrlService import json +from bases.FrameworkServices.UrlService import UrlService + # default module values (can be overridden per job in `config`) # update_every = 2 priority = 60000 @@ -38,10 +39,7 @@ CHARTS = { class Service(UrlService): def __init__(self, configuration=None, name=None): UrlService.__init__(self, configuration=configuration, name=name) - try: - self.baseurl = str(self.configuration['url']) - except (KeyError, TypeError): - self.baseurl = 'http://localhost:9090' + self.baseurl = self.configuration.get('url', 'http://localhost:9090') self.order = ORDER self.definitions = CHARTS @@ -55,7 +53,7 @@ class Service(UrlService): parsed = json.loads(raw) if str(parsed['returncode']) != 'ok': return None - except: + except (TypeError, ValueError): return None return parsed['data'][0] diff --git a/python.d/samba.chart.py b/python.d/samba.chart.py index 767c9746..3f4fd5a1 100644 --- a/python.d/samba.chart.py +++ b/python.d/samba.chart.py @@ -15,9 +15,11 @@ # a lot there, bring one or more out into its own chart and make it incremental # (like find and notify... good examples). -from base import ExecutableService import re +from bases.collection import find_binary +from bases.FrameworkServices.ExecutableService import ExecutableService + # default module values (can be overridden per job in `config`) update_every = 5 priority = 60000 @@ -94,10 +96,10 @@ class Service(ExecutableService): self.rgx_smb2 = re.compile(r'(smb2_[^:]+|syscall_.*file_bytes):\s+(\d+)') def check(self): - sudo_binary, smbstatus_binary = self.find_binary('sudo'), self.find_binary('smbstatus') + sudo_binary, smbstatus_binary = find_binary('sudo'), find_binary('smbstatus') if not (sudo_binary and smbstatus_binary): - self.error('Can\'t locate \'sudo\' or \'smbstatus\' binary') + self.error("Can\'t locate 'sudo' or 'smbstatus' binary") return False self.command = [sudo_binary, '-v'] diff --git a/python.d/sensors.chart.py b/python.d/sensors.chart.py index e83aacfd..06e420b6 100644 --- a/python.d/sensors.chart.py +++ b/python.d/sensors.chart.py @@ -2,8 +2,8 @@ # Description: sensors netdata python.d plugin # Author: Pawel Krupa (paulfantom) -from base import SimpleService -import lm_sensors as sensors +from bases.FrameworkServices.SimpleService import SimpleService +from third_party import lm_sensors as sensors # default module values (can be overridden per job in `config`) # update_every = 2 @@ -75,15 +75,12 @@ TYPE_MAP = { class Service(SimpleService): def __init__(self, configuration=None, name=None): SimpleService.__init__(self, configuration=configuration, name=name) - self.order = [] - self.definitions = {} - self.celsius = ('Celsius', lambda x: x) - self.fahrenheit = ('Fahrenheit', lambda x: x * 9 / 5 + 32) if self.configuration.get('fahrenheit') else False - self.choice = (choice for choice in [self.fahrenheit, self.celsius] if choice) - self.chips = [] + self.order = list() + self.definitions = dict() + self.chips = list() - def _get_data(self): - data = {} + def get_data(self): + data = dict() try: for chip in sensors.ChipIterator(): prefix = sensors.chip_snprintf_name(chip) @@ -92,46 +89,39 @@ class Service(SimpleService): for sf in sfi: val = sensors.get_value(chip, sf.number) break - typeName = TYPE_MAP[feature.type] - if typeName in LIMITS: - limit = LIMITS[typeName]; + type_name = TYPE_MAP[feature.type] + if type_name in LIMITS: + limit = LIMITS[type_name] if val < limit[0] or val > limit[1]: continue - if 'temp' in str(feature.name.decode()): - data[prefix + "_" + str(feature.name.decode())] = int(self.calc(val) * 1000) - else: data[prefix + "_" + str(feature.name.decode())] = int(val * 1000) - except Exception as e: - self.error(e) + except Exception as error: + self.error(error) return None - if len(data) == 0: - return None - return data + return data or None - def _create_definitions(self): - for type in ORDER: + def create_definitions(self): + for sensor in ORDER: for chip in sensors.ChipIterator(): chip_name = sensors.chip_snprintf_name(chip) - if len(self.chips) != 0 and not any([chip_name.startswith(ex) for ex in self.chips]): + if self.chips and not any([chip_name.startswith(ex) for ex in self.chips]): continue for feature in sensors.FeatureIterator(chip): sfi = sensors.SubFeatureIterator(chip, feature) vals = [sensors.get_value(chip, sf.number) for sf in sfi] if vals[0] == 0: continue - if TYPE_MAP[feature.type] == type: + if TYPE_MAP[feature.type] == sensor: # create chart name = chip_name + "_" + TYPE_MAP[feature.type] if name not in self.order: self.order.append(name) - chart_def = list(CHARTS[type]['options']) + chart_def = list(CHARTS[sensor]['options']) chart_def[1] = chip_name + chart_def[1] - if chart_def[2] == 'Celsius': - chart_def[2] = self.choice[0] self.definitions[name] = {'options': chart_def} self.definitions[name]['lines'] = [] - line = list(CHARTS[type]['lines'][0]) + line = list(CHARTS[sensor]['lines'][0]) line[0] = chip_name + "_" + str(feature.name.decode()) line[1] = sensors.get_label(chip, feature) self.definitions[name]['lines'].append(line) @@ -139,23 +129,11 @@ class Service(SimpleService): def check(self): try: sensors.init() - except Exception as e: - self.error(e) + except Exception as error: + self.error(error) return False - - try: - self.choice = next(self.choice) - except StopIteration: - # That can not happen but.. - self.choice = ('Celsius', lambda x: x) - self.calc = self.choice[1] - else: - self.calc = self.choice[1] - try: - self._create_definitions() - except Exception as e: - self.error(e) - return False + self.create_definitions() return True + diff --git a/python.d/smartd_log.chart.py b/python.d/smartd_log.chart.py index 4039c153..07ad88cd 100644 --- a/python.d/smartd_log.chart.py +++ b/python.d/smartd_log.chart.py @@ -2,221 +2,345 @@ # Description: smart netdata python.d module # Author: l2isbad, vorph1 -from re import compile as r_compile -from os import listdir, access, R_OK -from os.path import isfile, join, getsize, basename, isdir -try: - from queue import Queue -except ImportError: - from Queue import Queue -from threading import Thread -from base import SimpleService +import os +import re + from collections import namedtuple +from time import time -# default module values (can be overridden per job in `config`) -update_every = 5 -priority = 60000 +from bases.collection import read_last_line +from bases.FrameworkServices.SimpleService import SimpleService # charts order (can be overridden if you want less charts, or different order) ORDER = ['1', '4', '5', '7', '9', '12', '193', '194', '197', '198', '200'] SMART_ATTR = { - '1': 'Read Error Rate', - '2': 'Throughput Performance', - '3': 'Spin-Up Time', - '4': 'Start/Stop Count', - '5': 'Reallocated Sectors Count', - '6': 'Read Channel Margin', - '7': 'Seek Error Rate', - '8': 'Seek Time Performance', - '9': 'Power-On Hours Count', - '10': 'Spin-up Retries', - '11': 'Calibration Retries', - '12': 'Power Cycle Count', - '13': 'Soft Read Error Rate', - '100': 'Erase/Program Cycles', - '103': 'Translation Table Rebuild', - '108': 'Unknown (108)', - '170': 'Reserved Block Count', - '171': 'Program Fail Count', - '172': 'Erase Fail Count', - '173': 'Wear Leveller Worst Case Erase Count', - '174': 'Unexpected Power Loss', - '175': 'Program Fail Count', - '176': 'Erase Fail Count', - '177': 'Wear Leveling Count', - '178': 'Used Reserved Block Count', - '179': 'Used Reserved Block Count', - '180': 'Unused Reserved Block Count', - '181': 'Program Fail Count', - '182': 'Erase Fail Count', - '183': 'SATA Downshifts', - '184': 'End-to-End error', - '185': 'Head Stability', - '186': 'Induced Op-Vibration Detection', - '187': 'Reported Uncorrectable Errors', - '188': 'Command Timeout', - '189': 'High Fly Writes', - '190': 'Temperature', - '191': 'G-Sense Errors', - '192': 'Power-Off Retract Cycles', - '193': 'Load/Unload Cycles', - '194': 'Temperature', - '195': 'Hardware ECC Recovered', - '196': 'Reallocation Events', - '197': 'Current Pending Sectors', - '198': 'Off-line Uncorrectable', - '199': 'UDMA CRC Error Rate', - '200': 'Write Error Rate', - '201': 'Soft Read Errors', - '202': 'Data Address Mark Errors', - '203': 'Run Out Cancel', - '204': 'Soft ECC Corrections', - '205': 'Thermal Asperity Rate', - '206': 'Flying Height', - '207': 'Spin High Current', - '209': 'Offline Seek Performance', - '220': 'Disk Shift', - '221': 'G-Sense Error Rate', - '222': 'Loaded Hours', - '223': 'Load/Unload Retries', - '224': 'Load Friction', - '225': 'Load/Unload Cycles', - '226': 'Load-in Time', - '227': 'Torque Amplification Count', - '228': 'Power-Off Retracts', - '230': 'GMR Head Amplitude', - '231': 'Temperature', - '232': 'Available Reserved Space', - '233': 'Media Wearout Indicator', - '240': 'Head Flying Hours', - '241': 'Total LBAs Written', - '242': 'Total LBAs Read', - '250': 'Read Error Retry Rate' + '1': 'Read Error Rate', + '2': 'Throughput Performance', + '3': 'Spin-Up Time', + '4': 'Start/Stop Count', + '5': 'Reallocated Sectors Count', + '6': 'Read Channel Margin', + '7': 'Seek Error Rate', + '8': 'Seek Time Performance', + '9': 'Power-On Hours Count', + '10': 'Spin-up Retries', + '11': 'Calibration Retries', + '12': 'Power Cycle Count', + '13': 'Soft Read Error Rate', + '100': 'Erase/Program Cycles', + '103': 'Translation Table Rebuild', + '108': 'Unknown (108)', + '170': 'Reserved Block Count', + '171': 'Program Fail Count', + '172': 'Erase Fail Count', + '173': 'Wear Leveller Worst Case Erase Count', + '174': 'Unexpected Power Loss', + '175': 'Program Fail Count', + '176': 'Erase Fail Count', + '177': 'Wear Leveling Count', + '178': 'Used Reserved Block Count', + '179': 'Used Reserved Block Count', + '180': 'Unused Reserved Block Count', + '181': 'Program Fail Count', + '182': 'Erase Fail Count', + '183': 'SATA Downshifts', + '184': 'End-to-End error', + '185': 'Head Stability', + '186': 'Induced Op-Vibration Detection', + '187': 'Reported Uncorrectable Errors', + '188': 'Command Timeout', + '189': 'High Fly Writes', + '190': 'Temperature', + '191': 'G-Sense Errors', + '192': 'Power-Off Retract Cycles', + '193': 'Load/Unload Cycles', + '194': 'Temperature', + '195': 'Hardware ECC Recovered', + '196': 'Reallocation Events', + '197': 'Current Pending Sectors', + '198': 'Off-line Uncorrectable', + '199': 'UDMA CRC Error Rate', + '200': 'Write Error Rate', + '201': 'Soft Read Errors', + '202': 'Data Address Mark Errors', + '203': 'Run Out Cancel', + '204': 'Soft ECC Corrections', + '205': 'Thermal Asperity Rate', + '206': 'Flying Height', + '207': 'Spin High Current', + '209': 'Offline Seek Performance', + '220': 'Disk Shift', + '221': 'G-Sense Error Rate', + '222': 'Loaded Hours', + '223': 'Load/Unload Retries', + '224': 'Load Friction', + '225': 'Load/Unload Cycles', + '226': 'Load-in Time', + '227': 'Torque Amplification Count', + '228': 'Power-Off Retracts', + '230': 'GMR Head Amplitude', + '231': 'Temperature', + '232': 'Available Reserved Space', + '233': 'Media Wearout Indicator', + '240': 'Head Flying Hours', + '241': 'Total LBAs Written', + '242': 'Total LBAs Read', + '250': 'Read Error Retry Rate' +} + +LIMIT = namedtuple('LIMIT', ['min', 'max']) + +LIMITS = { + '194': LIMIT(0, 200) } -NAMED_DISKS = namedtuple('disks', ['name', 'size', 'number']) +RESCAN_INTERVAL = 60 + +REGEX = re.compile( + '(\d+);' # attribute + '(\d+);' # normalized value + '(\d+)', # raw value + re.X +) + + +def chart_template(chart_name): + units, attr_id = chart_name.split('_')[-2:] + title = '{value_type} {description}'.format(value_type=units.capitalize(), + description=SMART_ATTR[attr_id]) + family = SMART_ATTR[attr_id].lower() + + return { + chart_name: { + 'options': [None, title, units, family, 'smartd_log.' + chart_name, 'line'], + 'lines': [] + } + } + + +def handle_os_error(method): + def on_call(*args): + try: + return method(*args) + except OSError: + return None + return on_call + + +class SmartAttribute(object): + def __init__(self, idx, normalized, raw): + self.id = idx + self.normalized = normalized + self._raw = raw + + @property + def raw(self): + if self.id in LIMITS: + limit = LIMITS[self.id] + if limit.min <= int(self._raw) <= limit.max: + return self._raw + return None + return self._raw + + @raw.setter + def raw(self, value): + self._raw = value + + +class DiskLogFile: + def __init__(self, path): + self.path = path + self.size = os.path.getsize(path) + + @handle_os_error + def is_changed(self): + new_size = os.path.getsize(self.path) + old_size, self.size = self.size, new_size + + return new_size != old_size and new_size + + @staticmethod + @handle_os_error + def is_valid(log_file, exclude): + return all([log_file.endswith('.csv'), + not [p for p in exclude if p in log_file], + os.access(log_file, os.R_OK), + os.path.getsize(log_file)]) + + +class Disk: + def __init__(self, full_path, age): + self.log_file = DiskLogFile(full_path) + self.name = os.path.basename(full_path).split('.')[-3] + self.age = int(age) + self.status = True + self.attributes = dict() + + self.get_attributes() + + def __eq__(self, other): + if isinstance(other, Disk): + return self.name == other.name + return self.name == other + + @handle_os_error + def is_active(self): + return (time() - os.path.getmtime(self.log_file.path)) / 60 < self.age + + @handle_os_error + def get_attributes(self): + last_line = read_last_line(self.log_file.path) + self.attributes = dict((attr, SmartAttribute(attr, normalized, raw)) for attr, normalized, raw + in REGEX.findall(last_line)) + return True + + def data(self): + data = dict() + for attr in self.attributes.values(): + data['_'.join([self.name, 'normalized', attr.id])] = attr.normalized + if attr.raw is not None: + data['_'.join([self.name, 'raw', attr.id])] = attr.raw + return data class Service(SimpleService): def __init__(self, configuration=None, name=None): SimpleService.__init__(self, configuration=configuration, name=name) - self.regex = r_compile(r'(\d+);(\d+);(\d+)') self.log_path = self.configuration.get('log_path', '/var/log/smartd') - self.raw_values = self.configuration.get('raw_values') - self.attr = self.configuration.get('smart_attributes', []) - self.previous_data = dict() + self.raw = self.configuration.get('raw_values', True) + self.exclude = self.configuration.get('exclude_disks', str()).split() + self.age = self.configuration.get('age', 30) + + self.runs = 0 + self.disks = list() + self.order = list() + self.definitions = dict() def check(self): - # Can\'t start without smartd readable diks log files - disks = find_disks_in_log_path(self.log_path) - if not disks: - self.error('Can\'t locate any smartd log files in %s' % self.log_path) - return False - - # List of namedtuples to track smartd log file size - self.disks = [NAMED_DISKS(name=disks[i], size=0, number=i) for i in range(len(disks))] - - if self._get_data(): - self.create_charts() - return True - else: - self.error('Can\'t collect any data. Sorry.') - return False - - def _get_raw_data(self, queue, disk): - # The idea is to open a file. - # Jump to the end. - # Seek backward until '\n' symbol appears - # If '\n' is found or it's the beginning of the file - # readline()! (last or first line) - with open(disk, 'rb') as f: - f.seek(-2, 2) - while f.read(1) != b'\n': - f.seek(-2, 1) - if f.tell() == 0: - break - result = f.readline() - - result = result.decode() - result = self.regex.findall(result) - - queue.put([basename(disk), result]) - - def _get_data(self): - threads, result = list(), list() - queue = Queue() - to_netdata = dict() - - # If the size has not changed there is no reason to poll log files. - disks = [disk for disk in self.disks if self.size_changed(disk)] - if disks: - for disk in disks: - th = Thread(target=self._get_raw_data, args=(queue, disk.name)) - th.start() - threads.append(th) - - for thread in threads: - thread.join() - result.append(queue.get()) + self.disks = self.scan() + + if not self.disks: + return None + + user_defined_sa = self.configuration.get('smart_attributes') + + if user_defined_sa: + order = user_defined_sa.split() or ORDER else: - # Data from last real poll - return self.previous_data or None + order = ORDER - for elem in result: - for a, n, r in elem[1]: - to_netdata.update({'_'.join([elem[0], a]): r if self.raw_values else n}) + self.create_charts(order) - self.previous_data.update(to_netdata) + return True - return to_netdata or None + def get_data(self): + self.runs += 1 - def size_changed(self, disk): - # We are not interested in log files: - # 1. zero size - # 2. size is not changed since last poll - try: - size = getsize(disk.name) - if size != disk.size and size: - self.disks[disk.number] = disk._replace(size=size) - return True - else: - return False - except OSError: - # Remove unreadable/nonexisting log files from list of disks and previous_data - self.disks.remove(disk) - self.previous_data = dict([(k, v) for k, v in self.previous_data.items() if basename(disk.name) not in k]) - return False + if self.runs % RESCAN_INTERVAL == 0: + self.cleanup_and_rescan() + + data = dict() + + for disk in self.disks: + + if not disk.status: + continue + + changed = disk.log_file.is_changed() + + # True = changed, False = unchanged, None = Exception + if changed is None: + disk.status = False + continue + + if changed: + success = disk.get_attributes() + if not success: + disk.status = False + continue + + data.update(disk.data()) + + return data or None - def create_charts(self): + def create_charts(self, order): + for attr in order: + raw_name, normalized_name = 'attr_id_raw_' + attr, 'attr_id_normalized_' + attr + raw, normalized = chart_template(raw_name), chart_template(normalized_name) + self.order.extend([normalized_name, raw_name]) + self.definitions.update(raw) + self.definitions.update(normalized) - def create_lines(attrid): - result = list() for disk in self.disks: - name = basename(disk.name) - result.append(['_'.join([name, attrid]), name[:name.index('.')], 'absolute']) - return result + if attr not in disk.attributes: + self.debug("'{disk}' has no attribute '{attr_id}'".format(disk=disk.name, + attr_id=attr)) + continue + normalized[normalized_name]['lines'].append(['_'.join([disk.name, 'normalized', attr]), disk.name]) - # Use configured attributes, if present. If something goes wrong we don't care. - order = ORDER - try: - order = [attr for attr in self.attr.split() if attr in SMART_ATTR.keys()] or ORDER - except Exception: - pass - self.order = [''.join(['attrid', i]) for i in order] - self.definitions = dict() - units = 'raw' if self.raw_values else 'normalized' - - for k, v in dict([(k, v) for k, v in SMART_ATTR.items() if k in ORDER]).items(): - self.definitions.update({''.join(['attrid', k]): { - 'options': [None, v, units, v.lower(), 'smartd.attrid' + k, 'line'], - 'lines': create_lines(k)}}) - -def find_disks_in_log_path(log_path): - # smartd log file is OK if: - # 1. it is a file - # 2. file name endswith with 'csv' - # 3. file is readable - if not isdir(log_path): return None - return [join(log_path, f) for f in listdir(log_path) - if all([isfile(join(log_path, f)), f.endswith('.csv'), access(join(log_path, f), R_OK)])] + if not self.raw: + continue + + if disk.attributes[attr].raw is not None: + raw[raw_name]['lines'].append(['_'.join([disk.name, 'raw', attr]), disk.name]) + continue + self.debug("'{disk}' attribute '{attr_id}' value not in {limits}".format(disk=disk.name, + attr_id=attr, + limits=LIMITS[attr])) + + def cleanup_and_rescan(self): + self.cleanup() + new_disks = self.scan(only_new=True) + + for disk in new_disks: + valid = False + + for chart in self.charts: + value_type, idx = chart.id.split('_')[2:] + + if idx in disk.attributes: + valid = True + dimension_id = '_'.join([disk.name, value_type, idx]) + + if dimension_id in chart: + chart.hide_dimension(dimension_id=dimension_id, reverse=True) + else: + chart.add_dimension([dimension_id, disk.name]) + if valid: + self.disks.append(disk) + + def cleanup(self): + for disk in self.disks: + + if not disk.is_active(): + disk.status = False + if not disk.status: + for chart in self.charts: + dimension_id = '_'.join([disk.name, chart.id[8:]]) + chart.hide_dimension(dimension_id=dimension_id) + + self.disks = [disk for disk in self.disks if disk.status] + + def scan(self, only_new=None): + new_disks = list() + for f in os.listdir(self.log_path): + full_path = os.path.join(self.log_path, f) + + if DiskLogFile.is_valid(full_path, self.exclude): + disk = Disk(full_path, self.age) + + active = disk.is_active() + if active is None: + continue + if active: + if not only_new: + new_disks.append(disk) + else: + if disk not in self.disks: + new_disks.append(disk) + else: + if not only_new: + self.debug("'{disk}' not updated in the last {age} minutes, " + "skipping it.".format(disk=disk.name, age=self.age)) + return new_disks diff --git a/python.d/squid.chart.py b/python.d/squid.chart.py index e9e8f1d0..ba8f982f 100644 --- a/python.d/squid.chart.py +++ b/python.d/squid.chart.py @@ -2,8 +2,8 @@ # Description: squid netdata python.d module # Author: Pawel Krupa (paulfantom) -from base import SocketService -import select +from bases.FrameworkServices.SocketService import SocketService + # default module values (can be overridden per job in `config`) # update_every = 2 @@ -60,7 +60,7 @@ class Service(SocketService): """ response = self._get_raw_data() - data = {} + data = dict() try: raw = "" for tmp in response.split('\r\n'): @@ -81,11 +81,10 @@ class Service(SocketService): self.error("invalid data received") return None - if len(data) == 0: + if not data: self.error("no data received") return None - else: - return data + return data def _check_raw_data(self, data): header = data[:1024].lower() diff --git a/python.d/tomcat.chart.py b/python.d/tomcat.chart.py index 05547236..a570d564 100644 --- a/python.d/tomcat.chart.py +++ b/python.d/tomcat.chart.py @@ -2,9 +2,10 @@ # Description: tomcat netdata python.d module # Author: Pawel Krupa (paulfantom) -from base import UrlService import xml.etree.ElementTree as ET +from bases.FrameworkServices.UrlService import UrlService + # default module values (can be overridden per job in `config`) # update_every = 2 priority = 60000 @@ -71,6 +72,7 @@ CHARTS = { ]}, } + class Service(UrlService): def __init__(self, configuration=None, name=None): UrlService.__init__(self, configuration=configuration, name=name) @@ -87,7 +89,6 @@ class Service(UrlService): data = None raw_data = self._get_raw_data() if raw_data: - xml = None try: xml = ET.fromstring(raw_data) except ET.ParseError: @@ -100,27 +101,27 @@ class Service(UrlService): connector = None if self.connector_name: for conn in xml.findall('connector'): - if conn.get('name') == self.connector_name: + if self.connector_name in conn.get('name'): connector = conn break else: connector = xml.find('connector') memory = jvm.find('memory') - data['free'] = memory.get('free') + data['free'] = memory.get('free') data['total'] = memory.get('total') for pool in jvm.findall('memorypool'): name = pool.get('name') - if name == 'Eden Space': + if 'Eden Space' in name: data['eden_used'] = pool.get('usageUsed') data['eden_commited'] = pool.get('usageCommitted') data['eden_max'] = pool.get('usageMax') - elif name == 'Survivor Space': + elif 'Survivor Space' in name: data['survivor_used'] = pool.get('usageUsed') data['survivor_commited'] = pool.get('usageCommitted') data['survivor_max'] = pool.get('usageMax') - elif name == 'Tenured Gen': + elif 'Tenured Gen' in name or 'Old Gen' in name: data['tenured_used'] = pool.get('usageUsed') data['tenured_commited'] = pool.get('usageCommitted') data['tenured_max'] = pool.get('usageMax') diff --git a/python.d/varnish.chart.py b/python.d/varnish.chart.py index 2665bb38..d8145c0b 100644 --- a/python.d/varnish.chart.py +++ b/python.d/varnish.chart.py @@ -2,230 +2,240 @@ # Description: varnish netdata python.d module # Author: l2isbad -from base import SimpleService -from re import compile -from subprocess import Popen, PIPE +import re + +from bases.collection import find_binary +from bases.FrameworkServices.ExecutableService import ExecutableService # default module values (can be overridden per job in `config`) # update_every = 2 priority = 60000 retries = 60 -ORDER = ['session', 'hit_rate', 'chit_rate', 'expunge', 'threads', 'backend_health', 'memory_usage', 'bad', 'uptime'] - -CHARTS = {'backend_health': - {'lines': [['backend_conn', 'conn', 'incremental', 1, 1], - ['backend_unhealthy', 'unhealthy', 'incremental', 1, 1], - ['backend_busy', 'busy', 'incremental', 1, 1], - ['backend_fail', 'fail', 'incremental', 1, 1], - ['backend_reuse', 'reuse', 'incremental', 1, 1], - ['backend_recycle', 'resycle', 'incremental', 1, 1], - ['backend_toolate', 'toolate', 'incremental', 1, 1], - ['backend_retry', 'retry', 'incremental', 1, 1], - ['backend_req', 'req', 'incremental', 1, 1]], - 'options': [None, 'Backend health', 'connections', 'Backend health', 'varnish.backend_traf', 'line']}, - 'bad': - {'lines': [['sess_drop_b', None, 'incremental', 1, 1], - ['backend_unhealthy_b', None, 'incremental', 1, 1], - ['fetch_failed', None, 'incremental', 1, 1], - ['backend_busy_b', None, 'incremental', 1, 1], - ['threads_failed_b', None, 'incremental', 1, 1], - ['threads_limited_b', None, 'incremental', 1, 1], - ['threads_destroyed_b', None, 'incremental', 1, 1], - ['thread_queue_len_b', 'queue_len', 'absolute', 1, 1], - ['losthdr_b', None, 'incremental', 1, 1], - ['esi_errors_b', None, 'incremental', 1, 1], - ['esi_warnings_b', None, 'incremental', 1, 1], - ['sess_fail_b', None, 'incremental', 1, 1], - ['sc_pipe_overflow_b', None, 'incremental', 1, 1], - ['sess_pipe_overflow_b', None, 'incremental', 1, 1]], - 'options': [None, 'Misbehavior', 'problems', 'Problems summary', 'varnish.bad', 'line']}, - 'expunge': - {'lines': [['n_expired', 'expired', 'incremental', 1, 1], - ['n_lru_nuked', 'lru_nuked', 'incremental', 1, 1]], - 'options': [None, 'Object expunging', 'objects', 'Cache performance', 'varnish.expunge', 'line']}, - 'hit_rate': - {'lines': [['cache_hit_perc', 'hit', 'absolute', 1, 100], - ['cache_miss_perc', 'miss', 'absolute', 1, 100], - ['cache_hitpass_perc', 'hitpass', 'absolute', 1, 100]], - 'options': [None, 'All history hit rate ratio','percent', 'Cache performance', 'varnish.hit_rate', 'stacked']}, - 'chit_rate': - {'lines': [['cache_hit_cperc', 'hit', 'absolute', 1, 100], - ['cache_miss_cperc', 'miss', 'absolute', 1, 100], - ['cache_hitpass_cperc', 'hitpass', 'absolute', 1, 100]], - 'options': [None, 'Current poll hit rate ratio','percent', 'Cache performance', 'varnish.chit_rate', 'stacked']}, - 'memory_usage': - {'lines': [['s0.g_space', 'available', 'absolute', 1, 1048576], - ['s0.g_bytes', 'allocated', 'absolute', -1, 1048576]], - 'options': [None, 'Memory usage', 'megabytes', 'Memory usage', 'varnish.memory_usage', 'stacked']}, - 'session': - {'lines': [['sess_conn', 'sess_conn', 'incremental', 1, 1], - ['client_req', 'client_requests', 'incremental', 1, 1], - ['client_conn', 'client_conn', 'incremental', 1, 1], - ['client_drop', 'client_drop', 'incremental', 1, 1], - ['sess_dropped', 'sess_dropped', 'incremental', 1, 1]], - 'options': [None, 'Sessions', 'units', 'Client metrics', 'varnish.session', 'line']}, - 'threads': - {'lines': [['threads', None, 'absolute', 1, 1], - ['threads_created', 'created', 'incremental', 1, 1], - ['threads_failed', 'failed', 'incremental', 1, 1], - ['threads_limited', 'limited', 'incremental', 1, 1], - ['thread_queue_len', 'queue_len', 'incremental', 1, 1], - ['sess_queued', 'sess_queued', 'incremental', 1, 1]], - 'options': [None, 'Thread status', 'threads', 'Thread-related metrics', 'varnish.threads', 'line']}, - 'uptime': - {'lines': [['uptime', None, 'absolute', 1, 1]], - 'options': [None, 'Varnish uptime', 'seconds', 'Uptime', 'varnish.uptime', 'line']} +ORDER = ['session_connections', 'client_requests', + 'all_time_hit_rate', 'current_poll_hit_rate', 'cached_objects_expired', 'cached_objects_nuked', + 'threads_total', 'threads_statistics', 'threads_queue_len', + 'backend_connections', 'backend_requests', + 'esi_statistics', + 'memory_usage', + 'uptime'] + +CHARTS = { + 'session_connections': { + 'options': [None, 'Connections Statistics', 'connections/s', + 'client metrics', 'varnish.session_connection', 'line'], + 'lines': [ + ['sess_conn', 'accepted', 'incremental'], + ['sess_dropped', 'dropped', 'incremental'] + ] + }, + 'client_requests': { + 'options': [None, 'Client Requests', 'requests/s', + 'client metrics', 'varnish.client_requests', 'line'], + 'lines': [ + ['client_req', 'received', 'incremental'] + ] + }, + 'all_time_hit_rate': { + 'options': [None, 'All History Hit Rate Ratio', 'percent', 'cache performance', + 'varnish.all_time_hit_rate', 'stacked'], + 'lines': [ + ['cache_hit', 'hit', 'percentage-of-absolute-row'], + ['cache_miss', 'miss', 'percentage-of-absolute-row'], + ['cache_hitpass', 'hitpass', 'percentage-of-absolute-row']] + }, + 'current_poll_hit_rate': { + 'options': [None, 'Current Poll Hit Rate Ratio', 'percent', 'cache performance', + 'varnish.current_poll_hit_rate', 'stacked'], + 'lines': [ + ['cache_hit', 'hit', 'percentage-of-incremental-row'], + ['cache_miss', 'miss', 'percentage-of-incremental-row'], + ['cache_hitpass', 'hitpass', 'percentage-of-incremental-row'] + ] + }, + 'cached_objects_expired': { + 'options': [None, 'Expired Objects', 'expired/s', 'cache performance', + 'varnish.cached_objects_expired', 'line'], + 'lines': [ + ['n_expired', 'objects', 'incremental'] + ] + }, + 'cached_objects_nuked': { + 'options': [None, 'Least Recently Used Nuked Objects', 'nuked/s', 'cache performance', + 'varnish.cached_objects_nuked', 'line'], + 'lines': [ + ['n_lru_nuked', 'objects', 'incremental'] + ] + }, + 'threads_total': { + 'options': [None, 'Number Of Threads In All Pools', 'number', 'thread related metrics', + 'varnish.threads_total', 'line'], + 'lines': [ + ['threads', None, 'absolute'] + ] + }, + 'threads_statistics': { + 'options': [None, 'Threads Statistics', 'threads/s', 'thread related metrics', + 'varnish.threads_statistics', 'line'], + 'lines': [ + ['threads_created', 'created', 'incremental'], + ['threads_failed', 'failed', 'incremental'], + ['threads_limited', 'limited', 'incremental'] + ] + }, + 'threads_queue_len': { + 'options': [None, 'Current Queue Length', 'requests', 'thread related metrics', + 'varnish.threads_queue_len', 'line'], + 'lines': [ + ['thread_queue_len', 'in queue'] + ] + }, + 'backend_connections': { + 'options': [None, 'Backend Connections Statistics', 'connections/s', 'backend metrics', + 'varnish.backend_connections', 'line'], + 'lines': [ + ['backend_conn', 'successful', 'incremental'], + ['backend_unhealthy', 'unhealthy', 'incremental'], + ['backend_reuse', 'reused', 'incremental'], + ['backend_toolate', 'closed', 'incremental'], + ['backend_recycle', 'resycled', 'incremental'], + ['backend_fail', 'failed', 'incremental'] + ] + }, + 'backend_requests': { + 'options': [None, 'Requests To The Backend', 'requests/s', 'backend metrics', + 'varnish.backend_requests', 'line'], + 'lines': [ + ['backend_req', 'sent', 'incremental'] + ] + }, + 'esi_statistics': { + 'options': [None, 'ESI Statistics', 'problems/s', 'esi related metrics', 'varnish.esi_statistics', 'line'], + 'lines': [ + ['esi_errors', 'errors', 'incremental'], + ['esi_warnings', 'warnings', 'incremental'] + ] + }, + 'memory_usage': { + 'options': [None, 'Memory Usage', 'MB', 'memory usage', 'varnish.memory_usage', 'stacked'], + 'lines': [ + ['memory_free', 'free', 'absolute', 1, 1 << 20], + ['memory_allocated', 'allocated', 'absolute', 1, 1 << 20]] + }, + 'uptime': { + 'lines': [ + ['uptime', None, 'absolute'] + ], + 'options': [None, 'Uptime', 'seconds', 'uptime', 'varnish.uptime', 'line'] + } } -class Service(SimpleService): +class Parser: + _backend_new = re.compile(r'VBE.([\d\w_.]+)\(.*?\).(beresp[\w_]+)\s+(\d+)') + _backend_old = re.compile(r'VBE\.[\d\w-]+\.([\w\d_]+).(beresp[\w_]+)\s+(\d+)') + _default = re.compile(r'([A-Z]+\.)?([\d\w_.]+)\s+(\d+)') + + def __init__(self): + self.re_default = None + self.re_backend = None + + def init(self, data): + data = ''.join(data) + parsed_main = Parser._default.findall(data) + if parsed_main: + self.re_default = Parser._default + + parsed_backend = Parser._backend_new.findall(data) + if parsed_backend: + self.re_backend = Parser._backend_new + else: + parsed_backend = Parser._backend_old.findall(data) + if parsed_backend: + self.re_backend = Parser._backend_old + + def server_stats(self, data): + return self.re_default.findall(''.join(data)) + + def backend_stats(self, data): + return self.re_backend.findall(''.join(data)) + + +class Service(ExecutableService): def __init__(self, configuration=None, name=None): - SimpleService.__init__(self, configuration=configuration, name=name) - self.varnish = self.find_binary('varnishstat') - self.rgx_all = compile(r'([A-Z]+\.)?([\d\w_.]+)\s+(\d+)') - # Could be - # VBE.boot.super_backend.pipe_hdrbyte (new) - # or - # VBE.default2(127.0.0.2,,81).bereq_bodybytes (old) - # Regex result: [('super_backend', 'beresp_hdrbytes', '0'), ('super_backend', 'beresp_bodybytes', '0')] - self.rgx_bck = (compile(r'VBE.([\d\w_.]+)\(.*?\).(beresp[\w_]+)\s+(\d+)'), - compile(r'VBE\.[\d\w-]+\.([\w\d_]+).(beresp[\w_]+)\s+(\d+)')) - self.cache_prev = list() + ExecutableService.__init__(self, configuration=configuration, name=name) + self.order = ORDER + self.definitions = CHARTS + varnishstat = find_binary('varnishstat') + self.command = [varnishstat, '-1'] if varnishstat else None + self.parser = Parser() def check(self): - # Cant start without 'varnishstat' command - if not self.varnish: - self.error('Can\'t locate \'varnishstat\' binary or binary is not executable by netdata') + if not self.command: + self.error("Can't locate 'varnishstat' binary or binary is not executable by user netdata") return False - # If command is present and we can execute it we need to make sure.. - # 1. STDOUT is not empty + # STDOUT is not empty reply = self._get_raw_data() if not reply: - self.error('No output from \'varnishstat\' (not enough privileges?)') - return False - - # 2. Output is parsable (list is not empty after regex findall) - is_parsable = self.rgx_all.findall(reply) - if not is_parsable: - self.error('Cant parse output...') + self.error("No output from 'varnishstat'. Not enough privileges?") return False - # We need to find the right regex for backend parse - self.backend_list = self.rgx_bck[0].findall(reply)[::2] - if self.backend_list: - self.rgx_bck = self.rgx_bck[0] - else: - self.backend_list = self.rgx_bck[1].findall(reply)[::2] - self.rgx_bck = self.rgx_bck[1] + self.parser.init(reply) - # We are about to start! - self.create_charts() + # Output is parsable + if not self.parser.re_default: + self.error('Cant parse the output...') + return False - self.info('Plugin was started successfully') + if self.parser.re_backend: + backends = [b[0] for b in self.parser.backend_stats(reply)[::2]] + self.create_backends_charts(backends) return True - - def _get_raw_data(self): - try: - reply = Popen([self.varnish, '-1'], stdout=PIPE, stderr=PIPE, shell=False) - except OSError: - return None - - raw_data = reply.communicate()[0] - if not raw_data: - return None - - return raw_data.decode() - - def _get_data(self): + def get_data(self): """ Format data received from shell command :return: dict """ - raw_data = self._get_raw_data() - data_all = self.rgx_all.findall(raw_data) - data_backend = self.rgx_bck.findall(raw_data) + raw = self._get_raw_data() + if not raw: + return None - if not data_all: + data = dict() + server_stats = self.parser.server_stats(raw) + if not server_stats: return None - # 1. ALL data from 'varnishstat -1'. t - type(MAIN, MEMPOOL etc) - to_netdata = dict([(k, int(v)) for t, k, v in data_all]) - - # 2. ADD backend statistics - to_netdata.update(dict([('_'.join([n, k]), int(v)) for n, k, v in data_backend])) - - # 3. ADD additional keys to dict - # 3.1 Cache hit/miss/hitpass OVERALL in percent - cache_summary = sum([to_netdata.get('cache_hit', 0), to_netdata.get('cache_miss', 0), - to_netdata.get('cache_hitpass', 0)]) - to_netdata['cache_hit_perc'] = find_percent(to_netdata.get('cache_hit', 0), cache_summary, 10000) - to_netdata['cache_miss_perc'] = find_percent(to_netdata.get('cache_miss', 0), cache_summary, 10000) - to_netdata['cache_hitpass_perc'] = find_percent(to_netdata.get('cache_hitpass', 0), cache_summary, 10000) - - # 3.2 Cache hit/miss/hitpass CURRENT in percent - if self.cache_prev: - cache_summary = sum([to_netdata.get('cache_hit', 0), to_netdata.get('cache_miss', 0), - to_netdata.get('cache_hitpass', 0)]) - sum(self.cache_prev) - to_netdata['cache_hit_cperc'] = find_percent(to_netdata.get('cache_hit', 0) - self.cache_prev[0], cache_summary, 10000) - to_netdata['cache_miss_cperc'] = find_percent(to_netdata.get('cache_miss', 0) - self.cache_prev[1], cache_summary, 10000) - to_netdata['cache_hitpass_cperc'] = find_percent(to_netdata.get('cache_hitpass', 0) - self.cache_prev[2], cache_summary, 10000) - else: - to_netdata['cache_hit_cperc'] = 0 - to_netdata['cache_miss_cperc'] = 0 - to_netdata['cache_hitpass_cperc'] = 0 - - self.cache_prev = [to_netdata.get('cache_hit', 0), to_netdata.get('cache_miss', 0), to_netdata.get('cache_hitpass', 0)] - - # 3.3 Problems summary chart - for elem in ['backend_busy', 'backend_unhealthy', 'esi_errors', 'esi_warnings', 'losthdr', 'sess_drop', 'sc_pipe_overflow', - 'sess_fail', 'sess_pipe_overflow', 'threads_destroyed', 'threads_failed', 'threads_limited', 'thread_queue_len']: - if to_netdata.get(elem) is not None: - to_netdata[''.join([elem, '_b'])] = to_netdata.get(elem) - - # Ready steady go! - return to_netdata - - def create_charts(self): - # If 'all_charts' is true...ALL charts are displayed. If no only default + 'extra_charts' - #if self.configuration.get('all_charts'): - # self.order = EXTRA_ORDER - #else: - # try: - # extra_charts = list(filter(lambda chart: chart in EXTRA_ORDER, self.extra_charts.split())) - # except (AttributeError, NameError, ValueError): - # self.error('Extra charts disabled.') - # extra_charts = [] - - self.order = ORDER[:] - #self.order.extend(extra_charts) - - # Create static charts - #self.definitions = {chart: values for chart, values in CHARTS.items() if chart in self.order} - self.definitions = CHARTS - - # Create dynamic backend charts - if self.backend_list: - for backend in self.backend_list: - self.order.insert(0, ''.join([backend[0], '_resp_stats'])) - self.definitions.update({''.join([backend[0], '_resp_stats']): { - 'options': [None, - '%s response statistics' % backend[0].capitalize(), - "kilobit/s", - 'Backend response', - 'varnish.backend', - 'area'], - 'lines': [[''.join([backend[0], '_beresp_hdrbytes']), - 'header', 'incremental', 8, 1000], - [''.join([backend[0], '_beresp_bodybytes']), - 'body', 'incremental', -8, 1000]]}}) - - -def find_percent(value1, value2, multiply): - # If value2 is 0 return 0 - if not value2: - return 0 - else: - return round(float(value1) / float(value2) * multiply) + if self.parser.re_backend: + backend_stats = self.parser.backend_stats(raw) + data.update(dict(('_'.join([name, param]), value) for name, param, value in backend_stats)) + + data.update(dict((param, value) for _, param, value in server_stats)) + + data['memory_allocated'] = data['s0.g_bytes'] + data['memory_free'] = data['s0.g_space'] + + return data + + def create_backends_charts(self, backends): + for backend in backends: + chart_name = ''.join([backend, '_response_statistics']) + title = 'Backend "{0}"'.format(backend.capitalize()) + hdr_bytes = ''.join([backend, '_beresp_hdrbytes']) + body_bytes = ''.join([backend, '_beresp_bodybytes']) + + chart = { + chart_name: + { + 'options': [None, title, 'kilobits/s', 'backend response statistics', + 'varnish.backend', 'area'], + 'lines': [ + [hdr_bytes, 'header', 'incremental', 8, 1000], + [body_bytes, 'body', 'incremental', -8, 1000] + ] + } + } + + self.order.insert(0, chart_name) + self.definitions.update(chart) diff --git a/python.d/web_log.chart.py b/python.d/web_log.chart.py index a5359bc4..954ecd41 100644 --- a/python.d/web_log.chart.py +++ b/python.d/web_log.chart.py @@ -4,22 +4,20 @@ import bisect import re +import os from collections import namedtuple, defaultdict from copy import deepcopy -from os import access, R_OK -from os.path import getsize try: from itertools import filterfalse except ImportError: + from itertools import ifilter as filter from itertools import ifilterfalse as filterfalse -from base import LogService -import msg +from bases.collection import read_last_line +from bases.FrameworkServices.LogService import LogService -priority = 60000 -retries = 60 ORDER_APACHE_CACHE = ['apache_cache'] @@ -246,6 +244,8 @@ SQUID_CODES = dict(TCP='squid_transport_methods', UDP='squid_transport_methods', DENIED='squid_cache_events', NOFETCH='squid_cache_events', TUNNEL='squid_cache_events', ABORTED='squid_transport_errors', TIMEOUT='squid_transport_errors') +REQUEST_REGEX = re.compile(r'(?P<method>[A-Z]+) (?P<url>[^ ]+) [A-Z]+/(?P<http_version>\d(?:.\d)?)') + class Service(LogService): def __init__(self, configuration=None, name=None): @@ -254,8 +254,9 @@ class Service(LogService): :param name: """ LogService.__init__(self, configuration=configuration, name=name) - self.log_type = self.configuration.get('type', 'web') + self.configuration = configuration self.log_path = self.configuration.get('path') + self.job = None def check(self): """ @@ -267,123 +268,43 @@ class Service(LogService): 4. other checks depends on log "type" """ + log_type = self.configuration.get('type', 'web') log_types = dict(web=Web, apache_cache=ApacheCache, squid=Squid) - if self.log_type not in log_types: - self.error('bad log type (%s). Supported types: %s' % (self.log_type, log_types.keys())) + if log_type not in log_types: + self.error("bad log type {log_type}. Supported types: {types}".format(log_type=log_type, + types=log_types.keys())) return False if not self.log_path: self.error('log path is not specified') return False - if not (self._find_recent_log_file() and access(self.log_path, R_OK)): - self.error('%s not readable or not exist' % self.log_path) + if not (self._find_recent_log_file() and os.access(self.log_path, os.R_OK)): + self.error('{log_file} not readable or not exist'.format(log_file=self.log_path)) return False - if not getsize(self.log_path): - self.error('%s is empty' % self.log_path) + if not os.path.getsize(self.log_path): + self.error('{log_file} is empty'.format(log_file=self.log_path)) return False - self.configuration['update_every'] = self.update_every - self.configuration['name'] = self.name - self.configuration['override_name'] = self.override_name - self.configuration['_dimensions'] = self._dimensions - self.configuration['path'] = self.log_path - - cls = log_types[self.log_type] - self.Job = cls(configuration=self.configuration) - if self.Job.check(): - self.order = self.Job.order - self.definitions = self.Job.definitions - self.info('Current log file: %s' % self.log_path) + self.job = log_types[log_type](self) + if self.job.check(): + self.order = self.job.order + self.definitions = self.job.definitions return True return False def _get_data(self): - return self.Job.get_data(self._get_raw_data()) - - -class Mixin: - def filter_data(self, raw_data): - """ - :param raw_data: list - :return: - """ - if not self.pre_filter: - return raw_data - filtered = raw_data - for elem in self.pre_filter: - if elem.description == 'filter_include': - filtered = filter(elem.func, filtered) - elif elem.description == 'filter_exclude': - filtered = filterfalse(elem.func, filtered) - return filtered - - def add_new_dimension(self, dimension_id, chart_key, dimension=None, - algorithm='incremental', multiplier=1, divisor=1): - """ - :param dimension: - :param chart_key: - :param dimension_id: - :param algorithm: - :param multiplier: - :param divisor: - :return: - """ - - self.data[dimension_id] = 0 - # SET method check if dim in _dimensions - self.conf['_dimensions'].append(dimension_id) - # UPDATE method do SET only if dim in definitions - dimension_list = list(map(str, [dimension_id, - dimension if dimension else dimension_id, - algorithm, - multiplier, - divisor])) - self.definitions[chart_key]['lines'].append(dimension_list) - job_name = find_job_name(self.conf['override_name'], self.conf['name']) - opts = self.definitions[chart_key]['options'] - chart = 'CHART %s.%s "" "%s" %s "%s" %s %s 60000 %s\n' % (job_name, chart_key, - opts[1], opts[2], opts[3], - opts[4], opts[5], self.conf['update_every']) - print(chart + "DIMENSION %s\n" % ' '.join(dimension_list)) - - def get_last_line(self): - """ - Reads last line from the log file - :return: str: - """ - # Read last line (or first if there is only one line) - with open(self.conf['path'], 'rb') as logs: - logs.seek(-2, 2) - while logs.read(1) != b'\n': - logs.seek(-2, 1) - if logs.tell() == 0: - break - last_line = logs.readline() - try: - return last_line.decode() - except UnicodeDecodeError: - try: - return last_line.decode(encoding='utf-8') - except (TypeError, UnicodeDecodeError) as error: - msg.error('web_log', str(error)) - return False - - @staticmethod - def error(*params): - msg.error('web_log', ' '.join(map(str, params))) - - @staticmethod - def info(*params): - msg.info('web_log', ' '.join(map(str, params))) + return self.job.get_data(self._get_raw_data()) -class Web(Mixin): - def __init__(self, configuration): - self.conf = configuration - self.pre_filter = check_patterns('filter', self.conf.get('filter')) +class Web: + def __init__(self, service): + self.service = service + self.order = ORDER_WEB[:] + self.definitions = deepcopy(CHARTS_WEB) + self.pre_filter = check_patterns('filter', self.configuration.get('filter')) self.storage = dict() self.data = {'bytes_sent': 0, 'resp_length': 0, 'resp_time_min': 0, 'resp_time_max': 0, 'resp_time_avg': 0, 'resp_time_upstream_min': 0, 'resp_time_upstream_max': 0, @@ -392,23 +313,27 @@ class Web(Mixin): 'req_ipv6': 0, 'unique_tot_ipv4': 0, 'unique_tot_ipv6': 0, 'successful_requests': 0, 'redirects': 0, 'bad_requests': 0, 'server_errors': 0, 'other_requests': 0, 'GET': 0} + def __getattr__(self, item): + return getattr(self.service, item) + def check(self): - last_line = self.get_last_line() + last_line = read_last_line(self.log_path) if not last_line: return False # Custom_log_format or predefined log format. - if self.conf.get('custom_log_format'): + if self.configuration.get('custom_log_format'): match_dict, error = self.find_regex_custom(last_line) else: match_dict, error = self.find_regex(last_line) # "match_dict" is None if there are any problems if match_dict is None: - self.error(str(error)) + self.error(error) return False + self.storage['unique_all_time'] = list() - self.storage['url_pattern'] = check_patterns('url_pattern', self.conf.get('categories')) - self.storage['user_pattern'] = check_patterns('user_pattern', self.conf.get('user_defined')) + self.storage['url_pattern'] = check_patterns('url_pattern', self.configuration.get('categories')) + self.storage['user_pattern'] = check_patterns('user_pattern', self.configuration.get('user_defined')) self.create_web_charts(match_dict) # Create charts self.info('Collected data: %s' % list(match_dict.keys())) @@ -420,20 +345,21 @@ class Web(Mixin): :return: Create/remove additional charts depending on the 'match_dict' keys and configuration file options """ - self.order = ORDER_WEB[:] - self.definitions = deepcopy(CHARTS_WEB) - if 'resp_time' not in match_dict: self.order.remove('response_time') if 'resp_time_upstream' not in match_dict: self.order.remove('response_time_upstream') - if not self.conf.get('all_time', True): + if not self.configuration.get('all_time', True): self.order.remove('clients_all') # Add 'detailed_response_codes' chart if specified in the configuration - if self.conf.get('detailed_response_codes', True): - codes = DET_RESP_AGGR[:1] if self.conf.get('detailed_response_aggregate', True) else DET_RESP_AGGR[1:] + if self.configuration.get('detailed_response_codes', True): + if self.configuration.get('detailed_response_aggregate', True): + codes = DET_RESP_AGGR[:1] + else: + codes = DET_RESP_AGGR[1:] + for code in codes: self.order.append('detailed_response_codes%s' % code) self.definitions['detailed_response_codes%s' % code] \ @@ -444,9 +370,8 @@ class Web(Mixin): # Add 'requests_per_url' chart if specified in the configuration if self.storage['url_pattern']: for elem in self.storage['url_pattern']: - self.definitions['requests_per_url']['lines'].append([elem.description, - elem.description[12:], - 'incremental']) + dim = [elem.description, elem.description[12:], 'incremental'] + self.definitions['requests_per_url']['lines'].append(dim) self.data[elem.description] = 0 self.data['url_pattern_other'] = 0 else: @@ -455,9 +380,8 @@ class Web(Mixin): # Add 'requests_per_user_defined' chart if specified in the configuration if self.storage['user_pattern'] and 'user_defined' in match_dict: for elem in self.storage['user_pattern']: - self.definitions['requests_per_user_defined']['lines'].append([elem.description, - elem.description[13:], - 'incremental']) + dim = [elem.description, elem.description[13:], 'incremental'] + self.definitions['requests_per_user_defined']['lines'].append(dim) self.data[elem.description] = 0 self.data['user_pattern_other'] = 0 else: @@ -473,7 +397,7 @@ class Web(Mixin): if not raw_data: return None if raw_data is None else self.data - filtered_data = self.filter_data(raw_data=raw_data) + filtered_data = filter_data(raw_data=raw_data, pre_filter=self.pre_filter) unique_current = set() timings = defaultdict(lambda: dict(minimum=None, maximum=0, summary=0, count=0)) @@ -488,39 +412,24 @@ class Web(Mixin): except KeyError: self.data['0xx'] += 1 # detailed response code - if self.conf.get('detailed_response_codes', True): + if self.configuration.get('detailed_response_codes', True): self.get_data_per_response_codes_detailed(code=match_dict['code']) # response statuses self.get_data_per_statuses(code=match_dict['code']) - # requests per url - if self.storage['url_pattern']: - self.get_data_per_pattern(row=match_dict['url'], - other='url_pattern_other', - pattern=self.storage['url_pattern']) # requests per user defined pattern if self.storage['user_pattern'] and 'user_defined' in match_dict: self.get_data_per_pattern(row=match_dict['user_defined'], other='user_pattern_other', pattern=self.storage['user_pattern']) - # requests per http method - if match_dict['method'] not in self.data: - self.add_new_dimension(dimension_id=match_dict['method'], - chart_key='http_method') - self.data[match_dict['method']] += 1 - # requests per http version - if 'http_version' in match_dict: - dim_id = match_dict['http_version'].replace('.', '_') - if dim_id not in self.data: - self.add_new_dimension(dimension_id=dim_id, - chart_key='http_version', - dimension=match_dict['http_version']) - self.data[dim_id] += 1 + # method, url, http version + self.get_data_from_request_field(match_dict=match_dict) # bandwidth sent bytes_sent = match_dict['bytes_sent'] if '-' not in match_dict['bytes_sent'] else 0 self.data['bytes_sent'] += int(bytes_sent) # request processing time and bandwidth received if 'resp_length' in match_dict: - self.data['resp_length'] += int(match_dict['resp_length']) + resp_length = match_dict['resp_length'] if '-' not in match_dict['resp_length'] else 0 + self.data['resp_length'] += int(resp_length) if 'resp_time' in match_dict: get_timings(timings=timings['resp_time'], time=self.storage['func_resp_time'](float(match_dict['resp_time']))) @@ -531,7 +440,7 @@ class Web(Mixin): proto = 'ipv6' if ':' in match_dict['address'] else 'ipv4' self.data['req_' + proto] += 1 # unique clients ips - if self.conf.get('all_time', True): + if self.configuration.get('all_time', True): if address_not_in_pool(pool=self.storage['unique_all_time'], address=match_dict['address'], pool_size=self.data['unique_tot_ipv4'] + self.data['unique_tot_ipv6']): @@ -562,45 +471,35 @@ class Web(Mixin): # REGEX: 1.IPv4 address 2.HTTP method 3. URL 4. Response code # 5. Bytes sent 6. Response length 7. Response process time default = re.compile(r'(?P<address>[\da-f.:]+|localhost)' - r' -.*?"(?P<method>[A-Z]+)' - r' (?P<url>[^ ]+)' - r' [A-Z]+/(?P<http_version>\d\.\d)"' + r' -.*?"(?P<request>[^"]*)"' r' (?P<code>[1-9]\d{2})' r' (?P<bytes_sent>\d+|-)') apache_ext_insert = re.compile(r'(?P<address>[\da-f.:]+|localhost)' - r' -.*?"(?P<method>[A-Z]+)' - r' (?P<url>[^ ]+)' - r' [A-Z]+/(?P<http_version>\d\.\d)"' + r' -.*?"(?P<request>[^"]*)"' r' (?P<code>[1-9]\d{2})' r' (?P<bytes_sent>\d+|-)' - r' (?P<resp_length>\d+)' + r' (?P<resp_length>\d+|-)' r' (?P<resp_time>\d+) ') apache_ext_append = re.compile(r'(?P<address>[\da-f.:]+|localhost)' - r' -.*?"(?P<method>[A-Z]+)' - r' (?P<url>[^ ]+)' - r' [A-Z]+/(?P<http_version>\d\.\d)"' + r' -.*?"(?P<request>[^"]*)"' r' (?P<code>[1-9]\d{2})' r' (?P<bytes_sent>\d+|-)' r' .*?' - r' (?P<resp_length>\d+)' + r' (?P<resp_length>\d+|-)' r' (?P<resp_time>\d+)' r'(?: |$)') nginx_ext_insert = re.compile(r'(?P<address>[\da-f.:]+)' - r' -.*?"(?P<method>[A-Z]+)' - r' (?P<url>[^ ]+)' - r' [A-Z]+/(?P<http_version>\d\.\d)"' + r' -.*?"(?P<request>[^"]*)"' r' (?P<code>[1-9]\d{2})' r' (?P<bytes_sent>\d+)' r' (?P<resp_length>\d+)' r' (?P<resp_time>\d+\.\d+) ') nginx_ext2_insert = re.compile(r'(?P<address>[\da-f.:]+)' - r' -.*?"(?P<method>[A-Z]+)' - r' (?P<url>[^ ]+)' - r' [A-Z]+/(?P<http_version>\d\.\d)"' + r' -.*?"(?P<request>[^"]*)"' r' (?P<code>[1-9]\d{2})' r' (?P<bytes_sent>\d+)' r' (?P<resp_length>\d+)' @@ -608,9 +507,7 @@ class Web(Mixin): r' (?P<resp_time_upstream>[\d.-]+) ') nginx_ext_append = re.compile(r'(?P<address>[\da-f.:]+)' - r' -.*?"(?P<method>[A-Z]+)' - r' (?P<url>[^ ]+)' - r' [A-Z]+/(?P<http_version>\d\.\d)"' + r' -.*?"(?P<request>[^"]*)"' r' (?P<code>[1-9]\d{2})' r' (?P<bytes_sent>\d+)' r' .*?' @@ -669,14 +566,14 @@ class Web(Mixin): ("resp_length" is integer or "-", "resp_time" is integer or float) """ - if not hasattr(self.conf.get('custom_log_format'), 'keys'): + if not hasattr(self.configuration.get('custom_log_format'), 'keys'): return find_regex_return(msg='Custom log: "custom_log_format" is not a <dict>') - pattern = self.conf.get('custom_log_format', dict()).get('pattern') + pattern = self.configuration.get('custom_log_format', dict()).get('pattern') if not (pattern and isinstance(pattern, str)): return find_regex_return(msg='Custom log: "pattern" option is not specified or type is not <str>') - resp_time_func = self.conf.get('custom_log_format', dict()).get('time_multiplier') or 0 + resp_time_func = self.configuration.get('custom_log_format', dict()).get('time_multiplier') or 0 if not isinstance(resp_time_func, int): return find_regex_return(msg='Custom log: "time_multiplier" is not an integer') @@ -685,6 +582,7 @@ class Web(Mixin): regex = re.compile(pattern) except re.error as error: return find_regex_return(msg='Pattern compile error: %s' % str(error)) + match = regex.search(last_line) if not match: return find_regex_return(msg='Custom log: pattern search FAILED') @@ -693,14 +591,14 @@ class Web(Mixin): if match_dict is None: return find_regex_return(msg='Custom log: search OK but contains no named subgroups' ' (you need to use ?P<subgroup_name>)') - mandatory_dict = {'address': r'[\da-f.:]+|localhost', + mandatory_dict = {'address': r'[\w.:-]+', 'code': r'[1-9]\d{2}', - 'method': r'[A-Z]+', 'bytes_sent': r'\d+|-'} - optional_dict = {'resp_length': r'\d+', + optional_dict = {'resp_length': r'\d+|-', 'resp_time': r'[\d.]+', 'resp_time_upstream': r'[\d.-]+', - 'http_version': r'\d(\.\d)?'} + 'method': r'[A-Z]+', + 'http_version': r'\d(?:.\d)?'} mandatory_values = set(mandatory_dict) - set(match_dict) if mandatory_values: @@ -726,6 +624,36 @@ class Web(Mixin): self.storage['regex'] = regex return find_regex_return(match_dict=match_dict) + def get_data_from_request_field(self, match_dict): + if match_dict.get('request'): + match_dict = REQUEST_REGEX.search(match_dict['request']) + if match_dict: + match_dict = match_dict.groupdict() + else: + return + # requests per url + if match_dict.get('url') and self.storage['url_pattern']: + self.get_data_per_pattern(row=match_dict['url'], + other='url_pattern_other', + pattern=self.storage['url_pattern']) + # requests per http method + if match_dict.get('method'): + if match_dict['method'] not in self.data: + self.charts['http_method'].add_dimension([match_dict['method'], + match_dict['method'], + 'incremental']) + self.data[match_dict['method']] = 0 + self.data[match_dict['method']] += 1 + # requests per http version + if match_dict.get('http_version'): + dim_id = match_dict['http_version'].replace('.', '_') + if dim_id not in self.data: + self.charts['http_version'].add_dimension([dim_id, + match_dict['http_version'], + 'incremental']) + self.data[dim_id] = 0 + self.data[dim_id] += 1 + def get_data_per_response_codes_detailed(self, code): """ :param code: str: CODE from parsed line. Ex.: '202, '499' @@ -733,14 +661,14 @@ class Web(Mixin): Calls add_new_dimension method If the value is found for the first time """ if code not in self.data: - if self.conf.get('detailed_response_aggregate', True): - self.add_new_dimension(dimension_id=code, - chart_key='detailed_response_codes') + if self.configuration.get('detailed_response_aggregate', True): + self.charts['detailed_response_codes'].add_dimension([code, code, 'incremental']) + self.data[code] = 0 else: code_index = int(code[0]) if int(code[0]) < 6 else 6 chart_key = 'detailed_response_codes' + DET_RESP_AGGR[code_index] - self.add_new_dimension(dimension_id=code, - chart_key=chart_key) + self.charts[chart_key].add_dimension([code, code, 'incremental']) + self.data[code] = 0 self.data[code] += 1 def get_data_per_pattern(self, row, other, pattern): @@ -780,8 +708,8 @@ class Web(Mixin): class ApacheCache: - def __init__(self, configuration): - self.conf = configuration + def __init__(self, service): + self.service = service self.order = ORDER_APACHE_CACHE self.definitions = CHARTS_APACHE_CACHE @@ -805,12 +733,12 @@ class ApacheCache: return data -class Squid(Mixin): - def __init__(self, configuration): - self.conf = configuration +class Squid: + def __init__(self, service): + self.service = service self.order = ORDER_SQUID self.definitions = CHARTS_SQUID - self.pre_filter = check_patterns('filter', self.conf.get('filter')) + self.pre_filter = check_patterns('filter', self.configuration.get('filter')) self.storage = dict() self.data = {'duration_max': 0, 'duration_avg': 0, 'duration_min': 0, 'bytes': 0, '0xx': 0, '1xx': 0, '2xx': 0, '3xx': 0, '4xx': 0, '5xx': 0, @@ -819,8 +747,11 @@ class Squid(Mixin): 'redirects': 0, 'bad_requests': 0, 'server_errors': 0, 'other_requests': 0 } + def __getattr__(self, item): + return getattr(self.service, item) + def check(self): - last_line = self.get_last_line() + last_line = read_last_line(self.log_path) if not last_line: return False self.storage['unique_all_time'] = list() @@ -856,7 +787,7 @@ class Squid(Mixin): 'chart': 'squid_mime_type', 'func_dim_id': lambda v: v.split('/')[0], 'func_dim': None}} - if not self.conf.get('all_time', True): + if not self.configuration.get('all_time', True): self.order.remove('squid_clients_all') return True @@ -864,7 +795,7 @@ class Squid(Mixin): if not raw_data: return None if raw_data is None else self.data - filtered_data = self.filter_data(raw_data=raw_data) + filtered_data = filter_data(raw_data=raw_data, pre_filter=self.pre_filter) unique_ip = set() timings = defaultdict(lambda: dict(minimum=None, maximum=0, summary=0, count=0)) @@ -888,7 +819,7 @@ class Squid(Mixin): proto = 'ipv4' if '.' in match['client_address'] else 'ipv6' # unique clients ips - if self.conf.get('all_time', True): + if self.configuration.get('all_time', True): if address_not_in_pool(pool=self.storage['unique_all_time'], address=match['client_address'], pool_size=self.data['unique_tot_ipv4'] + self.data['unique_tot_ipv6']): @@ -904,9 +835,10 @@ class Squid(Mixin): dimension_id = values['func_dim_id'](match[key]) if values['func_dim_id'] else match[key] if dimension_id not in self.data: dimension = values['func_dim'](match[key]) if values['func_dim'] else dimension_id - self.add_new_dimension(dimension_id=dimension_id, - chart_key=values['chart'], - dimension=dimension) + self.charts[values['chart']].add_dimension([dimension_id, + dimension, + 'incremental']) + self.data[dimension_id] = 0 self.data[dimension_id] += 1 else: self.data['unmatched'] += 1 @@ -940,8 +872,8 @@ class Squid(Mixin): :return: """ if code not in self.data: - self.add_new_dimension(dimension_id=code, - chart_key='squid_code') + self.charts['squid_code'].add_dimension([code, code, 'incremental']) + self.data[code] = 0 self.data[code] += 1 for tag in code.split('_'): @@ -951,9 +883,8 @@ class Squid(Mixin): continue dimension_id = '_'.join(['code_detailed', tag]) if dimension_id not in self.data: - self.add_new_dimension(dimension_id=dimension_id, - dimension=tag, - chart_key=chart_key) + self.charts[chart_key].add_dimension([dimension_id, tag, 'incremental']) + self.data[dimension_id] = 0 self.data[dimension_id] += 1 @@ -1038,14 +969,19 @@ def check_patterns(string, dimension_regex_dict): return result or None -def find_job_name(override_name, name): +def filter_data(raw_data, pre_filter): """ - :param override_name: str: 'name' var from configuration file - :param name: str: 'job_name' from configuration file - :return: str: new job name - We need this for dynamic charts. Actually the same logic as in python.d.plugin. + :param raw_data: + :param pre_filter: + :return: """ - add_to_name = override_name or name - if add_to_name: - return '_'.join(['web_log', re.sub('\s+', '_', add_to_name)]) - return 'web_log' + + if not pre_filter: + return raw_data + filtered = raw_data + for elem in pre_filter: + if elem.description == 'filter_include': + filtered = filter(elem.func, filtered) + elif elem.description == 'filter_exclude': + filtered = filterfalse(elem.func, filtered) + return filtered diff --git a/src/Makefile.am b/src/Makefile.am index feddc326..1a1d3748 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -137,7 +137,8 @@ netdata_SOURCES = \ sys_devices_system_node.c \ unit_test.c \ unit_test.h \ - url.c url.h \ + url.c \ + url.h \ web_api_old.c \ web_api_old.h \ web_api_v1.c \ @@ -176,7 +177,8 @@ netdata_SOURCES += \ $(NULL) else netdata_SOURCES += \ - ipc.c ipc.h \ + ipc.c \ + ipc.h \ plugin_proc.c \ plugin_proc.h \ plugin_proc_diskspace.c \ @@ -193,6 +195,8 @@ netdata_SOURCES += \ proc_net_rpc_nfsd.c \ proc_net_snmp.c \ proc_net_snmp6.c \ + proc_net_sockstat.c \ + proc_net_sockstat6.c \ proc_net_softnet_stat.c \ proc_net_stat_conntrack.c \ proc_net_stat_synproxy.c \ @@ -258,6 +262,8 @@ cgroup_network_SOURCES = \ inlined.h \ log.c log.h \ procfile.c procfile.h \ + popen.c popen.h \ + signals.c signals.h \ $(NULL) cgroup_network_LDADD = \ diff --git a/src/Makefile.in b/src/Makefile.in index bc73c712..bf902c21 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -106,7 +106,8 @@ plugins_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) @FREEBSD_FALSE@@MACOS_TRUE@ $(NULL) @FREEBSD_FALSE@@MACOS_FALSE@am__append_6 = \ -@FREEBSD_FALSE@@MACOS_FALSE@ ipc.c ipc.h \ +@FREEBSD_FALSE@@MACOS_FALSE@ ipc.c \ +@FREEBSD_FALSE@@MACOS_FALSE@ ipc.h \ @FREEBSD_FALSE@@MACOS_FALSE@ plugin_proc.c \ @FREEBSD_FALSE@@MACOS_FALSE@ plugin_proc.h \ @FREEBSD_FALSE@@MACOS_FALSE@ plugin_proc_diskspace.c \ @@ -123,6 +124,8 @@ plugins_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) @FREEBSD_FALSE@@MACOS_FALSE@ proc_net_rpc_nfsd.c \ @FREEBSD_FALSE@@MACOS_FALSE@ proc_net_snmp.c \ @FREEBSD_FALSE@@MACOS_FALSE@ proc_net_snmp6.c \ +@FREEBSD_FALSE@@MACOS_FALSE@ proc_net_sockstat.c \ +@FREEBSD_FALSE@@MACOS_FALSE@ proc_net_sockstat6.c \ @FREEBSD_FALSE@@MACOS_FALSE@ proc_net_softnet_stat.c \ @FREEBSD_FALSE@@MACOS_FALSE@ proc_net_stat_conntrack.c \ @FREEBSD_FALSE@@MACOS_FALSE@ proc_net_stat_synproxy.c \ @@ -179,7 +182,8 @@ apps_plugin_OBJECTS = $(am_apps_plugin_OBJECTS) am__DEPENDENCIES_1 = apps_plugin_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) am_cgroup_network_OBJECTS = cgroup-network.$(OBJEXT) clocks.$(OBJEXT) \ - common.$(OBJEXT) log.$(OBJEXT) procfile.$(OBJEXT) + common.$(OBJEXT) log.$(OBJEXT) procfile.$(OBJEXT) \ + popen.$(OBJEXT) signals.$(OBJEXT) cgroup_network_OBJECTS = $(am_cgroup_network_OBJECTS) cgroup_network_DEPENDENCIES = $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) @@ -224,6 +228,7 @@ am__netdata_SOURCES_DIST = adaptive_resortable_list.c \ proc_loadavg.c proc_meminfo.c proc_net_dev.c \ proc_net_ip_vs_stats.c proc_net_netstat.c proc_net_rpc_nfs.c \ proc_net_rpc_nfsd.c proc_net_snmp.c proc_net_snmp6.c \ + proc_net_sockstat.c proc_net_sockstat6.c \ proc_net_softnet_stat.c proc_net_stat_conntrack.c \ proc_net_stat_synproxy.c proc_spl_kstat_zfs.c proc_stat.c \ proc_sys_kernel_random_entropy_avail.c proc_vmstat.c \ @@ -254,6 +259,8 @@ am__netdata_SOURCES_DIST = adaptive_resortable_list.c \ @FREEBSD_FALSE@@MACOS_FALSE@ proc_net_rpc_nfsd.$(OBJEXT) \ @FREEBSD_FALSE@@MACOS_FALSE@ proc_net_snmp.$(OBJEXT) \ @FREEBSD_FALSE@@MACOS_FALSE@ proc_net_snmp6.$(OBJEXT) \ +@FREEBSD_FALSE@@MACOS_FALSE@ proc_net_sockstat.$(OBJEXT) \ +@FREEBSD_FALSE@@MACOS_FALSE@ proc_net_sockstat6.$(OBJEXT) \ @FREEBSD_FALSE@@MACOS_FALSE@ proc_net_softnet_stat.$(OBJEXT) \ @FREEBSD_FALSE@@MACOS_FALSE@ proc_net_stat_conntrack.$(OBJEXT) \ @FREEBSD_FALSE@@MACOS_FALSE@ proc_net_stat_synproxy.$(OBJEXT) \ @@ -616,6 +623,8 @@ cgroup_network_SOURCES = \ inlined.h \ log.c log.h \ procfile.c procfile.h \ + popen.c popen.h \ + signals.c signals.h \ $(NULL) cgroup_network_LDADD = \ @@ -815,6 +824,8 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_net_rpc_nfsd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_net_snmp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_net_snmp6.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_net_sockstat.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_net_sockstat6.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_net_softnet_stat.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_net_stat_conntrack.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_net_stat_synproxy.Po@am__quote@ diff --git a/src/adaptive_resortable_list.c b/src/adaptive_resortable_list.c index f74c53ea..add1d8c9 100644 --- a/src/adaptive_resortable_list.c +++ b/src/adaptive_resortable_list.c @@ -2,7 +2,7 @@ // the default processor() of the ARL // can be overwritten at arl_create() -static inline void arl_callback_str2ull(const char *name, uint32_t hash, const char *value, void *dst) { +inline void arl_callback_str2ull(const char *name, uint32_t hash, const char *value, void *dst) { (void)name; (void)hash; @@ -11,6 +11,15 @@ static inline void arl_callback_str2ull(const char *name, uint32_t hash, const c // fprintf(stderr, "name '%s' with hash %u and value '%s' is %llu\n", name, hash, value, *d); } +inline void arl_callback_str2kernel_uint_t(const char *name, uint32_t hash, const char *value, void *dst) { + (void)name; + (void)hash; + + register kernel_uint_t *d = dst; + *d = str2kernel_uint_t(value); + // fprintf(stderr, "name '%s' with hash %u and value '%s' is %llu\n", name, hash, value, (unsigned long long)*d); +} + // create a new ARL ARL_BASE *arl_create(const char *name, void (*processor)(const char *, uint32_t, const char *, void *), size_t rechecks) { ARL_BASE *base = callocz(1, sizeof(ARL_BASE)); diff --git a/src/adaptive_resortable_list.h b/src/adaptive_resortable_list.h index 609cd0c4..c007fa31 100644 --- a/src/adaptive_resortable_list.h +++ b/src/adaptive_resortable_list.h @@ -110,6 +110,9 @@ extern int arl_find_or_create_and_relink(ARL_BASE *base, const char *s, const ch // begin an ARL iteration extern void arl_begin(ARL_BASE *base); +extern void arl_callback_str2ull(const char *name, uint32_t hash, const char *value, void *dst); +extern void arl_callback_str2kernel_uint_t(const char *name, uint32_t hash, const char *value, void *dst); + // check a keyword against the ARL // this is to be called for each keyword read from source data // s = the keyword, as collected diff --git a/src/appconfig.c b/src/appconfig.c index 2c7721b8..40cade81 100644 --- a/src/appconfig.c +++ b/src/appconfig.c @@ -567,6 +567,7 @@ void appconfig_generate(struct config *root, BUFFER *wb, int only_changed) else pri = 2; if(i == pri) { + int loaded = 0; int used = 0; int changed = 0; int count = 0; @@ -574,13 +575,14 @@ void appconfig_generate(struct config *root, BUFFER *wb, int only_changed) config_section_wrlock(co); for(cv = co->values; cv ; cv = cv->next) { used += (cv->flags & CONFIG_VALUE_USED)?1:0; + loaded += (cv->flags & CONFIG_VALUE_LOADED)?1:0; changed += (cv->flags & CONFIG_VALUE_CHANGED)?1:0; count++; } config_section_unlock(co); if(!count) continue; - if(only_changed && !changed) continue; + if(only_changed && !changed && !loaded) continue; if(!used) { buffer_sprintf(wb, "\n# section '%s' is not used.", co->name); @@ -594,7 +596,7 @@ void appconfig_generate(struct config *root, BUFFER *wb, int only_changed) if(used && !(cv->flags & CONFIG_VALUE_USED)) { buffer_sprintf(wb, "\n\t# option '%s' is not used.\n", cv->name); } - buffer_sprintf(wb, "\t%s%s = %s\n", ((!(cv->flags & CONFIG_VALUE_CHANGED)) && (cv->flags & CONFIG_VALUE_USED))?"# ":"", cv->name, cv->value); + buffer_sprintf(wb, "\t%s%s = %s\n", ((!(cv->flags & CONFIG_VALUE_LOADED)) && (!(cv->flags & CONFIG_VALUE_CHANGED)) && (cv->flags & CONFIG_VALUE_USED))?"# ":"", cv->name, cv->value); } config_section_unlock(co); } diff --git a/src/apps_plugin.c b/src/apps_plugin.c index c0eb5c08..3ac79777 100644 --- a/src/apps_plugin.c +++ b/src/apps_plugin.c @@ -1572,14 +1572,22 @@ static inline int read_pid_file_descriptors(struct pid_stat *p, void *ptr) { break; default: /* print protocol number and socket address */ +#if __FreeBSD_version < 1200031 sprintf(fdsname, "socket: other: %d %s %s", fds->kf_sock_protocol, fds->kf_sa_local.__ss_pad1, fds->kf_sa_local.__ss_pad2); +#else + sprintf(fdsname, "socket: other: %d %s %s", fds->kf_sock_protocol, fds->kf_un.kf_sock.kf_sa_local.__ss_pad1, fds->kf_un.kf_sock.kf_sa_local.__ss_pad2); +#endif } break; case KF_TYPE_PIPE: sprintf(fdsname, "pipe: %lu %lu", fds->kf_un.kf_pipe.kf_pipe_addr, fds->kf_un.kf_pipe.kf_pipe_peer); break; case KF_TYPE_PTS: +#if __FreeBSD_version < 1200031 sprintf(fdsname, "other: pts: %u", fds->kf_un.kf_pts.kf_pts_dev); +#else + sprintf(fdsname, "other: pts: %lu", fds->kf_un.kf_pts.kf_pts_dev); +#endif break; case KF_TYPE_SHM: sprintf(fdsname, "other: shm: %s size: %lu", fds->kf_path, fds->kf_un.kf_file.kf_file_size); @@ -306,7 +306,10 @@ int avl_walker(avl *node, int (*callback)(void *entry, void *data), void *data) } int avl_traverse(avl_tree *t, int (*callback)(void *entry, void *data), void *data) { - return avl_walker(t->root, callback, data); + if(t->root) + return avl_walker(t->root, callback, data); + else + return 0; } // --------------------------- diff --git a/src/backends.c b/src/backends.c index eed4ab40..df9a1ccb 100644 --- a/src/backends.c +++ b/src/backends.c @@ -615,18 +615,18 @@ void *backends_main(void *ptr) { chart_backend_reconnects = 0, chart_backend_latency = 0; - RRDSET *chart_metrics = rrdset_create_localhost("netdata", "backend_metrics", NULL, "backend", NULL, "Netdata Buffered Metrics", "metrics", 130600, backend_update_every, RRDSET_TYPE_LINE); + RRDSET *chart_metrics = rrdset_create_localhost("netdata", "backend_metrics", NULL, "backend", NULL, "Netdata Buffered Metrics", "metrics", "backends", NULL, 130600, backend_update_every, RRDSET_TYPE_LINE); rrddim_add(chart_metrics, "buffered", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); rrddim_add(chart_metrics, "lost", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); rrddim_add(chart_metrics, "sent", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - RRDSET *chart_bytes = rrdset_create_localhost("netdata", "backend_bytes", NULL, "backend", NULL, "Netdata Backend Data Size", "KB", 130610, backend_update_every, RRDSET_TYPE_AREA); + RRDSET *chart_bytes = rrdset_create_localhost("netdata", "backend_bytes", NULL, "backend", NULL, "Netdata Backend Data Size", "KB", "backends", NULL, 130610, backend_update_every, RRDSET_TYPE_AREA); rrddim_add(chart_bytes, "buffered", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); rrddim_add(chart_bytes, "lost", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); rrddim_add(chart_bytes, "sent", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); rrddim_add(chart_bytes, "received", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); - RRDSET *chart_ops = rrdset_create_localhost("netdata", "backend_ops", NULL, "backend", NULL, "Netdata Backend Operations", "operations", 130630, backend_update_every, RRDSET_TYPE_LINE); + RRDSET *chart_ops = rrdset_create_localhost("netdata", "backend_ops", NULL, "backend", NULL, "Netdata Backend Operations", "operations", "backends", NULL, 130630, backend_update_every, RRDSET_TYPE_LINE); rrddim_add(chart_ops, "write", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); rrddim_add(chart_ops, "discard", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); rrddim_add(chart_ops, "reconnect", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); @@ -640,11 +640,11 @@ void *backends_main(void *ptr) { * * issue #1432 and https://www.softlab.ntua.gr/facilities/documentation/unix/unix-socket-faq/unix-socket-faq-2.html * - RRDSET *chart_latency = rrdset_create_localhost("netdata", "backend_latency", NULL, "backend", NULL, "Netdata Backend Latency", "ms", 130620, backend_update_every, RRDSET_TYPE_AREA); + RRDSET *chart_latency = rrdset_create_localhost("netdata", "backend_latency", NULL, "backend", NULL, "Netdata Backend Latency", "ms", "backends", NULL, 130620, backend_update_every, RRDSET_TYPE_AREA); rrddim_add(chart_latency, "latency", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); */ - RRDSET *chart_rusage = rrdset_create_localhost("netdata", "backend_thread_cpu", NULL, "backend", NULL, "NetData Backend Thread CPU usage", "milliseconds/s", 130630, backend_update_every, RRDSET_TYPE_STACKED); + RRDSET *chart_rusage = rrdset_create_localhost("netdata", "backend_thread_cpu", NULL, "backend", NULL, "NetData Backend Thread CPU usage", "milliseconds/s", "backends", NULL, 130630, backend_update_every, RRDSET_TYPE_STACKED); rrddim_add(chart_rusage, "user", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL); rrddim_add(chart_rusage, "system", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL); diff --git a/src/cgroup-network.c b/src/cgroup-network.c index 8894d60e..7b1a0234 100644 --- a/src/cgroup-network.c +++ b/src/cgroup-network.c @@ -1,4 +1,5 @@ #include "common.h" +#include <libgen.h> #ifdef HAVE_SETNS #ifndef _GNU_SOURCE @@ -14,6 +15,10 @@ void netdata_cleanup_and_exit(int ret) { exit(ret); } +void health_reload(void) {}; +void rrdhost_save_all(void) {}; + + struct iface { const char *device; uint32_t hash; @@ -269,38 +274,62 @@ pid_t read_pid_from_cgroup(const char *path) { return pid; } -void usage(void) { - fprintf(stderr, "%s [ -p PID | --pid PID | --cgroup /path/to/cgroup ]\n", program_name); - exit(1); -} -int main(int argc, char **argv) { - pid_t pid = 0; +// ---------------------------------------------------------------------------- +// send the result to netdata - program_name = argv[0]; - program_version = VERSION; - error_log_syslog = 0; +struct found_device { + const char *host_device; + const char *guest_device; - if(argc == 2 && (!strcmp(argv[1], "version") || !strcmp(argv[1], "-version") || !strcmp(argv[1], "--version") || !strcmp(argv[1], "-v") || !strcmp(argv[1], "-V"))) { - fprintf(stderr, "cgroup-network %s\n", VERSION); - exit(0); - } + uint32_t host_device_hash; - if(argc != 3) - usage(); + struct found_device *next; +} *detected_devices = NULL; - if(!strcmp(argv[1], "-p") || !strcmp(argv[1], "--pid")) { - pid = atoi(argv[2]); +void add_device(const char *host, const char *guest) { + uint32_t hash = simple_hash(host); + + if(guest && (!*guest || strcmp(host, guest) == 0)) + guest = NULL; + + struct found_device *f; + for(f = detected_devices; f ; f = f->next) { + if(f->host_device_hash == hash && strcmp(host, f->host_device) == 0) { + + if(guest && !f->guest_device) + f->guest_device = strdup(guest); + + return; + } } - else if(!strcmp(argv[1], "--cgroup")) { - pid = read_pid_from_cgroup(argv[2]); + + f = mallocz(sizeof(struct found_device)); + f->host_device = strdupz(host); + f->host_device_hash = hash; + f->guest_device = (guest)?strdupz(guest):NULL; + f->next = detected_devices; + detected_devices = f; +} + +int send_devices(void) { + int found = 0; + + struct found_device *f; + for(f = detected_devices; f ; f = f->next) { + found++; + printf("%s %s\n", f->host_device, (f->guest_device)?f->guest_device:f->host_device); } - else - usage(); - if(pid <= 0) - fatal("Invalid pid %d", (int)pid); + return found; +} + +// ---------------------------------------------------------------------------- +// this function should be called only **ONCE** +// also it has to be the **LAST** to be called +// since it switches namespaces, so after this call, everything is different! +void detect_veth_interfaces(pid_t pid) { struct iface *host, *cgroup, *h, *c; const char *prefix = getenv("NETDATA_HOST_PREFIX"); @@ -321,20 +350,117 @@ int main(int argc, char **argv) { if(!eligible_ifaces(cgroup)) fatal("there are not double-linked cgroup interfaces available."); - int found = 0; for(h = host; h ; h = h->next) { if(iface_is_eligible(h)) { for (c = cgroup; c; c = c->next) { if(iface_is_eligible(c) && h->ifindex == c->iflink && h->iflink == c->ifindex) { - printf("%s %s\n", h->device, c->device); - found++; + add_device(h->device, c->device); } } } } +} - if(!found) - return 1; +// ---------------------------------------------------------------------------- +// call the external helper - return 0; +#define CGROUP_NETWORK_INTERFACE_MAX_LINE 2048 +void call_the_helper(const char *me, pid_t pid, const char *cgroup) { + const char *pluginsdir = getenv("NETDATA_PLUGINS_DIR"); + char *m = NULL; + + if(!pluginsdir || !*pluginsdir) { + m = strdupz(me); + pluginsdir = dirname(m); + } + + if(setresuid(0, 0, 0) == -1) + error("setresuid(0, 0, 0) failed."); + + char buffer[CGROUP_NETWORK_INTERFACE_MAX_LINE + 1]; + if(cgroup) + snprintfz(buffer, CGROUP_NETWORK_INTERFACE_MAX_LINE, "exec %s/cgroup-network-helper.sh --cgroup '%s'", pluginsdir, cgroup); + else + snprintfz(buffer, CGROUP_NETWORK_INTERFACE_MAX_LINE, "exec %s/cgroup-network-helper.sh --pid %d", pluginsdir, pid); + + info("running: %s", buffer); + + pid_t cgroup_pid; + FILE *fp = mypopen(buffer, &cgroup_pid); + if(fp) { + char *s; + while((s = fgets(buffer, CGROUP_NETWORK_INTERFACE_MAX_LINE, fp))) { + trim(s); + + if(*s && *s != '\n') { + char *t = s; + while(*t && *t != ' ') t++; + if(*t == ' ') { + *t = '\0'; + t++; + } + + if(!*s || !*t) continue; + add_device(s, t); + } + } + + mypclose(fp, cgroup_pid); + } + else + error("cannot execute cgroup-network helper script: %s", buffer); + + freez(m); +} + + +// ---------------------------------------------------------------------------- +// main + +void usage(void) { + fprintf(stderr, "%s [ -p PID | --pid PID | --cgroup /path/to/cgroup ]\n", program_name); + exit(1); +} + +int main(int argc, char **argv) { + pid_t pid = 0; + + program_name = argv[0]; + program_version = VERSION; + error_log_syslog = 0; + + if(argc == 2 && (!strcmp(argv[1], "version") || !strcmp(argv[1], "-version") || !strcmp(argv[1], "--version") || !strcmp(argv[1], "-v") || !strcmp(argv[1], "-V"))) { + fprintf(stderr, "cgroup-network %s\n", VERSION); + exit(0); + } + + if(argc != 3) + usage(); + + if(!strcmp(argv[1], "-p") || !strcmp(argv[1], "--pid")) { + pid = atoi(argv[2]); + + if(pid <= 0) { + errno = 0; + fatal("Invalid pid %d given", (int) pid); + } + + call_the_helper(argv[0], pid, NULL); + } + else if(!strcmp(argv[1], "--cgroup")) { + pid = read_pid_from_cgroup(argv[2]); + call_the_helper(argv[0], pid, argv[2]); + + if(pid <= 0 && !detected_devices) { + errno = 0; + fatal("Invalid pid %d read from cgroup '%s'", (int) pid, argv[2]); + } + } + else + usage(); + + if(pid > 0) + detect_veth_interfaces(pid); + + return send_devices(); } diff --git a/src/clocks.c b/src/clocks.c index 8f2aa740..2b1c36e3 100644 --- a/src/clocks.c +++ b/src/clocks.c @@ -115,8 +115,12 @@ usec_t heartbeat_next(heartbeat_t *hb, usec_t tick) if(likely(*hb != 0ULL)) { usec_t dt = now - *hb; *hb = now; - if(unlikely(dt >= tick + tick / 2)) + + if(unlikely(dt >= tick + tick / 2)) { + errno = 0; error("heartbeat missed %llu microseconds", dt - tick); + } + return dt; } else { diff --git a/src/common.c b/src/common.c index 5a953672..a976e96e 100644 --- a/src/common.c +++ b/src/common.c @@ -17,6 +17,7 @@ char *netdata_configured_cache_dir = NULL; char *netdata_configured_varlib_dir = NULL; char *netdata_configured_home_dir = NULL; char *netdata_configured_host_prefix = NULL; +char *netdata_configured_timezone = NULL; int enable_ksm = 1; @@ -1119,10 +1120,14 @@ pid_t gettid(void) { #ifdef __FreeBSD__ return (pid_t)pthread_getthreadid_np(); #elif defined(__APPLE__) +#if (defined __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1060) uint64_t curthreadid; pthread_threadid_np(NULL, &curthreadid); return (pid_t)curthreadid; -#else +#else /* __MAC_OS_X_VERSION_MIN_REQUIRED */ + return (pid_t)pthread_self; +#endif /* __MAC_OS_X_VERSION_MIN_REQUIRED */ +#else /* __APPLE__*/ return (pid_t)syscall(SYS_gettid); #endif /* __FreeBSD__, __APPLE__*/ } diff --git a/src/common.h b/src/common.h index 51d2bba5..667fe9d7 100644 --- a/src/common.h +++ b/src/common.h @@ -203,10 +203,21 @@ #define NETDATA_OS_TYPE "linux" #endif /* __FreeBSD__, __APPLE__*/ -#include "statistical.h" -#include "socket.h" +typedef enum rrdcalc_status { + RRDCALC_STATUS_REMOVED = -2, + RRDCALC_STATUS_UNDEFINED = -1, + RRDCALC_STATUS_UNINITIALIZED = 0, + RRDCALC_STATUS_CLEAR = 1, + RRDCALC_STATUS_RAISED = 2, + RRDCALC_STATUS_WARNING = 3, + RRDCALC_STATUS_CRITICAL = 4 +} RRDCALC_STATUS; + #include "eval.h" #include "health.h" + +#include "statistical.h" +#include "socket.h" #include "rrd.h" #include "plugin_tc.h" #include "plugins_d.h" @@ -232,12 +243,14 @@ extern char *netdata_configured_hostname; extern char *netdata_configured_config_dir; extern char *netdata_configured_log_dir; +extern char *netdata_configured_plugins_dir_base; extern char *netdata_configured_plugins_dir; extern char *netdata_configured_web_dir; extern char *netdata_configured_cache_dir; extern char *netdata_configured_varlib_dir; extern char *netdata_configured_home_dir; extern char *netdata_configured_host_prefix; +extern char *netdata_configured_timezone; extern void netdata_fix_chart_id(char *s); extern void netdata_fix_chart_name(char *s); @@ -166,7 +166,7 @@ static inline calculated_number eval_variable(EVAL_EXPRESSION *exp, EVAL_VARIABL } if(exp->rrdcalc && health_variable_lookup(v->name, v->hash, exp->rrdcalc, &n)) { - buffer_sprintf(exp->error_msg, "[ $%s = ", v->name); + buffer_sprintf(exp->error_msg, "[ ${%s} = ", v->name); print_parsed_as_constant(exp->error_msg, n); buffer_strcat(exp->error_msg, " ] "); return n; @@ -232,7 +232,7 @@ calculated_number eval_equal(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) { if(isinf(n1) && isinf(n2)) return 1; if(isnan(n1) || isnan(n2)) return 0; if(isinf(n1) || isinf(n2)) return 0; - return n1 == n2; + return calculated_number_equal(n1, n2); } calculated_number eval_not_equal(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) { return !eval_equal(exp, op, error); @@ -355,7 +355,7 @@ static inline calculated_number eval_node(EVAL_EXPRESSION *exp, EVAL_NODE *op, i static inline void print_parsed_as_variable(BUFFER *out, EVAL_VARIABLE *v, int *error) { (void)error; - buffer_sprintf(out, "$%s", v->name); + buffer_sprintf(out, "${%s}", v->name); } static inline void print_parsed_as_constant(BUFFER *out, calculated_number n) { @@ -703,17 +703,31 @@ static inline int parse_variable(const char **string, char *buffer, size_t len) const char *s = *string; // $ - if(s[0] == '$') { + if(*s == '$') { size_t i = 0; s++; - while(*s && !isvariableterm(*s) && i < len) - buffer[i++] = *s++; + if(*s == '{') { + // ${variable_name} + + s++; + while (*s && *s != '}' && i < len) + buffer[i++] = *s++; + + if(*s == '}') + s++; + } + else { + // $variable_name + + while (*s && !isvariableterm(*s) && i < len) + buffer[i++] = *s++; + } buffer[i] = '\0'; - if(buffer[0]) { - *string = &s[0]; + if (buffer[0]) { + *string = s; return 1; } } @@ -14,7 +14,7 @@ typedef struct eval_expression { const char *source; const char *parsed_as; - int *status; + RRDCALC_STATUS *status; calculated_number *this; time_t *after; time_t *before; diff --git a/src/freebsd_devstat.c b/src/freebsd_devstat.c index 5b0687d5..2ed64ad4 100644 --- a/src/freebsd_devstat.c +++ b/src/freebsd_devstat.c @@ -27,10 +27,15 @@ struct disk { struct prev_dstat { collected_number bytes_read; collected_number bytes_write; + collected_number bytes_free; collected_number operations_read; collected_number operations_write; + collected_number operations_other; + collected_number operations_free; collected_number duration_read_ms; collected_number duration_write_ms; + collected_number duration_other_ms; + collected_number duration_free_ms; collected_number busy_time_ms; } prev_dstat; @@ -39,10 +44,13 @@ struct disk { RRDSET *st_io; RRDDIM *rd_io_in; RRDDIM *rd_io_out; + RRDDIM *rd_io_free; RRDSET *st_ops; RRDDIM *rd_ops_in; RRDDIM *rd_ops_out; + RRDDIM *rd_ops_other; + RRDDIM *rd_ops_free; RRDSET *st_qops; RRDDIM *rd_qops; @@ -53,14 +61,19 @@ struct disk { RRDSET *st_iotime; RRDDIM *rd_iotime_in; RRDDIM *rd_iotime_out; + RRDDIM *rd_iotime_other; + RRDDIM *rd_iotime_free; RRDSET *st_await; RRDDIM *rd_await_in; RRDDIM *rd_await_out; + RRDDIM *rd_await_other; + RRDDIM *rd_await_free; RRDSET *st_avagsz; RRDDIM *rd_avagsz_in; RRDDIM *rd_avagsz_out; + RRDDIM *rd_avagsz_free; RRDSET *st_svctm; RRDDIM *rd_svctm; @@ -244,7 +257,8 @@ int do_kern_devstat(int update_every, usec_t dt) { for (i = 0; i < numdevs; i++) { if (likely(do_system_io)) { - if (((dstat[i].device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_DIRECT) || ((dstat[i].device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_STORARRAY)) { + if (((dstat[i].device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_DIRECT) || + ((dstat[i].device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_STORARRAY)) { total_disk_kbytes_read += dstat[i].bytes[DEVSTAT_READ] / KILO_FACTOR; total_disk_kbytes_write += dstat[i].bytes[DEVSTAT_WRITE] / KILO_FACTOR; } @@ -254,11 +268,14 @@ int do_kern_devstat(int update_every, usec_t dt) { if ((dstat[i].device_type & DEVSTAT_TYPE_PASS) == DEVSTAT_TYPE_PASS) continue; - if (((dstat[i].device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_DIRECT) || ((dstat[i].device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_STORARRAY)) { + if (((dstat[i].device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_DIRECT) || + ((dstat[i].device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_STORARRAY)) { char disk[DEVSTAT_NAME_LEN + MAX_INT_DIGITS + 1]; struct cur_dstat { collected_number duration_read_ms; collected_number duration_write_ms; + collected_number duration_other_ms; + collected_number duration_free_ms; collected_number busy_time_ms; } cur_dstat; @@ -299,12 +316,19 @@ int do_kern_devstat(int update_every, usec_t dt) { dm->prev_dstat.bytes_read = dstat[i].bytes[DEVSTAT_READ]; dm->prev_dstat.bytes_write = dstat[i].bytes[DEVSTAT_WRITE]; + dm->prev_dstat.bytes_free = dstat[i].bytes[DEVSTAT_FREE]; dm->prev_dstat.operations_read = dstat[i].operations[DEVSTAT_READ]; dm->prev_dstat.operations_write = dstat[i].operations[DEVSTAT_WRITE]; + dm->prev_dstat.operations_other = dstat[i].operations[DEVSTAT_NO_DATA]; + dm->prev_dstat.operations_free = dstat[i].operations[DEVSTAT_FREE]; dm->prev_dstat.duration_read_ms = dstat[i].duration[DEVSTAT_READ].sec * 1000 + dstat[i].duration[DEVSTAT_READ].frac * BINTIME_SCALE; dm->prev_dstat.duration_write_ms = dstat[i].duration[DEVSTAT_WRITE].sec * 1000 - + dstat[i].duration[DEVSTAT_READ].frac * BINTIME_SCALE; + + dstat[i].duration[DEVSTAT_WRITE].frac * BINTIME_SCALE; + dm->prev_dstat.duration_other_ms = dstat[i].duration[DEVSTAT_NO_DATA].sec * 1000 + + dstat[i].duration[DEVSTAT_NO_DATA].frac * BINTIME_SCALE; + dm->prev_dstat.duration_free_ms = dstat[i].duration[DEVSTAT_FREE].sec * 1000 + + dstat[i].duration[DEVSTAT_FREE].frac * BINTIME_SCALE; dm->prev_dstat.busy_time_ms = dstat[i].busy_time.sec * 1000 + dstat[i].busy_time.frac * BINTIME_SCALE; } @@ -312,13 +336,20 @@ int do_kern_devstat(int update_every, usec_t dt) { cur_dstat.duration_read_ms = dstat[i].duration[DEVSTAT_READ].sec * 1000 + dstat[i].duration[DEVSTAT_READ].frac * BINTIME_SCALE; cur_dstat.duration_write_ms = dstat[i].duration[DEVSTAT_WRITE].sec * 1000 - + dstat[i].duration[DEVSTAT_READ].frac * BINTIME_SCALE; + + dstat[i].duration[DEVSTAT_WRITE].frac * BINTIME_SCALE; + cur_dstat.duration_other_ms = dstat[i].duration[DEVSTAT_NO_DATA].sec * 1000 + + dstat[i].duration[DEVSTAT_NO_DATA].frac * BINTIME_SCALE; + cur_dstat.duration_free_ms = dstat[i].duration[DEVSTAT_FREE].sec * 1000 + + dstat[i].duration[DEVSTAT_FREE].frac * BINTIME_SCALE; + cur_dstat.busy_time_ms = dstat[i].busy_time.sec * 1000 + dstat[i].busy_time.frac * BINTIME_SCALE; // -------------------------------------------------------------------- if(dm->do_io == CONFIG_BOOLEAN_YES || (dm->do_io == CONFIG_BOOLEAN_AUTO && - (dstat[i].bytes[DEVSTAT_READ] || dstat[i].bytes[DEVSTAT_WRITE]))) { + (dstat[i].bytes[DEVSTAT_READ] || + dstat[i].bytes[DEVSTAT_WRITE] || + dstat[i].bytes[DEVSTAT_FREE]))) { if (unlikely(!dm->st_io)) { dm->st_io = rrdset_create_localhost("disk", disk, @@ -327,6 +358,8 @@ int do_kern_devstat(int update_every, usec_t dt) { "disk.io", "Disk I/O Bandwidth", "kilobytes/s", + "freebsd", + "devstat", 2000, update_every, RRDSET_TYPE_AREA @@ -336,18 +369,24 @@ int do_kern_devstat(int update_every, usec_t dt) { RRD_ALGORITHM_INCREMENTAL); dm->rd_io_out = rrddim_add(dm->st_io, "writes", NULL, -1, KILO_FACTOR, RRD_ALGORITHM_INCREMENTAL); + dm->rd_io_free = rrddim_add(dm->st_io, "frees", NULL, -1, KILO_FACTOR, + RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(dm->st_io); - rrddim_set_by_pointer(dm->st_io, dm->rd_io_in, dstat[i].bytes[DEVSTAT_READ]); - rrddim_set_by_pointer(dm->st_io, dm->rd_io_out, dstat[i].bytes[DEVSTAT_WRITE]); + rrddim_set_by_pointer(dm->st_io, dm->rd_io_in, dstat[i].bytes[DEVSTAT_READ]); + rrddim_set_by_pointer(dm->st_io, dm->rd_io_out, dstat[i].bytes[DEVSTAT_WRITE]); + rrddim_set_by_pointer(dm->st_io, dm->rd_io_free, dstat[i].bytes[DEVSTAT_FREE]); rrdset_done(dm->st_io); } // -------------------------------------------------------------------- if(dm->do_ops == CONFIG_BOOLEAN_YES || (dm->do_ops == CONFIG_BOOLEAN_AUTO && - (dstat[i].operations[DEVSTAT_READ] || dstat[i].operations[DEVSTAT_WRITE]))) { + (dstat[i].operations[DEVSTAT_READ] || + dstat[i].operations[DEVSTAT_WRITE] || + dstat[i].operations[DEVSTAT_NO_DATA] || + dstat[i].operations[DEVSTAT_FREE]))) { if (unlikely(!dm->st_ops)) { dm->st_ops = rrdset_create_localhost("disk_ops", disk, @@ -356,6 +395,8 @@ int do_kern_devstat(int update_every, usec_t dt) { "disk.ops", "Disk Completed I/O Operations", "operations/s", + "freebsd", + "devstat", 2001, update_every, RRDSET_TYPE_LINE @@ -363,14 +404,21 @@ int do_kern_devstat(int update_every, usec_t dt) { rrdset_flag_set(dm->st_ops, RRDSET_FLAG_DETAIL); - dm->rd_ops_in = rrddim_add(dm->st_ops, "reads", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - dm->rd_ops_out = rrddim_add(dm->st_ops, "writes", NULL, -1, 1, - RRD_ALGORITHM_INCREMENTAL); + dm->rd_ops_in = rrddim_add(dm->st_ops, "reads", NULL, 1, 1, + RRD_ALGORITHM_INCREMENTAL); + dm->rd_ops_out = rrddim_add(dm->st_ops, "writes", NULL, -1, 1, + RRD_ALGORITHM_INCREMENTAL); + dm->rd_ops_other = rrddim_add(dm->st_ops, "other", NULL, 1, 1, + RRD_ALGORITHM_INCREMENTAL); + dm->rd_ops_free = rrddim_add(dm->st_ops, "frees", NULL, -1, 1, + RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(dm->st_ops); - rrddim_set_by_pointer(dm->st_ops, dm->rd_ops_in, dstat[i].operations[DEVSTAT_READ]); - rrddim_set_by_pointer(dm->st_ops, dm->rd_ops_out, dstat[i].operations[DEVSTAT_WRITE]); + rrddim_set_by_pointer(dm->st_ops, dm->rd_ops_in, dstat[i].operations[DEVSTAT_READ]); + rrddim_set_by_pointer(dm->st_ops, dm->rd_ops_out, dstat[i].operations[DEVSTAT_WRITE]); + rrddim_set_by_pointer(dm->st_ops, dm->rd_ops_other, dstat[i].operations[DEVSTAT_NO_DATA]); + rrddim_set_by_pointer(dm->st_ops, dm->rd_ops_free, dstat[i].operations[DEVSTAT_FREE]); rrdset_done(dm->st_ops); } @@ -386,6 +434,8 @@ int do_kern_devstat(int update_every, usec_t dt) { "disk.qops", "Disk Current I/O Operations", "operations", + "freebsd", + "devstat", 2002, update_every, RRDSET_TYPE_LINE @@ -413,6 +463,8 @@ int do_kern_devstat(int update_every, usec_t dt) { "disk.util", "Disk Utilization Time", "% of time working", + "freebsd", + "devstat", 2004, update_every, RRDSET_TYPE_AREA @@ -432,7 +484,10 @@ int do_kern_devstat(int update_every, usec_t dt) { // -------------------------------------------------------------------- if(dm->do_iotime == CONFIG_BOOLEAN_YES || (dm->do_iotime == CONFIG_BOOLEAN_AUTO && - (cur_dstat.duration_read_ms || cur_dstat.duration_write_ms))) { + (cur_dstat.duration_read_ms || + cur_dstat.duration_write_ms || + cur_dstat.duration_other_ms || + cur_dstat.duration_free_ms))) { if (unlikely(!dm->st_iotime)) { dm->st_iotime = rrdset_create_localhost("disk_iotime", disk, @@ -441,6 +496,8 @@ int do_kern_devstat(int update_every, usec_t dt) { "disk.iotime", "Disk Total I/O Time", "milliseconds/s", + "freebsd", + "devstat", 2022, update_every, RRDSET_TYPE_LINE @@ -448,15 +505,21 @@ int do_kern_devstat(int update_every, usec_t dt) { rrdset_flag_set(dm->st_iotime, RRDSET_FLAG_DETAIL); - dm->rd_iotime_in = rrddim_add(dm->st_iotime, "reads", NULL, 1, 1, - RRD_ALGORITHM_INCREMENTAL); - dm->rd_iotime_out = rrddim_add(dm->st_iotime, "writes", NULL, -1, 1, - RRD_ALGORITHM_INCREMENTAL); + dm->rd_iotime_in = rrddim_add(dm->st_iotime, "reads", NULL, 1, 1, + RRD_ALGORITHM_INCREMENTAL); + dm->rd_iotime_out = rrddim_add(dm->st_iotime, "writes", NULL, -1, 1, + RRD_ALGORITHM_INCREMENTAL); + dm->rd_iotime_other = rrddim_add(dm->st_iotime, "other", NULL, 1, 1, + RRD_ALGORITHM_INCREMENTAL); + dm->rd_iotime_free = rrddim_add(dm->st_iotime, "frees", NULL, -1, 1, + RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(dm->st_iotime); - rrddim_set_by_pointer(dm->st_iotime, dm->rd_iotime_in, cur_dstat.duration_read_ms); - rrddim_set_by_pointer(dm->st_iotime, dm->rd_iotime_out, cur_dstat.duration_write_ms); + rrddim_set_by_pointer(dm->st_iotime, dm->rd_iotime_in, cur_dstat.duration_read_ms); + rrddim_set_by_pointer(dm->st_iotime, dm->rd_iotime_out, cur_dstat.duration_write_ms); + rrddim_set_by_pointer(dm->st_iotime, dm->rd_iotime_other, cur_dstat.duration_other_ms); + rrddim_set_by_pointer(dm->st_iotime, dm->rd_iotime_free, cur_dstat.duration_free_ms); rrdset_done(dm->st_iotime); } @@ -469,7 +532,10 @@ int do_kern_devstat(int update_every, usec_t dt) { // -------------------------------------------------------------------- if(dm->do_await == CONFIG_BOOLEAN_YES || (dm->do_await == CONFIG_BOOLEAN_AUTO && - (dstat[i].operations[DEVSTAT_READ] || dstat[i].operations[DEVSTAT_WRITE]))) { + (dstat[i].operations[DEVSTAT_READ] || + dstat[i].operations[DEVSTAT_WRITE] || + dstat[i].operations[DEVSTAT_NO_DATA] || + dstat[i].operations[DEVSTAT_FREE]))) { if (unlikely(!dm->st_await)) { dm->st_await = rrdset_create_localhost("disk_await", disk, @@ -478,6 +544,8 @@ int do_kern_devstat(int update_every, usec_t dt) { "disk.await", "Average Completed I/O Operation Time", "ms per operation", + "freebsd", + "devstat", 2005, update_every, RRDSET_TYPE_LINE @@ -485,9 +553,13 @@ int do_kern_devstat(int update_every, usec_t dt) { rrdset_flag_set(dm->st_await, RRDSET_FLAG_DETAIL); - dm->rd_await_in = rrddim_add(dm->st_await, "reads", NULL, 1, 1, + dm->rd_await_in = rrddim_add(dm->st_await, "reads", NULL, 1, 1, + RRD_ALGORITHM_ABSOLUTE); + dm->rd_await_out = rrddim_add(dm->st_await, "writes", NULL, -1, 1, RRD_ALGORITHM_ABSOLUTE); - dm->rd_await_out = rrddim_add(dm->st_await, "writes", NULL, -1, 1, + dm->rd_await_other = rrddim_add(dm->st_await, "other", NULL, 1, 1, + RRD_ALGORITHM_ABSOLUTE); + dm->rd_await_free = rrddim_add(dm->st_await, "frees", NULL, -1, 1, RRD_ALGORITHM_ABSOLUTE); } else rrdset_next(dm->st_await); @@ -506,13 +578,29 @@ int do_kern_devstat(int update_every, usec_t dt) { (dstat[i].operations[DEVSTAT_WRITE] - dm->prev_dstat.operations_write) : 0); + rrddim_set_by_pointer(dm->st_await, dm->rd_await_other, + (dstat[i].operations[DEVSTAT_NO_DATA] - + dm->prev_dstat.operations_other) ? + (cur_dstat.duration_other_ms - dm->prev_dstat.duration_other_ms) / + (dstat[i].operations[DEVSTAT_NO_DATA] - + dm->prev_dstat.operations_other) : + 0); + rrddim_set_by_pointer(dm->st_await, dm->rd_await_free, + (dstat[i].operations[DEVSTAT_FREE] - + dm->prev_dstat.operations_free) ? + (cur_dstat.duration_free_ms - dm->prev_dstat.duration_free_ms) / + (dstat[i].operations[DEVSTAT_FREE] - + dm->prev_dstat.operations_free) : + 0); rrdset_done(dm->st_await); } // -------------------------------------------------------------------- if(dm->do_avagsz == CONFIG_BOOLEAN_YES || (dm->do_avagsz == CONFIG_BOOLEAN_AUTO && - (dstat[i].operations[DEVSTAT_READ] || dstat[i].operations[DEVSTAT_WRITE]))) { + (dstat[i].operations[DEVSTAT_READ] || + dstat[i].operations[DEVSTAT_WRITE] || + dstat[i].operations[DEVSTAT_FREE]))) { if (unlikely(!dm->st_avagsz)) { dm->st_avagsz = rrdset_create_localhost("disk_avgsz", disk, @@ -521,6 +609,8 @@ int do_kern_devstat(int update_every, usec_t dt) { "disk.avgsz", "Average Completed I/O Operation Bandwidth", "kilobytes per operation", + "freebsd", + "devstat", 2006, update_every, RRDSET_TYPE_AREA @@ -528,10 +618,12 @@ int do_kern_devstat(int update_every, usec_t dt) { rrdset_flag_set(dm->st_avagsz, RRDSET_FLAG_DETAIL); - dm->rd_avagsz_in = rrddim_add(dm->st_avagsz, "reads", NULL, 1, KILO_FACTOR, - RRD_ALGORITHM_ABSOLUTE); - dm->rd_avagsz_out = rrddim_add(dm->st_avagsz, "writes", NULL, -1, KILO_FACTOR, - RRD_ALGORITHM_ABSOLUTE); + dm->rd_avagsz_in = rrddim_add(dm->st_avagsz, "reads", NULL, 1, KILO_FACTOR, + RRD_ALGORITHM_ABSOLUTE); + dm->rd_avagsz_out = rrddim_add(dm->st_avagsz, "writes", NULL, -1, KILO_FACTOR, + RRD_ALGORITHM_ABSOLUTE); + dm->rd_avagsz_free = rrddim_add(dm->st_avagsz, "frees", NULL, -1, KILO_FACTOR, + RRD_ALGORITHM_ABSOLUTE); } else rrdset_next(dm->st_avagsz); @@ -549,13 +641,23 @@ int do_kern_devstat(int update_every, usec_t dt) { (dstat[i].operations[DEVSTAT_WRITE] - dm->prev_dstat.operations_write) : 0); + rrddim_set_by_pointer(dm->st_avagsz, dm->rd_avagsz_free, + (dstat[i].operations[DEVSTAT_FREE] - + dm->prev_dstat.operations_free) ? + (dstat[i].bytes[DEVSTAT_FREE] - dm->prev_dstat.bytes_free) / + (dstat[i].operations[DEVSTAT_FREE] - + dm->prev_dstat.operations_free) : + 0); rrdset_done(dm->st_avagsz); } // -------------------------------------------------------------------- if(dm->do_svctm == CONFIG_BOOLEAN_YES || (dm->do_svctm == CONFIG_BOOLEAN_AUTO && - (dstat[i].operations[DEVSTAT_READ] || dstat[i].operations[DEVSTAT_WRITE]))) { + (dstat[i].operations[DEVSTAT_READ] || + dstat[i].operations[DEVSTAT_WRITE] || + dstat[i].operations[DEVSTAT_NO_DATA] || + dstat[i].operations[DEVSTAT_FREE]))) { if (unlikely(!dm->st_svctm)) { dm->st_svctm = rrdset_create_localhost("disk_svctm", disk, @@ -564,6 +666,8 @@ int do_kern_devstat(int update_every, usec_t dt) { "disk.svctm", "Average Service Time", "ms per operation", + "freebsd", + "devstat", 2007, update_every, RRDSET_TYPE_LINE @@ -578,10 +682,14 @@ int do_kern_devstat(int update_every, usec_t dt) { rrddim_set_by_pointer(dm->st_svctm, dm->rd_svctm, ((dstat[i].operations[DEVSTAT_READ] - dm->prev_dstat.operations_read) + - (dstat[i].operations[DEVSTAT_WRITE] - dm->prev_dstat.operations_write)) ? + (dstat[i].operations[DEVSTAT_WRITE] - dm->prev_dstat.operations_write) + + (dstat[i].operations[DEVSTAT_NO_DATA] - dm->prev_dstat.operations_other) + + (dstat[i].operations[DEVSTAT_FREE] - dm->prev_dstat.operations_free)) ? (cur_dstat.busy_time_ms - dm->prev_dstat.busy_time_ms) / ((dstat[i].operations[DEVSTAT_READ] - dm->prev_dstat.operations_read) + - (dstat[i].operations[DEVSTAT_WRITE] - dm->prev_dstat.operations_write)) : + (dstat[i].operations[DEVSTAT_WRITE] - dm->prev_dstat.operations_write) + + (dstat[i].operations[DEVSTAT_NO_DATA] - dm->prev_dstat.operations_other) + + (dstat[i].operations[DEVSTAT_FREE] - dm->prev_dstat.operations_free)) : 0); rrdset_done(dm->st_svctm); } @@ -590,10 +698,15 @@ int do_kern_devstat(int update_every, usec_t dt) { dm->prev_dstat.bytes_read = dstat[i].bytes[DEVSTAT_READ]; dm->prev_dstat.bytes_write = dstat[i].bytes[DEVSTAT_WRITE]; + dm->prev_dstat.bytes_free = dstat[i].bytes[DEVSTAT_FREE]; dm->prev_dstat.operations_read = dstat[i].operations[DEVSTAT_READ]; dm->prev_dstat.operations_write = dstat[i].operations[DEVSTAT_WRITE]; + dm->prev_dstat.operations_other = dstat[i].operations[DEVSTAT_NO_DATA]; + dm->prev_dstat.operations_free = dstat[i].operations[DEVSTAT_FREE]; dm->prev_dstat.duration_read_ms = cur_dstat.duration_read_ms; dm->prev_dstat.duration_write_ms = cur_dstat.duration_write_ms; + dm->prev_dstat.duration_other_ms = cur_dstat.duration_other_ms; + dm->prev_dstat.duration_free_ms = cur_dstat.duration_free_ms; dm->prev_dstat.busy_time_ms = cur_dstat.busy_time_ms; } } @@ -613,6 +726,8 @@ int do_kern_devstat(int update_every, usec_t dt) { NULL, "Disk I/O", "kilobytes/s", + "freebsd", + "devstat", 150, update_every, RRDSET_TYPE_AREA diff --git a/src/freebsd_getifaddrs.c b/src/freebsd_getifaddrs.c index 1a4448bd..94c0a6a4 100644 --- a/src/freebsd_getifaddrs.c +++ b/src/freebsd_getifaddrs.c @@ -228,6 +228,8 @@ int do_getifaddrs(int update_every, usec_t dt) { NULL, "IPv4 Bandwidth", "kilobits/s", + "freebsd", + "getifaddrs", 500, update_every, RRDSET_TYPE_AREA @@ -265,6 +267,8 @@ int do_getifaddrs(int update_every, usec_t dt) { NULL, "IPv6 Bandwidth", "kilobits/s", + "freebsd", + "getifaddrs", 500, update_every, RRDSET_TYPE_AREA @@ -333,6 +337,8 @@ int do_getifaddrs(int update_every, usec_t dt) { "net.net", "Bandwidth", "kilobits/s", + "freebsd", + "getifaddrs", 7000, update_every, RRDSET_TYPE_AREA @@ -360,6 +366,8 @@ int do_getifaddrs(int update_every, usec_t dt) { "net.packets", "Packets", "packets/s", + "freebsd", + "getifaddrs", 7001, update_every, RRDSET_TYPE_LINE @@ -397,6 +405,8 @@ int do_getifaddrs(int update_every, usec_t dt) { "net.errors", "Interface Errors", "errors/s", + "freebsd", + "getifaddrs", 7002, update_every, RRDSET_TYPE_LINE @@ -429,6 +439,8 @@ int do_getifaddrs(int update_every, usec_t dt) { "net.drops", "Interface Drops", "drops/s", + "freebsd", + "getifaddrs", 7003, update_every, RRDSET_TYPE_LINE @@ -462,6 +474,8 @@ int do_getifaddrs(int update_every, usec_t dt) { "net.events", "Network Interface Events", "events/s", + "freebsd", + "getifaddrs", 7006, update_every, RRDSET_TYPE_LINE diff --git a/src/freebsd_getmntinfo.c b/src/freebsd_getmntinfo.c index e7ca56b5..66be5331 100644 --- a/src/freebsd_getmntinfo.c +++ b/src/freebsd_getmntinfo.c @@ -223,6 +223,8 @@ int do_getmntinfo(int update_every, usec_t dt) { "disk.space", title, "GB", + "freebsd", + "getmntinfo", 2023, update_every, RRDSET_TYPE_STACKED @@ -260,6 +262,8 @@ int do_getmntinfo(int update_every, usec_t dt) { "disk.inodes", title, "Inodes", + "freebsd", + "getmntinfo", 2024, update_every, RRDSET_TYPE_STACKED diff --git a/src/freebsd_ipfw.c b/src/freebsd_ipfw.c index b89650a0..81264b3f 100644 --- a/src/freebsd_ipfw.c +++ b/src/freebsd_ipfw.c @@ -162,6 +162,8 @@ int do_ipfw(int update_every, usec_t dt) { NULL, "Memory allocated by rules", "bytes", + "freebsd", + "ipfw", 3005, update_every, RRDSET_TYPE_STACKED @@ -193,6 +195,8 @@ int do_ipfw(int update_every, usec_t dt) { NULL, "Packets", "packets/s", + "freebsd", + "ipfw", 3001, update_every, RRDSET_TYPE_STACKED @@ -208,6 +212,8 @@ int do_ipfw(int update_every, usec_t dt) { NULL, "Bytes", "bytes/s", + "freebsd", + "ipfw", 3002, update_every, RRDSET_TYPE_STACKED @@ -310,6 +316,8 @@ int do_ipfw(int update_every, usec_t dt) { NULL, "Active rules", "rules", + "freebsd", + "ipfw", 3003, update_every, RRDSET_TYPE_STACKED @@ -325,6 +333,8 @@ int do_ipfw(int update_every, usec_t dt) { NULL, "Expired rules", "rules", + "freebsd", + "ipfw", 3004, update_every, RRDSET_TYPE_STACKED diff --git a/src/freebsd_kstat_zfs.c b/src/freebsd_kstat_zfs.c index 17642994..1bd48d4b 100644 --- a/src/freebsd_kstat_zfs.c +++ b/src/freebsd_kstat_zfs.c @@ -1,9 +1,11 @@ #include "common.h" #include "zfs_common.h" -struct arcstats arcstats = { 0 }; +extern struct arcstats arcstats; +// -------------------------------------------------------------------------------------------------------------------- // kstat.zfs.misc.arcstats + int do_kstat_zfs_misc_arcstats(int update_every, usec_t dt) { (void)dt; @@ -103,15 +105,15 @@ int do_kstat_zfs_misc_arcstats(int update_every, usec_t dt) { int arc_sys_free[5]; } mibs; - l2exist = -1; + arcstats.l2exist = -1; if(unlikely(sysctlbyname("kstat.zfs.misc.arcstats.l2_size", &l2_size, &uint64_t_size, NULL, 0))) return 0; if(likely(l2_size)) - l2exist = 1; + arcstats.l2exist = 1; else - l2exist = 0; + arcstats.l2exist = 0; GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.hits", mibs.hits, arcstats.hits); GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.misses", mibs.misses, arcstats.misses); @@ -205,8 +207,92 @@ int do_kstat_zfs_misc_arcstats(int update_every, usec_t dt) { // missing mib: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.arc_need_free", mibs.arc_need_free, arcstats.arc_need_free); // missing mib: GETSYSCTL_SIMPLE("kstat.zfs.misc.arcstats.arc_sys_free", mibs.arc_sys_free, arcstats.arc_sys_free); - generate_charts_arcstats(update_every); - generate_charts_arc_summary(update_every); + generate_charts_arcstats("freebsd", update_every); + generate_charts_arc_summary("freebsd", update_every); + + return 0; +} + +// -------------------------------------------------------------------------------------------------------------------- +// kstat.zfs.misc.zio_trim + +int do_kstat_zfs_misc_zio_trim(int update_every, usec_t dt) { + (void)dt; + static int mib_bytes[5] = {0, 0, 0, 0, 0}, mib_success[5] = {0, 0, 0, 0, 0}, + mib_failed[5] = {0, 0, 0, 0, 0}, mib_unsupported[5] = {0, 0, 0, 0, 0}; + uint64_t bytes, success, failed, unsupported; + + if (unlikely(GETSYSCTL_SIMPLE("kstat.zfs.misc.zio_trim.bytes", mib_bytes, bytes) || + GETSYSCTL_SIMPLE("kstat.zfs.misc.zio_trim.success", mib_success, success) || + GETSYSCTL_SIMPLE("kstat.zfs.misc.zio_trim.failed", mib_failed, failed) || + GETSYSCTL_SIMPLE("kstat.zfs.misc.zio_trim.unsupported", mib_unsupported, unsupported))) { + error("DISABLED: zfs.trim_bytes chart"); + error("DISABLED: zfs.trim_success chart"); + error("DISABLED: kstat.zfs.misc.zio_trim module"); + return 1; + } else { + + // -------------------------------------------------------------------- + + static RRDSET *st_bytes = NULL; + static RRDDIM *rd_bytes = NULL; + + if (unlikely(!st_bytes)) { + st_bytes = rrdset_create_localhost( + "zfs", + "trim_bytes", + NULL, + "trim", + NULL, + "Successfully TRIMmed bytes", + "bytes", + "freebsd", + "zfs", + 2320, + update_every, + RRDSET_TYPE_LINE + ); + + rd_bytes = rrddim_add(st_bytes, "TRIMmed", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + } + else rrdset_next(st_bytes); + + rrddim_set_by_pointer(st_bytes, rd_bytes, bytes); + rrdset_done(st_bytes); + + // -------------------------------------------------------------------- + + static RRDSET *st_requests = NULL; + static RRDDIM *rd_successful = NULL, *rd_failed = NULL, *rd_unsupported = NULL; + + if (unlikely(!st_requests)) { + st_requests = rrdset_create_localhost( + "zfs", + "trim_requests", + NULL, + "trim", + NULL, + "TRIM requests", + "requests", + "freebsd", + "zfs", + 2321, + update_every, + RRDSET_TYPE_STACKED + ); + + rd_successful = rrddim_add(st_requests, "successful", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_failed = rrddim_add(st_requests, "failed", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_unsupported = rrddim_add(st_requests, "unsupported", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + } + else rrdset_next(st_requests); + + rrddim_set_by_pointer(st_requests, rd_successful, success); + rrddim_set_by_pointer(st_requests, rd_failed, failed); + rrddim_set_by_pointer(st_requests, rd_unsupported, unsupported); + rrdset_done(st_requests); + + } return 0; }
\ No newline at end of file diff --git a/src/freebsd_sysctl.c b/src/freebsd_sysctl.c index a87b872d..9f5615df 100644 --- a/src/freebsd_sysctl.c +++ b/src/freebsd_sysctl.c @@ -27,6 +27,62 @@ int system_pagesize = PAGE_SIZE; int number_of_cpus = 1; +#if __FreeBSD_version >= 1200029 +struct __vmmeter { + uint64_t v_swtch; + uint64_t v_trap; + uint64_t v_syscall; + uint64_t v_intr; + uint64_t v_soft; + uint64_t v_vm_faults; + uint64_t v_io_faults; + uint64_t v_cow_faults; + uint64_t v_cow_optim; + uint64_t v_zfod; + uint64_t v_ozfod; + uint64_t v_swapin; + uint64_t v_swapout; + uint64_t v_swappgsin; + uint64_t v_swappgsout; + uint64_t v_vnodein; + uint64_t v_vnodeout; + uint64_t v_vnodepgsin; + uint64_t v_vnodepgsout; + uint64_t v_intrans; + uint64_t v_reactivated; + uint64_t v_pdwakeups; + uint64_t v_pdpages; + uint64_t v_pdshortfalls; + uint64_t v_dfree; + uint64_t v_pfree; + uint64_t v_tfree; + uint64_t v_forks; + uint64_t v_vforks; + uint64_t v_rforks; + uint64_t v_kthreads; + uint64_t v_forkpages; + uint64_t v_vforkpages; + uint64_t v_rforkpages; + uint64_t v_kthreadpages; + u_int v_page_size; + u_int v_page_count; + u_int v_free_reserved; + u_int v_free_target; + u_int v_free_min; + u_int v_free_count; + u_int v_wire_count; + u_int v_active_count; + u_int v_inactive_target; + u_int v_inactive_count; + u_int v_laundry_count; + u_int v_pageout_free_min; + u_int v_interrupt_free_min; + u_int v_free_severe; +}; +typedef struct __vmmeter vmmeter_t; +#else +typedef struct vmmeter vmmeter_t; +#endif // -------------------------------------------------------------------------------------------------------------------- // FreeBSD plugin initialization @@ -77,16 +133,19 @@ int do_vm_loadavg(int update_every, usec_t dt){ static RRDDIM *rd_load1 = NULL, *rd_load2 = NULL, *rd_load3 = NULL; if (unlikely(!st)) { - st = rrdset_create_localhost("system", - "load", - NULL, - "load", - NULL, - "System Load Average", - "load", - 100, - (update_every < MIN_LOADAVG_UPDATE_EVERY) ? - MIN_LOADAVG_UPDATE_EVERY : update_every, RRDSET_TYPE_LINE + st = rrdset_create_localhost( + "system", + "load", + NULL, + "load", + NULL, + "System Load Average", + "load", + "freebsd", + "vm.loadavg", + 100, + (update_every < MIN_LOADAVG_UPDATE_EVERY) ? + MIN_LOADAVG_UPDATE_EVERY : update_every, RRDSET_TYPE_LINE ); rd_load1 = rrddim_add(st, "load1", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); rd_load2 = rrddim_add(st, "load5", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); @@ -143,16 +202,19 @@ int do_vm_vmtotal(int update_every, usec_t dt) { static RRDDIM *rd = NULL; if (unlikely(!st)) { - st = rrdset_create_localhost("system", - "active_processes", - NULL, - "processes", - NULL, - "System Active Processes", - "processes", - 750, - update_every, - RRDSET_TYPE_LINE + st = rrdset_create_localhost( + "system", + "active_processes", + NULL, + "processes", + NULL, + "System Active Processes", + "processes", + "freebsd", + "vm.vmtotal", + 750, + update_every, + RRDSET_TYPE_LINE ); rd = rrddim_add(st, "active", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); } @@ -169,16 +231,19 @@ int do_vm_vmtotal(int update_every, usec_t dt) { static RRDDIM *rd_running = NULL, *rd_blocked = NULL; if (unlikely(!st)) { - st = rrdset_create_localhost("system", - "processes", - NULL, - "processes", - NULL, - "System Processes", - "processes", - 600, - update_every, - RRDSET_TYPE_LINE + st = rrdset_create_localhost( + "system", + "processes", + NULL, + "processes", + NULL, + "System Processes", + "processes", + "freebsd", + "vm.vmtotal", + 600, + update_every, + RRDSET_TYPE_LINE ); rd_running = rrddim_add(st, "running", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); @@ -198,16 +263,19 @@ int do_vm_vmtotal(int update_every, usec_t dt) { static RRDDIM *rd = NULL; if (unlikely(!st)) { - st = rrdset_create_localhost("mem", - "committed", - NULL, - "system", - NULL, - "Committed (Allocated) Memory", - "MB", - 5000, - update_every, - RRDSET_TYPE_AREA + st = rrdset_create_localhost( + "mem", + "committed", + NULL, + "system", + NULL, + "Committed (Allocated) Memory", + "MB", + "freebsd", + "vm.vmtotal", + 5000, + update_every, + RRDSET_TYPE_AREA ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); @@ -254,15 +322,18 @@ int do_kern_cp_time(int update_every, usec_t dt) { static RRDDIM *rd_nice = NULL, *rd_system = NULL, *rd_user = NULL, *rd_interrupt = NULL, *rd_idle = NULL; if (unlikely(!st)) { - st = rrdset_create_localhost("system", - "cpu", - NULL, - "cpu", - "system.cpu", - "Total CPU utilization", - "percentage", - 100, update_every, - RRDSET_TYPE_STACKED + st = rrdset_create_localhost( + "system", + "cpu", + NULL, + "cpu", + "system.cpu", + "Total CPU utilization", + "percentage", + "freebsd", + "kern.cp_time", + 100, update_every, + RRDSET_TYPE_STACKED ); rd_nice = rrddim_add(st, "nice", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); @@ -332,16 +403,19 @@ int do_kern_cp_times(int update_every, usec_t dt) { for (i = 0; i < number_of_cpus; i++) { if (unlikely(!all_cpu_charts[i].st)) { snprintfz(all_cpu_charts[i].cpuid, MAX_INT_DIGITS, "cpu%d", i); - all_cpu_charts[i].st = rrdset_create_localhost("cpu", - all_cpu_charts[i].cpuid, - NULL, - "utilization", - "cpu.cpu", - "Core utilization", - "percentage", - 1000, - update_every, - RRDSET_TYPE_STACKED + all_cpu_charts[i].st = rrdset_create_localhost( + "cpu", + all_cpu_charts[i].cpuid, + NULL, + "utilization", + "cpu.cpu", + "Core utilization", + "percentage", + "freebsd", + "kern.cp_times", + 1000, + update_every, + RRDSET_TYPE_STACKED ); all_cpu_charts[i].rd_nice = rrddim_add(all_cpu_charts[i].st, "nice", NULL, 1, 1, @@ -413,18 +487,22 @@ int do_dev_cpu_temperature(int update_every, usec_t dt) { } if (unlikely(!st)) { - st = rrdset_create_localhost("cpu", - "temperature", - NULL, - "temperature", - "cpu.temperatute", - "Core temperature", - "degree", - 1050, - update_every, - RRDSET_TYPE_LINE + st = rrdset_create_localhost( + "cpu", + "temperature", + NULL, + "temperature", + "cpu.temperatute", + "Core temperature", + "Celsius", + "freebsd", + "dev.cpu.temperature", + 1050, + update_every, + RRDSET_TYPE_LINE ); - } else rrdset_next(st); + } + else rrdset_next(st); for (i = 0; i < number_of_cpus; i++) { if (unlikely(!rd_pcpu_temperature[i])) { @@ -443,6 +521,52 @@ int do_dev_cpu_temperature(int update_every, usec_t dt) { } // -------------------------------------------------------------------------------------------------------------------- +// dev.cpu.0.freq + +int do_dev_cpu_0_freq(int update_every, usec_t dt) { + (void)dt; + static int mib[4] = {0, 0, 0, 0}; + int cpufreq; + + if (unlikely(GETSYSCTL_SIMPLE("dev.cpu.0.freq", mib, cpufreq))) { + error("DISABLED: cpu.scaling_cur_freq chart"); + error("DISABLED: dev.cpu.0.freq module"); + return 1; + } else { + + // -------------------------------------------------------------------- + + static RRDSET *st = NULL; + static RRDDIM *rd = NULL; + + if (unlikely(!st)) { + st = rrdset_create_localhost( + "cpu", + "scaling_cur_freq", + NULL, + "cpufreq", + NULL, + "Current CPU Scaling Frequency", + "MHz", + "freebsd", + "dev.cpu.0.freq", + 5003, + update_every, + RRDSET_TYPE_LINE + ); + + rd = rrddim_add(st, "frequency", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); + } + else rrdset_next(st); + + rrddim_set_by_pointer(st, rd, cpufreq); + rrdset_done(st); + } + + return 0; +} + +// -------------------------------------------------------------------------------------------------------------------- // hw.intrcnt int do_hw_intcnt(int update_every, usec_t dt) { @@ -480,16 +604,19 @@ int do_hw_intcnt(int update_every, usec_t dt) { static RRDDIM *rd_intr = NULL; if (unlikely(!st_intr)) { - st_intr = rrdset_create_localhost("system", - "intr", - NULL, - "interrupts", - NULL, - "Total Hardware Interrupts", - "interrupts/s", - 900, - update_every, - RRDSET_TYPE_LINE + st_intr = rrdset_create_localhost( + "system", + "intr", + NULL, + "interrupts", + NULL, + "Total Hardware Interrupts", + "interrupts/s", + "freebsd", + "hw.intrcnt", + 900, + update_every, + RRDSET_TYPE_LINE ); rrdset_flag_set(st_intr, RRDSET_FLAG_DETAIL); @@ -519,20 +646,22 @@ int do_hw_intcnt(int update_every, usec_t dt) { // -------------------------------------------------------------------- static RRDSET *st_interrupts = NULL; - RRDDIM *rd_interrupts = NULL; void *p; if (unlikely(!st_interrupts)) - st_interrupts = rrdset_create_localhost("system", - "interrupts", - NULL, - "interrupts", - NULL, - "System interrupts", - "interrupts/s", - 1000, - update_every, - RRDSET_TYPE_STACKED + st_interrupts = rrdset_create_localhost( + "system", + "interrupts", + NULL, + "interrupts", + NULL, + "System interrupts", + "interrupts/s", + "freebsd", + "hw.intrcnt", + 1000, + update_every, + RRDSET_TYPE_STACKED ); else rrdset_next(st_interrupts); @@ -540,9 +669,11 @@ int do_hw_intcnt(int update_every, usec_t dt) { for (i = 0; i < nintr; i++) { p = intrnames + i * (MAXCOMLEN + 1); if (unlikely((intrcnt[i] != 0) && (*(char *) p != 0))) { - rd_interrupts = rrddim_find(st_interrupts, p); + RRDDIM *rd_interrupts = rrddim_find(st_interrupts, p); + if (unlikely(!rd_interrupts)) rd_interrupts = rrddim_add(st_interrupts, p, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rrddim_set_by_pointer(st_interrupts, rd_interrupts, intrcnt[i]); } } @@ -576,16 +707,19 @@ int do_vm_stats_sys_v_intr(int update_every, usec_t dt) { static RRDDIM *rd = NULL; if (unlikely(!st)) { - st = rrdset_create_localhost("system", - "dev_intr", - NULL, - "interrupts", - NULL, - "Device Interrupts", - "interrupts/s", - 1000, - update_every, - RRDSET_TYPE_LINE + st = rrdset_create_localhost( + "system", + "dev_intr", + NULL, + "interrupts", + NULL, + "Device Interrupts", + "interrupts/s", + "freebsd", + "vm.stats.sys.v_intr", + 1000, + update_every, + RRDSET_TYPE_LINE ); rd = rrddim_add(st, "interrupts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -619,16 +753,19 @@ int do_vm_stats_sys_v_soft(int update_every, usec_t dt) { static RRDDIM *rd = NULL; if (unlikely(!st)) { - st = rrdset_create_localhost("system", - "soft_intr", - NULL, - "interrupts", - NULL, - "Software Interrupts", - "interrupts/s", - 1100, - update_every, - RRDSET_TYPE_LINE + st = rrdset_create_localhost( + "system", + "soft_intr", + NULL, + "interrupts", + NULL, + "Software Interrupts", + "interrupts/s", + "freebsd", + "vm.stats.sys.v_soft", + 1100, + update_every, + RRDSET_TYPE_LINE ); rd = rrddim_add(st, "interrupts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -662,16 +799,19 @@ int do_vm_stats_sys_v_swtch(int update_every, usec_t dt) { static RRDDIM *rd = NULL; if (unlikely(!st)) { - st = rrdset_create_localhost("system", - "ctxt", - NULL, - "processes", - NULL, - "CPU Context Switches", - "context switches/s", - 800, - update_every, - RRDSET_TYPE_LINE + st = rrdset_create_localhost( + "system", + "ctxt", + NULL, + "processes", + NULL, + "CPU Context Switches", + "context switches/s", + "freebsd", + "vm.stats.sys.v_swtch", + 800, + update_every, + RRDSET_TYPE_LINE ); rd = rrddim_add(st, "switches", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -705,16 +845,19 @@ int do_vm_stats_sys_v_forks(int update_every, usec_t dt) { static RRDDIM *rd = NULL; if (unlikely(!st)) { - st = rrdset_create_localhost("system", - "forks", - NULL, - "processes", - NULL, - "Started Processes", - "processes/s", - 700, - update_every, - RRDSET_TYPE_LINE + st = rrdset_create_localhost( + "system", + "forks", + NULL, + "processes", + NULL, + "Started Processes", + "processes/s", + "freebsd", + "vm.stats.sys.v_swtch", + 700, + update_every, + RRDSET_TYPE_LINE ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); @@ -779,16 +922,19 @@ int do_vm_swap_info(int update_every, usec_t dt) { static RRDDIM *rd_free = NULL, *rd_used = NULL; if (unlikely(!st)) { - st = rrdset_create_localhost("system", - "swap", - NULL, - "swap", - NULL, - "System Swap", - "MB", - 201, - update_every, - RRDSET_TYPE_STACKED + st = rrdset_create_localhost( + "system", + "swap", + NULL, + "swap", + NULL, + "System Swap", + "MB", + "freebsd", + "vm.swap_info", + 201, + update_every, + RRDSET_TYPE_STACKED ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); @@ -813,7 +959,7 @@ int do_system_ram(int update_every, usec_t dt) { (void)dt; static int mib_active_count[4] = {0, 0, 0, 0}, mib_inactive_count[4] = {0, 0, 0, 0}, mib_wire_count[4] = {0, 0, 0, 0}, mib_cache_count[4] = {0, 0, 0, 0}, mib_vfs_bufspace[2] = {0, 0}, mib_free_count[4] = {0, 0, 0, 0}; - struct vmmeter vmmeter_data; + vmmeter_t vmmeter_data; int vfs_bufspace_count; if (unlikely(GETSYSCTL_SIMPLE("vm.stats.vm.v_active_count", mib_active_count, vmmeter_data.v_active_count) || @@ -825,7 +971,7 @@ int do_system_ram(int update_every, usec_t dt) { GETSYSCTL_SIMPLE("vfs.bufspace", mib_vfs_bufspace, vfs_bufspace_count) || GETSYSCTL_SIMPLE("vm.stats.vm.v_free_count", mib_free_count, vmmeter_data.v_free_count))) { error("DISABLED: system.ram chart"); - error("DISABLED: System.ram module"); + error("DISABLED: system.ram module"); return 1; } else { @@ -835,18 +981,20 @@ int do_system_ram(int update_every, usec_t dt) { static RRDDIM *rd_free = NULL, *rd_active = NULL, *rd_inactive = NULL, *rd_wired = NULL, *rd_cache = NULL, *rd_buffers = NULL; - st = rrdset_find_localhost("system.ram"); if (unlikely(!st)) { - st = rrdset_create_localhost("system", - "ram", - NULL, - "ram", - NULL, - "System RAM", - "MB", - 200, - update_every, - RRDSET_TYPE_STACKED + st = rrdset_create_localhost( + "system", + "ram", + NULL, + "ram", + NULL, + "System RAM", + "MB", + "freebsd", + "system.ram", + 200, + update_every, + RRDSET_TYPE_STACKED ); rd_free = rrddim_add(st, "free", NULL, system_pagesize, MEGA_FACTOR, RRD_ALGORITHM_ABSOLUTE); @@ -880,7 +1028,7 @@ int do_system_ram(int update_every, usec_t dt) { int do_vm_stats_sys_v_swappgs(int update_every, usec_t dt) { (void)dt; static int mib_swappgsin[4] = {0, 0, 0, 0}, mib_swappgsout[4] = {0, 0, 0, 0}; - struct vmmeter vmmeter_data; + vmmeter_t vmmeter_data; if (unlikely(GETSYSCTL_SIMPLE("vm.stats.vm.v_swappgsin", mib_swappgsin, vmmeter_data.v_swappgsin) || GETSYSCTL_SIMPLE("vm.stats.vm.v_swappgsout", mib_swappgsout, vmmeter_data.v_swappgsout))) { @@ -895,16 +1043,19 @@ int do_vm_stats_sys_v_swappgs(int update_every, usec_t dt) { static RRDDIM *rd_in = NULL, *rd_out = NULL; if (unlikely(!st)) { - st = rrdset_create_localhost("system", - "swapio", - NULL, - "swap", - NULL, - "Swap I/O", - "kilobytes/s", - 250, - update_every, - RRDSET_TYPE_AREA + st = rrdset_create_localhost( + "system", + "swapio", + NULL, + "swap", + NULL, + "Swap I/O", + "kilobytes/s", + "freebsd", + "vm.stats.vm.v_swappgs", + 250, + update_every, + RRDSET_TYPE_AREA ); rd_in = rrddim_add(st, "in", NULL, system_pagesize, KILO_FACTOR, RRD_ALGORITHM_INCREMENTAL); @@ -927,7 +1078,7 @@ int do_vm_stats_sys_v_pgfaults(int update_every, usec_t dt) { (void)dt; static int mib_vm_faults[4] = {0, 0, 0, 0}, mib_io_faults[4] = {0, 0, 0, 0}, mib_cow_faults[4] = {0, 0, 0, 0}, mib_cow_optim[4] = {0, 0, 0, 0}, mib_intrans[4] = {0, 0, 0, 0}; - struct vmmeter vmmeter_data; + vmmeter_t vmmeter_data; if (unlikely(GETSYSCTL_SIMPLE("vm.stats.vm.v_vm_faults", mib_vm_faults, vmmeter_data.v_vm_faults) || GETSYSCTL_SIMPLE("vm.stats.vm.v_io_faults", mib_io_faults, vmmeter_data.v_io_faults) || @@ -946,16 +1097,19 @@ int do_vm_stats_sys_v_pgfaults(int update_every, usec_t dt) { *rd_cow_optimized = NULL, *rd_in_transit = NULL; if (unlikely(!st)) { - st = rrdset_create_localhost("mem", - "pgfaults", - NULL, - "system", - NULL, - "Memory Page Faults", - "page faults/s", - 500, - update_every, - RRDSET_TYPE_LINE + st = rrdset_create_localhost( + "mem", + "pgfaults", + NULL, + "system", + NULL, + "Memory Page Faults", + "page faults/s", + "freebsd", + "vm.stats.vm.v_pgfaults", + 500, + update_every, + RRDSET_TYPE_LINE ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); @@ -1025,16 +1179,19 @@ int do_kern_ipc_sem(int update_every, usec_t dt) { static RRDDIM *rd_semaphores = NULL, *rd_semaphore_arrays = NULL; if (unlikely(!st_semaphores)) { - st_semaphores = rrdset_create_localhost("system", - "ipc_semaphores", - NULL, - "ipc semaphores", - NULL, - "IPC Semaphores", - "semaphores", - 1000, - update_every, - RRDSET_TYPE_AREA + st_semaphores = rrdset_create_localhost( + "system", + "ipc_semaphores", + NULL, + "ipc semaphores", + NULL, + "IPC Semaphores", + "semaphores", + "freebsd", + "kern.ipc.sem", + 1000, + update_every, + RRDSET_TYPE_AREA ); rd_semaphores = rrddim_add(st_semaphores, "semaphores", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); @@ -1047,16 +1204,19 @@ int do_kern_ipc_sem(int update_every, usec_t dt) { // -------------------------------------------------------------------- if (unlikely(!st_semaphore_arrays)) { - st_semaphore_arrays = rrdset_create_localhost("system", - "ipc_semaphore_arrays", - NULL, - "ipc semaphores", - NULL, - "IPC Semaphore Arrays", - "arrays", - 1000, - update_every, - RRDSET_TYPE_AREA + st_semaphore_arrays = rrdset_create_localhost( + "system", + "ipc_semaphore_arrays", + NULL, + "ipc semaphores", + NULL, + "IPC Semaphore Arrays", + "arrays", + "freebsd", + "kern.ipc.sem", + 1000, + update_every, + RRDSET_TYPE_AREA ); rd_semaphore_arrays = rrddim_add(st_semaphore_arrays, "arrays", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); @@ -1118,16 +1278,19 @@ int do_kern_ipc_shm(int update_every, usec_t dt) { static RRDDIM *rd_segments = NULL, *rd_allocated = NULL; if (unlikely(!st_segs)) { - st_segs = rrdset_create_localhost("system", - "ipc_shared_mem_segs", - NULL, - "ipc shared memory", - NULL, - "IPC Shared Memory Segments", - "segments", - 1000, - update_every, - RRDSET_TYPE_AREA + st_segs = rrdset_create_localhost( + "system", + "ipc_shared_mem_segs", + NULL, + "ipc shared memory", + NULL, + "IPC Shared Memory Segments", + "segments", + "freebsd", + "kern.ipc.shm", + 1000, + update_every, + RRDSET_TYPE_AREA ); rd_segments = rrddim_add(st_segs, "segments", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); @@ -1140,16 +1303,19 @@ int do_kern_ipc_shm(int update_every, usec_t dt) { // -------------------------------------------------------------------- if (unlikely(!st_size)) { - st_size = rrdset_create_localhost("system", - "ipc_shared_mem_size", - NULL, - "ipc shared memory", - NULL, - "IPC Shared Memory Segments Size", - "kilobytes", - 1000, - update_every, - RRDSET_TYPE_AREA + st_size = rrdset_create_localhost( + "system", + "ipc_shared_mem_size", + NULL, + "ipc shared memory", + NULL, + "IPC Shared Memory Segments Size", + "kilobytes", + "freebsd", + "kern.ipc.shm", + 1000, + update_every, + RRDSET_TYPE_AREA ); rd_allocated = rrddim_add(st_size, "allocated", NULL, 1, KILO_FACTOR, RRD_ALGORITHM_ABSOLUTE); @@ -1217,16 +1383,19 @@ int do_kern_ipc_msq(int update_every, usec_t dt) { static RRDDIM *rd_queues = NULL, *rd_messages = NULL, *rd_allocated = NULL, *rd_used = NULL; if (unlikely(!st_queues)) { - st_queues = rrdset_create_localhost("system", - "ipc_msq_queues", - NULL, - "ipc message queues", - NULL, - "Number of IPC Message Queues", - "queues", - 990, - update_every, - RRDSET_TYPE_AREA + st_queues = rrdset_create_localhost( + "system", + "ipc_msq_queues", + NULL, + "ipc message queues", + NULL, + "Number of IPC Message Queues", + "queues", + "freebsd", + "kern.ipc.msq", + 990, + update_every, + RRDSET_TYPE_AREA ); rd_queues = rrddim_add(st_queues, "queues", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); @@ -1239,16 +1408,19 @@ int do_kern_ipc_msq(int update_every, usec_t dt) { // -------------------------------------------------------------------- if (unlikely(!st_messages)) { - st_messages = rrdset_create_localhost("system", - "ipc_msq_messages", - NULL, - "ipc message queues", - NULL, - "Number of Messages in IPC Message Queues", - "messages", - 1000, - update_every, - RRDSET_TYPE_AREA + st_messages = rrdset_create_localhost( + "system", + "ipc_msq_messages", + NULL, + "ipc message queues", + NULL, + "Number of Messages in IPC Message Queues", + "messages", + "freebsd", + "kern.ipc.msq", + 1000, + update_every, + RRDSET_TYPE_AREA ); rd_messages = rrddim_add(st_messages, "messages", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); @@ -1261,16 +1433,19 @@ int do_kern_ipc_msq(int update_every, usec_t dt) { // -------------------------------------------------------------------- if (unlikely(!st_size)) { - st_size = rrdset_create_localhost("system", - "ipc_msq_size", - NULL, - "ipc message queues", - NULL, - "Size of IPC Message Queues", - "bytes", - 1100, - update_every, - RRDSET_TYPE_LINE + st_size = rrdset_create_localhost( + "system", + "ipc_msq_size", + NULL, + "ipc message queues", + NULL, + "Size of IPC Message Queues", + "bytes", + "freebsd", + "kern.ipc.msq", + 1100, + update_every, + RRDSET_TYPE_LINE ); rd_allocated = rrddim_add(st_size, "allocated", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); @@ -1302,16 +1477,19 @@ int do_uptime(int update_every, usec_t dt) { static RRDDIM *rd = NULL; if(unlikely(!st)) { - st = rrdset_create_localhost("system", - "uptime", - NULL, - "uptime", - NULL, - "System Uptime", - "seconds", - 1000, - update_every, - RRDSET_TYPE_LINE + st = rrdset_create_localhost( + "system", + "uptime", + NULL, + "uptime", + NULL, + "System Uptime", + "seconds", + "freebsd", + "uptime", + 1000, + update_every, + RRDSET_TYPE_LINE ); rd = rrddim_add(st, "uptime", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); @@ -1427,16 +1605,19 @@ int do_net_isr(int update_every, usec_t dt) { static RRDDIM *rd_dispatched = NULL, *rd_hybrid_dispatched = NULL, *rd_qdrops = NULL, *rd_queued = NULL; if (unlikely(!st)) { - st = rrdset_create_localhost("system", - "softnet_stat", - NULL, - "softnet_stat", - NULL, - "System softnet_stat", - "events/s", - 955, - update_every, - RRDSET_TYPE_LINE + st = rrdset_create_localhost( + "system", + "softnet_stat", + NULL, + "softnet_stat", + NULL, + "System softnet_stat", + "events/s", + "freebsd", + "net.isr", + 955, + update_every, + RRDSET_TYPE_LINE ); rd_dispatched = rrddim_add(st, "dispatched", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -1477,16 +1658,19 @@ int do_net_isr(int update_every, usec_t dt) { snprintfz(all_softnet_charts[i].netisr_cpuid, MAX_INT_DIGITS + 17, "cpu%d_softnet_stat", i); if (unlikely(!all_softnet_charts[i].st)) { - all_softnet_charts[i].st = rrdset_create_localhost("cpu", - all_softnet_charts[i].netisr_cpuid, - NULL, - "softnet_stat", - NULL, - "Per CPU netisr statistics", - "events/s", - 1101 + i, - update_every, - RRDSET_TYPE_LINE + all_softnet_charts[i].st = rrdset_create_localhost( + "cpu", + all_softnet_charts[i].netisr_cpuid, + NULL, + "softnet_stat", + NULL, + "Per CPU netisr statistics", + "events/s", + "freebsd", + "net.isr", + 1101 + i, + update_every, + RRDSET_TYPE_LINE ); all_softnet_charts[i].rd_dispatched = rrddim_add(all_softnet_charts[i].st, "dispatched", @@ -1536,16 +1720,19 @@ int do_net_inet_tcp_states(int update_every, usec_t dt) { static RRDDIM *rd = NULL; if (unlikely(!st)) { - st = rrdset_create_localhost("ipv4", - "tcpsock", - NULL, - "tcp", - NULL, - "IPv4 TCP Connections", - "active connections", - 2500, - update_every, - RRDSET_TYPE_LINE + st = rrdset_create_localhost( + "ipv4", + "tcpsock", + NULL, + "tcp", + NULL, + "IPv4 TCP Connections", + "active connections", + "freebsd", + "net.inet.tcp.states", + 2500, + update_every, + RRDSET_TYPE_LINE ); rd = rrddim_add(st, "CurrEstab", "connections", 1, 1, RRD_ALGORITHM_ABSOLUTE); @@ -1564,7 +1751,8 @@ int do_net_inet_tcp_states(int update_every, usec_t dt) { int do_net_inet_tcp_stats(int update_every, usec_t dt) { (void)dt; - static int do_tcp_packets = -1, do_tcp_errors = -1, do_tcp_handshake = -1, do_tcpext_connaborts = -1, do_tcpext_ofo = -1, do_tcpext_syncookies = -1, do_ecn = -1; + static int do_tcp_packets = -1, do_tcp_errors = -1, do_tcp_handshake = -1, do_tcpext_connaborts = -1, do_tcpext_ofo = -1, + do_tcpext_syncookies = -1, do_tcpext_listen = -1, do_ecn = -1; if (unlikely(do_tcp_packets == -1)) { do_tcp_packets = config_get_boolean("plugin:freebsd:net.inet.tcp.stats", "ipv4 TCP packets", 1); @@ -1576,12 +1764,15 @@ int do_net_inet_tcp_stats(int update_every, usec_t dt) { CONFIG_BOOLEAN_AUTO); do_tcpext_syncookies = config_get_boolean_ondemand("plugin:freebsd:net.inet.tcp.stats", "TCP SYN cookies", CONFIG_BOOLEAN_AUTO); + do_tcpext_listen = config_get_boolean_ondemand("plugin:freebsd:net.inet.tcp.stats", "TCP listen issues", + CONFIG_BOOLEAN_AUTO); do_ecn = config_get_boolean_ondemand("plugin:freebsd:net.inet.tcp.stats", "ECN packets", CONFIG_BOOLEAN_AUTO); } // see http://net-snmp.sourceforge.net/docs/mibs/tcp.html - if (likely(do_tcp_packets || do_tcp_errors || do_tcp_handshake || do_tcpext_connaborts || do_tcpext_ofo || do_tcpext_syncookies || do_ecn)) { + if (likely(do_tcp_packets || do_tcp_errors || do_tcp_handshake || do_tcpext_connaborts || do_tcpext_ofo || + do_tcpext_syncookies || do_tcpext_listen || do_ecn)) { static int mib[4] = {0, 0, 0, 0}; struct tcpstat tcpstat; @@ -1598,6 +1789,8 @@ int do_net_inet_tcp_stats(int update_every, usec_t dt) { error("DISABLED: ipv4.tcpofo chart"); do_tcpext_syncookies = 0; error("DISABLED: ipv4.tcpsyncookies chart"); + do_tcpext_listen = 0; + error("DISABLED: ipv4.tcplistenissues chart"); do_ecn = 0; error("DISABLED: ipv4.ecnpkts chart"); error("DISABLED: net.inet.tcp.stats module"); @@ -1611,16 +1804,19 @@ int do_net_inet_tcp_stats(int update_every, usec_t dt) { static RRDDIM *rd_in_segs = NULL, *rd_out_segs = NULL; if (unlikely(!st)) { - st = rrdset_create_localhost("ipv4", - "tcppackets", - NULL, - "tcp", - NULL, - "IPv4 TCP Packets", - "packets/s", - 2600, - update_every, - RRDSET_TYPE_LINE + st = rrdset_create_localhost( + "ipv4", + "tcppackets", + NULL, + "tcp", + NULL, + "IPv4 TCP Packets", + "packets/s", + "freebsd", + "net.inet.tcp.stats", + 2600, + update_every, + RRDSET_TYPE_LINE ); rd_in_segs = rrddim_add(st, "InSegs", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -1640,16 +1836,19 @@ int do_net_inet_tcp_stats(int update_every, usec_t dt) { static RRDDIM *rd_in_errs = NULL, *rd_in_csum_errs = NULL, *rd_retrans_segs = NULL; if (unlikely(!st)) { - st = rrdset_create_localhost("ipv4", - "tcperrors", - NULL, - "tcp", - NULL, - "IPv4 TCP Errors", - "packets/s", - 2700, - update_every, - RRDSET_TYPE_LINE + st = rrdset_create_localhost( + "ipv4", + "tcperrors", + NULL, + "tcp", + NULL, + "IPv4 TCP Errors", + "packets/s", + "freebsd", + "net.inet.tcp.stats", + 2700, + update_every, + RRDSET_TYPE_LINE ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); @@ -1679,16 +1878,19 @@ int do_net_inet_tcp_stats(int update_every, usec_t dt) { *rd_attempt_fails = NULL; if (unlikely(!st)) { - st = rrdset_create_localhost("ipv4", - "tcphandshake", - NULL, - "tcp", - NULL, - "IPv4 TCP Handshake Issues", - "events/s", - 2900, - update_every, - RRDSET_TYPE_LINE + st = rrdset_create_localhost( + "ipv4", + "tcphandshake", + NULL, + "tcp", + NULL, + "IPv4 TCP Handshake Issues", + "events/s", + "freebsd", + "net.inet.tcp.stats", + 2900, + update_every, + RRDSET_TYPE_LINE ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); @@ -1717,16 +1919,19 @@ int do_net_inet_tcp_stats(int update_every, usec_t dt) { *rd_on_timeout = NULL, *rd_on_linger = NULL; if (unlikely(!st)) { - st = rrdset_create_localhost("ipv4", - "tcpconnaborts", - NULL, - "tcp", - NULL, - "TCP Connection Aborts", - "connections/s", - 3010, - update_every, - RRDSET_TYPE_LINE + st = rrdset_create_localhost( + "ipv4", + "tcpconnaborts", + NULL, + "tcp", + NULL, + "TCP Connection Aborts", + "connections/s", + "freebsd", + "net.inet.tcp.stats", + 3010, + update_every, + RRDSET_TYPE_LINE ); rd_on_data = rrddim_add(st, "TCPAbortOnData", "baddata", 1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -1754,16 +1959,19 @@ int do_net_inet_tcp_stats(int update_every, usec_t dt) { static RRDDIM *rd_ofo_queue = NULL; if (unlikely(!st)) { - st = rrdset_create_localhost("ipv4", - "tcpofo", - NULL, - "tcp", - NULL, - "TCP Out-Of-Order Queue", - "packets/s", - 3050, - update_every, - RRDSET_TYPE_LINE + st = rrdset_create_localhost( + "ipv4", + "tcpofo", + NULL, + "tcp", + NULL, + "TCP Out-Of-Order Queue", + "packets/s", + "freebsd", + "net.inet.tcp.stats", + 3050, + update_every, + RRDSET_TYPE_LINE ); rd_ofo_queue = rrddim_add(st, "TCPOFOQueue", "inqueue", 1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -1783,16 +1991,19 @@ int do_net_inet_tcp_stats(int update_every, usec_t dt) { static RRDDIM *rd_recv = NULL, *rd_send = NULL, *rd_failed = NULL; if (unlikely(!st)) { - st = rrdset_create_localhost("ipv4", - "tcpsyncookies", - NULL, - "tcp", - NULL, - "TCP SYN Cookies", - "packets/s", - 3100, - update_every, - RRDSET_TYPE_LINE + st = rrdset_create_localhost( + "ipv4", + "tcpsyncookies", + NULL, + "tcp", + NULL, + "TCP SYN Cookies", + "packets/s", + "freebsd", + "net.inet.tcp.stats", + 3100, + update_every, + RRDSET_TYPE_LINE ); rd_recv = rrddim_add(st, "SyncookiesRecv", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -1806,6 +2017,41 @@ int do_net_inet_tcp_stats(int update_every, usec_t dt) { rrddim_set_by_pointer(st, rd_failed, tcpstat.tcps_sc_zonefail); rrdset_done(st); } + + // -------------------------------------------------------------------- + + if(do_tcpext_listen == CONFIG_BOOLEAN_YES || (do_tcpext_listen == CONFIG_BOOLEAN_AUTO && tcpstat.tcps_listendrop)) { + do_tcpext_listen = CONFIG_BOOLEAN_YES; + + static RRDSET *st_listen = NULL; + static RRDDIM *rd_overflows = NULL; + + if(unlikely(!st_listen)) { + + st_listen = rrdset_create_localhost( + "ipv4", + "tcplistenissues", + NULL, + "tcp", + NULL, + "TCP Listen Socket Issues", + "packets/s", + "freebsd", + "net.inet.tcp.stats", + 3015, + update_every, + RRDSET_TYPE_LINE + ); + + rd_overflows = rrddim_add(st_listen, "ListenOverflows", "overflows", 1, 1, RRD_ALGORITHM_INCREMENTAL); + } + else + rrdset_next(st_listen); + + rrddim_set_by_pointer(st_listen, rd_overflows, tcpstat.tcps_listendrop); + + rrdset_done(st_listen); + } // -------------------------------------------------------------------- @@ -1816,16 +2062,19 @@ int do_net_inet_tcp_stats(int update_every, usec_t dt) { static RRDDIM *rd_ce = NULL, *rd_no_ect = NULL, *rd_ect0 = NULL, *rd_ect1 = NULL; if (unlikely(!st)) { - st = rrdset_create_localhost("ipv4", - "ecnpkts", - NULL, - "ecn", - NULL, - "IPv4 ECN Statistics", - "packets/s", - 8700, - update_every, - RRDSET_TYPE_LINE + st = rrdset_create_localhost( + "ipv4", + "ecnpkts", + NULL, + "ecn", + NULL, + "IPv4 ECN Statistics", + "packets/s", + "freebsd", + "net.inet.tcp.stats", + 8700, + update_every, + RRDSET_TYPE_LINE ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); @@ -1887,16 +2136,19 @@ int do_net_inet_udp_stats(int update_every, usec_t dt) { static RRDDIM *rd_in = NULL, *rd_out = NULL; if (unlikely(!st)) { - st = rrdset_create_localhost("ipv4", - "udppackets", - NULL, - "udp", - NULL, - "IPv4 UDP Packets", - "packets/s", - 2601, - update_every, - RRDSET_TYPE_LINE + st = rrdset_create_localhost( + "ipv4", + "udppackets", + NULL, + "udp", + NULL, + "IPv4 UDP Packets", + "packets/s", + "freebsd", + "net.inet.udp.stats", + 2601, + update_every, + RRDSET_TYPE_LINE ); rd_in = rrddim_add(st, "InDatagrams", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -1917,16 +2169,19 @@ int do_net_inet_udp_stats(int update_every, usec_t dt) { *rd_in_csum_errors = NULL, *rd_ignored_multi = NULL; if (unlikely(!st)) { - st = rrdset_create_localhost("ipv4", - "udperrors", - NULL, - "udp", - NULL, - "IPv4 UDP Errors", - "events/s", - 2701, - update_every, - RRDSET_TYPE_LINE + st = rrdset_create_localhost( + "ipv4", + "udperrors", + NULL, + "udp", + NULL, + "IPv4 UDP Errors", + "events/s", + "freebsd", + "net.inet.udp.stats", + 2701, + update_every, + RRDSET_TYPE_LINE ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); @@ -2000,16 +2255,19 @@ int do_net_inet_icmp_stats(int update_every, usec_t dt) { static RRDDIM *rd_in = NULL, *rd_out = NULL; if (unlikely(!st)) { - st = rrdset_create_localhost("ipv4", - "icmp", - NULL, - "icmp", - NULL, - "IPv4 ICMP Packets", - "packets/s", - 2602, - update_every, - RRDSET_TYPE_LINE + st = rrdset_create_localhost( + "ipv4" + , "icmp" + , NULL + , "icmp" + , NULL + , "IPv4 ICMP Packets" + , "packets/s" + , "freebsd" + , "net.inet.icmp.stats" + , 2602 + , update_every + , RRDSET_TYPE_LINE ); rd_in = rrddim_add(st, "InMsgs", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -2030,9 +2288,20 @@ int do_net_inet_icmp_stats(int update_every, usec_t dt) { static RRDDIM *rd_in = NULL, *rd_out = NULL, *rd_in_csum = NULL; if (unlikely(!st)) { - st = rrdset_create_localhost("ipv4", "icmp_errors", NULL, "icmp", NULL, "IPv4 ICMP Errors", - "packets/s", - 2603, update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + "ipv4" + , "icmp_errors" + , NULL + , "icmp" + , NULL + , "IPv4 ICMP Errors" + , "packets/s" + , "freebsd" + , "net.inet.icmp.stats" + , 2603 + , update_every + , RRDSET_TYPE_LINE + ); rd_in = rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); rd_out = rrddim_add(st, "OutErrors", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -2055,8 +2324,20 @@ int do_net_inet_icmp_stats(int update_every, usec_t dt) { static RRDDIM *rd_in_reps = NULL, *rd_out_reps = NULL, *rd_in = NULL, *rd_out = NULL; if (unlikely(!st)) { - st = rrdset_create_localhost("ipv4", "icmpmsg", NULL, "icmp", NULL, "IPv4 ICMP Messages", - "packets/s", 2604, update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + "ipv4" + , "icmpmsg" + , NULL + , "icmp" + , NULL + , "IPv4 ICMP Messages" + , "packets/s" + , "freebsd" + , "net.inet.icmp.stats" + , 2604 + , update_every + , RRDSET_TYPE_LINE + ); rd_in_reps = rrddim_add(st, "InEchoReps", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); rd_out_reps = rrddim_add(st, "OutEchoReps", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -2121,16 +2402,19 @@ int do_net_inet_ip_stats(int update_every, usec_t dt) { *rd_in_delivers = NULL; if (unlikely(!st)) { - st = rrdset_create_localhost("ipv4", - "packets", - NULL, - "packets", - NULL, - "IPv4 Packets", - "packets/s", - 3000, - update_every, - RRDSET_TYPE_LINE + st = rrdset_create_localhost( + "ipv4", + "packets", + NULL, + "packets", + NULL, + "IPv4 Packets", + "packets/s", + "freebsd", + "net.inet.ip.stats", + 3000, + update_every, + RRDSET_TYPE_LINE ); rd_in_receives = rrddim_add(st, "InReceives", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -2154,16 +2438,19 @@ int do_net_inet_ip_stats(int update_every, usec_t dt) { static RRDDIM *rd_ok = NULL, *rd_fails = NULL, *rd_created = NULL; if (unlikely(!st)) { - st = rrdset_create_localhost("ipv4", - "fragsout", - NULL, - "fragments", - NULL, - "IPv4 Fragments Sent", - "packets/s", - 3010, - update_every, - RRDSET_TYPE_LINE + st = rrdset_create_localhost( + "ipv4", + "fragsout", + NULL, + "fragments", + NULL, + "IPv4 Fragments Sent", + "packets/s", + "freebsd", + "net.inet.ip.stats", + 3010, + update_every, + RRDSET_TYPE_LINE ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); @@ -2187,16 +2474,19 @@ int do_net_inet_ip_stats(int update_every, usec_t dt) { static RRDDIM *rd_ok = NULL, *rd_failed = NULL, *rd_all = NULL; if (unlikely(!st)) { - st = rrdset_create_localhost("ipv4", - "fragsin", - NULL, - "fragments", - NULL, - "IPv4 Fragments Reassembly", - "packets/s", - 3011, - update_every, - RRDSET_TYPE_LINE + st = rrdset_create_localhost( + "ipv4", + "fragsin", + NULL, + "fragments", + NULL, + "IPv4 Fragments Reassembly", + "packets/s", + "freebsd", + "net.inet.ip.stats", + 3011, + update_every, + RRDSET_TYPE_LINE ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); @@ -2222,16 +2512,19 @@ int do_net_inet_ip_stats(int update_every, usec_t dt) { *rd_in_addr_errors = NULL, *rd_in_unknown_protos = NULL; if (unlikely(!st)) { - st = rrdset_create_localhost("ipv4", - "errors", - NULL, - "errors", - NULL, - "IPv4 Errors", - "packets/s", - 3002, - update_every, - RRDSET_TYPE_LINE + st = rrdset_create_localhost( + "ipv4", + "errors", + NULL, + "errors", + NULL, + "IPv4 Errors", + "packets/s", + "freebsd", + "net.inet.ip.stats", + 3002, + update_every, + RRDSET_TYPE_LINE ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); @@ -2310,16 +2603,19 @@ int do_net_inet6_ip6_stats(int update_every, usec_t dt) { static RRDDIM *rd_received = NULL, *rd_sent = NULL, *rd_forwarded = NULL, *rd_delivers = NULL; if (unlikely(!st)) { - st = rrdset_create_localhost("ipv6", - "packets", - NULL, - "packets", - NULL, - "IPv6 Packets", - "packets/s", - 3000, - update_every, - RRDSET_TYPE_LINE + st = rrdset_create_localhost( + "ipv6", + "packets", + NULL, + "packets", + NULL, + "IPv6 Packets", + "packets/s", + "freebsd", + "net.inet6.ip6.stats", + 3000, + update_every, + RRDSET_TYPE_LINE ); rd_received = rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -2347,16 +2643,19 @@ int do_net_inet6_ip6_stats(int update_every, usec_t dt) { static RRDDIM *rd_ok = NULL, *rd_failed = NULL, *rd_all = NULL; if (unlikely(!st)) { - st = rrdset_create_localhost("ipv6", - "fragsout", - NULL, - "fragments", - NULL, - "IPv6 Fragments Sent", - "packets/s", - 3010, - update_every, - RRDSET_TYPE_LINE + st = rrdset_create_localhost( + "ipv6", + "fragsout", + NULL, + "fragments", + NULL, + "IPv6 Fragments Sent", + "packets/s", + "freebsd", + "net.inet6.ip6.stats", + 3010, + update_every, + RRDSET_TYPE_LINE ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); @@ -2384,16 +2683,19 @@ int do_net_inet6_ip6_stats(int update_every, usec_t dt) { static RRDDIM *rd_ok = NULL, *rd_failed = NULL, *rd_timeout = NULL, *rd_all = NULL; if (unlikely(!st)) { - st = rrdset_create_localhost("ipv6", - "fragsin", - NULL, - "fragments", - NULL, - "IPv6 Fragments Reassembly", - "packets/s", - 3011, - update_every, - RRDSET_TYPE_LINE + st = rrdset_create_localhost( + "ipv6", + "fragsin", + NULL, + "fragments", + NULL, + "IPv6 Fragments Reassembly", + "packets/s", + "freebsd", + "net.inet6.ip6.stats", + 3011, + update_every, + RRDSET_TYPE_LINE ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); @@ -2432,16 +2734,19 @@ int do_net_inet6_ip6_stats(int update_every, usec_t dt) { *rd_in_no_routes = NULL, *rd_out_no_routes = NULL; if (unlikely(!st)) { - st = rrdset_create_localhost("ipv6", - "errors", - NULL, - "errors", - NULL, - "IPv6 Errors", - "packets/s", - 3002, - update_every, - RRDSET_TYPE_LINE + st = rrdset_create_localhost( + "ipv6", + "errors", + NULL, + "errors", + NULL, + "IPv6 Errors", + "packets/s", + "freebsd", + "net.inet6.ip6.stats", + 3002, + update_every, + RRDSET_TYPE_LINE ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); @@ -2543,16 +2848,19 @@ int do_net_inet6_icmp6_stats(int update_every, usec_t dt) { static RRDDIM *rd_received = NULL, *rd_sent = NULL; if (unlikely(!st)) { - st = rrdset_create_localhost("ipv6", - "icmp", - NULL, - "icmp", - NULL, - "IPv6 ICMP Messages", - "messages/s", - 10000, - update_every, - RRDSET_TYPE_LINE + st = rrdset_create_localhost( + "ipv6", + "icmp", + NULL, + "icmp", + NULL, + "IPv6 ICMP Messages", + "messages/s", + "freebsd", + "net.inet6.icmp6.stats", + 10000, + update_every, + RRDSET_TYPE_LINE ); rd_received = rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -2575,16 +2883,19 @@ int do_net_inet6_icmp6_stats(int update_every, usec_t dt) { static RRDDIM *rd_received = NULL, *rd_sent = NULL; if (unlikely(!st)) { - st = rrdset_create_localhost("ipv6", - "icmpredir", - NULL, - "icmp", - NULL, - "IPv6 ICMP Redirects", - "redirects/s", - 10050, - update_every, - RRDSET_TYPE_LINE + st = rrdset_create_localhost( + "ipv6", + "icmpredir", + NULL, + "icmp", + NULL, + "IPv6 ICMP Redirects", + "redirects/s", + "freebsd", + "net.inet6.icmp6.stats", + 10050, + update_every, + RRDSET_TYPE_LINE ); rd_received = rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -2620,15 +2931,18 @@ int do_net_inet6_icmp6_stats(int update_every, usec_t dt) { *rd_out_parm_problems = NULL; if (unlikely(!st)) { - st = rrdset_create_localhost("ipv6", - "icmperrors", - NULL, "icmp", - NULL, - "IPv6 ICMP Errors", - "errors/s", - 10100, - update_every, - RRDSET_TYPE_LINE + st = rrdset_create_localhost( + "ipv6", + "icmperrors", + NULL, "icmp", + NULL, + "IPv6 ICMP Errors", + "errors/s", + "freebsd", + "net.inet6.icmp6.stats", + 10100, + update_every, + RRDSET_TYPE_LINE ); rd_in_errors = rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -2671,16 +2985,19 @@ int do_net_inet6_icmp6_stats(int update_every, usec_t dt) { static RRDDIM *rd_in = NULL, *rd_out = NULL, *rd_in_replies = NULL, *rd_out_replies = NULL; if (unlikely(!st)) { - st = rrdset_create_localhost("ipv6", - "icmpechos", - NULL, - "icmp", - NULL, - "IPv6 ICMP Echo", - "messages/s", - 10200, - update_every, - RRDSET_TYPE_LINE + st = rrdset_create_localhost( + "ipv6", + "icmpechos", + NULL, + "icmp", + NULL, + "IPv6 ICMP Echo", + "messages/s", + "freebsd", + "net.inet6.icmp6.stats", + 10200, + update_every, + RRDSET_TYPE_LINE ); rd_in = rrddim_add(st, "InEchos", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -2711,16 +3028,19 @@ int do_net_inet6_icmp6_stats(int update_every, usec_t dt) { *rd_in_advertisements = NULL, *rd_out_advertisements = NULL; if (unlikely(!st)) { - st = rrdset_create_localhost("ipv6", - "icmprouter", - NULL, - "icmp", - NULL, - "IPv6 Router Messages", - "messages/s", - 10400, - update_every, - RRDSET_TYPE_LINE + st = rrdset_create_localhost( + "ipv6", + "icmprouter", + NULL, + "icmp", + NULL, + "IPv6 Router Messages", + "messages/s", + "freebsd", + "net.inet6.icmp6.stats", + 10400, + update_every, + RRDSET_TYPE_LINE ); rd_in_solicits = rrddim_add(st, "InSolicits", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -2751,16 +3071,19 @@ int do_net_inet6_icmp6_stats(int update_every, usec_t dt) { *rd_in_advertisements = NULL, *rd_out_advertisements = NULL; if (unlikely(!st)) { - st = rrdset_create_localhost("ipv6", - "icmpneighbor", - NULL, - "icmp", - NULL, - "IPv6 Neighbor Messages", - "messages/s", - 10500, - update_every, - RRDSET_TYPE_LINE + st = rrdset_create_localhost( + "ipv6", + "icmpneighbor", + NULL, + "icmp", + NULL, + "IPv6 Neighbor Messages", + "messages/s", + "freebsd", + "net.inet6.icmp6.stats", + 10500, + update_every, + RRDSET_TYPE_LINE ); rd_in_solicits = rrddim_add(st, "InSolicits", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -2798,16 +3121,19 @@ int do_net_inet6_icmp6_stats(int update_every, usec_t dt) { *rd_out_135 = NULL, *rd_out_143 = NULL; if (unlikely(!st)) { - st = rrdset_create_localhost("ipv6", - "icmptypes", - NULL, - "icmp", - NULL, - "IPv6 ICMP Types", - "messages/s", - 10700, - update_every, - RRDSET_TYPE_LINE + st = rrdset_create_localhost( + "ipv6", + "icmptypes", + NULL, + "icmp", + NULL, + "IPv6 ICMP Types", + "messages/s", + "freebsd", + "net.inet6.icmp6.stats", + 10700, + update_every, + RRDSET_TYPE_LINE ); rd_in_1 = rrddim_add(st, "InType1", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); diff --git a/src/freeipmi_plugin.c b/src/freeipmi_plugin.c index 42a1ac01..9cd736bb 100644 --- a/src/freeipmi_plugin.c +++ b/src/freeipmi_plugin.c @@ -522,6 +522,49 @@ static void send_metrics_to_netdata() { } +static int *excluded_record_ids = NULL; +size_t excluded_record_ids_length = 0; + +static void excluded_record_ids_parse(const char *s) { + if(!s) return; + + while(*s) { + while(*s && !isdigit(*s)) s++; + + if(isdigit(*s)) { + char *e; + unsigned long n = strtoul(s, &e, 10); + s = e; + + if(n != 0) { + excluded_record_ids = realloc(excluded_record_ids, (excluded_record_ids_length + 1) * sizeof(int)); + excluded_record_ids[excluded_record_ids_length++] = (int)n; + } + } + } + + if(debug) { + fprintf(stderr, "freeipmi.plugin: excluded record ids:"); + size_t i; + for(i = 0; i < excluded_record_ids_length; i++) { + fprintf(stderr, " %d", excluded_record_ids[i]); + } + fprintf(stderr, "\n"); + } +} + + +static int excluded_record_ids_check(int record_id) { + size_t i; + + for(i = 0; i < excluded_record_ids_length; i++) { + if(excluded_record_ids[i] == record_id) + return 1; + } + + return 0; +} + static void netdata_get_sensor( int record_id , int sensor_number @@ -546,6 +589,10 @@ static void netdata_get_sensor( if(!sn) { // not found, create it + // check if it is excluded + if(excluded_record_ids_check(record_id)) + return; + sn = calloc(1, sizeof(struct sensor)); if(!sn) { fatal("cannot allocate %zu bytes of memory.", sizeof(struct sensor)); @@ -1482,6 +1529,9 @@ int main (int argc, char **argv) { " sensor-config-file FILE filename to read sensor configuration\n" " default: %s\n" "\n" + " ignore N1,N2,N3,... sensor IDs to ignore\n" + " default: none\n" + "\n" " -v\n" " -V\n" " version print version and exit\n" @@ -1538,10 +1588,16 @@ int main (int argc, char **argv) { if(debug) fprintf(stderr, "freeipmi.plugin: sensor config file set to '%s'\n", sensor_config_file); continue; } + else if(i < argc && strcmp("ignore", argv[i]) == 0) { + excluded_record_ids_parse(argv[++i]); + continue; + } error("freeipmi.plugin: ignoring parameter '%s'", argv[i]); } + errno = 0; + if(freq > netdata_update_every) netdata_update_every = freq; diff --git a/src/global_statistics.c b/src/global_statistics.c index 88688908..c184b6d6 100644 --- a/src/global_statistics.c +++ b/src/global_statistics.c @@ -114,13 +114,13 @@ inline void global_statistics_copy(struct global_statistics *gs, uint8_t options } void global_statistics_charts(void) { - static unsigned long long old_web_requests = 0, old_web_usec = 0, - old_content_size = 0, old_compressed_content_size = 0; + static unsigned long long old_web_requests = 0, + old_web_usec = 0, + old_content_size = 0, + old_compressed_content_size = 0; - static collected_number compression_ratio = -1, average_response_time = -1; - - static RRDSET *stcpu = NULL, *stcpu_thread = NULL, *stclients = NULL, *streqs = NULL, *stbytes = NULL, *stduration = NULL, - *stcompression = NULL; + static collected_number compression_ratio = -1, + average_response_time = -1; struct global_statistics gs; struct rusage me, thread; @@ -129,143 +129,280 @@ void global_statistics_charts(void) { getrusage(RUSAGE_THREAD, &thread); getrusage(RUSAGE_SELF, &me); + { + static RRDSET *st_cpu_thread = NULL; + static RRDDIM *rd_cpu_thread_user = NULL, + *rd_cpu_thread_system = NULL; + #ifdef __FreeBSD__ - if (!stcpu_thread) stcpu_thread = rrdset_find_localhost("netdata.plugin_freebsd_cpu"); - if (!stcpu_thread) { - stcpu_thread = rrdset_create_localhost("netdata", "plugin_freebsd_cpu", NULL, "freebsd", NULL - , "NetData FreeBSD Plugin CPU usage", "milliseconds/s", 132000 - , localhost->rrd_update_every, RRDSET_TYPE_STACKED); + if (unlikely(!st_cpu_thread)) { + st_cpu_thread = rrdset_create_localhost( + "netdata" + , "plugin_freebsd_cpu" + , NULL + , "freebsd" + , NULL + , "NetData FreeBSD Plugin CPU usage" + , "milliseconds/s" + , "netdata" + , "stats" + , 132000 + , localhost->rrd_update_every + , RRDSET_TYPE_STACKED + ); #else - if (!stcpu_thread) stcpu_thread = rrdset_find_localhost("netdata.plugin_proc_cpu"); - if (!stcpu_thread) { - stcpu_thread = rrdset_create_localhost("netdata", "plugin_proc_cpu", NULL, "proc", NULL - , "NetData Proc Plugin CPU usage", "milliseconds/s", 132000 - , localhost->rrd_update_every, RRDSET_TYPE_STACKED); + if (unlikely(!st_cpu_thread)) { + st_cpu_thread = rrdset_create_localhost( + "netdata" + , "plugin_proc_cpu" + , NULL + , "proc" + , NULL + , "NetData Proc Plugin CPU usage" + , "milliseconds/s" + , "netdata" + , "stats" + , 132000 + , localhost->rrd_update_every + , RRDSET_TYPE_STACKED + ); #endif - rrddim_add(stcpu_thread, "user", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(stcpu_thread, "system", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL); - } else rrdset_next(stcpu_thread); + rd_cpu_thread_user = rrddim_add(st_cpu_thread, "user", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL); + rd_cpu_thread_system = rrddim_add(st_cpu_thread, "system", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL); + } + else + rrdset_next(st_cpu_thread); - rrddim_set(stcpu_thread, "user", thread.ru_utime.tv_sec * 1000000ULL + thread.ru_utime.tv_usec); - rrddim_set(stcpu_thread, "system", thread.ru_stime.tv_sec * 1000000ULL + thread.ru_stime.tv_usec); - rrdset_done(stcpu_thread); + rrddim_set_by_pointer(st_cpu_thread, rd_cpu_thread_user, thread.ru_utime.tv_sec * 1000000ULL + thread.ru_utime.tv_usec); + rrddim_set_by_pointer(st_cpu_thread, rd_cpu_thread_system, thread.ru_stime.tv_sec * 1000000ULL + thread.ru_stime.tv_usec); + rrdset_done(st_cpu_thread); + } // ---------------------------------------------------------------- - if (!stcpu) stcpu = rrdset_find_localhost("netdata.server_cpu"); - if (!stcpu) { - stcpu = rrdset_create_localhost("netdata", "server_cpu", NULL, "netdata", NULL, "NetData CPU usage" - , "milliseconds/s", 130000, localhost->rrd_update_every, RRDSET_TYPE_STACKED); - - rrddim_add(stcpu, "user", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(stcpu, "system", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL); - } else rrdset_next(stcpu); - - rrddim_set(stcpu, "user", me.ru_utime.tv_sec * 1000000ULL + me.ru_utime.tv_usec); - rrddim_set(stcpu, "system", me.ru_stime.tv_sec * 1000000ULL + me.ru_stime.tv_usec); - rrdset_done(stcpu); + { + static RRDSET *st_cpu = NULL; + static RRDDIM *rd_cpu_user = NULL, + *rd_cpu_system = NULL; + + if (unlikely(!st_cpu)) { + st_cpu = rrdset_create_localhost( + "netdata" + , "server_cpu" + , NULL + , "netdata" + , NULL + , "NetData CPU usage" + , "milliseconds/s" + , "netdata" + , "stats" + , 130000 + , localhost->rrd_update_every + , RRDSET_TYPE_STACKED + ); + + rd_cpu_user = rrddim_add(st_cpu, "user", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL); + rd_cpu_system = rrddim_add(st_cpu, "system", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL); + } + else + rrdset_next(st_cpu); + + rrddim_set_by_pointer(st_cpu, rd_cpu_user, me.ru_utime.tv_sec * 1000000ULL + me.ru_utime.tv_usec); + rrddim_set_by_pointer(st_cpu, rd_cpu_system, me.ru_stime.tv_sec * 1000000ULL + me.ru_stime.tv_usec); + rrdset_done(st_cpu); + } // ---------------------------------------------------------------- - if (!stclients) stclients = rrdset_find_localhost("netdata.clients"); - if (!stclients) { - stclients = rrdset_create_localhost("netdata", "clients", NULL, "netdata", NULL, "NetData Web Clients" - , "connected clients", 130200, localhost->rrd_update_every, RRDSET_TYPE_LINE); - - rrddim_add(stclients, "clients", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - } else rrdset_next(stclients); - - rrddim_set(stclients, "clients", gs.connected_clients); - rrdset_done(stclients); + { + static RRDSET *st_clients = NULL; + static RRDDIM *rd_clients = NULL; + + if (unlikely(!st_clients)) { + st_clients = rrdset_create_localhost( + "netdata" + , "clients" + , NULL + , "netdata" + , NULL + , "NetData Web Clients" + , "connected clients" + , "netdata" + , "stats" + , 130200 + , localhost->rrd_update_every + , RRDSET_TYPE_LINE + ); + + rd_clients = rrddim_add(st_clients, "clients", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); + } + else + rrdset_next(st_clients); + + rrddim_set_by_pointer(st_clients, rd_clients, gs.connected_clients); + rrdset_done(st_clients); + } // ---------------------------------------------------------------- - if (!streqs) streqs = rrdset_find_localhost("netdata.requests"); - if (!streqs) { - streqs = rrdset_create_localhost("netdata", "requests", NULL, "netdata", NULL, "NetData Web Requests" - , "requests/s", 130300, localhost->rrd_update_every, RRDSET_TYPE_LINE); - - rrddim_add(streqs, "requests", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - } else rrdset_next(streqs); - - rrddim_set(streqs, "requests", (collected_number) gs.web_requests); - rrdset_done(streqs); + { + static RRDSET *st_reqs = NULL; + static RRDDIM *rd_requests = NULL; + + if (unlikely(!st_reqs)) { + st_reqs = rrdset_create_localhost( + "netdata" + , "requests" + , NULL + , "netdata" + , NULL + , "NetData Web Requests" + , "requests/s" + , "netdata" + , "stats" + , 130300 + , localhost->rrd_update_every + , RRDSET_TYPE_LINE + ); + + rd_requests = rrddim_add(st_reqs, "requests", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + } + else + rrdset_next(st_reqs); + + rrddim_set_by_pointer(st_reqs, rd_requests, (collected_number) gs.web_requests); + rrdset_done(st_reqs); + } // ---------------------------------------------------------------- - if (!stbytes) stbytes = rrdset_find_localhost("netdata.net"); - if (!stbytes) { - stbytes = rrdset_create_localhost("netdata", "net", NULL, "netdata", NULL, "NetData Network Traffic" - , "kilobits/s", 130000, localhost->rrd_update_every, RRDSET_TYPE_AREA); - - rrddim_add(stbytes, "in", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(stbytes, "out", NULL, -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); - } else rrdset_next(stbytes); - - rrddim_set(stbytes, "in", (collected_number) gs.bytes_received); - rrddim_set(stbytes, "out", (collected_number) gs.bytes_sent); - rrdset_done(stbytes); + { + static RRDSET *st_bytes = NULL; + static RRDDIM *rd_in = NULL, + *rd_out = NULL; + + if (unlikely(!st_bytes)) { + st_bytes = rrdset_create_localhost( + "netdata" + , "net" + , NULL + , "netdata" + , NULL + , "NetData Network Traffic" + , "kilobits/s" + , "netdata" + , "stats" + , 130000 + , localhost->rrd_update_every + , RRDSET_TYPE_AREA + ); + + rd_in = rrddim_add(st_bytes, "in", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); + rd_out = rrddim_add(st_bytes, "out", NULL, -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); + } + else + rrdset_next(st_bytes); + + rrddim_set_by_pointer(st_bytes, rd_in, (collected_number) gs.bytes_received); + rrddim_set_by_pointer(st_bytes, rd_out, (collected_number) gs.bytes_sent); + rrdset_done(st_bytes); + } // ---------------------------------------------------------------- - if (!stduration) stduration = rrdset_find_localhost("netdata.response_time"); - if (!stduration) { - stduration = rrdset_create_localhost("netdata", "response_time", NULL, "netdata", NULL - , "NetData API Response Time", "ms/request", 130400, localhost->rrd_update_every - , RRDSET_TYPE_LINE); - - rrddim_add(stduration, "average", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); - rrddim_add(stduration, "max", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); - } else rrdset_next(stduration); - - uint64_t gweb_usec = gs.web_usec; - uint64_t gweb_requests = gs.web_requests; - - uint64_t web_usec = (gweb_usec >= old_web_usec) ? gweb_usec - old_web_usec : 0; - uint64_t web_requests = (gweb_requests >= old_web_requests) ? gweb_requests - old_web_requests : 0; - - old_web_usec = gweb_usec; - old_web_requests = gweb_requests; - - if (web_requests) - average_response_time = (collected_number) (web_usec / web_requests); - - if (unlikely(average_response_time != -1)) - rrddim_set(stduration, "average", average_response_time); - else - rrddim_set(stduration, "average", 0); - - rrddim_set(stduration, "max", ((gs.web_usec_max)?(collected_number)gs.web_usec_max:average_response_time)); - rrdset_done(stduration); + { + static RRDSET *st_duration = NULL; + static RRDDIM *rd_average = NULL, + *rd_max = NULL; + + if (unlikely(!st_duration)) { + st_duration = rrdset_create_localhost( + "netdata" + , "response_time" + , NULL + , "netdata" + , NULL + , "NetData API Response Time" + , "ms/request" + , "netdata" + , "stats" + , 130400 + , localhost->rrd_update_every + , RRDSET_TYPE_LINE + ); + + rd_average = rrddim_add(st_duration, "average", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); + rd_max = rrddim_add(st_duration, "max", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); + } + else + rrdset_next(st_duration); + + uint64_t gweb_usec = gs.web_usec; + uint64_t gweb_requests = gs.web_requests; + + uint64_t web_usec = (gweb_usec >= old_web_usec) ? gweb_usec - old_web_usec : 0; + uint64_t web_requests = (gweb_requests >= old_web_requests) ? gweb_requests - old_web_requests : 0; + + old_web_usec = gweb_usec; + old_web_requests = gweb_requests; + + if (web_requests) + average_response_time = (collected_number) (web_usec / web_requests); + + if (unlikely(average_response_time != -1)) + rrddim_set_by_pointer(st_duration, rd_average, average_response_time); + else + rrddim_set_by_pointer(st_duration, rd_average, 0); + + rrddim_set_by_pointer(st_duration, rd_max, ((gs.web_usec_max)?(collected_number)gs.web_usec_max:average_response_time)); + rrdset_done(st_duration); + } // ---------------------------------------------------------------- - if (!stcompression) stcompression = rrdset_find_localhost("netdata.compression_ratio"); - if (!stcompression) { - stcompression = rrdset_create_localhost("netdata", "compression_ratio", NULL, "netdata", NULL - , "NetData API Responses Compression Savings Ratio", "percentage" - , 130500, localhost->rrd_update_every, RRDSET_TYPE_LINE); - - rrddim_add(stcompression, "savings", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); - } else rrdset_next(stcompression); - - // since we don't lock here to read the global statistics - // read the smaller value first - unsigned long long gcompressed_content_size = gs.compressed_content_size; - unsigned long long gcontent_size = gs.content_size; - - unsigned long long compressed_content_size = gcompressed_content_size - old_compressed_content_size; - unsigned long long content_size = gcontent_size - old_content_size; - - old_compressed_content_size = gcompressed_content_size; - old_content_size = gcontent_size; - - if (content_size && content_size >= compressed_content_size) - compression_ratio = ((content_size - compressed_content_size) * 100 * 1000) / content_size; - - if (compression_ratio != -1) - rrddim_set(stcompression, "savings", compression_ratio); - - rrdset_done(stcompression); + { + static RRDSET *st_compression = NULL; + static RRDDIM *rd_savings = NULL; + + if (unlikely(!st_compression)) { + st_compression = rrdset_create_localhost( + "netdata" + , "compression_ratio" + , NULL + , "netdata" + , NULL + , "NetData API Responses Compression Savings Ratio" + , "percentage" + , "netdata" + , "stats" + , 130500 + , localhost->rrd_update_every + , RRDSET_TYPE_LINE + ); + + rd_savings = rrddim_add(st_compression, "savings", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); + } + else + rrdset_next(st_compression); + + // since we don't lock here to read the global statistics + // read the smaller value first + unsigned long long gcompressed_content_size = gs.compressed_content_size; + unsigned long long gcontent_size = gs.content_size; + + unsigned long long compressed_content_size = gcompressed_content_size - old_compressed_content_size; + unsigned long long content_size = gcontent_size - old_content_size; + + old_compressed_content_size = gcompressed_content_size; + old_content_size = gcontent_size; + + if (content_size && content_size >= compressed_content_size) + compression_ratio = ((content_size - compressed_content_size) * 100 * 1000) / content_size; + + if (compression_ratio != -1) + rrddim_set_by_pointer(st_compression, rd_savings, compression_ratio); + + rrdset_done(st_compression); + } } diff --git a/src/health.c b/src/health.c index 136a1ecd..dfa7007b 100644 --- a/src/health.c +++ b/src/health.c @@ -34,10 +34,10 @@ void health_reload_host(RRDHOST *host) { rrdhost_wrlock(host); while(host->templates) - rrdcalctemplate_free(host, host->templates); + rrdcalctemplate_unlink_and_free(host, host->templates); while(host->alarms) - rrdcalc_free(host, host->alarms); + rrdcalc_unlink_and_free(host, host->alarms); rrdhost_unlock(host); @@ -84,7 +84,7 @@ void health_reload(void) { // ---------------------------------------------------------------------------- // health main thread and friends -static inline int rrdcalc_value2status(calculated_number n) { +static inline RRDCALC_STATUS rrdcalc_value2status(calculated_number n) { if(isnan(n) || isinf(n)) return RRDCALC_STATUS_UNDEFINED; if(n) return RRDCALC_STATUS_RAISED; return RRDCALC_STATUS_CLEAR; @@ -189,7 +189,6 @@ static inline void health_alarm_execute(RRDHOST *host, ALARM_ENTRY *ae) { done: health_alarm_log_save(host, ae); - return; } static inline void health_process_notifications(RRDHOST *host, ALARM_ENTRY *ae) { @@ -537,8 +536,8 @@ void *health_main(void *ptr) { if(unlikely(!(rc->rrdcalc_flags & RRDCALC_FLAG_RUNNABLE))) continue; - int warning_status = RRDCALC_STATUS_UNDEFINED; - int critical_status = RRDCALC_STATUS_UNDEFINED; + RRDCALC_STATUS warning_status = RRDCALC_STATUS_UNDEFINED; + RRDCALC_STATUS critical_status = RRDCALC_STATUS_UNDEFINED; // -------------------------------------------------------- // check the warning expression @@ -605,7 +604,7 @@ void *health_main(void *ptr) { // -------------------------------------------------------- // decide the final alarm status - int status = RRDCALC_STATUS_UNDEFINED; + RRDCALC_STATUS status = RRDCALC_STATUS_UNDEFINED; switch(warning_status) { case RRDCALC_STATUS_CLEAR: diff --git a/src/health.h b/src/health.h index 7028a914..f4157180 100644 --- a/src/health.h +++ b/src/health.h @@ -5,26 +5,28 @@ extern int default_health_enabled; extern int rrdvar_compare(void *a, void *b); -#define RRDVAR_TYPE_CALCULATED 1 -#define RRDVAR_TYPE_TIME_T 2 -#define RRDVAR_TYPE_COLLECTED 3 -#define RRDVAR_TYPE_TOTAL 4 -#define RRDVAR_TYPE_INT 5 -#define RRDVAR_TYPE_CALCULATED_ALLOCATED 6 - +typedef enum rrdvar_type { + RRDVAR_TYPE_CALCULATED = 1, + RRDVAR_TYPE_TIME_T = 2, + RRDVAR_TYPE_COLLECTED = 3, + RRDVAR_TYPE_TOTAL = 4, + RRDVAR_TYPE_INT = 5, + RRDVAR_TYPE_CALCULATED_ALLOCATED = 6 // a custom variable, allocated on purpose (ie. not inherited from charts) + // used only for custom host global variables +} RRDVAR_TYPE; // the variables as stored in the variables indexes // there are 3 indexes: -// 1. at each chart (RRDSET.variables_root_index) -// 2. at each context (RRDFAMILY.variables_root_index) -// 3. at each host (RRDHOST.variables_root_index) +// 1. at each chart (RRDSET.rrdvar_root_index) +// 2. at each context (RRDFAMILY.rrdvar_root_index) +// 3. at each host (RRDHOST.rrdvar_root_index) typedef struct rrdvar { avl avl; char *name; uint32_t hash; - int type; + RRDVAR_TYPE type; void *value; time_t last_updated; @@ -35,15 +37,24 @@ typedef struct rrdvar { // calculated / processed by the normal data collection process // This means, there will be no speed penalty for using // these variables + +typedef enum rrdvar_options { + RRDVAR_OPTION_DEFAULT = (0 << 0), + RRDVAR_OPTION_ALLOCATED = (1 << 0) // the value ptr is allocated (not a reference) + // future use +} RRDVAR_OPTIONS; + typedef struct rrdsetvar { + char *variable; // variable name + uint32_t hash; // variable name hash + char *key_fullid; // chart type.chart id.variable char *key_fullname; // chart type.chart name.variable - char *variable; // variable - int type; + RRDVAR_TYPE type; void *value; - uint32_t options; + RRDVAR_OPTIONS options; RRDVAR *var_local; RRDVAR *var_family; @@ -75,10 +86,10 @@ typedef struct rrddimvar { char *key_fullnameid; // chart type.chart name + dimension id char *key_fullnamename; // chart type.chart name + dimension name - int type; + RRDVAR_TYPE type; void *value; - uint32_t options; + RRDVAR_OPTIONS options; RRDVAR *var_local_id; RRDVAR *var_local_name; @@ -101,7 +112,7 @@ typedef struct rrddimvar { // calculated variables (defined in health configuration) // These aggregate time-series data at fixed intervals // (defined in their update_every member below) -// These increase the overhead of netdata. +// They increase the overhead of netdata. // // These calculations are allocated and linked (->next) // under RRDHOST. @@ -111,14 +122,6 @@ typedef struct rrddimvar { // having as RRDSET.calculations the RRDCALC to be processed // next. -#define RRDCALC_STATUS_REMOVED -2 -#define RRDCALC_STATUS_UNDEFINED -1 -#define RRDCALC_STATUS_UNINITIALIZED 0 -#define RRDCALC_STATUS_CLEAR 1 -#define RRDCALC_STATUS_RAISED 2 -#define RRDCALC_STATUS_WARNING 3 -#define RRDCALC_STATUS_CRITICAL 4 - #define RRDCALC_FLAG_DB_ERROR 0x00000001 #define RRDCALC_FLAG_DB_NAN 0x00000002 /* #define RRDCALC_FLAG_DB_STALE 0x00000004 */ @@ -179,7 +182,7 @@ typedef struct rrdcalc { // ------------------------------------------------------------------------ // runtime information - int status; // the current status of the alarm + RRDCALC_STATUS status; // the current status of the alarm calculated_number value; // the current value of the alarm calculated_number old_value; // the previous value of the alarm @@ -314,8 +317,8 @@ typedef struct alarm_entry { char *old_value_string; char *new_value_string; - int old_status; - int new_status; + RRDCALC_STATUS old_status; + RRDCALC_STATUS new_status; uint32_t flags; @@ -340,11 +343,11 @@ typedef struct alarm_log { #include "rrd.h" extern void rrdsetvar_rename_all(RRDSET *st); -extern RRDSETVAR *rrdsetvar_create(RRDSET *st, const char *variable, int type, void *value, uint32_t options); +extern RRDSETVAR *rrdsetvar_create(RRDSET *st, const char *variable, RRDVAR_TYPE type, void *value, RRDVAR_OPTIONS options); extern void rrdsetvar_free(RRDSETVAR *rs); extern void rrddimvar_rename_all(RRDDIM *rd); -extern RRDDIMVAR *rrddimvar_create(RRDDIM *rd, int type, const char *prefix, const char *suffix, void *value, uint32_t options); +extern RRDDIMVAR *rrddimvar_create(RRDDIM *rd, RRDVAR_TYPE type, const char *prefix, const char *suffix, void *value, RRDVAR_OPTIONS options); extern void rrddimvar_free(RRDDIMVAR *rs); extern void rrdsetcalc_link_matching(RRDSET *st); @@ -364,10 +367,14 @@ extern void health_alarm_log2json(RRDHOST *host, BUFFER *wb, uint32_t after); void health_api_v1_chart_variables2json(RRDSET *st, BUFFER *buf); extern RRDVAR *rrdvar_custom_host_variable_create(RRDHOST *host, const char *name); -extern void rrdvar_custom_host_variable_destroy(RRDHOST *host, const char *name); -extern void rrdvar_custom_host_variable_set(RRDVAR *rv, calculated_number value); +extern void rrdvar_custom_host_variable_set(RRDHOST *host, RRDVAR *rv, calculated_number value); -extern const char *rrdcalc_status2string(int status); +extern RRDSETVAR *rrdsetvar_custom_chart_variable_create(RRDSET *st, const char *name); +extern void rrdsetvar_custom_chart_variable_set(RRDSETVAR *rv, calculated_number value); + +extern void rrdvar_free_remaining_variables(RRDHOST *host, avl_tree_lock *tree_lock); + +extern const char *rrdcalc_status2string(RRDCALC_STATUS status); extern int health_alarm_log_open(RRDHOST *host); @@ -389,8 +396,8 @@ extern void health_alarm_log( time_t duration, calculated_number old_value, calculated_number new_value, - int old_status, - int new_status, + RRDCALC_STATUS old_status, + RRDCALC_STATUS new_status, const char *source, const char *units, const char *info, @@ -403,8 +410,13 @@ extern char *health_config_dir(void); extern void health_reload_host(RRDHOST *host); extern void health_alarm_log_free(RRDHOST *host); -extern void rrdcalc_free(RRDHOST *host, RRDCALC *rc); -extern void rrdcalctemplate_free(RRDHOST *host, RRDCALCTEMPLATE *rt); +extern void rrdcalc_free(RRDCALC *rc); +extern void rrdcalc_unlink_and_free(RRDHOST *host, RRDCALC *rc); + +extern void rrdcalctemplate_free(RRDCALCTEMPLATE *rt); +extern void rrdcalctemplate_unlink_and_free(RRDHOST *host, RRDCALCTEMPLATE *rt); + +extern int rrdvar_callback_for_all_host_variables(RRDHOST *host, int (*callback)(void *rrdvar, void *data), void *data); #ifdef NETDATA_HEALTH_INTERNALS #define RRDVAR_MAX_LENGTH 1024 @@ -416,7 +428,7 @@ extern int rrdvar_fix_name(char *variable); extern RRDCALC *rrdcalc_create(RRDHOST *host, RRDCALCTEMPLATE *rt, const char *chart); extern void rrdcalc_create_part2(RRDHOST *host, RRDCALC *rc); -extern RRDVAR *rrdvar_create_and_index(const char *scope, avl_tree_lock *tree, const char *name, int type, void *value); +extern RRDVAR *rrdvar_create_and_index(const char *scope, avl_tree_lock *tree, const char *name, RRDVAR_TYPE type, void *value); extern void rrdvar_free(RRDHOST *host, avl_tree_lock *tree, RRDVAR *rv); extern void health_alarm_log_free_one_nochecks_nounlink(ALARM_ENTRY *ae); diff --git a/src/health_config.c b/src/health_config.c index 2ead82ef..108eecc4 100644 --- a/src/health_config.c +++ b/src/health_config.c @@ -505,11 +505,12 @@ int health_readfile(RRDHOST *host, const char *path, const char *filename) { if(hash == hash_alarm && !strcasecmp(key, HEALTH_ALARM_KEY)) { if (rc && (ignore_this || !rrdcalc_add_alarm_from_config(host, rc))) - rrdcalc_free(host, rc); + rrdcalc_free(rc); if(rt) { if (ignore_this || !rrdcalctemplate_add_template_from_config(host, rt)) - rrdcalctemplate_free(host, rt); + rrdcalctemplate_free(rt); + rt = NULL; } @@ -532,12 +533,13 @@ int health_readfile(RRDHOST *host, const char *path, const char *filename) { else if(hash == hash_template && !strcasecmp(key, HEALTH_TEMPLATE_KEY)) { if(rc) { if(ignore_this || !rrdcalc_add_alarm_from_config(host, rc)) - rrdcalc_free(host, rc); + rrdcalc_free(rc); + rc = NULL; } if(rt && (ignore_this || !rrdcalctemplate_add_template_from_config(host, rt))) - rrdcalctemplate_free(host, rt); + rrdcalctemplate_free(rt); rt = callocz(1, sizeof(RRDCALCTEMPLATE)); rt->name = strdupz(value); @@ -833,10 +835,10 @@ int health_readfile(RRDHOST *host, const char *path, const char *filename) { } if(rc && (ignore_this || !rrdcalc_add_alarm_from_config(host, rc))) - rrdcalc_free(host, rc); + rrdcalc_free(rc); if(rt && (ignore_this || !rrdcalctemplate_add_template_from_config(host, rt))) - rrdcalctemplate_free(host, rt); + rrdcalctemplate_free(rt); fclose(fp); return 1; diff --git a/src/health_log.c b/src/health_log.c index 9881d35d..0314b086 100644 --- a/src/health_log.c +++ b/src/health_log.c @@ -351,8 +351,8 @@ inline void health_alarm_log( time_t duration, calculated_number old_value, calculated_number new_value, - int old_status, - int new_status, + RRDCALC_STATUS old_status, + RRDCALC_STATUS new_status, const char *source, const char *units, const char *info, @@ -163,11 +163,12 @@ static inline int ipc_sem_get_status(struct ipc_status *st) { int do_ipc(int update_every, usec_t dt) { (void)dt; - static int initialized = 0, read_limits_next = 0; + static int initialized = 0, read_limits_next = -1; static struct ipc_limits limits; static struct ipc_status status; - static RRDVAR *arrays_max = NULL, *semaphores_max = NULL; - static RRDSET *semaphores = NULL, *arrays = NULL; + static RRDSETVAR *arrays_max = NULL, *semaphores_max = NULL; + static RRDSET *st_semaphores = NULL, *st_arrays = NULL; + static RRDDIM *rd_semaphores = NULL, *rd_arrays = NULL; if(unlikely(!initialized)) { initialized = 1; @@ -184,28 +185,46 @@ int do_ipc(int update_every, usec_t dt) { return 1; } - arrays_max = rrdvar_custom_host_variable_create(localhost, "ipc.semaphores.arrays.max"); - semaphores_max = rrdvar_custom_host_variable_create(localhost, "ipc.semaphores.max"); - - if(arrays_max) rrdvar_custom_host_variable_set(arrays_max, limits.semmni); - if(semaphores_max) rrdvar_custom_host_variable_set(semaphores_max, limits.semmns); - // create the charts - semaphores = rrdset_find_localhost("system.ipc_semaphores"); - if(!semaphores) { - semaphores = rrdset_create_localhost("system", "ipc_semaphores", NULL, "ipc semaphores", NULL - , "IPC Semaphores", "semaphores", 1000, localhost->rrd_update_every - , RRDSET_TYPE_AREA); - rrddim_add(semaphores, "semaphores", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); + if(unlikely(!st_semaphores)) { + st_semaphores = rrdset_create_localhost( + "system" + , "ipc_semaphores" + , NULL + , "ipc semaphores" + , NULL + , "IPC Semaphores" + , "semaphores" + , "linux" + , "ipc" + , 1000 + , localhost->rrd_update_every + , RRDSET_TYPE_AREA + ); + rd_semaphores = rrddim_add(st_semaphores, "semaphores", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); } - arrays = rrdset_find_localhost("system.ipc_semaphore_arrays"); - if(!arrays) { - arrays = rrdset_create_localhost("system", "ipc_semaphore_arrays", NULL, "ipc semaphores", NULL - , "IPC Semaphore Arrays", "arrays", 1000, localhost->rrd_update_every - , RRDSET_TYPE_AREA); - rrddim_add(arrays, "arrays", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); + if(unlikely(!st_arrays)) { + st_arrays = rrdset_create_localhost( + "system" + , "ipc_semaphore_arrays" + , NULL + , "ipc semaphores" + , NULL + , "IPC Semaphore Arrays" + , "arrays" + , "linux" + , "ipc" + , 1000 + , localhost->rrd_update_every + , RRDSET_TYPE_AREA + ); + rd_arrays = rrddim_add(st_arrays, "arrays", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); } + + // variables + semaphores_max = rrdsetvar_custom_chart_variable_create(st_semaphores, "ipc.semaphores.max"); + arrays_max = rrdsetvar_custom_chart_variable_create(st_arrays, "ipc.semaphores.arrays.max"); } if(unlikely(read_limits_next < 0)) { @@ -213,11 +232,11 @@ int do_ipc(int update_every, usec_t dt) { error("Unable to fetch semaphore limits."); } else { - if(arrays_max) rrdvar_custom_host_variable_set(arrays_max, limits.semmni); - if(semaphores_max) rrdvar_custom_host_variable_set(semaphores_max, limits.semmns); + if(semaphores_max) rrdsetvar_custom_chart_variable_set(semaphores_max, limits.semmns); + if(arrays_max) rrdsetvar_custom_chart_variable_set(arrays_max, limits.semmni); - arrays->red = limits.semmni; - semaphores->red = limits.semmns; + st_arrays->red = limits.semmni; + st_semaphores->red = limits.semmns; read_limits_next = 60 / update_every; } @@ -230,13 +249,13 @@ int do_ipc(int update_every, usec_t dt) { return 0; } - if(semaphores->counter_done) rrdset_next(semaphores); - rrddim_set(semaphores, "semaphores", status.semaem); - rrdset_done(semaphores); + if(st_semaphores->counter_done) rrdset_next(st_semaphores); + rrddim_set_by_pointer(st_semaphores, rd_semaphores, status.semaem); + rrdset_done(st_semaphores); - if(arrays->counter_done) rrdset_next(arrays); - rrddim_set(arrays, "arrays", status.semusz); - rrdset_done(arrays); + if(st_arrays->counter_done) rrdset_next(st_arrays); + rrddim_set_by_pointer(st_arrays, rd_arrays, status.semusz); + rrdset_done(st_arrays); return 0; } diff --git a/src/macos_fw.c b/src/macos_fw.c index fa103e11..5e8ce0ee 100644 --- a/src/macos_fw.c +++ b/src/macos_fw.c @@ -112,8 +112,14 @@ int do_macos_iokit(int update_every, usec_t dt) { CFRelease(properties); IOObjectRelease(drive_media); + if(unlikely(!diskstat.name || !*diskstat.name)) { + IOObjectRelease(drive); + continue; + } + /* Obtain the properties for this drive object. */ if (unlikely(IORegistryEntryCreateCFProperties(drive, (CFMutableDictionaryRef *)&properties, kCFAllocatorDefault, 0))) { + IOObjectRelease(drive); error("MACOS: IORegistryEntryCreateCFProperties() failed"); do_io = 0; error("DISABLED: system.io"); @@ -138,9 +144,20 @@ int do_macos_iokit(int update_every, usec_t dt) { st = rrdset_find_bytype_localhost("disk", diskstat.name); if (unlikely(!st)) { - st = rrdset_create_localhost("disk", diskstat.name, NULL, diskstat.name, "disk.io" - , "Disk I/O Bandwidth", "kilobytes/s", 2000, update_every - , RRDSET_TYPE_AREA); + st = rrdset_create_localhost( + "disk" + , diskstat.name + , NULL + , diskstat.name + , "disk.io" + , "Disk I/O Bandwidth" + , "kilobytes/s" + , "macos" + , "iokit" + , 2000 + , update_every + , RRDSET_TYPE_AREA + ); rrddim_add(st, "reads", NULL, 1, 1024, RRD_ALGORITHM_INCREMENTAL); rrddim_add(st, "writes", NULL, -1, 1024, RRD_ALGORITHM_INCREMENTAL); @@ -165,9 +182,20 @@ int do_macos_iokit(int update_every, usec_t dt) { st = rrdset_find_bytype_localhost("disk_ops", diskstat.name); if (unlikely(!st)) { - st = rrdset_create_localhost("disk_ops", diskstat.name, NULL, diskstat.name, "disk.ops" - , "Disk Completed I/O Operations", "operations/s", 2001 - , update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + "disk_ops" + , diskstat.name + , NULL + , diskstat.name + , "disk.ops" + , "Disk Completed I/O Operations" + , "operations/s" + , "macos" + , "iokit" + , 2001 + , update_every + , RRDSET_TYPE_LINE + ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); rrddim_add(st, "reads", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -193,9 +221,20 @@ int do_macos_iokit(int update_every, usec_t dt) { st = rrdset_find_bytype_localhost("disk_util", diskstat.name); if (unlikely(!st)) { - st = rrdset_create_localhost("disk_util", diskstat.name, NULL, diskstat.name, "disk.util" - , "Disk Utilization Time", "% of time working", 2004, update_every - , RRDSET_TYPE_AREA); + st = rrdset_create_localhost( + "disk_util" + , diskstat.name + , NULL + , diskstat.name + , "disk.util" + , "Disk Utilization Time" + , "% of time working" + , "macos" + , "iokit" + , 2004 + , update_every + , RRDSET_TYPE_AREA + ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); rrddim_add(st, "utilization", NULL, 1, 10000000, RRD_ALGORITHM_INCREMENTAL); @@ -220,9 +259,20 @@ int do_macos_iokit(int update_every, usec_t dt) { st = rrdset_find_bytype_localhost("disk_iotime", diskstat.name); if (unlikely(!st)) { - st = rrdset_create_localhost("disk_iotime", diskstat.name, NULL, diskstat.name, "disk.iotime" - , "Disk Total I/O Time", "milliseconds/s", 2022, update_every - , RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + "disk_iotime" + , diskstat.name + , NULL + , diskstat.name + , "disk.iotime" + , "Disk Total I/O Time" + , "milliseconds/s" + , "macos" + , "iokit" + , 2022 + , update_every + , RRDSET_TYPE_LINE + ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); rrddim_add(st, "reads", NULL, 1, 1000000, RRD_ALGORITHM_INCREMENTAL); @@ -246,9 +296,20 @@ int do_macos_iokit(int update_every, usec_t dt) { st = rrdset_find_bytype_localhost("disk_await", diskstat.name); if (unlikely(!st)) { - st = rrdset_create_localhost("disk_await", diskstat.name, NULL, diskstat.name, "disk.await" - , "Average Completed I/O Operation Time", "ms per operation" - , 2005, update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + "disk_await" + , diskstat.name + , NULL + , diskstat.name + , "disk.await" + , "Average Completed I/O Operation Time" + , "ms per operation" + , "macos" + , "iokit" + , 2005 + , update_every + , RRDSET_TYPE_LINE + ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); rrddim_add(st, "reads", NULL, 1, 1000000, RRD_ALGORITHM_ABSOLUTE); @@ -266,10 +327,20 @@ int do_macos_iokit(int update_every, usec_t dt) { st = rrdset_find_bytype_localhost("disk_avgsz", diskstat.name); if (unlikely(!st)) { - st = rrdset_create_localhost("disk_avgsz", diskstat.name, NULL, diskstat.name, "disk.avgsz" - , "Average Completed I/O Operation Bandwidth" - , "kilobytes per operation", 2006, update_every - , RRDSET_TYPE_AREA); + st = rrdset_create_localhost( + "disk_avgsz" + , diskstat.name + , NULL + , diskstat.name + , "disk.avgsz" + , "Average Completed I/O Operation Bandwidth" + , "kilobytes per operation" + , "macos" + , "iokit" + , 2006 + , update_every + , RRDSET_TYPE_AREA + ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); rrddim_add(st, "reads", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); @@ -287,9 +358,20 @@ int do_macos_iokit(int update_every, usec_t dt) { st = rrdset_find_bytype_localhost("disk_svctm", diskstat.name); if (unlikely(!st)) { - st = rrdset_create_localhost("disk_svctm", diskstat.name, NULL, diskstat.name, "disk.svctm" - , "Average Service Time", "ms per operation", 2007 - , update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + "disk_svctm" + , diskstat.name + , NULL + , diskstat.name + , "disk.svctm" + , "Average Service Time" + , "ms per operation" + , "macos" + , "iokit" + , 2007 + , update_every + , RRDSET_TYPE_LINE + ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); rrddim_add(st, "svctm", NULL, 1, 1000000, RRD_ALGORITHM_ABSOLUTE); @@ -318,8 +400,20 @@ int do_macos_iokit(int update_every, usec_t dt) { if (likely(do_io)) { st = rrdset_find_bytype_localhost("system", "io"); if (unlikely(!st)) { - st = rrdset_create_localhost("system", "io", NULL, "disk", NULL, "Disk I/O", "kilobytes/s", 150 - , update_every, RRDSET_TYPE_AREA); + st = rrdset_create_localhost( + "system" + , "io" + , NULL + , "disk" + , NULL + , "Disk I/O" + , "kilobytes/s" + , "macos" + , "iokit" + , 150 + , update_every + , RRDSET_TYPE_AREA + ); rrddim_add(st, "in", NULL, 1, 1024, RRD_ALGORITHM_INCREMENTAL); rrddim_add(st, "out", NULL, -1, 1024, RRD_ALGORITHM_INCREMENTAL); } @@ -359,14 +453,24 @@ int do_macos_iokit(int update_every, usec_t dt) { st = rrdset_find_bytype_localhost("disk_space", mntbuf[i].f_mntonname); if (unlikely(!st)) { snprintfz(title, 4096, "Disk Space Usage for %s [%s]", mntbuf[i].f_mntonname, mntbuf[i].f_mntfromname); - st = rrdset_create_localhost("disk_space", mntbuf[i].f_mntonname, NULL, mntbuf[i].f_mntonname - , "disk.space", title, "GB", 2023, update_every - , RRDSET_TYPE_STACKED); + st = rrdset_create_localhost( + "disk_space" + , mntbuf[i].f_mntonname + , NULL + , mntbuf[i].f_mntonname + , "disk.space" + , title + , "GB" + , "macos" + , "iokit" + , 2023 + , update_every + , RRDSET_TYPE_STACKED + ); rrddim_add(st, "avail", NULL, mntbuf[i].f_bsize, GIGA_FACTOR, RRD_ALGORITHM_ABSOLUTE); rrddim_add(st, "used", NULL, mntbuf[i].f_bsize, GIGA_FACTOR, RRD_ALGORITHM_ABSOLUTE); - rrddim_add(st, "reserved_for_root", "reserved for root", mntbuf[i].f_bsize, GIGA_FACTOR, - RRD_ALGORITHM_ABSOLUTE); + rrddim_add(st, "reserved_for_root", "reserved for root", mntbuf[i].f_bsize, GIGA_FACTOR, RRD_ALGORITHM_ABSOLUTE); } else rrdset_next(st); @@ -382,9 +486,20 @@ int do_macos_iokit(int update_every, usec_t dt) { st = rrdset_find_bytype_localhost("disk_inodes", mntbuf[i].f_mntonname); if (unlikely(!st)) { snprintfz(title, 4096, "Disk Files (inodes) Usage for %s [%s]", mntbuf[i].f_mntonname, mntbuf[i].f_mntfromname); - st = rrdset_create_localhost("disk_inodes", mntbuf[i].f_mntonname, NULL, mntbuf[i].f_mntonname - , "disk.inodes", title, "Inodes", 2024, update_every - , RRDSET_TYPE_STACKED); + st = rrdset_create_localhost( + "disk_inodes" + , mntbuf[i].f_mntonname + , NULL + , mntbuf[i].f_mntonname + , "disk.inodes" + , title + , "Inodes" + , "macos" + , "iokit" + , 2024 + , update_every + , RRDSET_TYPE_STACKED + ); rrddim_add(st, "avail", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); rrddim_add(st, "used", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); @@ -417,8 +532,20 @@ int do_macos_iokit(int update_every, usec_t dt) { st = rrdset_find_bytype_localhost("net", ifa->ifa_name); if (unlikely(!st)) { - st = rrdset_create_localhost("net", ifa->ifa_name, NULL, ifa->ifa_name, "net.net", "Bandwidth" - , "kilobits/s", 7000, update_every, RRDSET_TYPE_AREA); + st = rrdset_create_localhost( + "net" + , ifa->ifa_name + , NULL + , ifa->ifa_name + , "net.net" + , "Bandwidth" + , "kilobits/s" + , "macos" + , "iokit" + , 7000 + , update_every + , RRDSET_TYPE_AREA + ); rrddim_add(st, "received", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); rrddim_add(st, "sent", NULL, -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); @@ -433,8 +560,20 @@ int do_macos_iokit(int update_every, usec_t dt) { st = rrdset_find_bytype_localhost("net_packets", ifa->ifa_name); if (unlikely(!st)) { - st = rrdset_create_localhost("net_packets", ifa->ifa_name, NULL, ifa->ifa_name, "net.packets" - , "Packets", "packets/s", 7001, update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + "net_packets" + , ifa->ifa_name + , NULL + , ifa->ifa_name + , "net.packets" + , "Packets" + , "packets/s" + , "macos" + , "iokit" + , 7001 + , update_every + , RRDSET_TYPE_LINE + ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -454,8 +593,20 @@ int do_macos_iokit(int update_every, usec_t dt) { st = rrdset_find_bytype_localhost("net_errors", ifa->ifa_name); if (unlikely(!st)) { - st = rrdset_create_localhost("net_errors", ifa->ifa_name, NULL, ifa->ifa_name, "net.errors" - , "Interface Errors", "errors/s", 7002, update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + "net_errors" + , ifa->ifa_name + , NULL + , ifa->ifa_name + , "net.errors" + , "Interface Errors" + , "errors/s" + , "macos" + , "iokit" + , 7002 + , update_every + , RRDSET_TYPE_LINE + ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); rrddim_add(st, "inbound", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -471,8 +622,20 @@ int do_macos_iokit(int update_every, usec_t dt) { st = rrdset_find_bytype_localhost("net_drops", ifa->ifa_name); if (unlikely(!st)) { - st = rrdset_create_localhost("net_drops", ifa->ifa_name, NULL, ifa->ifa_name, "net.drops" - , "Interface Drops", "drops/s", 7003, update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + "net_drops" + , ifa->ifa_name + , NULL + , ifa->ifa_name + , "net.drops" + , "Interface Drops" + , "drops/s" + , "macos" + , "iokit" + , 7003 + , update_every + , RRDSET_TYPE_LINE + ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); rrddim_add(st, "inbound", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -486,9 +649,20 @@ int do_macos_iokit(int update_every, usec_t dt) { st = rrdset_find_bytype_localhost("net_events", ifa->ifa_name); if (unlikely(!st)) { - st = rrdset_create_localhost("net_events", ifa->ifa_name, NULL, ifa->ifa_name, "net.events" - , "Network Interface Events", "events/s", 7006, update_every - , RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + "net_events" + , ifa->ifa_name + , NULL + , ifa->ifa_name + , "net.events" + , "Network Interface Events" + , "events/s" + , "macos" + , "iokit" + , 7006 + , update_every + , RRDSET_TYPE_LINE + ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); rrddim_add(st, "frames", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); diff --git a/src/macos_mach_smi.c b/src/macos_mach_smi.c index da282551..bcde589f 100644 --- a/src/macos_mach_smi.c +++ b/src/macos_mach_smi.c @@ -25,7 +25,11 @@ int do_macos_mach_smi(int update_every, usec_t dt) { natural_t cp_time[CPU_STATE_MAX]; // NEEDED BY: do_ram, do_swapio, do_pgfaults +#if (defined __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1060) vm_statistics64_data_t vm_statistics; +#else + vm_statistics_data_t vm_statistics; +#endif host = mach_host_self(); kr = host_page_size(host, &system_pagesize); @@ -50,8 +54,20 @@ int do_macos_mach_smi(int update_every, usec_t dt) { st = rrdset_find_bytype_localhost("system", "cpu"); if (unlikely(!st)) { - st = rrdset_create_localhost("system", "cpu", NULL, "cpu", "system.cpu", "Total CPU utilization" - , "percentage", 100, update_every, RRDSET_TYPE_STACKED); + st = rrdset_create_localhost( + "system" + , "cpu" + , NULL + , "cpu" + , "system.cpu" + , "Total CPU utilization" + , "percentage" + , "macos" + , "mach_smi" + , 100 + , update_every + , RRDSET_TYPE_STACKED + ); rrddim_add(st, "user", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); rrddim_add(st, "nice", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); @@ -73,8 +89,13 @@ int do_macos_mach_smi(int update_every, usec_t dt) { // -------------------------------------------------------------------- if (likely(do_ram || do_swapio || do_pgfaults)) { +#if (defined __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1060) count = sizeof(vm_statistics64_data_t); kr = host_statistics64(host, HOST_VM_INFO64, (host_info64_t)&vm_statistics, &count); +#else + count = sizeof(vm_statistics_data_t); + kr = host_statistics(host, HOST_VM_INFO, (host_info_t)&vm_statistics, &count); +#endif if (unlikely(kr != KERN_SUCCESS)) { error("MACOS: host_statistics64() failed: %s", mach_error_string(kr)); do_ram = 0; @@ -87,13 +108,27 @@ int do_macos_mach_smi(int update_every, usec_t dt) { if (likely(do_ram)) { st = rrdset_find_localhost("system.ram"); if (unlikely(!st)) { - st = rrdset_create_localhost("system", "ram", NULL, "ram", NULL, "System RAM", "MB", 200 - , update_every, RRDSET_TYPE_STACKED); + st = rrdset_create_localhost( + "system" + , "ram" + , NULL + , "ram" + , NULL + , "System RAM" + , "MB" + , "macos" + , "mach_smi" + , 200 + , update_every + , RRDSET_TYPE_STACKED + ); rrddim_add(st, "active", NULL, system_pagesize, 1048576, RRD_ALGORITHM_ABSOLUTE); rrddim_add(st, "wired", NULL, system_pagesize, 1048576, RRD_ALGORITHM_ABSOLUTE); +#if (defined __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090) rrddim_add(st, "throttled", NULL, system_pagesize, 1048576, RRD_ALGORITHM_ABSOLUTE); rrddim_add(st, "compressor", NULL, system_pagesize, 1048576, RRD_ALGORITHM_ABSOLUTE); +#endif rrddim_add(st, "inactive", NULL, system_pagesize, 1048576, RRD_ALGORITHM_ABSOLUTE); rrddim_add(st, "purgeable", NULL, system_pagesize, 1048576, RRD_ALGORITHM_ABSOLUTE); rrddim_add(st, "speculative", NULL, system_pagesize, 1048576, RRD_ALGORITHM_ABSOLUTE); @@ -103,8 +138,10 @@ int do_macos_mach_smi(int update_every, usec_t dt) { rrddim_set(st, "active", vm_statistics.active_count); rrddim_set(st, "wired", vm_statistics.wire_count); +#if (defined __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090) rrddim_set(st, "throttled", vm_statistics.throttled_count); rrddim_set(st, "compressor", vm_statistics.compressor_page_count); +#endif rrddim_set(st, "inactive", vm_statistics.inactive_count); rrddim_set(st, "purgeable", vm_statistics.purgeable_count); rrddim_set(st, "speculative", vm_statistics.speculative_count); @@ -112,13 +149,26 @@ int do_macos_mach_smi(int update_every, usec_t dt) { rrdset_done(st); } +#if (defined __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090) // -------------------------------------------------------------------- if (likely(do_swapio)) { st = rrdset_find_localhost("system.swapio"); if (unlikely(!st)) { - st = rrdset_create_localhost("system", "swapio", NULL, "swap", NULL, "Swap I/O", "kilobytes/s", 250 - , update_every, RRDSET_TYPE_AREA); + st = rrdset_create_localhost( + "system" + , "swapio" + , NULL + , "swap" + , NULL + , "Swap I/O" + , "kilobytes/s" + , "macos" + , "mach_smi" + , 250 + , update_every + , RRDSET_TYPE_AREA + ); rrddim_add(st, "in", NULL, system_pagesize, 1024, RRD_ALGORITHM_INCREMENTAL); rrddim_add(st, "out", NULL, -system_pagesize, 1024, RRD_ALGORITHM_INCREMENTAL); @@ -129,22 +179,37 @@ int do_macos_mach_smi(int update_every, usec_t dt) { rrddim_set(st, "out", vm_statistics.swapouts); rrdset_done(st); } +#endif // -------------------------------------------------------------------- if (likely(do_pgfaults)) { st = rrdset_find_localhost("mem.pgfaults"); if (unlikely(!st)) { - st = rrdset_create_localhost("mem", "pgfaults", NULL, "system", NULL, "Memory Page Faults" - , "page faults/s", 500, update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + "mem" + , "pgfaults" + , NULL + , "system" + , NULL + , "Memory Page Faults" + , "page faults/s" + , "macos" + , "mach_smi" + , 500 + , update_every + , RRDSET_TYPE_LINE + ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); rrddim_add(st, "memory", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); rrddim_add(st, "cow", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); rrddim_add(st, "pagein", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); rrddim_add(st, "pageout", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); +#if (defined __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090) rrddim_add(st, "compress", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); rrddim_add(st, "decompress", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); +#endif rrddim_add(st, "zero_fill", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); rrddim_add(st, "reactivate", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); rrddim_add(st, "purge", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -155,8 +220,10 @@ int do_macos_mach_smi(int update_every, usec_t dt) { rrddim_set(st, "cow", vm_statistics.cow_faults); rrddim_set(st, "pagein", vm_statistics.pageins); rrddim_set(st, "pageout", vm_statistics.pageouts); +#if (defined __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090) rrddim_set(st, "compress", vm_statistics.compressions); rrddim_set(st, "decompress", vm_statistics.decompressions); +#endif rrddim_set(st, "zero_fill", vm_statistics.zero_fill_count); rrddim_set(st, "reactivate", vm_statistics.reactivations); rrddim_set(st, "purge", vm_statistics.purges); diff --git a/src/macos_sysctl.c b/src/macos_sysctl.c index 843aceae..cb6fa8af 100644 --- a/src/macos_sysctl.c +++ b/src/macos_sysctl.c @@ -1,4 +1,5 @@ #include "common.h" +#include <Availability.h> #include <sys/sysctl.h> // NEEDED BY: do_bandwidth #include <net/route.h> @@ -112,9 +113,21 @@ int do_macos_sysctl(int update_every, usec_t dt) { /* * Dirty workaround for /usr/include/netinet6/ip6_var.h absence. * Struct ip6stat was copied from bsd/netinet6/ip6_var.h from xnu sources. + * Do the same for previously missing scope6_var.h on OS X < 10.11. */ #define IP6S_SRCRULE_COUNT 16 + +#if (defined __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED < 101100) +#ifndef _NETINET6_SCOPE6_VAR_H_ +#define _NETINET6_SCOPE6_VAR_H_ +#include <sys/appleapiopts.h> + +#define SCOPE6_ID_MAX 16 +#endif +#else #include <netinet6/scope6_var.h> +#endif + struct ip6stat { u_quad_t ip6s_total; /* total packets received */ u_quad_t ip6s_tooshort; /* packet too short */ @@ -217,9 +230,20 @@ int do_macos_sysctl(int update_every, usec_t dt) { st = rrdset_find_bytype_localhost("system", "load"); if (unlikely(!st)) { - st = rrdset_create_localhost("system", "load", NULL, "load", NULL, "System Load Average", "load" - , 100, (update_every < MIN_LOADAVG_UPDATE_EVERY) - ? MIN_LOADAVG_UPDATE_EVERY : update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + "system" + , "load" + , NULL + , "load" + , NULL + , "System Load Average" + , "load" + , "macos" + , "sysctl" + , 100 + , (update_every < MIN_LOADAVG_UPDATE_EVERY) ? MIN_LOADAVG_UPDATE_EVERY : update_every + , RRDSET_TYPE_LINE + ); rrddim_add(st, "load1", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); rrddim_add(st, "load5", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); rrddim_add(st, "load15", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); @@ -246,8 +270,20 @@ int do_macos_sysctl(int update_every, usec_t dt) { } else { st = rrdset_find_localhost("system.swap"); if (unlikely(!st)) { - st = rrdset_create_localhost("system", "swap", NULL, "swap", NULL, "System Swap", "MB", 201 - , update_every, RRDSET_TYPE_STACKED); + st = rrdset_create_localhost( + "system" + , "swap" + , NULL + , "swap" + , NULL + , "System Swap" + , "MB" + , "macos" + , "sysctl" + , 201 + , update_every + , RRDSET_TYPE_STACKED + ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); rrddim_add(st, "free", NULL, 1, 1048576, RRD_ALGORITHM_ABSOLUTE); @@ -296,8 +332,20 @@ int do_macos_sysctl(int update_every, usec_t dt) { } st = rrdset_find_localhost("system.ipv4"); if (unlikely(!st)) { - st = rrdset_create_localhost("system", "ipv4", NULL, "network", NULL, "IPv4 Bandwidth", "kilobits/s" - , 500, update_every, RRDSET_TYPE_AREA); + st = rrdset_create_localhost( + "system" + , "ipv4" + , NULL + , "network" + , NULL + , "IPv4 Bandwidth" + , "kilobits/s" + , "macos" + , "sysctl" + , 500 + , update_every + , RRDSET_TYPE_AREA + ); rrddim_add(st, "InOctets", "received", 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); rrddim_add(st, "OutOctets", "sent", -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); @@ -334,8 +382,20 @@ int do_macos_sysctl(int update_every, usec_t dt) { if (likely(do_tcp_packets)) { st = rrdset_find_localhost("ipv4.tcppackets"); if (unlikely(!st)) { - st = rrdset_create_localhost("ipv4", "tcppackets", NULL, "tcp", NULL, "IPv4 TCP Packets" - , "packets/s", 2600, update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + "ipv4" + , "tcppackets" + , NULL + , "tcp" + , NULL + , "IPv4 TCP Packets" + , "packets/s" + , "macos" + , "sysctl" + , 2600 + , update_every + , RRDSET_TYPE_LINE + ); rrddim_add(st, "InSegs", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL); rrddim_add(st, "OutSegs", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -352,8 +412,20 @@ int do_macos_sysctl(int update_every, usec_t dt) { if (likely(do_tcp_errors)) { st = rrdset_find_localhost("ipv4.tcperrors"); if (unlikely(!st)) { - st = rrdset_create_localhost("ipv4", "tcperrors", NULL, "tcp", NULL, "IPv4 TCP Errors", "packets/s" - , 2700, update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + "ipv4" + , "tcperrors" + , NULL + , "tcp" + , NULL + , "IPv4 TCP Errors" + , "packets/s" + , "macos" + , "sysctl" + , 2700 + , update_every + , RRDSET_TYPE_LINE + ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); rrddim_add(st, "InErrs", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -373,8 +445,20 @@ int do_macos_sysctl(int update_every, usec_t dt) { if (likely(do_tcp_handshake)) { st = rrdset_find_localhost("ipv4.tcphandshake"); if (unlikely(!st)) { - st = rrdset_create_localhost("ipv4", "tcphandshake", NULL, "tcp", NULL, "IPv4 TCP Handshake Issues" - , "events/s", 2900, update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + "ipv4" + , "tcphandshake" + , NULL + , "tcp" + , NULL + , "IPv4 TCP Handshake Issues" + , "events/s" + , "macos" + , "sysctl" + , 2900 + , update_every + , RRDSET_TYPE_LINE + ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); rrddim_add(st, "EstabResets", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -397,8 +481,20 @@ int do_macos_sysctl(int update_every, usec_t dt) { do_tcpext_connaborts = CONFIG_BOOLEAN_YES; st = rrdset_find_localhost("ipv4.tcpconnaborts"); if (unlikely(!st)) { - st = rrdset_create_localhost("ipv4", "tcpconnaborts", NULL, "tcp", NULL, "TCP Connection Aborts" - , "connections/s", 3010, update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + "ipv4" + , "tcpconnaborts" + , NULL + , "tcp" + , NULL + , "TCP Connection Aborts" + , "connections/s" + , "macos" + , "sysctl" + , 3010 + , update_every + , RRDSET_TYPE_LINE + ); rrddim_add(st, "TCPAbortOnData", "baddata", 1, 1, RRD_ALGORITHM_INCREMENTAL); rrddim_add(st, "TCPAbortOnClose", "userclosed", 1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -420,8 +516,20 @@ int do_macos_sysctl(int update_every, usec_t dt) { do_tcpext_ofo = CONFIG_BOOLEAN_YES; st = rrdset_find_localhost("ipv4.tcpofo"); if (unlikely(!st)) { - st = rrdset_create_localhost("ipv4", "tcpofo", NULL, "tcp", NULL, "TCP Out-Of-Order Queue" - , "packets/s", 3050, update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + "ipv4" + , "tcpofo" + , NULL + , "tcp" + , NULL + , "TCP Out-Of-Order Queue" + , "packets/s" + , "macos" + , "sysctl" + , 3050 + , update_every + , RRDSET_TYPE_LINE + ); rrddim_add(st, "TCPOFOQueue", "inqueue", 1, 1, RRD_ALGORITHM_INCREMENTAL); } @@ -438,8 +546,20 @@ int do_macos_sysctl(int update_every, usec_t dt) { st = rrdset_find_localhost("ipv4.tcpsyncookies"); if (unlikely(!st)) { - st = rrdset_create_localhost("ipv4", "tcpsyncookies", NULL, "tcp", NULL, "TCP SYN Cookies" - , "packets/s", 3100, update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + "ipv4" + , "tcpsyncookies" + , NULL + , "tcp" + , NULL + , "TCP SYN Cookies" + , "packets/s" + , "macos" + , "sysctl" + , 3100 + , update_every + , RRDSET_TYPE_LINE + ); rrddim_add(st, "SyncookiesRecv", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL); rrddim_add(st, "SyncookiesSent", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -455,12 +575,26 @@ int do_macos_sysctl(int update_every, usec_t dt) { // -------------------------------------------------------------------- + +#if (defined __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101100) if (do_ecn == CONFIG_BOOLEAN_YES || (do_ecn == CONFIG_BOOLEAN_AUTO && (tcpstat.tcps_ecn_recv_ce || tcpstat.tcps_ecn_not_supported))) { do_ecn = CONFIG_BOOLEAN_YES; st = rrdset_find_localhost("ipv4.ecnpkts"); if (unlikely(!st)) { - st = rrdset_create_localhost("ipv4", "ecnpkts", NULL, "ecn", NULL, "IPv4 ECN Statistics" - , "packets/s", 8700, update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + "ipv4" + , "ecnpkts" + , NULL + , "ecn" + , NULL + , "IPv4 ECN Statistics" + , "packets/s" + , "macos" + , "sysctl" + , 8700 + , update_every + , RRDSET_TYPE_LINE + ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); rrddim_add(st, "InCEPkts", "CEP", 1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -472,6 +606,7 @@ int do_macos_sysctl(int update_every, usec_t dt) { rrddim_set(st, "InNoECTPkts", tcpstat.tcps_ecn_not_supported); rrdset_done(st); } +#endif } } @@ -489,8 +624,20 @@ int do_macos_sysctl(int update_every, usec_t dt) { if (likely(do_udp_packets)) { st = rrdset_find_localhost("ipv4.udppackets"); if (unlikely(!st)) { - st = rrdset_create_localhost("ipv4", "udppackets", NULL, "udp", NULL, "IPv4 UDP Packets" - , "packets/s", 2601, update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + "ipv4" + , "udppackets" + , NULL + , "udp" + , NULL + , "IPv4 UDP Packets" + , "packets/s" + , "macos" + , "sysctl" + , 2601 + , update_every + , RRDSET_TYPE_LINE + ); rrddim_add(st, "InDatagrams", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL); rrddim_add(st, "OutDatagrams", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -507,23 +654,41 @@ int do_macos_sysctl(int update_every, usec_t dt) { if (likely(do_udp_errors)) { st = rrdset_find_localhost("ipv4.udperrors"); if (unlikely(!st)) { - st = rrdset_create_localhost("ipv4", "udperrors", NULL, "udp", NULL, "IPv4 UDP Errors", "events/s" - , 2701, update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + "ipv4" + , "udperrors" + , NULL + , "udp" + , NULL + , "IPv4 UDP Errors" + , "events/s" + , "macos" + , "sysctl" + , 2701 + , update_every + , RRDSET_TYPE_LINE + ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); rrddim_add(st, "NoPorts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); +#if (defined __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090) rrddim_add(st, "IgnoredMulti", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); +#endif } else rrdset_next(st); rrddim_set(st, "InErrors", udpstat.udps_hdrops + udpstat.udps_badlen); rrddim_set(st, "NoPorts", udpstat.udps_noport); rrddim_set(st, "RcvbufErrors", udpstat.udps_fullsock); +#if (defined __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090) rrddim_set(st, "InCsumErrors", udpstat.udps_badsum + udpstat.udps_nosum); rrddim_set(st, "IgnoredMulti", udpstat.udps_filtermcast); +#else + rrddim_set(st, "InCsumErrors", udpstat.udps_badsum); +#endif rrdset_done(st); } } @@ -550,8 +715,20 @@ int do_macos_sysctl(int update_every, usec_t dt) { if (likely(do_icmp_packets)) { st = rrdset_find_localhost("ipv4.icmp"); if (unlikely(!st)) { - st = rrdset_create_localhost("ipv4", "icmp", NULL, "icmp", NULL, "IPv4 ICMP Packets", "packets/s" - , 2602, update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + "ipv4" + , "icmp" + , NULL + , "icmp" + , NULL + , "IPv4 ICMP Packets" + , "packets/s" + , "macos" + , "sysctl" + , 2602 + , update_every + , RRDSET_TYPE_LINE + ); rrddim_add(st, "InMsgs", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL); rrddim_add(st, "OutMsgs", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -567,8 +744,20 @@ int do_macos_sysctl(int update_every, usec_t dt) { st = rrdset_find_localhost("ipv4.icmp_errors"); if (unlikely(!st)) { - st = rrdset_create_localhost("ipv4", "icmp_errors", NULL, "icmp", NULL, "IPv4 ICMP Errors" - , "packets/s", 2603, update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + "ipv4" + , "icmp_errors" + , NULL + , "icmp" + , NULL + , "IPv4 ICMP Errors" + , "packets/s" + , "macos" + , "sysctl" + , 2603 + , update_every + , RRDSET_TYPE_LINE + ); rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); rrddim_add(st, "OutErrors", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -588,8 +777,20 @@ int do_macos_sysctl(int update_every, usec_t dt) { if (likely(do_icmpmsg)) { st = rrdset_find_localhost("ipv4.icmpmsg"); if (unlikely(!st)) { - st = rrdset_create_localhost("ipv4", "icmpmsg", NULL, "icmp", NULL, "IPv4 ICMP Messages" - , "packets/s", 2604, update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + "ipv4" + , "icmpmsg" + , NULL + , "icmp" + , NULL + , "IPv4 ICMP Messages" + , "packets/s" + , "macos" + , "sysctl" + , 2604 + , update_every + , RRDSET_TYPE_LINE + ); rrddim_add(st, "InEchoReps", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); rrddim_add(st, "OutEchoReps", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -625,8 +826,20 @@ int do_macos_sysctl(int update_every, usec_t dt) { if (likely(do_ip_packets)) { st = rrdset_find_localhost("ipv4.packets"); if (unlikely(!st)) { - st = rrdset_create_localhost("ipv4", "packets", NULL, "packets", NULL, "IPv4 Packets", "packets/s" - , 3000, update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + "ipv4" + , "packets" + , NULL + , "packets" + , NULL + , "IPv4 Packets" + , "packets/s" + , "macos" + , "sysctl" + , 3000 + , update_every + , RRDSET_TYPE_LINE + ); rrddim_add(st, "InReceives", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL); rrddim_add(st, "OutRequests", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -647,8 +860,20 @@ int do_macos_sysctl(int update_every, usec_t dt) { if (likely(do_ip_fragsout)) { st = rrdset_find_localhost("ipv4.fragsout"); if (unlikely(!st)) { - st = rrdset_create_localhost("ipv4", "fragsout", NULL, "fragments", NULL, "IPv4 Fragments Sent" - , "packets/s", 3010, update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + "ipv4" + , "fragsout" + , NULL + , "fragments" + , NULL + , "IPv4 Fragments Sent" + , "packets/s" + , "macos" + , "sysctl" + , 3010 + , update_every + , RRDSET_TYPE_LINE + ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); rrddim_add(st, "FragOKs", "ok", 1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -668,8 +893,20 @@ int do_macos_sysctl(int update_every, usec_t dt) { if (likely(do_ip_fragsin)) { st = rrdset_find_localhost("ipv4.fragsin"); if (unlikely(!st)) { - st = rrdset_create_localhost("ipv4", "fragsin", NULL, "fragments", NULL, "IPv4 Fragments Reassembly" - , "packets/s", 3011, update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + "ipv4" + , "fragsin" + , NULL + , "fragments" + , NULL + , "IPv4 Fragments Reassembly" + , "packets/s" + , "macos" + , "sysctl" + , 3011 + , update_every + , RRDSET_TYPE_LINE + ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); rrddim_add(st, "ReasmOKs", "ok", 1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -689,8 +926,20 @@ int do_macos_sysctl(int update_every, usec_t dt) { if (likely(do_ip_errors)) { st = rrdset_find_localhost("ipv4.errors"); if (unlikely(!st)) { - st = rrdset_create_localhost("ipv4", "errors", NULL, "errors", NULL, "IPv4 Errors", "packets/s" - , 3002, update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + "ipv4" + , "errors" + , NULL + , "errors" + , NULL + , "IPv4 Errors" + , "packets/s" + , "macos" + , "sysctl" + , 3002 + , update_every + , RRDSET_TYPE_LINE + ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); rrddim_add(st, "InDiscards", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -734,8 +983,20 @@ int do_macos_sysctl(int update_every, usec_t dt) { do_ip6_packets = CONFIG_BOOLEAN_YES; st = rrdset_find_localhost("ipv6.packets"); if (unlikely(!st)) { - st = rrdset_create_localhost("ipv6", "packets", NULL, "packets", NULL, "IPv6 Packets", "packets/s" - , 3000, update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + "ipv6" + , "packets" + , NULL + , "packets" + , NULL + , "IPv6 Packets" + , "packets/s" + , "macos" + , "sysctl" + , 3000 + , update_every + , RRDSET_TYPE_LINE + ); rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -759,8 +1020,20 @@ int do_macos_sysctl(int update_every, usec_t dt) { do_ip6_fragsout = CONFIG_BOOLEAN_YES; st = rrdset_find_localhost("ipv6.fragsout"); if (unlikely(!st)) { - st = rrdset_create_localhost("ipv6", "fragsout", NULL, "fragments", NULL, "IPv6 Fragments Sent" - , "packets/s", 3010, update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + "ipv6" + , "fragsout" + , NULL + , "fragments" + , NULL + , "IPv6 Fragments Sent" + , "packets/s" + , "macos" + , "sysctl" + , 3010 + , update_every + , RRDSET_TYPE_LINE + ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); rrddim_add(st, "ok", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -783,8 +1056,20 @@ int do_macos_sysctl(int update_every, usec_t dt) { do_ip6_fragsin = CONFIG_BOOLEAN_YES; st = rrdset_find_localhost("ipv6.fragsin"); if (unlikely(!st)) { - st = rrdset_create_localhost("ipv6", "fragsin", NULL, "fragments", NULL, "IPv6 Fragments Reassembly" - , "packets/s", 3011, update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + "ipv6" + , "fragsin" + , NULL + , "fragments" + , NULL + , "IPv6 Fragments Reassembly" + , "packets/s" + , "macos" + , "sysctl" + , 3011 + , update_every + , RRDSET_TYPE_LINE + ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); rrddim_add(st, "ok", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -816,8 +1101,20 @@ int do_macos_sysctl(int update_every, usec_t dt) { do_ip6_errors = CONFIG_BOOLEAN_YES; st = rrdset_find_localhost("ipv6.errors"); if (unlikely(!st)) { - st = rrdset_create_localhost("ipv6", "errors", NULL, "errors", NULL, "IPv6 Errors", "packets/s" - , 3002, update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + "ipv6" + , "errors" + , NULL + , "errors" + , NULL + , "IPv6 Errors" + , "packets/s" + , "macos" + , "sysctl" + , 3002 + , update_every + , RRDSET_TYPE_LINE + ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); rrddim_add(st, "InDiscards", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -863,8 +1160,20 @@ int do_macos_sysctl(int update_every, usec_t dt) { do_icmp6 = CONFIG_BOOLEAN_YES; st = rrdset_find_localhost("ipv6.icmp"); if (unlikely(!st)) { - st = rrdset_create_localhost("ipv6", "icmp", NULL, "icmp", NULL, "IPv6 ICMP Messages", "messages/s" - , 10000, update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + "ipv6" + , "icmp" + , NULL + , "icmp" + , NULL + , "IPv6 ICMP Messages" + , "messages/s" + , "macos" + , "sysctl" + , 10000 + , update_every + , RRDSET_TYPE_LINE + ); rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -882,8 +1191,20 @@ int do_macos_sysctl(int update_every, usec_t dt) { do_icmp6_redir = CONFIG_BOOLEAN_YES; st = rrdset_find_localhost("ipv6.icmpredir"); if (unlikely(!st)) { - st = rrdset_create_localhost("ipv6", "icmpredir", NULL, "icmp", NULL, "IPv6 ICMP Redirects" - , "redirects/s", 10050, update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + "ipv6" + , "icmpredir" + , NULL + , "icmp" + , NULL + , "IPv6 ICMP Redirects" + , "redirects/s" + , "macos" + , "sysctl" + , 10050 + , update_every + , RRDSET_TYPE_LINE + ); rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -912,8 +1233,20 @@ int do_macos_sysctl(int update_every, usec_t dt) { do_icmp6_errors = CONFIG_BOOLEAN_YES; st = rrdset_find_localhost("ipv6.icmperrors"); if (unlikely(!st)) { - st = rrdset_create_localhost("ipv6", "icmperrors", NULL, "icmp", NULL, "IPv6 ICMP Errors" - , "errors/s", 10100, update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + "ipv6" + , "icmperrors" + , NULL + , "icmp" + , NULL + , "IPv6 ICMP Errors" + , "errors/s" + , "macos" + , "sysctl" + , 10100 + , update_every + , RRDSET_TYPE_LINE + ); rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); rrddim_add(st, "OutErrors", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -952,8 +1285,20 @@ int do_macos_sysctl(int update_every, usec_t dt) { do_icmp6_echos = CONFIG_BOOLEAN_YES; st = rrdset_find_localhost("ipv6.icmpechos"); if (unlikely(!st)) { - st = rrdset_create_localhost("ipv6", "icmpechos", NULL, "icmp", NULL, "IPv6 ICMP Echo", "messages/s" - , 10200, update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + "ipv6" + , "icmpechos" + , NULL + , "icmp" + , NULL + , "IPv6 ICMP Echo" + , "messages/s" + , "macos" + , "sysctl" + , 10200 + , update_every + , RRDSET_TYPE_LINE + ); rrddim_add(st, "InEchos", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); rrddim_add(st, "OutEchos", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -979,8 +1324,20 @@ int do_macos_sysctl(int update_every, usec_t dt) { do_icmp6_router = CONFIG_BOOLEAN_YES; st = rrdset_find_localhost("ipv6.icmprouter"); if (unlikely(!st)) { - st = rrdset_create_localhost("ipv6", "icmprouter", NULL, "icmp", NULL, "IPv6 Router Messages" - , "messages/s", 10400, update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + "ipv6" + , "icmprouter" + , NULL + , "icmp" + , NULL + , "IPv6 Router Messages" + , "messages/s" + , "macos" + , "sysctl" + , 10400 + , update_every + , RRDSET_TYPE_LINE + ); rrddim_add(st, "InSolicits", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); rrddim_add(st, "OutSolicits", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -1006,8 +1363,20 @@ int do_macos_sysctl(int update_every, usec_t dt) { do_icmp6_neighbor = CONFIG_BOOLEAN_YES; st = rrdset_find_localhost("ipv6.icmpneighbor"); if (unlikely(!st)) { - st = rrdset_create_localhost("ipv6", "icmpneighbor", NULL, "icmp", NULL, "IPv6 Neighbor Messages" - , "messages/s", 10500, update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + "ipv6" + , "icmpneighbor" + , NULL + , "icmp" + , NULL + , "IPv6 Neighbor Messages" + , "messages/s" + , "macos" + , "sysctl" + , 10500 + , update_every + , RRDSET_TYPE_LINE + ); rrddim_add(st, "InSolicits", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); rrddim_add(st, "OutSolicits", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -1039,8 +1408,20 @@ int do_macos_sysctl(int update_every, usec_t dt) { do_icmp6_types = CONFIG_BOOLEAN_YES; st = rrdset_find_localhost("ipv6.icmptypes"); if (unlikely(!st)) { - st = rrdset_create_localhost("ipv6", "icmptypes", NULL, "icmp", NULL, "IPv6 ICMP Types" - , "messages/s", 10700, update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + "ipv6" + , "icmptypes" + , NULL + , "icmp" + , NULL + , "IPv6 ICMP Types" + , "messages/s" + , "macos" + , "sysctl" + , 10700 + , update_every + , RRDSET_TYPE_LINE + ); rrddim_add(st, "InType1", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); rrddim_add(st, "InType128", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -1081,8 +1462,20 @@ int do_macos_sysctl(int update_every, usec_t dt) { st = rrdset_find_localhost("system.uptime"); if(unlikely(!st)) { - st = rrdset_create_localhost("system", "uptime", NULL, "uptime", NULL, "System Uptime", "seconds", 1000 - , update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + "system" + , "uptime" + , NULL + , "uptime" + , NULL + , "System Uptime" + , "seconds" + , "macos" + , "sysctl" + , 1000 + , update_every + , RRDSET_TYPE_LINE + ); rrddim_add(st, "uptime", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); } else rrdset_next(st); @@ -32,24 +32,34 @@ void netdata_cleanup_and_exit(int ret) { } struct netdata_static_thread static_threads[] = { + #ifdef INTERNAL_PLUGIN_NFACCT -// nfacct requires root access + // nfacct requires root access // so, we build it as an external plugin with setuid to root {"nfacct", CONFIG_SECTION_PLUGINS, "nfacct", 1, NULL, NULL, nfacct_main}, #endif - {"tc", CONFIG_SECTION_PLUGINS, "tc", 1, NULL, NULL, tc_main}, - {"idlejitter", CONFIG_SECTION_PLUGINS, "idlejitter", 1, NULL, NULL, cpuidlejitter_main}, +#ifdef NETDATA_INTERNAL_CHECKS + // debugging plugin + {"check", CONFIG_SECTION_PLUGINS, "checks", 0, NULL, NULL, checks_main}, +#endif + #if defined(__FreeBSD__) + // FreeBSD internal plugins {"freebsd", CONFIG_SECTION_PLUGINS, "freebsd", 1, NULL, NULL, freebsd_main}, #elif defined(__APPLE__) + // macOS internal plugins {"macos", CONFIG_SECTION_PLUGINS, "macos", 1, NULL, NULL, macos_main}, #else + // linux internal plugins {"proc", CONFIG_SECTION_PLUGINS, "proc", 1, NULL, NULL, proc_main}, {"diskspace", CONFIG_SECTION_PLUGINS, "diskspace", 1, NULL, NULL, proc_diskspace_main}, {"cgroups", CONFIG_SECTION_PLUGINS, "cgroups", 1, NULL, NULL, cgroups_main}, + {"tc", CONFIG_SECTION_PLUGINS, "tc", 1, NULL, NULL, tc_main}, #endif /* __FreeBSD__, __APPLE__*/ - {"check", CONFIG_SECTION_PLUGINS, "checks", 0, NULL, NULL, checks_main}, + + // common plugins for all systems + {"idlejitter", CONFIG_SECTION_PLUGINS, "idlejitter", 1, NULL, NULL, cpuidlejitter_main}, {"backends", NULL, NULL, 1, NULL, NULL, backends_main}, {"health", NULL, NULL, 1, NULL, NULL, health_main}, {"plugins.d", NULL, NULL, 1, NULL, NULL, pluginsd_main}, @@ -57,6 +67,7 @@ struct netdata_static_thread static_threads[] = { {"web-single-threaded", NULL, NULL, 0, NULL, NULL, socket_listen_main_single_threaded}, {"push-metrics", NULL, NULL, 0, NULL, NULL, rrdpush_sender_thread}, {"statsd", NULL, NULL, 1, NULL, NULL, statsd_main}, + {NULL, NULL, NULL, 0, NULL, NULL, NULL} }; @@ -83,6 +94,13 @@ void web_server_config_options(void) { web_x_frame_options = config_get(CONFIG_SECTION_WEB, "x-frame-options response header", ""); if(!*web_x_frame_options) web_x_frame_options = NULL; + web_allow_connections_from = simple_pattern_create(config_get(CONFIG_SECTION_WEB, "allow connections from", "localhost *"), SIMPLE_PATTERN_EXACT); + web_allow_dashboard_from = simple_pattern_create(config_get(CONFIG_SECTION_WEB, "allow dashboard from", "localhost *"), SIMPLE_PATTERN_EXACT); + web_allow_badges_from = simple_pattern_create(config_get(CONFIG_SECTION_WEB, "allow badges from", "*"), SIMPLE_PATTERN_EXACT); + web_allow_registry_from = simple_pattern_create(config_get(CONFIG_SECTION_REGISTRY, "allow from", "*"), SIMPLE_PATTERN_EXACT); + web_allow_streaming_from = simple_pattern_create(config_get(CONFIG_SECTION_WEB, "allow streaming from", "*"), SIMPLE_PATTERN_EXACT); + web_allow_netdataconf_from = simple_pattern_create(config_get(CONFIG_SECTION_WEB, "allow netdata.conf from", "localhost fd* 10.* 192.168.* 172.16.* 172.17.* 172.18.* 172.19.* 172.20.* 172.21.* 172.22.* 172.23.* 172.24.* 172.25.* 172.26.* 172.27.* 172.28.* 172.29.* 172.30.* 172.31.*"), SIMPLE_PATTERN_EXACT); + #ifdef NETDATA_WITH_ZLIB web_enable_gzip = config_get_boolean(CONFIG_SECTION_WEB, "enable gzip compression", web_enable_gzip); @@ -195,23 +213,8 @@ void kill_childs() tc_child_pid = 0; } - struct plugind *cd; - for(cd = pluginsd_root ; cd ; cd = cd->next) { - if(cd->enabled && !cd->obsolete) { - info("Stopping %s plugin thread", cd->id); - pthread_cancel(cd->thread); - - if(cd->pid) { - info("killing %s plugin child process pid %d", cd->id, cd->pid); - if(killpid(cd->pid, SIGTERM) != -1) - waitid(P_PID, (id_t) cd->pid, &info, WEXITED); - - cd->pid = 0; - } - - cd->obsolete = 1; - } - } + // stop all running plugins + pluginsd_stop_all_external_plugins(); // if, for any reason there is any child exited // catch it here @@ -221,7 +224,7 @@ void kill_childs() info("All threads/childs stopped."); } -struct option_def options[] = { +struct option_def option_definitions[] = { // opt description arg name default value { 'c', "Configuration file to load.", "filename", CONFIG_DIR "/" CONFIG_FILENAME}, { 'D', "Do not fork. Run in the foreground.", NULL, "run in the background"}, @@ -237,21 +240,21 @@ struct option_def options[] = { { 'W', "See Advanced options below.", "options", NULL}, }; -void help(int exitcode) { +int help(int exitcode) { FILE *stream; if(exitcode == 0) stream = stdout; else stream = stderr; - int num_opts = sizeof(options) / sizeof(struct option_def); + int num_opts = sizeof(option_definitions) / sizeof(struct option_def); int i; int max_len_arg = 0; // Compute maximum argument length for( i = 0; i < num_opts; i++ ) { - if(options[i].arg_name) { - int len_arg = (int)strlen(options[i].arg_name); + if(option_definitions[i].arg_name) { + int len_arg = (int)strlen(option_definitions[i].arg_name); if(len_arg > max_len_arg) max_len_arg = len_arg; } } @@ -289,9 +292,9 @@ void help(int exitcode) { // Output options description. for( i = 0; i < num_opts; i++ ) { - fprintf(stream, " -%c %-*s %s", options[i].val, max_len_arg, options[i].arg_name ? options[i].arg_name : "", options[i].description); - if(options[i].default_value) { - fprintf(stream, "\n %c %-*s Default: %s\n", ' ', max_len_arg, "", options[i].default_value); + fprintf(stream, " -%c %-*s %s", option_definitions[i].val, max_len_arg, option_definitions[i].arg_name ? option_definitions[i].arg_name : "", option_definitions[i].description); + if(option_definitions[i].default_value) { + fprintf(stream, "\n %c %-*s Default: %s\n", ' ', max_len_arg, "", option_definitions[i].default_value); } else { fprintf(stream, "\n"); } @@ -316,7 +319,7 @@ void help(int exitcode) { ); fflush(stream); - exit(exitcode); + return exitcode; } // TODO: Remove this function with the nix major release. @@ -454,17 +457,23 @@ static void get_netdata_configured_variables() { } // ------------------------------------------------------------------------ - // let the plugins know the min update_every - // get system paths + netdata_configured_config_dir = config_get(CONFIG_SECTION_GLOBAL, "config directory", CONFIG_DIR); netdata_configured_log_dir = config_get(CONFIG_SECTION_GLOBAL, "log directory", LOG_DIR); - netdata_configured_plugins_dir = config_get(CONFIG_SECTION_GLOBAL, "plugins directory", PLUGINS_DIR); netdata_configured_web_dir = config_get(CONFIG_SECTION_GLOBAL, "web files directory", WEB_DIR); netdata_configured_cache_dir = config_get(CONFIG_SECTION_GLOBAL, "cache directory", CACHE_DIR); netdata_configured_varlib_dir = config_get(CONFIG_SECTION_GLOBAL, "lib directory", VARLIB_DIR); netdata_configured_home_dir = config_get(CONFIG_SECTION_GLOBAL, "home directory", CACHE_DIR); + { + char plugins_dirs[(FILENAME_MAX * 2) + 1]; + snprintfz(plugins_dirs, FILENAME_MAX * 2, "\"%s\" \"%s/custom-plugins.d\"", PLUGINS_DIR, CONFIG_DIR); + netdata_configured_plugins_dir_base = strdupz(config_get(CONFIG_SECTION_GLOBAL, "plugins directory", plugins_dirs)); + quoted_strings_splitter(netdata_configured_plugins_dir_base, plugin_directories, PLUGINSD_MAX_DIRECTORIES, config_isspace); + netdata_configured_plugins_dir = plugin_directories[0]; + } + // ------------------------------------------------------------------------ // get default memory mode for the database @@ -489,6 +498,95 @@ static void get_netdata_configured_variables() { get_system_pid_max(); } +static void get_system_timezone(void) { + // avoid flood calls to stat(/etc/localtime) + // http://stackoverflow.com/questions/4554271/how-to-avoid-excessive-stat-etc-localtime-calls-in-strftime-on-linux + const char *tz = getenv("TZ"); + if(!tz || !*tz) + setenv("TZ", config_get(CONFIG_SECTION_GLOBAL, "TZ environment variable", ":/etc/localtime"), 0); + + char buffer[FILENAME_MAX + 1] = ""; + const char *timezone = NULL; + ssize_t ret; + + // use the TZ variable + if(tz && *tz && *tz != ':') { + timezone = tz; + // info("TIMEZONE: using TZ variable '%s'", timezone); + } + + // use the contents of /etc/timezone + if(!timezone && !read_file("/etc/timezone", buffer, FILENAME_MAX)) { + timezone = buffer; + // info("TIMEZONE: using the contents of /etc/timezone: '%s'", timezone); + } + + // read the link /etc/localtime + if(!timezone) { + ret = readlink("/etc/localtime", buffer, FILENAME_MAX); + + if(ret > 0) { + buffer[ret] = '\0'; + + char *cmp = "/usr/share/zoneinfo/"; + size_t cmp_len = strlen(cmp); + + char *s = strstr(buffer, cmp); + if (s && s[cmp_len]) { + timezone = &s[cmp_len]; + // info("TIMEZONE: using the link of /etc/localtime: '%s'", timezone); + } + } + else + buffer[0] = '\0'; + } + + // find the timezone from strftime() + if(!timezone) { + time_t t; + struct tm *tmp, tmbuf; + + t = now_realtime_sec(); + tmp = localtime_r(&t, &tmbuf); + + if (tmp != NULL) { + if(strftime(buffer, FILENAME_MAX, "%Z", tmp) == 0) + buffer[0] = '\0'; + else { + buffer[FILENAME_MAX] = '\0'; + timezone = buffer; + // info("TIMEZONE: using strftime(): '%s'", timezone); + } + } + } + + if(timezone && *timezone) { + // make sure it does not have illegal characters + // info("TIMEZONE: fixing '%s'", timezone); + + size_t len = strlen(timezone); + char tmp[len + 1]; + char *d = tmp; + *d = '\0'; + + while(*timezone) { + if(isalnum(*timezone) || *timezone == '_' || *timezone == '/') + *d++ = *timezone++; + else + timezone++; + } + *d = '\0'; + strncpyz(buffer, tmp, len); + timezone = buffer; + // info("TIMEZONE: fixed as '%s'", timezone); + } + + if(!timezone || !*timezone) + timezone = "unknown"; + + netdata_configured_timezone = config_get(CONFIG_SECTION_GLOBAL, "timezone", timezone); +} + void set_global_environment() { { char b[16]; @@ -506,11 +604,7 @@ void set_global_environment() { setenv("HOME" , verify_required_directory(netdata_configured_home_dir), 1); setenv("NETDATA_HOST_PREFIX", netdata_configured_host_prefix, 1); - // avoid flood calls to stat(/etc/localtime) - // http://stackoverflow.com/questions/4554271/how-to-avoid-excessive-stat-etc-localtime-calls-in-strftime-on-linux - const char *tz = getenv("TZ"); - if(!tz || !*tz) - setenv("TZ", config_get(CONFIG_SECTION_GLOBAL, "TZ environment variable", ":/etc/localtime"), 0); + get_system_timezone(); // set the path we need char path[1024 + 1], *p = getenv("PATH"); @@ -571,14 +665,14 @@ int main(int argc, char **argv) { // parse options { - int num_opts = sizeof(options) / sizeof(struct option_def); + int num_opts = sizeof(option_definitions) / sizeof(struct option_def); char optstring[(num_opts * 2) + 1]; int string_i = 0; for( i = 0; i < num_opts; i++ ) { - optstring[string_i] = options[i].val; + optstring[string_i] = option_definitions[i].val; string_i++; - if(options[i].arg_name) { + if(option_definitions[i].arg_name) { optstring[string_i] = ':'; string_i++; } @@ -593,7 +687,7 @@ int main(int argc, char **argv) { case 'c': if(config_load(optarg, 1) != 1) { error("Cannot load configuration file %s.", optarg); - exit(1); + return 1; } else { debug(D_OPTIONS, "Configuration loaded from %s.", optarg); @@ -604,8 +698,7 @@ int main(int argc, char **argv) { dont_fork = 1; break; case 'h': - help(0); - break; + return help(0); case 'i': config_set(CONFIG_SECTION_WEB, "bind to", optarg); break; @@ -635,8 +728,8 @@ int main(int argc, char **argv) { char* debug_flags_string = "debug_flags="; if(strcmp(optarg, "unittest") == 0) { - if(unit_test_buffer()) exit(1); - if(unit_test_str2ld()) exit(1); + if(unit_test_buffer()) return 1; + if(unit_test_str2ld()) return 1; //default_rrd_update_every = 1; //default_rrd_memory_mode = RRD_MEMORY_MODE_RAM; //if(!config_loaded) config_load(NULL, 0); @@ -646,10 +739,10 @@ int main(int argc, char **argv) { default_health_enabled = 0; rrd_init("unittest"); default_rrdpush_enabled = 0; - if(run_all_mockup_tests()) exit(1); - if(unit_test_storage()) exit(1); + if(run_all_mockup_tests()) return 1; + if(unit_test_storage()) return 1; fprintf(stderr, "\n\nALL TESTS PASSED\n\n"); - exit(0); + return 0; } else if(strcmp(optarg, "simple-pattern") == 0) { if(optind + 2 > argc) { @@ -673,24 +766,25 @@ int main(int argc, char **argv) { " -W simple-pattern '!/path/*/*.ext /path/*.ext' '/path/test.ext'\n" "\n" ); - exit(1); + return 1; } const char *heystack = argv[optind]; const char *needle = argv[optind + 1]; + size_t len = strlen(needle) + 1; + char wildcarded[len]; - SIMPLE_PATTERN *p = simple_pattern_create(heystack - , SIMPLE_PATTERN_EXACT); - int ret = simple_pattern_matches(p, needle); + SIMPLE_PATTERN *p = simple_pattern_create(heystack, SIMPLE_PATTERN_EXACT); + int ret = simple_pattern_matches_extract(p, needle, wildcarded, len); simple_pattern_free(p); if(ret) { - fprintf(stdout, "RESULT: MATCHED - pattern '%s' matches '%s'\n", heystack, needle); - exit(0); + fprintf(stdout, "RESULT: MATCHED - pattern '%s' matches '%s', wildcarded '%s'\n", heystack, needle, wildcarded); + return 0; } else { - fprintf(stdout, "RESULT: NOT MATCHED - pattern '%s' does not match '%s'\n", heystack, needle); - exit(1); + fprintf(stdout, "RESULT: NOT MATCHED - pattern '%s' does not match '%s', wildcarded '%s'\n", heystack, needle, wildcarded); + return 1; } } else if(strncmp(optarg, stacksize_string, strlen(stacksize_string)) == 0) { @@ -716,7 +810,7 @@ int main(int argc, char **argv) { " parameters." "\n" ); - exit(1); + return 1; } const char *section = argv[optind]; const char *key = argv[optind + 1]; @@ -741,7 +835,7 @@ int main(int argc, char **argv) { " -c netdata.conf has to be given before -W get.\n" "\n" ); - exit(1); + return 1; } if(!config_loaded) { @@ -757,18 +851,18 @@ int main(int argc, char **argv) { const char *def = argv[optind + 2]; const char *value = config_get(section, key, def); printf("%s\n", value); - exit(0); + return 0; } else { fprintf(stderr, "Unknown -W parameter '%s'\n", optarg); - help(1); + return help(1); } } break; + default: /* ? */ fprintf(stderr, "Unknown parameter '%c'\n", opt); - help(1); - break; + return help(1); } } } @@ -906,6 +1000,7 @@ int main(int argc, char **argv) { // -------------------------------------------------------------------- // create the listening sockets + web_client_api_v1_init(); web_server_threading_selection(); if(web_server_mode != WEB_SERVER_MODE_NONE) @@ -997,4 +1092,8 @@ int main(int argc, char **argv) { // Handle signals signals_handle(); + + // should never reach this point + // but we need it for rpmlint #2752 + return 1; } @@ -16,12 +16,6 @@ struct option_def { const char *default_value; }; -/** - * List of command line options. - * This can be used to compute manpage, help messages, ect. - */ -extern struct option_def options[]; - struct netdata_static_thread { char *name; diff --git a/src/plugin_checks.c b/src/plugin_checks.c index 3a0a83bd..9c1e42cc 100644 --- a/src/plugin_checks.c +++ b/src/plugin_checks.c @@ -1,5 +1,7 @@ #include "common.h" +#ifdef NETDATA_INTERNAL_CHECKS + void *checks_main(void *ptr) { struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr; @@ -16,18 +18,55 @@ void *checks_main(void *ptr) { RRDSET *check1, *check2, *check3, *apps_cpu = NULL; - check1 = rrdset_create_localhost("netdata", "check1", NULL, "netdata", NULL, "Caller gives microseconds" - , "a million !", 99999, localhost->rrd_update_every, RRDSET_TYPE_LINE); + check1 = rrdset_create_localhost( + "netdata" + , "check1" + , NULL + , "netdata" + , NULL + , "Caller gives microseconds" + , "a million !" + , "netdata" + , "checks" + , 99999 + , localhost->rrd_update_every + , RRDSET_TYPE_LINE + ); + rrddim_add(check1, "absolute", NULL, -1, 1, RRD_ALGORITHM_ABSOLUTE); rrddim_add(check1, "incremental", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - check2 = rrdset_create_localhost("netdata", "check2", NULL, "netdata", NULL, "Netdata calcs microseconds" - , "a million !", 99999, localhost->rrd_update_every, RRDSET_TYPE_LINE); + check2 = rrdset_create_localhost( + "netdata" + , "check2" + , NULL + , "netdata" + , NULL + , "Netdata calcs microseconds" + , "a million !" + , "netdata" + , "checks" + , 99999 + , localhost->rrd_update_every + , RRDSET_TYPE_LINE + ); rrddim_add(check2, "absolute", NULL, -1, 1, RRD_ALGORITHM_ABSOLUTE); rrddim_add(check2, "incremental", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - check3 = rrdset_create_localhost("netdata", "checkdt", NULL, "netdata", NULL, "Clock difference" - , "microseconds diff", 99999, localhost->rrd_update_every, RRDSET_TYPE_LINE); + check3 = rrdset_create_localhost( + "netdata" + , "checkdt" + , NULL + , "netdata" + , NULL + , "Clock difference" + , "microseconds diff" + , "netdata" + , "checks" + , 99999 + , localhost->rrd_update_every + , RRDSET_TYPE_LINE + ); rrddim_add(check3, "caller", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); rrddim_add(check3, "netdata", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); rrddim_add(check3, "apps.plugin", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); @@ -87,3 +126,4 @@ void *checks_main(void *ptr) { return NULL; } +#endif // NETDATA_INTERNAL_CHECKS diff --git a/src/plugin_checks.h b/src/plugin_checks.h index c27685b8..05a40bea 100644 --- a/src/plugin_checks.h +++ b/src/plugin_checks.h @@ -1,6 +1,8 @@ #ifndef NETDATA_PLUGIN_CHECKS_H #define NETDATA_PLUGIN_CHECKS_H 1 +#ifdef NETDATA_INTERNAL_CHECKS void *checks_main(void *ptr); +#endif // NETDATA_INTERNAL_CHECKS #endif /* NETDATA_PLUGIN_PROC_H */ diff --git a/src/plugin_freebsd.c b/src/plugin_freebsd.c index c09b28a5..a7825d85 100644 --- a/src/plugin_freebsd.c +++ b/src/plugin_freebsd.c @@ -37,6 +37,7 @@ static struct freebsd_module { // CPU metrics { .name = "kern.cp_times", .dim = "cp_times", .enabled = 1, .func = do_kern_cp_times }, { .name = "dev.cpu.temperature", .dim = "cpu_temperature", .enabled = 1, .func = do_dev_cpu_temperature }, + { .name = "dev.cpu.0.freq", .dim = "cpu_frequency", .enabled = 1, .func = do_dev_cpu_0_freq }, // disk metrics { .name = "kern.devstat", .dim = "kern_devstat", .enabled = 1, .func = do_kern_devstat }, @@ -56,6 +57,7 @@ static struct freebsd_module { // ZFS metrics { .name = "kstat.zfs.misc.arcstats", .dim = "arcstats", .enabled = 1, .func = do_kstat_zfs_misc_arcstats }, + { .name = "kstat.zfs.misc.zio_trim", .dim = "trim", .enabled = 1, .func = do_kstat_zfs_misc_zio_trim }, // ipfw metrics { .name = "ipfw", .dim = "ipfw", .enabled = 1, .func = do_ipfw }, @@ -127,9 +129,20 @@ void *freebsd_main(void *ptr) { st = rrdset_find_bytype_localhost("netdata", "plugin_freebsd_modules"); if(!st) { - st = rrdset_create_localhost("netdata", "plugin_freebsd_modules", NULL, "freebsd", NULL - , "NetData FreeBSD Plugin Modules Durations", "milliseconds/run", 132001 - , localhost->rrd_update_every, RRDSET_TYPE_STACKED); + st = rrdset_create_localhost( + "netdata" + , "plugin_freebsd_modules" + , NULL + , "freebsd" + , NULL + , "NetData FreeBSD Plugin Modules Durations" + , "milliseconds/run" + , "netdata" + , "stats" + , 132001 + , localhost->rrd_update_every + , RRDSET_TYPE_STACKED + ); for(i = 0 ; freebsd_modules[i].name ;i++) { struct freebsd_module *pm = &freebsd_modules[i]; diff --git a/src/plugin_freebsd.h b/src/plugin_freebsd.h index 78fe33d7..0a6f40c1 100644 --- a/src/plugin_freebsd.h +++ b/src/plugin_freebsd.h @@ -18,6 +18,7 @@ extern int do_vm_vmtotal(int update_every, usec_t dt); extern int do_kern_cp_time(int update_every, usec_t dt); extern int do_kern_cp_times(int update_every, usec_t dt); extern int do_dev_cpu_temperature(int update_every, usec_t dt); +extern int do_dev_cpu_0_freq(int update_every, usec_t dt); extern int do_hw_intcnt(int update_every, usec_t dt); extern int do_vm_stats_sys_v_intr(int update_every, usec_t dt); extern int do_vm_stats_sys_v_soft(int update_every, usec_t dt); @@ -43,6 +44,7 @@ extern int do_getifaddrs(int update_every, usec_t dt); extern int do_getmntinfo(int update_every, usec_t dt); extern int do_kern_devstat(int update_every, usec_t dt); extern int do_kstat_zfs_misc_arcstats(int update_every, usec_t dt); +extern int do_kstat_zfs_misc_zio_trim(int update_every, usec_t dt); extern int do_ipfw(int update_every, usec_t dt); #define GETSYSCTL_MIB(name, mib) getsysctl_mib(name, mib, sizeof(mib)/sizeof(int)) diff --git a/src/plugin_idlejitter.c b/src/plugin_idlejitter.c index 89f49023..8d933683 100644 --- a/src/plugin_idlejitter.c +++ b/src/plugin_idlejitter.c @@ -27,6 +27,8 @@ void *cpuidlejitter_main(void *ptr) { , NULL , "CPU Idle Jitter" , "microseconds lost/s" + , "idlejitter" + , NULL , 9999 , localhost->rrd_update_every , RRDSET_TYPE_AREA diff --git a/src/plugin_nfacct.c b/src/plugin_nfacct.c index 4c691be0..8319c672 100644 --- a/src/plugin_nfacct.c +++ b/src/plugin_nfacct.c @@ -302,6 +302,8 @@ static void nfstat_send_metrics() { , NULL , "Connection Tracker New Connections" , "connections/s" + , "nfacct" + , NULL , 3001 , nfstat_root.update_every , RRDSET_TYPE_LINE @@ -336,6 +338,8 @@ static void nfstat_send_metrics() { , NULL , "Connection Tracker Changes" , "changes/s" + , "nfacct" + , NULL , 3002 , nfstat_root.update_every , RRDSET_TYPE_LINE @@ -371,6 +375,8 @@ static void nfstat_send_metrics() { , NULL , "Connection Tracker Searches" , "searches/s" + , "nfacct" + , NULL , 3010 , nfstat_root.update_every , RRDSET_TYPE_LINE @@ -406,6 +412,8 @@ static void nfstat_send_metrics() { , NULL , "Connection Tracker Errors" , "events/s" + , "nfacct" + , NULL , 3005 , nfstat_root.update_every , RRDSET_TYPE_LINE @@ -443,6 +451,8 @@ static void nfstat_send_metrics() { , NULL , "Connection Tracker Expectations" , "expectations/s" + , "nfacct" + , NULL , 3003 , nfstat_root.update_every , RRDSET_TYPE_LINE @@ -661,6 +671,8 @@ static void nfacct_send_metrics() { , NULL , "Netfilter Accounting Packets" , "packets/s" + , "nfacct" + , NULL , 3206 , nfacct_root.update_every , RRDSET_TYPE_STACKED @@ -702,6 +714,8 @@ static void nfacct_send_metrics() { , NULL , "Netfilter Accounting Bandwidth" , "kilobytes/s" + , "nfacct" + , NULL , 3207 , nfacct_root.update_every , RRDSET_TYPE_STACKED diff --git a/src/plugin_proc.c b/src/plugin_proc.c index e64f5739..c4249c84 100644 --- a/src/plugin_proc.c +++ b/src/plugin_proc.c @@ -32,6 +32,8 @@ static struct proc_module { // network metrics { .name = "/proc/net/dev", .dim = "netdev", .func = do_proc_net_dev }, + { .name = "/proc/net/sockstat", .dim = "sockstat", .func = do_proc_net_sockstat }, + { .name = "/proc/net/sockstat6", .dim = "sockstat6", .func = do_proc_net_sockstat6 }, { .name = "/proc/net/netstat", .dim = "netstat", .func = do_proc_net_netstat }, // this has to be before /proc/net/snmp, because there is a shared metric { .name = "/proc/net/snmp", .dim = "snmp", .func = do_proc_net_snmp }, { .name = "/proc/net/snmp6", .dim = "snmp6", .func = do_proc_net_snmp6 }, @@ -118,9 +120,20 @@ void *proc_main(void *ptr) { st = rrdset_find_bytype_localhost("netdata", "plugin_proc_modules"); if(!st) { - st = rrdset_create_localhost("netdata", "plugin_proc_modules", NULL, "proc", NULL - , "NetData Proc Plugin Modules Durations", "milliseconds/run", 132001 - , localhost->rrd_update_every, RRDSET_TYPE_STACKED); + st = rrdset_create_localhost( + "netdata" + , "plugin_proc_modules" + , NULL + , "proc" + , NULL + , "NetData Proc Plugin Modules Durations" + , "milliseconds/run" + , "netdata" + , "stats" + , 132001 + , localhost->rrd_update_every + , RRDSET_TYPE_STACKED + ); for(i = 0 ; proc_modules[i].name ;i++) { struct proc_module *pm = &proc_modules[i]; diff --git a/src/plugin_proc.h b/src/plugin_proc.h index 72cfc6aa..fa567544 100644 --- a/src/plugin_proc.h +++ b/src/plugin_proc.h @@ -26,6 +26,8 @@ extern int do_proc_uptime(int update_every, usec_t dt); extern int do_proc_sys_devices_system_edac_mc(int update_every, usec_t dt); extern int do_proc_sys_devices_system_node(int update_every, usec_t dt); extern int do_proc_spl_kstat_zfs_arcstats(int update_every, usec_t dt); +extern int do_proc_net_sockstat(int update_every, usec_t dt); +extern int do_proc_net_sockstat6(int update_every, usec_t dt); extern int get_numa_node_count(void); diff --git a/src/plugin_proc_diskspace.c b/src/plugin_proc_diskspace.c index 52c1f5ae..e41e7618 100644 --- a/src/plugin_proc_diskspace.c +++ b/src/plugin_proc_diskspace.c @@ -227,6 +227,12 @@ static inline void do_disk_space_stats(struct mountinfo *mi, int update_every) { fsfilcnt_t freserved_root = favail_root - favail; fsfilcnt_t fused = ftotal - favail_root; + if(m->do_inodes == CONFIG_BOOLEAN_AUTO && favail == (fsfilcnt_t)-1) { + // this file system does not support inodes reporting + // eg. cephfs + m->do_inodes = CONFIG_BOOLEAN_NO; + } + #ifdef NETDATA_INTERNAL_CHECKS if(unlikely(btotal != bavail + breserved_root + bused)) error("DISKSPACE: disk inode statistics for '%s' (disk '%s') do not sum up: total = %llu, available = %llu, reserved = %llu, used = %llu", mi->mount_point, disk, (unsigned long long)ftotal, (unsigned long long)favail, (unsigned long long)freserved_root, (unsigned long long)fused); @@ -251,6 +257,8 @@ static inline void do_disk_space_stats(struct mountinfo *mi, int update_every) { , "disk.space" , title , "GB" + , "diskspace" + , NULL , 2023 , update_every , RRDSET_TYPE_STACKED @@ -289,6 +297,8 @@ static inline void do_disk_space_stats(struct mountinfo *mi, int update_every) { , "disk.inodes" , title , "Inodes" + , "diskspace" + , NULL , 2024 , update_every , RRDSET_TYPE_STACKED @@ -384,21 +394,21 @@ void *proc_diskspace_main(void *ptr) { getrusage(RUSAGE_THREAD, &thread); - if(!stcpu_thread) { - stcpu_thread = rrdset_find_localhost("netdata.plugin_diskspace"); - if(!stcpu_thread) - stcpu_thread = rrdset_create_localhost( - "netdata" - , "plugin_diskspace" - , NULL - , "diskspace" - , NULL - , "NetData Disk Space Plugin CPU usage" - , "milliseconds/s" - , 132020 - , update_every - , RRDSET_TYPE_STACKED - ); + if(unlikely(!stcpu_thread)) { + stcpu_thread = rrdset_create_localhost( + "netdata" + , "plugin_diskspace" + , NULL + , "diskspace" + , NULL + , "NetData Disk Space Plugin CPU usage" + , "milliseconds/s" + , "diskspace" + , NULL + , 132020 + , update_every + , RRDSET_TYPE_STACKED + ); rd_user = rrddim_add(stcpu_thread, "user", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL); rd_system = rrddim_add(stcpu_thread, "system", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL); @@ -412,21 +422,21 @@ void *proc_diskspace_main(void *ptr) { // ---------------------------------------------------------------- - if(!st_duration) { - st_duration = rrdset_find_localhost("netdata.plugin_diskspace_dt"); - if(!st_duration) - st_duration = rrdset_create_localhost( - "netdata" - , "plugin_diskspace_dt" - , NULL - , "diskspace" - , NULL - , "NetData Disk Space Plugin Duration" - , "milliseconds/run" - , 132021 - , update_every - , RRDSET_TYPE_AREA - ); + if(unlikely(!st_duration)) { + st_duration = rrdset_create_localhost( + "netdata" + , "plugin_diskspace_dt" + , NULL + , "diskspace" + , NULL + , "NetData Disk Space Plugin Duration" + , "milliseconds/run" + , "diskspace" + , NULL + , 132021 + , update_every + , RRDSET_TYPE_AREA + ); rd_duration = rrddim_add(st_duration, "duration", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); } diff --git a/src/plugin_tc.c b/src/plugin_tc.c index c928e61b..0d8fd3d6 100644 --- a/src/plugin_tc.c +++ b/src/plugin_tc.c @@ -81,6 +81,7 @@ struct tc_device { avl_tree classes_index; struct tc_class *classes; + struct tc_class *last_class; struct tc_device *next; struct tc_device *prev; @@ -139,11 +140,19 @@ static inline struct tc_class *tc_class_index_find(struct tc_device *st, const c static inline void tc_class_free(struct tc_device *n, struct tc_class *c) { if(c == n->classes) { - if(c->next) + if(likely(c->next)) n->classes = c->next; else n->classes = c->prev; } + + if(c == n->last_class) { + if(unlikely(c->next)) + n->last_class = c->next; + else + n->last_class = c->prev; + } + if(c->next) c->next->prev = c->prev; if(c->prev) c->prev->next = c->next; @@ -374,11 +383,20 @@ static inline void tc_device_commit(struct tc_device *d) { d->enabled_bytes = CONFIG_BOOLEAN_YES; if(unlikely(!d->st_bytes)) - d->st_bytes = rrdset_create_localhost(RRD_TYPE_TC, d->id, d->name ? d->name : d->id - , d->family ? d->family : d->id, RRD_TYPE_TC ".qos", "Class Usage" - , "kilobits/s", 7000, localhost->rrd_update_every - , d->enabled_all_classes_qdiscs ? RRDSET_TYPE_LINE - : RRDSET_TYPE_STACKED); + d->st_bytes = rrdset_create_localhost( + RRD_TYPE_TC + , d->id + , d->name ? d->name : d->id + , d->family ? d->family : d->id + , RRD_TYPE_TC ".qos" + , "Class Usage" + , "kilobits/s" + , "tc" + , NULL + , 7000 + , localhost->rrd_update_every + , d->enabled_all_classes_qdiscs ? RRDSET_TYPE_LINE : RRDSET_TYPE_STACKED + ); else { rrdset_next(d->st_bytes); @@ -413,10 +431,20 @@ static inline void tc_device_commit(struct tc_device *d) { snprintfz(id, RRD_ID_LENGTH_MAX, "%s_packets", d->id); snprintfz(name, RRD_ID_LENGTH_MAX, "%s_packets", d->name?d->name:d->id); - d->st_packets = rrdset_create_localhost(RRD_TYPE_TC, id, name, d->family ? d->family : d->id - , RRD_TYPE_TC ".qos_packets", "Class Packets", "packets/s", 7010 - , localhost->rrd_update_every, d->enabled_all_classes_qdiscs ? RRDSET_TYPE_LINE - : RRDSET_TYPE_STACKED); + d->st_packets = rrdset_create_localhost( + RRD_TYPE_TC + , id + , name + , d->family ? d->family : d->id + , RRD_TYPE_TC ".qos_packets" + , "Class Packets" + , "packets/s" + , "tc" + , NULL + , 7010 + , localhost->rrd_update_every + , d->enabled_all_classes_qdiscs ? RRDSET_TYPE_LINE : RRDSET_TYPE_STACKED + ); } else { rrdset_next(d->st_packets); @@ -456,11 +484,20 @@ static inline void tc_device_commit(struct tc_device *d) { snprintfz(id, RRD_ID_LENGTH_MAX, "%s_dropped", d->id); snprintfz(name, RRD_ID_LENGTH_MAX, "%s_dropped", d->name?d->name:d->id); - d->st_dropped = rrdset_create_localhost(RRD_TYPE_TC, id, name, d->family ? d->family : d->id - , RRD_TYPE_TC ".qos_dropped", "Class Dropped Packets", "packets/s" - , 7020, localhost->rrd_update_every - , d->enabled_all_classes_qdiscs ? RRDSET_TYPE_LINE - : RRDSET_TYPE_STACKED); + d->st_dropped = rrdset_create_localhost( + RRD_TYPE_TC + , id + , name + , d->family ? d->family : d->id + , RRD_TYPE_TC ".qos_dropped" + , "Class Dropped Packets" + , "packets/s" + , "tc" + , NULL + , 7020 + , localhost->rrd_update_every + , d->enabled_all_classes_qdiscs ? RRDSET_TYPE_LINE : RRDSET_TYPE_STACKED + ); } else { rrdset_next(d->st_dropped); @@ -500,9 +537,20 @@ static inline void tc_device_commit(struct tc_device *d) { snprintfz(id, RRD_ID_LENGTH_MAX, "%s_tokens", d->id); snprintfz(name, RRD_ID_LENGTH_MAX, "%s_tokens", d->name?d->name:d->id); - d->st_tokens = rrdset_create_localhost(RRD_TYPE_TC, id, name, d->family ? d->family : d->id - , RRD_TYPE_TC ".qos_tokens", "Class Tokens", "tokens", 7030 - , localhost->rrd_update_every, RRDSET_TYPE_LINE); + d->st_tokens = rrdset_create_localhost( + RRD_TYPE_TC + , id + , name + , d->family ? d->family : d->id + , RRD_TYPE_TC ".qos_tokens" + , "Class Tokens" + , "tokens" + , "tc" + , NULL + , 7030 + , localhost->rrd_update_every + , RRDSET_TYPE_LINE + ); } else { rrdset_next(d->st_tokens); @@ -543,9 +591,20 @@ static inline void tc_device_commit(struct tc_device *d) { snprintfz(id, RRD_ID_LENGTH_MAX, "%s_ctokens", d->id); snprintfz(name, RRD_ID_LENGTH_MAX, "%s_ctokens", d->name?d->name:d->id); - d->st_ctokens = rrdset_create_localhost(RRD_TYPE_TC, id, name, d->family ? d->family : d->id - , RRD_TYPE_TC ".qos_ctokens", "Class cTokens", "ctokens", 7040 - , localhost->rrd_update_every, RRDSET_TYPE_LINE); + d->st_ctokens = rrdset_create_localhost( + RRD_TYPE_TC + , id + , name + , d->family ? d->family : d->id + , RRD_TYPE_TC ".qos_ctokens" + , "Class cTokens" + , "ctokens" + , "tc" + , NULL + , 7040 + , localhost->rrd_update_every + , RRDSET_TYPE_LINE + ); } else { debug(D_TC_LOOP, "TC: Updating _ctokens chart for device '%s'", d->name?d->name:d->id); @@ -605,7 +664,7 @@ static inline void tc_device_set_device_name(struct tc_device *d, char *name) { d->name = NULL; } - if(likely(name && *name && strcmp(d->id, name))) { + if(likely(name && *name && strcmp(d->id, name) != 0)) { debug(D_TC_LOOP, "TC: Setting device '%s' name to '%s'", d->id, name); d->name = strdupz(name); d->name_updated = 1; @@ -663,9 +722,15 @@ static inline struct tc_class *tc_class_add(struct tc_device *n, char *id, char c = callocz(1, sizeof(struct tc_class)); - if(n->classes) n->classes->prev = c; - c->next = n->classes; - n->classes = c; + if(unlikely(!n->classes)) + n->classes = c; + + else if(likely(n->last_class)) { + n->last_class->next = c; + c->prev = n->last_class; + } + + n->last_class = c; c->id = strdupz(id); c->hash = simple_hash(c->id); @@ -776,7 +841,6 @@ void *tc_main(void *ptr) { error("Cannot set pthread cancel state to ENABLE."); struct rusage thread; - RRDSET *stcpu = NULL, *sttime = NULL; char buffer[TC_LINE_MAX+1] = ""; char *words[PLUGINSD_MAX_WORDS] = { NULL }; @@ -989,30 +1053,56 @@ void *tc_main(void *ptr) { // debug(D_TC_LOOP, "WORKTIME line '%s' '%s'", words[1], words[2]); getrusage(RUSAGE_THREAD, &thread); - if(unlikely(!stcpu)) stcpu = rrdset_find_localhost("netdata.plugin_tc_cpu"); + static RRDSET *stcpu = NULL; + static RRDDIM *rd_user = NULL, *rd_system = NULL; + if(unlikely(!stcpu)) { - stcpu = rrdset_create_localhost("netdata", "plugin_tc_cpu", NULL, "tc.helper", NULL - , "NetData TC CPU usage", "milliseconds/s", 135000, localhost->rrd_update_every - , RRDSET_TYPE_STACKED); - rrddim_add(stcpu, "user", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(stcpu, "system", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL); + stcpu = rrdset_create_localhost( + "netdata" + , "plugin_tc_cpu" + , NULL + , "tc.helper" + , NULL + , "NetData TC CPU usage" + , "milliseconds/s" + , "tc" + , NULL + , 135000 + , localhost->rrd_update_every + , RRDSET_TYPE_STACKED + ); + rd_user = rrddim_add(stcpu, "user", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL); + rd_system = rrddim_add(stcpu, "system", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(stcpu); - rrddim_set(stcpu, "user" , thread.ru_utime.tv_sec * 1000000ULL + thread.ru_utime.tv_usec); - rrddim_set(stcpu, "system", thread.ru_stime.tv_sec * 1000000ULL + thread.ru_stime.tv_usec); + rrddim_set_by_pointer(stcpu, rd_user , thread.ru_utime.tv_sec * 1000000ULL + thread.ru_utime.tv_usec); + rrddim_set_by_pointer(stcpu, rd_system, thread.ru_stime.tv_sec * 1000000ULL + thread.ru_stime.tv_usec); rrdset_done(stcpu); - if(unlikely(!sttime)) sttime = rrdset_find_localhost("netdata.plugin_tc_time"); + static RRDSET *sttime = NULL; + static RRDDIM *rd_run_time = NULL; + if(unlikely(!sttime)) { - sttime = rrdset_create_localhost("netdata", "plugin_tc_time", NULL, "tc.helper", NULL - , "NetData TC script execution", "milliseconds/run", 135001 - , localhost->rrd_update_every, RRDSET_TYPE_AREA); - rrddim_add(sttime, "run_time", "run time", 1, 1, RRD_ALGORITHM_ABSOLUTE); + sttime = rrdset_create_localhost( + "netdata" + , "plugin_tc_time" + , NULL + , "tc.helper" + , NULL + , "NetData TC script execution" + , "milliseconds/run" + , "tc" + , NULL + , 135001 + , localhost->rrd_update_every + , RRDSET_TYPE_AREA + ); + rd_run_time = rrddim_add(sttime, "run_time", "run time", 1, 1, RRD_ALGORITHM_ABSOLUTE); } else rrdset_next(sttime); - rrddim_set(sttime, "run_time", atoll(words[1])); + rrddim_set_by_pointer(sttime, rd_run_time, str2ll(words[1], NULL)); rrdset_done(sttime); } diff --git a/src/plugins_d.c b/src/plugins_d.c index 42433b55..d0f29f4d 100644 --- a/src/plugins_d.c +++ b/src/plugins_d.c @@ -1,5 +1,8 @@ #include "common.h" +char *plugin_directories[PLUGINSD_MAX_DIRECTORIES] = { NULL }; +char *netdata_configured_plugins_dir_base; + struct plugind *pluginsd_root = NULL; static inline int pluginsd_space(char c) { @@ -16,13 +19,27 @@ static inline int pluginsd_space(char c) { } } +inline int config_isspace(char c) { + switch(c) { + case ' ': + case '\t': + case '\r': + case '\n': + case ',': + return 1; + + default: + return 0; + } +} + // split a text into words, respecting quotes -inline int pluginsd_split_words(char *str, char **words, int max_words) { +inline int quoted_strings_splitter(char *str, char **words, int max_words, int (*custom_isspace)(char)) { char *s = str, quote = 0; int i = 0, j; // skip all white space - while(unlikely(pluginsd_space(*s))) s++; + while(unlikely(custom_isspace(*s))) s++; // check for quote if(unlikely(*s == '\'' || *s == '"')) { @@ -49,13 +66,13 @@ inline int pluginsd_split_words(char *str, char **words, int max_words) { } // if it is a space - else if(unlikely(quote == 0 && pluginsd_space(*s))) { + else if(unlikely(quote == 0 && custom_isspace(*s))) { // terminate the word *s++ = '\0'; // skip all white space - while(likely(pluginsd_space(*s))) s++; + while(likely(custom_isspace(*s))) s++; // check for quote if(unlikely(*s == '\'' || *s == '"')) { @@ -82,6 +99,10 @@ inline int pluginsd_split_words(char *str, char **words, int max_words) { return i; } +inline int pluginsd_split_words(char *str, char **words, int max_words) { + return quoted_strings_splitter(str, words, max_words, pluginsd_space); +} + inline size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int trust_durations) { int enabled = cd->enabled; @@ -101,6 +122,7 @@ inline size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int uint32_t CHART_HASH = simple_hash(PLUGINSD_KEYWORD_CHART); uint32_t DIMENSION_HASH = simple_hash(PLUGINSD_KEYWORD_DIMENSION); uint32_t DISABLE_HASH = simple_hash(PLUGINSD_KEYWORD_DISABLE); + uint32_t VARIABLE_HASH = simple_hash(PLUGINSD_KEYWORD_VARIABLE); RRDSET *st = NULL; uint32_t hash; @@ -212,10 +234,6 @@ inline size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int count++; } - else if(likely(hash == FLUSH_HASH && !strcmp(s, PLUGINSD_KEYWORD_FLUSH))) { - debug(D_PLUGINSD, "PLUGINSD: '%s' is requesting a FLUSH", cd->fullfilename); - st = NULL; - } else if(likely(hash == CHART_HASH && !strcmp(s, PLUGINSD_KEYWORD_CHART))) { st = NULL; @@ -229,6 +247,8 @@ inline size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int char *priority_s = words[8]; char *update_every_s = words[9]; char *options = words[10]; + char *plugin = words[11]; + char *module = words[12]; // parse the id from type char *id = NULL; @@ -275,22 +295,31 @@ inline size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int if(unlikely(!title)) title = ""; if(unlikely(!units)) units = "unknown"; - st = rrdset_find_bytype(host, type, id); - if(unlikely(!st)) { - debug(D_PLUGINSD, "PLUGINSD: Creating chart type='%s', id='%s', name='%s', family='%s', context='%s', chart='%s', priority=%d, update_every=%d" - , type, id - , name?name:"" - , family?family:"" - , context?context:"" - , rrdset_type_name(chart_type) - , priority - , update_every - ); - - st = rrdset_create(host, type, id, name, family, context, title, units, priority, update_every, chart_type); - cd->update_every = update_every; - } - else debug(D_PLUGINSD, "PLUGINSD: Chart '%s' already exists. Not adding it again.", st->id); + debug(D_PLUGINSD, "PLUGINSD: Creating chart type='%s', id='%s', name='%s', family='%s', context='%s', chart='%s', priority=%d, update_every=%d" + , type, id + , name?name:"" + , family?family:"" + , context?context:"" + , rrdset_type_name(chart_type) + , priority + , update_every + ); + + st = rrdset_create( + host + , type + , id + , name + , family + , context + , title + , units + , (plugin && *plugin)?plugin:cd->filename + , module + , priority + , update_every + , chart_type + ); if(options && *options) { if(strstr(options, "obsolete")) @@ -308,6 +337,11 @@ inline size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int else rrdset_flag_clear(st, RRDSET_FLAG_STORE_FIRST); } + else { + rrdset_isnot_obsolete(st); + rrdset_flag_clear(st, RRDSET_FLAG_DETAIL); + rrdset_flag_clear(st, RRDSET_FLAG_STORE_FIRST); + } } else if(likely(hash == DIMENSION_HASH && !strcmp(s, PLUGINSD_KEYWORD_DIMENSION))) { char *id = words[1]; @@ -359,6 +393,64 @@ inline size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int if(strstr(options, "nooverflow") != NULL) rrddim_flag_set(rd, RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS); } } + else if(likely(hash == VARIABLE_HASH && !strcmp(s, PLUGINSD_KEYWORD_VARIABLE))) { + char *name = words[1]; + char *value = words[2]; + int global = (st)?0:1; + + if(name && *name) { + if((strcmp(name, "GLOBAL") == 0 || strcmp(name, "HOST") == 0)) { + global = 1; + name = words[2]; + value = words[3]; + } + else if((strcmp(name, "LOCAL") == 0 || strcmp(name, "CHART") == 0)) { + global = 0; + name = words[2]; + value = words[3]; + } + } + + if(unlikely(!name || !*name)) { + error("PLUGINSD: '%s' is requesting a VARIABLE on host '%s', without a variable name. Disabling it.", cd->fullfilename, host->hostname); + enabled = 0; + break; + } + + if(unlikely(!value || !*value)) + value = NULL; + + if(value) { + char *endptr = NULL; + calculated_number v = (calculated_number)str2ld(value, &endptr); + + if(unlikely(endptr && *endptr)) { + if(endptr == value) + error("PLUGINSD: '%s': the value '%s' of VARIABLE '%s' on host '%s' cannot be parsed as a number", cd->fullfilename, value, name, host->hostname); + else + error("PLUGINSD: '%s': the value '%s' of VARIABLE '%s' on host '%s' has leftovers: '%s'", cd->fullfilename, value, name, host->hostname, endptr); + } + + if(global) { + RRDVAR *rv = rrdvar_custom_host_variable_create(host, name); + if (rv) rrdvar_custom_host_variable_set(host, rv, v); + else error("PLUGINSD: '%s': cannot find/create HOST VARIABLE '%s' on host '%s'", cd->fullfilename, name, host->hostname); + } + else if(st) { + RRDSETVAR *rs = rrdsetvar_custom_chart_variable_create(st, name); + if (rs) rrdsetvar_custom_chart_variable_set(rs, v); + else error("PLUGINSD: '%s': cannot find/create CHART VARIABLE '%s' on host '%s', chart '%s'", cd->fullfilename, name, host->hostname, st->id); + } + else + error("PLUGINSD: '%s': cannot find/create CHART VARIABLE '%s' on host '%s' without a chart", cd->fullfilename, name, host->hostname); + } + else + error("PLUGINSD: '%s': cannot set %s VARIABLE '%s' on host '%s' to an empty value", cd->fullfilename, (global)?"HOST":"CHART", name, host->hostname); + } + else if(likely(hash == FLUSH_HASH && !strcmp(s, PLUGINSD_KEYWORD_FLUSH))) { + debug(D_PLUGINSD, "PLUGINSD: '%s' is requesting a FLUSH", cd->fullfilename); + st = NULL; + } else if(unlikely(hash == DISABLE_HASH && !strcmp(s, PLUGINSD_KEYWORD_DISABLE))) { info("PLUGINSD: '%s' called DISABLE. Disabling it.", cd->fullfilename); enabled = 0; @@ -476,99 +568,131 @@ void *pluginsd_main(void *ptr) { int automatic_run = config_get_boolean(CONFIG_SECTION_PLUGINS, "enable running new plugins", 1); int scan_frequency = (int) config_get_number(CONFIG_SECTION_PLUGINS, "check for new plugins every", 60); - DIR *dir = NULL; - struct dirent *file = NULL; - struct plugind *cd; - - // enable the apps plugin by default - // config_get_boolean(CONFIG_SECTION_PLUGINS, "apps", 1); - if(scan_frequency < 1) scan_frequency = 1; + // store the errno for each plugins directory + // so that we don't log broken directories on each loop + int directory_errors[PLUGINSD_MAX_DIRECTORIES] = { 0 }; + for(;;) { if(unlikely(netdata_exit)) break; - dir = opendir(netdata_configured_plugins_dir); - if(unlikely(!dir)) { - error("Cannot open directory '%s'.", netdata_configured_plugins_dir); - goto cleanup; - } + int idx; + const char *directory_name; - while(likely((file = readdir(dir)))) { + for( idx = 0; idx < PLUGINSD_MAX_DIRECTORIES && (directory_name = plugin_directories[idx]) ; idx++ ) { if(unlikely(netdata_exit)) break; - debug(D_PLUGINSD, "PLUGINSD: Examining file '%s'", file->d_name); - - if(unlikely(strcmp(file->d_name, ".") == 0 || strcmp(file->d_name, "..") == 0)) continue; - - int len = (int) strlen(file->d_name); - if(unlikely(len <= (int)PLUGINSD_FILE_SUFFIX_LEN)) continue; - if(unlikely(strcmp(PLUGINSD_FILE_SUFFIX, &file->d_name[len - (int)PLUGINSD_FILE_SUFFIX_LEN]) != 0)) { - debug(D_PLUGINSD, "PLUGINSD: File '%s' does not end in '%s'.", file->d_name, PLUGINSD_FILE_SUFFIX); + errno = 0; + DIR *dir = opendir(directory_name); + if(unlikely(!dir)) { + if(directory_errors[idx] != errno) { + directory_errors[idx] = errno; + error("PLUGINSD: Cannot open plugins directory '%s'.", directory_name); + } continue; } - char pluginname[CONFIG_MAX_NAME + 1]; - snprintfz(pluginname, CONFIG_MAX_NAME, "%.*s", (int)(len - PLUGINSD_FILE_SUFFIX_LEN), file->d_name); - int enabled = config_get_boolean(CONFIG_SECTION_PLUGINS, pluginname, automatic_run); + struct dirent *file = NULL; + while(likely((file = readdir(dir)))) { + if(unlikely(netdata_exit)) break; - if(unlikely(!enabled)) { - debug(D_PLUGINSD, "PLUGINSD: plugin '%s' is not enabled", file->d_name); - continue; - } + debug(D_PLUGINSD, "PLUGINSD: Examining file '%s'", file->d_name); - // check if it runs already - for(cd = pluginsd_root ; cd ; cd = cd->next) - if(unlikely(strcmp(cd->filename, file->d_name) == 0)) break; + if(unlikely(strcmp(file->d_name, ".") == 0 || strcmp(file->d_name, "..") == 0)) continue; - if(likely(cd && !cd->obsolete)) { - debug(D_PLUGINSD, "PLUGINSD: plugin '%s' is already running", cd->filename); - continue; - } + int len = (int) strlen(file->d_name); + if(unlikely(len <= (int)PLUGINSD_FILE_SUFFIX_LEN)) continue; + if(unlikely(strcmp(PLUGINSD_FILE_SUFFIX, &file->d_name[len - (int)PLUGINSD_FILE_SUFFIX_LEN]) != 0)) { + debug(D_PLUGINSD, "PLUGINSD: File '%s' does not end in '%s'.", file->d_name, PLUGINSD_FILE_SUFFIX); + continue; + } + + char pluginname[CONFIG_MAX_NAME + 1]; + snprintfz(pluginname, CONFIG_MAX_NAME, "%.*s", (int)(len - PLUGINSD_FILE_SUFFIX_LEN), file->d_name); + int enabled = config_get_boolean(CONFIG_SECTION_PLUGINS, pluginname, automatic_run); + + if(unlikely(!enabled)) { + debug(D_PLUGINSD, "PLUGINSD: plugin '%s' is not enabled", file->d_name); + continue; + } + + // check if it runs already + struct plugind *cd; + for(cd = pluginsd_root ; cd ; cd = cd->next) + if(unlikely(strcmp(cd->filename, file->d_name) == 0)) break; - // it is not running - // allocate a new one, or use the obsolete one - if(unlikely(!cd)) { - cd = callocz(sizeof(struct plugind), 1); + if(likely(cd && !cd->obsolete)) { + debug(D_PLUGINSD, "PLUGINSD: plugin '%s' is already running", cd->filename); + continue; + } + + // it is not running + // allocate a new one, or use the obsolete one + if(unlikely(!cd)) { + cd = callocz(sizeof(struct plugind), 1); - snprintfz(cd->id, CONFIG_MAX_NAME, "plugin:%s", pluginname); + snprintfz(cd->id, CONFIG_MAX_NAME, "plugin:%s", pluginname); - strncpyz(cd->filename, file->d_name, FILENAME_MAX); - snprintfz(cd->fullfilename, FILENAME_MAX, "%s/%s", netdata_configured_plugins_dir, cd->filename); + strncpyz(cd->filename, file->d_name, FILENAME_MAX); + snprintfz(cd->fullfilename, FILENAME_MAX, "%s/%s", directory_name, cd->filename); - cd->enabled = enabled; - cd->update_every = (int) config_get_number(cd->id, "update every", localhost->rrd_update_every); - cd->started_t = now_realtime_sec(); + cd->enabled = enabled; + cd->update_every = (int) config_get_number(cd->id, "update every", localhost->rrd_update_every); + cd->started_t = now_realtime_sec(); - char *def = ""; - snprintfz(cd->cmd, PLUGINSD_CMD_MAX, "exec %s %d %s", cd->fullfilename, cd->update_every, config_get(cd->id, "command options", def)); + char *def = ""; + snprintfz(cd->cmd, PLUGINSD_CMD_MAX, "exec %s %d %s", cd->fullfilename, cd->update_every, config_get(cd->id, "command options", def)); - // link it - if(likely(pluginsd_root)) cd->next = pluginsd_root; - pluginsd_root = cd; + // link it + if(likely(pluginsd_root)) cd->next = pluginsd_root; + pluginsd_root = cd; - // it is not currently running - cd->obsolete = 1; + // it is not currently running + cd->obsolete = 1; - if(cd->enabled) { - // spawn a new thread for it - if(unlikely(pthread_create(&cd->thread, NULL, pluginsd_worker_thread, cd) != 0)) - error("PLUGINSD: failed to create new thread for plugin '%s'.", cd->filename); + if(cd->enabled) { + // spawn a new thread for it + if(unlikely(pthread_create(&cd->thread, NULL, pluginsd_worker_thread, cd) != 0)) + error("PLUGINSD: failed to create new thread for plugin '%s'.", cd->filename); - else if(unlikely(pthread_detach(cd->thread) != 0)) - error("PLUGINSD: Cannot request detach of newly created thread for plugin '%s'.", cd->filename); + else if(unlikely(pthread_detach(cd->thread) != 0)) + error("PLUGINSD: Cannot request detach of newly created thread for plugin '%s'.", cd->filename); + } } } + + closedir(dir); } - closedir(dir); sleep((unsigned int) scan_frequency); } -cleanup: info("PLUGINS.D thread exiting"); static_thread->enabled = 0; pthread_exit(NULL); return NULL; } + + +void pluginsd_stop_all_external_plugins() { + siginfo_t info; + struct plugind *cd; + for(cd = pluginsd_root ; cd ; cd = cd->next) { + if(cd->enabled && !cd->obsolete) { + info("Stopping %s plugin thread", cd->id); + pthread_cancel(cd->thread); + + if(cd->pid) { + info("killing %s plugin child process pid %d", cd->id, cd->pid); + if(killpid(cd->pid, SIGTERM) != -1) + waitid(P_PID, (id_t) cd->pid, &info, WEXITED); + + cd->pid = 0; + } + + cd->obsolete = 1; + } + } +} diff --git a/src/plugins_d.h b/src/plugins_d.h index 595a515c..4d708386 100644 --- a/src/plugins_d.h +++ b/src/plugins_d.h @@ -11,10 +11,14 @@ #define PLUGINSD_KEYWORD_END "END" #define PLUGINSD_KEYWORD_FLUSH "FLUSH" #define PLUGINSD_KEYWORD_DISABLE "DISABLE" +#define PLUGINSD_KEYWORD_VARIABLE "VARIABLE" #define PLUGINSD_LINE_MAX 1024 #define PLUGINSD_MAX_WORDS 20 +#define PLUGINSD_MAX_DIRECTORIES 20 +extern char *plugin_directories[PLUGINSD_MAX_DIRECTORIES]; + struct plugind { char id[CONFIG_MAX_NAME+1]; // config node id @@ -43,7 +47,12 @@ struct plugind { extern struct plugind *pluginsd_root; extern void *pluginsd_main(void *ptr); +extern void pluginsd_stop_all_external_plugins(void); + extern size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int trust_durations); extern int pluginsd_split_words(char *str, char **words, int max_words); +extern int quoted_strings_splitter(char *str, char **words, int max_words, int (*custom_isspace)(char)); +extern int config_isspace(char c); + #endif /* NETDATA_PLUGINS_D_H */ diff --git a/src/proc_diskstats.c b/src/proc_diskstats.c index 4a32ec94..866e49c7 100644 --- a/src/proc_diskstats.c +++ b/src/proc_diskstats.c @@ -2,12 +2,13 @@ #define RRD_TYPE_DISK "disk" +#define DISK_TYPE_UNKNOWN 0 #define DISK_TYPE_PHYSICAL 1 #define DISK_TYPE_PARTITION 2 -#define DISK_TYPE_CONTAINER 3 +#define DISK_TYPE_VIRTUAL 3 #define CONFIG_SECTION_DISKSTATS "plugin:proc:/proc/diskstats" -#define DELAULT_EXLUDED_DISKS "loop* ram*" +#define DEFAULT_EXCLUDED_DISKS "loop* ram*" static struct disk { char *disk; // the name of the disk (sda, sdb, etc, after being looked up) @@ -31,16 +32,41 @@ static struct disk { int updated; - RRDSET *st_avgsz; - RRDSET *st_await; - RRDSET *st_backlog; RRDSET *st_io; - RRDSET *st_iotime; - RRDSET *st_mops; + RRDDIM *rd_io_reads; + RRDDIM *rd_io_writes; + RRDSET *st_ops; + RRDDIM *rd_ops_reads; + RRDDIM *rd_ops_writes; + RRDSET *st_qops; - RRDSET *st_svctm; + RRDDIM *rd_qops_operations; + + RRDSET *st_backlog; + RRDDIM *rd_backlog_backlog; + RRDSET *st_util; + RRDDIM *rd_util_utilization; + + RRDSET *st_mops; + RRDDIM *rd_mops_reads; + RRDDIM *rd_mops_writes; + + RRDSET *st_iotime; + RRDDIM *rd_iotime_reads; + RRDDIM *rd_iotime_writes; + + RRDSET *st_await; + RRDDIM *rd_await_reads; + RRDDIM *rd_await_writes; + + RRDSET *st_avgsz; + RRDDIM *rd_avgsz_reads; + RRDDIM *rd_avgsz_writes; + + RRDSET *st_svctm; + RRDDIM *rd_svctm_svctm; struct disk *next; } *disk_root = NULL; @@ -49,21 +75,23 @@ static struct disk { static char *path_to_get_hw_sector_size = NULL; static char *path_to_get_hw_sector_size_partitions = NULL; -static char *path_to_find_block_device = NULL; +static char *path_to_sys_dev_block_major_minor_string = NULL; +static char *path_to_sys_block_device = NULL; +static char *path_to_sys_devices_virtual_block_device = NULL; static char *path_to_device_mapper = NULL; +static char *path_to_device_label = NULL; +static char *path_to_device_id = NULL; +static int name_disks_by_id = CONFIG_BOOLEAN_NO; -static inline char *get_disk_name(unsigned long major, unsigned long minor, char *disk) { - static int enabled = 1; - - if(!enabled) goto cleanup; - +static inline int get_disk_name_from_path(const char *path, char *result, size_t result_size, unsigned long major, unsigned long minor, char *disk) { char filename[FILENAME_MAX + 1]; - char link[FILENAME_MAX + 1]; + int found = 0; - DIR *dir = opendir(path_to_device_mapper); + result_size--; + + DIR *dir = opendir(path); if (!dir) { - error("DEVICE-MAPPER ('%s', %lu:%lu): Cannot open directory '%s'. Disabling device-mapper support.", disk, major, minor, path_to_device_mapper); - enabled = 0; + error("DEVICE-MAPPER ('%s', %lu:%lu): Cannot open directory '%s'. Disabling device-mapper support.", disk, major, minor, path); goto cleanup; } @@ -71,18 +99,18 @@ static inline char *get_disk_name(unsigned long major, unsigned long minor, char while ((de = readdir(dir))) { if(de->d_type != DT_LNK) continue; - snprintfz(filename, FILENAME_MAX, "%s/%s", path_to_device_mapper, de->d_name); - ssize_t len = readlink(filename, link, FILENAME_MAX); + snprintfz(filename, FILENAME_MAX, "%s/%s", path, de->d_name); + ssize_t len = readlink(filename, result, result_size); if(len <= 0) { error("DEVICE-MAPPER ('%s', %lu:%lu): Cannot read link '%s'.", disk, major, minor, filename); continue; } - link[len] = '\0'; - if(link[0] != '/') - snprintfz(filename, FILENAME_MAX, "%s/%s", path_to_device_mapper, link); + result[len] = '\0'; + if(result[0] != '/') + snprintfz(filename, FILENAME_MAX, "%s/%s", path, result); else - strncpyz(filename, link, FILENAME_MAX); + strncpyz(filename, result, FILENAME_MAX); struct stat sb; if(stat(filename, &sb) == -1) { @@ -102,17 +130,37 @@ static inline char *get_disk_name(unsigned long major, unsigned long minor, char // info("DEVICE-MAPPER ('%s', %lu:%lu): filename '%s' matches.", disk, major, minor, filename); - strncpy(link, de->d_name, FILENAME_MAX); - netdata_fix_chart_name(link); - disk = link; + strncpy(result, de->d_name, result_size); + found = 1; break; } closedir(dir); + cleanup: - return strdupz(disk); + + if(!found) + result[0] = '\0'; + + return found; } +static inline char *get_disk_name(unsigned long major, unsigned long minor, char *disk) { + char result[FILENAME_MAX + 1] = ""; + + if(!path_to_device_mapper || !*path_to_device_mapper || !get_disk_name_from_path(path_to_device_mapper, result, FILENAME_MAX + 1, major, minor, disk)) + if(!path_to_device_label || !*path_to_device_label || !get_disk_name_from_path(path_to_device_label, result, FILENAME_MAX + 1, major, minor, disk)) + if(name_disks_by_id != CONFIG_BOOLEAN_YES || !path_to_device_id || !*path_to_device_id || !get_disk_name_from_path(path_to_device_id, result, FILENAME_MAX + 1, major, minor, disk)) + strncpy(result, disk, FILENAME_MAX); + + if(!result[0]) + strncpy(result, disk, FILENAME_MAX); + + netdata_fix_chart_name(result); + return strdup(result); +} + + static struct disk *get_disk(unsigned long major, unsigned long minor, char *disk) { static struct mountinfo *disk_mountinfo_root = NULL; @@ -134,7 +182,7 @@ static struct disk *get_disk(unsigned long major, unsigned long minor, char *dis d->device = strdupz(disk); d->major = major; d->minor = minor; - d->type = DISK_TYPE_PHYSICAL; // Default type. Changed later if not correct. + d->type = DISK_TYPE_UNKNOWN; // Default type. Changed later if not correct. d->configured = 0; d->sector_size = 512; // the default, will be changed below d->next = NULL; @@ -148,33 +196,50 @@ static struct disk *get_disk(unsigned long major, unsigned long minor, char *dis last->next = d; } + char buffer[FILENAME_MAX + 1]; + + // find if it is a physical disk + // by checking if /sys/block/DISK is readable. + snprintfz(buffer, FILENAME_MAX, path_to_sys_block_device, disk); + if(likely(access(buffer, R_OK) == 0)) { + // assign it here, but it will be overwritten if it is not a physical disk + d->type = DISK_TYPE_PHYSICAL; + } + // find if it is a partition // by checking if /sys/dev/block/MAJOR:MINOR/partition is readable. - char buffer[FILENAME_MAX + 1]; - snprintfz(buffer, FILENAME_MAX, path_to_find_block_device, major, minor, "partition"); + snprintfz(buffer, FILENAME_MAX, path_to_sys_dev_block_major_minor_string, major, minor, "partition"); if(likely(access(buffer, R_OK) == 0)) { d->type = DISK_TYPE_PARTITION; } else { - // find if it is a container - // by checking if /sys/dev/block/MAJOR:MINOR/slaves has entries - snprintfz(buffer, FILENAME_MAX, path_to_find_block_device, major, minor, "slaves/"); - DIR *dirp = opendir(buffer); - if(likely(dirp != NULL)) { - struct dirent *dp; - while( (dp = readdir(dirp)) ) { - // . and .. are also files in empty folders. - if(unlikely(strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)) { - continue; + // find if it is a virtual disk + // by checking if /sys/devices/virtual/block/DISK is readable. + snprintfz(buffer, FILENAME_MAX, path_to_sys_devices_virtual_block_device, disk); + if(likely(access(buffer, R_OK) == 0)) { + d->type = DISK_TYPE_VIRTUAL; + } + else { + // find if it is a virtual device + // by checking if /sys/dev/block/MAJOR:MINOR/slaves has entries + snprintfz(buffer, FILENAME_MAX, path_to_sys_dev_block_major_minor_string, major, minor, "slaves/"); + DIR *dirp = opendir(buffer); + if (likely(dirp != NULL)) { + struct dirent *dp; + while ((dp = readdir(dirp))) { + // . and .. are also files in empty folders. + if (unlikely(strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)) { + continue; + } + + d->type = DISK_TYPE_VIRTUAL; + + // Stop the loop after we found one file. + break; } - - d->type = DISK_TYPE_CONTAINER; - - // Stop the loop after we found one file. - break; + if (unlikely(closedir(dirp) == -1)) + error("Unable to close dir %s", buffer); } - if(unlikely(closedir(dirp) == -1)) - error("Unable to close dir %s", buffer); } } @@ -296,8 +361,14 @@ int do_proc_diskstats(int update_every, usec_t dt) { char buffer[FILENAME_MAX + 1]; + snprintfz(buffer, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/block/%s"); + path_to_sys_block_device = config_get(CONFIG_SECTION_DISKSTATS, "path to get block device", buffer); + + snprintfz(buffer, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/devices/virtual/block/%s"); + path_to_sys_devices_virtual_block_device = config_get(CONFIG_SECTION_DISKSTATS, "path to get virtual block device", buffer); + snprintfz(buffer, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/dev/block/%lu:%lu/%s"); - path_to_find_block_device = config_get(CONFIG_SECTION_DISKSTATS, "path to get block device infos", buffer); + path_to_sys_dev_block_major_minor_string = config_get(CONFIG_SECTION_DISKSTATS, "path to get block device infos", buffer); snprintfz(buffer, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/block/%s/queue/hw_sector_size"); path_to_get_hw_sector_size = config_get(CONFIG_SECTION_DISKSTATS, "path to get h/w sector size", buffer); @@ -307,6 +378,14 @@ int do_proc_diskstats(int update_every, usec_t dt) { snprintfz(buffer, FILENAME_MAX, "%s/dev/mapper", netdata_configured_host_prefix); path_to_device_mapper = config_get(CONFIG_SECTION_DISKSTATS, "path to device mapper", buffer); + + snprintfz(buffer, FILENAME_MAX, "%s/dev/disk/by-label", netdata_configured_host_prefix); + path_to_device_label = config_get(CONFIG_SECTION_DISKSTATS, "path to /dev/disk/by-label", buffer); + + snprintfz(buffer, FILENAME_MAX, "%s/dev/disk/by-id", netdata_configured_host_prefix); + path_to_device_id = config_get(CONFIG_SECTION_DISKSTATS, "path to /dev/disk/by-id", buffer); + + name_disks_by_id = config_get_boolean(CONFIG_SECTION_DISKSTATS, "name disks by id", name_disks_by_id); } // -------------------------------------------------------------------------- @@ -323,6 +402,8 @@ int do_proc_diskstats(int update_every, usec_t dt) { size_t lines = procfile_lines(ff), l; + collected_number system_read_kb = 0, system_write_kb = 0; + for(l = 0; l < lines ;l++) { // -------------------------------------------------------------------------- // Read parameters @@ -398,6 +479,11 @@ int do_proc_diskstats(int update_every, usec_t dt) { struct disk *d = get_disk(major, minor, disk); d->updated = 1; + if(unlikely(d->type == DISK_TYPE_PHYSICAL)) { + system_read_kb += readsectors * d->sector_size / 1024; + system_write_kb += writesectors * d->sector_size / 1024; + } + // -------------------------------------------------------------------------- // Set its family based on mount point @@ -415,7 +501,7 @@ int do_proc_diskstats(int update_every, usec_t dt) { if(unlikely(!excluded_disks)) { excluded_disks = simple_pattern_create( - config_get(CONFIG_SECTION_DISKSTATS, "exclude disks", DELAULT_EXLUDED_DISKS), + config_get(CONFIG_SECTION_DISKSTATS, "exclude disks", DEFAULT_EXCLUDED_DISKS), SIMPLE_PATTERN_EXACT ); } @@ -449,6 +535,10 @@ int do_proc_diskstats(int update_every, usec_t dt) { // based on the type of disk switch(d->type) { + default: + case DISK_TYPE_UNKNOWN: + break; + case DISK_TYPE_PHYSICAL: def_performance = global_enable_performance_for_physical_disks; break; @@ -457,7 +547,7 @@ int do_proc_diskstats(int update_every, usec_t dt) { def_performance = global_enable_performance_for_partitions; break; - case DISK_TYPE_CONTAINER: + case DISK_TYPE_VIRTUAL: def_performance = global_enable_performance_for_virtual_disks; break; } @@ -518,18 +608,20 @@ int do_proc_diskstats(int update_every, usec_t dt) { , "disk.io" , "Disk I/O Bandwidth" , "kilobytes/s" + , "proc" + , "diskstats" , 2000 , update_every , RRDSET_TYPE_AREA ); - rrddim_add(d->st_io, "reads", NULL, d->sector_size, 1024, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(d->st_io, "writes", NULL, d->sector_size * -1, 1024, RRD_ALGORITHM_INCREMENTAL); + d->rd_io_reads = rrddim_add(d->st_io, "reads", NULL, d->sector_size, 1024, RRD_ALGORITHM_INCREMENTAL); + d->rd_io_writes = rrddim_add(d->st_io, "writes", NULL, d->sector_size * -1, 1024, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(d->st_io); - last_readsectors = rrddim_set(d->st_io, "reads", readsectors); - last_writesectors = rrddim_set(d->st_io, "writes", writesectors); + last_readsectors = rrddim_set_by_pointer(d->st_io, d->rd_io_reads, readsectors); + last_writesectors = rrddim_set_by_pointer(d->st_io, d->rd_io_writes, writesectors); rrdset_done(d->st_io); } @@ -547,6 +639,8 @@ int do_proc_diskstats(int update_every, usec_t dt) { , "disk.ops" , "Disk Completed I/O Operations" , "operations/s" + , "proc" + , "diskstats" , 2001 , update_every , RRDSET_TYPE_LINE @@ -554,13 +648,13 @@ int do_proc_diskstats(int update_every, usec_t dt) { rrdset_flag_set(d->st_ops, RRDSET_FLAG_DETAIL); - rrddim_add(d->st_ops, "reads", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(d->st_ops, "writes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + d->rd_ops_reads = rrddim_add(d->st_ops, "reads", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + d->rd_ops_writes = rrddim_add(d->st_ops, "writes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(d->st_ops); - last_reads = rrddim_set(d->st_ops, "reads", reads); - last_writes = rrddim_set(d->st_ops, "writes", writes); + last_reads = rrddim_set_by_pointer(d->st_ops, d->rd_ops_reads, reads); + last_writes = rrddim_set_by_pointer(d->st_ops, d->rd_ops_writes, writes); rrdset_done(d->st_ops); } @@ -578,6 +672,8 @@ int do_proc_diskstats(int update_every, usec_t dt) { , "disk.qops" , "Disk Current I/O Operations" , "operations" + , "proc" + , "diskstats" , 2002 , update_every , RRDSET_TYPE_LINE @@ -585,11 +681,11 @@ int do_proc_diskstats(int update_every, usec_t dt) { rrdset_flag_set(d->st_qops, RRDSET_FLAG_DETAIL); - rrddim_add(d->st_qops, "operations", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); + d->rd_qops_operations = rrddim_add(d->st_qops, "operations", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); } else rrdset_next(d->st_qops); - rrddim_set(d->st_qops, "operations", queued_ios); + rrddim_set_by_pointer(d->st_qops, d->rd_qops_operations, queued_ios); rrdset_done(d->st_qops); } @@ -607,6 +703,8 @@ int do_proc_diskstats(int update_every, usec_t dt) { , "disk.backlog" , "Disk Backlog" , "backlog (ms)" + , "proc" + , "diskstats" , 2003 , update_every , RRDSET_TYPE_AREA @@ -614,11 +712,11 @@ int do_proc_diskstats(int update_every, usec_t dt) { rrdset_flag_set(d->st_backlog, RRDSET_FLAG_DETAIL); - rrddim_add(d->st_backlog, "backlog", NULL, 1, 10, RRD_ALGORITHM_INCREMENTAL); + d->rd_backlog_backlog = rrddim_add(d->st_backlog, "backlog", NULL, 1, 10, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(d->st_backlog); - rrddim_set(d->st_backlog, "backlog", backlog_ms); + rrddim_set_by_pointer(d->st_backlog, d->rd_backlog_backlog, backlog_ms); rrdset_done(d->st_backlog); } @@ -636,6 +734,8 @@ int do_proc_diskstats(int update_every, usec_t dt) { , "disk.util" , "Disk Utilization Time" , "% of time working" + , "proc" + , "diskstats" , 2004 , update_every , RRDSET_TYPE_AREA @@ -643,11 +743,11 @@ int do_proc_diskstats(int update_every, usec_t dt) { rrdset_flag_set(d->st_util, RRDSET_FLAG_DETAIL); - rrddim_add(d->st_util, "utilization", NULL, 1, 10, RRD_ALGORITHM_INCREMENTAL); + d->rd_util_utilization = rrddim_add(d->st_util, "utilization", NULL, 1, 10, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(d->st_util); - last_busy_ms = rrddim_set(d->st_util, "utilization", busy_ms); + last_busy_ms = rrddim_set_by_pointer(d->st_util, d->rd_util_utilization, busy_ms); rrdset_done(d->st_util); } @@ -665,6 +765,8 @@ int do_proc_diskstats(int update_every, usec_t dt) { , "disk.mops" , "Disk Merged Operations" , "merged operations/s" + , "proc" + , "diskstats" , 2021 , update_every , RRDSET_TYPE_LINE @@ -672,13 +774,13 @@ int do_proc_diskstats(int update_every, usec_t dt) { rrdset_flag_set(d->st_mops, RRDSET_FLAG_DETAIL); - rrddim_add(d->st_mops, "reads", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(d->st_mops, "writes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + d->rd_mops_reads = rrddim_add(d->st_mops, "reads", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + d->rd_mops_writes = rrddim_add(d->st_mops, "writes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(d->st_mops); - rrddim_set(d->st_mops, "reads", mreads); - rrddim_set(d->st_mops, "writes", mwrites); + rrddim_set_by_pointer(d->st_mops, d->rd_mops_reads, mreads); + rrddim_set_by_pointer(d->st_mops, d->rd_mops_writes, mwrites); rrdset_done(d->st_mops); } @@ -696,6 +798,8 @@ int do_proc_diskstats(int update_every, usec_t dt) { , "disk.iotime" , "Disk Total I/O Time" , "milliseconds/s" + , "proc" + , "diskstats" , 2022 , update_every , RRDSET_TYPE_LINE @@ -703,13 +807,13 @@ int do_proc_diskstats(int update_every, usec_t dt) { rrdset_flag_set(d->st_iotime, RRDSET_FLAG_DETAIL); - rrddim_add(d->st_iotime, "reads", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(d->st_iotime, "writes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + d->rd_iotime_reads = rrddim_add(d->st_iotime, "reads", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + d->rd_iotime_writes = rrddim_add(d->st_iotime, "writes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(d->st_iotime); - last_readms = rrddim_set(d->st_iotime, "reads", readms); - last_writems = rrddim_set(d->st_iotime, "writes", writems); + last_readms = rrddim_set_by_pointer(d->st_iotime, d->rd_iotime_reads, readms); + last_writems = rrddim_set_by_pointer(d->st_iotime, d->rd_iotime_writes, writems); rrdset_done(d->st_iotime); } @@ -730,6 +834,8 @@ int do_proc_diskstats(int update_every, usec_t dt) { , "disk.await" , "Average Completed I/O Operation Time" , "ms per operation" + , "proc" + , "diskstats" , 2005 , update_every , RRDSET_TYPE_LINE @@ -737,13 +843,13 @@ int do_proc_diskstats(int update_every, usec_t dt) { rrdset_flag_set(d->st_await, RRDSET_FLAG_DETAIL); - rrddim_add(d->st_await, "reads", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - rrddim_add(d->st_await, "writes", NULL, -1, 1, RRD_ALGORITHM_ABSOLUTE); + d->rd_await_reads = rrddim_add(d->st_await, "reads", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); + d->rd_await_writes = rrddim_add(d->st_await, "writes", NULL, -1, 1, RRD_ALGORITHM_ABSOLUTE); } else rrdset_next(d->st_await); - rrddim_set(d->st_await, "reads", (reads - last_reads) ? (readms - last_readms) / (reads - last_reads) : 0); - rrddim_set(d->st_await, "writes", (writes - last_writes) ? (writems - last_writems) / (writes - last_writes) : 0); + rrddim_set_by_pointer(d->st_await, d->rd_await_reads, (reads - last_reads) ? (readms - last_readms) / (reads - last_reads) : 0); + rrddim_set_by_pointer(d->st_await, d->rd_await_writes, (writes - last_writes) ? (writems - last_writems) / (writes - last_writes) : 0); rrdset_done(d->st_await); } @@ -759,6 +865,8 @@ int do_proc_diskstats(int update_every, usec_t dt) { , "disk.avgsz" , "Average Completed I/O Operation Bandwidth" , "kilobytes per operation" + , "proc" + , "diskstats" , 2006 , update_every , RRDSET_TYPE_AREA @@ -766,13 +874,13 @@ int do_proc_diskstats(int update_every, usec_t dt) { rrdset_flag_set(d->st_avgsz, RRDSET_FLAG_DETAIL); - rrddim_add(d->st_avgsz, "reads", NULL, d->sector_size, 1024, RRD_ALGORITHM_ABSOLUTE); - rrddim_add(d->st_avgsz, "writes", NULL, d->sector_size * -1, 1024, RRD_ALGORITHM_ABSOLUTE); + d->rd_avgsz_reads = rrddim_add(d->st_avgsz, "reads", NULL, d->sector_size, 1024, RRD_ALGORITHM_ABSOLUTE); + d->rd_avgsz_writes = rrddim_add(d->st_avgsz, "writes", NULL, d->sector_size * -1, 1024, RRD_ALGORITHM_ABSOLUTE); } else rrdset_next(d->st_avgsz); - rrddim_set(d->st_avgsz, "reads", (reads - last_reads) ? (readsectors - last_readsectors) / (reads - last_reads) : 0); - rrddim_set(d->st_avgsz, "writes", (writes - last_writes) ? (writesectors - last_writesectors) / (writes - last_writes) : 0); + rrddim_set_by_pointer(d->st_avgsz, d->rd_avgsz_reads, (reads - last_reads) ? (readsectors - last_readsectors) / (reads - last_reads) : 0); + rrddim_set_by_pointer(d->st_avgsz, d->rd_avgsz_writes, (writes - last_writes) ? (writesectors - last_writesectors) / (writes - last_writes) : 0); rrdset_done(d->st_avgsz); } @@ -788,6 +896,8 @@ int do_proc_diskstats(int update_every, usec_t dt) { , "disk.svctm" , "Average Service Time" , "ms per operation" + , "proc" + , "diskstats" , 2007 , update_every , RRDSET_TYPE_LINE @@ -795,16 +905,52 @@ int do_proc_diskstats(int update_every, usec_t dt) { rrdset_flag_set(d->st_svctm, RRDSET_FLAG_DETAIL); - rrddim_add(d->st_svctm, "svctm", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); + d->rd_svctm_svctm = rrddim_add(d->st_svctm, "svctm", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); } else rrdset_next(d->st_svctm); - rrddim_set(d->st_svctm, "svctm", ((reads - last_reads) + (writes - last_writes)) ? (busy_ms - last_busy_ms) / ((reads - last_reads) + (writes - last_writes)) : 0); + rrddim_set_by_pointer(d->st_svctm, d->rd_svctm_svctm, ((reads - last_reads) + (writes - last_writes)) ? (busy_ms - last_busy_ms) / ((reads - last_reads) + (writes - last_writes)) : 0); rrdset_done(d->st_svctm); } } } + + // ------------------------------------------------------------------------ + // update the system total I/O + + if(global_do_io == CONFIG_BOOLEAN_YES || (global_do_io == CONFIG_BOOLEAN_AUTO && (system_read_kb || system_write_kb))) { + static RRDSET *st_io = NULL; + static RRDDIM *rd_in = NULL, *rd_out = NULL; + + if(unlikely(!st_io)) { + st_io = rrdset_create_localhost( + "system" + , "io" + , NULL + , "disk" + , NULL + , "Disk I/O" + , "kilobytes/s" + , "proc" + , "diskstats" + , 150 + , update_every + , RRDSET_TYPE_AREA + ); + + rd_in = rrddim_add(st_io, "in", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_out = rrddim_add(st_io, "out", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + } + else rrdset_next(st_io); + + rrddim_set_by_pointer(st_io, rd_in, system_read_kb); + rrddim_set_by_pointer(st_io, rd_out, system_write_kb); + rrdset_done(st_io); + } + + + // ------------------------------------------------------------------------ // cleanup removed disks struct disk *d = disk_root, *last = NULL; diff --git a/src/proc_interrupts.c b/src/proc_interrupts.c index b9f3941d..867f39eb 100644 --- a/src/proc_interrupts.c +++ b/src/proc_interrupts.c @@ -154,6 +154,8 @@ int do_proc_interrupts(int update_every, usec_t dt) { , NULL , "System interrupts" , "interrupts/s" + , "proc" + , "interrupts" , 1000 , update_every , RRDSET_TYPE_STACKED @@ -217,6 +219,8 @@ int do_proc_interrupts(int update_every, usec_t dt) { , "cpu.interrupts" , title , "interrupts/s" + , "proc" + , "interrupts" , 1100 + c , update_every , RRDSET_TYPE_STACKED diff --git a/src/proc_loadavg.c b/src/proc_loadavg.c index 54fc545a..868f7d50 100644 --- a/src/proc_loadavg.c +++ b/src/proc_loadavg.c @@ -60,6 +60,8 @@ int do_proc_loadavg(int update_every, usec_t dt) { , NULL , "System Load Average" , "load" + , "proc" + , "loadavg" , 100 , (update_every < MIN_LOADAVG_UPDATE_EVERY) ? MIN_LOADAVG_UPDATE_EVERY : update_every , RRDSET_TYPE_LINE @@ -98,6 +100,8 @@ int do_proc_loadavg(int update_every, usec_t dt) { , NULL , "System Active Processes" , "processes" + , "proc" + , "loadavg" , 750 , update_every , RRDSET_TYPE_LINE diff --git a/src/proc_meminfo.c b/src/proc_meminfo.c index 152a6366..085850c2 100644 --- a/src/proc_meminfo.c +++ b/src/proc_meminfo.c @@ -150,6 +150,8 @@ int do_proc_meminfo(int update_every, usec_t dt) { , NULL , "System RAM" , "MB" + , "proc" + , "meminfo" , 200 , update_every , RRDSET_TYPE_STACKED @@ -189,6 +191,8 @@ int do_proc_meminfo(int update_every, usec_t dt) { , NULL , "System Swap" , "MB" + , "proc" + , "meminfo" , 201 , update_every , RRDSET_TYPE_STACKED @@ -224,6 +228,8 @@ int do_proc_meminfo(int update_every, usec_t dt) { , NULL , "Corrupted Memory, detected by ECC" , "MB" + , "proc" + , "meminfo" , 9000 , update_every , RRDSET_TYPE_LINE @@ -255,6 +261,8 @@ int do_proc_meminfo(int update_every, usec_t dt) { , NULL , "Committed (Allocated) Memory" , "MB" + , "proc" + , "meminfo" , 5000 , update_every , RRDSET_TYPE_AREA @@ -286,6 +294,8 @@ int do_proc_meminfo(int update_every, usec_t dt) { , NULL , "Writeback Memory" , "MB" + , "proc" + , "meminfo" , 4000 , update_every , RRDSET_TYPE_LINE @@ -324,6 +334,8 @@ int do_proc_meminfo(int update_every, usec_t dt) { , NULL , "Memory Used by Kernel" , "MB" + , "proc" + , "meminfo" , 6000 , update_every , RRDSET_TYPE_STACKED @@ -361,6 +373,8 @@ int do_proc_meminfo(int update_every, usec_t dt) { , NULL , "Reclaimable Kernel Memory" , "MB" + , "proc" + , "meminfo" , 6500 , update_every , RRDSET_TYPE_STACKED diff --git a/src/proc_net_dev.c b/src/proc_net_dev.c index 6e12fc5d..32bb5bab 100644 --- a/src/proc_net_dev.c +++ b/src/proc_net_dev.c @@ -9,6 +9,7 @@ static struct netdev { size_t len; // flags + int virtual; int configured; int enabled; int updated; @@ -428,8 +429,14 @@ int do_proc_net_dev(int update_every, usec_t dt) { static procfile *ff = NULL; static int enable_new_interfaces = -1; static int do_bandwidth = -1, do_packets = -1, do_errors = -1, do_drops = -1, do_fifo = -1, do_compressed = -1, do_events = -1; + static char *path_to_sys_devices_virtual_net = NULL; if(unlikely(enable_new_interfaces == -1)) { + char filename[FILENAME_MAX + 1]; + + snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/devices/virtual/net/%s"); + path_to_sys_devices_virtual_net = config_get("plugin:proc:/proc/net/dev", "path to get virtual interfaces", filename); + enable_new_interfaces = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "enable new interfaces detected at runtime", CONFIG_BOOLEAN_AUTO); do_bandwidth = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "bandwidth for all interfaces", CONFIG_BOOLEAN_AUTO); @@ -459,6 +466,9 @@ int do_proc_net_dev(int update_every, usec_t dt) { netdev_found = 0; + kernel_uint_t system_rbytes = 0; + kernel_uint_t system_tbytes = 0; + size_t lines = procfile_lines(ff), l; for(l = 2; l < lines ;l++) { // require 17 words on each line @@ -479,28 +489,42 @@ int do_proc_net_dev(int update_every, usec_t dt) { if(d->enabled) d->enabled = !simple_pattern_matches(disabled_list, d->name); - char var_name[512 + 1]; - snprintfz(var_name, 512, "plugin:proc:/proc/net/dev:%s", d->name); - d->enabled = config_get_boolean_ondemand(var_name, "enabled", d->enabled); + char buffer[FILENAME_MAX + 1]; + + snprintfz(buffer, FILENAME_MAX, path_to_sys_devices_virtual_net, d->name); + if(likely(access(buffer, R_OK) == 0)) { + d->virtual = 1; + } + else + d->virtual = 0; + + snprintfz(buffer, FILENAME_MAX, "plugin:proc:/proc/net/dev:%s", d->name); + d->enabled = config_get_boolean_ondemand(buffer, "enabled", d->enabled); + d->virtual = config_get_boolean(buffer, "virtual", d->virtual); if(d->enabled == CONFIG_BOOLEAN_NO) continue; - d->do_bandwidth = config_get_boolean_ondemand(var_name, "bandwidth", do_bandwidth); - d->do_packets = config_get_boolean_ondemand(var_name, "packets", do_packets); - d->do_errors = config_get_boolean_ondemand(var_name, "errors", do_errors); - d->do_drops = config_get_boolean_ondemand(var_name, "drops", do_drops); - d->do_fifo = config_get_boolean_ondemand(var_name, "fifo", do_fifo); - d->do_compressed = config_get_boolean_ondemand(var_name, "compressed", do_compressed); - d->do_events = config_get_boolean_ondemand(var_name, "events", do_events); + d->do_bandwidth = config_get_boolean_ondemand(buffer, "bandwidth", do_bandwidth); + d->do_packets = config_get_boolean_ondemand(buffer, "packets", do_packets); + d->do_errors = config_get_boolean_ondemand(buffer, "errors", do_errors); + d->do_drops = config_get_boolean_ondemand(buffer, "drops", do_drops); + d->do_fifo = config_get_boolean_ondemand(buffer, "fifo", do_fifo); + d->do_compressed = config_get_boolean_ondemand(buffer, "compressed", do_compressed); + d->do_events = config_get_boolean_ondemand(buffer, "events", do_events); } if(unlikely(!d->enabled)) continue; - if(likely(d->do_bandwidth != CONFIG_BOOLEAN_NO)) { + if(likely(d->do_bandwidth != CONFIG_BOOLEAN_NO || !d->virtual)) { d->rbytes = str2kernel_uint_t(procfile_lineword(ff, l, 1)); d->tbytes = str2kernel_uint_t(procfile_lineword(ff, l, 9)); + + if(likely(!d->virtual)) { + system_rbytes += d->rbytes; + system_tbytes += d->tbytes; + } } if(likely(d->do_packets != CONFIG_BOOLEAN_NO)) { @@ -551,6 +575,8 @@ int do_proc_net_dev(int update_every, usec_t dt) { , "net.net" , "Bandwidth" , "kilobits/s" + , "proc" + , "net/dev" , d->priority , update_every , RRDSET_TYPE_AREA @@ -590,6 +616,8 @@ int do_proc_net_dev(int update_every, usec_t dt) { , "net.packets" , "Packets" , "packets/s" + , "proc" + , "net/dev" , d->priority + 1 , update_every , RRDSET_TYPE_LINE @@ -633,6 +661,8 @@ int do_proc_net_dev(int update_every, usec_t dt) { , "net.errors" , "Interface Errors" , "errors/s" + , "proc" + , "net/dev" , d->priority + 2 , update_every , RRDSET_TYPE_LINE @@ -674,6 +704,8 @@ int do_proc_net_dev(int update_every, usec_t dt) { , "net.drops" , "Interface Drops" , "drops/s" + , "proc" + , "net/dev" , d->priority + 3 , update_every , RRDSET_TYPE_LINE @@ -715,6 +747,8 @@ int do_proc_net_dev(int update_every, usec_t dt) { , "net.fifo" , "Interface FIFO Buffer Errors" , "errors" + , "proc" + , "net/dev" , d->priority + 4 , update_every , RRDSET_TYPE_LINE @@ -756,6 +790,8 @@ int do_proc_net_dev(int update_every, usec_t dt) { , "net.compressed" , "Compressed Packets" , "packets/s" + , "proc" + , "net/dev" , d->priority + 5 , update_every , RRDSET_TYPE_LINE @@ -797,6 +833,8 @@ int do_proc_net_dev(int update_every, usec_t dt) { , "net.events" , "Network Interface Events" , "events/s" + , "proc" + , "net/dev" , d->priority + 6 , update_every , RRDSET_TYPE_LINE @@ -817,6 +855,39 @@ int do_proc_net_dev(int update_every, usec_t dt) { } } + if(do_bandwidth == CONFIG_BOOLEAN_YES || (do_bandwidth == CONFIG_BOOLEAN_AUTO && (system_rbytes || system_tbytes))) { + do_bandwidth = CONFIG_BOOLEAN_YES; + static RRDSET *st_system_net = NULL; + static RRDDIM *rd_in = NULL, *rd_out = NULL; + + if(unlikely(!st_system_net)) { + st_system_net = rrdset_create_localhost( + "system" + , "net" + , NULL + , "network" + , NULL + , "Physical Network Interfaces Aggregated Bandwidth" + , "kilobits/s" + , "proc" + , "net/dev" + , 500 + , update_every + , RRDSET_TYPE_AREA + ); + + rd_in = rrddim_add(st_system_net, "InOctets", "received", 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); + rd_out = rrddim_add(st_system_net, "OutOctets", "sent", -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); + } + else + rrdset_next(st_system_net); + + rrddim_set_by_pointer(st_system_net, rd_in, (collected_number)system_rbytes); + rrddim_set_by_pointer(st_system_net, rd_out, (collected_number)system_tbytes); + + rrdset_done(st_system_net); + } + netdev_cleanup(); return 0; diff --git a/src/proc_net_ip_vs_stats.c b/src/proc_net_ip_vs_stats.c index aa806b46..d76972f3 100644 --- a/src/proc_net_ip_vs_stats.c +++ b/src/proc_net_ip_vs_stats.c @@ -35,16 +35,27 @@ int do_proc_net_ip_vs_stats(int update_every, usec_t dt) { InBytes = strtoull(procfile_lineword(ff, 2, 3), NULL, 16); OutBytes = strtoull(procfile_lineword(ff, 2, 4), NULL, 16); - RRDSET *st; // -------------------------------------------------------------------- if(do_sockets) { - st = rrdset_find_localhost(RRD_TYPE_NET_IPVS ".sockets"); - if(!st) { - st = rrdset_create_localhost(RRD_TYPE_NET_IPVS, "sockets", NULL, RRD_TYPE_NET_IPVS, NULL - , "IPVS New Connections", "connections/s", 3101, update_every - , RRDSET_TYPE_LINE); + static RRDSET *st = NULL; + + if(unlikely(!st)) { + st = rrdset_create_localhost( + RRD_TYPE_NET_IPVS + , "sockets" + , NULL + , RRD_TYPE_NET_IPVS + , NULL + , "IPVS New Connections" + , "connections/s" + , "proc" + , "net/ip_vs_stats" + , 3101 + , update_every + , RRDSET_TYPE_LINE + ); rrddim_add(st, "connections", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); } @@ -57,10 +68,22 @@ int do_proc_net_ip_vs_stats(int update_every, usec_t dt) { // -------------------------------------------------------------------- if(do_packets) { - st = rrdset_find_localhost(RRD_TYPE_NET_IPVS ".packets"); - if(!st) { - st = rrdset_create_localhost(RRD_TYPE_NET_IPVS, "packets", NULL, RRD_TYPE_NET_IPVS, NULL, "IPVS Packets" - , "packets/s", 3102, update_every, RRDSET_TYPE_LINE); + static RRDSET *st = NULL; + if(unlikely(!st)) { + st = rrdset_create_localhost( + RRD_TYPE_NET_IPVS + , "packets" + , NULL + , RRD_TYPE_NET_IPVS + , NULL + , "IPVS Packets" + , "packets/s" + , "proc" + , "net/ip_vs_stats" + , 3102 + , update_every + , RRDSET_TYPE_LINE + ); rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -75,10 +98,22 @@ int do_proc_net_ip_vs_stats(int update_every, usec_t dt) { // -------------------------------------------------------------------- if(do_bandwidth) { - st = rrdset_find_localhost(RRD_TYPE_NET_IPVS ".net"); - if(!st) { - st = rrdset_create_localhost(RRD_TYPE_NET_IPVS, "net", NULL, RRD_TYPE_NET_IPVS, NULL, "IPVS Bandwidth" - , "kilobits/s", 3100, update_every, RRDSET_TYPE_AREA); + static RRDSET *st = NULL; + if(unlikely(!st)) { + st = rrdset_create_localhost( + RRD_TYPE_NET_IPVS + , "net" + , NULL + , RRD_TYPE_NET_IPVS + , NULL + , "IPVS Bandwidth" + , "kilobits/s" + , "proc" + , "net/ip_vs_stats" + , 3100 + , update_every + , RRDSET_TYPE_AREA + ); rrddim_add(st, "received", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); rrddim_add(st, "sent", NULL, -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); diff --git a/src/proc_net_netstat.c b/src/proc_net_netstat.c index e01b81d2..dd070e4c 100644 --- a/src/proc_net_netstat.c +++ b/src/proc_net_netstat.c @@ -22,7 +22,9 @@ int do_proc_net_netstat(int update_every, usec_t dt) { (void)dt; static int do_bandwidth = -1, do_inerrors = -1, do_mcast = -1, do_bcast = -1, do_mcast_p = -1, do_bcast_p = -1, do_ecn = -1, \ - do_tcpext_reorder = -1, do_tcpext_syscookies = -1, do_tcpext_ofo = -1, do_tcpext_connaborts = -1, do_tcpext_memory = -1; + do_tcpext_reorder = -1, do_tcpext_syscookies = -1, do_tcpext_ofo = -1, do_tcpext_connaborts = -1, do_tcpext_memory = -1, + do_tcpext_listen = -1; + static uint32_t hash_ipext = 0, hash_tcpext = 0; static procfile *ff = NULL; @@ -93,6 +95,10 @@ int do_proc_net_netstat(int update_every, usec_t dt) { static unsigned long long tcpext_TCPAbortOnLinger = 0; // connections aborted after user close in linger timeout static unsigned long long tcpext_TCPAbortFailed = 0; // times unable to send RST due to no memory + // https://perfchron.com/2015/12/26/investigating-linux-network-issues-with-netstat-and-nstat/ + static unsigned long long tcpext_ListenOverflows = 0; // times the listen queue of a socket overflowed + static unsigned long long tcpext_ListenDrops = 0; // SYNs to LISTEN sockets ignored + // IPv4 TCP memory pressures static unsigned long long tcpext_TCPMemoryPressures = 0; @@ -116,6 +122,7 @@ int do_proc_net_netstat(int update_every, usec_t dt) { do_tcpext_ofo = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "TCP out-of-order queue", CONFIG_BOOLEAN_AUTO); do_tcpext_connaborts = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "TCP connection aborts", CONFIG_BOOLEAN_AUTO); do_tcpext_memory = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "TCP memory pressures", CONFIG_BOOLEAN_AUTO); + do_tcpext_listen = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "TCP listen issues", CONFIG_BOOLEAN_AUTO); arl_ipext = arl_create("netstat/ipext", NULL, 60); arl_tcpext = arl_create("netstat/tcpext", NULL, 60); @@ -197,6 +204,11 @@ int do_proc_net_netstat(int update_every, usec_t dt) { arl_expect(arl_tcpext, "TCPMemoryPressures", &tcpext_TCPMemoryPressures); } + if(do_tcpext_listen != CONFIG_BOOLEAN_NO) { + arl_expect(arl_tcpext, "ListenOverflows", &tcpext_ListenOverflows); + arl_expect(arl_tcpext, "ListenDrops", &tcpext_ListenDrops); + } + // shared metrics arl_expect(arl_tcpext, "TCPSynRetrans", &tcpext_TCPSynRetrans); } @@ -248,7 +260,9 @@ int do_proc_net_netstat(int update_every, usec_t dt) { , NULL , "IPv4 Bandwidth" , "kilobits/s" - , 500 + , "proc" + , "net/netstat" + , 501 , update_every , RRDSET_TYPE_AREA ); @@ -281,6 +295,8 @@ int do_proc_net_netstat(int update_every, usec_t dt) { , NULL , "IPv4 Input Errors" , "packets/s" + , "proc" + , "net/netstat" , 4000 , update_every , RRDSET_TYPE_LINE @@ -318,6 +334,8 @@ int do_proc_net_netstat(int update_every, usec_t dt) { , NULL , "IPv4 Multicast Bandwidth" , "kilobits/s" + , "proc" + , "net/netstat" , 9000 , update_every , RRDSET_TYPE_AREA @@ -354,6 +372,8 @@ int do_proc_net_netstat(int update_every, usec_t dt) { , NULL , "IPv4 Broadcast Bandwidth" , "kilobits/s" + , "proc" + , "net/netstat" , 8000 , update_every , RRDSET_TYPE_AREA @@ -390,6 +410,8 @@ int do_proc_net_netstat(int update_every, usec_t dt) { , NULL , "IPv4 Multicast Packets" , "packets/s" + , "proc" + , "net/netstat" , 8600 , update_every , RRDSET_TYPE_LINE @@ -425,6 +447,8 @@ int do_proc_net_netstat(int update_every, usec_t dt) { , NULL , "IPv4 Broadcast Packets" , "packets/s" + , "proc" + , "net/netstat" , 8500 , update_every , RRDSET_TYPE_LINE @@ -461,6 +485,8 @@ int do_proc_net_netstat(int update_every, usec_t dt) { , NULL , "IPv4 ECN Statistics" , "packets/s" + , "proc" + , "net/netstat" , 8700 , update_every , RRDSET_TYPE_LINE @@ -511,6 +537,8 @@ int do_proc_net_netstat(int update_every, usec_t dt) { , NULL , "TCP Memory Pressures" , "events/s" + , "proc" + , "net/netstat" , 3000 , update_every , RRDSET_TYPE_LINE @@ -543,6 +571,8 @@ int do_proc_net_netstat(int update_every, usec_t dt) { , NULL , "TCP Connection Aborts" , "connections/s" + , "proc" + , "net/netstat" , 3010 , update_every , RRDSET_TYPE_LINE @@ -585,6 +615,8 @@ int do_proc_net_netstat(int update_every, usec_t dt) { , NULL , "TCP Reordered Packets by Detection Method" , "packets/s" + , "proc" + , "net/netstat" , 3020 , update_every , RRDSET_TYPE_LINE @@ -624,6 +656,8 @@ int do_proc_net_netstat(int update_every, usec_t dt) { , NULL , "TCP Out-Of-Order Queue" , "packets/s" + , "proc" + , "net/netstat" , 3050 , update_every , RRDSET_TYPE_LINE @@ -663,6 +697,8 @@ int do_proc_net_netstat(int update_every, usec_t dt) { , NULL , "TCP SYN Cookies" , "packets/s" + , "proc" + , "net/netstat" , 3100 , update_every , RRDSET_TYPE_LINE @@ -682,6 +718,42 @@ int do_proc_net_netstat(int update_every, usec_t dt) { rrdset_done(st_syncookies); } + // -------------------------------------------------------------------- + + if(do_tcpext_listen == CONFIG_BOOLEAN_YES || (do_tcpext_listen == CONFIG_BOOLEAN_AUTO && (tcpext_ListenOverflows || tcpext_ListenDrops))) { + do_tcpext_listen = CONFIG_BOOLEAN_YES; + + static RRDSET *st_listen = NULL; + static RRDDIM *rd_overflows = NULL, *rd_drops = NULL; + + if(unlikely(!st_listen)) { + + st_listen = rrdset_create_localhost( + "ipv4" + , "tcplistenissues" + , NULL + , "tcp" + , NULL + , "TCP Listen Socket Issues" + , "packets/s" + , "proc" + , "net/netstat" + , 3015 + , update_every + , RRDSET_TYPE_LINE + ); + + rd_overflows = rrddim_add(st_listen, "ListenOverflows", "overflows", 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_drops = rrddim_add(st_listen, "ListenDrops", "drops", 1, 1, RRD_ALGORITHM_INCREMENTAL); + } + else + rrdset_next(st_listen); + + rrddim_set_by_pointer(st_listen, rd_overflows, tcpext_ListenOverflows); + rrddim_set_by_pointer(st_listen, rd_drops, tcpext_ListenDrops); + + rrdset_done(st_listen); + } } } diff --git a/src/proc_net_rpc_nfs.c b/src/proc_net_rpc_nfs.c index 0df91963..126216e0 100644 --- a/src/proc_net_rpc_nfs.c +++ b/src/proc_net_rpc_nfs.c @@ -4,127 +4,133 @@ struct nfs_procs { char name[30]; unsigned long long value; int present; + RRDDIM *rd; }; struct nfs_procs nfs_proc2_values[] = { - { "null", 0ULL, 0 }, - { "getattr", 0ULL, 0 }, - { "setattr", 0ULL, 0 }, - { "root", 0ULL, 0 }, - { "lookup", 0ULL, 0 }, - { "readlink", 0ULL, 0 }, - { "read", 0ULL, 0 }, - { "wrcache", 0ULL, 0 }, - { "write", 0ULL, 0 }, - { "create", 0ULL, 0 }, - { "remove", 0ULL, 0 }, - { "rename", 0ULL, 0 }, - { "link", 0ULL, 0 }, - { "symlink", 0ULL, 0 }, - { "mkdir", 0ULL, 0 }, - { "rmdir", 0ULL, 0 }, - { "readdir", 0ULL, 0 }, - { "fsstat", 0ULL, 0 }, - - /* termination */ - { "", 0ULL, 0 } + { "null" , 0ULL, 0, NULL} + , {"getattr" , 0ULL, 0, NULL} + , {"setattr" , 0ULL, 0, NULL} + , {"root" , 0ULL, 0, NULL} + , {"lookup" , 0ULL, 0, NULL} + , {"readlink", 0ULL, 0, NULL} + , {"read" , 0ULL, 0, NULL} + , {"wrcache" , 0ULL, 0, NULL} + , {"write" , 0ULL, 0, NULL} + , {"create" , 0ULL, 0, NULL} + , {"remove" , 0ULL, 0, NULL} + , {"rename" , 0ULL, 0, NULL} + , {"link" , 0ULL, 0, NULL} + , {"symlink" , 0ULL, 0, NULL} + , {"mkdir" , 0ULL, 0, NULL} + , {"rmdir" , 0ULL, 0, NULL} + , {"readdir" , 0ULL, 0, NULL} + , {"fsstat" , 0ULL, 0, NULL} + , + + /* termination */ + { "" , 0ULL, 0, NULL} }; struct nfs_procs nfs_proc3_values[] = { - { "null", 0ULL, 0 }, - { "getattr", 0ULL, 0 }, - { "setattr", 0ULL, 0 }, - { "lookup", 0ULL, 0 }, - { "access", 0ULL, 0 }, - { "readlink", 0ULL, 0 }, - { "read", 0ULL, 0 }, - { "write", 0ULL, 0 }, - { "create", 0ULL, 0 }, - { "mkdir", 0ULL, 0 }, - { "symlink", 0ULL, 0 }, - { "mknod", 0ULL, 0 }, - { "remove", 0ULL, 0 }, - { "rmdir", 0ULL, 0 }, - { "rename", 0ULL, 0 }, - { "link", 0ULL, 0 }, - { "readdir", 0ULL, 0 }, - { "readdirplus", 0ULL, 0 }, - { "fsstat", 0ULL, 0 }, - { "fsinfo", 0ULL, 0 }, - { "pathconf", 0ULL, 0 }, - { "commit", 0ULL, 0 }, - - /* termination */ - { "", 0ULL, 0 } + { "null" , 0ULL, 0, NULL} + , {"getattr" , 0ULL, 0, NULL} + , {"setattr" , 0ULL, 0, NULL} + , {"lookup" , 0ULL, 0, NULL} + , {"access" , 0ULL, 0, NULL} + , {"readlink" , 0ULL, 0, NULL} + , {"read" , 0ULL, 0, NULL} + , {"write" , 0ULL, 0, NULL} + , {"create" , 0ULL, 0, NULL} + , {"mkdir" , 0ULL, 0, NULL} + , {"symlink" , 0ULL, 0, NULL} + , {"mknod" , 0ULL, 0, NULL} + , {"remove" , 0ULL, 0, NULL} + , {"rmdir" , 0ULL, 0, NULL} + , {"rename" , 0ULL, 0, NULL} + , {"link" , 0ULL, 0, NULL} + , {"readdir" , 0ULL, 0, NULL} + , {"readdirplus", 0ULL, 0, NULL} + , {"fsstat" , 0ULL, 0, NULL} + , {"fsinfo" , 0ULL, 0, NULL} + , {"pathconf" , 0ULL, 0, NULL} + , {"commit" , 0ULL, 0, NULL} + , + + /* termination */ + { "" , 0ULL, 0, NULL} }; struct nfs_procs nfs_proc4_values[] = { - { "null", 0ULL, 0 }, - { "read", 0ULL, 0 }, - { "write", 0ULL, 0 }, - { "commit", 0ULL, 0 }, - { "open", 0ULL, 0 }, - { "open_conf", 0ULL, 0 }, - { "open_noat", 0ULL, 0 }, - { "open_dgrd", 0ULL, 0 }, - { "close", 0ULL, 0 }, - { "setattr", 0ULL, 0 }, - { "fsinfo", 0ULL, 0 }, - { "renew", 0ULL, 0 }, - { "setclntid", 0ULL, 0 }, - { "confirm", 0ULL, 0 }, - { "lock", 0ULL, 0 }, - { "lockt", 0ULL, 0 }, - { "locku", 0ULL, 0 }, - { "access", 0ULL, 0 }, - { "getattr", 0ULL, 0 }, - { "lookup", 0ULL, 0 }, - { "lookup_root", 0ULL, 0 }, - { "remove", 0ULL, 0 }, - { "rename", 0ULL, 0 }, - { "link", 0ULL, 0 }, - { "symlink", 0ULL, 0 }, - { "create", 0ULL, 0 }, - { "pathconf", 0ULL, 0 }, - { "statfs", 0ULL, 0 }, - { "readlink", 0ULL, 0 }, - { "readdir", 0ULL, 0 }, - { "server_caps", 0ULL, 0 }, - { "delegreturn", 0ULL, 0 }, - { "getacl", 0ULL, 0 }, - { "setacl", 0ULL, 0 }, - { "fs_locations", 0ULL, 0 }, - { "rel_lkowner", 0ULL, 0 }, - { "secinfo", 0ULL, 0 }, - { "fsid_present", 0ULL, 0 }, - - /* nfsv4.1 client ops */ - { "exchange_id", 0ULL, 0 }, - { "create_session", 0ULL, 0 }, - { "destroy_session", 0ULL, 0 }, - { "sequence", 0ULL, 0 }, - { "get_lease_time", 0ULL, 0 }, - { "reclaim_comp", 0ULL, 0 }, - { "layoutget", 0ULL, 0 }, - { "getdevinfo", 0ULL, 0 }, - { "layoutcommit", 0ULL, 0 }, - { "layoutreturn", 0ULL, 0 }, - { "secinfo_no", 0ULL, 0 }, - { "test_stateid", 0ULL, 0 }, - { "free_stateid", 0ULL, 0 }, - { "getdevicelist", 0ULL, 0 }, - { "bind_conn_to_ses", 0ULL, 0 }, - { "destroy_clientid", 0ULL, 0 }, - - /* nfsv4.2 client ops */ - { "seek", 0ULL, 0 }, - { "allocate", 0ULL, 0 }, - { "deallocate", 0ULL, 0 }, - { "layoutstats", 0ULL, 0 }, - { "clone", 0ULL, 0 }, - - /* termination */ - { "", 0ULL, 0 } + { "null" , 0ULL, 0, NULL} + , {"read" , 0ULL, 0, NULL} + , {"write" , 0ULL, 0, NULL} + , {"commit" , 0ULL, 0, NULL} + , {"open" , 0ULL, 0, NULL} + , {"open_conf" , 0ULL, 0, NULL} + , {"open_noat" , 0ULL, 0, NULL} + , {"open_dgrd" , 0ULL, 0, NULL} + , {"close" , 0ULL, 0, NULL} + , {"setattr" , 0ULL, 0, NULL} + , {"fsinfo" , 0ULL, 0, NULL} + , {"renew" , 0ULL, 0, NULL} + , {"setclntid" , 0ULL, 0, NULL} + , {"confirm" , 0ULL, 0, NULL} + , {"lock" , 0ULL, 0, NULL} + , {"lockt" , 0ULL, 0, NULL} + , {"locku" , 0ULL, 0, NULL} + , {"access" , 0ULL, 0, NULL} + , {"getattr" , 0ULL, 0, NULL} + , {"lookup" , 0ULL, 0, NULL} + , {"lookup_root" , 0ULL, 0, NULL} + , {"remove" , 0ULL, 0, NULL} + , {"rename" , 0ULL, 0, NULL} + , {"link" , 0ULL, 0, NULL} + , {"symlink" , 0ULL, 0, NULL} + , {"create" , 0ULL, 0, NULL} + , {"pathconf" , 0ULL, 0, NULL} + , {"statfs" , 0ULL, 0, NULL} + , {"readlink" , 0ULL, 0, NULL} + , {"readdir" , 0ULL, 0, NULL} + , {"server_caps" , 0ULL, 0, NULL} + , {"delegreturn" , 0ULL, 0, NULL} + , {"getacl" , 0ULL, 0, NULL} + , {"setacl" , 0ULL, 0, NULL} + , {"fs_locations" , 0ULL, 0, NULL} + , {"rel_lkowner" , 0ULL, 0, NULL} + , {"secinfo" , 0ULL, 0, NULL} + , {"fsid_present" , 0ULL, 0, NULL} + , + + /* nfsv4.1 client ops */ + { "exchange_id" , 0ULL, 0, NULL} + , {"create_session" , 0ULL, 0, NULL} + , {"destroy_session" , 0ULL, 0, NULL} + , {"sequence" , 0ULL, 0, NULL} + , {"get_lease_time" , 0ULL, 0, NULL} + , {"reclaim_comp" , 0ULL, 0, NULL} + , {"layoutget" , 0ULL, 0, NULL} + , {"getdevinfo" , 0ULL, 0, NULL} + , {"layoutcommit" , 0ULL, 0, NULL} + , {"layoutreturn" , 0ULL, 0, NULL} + , {"secinfo_no" , 0ULL, 0, NULL} + , {"test_stateid" , 0ULL, 0, NULL} + , {"free_stateid" , 0ULL, 0, NULL} + , {"getdevicelist" , 0ULL, 0, NULL} + , {"bind_conn_to_ses", 0ULL, 0, NULL} + , {"destroy_clientid", 0ULL, 0, NULL} + , + + /* nfsv4.2 client ops */ + { "seek" , 0ULL, 0, NULL} + , {"allocate" , 0ULL, 0, NULL} + , {"deallocate" , 0ULL, 0, NULL} + , {"layoutstats" , 0ULL, 0, NULL} + , {"clone" , 0ULL, 0, NULL} + , + + /* termination */ + { "" , 0ULL, 0, NULL} }; int do_proc_net_rpc_nfs(int update_every, usec_t dt) { @@ -264,68 +270,111 @@ int do_proc_net_rpc_nfs(int update_every, usec_t dt) { } } - RRDSET *st; - // -------------------------------------------------------------------- if(do_net == 2) { - st = rrdset_find_bytype_localhost("nfs", "net"); - if(!st) { - st = rrdset_create_localhost("nfs", "net", NULL, "network", NULL, "NFS Client Network", "operations/s", 5007 - , update_every, RRDSET_TYPE_STACKED); + static RRDSET *st = NULL; + static RRDDIM *rd_udp = NULL, + *rd_tcp = NULL; + + if(unlikely(!st)) { + st = rrdset_create_localhost( + "nfs" + , "net" + , NULL + , "network" + , NULL + , "NFS Client Network" + , "operations/s" + , "proc" + , "net/rpc/nfs" + , 5007 + , update_every + , RRDSET_TYPE_STACKED + ); + rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - rrddim_add(st, "udp", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "tcp", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_udp = rrddim_add(st, "udp", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_tcp = rrddim_add(st, "tcp", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(st); // ignore net_count, net_tcp_connections - if(net_count) {}; - if(net_tcp_connections) {}; + (void)net_count; + (void)net_tcp_connections; - rrddim_set(st, "udp", net_udp_count); - rrddim_set(st, "tcp", net_tcp_count); + rrddim_set_by_pointer(st, rd_udp, net_udp_count); + rrddim_set_by_pointer(st, rd_tcp, net_tcp_count); rrdset_done(st); } // -------------------------------------------------------------------- if(do_rpc == 2) { - st = rrdset_find_bytype_localhost("nfs", "rpc"); - if(!st) { - st = rrdset_create_localhost("nfs", "rpc", NULL, "rpc", NULL, "NFS Client Remote Procedure Calls Statistics" - , "calls/s", 5008, update_every, RRDSET_TYPE_LINE); + static RRDSET *st = NULL; + static RRDDIM *rd_calls = NULL, + *rd_retransmits = NULL, + *rd_auth_refresh = NULL; + + if(unlikely(!st)) { + st = rrdset_create_localhost( + "nfs" + , "rpc" + , NULL + , "rpc" + , NULL + , "NFS Client Remote Procedure Calls Statistics" + , "calls/s" + , "proc" + , "net/rpc/nfs" + , 5008 + , update_every + , RRDSET_TYPE_LINE + ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - rrddim_add(st, "calls", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "retransmits", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "auth_refresh", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_calls = rrddim_add(st, "calls", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_retransmits = rrddim_add(st, "retransmits", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_auth_refresh = rrddim_add(st, "auth_refresh", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(st); - rrddim_set(st, "calls", rpc_calls); - rrddim_set(st, "retransmits", rpc_retransmits); - rrddim_set(st, "auth_refresh", rpc_auth_refresh); + rrddim_set_by_pointer(st, rd_calls, rpc_calls); + rrddim_set_by_pointer(st, rd_retransmits, rpc_retransmits); + rrddim_set_by_pointer(st, rd_auth_refresh, rpc_auth_refresh); rrdset_done(st); } // -------------------------------------------------------------------- if(do_proc2 == 2) { - unsigned int i; - st = rrdset_find_bytype_localhost("nfs", "proc2"); - if(!st) { - st = rrdset_create_localhost("nfs", "proc2", NULL, "nfsv2rpc", NULL, "NFS v2 Client Remote Procedure Calls" - , "calls/s", 5009, update_every, RRDSET_TYPE_STACKED); - - for(i = 0; nfs_proc2_values[i].present ; i++) - rrddim_add(st, nfs_proc2_values[i].name, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + static RRDSET *st = NULL; + if(unlikely(!st)) { + st = rrdset_create_localhost( + "nfs" + , "proc2" + , NULL + , "nfsv2rpc" + , NULL + , "NFS v2 Client Remote Procedure Calls" + , "calls/s" + , "proc" + , "net/rpc/nfs" + , 5009 + , update_every + , RRDSET_TYPE_STACKED + ); } else rrdset_next(st); - for(i = 0; nfs_proc2_values[i].present ; i++) - rrddim_set(st, nfs_proc2_values[i].name, nfs_proc2_values[i].value); + size_t i; + for(i = 0; nfs_proc2_values[i].present ; i++) { + if(unlikely(!nfs_proc2_values[i].rd)) + nfs_proc2_values[i].rd = rrddim_add(st, nfs_proc2_values[i].name, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + + rrddim_set_by_pointer(st, nfs_proc2_values[i].rd, nfs_proc2_values[i].value); + } rrdset_done(st); } @@ -333,19 +382,32 @@ int do_proc_net_rpc_nfs(int update_every, usec_t dt) { // -------------------------------------------------------------------- if(do_proc3 == 2) { - unsigned int i; - st = rrdset_find_bytype_localhost("nfs", "proc3"); - if(!st) { - st = rrdset_create_localhost("nfs", "proc3", NULL, "nfsv3rpc", NULL, "NFS v3 Client Remote Procedure Calls" - , "calls/s", 5010, update_every, RRDSET_TYPE_STACKED); - - for(i = 0; nfs_proc3_values[i].present ; i++) - rrddim_add(st, nfs_proc3_values[i].name, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + static RRDSET *st = NULL; + if(unlikely(!st)) { + st = rrdset_create_localhost( + "nfs" + , "proc3" + , NULL + , "nfsv3rpc" + , NULL + , "NFS v3 Client Remote Procedure Calls" + , "calls/s" + , "proc" + , "net/rpc/nfs" + , 5010 + , update_every + , RRDSET_TYPE_STACKED + ); } else rrdset_next(st); - for(i = 0; nfs_proc3_values[i].present ; i++) - rrddim_set(st, nfs_proc3_values[i].name, nfs_proc3_values[i].value); + size_t i; + for(i = 0; nfs_proc3_values[i].present ; i++) { + if(unlikely(!nfs_proc3_values[i].rd)) + nfs_proc3_values[i].rd = rrddim_add(st, nfs_proc3_values[i].name, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + + rrddim_set_by_pointer(st, nfs_proc3_values[i].rd, nfs_proc3_values[i].value); + } rrdset_done(st); } @@ -353,19 +415,32 @@ int do_proc_net_rpc_nfs(int update_every, usec_t dt) { // -------------------------------------------------------------------- if(do_proc4 == 2) { - unsigned int i; - st = rrdset_find_bytype_localhost("nfs", "proc4"); - if(!st) { - st = rrdset_create_localhost("nfs", "proc4", NULL, "nfsv4rpc", NULL, "NFS v4 Client Remote Procedure Calls" - , "calls/s", 5011, update_every, RRDSET_TYPE_STACKED); - - for(i = 0; nfs_proc4_values[i].present ; i++) - rrddim_add(st, nfs_proc4_values[i].name, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + static RRDSET *st = NULL; + if(unlikely(!st)) { + st = rrdset_create_localhost( + "nfs" + , "proc4" + , NULL + , "nfsv4rpc" + , NULL + , "NFS v4 Client Remote Procedure Calls" + , "calls/s" + , "proc" + , "net/rpc/nfs" + , 5011 + , update_every + , RRDSET_TYPE_STACKED + ); } else rrdset_next(st); - for(i = 0; nfs_proc4_values[i].present ; i++) - rrddim_set(st, nfs_proc4_values[i].name, nfs_proc4_values[i].value); + size_t i; + for(i = 0; nfs_proc4_values[i].present ; i++) { + if(unlikely(!nfs_proc4_values[i].rd)) + nfs_proc4_values[i].rd = rrddim_add(st, nfs_proc4_values[i].name, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + + rrddim_set_by_pointer(st, nfs_proc4_values[i].rd, nfs_proc4_values[i].value); + } rrdset_done(st); } diff --git a/src/proc_net_rpc_nfsd.c b/src/proc_net_rpc_nfsd.c index b0ed58d1..f0c9a20c 100644 --- a/src/proc_net_rpc_nfsd.c +++ b/src/proc_net_rpc_nfsd.c @@ -4,208 +4,217 @@ struct nfsd_procs { char name[30]; unsigned long long value; int present; + RRDDIM *rd; }; struct nfsd_procs nfsd_proc2_values[] = { - { "null", 0ULL, 0 }, - { "getattr", 0ULL, 0 }, - { "setattr", 0ULL, 0 }, - { "root", 0ULL, 0 }, - { "lookup", 0ULL, 0 }, - { "readlink", 0ULL, 0 }, - { "read", 0ULL, 0 }, - { "wrcache", 0ULL, 0 }, - { "write", 0ULL, 0 }, - { "create", 0ULL, 0 }, - { "remove", 0ULL, 0 }, - { "rename", 0ULL, 0 }, - { "link", 0ULL, 0 }, - { "symlink", 0ULL, 0 }, - { "mkdir", 0ULL, 0 }, - { "rmdir", 0ULL, 0 }, - { "readdir", 0ULL, 0 }, - { "fsstat", 0ULL, 0 }, - - /* termination */ - { "", 0ULL, 0 } + { "null" , 0ULL, 0, NULL} + , {"getattr" , 0ULL, 0, NULL} + , {"setattr" , 0ULL, 0, NULL} + , {"root" , 0ULL, 0, NULL} + , {"lookup" , 0ULL, 0, NULL} + , {"readlink", 0ULL, 0, NULL} + , {"read" , 0ULL, 0, NULL} + , {"wrcache" , 0ULL, 0, NULL} + , {"write" , 0ULL, 0, NULL} + , {"create" , 0ULL, 0, NULL} + , {"remove" , 0ULL, 0, NULL} + , {"rename" , 0ULL, 0, NULL} + , {"link" , 0ULL, 0, NULL} + , {"symlink" , 0ULL, 0, NULL} + , {"mkdir" , 0ULL, 0, NULL} + , {"rmdir" , 0ULL, 0, NULL} + , {"readdir" , 0ULL, 0, NULL} + , {"fsstat" , 0ULL, 0, NULL} + , + + /* termination */ + { "" , 0ULL, 0, NULL} }; struct nfsd_procs nfsd_proc3_values[] = { - { "null", 0ULL, 0 }, - { "getattr", 0ULL, 0 }, - { "setattr", 0ULL, 0 }, - { "lookup", 0ULL, 0 }, - { "access", 0ULL, 0 }, - { "readlink", 0ULL, 0 }, - { "read", 0ULL, 0 }, - { "write", 0ULL, 0 }, - { "create", 0ULL, 0 }, - { "mkdir", 0ULL, 0 }, - { "symlink", 0ULL, 0 }, - { "mknod", 0ULL, 0 }, - { "remove", 0ULL, 0 }, - { "rmdir", 0ULL, 0 }, - { "rename", 0ULL, 0 }, - { "link", 0ULL, 0 }, - { "readdir", 0ULL, 0 }, - { "readdirplus", 0ULL, 0 }, - { "fsstat", 0ULL, 0 }, - { "fsinfo", 0ULL, 0 }, - { "pathconf", 0ULL, 0 }, - { "commit", 0ULL, 0 }, - - /* termination */ - { "", 0ULL, 0 } + { "null" , 0ULL, 0, NULL} + , {"getattr" , 0ULL, 0, NULL} + , {"setattr" , 0ULL, 0, NULL} + , {"lookup" , 0ULL, 0, NULL} + , {"access" , 0ULL, 0, NULL} + , {"readlink" , 0ULL, 0, NULL} + , {"read" , 0ULL, 0, NULL} + , {"write" , 0ULL, 0, NULL} + , {"create" , 0ULL, 0, NULL} + , {"mkdir" , 0ULL, 0, NULL} + , {"symlink" , 0ULL, 0, NULL} + , {"mknod" , 0ULL, 0, NULL} + , {"remove" , 0ULL, 0, NULL} + , {"rmdir" , 0ULL, 0, NULL} + , {"rename" , 0ULL, 0, NULL} + , {"link" , 0ULL, 0, NULL} + , {"readdir" , 0ULL, 0, NULL} + , {"readdirplus", 0ULL, 0, NULL} + , {"fsstat" , 0ULL, 0, NULL} + , {"fsinfo" , 0ULL, 0, NULL} + , {"pathconf" , 0ULL, 0, NULL} + , {"commit" , 0ULL, 0, NULL} + , + + /* termination */ + { "" , 0ULL, 0, NULL} }; struct nfsd_procs nfsd_proc4_values[] = { - { "null", 0ULL, 0 }, - { "read", 0ULL, 0 }, - { "write", 0ULL, 0 }, - { "commit", 0ULL, 0 }, - { "open", 0ULL, 0 }, - { "open_conf", 0ULL, 0 }, - { "open_noat", 0ULL, 0 }, - { "open_dgrd", 0ULL, 0 }, - { "close", 0ULL, 0 }, - { "setattr", 0ULL, 0 }, - { "fsinfo", 0ULL, 0 }, - { "renew", 0ULL, 0 }, - { "setclntid", 0ULL, 0 }, - { "confirm", 0ULL, 0 }, - { "lock", 0ULL, 0 }, - { "lockt", 0ULL, 0 }, - { "locku", 0ULL, 0 }, - { "access", 0ULL, 0 }, - { "getattr", 0ULL, 0 }, - { "lookup", 0ULL, 0 }, - { "lookup_root", 0ULL, 0 }, - { "remove", 0ULL, 0 }, - { "rename", 0ULL, 0 }, - { "link", 0ULL, 0 }, - { "symlink", 0ULL, 0 }, - { "create", 0ULL, 0 }, - { "pathconf", 0ULL, 0 }, - { "statfs", 0ULL, 0 }, - { "readlink", 0ULL, 0 }, - { "readdir", 0ULL, 0 }, - { "server_caps", 0ULL, 0 }, - { "delegreturn", 0ULL, 0 }, - { "getacl", 0ULL, 0 }, - { "setacl", 0ULL, 0 }, - { "fs_locations", 0ULL, 0 }, - { "rel_lkowner", 0ULL, 0 }, - { "secinfo", 0ULL, 0 }, - { "fsid_present", 0ULL, 0 }, - - /* nfsv4.1 client ops */ - { "exchange_id", 0ULL, 0 }, - { "create_session", 0ULL, 0 }, - { "destroy_session", 0ULL, 0 }, - { "sequence", 0ULL, 0 }, - { "get_lease_time", 0ULL, 0 }, - { "reclaim_comp", 0ULL, 0 }, - { "layoutget", 0ULL, 0 }, - { "getdevinfo", 0ULL, 0 }, - { "layoutcommit", 0ULL, 0 }, - { "layoutreturn", 0ULL, 0 }, - { "secinfo_no", 0ULL, 0 }, - { "test_stateid", 0ULL, 0 }, - { "free_stateid", 0ULL, 0 }, - { "getdevicelist", 0ULL, 0 }, - { "bind_conn_to_ses", 0ULL, 0 }, - { "destroy_clientid", 0ULL, 0 }, - - /* nfsv4.2 client ops */ - { "seek", 0ULL, 0 }, - { "allocate", 0ULL, 0 }, - { "deallocate", 0ULL, 0 }, - { "layoutstats", 0ULL, 0 }, - { "clone", 0ULL, 0 }, - - /* termination */ - { "", 0ULL, 0 } + { "null" , 0ULL, 0, NULL} + , {"read" , 0ULL, 0, NULL} + , {"write" , 0ULL, 0, NULL} + , {"commit" , 0ULL, 0, NULL} + , {"open" , 0ULL, 0, NULL} + , {"open_conf" , 0ULL, 0, NULL} + , {"open_noat" , 0ULL, 0, NULL} + , {"open_dgrd" , 0ULL, 0, NULL} + , {"close" , 0ULL, 0, NULL} + , {"setattr" , 0ULL, 0, NULL} + , {"fsinfo" , 0ULL, 0, NULL} + , {"renew" , 0ULL, 0, NULL} + , {"setclntid" , 0ULL, 0, NULL} + , {"confirm" , 0ULL, 0, NULL} + , {"lock" , 0ULL, 0, NULL} + , {"lockt" , 0ULL, 0, NULL} + , {"locku" , 0ULL, 0, NULL} + , {"access" , 0ULL, 0, NULL} + , {"getattr" , 0ULL, 0, NULL} + , {"lookup" , 0ULL, 0, NULL} + , {"lookup_root" , 0ULL, 0, NULL} + , {"remove" , 0ULL, 0, NULL} + , {"rename" , 0ULL, 0, NULL} + , {"link" , 0ULL, 0, NULL} + , {"symlink" , 0ULL, 0, NULL} + , {"create" , 0ULL, 0, NULL} + , {"pathconf" , 0ULL, 0, NULL} + , {"statfs" , 0ULL, 0, NULL} + , {"readlink" , 0ULL, 0, NULL} + , {"readdir" , 0ULL, 0, NULL} + , {"server_caps" , 0ULL, 0, NULL} + , {"delegreturn" , 0ULL, 0, NULL} + , {"getacl" , 0ULL, 0, NULL} + , {"setacl" , 0ULL, 0, NULL} + , {"fs_locations" , 0ULL, 0, NULL} + , {"rel_lkowner" , 0ULL, 0, NULL} + , {"secinfo" , 0ULL, 0, NULL} + , {"fsid_present" , 0ULL, 0, NULL} + , + + /* nfsv4.1 client ops */ + { "exchange_id" , 0ULL, 0, NULL} + , {"create_session" , 0ULL, 0, NULL} + , {"destroy_session" , 0ULL, 0, NULL} + , {"sequence" , 0ULL, 0, NULL} + , {"get_lease_time" , 0ULL, 0, NULL} + , {"reclaim_comp" , 0ULL, 0, NULL} + , {"layoutget" , 0ULL, 0, NULL} + , {"getdevinfo" , 0ULL, 0, NULL} + , {"layoutcommit" , 0ULL, 0, NULL} + , {"layoutreturn" , 0ULL, 0, NULL} + , {"secinfo_no" , 0ULL, 0, NULL} + , {"test_stateid" , 0ULL, 0, NULL} + , {"free_stateid" , 0ULL, 0, NULL} + , {"getdevicelist" , 0ULL, 0, NULL} + , {"bind_conn_to_ses", 0ULL, 0, NULL} + , {"destroy_clientid", 0ULL, 0, NULL} + , + + /* nfsv4.2 client ops */ + { "seek" , 0ULL, 0, NULL} + , {"allocate" , 0ULL, 0, NULL} + , {"deallocate" , 0ULL, 0, NULL} + , {"layoutstats" , 0ULL, 0, NULL} + , {"clone" , 0ULL, 0, NULL} + , + + /* termination */ + { "" , 0ULL, 0, NULL} }; struct nfsd_procs nfsd4_ops_values[] = { - { "unused_op0", 0ULL, 0}, - { "unused_op1", 0ULL, 0}, - { "future_op2", 0ULL, 0}, - { "access", 0ULL, 0}, - { "close", 0ULL, 0}, - { "commit", 0ULL, 0}, - { "create", 0ULL, 0}, - { "delegpurge", 0ULL, 0}, - { "delegreturn", 0ULL, 0}, - { "getattr", 0ULL, 0}, - { "getfh", 0ULL, 0}, - { "link", 0ULL, 0}, - { "lock", 0ULL, 0}, - { "lockt", 0ULL, 0}, - { "locku", 0ULL, 0}, - { "lookup", 0ULL, 0}, - { "lookup_root", 0ULL, 0}, - { "nverify", 0ULL, 0}, - { "open", 0ULL, 0}, - { "openattr", 0ULL, 0}, - { "open_confirm", 0ULL, 0}, - { "open_downgrade", 0ULL, 0}, - { "putfh", 0ULL, 0}, - { "putpubfh", 0ULL, 0}, - { "putrootfh", 0ULL, 0}, - { "read", 0ULL, 0}, - { "readdir", 0ULL, 0}, - { "readlink", 0ULL, 0}, - { "remove", 0ULL, 0}, - { "rename", 0ULL, 0}, - { "renew", 0ULL, 0}, - { "restorefh", 0ULL, 0}, - { "savefh", 0ULL, 0}, - { "secinfo", 0ULL, 0}, - { "setattr", 0ULL, 0}, - { "setclientid", 0ULL, 0}, - { "setclientid_confirm", 0ULL, 0}, - { "verify", 0ULL, 0}, - { "write", 0ULL, 0}, - { "release_lockowner", 0ULL, 0}, - - /* nfs41 */ - { "backchannel_ctl", 0ULL, 0}, - { "bind_conn_to_session", 0ULL, 0}, - { "exchange_id", 0ULL, 0}, - { "create_session", 0ULL, 0}, - { "destroy_session", 0ULL, 0}, - { "free_stateid", 0ULL, 0}, - { "get_dir_delegation", 0ULL, 0}, - { "getdeviceinfo", 0ULL, 0}, - { "getdevicelist", 0ULL, 0}, - { "layoutcommit", 0ULL, 0}, - { "layoutget", 0ULL, 0}, - { "layoutreturn", 0ULL, 0}, - { "secinfo_no_name", 0ULL, 0}, - { "sequence", 0ULL, 0}, - { "set_ssv", 0ULL, 0}, - { "test_stateid", 0ULL, 0}, - { "want_delegation", 0ULL, 0}, - { "destroy_clientid", 0ULL, 0}, - { "reclaim_complete", 0ULL, 0}, - - /* nfs42 */ - { "allocate", 0ULL, 0}, - { "copy", 0ULL, 0}, - { "copy_notify", 0ULL, 0}, - { "deallocate", 0ULL, 0}, - { "ioadvise", 0ULL, 0}, - { "layouterror", 0ULL, 0}, - { "layoutstats", 0ULL, 0}, - { "offload_cancel", 0ULL, 0}, - { "offload_status", 0ULL, 0}, - { "read_plus", 0ULL, 0}, - { "seek", 0ULL, 0}, - { "write_same", 0ULL, 0}, - - /* termination */ - { "", 0ULL, 0 } + { "unused_op0" , 0ULL, 0, NULL} + , {"unused_op1" , 0ULL, 0, NULL} + , {"future_op2" , 0ULL, 0, NULL} + , {"access" , 0ULL, 0, NULL} + , {"close" , 0ULL, 0, NULL} + , {"commit" , 0ULL, 0, NULL} + , {"create" , 0ULL, 0, NULL} + , {"delegpurge" , 0ULL, 0, NULL} + , {"delegreturn" , 0ULL, 0, NULL} + , {"getattr" , 0ULL, 0, NULL} + , {"getfh" , 0ULL, 0, NULL} + , {"link" , 0ULL, 0, NULL} + , {"lock" , 0ULL, 0, NULL} + , {"lockt" , 0ULL, 0, NULL} + , {"locku" , 0ULL, 0, NULL} + , {"lookup" , 0ULL, 0, NULL} + , {"lookup_root" , 0ULL, 0, NULL} + , {"nverify" , 0ULL, 0, NULL} + , {"open" , 0ULL, 0, NULL} + , {"openattr" , 0ULL, 0, NULL} + , {"open_confirm" , 0ULL, 0, NULL} + , {"open_downgrade" , 0ULL, 0, NULL} + , {"putfh" , 0ULL, 0, NULL} + , {"putpubfh" , 0ULL, 0, NULL} + , {"putrootfh" , 0ULL, 0, NULL} + , {"read" , 0ULL, 0, NULL} + , {"readdir" , 0ULL, 0, NULL} + , {"readlink" , 0ULL, 0, NULL} + , {"remove" , 0ULL, 0, NULL} + , {"rename" , 0ULL, 0, NULL} + , {"renew" , 0ULL, 0, NULL} + , {"restorefh" , 0ULL, 0, NULL} + , {"savefh" , 0ULL, 0, NULL} + , {"secinfo" , 0ULL, 0, NULL} + , {"setattr" , 0ULL, 0, NULL} + , {"setclientid" , 0ULL, 0, NULL} + , {"setclientid_confirm" , 0ULL, 0, NULL} + , {"verify" , 0ULL, 0, NULL} + , {"write" , 0ULL, 0, NULL} + , {"release_lockowner" , 0ULL, 0, NULL} + , + + /* nfs41 */ + { "backchannel_ctl" , 0ULL, 0, NULL} + , {"bind_conn_to_session", 0ULL, 0, NULL} + , {"exchange_id" , 0ULL, 0, NULL} + , {"create_session" , 0ULL, 0, NULL} + , {"destroy_session" , 0ULL, 0, NULL} + , {"free_stateid" , 0ULL, 0, NULL} + , {"get_dir_delegation" , 0ULL, 0, NULL} + , {"getdeviceinfo" , 0ULL, 0, NULL} + , {"getdevicelist" , 0ULL, 0, NULL} + , {"layoutcommit" , 0ULL, 0, NULL} + , {"layoutget" , 0ULL, 0, NULL} + , {"layoutreturn" , 0ULL, 0, NULL} + , {"secinfo_no_name" , 0ULL, 0, NULL} + , {"sequence" , 0ULL, 0, NULL} + , {"set_ssv" , 0ULL, 0, NULL} + , {"test_stateid" , 0ULL, 0, NULL} + , {"want_delegation" , 0ULL, 0, NULL} + , {"destroy_clientid" , 0ULL, 0, NULL} + , {"reclaim_complete" , 0ULL, 0, NULL} + , + + /* nfs42 */ + { "allocate" , 0ULL, 0, NULL} + , {"copy" , 0ULL, 0, NULL} + , {"copy_notify" , 0ULL, 0, NULL} + , {"deallocate" , 0ULL, 0, NULL} + , {"ioadvise" , 0ULL, 0, NULL} + , {"layouterror" , 0ULL, 0, NULL} + , {"layoutstats" , 0ULL, 0, NULL} + , {"offload_cancel" , 0ULL, 0, NULL} + , {"offload_status" , 0ULL, 0, NULL} + , {"read_plus" , 0ULL, 0, NULL} + , {"seek" , 0ULL, 0, NULL} + , {"write_same" , 0ULL, 0, NULL} + , + + /* termination */ + { "" , 0ULL, 0, NULL} }; @@ -487,234 +496,403 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) { } } - RRDSET *st; - // -------------------------------------------------------------------- if(do_rc == 2) { - st = rrdset_find_bytype_localhost("nfsd", "readcache"); - if(!st) { - st = rrdset_create_localhost("nfsd", "readcache", NULL, "cache", NULL, "NFS Server Read Cache", "reads/s" - , 5000, update_every, RRDSET_TYPE_STACKED); - - rrddim_add(st, "hits", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "misses", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "nocache", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + static RRDSET *st = NULL; + static RRDDIM *rd_hits = NULL, + *rd_misses = NULL, + *rd_nocache = NULL; + + if(unlikely(!st)) { + st = rrdset_create_localhost( + "nfsd" + , "readcache" + , NULL + , "cache" + , NULL + , "NFS Server Read Cache" + , "reads/s" + , "proc" + , "net/rpc/nfsd" + , 5000 + , update_every + , RRDSET_TYPE_STACKED + ); + + rd_hits = rrddim_add(st, "hits", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_misses = rrddim_add(st, "misses", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_nocache = rrddim_add(st, "nocache", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(st); - rrddim_set(st, "hits", rc_hits); - rrddim_set(st, "misses", rc_misses); - rrddim_set(st, "nocache", rc_nocache); + rrddim_set_by_pointer(st, rd_hits, rc_hits); + rrddim_set_by_pointer(st, rd_misses, rc_misses); + rrddim_set_by_pointer(st, rd_nocache, rc_nocache); rrdset_done(st); } // -------------------------------------------------------------------- if(do_fh == 2) { - st = rrdset_find_bytype_localhost("nfsd", "filehandles"); - if(!st) { - st = rrdset_create_localhost("nfsd", "filehandles", NULL, "filehandles", NULL, "NFS Server File Handles" - , "handles/s", 5001, update_every, RRDSET_TYPE_LINE); + static RRDSET *st = NULL; + static RRDDIM *rd_stale = NULL, + *rd_total_lookups = NULL, + *rd_anonymous_lookups = NULL, + *rd_dir_not_in_dcache = NULL, + *rd_non_dir_not_in_dcache = NULL; + + if(unlikely(!st)) { + st = rrdset_create_localhost( + "nfsd" + , "filehandles" + , NULL + , "filehandles" + , NULL + , "NFS Server File Handles" + , "handles/s" + , "proc" + , "net/rpc/nfsd" + , 5001 + , update_every + , RRDSET_TYPE_LINE + ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - rrddim_add(st, "stale", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); - rrddim_add(st, "total_lookups", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "anonymous_lookups", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "dir_not_in_dcache", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "non_dir_not_in_dcache", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_stale = rrddim_add(st, "stale", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); + rd_total_lookups = rrddim_add(st, "total_lookups", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_anonymous_lookups = rrddim_add(st, "anonymous_lookups", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_dir_not_in_dcache = rrddim_add(st, "dir_not_in_dcache", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_non_dir_not_in_dcache = rrddim_add(st, "non_dir_not_in_dcache", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(st); - rrddim_set(st, "stale", fh_stale); - rrddim_set(st, "total_lookups", fh_total_lookups); - rrddim_set(st, "anonymous_lookups", fh_anonymous_lookups); - rrddim_set(st, "dir_not_in_dcache", fh_dir_not_in_dcache); - rrddim_set(st, "non_dir_not_in_dcache", fh_non_dir_not_in_dcache); + rrddim_set_by_pointer(st, rd_stale, fh_stale); + rrddim_set_by_pointer(st, rd_total_lookups, fh_total_lookups); + rrddim_set_by_pointer(st, rd_anonymous_lookups, fh_anonymous_lookups); + rrddim_set_by_pointer(st, rd_dir_not_in_dcache, fh_dir_not_in_dcache); + rrddim_set_by_pointer(st, rd_non_dir_not_in_dcache, fh_non_dir_not_in_dcache); rrdset_done(st); } // -------------------------------------------------------------------- if(do_io == 2) { - st = rrdset_find_bytype_localhost("nfsd", "io"); - if(!st) { - st = rrdset_create_localhost("nfsd", "io", NULL, "io", NULL, "NFS Server I/O", "kilobytes/s", 5002 - , update_every, RRDSET_TYPE_AREA); - - rrddim_add(st, "read", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "write", NULL, -1, 1000, RRD_ALGORITHM_INCREMENTAL); + static RRDSET *st = NULL; + static RRDDIM *rd_read = NULL, + *rd_write = NULL; + + if(unlikely(!st)) { + st = rrdset_create_localhost( + "nfsd" + , "io" + , NULL + , "io" + , NULL + , "NFS Server I/O" + , "kilobytes/s" + , "proc" + , "net/rpc/nfsd" + , 5002 + , update_every + , RRDSET_TYPE_AREA + ); + + rd_read = rrddim_add(st, "read", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL); + rd_write = rrddim_add(st, "write", NULL, -1, 1000, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(st); - rrddim_set(st, "read", io_read); - rrddim_set(st, "write", io_write); + rrddim_set_by_pointer(st, rd_read, io_read); + rrddim_set_by_pointer(st, rd_write, io_write); rrdset_done(st); } // -------------------------------------------------------------------- if(do_th == 2) { - st = rrdset_find_bytype_localhost("nfsd", "threads"); - if(!st) { - st = rrdset_create_localhost("nfsd", "threads", NULL, "threads", NULL, "NFS Server Threads", "threads", 5003 - , update_every, RRDSET_TYPE_LINE); + { + static RRDSET *st = NULL; + static RRDDIM *rd_threads = NULL; + + if(unlikely(!st)) { + st = rrdset_create_localhost( + "nfsd" + , "threads" + , NULL + , "threads" + , NULL + , "NFS Server Threads" + , "threads" + , "proc" + , "net/rpc/nfsd" + , 5003 + , update_every + , RRDSET_TYPE_LINE + ); + + rd_threads = rrddim_add(st, "threads", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); + } + else rrdset_next(st); - rrddim_add(st, "threads", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); + rrddim_set_by_pointer(st, rd_threads, th_threads); + rrdset_done(st); } - else rrdset_next(st); - - rrddim_set(st, "threads", th_threads); - rrdset_done(st); - st = rrdset_find_bytype_localhost("nfsd", "threads_fullcnt"); - if(!st) { - st = rrdset_create_localhost("nfsd", "threads_fullcnt", NULL, "threads", NULL - , "NFS Server Threads Full Count", "ops/s", 5004, update_every - , RRDSET_TYPE_LINE); + { + static RRDSET *st = NULL; + static RRDDIM *rd_full_count = NULL; + + if(unlikely(!st)) { + st = rrdset_create_localhost( + "nfsd" + , "threads_fullcnt" + , NULL + , "threads" + , NULL + , "NFS Server Threads Full Count" + , "ops/s" + , "proc" + , "net/rpc/nfsd" + , 5004 + , update_every + , RRDSET_TYPE_LINE + ); + + rd_full_count = rrddim_add(st, "full_count", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + } + else rrdset_next(st); - rrddim_add(st, "full_count", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rrddim_set_by_pointer(st, rd_full_count, th_fullcnt); + rrdset_done(st); } - else rrdset_next(st); - rrddim_set(st, "full_count", th_fullcnt); - rrdset_done(st); - - st = rrdset_find_bytype_localhost("nfsd", "threads_histogram"); - if(!st) { - st = rrdset_create_localhost("nfsd", "threads_histogram", NULL, "threads", NULL - , "NFS Server Threads Usage Histogram", "percentage", 5005, update_every - , RRDSET_TYPE_LINE); - - rrddim_add(st, "0%-10%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); - rrddim_add(st, "10%-20%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); - rrddim_add(st, "20%-30%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); - rrddim_add(st, "30%-40%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); - rrddim_add(st, "40%-50%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); - rrddim_add(st, "50%-60%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); - rrddim_add(st, "60%-70%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); - rrddim_add(st, "70%-80%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); - rrddim_add(st, "80%-90%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); - rrddim_add(st, "90%-100%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); + { + static RRDSET *st = NULL; + static RRDDIM *rd_th_hist10 = NULL, + *rd_th_hist20 = NULL, + *rd_th_hist30 = NULL, + *rd_th_hist40 = NULL, + *rd_th_hist50 = NULL, + *rd_th_hist60 = NULL, + *rd_th_hist70 = NULL, + *rd_th_hist80 = NULL, + *rd_th_hist90 = NULL, + *rd_th_hist100 = NULL; + + if(unlikely(!st)) { + st = rrdset_create_localhost( + "nfsd" + , "threads_histogram" + , NULL + , "threads" + , NULL + , "NFS Server Threads Usage Histogram" + , "percentage" + , "proc" + , "net/rpc/nfsd" + , 5005 + , update_every + , RRDSET_TYPE_LINE + ); + + rd_th_hist10 = rrddim_add(st, "0%-10%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); + rd_th_hist20 = rrddim_add(st, "10%-20%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); + rd_th_hist30 = rrddim_add(st, "20%-30%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); + rd_th_hist40 = rrddim_add(st, "30%-40%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); + rd_th_hist50 = rrddim_add(st, "40%-50%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); + rd_th_hist60 = rrddim_add(st, "50%-60%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); + rd_th_hist70 = rrddim_add(st, "60%-70%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); + rd_th_hist80 = rrddim_add(st, "70%-80%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); + rd_th_hist90 = rrddim_add(st, "80%-90%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); + rd_th_hist100 = rrddim_add(st, "90%-100%", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); + } + else rrdset_next(st); + + rrddim_set_by_pointer(st, rd_th_hist10, th_hist10); + rrddim_set_by_pointer(st, rd_th_hist20, th_hist20); + rrddim_set_by_pointer(st, rd_th_hist30, th_hist30); + rrddim_set_by_pointer(st, rd_th_hist40, th_hist40); + rrddim_set_by_pointer(st, rd_th_hist50, th_hist50); + rrddim_set_by_pointer(st, rd_th_hist60, th_hist60); + rrddim_set_by_pointer(st, rd_th_hist70, th_hist70); + rrddim_set_by_pointer(st, rd_th_hist80, th_hist80); + rrddim_set_by_pointer(st, rd_th_hist90, th_hist90); + rrddim_set_by_pointer(st, rd_th_hist100, th_hist100); + rrdset_done(st); } - else rrdset_next(st); - - rrddim_set(st, "0%-10%", th_hist10); - rrddim_set(st, "10%-20%", th_hist20); - rrddim_set(st, "20%-30%", th_hist30); - rrddim_set(st, "30%-40%", th_hist40); - rrddim_set(st, "40%-50%", th_hist50); - rrddim_set(st, "50%-60%", th_hist60); - rrddim_set(st, "60%-70%", th_hist70); - rrddim_set(st, "70%-80%", th_hist80); - rrddim_set(st, "80%-90%", th_hist90); - rrddim_set(st, "90%-100%", th_hist100); - rrdset_done(st); } // -------------------------------------------------------------------- if(do_ra == 2) { - st = rrdset_find_bytype_localhost("nfsd", "readahead"); - if(!st) { - st = rrdset_create_localhost("nfsd", "readahead", NULL, "readahead", NULL, "NFS Server Read Ahead Depth" - , "percentage", 5005, update_every, RRDSET_TYPE_STACKED); - - rrddim_add(st, "10%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); - rrddim_add(st, "20%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); - rrddim_add(st, "30%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); - rrddim_add(st, "40%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); - rrddim_add(st, "50%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); - rrddim_add(st, "60%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); - rrddim_add(st, "70%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); - rrddim_add(st, "80%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); - rrddim_add(st, "90%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); - rrddim_add(st, "100%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); - rrddim_add(st, "misses", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); + static RRDSET *st = NULL; + static RRDDIM *rd_ra_hist10 = NULL, + *rd_ra_hist20 = NULL, + *rd_ra_hist30 = NULL, + *rd_ra_hist40 = NULL, + *rd_ra_hist50 = NULL, + *rd_ra_hist60 = NULL, + *rd_ra_hist70 = NULL, + *rd_ra_hist80 = NULL, + *rd_ra_hist90 = NULL, + *rd_ra_hist100 = NULL, + *rd_ra_none = NULL; + + if(unlikely(!st)) { + st = rrdset_create_localhost( + "nfsd" + , "readahead" + , NULL + , "readahead" + , NULL + , "NFS Server Read Ahead Depth" + , "percentage" + , "proc" + , "net/rpc/nfsd" + , 5005 + , update_every + , RRDSET_TYPE_STACKED + ); + + rd_ra_hist10 = rrddim_add(st, "10%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); + rd_ra_hist20 = rrddim_add(st, "20%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); + rd_ra_hist30 = rrddim_add(st, "30%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); + rd_ra_hist40 = rrddim_add(st, "40%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); + rd_ra_hist50 = rrddim_add(st, "50%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); + rd_ra_hist60 = rrddim_add(st, "60%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); + rd_ra_hist70 = rrddim_add(st, "70%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); + rd_ra_hist80 = rrddim_add(st, "80%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); + rd_ra_hist90 = rrddim_add(st, "90%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); + rd_ra_hist100 = rrddim_add(st, "100%", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); + rd_ra_none = rrddim_add(st, "misses", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL); } else rrdset_next(st); // ignore ra_size - if(ra_size) {}; - - rrddim_set(st, "10%", ra_hist10); - rrddim_set(st, "20%", ra_hist20); - rrddim_set(st, "30%", ra_hist30); - rrddim_set(st, "40%", ra_hist40); - rrddim_set(st, "50%", ra_hist50); - rrddim_set(st, "60%", ra_hist60); - rrddim_set(st, "70%", ra_hist70); - rrddim_set(st, "80%", ra_hist80); - rrddim_set(st, "90%", ra_hist90); - rrddim_set(st, "100%", ra_hist100); - rrddim_set(st, "misses", ra_none); + (void)ra_size; + + rrddim_set_by_pointer(st, rd_ra_hist10, ra_hist10); + rrddim_set_by_pointer(st, rd_ra_hist20, ra_hist20); + rrddim_set_by_pointer(st, rd_ra_hist30, ra_hist30); + rrddim_set_by_pointer(st, rd_ra_hist40, ra_hist40); + rrddim_set_by_pointer(st, rd_ra_hist50, ra_hist50); + rrddim_set_by_pointer(st, rd_ra_hist60, ra_hist60); + rrddim_set_by_pointer(st, rd_ra_hist70, ra_hist70); + rrddim_set_by_pointer(st, rd_ra_hist80, ra_hist80); + rrddim_set_by_pointer(st, rd_ra_hist90, ra_hist90); + rrddim_set_by_pointer(st, rd_ra_hist100,ra_hist100); + rrddim_set_by_pointer(st, rd_ra_none, ra_none); rrdset_done(st); } // -------------------------------------------------------------------- if(do_net == 2) { - st = rrdset_find_bytype_localhost("nfsd", "net"); - if(!st) { - st = rrdset_create_localhost("nfsd", "net", NULL, "network", NULL, "NFS Server Network Statistics" - , "packets/s", 5007, update_every, RRDSET_TYPE_STACKED); + static RRDSET *st = NULL; + static RRDDIM *rd_udp = NULL, + *rd_tcp = NULL; + + if(unlikely(!st)) { + st = rrdset_create_localhost( + "nfsd" + , "net" + , NULL + , "network" + , NULL + , "NFS Server Network Statistics" + , "packets/s" + , "proc" + , "net/rpc/nfsd" + , 5007 + , update_every + , RRDSET_TYPE_STACKED + ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - rrddim_add(st, "udp", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "tcp", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_udp = rrddim_add(st, "udp", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_tcp = rrddim_add(st, "tcp", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(st); // ignore net_count, net_tcp_connections - if(net_count) {}; - if(net_tcp_connections) {}; + (void)net_count; + (void)net_tcp_connections; - rrddim_set(st, "udp", net_udp_count); - rrddim_set(st, "tcp", net_tcp_count); + rrddim_set_by_pointer(st, rd_udp, net_udp_count); + rrddim_set_by_pointer(st, rd_tcp, net_tcp_count); rrdset_done(st); } // -------------------------------------------------------------------- if(do_rpc == 2) { - st = rrdset_find_bytype_localhost("nfsd", "rpc"); - if(!st) { - st = rrdset_create_localhost("nfsd", "rpc", NULL, "rpc", NULL - , "NFS Server Remote Procedure Calls Statistics", "calls/s", 5008, update_every - , RRDSET_TYPE_LINE); + static RRDSET *st = NULL; + static RRDDIM *rd_calls = NULL, + *rd_bad_format = NULL, + *rd_bad_auth = NULL; + + if(unlikely(!st)) { + st = rrdset_create_localhost( + "nfsd" + , "rpc" + , NULL + , "rpc" + , NULL + , "NFS Server Remote Procedure Calls Statistics" + , "calls/s" + , "proc" + , "net/rpc/nfsd" + , 5008 + , update_every + , RRDSET_TYPE_LINE + ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - rrddim_add(st, "calls", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "bad_format", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "bad_auth", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_calls = rrddim_add(st, "calls", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_bad_format = rrddim_add(st, "bad_format", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_bad_auth = rrddim_add(st, "bad_auth", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(st); // ignore rpc_bad_client - if(rpc_bad_client) {}; + (void)rpc_bad_client; - rrddim_set(st, "calls", rpc_calls); - rrddim_set(st, "bad_format", rpc_bad_format); - rrddim_set(st, "bad_auth", rpc_bad_auth); + rrddim_set_by_pointer(st, rd_calls, rpc_calls); + rrddim_set_by_pointer(st, rd_bad_format, rpc_bad_format); + rrddim_set_by_pointer(st, rd_bad_auth, rpc_bad_auth); rrdset_done(st); } // -------------------------------------------------------------------- if(do_proc2 == 2) { - unsigned int i; - st = rrdset_find_bytype_localhost("nfsd", "proc2"); - if(!st) { - st = rrdset_create_localhost("nfsd", "proc2", NULL, "nfsv2rpc", NULL, "NFS v2 Server Remote Procedure Calls" - , "calls/s", 5009, update_every, RRDSET_TYPE_STACKED); - - for(i = 0; nfsd_proc2_values[i].present ; i++) - rrddim_add(st, nfsd_proc2_values[i].name, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + static RRDSET *st = NULL; + if(unlikely(!st)) { + st = rrdset_create_localhost( + "nfsd" + , "proc2" + , NULL + , "nfsv2rpc" + , NULL + , "NFS v2 Server Remote Procedure Calls" + , "calls/s" + , "proc" + , "net/rpc/nfsd" + , 5009 + , update_every + , RRDSET_TYPE_STACKED + ); } else rrdset_next(st); - for(i = 0; nfsd_proc2_values[i].present ; i++) - rrddim_set(st, nfsd_proc2_values[i].name, nfsd_proc2_values[i].value); + size_t i; + for(i = 0; nfsd_proc2_values[i].present ; i++) { + if(unlikely(!nfsd_proc2_values[i].rd)) + nfsd_proc2_values[i].rd = rrddim_add(st, nfsd_proc2_values[i].name, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + + rrddim_set_by_pointer(st, nfsd_proc2_values[i].rd, nfsd_proc2_values[i].value); + } rrdset_done(st); } @@ -722,19 +900,32 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) { // -------------------------------------------------------------------- if(do_proc3 == 2) { - unsigned int i; - st = rrdset_find_bytype_localhost("nfsd", "proc3"); - if(!st) { - st = rrdset_create_localhost("nfsd", "proc3", NULL, "nfsv3rpc", NULL, "NFS v3 Server Remote Procedure Calls" - , "calls/s", 5010, update_every, RRDSET_TYPE_STACKED); - - for(i = 0; nfsd_proc3_values[i].present ; i++) - rrddim_add(st, nfsd_proc3_values[i].name, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + static RRDSET *st = NULL; + if(unlikely(!st)) { + st = rrdset_create_localhost( + "nfsd" + , "proc3" + , NULL + , "nfsv3rpc" + , NULL + , "NFS v3 Server Remote Procedure Calls" + , "calls/s" + , "proc" + , "net/rpc/nfsd" + , 5010 + , update_every + , RRDSET_TYPE_STACKED + ); } else rrdset_next(st); - for(i = 0; nfsd_proc3_values[i].present ; i++) - rrddim_set(st, nfsd_proc3_values[i].name, nfsd_proc3_values[i].value); + size_t i; + for(i = 0; nfsd_proc3_values[i].present ; i++) { + if(unlikely(!nfsd_proc3_values[i].rd)) + nfsd_proc3_values[i].rd = rrddim_add(st, nfsd_proc3_values[i].name, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + + rrddim_set_by_pointer(st, nfsd_proc3_values[i].rd, nfsd_proc3_values[i].value); + } rrdset_done(st); } @@ -742,19 +933,32 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) { // -------------------------------------------------------------------- if(do_proc4 == 2) { - unsigned int i; - st = rrdset_find_bytype_localhost("nfsd", "proc4"); - if(!st) { - st = rrdset_create_localhost("nfsd", "proc4", NULL, "nfsv4rpc", NULL, "NFS v4 Server Remote Procedure Calls" - , "calls/s", 5011, update_every, RRDSET_TYPE_STACKED); - - for(i = 0; nfsd_proc4_values[i].present ; i++) - rrddim_add(st, nfsd_proc4_values[i].name, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + static RRDSET *st = NULL; + if(unlikely(!st)) { + st = rrdset_create_localhost( + "nfsd" + , "proc4" + , NULL + , "nfsv4rpc" + , NULL + , "NFS v4 Server Remote Procedure Calls" + , "calls/s" + , "proc" + , "net/rpc/nfsd" + , 5011 + , update_every + , RRDSET_TYPE_STACKED + ); } else rrdset_next(st); - for(i = 0; nfsd_proc4_values[i].present ; i++) - rrddim_set(st, nfsd_proc4_values[i].name, nfsd_proc4_values[i].value); + size_t i; + for(i = 0; nfsd_proc4_values[i].present ; i++) { + if(unlikely(!nfsd_proc4_values[i].rd)) + nfsd_proc4_values[i].rd = rrddim_add(st, nfsd_proc4_values[i].name, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + + rrddim_set_by_pointer(st, nfsd_proc4_values[i].rd, nfsd_proc4_values[i].value); + } rrdset_done(st); } @@ -762,19 +966,32 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) { // -------------------------------------------------------------------- if(do_proc4ops == 2) { - unsigned int i; - st = rrdset_find_bytype_localhost("nfsd", "proc4ops"); - if(!st) { - st = rrdset_create_localhost("nfsd", "proc4ops", NULL, "nfsv2ops", NULL, "NFS v4 Server Operations" - , "operations/s", 5012, update_every, RRDSET_TYPE_STACKED); - - for(i = 0; nfsd4_ops_values[i].present ; i++) - rrddim_add(st, nfsd4_ops_values[i].name, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + static RRDSET *st = NULL; + if(unlikely(!st)) { + st = rrdset_create_localhost( + "nfsd" + , "proc4ops" + , NULL + , "nfsv2ops" + , NULL + , "NFS v4 Server Operations" + , "operations/s" + , "proc" + , "net/rpc/nfsd" + , 5012 + , update_every + , RRDSET_TYPE_STACKED + ); } else rrdset_next(st); - for(i = 0; nfsd4_ops_values[i].present ; i++) - rrddim_set(st, nfsd4_ops_values[i].name, nfsd4_ops_values[i].value); + size_t i; + for(i = 0; nfsd4_ops_values[i].present ; i++) { + if(unlikely(!nfsd4_ops_values[i].rd)) + nfsd4_ops_values[i].rd = rrddim_add(st, nfsd4_ops_values[i].name, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + + rrddim_set_by_pointer(st, nfsd4_ops_values[i].rd, nfsd4_ops_values[i].value); + } rrdset_done(st); } diff --git a/src/proc_net_snmp.c b/src/proc_net_snmp.c index 817c964b..fabfdf8c 100644 --- a/src/proc_net_snmp.c +++ b/src/proc_net_snmp.c @@ -2,197 +2,88 @@ #define RRD_TYPE_NET_SNMP "ipv4" -struct netstat_columns { - char *name; - uint32_t hash; - unsigned long long value; - int multiplier; // not needed everywhere - char *label; // not needed everywhere -}; - -static struct netstat_columns ip_data[] = { -// { "Forwarding", 0, 0, 1, NULL }, -// { "DefaultTTL", 0, 0, 1, NULL }, - { "InReceives", 0, 0, 1, NULL }, - { "InHdrErrors", 0, 0, 1, NULL }, - { "InAddrErrors", 0, 0, 1, NULL }, - { "ForwDatagrams", 0, 0, 1, NULL }, - { "InUnknownProtos", 0, 0, 1, NULL }, - { "InDiscards", 0, 0, 1, NULL }, - { "InDelivers", 0, 0, 1, NULL }, - { "OutRequests", 0, 0, 1, NULL }, - { "OutDiscards", 0, 0, 1, NULL }, - { "OutNoRoutes", 0, 0, 1, NULL }, -// { "ReasmTimeout", 0, 0, 1, NULL }, - { "ReasmReqds", 0, 0, 1, NULL }, - { "ReasmOKs", 0, 0, 1, NULL }, - { "ReasmFails", 0, 0, 1, NULL }, - { "FragOKs", 0, 0, 1, NULL }, - { "FragFails", 0, 0, 1, NULL }, - { "FragCreates", 0, 0, 1, NULL }, - { NULL, 0, 0, 0, NULL } -}; - -static struct netstat_columns icmp_data[] = { - { "InMsgs", 0, 0, 1, NULL }, - { "OutMsgs", 0, 0, -1, NULL }, - { "InErrors", 0, 0, 1, NULL }, - { "OutErrors", 0, 0, -1, NULL }, - { "InCsumErrors", 0, 0, 1, NULL }, - - // all these are available in icmpmsg -// { "InDestUnreachs", 0, 0, 1, NULL }, -// { "OutDestUnreachs", 0, 0, -1, NULL }, -// { "InTimeExcds", 0, 0, 1, NULL }, -// { "OutTimeExcds", 0, 0, -1, NULL }, -// { "InParmProbs", 0, 0, 1, NULL }, -// { "OutParmProbs", 0, 0, -1, NULL }, -// { "InSrcQuenchs", 0, 0, 1, NULL }, -// { "OutSrcQuenchs", 0, 0, -1, NULL }, -// { "InRedirects", 0, 0, 1, NULL }, -// { "OutRedirects", 0, 0, -1, NULL }, -// { "InEchos", 0, 0, 1, NULL }, -// { "OutEchos", 0, 0, -1, NULL }, -// { "InEchoReps", 0, 0, 1, NULL }, -// { "OutEchoReps", 0, 0, -1, NULL }, -// { "InTimestamps", 0, 0, 1, NULL }, -// { "OutTimestamps", 0, 0, -1, NULL }, -// { "InTimestampReps", 0, 0, 1, NULL }, -// { "OutTimestampReps", 0, 0, -1, NULL }, -// { "InAddrMasks", 0, 0, 1, NULL }, -// { "OutAddrMasks", 0, 0, -1, NULL }, -// { "InAddrMaskReps", 0, 0, 1, NULL }, -// { "OutAddrMaskReps", 0, 0, -1, NULL }, - - { NULL, 0, 0, 0, NULL } -}; - -static struct netstat_columns icmpmsg_data[] = { - { "InType0", 0, 0, 1, "InEchoReps" }, - { "OutType0", 0, 0, -1, "OutEchoReps" }, -// { "InType1", 0, 0, 1, NULL }, // unassigned -// { "OutType1", 0, 0, -1, NULL }, // unassigned -// { "InType2", 0, 0, 1, NULL }, // unassigned -// { "OutType2", 0, 0, -1, NULL }, // unassigned - { "InType3", 0, 0, 1, "InDestUnreachs" }, - { "OutType3", 0, 0, -1, "OutDestUnreachs" }, -// { "InType4", 0, 0, 1, "InSrcQuenchs" }, // deprecated -// { "OutType4", 0, 0, -1, "OutSrcQuenchs" }, // deprecated - { "InType5", 0, 0, 1, "InRedirects" }, - { "OutType5", 0, 0, -1, "OutRedirects" }, -// { "InType6", 0, 0, 1, "InAlterHostAddr" }, // deprecated -// { "OutType6", 0, 0, -1, "OutAlterHostAddr" }, // deprecated -// { "InType7", 0, 0, 1, NULL }, // unassigned -// { "OutType7", 0, 0, -1, NULL }, // unassigned - { "InType8", 0, 0, 1, "InEchos" }, - { "OutType8", 0, 0, -1, "OutEchos" }, - { "InType9", 0, 0, 1, "InRouterAdvert" }, - { "OutType9", 0, 0, -1, "OutRouterAdvert" }, - { "InType10", 0, 0, 1, "InRouterSelect" }, - { "OutType10", 0, 0, -1, "OutRouterSelect" }, - { "InType11", 0, 0, 1, "InTimeExcds" }, - { "OutType11", 0, 0, -1, "OutTimeExcds" }, - { "InType12", 0, 0, 1, "InParmProbs" }, - { "OutType12", 0, 0, -1, "OutParmProbs" }, - { "InType13", 0, 0, 1, "InTimestamps" }, - { "OutType13", 0, 0, -1, "OutTimestamps" }, - { "InType14", 0, 0, 1, "InTimestampReps" }, - { "OutType14", 0, 0, -1, "OutTimestampReps" }, -// { "InType15", 0, 0, 1, "InInfos" }, // deprecated -// { "OutType15", 0, 0, -1, "OutInfos" }, // deprecated -// { "InType16", 0, 0, 1, "InInfoReps" }, // deprecated -// { "OutType16", 0, 0, -1, "OutInfoReps" }, // deprecated -// { "InType17", 0, 0, 1, "InAddrMasks" }, // deprecated -// { "OutType17", 0, 0, -1, "OutAddrMasks" }, // deprecated -// { "InType18", 0, 0, 1, "InAddrMaskReps" }, // deprecated -// { "OutType18", 0, 0, -1, "OutAddrMaskReps" }, // deprecated -// { "InType30", 0, 0, 1, "InTraceroute" }, // deprecated -// { "OutType30", 0, 0, -1, "OutTraceroute" }, // deprecated - { NULL, 0, 0, 0, NULL } -}; - -static struct netstat_columns tcp_data[] = { -// { "RtoAlgorithm", 0, 0, 1, NULL }, -// { "RtoMin", 0, 0, 1, NULL }, -// { "RtoMax", 0, 0, 1, NULL }, -// { "MaxConn", 0, 0, 1, NULL }, - { "ActiveOpens", 0, 0, 1, NULL }, - { "PassiveOpens", 0, 0, 1, NULL }, - { "AttemptFails", 0, 0, 1, NULL }, - { "EstabResets", 0, 0, 1, NULL }, - { "CurrEstab", 0, 0, 1, NULL }, - { "InSegs", 0, 0, 1, NULL }, - { "OutSegs", 0, 0, 1, NULL }, - { "RetransSegs", 0, 0, 1, NULL }, - { "InErrs", 0, 0, 1, NULL }, - { "OutRsts", 0, 0, 1, NULL }, - { "InCsumErrors", 0, 0, 1, NULL }, - { NULL, 0, 0, 0, NULL } -}; - -static struct netstat_columns udp_data[] = { - { "InDatagrams", 0, 0, 1, NULL }, - { "NoPorts", 0, 0, 1, NULL }, - { "InErrors", 0, 0, 1, NULL }, - { "OutDatagrams", 0, 0, 1, NULL }, - { "RcvbufErrors", 0, 0, 1, NULL }, - { "SndbufErrors", 0, 0, 1, NULL }, - { "InCsumErrors", 0, 0, 1, NULL }, - { "IgnoredMulti", 0, 0, 1, NULL }, - { NULL, 0, 0, 0, NULL } -}; - -static struct netstat_columns udplite_data[] = { - { "InDatagrams", 0, 0, 1, NULL }, - { "NoPorts", 0, 0, 1, NULL }, - { "InErrors", 0, 0, 1, NULL }, - { "OutDatagrams", 0, 0, 1, NULL }, - { "RcvbufErrors", 0, 0, 1, NULL }, - { "SndbufErrors", 0, 0, 1, NULL }, - { "InCsumErrors", 0, 0, 1, NULL }, - { "IgnoredMulti", 0, 0, 1, NULL }, - { NULL, 0, 0, 0, NULL } -}; - -static void hash_array(struct netstat_columns *nc) { - int i; - - for(i = 0; nc[i].name ;i++) - nc[i].hash = simple_hash(nc[i].name); -} - -static unsigned long long *netstat_columns_find(struct netstat_columns *nc, const char *name) { - uint32_t i, hash = simple_hash(name); - - for(i = 0; nc[i].name ;i++) - if(unlikely(nc[i].hash == hash && !strcmp(nc[i].name, name))) - return &nc[i].value; - - fatal("Cannot find key '%s' in /proc/net/snmp internal array.", name); -} - -static void parse_line_pair(procfile *ff, struct netstat_columns *nc, size_t header_line, size_t values_line) { - size_t hwords = procfile_linewords(ff, header_line); - size_t vwords = procfile_linewords(ff, values_line); - size_t w, i; - - if(unlikely(vwords > hwords)) { - error("File /proc/net/snmp on header line %zu has %zu words, but on value line %zu has %zu words.", header_line, hwords, values_line, vwords); - vwords = hwords; - } - - for(w = 1; w < vwords ;w++) { - char *key = procfile_lineword(ff, header_line, w); - uint32_t hash = simple_hash(key); - - for(i = 0 ; nc[i].name ;i++) { - if(unlikely(hash == nc[i].hash && !strcmp(key, nc[i].name))) { - nc[i].value = str2ull(procfile_lineword(ff, values_line, w)); - break; - } - } - } -} +static struct proc_net_snmp { + // kernel_uint_t ip_Forwarding; + kernel_uint_t ip_DefaultTTL; + kernel_uint_t ip_InReceives; + kernel_uint_t ip_InHdrErrors; + kernel_uint_t ip_InAddrErrors; + kernel_uint_t ip_ForwDatagrams; + kernel_uint_t ip_InUnknownProtos; + kernel_uint_t ip_InDiscards; + kernel_uint_t ip_InDelivers; + kernel_uint_t ip_OutRequests; + kernel_uint_t ip_OutDiscards; + kernel_uint_t ip_OutNoRoutes; + kernel_uint_t ip_ReasmTimeout; + kernel_uint_t ip_ReasmReqds; + kernel_uint_t ip_ReasmOKs; + kernel_uint_t ip_ReasmFails; + kernel_uint_t ip_FragOKs; + kernel_uint_t ip_FragFails; + kernel_uint_t ip_FragCreates; + + kernel_uint_t icmp_InMsgs; + kernel_uint_t icmp_OutMsgs; + kernel_uint_t icmp_InErrors; + kernel_uint_t icmp_OutErrors; + kernel_uint_t icmp_InCsumErrors; + + kernel_uint_t icmpmsg_InEchoReps; + kernel_uint_t icmpmsg_OutEchoReps; + kernel_uint_t icmpmsg_InDestUnreachs; + kernel_uint_t icmpmsg_OutDestUnreachs; + kernel_uint_t icmpmsg_InRedirects; + kernel_uint_t icmpmsg_OutRedirects; + kernel_uint_t icmpmsg_InEchos; + kernel_uint_t icmpmsg_OutEchos; + kernel_uint_t icmpmsg_InRouterAdvert; + kernel_uint_t icmpmsg_OutRouterAdvert; + kernel_uint_t icmpmsg_InRouterSelect; + kernel_uint_t icmpmsg_OutRouterSelect; + kernel_uint_t icmpmsg_InTimeExcds; + kernel_uint_t icmpmsg_OutTimeExcds; + kernel_uint_t icmpmsg_InParmProbs; + kernel_uint_t icmpmsg_OutParmProbs; + kernel_uint_t icmpmsg_InTimestamps; + kernel_uint_t icmpmsg_OutTimestamps; + kernel_uint_t icmpmsg_InTimestampReps; + kernel_uint_t icmpmsg_OutTimestampReps; + + //kernel_uint_t tcp_RtoAlgorithm; + //kernel_uint_t tcp_RtoMin; + //kernel_uint_t tcp_RtoMax; + ssize_t tcp_MaxConn; + kernel_uint_t tcp_ActiveOpens; + kernel_uint_t tcp_PassiveOpens; + kernel_uint_t tcp_AttemptFails; + kernel_uint_t tcp_EstabResets; + kernel_uint_t tcp_CurrEstab; + kernel_uint_t tcp_InSegs; + kernel_uint_t tcp_OutSegs; + kernel_uint_t tcp_RetransSegs; + kernel_uint_t tcp_InErrs; + kernel_uint_t tcp_OutRsts; + kernel_uint_t tcp_InCsumErrors; + + kernel_uint_t udp_InDatagrams; + kernel_uint_t udp_NoPorts; + kernel_uint_t udp_InErrors; + kernel_uint_t udp_OutDatagrams; + kernel_uint_t udp_RcvbufErrors; + kernel_uint_t udp_SndbufErrors; + kernel_uint_t udp_InCsumErrors; + kernel_uint_t udp_IgnoredMulti; + + kernel_uint_t udplite_InDatagrams; + kernel_uint_t udplite_NoPorts; + kernel_uint_t udplite_InErrors; + kernel_uint_t udplite_OutDatagrams; + kernel_uint_t udplite_RcvbufErrors; + kernel_uint_t udplite_SndbufErrors; + kernel_uint_t udplite_InCsumErrors; + kernel_uint_t udplite_IgnoredMulti; +} snmp_root = { 0 }; int do_proc_net_snmp(int update_every, usec_t dt) { (void)dt; @@ -203,67 +94,17 @@ int do_proc_net_snmp(int update_every, usec_t dt) { do_udp_packets = -1, do_udp_errors = -1, do_icmp_packets = -1, do_icmpmsg = -1, do_udplite_packets = -1; static uint32_t hash_ip = 0, hash_icmp = 0, hash_tcp = 0, hash_udp = 0, hash_icmpmsg = 0, hash_udplite = 0; - //static unsigned long long *ip_Forwarding = NULL; - //static unsigned long long *ip_DefaultTTL = NULL; - static unsigned long long *ip_InReceives = NULL; - static unsigned long long *ip_InHdrErrors = NULL; - static unsigned long long *ip_InAddrErrors = NULL; - static unsigned long long *ip_ForwDatagrams = NULL; - static unsigned long long *ip_InUnknownProtos = NULL; - static unsigned long long *ip_InDiscards = NULL; - static unsigned long long *ip_InDelivers = NULL; - static unsigned long long *ip_OutRequests = NULL; - static unsigned long long *ip_OutDiscards = NULL; - static unsigned long long *ip_OutNoRoutes = NULL; - //static unsigned long long *ip_ReasmTimeout = NULL; - static unsigned long long *ip_ReasmReqds = NULL; - static unsigned long long *ip_ReasmOKs = NULL; - static unsigned long long *ip_ReasmFails = NULL; - static unsigned long long *ip_FragOKs = NULL; - static unsigned long long *ip_FragFails = NULL; - static unsigned long long *ip_FragCreates = NULL; - - static unsigned long long *icmp_InMsgs = NULL; - static unsigned long long *icmp_OutMsgs = NULL; - static unsigned long long *icmp_InErrors = NULL; - static unsigned long long *icmp_OutErrors = NULL; - static unsigned long long *icmp_InCsumErrors = NULL; - - //static unsigned long long *tcp_RtoAlgorithm = NULL; - //static unsigned long long *tcp_RtoMin = NULL; - //static unsigned long long *tcp_RtoMax = NULL; - //static unsigned long long *tcp_MaxConn = NULL; - static unsigned long long *tcp_ActiveOpens = NULL; - static unsigned long long *tcp_PassiveOpens = NULL; - static unsigned long long *tcp_AttemptFails = NULL; - static unsigned long long *tcp_EstabResets = NULL; - static unsigned long long *tcp_CurrEstab = NULL; - static unsigned long long *tcp_InSegs = NULL; - static unsigned long long *tcp_OutSegs = NULL; - static unsigned long long *tcp_RetransSegs = NULL; - static unsigned long long *tcp_InErrs = NULL; - static unsigned long long *tcp_OutRsts = NULL; - static unsigned long long *tcp_InCsumErrors = NULL; - - static unsigned long long *udp_InDatagrams = NULL; - static unsigned long long *udp_NoPorts = NULL; - static unsigned long long *udp_InErrors = NULL; - static unsigned long long *udp_OutDatagrams = NULL; - static unsigned long long *udp_RcvbufErrors = NULL; - static unsigned long long *udp_SndbufErrors = NULL; - static unsigned long long *udp_InCsumErrors = NULL; - static unsigned long long *udp_IgnoredMulti = NULL; - - static unsigned long long *udplite_InDatagrams = NULL; - static unsigned long long *udplite_NoPorts = NULL; - static unsigned long long *udplite_InErrors = NULL; - static unsigned long long *udplite_OutDatagrams = NULL; - static unsigned long long *udplite_RcvbufErrors = NULL; - static unsigned long long *udplite_SndbufErrors = NULL; - static unsigned long long *udplite_InCsumErrors = NULL; - static unsigned long long *udplite_IgnoredMulti = NULL; - - if(unlikely(do_ip_packets == -1)) { + static ARL_BASE *arl_ip = NULL, + *arl_icmp = NULL, + *arl_icmpmsg = NULL, + *arl_tcp = NULL, + *arl_udp = NULL, + *arl_udplite = NULL; + + static RRDVAR *tcp_max_connections_var = NULL; + static ssize_t last_max_connections = 0; + + if(unlikely(!arl_ip)) { do_ip_packets = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 packets", 1); do_ip_fragsout = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 fragments sent", 1); do_ip_fragsin = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 fragments assembly", 1); @@ -285,72 +126,94 @@ int do_proc_net_snmp(int update_every, usec_t dt) { hash_icmpmsg = simple_hash("IcmpMsg"); hash_udplite = simple_hash("UdpLite"); - hash_array(ip_data); - hash_array(tcp_data); - hash_array(udp_data); - hash_array(icmp_data); - hash_array(icmpmsg_data); - hash_array(udplite_data); - - //ip_Forwarding = netstat_columns_find(ip_data, "Forwarding"); - //ip_DefaultTTL = netstat_columns_find(ip_data, "DefaultTTL"); - ip_InReceives = netstat_columns_find(ip_data, "InReceives"); - ip_InHdrErrors = netstat_columns_find(ip_data, "InHdrErrors"); - ip_InAddrErrors = netstat_columns_find(ip_data, "InAddrErrors"); - ip_ForwDatagrams = netstat_columns_find(ip_data, "ForwDatagrams"); - ip_InUnknownProtos = netstat_columns_find(ip_data, "InUnknownProtos"); - ip_InDiscards = netstat_columns_find(ip_data, "InDiscards"); - ip_InDelivers = netstat_columns_find(ip_data, "InDelivers"); - ip_OutRequests = netstat_columns_find(ip_data, "OutRequests"); - ip_OutDiscards = netstat_columns_find(ip_data, "OutDiscards"); - ip_OutNoRoutes = netstat_columns_find(ip_data, "OutNoRoutes"); - //ip_ReasmTimeout = netstat_columns_find(ip_data, "ReasmTimeout"); - ip_ReasmReqds = netstat_columns_find(ip_data, "ReasmReqds"); - ip_ReasmOKs = netstat_columns_find(ip_data, "ReasmOKs"); - ip_ReasmFails = netstat_columns_find(ip_data, "ReasmFails"); - ip_FragOKs = netstat_columns_find(ip_data, "FragOKs"); - ip_FragFails = netstat_columns_find(ip_data, "FragFails"); - ip_FragCreates = netstat_columns_find(ip_data, "FragCreates"); - - icmp_InMsgs = netstat_columns_find(icmp_data, "InMsgs"); - icmp_OutMsgs = netstat_columns_find(icmp_data, "OutMsgs"); - icmp_InErrors = netstat_columns_find(icmp_data, "InErrors"); - icmp_OutErrors = netstat_columns_find(icmp_data, "OutErrors"); - icmp_InCsumErrors = netstat_columns_find(icmp_data, "InCsumErrors"); - - //tcp_RtoAlgorithm = netstat_columns_find(tcp_data, "RtoAlgorithm"); - //tcp_RtoMin = netstat_columns_find(tcp_data, "RtoMin"); - //tcp_RtoMax = netstat_columns_find(tcp_data, "RtoMax"); - //tcp_MaxConn = netstat_columns_find(tcp_data, "MaxConn"); - tcp_ActiveOpens = netstat_columns_find(tcp_data, "ActiveOpens"); - tcp_PassiveOpens = netstat_columns_find(tcp_data, "PassiveOpens"); - tcp_AttemptFails = netstat_columns_find(tcp_data, "AttemptFails"); - tcp_EstabResets = netstat_columns_find(tcp_data, "EstabResets"); - tcp_CurrEstab = netstat_columns_find(tcp_data, "CurrEstab"); - tcp_InSegs = netstat_columns_find(tcp_data, "InSegs"); - tcp_OutSegs = netstat_columns_find(tcp_data, "OutSegs"); - tcp_RetransSegs = netstat_columns_find(tcp_data, "RetransSegs"); - tcp_InErrs = netstat_columns_find(tcp_data, "InErrs"); - tcp_OutRsts = netstat_columns_find(tcp_data, "OutRsts"); - tcp_InCsumErrors = netstat_columns_find(tcp_data, "InCsumErrors"); - - udp_InDatagrams = netstat_columns_find(udp_data, "InDatagrams"); - udp_NoPorts = netstat_columns_find(udp_data, "NoPorts"); - udp_InErrors = netstat_columns_find(udp_data, "InErrors"); - udp_OutDatagrams = netstat_columns_find(udp_data, "OutDatagrams"); - udp_RcvbufErrors = netstat_columns_find(udp_data, "RcvbufErrors"); - udp_SndbufErrors = netstat_columns_find(udp_data, "SndbufErrors"); - udp_InCsumErrors = netstat_columns_find(udp_data, "InCsumErrors"); - udp_IgnoredMulti = netstat_columns_find(udp_data, "IgnoredMulti"); - - udplite_InDatagrams = netstat_columns_find(udplite_data, "InDatagrams"); - udplite_NoPorts = netstat_columns_find(udplite_data, "NoPorts"); - udplite_InErrors = netstat_columns_find(udplite_data, "InErrors"); - udplite_OutDatagrams = netstat_columns_find(udplite_data, "OutDatagrams"); - udplite_RcvbufErrors = netstat_columns_find(udplite_data, "RcvbufErrors"); - udplite_SndbufErrors = netstat_columns_find(udplite_data, "SndbufErrors"); - udplite_InCsumErrors = netstat_columns_find(udplite_data, "InCsumErrors"); - udplite_IgnoredMulti = netstat_columns_find(udplite_data, "IgnoredMulti"); + arl_ip = arl_create("snmp/Ip", arl_callback_str2kernel_uint_t, 60); + // arl_expect(arl_ip, "Forwarding", &snmp_root.ip_Forwarding); + arl_expect(arl_ip, "DefaultTTL", &snmp_root.ip_DefaultTTL); + arl_expect(arl_ip, "InReceives", &snmp_root.ip_InReceives); + arl_expect(arl_ip, "InHdrErrors", &snmp_root.ip_InHdrErrors); + arl_expect(arl_ip, "InAddrErrors", &snmp_root.ip_InAddrErrors); + arl_expect(arl_ip, "ForwDatagrams", &snmp_root.ip_ForwDatagrams); + arl_expect(arl_ip, "InUnknownProtos", &snmp_root.ip_InUnknownProtos); + arl_expect(arl_ip, "InDiscards", &snmp_root.ip_InDiscards); + arl_expect(arl_ip, "InDelivers", &snmp_root.ip_InDelivers); + arl_expect(arl_ip, "OutRequests", &snmp_root.ip_OutRequests); + arl_expect(arl_ip, "OutDiscards", &snmp_root.ip_OutDiscards); + arl_expect(arl_ip, "OutNoRoutes", &snmp_root.ip_OutNoRoutes); + arl_expect(arl_ip, "ReasmTimeout", &snmp_root.ip_ReasmTimeout); + arl_expect(arl_ip, "ReasmReqds", &snmp_root.ip_ReasmReqds); + arl_expect(arl_ip, "ReasmOKs", &snmp_root.ip_ReasmOKs); + arl_expect(arl_ip, "ReasmFails", &snmp_root.ip_ReasmFails); + arl_expect(arl_ip, "FragOKs", &snmp_root.ip_FragOKs); + arl_expect(arl_ip, "FragFails", &snmp_root.ip_FragFails); + arl_expect(arl_ip, "FragCreates", &snmp_root.ip_FragCreates); + + arl_icmp = arl_create("snmp/Icmp", arl_callback_str2kernel_uint_t, 60); + arl_expect(arl_icmp, "InMsgs", &snmp_root.icmp_InMsgs); + arl_expect(arl_icmp, "OutMsgs", &snmp_root.icmp_OutMsgs); + arl_expect(arl_icmp, "InErrors", &snmp_root.icmp_InErrors); + arl_expect(arl_icmp, "OutErrors", &snmp_root.icmp_OutErrors); + arl_expect(arl_icmp, "InCsumErrors", &snmp_root.icmp_InCsumErrors); + + arl_icmpmsg = arl_create("snmp/Icmpmsg", arl_callback_str2kernel_uint_t, 60); + arl_expect(arl_icmpmsg, "InType0", &snmp_root.icmpmsg_InEchoReps); + arl_expect(arl_icmpmsg, "OutType0", &snmp_root.icmpmsg_OutEchoReps); + arl_expect(arl_icmpmsg, "InType3", &snmp_root.icmpmsg_InDestUnreachs); + arl_expect(arl_icmpmsg, "OutType3", &snmp_root.icmpmsg_OutDestUnreachs); + arl_expect(arl_icmpmsg, "InType5", &snmp_root.icmpmsg_InRedirects); + arl_expect(arl_icmpmsg, "OutType5", &snmp_root.icmpmsg_OutRedirects); + arl_expect(arl_icmpmsg, "InType8", &snmp_root.icmpmsg_InEchos); + arl_expect(arl_icmpmsg, "OutType8", &snmp_root.icmpmsg_OutEchos); + arl_expect(arl_icmpmsg, "InType9", &snmp_root.icmpmsg_InRouterAdvert); + arl_expect(arl_icmpmsg, "OutType9", &snmp_root.icmpmsg_OutRouterAdvert); + arl_expect(arl_icmpmsg, "InType10", &snmp_root.icmpmsg_InRouterSelect); + arl_expect(arl_icmpmsg, "OutType10", &snmp_root.icmpmsg_OutRouterSelect); + arl_expect(arl_icmpmsg, "InType11", &snmp_root.icmpmsg_InTimeExcds); + arl_expect(arl_icmpmsg, "OutType11", &snmp_root.icmpmsg_OutTimeExcds); + arl_expect(arl_icmpmsg, "InType12", &snmp_root.icmpmsg_InParmProbs); + arl_expect(arl_icmpmsg, "OutType12", &snmp_root.icmpmsg_OutParmProbs); + arl_expect(arl_icmpmsg, "InType13", &snmp_root.icmpmsg_InTimestamps); + arl_expect(arl_icmpmsg, "OutType13", &snmp_root.icmpmsg_OutTimestamps); + arl_expect(arl_icmpmsg, "InType14", &snmp_root.icmpmsg_InTimestampReps); + arl_expect(arl_icmpmsg, "OutType14", &snmp_root.icmpmsg_OutTimestampReps); + + arl_tcp = arl_create("snmp/Tcp", arl_callback_str2kernel_uint_t, 60); + // arl_expect(arl_tcp, "RtoAlgorithm", &snmp_root.tcp_RtoAlgorithm); + // arl_expect(arl_tcp, "RtoMin", &snmp_root.tcp_RtoMin); + // arl_expect(arl_tcp, "RtoMax", &snmp_root.tcp_RtoMax); + arl_expect(arl_tcp, "MaxConn", &snmp_root.tcp_MaxConn); + arl_expect(arl_tcp, "ActiveOpens", &snmp_root.tcp_ActiveOpens); + arl_expect(arl_tcp, "PassiveOpens", &snmp_root.tcp_PassiveOpens); + arl_expect(arl_tcp, "AttemptFails", &snmp_root.tcp_AttemptFails); + arl_expect(arl_tcp, "EstabResets", &snmp_root.tcp_EstabResets); + arl_expect(arl_tcp, "CurrEstab", &snmp_root.tcp_CurrEstab); + arl_expect(arl_tcp, "InSegs", &snmp_root.tcp_InSegs); + arl_expect(arl_tcp, "OutSegs", &snmp_root.tcp_OutSegs); + arl_expect(arl_tcp, "RetransSegs", &snmp_root.tcp_RetransSegs); + arl_expect(arl_tcp, "InErrs", &snmp_root.tcp_InErrs); + arl_expect(arl_tcp, "OutRsts", &snmp_root.tcp_OutRsts); + arl_expect(arl_tcp, "InCsumErrors", &snmp_root.tcp_InCsumErrors); + + arl_udp = arl_create("snmp/Udp", arl_callback_str2kernel_uint_t, 60); + arl_expect(arl_udp, "InDatagrams", &snmp_root.udp_InDatagrams); + arl_expect(arl_udp, "NoPorts", &snmp_root.udp_NoPorts); + arl_expect(arl_udp, "InErrors", &snmp_root.udp_InErrors); + arl_expect(arl_udp, "OutDatagrams", &snmp_root.udp_OutDatagrams); + arl_expect(arl_udp, "RcvbufErrors", &snmp_root.udp_RcvbufErrors); + arl_expect(arl_udp, "SndbufErrors", &snmp_root.udp_SndbufErrors); + arl_expect(arl_udp, "InCsumErrors", &snmp_root.udp_InCsumErrors); + arl_expect(arl_udp, "IgnoredMulti", &snmp_root.udp_IgnoredMulti); + + arl_udplite = arl_create("snmp/Udplite", arl_callback_str2kernel_uint_t, 60); + arl_expect(arl_udplite, "InDatagrams", &snmp_root.udplite_InDatagrams); + arl_expect(arl_udplite, "NoPorts", &snmp_root.udplite_NoPorts); + arl_expect(arl_udplite, "InErrors", &snmp_root.udplite_InErrors); + arl_expect(arl_udplite, "OutDatagrams", &snmp_root.udplite_OutDatagrams); + arl_expect(arl_udplite, "RcvbufErrors", &snmp_root.udplite_RcvbufErrors); + arl_expect(arl_udplite, "SndbufErrors", &snmp_root.udplite_SndbufErrors); + arl_expect(arl_udplite, "InCsumErrors", &snmp_root.udplite_InCsumErrors); + arl_expect(arl_udplite, "IgnoredMulti", &snmp_root.udplite_IgnoredMulti); + + tcp_max_connections_var = rrdvar_custom_host_variable_create(localhost, "tcp_max_connections"); } if(unlikely(!ff)) { @@ -364,9 +227,7 @@ int do_proc_net_snmp(int update_every, usec_t dt) { if(unlikely(!ff)) return 0; // we return 0, so that we will retry to open it next time size_t lines = procfile_lines(ff), l; - size_t words; - - RRDSET *st; + size_t words, w; for(l = 0; l < lines ;l++) { char *key = procfile_lineword(ff, l, 0); @@ -386,101 +247,170 @@ int do_proc_net_snmp(int update_every, usec_t dt) { continue; } - // see also http://net-snmp.sourceforge.net/docs/mibs/ip.html - parse_line_pair(ff, ip_data, h, l); + arl_begin(arl_ip); + for(w = 1; w < words ; w++) { + if (unlikely(arl_check(arl_ip, procfile_lineword(ff, h, w), procfile_lineword(ff, l, w)) != 0)) + break; + } // -------------------------------------------------------------------- if(do_ip_packets) { - st = rrdset_find_localhost(RRD_TYPE_NET_SNMP ".packets"); - if(!st) { - st = rrdset_create_localhost(RRD_TYPE_NET_SNMP, "packets", NULL, "packets", NULL, "IPv4 Packets" - , "packets/s", 3000, update_every, RRDSET_TYPE_LINE); - - rrddim_add(st, "InReceives", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "OutRequests", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "ForwDatagrams", "forwarded", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "InDelivers", "delivered", 1, 1, RRD_ALGORITHM_INCREMENTAL); + static RRDSET *st = NULL; + static RRDDIM *rd_InReceives = NULL, + *rd_OutRequests = NULL, + *rd_ForwDatagrams = NULL, + *rd_InDelivers = NULL; + + if(unlikely(!st)) { + st = rrdset_create_localhost( + RRD_TYPE_NET_SNMP + , "packets" + , NULL + , "packets" + , NULL + , "IPv4 Packets" + , "packets/s" + , "proc" + , "net/snmp" + , 2450 + , update_every + , RRDSET_TYPE_LINE + ); + + rd_InReceives = rrddim_add(st, "InReceives", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_OutRequests = rrddim_add(st, "OutRequests", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_ForwDatagrams = rrddim_add(st, "ForwDatagrams", "forwarded", 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InDelivers = rrddim_add(st, "InDelivers", "delivered", 1, 1, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(st); - rrddim_set(st, "OutRequests", *ip_OutRequests); - rrddim_set(st, "InReceives", *ip_InReceives); - rrddim_set(st, "ForwDatagrams", *ip_ForwDatagrams); - rrddim_set(st, "InDelivers", *ip_InDelivers); + rrddim_set_by_pointer(st, rd_OutRequests, (collected_number)snmp_root.ip_OutRequests); + rrddim_set_by_pointer(st, rd_InReceives, (collected_number)snmp_root.ip_InReceives); + rrddim_set_by_pointer(st, rd_ForwDatagrams, (collected_number)snmp_root.ip_ForwDatagrams); + rrddim_set_by_pointer(st, rd_InDelivers, (collected_number)snmp_root.ip_InDelivers); rrdset_done(st); } // -------------------------------------------------------------------- if(do_ip_fragsout) { - st = rrdset_find_localhost(RRD_TYPE_NET_SNMP ".fragsout"); - if(!st) { - st = rrdset_create_localhost(RRD_TYPE_NET_SNMP, "fragsout", NULL, "fragments", NULL - , "IPv4 Fragments Sent", "packets/s", 3010, update_every - , RRDSET_TYPE_LINE); + static RRDSET *st = NULL; + static RRDDIM *rd_FragOKs = NULL, + *rd_FragFails = NULL, + *rd_FragCreates = NULL; + + if(unlikely(!st)) { + st = rrdset_create_localhost( + RRD_TYPE_NET_SNMP + , "fragsout" + , NULL + , "fragments" + , NULL + , "IPv4 Fragments Sent" + , "packets/s" + , "proc" + , "net/snmp" + , 3020 + , update_every + , RRDSET_TYPE_LINE + ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - rrddim_add(st, "FragOKs", "ok", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "FragFails", "failed", -1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "FragCreates", "created", 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_FragOKs = rrddim_add(st, "FragOKs", "ok", 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_FragFails = rrddim_add(st, "FragFails", "failed", -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_FragCreates = rrddim_add(st, "FragCreates", "created", 1, 1, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(st); - rrddim_set(st, "FragOKs", *ip_FragOKs); - rrddim_set(st, "FragFails", *ip_FragFails); - rrddim_set(st, "FragCreates", *ip_FragCreates); + rrddim_set_by_pointer(st, rd_FragOKs, (collected_number)snmp_root.ip_FragOKs); + rrddim_set_by_pointer(st, rd_FragFails, (collected_number)snmp_root.ip_FragFails); + rrddim_set_by_pointer(st, rd_FragCreates, (collected_number)snmp_root.ip_FragCreates); rrdset_done(st); } // -------------------------------------------------------------------- if(do_ip_fragsin) { - st = rrdset_find_localhost(RRD_TYPE_NET_SNMP ".fragsin"); - if(!st) { - st = rrdset_create_localhost(RRD_TYPE_NET_SNMP, "fragsin", NULL, "fragments", NULL - , "IPv4 Fragments Reassembly", "packets/s", 3011, update_every - , RRDSET_TYPE_LINE); + static RRDSET *st = NULL; + static RRDDIM *rd_ReasmOKs = NULL, + *rd_ReasmFails = NULL, + *rd_ReasmReqds = NULL; + + if(unlikely(!st)) { + st = rrdset_create_localhost( + RRD_TYPE_NET_SNMP + , "fragsin" + , NULL + , "fragments" + , NULL + , "IPv4 Fragments Reassembly" + , "packets/s" + , "proc" + , "net/snmp" + , 3030 + , update_every + , RRDSET_TYPE_LINE + ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - rrddim_add(st, "ReasmOKs", "ok", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "ReasmFails", "failed", -1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "ReasmReqds", "all", 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_ReasmOKs = rrddim_add(st, "ReasmOKs", "ok", 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_ReasmFails = rrddim_add(st, "ReasmFails", "failed", -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_ReasmReqds = rrddim_add(st, "ReasmReqds", "all", 1, 1, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(st); - rrddim_set(st, "ReasmOKs", *ip_ReasmOKs); - rrddim_set(st, "ReasmFails", *ip_ReasmFails); - rrddim_set(st, "ReasmReqds", *ip_ReasmReqds); + rrddim_set_by_pointer(st, rd_ReasmOKs, (collected_number)snmp_root.ip_ReasmOKs); + rrddim_set_by_pointer(st, rd_ReasmFails, (collected_number)snmp_root.ip_ReasmFails); + rrddim_set_by_pointer(st, rd_ReasmReqds, (collected_number)snmp_root.ip_ReasmReqds); rrdset_done(st); } // -------------------------------------------------------------------- if(do_ip_errors) { - st = rrdset_find_localhost(RRD_TYPE_NET_SNMP ".errors"); - if(!st) { - st = rrdset_create_localhost(RRD_TYPE_NET_SNMP, "errors", NULL, "errors", NULL, "IPv4 Errors" - , "packets/s", 3002, update_every, RRDSET_TYPE_LINE); + static RRDSET *st = NULL; + static RRDDIM *rd_InDiscards = NULL, + *rd_OutDiscards = NULL, + *rd_InHdrErrors = NULL, + *rd_OutNoRoutes = NULL, + *rd_InAddrErrors = NULL, + *rd_InUnknownProtos = NULL; + + if(unlikely(!st)) { + st = rrdset_create_localhost( + RRD_TYPE_NET_SNMP + , "errors" + , NULL + , "errors" + , NULL + , "IPv4 Errors" + , "packets/s" + , "proc" + , "net/snmp" + , 2470 + , update_every + , RRDSET_TYPE_LINE + ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - rrddim_add(st, "InDiscards", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "OutDiscards", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InDiscards = rrddim_add(st, "InDiscards", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_OutDiscards = rrddim_add(st, "OutDiscards", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "InHdrErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "OutNoRoutes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InHdrErrors = rrddim_add(st, "InHdrErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_OutNoRoutes = rrddim_add(st, "OutNoRoutes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "InAddrErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "InUnknownProtos", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InAddrErrors = rrddim_add(st, "InAddrErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InUnknownProtos = rrddim_add(st, "InUnknownProtos", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(st); - rrddim_set(st, "InDiscards", *ip_InDiscards); - rrddim_set(st, "OutDiscards", *ip_OutDiscards); - rrddim_set(st, "InHdrErrors", *ip_InHdrErrors); - rrddim_set(st, "InAddrErrors", *ip_InAddrErrors); - rrddim_set(st, "InUnknownProtos", *ip_InUnknownProtos); - rrddim_set(st, "OutNoRoutes", *ip_OutNoRoutes); + rrddim_set_by_pointer(st, rd_InDiscards, (collected_number)snmp_root.ip_InDiscards); + rrddim_set_by_pointer(st, rd_OutDiscards, (collected_number)snmp_root.ip_OutDiscards); + rrddim_set_by_pointer(st, rd_InHdrErrors, (collected_number)snmp_root.ip_InHdrErrors); + rrddim_set_by_pointer(st, rd_InAddrErrors, (collected_number)snmp_root.ip_InAddrErrors); + rrddim_set_by_pointer(st, rd_InUnknownProtos, (collected_number)snmp_root.ip_InUnknownProtos); + rrddim_set_by_pointer(st, rd_OutNoRoutes, (collected_number)snmp_root.ip_OutNoRoutes); rrdset_done(st); } } @@ -498,43 +428,81 @@ int do_proc_net_snmp(int update_every, usec_t dt) { continue; } - parse_line_pair(ff, icmp_data, h, l); + arl_begin(arl_icmp); + for(w = 1; w < words ; w++) { + if (unlikely(arl_check(arl_icmp, procfile_lineword(ff, h, w), procfile_lineword(ff, l, w)) != 0)) + break; + } // -------------------------------------------------------------------- if(do_icmp_packets) { - st = rrdset_find_localhost(RRD_TYPE_NET_SNMP ".icmp"); - if(!st) { - st = rrdset_create_localhost(RRD_TYPE_NET_SNMP, "icmp", NULL, "icmp", NULL, "IPv4 ICMP Packets" - , "packets/s", 2602, update_every, RRDSET_TYPE_LINE); - - rrddim_add(st, "InMsgs", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "OutMsgs", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL); + { + static RRDSET *st_packets = NULL; + static RRDDIM *rd_InMsgs = NULL, + *rd_OutMsgs = NULL; + + if(unlikely(!st_packets)) { + st_packets = rrdset_create_localhost( + RRD_TYPE_NET_SNMP + , "icmp" + , NULL + , "icmp" + , NULL + , "IPv4 ICMP Packets" + , "packets/s" + , "proc" + , "net/snmp" + , 2602 + , update_every + , RRDSET_TYPE_LINE + ); + + rd_InMsgs = rrddim_add(st_packets, "InMsgs", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_OutMsgs = rrddim_add(st_packets, "OutMsgs", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL); + } + else rrdset_next(st_packets); + + rrddim_set_by_pointer(st_packets, rd_InMsgs, (collected_number)snmp_root.icmp_InMsgs); + rrddim_set_by_pointer(st_packets, rd_OutMsgs, (collected_number)snmp_root.icmp_OutMsgs); + + rrdset_done(st_packets); } - else rrdset_next(st); - - rrddim_set(st, "InMsgs", *icmp_InMsgs); - rrddim_set(st, "OutMsgs", *icmp_OutMsgs); - - rrdset_done(st); - - st = rrdset_find_localhost(RRD_TYPE_NET_SNMP ".icmp_errors"); - if(!st) { - st = rrdset_create_localhost(RRD_TYPE_NET_SNMP, "icmp_errors", NULL, "icmp", NULL - , "IPv4 ICMP Errors", "packets/s", 2603, update_every - , RRDSET_TYPE_LINE); - rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "OutErrors", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + { + static RRDSET *st_errors = NULL; + static RRDDIM *rd_InErrors = NULL, + *rd_OutErrors = NULL, + *rd_InCsumErrors = NULL; + + if(unlikely(!st_errors)) { + st_errors = rrdset_create_localhost( + RRD_TYPE_NET_SNMP + , "icmp_errors" + , NULL + , "icmp" + , NULL + , "IPv4 ICMP Errors" + , "packets/s" + , "proc" + , "net/snmp" + , 2603 + , update_every + , RRDSET_TYPE_LINE + ); + + rd_InErrors = rrddim_add(st_errors, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_OutErrors = rrddim_add(st_errors, "OutErrors", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InCsumErrors = rrddim_add(st_errors, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + } + else rrdset_next(st_errors); + + rrddim_set_by_pointer(st_errors, rd_InErrors, (collected_number)snmp_root.icmp_InErrors); + rrddim_set_by_pointer(st_errors, rd_OutErrors, (collected_number)snmp_root.icmp_OutErrors); + rrddim_set_by_pointer(st_errors, rd_InCsumErrors, (collected_number)snmp_root.icmp_InCsumErrors); + + rrdset_done(st_errors); } - else rrdset_next(st); - - rrddim_set(st, "InErrors", *icmp_InErrors); - rrddim_set(st, "OutErrors", *icmp_OutErrors); - rrddim_set(st, "InCsumErrors", *icmp_InCsumErrors); - - rrdset_done(st); } } else if(unlikely(hash == hash_icmpmsg && strcmp(key, "IcmpMsg") == 0)) { @@ -545,25 +513,102 @@ int do_proc_net_snmp(int update_every, usec_t dt) { break; } - parse_line_pair(ff, icmpmsg_data, h, l); + words = procfile_linewords(ff, l); + if(words < 3) { + error("Cannot read /proc/net/snmp IcmpMsg line. Expected 3+ params, read %zu.", words); + continue; + } + + arl_begin(arl_icmpmsg); + for(w = 1; w < words ; w++) { + if (unlikely(arl_check(arl_icmpmsg, procfile_lineword(ff, h, w), procfile_lineword(ff, l, w)) != 0)) + break; + } // -------------------------------------------------------------------- if(do_icmpmsg) { - int i; - - st = rrdset_find_localhost(RRD_TYPE_NET_SNMP ".icmpmsg"); - if(!st) { - st = rrdset_create_localhost(RRD_TYPE_NET_SNMP, "icmpmsg", NULL, "icmp", NULL, "IPv4 ICMP Messages" - , "packets/s", 2604, update_every, RRDSET_TYPE_LINE); + static RRDSET *st = NULL; + static RRDDIM *rd_InEchoReps = NULL, + *rd_OutEchoReps = NULL, + *rd_InDestUnreachs = NULL, + *rd_OutDestUnreachs = NULL, + *rd_InRedirects = NULL, + *rd_OutRedirects = NULL, + *rd_InEchos = NULL, + *rd_OutEchos = NULL, + *rd_InRouterAdvert = NULL, + *rd_OutRouterAdvert = NULL, + *rd_InRouterSelect = NULL, + *rd_OutRouterSelect = NULL, + *rd_InTimeExcds = NULL, + *rd_OutTimeExcds = NULL, + *rd_InParmProbs = NULL, + *rd_OutParmProbs = NULL, + *rd_InTimestamps = NULL, + *rd_OutTimestamps = NULL, + *rd_InTimestampReps = NULL, + *rd_OutTimestampReps = NULL; + + if(unlikely(!st)) { + st = rrdset_create_localhost( + RRD_TYPE_NET_SNMP + , "icmpmsg" + , NULL + , "icmp" + , NULL + , "IPv4 ICMP Messages" + , "packets/s" + , "proc" + , "net/snmp" + , 2604 + , update_every + , RRDSET_TYPE_LINE + ); - for(i = 0; icmpmsg_data[i].name ;i++) - rrddim_add(st, icmpmsg_data[i].name, icmpmsg_data[i].label, icmpmsg_data[i].multiplier, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InEchoReps = rrddim_add(st, "InType0", "InEchoReps", 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_OutEchoReps = rrddim_add(st, "OutType0", "OutEchoReps", -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InDestUnreachs = rrddim_add(st, "InType3", "InDestUnreachs", 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_OutDestUnreachs = rrddim_add(st, "OutType3", "OutDestUnreachs", -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InRedirects = rrddim_add(st, "InType5", "InRedirects", 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_OutRedirects = rrddim_add(st, "OutType5", "OutRedirects", -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InEchos = rrddim_add(st, "InType8", "InEchos", 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_OutEchos = rrddim_add(st, "OutType8", "OutEchos", -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InRouterAdvert = rrddim_add(st, "InType9", "InRouterAdvert", 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_OutRouterAdvert = rrddim_add(st, "OutType9", "OutRouterAdvert", -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InRouterSelect = rrddim_add(st, "InType10", "InRouterSelect", 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_OutRouterSelect = rrddim_add(st, "OutType10", "OutRouterSelect", -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InTimeExcds = rrddim_add(st, "InType11", "InTimeExcds", 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_OutTimeExcds = rrddim_add(st, "OutType11", "OutTimeExcds", -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InParmProbs = rrddim_add(st, "InType12", "InParmProbs", 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_OutParmProbs = rrddim_add(st, "OutType12", "OutParmProbs", -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InTimestamps = rrddim_add(st, "InType13", "InTimestamps", 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_OutTimestamps = rrddim_add(st, "OutType13", "OutTimestamps", -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InTimestampReps = rrddim_add(st, "InType14", "InTimestampReps", 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_OutTimestampReps = rrddim_add(st, "OutType14", "OutTimestampReps", -1, 1, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(st); - for(i = 0; icmpmsg_data[i].name ;i++) - rrddim_set(st, icmpmsg_data[i].name, icmpmsg_data[i].value); + rrddim_set_by_pointer(st, rd_InEchoReps, (collected_number)snmp_root.icmpmsg_InEchoReps); + rrddim_set_by_pointer(st, rd_OutEchoReps, (collected_number)snmp_root.icmpmsg_OutEchoReps); + rrddim_set_by_pointer(st, rd_InDestUnreachs, (collected_number)snmp_root.icmpmsg_InDestUnreachs); + rrddim_set_by_pointer(st, rd_OutDestUnreachs, (collected_number)snmp_root.icmpmsg_OutDestUnreachs); + rrddim_set_by_pointer(st, rd_InRedirects, (collected_number)snmp_root.icmpmsg_InRedirects); + rrddim_set_by_pointer(st, rd_OutRedirects, (collected_number)snmp_root.icmpmsg_OutRedirects); + rrddim_set_by_pointer(st, rd_InEchos, (collected_number)snmp_root.icmpmsg_InEchos); + rrddim_set_by_pointer(st, rd_OutEchos, (collected_number)snmp_root.icmpmsg_OutEchos); + rrddim_set_by_pointer(st, rd_InRouterAdvert, (collected_number)snmp_root.icmpmsg_InRouterAdvert); + rrddim_set_by_pointer(st, rd_OutRouterAdvert, (collected_number)snmp_root.icmpmsg_OutRouterAdvert); + rrddim_set_by_pointer(st, rd_InRouterSelect, (collected_number)snmp_root.icmpmsg_InRouterSelect); + rrddim_set_by_pointer(st, rd_OutRouterSelect, (collected_number)snmp_root.icmpmsg_OutRouterSelect); + rrddim_set_by_pointer(st, rd_InTimeExcds, (collected_number)snmp_root.icmpmsg_InTimeExcds); + rrddim_set_by_pointer(st, rd_OutTimeExcds, (collected_number)snmp_root.icmpmsg_OutTimeExcds); + rrddim_set_by_pointer(st, rd_InParmProbs, (collected_number)snmp_root.icmpmsg_InParmProbs); + rrddim_set_by_pointer(st, rd_OutParmProbs, (collected_number)snmp_root.icmpmsg_OutParmProbs); + rrddim_set_by_pointer(st, rd_InTimestamps, (collected_number)snmp_root.icmpmsg_InTimestamps); + rrddim_set_by_pointer(st, rd_OutTimestamps, (collected_number)snmp_root.icmpmsg_OutTimestamps); + rrddim_set_by_pointer(st, rd_InTimestampReps, (collected_number)snmp_root.icmpmsg_InTimestampReps); + rrddim_set_by_pointer(st, rd_OutTimestampReps, (collected_number)snmp_root.icmpmsg_OutTimestampReps); rrdset_done(st); } @@ -582,69 +627,132 @@ int do_proc_net_snmp(int update_every, usec_t dt) { continue; } - parse_line_pair(ff, tcp_data, h, l); + arl_begin(arl_tcp); + for(w = 1; w < words ; w++) { + if (unlikely(arl_check(arl_tcp, procfile_lineword(ff, h, w), procfile_lineword(ff, l, w)) != 0)) + break; + } + + // -------------------------------------------------------------------- + + if(snmp_root.tcp_MaxConn != last_max_connections) { + last_max_connections = snmp_root.tcp_MaxConn; + rrdvar_custom_host_variable_set(localhost, tcp_max_connections_var, last_max_connections); + } // -------------------------------------------------------------------- // see http://net-snmp.sourceforge.net/docs/mibs/tcp.html if(do_tcp_sockets) { - st = rrdset_find_localhost(RRD_TYPE_NET_SNMP ".tcpsock"); - if(!st) { - st = rrdset_create_localhost(RRD_TYPE_NET_SNMP, "tcpsock", NULL, "tcp", NULL, "IPv4 TCP Connections" - , "active connections", 2500, update_every, RRDSET_TYPE_LINE); + static RRDSET *st = NULL; + static RRDDIM *rd_CurrEstab = NULL; - rrddim_add(st, "CurrEstab", "connections", 1, 1, RRD_ALGORITHM_ABSOLUTE); + if(unlikely(!st)) { + st = rrdset_create_localhost( + RRD_TYPE_NET_SNMP + , "tcpsock" + , NULL + , "tcp" + , NULL + , "IPv4 TCP Connections" + , "active connections" + , "proc" + , "net/snmp" + , 2501 + , update_every + , RRDSET_TYPE_LINE + ); + + rd_CurrEstab = rrddim_add(st, "CurrEstab", "connections", 1, 1, RRD_ALGORITHM_ABSOLUTE); } else rrdset_next(st); - rrddim_set(st, "CurrEstab", *tcp_CurrEstab); + rrddim_set_by_pointer(st, rd_CurrEstab, (collected_number)snmp_root.tcp_CurrEstab); rrdset_done(st); } // -------------------------------------------------------------------- if(do_tcp_packets) { - st = rrdset_find_localhost(RRD_TYPE_NET_SNMP ".tcppackets"); - if(!st) { - st = rrdset_create_localhost(RRD_TYPE_NET_SNMP, "tcppackets", NULL, "tcp", NULL, "IPv4 TCP Packets" - , "packets/s", 2600, update_every, RRDSET_TYPE_LINE); + static RRDSET *st = NULL; + static RRDDIM *rd_InSegs = NULL, + *rd_OutSegs = NULL; + + if(unlikely(!st)) { + st = rrdset_create_localhost( + RRD_TYPE_NET_SNMP + , "tcppackets" + , NULL + , "tcp" + , NULL + , "IPv4 TCP Packets" + , "packets/s" + , "proc" + , "net/snmp" + , 2510 + , update_every + , RRDSET_TYPE_LINE + ); - rrddim_add(st, "InSegs", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "OutSegs", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InSegs = rrddim_add(st, "InSegs", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_OutSegs = rrddim_add(st, "OutSegs", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(st); - rrddim_set(st, "InSegs", *tcp_InSegs); - rrddim_set(st, "OutSegs", *tcp_OutSegs); + rrddim_set_by_pointer(st, rd_InSegs, (collected_number)snmp_root.tcp_InSegs); + rrddim_set_by_pointer(st, rd_OutSegs, (collected_number)snmp_root.tcp_OutSegs); rrdset_done(st); } // -------------------------------------------------------------------- if(do_tcp_errors) { - st = rrdset_find_localhost(RRD_TYPE_NET_SNMP ".tcperrors"); - if(!st) { - st = rrdset_create_localhost(RRD_TYPE_NET_SNMP, "tcperrors", NULL, "tcp", NULL, "IPv4 TCP Errors" - , "packets/s", 2700, update_every, RRDSET_TYPE_LINE); + static RRDSET *st = NULL; + static RRDDIM *rd_InErrs = NULL, + *rd_InCsumErrors = NULL, + *rd_RetransSegs = NULL; + + if(unlikely(!st)) { + st = rrdset_create_localhost( + RRD_TYPE_NET_SNMP + , "tcperrors" + , NULL + , "tcp" + , NULL + , "IPv4 TCP Errors" + , "packets/s" + , "proc" + , "net/snmp" + , 2520 + , update_every + , RRDSET_TYPE_LINE + ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - rrddim_add(st, "InErrs", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "RetransSegs", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InErrs = rrddim_add(st, "InErrs", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InCsumErrors = rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_RetransSegs = rrddim_add(st, "RetransSegs", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(st); - rrddim_set(st, "InErrs", *tcp_InErrs); - rrddim_set(st, "InCsumErrors", *tcp_InCsumErrors); - rrddim_set(st, "RetransSegs", *tcp_RetransSegs); + rrddim_set_by_pointer(st, rd_InErrs, (collected_number)snmp_root.tcp_InErrs); + rrddim_set_by_pointer(st, rd_InCsumErrors, (collected_number)snmp_root.tcp_InCsumErrors); + rrddim_set_by_pointer(st, rd_RetransSegs, (collected_number)snmp_root.tcp_RetransSegs); rrdset_done(st); } // -------------------------------------------------------------------- if(do_tcp_handshake) { - st = rrdset_find_localhost(RRD_TYPE_NET_SNMP ".tcphandshake"); - if(!st) { + static RRDSET *st = NULL; + static RRDDIM *rd_EstabResets = NULL, + *rd_OutRsts = NULL, + *rd_ActiveOpens = NULL, + *rd_PassiveOpens = NULL, + *rd_AttemptFails = NULL, + *rd_TCPSynRetrans = NULL; + + if(unlikely(!st)) { st = rrdset_create_localhost( RRD_TYPE_NET_SNMP , "tcphandshake" @@ -653,27 +761,29 @@ int do_proc_net_snmp(int update_every, usec_t dt) { , NULL , "IPv4 TCP Handshake Issues" , "events/s" - , 2900 + , "proc" + , "net/snmp" + , 2530 , update_every , RRDSET_TYPE_LINE ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - rrddim_add(st, "EstabResets", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "OutRsts", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "ActiveOpens", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "PassiveOpens", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "AttemptFails", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "TCPSynRetrans", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_EstabResets = rrddim_add(st, "EstabResets", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_OutRsts = rrddim_add(st, "OutRsts", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_ActiveOpens = rrddim_add(st, "ActiveOpens", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_PassiveOpens = rrddim_add(st, "PassiveOpens", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_AttemptFails = rrddim_add(st, "AttemptFails", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_TCPSynRetrans = rrddim_add(st, "TCPSynRetrans", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(st); - rrddim_set(st, "EstabResets", *tcp_EstabResets); - rrddim_set(st, "OutRsts", *tcp_OutRsts); - rrddim_set(st, "ActiveOpens", *tcp_ActiveOpens); - rrddim_set(st, "PassiveOpens", *tcp_PassiveOpens); - rrddim_set(st, "AttemptFails", *tcp_AttemptFails); - rrddim_set(st, "TCPSynRetrans", tcpext_TCPSynRetrans); + rrddim_set_by_pointer(st, rd_EstabResets, (collected_number)snmp_root.tcp_EstabResets); + rrddim_set_by_pointer(st, rd_OutRsts, (collected_number)snmp_root.tcp_OutRsts); + rrddim_set_by_pointer(st, rd_ActiveOpens, (collected_number)snmp_root.tcp_ActiveOpens); + rrddim_set_by_pointer(st, rd_PassiveOpens, (collected_number)snmp_root.tcp_PassiveOpens); + rrddim_set_by_pointer(st, rd_AttemptFails, (collected_number)snmp_root.tcp_AttemptFails); + rrddim_set_by_pointer(st, rd_TCPSynRetrans, tcpext_TCPSynRetrans); rrdset_done(st); } } @@ -691,51 +801,89 @@ int do_proc_net_snmp(int update_every, usec_t dt) { continue; } - parse_line_pair(ff, udp_data, h, l); + arl_begin(arl_udp); + for(w = 1; w < words ; w++) { + if (unlikely(arl_check(arl_udp, procfile_lineword(ff, h, w), procfile_lineword(ff, l, w)) != 0)) + break; + } // -------------------------------------------------------------------- // see http://net-snmp.sourceforge.net/docs/mibs/udp.html if(do_udp_packets) { - st = rrdset_find_localhost(RRD_TYPE_NET_SNMP ".udppackets"); - if(!st) { - st = rrdset_create_localhost(RRD_TYPE_NET_SNMP, "udppackets", NULL, "udp", NULL, "IPv4 UDP Packets" - , "packets/s", 2601, update_every, RRDSET_TYPE_LINE); + static RRDSET *st = NULL; + static RRDDIM *rd_InDatagrams = NULL, + *rd_OutDatagrams = NULL; - rrddim_add(st, "InDatagrams", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "OutDatagrams", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL); + if(unlikely(!st)) { + st = rrdset_create_localhost( + RRD_TYPE_NET_SNMP + , "udppackets" + , NULL + , "udp" + , NULL + , "IPv4 UDP Packets" + , "packets/s" + , "proc" + , "net/snmp" + , 2602 + , update_every + , RRDSET_TYPE_LINE + ); + + rd_InDatagrams = rrddim_add(st, "InDatagrams", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_OutDatagrams = rrddim_add(st, "OutDatagrams", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(st); - rrddim_set(st, "InDatagrams", *udp_InDatagrams); - rrddim_set(st, "OutDatagrams", *udp_OutDatagrams); + rrddim_set_by_pointer(st, rd_InDatagrams, (collected_number)snmp_root.udp_InDatagrams); + rrddim_set_by_pointer(st, rd_OutDatagrams, (collected_number)snmp_root.udp_OutDatagrams); rrdset_done(st); } // -------------------------------------------------------------------- if(do_udp_errors) { - st = rrdset_find_localhost(RRD_TYPE_NET_SNMP ".udperrors"); - if(!st) { - st = rrdset_create_localhost(RRD_TYPE_NET_SNMP, "udperrors", NULL, "udp", NULL, "IPv4 UDP Errors" - , "events/s", 2701, update_every, RRDSET_TYPE_LINE); + static RRDSET *st = NULL; + static RRDDIM *rd_RcvbufErrors = NULL, + *rd_SndbufErrors = NULL, + *rd_InErrors = NULL, + *rd_NoPorts = NULL, + *rd_InCsumErrors = NULL, + *rd_IgnoredMulti = NULL; + + if(unlikely(!st)) { + st = rrdset_create_localhost( + RRD_TYPE_NET_SNMP + , "udperrors" + , NULL + , "udp" + , NULL + , "IPv4 UDP Errors" + , "events/s" + , "proc" + , "net/snmp" + , 2701 + , update_every + , RRDSET_TYPE_LINE + ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "SndbufErrors", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "NoPorts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "IgnoredMulti", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_RcvbufErrors = rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_SndbufErrors = rrddim_add(st, "SndbufErrors", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InErrors = rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_NoPorts = rrddim_add(st, "NoPorts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InCsumErrors = rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_IgnoredMulti = rrddim_add(st, "IgnoredMulti", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(st); - rrddim_set(st, "InErrors", *udp_InErrors); - rrddim_set(st, "NoPorts", *udp_NoPorts); - rrddim_set(st, "RcvbufErrors", *udp_RcvbufErrors); - rrddim_set(st, "SndbufErrors", *udp_SndbufErrors); - rrddim_set(st, "InCsumErrors", *udp_InCsumErrors); - rrddim_set(st, "IgnoredMulti", *udp_IgnoredMulti); + rrddim_set_by_pointer(st, rd_InErrors, (collected_number)snmp_root.udp_InErrors); + rrddim_set_by_pointer(st, rd_NoPorts, (collected_number)snmp_root.udp_NoPorts); + rrddim_set_by_pointer(st, rd_RcvbufErrors, (collected_number)snmp_root.udp_RcvbufErrors); + rrddim_set_by_pointer(st, rd_SndbufErrors, (collected_number)snmp_root.udp_SndbufErrors); + rrddim_set_by_pointer(st, rd_InCsumErrors, (collected_number)snmp_root.udp_InCsumErrors); + rrddim_set_by_pointer(st, rd_IgnoredMulti, (collected_number)snmp_root.udp_IgnoredMulti); rrdset_done(st); } } @@ -753,48 +901,87 @@ int do_proc_net_snmp(int update_every, usec_t dt) { continue; } - parse_line_pair(ff, udplite_data, h, l); + arl_begin(arl_udplite); + for(w = 1; w < words ; w++) { + if (unlikely(arl_check(arl_udplite, procfile_lineword(ff, h, w), procfile_lineword(ff, l, w)) != 0)) + break; + } // -------------------------------------------------------------------- if(do_udplite_packets) { - st = rrdset_find_localhost(RRD_TYPE_NET_SNMP ".udplite"); - if(!st) { - st = rrdset_create_localhost(RRD_TYPE_NET_SNMP, "udplite", NULL, "udplite", NULL - , "IPv4 UDPLite Packets", "packets/s", 2603, update_every - , RRDSET_TYPE_LINE); - - rrddim_add(st, "InDatagrams", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "OutDatagrams", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL); + { + static RRDSET *st = NULL; + static RRDDIM *rd_InDatagrams = NULL, + *rd_OutDatagrams = NULL; + + if(unlikely(!st)) { + st = rrdset_create_localhost( + RRD_TYPE_NET_SNMP + , "udplite" + , NULL + , "udplite" + , NULL + , "IPv4 UDPLite Packets" + , "packets/s" + , "proc" + , "net/snmp" + , 2603 + , update_every + , RRDSET_TYPE_LINE + ); + + rd_InDatagrams = rrddim_add(st, "InDatagrams", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_OutDatagrams = rrddim_add(st, "OutDatagrams", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL); + } + else rrdset_next(st); + + rrddim_set_by_pointer(st, rd_InDatagrams, (collected_number)snmp_root.udplite_InDatagrams); + rrddim_set_by_pointer(st, rd_OutDatagrams, (collected_number)snmp_root.udplite_OutDatagrams); + rrdset_done(st); } - else rrdset_next(st); - - rrddim_set(st, "InDatagrams", *udplite_InDatagrams); - rrddim_set(st, "OutDatagrams", *udplite_OutDatagrams); - rrdset_done(st); - st = rrdset_find_localhost(RRD_TYPE_NET_SNMP ".udplite_errors"); - if(!st) { - st = rrdset_create_localhost(RRD_TYPE_NET_SNMP, "udplite_errors", NULL, "udplite", NULL - , "IPv4 UDPLite Errors", "packets/s", 2604, update_every - , RRDSET_TYPE_LINE); - - rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "SndbufErrors", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "NoPorts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "IgnoredMulti", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + { + static RRDSET *st = NULL; + static RRDDIM *rd_RcvbufErrors = NULL, + *rd_SndbufErrors = NULL, + *rd_InErrors = NULL, + *rd_NoPorts = NULL, + *rd_InCsumErrors = NULL, + *rd_IgnoredMulti = NULL; + + if(unlikely(!st)) { + st = rrdset_create_localhost( + RRD_TYPE_NET_SNMP + , "udplite_errors" + , NULL + , "udplite" + , NULL + , "IPv4 UDPLite Errors" + , "packets/s" + , "proc" + , "net/snmp" + , 2604 + , update_every + , RRDSET_TYPE_LINE); + + rd_RcvbufErrors = rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_SndbufErrors = rrddim_add(st, "SndbufErrors", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InErrors = rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_NoPorts = rrddim_add(st, "NoPorts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InCsumErrors = rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_IgnoredMulti = rrddim_add(st, "IgnoredMulti", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + } + else rrdset_next(st); + + rrddim_set_by_pointer(st, rd_NoPorts, (collected_number)snmp_root.udplite_NoPorts); + rrddim_set_by_pointer(st, rd_InErrors, (collected_number)snmp_root.udplite_InErrors); + rrddim_set_by_pointer(st, rd_InCsumErrors, (collected_number)snmp_root.udplite_InCsumErrors); + rrddim_set_by_pointer(st, rd_RcvbufErrors, (collected_number)snmp_root.udplite_RcvbufErrors); + rrddim_set_by_pointer(st, rd_SndbufErrors, (collected_number)snmp_root.udplite_SndbufErrors); + rrddim_set_by_pointer(st, rd_IgnoredMulti, (collected_number)snmp_root.udplite_IgnoredMulti); + rrdset_done(st); } - else rrdset_next(st); - - rrddim_set(st, "NoPorts", *udplite_NoPorts); - rrddim_set(st, "InErrors", *udplite_InErrors); - rrddim_set(st, "InCsumErrors", *udplite_InCsumErrors); - rrddim_set(st, "RcvbufErrors", *udplite_RcvbufErrors); - rrddim_set(st, "SndbufErrors", *udplite_SndbufErrors); - rrddim_set(st, "IgnoredMulti", *udplite_IgnoredMulti); - rrdset_done(st); } } } diff --git a/src/proc_net_snmp6.c b/src/proc_net_snmp6.c index 6649b7af..bd71b391 100644 --- a/src/proc_net_snmp6.c +++ b/src/proc_net_snmp6.c @@ -272,24 +272,37 @@ int do_proc_net_snmp6(int update_every, usec_t dt) { procfile_lineword(ff, l, 1)))) break; } - RRDSET *st; - // -------------------------------------------------------------------- if(do_bandwidth == CONFIG_BOOLEAN_YES || (do_bandwidth == CONFIG_BOOLEAN_AUTO && (Ip6InOctets || Ip6OutOctets))) { do_bandwidth = CONFIG_BOOLEAN_YES; - st = rrdset_find_localhost("system.ipv6"); - if(unlikely(!st)) { - st = rrdset_create_localhost("system", "ipv6", NULL, "network", NULL, "IPv6 Bandwidth", "kilobits/s", 500 - , update_every, RRDSET_TYPE_AREA); + static RRDSET *st = NULL; + static RRDDIM *rd_received = NULL, + *rd_sent = NULL; - rrddim_add(st, "received", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "sent", NULL, -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); + if(unlikely(!st)) { + st = rrdset_create_localhost( + "system" + , "ipv6" + , NULL + , "network" + , NULL + , "IPv6 Bandwidth" + , "kilobits/s" + , "proc" + , "net/snmp6" + , 502 + , update_every + , RRDSET_TYPE_AREA + ); + + rd_received = rrddim_add(st, "InOctets", "received", 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); + rd_sent = rrddim_add(st, "OutOctets", "sent", -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(st); - rrddim_set(st, "sent", Ip6OutOctets); - rrddim_set(st, "received", Ip6InOctets); + rrddim_set_by_pointer(st, rd_received, Ip6InOctets); + rrddim_set_by_pointer(st, rd_sent, Ip6OutOctets); rrdset_done(st); } @@ -297,22 +310,39 @@ int do_proc_net_snmp6(int update_every, usec_t dt) { if(do_ip_packets == CONFIG_BOOLEAN_YES || (do_ip_packets == CONFIG_BOOLEAN_AUTO && (Ip6InReceives || Ip6OutRequests || Ip6InDelivers || Ip6OutForwDatagrams))) { do_ip_packets = CONFIG_BOOLEAN_YES; - st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".packets"); - if(unlikely(!st)) { - st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "packets", NULL, "packets", NULL, "IPv6 Packets" - , "packets/s", 3000, update_every, RRDSET_TYPE_LINE); + static RRDSET *st = NULL; + static RRDDIM *rd_received = NULL, + *rd_sent = NULL, + *rd_forwarded = NULL, + *rd_delivers = NULL; - rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "forwarded", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "delivers", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + if(unlikely(!st)) { + st = rrdset_create_localhost( + RRD_TYPE_NET_SNMP6 + , "packets" + , NULL + , "packets" + , NULL + , "IPv6 Packets" + , "packets/s" + , "proc" + , "net/snmp6" + , 3000 + , update_every + , RRDSET_TYPE_LINE + ); + + rd_received = rrddim_add(st, "InReceives", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_sent = rrddim_add(st, "OutRequests", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_forwarded = rrddim_add(st, "OutForwDatagrams", "forwarded", -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_delivers = rrddim_add(st, "InDelivers", "delivers", 1, 1, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(st); - rrddim_set(st, "sent", Ip6OutRequests); - rrddim_set(st, "received", Ip6InReceives); - rrddim_set(st, "forwarded", Ip6OutForwDatagrams); - rrddim_set(st, "delivers", Ip6InDelivers); + rrddim_set_by_pointer(st, rd_received, Ip6InReceives); + rrddim_set_by_pointer(st, rd_sent, Ip6OutRequests); + rrddim_set_by_pointer(st, rd_forwarded, Ip6OutForwDatagrams); + rrddim_set_by_pointer(st, rd_delivers, Ip6InDelivers); rrdset_done(st); } @@ -320,21 +350,37 @@ int do_proc_net_snmp6(int update_every, usec_t dt) { if(do_ip_fragsout == CONFIG_BOOLEAN_YES || (do_ip_fragsout == CONFIG_BOOLEAN_AUTO && (Ip6FragOKs || Ip6FragFails || Ip6FragCreates))) { do_ip_fragsout = CONFIG_BOOLEAN_YES; - st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".fragsout"); + static RRDSET *st = NULL; + static RRDDIM *rd_ok = NULL, + *rd_failed = NULL, + *rd_all = NULL; + if(unlikely(!st)) { - st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "fragsout", NULL, "fragments", NULL, "IPv6 Fragments Sent" - , "packets/s", 3010, update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + RRD_TYPE_NET_SNMP6 + , "fragsout" + , NULL + , "fragments6" + , NULL + , "IPv6 Fragments Sent" + , "packets/s" + , "proc" + , "net/snmp6" + , 3011 + , update_every + , RRDSET_TYPE_LINE + ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - rrddim_add(st, "ok", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "failed", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "all", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_ok = rrddim_add(st, "FragOKs", "ok", 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_failed = rrddim_add(st, "FragFails", "failed", -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_all = rrddim_add(st, "FragCreates", "all", 1, 1, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(st); - rrddim_set(st, "ok", Ip6FragOKs); - rrddim_set(st, "failed", Ip6FragFails); - rrddim_set(st, "all", Ip6FragCreates); + rrddim_set_by_pointer(st, rd_ok, Ip6FragOKs); + rrddim_set_by_pointer(st, rd_failed, Ip6FragFails); + rrddim_set_by_pointer(st, rd_all, Ip6FragCreates); rrdset_done(st); } @@ -348,24 +394,40 @@ int do_proc_net_snmp6(int update_every, usec_t dt) { || Ip6ReasmReqds ))) { do_ip_fragsin = CONFIG_BOOLEAN_YES; - st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".fragsin"); + + static RRDSET *st = NULL; + static RRDDIM *rd_ok = NULL, + *rd_failed = NULL, + *rd_timeout = NULL, + *rd_all = NULL; + if(unlikely(!st)) { - st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "fragsin", NULL, "fragments", NULL - , "IPv6 Fragments Reassembly", "packets/s", 3011, update_every - , RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + RRD_TYPE_NET_SNMP6 + , "fragsin" + , NULL + , "fragments6" + , NULL + , "IPv6 Fragments Reassembly" + , "packets/s" + , "proc" + , "net/snmp6" + , 3012 + , update_every + , RRDSET_TYPE_LINE); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - rrddim_add(st, "ok", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "failed", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "timeout", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "all", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_ok = rrddim_add(st, "ReasmOKs", "ok", 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_failed = rrddim_add(st, "ReasmFails", "failed", -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_timeout = rrddim_add(st, "ReasmTimeout", "timeout", -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_all = rrddim_add(st, "ReasmReqds", "all", 1, 1, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(st); - rrddim_set(st, "ok", Ip6ReasmOKs); - rrddim_set(st, "failed", Ip6ReasmFails); - rrddim_set(st, "timeout", Ip6ReasmTimeout); - rrddim_set(st, "all", Ip6ReasmReqds); + rrddim_set_by_pointer(st, rd_ok, Ip6ReasmOKs); + rrddim_set_by_pointer(st, rd_failed, Ip6ReasmFails); + rrddim_set_by_pointer(st, rd_timeout, Ip6ReasmTimeout); + rrddim_set_by_pointer(st, rd_all, Ip6ReasmReqds); rrdset_done(st); } @@ -383,37 +445,55 @@ int do_proc_net_snmp6(int update_every, usec_t dt) { || Ip6InNoRoutes ))) { do_ip_errors = CONFIG_BOOLEAN_YES; - st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".errors"); + static RRDSET *st = NULL; + static RRDDIM *rd_InDiscards = NULL, + *rd_OutDiscards = NULL, + *rd_InHdrErrors = NULL, + *rd_InAddrErrors = NULL, + *rd_InUnknownProtos = NULL, + *rd_InTooBigErrors = NULL, + *rd_InTruncatedPkts = NULL, + *rd_InNoRoutes = NULL, + *rd_OutNoRoutes = NULL; + if(unlikely(!st)) { - st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "errors", NULL, "errors", NULL, "IPv6 Errors", "packets/s" - , 3002, update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + RRD_TYPE_NET_SNMP6 + , "errors" + , NULL + , "errors" + , NULL + , "IPv6 Errors" + , "packets/s" + , "proc" + , "net/snmp6" + , 3002 + , update_every + , RRDSET_TYPE_LINE + ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - rrddim_add(st, "InDiscards", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "OutDiscards", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - - rrddim_add(st, "InHdrErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "InAddrErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "InUnknownProtos", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "InTooBigErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "InTruncatedPkts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "InNoRoutes", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - - rrddim_add(st, "OutNoRoutes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InDiscards = rrddim_add(st, "InDiscards", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_OutDiscards = rrddim_add(st, "OutDiscards", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InHdrErrors = rrddim_add(st, "InHdrErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InAddrErrors = rrddim_add(st, "InAddrErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InUnknownProtos = rrddim_add(st, "InUnknownProtos", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InTooBigErrors = rrddim_add(st, "InTooBigErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InTruncatedPkts = rrddim_add(st, "InTruncatedPkts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InNoRoutes = rrddim_add(st, "InNoRoutes", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_OutNoRoutes = rrddim_add(st, "OutNoRoutes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(st); - rrddim_set(st, "InDiscards", Ip6InDiscards); - rrddim_set(st, "OutDiscards", Ip6OutDiscards); - - rrddim_set(st, "InHdrErrors", Ip6InHdrErrors); - rrddim_set(st, "InAddrErrors", Ip6InAddrErrors); - rrddim_set(st, "InUnknownProtos", Ip6InUnknownProtos); - rrddim_set(st, "InTooBigErrors", Ip6InTooBigErrors); - rrddim_set(st, "InTruncatedPkts", Ip6InTruncatedPkts); - rrddim_set(st, "InNoRoutes", Ip6InNoRoutes); - - rrddim_set(st, "OutNoRoutes", Ip6OutNoRoutes); + rrddim_set_by_pointer(st, rd_InDiscards, Ip6InDiscards); + rrddim_set_by_pointer(st, rd_OutDiscards, Ip6OutDiscards); + rrddim_set_by_pointer(st, rd_InHdrErrors, Ip6InHdrErrors); + rrddim_set_by_pointer(st, rd_InAddrErrors, Ip6InAddrErrors); + rrddim_set_by_pointer(st, rd_InUnknownProtos, Ip6InUnknownProtos); + rrddim_set_by_pointer(st, rd_InTooBigErrors, Ip6InTooBigErrors); + rrddim_set_by_pointer(st, rd_InTruncatedPkts, Ip6InTruncatedPkts); + rrddim_set_by_pointer(st, rd_InNoRoutes, Ip6InNoRoutes); + rrddim_set_by_pointer(st, rd_OutNoRoutes, Ip6OutNoRoutes); rrdset_done(st); } @@ -421,18 +501,33 @@ int do_proc_net_snmp6(int update_every, usec_t dt) { if(do_udp_packets == CONFIG_BOOLEAN_YES || (do_udp_packets == CONFIG_BOOLEAN_AUTO && (Udp6InDatagrams || Udp6OutDatagrams))) { do_udp_packets = CONFIG_BOOLEAN_YES; - st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".udppackets"); - if(unlikely(!st)) { - st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "udppackets", NULL, "udp", NULL, "IPv6 UDP Packets" - , "packets/s", 3601, update_every, RRDSET_TYPE_LINE); + static RRDSET *st = NULL; + static RRDDIM *rd_received = NULL, + *rd_sent = NULL; - rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + if(unlikely(!st)) { + st = rrdset_create_localhost( + RRD_TYPE_NET_SNMP6 + , "udppackets" + , NULL + , "udp6" + , NULL + , "IPv6 UDP Packets" + , "packets/s" + , "proc" + , "net/snmp6" + , 3601 + , update_every + , RRDSET_TYPE_LINE + ); + + rd_received = rrddim_add(st, "InDatagrams", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_sent = rrddim_add(st, "OutDatagrams", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(st); - rrddim_set(st, "received", Udp6InDatagrams); - rrddim_set(st, "sent", Udp6OutDatagrams); + rrddim_set_by_pointer(st, rd_received, Udp6InDatagrams); + rrddim_set_by_pointer(st, rd_sent, Udp6OutDatagrams); rrdset_done(st); } @@ -448,27 +543,46 @@ int do_proc_net_snmp6(int update_every, usec_t dt) { || Udp6IgnoredMulti ))) { do_udp_errors = CONFIG_BOOLEAN_YES; - st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".udperrors"); + static RRDSET *st = NULL; + static RRDDIM *rd_RcvbufErrors = NULL, + *rd_SndbufErrors = NULL, + *rd_InErrors = NULL, + *rd_NoPorts = NULL, + *rd_InCsumErrors = NULL, + *rd_IgnoredMulti = NULL; + if(unlikely(!st)) { - st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "udperrors", NULL, "udp", NULL, "IPv6 UDP Errors" - , "events/s", 3701, update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + RRD_TYPE_NET_SNMP6 + , "udperrors" + , NULL + , "udp6" + , NULL + , "IPv6 UDP Errors" + , "events/s" + , "proc" + , "net/snmp6" + , 3701 + , update_every + , RRDSET_TYPE_LINE + ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "SndbufErrors", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "NoPorts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "IgnoredMulti", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_RcvbufErrors = rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_SndbufErrors = rrddim_add(st, "SndbufErrors", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InErrors = rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_NoPorts = rrddim_add(st, "NoPorts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InCsumErrors = rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_IgnoredMulti = rrddim_add(st, "IgnoredMulti", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(st); - rrddim_set(st, "InErrors", Udp6InErrors); - rrddim_set(st, "NoPorts", Udp6NoPorts); - rrddim_set(st, "RcvbufErrors", Udp6RcvbufErrors); - rrddim_set(st, "SndbufErrors", Udp6SndbufErrors); - rrddim_set(st, "InCsumErrors", Udp6InCsumErrors); - rrddim_set(st, "IgnoredMulti", Udp6IgnoredMulti); + rrddim_set_by_pointer(st, rd_RcvbufErrors, Udp6RcvbufErrors); + rrddim_set_by_pointer(st, rd_SndbufErrors, Udp6SndbufErrors); + rrddim_set_by_pointer(st, rd_InErrors, Udp6InErrors); + rrddim_set_by_pointer(st, rd_NoPorts, Udp6NoPorts); + rrddim_set_by_pointer(st, rd_InCsumErrors, Udp6InCsumErrors); + rrddim_set_by_pointer(st, rd_IgnoredMulti, Udp6IgnoredMulti); rrdset_done(st); } @@ -476,18 +590,33 @@ int do_proc_net_snmp6(int update_every, usec_t dt) { if(do_udplite_packets == CONFIG_BOOLEAN_YES || (do_udplite_packets == CONFIG_BOOLEAN_AUTO && (UdpLite6InDatagrams || UdpLite6OutDatagrams))) { do_udplite_packets = CONFIG_BOOLEAN_YES; - st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".udplitepackets"); - if(unlikely(!st)) { - st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "udplitepackets", NULL, "udplite", NULL - , "IPv6 UDPlite Packets", "packets/s", 3601, update_every, RRDSET_TYPE_LINE); + static RRDSET *st = NULL; + static RRDDIM *rd_received = NULL, + *rd_sent = NULL; - rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + if(unlikely(!st)) { + st = rrdset_create_localhost( + RRD_TYPE_NET_SNMP6 + , "udplitepackets" + , NULL + , "udplite6" + , NULL + , "IPv6 UDPlite Packets" + , "packets/s" + , "proc" + , "net/snmp6" + , 3602 + , update_every + , RRDSET_TYPE_LINE + ); + + rd_received = rrddim_add(st, "InDatagrams", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_sent = rrddim_add(st, "OutDatagrams", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(st); - rrddim_set(st, "received", UdpLite6InDatagrams); - rrddim_set(st, "sent", UdpLite6OutDatagrams); + rrddim_set_by_pointer(st, rd_received, UdpLite6InDatagrams); + rrddim_set_by_pointer(st, rd_sent, UdpLite6OutDatagrams); rrdset_done(st); } @@ -503,25 +632,43 @@ int do_proc_net_snmp6(int update_every, usec_t dt) { || UdpLite6InCsumErrors ))) { do_udplite_errors = CONFIG_BOOLEAN_YES; - st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".udpliteerrors"); + static RRDSET *st = NULL; + static RRDDIM *rd_RcvbufErrors = NULL, + *rd_SndbufErrors = NULL, + *rd_InErrors = NULL, + *rd_NoPorts = NULL, + *rd_InCsumErrors = NULL; + if(unlikely(!st)) { - st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "udpliteerrors", NULL, "udplite", NULL - , "IPv6 UDP Lite Errors", "events/s", 3701, update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + RRD_TYPE_NET_SNMP6 + , "udpliteerrors" + , NULL + , "udplite6" + , NULL + , "IPv6 UDP Lite Errors" + , "events/s" + , "proc" + , "net/snmp6" + , 3701 + , update_every + , RRDSET_TYPE_LINE + ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "SndbufErrors", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "NoPorts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_RcvbufErrors = rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_SndbufErrors = rrddim_add(st, "SndbufErrors", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InErrors = rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_NoPorts = rrddim_add(st, "NoPorts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InCsumErrors = rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(st); - rrddim_set(st, "InErrors", UdpLite6InErrors); - rrddim_set(st, "NoPorts", UdpLite6NoPorts); - rrddim_set(st, "RcvbufErrors", UdpLite6RcvbufErrors); - rrddim_set(st, "SndbufErrors", UdpLite6SndbufErrors); - rrddim_set(st, "InCsumErrors", UdpLite6InCsumErrors); + rrddim_set_by_pointer(st, rd_InErrors, UdpLite6InErrors); + rrddim_set_by_pointer(st, rd_NoPorts, UdpLite6NoPorts); + rrddim_set_by_pointer(st, rd_RcvbufErrors, UdpLite6RcvbufErrors); + rrddim_set_by_pointer(st, rd_SndbufErrors, UdpLite6SndbufErrors); + rrddim_set_by_pointer(st, rd_InCsumErrors, UdpLite6InCsumErrors); rrdset_done(st); } @@ -529,20 +676,34 @@ int do_proc_net_snmp6(int update_every, usec_t dt) { if(do_mcast == CONFIG_BOOLEAN_YES || (do_mcast == CONFIG_BOOLEAN_AUTO && (Ip6OutMcastOctets || Ip6InMcastOctets))) { do_mcast = CONFIG_BOOLEAN_YES; - st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".mcast"); + static RRDSET *st = NULL; + static RRDDIM *rd_Ip6InMcastOctets = NULL, + *rd_Ip6OutMcastOctets = NULL; + if(unlikely(!st)) { - st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "mcast", NULL, "multicast", NULL - , "IPv6 Multicast Bandwidth", "kilobits/s", 9000, update_every - , RRDSET_TYPE_AREA); + st = rrdset_create_localhost( + RRD_TYPE_NET_SNMP6 + , "mcast" + , NULL + , "multicast6" + , NULL + , "IPv6 Multicast Bandwidth" + , "kilobits/s" + , "proc" + , "net/snmp6" + , 9000 + , update_every + , RRDSET_TYPE_AREA + ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - rrddim_add(st, "received", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "sent", NULL, -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); + rd_Ip6InMcastOctets = rrddim_add(st, "InMcastOctets", "received", 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); + rd_Ip6OutMcastOctets = rrddim_add(st, "OutMcastOctets", "sent", -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(st); - rrddim_set(st, "sent", Ip6OutMcastOctets); - rrddim_set(st, "received", Ip6InMcastOctets); + rrddim_set_by_pointer(st, rd_Ip6InMcastOctets, Ip6InMcastOctets); + rrddim_set_by_pointer(st, rd_Ip6OutMcastOctets, Ip6OutMcastOctets); rrdset_done(st); } @@ -550,20 +711,34 @@ int do_proc_net_snmp6(int update_every, usec_t dt) { if(do_bcast == CONFIG_BOOLEAN_YES || (do_bcast == CONFIG_BOOLEAN_AUTO && (Ip6OutBcastOctets || Ip6InBcastOctets))) { do_bcast = CONFIG_BOOLEAN_YES; - st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".bcast"); + static RRDSET *st = NULL; + static RRDDIM *rd_Ip6InBcastOctets = NULL, + *rd_Ip6OutBcastOctets = NULL; + if(unlikely(!st)) { - st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "bcast", NULL, "broadcast", NULL - , "IPv6 Broadcast Bandwidth", "kilobits/s", 8000, update_every - , RRDSET_TYPE_AREA); + st = rrdset_create_localhost( + RRD_TYPE_NET_SNMP6 + , "bcast" + , NULL + , "broadcast6" + , NULL + , "IPv6 Broadcast Bandwidth" + , "kilobits/s" + , "proc" + , "net/snmp6" + , 8000 + , update_every + , RRDSET_TYPE_AREA + ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - rrddim_add(st, "received", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "sent", NULL, -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); + rd_Ip6InBcastOctets = rrddim_add(st, "InBcastOctets", "received", 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); + rd_Ip6OutBcastOctets = rrddim_add(st, "OutBcastOctets", "sent", -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(st); - rrddim_set(st, "sent", Ip6OutBcastOctets); - rrddim_set(st, "received", Ip6InBcastOctets); + rrddim_set_by_pointer(st, rd_Ip6InBcastOctets, Ip6InBcastOctets); + rrddim_set_by_pointer(st, rd_Ip6OutBcastOctets, Ip6OutBcastOctets); rrdset_done(st); } @@ -571,19 +746,34 @@ int do_proc_net_snmp6(int update_every, usec_t dt) { if(do_mcast_p == CONFIG_BOOLEAN_YES || (do_mcast_p == CONFIG_BOOLEAN_AUTO && (Ip6OutMcastPkts || Ip6InMcastPkts))) { do_mcast_p = CONFIG_BOOLEAN_YES; - st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".mcastpkts"); + static RRDSET *st = NULL; + static RRDDIM *rd_Ip6InMcastPkts = NULL, + *rd_Ip6OutMcastPkts = NULL; + if(unlikely(!st)) { - st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "mcastpkts", NULL, "multicast", NULL - , "IPv6 Multicast Packets", "packets/s", 9500, update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + RRD_TYPE_NET_SNMP6 + , "mcastpkts" + , NULL + , "multicast6" + , NULL + , "IPv6 Multicast Packets" + , "packets/s" + , "proc" + , "net/snmp6" + , 9500 + , update_every + , RRDSET_TYPE_LINE + ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_Ip6InMcastPkts = rrddim_add(st, "InMcastPkts", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_Ip6OutMcastPkts = rrddim_add(st, "OutMcastPkts", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(st); - rrddim_set(st, "sent", Ip6OutMcastPkts); - rrddim_set(st, "received", Ip6InMcastPkts); + rrddim_set_by_pointer(st, rd_Ip6InMcastPkts, Ip6InMcastPkts); + rrddim_set_by_pointer(st, rd_Ip6OutMcastPkts, Ip6OutMcastPkts); rrdset_done(st); } @@ -591,18 +781,33 @@ int do_proc_net_snmp6(int update_every, usec_t dt) { if(do_icmp == CONFIG_BOOLEAN_YES || (do_icmp == CONFIG_BOOLEAN_AUTO && (Icmp6InMsgs || Icmp6OutMsgs))) { do_icmp = CONFIG_BOOLEAN_YES; - st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".icmp"); - if(unlikely(!st)) { - st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "icmp", NULL, "icmp", NULL, "IPv6 ICMP Messages" - , "messages/s", 10000, update_every, RRDSET_TYPE_LINE); + static RRDSET *st = NULL; + static RRDDIM *rd_Icmp6InMsgs = NULL, + *rd_Icmp6OutMsgs = NULL; - rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + if(unlikely(!st)) { + st = rrdset_create_localhost( + RRD_TYPE_NET_SNMP6 + , "icmp" + , NULL + , "icmp6" + , NULL + , "IPv6 ICMP Messages" + , "messages/s" + , "proc" + , "net/snmp6" + , 10000 + , update_every + , RRDSET_TYPE_LINE + ); + + rd_Icmp6InMsgs = rrddim_add(st, "InMsgs", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_Icmp6OutMsgs = rrddim_add(st, "OutMsgs", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(st); - rrddim_set(st, "sent", Icmp6InMsgs); - rrddim_set(st, "received", Icmp6OutMsgs); + rrddim_set_by_pointer(st, rd_Icmp6InMsgs, Icmp6InMsgs); + rrddim_set_by_pointer(st, rd_Icmp6OutMsgs, Icmp6OutMsgs); rrdset_done(st); } @@ -610,18 +815,33 @@ int do_proc_net_snmp6(int update_every, usec_t dt) { if(do_icmp_redir == CONFIG_BOOLEAN_YES || (do_icmp_redir == CONFIG_BOOLEAN_AUTO && (Icmp6InRedirects || Icmp6OutRedirects))) { do_icmp_redir = CONFIG_BOOLEAN_YES; - st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".icmpredir"); - if(unlikely(!st)) { - st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "icmpredir", NULL, "icmp", NULL, "IPv6 ICMP Redirects" - , "redirects/s", 10050, update_every, RRDSET_TYPE_LINE); + static RRDSET *st = NULL; + static RRDDIM *rd_Icmp6InRedirects = NULL, + *rd_Icmp6OutRedirects = NULL; - rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + if(unlikely(!st)) { + st = rrdset_create_localhost( + RRD_TYPE_NET_SNMP6 + , "icmpredir" + , NULL + , "icmp6" + , NULL + , "IPv6 ICMP Redirects" + , "redirects/s" + , "proc" + , "net/snmp6" + , 10050 + , update_every + , RRDSET_TYPE_LINE + ); + + rd_Icmp6InRedirects = rrddim_add(st, "InRedirects", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_Icmp6OutRedirects = rrddim_add(st, "OutRedirects", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(st); - rrddim_set(st, "sent", Icmp6InRedirects); - rrddim_set(st, "received", Icmp6OutRedirects); + rrddim_set_by_pointer(st, rd_Icmp6InRedirects, Icmp6InRedirects); + rrddim_set_by_pointer(st, rd_Icmp6OutRedirects, Icmp6OutRedirects); rrdset_done(st); } @@ -642,37 +862,60 @@ int do_proc_net_snmp6(int update_every, usec_t dt) { || Icmp6OutParmProblems ))) { do_icmp_errors = CONFIG_BOOLEAN_YES; - st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".icmperrors"); + static RRDSET *st = NULL; + static RRDDIM *rd_InErrors = NULL, + *rd_OutErrors = NULL, + *rd_InCsumErrors = NULL, + *rd_InDestUnreachs = NULL, + *rd_InPktTooBigs = NULL, + *rd_InTimeExcds = NULL, + *rd_InParmProblems = NULL, + *rd_OutDestUnreachs = NULL, + *rd_OutPktTooBigs = NULL, + *rd_OutTimeExcds = NULL, + *rd_OutParmProblems = NULL; + if(unlikely(!st)) { - st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "icmperrors", NULL, "icmp", NULL, "IPv6 ICMP Errors" - , "errors/s", 10100, update_every, RRDSET_TYPE_LINE); - - rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "OutErrors", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - - rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "InDestUnreachs", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "InPktTooBigs", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "InTimeExcds", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "InParmProblems", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "OutDestUnreachs", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "OutPktTooBigs", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "OutTimeExcds", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "OutParmProblems", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + st = rrdset_create_localhost( + RRD_TYPE_NET_SNMP6 + , "icmperrors" + , NULL + , "icmp6" + , NULL + , "IPv6 ICMP Errors" + , "errors/s" + , "proc" + , "net/snmp6" + , 10100 + , update_every + , RRDSET_TYPE_LINE + ); + + rd_InErrors = rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_OutErrors = rrddim_add(st, "OutErrors", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InCsumErrors = rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InDestUnreachs = rrddim_add(st, "InDestUnreachs", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InPktTooBigs = rrddim_add(st, "InPktTooBigs", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InTimeExcds = rrddim_add(st, "InTimeExcds", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InParmProblems = rrddim_add(st, "InParmProblems", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_OutDestUnreachs = rrddim_add(st, "OutDestUnreachs", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_OutPktTooBigs = rrddim_add(st, "OutPktTooBigs", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_OutTimeExcds = rrddim_add(st, "OutTimeExcds", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_OutParmProblems = rrddim_add(st, "OutParmProblems", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(st); - rrddim_set(st, "InErrors", Icmp6InErrors); - rrddim_set(st, "OutErrors", Icmp6OutErrors); - rrddim_set(st, "InCsumErrors", Icmp6InCsumErrors); - rrddim_set(st, "InDestUnreachs", Icmp6InDestUnreachs); - rrddim_set(st, "InPktTooBigs", Icmp6InPktTooBigs); - rrddim_set(st, "InTimeExcds", Icmp6InTimeExcds); - rrddim_set(st, "InParmProblems", Icmp6InParmProblems); - rrddim_set(st, "OutDestUnreachs", Icmp6OutDestUnreachs); - rrddim_set(st, "OutPktTooBigs", Icmp6OutPktTooBigs); - rrddim_set(st, "OutTimeExcds", Icmp6OutTimeExcds); - rrddim_set(st, "OutParmProblems", Icmp6OutParmProblems); + rrddim_set_by_pointer(st, rd_InErrors, Icmp6InErrors); + rrddim_set_by_pointer(st, rd_OutErrors, Icmp6OutErrors); + rrddim_set_by_pointer(st, rd_InCsumErrors, Icmp6InCsumErrors); + rrddim_set_by_pointer(st, rd_InDestUnreachs, Icmp6InDestUnreachs); + rrddim_set_by_pointer(st, rd_InPktTooBigs, Icmp6InPktTooBigs); + rrddim_set_by_pointer(st, rd_InTimeExcds, Icmp6InTimeExcds); + rrddim_set_by_pointer(st, rd_InParmProblems, Icmp6InParmProblems); + rrddim_set_by_pointer(st, rd_OutDestUnreachs, Icmp6OutDestUnreachs); + rrddim_set_by_pointer(st, rd_OutPktTooBigs, Icmp6OutPktTooBigs); + rrddim_set_by_pointer(st, rd_OutTimeExcds, Icmp6OutTimeExcds); + rrddim_set_by_pointer(st, rd_OutParmProblems, Icmp6OutParmProblems); rrdset_done(st); } @@ -686,22 +929,39 @@ int do_proc_net_snmp6(int update_every, usec_t dt) { || Icmp6OutEchoReplies ))) { do_icmp_echos = CONFIG_BOOLEAN_YES; - st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".icmpechos"); - if(unlikely(!st)) { - st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "icmpechos", NULL, "icmp", NULL, "IPv6 ICMP Echo" - , "messages/s", 10200, update_every, RRDSET_TYPE_LINE); + static RRDSET *st = NULL; + static RRDDIM *rd_InEchos = NULL, + *rd_OutEchos = NULL, + *rd_InEchoReplies = NULL, + *rd_OutEchoReplies = NULL; - rrddim_add(st, "InEchos", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "OutEchos", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "InEchoReplies", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "OutEchoReplies", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + if(unlikely(!st)) { + st = rrdset_create_localhost( + RRD_TYPE_NET_SNMP6 + , "icmpechos" + , NULL + , "icmp6" + , NULL + , "IPv6 ICMP Echo" + , "messages/s" + , "proc" + , "net/snmp6" + , 10200 + , update_every + , RRDSET_TYPE_LINE + ); + + rd_InEchos = rrddim_add(st, "InEchos", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_OutEchos = rrddim_add(st, "OutEchos", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InEchoReplies = rrddim_add(st, "InEchoReplies", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_OutEchoReplies = rrddim_add(st, "OutEchoReplies", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(st); - rrddim_set(st, "InEchos", Icmp6InEchos); - rrddim_set(st, "OutEchos", Icmp6OutEchos); - rrddim_set(st, "InEchoReplies", Icmp6InEchoReplies); - rrddim_set(st, "OutEchoReplies", Icmp6OutEchoReplies); + rrddim_set_by_pointer(st, rd_InEchos, Icmp6InEchos); + rrddim_set_by_pointer(st, rd_OutEchos, Icmp6OutEchos); + rrddim_set_by_pointer(st, rd_InEchoReplies, Icmp6InEchoReplies); + rrddim_set_by_pointer(st, rd_OutEchoReplies, Icmp6OutEchoReplies); rrdset_done(st); } @@ -717,27 +977,44 @@ int do_proc_net_snmp6(int update_every, usec_t dt) { || Icmp6OutGroupMembReductions ))) { do_icmp_groupmemb = CONFIG_BOOLEAN_YES; - st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".groupmemb"); + static RRDSET *st = NULL; + static RRDDIM *rd_InQueries = NULL, + *rd_OutQueries = NULL, + *rd_InResponses = NULL, + *rd_OutResponses = NULL, + *rd_InReductions = NULL, + *rd_OutReductions = NULL; + if(unlikely(!st)) { - st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "groupmemb", NULL, "icmp", NULL - , "IPv6 ICMP Group Membership", "messages/s", 10300, update_every - , RRDSET_TYPE_LINE); - - rrddim_add(st, "InQueries", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "OutQueries", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "InResponses", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "OutResponses", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "InReductions", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "OutReductions", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + st = rrdset_create_localhost( + RRD_TYPE_NET_SNMP6 + , "groupmemb" + , NULL + , "icmp6" + , NULL + , "IPv6 ICMP Group Membership" + , "messages/s" + , "proc" + , "net/snmp6" + , 10300 + , update_every + , RRDSET_TYPE_LINE); + + rd_InQueries = rrddim_add(st, "InQueries", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_OutQueries = rrddim_add(st, "OutQueries", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InResponses = rrddim_add(st, "InResponses", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_OutResponses = rrddim_add(st, "OutResponses", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InReductions = rrddim_add(st, "InReductions", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_OutReductions = rrddim_add(st, "OutReductions", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(st); - rrddim_set(st, "InQueries", Icmp6InGroupMembQueries); - rrddim_set(st, "OutQueries", Icmp6OutGroupMembQueries); - rrddim_set(st, "InResponses", Icmp6InGroupMembResponses); - rrddim_set(st, "OutResponses", Icmp6OutGroupMembResponses); - rrddim_set(st, "InReductions", Icmp6InGroupMembReductions); - rrddim_set(st, "OutReductions", Icmp6OutGroupMembReductions); + rrddim_set_by_pointer(st, rd_InQueries, Icmp6InGroupMembQueries); + rrddim_set_by_pointer(st, rd_OutQueries, Icmp6OutGroupMembQueries); + rrddim_set_by_pointer(st, rd_InResponses, Icmp6InGroupMembResponses); + rrddim_set_by_pointer(st, rd_OutResponses, Icmp6OutGroupMembResponses); + rrddim_set_by_pointer(st, rd_InReductions, Icmp6InGroupMembReductions); + rrddim_set_by_pointer(st, rd_OutReductions, Icmp6OutGroupMembReductions); rrdset_done(st); } @@ -751,22 +1028,39 @@ int do_proc_net_snmp6(int update_every, usec_t dt) { || Icmp6OutRouterAdvertisements ))) { do_icmp_router = CONFIG_BOOLEAN_YES; - st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".icmprouter"); - if(unlikely(!st)) { - st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "icmprouter", NULL, "icmp", NULL, "IPv6 Router Messages" - , "messages/s", 10400, update_every, RRDSET_TYPE_LINE); + static RRDSET *st = NULL; + static RRDDIM *rd_InSolicits = NULL, + *rd_OutSolicits = NULL, + *rd_InAdvertisements = NULL, + *rd_OutAdvertisements = NULL; - rrddim_add(st, "InSolicits", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "OutSolicits", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "InAdvertisements", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "OutAdvertisements", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + if(unlikely(!st)) { + st = rrdset_create_localhost( + RRD_TYPE_NET_SNMP6 + , "icmprouter" + , NULL + , "icmp6" + , NULL + , "IPv6 Router Messages" + , "messages/s" + , "proc" + , "net/snmp6" + , 10400 + , update_every + , RRDSET_TYPE_LINE + ); + + rd_InSolicits = rrddim_add(st, "InSolicits", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_OutSolicits = rrddim_add(st, "OutSolicits", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InAdvertisements = rrddim_add(st, "InAdvertisements", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_OutAdvertisements = rrddim_add(st, "OutAdvertisements", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(st); - rrddim_set(st, "InSolicits", Icmp6InRouterSolicits); - rrddim_set(st, "OutSolicits", Icmp6OutRouterSolicits); - rrddim_set(st, "InAdvertisements", Icmp6InRouterAdvertisements); - rrddim_set(st, "OutAdvertisements", Icmp6OutRouterAdvertisements); + rrddim_set_by_pointer(st, rd_InSolicits, Icmp6InRouterSolicits); + rrddim_set_by_pointer(st, rd_OutSolicits, Icmp6OutRouterSolicits); + rrddim_set_by_pointer(st, rd_InAdvertisements, Icmp6InRouterAdvertisements); + rrddim_set_by_pointer(st, rd_OutAdvertisements, Icmp6OutRouterAdvertisements); rrdset_done(st); } @@ -780,23 +1074,39 @@ int do_proc_net_snmp6(int update_every, usec_t dt) { || Icmp6OutNeighborAdvertisements ))) { do_icmp_neighbor = CONFIG_BOOLEAN_YES; - st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".icmpneighbor"); + static RRDSET *st = NULL; + static RRDDIM *rd_InSolicits = NULL, + *rd_OutSolicits = NULL, + *rd_InAdvertisements = NULL, + *rd_OutAdvertisements = NULL; + if(unlikely(!st)) { - st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "icmpneighbor", NULL, "icmp", NULL - , "IPv6 Neighbor Messages", "messages/s", 10500, update_every - , RRDSET_TYPE_LINE); - - rrddim_add(st, "InSolicits", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "OutSolicits", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "InAdvertisements", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "OutAdvertisements", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + st = rrdset_create_localhost( + RRD_TYPE_NET_SNMP6 + , "icmpneighbor" + , NULL + , "icmp6" + , NULL + , "IPv6 Neighbor Messages" + , "messages/s" + , "proc" + , "net/snmp6" + , 10500 + , update_every + , RRDSET_TYPE_LINE + ); + + rd_InSolicits = rrddim_add(st, "InSolicits", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_OutSolicits = rrddim_add(st, "OutSolicits", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InAdvertisements = rrddim_add(st, "InAdvertisements", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_OutAdvertisements = rrddim_add(st, "OutAdvertisements", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(st); - rrddim_set(st, "InSolicits", Icmp6InNeighborSolicits); - rrddim_set(st, "OutSolicits", Icmp6OutNeighborSolicits); - rrddim_set(st, "InAdvertisements", Icmp6InNeighborAdvertisements); - rrddim_set(st, "OutAdvertisements", Icmp6OutNeighborAdvertisements); + rrddim_set_by_pointer(st, rd_InSolicits, Icmp6InNeighborSolicits); + rrddim_set_by_pointer(st, rd_OutSolicits, Icmp6OutNeighborSolicits); + rrddim_set_by_pointer(st, rd_InAdvertisements, Icmp6InNeighborAdvertisements); + rrddim_set_by_pointer(st, rd_OutAdvertisements, Icmp6OutNeighborAdvertisements); rrdset_done(st); } @@ -804,18 +1114,33 @@ int do_proc_net_snmp6(int update_every, usec_t dt) { if(do_icmp_mldv2 == CONFIG_BOOLEAN_YES || (do_icmp_mldv2 == CONFIG_BOOLEAN_AUTO && (Icmp6InMLDv2Reports || Icmp6OutMLDv2Reports))) { do_icmp_mldv2 = CONFIG_BOOLEAN_YES; - st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".icmpmldv2"); - if(unlikely(!st)) { - st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "icmpmldv2", NULL, "icmp", NULL, "IPv6 ICMP MLDv2 Reports" - , "reports/s", 10600, update_every, RRDSET_TYPE_LINE); + static RRDSET *st = NULL; + static RRDDIM *rd_InMLDv2Reports = NULL, + *rd_OutMLDv2Reports = NULL; - rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + if(unlikely(!st)) { + st = rrdset_create_localhost( + RRD_TYPE_NET_SNMP6 + , "icmpmldv2" + , NULL + , "icmp6" + , NULL + , "IPv6 ICMP MLDv2 Reports" + , "reports/s" + , "proc" + , "net/snmp6" + , 10600 + , update_every + , RRDSET_TYPE_LINE + ); + + rd_InMLDv2Reports = rrddim_add(st, "InMLDv2Reports", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_OutMLDv2Reports = rrddim_add(st, "OutMLDv2Reports", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(st); - rrddim_set(st, "sent", Icmp6InMLDv2Reports); - rrddim_set(st, "received", Icmp6OutMLDv2Reports); + rrddim_set_by_pointer(st, rd_InMLDv2Reports, Icmp6InMLDv2Reports); + rrddim_set_by_pointer(st, rd_OutMLDv2Reports, Icmp6OutMLDv2Reports); rrdset_done(st); } @@ -835,34 +1160,57 @@ int do_proc_net_snmp6(int update_every, usec_t dt) { || Icmp6OutType143 ))) { do_icmp_types = CONFIG_BOOLEAN_YES; - st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".icmptypes"); + static RRDSET *st = NULL; + static RRDDIM *rd_InType1 = NULL, + *rd_InType128 = NULL, + *rd_InType129 = NULL, + *rd_InType136 = NULL, + *rd_OutType1 = NULL, + *rd_OutType128 = NULL, + *rd_OutType129 = NULL, + *rd_OutType133 = NULL, + *rd_OutType135 = NULL, + *rd_OutType143 = NULL; + if(unlikely(!st)) { - st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "icmptypes", NULL, "icmp", NULL, "IPv6 ICMP Types" - , "messages/s", 10700, update_every, RRDSET_TYPE_LINE); - - rrddim_add(st, "InType1", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "InType128", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "InType129", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "InType136", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "OutType1", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "OutType128", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "OutType129", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "OutType133", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "OutType135", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "OutType143", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + st = rrdset_create_localhost( + RRD_TYPE_NET_SNMP6 + , "icmptypes" + , NULL + , "icmp6" + , NULL + , "IPv6 ICMP Types" + , "messages/s" + , "proc" + , "net/snmp6" + , 10700 + , update_every + , RRDSET_TYPE_LINE + ); + + rd_InType1 = rrddim_add(st, "InType1", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InType128 = rrddim_add(st, "InType128", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InType129 = rrddim_add(st, "InType129", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InType136 = rrddim_add(st, "InType136", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_OutType1 = rrddim_add(st, "OutType1", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_OutType128 = rrddim_add(st, "OutType128", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_OutType129 = rrddim_add(st, "OutType129", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_OutType133 = rrddim_add(st, "OutType133", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_OutType135 = rrddim_add(st, "OutType135", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_OutType143 = rrddim_add(st, "OutType143", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(st); - rrddim_set(st, "InType1", Icmp6InType1); - rrddim_set(st, "InType128", Icmp6InType128); - rrddim_set(st, "InType129", Icmp6InType129); - rrddim_set(st, "InType136", Icmp6InType136); - rrddim_set(st, "OutType1", Icmp6OutType1); - rrddim_set(st, "OutType128", Icmp6OutType128); - rrddim_set(st, "OutType129", Icmp6OutType129); - rrddim_set(st, "OutType133", Icmp6OutType133); - rrddim_set(st, "OutType135", Icmp6OutType135); - rrddim_set(st, "OutType143", Icmp6OutType143); + rrddim_set_by_pointer(st, rd_InType1, Icmp6InType1); + rrddim_set_by_pointer(st, rd_InType128, Icmp6InType128); + rrddim_set_by_pointer(st, rd_InType129, Icmp6InType129); + rrddim_set_by_pointer(st, rd_InType136, Icmp6InType136); + rrddim_set_by_pointer(st, rd_OutType1, Icmp6OutType1); + rrddim_set_by_pointer(st, rd_OutType128, Icmp6OutType128); + rrddim_set_by_pointer(st, rd_OutType129, Icmp6OutType129); + rrddim_set_by_pointer(st, rd_OutType133, Icmp6OutType133); + rrddim_set_by_pointer(st, rd_OutType135, Icmp6OutType135); + rrddim_set_by_pointer(st, rd_OutType143, Icmp6OutType143); rrdset_done(st); } @@ -876,22 +1224,39 @@ int do_proc_net_snmp6(int update_every, usec_t dt) { || Ip6InCEPkts ))) { do_ect = CONFIG_BOOLEAN_YES; - st = rrdset_find_localhost(RRD_TYPE_NET_SNMP6 ".ect"); - if(unlikely(!st)) { - st = rrdset_create_localhost(RRD_TYPE_NET_SNMP6, "ect", NULL, "packets", NULL, "IPv6 ECT Packets" - , "packets/s", 10800, update_every, RRDSET_TYPE_LINE); + static RRDSET *st = NULL; + static RRDDIM *rd_InNoECTPkts = NULL, + *rd_InECT1Pkts = NULL, + *rd_InECT0Pkts = NULL, + *rd_InCEPkts = NULL; - rrddim_add(st, "InNoECTPkts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "InECT1Pkts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "InECT0Pkts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "InCEPkts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + if(unlikely(!st)) { + st = rrdset_create_localhost( + RRD_TYPE_NET_SNMP6 + , "ect" + , NULL + , "packets" + , NULL + , "IPv6 ECT Packets" + , "packets/s" + , "proc" + , "net/snmp6" + , 10800 + , update_every + , RRDSET_TYPE_LINE + ); + + rd_InNoECTPkts = rrddim_add(st, "InNoECTPkts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InECT1Pkts = rrddim_add(st, "InECT1Pkts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InECT0Pkts = rrddim_add(st, "InECT0Pkts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_InCEPkts = rrddim_add(st, "InCEPkts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(st); - rrddim_set(st, "InNoECTPkts", Ip6InNoECTPkts); - rrddim_set(st, "InECT1Pkts", Ip6InECT1Pkts); - rrddim_set(st, "InECT0Pkts", Ip6InECT0Pkts); - rrddim_set(st, "InCEPkts", Ip6InCEPkts); + rrddim_set_by_pointer(st, rd_InNoECTPkts, Ip6InNoECTPkts); + rrddim_set_by_pointer(st, rd_InECT1Pkts, Ip6InECT1Pkts); + rrddim_set_by_pointer(st, rd_InECT0Pkts, Ip6InECT0Pkts); + rrddim_set_by_pointer(st, rd_InCEPkts, Ip6InCEPkts); rrdset_done(st); } diff --git a/src/proc_net_sockstat.c b/src/proc_net_sockstat.c new file mode 100644 index 00000000..2ca4061b --- /dev/null +++ b/src/proc_net_sockstat.c @@ -0,0 +1,514 @@ +#include "common.h" + +static struct proc_net_sockstat { + kernel_uint_t sockets_used; + + kernel_uint_t tcp_inuse; + kernel_uint_t tcp_orphan; + kernel_uint_t tcp_tw; + kernel_uint_t tcp_alloc; + kernel_uint_t tcp_mem; + + kernel_uint_t udp_inuse; + kernel_uint_t udp_mem; + + kernel_uint_t udplite_inuse; + + kernel_uint_t raw_inuse; + + kernel_uint_t frag_inuse; + kernel_uint_t frag_memory; +} sockstat_root = { 0 }; + + +static int read_tcp_mem(void) { + static char *filename = NULL; + static RRDVAR *tcp_mem_low_threshold = NULL, + *tcp_mem_pressure_threshold = NULL, + *tcp_mem_high_threshold = NULL; + + if(unlikely(!tcp_mem_low_threshold)) { + tcp_mem_low_threshold = rrdvar_custom_host_variable_create(localhost, "tcp_mem_low"); + tcp_mem_pressure_threshold = rrdvar_custom_host_variable_create(localhost, "tcp_mem_pressure"); + tcp_mem_high_threshold = rrdvar_custom_host_variable_create(localhost, "tcp_mem_high"); + } + + if(unlikely(!filename)) { + char buffer[FILENAME_MAX + 1]; + snprintfz(buffer, FILENAME_MAX, "%s/proc/sys/net/ipv4/tcp_mem", netdata_configured_host_prefix); + filename = strdupz(buffer); + } + + char buffer[200 + 1], *start, *end; + if(read_file(filename, buffer, 200) != 0) return 1; + buffer[200] = '\0'; + + unsigned long long low = 0, pressure = 0, high = 0; + + start = buffer; + low = strtoull(start, &end, 10); + + start = end; + pressure = strtoull(start, &end, 10); + + start = end; + high = strtoull(start, &end, 10); + + // fprintf(stderr, "TCP MEM low = %llu, pressure = %llu, high = %llu\n", low, pressure, high); + + rrdvar_custom_host_variable_set(localhost, tcp_mem_low_threshold, low * sysconf(_SC_PAGESIZE) / 1024); + rrdvar_custom_host_variable_set(localhost, tcp_mem_pressure_threshold, pressure * sysconf(_SC_PAGESIZE) / 1024); + rrdvar_custom_host_variable_set(localhost, tcp_mem_high_threshold, high * sysconf(_SC_PAGESIZE) / 1024); + + return 0; +} + +static kernel_uint_t read_tcp_max_orphans(void) { + static char *filename = NULL; + static RRDVAR *tcp_max_orphans_var = NULL; + + if(unlikely(!filename)) { + char buffer[FILENAME_MAX + 1]; + snprintfz(buffer, FILENAME_MAX, "%s/proc/sys/net/ipv4/tcp_max_orphans", netdata_configured_host_prefix); + filename = strdupz(buffer); + } + + unsigned long long tcp_max_orphans = 0; + if(read_single_number_file(filename, &tcp_max_orphans) == 0) { + + if(unlikely(!tcp_max_orphans_var)) + tcp_max_orphans_var = rrdvar_custom_host_variable_create(localhost, "tcp_max_orphans"); + + rrdvar_custom_host_variable_set(localhost, tcp_max_orphans_var, tcp_max_orphans); + return tcp_max_orphans; + } + + return 0; +} + +int do_proc_net_sockstat(int update_every, usec_t dt) { + (void)dt; + + static procfile *ff = NULL; + + static uint32_t hash_sockets = 0, + hash_raw = 0, + hash_frag = 0, + hash_tcp = 0, + hash_udp = 0, + hash_udplite = 0; + + static long long update_constants_every = 60, update_constants_count = 0; + + static ARL_BASE *arl_sockets = NULL; + static ARL_BASE *arl_tcp = NULL; + static ARL_BASE *arl_udp = NULL; + static ARL_BASE *arl_udplite = NULL; + static ARL_BASE *arl_raw = NULL; + static ARL_BASE *arl_frag = NULL; + + static int do_sockets = -1, do_tcp_sockets = -1, do_tcp_mem = -1, do_udp_sockets = -1, do_udp_mem = -1, do_udplite_sockets = -1, do_raw_sockets = -1, do_frag_sockets = -1, do_frag_mem = -1; + + static char *keys[7] = { NULL }; + static uint32_t hashes[7] = { 0 }; + static ARL_BASE *bases[7] = { NULL }; + + if(unlikely(!arl_sockets)) { + do_sockets = config_get_boolean_ondemand("plugin:proc:/proc/net/sockstat", "ipv4 sockets", CONFIG_BOOLEAN_AUTO); + do_tcp_sockets = config_get_boolean_ondemand("plugin:proc:/proc/net/sockstat", "ipv4 TCP sockets", CONFIG_BOOLEAN_AUTO); + do_tcp_mem = config_get_boolean_ondemand("plugin:proc:/proc/net/sockstat", "ipv4 TCP memory", CONFIG_BOOLEAN_AUTO); + do_udp_sockets = config_get_boolean_ondemand("plugin:proc:/proc/net/sockstat", "ipv4 UDP sockets", CONFIG_BOOLEAN_AUTO); + do_udp_mem = config_get_boolean_ondemand("plugin:proc:/proc/net/sockstat", "ipv4 UDP memory", CONFIG_BOOLEAN_AUTO); + do_udplite_sockets = config_get_boolean_ondemand("plugin:proc:/proc/net/sockstat", "ipv4 UDPLITE sockets", CONFIG_BOOLEAN_AUTO); + do_raw_sockets = config_get_boolean_ondemand("plugin:proc:/proc/net/sockstat", "ipv4 RAW sockets", CONFIG_BOOLEAN_AUTO); + do_frag_sockets = config_get_boolean_ondemand("plugin:proc:/proc/net/sockstat", "ipv4 FRAG sockets", CONFIG_BOOLEAN_AUTO); + do_frag_mem = config_get_boolean_ondemand("plugin:proc:/proc/net/sockstat", "ipv4 FRAG memory", CONFIG_BOOLEAN_AUTO); + + update_constants_every = config_get_number("plugin:proc:/proc/net/sockstat", "update constants every", update_constants_every); + update_constants_count = update_constants_every; + + arl_sockets = arl_create("sockstat/sockets", arl_callback_str2kernel_uint_t, 60); + arl_expect(arl_sockets, "used", &sockstat_root.sockets_used); + + arl_tcp = arl_create("sockstat/TCP", arl_callback_str2kernel_uint_t, 60); + arl_expect(arl_tcp, "inuse", &sockstat_root.tcp_inuse); + arl_expect(arl_tcp, "orphan", &sockstat_root.tcp_orphan); + arl_expect(arl_tcp, "tw", &sockstat_root.tcp_tw); + arl_expect(arl_tcp, "alloc", &sockstat_root.tcp_alloc); + arl_expect(arl_tcp, "mem", &sockstat_root.tcp_mem); + + arl_udp = arl_create("sockstat/UDP", arl_callback_str2kernel_uint_t, 60); + arl_expect(arl_udp, "inuse", &sockstat_root.udp_inuse); + arl_expect(arl_udp, "mem", &sockstat_root.udp_mem); + + arl_udplite = arl_create("sockstat/UDPLITE", arl_callback_str2kernel_uint_t, 60); + arl_expect(arl_udplite, "inuse", &sockstat_root.udplite_inuse); + + arl_raw = arl_create("sockstat/RAW", arl_callback_str2kernel_uint_t, 60); + arl_expect(arl_raw, "inuse", &sockstat_root.raw_inuse); + + arl_frag = arl_create("sockstat/FRAG", arl_callback_str2kernel_uint_t, 60); + arl_expect(arl_frag, "inuse", &sockstat_root.frag_inuse); + arl_expect(arl_frag, "memory", &sockstat_root.frag_memory); + + hash_sockets = simple_hash("sockets"); + hash_tcp = simple_hash("TCP"); + hash_udp = simple_hash("UDP"); + hash_udplite = simple_hash("UDPLITE"); + hash_raw = simple_hash("RAW"); + hash_frag = simple_hash("FRAG"); + + keys[0] = "sockets"; hashes[0] = hash_sockets; bases[0] = arl_sockets; + keys[1] = "TCP"; hashes[1] = hash_tcp; bases[1] = arl_tcp; + keys[2] = "UDP"; hashes[2] = hash_udp; bases[2] = arl_udp; + keys[3] = "UDPLITE"; hashes[3] = hash_udplite; bases[3] = arl_udplite; + keys[4] = "RAW"; hashes[4] = hash_raw; bases[4] = arl_raw; + keys[5] = "FRAG"; hashes[5] = hash_frag; bases[5] = arl_frag; + keys[6] = NULL; // terminator + } + + update_constants_count += update_every; + if(unlikely(update_constants_count > update_constants_every)) { + read_tcp_max_orphans(); + read_tcp_mem(); + update_constants_count = 0; + } + + if(unlikely(!ff)) { + char filename[FILENAME_MAX + 1]; + snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/net/sockstat"); + ff = procfile_open(config_get("plugin:proc:/proc/net/sockstat", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT); + if(unlikely(!ff)) return 1; + } + + ff = procfile_readall(ff); + if(unlikely(!ff)) return 0; // we return 0, so that we will retry to open it next time + + size_t lines = procfile_lines(ff), l; + + for(l = 0; l < lines ;l++) { + size_t words = procfile_linewords(ff, l); + char *key = procfile_lineword(ff, l, 0); + uint32_t hash = simple_hash(key); + + int k; + for(k = 0; keys[k] ; k++) { + if(unlikely(hash == hashes[k] && strcmp(key, keys[k]) == 0)) { + // fprintf(stderr, "KEY: '%s', l=%zu, w=1, words=%zu\n", key, l, words); + ARL_BASE *arl = bases[k]; + arl_begin(arl); + size_t w = 1; + + while(w + 1 < words) { + char *name = procfile_lineword(ff, l, w); w++; + char *value = procfile_lineword(ff, l, w); w++; + // fprintf(stderr, " > NAME '%s', VALUE '%s', l=%zu, w=%zu, words=%zu\n", name, value, l, w, words); + if(unlikely(arl_check(arl, name, value) != 0)) + break; + } + + break; + } + } + } + + // ------------------------------------------------------------------------ + + if(do_sockets == CONFIG_BOOLEAN_YES || (do_sockets == CONFIG_BOOLEAN_AUTO && sockstat_root.sockets_used)) { + do_sockets = CONFIG_BOOLEAN_YES; + + static RRDSET *st = NULL; + static RRDDIM *rd_used = NULL; + + if(unlikely(!st)) { + st = rrdset_create_localhost( + "ipv4" + , "sockstat_sockets" + , NULL + , "sockets" + , NULL + , "IPv4 Sockets Used" + , "sockets" + , "proc" + , "net/sockstat" + , 2400 + , update_every + , RRDSET_TYPE_LINE + ); + + rd_used = rrddim_add(st, "used", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); + } + else rrdset_next(st); + + rrddim_set_by_pointer(st, rd_used, (collected_number)sockstat_root.sockets_used); + rrdset_done(st); + } + + // ------------------------------------------------------------------------ + + if(do_tcp_sockets == CONFIG_BOOLEAN_YES || (do_tcp_sockets == CONFIG_BOOLEAN_AUTO && (sockstat_root.tcp_inuse || sockstat_root.tcp_orphan || sockstat_root.tcp_tw || sockstat_root.tcp_alloc))) { + do_tcp_sockets = CONFIG_BOOLEAN_YES; + + static RRDSET *st = NULL; + static RRDDIM *rd_inuse = NULL, + *rd_orphan = NULL, + *rd_timewait = NULL, + *rd_alloc = NULL; + + if(unlikely(!st)) { + st = rrdset_create_localhost( + "ipv4" + , "sockstat_tcp_sockets" + , NULL + , "tcp" + , NULL + , "IPv4 TCP Sockets" + , "sockets" + , "proc" + , "net/sockstat" + , 2500 + , update_every + , RRDSET_TYPE_LINE + ); + + rd_alloc = rrddim_add(st, "alloc", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); + rd_orphan = rrddim_add(st, "orphan", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); + rd_inuse = rrddim_add(st, "inuse", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); + rd_timewait = rrddim_add(st, "timewait", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); + } + else rrdset_next(st); + + rrddim_set_by_pointer(st, rd_inuse, (collected_number)sockstat_root.tcp_inuse); + rrddim_set_by_pointer(st, rd_orphan, (collected_number)sockstat_root.tcp_orphan); + rrddim_set_by_pointer(st, rd_timewait, (collected_number)sockstat_root.tcp_tw); + rrddim_set_by_pointer(st, rd_alloc, (collected_number)sockstat_root.tcp_alloc); + rrdset_done(st); + } + + // ------------------------------------------------------------------------ + + if(do_tcp_mem == CONFIG_BOOLEAN_YES || (do_tcp_mem == CONFIG_BOOLEAN_AUTO && sockstat_root.tcp_mem)) { + do_tcp_mem = CONFIG_BOOLEAN_YES; + + static RRDSET *st = NULL; + static RRDDIM *rd_mem = NULL; + + if(unlikely(!st)) { + st = rrdset_create_localhost( + "ipv4" + , "sockstat_tcp_mem" + , NULL + , "tcp" + , NULL + , "IPv4 TCP Sockets Memory" + , "KB" + , "proc" + , "net/sockstat" + , 2540 + , update_every + , RRDSET_TYPE_AREA + ); + + rd_mem = rrddim_add(st, "mem", NULL, sysconf(_SC_PAGESIZE), 1024, RRD_ALGORITHM_ABSOLUTE); + } + else rrdset_next(st); + + rrddim_set_by_pointer(st, rd_mem, (collected_number)sockstat_root.tcp_mem); + rrdset_done(st); + } + + // ------------------------------------------------------------------------ + + if(do_udp_sockets == CONFIG_BOOLEAN_YES || (do_udp_sockets == CONFIG_BOOLEAN_AUTO && sockstat_root.udp_inuse)) { + do_udp_sockets = CONFIG_BOOLEAN_YES; + + static RRDSET *st = NULL; + static RRDDIM *rd_inuse = NULL; + + if(unlikely(!st)) { + st = rrdset_create_localhost( + "ipv4" + , "sockstat_udp_sockets" + , NULL + , "udp" + , NULL + , "IPv4 UDP Sockets" + , "sockets" + , "proc" + , "net/sockstat" + , 2600 + , update_every + , RRDSET_TYPE_LINE + ); + + rd_inuse = rrddim_add(st, "inuse", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); + } + else rrdset_next(st); + + rrddim_set_by_pointer(st, rd_inuse, (collected_number)sockstat_root.udp_inuse); + rrdset_done(st); + } + + // ------------------------------------------------------------------------ + + if(do_udp_mem == CONFIG_BOOLEAN_YES || (do_udp_mem == CONFIG_BOOLEAN_AUTO && sockstat_root.udp_mem)) { + do_udp_mem = CONFIG_BOOLEAN_YES; + + static RRDSET *st = NULL; + static RRDDIM *rd_mem = NULL; + + if(unlikely(!st)) { + st = rrdset_create_localhost( + "ipv4" + , "sockstat_udp_mem" + , NULL + , "udp" + , NULL + , "IPv4 UDP Sockets Memory" + , "KB" + , "proc" + , "net/sockstat" + , 2603 + , update_every + , RRDSET_TYPE_AREA + ); + + rd_mem = rrddim_add(st, "mem", NULL, sysconf(_SC_PAGESIZE), 1024, RRD_ALGORITHM_ABSOLUTE); + } + else rrdset_next(st); + + rrddim_set_by_pointer(st, rd_mem, (collected_number)sockstat_root.udp_mem); + rrdset_done(st); + } + + // ------------------------------------------------------------------------ + + if(do_udplite_sockets == CONFIG_BOOLEAN_YES || (do_udplite_sockets == CONFIG_BOOLEAN_AUTO && sockstat_root.udplite_inuse)) { + do_udplite_sockets = CONFIG_BOOLEAN_YES; + + static RRDSET *st = NULL; + static RRDDIM *rd_inuse = NULL; + + if(unlikely(!st)) { + st = rrdset_create_localhost( + "ipv4" + , "sockstat_udplite_sockets" + , NULL + , "udplite" + , NULL + , "IPv4 UDPLITE Sockets" + , "sockets" + , "proc" + , "net/sockstat" + , 2602 + , update_every + , RRDSET_TYPE_LINE + ); + + rd_inuse = rrddim_add(st, "inuse", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); + } + else rrdset_next(st); + + rrddim_set_by_pointer(st, rd_inuse, (collected_number)sockstat_root.udplite_inuse); + rrdset_done(st); + } + + // ------------------------------------------------------------------------ + + if(do_raw_sockets == CONFIG_BOOLEAN_YES || (do_raw_sockets == CONFIG_BOOLEAN_AUTO && sockstat_root.raw_inuse)) { + do_raw_sockets = CONFIG_BOOLEAN_YES; + + static RRDSET *st = NULL; + static RRDDIM *rd_inuse = NULL; + + if(unlikely(!st)) { + st = rrdset_create_localhost( + "ipv4" + , "sockstat_raw_sockets" + , NULL + , "raw" + , NULL + , "IPv4 RAW Sockets" + , "sockets" + , "proc" + , "net/sockstat" + , 3010 + , update_every + , RRDSET_TYPE_LINE + ); + + rd_inuse = rrddim_add(st, "inuse", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); + } + else rrdset_next(st); + + rrddim_set_by_pointer(st, rd_inuse, (collected_number)sockstat_root.raw_inuse); + rrdset_done(st); + } + + // ------------------------------------------------------------------------ + + if(do_frag_sockets == CONFIG_BOOLEAN_YES || (do_frag_sockets == CONFIG_BOOLEAN_AUTO && sockstat_root.frag_inuse)) { + do_frag_sockets = CONFIG_BOOLEAN_YES; + + static RRDSET *st = NULL; + static RRDDIM *rd_inuse = NULL; + + if(unlikely(!st)) { + st = rrdset_create_localhost( + "ipv4" + , "sockstat_frag_sockets" + , NULL + , "fragments" + , NULL + , "IPv4 FRAG Sockets" + , "fragments" + , "proc" + , "net/sockstat" + , 3010 + , update_every + , RRDSET_TYPE_LINE + ); + + rd_inuse = rrddim_add(st, "inuse", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); + } + else rrdset_next(st); + + rrddim_set_by_pointer(st, rd_inuse, (collected_number)sockstat_root.frag_inuse); + rrdset_done(st); + } + + // ------------------------------------------------------------------------ + + if(do_frag_mem == CONFIG_BOOLEAN_YES || (do_frag_mem == CONFIG_BOOLEAN_AUTO && sockstat_root.frag_memory)) { + do_frag_mem = CONFIG_BOOLEAN_YES; + + static RRDSET *st = NULL; + static RRDDIM *rd_mem = NULL; + + if(unlikely(!st)) { + st = rrdset_create_localhost( + "ipv4" + , "sockstat_frag_mem" + , NULL + , "fragments" + , NULL + , "IPv4 FRAG Sockets Memory" + , "KB" + , "proc" + , "net/sockstat" + , 3020 + , update_every + , RRDSET_TYPE_AREA + ); + + rd_mem = rrddim_add(st, "mem", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); + } + else rrdset_next(st); + + rrddim_set_by_pointer(st, rd_mem, (collected_number)sockstat_root.frag_memory); + rrdset_done(st); + } + + return 0; +} + diff --git a/src/proc_net_sockstat6.c b/src/proc_net_sockstat6.c new file mode 100644 index 00000000..97175ccf --- /dev/null +++ b/src/proc_net_sockstat6.c @@ -0,0 +1,269 @@ +#include "common.h" + +static struct proc_net_sockstat6 { + kernel_uint_t tcp6_inuse; + kernel_uint_t udp6_inuse; + kernel_uint_t udplite6_inuse; + kernel_uint_t raw6_inuse; + kernel_uint_t frag6_inuse; +} sockstat6_root = { 0 }; + +int do_proc_net_sockstat6(int update_every, usec_t dt) { + (void)dt; + + static procfile *ff = NULL; + + static uint32_t hash_raw = 0, + hash_frag = 0, + hash_tcp = 0, + hash_udp = 0, + hash_udplite = 0; + + static ARL_BASE *arl_tcp = NULL; + static ARL_BASE *arl_udp = NULL; + static ARL_BASE *arl_udplite = NULL; + static ARL_BASE *arl_raw = NULL; + static ARL_BASE *arl_frag = NULL; + + static int do_tcp_sockets = -1, do_udp_sockets = -1, do_udplite_sockets = -1, do_raw_sockets = -1, do_frag_sockets = -1; + + static char *keys[6] = { NULL }; + static uint32_t hashes[6] = { 0 }; + static ARL_BASE *bases[6] = { NULL }; + + if(unlikely(!arl_tcp)) { + do_tcp_sockets = config_get_boolean_ondemand("plugin:proc:/proc/net/sockstat6", "ipv6 TCP sockets", CONFIG_BOOLEAN_AUTO); + do_udp_sockets = config_get_boolean_ondemand("plugin:proc:/proc/net/sockstat6", "ipv6 UDP sockets", CONFIG_BOOLEAN_AUTO); + do_udplite_sockets = config_get_boolean_ondemand("plugin:proc:/proc/net/sockstat6", "ipv6 UDPLITE sockets", CONFIG_BOOLEAN_AUTO); + do_raw_sockets = config_get_boolean_ondemand("plugin:proc:/proc/net/sockstat6", "ipv6 RAW sockets", CONFIG_BOOLEAN_AUTO); + do_frag_sockets = config_get_boolean_ondemand("plugin:proc:/proc/net/sockstat6", "ipv6 FRAG sockets", CONFIG_BOOLEAN_AUTO); + + arl_tcp = arl_create("sockstat6/TCP6", arl_callback_str2kernel_uint_t, 60); + arl_expect(arl_tcp, "inuse", &sockstat6_root.tcp6_inuse); + + arl_udp = arl_create("sockstat6/UDP6", arl_callback_str2kernel_uint_t, 60); + arl_expect(arl_udp, "inuse", &sockstat6_root.udp6_inuse); + + arl_udplite = arl_create("sockstat6/UDPLITE6", arl_callback_str2kernel_uint_t, 60); + arl_expect(arl_udplite, "inuse", &sockstat6_root.udplite6_inuse); + + arl_raw = arl_create("sockstat6/RAW6", arl_callback_str2kernel_uint_t, 60); + arl_expect(arl_raw, "inuse", &sockstat6_root.raw6_inuse); + + arl_frag = arl_create("sockstat6/FRAG6", arl_callback_str2kernel_uint_t, 60); + arl_expect(arl_frag, "inuse", &sockstat6_root.frag6_inuse); + + hash_tcp = simple_hash("TCP6"); + hash_udp = simple_hash("UDP6"); + hash_udplite = simple_hash("UDPLITE6"); + hash_raw = simple_hash("RAW6"); + hash_frag = simple_hash("FRAG6"); + + keys[0] = "TCP6"; hashes[0] = hash_tcp; bases[0] = arl_tcp; + keys[1] = "UDP6"; hashes[1] = hash_udp; bases[1] = arl_udp; + keys[2] = "UDPLITE6"; hashes[2] = hash_udplite; bases[2] = arl_udplite; + keys[3] = "RAW6"; hashes[3] = hash_raw; bases[3] = arl_raw; + keys[4] = "FRAG6"; hashes[4] = hash_frag; bases[4] = arl_frag; + keys[5] = NULL; // terminator + } + + if(unlikely(!ff)) { + char filename[FILENAME_MAX + 1]; + snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/net/sockstat6"); + ff = procfile_open(config_get("plugin:proc:/proc/net/sockstat6", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT); + if(unlikely(!ff)) return 1; + } + + ff = procfile_readall(ff); + if(unlikely(!ff)) return 0; // we return 0, so that we will retry to open it next time + + size_t lines = procfile_lines(ff), l; + + for(l = 0; l < lines ;l++) { + size_t words = procfile_linewords(ff, l); + char *key = procfile_lineword(ff, l, 0); + uint32_t hash = simple_hash(key); + + int k; + for(k = 0; keys[k] ; k++) { + if(unlikely(hash == hashes[k] && strcmp(key, keys[k]) == 0)) { + // fprintf(stderr, "KEY: '%s', l=%zu, w=1, words=%zu\n", key, l, words); + ARL_BASE *arl = bases[k]; + arl_begin(arl); + size_t w = 1; + + while(w + 1 < words) { + char *name = procfile_lineword(ff, l, w); w++; + char *value = procfile_lineword(ff, l, w); w++; + // fprintf(stderr, " > NAME '%s', VALUE '%s', l=%zu, w=%zu, words=%zu\n", name, value, l, w, words); + if(unlikely(arl_check(arl, name, value) != 0)) + break; + } + + break; + } + } + } + + // ------------------------------------------------------------------------ + + if(do_tcp_sockets == CONFIG_BOOLEAN_YES || (do_tcp_sockets == CONFIG_BOOLEAN_AUTO && (sockstat6_root.tcp6_inuse))) { + do_tcp_sockets = CONFIG_BOOLEAN_YES; + + static RRDSET *st = NULL; + static RRDDIM *rd_inuse = NULL; + + if(unlikely(!st)) { + st = rrdset_create_localhost( + "ipv6" + , "sockstat6_tcp_sockets" + , NULL + , "tcp6" + , NULL + , "IPv6 TCP Sockets" + , "sockets" + , "proc" + , "net/sockstat6" + , 3599 + , update_every + , RRDSET_TYPE_LINE + ); + + rd_inuse = rrddim_add(st, "inuse", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); + } + else rrdset_next(st); + + rrddim_set_by_pointer(st, rd_inuse, (collected_number)sockstat6_root.tcp6_inuse); + rrdset_done(st); + } + + // ------------------------------------------------------------------------ + + if(do_udp_sockets == CONFIG_BOOLEAN_YES || (do_udp_sockets == CONFIG_BOOLEAN_AUTO && sockstat6_root.udp6_inuse)) { + do_udp_sockets = CONFIG_BOOLEAN_YES; + + static RRDSET *st = NULL; + static RRDDIM *rd_inuse = NULL; + + if(unlikely(!st)) { + st = rrdset_create_localhost( + "ipv6" + , "sockstat6_udp_sockets" + , NULL + , "udp6" + , NULL + , "IPv6 UDP Sockets" + , "sockets" + , "proc" + , "net/sockstat6" + , 3600 + , update_every + , RRDSET_TYPE_LINE + ); + + rd_inuse = rrddim_add(st, "inuse", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); + } + else rrdset_next(st); + + rrddim_set_by_pointer(st, rd_inuse, (collected_number)sockstat6_root.udp6_inuse); + rrdset_done(st); + } + + // ------------------------------------------------------------------------ + + if(do_udplite_sockets == CONFIG_BOOLEAN_YES || (do_udplite_sockets == CONFIG_BOOLEAN_AUTO && sockstat6_root.udplite6_inuse)) { + do_udplite_sockets = CONFIG_BOOLEAN_YES; + + static RRDSET *st = NULL; + static RRDDIM *rd_inuse = NULL; + + if(unlikely(!st)) { + st = rrdset_create_localhost( + "ipv6" + , "sockstat6_udplite_sockets" + , NULL + , "udplite6" + , NULL + , "IPv6 UDPLITE Sockets" + , "sockets" + , "proc" + , "net/sockstat6" + , 3601 + , update_every + , RRDSET_TYPE_LINE + ); + + rd_inuse = rrddim_add(st, "inuse", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); + } + else rrdset_next(st); + + rrddim_set_by_pointer(st, rd_inuse, (collected_number)sockstat6_root.udplite6_inuse); + rrdset_done(st); + } + + // ------------------------------------------------------------------------ + + if(do_raw_sockets == CONFIG_BOOLEAN_YES || (do_raw_sockets == CONFIG_BOOLEAN_AUTO && sockstat6_root.raw6_inuse)) { + do_raw_sockets = CONFIG_BOOLEAN_YES; + + static RRDSET *st = NULL; + static RRDDIM *rd_inuse = NULL; + + if(unlikely(!st)) { + st = rrdset_create_localhost( + "ipv6" + , "sockstat6_raw_sockets" + , NULL + , "raw6" + , NULL + , "IPv6 RAW Sockets" + , "sockets" + , "proc" + , "net/sockstat6" + , 3700 + , update_every + , RRDSET_TYPE_LINE + ); + + rd_inuse = rrddim_add(st, "inuse", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); + } + else rrdset_next(st); + + rrddim_set_by_pointer(st, rd_inuse, (collected_number)sockstat6_root.raw6_inuse); + rrdset_done(st); + } + + // ------------------------------------------------------------------------ + + if(do_frag_sockets == CONFIG_BOOLEAN_YES || (do_frag_sockets == CONFIG_BOOLEAN_AUTO && sockstat6_root.frag6_inuse)) { + do_frag_sockets = CONFIG_BOOLEAN_YES; + + static RRDSET *st = NULL; + static RRDDIM *rd_inuse = NULL; + + if(unlikely(!st)) { + st = rrdset_create_localhost( + "ipv6" + , "sockstat6_frag_sockets" + , NULL + , "fragments6" + , NULL + , "IPv6 FRAG Sockets" + , "fragments" + , "proc" + , "net/sockstat6" + , 3010 + , update_every + , RRDSET_TYPE_LINE + ); + + rd_inuse = rrddim_add(st, "inuse", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); + } + else rrdset_next(st); + + rrddim_set_by_pointer(st, rd_inuse, (collected_number)sockstat6_root.frag6_inuse); + rrdset_done(st); + } + + return 0; +} diff --git a/src/proc_net_softnet_stat.c b/src/proc_net_softnet_stat.c index b03a43c5..f3c117e1 100644 --- a/src/proc_net_softnet_stat.c +++ b/src/proc_net_softnet_stat.c @@ -79,8 +79,20 @@ int do_proc_net_softnet_stat(int update_every, usec_t dt) { st = rrdset_find_bytype_localhost("system", "softnet_stat"); if(unlikely(!st)) { - st = rrdset_create_localhost("system", "softnet_stat", NULL, "softnet_stat", "system.softnet_stat", "System softnet_stat" - , "events/s", 955, update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + "system" + , "softnet_stat" + , NULL + , "softnet_stat" + , "system.softnet_stat" + , "System softnet_stat" + , "events/s" + , "proc" + , "net/softnet_stat" + , 955 + , update_every + , RRDSET_TYPE_LINE + ); for(w = 0; w < allocated_columns ;w++) if(unlikely(softnet_column_name(w))) rrddim_add(st, softnet_column_name(w), NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); @@ -103,8 +115,20 @@ int do_proc_net_softnet_stat(int update_every, usec_t dt) { char title[100+1]; snprintfz(title, 100, "CPU%zu softnet_stat", l); - st = rrdset_create_localhost("cpu", id, NULL, "softnet_stat", "cpu.softnet_stat", title, "events/s", 4101 + l - , update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + "cpu" + , id + , NULL + , "softnet_stat" + , "cpu.softnet_stat" + , title + , "events/s" + , "proc" + , "net/softnet_stat" + , 4101 + l + , update_every + , RRDSET_TYPE_LINE + ); for(w = 0; w < allocated_columns ;w++) if(unlikely(softnet_column_name(w))) rrddim_add(st, softnet_column_name(w), NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); diff --git a/src/proc_net_stat_conntrack.c b/src/proc_net_stat_conntrack.c index e04b80a3..363fbc19 100644 --- a/src/proc_net_stat_conntrack.c +++ b/src/proc_net_stat_conntrack.c @@ -122,136 +122,225 @@ int do_proc_net_stat_conntrack(int update_every, usec_t dt) { unsigned long long max; if(likely(!read_single_number_file(nf_conntrack_max_filename, &max))) - rrdvar_custom_host_variable_set(rrdvar_max, max); + rrdvar_custom_host_variable_set(localhost, rrdvar_max, max); } - RRDSET *st; - // -------------------------------------------------------------------- if(do_sockets) { - st = rrdset_find_localhost(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_sockets"); - if(unlikely(!st)) { - st = rrdset_create_localhost(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_sockets", NULL - , RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Connections" - , "active connections", 3000, update_every, RRDSET_TYPE_LINE); + static RRDSET *st = NULL; + static RRDDIM *rd_connections = NULL; - rrddim_add(st, "connections", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); + if(unlikely(!st)) { + st = rrdset_create_localhost( + RRD_TYPE_NET_STAT_NETFILTER + , RRD_TYPE_NET_STAT_CONNTRACK "_sockets" + , NULL + , RRD_TYPE_NET_STAT_CONNTRACK + , NULL + , "Connection Tracker Connections" + , "active connections" + , "proc" + , "net/stat/nf_conntrack" + , 3000 + , update_every + , RRDSET_TYPE_LINE + ); + + rd_connections = rrddim_add(st, "connections", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); } else rrdset_next(st); - rrddim_set(st, "connections", aentries); + rrddim_set_by_pointer(st, rd_connections, aentries); rrdset_done(st); } // -------------------------------------------------------------------- if(do_new) { - st = rrdset_find_localhost(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_new"); - if(unlikely(!st)) { - st = rrdset_create_localhost(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_new", NULL - , RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker New Connections" - , "connections/s", 3001, update_every, RRDSET_TYPE_LINE); + static RRDSET *st = NULL; + static RRDDIM + *rd_new = NULL, + *rd_ignore = NULL, + *rd_invalid = NULL; - rrddim_add(st, "new", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "ignore", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "invalid", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + if(unlikely(!st)) { + st = rrdset_create_localhost( + RRD_TYPE_NET_STAT_NETFILTER + , RRD_TYPE_NET_STAT_CONNTRACK "_new" + , NULL + , RRD_TYPE_NET_STAT_CONNTRACK + , NULL + , "Connection Tracker New Connections" + , "connections/s" + , "proc" + , "net/stat/nf_conntrack" + , 3001 + , update_every + , RRDSET_TYPE_LINE + ); + + rd_new = rrddim_add(st, "new", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_ignore = rrddim_add(st, "ignore", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_invalid = rrddim_add(st, "invalid", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(st); - rrddim_set(st, "new", anew); - rrddim_set(st, "ignore", aignore); - rrddim_set(st, "invalid", ainvalid); + rrddim_set_by_pointer(st, rd_new, anew); + rrddim_set_by_pointer(st, rd_ignore, aignore); + rrddim_set_by_pointer(st, rd_invalid, ainvalid); rrdset_done(st); } // -------------------------------------------------------------------- if(do_changes) { - st = rrdset_find_localhost(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_changes"); + static RRDSET *st = NULL; + static RRDDIM + *rd_inserted = NULL, + *rd_deleted = NULL, + *rd_delete_list = NULL; + if(unlikely(!st)) { - st = rrdset_create_localhost(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_changes", NULL - , RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Changes", "changes/s" - , 3002, update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + RRD_TYPE_NET_STAT_NETFILTER + , RRD_TYPE_NET_STAT_CONNTRACK "_changes" + , NULL + , RRD_TYPE_NET_STAT_CONNTRACK + , NULL + , "Connection Tracker Changes" + , "changes/s" + , "proc" + , "net/stat/nf_conntrack" + , 3002 + , update_every + , RRDSET_TYPE_LINE + ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - rrddim_add(st, "inserted", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "deleted", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "delete_list", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_inserted = rrddim_add(st, "inserted", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_deleted = rrddim_add(st, "deleted", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_delete_list = rrddim_add(st, "delete_list", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(st); - rrddim_set(st, "inserted", ainsert); - rrddim_set(st, "deleted", adelete); - rrddim_set(st, "delete_list", adelete_list); + rrddim_set_by_pointer(st, rd_inserted, ainsert); + rrddim_set_by_pointer(st, rd_deleted, adelete); + rrddim_set_by_pointer(st, rd_delete_list, adelete_list); rrdset_done(st); } // -------------------------------------------------------------------- if(do_expect) { - st = rrdset_find_localhost(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_expect"); + static RRDSET *st = NULL; + static RRDDIM *rd_created = NULL, + *rd_deleted = NULL, + *rd_new = NULL; + if(unlikely(!st)) { - st = rrdset_create_localhost(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_expect", NULL - , RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Expectations" - , "expectations/s", 3003, update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + RRD_TYPE_NET_STAT_NETFILTER + , RRD_TYPE_NET_STAT_CONNTRACK "_expect" + , NULL + , RRD_TYPE_NET_STAT_CONNTRACK + , NULL + , "Connection Tracker Expectations" + , "expectations/s" + , "proc" + , "net/stat/nf_conntrack" + , 3003 + , update_every + , RRDSET_TYPE_LINE + ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - rrddim_add(st, "created", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "deleted", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "new", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_created = rrddim_add(st, "created", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_deleted = rrddim_add(st, "deleted", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_new = rrddim_add(st, "new", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(st); - rrddim_set(st, "created", aexpect_create); - rrddim_set(st, "deleted", aexpect_delete); - rrddim_set(st, "new", aexpect_new); + rrddim_set_by_pointer(st, rd_created, aexpect_create); + rrddim_set_by_pointer(st, rd_deleted, aexpect_delete); + rrddim_set_by_pointer(st, rd_new, aexpect_new); rrdset_done(st); } // -------------------------------------------------------------------- if(do_search) { - st = rrdset_find_localhost(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_search"); + static RRDSET *st = NULL; + static RRDDIM *rd_searched = NULL, + *rd_restarted = NULL, + *rd_found = NULL; + if(unlikely(!st)) { - st = rrdset_create_localhost(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_search", NULL - , RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Searches" - , "searches/s", 3010, update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + RRD_TYPE_NET_STAT_NETFILTER + , RRD_TYPE_NET_STAT_CONNTRACK "_search" + , NULL + , RRD_TYPE_NET_STAT_CONNTRACK + , NULL + , "Connection Tracker Searches" + , "searches/s" + , "proc" + , "net/stat/nf_conntrack" + , 3010 + , update_every + , RRDSET_TYPE_LINE + ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - rrddim_add(st, "searched", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "restarted", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "found", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_searched = rrddim_add(st, "searched", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_restarted = rrddim_add(st, "restarted", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_found = rrddim_add(st, "found", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(st); - rrddim_set(st, "searched", asearched); - rrddim_set(st, "restarted", asearch_restart); - rrddim_set(st, "found", afound); + rrddim_set_by_pointer(st, rd_searched, asearched); + rrddim_set_by_pointer(st, rd_restarted, asearch_restart); + rrddim_set_by_pointer(st, rd_found, afound); rrdset_done(st); } // -------------------------------------------------------------------- if(do_errors) { - st = rrdset_find_localhost(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_errors"); + static RRDSET *st = NULL; + static RRDDIM *rd_icmp_error = NULL, + *rd_insert_failed = NULL, + *rd_drop = NULL, + *rd_early_drop = NULL; + if(unlikely(!st)) { - st = rrdset_create_localhost(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_errors", NULL - , RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Errors", "events/s" - , 3005, update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + RRD_TYPE_NET_STAT_NETFILTER + , RRD_TYPE_NET_STAT_CONNTRACK "_errors" + , NULL + , RRD_TYPE_NET_STAT_CONNTRACK + , NULL + , "Connection Tracker Errors" + , "events/s" + , "proc" + , "net/stat/nf_conntrack" + , 3005 + , update_every + , RRDSET_TYPE_LINE + ); rrdset_flag_set(st, RRDSET_FLAG_DETAIL); - rrddim_add(st, "icmp_error", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "insert_failed", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "drop", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); - rrddim_add(st, "early_drop", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_icmp_error = rrddim_add(st, "icmp_error", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_insert_failed = rrddim_add(st, "insert_failed", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_drop = rrddim_add(st, "drop", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); + rd_early_drop = rrddim_add(st, "early_drop", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(st); - rrddim_set(st, "icmp_error", aicmp_error); - rrddim_set(st, "insert_failed", ainsert_failed); - rrddim_set(st, "drop", adrop); - rrddim_set(st, "early_drop", aearly_drop); + rrddim_set_by_pointer(st, rd_icmp_error, aicmp_error); + rrddim_set_by_pointer(st, rd_insert_failed, ainsert_failed); + rrddim_set_by_pointer(st, rd_drop, adrop); + rrddim_set_by_pointer(st, rd_early_drop, aearly_drop); rrdset_done(st); } diff --git a/src/proc_net_stat_synproxy.c b/src/proc_net_stat_synproxy.c index 5a1fc30e..0d6f6ee0 100644 --- a/src/proc_net_stat_synproxy.c +++ b/src/proc_net_stat_synproxy.c @@ -53,18 +53,27 @@ int do_proc_net_stat_synproxy(int update_every, usec_t dt) { unsigned long long events = entries + syn_received + cookie_invalid + cookie_valid + cookie_retrans + conn_reopened; - RRDSET *st; - // -------------------------------------------------------------------- if((do_entries == CONFIG_BOOLEAN_AUTO && events) || do_entries == CONFIG_BOOLEAN_YES) { do_entries = CONFIG_BOOLEAN_YES; - st = rrdset_find_localhost(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_SYNPROXY "_entries"); + static RRDSET *st = NULL; if(unlikely(!st)) { - st = rrdset_create_localhost(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_SYNPROXY "_entries", NULL - , RRD_TYPE_NET_STAT_SYNPROXY, NULL, "SYNPROXY Entries Used", "entries", 3304 - , update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + RRD_TYPE_NET_STAT_NETFILTER + , RRD_TYPE_NET_STAT_SYNPROXY "_entries" + , NULL + , RRD_TYPE_NET_STAT_SYNPROXY + , NULL + , "SYNPROXY Entries Used" + , "entries" + , "proc" + , "net/stat/synproxy" + , 3304 + , update_every + , RRDSET_TYPE_LINE + ); rrddim_add(st, "entries", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); } @@ -79,11 +88,22 @@ int do_proc_net_stat_synproxy(int update_every, usec_t dt) { if((do_syns == CONFIG_BOOLEAN_AUTO && events) || do_syns == CONFIG_BOOLEAN_YES) { do_syns = CONFIG_BOOLEAN_YES; - st = rrdset_find_localhost(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_SYNPROXY "_syn_received"); + static RRDSET *st = NULL; if(unlikely(!st)) { - st = rrdset_create_localhost(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_SYNPROXY "_syn_received", NULL - , RRD_TYPE_NET_STAT_SYNPROXY, NULL, "SYNPROXY SYN Packets received", "SYN/s" - , 3301, update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + RRD_TYPE_NET_STAT_NETFILTER + , RRD_TYPE_NET_STAT_SYNPROXY "_syn_received" + , NULL + , RRD_TYPE_NET_STAT_SYNPROXY + , NULL + , "SYNPROXY SYN Packets received" + , "SYN/s" + , "proc" + , "net/stat/synproxy" + , 3301 + , update_every + , RRDSET_TYPE_LINE + ); rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); } @@ -98,11 +118,22 @@ int do_proc_net_stat_synproxy(int update_every, usec_t dt) { if((do_reopened == CONFIG_BOOLEAN_AUTO && events) || do_reopened == CONFIG_BOOLEAN_YES) { do_reopened = CONFIG_BOOLEAN_YES; - st = rrdset_find_localhost(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_SYNPROXY "_conn_reopened"); + static RRDSET *st = NULL; if(unlikely(!st)) { - st = rrdset_create_localhost(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_SYNPROXY "_conn_reopened", NULL - , RRD_TYPE_NET_STAT_SYNPROXY, NULL, "SYNPROXY Connections Reopened" - , "connections/s", 3303, update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + RRD_TYPE_NET_STAT_NETFILTER + , RRD_TYPE_NET_STAT_SYNPROXY "_conn_reopened" + , NULL + , RRD_TYPE_NET_STAT_SYNPROXY + , NULL + , "SYNPROXY Connections Reopened" + , "connections/s" + , "proc" + , "net/stat/synproxy" + , 3303 + , update_every + , RRDSET_TYPE_LINE + ); rrddim_add(st, "reopened", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); } @@ -117,11 +148,22 @@ int do_proc_net_stat_synproxy(int update_every, usec_t dt) { if((do_cookies == CONFIG_BOOLEAN_AUTO && events) || do_cookies == CONFIG_BOOLEAN_YES) { do_cookies = CONFIG_BOOLEAN_YES; - st = rrdset_find_localhost(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_SYNPROXY "_cookies"); + static RRDSET *st = NULL; if(unlikely(!st)) { - st = rrdset_create_localhost(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_SYNPROXY "_cookies", NULL - , RRD_TYPE_NET_STAT_SYNPROXY, NULL, "SYNPROXY TCP Cookies", "cookies/s", 3302 - , update_every, RRDSET_TYPE_LINE); + st = rrdset_create_localhost( + RRD_TYPE_NET_STAT_NETFILTER + , RRD_TYPE_NET_STAT_SYNPROXY "_cookies" + , NULL + , RRD_TYPE_NET_STAT_SYNPROXY + , NULL + , "SYNPROXY TCP Cookies" + , "cookies/s" + , "proc" + , "net/stat/synproxy" + , 3302 + , update_every + , RRDSET_TYPE_LINE + ); rrddim_add(st, "valid", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); rrddim_add(st, "invalid", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL); diff --git a/src/proc_softirqs.c b/src/proc_softirqs.c index 352407a4..a1b9947e 100644 --- a/src/proc_softirqs.c +++ b/src/proc_softirqs.c @@ -136,6 +136,8 @@ int do_proc_softirqs(int update_every, usec_t dt) { , NULL , "System softirqs" , "softirqs/s" + , "proc" + , "softirqs" , 950 , update_every , RRDSET_TYPE_STACKED @@ -212,6 +214,8 @@ int do_proc_softirqs(int update_every, usec_t dt) { , "cpu.softirqs" , title , "softirqs/s" + , "proc" + , "softirqs" , 3000 + c , update_every , RRDSET_TYPE_STACKED diff --git a/src/proc_spl_kstat_zfs.c b/src/proc_spl_kstat_zfs.c index dee7a6b3..9d489d8e 100644 --- a/src/proc_spl_kstat_zfs.c +++ b/src/proc_spl_kstat_zfs.c @@ -3,7 +3,7 @@ #define ZFS_PROC_ARCSTATS "/proc/spl/kstat/zfs/arcstats" -struct arcstats arcstats = { 0 }; +extern struct arcstats arcstats; int do_proc_spl_kstat_zfs_arcstats(int update_every, usec_t dt) { (void)dt; @@ -11,7 +11,7 @@ int do_proc_spl_kstat_zfs_arcstats(int update_every, usec_t dt) { static procfile *ff = NULL; static ARL_BASE *arl_base = NULL; - l2exist = -1; + arcstats.l2exist = -1; if(unlikely(!arl_base)) { arl_base = arl_create("arcstats", NULL, 60); @@ -135,19 +135,19 @@ int do_proc_spl_kstat_zfs_arcstats(int update_every, usec_t dt) { const char *key = procfile_lineword(ff, l, 0); const char *value = procfile_lineword(ff, l, 2); - if(unlikely(l2exist == -1)) { + if(unlikely(arcstats.l2exist == -1)) { if(key[0] == 'l' && key[1] == '2' && key[2] == '_') - l2exist = 1; + arcstats.l2exist = 1; } if(unlikely(arl_check(arl_base, key, value))) break; } - if(unlikely(l2exist == -1)) - l2exist = 0; + if(unlikely(arcstats.l2exist == -1)) + arcstats.l2exist = 0; - generate_charts_arcstats(update_every); - generate_charts_arc_summary(update_every); + generate_charts_arcstats("proc", update_every); + generate_charts_arc_summary("proc", update_every); return 0; } diff --git a/src/proc_stat.c b/src/proc_stat.c index 40bf5cfa..907b659d 100644 --- a/src/proc_stat.c +++ b/src/proc_stat.c @@ -287,6 +287,8 @@ int do_proc_stat(int update_every, usec_t dt) { , context , title , "percentage" + , "proc" + , "stat" , priority , update_every , RRDSET_TYPE_STACKED @@ -337,6 +339,8 @@ int do_proc_stat(int update_every, usec_t dt) { , NULL , "CPU Interrupts" , "interrupts/s" + , "proc" + , "stat" , 900 , update_every , RRDSET_TYPE_LINE @@ -367,6 +371,8 @@ int do_proc_stat(int update_every, usec_t dt) { , NULL , "CPU Context Switches" , "context switches/s" + , "proc" + , "stat" , 800 , update_every , RRDSET_TYPE_LINE @@ -406,6 +412,8 @@ int do_proc_stat(int update_every, usec_t dt) { , NULL , "Started Processes" , "processes/s" + , "proc" + , "stat" , 700 , update_every , RRDSET_TYPE_LINE @@ -436,6 +444,8 @@ int do_proc_stat(int update_every, usec_t dt) { , NULL , "System Processes" , "processes" + , "proc" + , "stat" , 600 , update_every , RRDSET_TYPE_LINE @@ -468,6 +478,8 @@ int do_proc_stat(int update_every, usec_t dt) { , "cpu.core_throttling" , "Core Thermal Throttling Events" , "events/s" + , "proc" + , "stat" , 5001 , update_every , RRDSET_TYPE_LINE @@ -496,6 +508,8 @@ int do_proc_stat(int update_every, usec_t dt) { , "cpu.package_throttling" , "Package Thermal Throttling Events" , "events/s" + , "proc" + , "stat" , 5002 , update_every , RRDSET_TYPE_LINE @@ -524,6 +538,8 @@ int do_proc_stat(int update_every, usec_t dt) { , "cpu.scaling_cur_freq" , "Per CPU Core, Current CPU Scaling Frequency" , "MHz" + , "proc" + , "stat" , 5003 , update_every , RRDSET_TYPE_LINE diff --git a/src/proc_sys_kernel_random_entropy_avail.c b/src/proc_sys_kernel_random_entropy_avail.c index 267ea271..ca4d7657 100644 --- a/src/proc_sys_kernel_random_entropy_avail.c +++ b/src/proc_sys_kernel_random_entropy_avail.c @@ -29,6 +29,8 @@ int do_proc_sys_kernel_random_entropy_avail(int update_every, usec_t dt) { , NULL , "Available Entropy" , "entropy" + , "proc" + , "sys/kernel/random/entropy_avail" , 1000 , update_every , RRDSET_TYPE_LINE diff --git a/src/proc_uptime.c b/src/proc_uptime.c index fb05b5cb..8f4b9029 100644 --- a/src/proc_uptime.c +++ b/src/proc_uptime.c @@ -50,6 +50,8 @@ int do_proc_uptime(int update_every, usec_t dt) { , NULL , "System Uptime" , "seconds" + , "proc" + , "uptime" , 1000 , update_every , RRDSET_TYPE_LINE diff --git a/src/proc_vmstat.c b/src/proc_vmstat.c index 2382116f..72ca3818 100644 --- a/src/proc_vmstat.c +++ b/src/proc_vmstat.c @@ -102,6 +102,8 @@ int do_proc_vmstat(int update_every, usec_t dt) { , NULL , "Swap I/O" , "kilobytes/s" + , "proc" + , "vmstat" , 250 , update_every , RRDSET_TYPE_AREA @@ -126,13 +128,15 @@ int do_proc_vmstat(int update_every, usec_t dt) { if(unlikely(!st_io)) { st_io = rrdset_create_localhost( "system" - , "io" + , "pgpgio" , NULL , "disk" , NULL - , "Disk I/O" + , "Memory Paged from/to disk" , "kilobytes/s" - , 150 + , "proc" + , "vmstat" + , 151 , update_every , RRDSET_TYPE_AREA ); @@ -162,6 +166,8 @@ int do_proc_vmstat(int update_every, usec_t dt) { , NULL , "Memory Page Faults" , "page faults/s" + , "proc" + , "vmstat" , 500 , update_every , RRDSET_TYPE_LINE @@ -205,6 +211,8 @@ int do_proc_vmstat(int update_every, usec_t dt) { , NULL , "NUMA events" , "events/s" + , "proc" + , "vmstat" , 800 , update_every , RRDSET_TYPE_LINE diff --git a/src/registry.c b/src/registry.c index 76e3fa4d..9d382e86 100644 --- a/src/registry.c +++ b/src/registry.c @@ -323,11 +323,21 @@ void registry_statistics(void) { static RRDSET *sts = NULL, *stc = NULL, *stm = NULL; - if(!sts) sts = rrdset_find_localhost("netdata.registry_sessions"); - if(!sts) { - sts = rrdset_create_localhost("netdata", "registry_sessions", NULL, "registry", NULL - , "NetData Registry Sessions", "session", 131000, localhost->rrd_update_every - , RRDSET_TYPE_LINE); + if(unlikely(!sts)) { + sts = rrdset_create_localhost( + "netdata" + , "registry_sessions" + , NULL + , "registry" + , NULL + , "NetData Registry Sessions" + , "session" + , "registry" + , "stats" + , 131000 + , localhost->rrd_update_every + , RRDSET_TYPE_LINE + ); rrddim_add(sts, "sessions", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); } @@ -338,10 +348,21 @@ void registry_statistics(void) { // ------------------------------------------------------------------------ - if(!stc) stc = rrdset_find_localhost("netdata.registry_entries"); - if(!stc) { - stc = rrdset_create_localhost("netdata", "registry_entries", NULL, "registry", NULL, "NetData Registry Entries" - , "entries", 131100, localhost->rrd_update_every, RRDSET_TYPE_LINE); + if(unlikely(!stc)) { + stc = rrdset_create_localhost( + "netdata" + , "registry_entries" + , NULL + , "registry" + , NULL + , "NetData Registry Entries" + , "entries" + , "registry" + , "stats" + , 131100 + , localhost->rrd_update_every + , RRDSET_TYPE_LINE + ); rrddim_add(stc, "persons", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); rrddim_add(stc, "machines", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); @@ -360,10 +381,21 @@ void registry_statistics(void) { // ------------------------------------------------------------------------ - if(!stm) stm = rrdset_find_localhost("netdata.registry_mem"); - if(!stm) { - stm = rrdset_create_localhost("netdata", "registry_mem", NULL, "registry", NULL, "NetData Registry Memory", "KB" - , 131300, localhost->rrd_update_every, RRDSET_TYPE_STACKED); + if(unlikely(!stm)) { + stm = rrdset_create_localhost( + "netdata" + , "registry_mem" + , NULL + , "registry" + , NULL + , "NetData Registry Memory" + , "KB" + , "registry" + , "stats" + , 131300 + , localhost->rrd_update_every + , RRDSET_TYPE_STACKED + ); rrddim_add(stm, "persons", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); rrddim_add(stm, "machines", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE); @@ -87,7 +87,7 @@ struct rrdfamily { size_t use_count; - avl_tree_lock variables_root_index; + avl_tree_lock rrdvar_root_index; }; typedef struct rrdfamily RRDFAMILY; @@ -266,9 +266,9 @@ struct rrdset { char *units; // units of measurement char *context; // the template of this data set - uint32_t hash_context; + uint32_t hash_context; // the hash of the chart's context - RRDSET_TYPE chart_type; + RRDSET_TYPE chart_type; // line, area, stacked int update_every; // every how many seconds is this updated? @@ -282,7 +282,7 @@ struct rrdset { int gap_when_lost_iterations_above; // after how many lost iterations a gap should be stored // netdata will interpolate values for gaps lower than this - long priority; + long priority; // the sorting priority of this chart // ------------------------------------------------------------------------ @@ -300,7 +300,11 @@ struct rrdset { time_t last_accessed_time; // the last time this RRDSET has been accessed time_t upstream_resync_time; // the timestamp up to which we should resync clock upstream - size_t unused[8]; + + char *plugin_name; // the name of the plugin that generated this + char *module_name; // the name of the plugin module that generated this + + size_t unused[6]; uint32_t hash; // a simple hash on the id, to speed up searching // we first compare hashes, and only if the hashes are equal we do string comparisons @@ -315,20 +319,20 @@ struct rrdset { total_number collected_total; // used internally to calculate percentages total_number last_collected_total; // used internally to calculate percentages - RRDFAMILY *rrdfamily; - struct rrdhost *rrdhost; + RRDFAMILY *rrdfamily; // pointer to RRDFAMILY this chart belongs to + struct rrdhost *rrdhost; // pointer to RRDHOST this chart belongs to struct rrdset *next; // linking of rrdsets // ------------------------------------------------------------------------ // local variables - calculated_number green; - calculated_number red; + calculated_number green; // green threshold for this chart + calculated_number red; // red threshold for this chart - avl_tree_lock variables_root_index; - RRDSETVAR *variables; - RRDCALC *alarms; + avl_tree_lock rrdvar_root_index; // RRDVAR index for this chart + RRDSETVAR *variables; // RRDSETVAR linked list for this chart (one RRDSETVAR, many RRDVARs) + RRDCALC *alarms; // RRDCALC linked list for this chart // ------------------------------------------------------------------------ // members for checking the data when loading from disk @@ -368,9 +372,9 @@ typedef struct rrdset RRDSET; // and may lead to missing information. typedef enum rrdhost_flags { - RRDHOST_ORPHAN = 1 << 0, // this host is orphan (not receiving data) - RRDHOST_DELETE_OBSOLETE_CHARTS = 1 << 1, // delete files of obsolete charts - RRDHOST_DELETE_ORPHAN_HOST = 1 << 2 // delete the entire host when orphan + RRDHOST_FLAG_ORPHAN = 1 << 0, // this host is orphan (not receiving data) + RRDHOST_FLAG_DELETE_OBSOLETE_CHARTS = 1 << 1, // delete files of obsolete charts + RRDHOST_FLAG_DELETE_ORPHAN_HOST = 1 << 2 // delete the entire host when orphan } RRDHOST_FLAGS; #ifdef HAVE_C___ATOMIC @@ -410,6 +414,7 @@ struct rrdhost { const char *os; // the O/S type of the host const char *tags; // tags for this host + const char *timezone; // the timezone of the host uint32_t flags; // flags about this RRDHOST @@ -424,17 +429,26 @@ struct rrdhost { // ------------------------------------------------------------------------ // streaming of data to remote hosts - rrdpush - int rrdpush_enabled:1; // 1 when this host sends metrics to another netdata - char *rrdpush_destination; // where to send metrics to - char *rrdpush_api_key; // the api key at the receiving netdata - volatile int rrdpush_connected:1; // 1 when the sender is ready to push metrics - volatile int rrdpush_spawn:1; // 1 when the sender thread has been spawn - volatile int rrdpush_error_shown:1; // 1 when we have logged a communication error - int rrdpush_socket; // the fd of the socket to the remote host, or -1 - pthread_t rrdpush_thread; // the sender thread - netdata_mutex_t rrdpush_mutex; // exclusive access to rrdpush_buffer - int rrdpush_pipe[2]; // collector to sender thread communication - BUFFER *rrdpush_buffer; // collector fills it, sender sends them + int rrdpush_send_enabled:1; // 1 when this host sends metrics to another netdata + char *rrdpush_send_destination; // where to send metrics to + char *rrdpush_send_api_key; // the api key at the receiving netdata + + // the following are state information for the threading + // streaming metrics from this netdata to an upstream netdata + volatile int rrdpush_sender_spawn:1; // 1 when the sender thread has been spawn + pthread_t rrdpush_sender_thread; // the sender thread + + volatile int rrdpush_sender_connected:1; // 1 when the sender is ready to push metrics + int rrdpush_sender_socket; // the fd of the socket to the remote host, or -1 + + volatile int rrdpush_sender_error_shown:1; // 1 when we have logged a communication error + volatile int rrdpush_sender_join:1; // 1 when we have to join the sending thread + + // metrics may be collected asynchronously + // these synchronize all the threads willing the write to our sending buffer + netdata_mutex_t rrdpush_sender_buffer_mutex; // exclusive access to rrdpush_sender_buffer + int rrdpush_sender_pipe[2]; // collector to sender thread signaling + BUFFER *rrdpush_sender_buffer; // collector fills it, sender sends it // ------------------------------------------------------------------------ @@ -483,11 +497,14 @@ struct rrdhost { netdata_rwlock_t rrdhost_rwlock; // lock for this RRDHOST (protects rrdset_root linked list) + // ------------------------------------------------------------------------ + // indexes + avl_tree_lock rrdset_root_index; // the host's charts index (by id) avl_tree_lock rrdset_root_index_name; // the host's charts index (by name) avl_tree_lock rrdfamily_root_index; // the host's chart families index - avl_tree_lock variables_root_index; // the host's chart variables index + avl_tree_lock rrdvar_root_index; // the host's chart variables index struct rrdhost *next; }; @@ -532,6 +549,7 @@ extern RRDHOST *rrdhost_find_or_create( , const char *registry_hostname , const char *guid , const char *os + , const char *timezone , const char *tags , int update_every , long history @@ -560,8 +578,8 @@ extern void __rrd_check_wrlock(const char *file, const char *function, const uns #else #define rrdhost_check_rdlock(host) (void)0 #define rrdhost_check_wrlock(host) (void)0 -#define rrdset_check_rdlock(host) (void)0 -#define rrdset_check_wrlock(host) (void)0 +#define rrdset_check_rdlock(st) (void)0 +#define rrdset_check_wrlock(st) (void)0 #define rrd_check_rdlock() (void)0 #define rrd_check_wrlock() (void)0 #endif @@ -569,7 +587,7 @@ extern void __rrd_check_wrlock(const char *file, const char *function, const uns // ---------------------------------------------------------------------------- // RRDSET functions -extern void rrdset_set_name(RRDSET *st, const char *name); +extern int rrdset_set_name(RRDSET *st, const char *name); extern RRDSET *rrdset_create_custom(RRDHOST *host , const char *type @@ -579,26 +597,30 @@ extern RRDSET *rrdset_create_custom(RRDHOST *host , const char *context , const char *title , const char *units + , const char *plugin + , const char *module , long priority , int update_every , RRDSET_TYPE chart_type , RRD_MEMORY_MODE memory_mode , long history_entries); -#define rrdset_create(host, type, id, name, family, context, title, units, priority, update_every, chart_type) \ - rrdset_create_custom(host, type, id, name, family, context, title, units, priority, update_every, chart_type, (host)->rrd_memory_mode, (host)->rrd_history_entries) +#define rrdset_create(host, type, id, name, family, context, title, units, plugin, module, priority, update_every, chart_type) \ + rrdset_create_custom(host, type, id, name, family, context, title, units, plugin, module, priority, update_every, chart_type, (host)->rrd_memory_mode, (host)->rrd_history_entries) -#define rrdset_create_localhost(type, id, name, family, context, title, units, priority, update_every, chart_type) \ - rrdset_create(localhost, type, id, name, family, context, title, units, priority, update_every, chart_type) +#define rrdset_create_localhost(type, id, name, family, context, title, units, plugin, module, priority, update_every, chart_type) \ + rrdset_create(localhost, type, id, name, family, context, title, units, plugin, module, priority, update_every, chart_type) extern void rrdhost_free_all(void); extern void rrdhost_save_all(void); extern void rrdhost_cleanup_all(void); -extern void rrdhost_cleanup_orphan_hosts(RRDHOST *protected); +extern void rrdhost_cleanup_orphan_hosts_nolock(RRDHOST *protected); extern void rrdhost_free(RRDHOST *host); -extern void rrdhost_save(RRDHOST *host); -extern void rrdhost_delete(RRDHOST *host); +extern void rrdhost_save_charts(RRDHOST *host); +extern void rrdhost_delete_charts(RRDHOST *host); + +extern int rrdhost_should_be_removed(RRDHOST *host, RRDHOST *protected, time_t now); extern void rrdset_update_heterogeneous_flag(RRDSET *st); @@ -678,7 +700,6 @@ extern collected_number rrddim_set(RRDSET *st, const char *id, collected_number extern long align_entries_to_pagesize(RRD_MEMORY_MODE mode, long entries); - // ---------------------------------------------------------------------------- // RRD internal functions diff --git a/src/rrd2json.c b/src/rrd2json.c index 84d90448..00d7a552 100644 --- a/src/rrd2json.c +++ b/src/rrd2json.c @@ -13,6 +13,8 @@ void rrd_stats_api_v1_chart_with_data(RRDSET *st, BUFFER *wb, size_t *dimensions "\t\t\t\"context\": \"%s\",\n" "\t\t\t\"title\": \"%s (%s)\",\n" "\t\t\t\"priority\": %ld,\n" + "\t\t\t\"plugin\": \"%s\",\n" + "\t\t\t\"module\": \"%s\",\n" "\t\t\t\"enabled\": %s,\n" "\t\t\t\"units\": \"%s\",\n" "\t\t\t\"data_url\": \"/api/v1/data?chart=%s\",\n" @@ -29,6 +31,8 @@ void rrd_stats_api_v1_chart_with_data(RRDSET *st, BUFFER *wb, size_t *dimensions , st->context , st->title, st->name , st->priority + , st->plugin_name?st->plugin_name:"" + , st->module_name?st->module_name:"" , rrdset_flag_check(st, RRDSET_FLAG_ENABLED)?"true":"false" , st->units , st->name @@ -48,13 +52,14 @@ void rrd_stats_api_v1_chart_with_data(RRDSET *st, BUFFER *wb, size_t *dimensions memory += rd->memsize; - buffer_sprintf(wb, - "%s" - "\t\t\t\t\"%s\": { \"name\": \"%s\" }" - , dimensions?",\n":"" - , rd->id - , rd->name - ); + buffer_sprintf( + wb + , "%s" + "\t\t\t\t\"%s\": { \"name\": \"%s\" }" + , dimensions ? ",\n" : "" + , rd->id + , rd->name + ); dimensions++; } @@ -67,8 +72,33 @@ void rrd_stats_api_v1_chart_with_data(RRDSET *st, BUFFER *wb, size_t *dimensions buffer_strcat(wb, ",\n\t\t\t\"red\": "); buffer_rrd_value(wb, st->red); + buffer_strcat(wb, ",\n\t\t\t\"alarms\": {\n"); + size_t alarms = 0; + RRDCALC *rc; + for(rc = st->alarms; rc ; rc = rc->rrdset_next) { + + buffer_sprintf( + wb + , "%s" + "\t\t\t\t\"%s\": {\n" + "\t\t\t\t\t\"id\": %u,\n" + "\t\t\t\t\t\"status\": \"%s\",\n" + "\t\t\t\t\t\"units\": \"%s\",\n" + "\t\t\t\t\t\"update_every\": %d\n" + "\t\t\t\t}" + , (alarms) ? ",\n" : "" + , rc->name + , rc->id + , rrdcalc_status2string(rc->status) + , rc->units + , rc->update_every + ); + + alarms++; + } + buffer_sprintf(wb, - "\n\t\t}" + "\n\t\t\t}\n\t\t}" ); rrdset_unlock(st); @@ -92,6 +122,7 @@ void rrd_stats_api_v1_charts(RRDHOST *host, BUFFER *wb) { "\t\"hostname\": \"%s\"" ",\n\t\"version\": \"%s\"" ",\n\t\"os\": \"%s\"" + ",\n\t\"timezone\": \"%s\"" ",\n\t\"update_every\": %d" ",\n\t\"history\": %ld" ",\n\t\"custom_info\": \"%s\"" @@ -99,6 +130,7 @@ void rrd_stats_api_v1_charts(RRDHOST *host, BUFFER *wb) { , host->hostname , program_version , host->os + , host->timezone , host->rrd_update_every , host->rrd_history_entries , custom_dashboard_info_js_filename @@ -126,7 +158,8 @@ void rrd_stats_api_v1_charts(RRDHOST *host, BUFFER *wb) { } rrdhost_unlock(host); - buffer_sprintf(wb, "\n\t}" + buffer_sprintf(wb + , "\n\t}" ",\n\t\"charts_count\": %zu" ",\n\t\"dimensions_count\": %zu" ",\n\t\"alarms_count\": %zu" @@ -142,24 +175,31 @@ void rrd_stats_api_v1_charts(RRDHOST *host, BUFFER *wb) { if(unlikely(rrd_hosts_available > 1)) { rrd_rdlock(); + + size_t found = 0; RRDHOST *h; rrdhost_foreach_read(h) { - buffer_sprintf(wb, - "%s\n\t\t{" - "\n\t\t\t\"hostname\": \"%s\"" - "\n\t\t}" - , (h != localhost) ? "," : "" - , h->hostname - ); + if(!rrdhost_should_be_removed(h, host, now)) { + buffer_sprintf(wb + , "%s\n\t\t{" + "\n\t\t\t\"hostname\": \"%s\"" + "\n\t\t}" + , (found > 0) ? "," : "" + , h->hostname + ); + + found++; + } } + rrd_unlock(); } else { - buffer_sprintf(wb, - "\n\t\t{" - "\n\t\t\t\"hostname\": \"%s\"" - "\n\t\t}" - , host->hostname + buffer_sprintf(wb + , "\n\t\t{" + "\n\t\t\t\"hostname\": \"%s\"" + "\n\t\t}" + , host->hostname ); } diff --git a/src/rrd2json.h b/src/rrd2json.h index a3b9c950..7212c0b3 100644 --- a/src/rrd2json.h +++ b/src/rrd2json.h @@ -61,6 +61,7 @@ #define RRDR_OPTION_LABEL_QUOTES 0x00000400 // in CSV output, wrap header labels in double quotes #define RRDR_OPTION_PERCENTAGE 0x00000800 // give values as percentage of total #define RRDR_OPTION_NOT_ALIGNED 0x00001000 // do not align charts for persistant timeframes +#define RRDR_OPTION_DISPLAY_ABS 0x00002000 // for badges, display the absolute value, but calculate colors with sign extern void rrd_stats_api_v1_chart(RRDSET *st, BUFFER *wb); extern void rrd_stats_api_v1_charts(RRDHOST *host, BUFFER *wb); diff --git a/src/rrdcalc.c b/src/rrdcalc.c index bb90a4c6..4177733b 100644 --- a/src/rrdcalc.c +++ b/src/rrdcalc.c @@ -4,7 +4,7 @@ // ---------------------------------------------------------------------------- // RRDCALC management -inline const char *rrdcalc_status2string(int status) { +inline const char *rrdcalc_status2string(RRDCALC_STATUS status) { switch(status) { case RRDCALC_STATUS_REMOVED: return "REMOVED"; @@ -62,15 +62,15 @@ static void rrdsetcalc_link(RRDSET *st, RRDCALC *rc) { st->red = rc->red; } - rc->local = rrdvar_create_and_index("local", &st->variables_root_index, rc->name, RRDVAR_TYPE_CALCULATED, &rc->value); - rc->family = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rc->name, RRDVAR_TYPE_CALCULATED, &rc->value); + rc->local = rrdvar_create_and_index("local", &st->rrdvar_root_index, rc->name, RRDVAR_TYPE_CALCULATED, &rc->value); + rc->family = rrdvar_create_and_index("family", &st->rrdfamily->rrdvar_root_index, rc->name, RRDVAR_TYPE_CALCULATED, &rc->value); char fullname[RRDVAR_MAX_LENGTH + 1]; snprintfz(fullname, RRDVAR_MAX_LENGTH, "%s.%s", st->id, rc->name); - rc->hostid = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, fullname, RRDVAR_TYPE_CALCULATED, &rc->value); + rc->hostid = rrdvar_create_and_index("host", &st->rrdhost->rrdvar_root_index, fullname, RRDVAR_TYPE_CALCULATED, &rc->value); snprintfz(fullname, RRDVAR_MAX_LENGTH, "%s.%s", st->name, rc->name); - rc->hostname = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, fullname, RRDVAR_TYPE_CALCULATED, &rc->value); + rc->hostname = rrdvar_create_and_index("host", &st->rrdhost->rrdvar_root_index, fullname, RRDVAR_TYPE_CALCULATED, &rc->value); if(!rc->units) rc->units = strdupz(st->units); @@ -173,16 +173,16 @@ inline void rrdsetcalc_unlink(RRDCALC *rc) { rc->rrdset_prev = rc->rrdset_next = NULL; - rrdvar_free(st->rrdhost, &st->variables_root_index, rc->local); + rrdvar_free(st->rrdhost, &st->rrdvar_root_index, rc->local); rc->local = NULL; - rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rc->family); + rrdvar_free(st->rrdhost, &st->rrdfamily->rrdvar_root_index, rc->family); rc->family = NULL; - rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rc->hostid); + rrdvar_free(st->rrdhost, &st->rrdhost->rrdvar_root_index, rc->hostid); rc->hostid = NULL; - rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rc->hostname); + rrdvar_free(st->rrdhost, &st->rrdhost->rrdvar_root_index, rc->hostname); rc->hostname = NULL; rc->rrdset = NULL; @@ -375,8 +375,27 @@ inline RRDCALC *rrdcalc_create(RRDHOST *host, RRDCALCTEMPLATE *rt, const char *c return rc; } -void rrdcalc_free(RRDHOST *host, RRDCALC *rc) { - if(!rc) return; +void rrdcalc_free(RRDCALC *rc) { + if(unlikely(!rc)) return; + + expression_free(rc->calculation); + expression_free(rc->warning); + expression_free(rc->critical); + + freez(rc->name); + freez(rc->chart); + freez(rc->family); + freez(rc->dimensions); + freez(rc->exec); + freez(rc->recipient); + freez(rc->source); + freez(rc->units); + freez(rc->info); + freez(rc); +} + +void rrdcalc_unlink_and_free(RRDHOST *host, RRDCALC *rc) { + if(unlikely(!rc)) return; debug(D_HEALTH, "Health removing alarm '%s.%s' of host '%s'", rc->chart?rc->chart:"NOCHART", rc->name, host->hostname); @@ -398,18 +417,5 @@ void rrdcalc_free(RRDHOST *host, RRDCALC *rc) { error("Cannot unlink alarm '%s.%s' from host '%s': not found", rc->chart?rc->chart:"NOCHART", rc->name, host->hostname); } - expression_free(rc->calculation); - expression_free(rc->warning); - expression_free(rc->critical); - - freez(rc->name); - freez(rc->chart); - freez(rc->family); - freez(rc->dimensions); - freez(rc->exec); - freez(rc->recipient); - freez(rc->source); - freez(rc->units); - freez(rc->info); - freez(rc); + rrdcalc_free(rc); } diff --git a/src/rrdcalctemplate.c b/src/rrdcalctemplate.c index b5d2c7d6..4ec24cd2 100644 --- a/src/rrdcalctemplate.c +++ b/src/rrdcalctemplate.c @@ -22,25 +22,9 @@ void rrdcalctemplate_link_matching(RRDSET *st) { } } -inline void rrdcalctemplate_free(RRDHOST *host, RRDCALCTEMPLATE *rt) { +inline void rrdcalctemplate_free(RRDCALCTEMPLATE *rt) { if(unlikely(!rt)) return; - debug(D_HEALTH, "Health removing template '%s' of host '%s'", rt->name, host->hostname); - - if(host->templates == rt) { - host->templates = rt->next; - } - else { - RRDCALCTEMPLATE *t; - for (t = host->templates; t && t->next != rt; t = t->next ) ; - if(t) { - t->next = rt->next; - rt->next = NULL; - } - else - error("Cannot find RRDCALCTEMPLATE '%s' linked in host '%s'", rt->name, host->hostname); - } - expression_free(rt->calculation); expression_free(rt->warning); expression_free(rt->critical); @@ -59,4 +43,26 @@ inline void rrdcalctemplate_free(RRDHOST *host, RRDCALCTEMPLATE *rt) { freez(rt); } +inline void rrdcalctemplate_unlink_and_free(RRDHOST *host, RRDCALCTEMPLATE *rt) { + if(unlikely(!rt)) return; + + debug(D_HEALTH, "Health removing template '%s' of host '%s'", rt->name, host->hostname); + + if(host->templates == rt) { + host->templates = rt->next; + } + else { + RRDCALCTEMPLATE *t; + for (t = host->templates; t && t->next != rt; t = t->next ) ; + if(t) { + t->next = rt->next; + rt->next = NULL; + } + else + error("Cannot find RRDCALCTEMPLATE '%s' linked in host '%s'", rt->name, host->hostname); + } + + rrdcalctemplate_free(rt); +} + diff --git a/src/rrddim.c b/src/rrddim.c index 8df54839..6477a1cb 100644 --- a/src/rrddim.c +++ b/src/rrddim.c @@ -155,7 +155,7 @@ RRDDIM *rrddim_add_custom(RRDSET *st, const char *id, const char *name, collecte reset = 1; } else if(dt_usec(&now, &rd->last_collected_time) > (rd->entries * rd->update_every * USEC_PER_SEC)) { - error("File %s is too old (last collected %llu seconds ago, but the database is %ld seconds). Clearing it.", fullfilename, dt_usec(&now, &rd->last_collected_time) / USEC_PER_SEC, rd->entries * rd->update_every); + info("File %s is too old (last collected %llu seconds ago, but the database is %ld seconds). Clearing it.", fullfilename, dt_usec(&now, &rd->last_collected_time) / USEC_PER_SEC, rd->entries * rd->update_every); memset(rd, 0, size); reset = 1; } @@ -262,9 +262,9 @@ RRDDIM *rrddim_add_custom(RRDSET *st, const char *id, const char *name, collecte } if(st->rrdhost->health_enabled) { - rrddimvar_create(rd, RRDVAR_TYPE_CALCULATED, NULL, NULL, &rd->last_stored_value, 0); - rrddimvar_create(rd, RRDVAR_TYPE_COLLECTED, NULL, "_raw", &rd->last_collected_value, 0); - rrddimvar_create(rd, RRDVAR_TYPE_TIME_T, NULL, "_last_collected_t", &rd->last_collected_time.tv_sec, 0); + rrddimvar_create(rd, RRDVAR_TYPE_CALCULATED, NULL, NULL, &rd->last_stored_value, RRDVAR_OPTION_DEFAULT); + rrddimvar_create(rd, RRDVAR_TYPE_COLLECTED, NULL, "_raw", &rd->last_collected_value, RRDVAR_OPTION_DEFAULT); + rrddimvar_create(rd, RRDVAR_TYPE_TIME_T, NULL, "_last_collected_t", &rd->last_collected_time.tv_sec, RRDVAR_OPTION_DEFAULT); } rrdset_unlock(st); diff --git a/src/rrddimvar.c b/src/rrddimvar.c index f6eb6d8e..0d20815b 100644 --- a/src/rrddimvar.c +++ b/src/rrddimvar.c @@ -13,38 +13,38 @@ static inline void rrddimvar_free_variables(RRDDIMVAR *rs) { // CHART VARIABLES FOR THIS DIMENSION - rrdvar_free(st->rrdhost, &st->variables_root_index, rs->var_local_id); + rrdvar_free(st->rrdhost, &st->rrdvar_root_index, rs->var_local_id); rs->var_local_id = NULL; - rrdvar_free(st->rrdhost, &st->variables_root_index, rs->var_local_name); + rrdvar_free(st->rrdhost, &st->rrdvar_root_index, rs->var_local_name); rs->var_local_name = NULL; // FAMILY VARIABLES FOR THIS DIMENSION - rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rs->var_family_id); + rrdvar_free(st->rrdhost, &st->rrdfamily->rrdvar_root_index, rs->var_family_id); rs->var_family_id = NULL; - rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rs->var_family_name); + rrdvar_free(st->rrdhost, &st->rrdfamily->rrdvar_root_index, rs->var_family_name); rs->var_family_name = NULL; - rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rs->var_family_contextid); + rrdvar_free(st->rrdhost, &st->rrdfamily->rrdvar_root_index, rs->var_family_contextid); rs->var_family_contextid = NULL; - rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rs->var_family_contextname); + rrdvar_free(st->rrdhost, &st->rrdfamily->rrdvar_root_index, rs->var_family_contextname); rs->var_family_contextname = NULL; // HOST VARIABLES FOR THIS DIMENSION - rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->var_host_chartidid); + rrdvar_free(st->rrdhost, &st->rrdhost->rrdvar_root_index, rs->var_host_chartidid); rs->var_host_chartidid = NULL; - rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->var_host_chartidname); + rrdvar_free(st->rrdhost, &st->rrdhost->rrdvar_root_index, rs->var_host_chartidname); rs->var_host_chartidname = NULL; - rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->var_host_chartnameid); + rrdvar_free(st->rrdhost, &st->rrdhost->rrdvar_root_index, rs->var_host_chartnameid); rs->var_host_chartnameid = NULL; - rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->var_host_chartnamename); + rrdvar_free(st->rrdhost, &st->rrdhost->rrdvar_root_index, rs->var_host_chartnamename); rs->var_host_chartnamename = NULL; // KEYS @@ -115,8 +115,8 @@ static inline void rrddimvar_create_variables(RRDDIMVAR *rs) { // - $id // - $name - rs->var_local_id = rrdvar_create_and_index("local", &st->variables_root_index, rs->key_id, rs->type, rs->value); - rs->var_local_name = rrdvar_create_and_index("local", &st->variables_root_index, rs->key_name, rs->type, rs->value); + rs->var_local_id = rrdvar_create_and_index("local", &st->rrdvar_root_index, rs->key_id, rs->type, rs->value); + rs->var_local_name = rrdvar_create_and_index("local", &st->rrdvar_root_index, rs->key_name, rs->type, rs->value); // FAMILY VARIABLES FOR THIS DIMENSION // ----------------------------------- @@ -127,10 +127,10 @@ static inline void rrddimvar_create_variables(RRDDIMVAR *rs) { // - $chart-context.id // - $chart-context.name - rs->var_family_id = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rs->key_id, rs->type, rs->value); - rs->var_family_name = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rs->key_name, rs->type, rs->value); - rs->var_family_contextid = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rs->key_contextid, rs->type, rs->value); - rs->var_family_contextname = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rs->key_contextname, rs->type, rs->value); + rs->var_family_id = rrdvar_create_and_index("family", &st->rrdfamily->rrdvar_root_index, rs->key_id, rs->type, rs->value); + rs->var_family_name = rrdvar_create_and_index("family", &st->rrdfamily->rrdvar_root_index, rs->key_name, rs->type, rs->value); + rs->var_family_contextid = rrdvar_create_and_index("family", &st->rrdfamily->rrdvar_root_index, rs->key_contextid, rs->type, rs->value); + rs->var_family_contextname = rrdvar_create_and_index("family", &st->rrdfamily->rrdvar_root_index, rs->key_contextname, rs->type, rs->value); // HOST VARIABLES FOR THIS DIMENSION // ----------------------------------- @@ -141,13 +141,13 @@ static inline void rrddimvar_create_variables(RRDDIMVAR *rs) { // - $chart-name.id // - $chart-name.name - rs->var_host_chartidid = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->key_fullidid, rs->type, rs->value); - rs->var_host_chartidname = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->key_fullidname, rs->type, rs->value); - rs->var_host_chartnameid = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->key_fullnameid, rs->type, rs->value); - rs->var_host_chartnamename = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->key_fullnamename, rs->type, rs->value); + rs->var_host_chartidid = rrdvar_create_and_index("host", &st->rrdhost->rrdvar_root_index, rs->key_fullidid, rs->type, rs->value); + rs->var_host_chartidname = rrdvar_create_and_index("host", &st->rrdhost->rrdvar_root_index, rs->key_fullidname, rs->type, rs->value); + rs->var_host_chartnameid = rrdvar_create_and_index("host", &st->rrdhost->rrdvar_root_index, rs->key_fullnameid, rs->type, rs->value); + rs->var_host_chartnamename = rrdvar_create_and_index("host", &st->rrdhost->rrdvar_root_index, rs->key_fullnamename, rs->type, rs->value); } -RRDDIMVAR *rrddimvar_create(RRDDIM *rd, int type, const char *prefix, const char *suffix, void *value, uint32_t options) { +RRDDIMVAR *rrddimvar_create(RRDDIM *rd, RRDVAR_TYPE type, const char *prefix, const char *suffix, void *value, RRDVAR_OPTIONS options) { RRDSET *st = rd->rrdset; debug(D_VARIABLES, "RRDDIMSET create for chart id '%s' name '%s', dimension id '%s', name '%s%s%s'", st->id, st->name, rd->id, (prefix)?prefix:"", rd->name, (suffix)?suffix:""); diff --git a/src/rrdfamily.c b/src/rrdfamily.c index fc203e91..905ae480 100644 --- a/src/rrdfamily.c +++ b/src/rrdfamily.c @@ -30,11 +30,11 @@ RRDFAMILY *rrdfamily_create(RRDHOST *host, const char *id) { rc->hash_family = simple_hash(rc->family); // initialize the variables index - avl_init_lock(&rc->variables_root_index, rrdvar_compare); + avl_init_lock(&rc->rrdvar_root_index, rrdvar_compare); RRDFAMILY *ret = rrdfamily_index_add(host, rc); if(ret != rc) - fatal("RRDFAMILY: INTERNAL ERROR: Expected to INSERT RRDFAMILY '%s' into index, but inserted '%s'.", rc->family, (ret)?ret->family:"NONE"); + error("RRDFAMILY: INTERNAL ERROR: Expected to INSERT RRDFAMILY '%s' into index, but inserted '%s'.", rc->family, (ret)?ret->family:"NONE"); } rc->use_count++; @@ -46,13 +46,14 @@ void rrdfamily_free(RRDHOST *host, RRDFAMILY *rc) { if(!rc->use_count) { RRDFAMILY *ret = rrdfamily_index_del(host, rc); if(ret != rc) - fatal("RRDFAMILY: INTERNAL ERROR: Expected to DELETE RRDFAMILY '%s' from index, but deleted '%s'.", rc->family, (ret)?ret->family:"NONE"); - - if(rc->variables_root_index.avl_tree.root != NULL) - fatal("RRDFAMILY: INTERNAL ERROR: Variables index of RRDFAMILY '%s' that is freed, is not empty.", rc->family); - - freez((void *)rc->family); - freez(rc); + error("RRDFAMILY: INTERNAL ERROR: Expected to DELETE RRDFAMILY '%s' from index, but deleted '%s'.", rc->family, (ret)?ret->family:"NONE"); + else { + debug(D_RRD_CALLS, "RRDFAMILY: Cleaning up remaining family variables for host '%s', family '%s'", host->hostname, rc->family); + rrdvar_free_remaining_variables(host, &rc->rrdvar_root_index); + + freez((void *) rc->family); + freez(rc); + } } } diff --git a/src/rrdhost.c b/src/rrdhost.c index ff8aa561..831cc46c 100644 --- a/src/rrdhost.c +++ b/src/rrdhost.c @@ -86,6 +86,15 @@ static inline void rrdhost_init_os(RRDHOST *host, const char *os) { freez(old); } +static inline void rrdhost_init_timezone(RRDHOST *host, const char *timezone) { + if(host->timezone && timezone && !strcmp(host->timezone, timezone)) + return; + + void *old = (void *)host->timezone; + host->timezone = strdupz((timezone && *timezone)?timezone:"unknown"); + freez(old); +} + static inline void rrdhost_init_machine_guid(RRDHOST *host, const char *machine_guid) { strncpy(host->machine_guid, machine_guid, GUID_LEN); host->machine_guid[GUID_LEN] = '\0'; @@ -100,6 +109,7 @@ RRDHOST *rrdhost_create(const char *hostname, const char *registry_hostname, const char *guid, const char *os, + const char *timezone, const char *tags, int update_every, long entries, @@ -120,33 +130,34 @@ RRDHOST *rrdhost_create(const char *hostname, host->rrd_history_entries = align_entries_to_pagesize(memory_mode, entries); host->rrd_memory_mode = memory_mode; host->health_enabled = (memory_mode == RRD_MEMORY_MODE_NONE)? 0 : health_enabled; - host->rrdpush_enabled = (rrdpush_enabled && rrdpush_destination && *rrdpush_destination && rrdpush_api_key && *rrdpush_api_key); - host->rrdpush_destination = (host->rrdpush_enabled)?strdupz(rrdpush_destination):NULL; - host->rrdpush_api_key = (host->rrdpush_enabled)?strdupz(rrdpush_api_key):NULL; + host->rrdpush_send_enabled = (rrdpush_enabled && rrdpush_destination && *rrdpush_destination && rrdpush_api_key && *rrdpush_api_key); + host->rrdpush_send_destination = (host->rrdpush_send_enabled)?strdupz(rrdpush_destination):NULL; + host->rrdpush_send_api_key = (host->rrdpush_send_enabled)?strdupz(rrdpush_api_key):NULL; - host->rrdpush_pipe[0] = -1; - host->rrdpush_pipe[1] = -1; - host->rrdpush_socket = -1; + host->rrdpush_sender_pipe[0] = -1; + host->rrdpush_sender_pipe[1] = -1; + host->rrdpush_sender_socket = -1; - netdata_mutex_init(&host->rrdpush_mutex); + netdata_mutex_init(&host->rrdpush_sender_buffer_mutex); netdata_rwlock_init(&host->rrdhost_rwlock); rrdhost_init_hostname(host, hostname); rrdhost_init_machine_guid(host, guid); rrdhost_init_os(host, os); + rrdhost_init_timezone(host, timezone); rrdhost_init_tags(host, tags); host->registry_hostname = strdupz((registry_hostname && *registry_hostname)?registry_hostname:hostname); avl_init_lock(&(host->rrdset_root_index), rrdset_compare); avl_init_lock(&(host->rrdset_root_index_name), rrdset_compare_name); avl_init_lock(&(host->rrdfamily_root_index), rrdfamily_compare); - avl_init_lock(&(host->variables_root_index), rrdvar_compare); + avl_init_lock(&(host->rrdvar_root_index), rrdvar_compare); if(config_get_boolean(CONFIG_SECTION_GLOBAL, "delete obsolete charts files", 1)) - rrdhost_flag_set(host, RRDHOST_DELETE_OBSOLETE_CHARTS); + rrdhost_flag_set(host, RRDHOST_FLAG_DELETE_OBSOLETE_CHARTS); if(config_get_boolean(CONFIG_SECTION_GLOBAL, "delete orphan hosts files", 1) && !is_localhost) - rrdhost_flag_set(host, RRDHOST_DELETE_ORPHAN_HOST); + rrdhost_flag_set(host, RRDHOST_FLAG_DELETE_ORPHAN_HOST); // ------------------------------------------------------------------------ @@ -251,7 +262,8 @@ RRDHOST *rrdhost_create(const char *hostname, } else { info("Host '%s' (at registry as '%s') with guid '%s' initialized" - ", os %s" + ", os '%s'" + ", timezone '%s'" ", tags '%s'" ", update every %d" ", memory mode %s" @@ -268,13 +280,14 @@ RRDHOST *rrdhost_create(const char *hostname, , host->registry_hostname , host->machine_guid , host->os + , host->timezone , (host->tags)?host->tags:"" , host->rrd_update_every , rrd_memory_mode_name(host->rrd_memory_mode) , host->rrd_history_entries - , host->rrdpush_enabled?"enabled":"disabled" - , host->rrdpush_destination?host->rrdpush_destination:"" - , host->rrdpush_api_key?host->rrdpush_api_key:"" + , host->rrdpush_send_enabled?"enabled":"disabled" + , host->rrdpush_send_destination?host->rrdpush_send_destination:"" + , host->rrdpush_send_api_key?host->rrdpush_send_api_key:"" , host->health_enabled?"enabled":"disabled" , host->cache_dir , host->varlib_dir @@ -294,6 +307,7 @@ RRDHOST *rrdhost_find_or_create( , const char *registry_hostname , const char *guid , const char *os + , const char *timezone , const char *tags , int update_every , long history @@ -313,6 +327,7 @@ RRDHOST *rrdhost_find_or_create( , registry_hostname , guid , os + , timezone , tags , update_every , history @@ -346,16 +361,18 @@ RRDHOST *rrdhost_find_or_create( // update host tags rrdhost_init_tags(host, tags); } - rrd_unlock(); - rrdhost_cleanup_orphan_hosts(host); + rrdhost_cleanup_orphan_hosts_nolock(host); + + rrd_unlock(); return host; } -static inline int rrdhost_should_be_removed(RRDHOST *host, RRDHOST *protected, time_t now) { +inline int rrdhost_should_be_removed(RRDHOST *host, RRDHOST *protected, time_t now) { if(host != protected && host != localhost + && rrdhost_flag_check(host, RRDHOST_FLAG_ORPHAN) && !host->connected_senders && host->senders_disconnected_time && host->senders_disconnected_time + rrdhost_free_orphan_time < now) @@ -364,11 +381,9 @@ static inline int rrdhost_should_be_removed(RRDHOST *host, RRDHOST *protected, t return 0; } -void rrdhost_cleanup_orphan_hosts(RRDHOST *protected) { +void rrdhost_cleanup_orphan_hosts_nolock(RRDHOST *protected) { time_t now = now_realtime_sec(); - rrd_wrlock(); - RRDHOST *host; restart_after_removal: @@ -376,17 +391,15 @@ restart_after_removal: if(rrdhost_should_be_removed(host, protected, now)) { info("Host '%s' with machine guid '%s' is obsolete - cleaning up.", host->hostname, host->machine_guid); - if(rrdset_flag_check(host, RRDHOST_DELETE_ORPHAN_HOST) && rrdset_flag_check(host, RRDHOST_ORPHAN)) - rrdhost_delete(host); + if(rrdhost_flag_check(host, RRDHOST_FLAG_DELETE_ORPHAN_HOST)) + rrdhost_delete_charts(host); else - rrdhost_save(host); + rrdhost_save_charts(host); rrdhost_free(host); goto restart_after_removal; } } - - rrd_unlock(); } // ---------------------------------------------------------------------------- @@ -406,6 +419,7 @@ void rrd_init(char *hostname) { , registry_get_this_machine_hostname() , registry_get_this_machine_guid() , os_type + , netdata_configured_timezone , config_get(CONFIG_SECTION_BACKEND, "host tags", "") , default_rrd_update_every , default_rrd_history_entries @@ -473,12 +487,19 @@ void rrdhost_free(RRDHOST *host) { // ------------------------------------------------------------------------ // release its children resources - while(host->rrdset_root) rrdset_free(host->rrdset_root); + while(host->rrdset_root) + rrdset_free(host->rrdset_root); - while(host->alarms) rrdcalc_free(host, host->alarms); - while(host->templates) rrdcalctemplate_free(host, host->templates); - health_alarm_log_free(host); + while(host->alarms) + rrdcalc_unlink_and_free(host, host->alarms); + while(host->templates) + rrdcalctemplate_unlink_and_free(host, host->templates); + + debug(D_RRD_CALLS, "RRDHOST: Cleaning up remaining host variables for host '%s'", host->hostname); + rrdvar_free_remaining_variables(host, &host->rrdvar_root_index); + + health_alarm_log_free(host); // ------------------------------------------------------------------------ // remove it from the indexes @@ -508,10 +529,11 @@ void rrdhost_free(RRDHOST *host) { freez((void *)host->tags); freez((void *)host->os); + freez((void *)host->timezone); freez(host->cache_dir); freez(host->varlib_dir); - freez(host->rrdpush_api_key); - freez(host->rrdpush_destination); + freez(host->rrdpush_send_api_key); + freez(host->rrdpush_send_destination); freez(host->health_default_exec); freez(host->health_default_recipient); freez(host->health_log_filename); @@ -534,7 +556,7 @@ void rrdhost_free_all(void) { // ---------------------------------------------------------------------------- // RRDHOST - save host files -void rrdhost_save(RRDHOST *host) { +void rrdhost_save_charts(RRDHOST *host) { if(!host) return; info("Saving/Closing database of host '%s'...", host->hostname); @@ -557,7 +579,7 @@ void rrdhost_save(RRDHOST *host) { // ---------------------------------------------------------------------------- // RRDHOST - delete host files -void rrdhost_delete(RRDHOST *host) { +void rrdhost_delete_charts(RRDHOST *host) { if(!host) return; info("Deleting database of host '%s'...", host->hostname); @@ -582,12 +604,13 @@ void rrdhost_delete(RRDHOST *host) { // ---------------------------------------------------------------------------- // RRDHOST - cleanup host files -void rrdhost_cleanup(RRDHOST *host) { +void rrdhost_cleanup_charts(RRDHOST *host) { if(!host) return; info("Cleaning up database of host '%s'...", host->hostname); RRDSET *st; + uint32_t rrdhost_delete_obsolete_charts = rrdhost_flag_check(host, RRDHOST_FLAG_DELETE_OBSOLETE_CHARTS); // we get a write lock // to ensure only one thread is saving the database @@ -596,7 +619,7 @@ void rrdhost_cleanup(RRDHOST *host) { rrdset_foreach_write(st, host) { rrdset_rdlock(st); - if(rrdset_flag_check(st, RRDSET_FLAG_OBSOLETE) && rrdhost_flag_check(host, RRDHOST_DELETE_OBSOLETE_CHARTS)) + if(rrdhost_delete_obsolete_charts && rrdset_flag_check(st, RRDSET_FLAG_OBSOLETE)) rrdset_delete(st); else rrdset_save(st); @@ -618,7 +641,7 @@ void rrdhost_save_all(void) { RRDHOST *host; rrdhost_foreach_read(host) - rrdhost_save(host); + rrdhost_save_charts(host); rrd_unlock(); } @@ -633,10 +656,10 @@ void rrdhost_cleanup_all(void) { RRDHOST *host; rrdhost_foreach_read(host) { - if(host != localhost && rrdhost_flag_check(host, RRDHOST_DELETE_OBSOLETE_CHARTS) && !host->connected_senders) - rrdhost_delete(host); + if(host != localhost && rrdhost_flag_check(host, RRDHOST_FLAG_DELETE_OBSOLETE_CHARTS) && !host->connected_senders) + rrdhost_delete_charts(host); else - rrdhost_cleanup(host); + rrdhost_cleanup_charts(host); } rrd_unlock(); @@ -651,6 +674,8 @@ void rrdhost_cleanup_obsolete_charts(RRDHOST *host) { RRDSET *st; + uint32_t rrdhost_delete_obsolete_charts = rrdhost_flag_check(host, RRDHOST_FLAG_DELETE_OBSOLETE_CHARTS); + restart_after_removal: rrdset_foreach_write(st, host) { if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_OBSOLETE) @@ -661,7 +686,7 @@ restart_after_removal: rrdset_rdlock(st); - if(rrdhost_flag_check(host, RRDHOST_DELETE_OBSOLETE_CHARTS)) + if(rrdhost_delete_obsolete_charts) rrdset_delete(st); else rrdset_save(st); diff --git a/src/rrdpush.c b/src/rrdpush.c index c1d052fd..2d10c3ca 100644 --- a/src/rrdpush.c +++ b/src/rrdpush.c @@ -59,72 +59,100 @@ int rrdpush_init() { // this is for the first iterations of each chart unsigned int remote_clock_resync_iterations = 60; -#define rrdpush_lock(host) netdata_mutex_lock(&((host)->rrdpush_mutex)) -#define rrdpush_unlock(host) netdata_mutex_unlock(&((host)->rrdpush_mutex)) +#define rrdpush_buffer_lock(host) netdata_mutex_lock(&((host)->rrdpush_sender_buffer_mutex)) +#define rrdpush_buffer_unlock(host) netdata_mutex_unlock(&((host)->rrdpush_sender_buffer_mutex)) // checks if the current chart definition has been sent static inline int need_to_send_chart_definition(RRDSET *st) { + rrdset_check_rdlock(st); + if(unlikely(!(rrdset_flag_check(st, RRDSET_FLAG_EXPOSED_UPSTREAM)))) return 1; RRDDIM *rd; rrddim_foreach_read(rd, st) - if(!rd->exposed) + if(unlikely(!rd->exposed)) return 1; return 0; } // sends the current chart definition -static inline void send_chart_definition(RRDSET *st) { +static inline void rrdpush_send_chart_definition_nolock(RRDSET *st) { + RRDHOST *host = st->rrdhost; + rrdset_flag_set(st, RRDSET_FLAG_EXPOSED_UPSTREAM); - buffer_sprintf(st->rrdhost->rrdpush_buffer, "CHART \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" %ld %d \"%s %s %s\"\n" - , st->id - , st->name - , st->title - , st->units - , st->family - , st->context - , rrdset_type_name(st->chart_type) - , st->priority - , st->update_every - , rrdset_flag_check(st, RRDSET_FLAG_OBSOLETE)?"obsolete":"" - , rrdset_flag_check(st, RRDSET_FLAG_DETAIL)?"detail":"" - , rrdset_flag_check(st, RRDSET_FLAG_STORE_FIRST)?"store_first":"" + // send the chart + buffer_sprintf( + host->rrdpush_sender_buffer + , "CHART \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" %ld %d \"%s %s %s\" \"%s\" \"%s\"\n" + , st->id + , st->name + , st->title + , st->units + , st->family + , st->context + , rrdset_type_name(st->chart_type) + , st->priority + , st->update_every + , rrdset_flag_check(st, RRDSET_FLAG_OBSOLETE)?"obsolete":"" + , rrdset_flag_check(st, RRDSET_FLAG_DETAIL)?"detail":"" + , rrdset_flag_check(st, RRDSET_FLAG_STORE_FIRST)?"store_first":"" + , (st->plugin_name)?st->plugin_name:"" + , (st->module_name)?st->module_name:"" ); + // send the dimensions RRDDIM *rd; rrddim_foreach_read(rd, st) { - buffer_sprintf(st->rrdhost->rrdpush_buffer, "DIMENSION \"%s\" \"%s\" \"%s\" " COLLECTED_NUMBER_FORMAT " " COLLECTED_NUMBER_FORMAT " \"%s %s\"\n" - , rd->id - , rd->name - , rrd_algorithm_name(rd->algorithm) - , rd->multiplier - , rd->divisor - , rrddim_flag_check(rd, RRDDIM_FLAG_HIDDEN)?"hidden":"" - , rrddim_flag_check(rd, RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS)?"noreset":"" + buffer_sprintf( + host->rrdpush_sender_buffer + , "DIMENSION \"%s\" \"%s\" \"%s\" " COLLECTED_NUMBER_FORMAT " " COLLECTED_NUMBER_FORMAT " \"%s %s\"\n" + , rd->id + , rd->name + , rrd_algorithm_name(rd->algorithm) + , rd->multiplier + , rd->divisor + , rrddim_flag_check(rd, RRDDIM_FLAG_HIDDEN)?"hidden":"" + , rrddim_flag_check(rd, RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS)?"noreset":"" ); rd->exposed = 1; } + // send the chart local custom variables + RRDSETVAR *rs; + for(rs = st->variables; rs ;rs = rs->next) { + if(unlikely(rs->options && RRDVAR_OPTION_ALLOCATED)) { + calculated_number *value = (calculated_number *) rs->value; + + buffer_sprintf( + host->rrdpush_sender_buffer + , "VARIABLE CHART %s = " CALCULATED_NUMBER_FORMAT "\n" + , rs->variable + , *value + ); + } + } + st->upstream_resync_time = st->last_collected_time.tv_sec + (remote_clock_resync_iterations * st->update_every); } // sends the current chart dimensions -static inline void send_chart_metrics(RRDSET *st) { - buffer_sprintf(st->rrdhost->rrdpush_buffer, "BEGIN \"%s\" %llu\n", st->id, (st->upstream_resync_time > st->last_collected_time.tv_sec)?st->usec_since_last_update:0); +static inline void rrdpush_send_chart_metrics_nolock(RRDSET *st) { + buffer_sprintf(st->rrdhost->rrdpush_sender_buffer, "BEGIN \"%s\" %llu\n", st->id, (st->upstream_resync_time > st->last_collected_time.tv_sec)?st->usec_since_last_update:0); RRDDIM *rd; rrddim_foreach_read(rd, st) { if(rd->updated && rd->exposed) - buffer_sprintf(st->rrdhost->rrdpush_buffer, "SET \"%s\" = " COLLECTED_NUMBER_FORMAT "\n" - , rd->id - , rd->collected_value + buffer_sprintf(st->rrdhost->rrdpush_sender_buffer + , "SET \"%s\" = " COLLECTED_NUMBER_FORMAT "\n" + , rd->id + , rd->collected_value ); } - buffer_strcat(st->rrdhost->rrdpush_buffer, "END\n"); + buffer_strcat(st->rrdhost->rrdpush_sender_buffer, "END\n"); } static void rrdpush_sender_thread_spawn(RRDHOST *host); @@ -133,9 +161,9 @@ void rrdset_push_chart_definition(RRDSET *st) { RRDHOST *host = st->rrdhost; rrdset_rdlock(st); - rrdpush_lock(host); - send_chart_definition(st); - rrdpush_unlock(host); + rrdpush_buffer_lock(host); + rrdpush_send_chart_definition_nolock(st); + rrdpush_buffer_unlock(host); rrdset_unlock(st); } @@ -145,40 +173,81 @@ void rrdset_done_push(RRDSET *st) { if(unlikely(!rrdset_flag_check(st, RRDSET_FLAG_ENABLED))) return; - rrdpush_lock(host); + rrdpush_buffer_lock(host); - if(unlikely(host->rrdpush_enabled && !host->rrdpush_spawn)) + if(unlikely(host->rrdpush_send_enabled && !host->rrdpush_sender_spawn)) rrdpush_sender_thread_spawn(host); - if(unlikely(!host->rrdpush_buffer || !host->rrdpush_connected)) { - if(unlikely(!host->rrdpush_error_shown)) + if(unlikely(!host->rrdpush_sender_buffer || !host->rrdpush_sender_connected)) { + if(unlikely(!host->rrdpush_sender_error_shown)) error("STREAM %s [send]: not ready - discarding collected metrics.", host->hostname); - host->rrdpush_error_shown = 1; + host->rrdpush_sender_error_shown = 1; - rrdpush_unlock(host); + rrdpush_buffer_unlock(host); return; } - else if(unlikely(host->rrdpush_error_shown)) { - info("STREAM %s [send]: ready - sending metrics...", host->hostname); - host->rrdpush_error_shown = 0; + else if(unlikely(host->rrdpush_sender_error_shown)) { + info("STREAM %s [send]: sending metrics...", host->hostname); + host->rrdpush_sender_error_shown = 0; } if(need_to_send_chart_definition(st)) - send_chart_definition(st); + rrdpush_send_chart_definition_nolock(st); - send_chart_metrics(st); + rrdpush_send_chart_metrics_nolock(st); // signal the sender there are more data - if(write(host->rrdpush_pipe[PIPE_WRITE], " ", 1) == -1) + if(host->rrdpush_sender_pipe[PIPE_WRITE] != -1 && write(host->rrdpush_sender_pipe[PIPE_WRITE], " ", 1) == -1) error("STREAM %s [send]: cannot write to internal pipe", host->hostname); - rrdpush_unlock(host); + rrdpush_buffer_unlock(host); } // ---------------------------------------------------------------------------- // rrdpush sender thread +static inline void rrdpush_sender_add_host_variable_to_buffer_nolock(RRDHOST *host, RRDVAR *rv) { + calculated_number *value = (calculated_number *)rv->value; + + buffer_sprintf( + host->rrdpush_sender_buffer + , "VARIABLE HOST %s = " CALCULATED_NUMBER_FORMAT "\n" + , rv->name + , *value + ); + + debug(D_STREAM, "RRDVAR pushed HOST VARIABLE %s = " CALCULATED_NUMBER_FORMAT, rv->name, *value); +} + +void rrdpush_sender_send_this_host_variable_now(RRDHOST *host, RRDVAR *rv) { + if(host->rrdpush_send_enabled && host->rrdpush_sender_spawn && host->rrdpush_sender_connected) { + rrdpush_buffer_lock(host); + rrdpush_sender_add_host_variable_to_buffer_nolock(host, rv); + rrdpush_buffer_unlock(host); + } +} + +static int rrdpush_sender_thread_custom_host_variables_callback(void *rrdvar_ptr, void *host_ptr) { + RRDVAR *rv = (RRDVAR *)rrdvar_ptr; + RRDHOST *host = (RRDHOST *)host_ptr; + + if(unlikely(rv->type == RRDVAR_TYPE_CALCULATED_ALLOCATED)) { + rrdpush_sender_add_host_variable_to_buffer_nolock(host, rv); + + // return 1, so that the traversal will return the number of variables sent + return 1; + } + + // returning a negative number will break the traversal + return 0; +} + +static void rrdpush_sender_thread_send_custom_host_variables(RRDHOST *host) { + int ret = rrdvar_callback_for_all_host_variables(host, rrdpush_sender_thread_custom_host_variables_callback, host); + debug(D_STREAM, "RRDVAR sent %d VARIABLES", ret); +} + // resets all the chart, so that their definitions // will be resent to the central netdata static void rrdpush_sender_thread_reset_all_charts(RRDHOST *host) { @@ -186,6 +255,7 @@ static void rrdpush_sender_thread_reset_all_charts(RRDHOST *host) { RRDSET *st; rrdset_foreach_read(st, host) { + rrdset_flag_clear(st, RRDSET_FLAG_EXPOSED_UPSTREAM); st->upstream_resync_time = 0; @@ -202,68 +272,198 @@ static void rrdpush_sender_thread_reset_all_charts(RRDHOST *host) { } static inline void rrdpush_sender_thread_data_flush(RRDHOST *host) { - rrdpush_lock(host); + rrdpush_buffer_lock(host); - if(buffer_strlen(host->rrdpush_buffer)) - error("STREAM %s [send]: discarding %zu bytes of metrics already in the buffer.", host->hostname, buffer_strlen(host->rrdpush_buffer)); + if(buffer_strlen(host->rrdpush_sender_buffer)) + error("STREAM %s [send]: discarding %zu bytes of metrics already in the buffer.", host->hostname, buffer_strlen(host->rrdpush_sender_buffer)); - buffer_flush(host->rrdpush_buffer); + buffer_flush(host->rrdpush_sender_buffer); rrdpush_sender_thread_reset_all_charts(host); + rrdpush_sender_thread_send_custom_host_variables(host); - rrdpush_unlock(host); + rrdpush_buffer_unlock(host); } -static void rrdpush_sender_thread_cleanup_locked_all(RRDHOST *host) { - host->rrdpush_connected = 0; +void rrdpush_sender_thread_stop(RRDHOST *host) { + rrdpush_buffer_lock(host); + rrdhost_wrlock(host); + + pthread_t thr = 0; - if(host->rrdpush_socket != -1) { - close(host->rrdpush_socket); - host->rrdpush_socket = -1; + if(host->rrdpush_sender_spawn) { + info("STREAM %s [send]: signaling sending thread to stop...", host->hostname); + + // signal the thread that we want to join it + host->rrdpush_sender_join = 1; + + // copy the thread id, so that we will be waiting for the right one + // even if a new one has been spawn + thr = host->rrdpush_sender_thread; + + // signal it to cancel + int ret = pthread_cancel(host->rrdpush_sender_thread); + if(ret != 0) + error("STREAM %s [send]: pthread_cancel() returned error.", host->hostname); } - // close the pipe - if(host->rrdpush_pipe[PIPE_READ] != -1) { - close(host->rrdpush_pipe[PIPE_READ]); - host->rrdpush_pipe[PIPE_READ] = -1; + rrdhost_unlock(host); + rrdpush_buffer_unlock(host); + + if(thr != 0) { + info("STREAM %s [send]: waiting for the sending thread to stop...", host->hostname); + + void *result; + int ret = pthread_join(thr, &result); + if(ret != 0) + error("STREAM %s [send]: pthread_join() returned error.", host->hostname); + + info("STREAM %s [send]: sending thread has exited.", host->hostname); + } +} + +static inline void rrdpush_sender_thread_close_socket(RRDHOST *host) { + host->rrdpush_sender_connected = 0; + + if(host->rrdpush_sender_socket != -1) { + close(host->rrdpush_sender_socket); + host->rrdpush_sender_socket = -1; + } +} + +static int rrdpush_sender_thread_connect_to_master(RRDHOST *host, int default_port, int timeout, size_t *reconnects_counter, char *connected_to, size_t connected_to_size) { + struct timeval tv = { + .tv_sec = timeout, + .tv_usec = 0 + }; + + // make sure the socket is closed + rrdpush_sender_thread_close_socket(host); + + debug(D_STREAM, "STREAM: Attempting to connect..."); + info("STREAM %s [send to %s]: connecting...", host->hostname, host->rrdpush_send_destination); + + host->rrdpush_sender_socket = connect_to_one_of( + host->rrdpush_send_destination + , default_port + , &tv + , reconnects_counter + , connected_to + , connected_to_size + ); + + if(unlikely(host->rrdpush_sender_socket == -1)) { + error("STREAM %s [send to %s]: failed to connect", host->hostname, host->rrdpush_send_destination); + return 0; + } + + info("STREAM %s [send to %s]: initializing communication...", host->hostname, connected_to); + + #define HTTP_HEADER_SIZE 8192 + char http[HTTP_HEADER_SIZE + 1]; + snprintfz(http, HTTP_HEADER_SIZE, + "STREAM key=%s&hostname=%s®istry_hostname=%s&machine_guid=%s&update_every=%d&os=%s&timezone=%s&tags=%s HTTP/1.1\r\n" + "User-Agent: netdata-push-service/%s\r\n" + "Accept: */*\r\n\r\n" + , host->rrdpush_send_api_key + , host->hostname + , host->registry_hostname + , host->machine_guid + , default_rrd_update_every + , host->os + , host->timezone + , (host->tags)?host->tags:"" + , program_version + ); + + if(send_timeout(host->rrdpush_sender_socket, http, strlen(http), 0, timeout) == -1) { + error("STREAM %s [send to %s]: failed to send HTTP header to remote netdata.", host->hostname, connected_to); + rrdpush_sender_thread_close_socket(host); + return 0; } - if(host->rrdpush_pipe[PIPE_WRITE] != -1) { - close(host->rrdpush_pipe[PIPE_WRITE]); - host->rrdpush_pipe[PIPE_WRITE] = -1; + info("STREAM %s [send to %s]: waiting response from remote netdata...", host->hostname, connected_to); + + if(recv_timeout(host->rrdpush_sender_socket, http, HTTP_HEADER_SIZE, 0, timeout) == -1) { + error("STREAM %s [send to %s]: remote netdata does not respond.", host->hostname, connected_to); + rrdpush_sender_thread_close_socket(host); + return 0; + } + + if(strncmp(http, START_STREAMING_PROMPT, strlen(START_STREAMING_PROMPT)) != 0) { + error("STREAM %s [send to %s]: server is not replying properly (is it a netdata?).", host->hostname, connected_to); + rrdpush_sender_thread_close_socket(host); + return 0; } - buffer_free(host->rrdpush_buffer); - host->rrdpush_buffer = NULL; + info("STREAM %s [send to %s]: established communication - ready to send metrics...", host->hostname, connected_to); - host->rrdpush_spawn = 0; + if(sock_setnonblock(host->rrdpush_sender_socket) < 0) + error("STREAM %s [send to %s]: cannot set non-blocking mode for socket.", host->hostname, connected_to); + + if(sock_enlarge_out(host->rrdpush_sender_socket) < 0) + error("STREAM %s [send to %s]: cannot enlarge the socket buffer.", host->hostname, connected_to); + + debug(D_STREAM, "STREAM: Connected on fd %d...", host->rrdpush_sender_socket); + + return 1; } -void rrdpush_sender_thread_stop(RRDHOST *host) { - rrdpush_lock(host); +static void rrdpush_sender_thread_cleanup_callback(void *ptr) { + RRDHOST *host = (RRDHOST *)ptr; + + rrdpush_buffer_lock(host); rrdhost_wrlock(host); - if(host->rrdpush_spawn) { - info("STREAM %s [send]: stopping sending thread...", host->hostname); - pthread_cancel(host->rrdpush_thread); - rrdpush_sender_thread_cleanup_locked_all(host); + info("STREAM %s [send]: sending thread cleans up...", host->hostname); + + rrdpush_sender_thread_close_socket(host); + + // close the pipe + if(host->rrdpush_sender_pipe[PIPE_READ] != -1) { + close(host->rrdpush_sender_pipe[PIPE_READ]); + host->rrdpush_sender_pipe[PIPE_READ] = -1; + } + + if(host->rrdpush_sender_pipe[PIPE_WRITE] != -1) { + close(host->rrdpush_sender_pipe[PIPE_WRITE]); + host->rrdpush_sender_pipe[PIPE_WRITE] = -1; } + buffer_free(host->rrdpush_sender_buffer); + host->rrdpush_sender_buffer = NULL; + + if(!host->rrdpush_sender_join) { + info("STREAM %s [send]: sending thread detaches itself.", host->hostname); + if(pthread_detach(pthread_self())) + error("STREAM %s [send]: pthread_detach() failed.", host->hostname); + } + + host->rrdpush_sender_spawn = 0; + + info("STREAM %s [send]: sending thread now exits.", host->hostname); + rrdhost_unlock(host); - rrdpush_unlock(host); + rrdpush_buffer_unlock(host); } void *rrdpush_sender_thread(void *ptr) { RRDHOST *host = (RRDHOST *)ptr; - info("STREAM %s [send]: thread created (task id %d)", host->hostname, gettid()); + if(!host->rrdpush_send_enabled || !host->rrdpush_send_destination || !*host->rrdpush_send_destination || !host->rrdpush_send_api_key || !*host->rrdpush_send_api_key) { + error("STREAM %s [send]: thread created (task id %d), but host has streaming disabled.", host->hostname, gettid()); + pthread_exit(NULL); + return NULL; + } - if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0) - error("STREAM %s [send]: cannot set pthread cancel type to DEFERRED.", host->hostname); + info("STREAM %s [send]: thread created (task id %d)", host->hostname, gettid()); if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0) error("STREAM %s [send]: cannot set pthread cancel state to ENABLE.", host->hostname); + if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0) + error("STREAM %s [send]: cannot set pthread cancel type to DEFERRED.", host->hostname); + int timeout = (int)appconfig_get_number(&stream_config, CONFIG_SECTION_STREAM, "timeout seconds", 60); int default_port = (int)appconfig_get_number(&stream_config, CONFIG_SECTION_STREAM, "default port", 19999); size_t max_size = (size_t)appconfig_get_number(&stream_config, CONFIG_SECTION_STREAM, "buffer size bytes", 1024 * 1024); @@ -271,24 +471,17 @@ void *rrdpush_sender_thread(void *ptr) { remote_clock_resync_iterations = (unsigned int)appconfig_get_number(&stream_config, CONFIG_SECTION_STREAM, "initial clock resync iterations", remote_clock_resync_iterations); char connected_to[CONNECTED_TO_SIZE + 1] = ""; - if(!host->rrdpush_enabled || !host->rrdpush_destination || !*host->rrdpush_destination || !host->rrdpush_api_key || !*host->rrdpush_api_key) - goto cleanup; - // initialize rrdpush globals - host->rrdpush_buffer = buffer_create(1); - host->rrdpush_connected = 0; - if(pipe(host->rrdpush_pipe) == -1) fatal("STREAM %s [send]: cannot create required pipe.", host->hostname); + host->rrdpush_sender_buffer = buffer_create(1); + host->rrdpush_sender_connected = 0; + if(pipe(host->rrdpush_sender_pipe) == -1) fatal("STREAM %s [send]: cannot create required pipe.", host->hostname); // initialize local variables size_t begin = 0; size_t reconnects_counter = 0; size_t sent_bytes = 0; - size_t sent_connection = 0; + size_t sent_bytes_on_this_connection = 0; - struct timeval tv = { - .tv_sec = timeout, - .tv_usec = 0 - }; time_t last_sent_t = 0; struct pollfd fds[2], *ifd, *ofd; @@ -297,260 +490,206 @@ void *rrdpush_sender_thread(void *ptr) { ifd = &fds[0]; ofd = &fds[1]; - for(; host->rrdpush_enabled && !netdata_exit ;) { - debug(D_STREAM, "STREAM: Checking if we need to timeout the connection..."); - if(host->rrdpush_socket != -1 && now_monotonic_sec() - last_sent_t > timeout) { - error("STREAM %s [send to %s]: could not send metrics for %d seconds - closing connection - we have sent %zu bytes on this connection.", host->hostname, connected_to, timeout, sent_connection); - close(host->rrdpush_socket); - host->rrdpush_socket = -1; - } + size_t not_connected_loops = 0; - if(unlikely(host->rrdpush_socket == -1)) { - debug(D_STREAM, "STREAM: Attempting to connect..."); + pthread_cleanup_push(rrdpush_sender_thread_cleanup_callback, host); - // stop appending data into rrdpush_buffer - // they will be lost, so there is no point to do it - host->rrdpush_connected = 0; + for(; host->rrdpush_send_enabled && !netdata_exit ;) { + // check for outstanding cancellation requests + pthread_testcancel(); - info("STREAM %s [send to %s]: connecting...", host->hostname, host->rrdpush_destination); - host->rrdpush_socket = connect_to_one_of(host->rrdpush_destination, default_port, &tv, &reconnects_counter, connected_to, CONNECTED_TO_SIZE); + // if we don't have socket open, lets wait a bit + if(unlikely(host->rrdpush_sender_socket == -1)) { + if(not_connected_loops == 0 && sent_bytes_on_this_connection > 0) { + // fast re-connection on first disconnect + sleep_usec(USEC_PER_MS * 500); // milliseconds + } + else { + // slow re-connection on repeating errors + sleep_usec(USEC_PER_SEC * reconnect_delay); // seconds + } - if(unlikely(host->rrdpush_socket == -1)) { - error("STREAM %s [send to %s]: failed to connect", host->hostname, host->rrdpush_destination); - sleep(reconnect_delay); - continue; - } + if(rrdpush_sender_thread_connect_to_master(host, default_port, timeout, &reconnects_counter, connected_to, CONNECTED_TO_SIZE)) { + last_sent_t = now_monotonic_sec(); - info("STREAM %s [send to %s]: initializing communication...", host->hostname, connected_to); + // reset the buffer, to properly send charts and metrics + rrdpush_sender_thread_data_flush(host); - #define HTTP_HEADER_SIZE 8192 - char http[HTTP_HEADER_SIZE + 1]; - snprintfz(http, HTTP_HEADER_SIZE, - "STREAM key=%s&hostname=%s®istry_hostname=%s&machine_guid=%s&update_every=%d&os=%s&tags=%s HTTP/1.1\r\n" - "User-Agent: netdata-push-service/%s\r\n" - "Accept: */*\r\n\r\n" - , host->rrdpush_api_key - , host->hostname - , host->registry_hostname - , host->machine_guid - , default_rrd_update_every - , host->os - , (host->tags)?host->tags:"" - , program_version - ); + // make sure the next reconnection will be immediate + not_connected_loops = 0; - if(send_timeout(host->rrdpush_socket, http, strlen(http), 0, timeout) == -1) { - close(host->rrdpush_socket); - host->rrdpush_socket = -1; - error("STREAM %s [send to %s]: failed to send http header to netdata", host->hostname, connected_to); - sleep(reconnect_delay); - continue; - } + // reset the bytes we have sent for this session + sent_bytes_on_this_connection = 0; - info("STREAM %s [send to %s]: waiting response from remote netdata...", host->hostname, connected_to); + // let the data collection threads know we are ready + host->rrdpush_sender_connected = 1; + } + else { + // increase the failed connections counter + not_connected_loops++; - if(recv_timeout(host->rrdpush_socket, http, HTTP_HEADER_SIZE, 0, timeout) == -1) { - close(host->rrdpush_socket); - host->rrdpush_socket = -1; - error("STREAM %s [send to %s]: failed to initialize communication", host->hostname, connected_to); - sleep(reconnect_delay); - continue; - } + // reset the number of bytes sent + sent_bytes_on_this_connection = 0; + } - if(strncmp(http, START_STREAMING_PROMPT, strlen(START_STREAMING_PROMPT))) { - close(host->rrdpush_socket); - host->rrdpush_socket = -1; - error("STREAM %s [send to %s]: server is not replying properly.", host->hostname, connected_to); - sleep(reconnect_delay); + // loop through continue; } - - info("STREAM %s [send to %s]: established communication - sending metrics...", host->hostname, connected_to); - last_sent_t = now_monotonic_sec(); - - if(sock_setnonblock(host->rrdpush_socket) < 0) - error("STREAM %s [send to %s]: cannot set non-blocking mode for socket.", host->hostname, connected_to); - - if(sock_enlarge_out(host->rrdpush_socket) < 0) - error("STREAM %s [send to %s]: cannot enlarge the socket buffer.", host->hostname, connected_to); - - rrdpush_sender_thread_data_flush(host); - sent_connection = 0; - - // allow appending data into rrdpush_buffer - host->rrdpush_connected = 1; - - debug(D_STREAM, "STREAM: Connected on fd %d...", host->rrdpush_socket); - } - - ifd->fd = host->rrdpush_pipe[PIPE_READ]; - ifd->events = POLLIN; - ifd->revents = 0; - - ofd->fd = host->rrdpush_socket; - ofd->revents = 0; - if(ofd->fd != -1 && begin < buffer_strlen(host->rrdpush_buffer)) { - debug(D_STREAM, "STREAM: Requesting data output on streaming socket %d...", ofd->fd); - ofd->events = POLLOUT; - fdmax = 2; - } - else { - debug(D_STREAM, "STREAM: Not requesting data output on streaming socket %d (nothing to send now)...", ofd->fd); - ofd->events = 0; - fdmax = 1; - } - - debug(D_STREAM, "STREAM: Waiting for poll() events (current buffer length %zu bytes)...", buffer_strlen(host->rrdpush_buffer)); - if(netdata_exit) break; - int retval = poll(fds, fdmax, 1000); - if(netdata_exit) break; - - if(unlikely(retval == -1)) { - debug(D_STREAM, "STREAM: poll() failed (current buffer length %zu bytes)...", buffer_strlen(host->rrdpush_buffer)); - - if(errno == EAGAIN || errno == EINTR) { - debug(D_STREAM, "STREAM: poll() failed with EAGAIN or EINTR..."); - continue; + else if(unlikely(now_monotonic_sec() - last_sent_t > timeout)) { + error("STREAM %s [send to %s]: could not send metrics for %d seconds - closing connection - we have sent %zu bytes on this connection.", host->hostname, connected_to, timeout, sent_bytes_on_this_connection); + rrdpush_sender_thread_close_socket(host); } - error("STREAM %s [send to %s]: failed to poll().", host->hostname, connected_to); - close(host->rrdpush_socket); - host->rrdpush_socket = -1; - break; - } - else if(likely(retval)) { - if (ifd->revents & POLLIN || ifd->revents & POLLPRI) { - debug(D_STREAM, "STREAM: Data added to send buffer (current buffer length %zu bytes)...", buffer_strlen(host->rrdpush_buffer)); + ifd->fd = host->rrdpush_sender_pipe[PIPE_READ]; + ifd->events = POLLIN; + ifd->revents = 0; - char buffer[1000 + 1]; - if (read(host->rrdpush_pipe[PIPE_READ], buffer, 1000) == -1) - error("STREAM %s [send to %s]: cannot read from internal pipe.", host->hostname, connected_to); + ofd->fd = host->rrdpush_sender_socket; + ofd->revents = 0; + if(ofd->fd != -1 && begin < buffer_strlen(host->rrdpush_sender_buffer)) { + debug(D_STREAM, "STREAM: Requesting data output on streaming socket %d...", ofd->fd); + ofd->events = POLLOUT; + fdmax = 2; + } + else { + debug(D_STREAM, "STREAM: Not requesting data output on streaming socket %d (nothing to send now)...", ofd->fd); + ofd->events = 0; + fdmax = 1; } - if (ofd->revents & POLLOUT) { - if (begin < buffer_strlen(host->rrdpush_buffer)) { - debug(D_STREAM, "STREAM: Sending data (current buffer length %zu bytes, begin = %zu)...", buffer_strlen(host->rrdpush_buffer), begin); + debug(D_STREAM, "STREAM: Waiting for poll() events (current buffer length %zu bytes)...", buffer_strlen(host->rrdpush_sender_buffer)); + if(unlikely(netdata_exit)) break; + int retval = poll(fds, fdmax, 1000); + if(unlikely(netdata_exit)) break; - // BEGIN RRDPUSH LOCKED SESSION + if(unlikely(retval == -1)) { + debug(D_STREAM, "STREAM: poll() failed (current buffer length %zu bytes)...", buffer_strlen(host->rrdpush_sender_buffer)); - // during this session, data collectors - // will not be able to append data to our buffer - // but the socket is in non-blocking mode - // so, we will not block at send() + if(errno == EAGAIN || errno == EINTR) { + debug(D_STREAM, "STREAM: poll() failed with EAGAIN or EINTR..."); + } + else { + error("STREAM %s [send to %s]: failed to poll(). Closing socket.", host->hostname, connected_to); + rrdpush_sender_thread_close_socket(host); + } - if (pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL) != 0) - error("STREAM %s [send]: cannot set pthread cancel state to DISABLE.", host->hostname); + continue; + } + else if(likely(retval)) { + if (ifd->revents & POLLIN || ifd->revents & POLLPRI) { + debug(D_STREAM, "STREAM: Data added to send buffer (current buffer length %zu bytes)...", buffer_strlen(host->rrdpush_sender_buffer)); - debug(D_STREAM, "STREAM: Getting exclusive lock on host..."); - rrdpush_lock(host); + char buffer[1000 + 1]; + if (read(host->rrdpush_sender_pipe[PIPE_READ], buffer, 1000) == -1) + error("STREAM %s [send to %s]: cannot read from internal pipe.", host->hostname, connected_to); + } - debug(D_STREAM, "STREAM: Sending data, starting from %zu, size %zu...", begin, buffer_strlen(host->rrdpush_buffer)); - ssize_t ret = send(host->rrdpush_socket, &host->rrdpush_buffer->buffer[begin], buffer_strlen(host->rrdpush_buffer) - begin, MSG_DONTWAIT); - if (unlikely(ret == -1)) { - if (errno != EAGAIN && errno != EINTR && errno != EWOULDBLOCK) { - debug(D_STREAM, "STREAM: Send failed - closing socket..."); - error("STREAM %s [send to %s]: failed to send metrics - closing connection - we have sent %zu bytes on this connection.", host->hostname, connected_to, sent_connection); - close(host->rrdpush_socket); - host->rrdpush_socket = -1; - } - else { - debug(D_STREAM, "STREAM: Send failed - will retry..."); + if (ofd->revents & POLLOUT) { + if (begin < buffer_strlen(host->rrdpush_sender_buffer)) { + debug(D_STREAM, "STREAM: Sending data (current buffer length %zu bytes, begin = %zu)...", buffer_strlen(host->rrdpush_sender_buffer), begin); + + // BEGIN RRDPUSH LOCKED SESSION + + // during this session, data collectors + // will not be able to append data to our buffer + // but the socket is in non-blocking mode + // so, we will not block at send() + + if (pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL) != 0) + error("STREAM %s [send]: cannot set pthread cancel state to DISABLE.", host->hostname); + + debug(D_STREAM, "STREAM: Getting exclusive lock on host..."); + rrdpush_buffer_lock(host); + + debug(D_STREAM, "STREAM: Sending data, starting from %zu, size %zu...", begin, buffer_strlen(host->rrdpush_sender_buffer)); + ssize_t ret = send(host->rrdpush_sender_socket, &host->rrdpush_sender_buffer->buffer[begin], buffer_strlen(host->rrdpush_sender_buffer) - begin, MSG_DONTWAIT); + if (unlikely(ret == -1)) { + if (errno != EAGAIN && errno != EINTR && errno != EWOULDBLOCK) { + debug(D_STREAM, "STREAM: Send failed - closing socket..."); + error("STREAM %s [send to %s]: failed to send metrics - closing connection - we have sent %zu bytes on this connection.", host->hostname, connected_to, sent_bytes_on_this_connection); + rrdpush_sender_thread_close_socket(host); + } + else { + debug(D_STREAM, "STREAM: Send failed - will retry..."); + } } - } - else if (likely(ret > 0)) { - // DEBUG - dump the scring to see it - //char c = host->rrdpush_buffer->buffer[begin + ret]; - //host->rrdpush_buffer->buffer[begin + ret] = '\0'; - //debug(D_STREAM, "STREAM: sent from %zu to %zd:\n%s\n", begin, ret, &host->rrdpush_buffer->buffer[begin]); - //host->rrdpush_buffer->buffer[begin + ret] = c; - - sent_connection += ret; - sent_bytes += ret; - begin += ret; - - if (begin == buffer_strlen(host->rrdpush_buffer)) { - // we send it all - - debug(D_STREAM, "STREAM: Sent %zd bytes (the whole buffer)...", ret); - buffer_flush(host->rrdpush_buffer); - begin = 0; + else if (likely(ret > 0)) { + // DEBUG - dump the string to see it + //char c = host->rrdpush_sender_buffer->buffer[begin + ret]; + //host->rrdpush_sender_buffer->buffer[begin + ret] = '\0'; + //debug(D_STREAM, "STREAM: sent from %zu to %zd:\n%s\n", begin, ret, &host->rrdpush_sender_buffer->buffer[begin]); + //host->rrdpush_sender_buffer->buffer[begin + ret] = c; + + sent_bytes_on_this_connection += ret; + sent_bytes += ret; + begin += ret; + + if (begin == buffer_strlen(host->rrdpush_sender_buffer)) { + // we send it all + + debug(D_STREAM, "STREAM: Sent %zd bytes (the whole buffer)...", ret); + buffer_flush(host->rrdpush_sender_buffer); + begin = 0; + } + else { + debug(D_STREAM, "STREAM: Sent %zd bytes (part of the data buffer)...", ret); + } + + last_sent_t = now_monotonic_sec(); } else { - debug(D_STREAM, "STREAM: Sent %zd bytes (part of the data buffer)...", ret); + debug(D_STREAM, "STREAM: send() returned %zd - closing the socket...", ret); + error("STREAM %s [send to %s]: failed to send metrics (send() returned %zd) - closing connection - we have sent %zu bytes on this connection.", + host->hostname, connected_to, ret, sent_bytes_on_this_connection); + rrdpush_sender_thread_close_socket(host); } - last_sent_t = now_monotonic_sec(); + debug(D_STREAM, "STREAM: Releasing exclusive lock on host..."); + rrdpush_buffer_unlock(host); + + if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0) + error("STREAM %s [send]: cannot set pthread cancel state to ENABLE.", host->hostname); + + // END RRDPUSH LOCKED SESSION } else { - debug(D_STREAM, "STREAM: send() returned %zd - closing the socket...", ret); - error("STREAM %s [send to %s]: failed to send metrics (send() returned %zd) - closing connection - we have sent %zu bytes on this connection.", - host->hostname, connected_to, ret, sent_connection); - close(host->rrdpush_socket); - host->rrdpush_socket = -1; + debug(D_STREAM, "STREAM: we have sent the entire buffer, but we received POLLOUT..."); } - - debug(D_STREAM, "STREAM: Releasing exclusive lock on host..."); - rrdpush_unlock(host); - - if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0) - error("STREAM %s [send]: cannot set pthread cancel state to ENABLE.", host->hostname); - - // END RRDPUSH LOCKED SESSION - } - else { - debug(D_STREAM, "STREAM: we have sent the entire buffer, but we received POLLOUT..."); } - } - if(unlikely(ofd->revents & POLLERR)) { - debug(D_STREAM, "STREAM: Send failed (POLLERR) - closing socket..."); - error("STREAM %s [send to %s]: connection reports errors (POLLERR), closing it - we have sent %zu bytes on this connection.", host->hostname, connected_to, sent_connection); - close(host->rrdpush_socket); - host->rrdpush_socket = -1; - } - else if(unlikely(ofd->revents & POLLHUP)) { - debug(D_STREAM, "STREAM: Send failed (POLLHUP) - closing socket..."); - error("STREAM %s [send to %s]: connection closed by remote end (POLLHUP) - we have sent %zu bytes on this connection.", host->hostname, connected_to, sent_connection); - close(host->rrdpush_socket); - host->rrdpush_socket = -1; + if(host->rrdpush_sender_socket != -1) { + char *error = NULL; + + if (unlikely(ofd->revents & POLLERR)) + error = "socket reports errors (POLLERR)"; + + else if (unlikely(ofd->revents & POLLHUP)) + error = "connection closed by remote end (POLLHUP)"; + + else if (unlikely(ofd->revents & POLLNVAL)) + error = "connection is invalid (POLLNVAL)"; + + if(unlikely(error)) { + debug(D_STREAM, "STREAM: %s - closing socket...", error); + error("STREAM %s [send to %s]: %s - reopening socket - we have sent %zu bytes on this connection.", host->hostname, connected_to, error, sent_bytes_on_this_connection); + rrdpush_sender_thread_close_socket(host); + } + } } - else if(unlikely(ofd->revents & POLLNVAL)) { - debug(D_STREAM, "STREAM: Send failed (POLLNVAL) - closing socket..."); - error("STREAM %s [send to %s]: connection is invalid (POLLNVAL), closing it - we have sent %zu bytes on this connection.", host->hostname, connected_to, sent_connection); - close(host->rrdpush_socket); - host->rrdpush_socket = -1; + else { + debug(D_STREAM, "STREAM: poll() timed out."); } - } - else { - debug(D_STREAM, "STREAM: poll() timed out."); - } - // protection from overflow - if(buffer_strlen(host->rrdpush_buffer) > max_size) { - debug(D_STREAM, "STREAM: Buffer is too big (%zu bytes), bigger than the max (%zu) - flushing it...", buffer_strlen(host->rrdpush_buffer), max_size); - errno = 0; - error("STREAM %s [send to %s]: too many data pending - buffer is %zu bytes long, %zu unsent - we have sent %zu bytes in total, %zu on this connection. Closing connection to flush the data.", host->hostname, connected_to, host->rrdpush_buffer->len, host->rrdpush_buffer->len - begin, sent_bytes, sent_connection); - if(host->rrdpush_socket != -1) { - close(host->rrdpush_socket); - host->rrdpush_socket = -1; + // protection from overflow + if(buffer_strlen(host->rrdpush_sender_buffer) > max_size) { + debug(D_STREAM, "STREAM: Buffer is too big (%zu bytes), bigger than the max (%zu) - flushing it...", buffer_strlen(host->rrdpush_sender_buffer), max_size); + errno = 0; + error("STREAM %s [send to %s]: too many data pending - buffer is %zu bytes long, %zu unsent - we have sent %zu bytes in total, %zu on this connection. Closing connection to flush the data.", host->hostname, connected_to, host->rrdpush_sender_buffer->len, host->rrdpush_sender_buffer->len - begin, sent_bytes, sent_bytes_on_this_connection); + rrdpush_sender_thread_close_socket(host); } } - } - -cleanup: - debug(D_WEB_CLIENT, "STREAM %s [send]: sending thread exits.", host->hostname); - - if(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL) != 0) - error("STREAM %s [send]: cannot set pthread cancel state to DISABLE.", host->hostname); - - rrdpush_lock(host); - rrdhost_wrlock(host); - rrdpush_sender_thread_cleanup_locked_all(host); - rrdhost_unlock(host); - rrdpush_unlock(host); - if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0) - error("STREAM %s [send]: cannot set pthread cancel state to ENABLE.", host->hostname); + pthread_cleanup_pop(1); pthread_exit(NULL); return NULL; @@ -560,7 +699,11 @@ cleanup: // ---------------------------------------------------------------------------- // rrdpush receiver thread -static int rrdpush_receive(int fd, const char *key, const char *hostname, const char *registry_hostname, const char *machine_guid, const char *os, const char *tags, int update_every, char *client_ip, char *client_port) { +static void log_stream_connection(const char *client_ip, const char *client_port, const char *api_key, const char *machine_guid, const char *host, const char *msg) { + log_access("STREAM: %d '[%s]:%s' '%s' host '%s' api key '%s' machine guid '%s'", gettid(), client_ip, client_port, msg, host, api_key, machine_guid); +} + +static int rrdpush_receive(int fd, const char *key, const char *hostname, const char *registry_hostname, const char *machine_guid, const char *os, const char *timezone, const char *tags, int update_every, char *client_ip, char *client_port) { RRDHOST *host; int history = default_rrd_history_entries; RRD_MEMORY_MODE mode = default_rrd_memory_mode; @@ -606,6 +749,7 @@ static int rrdpush_receive(int fd, const char *key, const char *hostname, const , registry_hostname , machine_guid , os + , timezone , tags , update_every , history @@ -618,6 +762,7 @@ static int rrdpush_receive(int fd, const char *key, const char *hostname, const if(!host) { close(fd); + log_stream_connection(client_ip, client_port, key, machine_guid, hostname, "FAILED - CANNOT ACQUIRE HOST"); error("STREAM %s [receive from [%s]:%s]: failed to find/create host structure.", hostname, client_ip, client_port); return 1; } @@ -656,6 +801,7 @@ static int rrdpush_receive(int fd, const char *key, const char *hostname, const info("STREAM %s [receive from [%s]:%s]: initializing communication...", host->hostname, client_ip, client_port); if(send_timeout(fd, START_STREAMING_PROMPT, strlen(START_STREAMING_PROMPT), 0, 60) != strlen(START_STREAMING_PROMPT)) { + log_stream_connection(client_ip, client_port, key, host->machine_guid, host->hostname, "FAILED - CANNOT REPLY"); error("STREAM %s [receive from [%s]:%s]: cannot send ready command.", host->hostname, client_ip, client_port); close(fd); return 0; @@ -668,6 +814,7 @@ static int rrdpush_receive(int fd, const char *key, const char *hostname, const // convert the socket to a FILE * FILE *fp = fdopen(fd, "r"); if(!fp) { + log_stream_connection(client_ip, client_port, key, host->machine_guid, host->hostname, "FAILED - SOCKET ERROR"); error("STREAM %s [receive from [%s]:%s]: failed to get a FILE for FD %d.", host->hostname, client_ip, client_port, fd); close(fd); return 0; @@ -677,8 +824,9 @@ static int rrdpush_receive(int fd, const char *key, const char *hostname, const if(host->connected_senders > 0) info("STREAM %s [receive from [%s]:%s]: multiple streaming connections for the same host detected. If multiple netdata are pushing metrics for the same charts, at the same time, the result is unexpected.", host->hostname, client_ip, client_port); + rrdhost_flag_clear(host, RRDHOST_FLAG_ORPHAN); host->connected_senders++; - rrdhost_flag_clear(host, RRDHOST_ORPHAN); + host->senders_disconnected_time = 0; if(health_enabled != CONFIG_BOOLEAN_NO) { if(alarms_delay > 0) { host->health_delay_up_to = now_realtime_sec() + alarms_delay; @@ -692,20 +840,25 @@ static int rrdpush_receive(int fd, const char *key, const char *hostname, const // call the plugins.d processor to receive the metrics info("STREAM %s [receive from [%s]:%s]: receiving metrics...", host->hostname, client_ip, client_port); + log_stream_connection(client_ip, client_port, key, host->machine_guid, host->hostname, "CONNECTED"); + size_t count = pluginsd_process(host, &cd, fp, 1); - error("STREAM %s [receive from [%s]:%s]: disconnected (completed updates %zu).", host->hostname, client_ip, client_port, count); + + log_stream_connection(client_ip, client_port, key, host->machine_guid, host->hostname, "DISCONNECTED"); + error("STREAM %s [receive from [%s]:%s]: disconnected (completed %zu updates).", host->hostname, client_ip, client_port, count); rrdhost_wrlock(host); host->senders_disconnected_time = now_realtime_sec(); host->connected_senders--; if(!host->connected_senders) { - rrdhost_flag_set(host, RRDHOST_ORPHAN); + rrdhost_flag_set(host, RRDHOST_FLAG_ORPHAN); if(health_enabled == CONFIG_BOOLEAN_AUTO) host->health_enabled = 0; } rrdhost_unlock(host); - rrdpush_sender_thread_stop(host); + if(host->connected_senders == 0) + rrdpush_sender_thread_stop(host); // cleanup fclose(fp); @@ -720,6 +873,7 @@ struct rrdpush_thread { char *registry_hostname; char *machine_guid; char *os; + char *timezone; char *tags; char *client_ip; char *client_port; @@ -737,7 +891,7 @@ static void *rrdpush_receiver_thread(void *ptr) { info("STREAM %s [%s]:%s: receive thread created (task id %d)", rpt->hostname, rpt->client_ip, rpt->client_port, gettid()); - rrdpush_receive(rpt->fd, rpt->key, rpt->hostname, rpt->registry_hostname, rpt->machine_guid, rpt->os, rpt->tags, rpt->update_every, rpt->client_ip, rpt->client_port); + rrdpush_receive(rpt->fd, rpt->key, rpt->hostname, rpt->registry_hostname, rpt->machine_guid, rpt->os, rpt->timezone, rpt->tags, rpt->update_every, rpt->client_ip, rpt->client_port); info("STREAM %s [receive from [%s]:%s]: receive thread ended (task id %d)", rpt->hostname, rpt->client_ip, rpt->client_port, gettid()); freez(rpt->key); @@ -745,6 +899,7 @@ static void *rrdpush_receiver_thread(void *ptr) { freez(rpt->registry_hostname); freez(rpt->machine_guid); freez(rpt->os); + freez(rpt->timezone); freez(rpt->tags); freez(rpt->client_ip); freez(rpt->client_port); @@ -757,25 +912,30 @@ static void *rrdpush_receiver_thread(void *ptr) { static void rrdpush_sender_thread_spawn(RRDHOST *host) { rrdhost_wrlock(host); - if(!host->rrdpush_spawn) { - if(pthread_create(&host->rrdpush_thread, NULL, rrdpush_sender_thread, (void *) host)) + if(!host->rrdpush_sender_spawn) { + if(pthread_create(&host->rrdpush_sender_thread, NULL, rrdpush_sender_thread, (void *) host)) error("STREAM %s [send]: failed to create new thread for client.", host->hostname); - - else if(pthread_detach(host->rrdpush_thread)) - error("STREAM %s [send]: cannot request detach newly created thread.", host->hostname); - - host->rrdpush_spawn = 1; + else + host->rrdpush_sender_spawn = 1; } rrdhost_unlock(host); } +int rrdpush_receiver_permission_denied(struct web_client *w) { + // we always respond with the same message and error code + // to prevent an attacker from gaining info about the error + buffer_flush(w->response.data); + buffer_sprintf(w->response.data, "You are not permitted to access this. Check the logs for more info."); + return 401; +} + int rrdpush_receiver_thread_spawn(RRDHOST *host, struct web_client *w, char *url) { (void)host; info("STREAM [receive from [%s]:%s]: new client connection.", w->client_ip, w->client_port); - char *key = NULL, *hostname = NULL, *registry_hostname = NULL, *machine_guid = NULL, *os = "unknown", *tags = NULL; + char *key = NULL, *hostname = NULL, *registry_hostname = NULL, *machine_guid = NULL, *os = "unknown", *timezone = "unknown", *tags = NULL; int update_every = default_rrd_update_every; char buf[GUID_LEN + 1]; @@ -799,6 +959,8 @@ int rrdpush_receiver_thread_spawn(RRDHOST *host, struct web_client *w, char *url update_every = (int)strtoul(value, NULL, 0); else if(!strcmp(name, "os")) os = value; + else if(!strcmp(name, "timezone")) + timezone = value; else if(!strcmp(name, "tags")) tags = value; else @@ -806,52 +968,71 @@ int rrdpush_receiver_thread_spawn(RRDHOST *host, struct web_client *w, char *url } if(!key || !*key) { + log_stream_connection(w->client_ip, w->client_port, (key && *key)?key:"-", (machine_guid && *machine_guid)?machine_guid:"-", (hostname && *hostname)?hostname:"-", "ACCESS DENIED - NO KEY"); error("STREAM [receive from [%s]:%s]: request without an API key. Forbidding access.", w->client_ip, w->client_port); - buffer_flush(w->response.data); - buffer_sprintf(w->response.data, "You need an API key for this request."); - return 401; + return rrdpush_receiver_permission_denied(w); } if(!hostname || !*hostname) { + log_stream_connection(w->client_ip, w->client_port, (key && *key)?key:"-", (machine_guid && *machine_guid)?machine_guid:"-", (hostname && *hostname)?hostname:"-", "ACCESS DENIED - NO HOSTNAME"); error("STREAM [receive from [%s]:%s]: request without a hostname. Forbidding access.", w->client_ip, w->client_port); - buffer_flush(w->response.data); - buffer_sprintf(w->response.data, "You need to send a hostname too."); - return 400; + return rrdpush_receiver_permission_denied(w); } if(!machine_guid || !*machine_guid) { + log_stream_connection(w->client_ip, w->client_port, (key && *key)?key:"-", (machine_guid && *machine_guid)?machine_guid:"-", (hostname && *hostname)?hostname:"-", "ACCESS DENIED - NO MACHINE GUID"); error("STREAM [receive from [%s]:%s]: request without a machine GUID. Forbidding access.", w->client_ip, w->client_port); - buffer_flush(w->response.data); - buffer_sprintf(w->response.data, "You need to send a machine GUID too."); - return 400; + return rrdpush_receiver_permission_denied(w); } if(regenerate_guid(key, buf) == -1) { + log_stream_connection(w->client_ip, w->client_port, (key && *key)?key:"-", (machine_guid && *machine_guid)?machine_guid:"-", (hostname && *hostname)?hostname:"-", "ACCESS DENIED - INVALID KEY"); error("STREAM [receive from [%s]:%s]: API key '%s' is not valid GUID (use the command uuidgen to generate one). Forbidding access.", w->client_ip, w->client_port, key); - buffer_flush(w->response.data); - buffer_sprintf(w->response.data, "Your API key is invalid."); - return 401; + return rrdpush_receiver_permission_denied(w); } if(regenerate_guid(machine_guid, buf) == -1) { + log_stream_connection(w->client_ip, w->client_port, (key && *key)?key:"-", (machine_guid && *machine_guid)?machine_guid:"-", (hostname && *hostname)?hostname:"-", "ACCESS DENIED - INVALID MACHINE GUID"); error("STREAM [receive from [%s]:%s]: machine GUID '%s' is not GUID. Forbidding access.", w->client_ip, w->client_port, machine_guid); - buffer_flush(w->response.data); - buffer_sprintf(w->response.data, "Your machine GUID is invalid."); - return 404; + return rrdpush_receiver_permission_denied(w); } if(!appconfig_get_boolean(&stream_config, key, "enabled", 0)) { + log_stream_connection(w->client_ip, w->client_port, (key && *key)?key:"-", (machine_guid && *machine_guid)?machine_guid:"-", (hostname && *hostname)?hostname:"-", "ACCESS DENIED - KEY NOT ENABLED"); error("STREAM [receive from [%s]:%s]: API key '%s' is not allowed. Forbidding access.", w->client_ip, w->client_port, key); - buffer_flush(w->response.data); - buffer_sprintf(w->response.data, "Your API key is not permitted access."); - return 401; + return rrdpush_receiver_permission_denied(w); + } + + { + SIMPLE_PATTERN *key_allow_from = simple_pattern_create(appconfig_get(&stream_config, key, "allow from", "*"), SIMPLE_PATTERN_EXACT); + if(key_allow_from) { + if(!simple_pattern_matches(key_allow_from, w->client_ip)) { + simple_pattern_free(key_allow_from); + log_stream_connection(w->client_ip, w->client_port, (key && *key)?key:"-", (machine_guid && *machine_guid)?machine_guid:"-", (hostname && *hostname) ? hostname : "-", "ACCESS DENIED - KEY NOT ALLOWED FROM THIS IP"); + error("STREAM [receive from [%s]:%s]: API key '%s' is not permitted from this IP. Forbidding access.", w->client_ip, w->client_port, key); + return rrdpush_receiver_permission_denied(w); + } + simple_pattern_free(key_allow_from); + } } if(!appconfig_get_boolean(&stream_config, machine_guid, "enabled", 1)) { + log_stream_connection(w->client_ip, w->client_port, (key && *key)?key:"-", (machine_guid && *machine_guid)?machine_guid:"-", (hostname && *hostname)?hostname:"-", "ACCESS DENIED - MACHINE GUID NOT ENABLED"); error("STREAM [receive from [%s]:%s]: machine GUID '%s' is not allowed. Forbidding access.", w->client_ip, w->client_port, machine_guid); - buffer_flush(w->response.data); - buffer_sprintf(w->response.data, "Your machine guide is not permitted access."); - return 404; + return rrdpush_receiver_permission_denied(w); + } + + { + SIMPLE_PATTERN *machine_allow_from = simple_pattern_create(appconfig_get(&stream_config, machine_guid, "allow from", "*"), SIMPLE_PATTERN_EXACT); + if(machine_allow_from) { + if(!simple_pattern_matches(machine_allow_from, w->client_ip)) { + simple_pattern_free(machine_allow_from); + log_stream_connection(w->client_ip, w->client_port, (key && *key)?key:"-", (machine_guid && *machine_guid)?machine_guid:"-", (hostname && *hostname) ? hostname : "-", "ACCESS DENIED - MACHINE GUID NOT ALLOWED FROM THIS IP"); + error("STREAM [receive from [%s]:%s]: Machine GUID '%s' is not permitted from this IP. Forbidding access.", w->client_ip, w->client_port, machine_guid); + return rrdpush_receiver_permission_denied(w); + } + simple_pattern_free(machine_allow_from); + } } struct rrdpush_thread *rpt = mallocz(sizeof(struct rrdpush_thread)); @@ -861,6 +1042,7 @@ int rrdpush_receiver_thread_spawn(RRDHOST *host, struct web_client *w, char *url rpt->registry_hostname = strdupz((registry_hostname && *registry_hostname)?registry_hostname:hostname); rpt->machine_guid = strdupz(machine_guid); rpt->os = strdupz(os); + rpt->timezone = strdupz(timezone); rpt->tags = (tags)?strdupz(tags):NULL; rpt->client_ip = strdupz(w->client_ip); rpt->client_port = strdupz(w->client_port); diff --git a/src/rrdpush.h b/src/rrdpush.h index c3c7f4a5..bf3d9435 100644 --- a/src/rrdpush.h +++ b/src/rrdpush.h @@ -14,4 +14,6 @@ extern void *rrdpush_sender_thread(void *ptr); extern int rrdpush_receiver_thread_spawn(RRDHOST *host, struct web_client *w, char *url); extern void rrdpush_sender_thread_stop(RRDHOST *host); +extern void rrdpush_sender_send_this_host_variable_now(RRDHOST *host, RRDVAR *rv); + #endif //NETDATA_RRDPUSH_H diff --git a/src/rrdset.c b/src/rrdset.c index c5168f02..8504d1cb 100644 --- a/src/rrdset.c +++ b/src/rrdset.c @@ -135,11 +135,11 @@ char *rrdset_strncpyz_name(char *to, const char *from, size_t length) { return to; } -void rrdset_set_name(RRDSET *st, const char *name) { +int rrdset_set_name(RRDSET *st, const char *name) { if(unlikely(st->name && !strcmp(st->name, name))) - return; + return 1; - debug(D_RRD_CALLS, "rrdset_set_name() old: %s, new: %s", st->name, name); + debug(D_RRD_CALLS, "rrdset_set_name() old: '%s', new: '%s'", st->name?st->name:"", name); char b[CONFIG_MAX_VALUE + 1]; char n[RRD_ID_LENGTH_MAX + 1]; @@ -147,6 +147,11 @@ void rrdset_set_name(RRDSET *st, const char *name) { snprintfz(n, RRD_ID_LENGTH_MAX, "%s.%s", st->type, name); rrdset_strncpyz_name(b, n, CONFIG_MAX_VALUE); + if(rrdset_index_find_name(st->rrdhost, b, 0)) { + error("RRDSET: chart name '%s' on host '%s' already exists.", b, st->rrdhost->hostname); + return 0; + } + if(st->name) { rrdset_index_del_name(st->rrdhost, st); st->name = config_set_default(st->config_section, "name", b); @@ -166,6 +171,8 @@ void rrdset_set_name(RRDSET *st, const char *name) { if(unlikely(rrdset_index_add_name(st->rrdhost, st) != st)) error("RRDSET: INTERNAL ERROR: attempted to index duplicate chart name '%s'", st->name); + + return 1; } inline void rrdset_is_obsolete(RRDSET *st) { @@ -175,7 +182,7 @@ inline void rrdset_is_obsolete(RRDSET *st) { // the chart will not get more updates (data collection) // so, we have to push its definition now - if(unlikely(st->rrdhost->rrdpush_enabled)) + if(unlikely(st->rrdhost->rrdpush_send_enabled)) rrdset_push_chart_definition(st); } } @@ -309,6 +316,9 @@ void rrdset_free(RRDSET *st) { rrdfamily_free(st->rrdhost, st->rrdfamily); + debug(D_RRD_CALLS, "RRDSET: Cleaning up remaining chart variables for host '%s', chart '%s'", st->rrdhost->hostname, st->id); + rrdvar_free_remaining_variables(st->rrdhost, &st->rrdvar_root_index); + // ------------------------------------------------------------------------ // unlink it from the host @@ -334,6 +344,8 @@ void rrdset_free(RRDSET *st) { // free directly allocated members freez(st->config_section); + freez(st->plugin_name); + freez(st->module_name); switch(st->rrd_memory_mode) { case RRD_MEMORY_MODE_SAVE: @@ -416,6 +428,8 @@ RRDSET *rrdset_create_custom( , const char *context , const char *title , const char *units + , const char *plugin + , const char *module , long priority , int update_every , RRDSET_TYPE chart_type @@ -423,12 +437,30 @@ RRDSET *rrdset_create_custom( , long history_entries ) { if(!type || !type[0]) { - fatal("Cannot create rrd stats without a type."); + fatal("Cannot create rrd stats without a type: id '%s', name '%s', family '%s', context '%s', title '%s', units '%s', plugin '%s', module '%s'." + , (id && *id)?id:"<unset>" + , (name && *name)?name:"<unset>" + , (family && *family)?family:"<unset>" + , (context && *context)?context:"<unset>" + , (title && *title)?title:"<unset>" + , (units && *units)?units:"<unset>" + , (plugin && *plugin)?plugin:"<unset>" + , (module && *module)?module:"<unset>" + ); return NULL; } if(!id || !id[0]) { - fatal("Cannot create rrd stats without an id."); + fatal("Cannot create rrd stats without an id: type '%s', name '%s', family '%s', context '%s', title '%s', units '%s', plugin '%s', module '%s'." + , type + , (name && *name)?name:"<unset>" + , (family && *family)?family:"<unset>" + , (context && *context)?context:"<unset>" + , (title && *title)?title:"<unset>" + , (units && *units)?units:"<unset>" + , (plugin && *plugin)?plugin:"<unset>" + , (module && *module)?module:"<unset>" + ); return NULL; } @@ -495,7 +527,7 @@ RRDSET *rrdset_create_custom( if(st) { memset(&st->avl, 0, sizeof(avl)); memset(&st->avlname, 0, sizeof(avl)); - memset(&st->variables_root_index, 0, sizeof(avl_tree_lock)); + memset(&st->rrdvar_root_index, 0, sizeof(avl_tree_lock)); memset(&st->dimensions_index, 0, sizeof(avl_tree_lock)); memset(&st->rrdset_rwlock, 0, sizeof(netdata_rwlock_t)); @@ -507,6 +539,8 @@ RRDSET *rrdset_create_custom( st->units = NULL; st->context = NULL; st->cache_dir = NULL; + st->plugin_name = NULL; + st->module_name = NULL; st->dimensions = NULL; st->rrdfamily = NULL; st->rrdhost = NULL; @@ -564,6 +598,9 @@ RRDSET *rrdset_create_custom( st->rrd_memory_mode = (memory_mode == RRD_MEMORY_MODE_NONE) ? RRD_MEMORY_MODE_NONE : RRD_MEMORY_MODE_ALLOC; } + st->plugin_name = plugin?strdup(plugin):NULL; + st->module_name = module?strdup(module):NULL; + st->config_section = strdup(config_section); st->rrdhost = host; st->memsize = size; @@ -624,12 +661,16 @@ RRDSET *rrdset_create_custom( st->upstream_resync_time = 0; avl_init_lock(&st->dimensions_index, rrddim_compare); - avl_init_lock(&st->variables_root_index, rrdvar_compare); + avl_init_lock(&st->rrdvar_root_index, rrdvar_compare); netdata_rwlock_init(&st->rrdset_rwlock); - if(name && *name) rrdset_set_name(st, name); - else rrdset_set_name(st, id); + if(name && *name && rrdset_set_name(st, name)) + // we did set the name + ; + else + // could not use the name, use the id + rrdset_set_name(st, id); st->title = config_get(st->config_section, "title", title); json_fix_string(st->title); @@ -640,11 +681,11 @@ RRDSET *rrdset_create_custom( host->rrdset_root = st; if(host->health_enabled) { - rrdsetvar_create(st, "last_collected_t", RRDVAR_TYPE_TIME_T, &st->last_collected_time.tv_sec, 0); - rrdsetvar_create(st, "collected_total_raw", RRDVAR_TYPE_TOTAL, &st->last_collected_total, 0); - rrdsetvar_create(st, "green", RRDVAR_TYPE_CALCULATED, &st->green, 0); - rrdsetvar_create(st, "red", RRDVAR_TYPE_CALCULATED, &st->red, 0); - rrdsetvar_create(st, "update_every", RRDVAR_TYPE_INT, &st->update_every, 0); + rrdsetvar_create(st, "last_collected_t", RRDVAR_TYPE_TIME_T, &st->last_collected_time.tv_sec, RRDVAR_OPTION_DEFAULT); + rrdsetvar_create(st, "collected_total_raw", RRDVAR_TYPE_TOTAL, &st->last_collected_total, RRDVAR_OPTION_DEFAULT); + rrdsetvar_create(st, "green", RRDVAR_TYPE_CALCULATED, &st->green, RRDVAR_OPTION_DEFAULT); + rrdsetvar_create(st, "red", RRDVAR_TYPE_CALCULATED, &st->red, RRDVAR_OPTION_DEFAULT); + rrdsetvar_create(st, "update_every", RRDVAR_TYPE_INT, &st->update_every, RRDVAR_OPTION_DEFAULT); } if(unlikely(rrdset_index_add(host, st) != st)) @@ -1029,7 +1070,7 @@ void rrdset_done(RRDSET *st) { if(unlikely(netdata_exit)) return; if(unlikely(st->rrd_memory_mode == RRD_MEMORY_MODE_NONE)) { - if(unlikely(st->rrdhost->rrdpush_enabled)) + if(unlikely(st->rrdhost->rrdpush_send_enabled)) rrdset_done_push_exclusive(st); return; @@ -1154,7 +1195,7 @@ void rrdset_done(RRDSET *st) { } st->counter_done++; - if(unlikely(st->rrdhost->rrdpush_enabled)) + if(unlikely(st->rrdhost->rrdpush_send_enabled)) rrdset_done_push(st); #ifdef NETDATA_INTERNAL_CHECKS diff --git a/src/rrdsetvar.c b/src/rrdsetvar.c index 03d7aece..280156a8 100644 --- a/src/rrdsetvar.c +++ b/src/rrdsetvar.c @@ -8,29 +8,29 @@ static inline void rrdsetvar_free_variables(RRDSETVAR *rs) { RRDSET *st = rs->rrdset; + // ------------------------------------------------------------------------ // CHART - - rrdvar_free(st->rrdhost, &st->variables_root_index, rs->var_local); + rrdvar_free(st->rrdhost, &st->rrdvar_root_index, rs->var_local); rs->var_local = NULL; + // ------------------------------------------------------------------------ // FAMILY - - rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rs->var_family); + rrdvar_free(st->rrdhost, &st->rrdfamily->rrdvar_root_index, rs->var_family); rs->var_family = NULL; - rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->var_host); - rs->var_host = NULL; + rrdvar_free(st->rrdhost, &st->rrdfamily->rrdvar_root_index, rs->var_family_name); + rs->var_family_name = NULL; + // ------------------------------------------------------------------------ // HOST + rrdvar_free(st->rrdhost, &st->rrdhost->rrdvar_root_index, rs->var_host); + rs->var_host = NULL; - rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rs->var_family_name); - rs->var_family_name = NULL; - - rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->var_host_name); + rrdvar_free(st->rrdhost, &st->rrdhost->rrdvar_root_index, rs->var_host_name); rs->var_host_name = NULL; + // ------------------------------------------------------------------------ // KEYS - freez(rs->key_fullid); rs->key_fullid = NULL; @@ -39,10 +39,14 @@ static inline void rrdsetvar_free_variables(RRDSETVAR *rs) { } static inline void rrdsetvar_create_variables(RRDSETVAR *rs) { - rrdsetvar_free_variables(rs); - RRDSET *st = rs->rrdset; + // ------------------------------------------------------------------------ + // free the old ones (if any) + + rrdsetvar_free_variables(rs); + + // ------------------------------------------------------------------------ // KEYS char buffer[RRDVAR_MAX_LENGTH + 1]; @@ -52,27 +56,27 @@ static inline void rrdsetvar_create_variables(RRDSETVAR *rs) { snprintfz(buffer, RRDVAR_MAX_LENGTH, "%s.%s", st->name, rs->variable); rs->key_fullname = strdupz(buffer); + // ------------------------------------------------------------------------ // CHART + rs->var_local = rrdvar_create_and_index("local", &st->rrdvar_root_index, rs->variable, rs->type, rs->value); - rs->var_local = rrdvar_create_and_index("local", &st->variables_root_index, rs->variable, rs->type, rs->value); - + // ------------------------------------------------------------------------ // FAMILY + rs->var_family = rrdvar_create_and_index("family", &st->rrdfamily->rrdvar_root_index, rs->key_fullid, rs->type, rs->value); + rs->var_family_name = rrdvar_create_and_index("family", &st->rrdfamily->rrdvar_root_index, rs->key_fullname, rs->type, rs->value); - rs->var_family = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rs->key_fullid, rs->type, rs->value); - rs->var_family_name = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rs->key_fullname, rs->type, rs->value); - + // ------------------------------------------------------------------------ // HOST - - rs->var_host = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->key_fullid, rs->type, rs->value); - rs->var_host_name = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->key_fullname, rs->type, rs->value); - + rs->var_host = rrdvar_create_and_index("host", &st->rrdhost->rrdvar_root_index, rs->key_fullid, rs->type, rs->value); + rs->var_host_name = rrdvar_create_and_index("host", &st->rrdhost->rrdvar_root_index, rs->key_fullname, rs->type, rs->value); } -RRDSETVAR *rrdsetvar_create(RRDSET *st, const char *variable, int type, void *value, uint32_t options) { +RRDSETVAR *rrdsetvar_create(RRDSET *st, const char *variable, RRDVAR_TYPE type, void *value, RRDVAR_OPTIONS options) { debug(D_VARIABLES, "RRDVARSET create for chart id '%s' name '%s' with variable name '%s'", st->id, st->name, variable); RRDSETVAR *rs = (RRDSETVAR *)callocz(1, sizeof(RRDSETVAR)); rs->variable = strdupz(variable); + rs->hash = simple_hash(rs->variable); rs->type = type; rs->value = value; rs->options = options; @@ -89,11 +93,9 @@ RRDSETVAR *rrdsetvar_create(RRDSET *st, const char *variable, int type, void *va void rrdsetvar_rename_all(RRDSET *st) { debug(D_VARIABLES, "RRDSETVAR rename for chart id '%s' name '%s'", st->id, st->name); - RRDSETVAR *rs, *next = st->variables; - while((rs = next)) { - next = rs->next; + RRDSETVAR *rs; + for(rs = st->variables; rs ; rs = rs->next) rrdsetvar_create_variables(rs); - } rrdsetcalc_link_matching(st); } @@ -115,6 +117,63 @@ void rrdsetvar_free(RRDSETVAR *rs) { rrdsetvar_free_variables(rs); freez(rs->variable); + + if(rs->options & RRDVAR_OPTION_ALLOCATED) + freez(rs->value); + freez(rs); } +// -------------------------------------------------------------------------------------------------------------------- +// custom chart variables + +RRDSETVAR *rrdsetvar_custom_chart_variable_create(RRDSET *st, const char *name) { + char *n = strdupz(name); + rrdvar_fix_name(n); + uint32_t hash = simple_hash(n); + + rrdset_wrlock(st); + + // find it + RRDSETVAR *rs; + for(rs = st->variables; rs ; rs = rs->next) { + if(hash == rs->hash && strcmp(n, rs->variable) == 0) { + rrdset_unlock(st); + if(rs->options & RRDVAR_OPTION_ALLOCATED) { + free(n); + return rs; + } + else { + error("RRDSETVAR: custom variable '%s' on chart '%s' of host '%s', conflicts with an internal chart variable", n, st->id, st->rrdhost->hostname); + free(n); + return NULL; + } + } + } + + // not found, allocate one + + calculated_number *v = mallocz(sizeof(calculated_number)); + *v = NAN; + + rs = rrdsetvar_create(st, n, RRDVAR_TYPE_CALCULATED, v, RRDVAR_OPTION_ALLOCATED); + rrdset_unlock(st); + + free(n); + return rs; +} + +void rrdsetvar_custom_chart_variable_set(RRDSETVAR *rs, calculated_number value) { + if(unlikely(!(rs->options & RRDVAR_OPTION_ALLOCATED))) { + error("RRDSETVAR: requested to set variable '%s' of chart '%s' on host '%s' to value " CALCULATED_NUMBER_FORMAT " but the variable is not a custom one.", rs->variable, rs->rrdset->id, rs->rrdset->rrdhost->hostname, value); + } + else { + calculated_number *v = rs->value; + if(*v != value) { + *v = value; + + // mark the chart to be sent upstream + rrdset_flag_clear(rs->rrdset, RRDSET_FLAG_EXPOSED_UPSTREAM); + } + } +} diff --git a/src/rrdvar.c b/src/rrdvar.c index 2223d7c9..9119b538 100644 --- a/src/rrdvar.c +++ b/src/rrdvar.c @@ -56,14 +56,17 @@ inline void rrdvar_free(RRDHOST *host, avl_tree_lock *tree, RRDVAR *rv) { if(tree) { debug(D_VARIABLES, "Deleting variable '%s'", rv->name); if(unlikely(!rrdvar_index_del(tree, rv))) - error("Attempted to delete variable '%s' from host '%s', but it is not found.", rv->name, host->hostname); + error("RRDVAR: Attempted to delete variable '%s' from host '%s', but it is not found.", rv->name, host->hostname); } + if(rv->type == RRDVAR_TYPE_CALCULATED_ALLOCATED) + freez(rv->value); + freez(rv->name); freez(rv); } -inline RRDVAR *rrdvar_create_and_index(const char *scope, avl_tree_lock *tree, const char *name, int type, void *value) { +inline RRDVAR *rrdvar_create_and_index(const char *scope, avl_tree_lock *tree, const char *name, RRDVAR_TYPE type, void *value) { char *variable = strdupz(name); rrdvar_fix_name(variable); uint32_t hash = simple_hash(variable); @@ -81,7 +84,8 @@ inline RRDVAR *rrdvar_create_and_index(const char *scope, avl_tree_lock *tree, c RRDVAR *ret = rrdvar_index_add(tree, rv); if(unlikely(ret != rv)) { debug(D_VARIABLES, "Variable '%s' in scope '%s' already exists", variable, scope); - rrdvar_free(NULL, NULL, rv); + freez(rv); + freez(variable); rv = NULL; } else @@ -101,61 +105,64 @@ inline RRDVAR *rrdvar_create_and_index(const char *scope, avl_tree_lock *tree, c return rv; } +void rrdvar_free_remaining_variables(RRDHOST *host, avl_tree_lock *tree_lock) { + // FIXME: this is not bullet proof - avl should support some means to destroy it + // with a callback for each item already in the index + + RRDVAR *rv, *last = NULL; + while((rv = (RRDVAR *)tree_lock->avl_tree.root)) { + if(unlikely(rv == last)) { + error("RRDVAR: INTERNAL ERROR: Cannot cleanup tree of RRDVARs"); + break; + } + last = rv; + rrdvar_free(host, tree_lock, rv); + } +} + // ---------------------------------------------------------------------------- -// CUSTOM VARIABLES +// CUSTOM HOST VARIABLES -RRDVAR *rrdvar_custom_host_variable_create(RRDHOST *host, const char *name) { +inline int rrdvar_callback_for_all_host_variables(RRDHOST *host, int (*callback)(void *rrdvar, void *data), void *data) { + return avl_traverse_lock(&host->rrdvar_root_index, callback, data); +} + +static RRDVAR *rrdvar_custom_variable_create(const char *scope, avl_tree_lock *tree_lock, const char *name) { calculated_number *v = callocz(1, sizeof(calculated_number)); *v = NAN; - RRDVAR *rv = rrdvar_create_and_index("host", &host->variables_root_index, name, RRDVAR_TYPE_CALCULATED_ALLOCATED, v); + + RRDVAR *rv = rrdvar_create_and_index(scope, tree_lock, name, RRDVAR_TYPE_CALCULATED_ALLOCATED, v); if(unlikely(!rv)) { free(v); - error("Requested variable '%s' already exists - possibly 2 plugins will be updating it at the same time", name); + debug(D_VARIABLES, "Requested variable '%s' already exists - possibly 2 plugins are updating it at the same time.", name); char *variable = strdupz(name); rrdvar_fix_name(variable); uint32_t hash = simple_hash(variable); - rv = rrdvar_index_find(&host->variables_root_index, variable, hash); + rv = rrdvar_index_find(tree_lock, variable, hash); + + freez(variable); } return rv; } -void rrdvar_custom_host_variable_destroy(RRDHOST *host, const char *name) { - char *variable = strdupz(name); - rrdvar_fix_name(variable); - uint32_t hash = simple_hash(variable); - - RRDVAR *rv = rrdvar_index_find(&host->variables_root_index, variable, hash); - freez(variable); - - if(!rv) { - error("Attempted to remove variable '%s' from host '%s', but it does not exist.", name, host->hostname); - return; - } - - if(rv->type != RRDVAR_TYPE_CALCULATED_ALLOCATED) { - error("Attempted to remove variable '%s' from host '%s', but it does not a custom allocated variable.", name, host->hostname); - return; - } - - if(!rrdvar_index_del(&host->variables_root_index, rv)) { - error("Attempted to remove variable '%s' from host '%s', but it cannot be found.", name, host->hostname); - return; - } - - freez(rv->name); - freez(rv->value); - freez(rv); +RRDVAR *rrdvar_custom_host_variable_create(RRDHOST *host, const char *name) { + return rrdvar_custom_variable_create("host", &host->rrdvar_root_index, name); } -void rrdvar_custom_host_variable_set(RRDVAR *rv, calculated_number value) { +void rrdvar_custom_host_variable_set(RRDHOST *host, RRDVAR *rv, calculated_number value) { if(rv->type != RRDVAR_TYPE_CALCULATED_ALLOCATED) error("requested to set variable '%s' to value " CALCULATED_NUMBER_FORMAT " but the variable is not a custom one.", rv->name, value); else { calculated_number *v = rv->value; - *v = value; + if(*v != value) { + *v = value; + + // if the host is streaming, send this variable upstream immediately + rrdpush_sender_send_this_host_variable_now(host, rv); + } } } @@ -191,7 +198,7 @@ static calculated_number rrdvar2number(RRDVAR *rv) { } default: - error("I don't know how to convert RRDVAR type %d to calculated_number", rv->type); + error("I don't know how to convert RRDVAR type %u to calculated_number", rv->type); return NAN; } } @@ -202,19 +209,19 @@ int health_variable_lookup(const char *variable, uint32_t hash, RRDCALC *rc, cal if(!st) return 0; - rv = rrdvar_index_find(&st->variables_root_index, variable, hash); + rv = rrdvar_index_find(&st->rrdvar_root_index, variable, hash); if(rv) { *result = rrdvar2number(rv); return 1; } - rv = rrdvar_index_find(&st->rrdfamily->variables_root_index, variable, hash); + rv = rrdvar_index_find(&st->rrdfamily->rrdvar_root_index, variable, hash); if(rv) { *result = rrdvar2number(rv); return 1; } - rv = rrdvar_index_find(&st->rrdhost->variables_root_index, variable, hash); + rv = rrdvar_index_find(&st->rrdhost->rrdvar_root_index, variable, hash); if(rv) { *result = rrdvar2number(rv); return 1; @@ -253,13 +260,13 @@ void health_api_v1_chart_variables2json(RRDSET *st, BUFFER *buf) { }; buffer_sprintf(buf, "{\n\t\"chart\": \"%s\",\n\t\"chart_name\": \"%s\",\n\t\"chart_context\": \"%s\",\n\t\"chart_variables\": {", st->id, st->name, st->context); - avl_traverse_lock(&st->variables_root_index, single_variable2json, (void *)&helper); + avl_traverse_lock(&st->rrdvar_root_index, single_variable2json, (void *)&helper); buffer_sprintf(buf, "\n\t},\n\t\"family\": \"%s\",\n\t\"family_variables\": {", st->family); helper.counter = 0; - avl_traverse_lock(&st->rrdfamily->variables_root_index, single_variable2json, (void *)&helper); + avl_traverse_lock(&st->rrdfamily->rrdvar_root_index, single_variable2json, (void *)&helper); buffer_sprintf(buf, "\n\t},\n\t\"host\": \"%s\",\n\t\"host_variables\": {", st->rrdhost->hostname); helper.counter = 0; - avl_traverse_lock(&st->rrdhost->variables_root_index, single_variable2json, (void *)&helper); + avl_traverse_lock(&st->rrdhost->rrdvar_root_index, single_variable2json, (void *)&helper); buffer_strcat(buf, "\n\t}\n}\n"); } diff --git a/src/signals.h b/src/signals.h index d8611ede..2fdd3655 100644 --- a/src/signals.h +++ b/src/signals.h @@ -4,7 +4,7 @@ extern void signals_init(void); extern void signals_block(void); extern void signals_unblock(void); -extern void signals_handle(void); extern void signals_reset(void); +extern void signals_handle(void) NORETURN; #endif //NETDATA_SIGNALS_H diff --git a/src/simple_pattern.c b/src/simple_pattern.c index f72a42d0..469ea396 100644 --- a/src/simple_pattern.c +++ b/src/simple_pattern.c @@ -12,12 +12,13 @@ struct simple_pattern { struct simple_pattern *next; }; -static inline struct simple_pattern *parse_pattern(const char *str, SIMPLE_PREFIX_MODE default_mode) { +static inline struct simple_pattern *parse_pattern(char *str, SIMPLE_PREFIX_MODE default_mode) { + // fprintf(stderr, "PARSING PATTERN: '%s'\n", str); + SIMPLE_PREFIX_MODE mode; struct simple_pattern *child = NULL; - char *buf = strdupz(str); - char *s = buf, *c = buf; + char *s = str, *c = str; // skip asterisks in front while(*c == '*') c++; @@ -64,8 +65,6 @@ static inline struct simple_pattern *parse_pattern(const char *str, SIMPLE_PREFI m->child = child; - freez(buf); - return m; } @@ -74,51 +73,63 @@ SIMPLE_PATTERN *simple_pattern_create(const char *list, SIMPLE_PREFIX_MODE defau if(unlikely(!list || !*list)) return root; - char *buf = strdupz(list); - if(buf && *buf) { - char *s = buf; + char *buf = mallocz(strlen(list) + 1); + const char *s = list; - while(s && *s) { - char negative = 0; + while(s && *s) { + buf[0] = '\0'; + char *c = buf; - // skip all spaces - while(isspace(*s)) s++; + char negative = 0; - if(*s == '!') { - negative = 1; - s++; - } + // skip all spaces + while(isspace(*s)) + s++; - // empty string - if(unlikely(!*s)) break; + if(*s == '!') { + negative = 1; + s++; + } - // find the next space - char *c = s; - while(*c && !isspace(*c)) c++; + // empty string + if(unlikely(!*s)) + break; - // find the next word - char *n; - if(likely(*c)) n = c + 1; - else n = NULL; + // find the next space + char escape = 0; + while(*s) { + if(*s == '\\' && !escape) { + escape = 1; + s++; + } + else { + if (isspace(*s) && !escape) { + s++; + break; + } - // terminate our string - *c = '\0'; + *c++ = *s++; + escape = 0; + } + } - struct simple_pattern *m = parse_pattern(s, default_mode); - m->negative = negative; + // terminate our string + *c = '\0'; - if(likely(n)) *c = ' '; + // if we matched the empty string, skip it + if(unlikely(!*buf)) + continue; - // link it at the end - if(unlikely(!root)) - root = last = m; - else { - last->next = m; - last = m; - } + // fprintf(stderr, "FOUND PATTERN: '%s'\n", buf); + struct simple_pattern *m = parse_pattern(buf, default_mode); + m->negative = negative; - // prepare for next loop - s = n; + // link it at the end + if(unlikely(!root)) + root = last = m; + else { + last->next = m; + last = m; } } @@ -126,7 +137,28 @@ SIMPLE_PATTERN *simple_pattern_create(const char *list, SIMPLE_PREFIX_MODE defau return (SIMPLE_PATTERN *)root; } -static inline int match_pattern(struct simple_pattern *m, const char *str, size_t len) { +static inline char *add_wildcarded(const char *matched, size_t matched_size, char *wildcarded, size_t *wildcarded_size) { + //if(matched_size) { + // char buf[matched_size + 1]; + // strncpyz(buf, matched, matched_size); + // fprintf(stderr, "ADD WILDCARDED '%s' of length %zu\n", buf, matched_size); + //} + + if(unlikely(wildcarded && *wildcarded_size && matched && *matched && matched_size)) { + size_t wss = *wildcarded_size - 1; + size_t len = (matched_size < wss)?matched_size:wss; + if(likely(len)) { + strncpyz(wildcarded, matched, len); + + *wildcarded_size -= len; + return &wildcarded[len]; + } + } + + return wildcarded; +} + +static inline int match_pattern(struct simple_pattern *m, const char *str, size_t len, char *wildcarded, size_t *wildcarded_size) { char *s; if(m->len <= len) { @@ -134,20 +166,28 @@ static inline int match_pattern(struct simple_pattern *m, const char *str, size_ case SIMPLE_PATTERN_SUBSTRING: if(!m->len) return 1; if((s = strstr(str, m->match))) { - if(!m->child) return 1; - return match_pattern(m->child, &s[m->len], len - (s - str) - m->len); + wildcarded = add_wildcarded(str, s - str, wildcarded, wildcarded_size); + if(!m->child) { + wildcarded = add_wildcarded(&s[m->len], len - (&s[m->len] - str), wildcarded, wildcarded_size); + return 1; + } + return match_pattern(m->child, &s[m->len], len - (s - str) - m->len, wildcarded, wildcarded_size); } break; case SIMPLE_PATTERN_PREFIX: if(unlikely(strncmp(str, m->match, m->len) == 0)) { - if(!m->child) return 1; - return match_pattern(m->child, &str[m->len], len - m->len); + if(!m->child) { + wildcarded = add_wildcarded(&str[m->len], len - m->len, wildcarded, wildcarded_size); + return 1; + } + return match_pattern(m->child, &str[m->len], len - m->len, wildcarded, wildcarded_size); } break; case SIMPLE_PATTERN_SUFFIX: if(unlikely(strcmp(&str[len - m->len], m->match) == 0)) { + wildcarded = add_wildcarded(str, len - m->len, wildcarded, wildcarded_size); if(!m->child) return 1; return 0; } @@ -166,17 +206,26 @@ static inline int match_pattern(struct simple_pattern *m, const char *str, size_ return 0; } -int simple_pattern_matches(SIMPLE_PATTERN *list, const char *str) { +int simple_pattern_matches_extract(SIMPLE_PATTERN *list, const char *str, char *wildcarded, size_t wildcarded_size) { struct simple_pattern *m, *root = (struct simple_pattern *)list; if(unlikely(!root || !str || !*str)) return 0; size_t len = strlen(str); - for(m = root; m ; m = m->next) - if(match_pattern(m, str, len)) { - if(m->negative) return 0; + for(m = root; m ; m = m->next) { + char *ws = wildcarded; + size_t wss = wildcarded_size; + if(unlikely(ws)) *ws = '\0'; + + if (match_pattern(m, str, len, ws, &wss)) { + + //if(ws && wss) + // fprintf(stderr, "FINAL WILDCARDED '%s' of length %zu\n", ws, strlen(ws)); + + if (m->negative) return 0; return 1; } + } return 0; } diff --git a/src/simple_pattern.h b/src/simple_pattern.h index 3768c508..60a25f49 100644 --- a/src/simple_pattern.h +++ b/src/simple_pattern.h @@ -15,8 +15,11 @@ typedef void SIMPLE_PATTERN; // should be considered PREFIX matches. extern SIMPLE_PATTERN *simple_pattern_create(const char *list, SIMPLE_PREFIX_MODE default_mode); +// test if string str is matched from the pattern and fill 'wildcarded' with the parts matched by '*' +extern int simple_pattern_matches_extract(SIMPLE_PATTERN *list, const char *str, char *wildcarded, size_t wildcarded_size); + // test if string str is matched from the pattern -extern int simple_pattern_matches(SIMPLE_PATTERN *list, const char *str); +#define simple_pattern_matches(list, str) simple_pattern_matches_extract(list, str, NULL, 0) // free a simple_pattern that was created with simple_pattern_create() // list can be NULL, in which case, this does nothing. diff --git a/src/socket.c b/src/socket.c index d28df81a..906ab33d 100644 --- a/src/socket.c +++ b/src/socket.c @@ -857,7 +857,7 @@ int accept4(int sock, struct sockaddr *addr, socklen_t *addrlen, int flags) { // -------------------------------------------------------------------------------------------------------------------- // accept_socket() - accept a socket and store client IP and port -int accept_socket(int fd, int flags, char *client_ip, size_t ipsize, char *client_port, size_t portsize) { +int accept_socket(int fd, int flags, char *client_ip, size_t ipsize, char *client_port, size_t portsize, SIMPLE_PATTERN *access_list) { struct sockaddr_storage sadr; socklen_t addrlen = sizeof(sadr); @@ -873,6 +873,13 @@ int accept_socket(int fd, int flags, char *client_ip, size_t ipsize, char *clien client_port[portsize - 1] = '\0'; switch (((struct sockaddr *)&sadr)->sa_family) { + case AF_UNIX: + debug(D_LISTENER, "New UNIX domain web client from %s on socket %d.", client_ip, fd); + // set the port - certain versions of libc return garbage on unix sockets + strncpy(client_port, "UNIX", portsize); + client_port[portsize - 1] = '\0'; + break; + case AF_INET: debug(D_LISTENER, "New IPv4 web client from %s port %s on socket %d.", client_ip, client_port, fd); break; @@ -881,7 +888,8 @@ int accept_socket(int fd, int flags, char *client_ip, size_t ipsize, char *clien if (strncmp(client_ip, "::ffff:", 7) == 0) { memmove(client_ip, &client_ip[7], strlen(&client_ip[7]) + 1); debug(D_LISTENER, "New IPv4 web client from %s port %s on socket %d.", client_ip, client_port, fd); - } else + } + else debug(D_LISTENER, "New IPv6 web client from %s port %s on socket %d.", client_ip, client_port, fd); break; @@ -889,6 +897,22 @@ int accept_socket(int fd, int flags, char *client_ip, size_t ipsize, char *clien debug(D_LISTENER, "New UNKNOWN web client from %s port %s on socket %d.", client_ip, client_port, fd); break; } + + if(access_list) { + if(!strcmp(client_ip, "127.0.0.1") || !strcmp(client_ip, "::1")) { + strncpy(client_ip, "localhost", ipsize); + client_ip[ipsize - 1] = '\0'; + } + + if(unlikely(!simple_pattern_matches(access_list, client_ip))) { + errno = 0; + debug(D_LISTENER, "Permission denied for client '%s', port '%s'", client_ip, client_port); + error("DENIED ACCESS to client '%s'", client_ip); + close(nfd); + nfd = -1; + errno = EPERM; + } + } } #ifdef HAVE_ACCEPT4 else if(errno == ENOSYS) @@ -928,8 +952,8 @@ struct poll { struct pollinfo *inf; struct pollinfo *first_free; - void *(*add_callback)(int fd, short int *events); - void (*del_callback)(int fd, void *data); + void *(*add_callback)(int fd, int socktype, short int *events); + void (*del_callback)(int fd, int socktype, void *data); int (*rcv_callback)(int fd, int socktype, void *data, short int *events); int (*snd_callback)(int fd, int socktype, void *data, short int *events); }; @@ -984,7 +1008,7 @@ static inline struct pollinfo *poll_add_fd(struct poll *p, int fd, int socktype, p->max = pi->slot; if(pi->flags & POLLINFO_FLAG_CLIENT_SOCKET) { - pi->data = p->add_callback(fd, &pf->events); + pi->data = p->add_callback(fd, pi->socktype, &pf->events); } if(pi->flags & POLLINFO_FLAG_SERVER_SOCKET) { @@ -1003,7 +1027,7 @@ static inline void poll_close_fd(struct poll *p, struct pollinfo *pi) { if(unlikely(pf->fd == -1)) return; if(pi->flags & POLLINFO_FLAG_CLIENT_SOCKET) { - p->del_callback(pf->fd, pi->data); + p->del_callback(pf->fd, pi->socktype, pi->data); } close(pf->fd); @@ -1036,14 +1060,16 @@ static inline void poll_close_fd(struct poll *p, struct pollinfo *pi) { debug(D_POLLFD, "POLLFD: DEL: completed, slots = %zu, used = %zu, min = %zu, max = %zu, next free = %zd", p->slots, p->used, p->min, p->max, p->first_free?(ssize_t)p->first_free->slot:(ssize_t)-1); } -static void *add_callback_default(int fd, short int *events) { +static void *add_callback_default(int fd, int socktype, short int *events) { (void)fd; + (void)socktype; (void)events; return NULL; } -static void del_callback_default(int fd, void *data) { +static void del_callback_default(int fd, int socktype, void *data) { (void)fd; + (void)socktype; (void)data; if(data) @@ -1100,10 +1126,11 @@ void poll_events_cleanup(void *data) { } void poll_events(LISTEN_SOCKETS *sockets - , void *(*add_callback)(int fd, short int *events) - , void (*del_callback)(int fd, void *data) + , void *(*add_callback)(int fd, int socktype, short int *events) + , void (*del_callback)(int fd, int socktype, void *data) , int (*rcv_callback)(int fd, int socktype, void *data, short int *events) , int (*snd_callback)(int fd, int socktype, void *data, short int *events) + , SIMPLE_PATTERN *access_list , void *data ) { int retval; @@ -1182,7 +1209,7 @@ void poll_events(LISTEN_SOCKETS *sockets char client_port[NI_MAXSERV + 1]; debug(D_POLLFD, "POLLFD: LISTENER: calling accept4() slot %zu (fd %d)", i, fd); - nfd = accept_socket(fd, SOCK_NONBLOCK, client_ip, NI_MAXHOST + 1, client_port, NI_MAXSERV + 1); + nfd = accept_socket(fd, SOCK_NONBLOCK, client_ip, NI_MAXHOST + 1, client_port, NI_MAXSERV + 1, access_list); if (nfd < 0) { // accept failed @@ -1212,6 +1239,8 @@ void poll_events(LISTEN_SOCKETS *sockets debug(D_POLLFD, "POLLFD: LISTENER: reading data from UDP slot %zu (fd %d)", i, fd); + // FIXME: access_list is not applied to UDP + p.rcv_callback(fd, pi->socktype, pi->data, &pf->events); break; } diff --git a/src/socket.h b/src/socket.h index 8ca7288c..08b8518b 100644 --- a/src/socket.h +++ b/src/socket.h @@ -35,7 +35,7 @@ extern int sock_setreuse_port(int fd, int reuse); extern int sock_enlarge_in(int fd); extern int sock_enlarge_out(int fd); -extern int accept_socket(int fd, int flags, char *client_ip, size_t ipsize, char *client_port, size_t portsize); +extern int accept_socket(int fd, int flags, char *client_ip, size_t ipsize, char *client_port, size_t portsize, SIMPLE_PATTERN *access_list); #ifndef HAVE_ACCEPT4 extern int accept4(int sock, struct sockaddr *addr, socklen_t *addrlen, int flags); @@ -52,10 +52,11 @@ extern int accept4(int sock, struct sockaddr *addr, socklen_t *addrlen, int flag extern void poll_events(LISTEN_SOCKETS *sockets - , void *(*add_callback)(int fd, short int *events) - , void (*del_callback)(int fd, void *data) + , void *(*add_callback)(int fd, int socktype, short int *events) + , void (*del_callback)(int fd, int socktype, void *data) , int (*rcv_callback)(int fd, int socktype, void *data, short int *events) , int (*snd_callback)(int fd, int socktype, void *data, short int *events) + , SIMPLE_PATTERN *access_list , void *data ); diff --git a/src/statsd.c b/src/statsd.c index 08ce3e2f..39041ca8 100644 --- a/src/statsd.c +++ b/src/statsd.c @@ -54,6 +54,8 @@ typedef struct statsd_histogram_extensions { collected_number last_stddev; collected_number last_sum; + int zeroed; + RRDDIM *rd_min; RRDDIM *rd_max; RRDDIM *rd_percentile; @@ -165,18 +167,21 @@ typedef enum statsd_app_chart_dimension_value_type { } STATSD_APP_CHART_DIM_VALUE_TYPE; typedef struct statsd_app_chart_dimension { - const char *name; - const char *metric; - uint32_t metric_hash; - collected_number multiplier; - collected_number divisor; - STATSD_APP_CHART_DIM_VALUE_TYPE value_type; + const char *name; // the name of this dimension + const char *metric; // the source metric name of this dimension + uint32_t metric_hash; // hash for fast string comparisons + + SIMPLE_PATTERN *metric_pattern; // set when the 'metric' is a simple pattern + + collected_number multiplier; // the multipler of the dimension + collected_number divisor; // the divisor of the dimension + STATSD_APP_CHART_DIM_VALUE_TYPE value_type; // which value to use of the source metric - RRDDIM *rd; - collected_number *value_ptr; - RRD_ALGORITHM algorithm; + RRDDIM *rd; // a pointer to the RRDDIM that has been created for this dimension + collected_number *value_ptr; // a pointer to the source metric value + RRD_ALGORITHM algorithm; // the algorithm of this dimension - struct statsd_app_chart_dimension *next; + struct statsd_app_chart_dimension *next; // the next dimension for this chart } STATSD_APP_CHART_DIM; typedef struct statsd_app_chart { @@ -202,6 +207,7 @@ typedef struct statsd_app { SIMPLE_PATTERN *metrics; STATS_METRIC_OPTIONS default_options; RRD_MEMORY_MODE rrd_memory_mode; + DICTIONARY *dict; long rrd_history_entries; const char *source; @@ -482,7 +488,7 @@ static inline void statsd_process_histogram(STATSD_METRIC *m, const char *value, static inline void statsd_process_timer(STATSD_METRIC *m, const char *value, const char *sampling) { if(unlikely(!value || !*value)) { - error("STATSD: metric of type set, with empty value is ignored."); + error("STATSD: metric of type timer, with empty value is ignored."); return; } @@ -685,8 +691,9 @@ struct statsd_udp { #endif // new TCP client connected -static void *statsd_add_callback(int fd, short int *events) { +static void *statsd_add_callback(int fd, int socktype, short int *events) { (void)fd; + (void)socktype; *events = POLLIN; struct statsd_tcp *data = (struct statsd_tcp *)callocz(sizeof(struct statsd_tcp) + STATSD_TCP_BUFFER_SIZE, 1); @@ -697,8 +704,9 @@ static void *statsd_add_callback(int fd, short int *events) { } // TCP client disconnected -static void statsd_del_callback(int fd, void *data) { +static void statsd_del_callback(int fd, int socktype, void *data) { (void)fd; + (void)socktype; if(data) { struct statsd_tcp *t = data; @@ -912,6 +920,7 @@ void *statsd_collector_thread(void *ptr) { , statsd_del_callback , statsd_rcv_callback , statsd_snd_callback + , NULL , (void *)d ); @@ -928,6 +937,83 @@ void *statsd_collector_thread(void *ptr) { #define STATSD_CONF_LINE_MAX 8192 +static STATSD_APP_CHART_DIM_VALUE_TYPE string2valuetype(const char *type, size_t line, const char *path, const char *filename) { + if(!type || !*type) type = "last"; + + if(!strcmp(type, "events")) return STATSD_APP_CHART_DIM_VALUE_TYPE_EVENTS; + else if(!strcmp(type, "last")) return STATSD_APP_CHART_DIM_VALUE_TYPE_LAST; + else if(!strcmp(type, "min")) return STATSD_APP_CHART_DIM_VALUE_TYPE_MIN; + else if(!strcmp(type, "max")) return STATSD_APP_CHART_DIM_VALUE_TYPE_MAX; + else if(!strcmp(type, "sum")) return STATSD_APP_CHART_DIM_VALUE_TYPE_SUM; + else if(!strcmp(type, "average")) return STATSD_APP_CHART_DIM_VALUE_TYPE_AVERAGE; + else if(!strcmp(type, "median")) return STATSD_APP_CHART_DIM_VALUE_TYPE_MEDIAN; + else if(!strcmp(type, "stddev")) return STATSD_APP_CHART_DIM_VALUE_TYPE_STDDEV; + else if(!strcmp(type, "percentile")) return STATSD_APP_CHART_DIM_VALUE_TYPE_PERCENTILE; + + error("STATSD: invalid type '%s' at line %zu of file '%s/%s'. Using 'last'.", type, line, path, filename); + return STATSD_APP_CHART_DIM_VALUE_TYPE_LAST; +} + +static const char *valuetype2string(STATSD_APP_CHART_DIM_VALUE_TYPE type) { + switch(type) { + case STATSD_APP_CHART_DIM_VALUE_TYPE_EVENTS: return "events"; + case STATSD_APP_CHART_DIM_VALUE_TYPE_LAST: return "last"; + case STATSD_APP_CHART_DIM_VALUE_TYPE_MIN: return "min"; + case STATSD_APP_CHART_DIM_VALUE_TYPE_MAX: return "max"; + case STATSD_APP_CHART_DIM_VALUE_TYPE_SUM: return "sum"; + case STATSD_APP_CHART_DIM_VALUE_TYPE_AVERAGE: return "average"; + case STATSD_APP_CHART_DIM_VALUE_TYPE_MEDIAN: return "median"; + case STATSD_APP_CHART_DIM_VALUE_TYPE_STDDEV: return "stddev"; + case STATSD_APP_CHART_DIM_VALUE_TYPE_PERCENTILE: return "percentile"; + } + + return "unknown"; +} + +static STATSD_APP_CHART_DIM *add_dimension_to_app_chart( + STATSD_APP *app + , STATSD_APP_CHART *chart + , const char *metric_name + , const char *dim_name + , collected_number multiplier + , collected_number divisor + , STATSD_APP_CHART_DIM_VALUE_TYPE value_type +) { + STATSD_APP_CHART_DIM *dim = callocz(sizeof(STATSD_APP_CHART_DIM), 1); + + dim->metric = strdupz(metric_name); + dim->metric_hash = simple_hash(dim->metric); + + dim->name = strdupz((dim_name)?dim_name:""); + dim->multiplier = multiplier; + dim->divisor = divisor; + dim->value_type = value_type; + + if(!dim->multiplier) + dim->multiplier = 1; + + if(!dim->divisor) + dim->divisor = 1; + + // append it to the list of dimension + STATSD_APP_CHART_DIM *tdim; + for(tdim = chart->dimensions; tdim && tdim->next ; tdim = tdim->next) ; + if(!tdim) { + dim->next = chart->dimensions; + chart->dimensions = dim; + } + else { + dim->next = tdim->next; + tdim->next = dim; + } + chart->dimensions_count++; + + debug(D_STATSD, "Added dimension '%s' to chart '%s' of app '%s', for metric '%s', with type %u, multiplier " COLLECTED_NUMBER_FORMAT ", divisor " COLLECTED_NUMBER_FORMAT, + dim->name, chart->id, app->name, dim->metric, dim->value_type, dim->multiplier, dim->divisor); + + return dim; +} + int statsd_readfile(const char *path, const char *filename) { debug(D_STATSD, "STATSD configuration reading file '%s/%s'", path, filename); @@ -943,6 +1029,7 @@ int statsd_readfile(const char *path, const char *filename) { STATSD_APP *app = NULL; STATSD_APP_CHART *chart = NULL; + DICTIONARY *dict = NULL; size_t line = 0; char *s; @@ -973,22 +1060,33 @@ int statsd_readfile(const char *path, const char *filename) { app->next = statsd.apps; statsd.apps = app; chart = NULL; + dict = NULL; } else if(app) { - // a new chart - chart = callocz(sizeof(STATSD_APP_CHART), 1); - netdata_fix_chart_id(s); - chart->id = strdupz(s); - chart->name = strdupz(s); - chart->title = strdupz("Statsd chart"); - chart->context = strdupz(s); - chart->family = strdupz("overview"); - chart->units = strdupz("value"); - chart->priority = STATSD_CHART_PRIORITY; - chart->chart_type = RRDSET_TYPE_LINE; - - chart->next = app->charts; - app->charts = chart; + if(!strcmp(s, "dictionary")) { + if(!app->dict) + app->dict = dictionary_create(DICTIONARY_FLAG_SINGLE_THREADED); + + dict = app->dict; + } + else { + dict = NULL; + + // a new chart + chart = callocz(sizeof(STATSD_APP_CHART), 1); + netdata_fix_chart_id(s); + chart->id = strdupz(s); + chart->name = strdupz(s); + chart->title = strdupz("Statsd chart"); + chart->context = strdupz(s); + chart->family = strdupz("overview"); + chart->units = strdupz("value"); + chart->priority = STATSD_CHART_PRIORITY; + chart->chart_type = RRDSET_TYPE_LINE; + + chart->next = app->charts; + app->charts = chart; + } } else error("STATSD: ignoring line %zu ('%s') of file '%s/%s', [app] is not defined.", line, s, path, filename); @@ -1022,7 +1120,14 @@ int statsd_readfile(const char *path, const char *filename) { continue; } - if(!chart) { + if(unlikely(dict)) { + // parse [dictionary] members + + dictionary_set(dict, name, value, strlen(value) + 1); + } + else if(!chart) { + // parse [app] members + if(!strcmp(name, "name")) { freez((void *)app->name); netdata_fix_chart_name(value); @@ -1056,6 +1161,8 @@ int statsd_readfile(const char *path, const char *filename) { } } else { + // parse [chart] members + if(!strcmp(name, "name")) { freez((void *)chart->name); netdata_fix_chart_id(value); @@ -1086,63 +1193,50 @@ int statsd_readfile(const char *path, const char *filename) { } else if (!strcmp(name, "dimension")) { // metric [name [type [multiplier [divisor]]]] - char *words[5]; - pluginsd_split_words(value, words, 5); - - char *metric_name = words[0]; - char *dim_name = words[1]; - char *type = words[2]; - char *multipler = words[3]; - char *divisor = words[4]; - - STATSD_APP_CHART_DIM *dim = callocz(sizeof(STATSD_APP_CHART_DIM), 1); - - dim->metric = strdupz(metric_name); - dim->metric_hash = simple_hash(dim->metric); - - dim->name = strdupz((dim_name && *dim_name)?dim_name:metric_name); - dim->multiplier = (multipler && *multipler)?str2l(multipler):1; - dim->divisor = (divisor && *divisor)?str2l(divisor):1; - - if(!type || !*type) type = "last"; - if(!strcmp(type, "events")) dim->value_type = STATSD_APP_CHART_DIM_VALUE_TYPE_EVENTS; - else if(!strcmp(type, "last")) dim->value_type = STATSD_APP_CHART_DIM_VALUE_TYPE_LAST; - else if(!strcmp(type, "min")) dim->value_type = STATSD_APP_CHART_DIM_VALUE_TYPE_MIN; - else if(!strcmp(type, "max")) dim->value_type = STATSD_APP_CHART_DIM_VALUE_TYPE_MAX; - else if(!strcmp(type, "sum")) dim->value_type = STATSD_APP_CHART_DIM_VALUE_TYPE_SUM; - else if(!strcmp(type, "average")) dim->value_type = STATSD_APP_CHART_DIM_VALUE_TYPE_AVERAGE; - else if(!strcmp(type, "median")) dim->value_type = STATSD_APP_CHART_DIM_VALUE_TYPE_MEDIAN; - else if(!strcmp(type, "stddev")) dim->value_type = STATSD_APP_CHART_DIM_VALUE_TYPE_STDDEV; - else if(!strcmp(type, "percentile")) dim->value_type = STATSD_APP_CHART_DIM_VALUE_TYPE_PERCENTILE; - else { - error("STATSD: invalid type '%s' at line %zu of file '%s/%s'. Using 'last'.", type, line, path, filename); - dim->value_type = STATSD_APP_CHART_DIM_VALUE_TYPE_LAST; - } + char *words[10]; + pluginsd_split_words(value, words, 10); - if(!dim->multiplier) { - error("STATSD: invalid multiplier value '%s' at line %zu of file '%s/%s'. Using 1.", multipler, line, path, filename); - dim->multiplier = 1; - } - if(!dim->divisor) { - error("STATSD: invalid divisor value '%s' at line %zu of file '%s/%s'. Using 1.", divisor, line, path, filename); - dim->divisor = 1; - } + int pattern = 0; + size_t i = 0; + char *metric_name = words[i++]; - // append it to the list of dimension - STATSD_APP_CHART_DIM *tdim; - for(tdim = chart->dimensions; tdim && tdim->next ; tdim = tdim->next) ; - if(!tdim) { - dim->next = chart->dimensions; - chart->dimensions = dim; + if(strcmp(metric_name, "pattern") == 0) { + metric_name = words[i++]; + pattern = 1; } - else { - dim->next = tdim->next; - tdim->next = dim; + + char *dim_name = words[i++]; + char *type = words[i++]; + char *multipler = words[i++]; + char *divisor = words[i++]; + + if(!pattern) { + if(app->dict) { + if(dim_name && *dim_name) { + char *n = dictionary_get(app->dict, dim_name); + if(n) dim_name = n; + } + else { + dim_name = dictionary_get(app->dict, metric_name); + } + } + + if(!dim_name || !*dim_name) + dim_name = metric_name; } - chart->dimensions_count++; - debug(D_STATSD, "Added dimension '%s' to chart '%s' of app '%s', for metric '%s', with type %u, multiplier " COLLECTED_NUMBER_FORMAT ", divisor " COLLECTED_NUMBER_FORMAT, - dim->name, chart->id, app->name, dim->metric, dim->value_type, dim->multiplier, dim->divisor); + STATSD_APP_CHART_DIM *dim = add_dimension_to_app_chart( + app + , chart + , metric_name + , dim_name + , (multipler && *multipler)?str2l(multipler):1 + , (divisor && *divisor)?str2l(divisor):1 + , string2valuetype(type, line, path, filename) + ); + + if(pattern) + dim->metric_pattern = simple_pattern_create(dim->metric, SIMPLE_PATTERN_EXACT); } else { error("STATSD: ignoring line %zu ('%s') of file '%s/%s'. Unknown keyword for the [%s] section.", line, name, path, filename, chart->id); @@ -1248,19 +1342,21 @@ static inline RRDSET *statsd_private_rrdset_create( statsd.private_charts++; RRDSET *st = rrdset_create_custom( - localhost - , type - , id - , name - , family - , context - , title - , units - , priority - , update_every - , chart_type - , memory_mode - , history + localhost // host + , type // type + , id // id + , name // name + , family // family + , context // context + , title // title + , units // units + , "statsd" // plugin + , NULL // module + , priority // priority + , update_every // update every + , chart_type // chart type + , memory_mode // memory mode + , history // history ); rrdset_flag_set(st, RRDSET_FLAG_STORE_FIRST); // rrdset_flag_set(st, RRDSET_FLAG_DEBUG); @@ -1484,6 +1580,22 @@ static inline void statsd_flush_timer_or_histogram(STATSD_METRIC *m, const char netdata_mutex_lock(&m->histogram.ext->mutex); + if(unlikely(!m->histogram.ext->zeroed)) { + // reset the metrics + // if we collected anything, they will be updated below + // this ensures that we report zeros if nothing is collected + + m->histogram.ext->last_min = 0; + m->histogram.ext->last_max = 0; + m->last = 0; + m->histogram.ext->last_median = 0; + m->histogram.ext->last_stddev = 0; + m->histogram.ext->last_sum = 0; + m->histogram.ext->last_percentile = 0; + + m->histogram.ext->zeroed = 1; + } + int updated = 0; if(m->count && !m->reset && m->histogram.ext->used > 0) { size_t len = m->histogram.ext->used; @@ -1506,11 +1618,11 @@ static inline void statsd_flush_timer_or_histogram(STATSD_METRIC *m, const char debug(D_STATSD, "STATSD %s metric %s: min " COLLECTED_NUMBER_FORMAT ", max " COLLECTED_NUMBER_FORMAT ", last " COLLECTED_NUMBER_FORMAT ", pcent " COLLECTED_NUMBER_FORMAT ", median " COLLECTED_NUMBER_FORMAT ", stddev " COLLECTED_NUMBER_FORMAT ", sum " COLLECTED_NUMBER_FORMAT, dim, m->name, m->histogram.ext->last_min, m->histogram.ext->last_max, m->last, m->histogram.ext->last_percentile, m->histogram.ext->last_median, m->histogram.ext->last_stddev, m->histogram.ext->last_sum); + m->histogram.ext->zeroed = 0; m->reset = 1; updated = 1; } - if(m->options & STATSD_METRIC_OPTION_PRIVATE_CHART_ENABLED && (updated || !(m->options & STATSD_METRIC_OPTION_SHOW_GAPS_WHEN_NOT_COLLECTED))) statsd_private_chart_timer_or_histogram(m, dim, family, units); @@ -1540,6 +1652,71 @@ static inline RRD_ALGORITHM statsd_algorithm_for_metric(STATSD_METRIC *m) { } } +static inline void link_metric_to_app_dimension(STATSD_APP *app, STATSD_METRIC *m, STATSD_APP_CHART *chart, STATSD_APP_CHART_DIM *dim) { + if(dim->value_type == STATSD_APP_CHART_DIM_VALUE_TYPE_EVENTS) { + dim->value_ptr = &m->events; + dim->algorithm = RRD_ALGORITHM_INCREMENTAL; + } + else if(m->type == STATSD_METRIC_TYPE_HISTOGRAM || m->type == STATSD_METRIC_TYPE_TIMER) { + dim->algorithm = RRD_ALGORITHM_ABSOLUTE; + dim->divisor *= statsd.decimal_detail; + + switch(dim->value_type) { + case STATSD_APP_CHART_DIM_VALUE_TYPE_EVENTS: + // will never match - added to avoid warning + break; + + case STATSD_APP_CHART_DIM_VALUE_TYPE_LAST: + case STATSD_APP_CHART_DIM_VALUE_TYPE_AVERAGE: + dim->value_ptr = &m->last; + break; + + case STATSD_APP_CHART_DIM_VALUE_TYPE_SUM: + dim->value_ptr = &m->histogram.ext->last_sum; + break; + + case STATSD_APP_CHART_DIM_VALUE_TYPE_MIN: + dim->value_ptr = &m->histogram.ext->last_min; + break; + + case STATSD_APP_CHART_DIM_VALUE_TYPE_MAX: + dim->value_ptr = &m->histogram.ext->last_max; + break; + + case STATSD_APP_CHART_DIM_VALUE_TYPE_MEDIAN: + dim->value_ptr = &m->histogram.ext->last_median; + break; + + case STATSD_APP_CHART_DIM_VALUE_TYPE_PERCENTILE: + dim->value_ptr = &m->histogram.ext->last_percentile; + break; + + case STATSD_APP_CHART_DIM_VALUE_TYPE_STDDEV: + dim->value_ptr = &m->histogram.ext->last_stddev; + break; + } + } + else { + if (dim->value_type != STATSD_APP_CHART_DIM_VALUE_TYPE_LAST) + error("STATSD: unsupported value type for dimension '%s' of chart '%s' of app '%s' on metric '%s'", dim->name, chart->id, app->name, m->name); + + dim->value_ptr = &m->last; + dim->algorithm = statsd_algorithm_for_metric(m); + + if(m->type == STATSD_METRIC_TYPE_GAUGE) + dim->divisor *= statsd.decimal_detail; + } + + if(unlikely(chart->st && dim->rd)) { + rrddim_set_algorithm(chart->st, dim->rd, dim->algorithm); + rrddim_set_multiplier(chart->st, dim->rd, dim->multiplier); + rrddim_set_divisor(chart->st, dim->rd, dim->divisor); + } + + chart->dimensions_linked_count++; + debug(D_STATSD, "metric '%s' of type %u linked with app '%s', chart '%s', dimension '%s', algorithm '%s'", m->name, m->type, app->name, chart->id, dim->name, rrd_algorithm_name(dim->algorithm)); +} + static inline void check_if_metric_is_for_app(STATSD_INDEX *index, STATSD_METRIC *m) { (void)index; @@ -1565,78 +1742,103 @@ static inline void check_if_metric_is_for_app(STATSD_INDEX *index, STATSD_METRIC // check if there is a chart in this app, willing to get this metric STATSD_APP_CHART *chart; for(chart = app->charts; chart; chart = chart->next) { + STATSD_APP_CHART_DIM *dim; for(dim = chart->dimensions; dim ; dim = dim->next) { - if(!dim->value_ptr && dim->metric_hash == m->hash && !strcmp(dim->metric, m->name)) { - // we have a match - this metric should be linked to this dimension + if(unlikely(dim->metric_pattern)) { + size_t dim_name_len = strlen(dim->name); + size_t wildcarded_len = dim_name_len + strlen(m->name) + 1; + char wildcarded[wildcarded_len]; - if(dim->value_type == STATSD_APP_CHART_DIM_VALUE_TYPE_EVENTS) { - dim->value_ptr = &m->events; - dim->algorithm = RRD_ALGORITHM_INCREMENTAL; - } - else if(m->type == STATSD_METRIC_TYPE_HISTOGRAM || m->type == STATSD_METRIC_TYPE_TIMER) { - dim->algorithm = RRD_ALGORITHM_ABSOLUTE; - dim->divisor *= statsd.decimal_detail; - - switch(dim->value_type) { - case STATSD_APP_CHART_DIM_VALUE_TYPE_EVENTS: - // will never match - added to avoid warning - break; - - case STATSD_APP_CHART_DIM_VALUE_TYPE_LAST: - case STATSD_APP_CHART_DIM_VALUE_TYPE_AVERAGE: - dim->value_ptr = &m->last; - break; - - case STATSD_APP_CHART_DIM_VALUE_TYPE_SUM: - dim->value_ptr = &m->histogram.ext->last_sum; - break; - - case STATSD_APP_CHART_DIM_VALUE_TYPE_MIN: - dim->value_ptr = &m->histogram.ext->last_min; - break; - - case STATSD_APP_CHART_DIM_VALUE_TYPE_MAX: - dim->value_ptr = &m->histogram.ext->last_max; - break; - - case STATSD_APP_CHART_DIM_VALUE_TYPE_MEDIAN: - dim->value_ptr = &m->histogram.ext->last_median; - break; - - case STATSD_APP_CHART_DIM_VALUE_TYPE_PERCENTILE: - dim->value_ptr = &m->histogram.ext->last_percentile; - break; - - case STATSD_APP_CHART_DIM_VALUE_TYPE_STDDEV: - dim->value_ptr = &m->histogram.ext->last_stddev; - break; - } - } - else { - if (dim->value_type != STATSD_APP_CHART_DIM_VALUE_TYPE_LAST) - error("STATSD: unsupported value type for dimension '%s' of chart '%s' of app '%s' on metric '%s'", dim->name, chart->id, app->name, m->name); + strcpy(wildcarded, dim->name); + char *ws = &wildcarded[dim_name_len]; - dim->value_ptr = &m->last; - dim->algorithm = statsd_algorithm_for_metric(m); + if(simple_pattern_matches_extract(dim->metric_pattern, m->name, ws, wildcarded_len - dim_name_len)) { - if(m->type == STATSD_METRIC_TYPE_GAUGE) - dim->divisor *= statsd.decimal_detail; - } + char *final_name = NULL; - if(unlikely(chart->st && dim->rd)) { - rrddim_set_algorithm(chart->st, dim->rd, dim->algorithm); - rrddim_set_multiplier(chart->st, dim->rd, dim->multiplier); - rrddim_set_divisor(chart->st, dim->rd, dim->divisor); - } + if(app->dict) { + if(likely(*wildcarded)) { + // use the name of the wildcarded string + final_name = dictionary_get(app->dict, wildcarded); + } + + if(unlikely(!final_name)) { + // use the name of the metric + final_name = dictionary_get(app->dict, m->name); + } + } - chart->dimensions_linked_count++; - debug(D_STATSD, "metric '%s' of type %u linked with app '%s', chart '%s', dimension '%s', algorithm '%s'", m->name, m->type, app->name, chart->id, dim->name, rrd_algorithm_name(dim->algorithm)); + if(unlikely(!final_name)) + final_name = wildcarded; + + add_dimension_to_app_chart( + app + , chart + , m->name + , final_name + , dim->multiplier + , dim->divisor + , dim->value_type + ); + + // the new dimension is appended to the list + // so, it will be matched and linked later too + } + } + else if(!dim->value_ptr && dim->metric_hash == m->hash && !strcmp(dim->metric, m->name)) { + // we have a match - this metric should be linked to this dimension + link_metric_to_app_dimension(app, m, chart, dim); } } + + } + } + } +} + +static inline RRDDIM *statsd_add_dim_to_app_chart(STATSD_APP *app, STATSD_APP_CHART *chart, STATSD_APP_CHART_DIM *dim) { + (void)app; + + // allow the same statsd metric to be added multiple times to the same chart + + STATSD_APP_CHART_DIM *tdim; + size_t count_same_metric = 0, count_same_metric_value_type = 0; + size_t pos_same_metric_value_type = 0; + + for (tdim = chart->dimensions; tdim && tdim->next; tdim = tdim->next) { + if (dim->metric_hash == tdim->metric_hash && !strcmp(dim->metric, tdim->metric)) { + count_same_metric++; + + if(dim->value_type == tdim->value_type) { + count_same_metric_value_type++; + if (tdim == dim) + pos_same_metric_value_type = count_same_metric_value_type; } } } + + if(count_same_metric > 1) { + // the same metric is found multiple times + + size_t len = strlen(dim->metric) + 100; + char metric[ len + 1 ]; + + if(count_same_metric_value_type > 1) { + // the same metric, with the same value type, is added multiple times + snprintfz(metric, len, "%s_%s%zu", dim->metric, valuetype2string(dim->value_type), pos_same_metric_value_type); + } + else { + // the same metric, with different value type is added + snprintfz(metric, len, "%s_%s", dim->metric, valuetype2string(dim->value_type)); + } + + dim->rd = rrddim_add(chart->st, metric, dim->name, dim->multiplier, dim->divisor, dim->algorithm); + return dim->rd; + } + + dim->rd = rrddim_add(chart->st, dim->metric, dim->name, dim->multiplier, dim->divisor, dim->algorithm); + return dim->rd; } static inline void statsd_update_app_chart(STATSD_APP *app, STATSD_APP_CHART *chart) { @@ -1644,19 +1846,21 @@ static inline void statsd_update_app_chart(STATSD_APP *app, STATSD_APP_CHART *ch if(!chart->st) { chart->st = rrdset_create_custom( - localhost - , app->name - , chart->id - , chart->name - , chart->family - , chart->context - , chart->title - , chart->units - , chart->priority - , statsd.update_every - , chart->chart_type - , app->rrd_memory_mode - , app->rrd_history_entries + localhost // host + , app->name // type + , chart->id // id + , chart->name // name + , chart->family // family + , chart->context // context + , chart->title // title + , chart->units // units + , "statsd" // plugin + , NULL // module + , chart->priority // priority + , statsd.update_every // update every + , chart->chart_type // chart type + , app->rrd_memory_mode // memory mode + , app->rrd_history_entries // history ); rrdset_flag_set(chart->st, RRDSET_FLAG_STORE_FIRST); @@ -1666,12 +1870,14 @@ static inline void statsd_update_app_chart(STATSD_APP *app, STATSD_APP_CHART *ch STATSD_APP_CHART_DIM *dim; for(dim = chart->dimensions; dim ;dim = dim->next) { - if(unlikely(!dim->rd)) - dim->rd = rrddim_add(chart->st, dim->name, NULL, dim->multiplier, dim->divisor, dim->algorithm); + if(likely(!dim->metric_pattern)) { + if (unlikely(!dim->rd)) + statsd_add_dim_to_app_chart(app, chart, dim); - if(unlikely(dim->value_ptr)) { - debug(D_STATSD, "updating dimension '%s' (%s) of chart '%s' (%s) for app '%s' with value " COLLECTED_NUMBER_FORMAT, dim->name, dim->rd->id, chart->id, chart->st->id, app->name, *dim->value_ptr); - rrddim_set_by_pointer(chart->st, dim->rd, *dim->value_ptr); + if (unlikely(dim->value_ptr)) { + debug(D_STATSD, "updating dimension '%s' (%s) of chart '%s' (%s) for app '%s' with value " COLLECTED_NUMBER_FORMAT, dim->name, dim->rd->id, chart->id, chart->st->id, app->name, *dim->value_ptr); + rrddim_set_by_pointer(chart->st, dim->rd, *dim->value_ptr); + } } } @@ -1871,6 +2077,8 @@ void *statsd_main(void *ptr) { , NULL , "Metrics in the netdata statsd database" , "metrics" + , "netdata" + , "stats" , 132000 , statsd.update_every , RRDSET_TYPE_STACKED @@ -1890,6 +2098,8 @@ void *statsd_main(void *ptr) { , NULL , "Events processed by the netdata statsd server" , "events/s" + , "netdata" + , "stats" , 132001 , statsd.update_every , RRDSET_TYPE_STACKED @@ -1911,6 +2121,8 @@ void *statsd_main(void *ptr) { , NULL , "Read operations made by the netdata statsd server" , "reads/s" + , "netdata" + , "stats" , 132002 , statsd.update_every , RRDSET_TYPE_STACKED @@ -1926,6 +2138,8 @@ void *statsd_main(void *ptr) { , NULL , "Bytes read by the netdata statsd server" , "kilobits/s" + , "netdata" + , "stats" , 132003 , statsd.update_every , RRDSET_TYPE_STACKED @@ -1941,6 +2155,8 @@ void *statsd_main(void *ptr) { , NULL , "Network packets processed by the netdata statsd server" , "packets/s" + , "netdata" + , "stats" , 132004 , statsd.update_every , RRDSET_TYPE_STACKED @@ -1956,6 +2172,8 @@ void *statsd_main(void *ptr) { , NULL , "Private metric charts created by the netdata statsd server" , "charts" + , "netdata" + , "stats" , 132010 , statsd.update_every , RRDSET_TYPE_AREA diff --git a/src/storage_number.c b/src/storage_number.c index 05494120..3fd22a41 100644 --- a/src/storage_number.c +++ b/src/storage_number.c @@ -39,7 +39,9 @@ storage_number pack_storage_number(calculated_number value, uint32_t flags) r += (1 << 30) + (m << 27); // the multiplier m if(n > (calculated_number)0x00ffffff) { + #ifdef NETDATA_INTERNAL_CHECKS error("Number " CALCULATED_NUMBER_FORMAT " is too big.", value); + #endif r += 0x00ffffff; return r; } diff --git a/src/storage_number.h b/src/storage_number.h index 3c1b6bab..616ff881 100644 --- a/src/storage_number.h +++ b/src/storage_number.h @@ -17,6 +17,9 @@ typedef long double collected_number; #define calculated_number_llrint(x) llrintl(x) #define calculated_number_round(x) roundl(x) #define calculated_number_fabs(x) fabsl(x) +#define calculated_number_epsilon (calculated_number)0.0000001 + +#define calculated_number_equal(a, b) (calculated_number_fabs((a) - (b)) < calculated_number_epsilon) typedef uint32_t storage_number; #define STORAGE_NUMBER_FORMAT "%u" diff --git a/src/sys_devices_system_edac_mc.c b/src/sys_devices_system_edac_mc.c index 7ec98943..9eac8a12 100644 --- a/src/sys_devices_system_edac_mc.c +++ b/src/sys_devices_system_edac_mc.c @@ -140,6 +140,8 @@ int do_proc_sys_devices_system_edac_mc(int update_every, usec_t dt) { , NULL , "ECC Memory Correctable Errors" , "errors" + , "proc" + , "/sys/devices/system/edac/mc" , 6600 , update_every , RRDSET_TYPE_LINE @@ -176,6 +178,8 @@ int do_proc_sys_devices_system_edac_mc(int update_every, usec_t dt) { , NULL , "ECC Memory Uncorrectable Errors" , "errors" + , "proc" + , "/sys/devices/system/edac/mc" , 6610 , update_every , RRDSET_TYPE_LINE diff --git a/src/sys_devices_system_node.c b/src/sys_devices_system_node.c index a7690e7b..86d55b29 100644 --- a/src/sys_devices_system_node.c +++ b/src/sys_devices_system_node.c @@ -105,6 +105,8 @@ int do_proc_sys_devices_system_node(int update_every, usec_t dt) { , NULL , "NUMA events" , "events/s" + , "proc" + , "/sys/devices/system/node" , 1000 , update_every , RRDSET_TYPE_LINE diff --git a/src/sys_fs_cgroup.c b/src/sys_fs_cgroup.c index c047547e..946831af 100644 --- a/src/sys_fs_cgroup.c +++ b/src/sys_fs_cgroup.c @@ -151,7 +151,8 @@ void read_cgroup_plugin_configuration() { // ---------------------------------------------------------------- " !*/init.scope " // ignore init.scope - " *.scope " // we need all *.scope for sure + " !/system.slice/run-*.scope " // ignore system.slice/run-XXXX.scope + " *.scope " // we need all other *.scope for sure // ---------------------------------------------------------------- @@ -180,6 +181,7 @@ void read_cgroup_plugin_configuration() { config_get("plugin:cgroups", "search for cgroups in subpaths matching", " !*/init.scope " // ignore init.scope " !*-qemu " // #345 + " !*.libvirt-qemu " // #3010 " !/init.scope " " !/system " " !/systemd " @@ -201,6 +203,9 @@ void read_cgroup_plugin_configuration() { " *docker* " " *lxc* " " *qemu* " + " *.libvirt-qemu " // #3010 + " !*/vcpu* " // libvirtd adds these sub-cgroups + " !*/emulator* " // libvirtd adds these sub-cgroups " !/ " " !*.mount " " !*.partition " @@ -762,7 +767,7 @@ static inline void read_cgroup_network_interfaces(struct cgroup *cg) { } if(!*t) { - error("CGROUP: empty container interface returned by script"); + error("CGROUP: empty guest interface returned by script"); continue; } @@ -1447,6 +1452,8 @@ void update_systemd_services_charts( , "services.cpu" , title , "%" + , "cgroup" + , "systemd" , CHART_PRIORITY_SYSTEMD_SERVICES , update_every , RRDSET_TYPE_STACKED @@ -1469,6 +1476,8 @@ void update_systemd_services_charts( , (cgroup_used_memory_without_cache) ? "Systemd Services Used Memory without Cache" : "Systemd Services Used Memory" , "MB" + , "cgroup" + , "systemd" , CHART_PRIORITY_SYSTEMD_SERVICES + 10 , update_every , RRDSET_TYPE_STACKED @@ -1490,6 +1499,8 @@ void update_systemd_services_charts( , "services.mem_rss" , "Systemd Services RSS Memory" , "MB" + , "cgroup" + , "systemd" , CHART_PRIORITY_SYSTEMD_SERVICES + 20 , update_every , RRDSET_TYPE_STACKED @@ -1509,6 +1520,8 @@ void update_systemd_services_charts( , "services.mem_mapped" , "Systemd Services Mapped Memory" , "MB" + , "cgroup" + , "systemd" , CHART_PRIORITY_SYSTEMD_SERVICES + 30 , update_every , RRDSET_TYPE_STACKED @@ -1528,6 +1541,8 @@ void update_systemd_services_charts( , "services.mem_cache" , "Systemd Services Cache Memory" , "MB" + , "cgroup" + , "systemd" , CHART_PRIORITY_SYSTEMD_SERVICES + 40 , update_every , RRDSET_TYPE_STACKED @@ -1547,6 +1562,8 @@ void update_systemd_services_charts( , "services.mem_writeback" , "Systemd Services Writeback Memory" , "MB" + , "cgroup" + , "systemd" , CHART_PRIORITY_SYSTEMD_SERVICES + 50 , update_every , RRDSET_TYPE_STACKED @@ -1566,6 +1583,8 @@ void update_systemd_services_charts( , "services.mem_pgfault" , "Systemd Services Memory Minor Page Faults" , "MB/s" + , "cgroup" + , "systemd" , CHART_PRIORITY_SYSTEMD_SERVICES + 60 , update_every , RRDSET_TYPE_STACKED @@ -1584,6 +1603,8 @@ void update_systemd_services_charts( , "services.mem_pgmajfault" , "Systemd Services Memory Major Page Faults" , "MB/s" + , "cgroup" + , "systemd" , CHART_PRIORITY_SYSTEMD_SERVICES + 70 , update_every , RRDSET_TYPE_STACKED @@ -1603,6 +1624,8 @@ void update_systemd_services_charts( , "services.mem_pgpgin" , "Systemd Services Memory Charging Activity" , "MB/s" + , "cgroup" + , "systemd" , CHART_PRIORITY_SYSTEMD_SERVICES + 80 , update_every , RRDSET_TYPE_STACKED @@ -1622,6 +1645,8 @@ void update_systemd_services_charts( , "services.mem_pgpgout" , "Systemd Services Memory Uncharging Activity" , "MB/s" + , "cgroup" + , "systemd" , CHART_PRIORITY_SYSTEMD_SERVICES + 90 , update_every , RRDSET_TYPE_STACKED @@ -1643,6 +1668,8 @@ void update_systemd_services_charts( , "services.mem_failcnt" , "Systemd Services Memory Limit Failures" , "MB" + , "cgroup" + , "systemd" , CHART_PRIORITY_SYSTEMD_SERVICES + 110 , update_every , RRDSET_TYPE_STACKED @@ -1664,6 +1691,8 @@ void update_systemd_services_charts( , "services.swap_usage" , "Systemd Services Swap Memory Used" , "MB" + , "cgroup" + , "systemd" , CHART_PRIORITY_SYSTEMD_SERVICES + 100 , update_every , RRDSET_TYPE_STACKED @@ -1685,6 +1714,8 @@ void update_systemd_services_charts( , "services.io_read" , "Systemd Services Disk Read Bandwidth" , "KB/s" + , "cgroup" + , "systemd" , CHART_PRIORITY_SYSTEMD_SERVICES + 120 , update_every , RRDSET_TYPE_STACKED @@ -1704,6 +1735,8 @@ void update_systemd_services_charts( , "services.io_write" , "Systemd Services Disk Write Bandwidth" , "KB/s" + , "cgroup" + , "systemd" , CHART_PRIORITY_SYSTEMD_SERVICES + 130 , update_every , RRDSET_TYPE_STACKED @@ -1725,6 +1758,8 @@ void update_systemd_services_charts( , "services.io_ops_read" , "Systemd Services Disk Read Operations" , "operations/s" + , "cgroup" + , "systemd" , CHART_PRIORITY_SYSTEMD_SERVICES + 140 , update_every , RRDSET_TYPE_STACKED @@ -1744,6 +1779,8 @@ void update_systemd_services_charts( , "services.io_ops_write" , "Systemd Services Disk Write Operations" , "operations/s" + , "cgroup" + , "systemd" , CHART_PRIORITY_SYSTEMD_SERVICES + 150 , update_every , RRDSET_TYPE_STACKED @@ -1765,6 +1802,8 @@ void update_systemd_services_charts( , "services.throttle_io_read" , "Systemd Services Throttle Disk Read Bandwidth" , "KB/s" + , "cgroup" + , "systemd" , CHART_PRIORITY_SYSTEMD_SERVICES + 160 , update_every , RRDSET_TYPE_STACKED @@ -1784,6 +1823,8 @@ void update_systemd_services_charts( , "services.throttle_io_write" , "Systemd Services Throttle Disk Write Bandwidth" , "KB/s" + , "cgroup" + , "systemd" , CHART_PRIORITY_SYSTEMD_SERVICES + 170 , update_every , RRDSET_TYPE_STACKED @@ -1805,6 +1846,8 @@ void update_systemd_services_charts( , "services.throttle_io_ops_read" , "Systemd Services Throttle Disk Read Operations" , "operations/s" + , "cgroup" + , "systemd" , CHART_PRIORITY_SYSTEMD_SERVICES + 180 , update_every , RRDSET_TYPE_STACKED @@ -1824,6 +1867,8 @@ void update_systemd_services_charts( , "services.throttle_io_ops_write" , "Systemd Services Throttle Disk Write Operations" , "operations/s" + , "cgroup" + , "systemd" , CHART_PRIORITY_SYSTEMD_SERVICES + 190 , update_every , RRDSET_TYPE_STACKED @@ -1845,6 +1890,8 @@ void update_systemd_services_charts( , "services.queued_io_ops_read" , "Systemd Services Queued Disk Read Operations" , "operations/s" + , "cgroup" + , "systemd" , CHART_PRIORITY_SYSTEMD_SERVICES + 200 , update_every , RRDSET_TYPE_STACKED @@ -1864,6 +1911,8 @@ void update_systemd_services_charts( , "services.queued_io_ops_write" , "Systemd Services Queued Disk Write Operations" , "operations/s" + , "cgroup" + , "systemd" , CHART_PRIORITY_SYSTEMD_SERVICES + 210 , update_every , RRDSET_TYPE_STACKED @@ -1885,6 +1934,8 @@ void update_systemd_services_charts( , "services.merged_io_ops_read" , "Systemd Services Merged Disk Read Operations" , "operations/s" + , "cgroup" + , "systemd" , CHART_PRIORITY_SYSTEMD_SERVICES + 220 , update_every , RRDSET_TYPE_STACKED @@ -1904,6 +1955,8 @@ void update_systemd_services_charts( , "services.merged_io_ops_write" , "Systemd Services Merged Disk Write Operations" , "operations/s" + , "cgroup" + , "systemd" , CHART_PRIORITY_SYSTEMD_SERVICES + 230 , update_every , RRDSET_TYPE_STACKED @@ -2184,6 +2237,8 @@ void update_cgroup_charts(int update_every) { , "cgroup.cpu" , title , "%" + , "cgroup" + , "default" , CHART_PRIORITY_CONTAINERS , update_every , RRDSET_TYPE_STACKED @@ -2215,6 +2270,8 @@ void update_cgroup_charts(int update_every) { , "cgroup.cpu_per_core" , title , "%" + , "cgroup" + , "default" , CHART_PRIORITY_CONTAINERS + 100 , update_every , RRDSET_TYPE_STACKED @@ -2247,6 +2304,8 @@ void update_cgroup_charts(int update_every) { , "cgroup.mem" , title , "MB" + , "cgroup" + , "default" , CHART_PRIORITY_CONTAINERS + 210 , update_every , RRDSET_TYPE_STACKED @@ -2285,6 +2344,8 @@ void update_cgroup_charts(int update_every) { , "cgroup.writeback" , title , "MB" + , "cgroup" + , "default" , CHART_PRIORITY_CONTAINERS + 300 , update_every , RRDSET_TYPE_AREA @@ -2315,6 +2376,8 @@ void update_cgroup_charts(int update_every) { , "cgroup.mem_activity" , title , "MB/s" + , "cgroup" + , "default" , CHART_PRIORITY_CONTAINERS + 400 , update_every , RRDSET_TYPE_LINE @@ -2341,6 +2404,8 @@ void update_cgroup_charts(int update_every) { , "cgroup.pgfaults" , title , "MB/s" + , "cgroup" + , "default" , CHART_PRIORITY_CONTAINERS + 500 , update_every , RRDSET_TYPE_LINE @@ -2369,6 +2434,8 @@ void update_cgroup_charts(int update_every) { , "cgroup.mem_usage" , title , "MB" + , "cgroup" + , "default" , CHART_PRIORITY_CONTAINERS + 200 , update_every , RRDSET_TYPE_STACKED @@ -2397,6 +2464,8 @@ void update_cgroup_charts(int update_every) { , "cgroup.mem_failcnt" , title , "count" + , "cgroup" + , "default" , CHART_PRIORITY_CONTAINERS + 250 , update_every , RRDSET_TYPE_LINE @@ -2423,6 +2492,8 @@ void update_cgroup_charts(int update_every) { , "cgroup.io" , title , "KB/s" + , "cgroup" + , "default" , CHART_PRIORITY_CONTAINERS + 1200 , update_every , RRDSET_TYPE_AREA @@ -2451,6 +2522,8 @@ void update_cgroup_charts(int update_every) { , "cgroup.serviced_ops" , title , "operations/s" + , "cgroup" + , "default" , CHART_PRIORITY_CONTAINERS + 1200 , update_every , RRDSET_TYPE_LINE @@ -2479,6 +2552,8 @@ void update_cgroup_charts(int update_every) { , "cgroup.throttle_io" , title , "KB/s" + , "cgroup" + , "default" , CHART_PRIORITY_CONTAINERS + 1200 , update_every , RRDSET_TYPE_AREA @@ -2507,6 +2582,8 @@ void update_cgroup_charts(int update_every) { , "cgroup.throttle_serviced_ops" , title , "operations/s" + , "cgroup" + , "default" , CHART_PRIORITY_CONTAINERS + 1200 , update_every , RRDSET_TYPE_LINE @@ -2535,6 +2612,8 @@ void update_cgroup_charts(int update_every) { , "cgroup.queued_ops" , title , "operations" + , "cgroup" + , "default" , CHART_PRIORITY_CONTAINERS + 2000 , update_every , RRDSET_TYPE_LINE @@ -2563,6 +2642,8 @@ void update_cgroup_charts(int update_every) { , "cgroup.merged_ops" , title , "operations/s" + , "cgroup" + , "default" , CHART_PRIORITY_CONTAINERS + 2100 , update_every , RRDSET_TYPE_LINE @@ -2650,6 +2731,8 @@ void *cgroups_main(void *ptr) { , NULL , "NetData CGroups Plugin CPU usage" , "milliseconds/s" + , "cgroup" + , "stats" , 132000 , cgroup_update_every , RRDSET_TYPE_STACKED diff --git a/src/sys_kernel_mm_ksm.c b/src/sys_kernel_mm_ksm.c index 6b04ef28..356315be 100644 --- a/src/sys_kernel_mm_ksm.c +++ b/src/sys_kernel_mm_ksm.c @@ -102,6 +102,8 @@ int do_sys_kernel_mm_ksm(int update_every, usec_t dt) { , NULL , "Kernel Same Page Merging" , "MB" + , "proc" + , "/sys/kernel/mm/ksm" , 5000 , update_every , RRDSET_TYPE_AREA @@ -140,6 +142,8 @@ int do_sys_kernel_mm_ksm(int update_every, usec_t dt) { , NULL , "Kernel Same Page Merging Savings" , "MB" + , "proc" + , "/sys/kernel/mm/ksm" , 5001 , update_every , RRDSET_TYPE_AREA @@ -172,6 +176,8 @@ int do_sys_kernel_mm_ksm(int update_every, usec_t dt) { , NULL , "Kernel Same Page Merging Effectiveness" , "percentage" + , "proc" + , "/sys/kernel/mm/ksm" , 5002 , update_every , RRDSET_TYPE_LINE diff --git a/src/unit_test.c b/src/unit_test.c index 3c963211..821063ba 100644 --- a/src/unit_test.c +++ b/src/unit_test.c @@ -1,5 +1,62 @@ #include "common.h" +static int check_rrdcalc_comparisons(void) { + RRDCALC_STATUS a, b; + + // make sure calloc() sets the status to UNINITIALIZED + memset(&a, 0, sizeof(RRDCALC_STATUS)); + if(a != RRDCALC_STATUS_UNINITIALIZED) { + fprintf(stderr, "%s is not zero.\n", rrdcalc_status2string(RRDCALC_STATUS_UNINITIALIZED)); + return 1; + } + + a = RRDCALC_STATUS_REMOVED; + b = RRDCALC_STATUS_UNDEFINED; + if(!(a < b)) { + fprintf(stderr, "%s is not less than %s\n", rrdcalc_status2string(a), rrdcalc_status2string(b)); + return 1; + } + + a = RRDCALC_STATUS_UNDEFINED; + b = RRDCALC_STATUS_UNINITIALIZED; + if(!(a < b)) { + fprintf(stderr, "%s is not less than %s\n", rrdcalc_status2string(a), rrdcalc_status2string(b)); + return 1; + } + + a = RRDCALC_STATUS_UNINITIALIZED; + b = RRDCALC_STATUS_CLEAR; + if(!(a < b)) { + fprintf(stderr, "%s is not less than %s\n", rrdcalc_status2string(a), rrdcalc_status2string(b)); + return 1; + } + + a = RRDCALC_STATUS_CLEAR; + b = RRDCALC_STATUS_RAISED; + if(!(a < b)) { + fprintf(stderr, "%s is not less than %s\n", rrdcalc_status2string(a), rrdcalc_status2string(b)); + return 1; + } + + a = RRDCALC_STATUS_RAISED; + b = RRDCALC_STATUS_WARNING; + if(!(a < b)) { + fprintf(stderr, "%s is not less than %s\n", rrdcalc_status2string(a), rrdcalc_status2string(b)); + return 1; + } + + a = RRDCALC_STATUS_WARNING; + b = RRDCALC_STATUS_CRITICAL; + if(!(a < b)) { + fprintf(stderr, "%s is not less than %s\n", rrdcalc_status2string(a), rrdcalc_status2string(b)); + return 1; + } + + fprintf(stderr, "RRDCALC_STATUSes are sortable.\n"); + + return 0; +} + int check_storage_number(calculated_number n, int debug) { char buffer[100]; uint32_t flags = SN_EXISTS; @@ -973,7 +1030,7 @@ int run_test(struct test *test) snprintfz(name, 100, "unittest-%s", test->name); // create the chart - RRDSET *st = rrdset_create_localhost("netdata", name, name, "netdata", NULL, "Unit Testing", "a value", 1 + RRDSET *st = rrdset_create_localhost("netdata", name, name, "netdata", NULL, "Unit Testing", "a value", "unittest", NULL, 1 , test->update_every, RRDSET_TYPE_LINE); RRDDIM *rd = rrddim_add(st, "dim1", NULL, test->multiplier, test->divisor, test->algorithm); @@ -1062,7 +1119,7 @@ int run_test(struct test *test) static int test_variable_renames(void) { fprintf(stderr, "Creating chart\n"); - RRDSET *st = rrdset_create_localhost("chart", "ID", NULL, "family", "context", "Unit Testing", "a value", 1, 1, RRDSET_TYPE_LINE); + RRDSET *st = rrdset_create_localhost("chart", "ID", NULL, "family", "context", "Unit Testing", "a value", "unittest", NULL, 1, 1, RRDSET_TYPE_LINE); fprintf(stderr, "Created chart with id '%s', name '%s'\n", st->id, st->name); fprintf(stderr, "Creating dimension DIM1\n"); @@ -1106,6 +1163,9 @@ static int test_variable_renames(void) { int run_all_mockup_tests(void) { + if(check_rrdcalc_comparisons()) + return 1; + if(!test_variable_renames()) return 1; @@ -1182,7 +1242,7 @@ int unit_test(long delay, long shift) int do_abst = 0; int do_absi = 0; - RRDSET *st = rrdset_create_localhost("netdata", name, name, "netdata", NULL, "Unit Testing", "a value", 1, 1 + RRDSET *st = rrdset_create_localhost("netdata", name, name, "netdata", NULL, "Unit Testing", "a value", "unittest", NULL, 1, 1 , RRDSET_TYPE_LINE); rrdset_flag_set(st, RRDSET_FLAG_DEBUG); diff --git a/src/web_api_v1.c b/src/web_api_v1.c index 9514f8db..02c6b0ed 100644 --- a/src/web_api_v1.c +++ b/src/web_api_v1.c @@ -1,20 +1,105 @@ #include "common.h" -inline int web_client_api_request_v1_data_group(char *name, int def) { - if(!strcmp(name, "average")) - return GROUP_AVERAGE; - - else if(!strcmp(name, "min")) - return GROUP_MIN; - - else if(!strcmp(name, "max")) - return GROUP_MAX; +static struct { + const char *name; + uint32_t hash; + int value; +} api_v1_data_groups[] = { + { "average" , 0 , GROUP_AVERAGE} + , {"min" , 0 , GROUP_MIN} + , {"max" , 0 , GROUP_MAX} + , {"sum" , 0 , GROUP_SUM} + , {"incremental_sum", 0 , GROUP_INCREMENTAL_SUM} + , {"incremental-sum", 0 , GROUP_INCREMENTAL_SUM} + , { NULL, 0, 0} +}; + +static struct { + const char *name; + uint32_t hash; + uint32_t value; +} api_v1_data_options[] = { + { "nonzero" , 0 , RRDR_OPTION_NONZERO} + , {"flip" , 0 , RRDR_OPTION_REVERSED} + , {"reversed" , 0 , RRDR_OPTION_REVERSED} + , {"reverse" , 0 , RRDR_OPTION_REVERSED} + , {"jsonwrap" , 0 , RRDR_OPTION_JSON_WRAP} + , {"min2max" , 0 , RRDR_OPTION_MIN2MAX} + , {"ms" , 0 , RRDR_OPTION_MILLISECONDS} + , {"milliseconds" , 0 , RRDR_OPTION_MILLISECONDS} + , {"abs" , 0 , RRDR_OPTION_ABSOLUTE} + , {"absolute" , 0 , RRDR_OPTION_ABSOLUTE} + , {"absolute_sum" , 0 , RRDR_OPTION_ABSOLUTE} + , {"absolute-sum" , 0 , RRDR_OPTION_ABSOLUTE} + , {"display_absolute", 0 , RRDR_OPTION_DISPLAY_ABS} + , {"display-absolute", 0 , RRDR_OPTION_DISPLAY_ABS} + , {"seconds" , 0 , RRDR_OPTION_SECONDS} + , {"null2zero" , 0 , RRDR_OPTION_NULL2ZERO} + , {"objectrows" , 0 , RRDR_OPTION_OBJECTSROWS} + , {"google_json" , 0 , RRDR_OPTION_GOOGLE_JSON} + , {"google-json" , 0 , RRDR_OPTION_GOOGLE_JSON} + , {"percentage" , 0 , RRDR_OPTION_PERCENTAGE} + , {"unaligned" , 0 , RRDR_OPTION_NOT_ALIGNED} + , { NULL, 0, 0} +}; + +static struct { + const char *name; + uint32_t hash; + uint32_t value; +} api_v1_data_formats[] = { + { DATASOURCE_FORMAT_DATATABLE_JSON , 0 , DATASOURCE_DATATABLE_JSON} + , {DATASOURCE_FORMAT_DATATABLE_JSONP, 0 , DATASOURCE_DATATABLE_JSONP} + , {DATASOURCE_FORMAT_JSON , 0 , DATASOURCE_JSON} + , {DATASOURCE_FORMAT_JSONP , 0 , DATASOURCE_JSONP} + , {DATASOURCE_FORMAT_SSV , 0 , DATASOURCE_SSV} + , {DATASOURCE_FORMAT_CSV , 0 , DATASOURCE_CSV} + , {DATASOURCE_FORMAT_TSV , 0 , DATASOURCE_TSV} + , {"tsv-excel" , 0 , DATASOURCE_TSV} + , {DATASOURCE_FORMAT_HTML , 0 , DATASOURCE_HTML} + , {DATASOURCE_FORMAT_JS_ARRAY , 0 , DATASOURCE_JS_ARRAY} + , {DATASOURCE_FORMAT_SSV_COMMA , 0 , DATASOURCE_SSV_COMMA} + , {DATASOURCE_FORMAT_CSV_JSON_ARRAY , 0 , DATASOURCE_CSV_JSON_ARRAY} + , { NULL, 0, 0} +}; + +static struct { + const char *name; + uint32_t hash; + uint32_t value; +} api_v1_data_google_formats[] = { + // this is not error - when google requests json, it expects javascript + // https://developers.google.com/chart/interactive/docs/dev/implementing_data_source#responseformat + { "json" , 0 , DATASOURCE_DATATABLE_JSONP} + , {"html" , 0 , DATASOURCE_HTML} + , {"csv" , 0 , DATASOURCE_CSV} + , {"tsv-excel", 0 , DATASOURCE_TSV} + , { NULL, 0, 0} +}; + +void web_client_api_v1_init(void) { + int i; + + for(i = 0; api_v1_data_groups[i].name ; i++) + api_v1_data_groups[i].hash = simple_hash(api_v1_data_groups[i].name); + + for(i = 0; api_v1_data_options[i].name ; i++) + api_v1_data_options[i].hash = simple_hash(api_v1_data_options[i].name); + + for(i = 0; api_v1_data_formats[i].name ; i++) + api_v1_data_formats[i].hash = simple_hash(api_v1_data_formats[i].name); + + for(i = 0; api_v1_data_google_formats[i].name ; i++) + api_v1_data_google_formats[i].hash = simple_hash(api_v1_data_google_formats[i].name); +} - else if(!strcmp(name, "sum")) - return GROUP_SUM; +inline int web_client_api_request_v1_data_group(char *name, int def) { + int i; - else if(!strcmp(name, "incremental-sum")) - return GROUP_INCREMENTAL_SUM; + uint32_t hash = simple_hash(name); + for(i = 0; api_v1_data_groups[i].name ; i++) + if(unlikely(hash == api_v1_data_groups[i].hash && !strcmp(name, api_v1_data_groups[i].name))) + return api_v1_data_groups[i].value; return def; } @@ -26,84 +111,41 @@ inline uint32_t web_client_api_request_v1_data_options(char *o) { while(o && *o && (tok = mystrsep(&o, ", |"))) { if(!*tok) continue; - if(!strcmp(tok, "nonzero")) - ret |= RRDR_OPTION_NONZERO; - else if(!strcmp(tok, "flip") || !strcmp(tok, "reversed") || !strcmp(tok, "reverse")) - ret |= RRDR_OPTION_REVERSED; - else if(!strcmp(tok, "jsonwrap")) - ret |= RRDR_OPTION_JSON_WRAP; - else if(!strcmp(tok, "min2max")) - ret |= RRDR_OPTION_MIN2MAX; - else if(!strcmp(tok, "ms") || !strcmp(tok, "milliseconds")) - ret |= RRDR_OPTION_MILLISECONDS; - else if(!strcmp(tok, "abs") || !strcmp(tok, "absolute") || !strcmp(tok, "absolute_sum") || !strcmp(tok, "absolute-sum")) - ret |= RRDR_OPTION_ABSOLUTE; - else if(!strcmp(tok, "seconds")) - ret |= RRDR_OPTION_SECONDS; - else if(!strcmp(tok, "null2zero")) - ret |= RRDR_OPTION_NULL2ZERO; - else if(!strcmp(tok, "objectrows")) - ret |= RRDR_OPTION_OBJECTSROWS; - else if(!strcmp(tok, "google_json")) - ret |= RRDR_OPTION_GOOGLE_JSON; - else if(!strcmp(tok, "percentage")) - ret |= RRDR_OPTION_PERCENTAGE; - else if(!strcmp(tok, "unaligned")) - ret |= RRDR_OPTION_NOT_ALIGNED; + uint32_t hash = simple_hash(tok); + int i; + for(i = 0; api_v1_data_options[i].name ; i++) { + if (unlikely(hash == api_v1_data_options[i].hash && !strcmp(tok, api_v1_data_options[i].name))) { + ret |= api_v1_data_options[i].value; + break; + } + } } return ret; } inline uint32_t web_client_api_request_v1_data_format(char *name) { - if(!strcmp(name, DATASOURCE_FORMAT_DATATABLE_JSON)) // datatable - return DATASOURCE_DATATABLE_JSON; - - else if(!strcmp(name, DATASOURCE_FORMAT_DATATABLE_JSONP)) // datasource - return DATASOURCE_DATATABLE_JSONP; - - else if(!strcmp(name, DATASOURCE_FORMAT_JSON)) // json - return DATASOURCE_JSON; - - else if(!strcmp(name, DATASOURCE_FORMAT_JSONP)) // jsonp - return DATASOURCE_JSONP; - - else if(!strcmp(name, DATASOURCE_FORMAT_SSV)) // ssv - return DATASOURCE_SSV; - - else if(!strcmp(name, DATASOURCE_FORMAT_CSV)) // csv - return DATASOURCE_CSV; - - else if(!strcmp(name, DATASOURCE_FORMAT_TSV) || !strcmp(name, "tsv-excel")) // tsv - return DATASOURCE_TSV; - - else if(!strcmp(name, DATASOURCE_FORMAT_HTML)) // html - return DATASOURCE_HTML; - - else if(!strcmp(name, DATASOURCE_FORMAT_JS_ARRAY)) // array - return DATASOURCE_JS_ARRAY; + uint32_t hash = simple_hash(name); + int i; - else if(!strcmp(name, DATASOURCE_FORMAT_SSV_COMMA)) // ssvcomma - return DATASOURCE_SSV_COMMA; - - else if(!strcmp(name, DATASOURCE_FORMAT_CSV_JSON_ARRAY)) // csvjsonarray - return DATASOURCE_CSV_JSON_ARRAY; + for(i = 0; api_v1_data_formats[i].name ; i++) { + if (unlikely(hash == api_v1_data_formats[i].hash && !strcmp(name, api_v1_data_formats[i].name))) { + return api_v1_data_formats[i].value; + } + } return DATASOURCE_JSON; } inline uint32_t web_client_api_request_v1_data_google_format(char *name) { - if(!strcmp(name, "json")) - return DATASOURCE_DATATABLE_JSONP; - - else if(!strcmp(name, "html")) - return DATASOURCE_HTML; + uint32_t hash = simple_hash(name); + int i; - else if(!strcmp(name, "csv")) - return DATASOURCE_CSV; - - else if(!strcmp(name, "tsv-excel")) - return DATASOURCE_TSV; + for(i = 0; api_v1_data_google_formats[i].name ; i++) { + if (unlikely(hash == api_v1_data_google_formats[i].hash && !strcmp(name, api_v1_data_google_formats[i].name))) { + return api_v1_data_google_formats[i].value; + } + } return DATASOURCE_JSON; } @@ -371,7 +413,7 @@ int web_client_api_request_v1_badge(RRDHOST *host, struct web_client *w, char *u if(!st) st = rrdset_find_byname(host, chart); if(!st) { buffer_no_cacheable(w->response.data); - buffer_svg(w->response.data, "chart not found", NAN, "", NULL, NULL, -1); + buffer_svg(w->response.data, "chart not found", NAN, "", NULL, NULL, -1, 0); ret = 200; goto cleanup; } @@ -382,7 +424,7 @@ int web_client_api_request_v1_badge(RRDHOST *host, struct web_client *w, char *u rc = rrdcalc_find(st, alarm); if (!rc) { buffer_no_cacheable(w->response.data); - buffer_svg(w->response.data, "alarm not found", NAN, "", NULL, NULL, -1); + buffer_svg(w->response.data, "alarm not found", NAN, "", NULL, NULL, -1, 0); ret = 200; goto cleanup; } @@ -498,7 +540,9 @@ int web_client_api_request_v1_badge(RRDHOST *host, struct web_client *w, char *u units, label_color, value_color, - precision); + precision, + options + ); ret = 200; } else { @@ -532,7 +576,9 @@ int web_client_api_request_v1_badge(RRDHOST *host, struct web_client *w, char *u units, label_color, value_color, - precision); + precision, + options + ); } cleanup: @@ -816,55 +862,65 @@ inline int web_client_api_request_v1_registry(RRDHOST *host, struct web_client * #endif /* NETDATA_INTERNAL_CHECKS */ } - if(respect_web_browser_do_not_track_policy && web_client_has_donottrack(w)) { + if(unlikely(respect_web_browser_do_not_track_policy && web_client_has_donottrack(w))) { buffer_flush(w->response.data); buffer_sprintf(w->response.data, "Your web browser is sending 'DNT: 1' (Do Not Track). The registry requires persistent cookies on your browser to work."); return 400; } - if(action == 'A' && (!machine_guid || !machine_url || !url_name)) { - error("Invalid registry request - access requires these parameters: machine ('%s'), url ('%s'), name ('%s')", - machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", url_name?url_name:"UNSET"); - buffer_flush(w->response.data); - buffer_strcat(w->response.data, "Invalid registry Access request."); - return 400; - } - else if(action == 'D' && (!machine_guid || !machine_url || !delete_url)) { - error("Invalid registry request - delete requires these parameters: machine ('%s'), url ('%s'), delete_url ('%s')", - machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", delete_url?delete_url:"UNSET"); - buffer_flush(w->response.data); - buffer_strcat(w->response.data, "Invalid registry Delete request."); - return 400; + if(unlikely(action == 'H')) { + // HELLO request, dashboard ACL + if(unlikely(!web_client_can_access_dashboard(w))) + return web_client_permission_denied(w); } - else if(action == 'S' && (!machine_guid || !machine_url || !search_machine_guid)) { - error("Invalid registry request - search requires these parameters: machine ('%s'), url ('%s'), for ('%s')", - machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", search_machine_guid?search_machine_guid:"UNSET"); - buffer_flush(w->response.data); - buffer_strcat(w->response.data, "Invalid registry Search request."); - return 400; - } - else if(action == 'W' && (!machine_guid || !machine_url || !to_person_guid)) { - error("Invalid registry request - switching identity requires these parameters: machine ('%s'), url ('%s'), to ('%s')", - machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", to_person_guid?to_person_guid:"UNSET"); - buffer_flush(w->response.data); - buffer_strcat(w->response.data, "Invalid registry Switch request."); - return 400; + else { + // everything else, registry ACL + if(unlikely(!web_client_can_access_registry(w))) + return web_client_permission_denied(w); } switch(action) { case 'A': + if(unlikely(!machine_guid || !machine_url || !url_name)) { + error("Invalid registry request - access requires these parameters: machine ('%s'), url ('%s'), name ('%s')", machine_guid ? machine_guid : "UNSET", machine_url ? machine_url : "UNSET", url_name ? url_name : "UNSET"); + buffer_flush(w->response.data); + buffer_strcat(w->response.data, "Invalid registry Access request."); + return 400; + } + web_client_enable_tracking_required(w); return registry_request_access_json(host, w, person_guid, machine_guid, machine_url, url_name, now_realtime_sec()); case 'D': + if(unlikely(!machine_guid || !machine_url || !delete_url)) { + error("Invalid registry request - delete requires these parameters: machine ('%s'), url ('%s'), delete_url ('%s')", machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", delete_url?delete_url:"UNSET"); + buffer_flush(w->response.data); + buffer_strcat(w->response.data, "Invalid registry Delete request."); + return 400; + } + web_client_enable_tracking_required(w); return registry_request_delete_json(host, w, person_guid, machine_guid, machine_url, delete_url, now_realtime_sec()); case 'S': + if(unlikely(!machine_guid || !machine_url || !search_machine_guid)) { + error("Invalid registry request - search requires these parameters: machine ('%s'), url ('%s'), for ('%s')", machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", search_machine_guid?search_machine_guid:"UNSET"); + buffer_flush(w->response.data); + buffer_strcat(w->response.data, "Invalid registry Search request."); + return 400; + } + web_client_enable_tracking_required(w); return registry_request_search_json(host, w, person_guid, machine_guid, machine_url, search_machine_guid, now_realtime_sec()); case 'W': + if(unlikely(!machine_guid || !machine_url || !to_person_guid)) { + error("Invalid registry request - switching identity requires these parameters: machine ('%s'), url ('%s'), to ('%s')", machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", to_person_guid?to_person_guid:"UNSET"); + buffer_flush(w->response.data); + buffer_strcat(w->response.data, "Invalid registry Switch request."); + return 400; + } + web_client_enable_tracking_required(w); return registry_request_switch_json(host, w, person_guid, machine_guid, machine_url, to_person_guid, now_realtime_sec()); @@ -878,19 +934,40 @@ inline int web_client_api_request_v1_registry(RRDHOST *host, struct web_client * } } +static struct api_command { + const char *command; + uint32_t hash; + WEB_CLIENT_ACL acl; + int (*callback)(RRDHOST *host, struct web_client *w, char *url); +} api_commands[] = { + { "data", 0, WEB_CLIENT_ACL_DASHBOARD, web_client_api_request_v1_data }, + { "chart", 0, WEB_CLIENT_ACL_DASHBOARD, web_client_api_request_v1_chart }, + { "charts", 0, WEB_CLIENT_ACL_DASHBOARD, web_client_api_request_v1_charts }, + + // registry checks the ACL by itself, so we allow everything + { "registry", 0, WEB_CLIENT_ACL_NOCHECK, web_client_api_request_v1_registry }, + + // badges can be fetched with both dashboard and badge permissions + { "badge.svg", 0, WEB_CLIENT_ACL_DASHBOARD|WEB_CLIENT_ACL_BADGE, web_client_api_request_v1_badge }, + + { "alarms", 0, WEB_CLIENT_ACL_DASHBOARD, web_client_api_request_v1_alarms }, + { "alarm_log", 0, WEB_CLIENT_ACL_DASHBOARD, web_client_api_request_v1_alarm_log }, + { "alarm_variables", 0, WEB_CLIENT_ACL_DASHBOARD, web_client_api_request_v1_alarm_variables }, + { "allmetrics", 0, WEB_CLIENT_ACL_DASHBOARD, web_client_api_request_v1_allmetrics }, + + // terminator + { NULL, 0, WEB_CLIENT_ACL_NONE, NULL }, +}; + inline int web_client_api_request_v1(RRDHOST *host, struct web_client *w, char *url) { - static uint32_t hash_data = 0, hash_chart = 0, hash_charts = 0, hash_registry = 0, hash_badge = 0, hash_alarms = 0, hash_alarm_log = 0, hash_alarm_variables = 0, hash_raw = 0; + static int initialized = 0; + int i; + + if(unlikely(initialized == 0)) { + initialized = 1; - if(unlikely(hash_data == 0)) { - hash_data = simple_hash("data"); - hash_chart = simple_hash("chart"); - hash_charts = simple_hash("charts"); - hash_registry = simple_hash("registry"); - hash_badge = simple_hash("badge.svg"); - hash_alarms = simple_hash("alarms"); - hash_alarm_log = simple_hash("alarm_log"); - hash_alarm_variables = simple_hash("alarm_variables"); - hash_raw = simple_hash("allmetrics"); + for(i = 0; api_commands[i].command ; i++) + api_commands[i].hash = simple_hash(api_commands[i].command); } // get the command @@ -899,39 +976,19 @@ inline int web_client_api_request_v1(RRDHOST *host, struct web_client *w, char * debug(D_WEB_CLIENT, "%llu: Searching for API v1 command '%s'.", w->id, tok); uint32_t hash = simple_hash(tok); - if(hash == hash_data && !strcmp(tok, "data")) - return web_client_api_request_v1_data(host, w, url); - - else if(hash == hash_chart && !strcmp(tok, "chart")) - return web_client_api_request_v1_chart(host, w, url); - - else if(hash == hash_charts && !strcmp(tok, "charts")) - return web_client_api_request_v1_charts(host, w, url); - - else if(hash == hash_registry && !strcmp(tok, "registry")) - return web_client_api_request_v1_registry(host, w, url); - - else if(hash == hash_badge && !strcmp(tok, "badge.svg")) - return web_client_api_request_v1_badge(host, w, url); - - else if(hash == hash_alarms && !strcmp(tok, "alarms")) - return web_client_api_request_v1_alarms(host, w, url); - - else if(hash == hash_alarm_log && !strcmp(tok, "alarm_log")) - return web_client_api_request_v1_alarm_log(host, w, url); + for(i = 0; api_commands[i].command ;i++) { + if(unlikely(hash == api_commands[i].hash && !strcmp(tok, api_commands[i].command))) { + if(unlikely(api_commands[i].acl != WEB_CLIENT_ACL_NOCHECK) && !(w->acl & api_commands[i].acl)) + return web_client_permission_denied(w); - else if(hash == hash_alarm_variables && !strcmp(tok, "alarm_variables")) - return web_client_api_request_v1_alarm_variables(host, w, url); - - else if(hash == hash_raw && !strcmp(tok, "allmetrics")) - return web_client_api_request_v1_allmetrics(host, w, url); - - else { - buffer_flush(w->response.data); - buffer_strcat(w->response.data, "Unsupported v1 API command: "); - buffer_strcat_htmlescape(w->response.data, tok); - return 404; + return api_commands[i].callback(host, w, url); + } } + + buffer_flush(w->response.data); + buffer_strcat(w->response.data, "Unsupported v1 API command: "); + buffer_strcat_htmlescape(w->response.data, tok); + return 404; } else { buffer_flush(w->response.data); diff --git a/src/web_api_v1.h b/src/web_api_v1.h index e980edb1..6f4de1ab 100644 --- a/src/web_api_v1.h +++ b/src/web_api_v1.h @@ -18,4 +18,6 @@ extern int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, c extern int web_client_api_request_v1_registry(RRDHOST *host, struct web_client *w, char *url); extern int web_client_api_request_v1(RRDHOST *host, struct web_client *w, char *url); +extern void web_client_api_v1_init(void); + #endif //NETDATA_WEB_API_V1_H diff --git a/src/web_buffer_svg.c b/src/web_buffer_svg.c index 287bbd6b..25128bd3 100644 --- a/src/web_buffer_svg.c +++ b/src/web_buffer_svg.c @@ -382,7 +382,7 @@ static inline char *format_value_with_precision_and_unit(char *value_string, siz calculated_number abs = value; if(isless(value, 0)) { lstop = 1; - abs = -value; + abs = calculated_number_fabs(value); } if(isgreaterequal(abs, 1000)) { @@ -610,16 +610,22 @@ static inline const char *color_map(const char *color) { return color; } +typedef enum color_comparison { + COLOR_COMPARE_EQUAL, + COLOR_COMPARE_NOTEQUAL, + COLOR_COMPARE_LESS, + COLOR_COMPARE_LESSEQUAL, + COLOR_COMPARE_GREATER, + COLOR_COMPARE_GREATEREQUAL, +} BADGE_COLOR_COMPARISON; + static inline void calc_colorz(const char *color, char *final, size_t len, calculated_number value) { - int value_is_null = 0; - if(isnan(value) || isinf(value)) { - value = 0.0; - value_is_null = 1; - } + if(isnan(value) || isinf(value)) + value = NAN; char color_buffer[256 + 1] = ""; char value_buffer[256 + 1] = ""; - char comparison = '>'; + BADGE_COLOR_COMPARISON comparison = COLOR_COMPARE_GREATER; // example input: // color<max|color>min|color:null... @@ -633,8 +639,15 @@ static inline void calc_colorz(const char *color, char *final, size_t len, calcu while(*t && *t != '|') { switch(*t) { + case '!': + if(t[1] == '=') t++; + comparison = COLOR_COMPARE_NOTEQUAL; + dv = value_buffer; + break; + + case '=': case ':': - comparison = '='; + comparison = COLOR_COMPARE_EQUAL; dv = value_buffer; break; @@ -642,11 +655,11 @@ static inline void calc_colorz(const char *color, char *final, size_t len, calcu case ')': case '>': if(t[1] == '=') { - comparison = ')'; + comparison = COLOR_COMPARE_GREATEREQUAL; t++; } else - comparison = '>'; + comparison = COLOR_COMPARE_GREATER; dv = value_buffer; break; @@ -654,11 +667,15 @@ static inline void calc_colorz(const char *color, char *final, size_t len, calcu case '(': case '<': if(t[1] == '=') { - comparison = '('; + comparison = COLOR_COMPARE_LESSEQUAL; + t++; + } + else if(t[1] == '>' || t[1] == ')' || t[1] == '}') { + comparison = COLOR_COMPARE_NOTEQUAL; t++; } else - comparison = '<'; + comparison = COLOR_COMPARE_LESS; dv = value_buffer; break; @@ -689,19 +706,28 @@ static inline void calc_colorz(const char *color, char *final, size_t len, calcu *dc = '\0'; if(dv) { *dv = '\0'; + calculated_number v; - if(value_is_null) { - if(!*value_buffer || !strcmp(value_buffer, "null")) - break; + if(!*value_buffer || !strcmp(value_buffer, "null")) { + v = NAN; } else { - calculated_number v = str2l(value_buffer); + v = str2l(value_buffer); + if(isnan(v) || isinf(v)) + v = NAN; + } - if(comparison == '<' && value < v) break; - else if(comparison == '(' && value <= v) break; - else if(comparison == '>' && value > v) break; - else if(comparison == ')' && value >= v) break; - else if(comparison == '=' && value == v) break; + if(unlikely(isnan(value) || isnan(v))) { + if(isnan(value) && isnan(v)) + break; + } + else { + if (unlikely(comparison == COLOR_COMPARE_LESS && isless(value, v))) break; + else if (unlikely(comparison == COLOR_COMPARE_LESSEQUAL && islessequal(value, v))) break; + else if (unlikely(comparison == COLOR_COMPARE_GREATER && isgreater(value, v))) break; + else if (unlikely(comparison == COLOR_COMPARE_GREATEREQUAL && isgreaterequal(value, v))) break; + else if (unlikely(comparison == COLOR_COMPARE_EQUAL && !islessgreater(value, v))) break; + else if (unlikely(comparison == COLOR_COMPARE_NOTEQUAL && islessgreater(value, v))) break; } } else @@ -726,7 +752,7 @@ static inline void calc_colorz(const char *color, char *final, size_t len, calcu // colors #define COLOR_STRING_SIZE 100 -void buffer_svg(BUFFER *wb, const char *label, calculated_number value, const char *units, const char *label_color, const char *value_color, int precision) { +void buffer_svg(BUFFER *wb, const char *label, calculated_number value, const char *units, const char *label_color, const char *value_color, int precision, uint32_t options) { char label_buffer[LABEL_STRING_SIZE + 1] , value_color_buffer[COLOR_STRING_SIZE + 1] , value_string[VALUE_STRING_SIZE + 1] @@ -744,7 +770,7 @@ void buffer_svg(BUFFER *wb, const char *label, calculated_number value, const ch value_color = (isnan(value) || isinf(value))?"#999":"#4c1"; calc_colorz(value_color, value_color_buffer, COLOR_STRING_SIZE, value); - format_value_and_unit(value_string, VALUE_STRING_SIZE, value, units, precision); + format_value_and_unit(value_string, VALUE_STRING_SIZE, (options & RRDR_OPTION_DISPLAY_ABS)?calculated_number_fabs(value):value, units, precision); // we need to copy the label, since verdana11_width may write to it strncpyz(label_buffer, label, LABEL_STRING_SIZE); diff --git a/src/web_buffer_svg.h b/src/web_buffer_svg.h index 49f73e44..c09ef7bc 100644 --- a/src/web_buffer_svg.h +++ b/src/web_buffer_svg.h @@ -1,7 +1,7 @@ #ifndef NETDATA_WEB_BUFFER_SVG_H #define NETDATA_WEB_BUFFER_SVG_H 1 -extern void buffer_svg(BUFFER *wb, const char *label, calculated_number value, const char *units, const char *label_color, const char *value_color, int precision); +extern void buffer_svg(BUFFER *wb, const char *label, calculated_number value, const char *units, const char *label_color, const char *value_color, int precision, uint32_t options); extern char *format_value_and_unit(char *value_string, size_t value_string_len, calculated_number value, const char *units, int precision); #endif /* NETDATA_WEB_BUFFER_SVG_H */ diff --git a/src/web_client.c b/src/web_client.c index 6ec3e11e..e17bac92 100644 --- a/src/web_client.c +++ b/src/web_client.c @@ -8,6 +8,15 @@ int web_client_timeout = DEFAULT_DISCONNECT_IDLE_WEB_CLIENTS_AFTER_SECONDS; int respect_web_browser_do_not_track_policy = 0; char *web_x_frame_options = NULL; +SIMPLE_PATTERN *web_allow_connections_from = NULL; +SIMPLE_PATTERN *web_allow_streaming_from = NULL; +SIMPLE_PATTERN *web_allow_netdataconf_from = NULL; + +// WEB_CLIENT_ACL +SIMPLE_PATTERN *web_allow_dashboard_from = NULL; +SIMPLE_PATTERN *web_allow_registry_from = NULL; +SIMPLE_PATTERN *web_allow_badges_from = NULL; + #ifdef NETDATA_WITH_ZLIB int web_enable_gzip = 1, web_gzip_level = 3, web_gzip_strategy = Z_DEFAULT_STRATEGY; #endif /* NETDATA_WITH_ZLIB */ @@ -50,6 +59,31 @@ static inline int web_client_uncrock_socket(struct web_client *w) { return 0; } +inline int web_client_permission_denied(struct web_client *w) { + w->response.data->contenttype = CT_TEXT_PLAIN; + buffer_flush(w->response.data); + buffer_strcat(w->response.data, "You are not allowed to access this resource."); + w->response.code = 403; + return 403; +} + +static void log_connection(struct web_client *w, const char *msg) { + log_access("%llu: %d '[%s]:%s' '%s'", w->id, gettid(), w->client_ip, w->client_port, msg); +} + +static void web_client_update_acl_matches(struct web_client *w) { + w->acl = WEB_CLIENT_ACL_NONE; + + if(!web_allow_dashboard_from || simple_pattern_matches(web_allow_dashboard_from, w->client_ip)) + w->acl |= WEB_CLIENT_ACL_DASHBOARD; + + if(!web_allow_registry_from || simple_pattern_matches(web_allow_registry_from, w->client_ip)) + w->acl |= WEB_CLIENT_ACL_REGISTRY; + + if(!web_allow_badges_from || simple_pattern_matches(web_allow_badges_from, w->client_ip)) + w->acl |= WEB_CLIENT_ACL_BADGE; +} + struct web_client *web_client_create(int listener) { struct web_client *w; @@ -58,12 +92,25 @@ struct web_client *web_client_create(int listener) { w->mode = WEB_CLIENT_MODE_NORMAL; { - w->ifd = accept_socket(listener, SOCK_NONBLOCK, w->client_ip, sizeof(w->client_ip), w->client_port, sizeof(w->client_port)); + w->ifd = accept_socket(listener, SOCK_NONBLOCK, w->client_ip, sizeof(w->client_ip), w->client_port, sizeof(w->client_port), web_allow_connections_from); + + if(unlikely(!*w->client_ip)) strcpy(w->client_ip, "-"); + if(unlikely(!*w->client_port)) strcpy(w->client_port, "-"); + if (w->ifd == -1) { - error("%llu: Cannot accept new incoming connection.", w->id); + if(errno == EPERM) + log_connection(w, "ACCESS DENIED"); + else { + log_connection(w, "CONNECTION FAILED"); + error("%llu: Failed to accept new incoming connection.", w->id); + } + freez(w); return NULL; } + else + log_connection(w, "CONNECTED"); + w->ofd = w->ifd; int flag = 1; @@ -75,6 +122,8 @@ struct web_client *web_client_create(int listener) { error("%llu: Cannot set SO_KEEPALIVE on socket.", w->id); } + web_client_update_acl_matches(w); + w->response.data = buffer_create(INITIAL_WEB_DATA_LENGTH); w->response.header = buffer_create(HTTP_RESPONSE_HEADER_SIZE); w->response.header_output = buffer_create(HTTP_RESPONSE_HEADER_SIZE); @@ -119,18 +168,45 @@ void web_client_reset(struct web_client *w) { // -------------------------------------------------------------------- - // access log - log_access("%llu: (sent/all = %zu/%zu bytes %0.0f%%, prep/sent/total = %0.2f/%0.2f/%0.2f ms) %s: %d '%s'", - w->id, - sent, size, -((size > 0) ? ((size - sent) / (double) size * 100.0) : 0.0), - dt_usec(&w->tv_ready, &w->tv_in) / 1000.0, - dt_usec(&tv, &w->tv_ready) / 1000.0, - dt_usec(&tv, &w->tv_in) / 1000.0, - (w->mode == WEB_CLIENT_MODE_FILECOPY) ? "filecopy" : ((w->mode == WEB_CLIENT_MODE_OPTIONS) - ? "options" : "data"), - w->response.code, - w->last_url + const char *mode; + switch(w->mode) { + case WEB_CLIENT_MODE_FILECOPY: + mode = "FILECOPY"; + break; + + case WEB_CLIENT_MODE_OPTIONS: + mode = "OPTIONS"; + break; + + case WEB_CLIENT_MODE_STREAM: + mode = "STREAM"; + break; + + case WEB_CLIENT_MODE_NORMAL: + mode = "DATA"; + break; + + default: + mode = "UNKNOWN"; + break; + } + + // access log + log_access("%llu: %d '[%s]:%s' '%s' (sent/all = %zu/%zu bytes %0.0f%%, prep/sent/total = %0.2f/%0.2f/%0.2f ms) %d '%s'", + w->id + , gettid() + , w->client_ip + , w->client_port + , mode + , sent + , size + , -((size > 0) ? ((size - sent) / (double) size * 100.0) : 0.0) + , dt_usec(&w->tv_ready, &w->tv_in) / 1000.0 + , dt_usec(&tv, &w->tv_ready) / 1000.0 + , dt_usec(&tv, &w->tv_in) / 1000.0 + , w->response.code + , w->last_url ); } @@ -271,6 +347,9 @@ gid_t web_files_gid(void) { int mysendfile(struct web_client *w, char *filename) { debug(D_WEB_CLIENT, "%llu: Looking for file '%s/%s'", w->id, netdata_configured_web_dir, filename); + if(!web_client_can_access_dashboard(w)) + return web_client_permission_denied(w); + // skip leading slashes while (*filename == '/') filename++; @@ -553,6 +632,13 @@ static inline int check_host_and_call(RRDHOST *host, struct web_client *w, char return func(host, w, url); } +static inline int check_host_and_dashboard_acl_and_call(RRDHOST *host, struct web_client *w, char *url, int (*func)(RRDHOST *, struct web_client *, char *)) { + if(!web_client_can_access_dashboard(w)) + return web_client_permission_denied(w); + + return check_host_and_call(host, w, url, func); +} + int web_client_api_request(RRDHOST *host, struct web_client *w, char *url) { // get the api version @@ -1082,25 +1168,28 @@ static inline int web_client_process_url(RRDHOST *host, struct web_client *w, ch } else if(unlikely(hash == hash_data && strcmp(tok, WEB_PATH_DATA) == 0)) { // old API "data" debug(D_WEB_CLIENT_ACCESS, "%llu: old API data request...", w->id); - return check_host_and_call(host, w, url, web_client_api_old_data_request_json); + return check_host_and_dashboard_acl_and_call(host, w, url, web_client_api_old_data_request_json); } else if(unlikely(hash == hash_datasource && strcmp(tok, WEB_PATH_DATASOURCE) == 0)) { // old API "datasource" debug(D_WEB_CLIENT_ACCESS, "%llu: old API datasource request...", w->id); - return check_host_and_call(host, w, url, web_client_api_old_data_request_jsonp); + return check_host_and_dashboard_acl_and_call(host, w, url, web_client_api_old_data_request_jsonp); } else if(unlikely(hash == hash_graph && strcmp(tok, WEB_PATH_GRAPH) == 0)) { // old API "graph" debug(D_WEB_CLIENT_ACCESS, "%llu: old API graph request...", w->id); - return check_host_and_call(host, w, url, web_client_api_old_graph_request); + return check_host_and_dashboard_acl_and_call(host, w, url, web_client_api_old_graph_request); } else if(unlikely(hash == hash_list && strcmp(tok, "list") == 0)) { // old API "list" debug(D_WEB_CLIENT_ACCESS, "%llu: old API list request...", w->id); - return check_host_and_call(host, w, url, web_client_api_old_list_request); + return check_host_and_dashboard_acl_and_call(host, w, url, web_client_api_old_list_request); } else if(unlikely(hash == hash_all_json && strcmp(tok, "all.json") == 0)) { // old API "all.json" debug(D_WEB_CLIENT_ACCESS, "%llu: old API all.json request...", w->id); - return check_host_and_call(host, w, url, web_client_api_old_all_json); + return check_host_and_dashboard_acl_and_call(host, w, url, web_client_api_old_all_json); } else if(unlikely(hash == hash_netdata_conf && strcmp(tok, "netdata.conf") == 0)) { // netdata.conf + if(unlikely(!web_client_can_access_netdataconf(w))) + return web_client_permission_denied(w); + debug(D_WEB_CLIENT_ACCESS, "%llu: generating netdata.conf ...", w->id); w->response.data->contenttype = CT_TEXT_PLAIN; buffer_flush(w->response.data); @@ -1109,6 +1198,9 @@ static inline int web_client_process_url(RRDHOST *host, struct web_client *w, ch } #ifdef NETDATA_INTERNAL_CHECKS else if(unlikely(hash == hash_exit && strcmp(tok, "exit") == 0)) { + if(unlikely(!web_client_can_access_netdataconf(w))) + return web_client_permission_denied(w); + w->response.data->contenttype = CT_TEXT_PLAIN; buffer_flush(w->response.data); @@ -1122,6 +1214,9 @@ static inline int web_client_process_url(RRDHOST *host, struct web_client *w, ch return 200; } else if(unlikely(hash == hash_debug && strcmp(tok, "debug") == 0)) { + if(unlikely(!web_client_can_access_netdataconf(w))) + return web_client_permission_denied(w); + buffer_flush(w->response.data); // get the name of the data to show @@ -1159,6 +1254,9 @@ static inline int web_client_process_url(RRDHOST *host, struct web_client *w, ch return 400; } else if(unlikely(hash == hash_mirror && strcmp(tok, "mirror") == 0)) { + if(unlikely(!web_client_can_access_netdataconf(w))) + return web_client_permission_denied(w); + debug(D_WEB_CLIENT_ACCESS, "%llu: Mirroring...", w->id); // replace the zero bytes with spaces @@ -1189,10 +1287,20 @@ void web_client_process_request(struct web_client *w) { case HTTP_VALIDATION_OK: switch(w->mode) { case WEB_CLIENT_MODE_STREAM: + if(unlikely(!web_client_can_access_stream(w))) { + web_client_permission_denied(w); + return; + } + w->response.code = rrdpush_receiver_thread_spawn(localhost, w, w->decoded_url); return; case WEB_CLIENT_MODE_OPTIONS: + if(unlikely(!web_client_can_access_dashboard(w) && !web_client_can_access_registry(w) && !web_client_can_access_badges(w))) { + web_client_permission_denied(w); + return; + } + w->response.data->contenttype = CT_TEXT_PLAIN; buffer_flush(w->response.data); buffer_strcat(w->response.data, "OK"); @@ -1201,6 +1309,11 @@ void web_client_process_request(struct web_client *w) { case WEB_CLIENT_MODE_FILECOPY: case WEB_CLIENT_MODE_NORMAL: + if(unlikely(!web_client_can_access_dashboard(w) && !web_client_can_access_registry(w) && !web_client_can_access_badges(w))) { + web_client_permission_denied(w); + return; + } + w->response.code = web_client_process_url(localhost, w, w->decoded_url); break; } @@ -1607,8 +1720,6 @@ void *web_client_main(void *ptr) int retval, timeout; nfds_t fdmax = 0; - log_access("%llu: %s port %s connected on thread task id %d", w->id, w->client_ip, w->client_port, gettid()); - for(;;) { if(unlikely(netdata_exit)) break; @@ -1716,9 +1827,11 @@ void *web_client_main(void *ptr) } } + if(w->mode != WEB_CLIENT_MODE_STREAM) + log_connection(w, "DISCONNECTED"); + web_client_reset(w); - log_access("%llu: %s port %s disconnected from thread task id %d", w->id, w->client_ip, w->client_port, gettid()); debug(D_WEB_CLIENT, "%llu: done...", w->id); // close the sockets/files now diff --git a/src/web_client.h b/src/web_client.h index 126a494f..a07558e1 100644 --- a/src/web_client.h +++ b/src/web_client.h @@ -44,7 +44,7 @@ typedef enum web_client_flags { //#define web_client_flag_set(w, flag) __atomic_or_fetch(&((w)->flags), flag, __ATOMIC_SEQ_CST) //#define web_client_flag_clear(w, flag) __atomic_and_fetch(&((w)->flags), ~flag, __ATOMIC_SEQ_CST) //#else -#define web_client_flag_check(w, flag) ((w)->flags & flag) +#define web_client_flag_check(w, flag) ((w)->flags & (flag)) #define web_client_flag_set(w, flag) (w)->flags |= flag #define web_client_flag_clear(w, flag) (w)->flags &= ~flag //#endif @@ -77,6 +77,7 @@ typedef enum web_client_flags { #define web_client_set_tcp(w) web_client_flag_set(w, WEB_CLIENT_FLAG_TCP_CLIENT) #define web_client_set_unix(w) web_client_flag_set(w, WEB_CLIENT_FLAG_UNIX_CLIENT) +#define web_client_check_unix(w) web_client_flag_check(w, WEB_CLIENT_FLAG_UNIX_CLIENT) #define web_client_is_corkable(w) web_client_flag_check(w, WEB_CLIENT_FLAG_TCP_CLIENT) @@ -107,11 +108,30 @@ struct response { }; +typedef enum web_client_acl { + WEB_CLIENT_ACL_NONE = 0, + WEB_CLIENT_ACL_NOCHECK = 0, + WEB_CLIENT_ACL_DASHBOARD = 1 << 0, + WEB_CLIENT_ACL_REGISTRY = 1 << 1, + WEB_CLIENT_ACL_BADGE = 1 << 2 +} WEB_CLIENT_ACL; + +#define web_client_can_access_dashboard(w) ((w)->acl & WEB_CLIENT_ACL_DASHBOARD) +#define web_client_can_access_registry(w) ((w)->acl & WEB_CLIENT_ACL_REGISTRY) +#define web_client_can_access_badges(w) ((w)->acl & WEB_CLIENT_ACL_BADGE) + +#define web_client_can_access_stream(w) \ + (!web_allow_streaming_from || simple_pattern_matches(web_allow_streaming_from, (w)->client_ip)) + +#define web_client_can_access_netdataconf(w) \ + (!web_allow_netdataconf_from || simple_pattern_matches(web_allow_netdataconf_from, (w)->client_ip)) + struct web_client { unsigned long long id; WEB_CLIENT_FLAGS flags; // status flags for the client WEB_CLIENT_MODE mode; // the operational mode of the client + WEB_CLIENT_ACL acl; // the access list of the client int tcp_cork; // 1 = we have a cork on the socket @@ -142,10 +162,18 @@ struct web_client { }; extern struct web_client *web_clients; +extern SIMPLE_PATTERN *web_allow_connections_from; +extern SIMPLE_PATTERN *web_allow_dashboard_from; +extern SIMPLE_PATTERN *web_allow_registry_from; +extern SIMPLE_PATTERN *web_allow_badges_from; +extern SIMPLE_PATTERN *web_allow_streaming_from; +extern SIMPLE_PATTERN *web_allow_netdataconf_from; extern uid_t web_files_uid(void); extern uid_t web_files_gid(void); +extern int web_client_permission_denied(struct web_client *w); + extern struct web_client *web_client_create(int listener); extern struct web_client *web_client_free(struct web_client *w); extern ssize_t web_client_send(struct web_client *w); diff --git a/src/web_server.c b/src/web_server.c index 72168d15..d231cbb5 100644 --- a/src/web_server.c +++ b/src/web_server.c @@ -168,6 +168,11 @@ void *socket_listen_main_multi_threaded(void *ptr) { continue; } + if(api_sockets.fds_families[i] == AF_UNIX) + web_client_set_unix(w); + else + web_client_set_tcp(w); + if(pthread_create(&w->thread, NULL, web_client_main, w) != 0) { error("%llu: failed to create new thread for web client.", w->id); WEB_CLIENT_IS_OBSOLETE(w); @@ -203,8 +208,8 @@ static inline int single_threaded_link_client(struct web_client *w, fd_set *ifds if(unlikely(web_client_check_obsolete(w) || web_client_check_dead(w) || (!web_client_has_wait_receive(w) && !web_client_has_wait_send(w)))) return 1; - if(unlikely(w->ifd < 0 || w->ifd >= FD_SETSIZE || w->ofd < 0 || w->ofd >= FD_SETSIZE)) { - error("%llu: invalid file descriptor, ifd = %d, ofd = %d (required 0 <= fd < FD_SETSIZE (%d)", w->id, w->ifd, w->ofd, FD_SETSIZE); + if(unlikely(w->ifd < 0 || w->ifd >= (int)FD_SETSIZE || w->ofd < 0 || w->ofd >= (int)FD_SETSIZE)) { + error("%llu: invalid file descriptor, ifd = %d, ofd = %d (required 0 <= fd < FD_SETSIZE (%d)", w->id, w->ifd, w->ofd, (int)FD_SETSIZE); return 1; } @@ -261,7 +266,7 @@ void *socket_listen_main_single_threaded(void *ptr) { fatal("LISTENER: no listen sockets available."); size_t i; - for(i = 0; i < FD_SETSIZE ; i++) + for(i = 0; i < (size_t)FD_SETSIZE ; i++) single_threaded_clients[i] = NULL; fd_set ifds, ofds, efds, rifds, rofds, refds; @@ -271,7 +276,7 @@ void *socket_listen_main_single_threaded(void *ptr) { int fdmax = 0; for(i = 0; i < api_sockets.opened ; i++) { - if (api_sockets.fds[i] < 0 || api_sockets.fds[i] >= FD_SETSIZE) + if (api_sockets.fds[i] < 0 || api_sockets.fds[i] >= (int)FD_SETSIZE) fatal("LISTENER: Listen socket %d is not ready, or invalid.", api_sockets.fds[i]); info("Listening on '%s'", (api_sockets.fds_names[i])?api_sockets.fds_names[i]:"UNKNOWN"); @@ -372,3 +377,142 @@ void *socket_listen_main_single_threaded(void *ptr) { pthread_exit(NULL); return NULL; } + + +#if 0 +// new TCP client connected +static void *web_server_add_callback(int fd, int socktype, short int *events) { + (void)fd; + (void)socktype; + + *events = POLLIN; + + debug(D_WEB_CLIENT_ACCESS, "LISTENER on %d: new connection.", fd); + struct web_client *w = web_client_create(fd); + + if(unlikely(socktype == AF_UNIX)) + web_client_set_unix(w); + else + web_client_set_tcp(w); + + return (void *)w; +} + +// TCP client disconnected +static void web_server_del_callback(int fd, int socktype, void *data) { + (void)fd; + (void)socktype; + + struct web_client *w = (struct web_client *)data; + + if(w) { + if(w->ofd == -1 || fd == w->ofd) { + // we free the client, only if the closing fd + // is the client socket + web_client_free(w); + } + } + + return; +} + +// Receive data +static int web_server_rcv_callback(int fd, int socktype, void *data, short int *events) { + (void)fd; + (void)socktype; + + *events = 0; + + struct web_client *w = (struct web_client *)data; + + if(unlikely(!web_client_has_wait_receive(w))) + return -1; + + if(unlikely(web_client_receive(w) < 0)) + return -1; + + if(unlikely(w->mode == WEB_CLIENT_MODE_FILECOPY)) { + if(unlikely(w->ifd != -1 && w->ifd != fd)) { + // FIXME: we switched input fd + // add a new socket to poll_events, with the same + } + else if(unlikely(w->ifd == -1)) { + // FIXME: we closed input fd + // instruct poll_events() to close fd + return -1; + } + } + else { + debug(D_WEB_CLIENT, "%llu: Processing received data.", w->id); + web_client_process_request(w); + } + + if(unlikely(w->ifd == fd && web_client_has_wait_receive(w))) + *events |= POLLIN; + + if(unlikely(w->ofd == fd && web_client_has_wait_send(w))) + *events |= POLLOUT; + + if(unlikely(*events == 0)) + return -1; + + return 0; +} + +static int web_server_snd_callback(int fd, int socktype, void *data, short int *events) { + (void)fd; + (void)socktype; + + struct web_client *w = (struct web_client *)data; + + if(unlikely(!web_client_has_wait_send(w))) + return -1; + + if(unlikely(web_client_send(w) < 0)) + return -1; + + if(unlikely(w->ifd == fd && web_client_has_wait_receive(w))) + *events |= POLLIN; + + if(unlikely(w->ofd == fd && web_client_has_wait_send(w))) + *events |= POLLOUT; + + if(unlikely(*events == 0)) + return -1; + + return 0; +} + +void *socket_listen_main_single_threaded(void *ptr) { + struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr; + + web_server_mode = WEB_SERVER_MODE_SINGLE_THREADED; + + info("Single-threaded WEB SERVER thread created with task id %d", gettid()); + + if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0) + error("Cannot set pthread cancel type to DEFERRED."); + + if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0) + error("Cannot set pthread cancel state to ENABLE."); + + if(!api_sockets.opened) + fatal("LISTENER: no listen sockets available."); + + poll_events(&api_sockets + , web_server_add_callback + , web_server_del_callback + , web_server_rcv_callback + , web_server_snd_callback + , web_allow_connections_from + , NULL + ); + + debug(D_WEB_CLIENT, "LISTENER: exit!"); + listen_sockets_close(&api_sockets); + + static_thread->enabled = 0; + pthread_exit(NULL); + return NULL; +} +#endif diff --git a/src/zfs_common.c b/src/zfs_common.c index 7fa05b03..0915416f 100644 --- a/src/zfs_common.c +++ b/src/zfs_common.c @@ -1,9 +1,9 @@ #include "common.h" #include "zfs_common.h" -extern struct arcstats arcstats; +struct arcstats arcstats = { 0 }; -void generate_charts_arcstats(int update_every) { +void generate_charts_arcstats(const char *plugin, int update_every) { // ARC reads unsigned long long aread = arcstats.hits + arcstats.misses; @@ -24,8 +24,8 @@ void generate_charts_arcstats(int update_every) { unsigned long long mread = mhit + mmiss; // l2 reads - unsigned long long l2hit = arcstats.l2_hits + arcstats.l2_misses; - unsigned long long l2miss = arcstats.prefetch_metadata_misses + arcstats.demand_metadata_misses; + unsigned long long l2hit = arcstats.l2_hits; + unsigned long long l2miss = arcstats.l2_misses; unsigned long long l2read = l2hit + l2miss; // -------------------------------------------------------------------- @@ -46,6 +46,8 @@ void generate_charts_arcstats(int update_every) { , NULL , "ZFS ARC Size" , "MB" + , plugin + , "zfs" , 2000 , update_every , RRDSET_TYPE_AREA @@ -68,7 +70,7 @@ void generate_charts_arcstats(int update_every) { // -------------------------------------------------------------------- - if(likely(l2exist)) { + if(likely(arcstats.l2exist)) { static RRDSET *st_l2_size = NULL; static RRDDIM *rd_l2_size = NULL; static RRDDIM *rd_l2_asize = NULL; @@ -82,6 +84,8 @@ void generate_charts_arcstats(int update_every) { , NULL , "ZFS L2 ARC Size" , "MB" + , plugin + , "zfs" , 2000 , update_every , RRDSET_TYPE_AREA @@ -117,6 +121,8 @@ void generate_charts_arcstats(int update_every) { , NULL , "ZFS Reads" , "reads/s" + , plugin + , "zfs" , 2010 , update_every , RRDSET_TYPE_AREA @@ -127,7 +133,7 @@ void generate_charts_arcstats(int update_every) { rd_pread = rrddim_add(st_reads, "preads", "prefetch", 1, 1, RRD_ALGORITHM_INCREMENTAL); rd_mread = rrddim_add(st_reads, "mreads", "metadata", 1, 1, RRD_ALGORITHM_INCREMENTAL); - if(l2exist) + if(arcstats.l2exist) rd_l2read = rrddim_add(st_reads, "l2reads", "l2", 1, 1, RRD_ALGORITHM_INCREMENTAL); } else @@ -138,7 +144,7 @@ void generate_charts_arcstats(int update_every) { rrddim_set_by_pointer(st_reads, rd_pread, pread); rrddim_set_by_pointer(st_reads, rd_mread, mread); - if(l2exist) + if(arcstats.l2exist) rrddim_set_by_pointer(st_reads, rd_l2read, l2read); rrdset_done(st_reads); @@ -146,7 +152,7 @@ void generate_charts_arcstats(int update_every) { // -------------------------------------------------------------------- - if(likely(l2exist)) { + if(likely(arcstats.l2exist)) { static RRDSET *st_l2bytes = NULL; static RRDDIM *rd_l2_read_bytes = NULL; static RRDDIM *rd_l2_write_bytes = NULL; @@ -160,6 +166,8 @@ void generate_charts_arcstats(int update_every) { , NULL , "ZFS ARC L2 Read/Write Rate" , "kilobytes/s" + , plugin + , "zfs" , 2200 , update_every , RRDSET_TYPE_AREA @@ -192,6 +200,8 @@ void generate_charts_arcstats(int update_every) { , NULL , "ZFS ARC Hits" , "percentage" + , plugin + , "zfs" , 2020 , update_every , RRDSET_TYPE_STACKED @@ -224,6 +234,8 @@ void generate_charts_arcstats(int update_every) { , NULL , "ZFS Demand Hits" , "percentage" + , plugin + , "zfs" , 2030 , update_every , RRDSET_TYPE_STACKED @@ -256,6 +268,8 @@ void generate_charts_arcstats(int update_every) { , NULL , "ZFS Prefetch Hits" , "percentage" + , plugin + , "zfs" , 2040 , update_every , RRDSET_TYPE_STACKED @@ -288,6 +302,8 @@ void generate_charts_arcstats(int update_every) { , NULL , "ZFS Metadata Hits" , "percentage" + , plugin + , "zfs" , 2050 , update_every , RRDSET_TYPE_STACKED @@ -306,7 +322,7 @@ void generate_charts_arcstats(int update_every) { // -------------------------------------------------------------------- - if(likely(l2exist)) { + if(likely(arcstats.l2exist)) { static RRDSET *st_l2hits = NULL; static RRDDIM *rd_l2hits = NULL; static RRDDIM *rd_l2misses = NULL; @@ -320,6 +336,8 @@ void generate_charts_arcstats(int update_every) { , NULL , "ZFS L2 Hits" , "percentage" + , plugin + , "zfs" , 2060 , update_every , RRDSET_TYPE_STACKED @@ -354,6 +372,8 @@ void generate_charts_arcstats(int update_every) { , NULL , "ZFS List Hits" , "hits/s" + , plugin + , "zfs" , 2100 , update_every , RRDSET_TYPE_AREA @@ -375,7 +395,7 @@ void generate_charts_arcstats(int update_every) { } } -void generate_charts_arc_summary(int update_every) { +void generate_charts_arc_summary(const char *plugin, int update_every) { unsigned long long arc_accesses_total = arcstats.hits + arcstats.misses; unsigned long long real_hits = arcstats.mfu_hits + arcstats.mru_hits; unsigned long long real_misses = arc_accesses_total - real_hits; @@ -411,6 +431,8 @@ void generate_charts_arc_summary(int update_every) { , NULL , "ZFS ARC Size Breakdown" , "percentage" + , plugin + , "zfs" , 2020 , update_every , RRDSET_TYPE_STACKED @@ -448,6 +470,8 @@ void generate_charts_arc_summary(int update_every) { , NULL , "ZFS Memory Operations" , "operations/s" + , plugin + , "zfs" , 2023 , update_every , RRDSET_TYPE_LINE @@ -492,6 +516,8 @@ void generate_charts_arc_summary(int update_every) { , NULL , "ZFS Important Operations" , "operations/s" + , plugin + , "zfs" , 2022 , update_every , RRDSET_TYPE_LINE @@ -528,6 +554,8 @@ void generate_charts_arc_summary(int update_every) { , NULL , "ZFS Actual Cache Hits" , "percentage" + , plugin + , "zfs" , 2019 , update_every , RRDSET_TYPE_STACKED @@ -560,6 +588,8 @@ void generate_charts_arc_summary(int update_every) { , NULL , "ZFS Data Demand Efficiency" , "percentage" + , plugin + , "zfs" , 2031 , update_every , RRDSET_TYPE_STACKED @@ -592,6 +622,8 @@ void generate_charts_arc_summary(int update_every) { , NULL , "ZFS Data Prefetch Efficiency" , "percentage" + , plugin + , "zfs" , 2032 , update_every , RRDSET_TYPE_STACKED @@ -624,6 +656,8 @@ void generate_charts_arc_summary(int update_every) { , NULL , "ZFS ARC Hash Elements" , "elements" + , plugin + , "zfs" , 2300 , update_every , RRDSET_TYPE_LINE @@ -656,6 +690,8 @@ void generate_charts_arc_summary(int update_every) { , NULL , "ZFS ARC Hash Chains" , "chains" + , plugin + , "zfs" , 2310 , update_every , RRDSET_TYPE_LINE diff --git a/src/zfs_common.h b/src/zfs_common.h index 9d3aa7df..4494e70c 100644 --- a/src/zfs_common.h +++ b/src/zfs_common.h @@ -8,6 +8,7 @@ #define ZFS_FAMILY_HASH "hashes" struct arcstats { + // values unsigned long long hits; unsigned long long misses; unsigned long long demand_data_hits; @@ -99,11 +100,12 @@ struct arcstats { unsigned long long arc_meta_min; unsigned long long arc_need_free; unsigned long long arc_sys_free; -}; -int l2exist; + // flags + int l2exist; +}; -void generate_charts_arcstats(int update_every); -void generate_charts_arc_summary(int update_every); +void generate_charts_arcstats(const char *plugin, int update_every); +void generate_charts_arc_summary(const char *plugin, int update_every); #endif //NETDATA_ZFS_COMMON_H diff --git a/system/netdata-openrc.in b/system/netdata-openrc.in index 465e1232..ce76f7e6 100644 --- a/system/netdata-openrc.in +++ b/system/netdata-openrc.in @@ -23,7 +23,7 @@ extra_started_commands="getconf" pidfile="/run/netdata.pid" -command="${NETDATA_INSTALL_PATH}/usr/sbin/netdata" +command="@sbindir_POST@/netdata" command_background="yes" command_args="-P ${pidfile} ${NETDATA_EXTRA_ARGS}" # start_stop_daemon_args="-u ${NETDATA_OWNER}" @@ -38,13 +38,13 @@ depend() { } start_post() { - if [[ ! -f @sysconfdir_POST@/netdata/netdata.conf ]]; then + if [ ! -f @sysconfdir_POST@/netdata/netdata.conf ]; then ebegin "Downloading default configuration to @sysconfdir_POST@/netdata/netdata.conf" sleep 2 curl -s -o @sysconfdir_POST@/netdata/netdata.conf.new "${NETDATA_CONFIG_URL}" ret=$? - if [[ $ret -eq 0 && -s @sysconfdir_POST@/netdata/netdata.conf.new ]]; then - mv @sysconfdir_POST@/netdata/netdata.conf{.new,} + if [ $ret -eq 0 && -s @sysconfdir_POST@/netdata/netdata.conf.new ]; then + mv @sysconfdir_POST@/netdata/netdata.conf.new @sysconfdir_POST@/netdata/netdata.conf else ret=1 rm @sysconfdir_POST@/netdata/netdata.conf.new 2>/dev/null @@ -57,20 +57,20 @@ stop_post() { local result ret=0 count=0 sigkill=0 ebegin "Waiting for netdata to save its database" - while [[ -f "${pidfile}" ]]; do - if [[ $count -gt ${NETDATA_WAIT_EXIT_TIMEOUT} ]]; then + while [ -f "${pidfile}" ]; do + if [ $count -gt ${NETDATA_WAIT_EXIT_TIMEOUT} ]; then sigkill=1 break fi - count=$[count + 1] + count=$((count + 1)) kill -0 $(cat ${pidfile}) 2>/dev/null ret=$? test $ret -eq 0 && sleep 1 done eend $sigkill - if [[ $sigkill -eq 1 && -f "${pidfile}" ]]; then + if [ $sigkill -eq 1 -a -f "${pidfile}" ]; then ebegin "Netdata is taking too long to exit, forcing it to quit" kill -SIGKILL $(cat ${pidfile}) 2>/dev/null eend $? diff --git a/system/netdata.service.in b/system/netdata.service.in index 1d4af988..58cdff22 100644 --- a/system/netdata.service.in +++ b/system/netdata.service.in @@ -9,6 +9,9 @@ Group=netdata RuntimeDirectory=netdata RuntimeDirectoryMode=0775 ExecStart=@sbindir_POST@/netdata -P /run/netdata/netdata.pid -D +ExecStartPre=/bin/mkdir -p @localstatedir_POST@/cache/netdata +ExecStartPre=/bin/chown -R netdata:netdata @localstatedir_POST@/cache/netdata +PermissionsStartOnly=true # saving a big db on slow disks may need some time TimeoutStopSec=60 diff --git a/web/Makefile.am b/web/Makefile.am index b587f5a1..02d89317 100644 --- a/web/Makefile.am +++ b/web/Makefile.am @@ -39,6 +39,7 @@ dist_webold_DATA = \ weblibdir=$(webdir)/lib dist_weblib_DATA = \ lib/bootstrap-3.3.7.min.js \ + lib/bootstrap-slider-10.0.0.min.js \ lib/bootstrap-table-1.11.0.min.js \ lib/bootstrap-table-export-1.11.0.min.js \ lib/bootstrap-toggle-2.2.2.min.js \ @@ -46,13 +47,16 @@ dist_weblib_DATA = \ lib/d3-3.5.17.min.js \ lib/dygraph-combined-dd74404.js \ lib/dygraph-smooth-plotter-dd74404.js \ + lib/fontawesome-all-5.0.1.min.js \ lib/gauge-1.3.2.min.js \ lib/jquery-2.2.4.min.js \ lib/jquery.easypiechart-97b5824.min.js \ - lib/perfect-scrollbar-0.6.15.min.js \ lib/jquery.peity-3.2.0.min.js \ lib/jquery.sparkline-2.1.2.min.js \ + lib/lz-string-1.4.4.min.js \ lib/morris-0.5.1.min.js \ + lib/pako-1.0.6.min.js \ + lib/perfect-scrollbar-0.6.15.min.js \ lib/raphael-2.2.4-min.js \ lib/tableExport-1.6.0.min.js \ $(NULL) @@ -63,8 +67,8 @@ dist_webcss_DATA = \ css/bootstrap-3.3.7.css \ css/bootstrap-theme-3.3.7.min.css \ css/bootstrap-slate-flat-3.3.7.css \ + css/bootstrap-slider-10.0.0.min.css \ css/bootstrap-toggle-2.2.2.min.css \ - css/font-awesome.min.css \ css/c3-0.4.11.min.css \ $(NULL) @@ -75,12 +79,6 @@ dist_webfonts_DATA = \ fonts/glyphicons-halflings-regular.ttf \ fonts/glyphicons-halflings-regular.woff \ fonts/glyphicons-halflings-regular.woff2 \ - fonts/FontAwesome.otf \ - fonts/fontawesome-webfont.eot \ - fonts/fontawesome-webfont.svg \ - fonts/fontawesome-webfont.ttf \ - fonts/fontawesome-webfont.woff \ - fonts/fontawesome-webfont.woff2 \ $(NULL) webimagesdir=$(webdir)/images diff --git a/web/Makefile.in b/web/Makefile.in index 42939d2a..92f5c088 100644 --- a/web/Makefile.in +++ b/web/Makefile.in @@ -340,6 +340,7 @@ dist_webold_DATA = \ weblibdir = $(webdir)/lib dist_weblib_DATA = \ lib/bootstrap-3.3.7.min.js \ + lib/bootstrap-slider-10.0.0.min.js \ lib/bootstrap-table-1.11.0.min.js \ lib/bootstrap-table-export-1.11.0.min.js \ lib/bootstrap-toggle-2.2.2.min.js \ @@ -347,13 +348,16 @@ dist_weblib_DATA = \ lib/d3-3.5.17.min.js \ lib/dygraph-combined-dd74404.js \ lib/dygraph-smooth-plotter-dd74404.js \ + lib/fontawesome-all-5.0.1.min.js \ lib/gauge-1.3.2.min.js \ lib/jquery-2.2.4.min.js \ lib/jquery.easypiechart-97b5824.min.js \ - lib/perfect-scrollbar-0.6.15.min.js \ lib/jquery.peity-3.2.0.min.js \ lib/jquery.sparkline-2.1.2.min.js \ + lib/lz-string-1.4.4.min.js \ lib/morris-0.5.1.min.js \ + lib/pako-1.0.6.min.js \ + lib/perfect-scrollbar-0.6.15.min.js \ lib/raphael-2.2.4-min.js \ lib/tableExport-1.6.0.min.js \ $(NULL) @@ -364,8 +368,8 @@ dist_webcss_DATA = \ css/bootstrap-3.3.7.css \ css/bootstrap-theme-3.3.7.min.css \ css/bootstrap-slate-flat-3.3.7.css \ + css/bootstrap-slider-10.0.0.min.css \ css/bootstrap-toggle-2.2.2.min.css \ - css/font-awesome.min.css \ css/c3-0.4.11.min.css \ $(NULL) @@ -376,12 +380,6 @@ dist_webfonts_DATA = \ fonts/glyphicons-halflings-regular.ttf \ fonts/glyphicons-halflings-regular.woff \ fonts/glyphicons-halflings-regular.woff2 \ - fonts/FontAwesome.otf \ - fonts/fontawesome-webfont.eot \ - fonts/fontawesome-webfont.svg \ - fonts/fontawesome-webfont.ttf \ - fonts/fontawesome-webfont.woff \ - fonts/fontawesome-webfont.woff2 \ $(NULL) webimagesdir = $(webdir)/images diff --git a/web/css/bootstrap-slider-10.0.0.min.css b/web/css/bootstrap-slider-10.0.0.min.css new file mode 100644 index 00000000..1cf68b5e --- /dev/null +++ b/web/css/bootstrap-slider-10.0.0.min.css @@ -0,0 +1,41 @@ +/*! ======================================================= + VERSION 10.0.0 +========================================================= */ +/*! ========================================================= + * bootstrap-slider.js + * + * Maintainers: + * Kyle Kemp + * - Twitter: @seiyria + * - Github: seiyria + * Rohit Kalkur + * - Twitter: @Rovolutionary + * - Github: rovolution + * + * ========================================================= + * + * bootstrap-slider is released under the MIT License + * Copyright (c) 2017 Kyle Kemp, Rohit Kalkur, and contributors + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ========================================================= */.slider{display:inline-block;vertical-align:middle;position:relative}.slider.slider-horizontal{width:210px;height:20px}.slider.slider-horizontal .slider-track{height:10px;width:100%;margin-top:-5px;top:50%;left:0}.slider.slider-horizontal .slider-selection,.slider.slider-horizontal .slider-track-low,.slider.slider-horizontal .slider-track-high{height:100%;top:0;bottom:0}.slider.slider-horizontal .slider-tick,.slider.slider-horizontal .slider-handle{margin-left:-10px}.slider.slider-horizontal .slider-tick.triangle,.slider.slider-horizontal .slider-handle.triangle{position:relative;top:50%;-ms-transform:translateY(-50%);transform:translateY(-50%);border-width:0 10px 10px 10px;width:0;height:0;border-bottom-color:#2e6da4;margin-top:0}.slider.slider-horizontal .slider-tick-container{white-space:nowrap;position:absolute;top:0;left:0;width:100%}.slider.slider-horizontal .slider-tick-label-container{white-space:nowrap;margin-top:20px}.slider.slider-horizontal .slider-tick-label-container .slider-tick-label{padding-top:4px;display:inline-block;text-align:center}.slider.slider-horizontal .tooltip{-ms-transform:translateX(-50%);transform:translateX(-50%)}.slider.slider-horizontal.slider-rtl .slider-track{left:initial;right:0}.slider.slider-horizontal.slider-rtl .slider-tick,.slider.slider-horizontal.slider-rtl .slider-handle{margin-left:initial;margin-right:-10px}.slider.slider-horizontal.slider-rtl .slider-tick-container{left:initial;right:0}.slider.slider-horizontal.slider-rtl .tooltip{-ms-transform:translateX(50%);transform:translateX(50%)}.slider.slider-vertical{height:210px;width:20px}.slider.slider-vertical .slider-track{width:10px;height:100%;left:25%;top:0}.slider.slider-vertical .slider-selection{width:100%;left:0;top:0;bottom:0}.slider.slider-vertical .slider-track-low,.slider.slider-vertical .slider-track-high{width:100%;left:0;right:0}.slider.slider-vertical .slider-tick,.slider.slider-vertical .slider-handle{margin-top:-10px}.slider.slider-vertical .slider-tick.triangle,.slider.slider-vertical .slider-handle.triangle{border-width:10px 0 10px 10px;width:1px;height:1px;border-left-color:#2e6da4;border-right-color:#2e6da4;margin-left:0;margin-right:0}.slider.slider-vertical .slider-tick-label-container{white-space:nowrap}.slider.slider-vertical .slider-tick-label-container .slider-tick-label{padding-left:4px}.slider.slider-vertical .tooltip{-ms-transform:translateY(-50%);transform:translateY(-50%)}.slider.slider-vertical.slider-rtl .slider-track{left:initial;right:25%}.slider.slider-vertical.slider-rtl .slider-selection{left:initial;right:0}.slider.slider-vertical.slider-rtl .slider-tick.triangle,.slider.slider-vertical.slider-rtl .slider-handle.triangle{border-width:10px 10px 10px 0}.slider.slider-vertical.slider-rtl .slider-tick-label-container .slider-tick-label{padding-left:initial;padding-right:4px}.slider.slider-disabled .slider-handle{background-image:-webkit-linear-gradient(top,#dfdfdf 0,#bebebe 100%);background-image:-o-linear-gradient(top,#dfdfdf 0,#bebebe 100%);background-image:linear-gradient(to bottom,#dfdfdf 0,#bebebe 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdfdfdf',endColorstr='#ffbebebe',GradientType=0)}.slider.slider-disabled .slider-track{background-image:-webkit-linear-gradient(top,#e5e5e5 0,#e9e9e9 100%);background-image:-o-linear-gradient(top,#e5e5e5 0,#e9e9e9 100%);background-image:linear-gradient(to bottom,#e5e5e5 0,#e9e9e9 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe5e5e5',endColorstr='#ffe9e9e9',GradientType=0);cursor:not-allowed}.slider input{display:none}.slider .tooltip.top{margin-top:-36px}.slider .tooltip-inner{white-space:nowrap;max-width:none}.slider .hide{display:none}.slider-track{position:absolute;cursor:pointer;background-image:-webkit-linear-gradient(top,#f5f5f5 0,#f9f9f9 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#f9f9f9 100%);background-image:linear-gradient(to bottom,#f5f5f5 0,#f9f9f9 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5',endColorstr='#fff9f9f9',GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);border-radius:4px}.slider-selection{position:absolute;background-image:-webkit-linear-gradient(top,#f9f9f9 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#f9f9f9 0,#f5f5f5 100%);background-image:linear-gradient(to bottom,#f9f9f9 0,#f5f5f5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff9f9f9',endColorstr='#fff5f5f5',GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;border-radius:4px}.slider-selection.tick-slider-selection{background-image:-webkit-linear-gradient(top,#8ac1ef 0,#82b3de 100%);background-image:-o-linear-gradient(top,#8ac1ef 0,#82b3de 100%);background-image:linear-gradient(to bottom,#8ac1ef 0,#82b3de 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff8ac1ef',endColorstr='#ff82b3de',GradientType=0)}.slider-track-low,.slider-track-high{position:absolute;background:transparent;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;border-radius:4px}.slider-handle{position:absolute;top:0;width:20px;height:20px;background-color:#337ab7;background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7',endColorstr='#ff2e6da4',GradientType=0);filter:none;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.2),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.2),0 1px 2px rgba(0,0,0,.05);border:0 solid transparent}.slider-handle.round{border-radius:50%}.slider-handle.triangle{background:transparent none}.slider-handle.custom{background:transparent none}.slider-handle.custom::before{line-height:20px;font-size:20px;content:'\2605';color:#726204}.slider-tick{position:absolute;width:20px;height:20px;background-image:-webkit-linear-gradient(top,#f9f9f9 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#f9f9f9 0,#f5f5f5 100%);background-image:linear-gradient(to bottom,#f9f9f9 0,#f5f5f5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff9f9f9',endColorstr='#fff5f5f5',GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;filter:none;opacity:.8;border:0 solid transparent}.slider-tick.round{border-radius:50%}.slider-tick.triangle{background:transparent none}.slider-tick.custom{background:transparent none}.slider-tick.custom::before{line-height:20px;font-size:20px;content:'\2605';color:#726204}.slider-tick.in-selection{background-image:-webkit-linear-gradient(top,#8ac1ef 0,#82b3de 100%);background-image:-o-linear-gradient(top,#8ac1ef 0,#82b3de 100%);background-image:linear-gradient(to bottom,#8ac1ef 0,#82b3de 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff8ac1ef',endColorstr='#ff82b3de',GradientType=0);opacity:1}
\ No newline at end of file diff --git a/web/dashboard.css b/web/dashboard.css index 42ffa3dd..79febaa4 100644 --- a/web/dashboard.css +++ b/web/dashboard.css @@ -44,6 +44,8 @@ body { display: inline-block; overflow: hidden; + transform: translate3d(0,0,0); + /* required for child elements to have absolute position */ position: relative; @@ -54,6 +56,8 @@ body { display: inline-block; overflow: hidden; + transform: translate3d(0,0,0); + /* required for child elements to have absolute position */ position: relative; @@ -70,6 +74,8 @@ body { display: inline-block; overflow: hidden; + transform: translate3d(0,0,0); + /* required for child elements to have absolute position */ position: relative; @@ -93,6 +99,8 @@ body { display: inline-block; overflow: hidden; + transform: translate3d(0,0,0); + /* fix minimum scrollbar issue in firefox */ min-height: 99px; @@ -108,9 +116,9 @@ body { bottom: 0px; right: 0px; height: 15px; - width: 30px; + width: 20px; background-color: White; - font-size: 12px; + font-size: 15px; vertical-align: middle; line-height: 15px; cursor: ns-resize; @@ -286,6 +294,7 @@ body { white-space: nowrap; display: inline-block; cursor: pointer; + -webkit-print-color-adjust: exact; } .netdata-legend-value { diff --git a/web/dashboard.js b/web/dashboard.js index f119a537..dc7f4ea3 100644 --- a/web/dashboard.js +++ b/web/dashboard.js @@ -45,6 +45,10 @@ * (default: null) */ /*global netdataServer *//* string, the URL of the netdata server to use * (default: the URL the page is hosted at) */ +/*global netdataServerStatic *//* string, the URL of the netdata server to use for static files + * (default: netdataServer) */ +/*global netdataSnapshotData *//* object, a netdata snapshot loaded + * (default: null) */ // ---------------------------------------------------------------------------- // global namespace @@ -123,32 +127,43 @@ var NETDATA = window.NETDATA || {}; else if(NETDATA.serverDefault.slice(-1) !== '/') NETDATA.serverDefault += '/'; + if(typeof netdataServerStatic !== 'undefined' && netdataServerStatic !== null && netdataServerStatic !== '') { + NETDATA.serverStatic = netdataServerStatic; + if(NETDATA.serverStatic.slice(-1) !== '/') + NETDATA.serverStatic += '/'; + } + else { + NETDATA.serverStatic = NETDATA.serverDefault; + } + + // default URLs for all the external files we need // make them RELATIVE so that the whole thing can also be // installed under a web server - NETDATA.jQuery = NETDATA.serverDefault + 'lib/jquery-2.2.4.min.js'; - NETDATA.peity_js = NETDATA.serverDefault + 'lib/jquery.peity-3.2.0.min.js'; - NETDATA.sparkline_js = NETDATA.serverDefault + 'lib/jquery.sparkline-2.1.2.min.js'; - NETDATA.easypiechart_js = NETDATA.serverDefault + 'lib/jquery.easypiechart-97b5824.min.js'; - NETDATA.gauge_js = NETDATA.serverDefault + 'lib/gauge-1.3.2.min.js'; - NETDATA.dygraph_js = NETDATA.serverDefault + 'lib/dygraph-combined-dd74404.js'; - NETDATA.dygraph_smooth_js = NETDATA.serverDefault + 'lib/dygraph-smooth-plotter-dd74404.js'; - NETDATA.raphael_js = NETDATA.serverDefault + 'lib/raphael-2.2.4-min.js'; - NETDATA.c3_js = NETDATA.serverDefault + 'lib/c3-0.4.11.min.js'; - NETDATA.c3_css = NETDATA.serverDefault + 'css/c3-0.4.11.min.css'; - NETDATA.d3_js = NETDATA.serverDefault + 'lib/d3-3.5.17.min.js'; - NETDATA.morris_js = NETDATA.serverDefault + 'lib/morris-0.5.1.min.js'; - NETDATA.morris_css = NETDATA.serverDefault + 'css/morris-0.5.1.css'; + NETDATA.jQuery = NETDATA.serverStatic + 'lib/jquery-2.2.4.min.js'; + NETDATA.peity_js = NETDATA.serverStatic + 'lib/jquery.peity-3.2.0.min.js'; + NETDATA.sparkline_js = NETDATA.serverStatic + 'lib/jquery.sparkline-2.1.2.min.js'; + NETDATA.easypiechart_js = NETDATA.serverStatic + 'lib/jquery.easypiechart-97b5824.min.js'; + NETDATA.gauge_js = NETDATA.serverStatic + 'lib/gauge-1.3.2.min.js'; + NETDATA.dygraph_js = NETDATA.serverStatic + 'lib/dygraph-combined-dd74404.js'; + NETDATA.dygraph_smooth_js = NETDATA.serverStatic + 'lib/dygraph-smooth-plotter-dd74404.js'; + NETDATA.raphael_js = NETDATA.serverStatic + 'lib/raphael-2.2.4-min.js'; + NETDATA.c3_js = NETDATA.serverStatic + 'lib/c3-0.4.11.min.js'; + NETDATA.c3_css = NETDATA.serverStatic + 'css/c3-0.4.11.min.css'; + NETDATA.d3_js = NETDATA.serverStatic + 'lib/d3-3.5.17.min.js'; + NETDATA.morris_js = NETDATA.serverStatic + 'lib/morris-0.5.1.min.js'; + NETDATA.morris_css = NETDATA.serverStatic + 'css/morris-0.5.1.css'; NETDATA.google_js = 'https://www.google.com/jsapi'; NETDATA.themes = { white: { - bootstrap_css: NETDATA.serverDefault + 'css/bootstrap-3.3.7.css', - dashboard_css: NETDATA.serverDefault + 'dashboard.css?v20170725-1', + bootstrap_css: NETDATA.serverStatic + 'css/bootstrap-3.3.7.css', + dashboard_css: NETDATA.serverStatic + 'dashboard.css?v20171208-1', background: '#FFFFFF', foreground: '#000000', grid: '#F0F0F0', axis: '#F0F0F0', + highlight: '#F5F5F5', colors: [ '#3366CC', '#DC3912', '#109618', '#FF9900', '#990099', '#DD4477', '#3B3EAC', '#66AA00', '#0099C6', '#B82E2E', '#AAAA11', '#5574A6', '#994499', '#22AA99', '#6633CC', '#E67300', '#316395', '#8B0707', @@ -160,12 +175,13 @@ var NETDATA = window.NETDATA || {}; gauge_gradient: false }, slate: { - bootstrap_css: NETDATA.serverDefault + 'css/bootstrap-slate-flat-3.3.7.css?v20161229-1', - dashboard_css: NETDATA.serverDefault + 'dashboard.slate.css?v20170725-1', + bootstrap_css: NETDATA.serverStatic + 'css/bootstrap-slate-flat-3.3.7.css?v20161229-1', + dashboard_css: NETDATA.serverStatic + 'dashboard.slate.css?v20171208-1', background: '#272b30', foreground: '#C8C8C8', grid: '#283236', axis: '#283236', + highlight: '#383838', /* colors: [ '#55bb33', '#ff2222', '#0099C6', '#faa11b', '#adbce0', '#DDDD00', '#4178ba', '#f58122', '#a5cc39', '#f58667', '#f5ef89', '#cf93c0', '#a5d18a', '#b8539d', '#3954a3', '#c8a9cf', '#c7de8a', '#fad20a', @@ -202,6 +218,9 @@ var NETDATA = window.NETDATA || {}; // (blue) (red) (orange) (green) (pink) (brown) (purple) (yellow) (gray) //NETDATA.colors = [ '#5DA5DA', '#F15854', '#FAA43A', '#60BD68', '#F17CB0', '#B2912F', '#B276B2', '#DECF3F', '#4D4D4D' ]; + if(typeof netdataSnapshotData === 'undefined') + netdataSnapshotData = null; + if(typeof netdataShowHelp === 'undefined') netdataShowHelp = true; @@ -247,7 +266,6 @@ var NETDATA = window.NETDATA || {}; // if the user does not specify any of these, the following will be used NETDATA.chartDefaults = { - host: NETDATA.serverDefault, // the server to get data from width: '100%', // the chart width - can be null height: '100%', // the chart height - can be null min_width: null, // the chart minimum width - can be null @@ -287,13 +305,33 @@ var NETDATA = window.NETDATA || {}; // rendering the chart that is panned or zoomed). // Used with .current.global_pan_sync_time - last_page_resize: Date.now(), // the timestamp of the last resize request + on_scroll_refresher_stop_until: 0, // timestamp in ms - used to stop evaluating + // charts for some time, after a page scroll + + last_page_resize: Date.now(), // the timestamp of the last resize request last_page_scroll: 0, // the timestamp the last time the page was scrolled + browser_timezone: 'unknown', // timezone detected by javascript + server_timezone: 'unknown', // timezone reported by the server + + force_data_points: 0, // force the number of points to be returned for charts + fake_chart_rendering: false, // when set to true, the dashboard will download data but will not render the charts + + passive_events: null, // true if the browser supports passive events + // the current profile // we may have many... current: { + units: 'auto', // can be 'auto' or 'original' + temperature: 'celsius', // can be 'celsius' or 'fahrenheit' + seconds_as_time: true, // show seconds as DDd:HH:MM:SS ? + timezone: 'default', // the timezone to use, or 'default' + user_set_server_timezone: 'default', // as set by the user on the dashboard + + legend_toolbox: true, // show the legend toolbox on charts + resize_charts: true, // show the resize handler on charts + pixels_per_point: isSlowDevice()?5:1, // the minimum pixels per point for all charts // increase this to speed javascript up // each chart library has its own limit too @@ -318,11 +356,11 @@ var NETDATA = window.NETDATA || {}; idle_lost_focus: 500, // ms - when the window does not have focus, check // if focus has been regained, every this time - global_pan_sync_time: 1000, // ms - when you pan or zoom a chart, the background + global_pan_sync_time: 300, // ms - when you pan or zoom a chart, the background // auto-refreshing of charts is paused for this amount // of time - sync_selection_delay: 1500, // ms - when you pan or zoom a chart, wait this amount + sync_selection_delay: 400, // ms - when you pan or zoom a chart, wait this amount // of time before setting up synchronized selections // on hover. @@ -355,8 +393,6 @@ var NETDATA = window.NETDATA || {}; smooth_plot: (isSlowDevice() === false), // enable smooth plot, where possible - charts_selection_animation_delay: 50, // delay to animate charts when syncing selection - color_fill_opacity_line: 1.0, color_fill_opacity_area: 0.2, color_fill_opacity_stacked: 0.8, @@ -368,7 +404,7 @@ var NETDATA = window.NETDATA || {}; abort_ajax_on_scroll: false, // kill pending ajax page scroll async_on_scroll: false, // sync/async onscroll handler - onscroll_worker_duration_threshold: 30, // time in ms, to consider slow the onscroll handler + onscroll_worker_duration_threshold: 30, // time in ms, for async scroll handler retries_on_data_failures: 3, // how many retries to make if we can't fetch chart data from the server @@ -381,11 +417,13 @@ var NETDATA = window.NETDATA || {}; focus: false, visibility: false, chart_data_url: false, - chart_errors: false, // FIXME: remember to set it to false before merging + chart_errors: true, // FIXME: remember to set it to false before merging chart_timing: false, chart_calls: false, libraries: false, - dygraph: false + dygraph: false, + globalSelectionSync:false, + globalPanAndZoom: false } }; @@ -397,6 +435,114 @@ var NETDATA = window.NETDATA || {}; // ---------------------------------------------------------------------------------------------------------------- + + NETDATA.timeout = { + // by default, these are just wrappers to setTimeout() / clearTimeout() + + step: function(callback) { + return window.setTimeout(callback, 1000 / 60); + }, + + set: function(callback, delay) { + return window.setTimeout(callback, delay); + }, + + clear: function(id) { + return window.clearTimeout(id); + }, + + init: function() { + var custom = true; + + if(window.requestAnimationFrame) { + this.step = function(callback) { + return window.requestAnimationFrame(callback); + }; + + this.clear = function(handle) { + return window.cancelAnimationFrame(handle.value); + }; + } + else if(window.webkitRequestAnimationFrame) { + this.step = function(callback) { + return window.webkitRequestAnimationFrame(callback); + }; + + if(window.webkitCancelAnimationFrame) { + this.clear = function (handle) { + return window.webkitCancelAnimationFrame(handle.value); + }; + } + else if(window.webkitCancelRequestAnimationFrame) { + this.clear = function (handle) { + return window.webkitCancelRequestAnimationFrame(handle.value); + }; + } + } + else if(window.mozRequestAnimationFrame) { + this.step = function(callback) { + return window.mozRequestAnimationFrame(callback); + }; + + this.clear = function(handle) { + return window.mozCancelRequestAnimationFrame(handle.value); + }; + } + else if(window.oRequestAnimationFrame) { + this.step = function(callback) { + return window.oRequestAnimationFrame(callback); + }; + + this.clear = function(handle) { + return window.oCancelRequestAnimationFrame(handle.value); + }; + } + else if(window.msRequestAnimationFrame) { + this.step = function(callback) { + return window.msRequestAnimationFrame(callback); + }; + + this.clear = function(handle) { + return window.msCancelRequestAnimationFrame(handle.value); + }; + } + else + custom = false; + + + if(custom === true) { + // we have installed custom .step() / .clear() functions + // overwrite the .set() too + + this.set = function(callback, delay) { + var that = this; + + var start = Date.now(), + handle = new Object(); + + function loop() { + var current = Date.now(), + delta = current - start; + + if(delta >= delay) { + callback.call(); + } + else { + handle.value = that.step(loop); + } + } + + handle.value = that.step(loop); + return handle; + }; + } + } + }; + + NETDATA.timeout.init(); + + + // ---------------------------------------------------------------------------------------------------------------- // local storage options NETDATA.localStorage = { @@ -562,6 +708,8 @@ var NETDATA = window.NETDATA || {}; } } } + + NETDATA.dateTime.init(NETDATA.options.current.timezone); }; // ---------------------------------------------------------------------------------------------------------------- @@ -578,113 +726,111 @@ var NETDATA = window.NETDATA || {}; NETDATA.onresizeCallback(); }; - NETDATA.onscroll_updater_count = 0; - NETDATA.onscroll_updater_running = false; - NETDATA.onscroll_updater_last_run = 0; - NETDATA.onscroll_updater_watchdog = null; - NETDATA.onscroll_updater_max_duration = 0; - NETDATA.onscroll_updater_above_threshold_count = 0; - NETDATA.onscroll_updater = function() { - NETDATA.onscroll_updater_running = true; - NETDATA.onscroll_updater_count++; - var start = Date.now(); - + NETDATA.abort_all_refreshes = function() { var targets = NETDATA.options.targets; var len = targets.length; + while (len--) { + if (targets[len].fetching_data === true) { + if (typeof targets[len].xhr !== 'undefined') { + targets[len].xhr.abort(); + targets[len].running = false; + targets[len].fetching_data = false; + } + } + } + }; + + NETDATA.onscroll_start_delay = function() { + NETDATA.options.last_page_scroll = Date.now(); + + NETDATA.options.on_scroll_refresher_stop_until = + NETDATA.options.last_page_scroll + + ((NETDATA.options.current.async_on_scroll === true) ? 1000 : 0); + }; + + NETDATA.onscroll_end_delay = function() { + NETDATA.options.on_scroll_refresher_stop_until = + Date.now() + + ((NETDATA.options.current.async_on_scroll === true) ? NETDATA.options.current.onscroll_worker_duration_threshold : 0); + }; + + NETDATA.onscroll_updater_timeout_id = undefined; + NETDATA.onscroll_updater = function() { + if(NETDATA.options.targets === null) return; + + //var start = Date.now(); + + // console.log('onscroll_updater() begin'); + + NETDATA.globalSelectionSync.stop(); + // when the user scrolls he sees that we have // hidden all the not-visible charts // using this little function we try to switch // the charts back to visible quickly + if(NETDATA.options.abort_ajax_on_scroll === true) + NETDATA.abort_all_refreshes(); - if(NETDATA.options.abort_ajax_on_scroll === true) { - // we have to cancel pending requests too - - while (len--) { - if (targets[len].fetching_data === true) { - if (typeof targets[len].xhr !== 'undefined') { - targets[len].xhr.abort(); - targets[len].running = false; - targets[len].fetching_data = false; - } - targets[len].isVisible(); - } - } - } - else { - // just find which charts are visible + if(NETDATA.options.current.parallel_refresher === false) { + var targets = NETDATA.options.targets; + var len = targets.length; while (len--) targets[len].isVisible(); } - var end = Date.now(); - // console.log('scroll No ' + NETDATA.onscroll_updater_count + ' calculation took ' + (end - start).toString() + ' ms'); + //var end = Date.now(); + //var dt = end - start; + // console.log('count = ' + targets.length + ', average = ' + Math.round(dt / targets.length).toString() + ', dt = ' + dt); - if(NETDATA.options.current.async_on_scroll === false) { - var dt = end - start; - if(dt > NETDATA.onscroll_updater_max_duration) { - // console.log('max onscroll event handler duration increased to ' + dt); - NETDATA.onscroll_updater_max_duration = dt; - } - - if(dt > NETDATA.options.current.onscroll_worker_duration_threshold) { - // console.log('slow: ' + dt); - NETDATA.onscroll_updater_above_threshold_count++; - - if(NETDATA.onscroll_updater_above_threshold_count > 2 && NETDATA.onscroll_updater_above_threshold_count * 100 / NETDATA.onscroll_updater_count > 2) { - NETDATA.setOption('async_on_scroll', true); - console.log('NETDATA: your browser is slow - enabling asynchronous onscroll event handler.'); - } - } - } - - NETDATA.onscroll_updater_last_run = start; - NETDATA.onscroll_updater_running = false; + NETDATA.onscroll_end_delay(); }; NETDATA.scrollUp = false; NETDATA.scrollY = window.scrollY; NETDATA.onscroll = function() { - // console.log('onscroll'); + //console.log('onscroll() begin'); + + NETDATA.onscroll_start_delay(); + NETDATA.chartRefresherReschedule(); NETDATA.scrollUp = (window.scrollY > NETDATA.scrollY); NETDATA.scrollY = window.scrollY; - NETDATA.options.last_page_scroll = Date.now(); - NETDATA.options.auto_refresher_stop_until = 0; - - if(NETDATA.options.targets === null) return; + if(NETDATA.onscroll_updater_timeout_id) + NETDATA.timeout.clear(NETDATA.onscroll_updater_timeout_id); - if(NETDATA.options.current.async_on_scroll === true) { - // async - if(NETDATA.onscroll_updater_running === false) { - NETDATA.onscroll_updater_running = true; - setTimeout(NETDATA.onscroll_updater, 0); - } - else { - if(NETDATA.onscroll_updater_watchdog !== null) - clearTimeout(NETDATA.onscroll_updater_watchdog); + NETDATA.onscroll_updater_timeout_id = NETDATA.timeout.set(NETDATA.onscroll_updater, 0); + //console.log('onscroll() end'); + }; - NETDATA.onscroll_updater_watchdog = setTimeout(function() { - if(NETDATA.onscroll_updater_running === false && NETDATA.options.last_page_scroll > NETDATA.onscroll_updater_last_run) { - // console.log('watchdog'); - NETDATA.onscroll_updater(); + NETDATA.supportsPassiveEvents = function() { + if(NETDATA.options.passive_events === null) { + var supportsPassive = false; + try { + var opts = Object.defineProperty({}, 'passive', { + get: function () { + supportsPassive = true; } - - NETDATA.onscroll_updater_watchdog = null; - }, 200); + }); + window.addEventListener("test", null, opts); + } catch (e) { + console.log('browser does not support passive events'); } + + NETDATA.options.passive_events = supportsPassive; } - else { - // sync - NETDATA.onscroll_updater(); - } + + // console.log('passive ' + NETDATA.options.passive_events); + return NETDATA.options.passive_events; }; - window.onresize = NETDATA.onresize; - window.onscroll = NETDATA.onscroll; + window.addEventListener('resize', NETDATA.onresize, NETDATA.supportsPassiveEvents() ? { passive: true } : false); + window.addEventListener('scroll', NETDATA.onscroll, NETDATA.supportsPassiveEvents() ? { passive: true } : false); + // window.onresize = NETDATA.onresize; + // window.onscroll = NETDATA.onscroll; // ---------------------------------------------------------------------------------------------------------------- // Error Handling @@ -847,6 +993,7 @@ var NETDATA = window.NETDATA || {}; } }, + // the fallback getFixed: function(min, max) { var key = max; if(min === max) { @@ -882,7 +1029,7 @@ var NETDATA = window.NETDATA || {}; }, testIntlNumberFormat: function() { - var n = 1.12345; + var value = 1.12345; var e1 = "1.12", e2 = "1,12"; var s = ""; @@ -893,7 +1040,7 @@ var NETDATA = window.NETDATA || {}; maximumFractionDigits: 2 }); - s = x.format(n); + s = x.format(value); } catch(e) { s = ""; @@ -904,7 +1051,7 @@ var NETDATA = window.NETDATA || {}; }, testLocaleString: function() { - var n = 1.12345; + var value = 1.12345; var e1 = "1.12", e2 = "1,12"; var s = ""; @@ -993,6 +1140,11 @@ var NETDATA = window.NETDATA || {}; keys: {}, latest: {}, + globalReset: function() { + this.keys = {}; + this.latest = {}; + }, + get: function(state) { if(typeof state.tmp.__commonMin === 'undefined') { // get the commonMin setting @@ -1047,6 +1199,11 @@ var NETDATA = window.NETDATA || {}; keys: {}, latest: {}, + globalReset: function() { + this.keys = {}; + this.latest = {}; + }, + get: function(state) { if(typeof state.tmp.__commonMax === 'undefined') { // get the commonMax setting @@ -1117,14 +1274,11 @@ var NETDATA = window.NETDATA || {}; NETDATA.chartRegistry = { charts: {}, - fixid: function(id) { - return id.replace(/:/g, "_").replace(/\//g, "_"); + globalReset: function() { + this.charts = {}; }, add: function(host, id, data) { - host = this.fixid(host); - id = this.fixid(id); - if(typeof this.charts[host] === 'undefined') this.charts[host] = {}; @@ -1133,9 +1287,6 @@ var NETDATA = window.NETDATA || {}; }, get: function(host, id) { - host = this.fixid(host); - id = this.fixid(id); - if(typeof this.charts[host] === 'undefined') return null; @@ -1151,28 +1302,40 @@ var NETDATA = window.NETDATA || {}; var self = this; - $.ajax({ - url: host + '/api/v1/charts', - async: true, - cache: false, - xhrFields: { withCredentials: true } // required for the cookie - }) - .done(function(data) { + function got_data(h, data, callback) { if(data !== null) { - var h = NETDATA.chartRegistry.fixid(host); self.charts[h] = data.charts; + + // update the server timezone in our options + if(typeof data.timezone === 'string') + NETDATA.options.server_timezone = data.timezone; } - else NETDATA.error(406, host + '/api/v1/charts'); + else NETDATA.error(406, h + '/api/v1/charts'); if(typeof callback === 'function') - return callback(data); - }) - .fail(function() { - NETDATA.error(405, host + '/api/v1/charts'); + callback(data); + } - if(typeof callback === 'function') - return callback(null); - }); + if(netdataSnapshotData !== null) { + got_data(host, netdataSnapshotData.charts, callback); + } + else { + $.ajax({ + url: host + '/api/v1/charts', + async: true, + cache: false, + xhrFields: {withCredentials: true} // required for the cookie + }) + .done(function (data) { + got_data(host, data, callback); + }) + .fail(function () { + NETDATA.error(405, host + '/api/v1/charts'); + + if (typeof callback === 'function') + callback(null); + }); + } } }; @@ -1199,20 +1362,45 @@ var NETDATA = window.NETDATA || {}; callback: null, + globalReset: function() { + this.clearMaster(); + this.seq = 0; + this.master = null; + this.force_after_ms = null; + this.force_before_ms = null; + this.callback = null; + }, + + delay: function() { + if(NETDATA.options.debug.globalPanAndZoom === true) + console.log('globalPanAndZoom.delay()'); + + NETDATA.options.auto_refresher_stop_until = Date.now() + NETDATA.options.current.global_pan_sync_time; + }, + // set a new master setMaster: function(state, after, before) { + this.delay(); + if(NETDATA.options.current.sync_pan_and_zoom === false) return; - if(this.master !== null && this.master !== state) + if(this.master === null) { + if(NETDATA.options.debug.globalPanAndZoom === true) + console.log('globalPanAndZoom.setMaster(' + state.id + ', ' + after + ', ' + before + ') SET MASTER'); + } + else if(this.master !== state) { + if(NETDATA.options.debug.globalPanAndZoom === true) + console.log('globalPanAndZoom.setMaster(' + state.id + ', ' + after + ', ' + before + ') CHANGED MASTER'); + this.master.resetChart(true, true); + } var now = Date.now(); this.master = state; this.seq = now; this.force_after_ms = after; this.force_before_ms = before; - NETDATA.options.auto_refresher_stop_until = now + NETDATA.options.current.global_pan_sync_time; if(typeof this.callback === 'function') this.callback(true, after, before); @@ -1220,6 +1408,9 @@ var NETDATA = window.NETDATA || {}; // clear the master clearMaster: function() { + if(NETDATA.options.debug.globalPanAndZoom === true) + console.log('globalPanAndZoom.clearMaster()'); + if(this.master !== null) { var st = this.master; this.master = null; @@ -1261,6 +1452,86 @@ var NETDATA = window.NETDATA || {}; }; // ---------------------------------------------------------------------------------------------------------------- + // global chart underlay (time-frame highlighting) + + NETDATA.globalChartUnderlay = { + callback: null, // what to call when a highlighted range is setup + after: null, // highlight after this time + before: null, // highlight before this time + view_after: null, // the charts after_ms viewport when the highlight was setup + view_before: null, // the charts before_ms viewport, when the highlight was setup + state: null, // the chart the highlight was setup + + isActive: function() { + return (this.after !== null && this.before !== null); + }, + + hasViewport: function() { + return (this.state !== null && this.view_after !== null && this.view_before !== null); + }, + + init: function(state, after, before, view_after, view_before) { + this.state = (typeof state !== 'undefined') ? state : null; + this.after = (typeof after !== 'undefined' && after !== null && after > 0) ? after : null; + this.before = (typeof before !== 'undefined' && before !== null && before > 0) ? before : null; + this.view_after = (typeof view_after !== 'undefined' && view_after !== null && view_after > 0) ? view_after : null; + this.view_before = (typeof view_before !== 'undefined' && view_before !== null && view_before > 0) ? view_before : null; + }, + + setup: function() { + if(this.isActive() === true) { + if (this.state === null) + this.state = NETDATA.options.targets[0]; + + if (typeof this.callback === 'function') + this.callback(true, this.after, this.before); + } + else { + if (typeof this.callback === 'function') + this.callback(false, 0, 0); + } + }, + + set: function(state, after, before, view_after, view_before) { + if(after > before) { + var t = after; + after = before; + before = t; + } + + this.init(state, after, before, view_after, view_before); + + if (this.hasViewport() === true) + NETDATA.globalPanAndZoom.setMaster(this.state, this.view_after, this.view_before); + + this.setup(); + }, + + clear: function() { + this.after = null; + this.before = null; + this.state = null; + this.view_after = null; + this.view_before = null; + + if(typeof this.callback === 'function') + this.callback(false, 0, 0); + }, + + focus: function() { + if(this.isActive() === true && this.hasViewport() === true) { + if(this.state === null) + this.state = NETDATA.options.targets[0]; + + if(NETDATA.globalPanAndZoom.isMaster(this.state) === true) + NETDATA.globalPanAndZoom.clearMaster(); + + NETDATA.globalPanAndZoom.setMaster(this.state, this.view_after, this.view_before, true); + } + } + }; + + // ---------------------------------------------------------------------------------------------------------------- // dimensions selection // FIXME @@ -1290,7 +1561,7 @@ var NETDATA = window.NETDATA || {}; if(this.name_div !== name_div) { this.name_div = name_div; this.name_div.title = this.label; - this.name_div.style.color = this.color; + this.name_div.style.setProperty('color', this.color, 'important'); if(this.selected === false) this.name_div.className = 'netdata-legend-name not-selected'; else @@ -1300,7 +1571,7 @@ var NETDATA = window.NETDATA || {}; if(this.value_div !== value_div) { this.value_div = value_div; this.value_div.title = this.label; - this.value_div.style.color = this.color; + this.value_div.style.setProperty('color', this.color, 'important'); if(this.selected === false) this.value_div.className = 'netdata-legend-value not-selected'; else @@ -1464,6 +1735,422 @@ var NETDATA = window.NETDATA || {}; // ---------------------------------------------------------------------------------------------------------------- + // date/time conversion + + NETDATA.dateTime = { + using_timezone: false, + + // these are the old netdata functions + // we fallback to these, if the new ones fail + + localeDateStringNative: function(d) { + return d.toLocaleDateString(); + }, + + localeTimeStringNative: function(d) { + return d.toLocaleTimeString(); + }, + + xAxisTimeStringNative: function(d) { + return NETDATA.zeropad(d.getHours()) + ":" + + NETDATA.zeropad(d.getMinutes()) + ":" + + NETDATA.zeropad(d.getSeconds()); + }, + + // initialize the new date/time conversion + // functions. + // if this fails, we fallback to the above + init: function(timezone) { + //console.log('init with timezone: ' + timezone); + + // detect browser timezone + try { + NETDATA.options.browser_timezone = Intl.DateTimeFormat().resolvedOptions().timeZone; + } + catch(e) { + console.log('failed to detect browser timezone: ' + e.toString()); + NETDATA.options.browser_timezone = 'cannot-detect-it'; + } + + var ret = false; + + try { + var dateOptions ={ + localeMatcher: 'best fit', + formatMatcher: 'best fit', + weekday: 'short', + year: 'numeric', + month: 'short', + day: '2-digit' + }; + + var timeOptions = { + localeMatcher: 'best fit', + hour12: false, + formatMatcher: 'best fit', + hour: '2-digit', + minute: '2-digit', + second: '2-digit' + }; + + var xAxisOptions = { + localeMatcher: 'best fit', + hour12: false, + formatMatcher: 'best fit', + hour: '2-digit', + minute: '2-digit', + second: '2-digit' + }; + + if(typeof timezone === 'string' && timezone !== '' && timezone !== 'default') { + dateOptions.timeZone = timezone; + timeOptions.timeZone = timezone; + timeOptions.timeZoneName = 'short'; + xAxisOptions.timeZone = timezone; + this.using_timezone = true; + } + else { + timezone = 'default'; + this.using_timezone = false; + } + + this.dateFormat = new Intl.DateTimeFormat(navigator.language, dateOptions); + this.timeFormat = new Intl.DateTimeFormat(navigator.language, timeOptions); + this.xAxisFormat = new Intl.DateTimeFormat(navigator.language, xAxisOptions); + + this.localeDateString = function(d) { + return this.dateFormat.format(d); + }; + + this.localeTimeString = function(d) { + return this.timeFormat.format(d); + }; + + this.xAxisTimeString = function(d) { + return this.xAxisFormat.format(d); + }; + + var d = new Date(); + var t = this.dateFormat.format(d) + ' ' + this.timeFormat.format(d) + ' ' + this.xAxisFormat.format(d); + + ret = true; + } + catch(e) { + console.log('Cannot setup Date/Time formatting: ' + e.toString()); + + timezone = 'default'; + this.localeDateString = this.localeDateStringNative; + this.localeTimeString = this.localeTimeStringNative; + this.xAxisTimeString = this.xAxisTimeStringNative; + this.using_timezone = false; + + ret = false; + } + + // save it + //console.log('init setOption timezone: ' + timezone); + NETDATA.setOption('timezone', timezone); + + return ret; + } + }; + NETDATA.dateTime.init(NETDATA.options.current.timezone); + + + // ---------------------------------------------------------------------------------------------------------------- + // units conversion + + NETDATA.unitsConversion = { + keys: {}, // keys for data-common-units + latest: {}, // latest selected units for data-common-units + + globalReset: function() { + this.keys = {}; + this.latest = {}; + }, + + scalableUnits: { + 'kilobits/s': { + 'bits/s': 1 / 1000, + 'kilobits/s': 1, + 'megabits/s': 1000, + 'gigabits/s': 1000000 + }, + 'kilobytes/s': { + 'bytes/s': 1 / 1024, + 'kilobytes/s': 1, + 'megabytes/s': 1024, + 'gigabytes/s': 1024 * 1024 + }, + 'KB/s': { + 'B/s': 1 / 1024, + 'KB/s': 1, + 'MB/s': 1024, + 'GB/s': 1024 * 1024 + }, + 'KB': { + 'B': 1 / 1024, + 'KB': 1, + 'MB': 1024, + 'GB': 1024 * 1024 + }, + 'MB': { + 'KB': 1 / 1024, + 'MB': 1, + 'GB': 1024, + 'TB': 1024 * 1024 + }, + 'GB': { + 'MB': 1 / 1024, + 'GB': 1, + 'TB': 1024 + } + /* + 'seconds': { + 'milliseconds': 0.001, + 'seconds': 1, + 'minutes': 60, + 'hours': 3600, + 'days': 86400 + } + */ + }, + + convertibleUnits: { + 'Celsius': { + 'Fahrenheit': { + check: function() { return NETDATA.options.current.temperature === 'fahrenheit'; }, + convert: function(value) { return value * 9 / 5 + 32; } + } + }, + 'celsius': { + 'fahrenheit': { + check: function() { return NETDATA.options.current.temperature === 'fahrenheit'; }, + convert: function(value) { return value * 9 / 5 + 32; } + } + }, + 'seconds': { + 'time': { + check: function () { return NETDATA.options.current.seconds_as_time; }, + convert: function (seconds) { + seconds = Math.abs(seconds); + + var days = Math.floor(seconds / 86400); + seconds -= days * 86400; + + var hours = Math.floor(seconds / 3600); + seconds -= hours * 3600; + + var minutes = Math.floor(seconds / 60); + seconds -= minutes * 60; + + seconds = Math.round(seconds); + + var ms_txt = ''; + /* + var ms = seconds - Math.floor(seconds); + seconds -= ms; + ms = Math.round(ms * 1000); + + if(ms > 1) { + if(ms < 10) + ms_txt = '.00' + ms.toString(); + else if(ms < 100) + ms_txt = '.0' + ms.toString(); + else + ms_txt = '.' + ms.toString(); + } + */ + + return ((days > 0)?days.toString() + 'd:':'').toString() + + NETDATA.zeropad(hours) + ':' + + NETDATA.zeropad(minutes) + ':' + + NETDATA.zeropad(seconds) + + ms_txt; + } + } + } + }, + + // get a function that converts the units + // + every time units are switched call the callback + get: function(uuid, min, max, units, desired_units, common_units_name, switch_units_callback) { + // validate the parameters + if(typeof units === 'undefined') + units = 'undefined'; + + // check if we support units conversion + if(typeof this.scalableUnits[units] === 'undefined' && typeof this.convertibleUnits[units] === 'undefined') { + // we can't convert these units + //console.log('DEBUG: ' + uuid.toString() + ' can\'t convert units: ' + units.toString()); + return function(value) { return value; }; + } + + // check if the caller wants the original units + if(typeof desired_units === 'undefined' || desired_units === null || desired_units === 'original' || desired_units === units) { + //console.log('DEBUG: ' + uuid.toString() + ' original units wanted'); + switch_units_callback(units); + return function(value) { return value; }; + } + + // now we know we can convert the units + // and the caller wants some kind of conversion + + var tunits = null; + var tdivider = 0; + var x; + + if(typeof this.scalableUnits[units] !== 'undefined') { + // units that can be scaled + // we decide a divider + + // console.log('NETDATA.unitsConversion.get(' + units.toString() + ', ' + desired_units.toString() + ', function()) decide divider with min = ' + min.toString() + ', max = ' + max.toString()); + + if (desired_units === 'auto') { + // the caller wants to auto-scale the units + + // find the absolute maximum value that is rendered on the chart + // based on this we decide the scale + min = Math.abs(min); + max = Math.abs(max); + if (min > max) max = min; + + // find the smallest scale that provides integers + for (x in this.scalableUnits[units]) { + if (this.scalableUnits[units].hasOwnProperty(x)) { + var m = this.scalableUnits[units][x]; + if (m <= max && m > tdivider) { + tunits = x; + tdivider = m; + } + } + } + + if(tunits === null || tdivider <= 0) { + // we couldn't find one + //console.log('DEBUG: ' + uuid.toString() + ' cannot find an auto-scaling candidate for units: ' + units.toString() + ' (max: ' + max.toString() + ')'); + switch_units_callback(units); + return function(value) { return value; }; + } + + if(typeof common_units_name === 'string' && typeof uuid === 'string') { + // the caller wants several charts to have the same units + // data-common-units + + var common_units_key = common_units_name + '-' + units; + + // add our divider into the list of keys + var t = this.keys[common_units_key]; + if(typeof t === 'undefined') { + this.keys[common_units_key] = {}; + t = this.keys[common_units_key]; + } + t[uuid] = { + units: tunits, + divider: tdivider + }; + + // find the max divider of all charts + var common_units = t[uuid]; + for(x in t) { + if (t.hasOwnProperty(x) && t[x].divider > common_units.divider) + common_units = t[x]; + } + + // save our common_max to the latest keys + var latest = this.latest[common_units_key]; + if(typeof latest === 'undefined') { + this.latest[common_units_key] = {}; + latest = this.latest[common_units_key]; + } + latest.units = common_units.units; + latest.divider = common_units.divider; + + tunits = latest.units; + tdivider = latest.divider; + + //console.log('DEBUG: ' + uuid.toString() + ' converted units: ' + units.toString() + ' to units: ' + tunits.toString() + ' with divider ' + tdivider.toString() + ', common-units=' + common_units_name.toString() + ((t[uuid].divider !== tdivider)?' USED COMMON, mine was ' + t[uuid].units:' set common').toString()); + + // apply it to this chart + switch_units_callback(tunits); + return function(value) { + if(tdivider !== latest.divider) { + // another chart switched our common units + // we should switch them too + //console.log('DEBUG: ' + uuid + ' switching units due to a common-units change, from ' + tunits.toString() + ' to ' + latest.units.toString()); + tunits = latest.units; + tdivider = latest.divider; + switch_units_callback(tunits); + } + + return value / tdivider; + } + } + else { + // the caller did not give data-common-units + // this chart auto-scales independently of all others + //console.log('DEBUG: ' + uuid.toString() + ' converted units: ' + units.toString() + ' to units: ' + tunits.toString() + ' with divider ' + tdivider.toString() + ', autonomously'); + + switch_units_callback(tunits); + return function (value) { return value / tdivider; }; + } + } + else { + // the caller wants specific units + + if(typeof this.scalableUnits[units][desired_units] !== 'undefined') { + // all good, set the new units + tdivider = this.scalableUnits[units][desired_units]; + // console.log('DEBUG: ' + uuid.toString() + ' converted units: ' + units.toString() + ' to units: ' + desired_units.toString() + ' with divider ' + tdivider.toString() + ', by reference'); + switch_units_callback(desired_units); + return function (value) { return value / tdivider; }; + } + else { + // oops! switch back to original units + console.log('Units conversion from ' + units.toString() + ' to ' + desired_units.toString() + ' is not supported.'); + switch_units_callback(units); + return function (value) { return value; }; + } + } + } + else if(typeof this.convertibleUnits[units] !== 'undefined') { + // units that can be converted + if(desired_units === 'auto') { + for(x in this.convertibleUnits[units]) { + if (this.convertibleUnits[units].hasOwnProperty(x)) { + if (this.convertibleUnits[units][x].check()) { + //console.log('DEBUG: ' + uuid.toString() + ' converting ' + units.toString() + ' to: ' + x.toString()); + switch_units_callback(x); + return this.convertibleUnits[units][x].convert; + } + } + } + + // none checked ok + //console.log('DEBUG: ' + uuid.toString() + ' no conversion available for ' + units.toString() + ' to: ' + desired_units.toString()); + switch_units_callback(units); + return function (value) { return value; }; + } + else if(typeof this.convertibleUnits[units][desired_units] !== 'undefined') { + switch_units_callback(desired_units); + return this.convertibleUnits[units][desired_units].convert; + } + else { + console.log('Units conversion from ' + units.toString() + ' to ' + desired_units.toString() + ' is not supported.'); + switch_units_callback(units); + return function (value) { return value; }; + } + } + else { + // hm... did we forget to implement the new type? + console.log('Unmatched unit conversion method for units ' + units.toString()); + switch_units_callback(units); + return function (value) { return value; }; + } + } + }; + + // ---------------------------------------------------------------------------------------------------------------- // global selection sync NETDATA.globalSelectionSync = { @@ -1471,15 +2158,126 @@ var NETDATA = window.NETDATA || {}; dont_sync_before: 0, last_t: 0, slaves: [], + timeout_id: undefined, + + globalReset: function() { + this.stop(); + this.state = null; + this.dont_sync_before = 0; + this.last_t = 0; + this.slaves = []; + this.timeout_id = undefined; + }, + + active: function() { + return (this.state !== null); + }, + + // return true if global selection sync can be enabled now + enabled: function() { + // console.log('enabled()'); + // can we globally apply selection sync? + if(NETDATA.options.current.sync_selection === false) + return false; + + return (this.dont_sync_before <= Date.now()); + }, + + // set the global selection sync master + setMaster: function(state) { + if(this.enabled() === false) { + this.stop(); + return; + } + + if(this.state === state) + return; - stop: function() { if(this.state !== null) - this.state.globalSelectionSyncStop(); + this.stop(); + + if(NETDATA.options.debug.globalSelectionSync === true) + console.log('globalSelectionSync.setMaster(' + state.id + ')'); + + state.selected = true; + this.state = state; + this.last_t = 0; + + // find all slaves + this.slaves = []; + var len = NETDATA.options.targets.length; + while(len--) { + var st = NETDATA.options.targets[len]; + if (this.state !== st && st.globalSelectionSyncIsEligible() === true) + this.slaves.push(st); + } + + // this.delay(100); }, - delay: function() { + // stop global selection sync + stop: function() { if(this.state !== null) { - this.state.globalSelectionSyncDelay(); + if(NETDATA.options.debug.globalSelectionSync === true) + console.log('globalSelectionSync.stop()'); + + var len = this.slaves.length; + while (len--) + this.slaves[len].clearSelection(); + + this.state.clearSelection(); + + this.last_t = 0; + this.slaves = []; + this.state = null; + } + }, + + // delay global selection sync for some time + delay: function(ms) { + if(NETDATA.options.current.sync_selection === true) { + if(NETDATA.options.debug.globalSelectionSync === true) + console.log('globalSelectionSync.delay()'); + + if(typeof ms === 'number') + this.dont_sync_before = Date.now() + ms; + else + this.dont_sync_before = Date.now() + NETDATA.options.current.sync_selection_delay; + } + }, + + __syncSlaves: function() { + if(NETDATA.globalSelectionSync.enabled() === true) { + if(NETDATA.options.debug.globalSelectionSync === true) + console.log('globalSelectionSync.__syncSlaves()'); + + var t = NETDATA.globalSelectionSync.last_t; + var len = NETDATA.globalSelectionSync.slaves.length; + while (len--) + NETDATA.globalSelectionSync.slaves[len].setSelection(t); + + this.timeout_id = undefined; + } + }, + + // sync all the visible charts to the given time + // this is to be called from the chart libraries + sync: function(state, t) { + if(NETDATA.options.current.sync_selection === true) { + if(NETDATA.options.debug.globalSelectionSync === true) + console.log('globalSelectionSync.sync(' + state.id + ', ' + t.toString() + ')'); + + this.setMaster(state); + + if(t === this.last_t) + return; + + this.last_t = t; + + if (this.timeout_id) + NETDATA.timeout.clear(this.timeout_id); + + this.timeout_id = NETDATA.timeout.set(this.__syncSlaves, 0); } } }; @@ -1653,7 +2451,7 @@ var NETDATA = window.NETDATA || {}; return; // string - the netdata server URL, without any path - that.host = NETDATA.dataAttribute(that.element, 'host', NETDATA.chartDefaults.host); + that.host = NETDATA.dataAttribute(that.element, 'host', NETDATA.serverDefault); // make sure the host does not end with / // all netdata API requests use absolute paths @@ -1676,6 +2474,10 @@ var NETDATA = window.NETDATA || {}; that.title = NETDATA.dataAttribute(that.element, 'title', null); // the title of the chart that.units = NETDATA.dataAttribute(that.element, 'units', null); // the units of the chart dimensions + that.units_desired = NETDATA.dataAttribute(that.element, 'desired-units', NETDATA.options.current.units); // the units of the chart dimensions + that.units_current = that.units; + that.units_common = NETDATA.dataAttribute(that.element, 'common-units', null); + that.append_options = NETDATA.dataAttribute(that.element, 'append-options', null); // additional options to pass to netdata that.override_options = NETDATA.dataAttribute(that.element, 'override-options', null); // override options to pass to netdata @@ -1723,6 +2525,7 @@ var NETDATA = window.NETDATA || {}; that.element_chart = null; // the element with the chart that.element_legend = null; // the element with the legend of the chart (if created by us) that.element_legend_childs = { + content: null, hidden: null, title_date: null, title_time: null, @@ -1742,7 +2545,7 @@ var NETDATA = window.NETDATA || {}; that.log('destroyDOM()'); // that.element.className = 'netdata-message icon'; - // that.element.innerHTML = '<i class="fa fa-refresh"></i> netdata'; + // that.element.innerHTML = '<i class="fas fa-sync"></i> netdata'; that.element.innerHTML = ''; that.element_message = null; that.element_legend = null; @@ -1797,6 +2600,10 @@ var NETDATA = window.NETDATA || {}; that.element.style.min_width = NETDATA.chartDefaults.min_width; }; + var invisibleSearchableText = function() { + return '<span style="position:absolute; opacity: 0; width: 0px;">' + that.id + '</span>'; + } + /* init() private * initialize state variables * destroy all (possibly) created state elements @@ -1806,6 +2613,7 @@ var NETDATA = window.NETDATA || {}; if(that.enabled === false) return; runtimeInit(); + that.element.innerHTML = invisibleSearchableText(); that.tm.last_initialized = Date.now(); that.setMode('auto'); @@ -1868,19 +2676,19 @@ var NETDATA = window.NETDATA || {}; var icon; if(that.chart !== null) { if(that.chart.chart_type === 'line') - icon = '<i class="fa fa-line-chart"></i>'; + icon = '<i class="fas fa-chart-line"></i>'; else - icon = '<i class="fa fa-area-chart"></i>'; + icon = '<i class="fas fa-chart-area"></i>'; } else - icon = '<i class="fa fa-area-chart"></i>'; + icon = '<i class="fas fa-chart-area"></i>'; - showMessageIcon(icon + ' netdata'); + showMessageIcon(icon + ' netdata' + invisibleSearchableText()); }; var showLoading = function() { if(that.chart_created === false) { - showMessageIcon('<i class="fa fa-refresh"></i> netdata'); + showMessageIcon('<i class="fas fa-sync-alt"></i> netdata'); return true; } return false; @@ -1896,13 +2704,34 @@ var NETDATA = window.NETDATA || {}; if(isHidden() === true) return; if(that.chart_created === true) { + if(NETDATA.options.current.show_help === true) { + if(that.element_legend_childs.toolbox !== null) { + $(that.element_legend_childs.toolbox_left).popover('hide'); + $(that.element_legend_childs.toolbox_reset).popover('hide'); + $(that.element_legend_childs.toolbox_right).popover('hide'); + $(that.element_legend_childs.toolbox_zoomin).popover('hide'); + $(that.element_legend_childs.toolbox_zoomout).popover('hide'); + } + + if(that.element_legend_childs.resize_handler !== null) + $(that.element_legend_childs.resize_handler).popover('hide'); + + if(that.element_legend_childs.content !== null) + $(that.element_legend_childs.content).popover('hide'); + } + if(NETDATA.options.current.destroy_on_hide === true) { + // that.log('hideChart() init'); + // we should destroy it init('force'); } else { + // that.log('hideChart()'); + showRendering(); that.element_chart.style.display = 'none'; + that.element.style.willChange = 'auto'; if(that.element_legend !== null) that.element_legend.style.display = 'none'; if(that.element_legend_childs.toolbox !== null) that.element_legend_childs.toolbox.style.display = 'none'; if(that.element_legend_childs.resize_handler !== null) that.element_legend_childs.resize_handler.style.display = 'none'; @@ -1928,11 +2757,14 @@ var NETDATA = window.NETDATA || {}; that.updates_since_last_unhide = 0; if(that.chart_created === false) { + // that.log('unhideChart() init'); // we need to re-initialize it, to show our background // logo in bootstrap tabs, until the chart loads init('force'); } else { + // that.log('unhideChart()'); + that.element.style.willChange = 'transform'; that.tm.last_unhidden = Date.now(); that.element_chart.style.display = ''; if(that.element_legend !== null) that.element_legend.style.display = ''; @@ -1943,16 +2775,34 @@ var NETDATA = window.NETDATA || {}; } }; - var canBeRendered = function() { - return (isHidden() === false && that.isVisible(true) === true); + var canBeRendered = function(uncached_visibility) { + return ( + ( + NETDATA.options.page_is_visible === true || + NETDATA.options.current.stop_updates_when_focus_is_lost === false || + that.updates_since_last_unhide === 0 + ) + && isHidden() === false && that.isVisible(uncached_visibility) === true + ); }; // https://github.com/petkaantonov/bluebird/wiki/Optimization-killers var callChartLibraryUpdateSafely = function(data) { var status; - if(canBeRendered() === false) - return false; + // we should not do this here + // if we prevent rendering the chart then: + // 1. globalSelectionSync will be wrong + // 2. globalPanAndZoom will be wrong + //if(canBeRendered(true) === false) + // return false; + + if(NETDATA.options.fake_chart_rendering === true) + return true; + + that.updates_counter++; + that.updates_since_last_unhide++; + that.updates_since_last_creation++; if(NETDATA.options.debug.chart_errors === true) status = that.library.update(that, data); @@ -1977,8 +2827,19 @@ var NETDATA = window.NETDATA || {}; var callChartLibraryCreateSafely = function(data) { var status; - if(canBeRendered() === false) - return false; + // we should not do this here + // if we prevent rendering the chart then: + // 1. globalSelectionSync will be wrong + // 2. globalPanAndZoom will be wrong + //if(canBeRendered(true) === false) + // return false; + + if(NETDATA.options.fake_chart_rendering === true) + return true; + + that.updates_counter++; + that.updates_since_last_unhide++; + that.updates_since_last_creation++; if(NETDATA.options.debug.chart_errors === true) status = that.library.create(that, data); @@ -2049,6 +2910,21 @@ var NETDATA = window.NETDATA || {}; resizeChart(); }; + this.resizeForPrint = function() { + if(typeof this.element_legend_childs !== 'undefined' && this.element_legend_childs.perfect_scroller !== null) { + var current = this.element.clientHeight; + var optimal = current + + this.element_legend_childs.perfect_scroller.scrollHeight + - this.element_legend_childs.perfect_scroller.clientHeight; + + if(optimal > current) { + // this.log('resized'); + this.element.style.height = optimal + 'px'; + this.library.resize(this); + } + } + }; + this.resizeHandler = function(e) { e.preventDefault(); @@ -2178,7 +3054,7 @@ var NETDATA = window.NETDATA || {}; var noDataToShow = function() { - showMessageIcon('<i class="fa fa-warning"></i> empty'); + showMessageIcon('<i class="fas fa-exclamation-triangle"></i> empty'); that.legendUpdateDOM(); that.tm.last_autorefreshed = Date.now(); // that.data_update_every = 30 * 1000; @@ -2216,74 +3092,6 @@ var NETDATA = window.NETDATA || {}; // ---------------------------------------------------------------------------------------------------------------- // global selection sync - // prevent to global selection sync for some time - this.globalSelectionSyncDelay = function(ms) { - if(NETDATA.options.current.sync_selection === false) - return; - - if(typeof ms === 'number') - NETDATA.globalSelectionSync.dont_sync_before = Date.now() + ms; - else - NETDATA.globalSelectionSync.dont_sync_before = Date.now() + NETDATA.options.current.sync_selection_delay; - }; - - // can we globally apply selection sync? - this.globalSelectionSyncAbility = function() { - if(NETDATA.options.current.sync_selection === false) - return false; - - return (NETDATA.globalSelectionSync.dont_sync_before <= Date.now()); - }; - - this.globalSelectionSyncIsMaster = function() { - return (NETDATA.globalSelectionSync.state === this); - }; - - // this chart is the master of the global selection sync - this.globalSelectionSyncBeMaster = function() { - // am I the master? - if(this.globalSelectionSyncIsMaster()) { - if(this.debug === true) - this.log('sync: I am the master already.'); - - return; - } - - if(NETDATA.globalSelectionSync.state) { - if(this.debug === true) - this.log('sync: I am not the sync master. Resetting global sync.'); - - this.globalSelectionSyncStop(); - } - - // become the master - if(this.debug === true) - this.log('sync: becoming sync master.'); - - this.selected = true; - NETDATA.globalSelectionSync.state = this; - - // find the all slaves - var targets = NETDATA.options.targets; - var len = targets.length; - while(len--) { - var st = targets[len]; - - if(st === this) { - if(this.debug === true) - st.log('sync: not adding me to sync'); - } - else if(st.globalSelectionSyncIsEligible()) { - if(this.debug === true) - st.log('sync: adding to sync as slave'); - - st.globalSelectionSyncBeSlave(); - } - } - - // this.globalSelectionSyncDelay(100); - }; - // can the chart participate to the global selection sync as a slave? this.globalSelectionSyncIsEligible = function() { return (this.enabled === true @@ -2293,61 +3101,6 @@ var NETDATA = window.NETDATA || {}; && this.chart_created === true); }; - // this chart becomes a slave of the global selection sync - this.globalSelectionSyncBeSlave = function() { - if(NETDATA.globalSelectionSync.state !== this) - NETDATA.globalSelectionSync.slaves.push(this); - }; - - // sync all the visible charts to the given time - // this is to be called from the chart libraries - this.globalSelectionSync = function(t) { - if(this.globalSelectionSyncAbility() === false) - return; - - if(this.globalSelectionSyncIsMaster() === false) { - if(this.debug === true) - this.log('sync: trying to be sync master.'); - - this.globalSelectionSyncBeMaster(); - - if(this.globalSelectionSyncAbility() === false) - return; - } - - NETDATA.globalSelectionSync.last_t = t; - $.each(NETDATA.globalSelectionSync.slaves, function(i, st) { - st.setSelection(t); - }); - }; - - // stop syncing all charts to the given time - this.globalSelectionSyncStop = function() { - if(NETDATA.globalSelectionSync.slaves.length) { - if(this.debug === true) - this.log('sync: cleaning up...'); - - $.each(NETDATA.globalSelectionSync.slaves, function(i, st) { - if(st === that) { - if(that.debug === true) - st.log('sync: not adding me to sync stop'); - } - else { - if(that.debug === true) - st.log('sync: removed slave from sync'); - - st.clearSelection(); - } - }); - - NETDATA.globalSelectionSync.last_t = 0; - NETDATA.globalSelectionSync.slaves = []; - NETDATA.globalSelectionSync.state = null; - } - - this.clearSelection(); - }; - this.setSelection = function(t) { if(typeof this.library.setSelection === 'function') this.selected = (this.library.setSelection(this, t) === true); @@ -2376,6 +3129,8 @@ var NETDATA = window.NETDATA || {}; return this.selected; }; + // ---------------------------------------------------------------------------------------------------------------- + // find if a timestamp (ms) is shown in the current chart this.timeIsVisible = function(t) { return (t >= this.data_after && t <= this.data_before); @@ -2448,10 +3203,13 @@ var NETDATA = window.NETDATA || {}; } }; - this.updateChartPanOrZoom = function(after, before) { + this.updateChartPanOrZoom = function(after, before, callback) { var logme = 'updateChartPanOrZoom(' + after + ', ' + before + '): '; var ret = true; + NETDATA.globalPanAndZoom.delay(); + NETDATA.globalSelectionSync.delay(); + if(this.debug === true) this.log(logme); @@ -2521,9 +3279,58 @@ var NETDATA = window.NETDATA || {}; this.current.force_after_ms = after; this.current.force_before_ms = before; NETDATA.globalPanAndZoom.setMaster(this, after, before); + + if(ret === true && typeof callback === 'function') + callback(); + return ret; }; + this.updateChartPanOrZoomAsyncTimeOutId = undefined; + this.updateChartPanOrZoomAsync = function(after, before, callback) { + NETDATA.globalPanAndZoom.delay(); + NETDATA.globalSelectionSync.delay(); + + if(NETDATA.globalPanAndZoom.isMaster(this) === false) { + this.pauseChart(); + NETDATA.globalPanAndZoom.setMaster(this, after, before); + // NETDATA.globalSelectionSync.stop(); + NETDATA.globalSelectionSync.setMaster(this); + } + + if(this.updateChartPanOrZoomAsyncTimeOutId) + NETDATA.timeout.clear(this.updateChartPanOrZoomAsyncTimeOutId); + + NETDATA.timeout.set(function() { + that.updateChartPanOrZoomAsyncTimeOutId = undefined; + that.updateChartPanOrZoom(after, before, callback); + }, 0); + }; + + var __unitsConversionLastUnits = undefined; + var __unitsConversionLastUnitsDesired = undefined; + var __unitsConversionLastMin = undefined; + var __unitsConversionLastMax = undefined; + var __unitsConversion = function(value) { return value; }; + this.unitsConversionSetup = function(min, max) { + if(this.units !== __unitsConversionLastUnits + || this.units_desired !== __unitsConversionLastUnitsDesired + || min !== __unitsConversionLastMin + || max !== __unitsConversionLastMax) { + + __unitsConversionLastUnits = this.units; + __unitsConversionLastUnitsDesired = this.units_desired; + __unitsConversionLastMin = min; + __unitsConversionLastMax = max; + + __unitsConversion = NETDATA.unitsConversion.get(this.uuid, min, max, this.units, this.units_desired, this.units_common, function (units) { + // console.log('switching units from ' + that.units.toString() + ' to ' + units.toString()); + that.units_current = units; + that.legendSetUnitsString(that.units_current); + }); + } + }; + var __legendFormatValueChartDecimalsLastMin = undefined; var __legendFormatValueChartDecimalsLastMax = undefined; var __legendFormatValueChartDecimals = -1; @@ -2532,6 +3339,15 @@ var NETDATA = window.NETDATA || {}; if(min === __legendFormatValueChartDecimalsLastMin && max === __legendFormatValueChartDecimalsLastMax) return; + this.unitsConversionSetup(min, max); + if(__unitsConversion !== null) { + min = __unitsConversion(min); + max = __unitsConversion(max); + + if(typeof min !== 'number' || typeof max !== 'number') + return; + } + __legendFormatValueChartDecimalsLastMin = min; __legendFormatValueChartDecimalsLastMax = max; @@ -2576,7 +3392,13 @@ var NETDATA = window.NETDATA || {}; }; this.legendFormatValue = function(value) { - if(typeof value !== 'number') return '-'; + if(typeof value !== 'number') + return '-'; + + value = __unitsConversion(value); + + if(typeof value !== 'number') + return value; if(__intlNumberFormat !== null) return __intlNumberFormat.format(value); @@ -2619,11 +3441,11 @@ var NETDATA = window.NETDATA || {}; s = r = this.legendFormatValue(value); if(typeof series.last === 'number') { - if(v > series.last) s += '<i class="fa fa-angle-up" style="width: 8px; text-align: center; overflow: hidden; vertical-align: middle;"></i>'; - else if(v < series.last) s += '<i class="fa fa-angle-down" style="width: 8px; text-align: center; overflow: hidden; vertical-align: middle;"></i>'; - else s += '<i class="fa fa-angle-left" style="width: 8px; text-align: center; overflow: hidden; vertical-align: middle;"></i>'; + if(v > series.last) s += '<i class="fas fa-angle-up" style="width: 8px; text-align: center; overflow: hidden; vertical-align: middle;"></i>'; + else if(v < series.last) s += '<i class="fas fa-angle-down" style="width: 8px; text-align: center; overflow: hidden; vertical-align: middle;"></i>'; + else s += '<i class="fas fa-angle-left" style="width: 8px; text-align: center; overflow: hidden; vertical-align: middle;"></i>'; } - else s += '<i class="fa fa-angle-right" style="width: 8px; text-align: center; overflow: hidden; vertical-align: middle;"></i>'; + else s += '<i class="fas fa-angle-right" style="width: 8px; text-align: center; overflow: hidden; vertical-align: middle;"></i>'; series.last = v; } @@ -2647,22 +3469,22 @@ var NETDATA = window.NETDATA || {}; if(series.user !== null) series.user.innerText = s; }; - this.__legendSetDateString = function(date) { - if(date !== this.tmp.__last_shown_legend_date) { + this.legendSetDateString = function(date) { + if(this.element_legend_childs.title_date !== null && date !== this.tmp.__last_shown_legend_date) { this.element_legend_childs.title_date.innerText = date; this.tmp.__last_shown_legend_date = date; } }; - this.__legendSetTimeString = function(time) { - if(time !== this.tmp.__last_shown_legend_time) { + this.legendSetTimeString = function(time) { + if(this.element_legend_childs.title_time !== null && time !== this.tmp.__last_shown_legend_time) { this.element_legend_childs.title_time.innerText = time; this.tmp.__last_shown_legend_time = time; } }; - this.__legendSetUnitsString = function(units) { - if(units !== this.tmp.__last_shown_legend_units) { + this.legendSetUnitsString = function(units) { + if(this.element_legend_childs.title_units !== null && units !== this.tmp.__last_shown_legend_units) { this.element_legend_childs.title_units.innerText = units; this.tmp.__last_shown_legend_units = units; } @@ -2683,29 +3505,19 @@ var NETDATA = window.NETDATA || {}; if(this.legendSetDateLast.ms !== ms) { var d = new Date(ms); this.legendSetDateLast.ms = ms; - this.legendSetDateLast.date = d.toLocaleDateString(); - this.legendSetDateLast.time = d.toLocaleTimeString(); + this.legendSetDateLast.date = NETDATA.dateTime.localeDateString(d); + this.legendSetDateLast.time = NETDATA.dateTime.localeTimeString(d); } - if(this.element_legend_childs.title_date !== null) - this.__legendSetDateString(this.legendSetDateLast.date); - - if(this.element_legend_childs.title_time !== null) - this.__legendSetTimeString(this.legendSetDateLast.time); - - if(this.element_legend_childs.title_units !== null) - this.__legendSetUnitsString(this.units) + this.legendSetDateString(this.legendSetDateLast.date); + this.legendSetTimeString(this.legendSetDateLast.time); + this.legendSetUnitsString(this.units_current) }; this.legendShowUndefined = function() { - if(this.element_legend_childs.title_date !== null) - this.__legendSetDateString(' '); - - if(this.element_legend_childs.title_time !== null) - this.__legendSetTimeString(this.chart.name); - - if(this.element_legend_childs.title_units !== null) - this.__legendSetUnitsString(' '); + this.legendSetDateString(this.legendPluginModuleString(false)); + this.legendSetTimeString(this.chart.context.toString()); + // this.legendSetUnitsString(' '); if(this.data && this.element_legend_childs.series !== null) { var labels = this.data.dimension_names; @@ -2869,6 +3681,42 @@ var NETDATA = window.NETDATA || {}; return this.colors; }; + this.legendPluginModuleString = function(withContext) { + var str = ' '; + var context = ''; + + if(typeof this.chart !== 'undefined') { + if(withContext && typeof this.chart.context === 'string') + context = this.chart.context; + + if (typeof this.chart.plugin === 'string' && this.chart.plugin !== '') { + str = this.chart.plugin; + if (typeof this.chart.module === 'string' && this.chart.module !== '') { + str += '/' + this.chart.module; + } + + if (withContext && context !== '') + str += ', ' + context; + } + else if (withContext && context !== '') + str = context; + } + + return str; + }; + + this.legendResolutionTooltip = function () { + if(!this.chart) return ''; + + var collected = this.chart.update_every; + var viewed = (this.data)?this.data.view_update_every:collected; + + if(collected === viewed) + return "resolution " + NETDATA.seconds4human(collected); + + return "resolution " + NETDATA.seconds4human(viewed) + ", collected every " + NETDATA.seconds4human(collected); + }; + this.legendUpdateDOM = function() { var needed = false, dim, keys, len, i; @@ -2961,7 +3809,7 @@ var NETDATA = window.NETDATA || {}; label.name.innerHTML = '<table class="netdata-legend-name-table-' + state.chart.chart_type + '" style="background-color: ' - + 'rgba(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + NETDATA.options.current['color_fill_opacity_' + state.chart.chart_type] + ')' + + 'rgba(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + NETDATA.options.current['color_fill_opacity_' + state.chart.chart_type] + ') !important' + '"><tr class="netdata-legend-name-tr"><td class="netdata-legend-name-td"></td></tr></table>'; var text = document.createTextNode(' ' + name); @@ -2998,14 +3846,14 @@ var NETDATA = window.NETDATA || {}; this.element_legend_childs = { content: content, - resize_handler: document.createElement('div'), - toolbox: document.createElement('div'), - toolbox_left: document.createElement('div'), - toolbox_right: document.createElement('div'), - toolbox_reset: document.createElement('div'), - toolbox_zoomin: document.createElement('div'), - toolbox_zoomout: document.createElement('div'), - toolbox_volume: document.createElement('div'), + resize_handler: null, + toolbox: null, + toolbox_left: null, + toolbox_right: null, + toolbox_reset: null, + toolbox_zoomin: null, + toolbox_zoomout: null, + toolbox_volume: null, title_date: document.createElement('span'), title_time: document.createElement('span'), title_units: document.createElement('span'), @@ -3013,7 +3861,15 @@ var NETDATA = window.NETDATA || {}; series: {} }; - if(this.library.toolboxPanAndZoom !== null) { + if(NETDATA.options.current.legend_toolbox === true && this.library.toolboxPanAndZoom !== null) { + this.element_legend_childs.toolbox = document.createElement('div'); + this.element_legend_childs.toolbox_left = document.createElement('div'); + this.element_legend_childs.toolbox_right = document.createElement('div'); + this.element_legend_childs.toolbox_reset = document.createElement('div'); + this.element_legend_childs.toolbox_zoomin = document.createElement('div'); + this.element_legend_childs.toolbox_zoomout = document.createElement('div'); + this.element_legend_childs.toolbox_volume = document.createElement('div'); + var get_pan_and_zoom_step = function(event) { if (event.ctrlKey) return NETDATA.options.current.pan_and_zoom_factor * NETDATA.options.current.pan_and_zoom_factor_multiplier_control; @@ -3032,7 +3888,7 @@ var NETDATA = window.NETDATA || {}; this.element.appendChild(this.element_legend_childs.toolbox); this.element_legend_childs.toolbox_left.className += ' netdata-legend-toolbox-button'; - this.element_legend_childs.toolbox_left.innerHTML = '<i class="fa fa-backward"></i>'; + this.element_legend_childs.toolbox_left.innerHTML = '<i class="fas fa-backward"></i>'; this.element_legend_childs.toolbox.appendChild(this.element_legend_childs.toolbox_left); this.element_legend_childs.toolbox_left.onclick = function(e) { e.preventDefault(); @@ -3052,12 +3908,12 @@ var NETDATA = window.NETDATA || {}; placement: 'bottom', delay: { show: NETDATA.options.current.show_help_delay_show_ms, hide: NETDATA.options.current.show_help_delay_hide_ms }, title: 'Pan Left', - content: 'Pan the chart to the left. You can also <b>drag it</b> with your mouse or your finger (on touch devices).<br/><small>Help, can be disabled from the settings.</small>' + content: 'Pan the chart to the left. You can also <b>drag it</b> with your mouse or your finger (on touch devices).<br/><small>Help can be disabled from the settings.</small>' }); this.element_legend_childs.toolbox_reset.className += ' netdata-legend-toolbox-button'; - this.element_legend_childs.toolbox_reset.innerHTML = '<i class="fa fa-play"></i>'; + this.element_legend_childs.toolbox_reset.innerHTML = '<i class="fas fa-play"></i>'; this.element_legend_childs.toolbox.appendChild(this.element_legend_childs.toolbox_reset); this.element_legend_childs.toolbox_reset.onclick = function(e) { e.preventDefault(); @@ -3072,11 +3928,11 @@ var NETDATA = window.NETDATA || {}; placement: 'bottom', delay: { show: NETDATA.options.current.show_help_delay_show_ms, hide: NETDATA.options.current.show_help_delay_hide_ms }, title: 'Chart Reset', - content: 'Reset all the charts to their default auto-refreshing state. You can also <b>double click</b> the chart contents with your mouse or your finger (on touch devices).<br/><small>Help, can be disabled from the settings.</small>' + content: 'Reset all the charts to their default auto-refreshing state. You can also <b>double click</b> the chart contents with your mouse or your finger (on touch devices).<br/><small>Help can be disabled from the settings.</small>' }); this.element_legend_childs.toolbox_right.className += ' netdata-legend-toolbox-button'; - this.element_legend_childs.toolbox_right.innerHTML = '<i class="fa fa-forward"></i>'; + this.element_legend_childs.toolbox_right.innerHTML = '<i class="fas fa-forward"></i>'; this.element_legend_childs.toolbox.appendChild(this.element_legend_childs.toolbox_right); this.element_legend_childs.toolbox_right.onclick = function(e) { e.preventDefault(); @@ -3100,7 +3956,7 @@ var NETDATA = window.NETDATA || {}; this.element_legend_childs.toolbox_zoomin.className += ' netdata-legend-toolbox-button'; - this.element_legend_childs.toolbox_zoomin.innerHTML = '<i class="fa fa-plus"></i>'; + this.element_legend_childs.toolbox_zoomin.innerHTML = '<i class="fas fa-plus"></i>'; this.element_legend_childs.toolbox.appendChild(this.element_legend_childs.toolbox_zoomin); this.element_legend_childs.toolbox_zoomin.onclick = function(e) { e.preventDefault(); @@ -3118,11 +3974,11 @@ var NETDATA = window.NETDATA || {}; placement: 'bottom', delay: { show: NETDATA.options.current.show_help_delay_show_ms, hide: NETDATA.options.current.show_help_delay_hide_ms }, title: 'Chart Zoom In', - content: 'Zoom in the chart. You can also press SHIFT and select an area of the chart to zoom in. On Chrome and Opera, you can press the SHIFT or the ALT keys and then use the mouse wheel to zoom in or out.<br/><small>Help, can be disabled from the settings.</small>' + content: 'Zoom in the chart. You can also press SHIFT and select an area of the chart, or press SHIFT or ALT and use the mouse wheel or 2-finger touchpad scroll to zoom in or out.<br/><small>Help, can be disabled from the settings.</small>' }); this.element_legend_childs.toolbox_zoomout.className += ' netdata-legend-toolbox-button'; - this.element_legend_childs.toolbox_zoomout.innerHTML = '<i class="fa fa-minus"></i>'; + this.element_legend_childs.toolbox_zoomout.innerHTML = '<i class="fas fa-minus"></i>'; this.element_legend_childs.toolbox.appendChild(this.element_legend_childs.toolbox_zoomout); this.element_legend_childs.toolbox_zoomout.onclick = function(e) { e.preventDefault(); @@ -3141,11 +3997,11 @@ var NETDATA = window.NETDATA || {}; placement: 'bottom', delay: { show: NETDATA.options.current.show_help_delay_show_ms, hide: NETDATA.options.current.show_help_delay_hide_ms }, title: 'Chart Zoom Out', - content: 'Zoom out the chart. On Chrome and Opera, you can also press the SHIFT or the ALT keys and then use the mouse wheel to zoom in or out.<br/><small>Help, can be disabled from the settings.</small>' + content: 'Zoom out the chart. You can also press SHIFT or ALT and use the mouse wheel, or 2-finger touchpad scroll to zoom in or out.<br/><small>Help, can be disabled from the settings.</small>' }); //this.element_legend_childs.toolbox_volume.className += ' netdata-legend-toolbox-button'; - //this.element_legend_childs.toolbox_volume.innerHTML = '<i class="fa fa-sort-amount-desc"></i>'; + //this.element_legend_childs.toolbox_volume.innerHTML = '<i class="fas fa-sort-amount-down"></i>'; //this.element_legend_childs.toolbox_volume.title = 'Visible Volume'; //this.element_legend_childs.toolbox.appendChild(this.element_legend_childs.toolbox_volume); //this.element_legend_childs.toolbox_volume.onclick = function(e) { @@ -3153,41 +4009,44 @@ var NETDATA = window.NETDATA || {}; //alert('clicked toolbox_volume on ' + that.id); //} } - else { - this.element_legend_childs.toolbox = null; - this.element_legend_childs.toolbox_left = null; - this.element_legend_childs.toolbox_reset = null; - this.element_legend_childs.toolbox_right = null; - this.element_legend_childs.toolbox_zoomin = null; - this.element_legend_childs.toolbox_zoomout = null; - this.element_legend_childs.toolbox_volume = null; - } - this.element_legend_childs.resize_handler.className += " netdata-legend-resize-handler"; - this.element_legend_childs.resize_handler.innerHTML = '<i class="fa fa-chevron-up"></i><i class="fa fa-chevron-down"></i>'; - this.element.appendChild(this.element_legend_childs.resize_handler); - if(NETDATA.options.current.show_help === true) - $(this.element_legend_childs.resize_handler).popover({ - container: "body", - animation: false, - html: true, - trigger: 'hover', - placement: 'bottom', - delay: { show: NETDATA.options.current.show_help_delay_show_ms, hide: NETDATA.options.current.show_help_delay_hide_ms }, - title: 'Chart Resize', - content: 'Drag this point with your mouse or your finger (on touch devices), to resize the chart vertically. You can also <b>double click it</b> or <b>double tap it</b> to reset between 2 states: the default and the one that fits all the values.<br/><small>Help, can be disabled from the settings.</small>' - }); + if(NETDATA.options.current.resize_charts === true) { + this.element_legend_childs.resize_handler = document.createElement('div'); + + this.element_legend_childs.resize_handler.className += " netdata-legend-resize-handler"; + this.element_legend_childs.resize_handler.innerHTML = '<i class="fas fa-sort"></i>'; + this.element.appendChild(this.element_legend_childs.resize_handler); + if (NETDATA.options.current.show_help === true) + $(this.element_legend_childs.resize_handler).popover({ + container: "body", + animation: false, + html: true, + trigger: 'hover', + placement: 'bottom', + delay: { + show: NETDATA.options.current.show_help_delay_show_ms, + hide: NETDATA.options.current.show_help_delay_hide_ms + }, + title: 'Chart Resize', + content: 'Drag this point with your mouse or your finger (on touch devices), to resize the chart vertically. You can also <b>double click it</b> or <b>double tap it</b> to reset between 2 states: the default and the one that fits all the values.<br/><small>Help, can be disabled from the settings.</small>' + }); - // mousedown event - this.element_legend_childs.resize_handler.onmousedown = - function(e) { + // mousedown event + this.element_legend_childs.resize_handler.onmousedown = + function (e) { + that.resizeHandler(e); + }; + + // touchstart event + this.element_legend_childs.resize_handler.addEventListener('touchstart', function (e) { that.resizeHandler(e); - }; + }, false); + } - // touchstart event - this.element_legend_childs.resize_handler.addEventListener('touchstart', function(e) { - that.resizeHandler(e); - }, false); + if(this.chart) { + this.element_legend_childs.title_date.title = this.legendPluginModuleString(true); + this.element_legend_childs.title_time.title = this.legendResolutionTooltip(); + } this.element_legend_childs.title_date.className += " netdata-legend-title-date"; this.element_legend.appendChild(this.element_legend_childs.title_date); @@ -3202,6 +4061,7 @@ var NETDATA = window.NETDATA || {}; this.element_legend.appendChild(document.createElement('br')); this.element_legend_childs.title_units.className += " netdata-legend-title-units"; + this.element_legend_childs.title_units.innerText = this.units_current; this.element_legend.appendChild(this.element_legend_childs.title_units); this.tmp.__last_shown_legend_units = undefined; @@ -3213,6 +4073,8 @@ var NETDATA = window.NETDATA || {}; content.className = 'netdata-legend-series-content'; this.element_legend_childs.perfect_scroller.appendChild(content); + this.element_legend_childs.content = content; + if(NETDATA.options.current.show_help === true) $(content).popover({ container: "body", @@ -3351,37 +4213,62 @@ var NETDATA = window.NETDATA || {}; return ret; }; - this.chartURL = function() { - var after, before, points_multiplier = 1; - if(NETDATA.globalPanAndZoom.isActive() && NETDATA.globalPanAndZoom.isMaster(this) === false) { - this.tm.pan_and_zoom_seq = NETDATA.globalPanAndZoom.seq; + this.chartDataUniqueID = function() { + return this.id + ',' + this.library_name + ',' + this.dimensions + ',' + this.chartURLOptions(); + }; - after = Math.round(NETDATA.globalPanAndZoom.force_after_ms / 1000); - before = Math.round(NETDATA.globalPanAndZoom.force_before_ms / 1000); - this.view_after = after * 1000; - this.view_before = before * 1000; + this.chartURLOptions = function() { + var ret = ''; - this.requested_padding = null; - points_multiplier = 1; - } - else if(this.current.force_before_ms !== null && this.current.force_after_ms !== null) { - this.tm.pan_and_zoom_seq = 0; + if(this.override_options !== null) + ret = this.override_options.toString(); + else + ret = this.library.options(this); - before = Math.round(this.current.force_before_ms / 1000); - after = Math.round(this.current.force_after_ms / 1000); - this.view_after = after * 1000; - this.view_before = before * 1000; + if(this.append_options !== null) + ret += '|' + this.append_options.toString(); + + ret += '|jsonwrap'; + + if(NETDATA.options.current.eliminate_zero_dimensions === true) + ret += '|nonzero'; - if(NETDATA.options.current.pan_and_zoom_data_padding === true) { - this.requested_padding = Math.round((before - after) / 2); - after -= this.requested_padding; - before += this.requested_padding; - this.requested_padding *= 1000; - points_multiplier = 2; + return ret; + }; + + this.chartURL = function() { + var after, before, points_multiplier = 1; + if(NETDATA.globalPanAndZoom.isActive()) { + if(this.current.force_before_ms !== null && this.current.force_after_ms !== null) { + this.tm.pan_and_zoom_seq = 0; + + before = Math.round(this.current.force_before_ms / 1000); + after = Math.round(this.current.force_after_ms / 1000); + this.view_after = after * 1000; + this.view_before = before * 1000; + + if(NETDATA.options.current.pan_and_zoom_data_padding === true) { + this.requested_padding = Math.round((before - after) / 2); + after -= this.requested_padding; + before += this.requested_padding; + this.requested_padding *= 1000; + points_multiplier = 2; + } + + this.current.force_before_ms = null; + this.current.force_after_ms = null; } + else { + this.tm.pan_and_zoom_seq = NETDATA.globalPanAndZoom.seq; + + after = Math.round(NETDATA.globalPanAndZoom.force_after_ms / 1000); + before = Math.round(NETDATA.globalPanAndZoom.force_before_ms / 1000); + this.view_after = after * 1000; + this.view_before = before * 1000; - this.current.force_before_ms = null; - this.current.force_after_ms = null; + this.requested_padding = null; + points_multiplier = 1; + } } else { this.tm.pan_and_zoom_seq = 0; @@ -3398,26 +4285,22 @@ var NETDATA = window.NETDATA || {}; this.requested_after = after * 1000; this.requested_before = before * 1000; - this.data_points = this.points || Math.round(this.chartWidth() / this.chartPixelsPerPoint()); + var data_points; + if(NETDATA.options.force_data_points !== 0) { + data_points = NETDATA.options.force_data_points; + this.data_points = data_points; + } + else { + this.data_points = this.points || Math.round(this.chartWidth() / this.chartPixelsPerPoint()); + data_points = this.data_points * points_multiplier; + } // build the data URL this.data_url = this.host + this.chart.data_url; this.data_url += "&format=" + this.library.format(); - this.data_url += "&points=" + (this.data_points * points_multiplier).toString(); + this.data_url += "&points=" + (data_points).toString(); this.data_url += "&group=" + this.method; - - if(this.override_options !== null) - this.data_url += "&options=" + this.override_options.toString(); - else - this.data_url += "&options=" + this.library.options(this); - - this.data_url += '|jsonwrap'; - - if(NETDATA.options.current.eliminate_zero_dimensions === true) - this.data_url += '|nonzero'; - - if(this.append_options !== null) - this.data_url += '|' + this.append_options.toString(); + this.data_url += "&options=" + this.chartURLOptions(); if(after) this.data_url += "&after=" + after.toString(); @@ -3429,7 +4312,7 @@ var NETDATA = window.NETDATA || {}; this.data_url += "&dimensions=" + this.dimensions; if(NETDATA.options.debug.chart_data_url === true || this.debug === true) - this.log('chartURL(): ' + this.data_url + ' WxH:' + this.chartWidth() + 'x' + this.chartHeight() + ' points: ' + this.data_points + ' library: ' + this.library_name); + this.log('chartURL(): ' + this.data_url + ' WxH:' + this.chartWidth() + 'x' + this.chartHeight() + ' points: ' + data_points.toString() + ' library: ' + this.library_name); }; this.redrawChart = function() { @@ -3445,19 +4328,24 @@ var NETDATA = window.NETDATA || {}; resizeChart(); this.data = data; - this.updates_counter++; - this.updates_since_last_unhide++; - this.updates_since_last_creation++; var started = Date.now(); + var view_update_every = data.view_update_every * 1000; + + + if(this.data_update_every !== view_update_every) { + if(this.element_legend_childs.title_time) + this.element_legend_childs.title_time.title = this.legendResolutionTooltip(); + } // if the result is JSON, find the latest update-every - this.data_update_every = data.view_update_every * 1000; + this.data_update_every = view_update_every; this.data_after = data.after * 1000; this.data_before = data.before * 1000; this.netdata_first = data.first_entry * 1000; this.netdata_last = data.last_entry * 1000; this.data_points = data.points; + data.state = this; if(NETDATA.options.current.pan_and_zoom_data_padding === true && this.requested_padding !== null) { @@ -3549,6 +4437,58 @@ var NETDATA = window.NETDATA || {}; this.refresh_dt_element.innerText = this.refresh_dt_ms.toString(); }; + this.getSnapshotData = function(key) { + if(this.debug === true) + this.log('updating from snapshot: ' + key); + + if(typeof netdataSnapshotData.data[key] === 'undefined') { + this.log('snapshot does not include data for key "' + key + '"'); + return null; + } + + if(typeof netdataSnapshotData.data[key] !== 'string') { + this.log('snapshot data for key "' + key + '" is not string'); + return null; + } + + var uncompressed; + try { + uncompressed = netdataSnapshotData.uncompress(netdataSnapshotData.data[key]); + + if(uncompressed === null) { + this.log('uncompressed snapshot data for key ' + key + ' is null'); + return null; + } + + if(typeof uncompressed === 'undefined') { + this.log('uncompressed snapshot data for key ' + key + ' is undefined'); + return null; + } + } + catch(e) { + this.log('decompression of snapshot data for key ' + key + ' failed'); + console.log(e); + uncompressed = null; + } + + if(typeof uncompressed !== 'string') { + this.log('uncompressed snapshot data for key ' + key + ' is not string'); + return null; + } + + var data; + try { + data = JSON.parse(uncompressed); + } + catch(e) { + this.log('parsing snapshot data for key ' + key + ' failed'); + console.log(e); + data = null; + } + + return data; + }; + this.updateChart = function(callback) { if(this.debug === true) this.log('updateChart()'); @@ -3558,7 +4498,7 @@ var NETDATA = window.NETDATA || {}; this.log('I am already updating...'); if(typeof callback === 'function') - return callback(); + return callback(false, 'already running'); return; } @@ -3570,14 +4510,14 @@ var NETDATA = window.NETDATA || {}; this.log('I am not enabled'); if(typeof callback === 'function') - return callback(); + return callback(false, 'not enabled'); return; } if(canBeRendered() === false) { if(typeof callback === 'function') - return callback(); + return callback(false, 'cannot be rendered'); return; } @@ -3600,7 +4540,7 @@ var NETDATA = window.NETDATA || {}; error('chart library "' + this.library_name + '" is not available.'); if(typeof callback === 'function') - return callback(); + return callback(false, 'library not available'); return; } @@ -3609,17 +4549,40 @@ var NETDATA = window.NETDATA || {}; this.clearSelection(); this.chartURL(); - if(this.debug === true) - this.log('updating from ' + this.data_url); - NETDATA.statistics.refreshes_total++; NETDATA.statistics.refreshes_active++; if(NETDATA.statistics.refreshes_active > NETDATA.statistics.refreshes_active_max) NETDATA.statistics.refreshes_active_max = NETDATA.statistics.refreshes_active; + var ok = false; this.fetching_data = true; + if(netdataSnapshotData !== null) { + var key = this.chartDataUniqueID(); + var data = this.getSnapshotData(key); + if (data !== null) { + ok = true; + this.updateChartWithData(data); + } + else { + ok = false; + error('cannot get data from snapshot for key: "' + key + '"'); + that.tm.last_autorefreshed = Date.now(); + } + + NETDATA.statistics.refreshes_active--; + this.fetching_data = false; + + if(typeof callback === 'function') + callback(ok, 'snapshot'); + + return; + } + + if(this.debug === true) + this.log('updating from ' + this.data_url); + this.xhr = $.ajax( { url: this.data_url, cache: false, @@ -3633,6 +4596,7 @@ var NETDATA = window.NETDATA || {}; .done(function(data) { that.xhr = undefined; that.retries_on_data_failures = 0; + ok = true; if(that.debug === true) that.log('data received. updating chart.'); @@ -3662,11 +4626,14 @@ var NETDATA = window.NETDATA || {}; that.fetching_data = false; if(typeof callback === 'function') - return callback(); + return callback(ok, 'download'); }); }; var __isVisible = function() { + if(NETDATA.options.current.update_only_visible === false) + return true; + // tolerance is the number of pixels a chart can be off-screen // to consider it as visible and refresh it as if was visible var tolerance = 0; @@ -3697,6 +4664,7 @@ var NETDATA = window.NETDATA || {}; this.tmp.___isVisible___ = __isVisible(); if(this.tmp.___isVisible___ === true) unhideChart(); else hideChart(); + return this.tmp.___isVisible___; }; @@ -3705,18 +4673,16 @@ var NETDATA = window.NETDATA || {}; }; this.canBeAutoRefreshed = function() { - var now = Date.now(); - - if(this.running === true) { + if(this.enabled === false) { if(this.debug === true) - this.log('I am already running'); + this.log('canBeAutoRefreshed() -> not enabled'); return false; } - if(this.enabled === false) { + if(this.running === true) { if(this.debug === true) - this.log('I am not enabled'); + this.log('canBeAutoRefreshed() -> already running'); return false; } @@ -3724,99 +4690,112 @@ var NETDATA = window.NETDATA || {}; if(this.library === null || this.library.enabled === false) { error('charting library "' + this.library_name + '" is not available'); if(this.debug === true) - this.log('My chart library ' + this.library_name + ' is not available'); + this.log('canBeAutoRefreshed() -> chart library ' + this.library_name + ' is not available'); return false; } if(this.isVisible() === false) { if(NETDATA.options.debug.visibility === true || this.debug === true) - this.log('I am not visible'); + this.log('canBeAutoRefreshed() -> not visible'); return false; } + var now = Date.now(); + if(this.current.force_update_at !== 0 && this.current.force_update_at < now) { if(this.debug === true) - this.log('timed force update detected - allowing this update'); + this.log('canBeAutoRefreshed() -> timed force update - allowing this update'); this.current.force_update_at = 0; return true; } - if(this.isAutoRefreshable() === true) { - // allow the first update, even if the page is not visible - if(this.updates_counter && this.updates_since_last_unhide && NETDATA.options.page_is_visible === false) { - // if(NETDATA.options.debug.focus === true || this.debug === true) - // this.log('canBeAutoRefreshed(): page does not have focus'); + if(this.isAutoRefreshable() === false) { + if(this.debug === true) + this.log('canBeAutoRefreshed() -> not auto-refreshable'); - return false; - } + return false; + } + + // allow the first update, even if the page is not visible + if(NETDATA.options.page_is_visible === false && this.updates_counter && this.updates_since_last_unhide) { + if(NETDATA.options.debug.focus === true || this.debug === true) + this.log('canBeAutoRefreshed() -> not the first update, and page does not have focus'); + + return false; + } + + if(this.needsRecreation() === true) { + if(this.debug === true) + this.log('canBeAutoRefreshed() -> needs re-creation.'); + + return true; + } + + if(NETDATA.options.auto_refresher_stop_until >= now) { + if(this.debug === true) + this.log('canBeAutoRefreshed() -> stopped until is in future.'); + + return false; + } - if(this.needsRecreation() === true) { + // options valid only for autoRefresh() + if(NETDATA.globalPanAndZoom.isActive()) { + if(NETDATA.globalPanAndZoom.shouldBeAutoRefreshed(this)) { if(this.debug === true) - this.log('canBeAutoRefreshed(): needs re-creation.'); + this.log('canBeAutoRefreshed(): global panning: I need an update.'); return true; } + else { + if(this.debug === true) + this.log('canBeAutoRefreshed(): global panning: I am already up to date.'); - // options valid only for autoRefresh() - if(NETDATA.options.auto_refresher_stop_until === 0 || NETDATA.options.auto_refresher_stop_until < now) { - if(NETDATA.globalPanAndZoom.isActive()) { - if(NETDATA.globalPanAndZoom.shouldBeAutoRefreshed(this)) { - if(this.debug === true) - this.log('canBeAutoRefreshed(): global panning: I need an update.'); - - return true; - } - else { - if(this.debug === true) - this.log('canBeAutoRefreshed(): global panning: I am already up to date.'); - - return false; - } - } + return false; + } + } - if(this.selected === true) { - if(this.debug === true) - this.log('canBeAutoRefreshed(): I have a selection in place.'); + if(this.selected === true) { + if(this.debug === true) + this.log('canBeAutoRefreshed(): I have a selection in place.'); - return false; - } + return false; + } - if(this.paused === true) { - if(this.debug === true) - this.log('canBeAutoRefreshed(): I am paused.'); + if(this.paused === true) { + if(this.debug === true) + this.log('canBeAutoRefreshed(): I am paused.'); - return false; - } + return false; + } - if(now - this.tm.last_autorefreshed >= this.data_update_every) { - if(this.debug === true) - this.log('canBeAutoRefreshed(): It is time to update me.'); + if(now - this.tm.last_autorefreshed >= this.data_update_every) { + if(this.debug === true) + this.log('canBeAutoRefreshed(): It is time to update me.'); - return true; - } - } + return true; } return false; }; this.autoRefresh = function(callback) { - if(this.canBeAutoRefreshed() === true && this.running === false) { - var state = this; + var state = that; + + if(state.canBeAutoRefreshed() === true && state.running === false) { state.running = true; state.updateChart(function() { state.running = false; - if(typeof callback !== 'undefined') + if(typeof callback === 'function') return callback(); }); } else { - if(typeof callback !== 'undefined') + if(typeof callback === 'function') return callback(); } }; @@ -3831,8 +4810,10 @@ var NETDATA = window.NETDATA || {}; if(this.title === null) this.title = chart.title; - if(this.units === null) + if(this.units === null) { this.units = chart.units; + this.units_current = this.units; + } }; // fetch the chart description from the netdata server @@ -3844,6 +4825,15 @@ var NETDATA = window.NETDATA || {}; if(typeof callback === 'function') return callback(); } + else if(netdataSnapshotData !== null) { + // console.log(this); + // console.log(NETDATA.chartRegistry); + NETDATA.error(404, 'host: ' + this.host + ', chart: ' + this.id); + error('chart not found in snapshot'); + + if(typeof callback === 'function') + return callback(); + } else { this.chart_url = "/api/v1/chart?chart=" + this.id; @@ -3882,7 +4872,7 @@ var NETDATA = window.NETDATA || {}; NETDATA.resetAllCharts = function(state) { // first clear the global selection sync // to make sure no chart is in selected state - state.globalSelectionSyncStop(); + NETDATA.globalSelectionSync.stop(); // there are 2 possibilities here // a. state is the global Pan and Zoom master @@ -4036,18 +5026,86 @@ var NETDATA = window.NETDATA || {}; NETDATA.options.pause = false; }; + NETDATA.seconds4human = function (seconds, options) { + var default_options = { + now: 'now', + space: ' ', + negative_suffix: 'ago', + day: 'day', + days: 'days', + hour: 'hour', + hours: 'hours', + minute: 'min', + minutes: 'mins', + second: 'sec', + seconds: 'secs', + and: 'and' + }; + + if(typeof options !== 'object') + options = default_options; + else { + var x; + for(x in default_options) { + if(typeof options[x] !== 'string') + options[x] = default_options[x]; + } + } + + if(typeof seconds === 'string') + seconds = parseInt(seconds, 10); + + if(seconds === 0) + return options.now; + + var suffix = ''; + if(seconds < 0) { + seconds = -seconds; + if(options.negative_suffix !== '') suffix = options.space + options.negative_suffix; + } + + var days = Math.floor(seconds / 86400); + seconds -= (days * 86400); + + var hours = Math.floor(seconds / 3600); + seconds -= (hours * 3600); + + var minutes = Math.floor(seconds / 60); + seconds -= (minutes * 60); + + var strings = []; + + if(days > 1) strings.push(days.toString() + options.space + options.days); + else if(days === 1) strings.push(days.toString() + options.space + options.day); + + if(hours > 1) strings.push(hours.toString() + options.space + options.hours); + else if(hours === 1) strings.push(hours.toString() + options.space + options.hour); + + if(minutes > 1) strings.push(minutes.toString() + options.space + options.minutes); + else if(minutes === 1) strings.push(minutes.toString() + options.space + options.minute); + + if(seconds > 1) strings.push(Math.floor(seconds).toString() + options.space + options.seconds); + else if(seconds === 1) strings.push(Math.floor(seconds).toString() + options.space + options.second); + + if(strings.length === 1) + return strings.pop() + suffix; + + var last = strings.pop(); + return strings.join(", ") + " " + options.and + " " + last + suffix; + }; + // ---------------------------------------------------------------------------------------------------------------- // this is purely sequential charts refresher // it is meant to be autonomous - NETDATA.chartRefresherNoParallel = function(index) { + NETDATA.chartRefresherNoParallel = function(index, callback) { if(NETDATA.options.debug.main_loop === true) console.log('NETDATA.chartRefresherNoParallel(' + index + ')'); if(NETDATA.options.updated_dom === true) { // the dom has been updated // get the dom parts again - NETDATA.parseDom(NETDATA.chartRefresher); + NETDATA.parseDom(callback); return; } if(index >= NETDATA.options.targets.length) { @@ -4055,10 +5113,7 @@ var NETDATA = window.NETDATA || {}; console.log('waiting to restart main loop...'); NETDATA.options.auto_refresher_fast_weight = 0; - - setTimeout(function() { - NETDATA.chartRefresher(); - }, NETDATA.options.current.idle_between_loops); + callback(); } else { var state = NETDATA.options.targets[index]; @@ -4067,19 +5122,22 @@ var NETDATA = window.NETDATA || {}; if(NETDATA.options.debug.main_loop === true) console.log('fast rendering...'); - setTimeout(function() { - state.autoRefresh(function () { - NETDATA.chartRefresherNoParallel(++index); - }); - }, 0); + if(state.isVisible() === true) + NETDATA.timeout.set(function() { + state.autoRefresh(function () { + NETDATA.chartRefresherNoParallel(++index, callback); + }); + }, 0); + else + NETDATA.chartRefresherNoParallel(++index, callback); } else { if(NETDATA.options.debug.main_loop === true) console.log('waiting for next refresh...'); NETDATA.options.auto_refresher_fast_weight = 0; - setTimeout(function() { + NETDATA.timeout.set(function() { state.autoRefresh(function() { - NETDATA.chartRefresherNoParallel(++index); + NETDATA.chartRefresherNoParallel(++index, callback); }); }, NETDATA.options.current.idle_between_charts); } @@ -4091,27 +5149,92 @@ var NETDATA = window.NETDATA || {}; }; // the default refresher + NETDATA.chartRefresherLastRun = 0; + NETDATA.chartRefresherRunsAfterParseDom = 0; + NETDATA.chartRefresherTimeoutId = undefined; + + NETDATA.chartRefresherReschedule = function() { + if(NETDATA.options.current.async_on_scroll === true) { + if(NETDATA.chartRefresherTimeoutId) + NETDATA.timeout.clear(NETDATA.chartRefresherTimeoutId); + NETDATA.chartRefresherTimeoutId = NETDATA.timeout.set(NETDATA.chartRefresher, NETDATA.options.current.onscroll_worker_duration_threshold); + //console.log('chartRefresherReschedule()'); + } + }; + NETDATA.chartRefresher = function() { - // console.log('auto-refresher...'); + // console.log('chartRefresher() begin ' + (Date.now() - NETDATA.chartRefresherLastRun).toString() + ' ms since last run'); + + if(NETDATA.options.page_is_visible === false + && NETDATA.options.current.stop_updates_when_focus_is_lost === true + && NETDATA.chartRefresherLastRun > NETDATA.options.last_page_resize + && NETDATA.chartRefresherLastRun > NETDATA.options.last_page_scroll + && NETDATA.chartRefresherRunsAfterParseDom > 10 + ) { + setTimeout( + NETDATA.chartRefresher, + NETDATA.options.current.idle_lost_focus + ); + + // console.log('chartRefresher() page without focus, will run in ' + NETDATA.options.current.idle_lost_focus.toString() + ' ms, ' + NETDATA.chartRefresherRunsAfterParseDom.toString()); + return; + } + NETDATA.chartRefresherRunsAfterParseDom++; + + var now = Date.now(); + NETDATA.chartRefresherLastRun = now; + + if( now < NETDATA.options.on_scroll_refresher_stop_until ) { + NETDATA.chartRefresherTimeoutId = NETDATA.timeout.set( + NETDATA.chartRefresher, + NETDATA.chartRefresherWaitTime() + ); + + // console.log('chartRefresher() end1 will run in ' + NETDATA.chartRefresherWaitTime().toString() + ' ms'); + return; + } + + if( now < NETDATA.options.auto_refresher_stop_until ) { + NETDATA.chartRefresherTimeoutId = NETDATA.timeout.set( + NETDATA.chartRefresher, + NETDATA.chartRefresherWaitTime() + ); + + // console.log('chartRefresher() end2 will run in ' + NETDATA.chartRefresherWaitTime().toString() + ' ms'); + return; + } if(NETDATA.options.pause === true) { // console.log('auto-refresher is paused'); - setTimeout(NETDATA.chartRefresher, - NETDATA.chartRefresherWaitTime()); + NETDATA.chartRefresherTimeoutId = NETDATA.timeout.set( + NETDATA.chartRefresher, + NETDATA.chartRefresherWaitTime() + ); + + // console.log('chartRefresher() end3 will run in ' + NETDATA.chartRefresherWaitTime().toString() + ' ms'); return; } if(typeof NETDATA.options.pauseCallback === 'function') { // console.log('auto-refresher is calling pauseCallback'); + NETDATA.options.pause = true; NETDATA.options.pauseCallback(); NETDATA.chartRefresher(); + + // console.log('chartRefresher() end4 (nested)'); return; } if(NETDATA.options.current.parallel_refresher === false) { // console.log('auto-refresher is calling chartRefresherNoParallel(0)'); - NETDATA.chartRefresherNoParallel(0); + NETDATA.chartRefresherNoParallel(0, function() { + NETDATA.chartRefresherTimeoutId = NETDATA.timeout.set( + NETDATA.chartRefresher, + NETDATA.options.current.idle_between_loops + ); + }); + // console.log('chartRefresher() end5 (no parallel, nested)'); return; } @@ -4120,53 +5243,66 @@ var NETDATA = window.NETDATA || {}; // get the dom parts again // console.log('auto-refresher is calling parseDom()'); NETDATA.parseDom(NETDATA.chartRefresher); + // console.log('chartRefresher() end6 (parseDom)'); return; } - var parallel = []; - var targets = NETDATA.options.targets; - var len = targets.length; - var state; - while(len--) { - state = targets[len]; - if(state.isVisible() === false || state.running === true) - continue; - - if(state.library.initialized === false) { - if(state.library.enabled === true) { - state.library.initialize(NETDATA.chartRefresher); - return; - } - else { - state.error('chart library "' + state.library_name + '" is not enabled.'); + if(NETDATA.globalSelectionSync.active() === false) { + var parallel = []; + var targets = NETDATA.options.targets; + var len = targets.length; + var state; + while(len--) { + state = targets[len]; + if(state.isVisible() === false || state.running === true) + continue; + + if(state.library.initialized === false) { + if(state.library.enabled === true) { + state.library.initialize(NETDATA.chartRefresher); + //console.log('chartRefresher() end6 (library init)'); + return; + } + else { + state.error('chart library "' + state.library_name + '" is not enabled.'); + } } + + if(NETDATA.scrollUp === true) + parallel.unshift(state); + else + parallel.push(state); } - if(NETDATA.scrollUp === true) - parallel.unshift(state); - else - parallel.push(state); - } + len = parallel.length; + while (len--) { + state = parallel[len]; + // console.log('auto-refresher executing in parallel for ' + parallel.length.toString() + ' charts'); + // this will execute the jobs in parallel - if(parallel.length > 0) { - // console.log('auto-refresher executing in parallel for ' + parallel.length.toString() + ' charts'); - // this will execute the jobs in parallel - $(parallel).each(function() { - this.autoRefresh(); - }) + if (state.running === false) + NETDATA.timeout.set(state.autoRefresh, 0); + } + //else { + // console.log('auto-refresher nothing to do'); + //} } - //else { - // console.log('auto-refresher nothing to do'); - //} // run the next refresh iteration - setTimeout(NETDATA.chartRefresher, - NETDATA.chartRefresherWaitTime()); + NETDATA.chartRefresherTimeoutId = NETDATA.timeout.set( + NETDATA.chartRefresher, + NETDATA.chartRefresherWaitTime() + ); + + //console.log('chartRefresher() completed in ' + (Date.now() - now).toString() + ' ms'); }; NETDATA.parseDom = function(callback) { + //console.log('parseDom()'); + NETDATA.options.last_page_scroll = Date.now(); NETDATA.options.updated_dom = false; + NETDATA.chartRefresherRunsAfterParseDom = 0; var targets = $('div[data-netdata]'); //.filter(':visible'); @@ -4181,14 +5317,26 @@ var NETDATA = window.NETDATA || {}; NETDATA.options.targets.push(NETDATA.chartState(targets[len])); } + if(NETDATA.globalChartUnderlay.isActive() === true) + NETDATA.globalChartUnderlay.setup(); + else + NETDATA.globalChartUnderlay.clear(); + if(typeof callback === 'function') return callback(); }; // this is the main function - where everything starts + NETDATA.started = false; NETDATA.start = function() { // this should be called only once + if(NETDATA.started === true) { + console.log('netdata is already started'); + return; + } + + NETDATA.started = true; NETDATA.options.page_is_visible = true; $(window).blur(function() { @@ -4240,6 +5388,18 @@ var NETDATA = window.NETDATA || {}; netdataCallback(); }; + NETDATA.globalReset = function() { + NETDATA.globalSelectionSync.globalReset(); + NETDATA.globalPanAndZoom.globalReset(); + NETDATA.chartRegistry.globalReset(); + NETDATA.commonMin.globalReset(); + NETDATA.commonMax.globalReset(); + NETDATA.unitsConversion.globalReset(); + NETDATA.options.targets = null; + NETDATA.parseDom(); + NETDATA.unpause(); + }; + // ---------------------------------------------------------------------------------------------------------------- // peity @@ -4375,7 +5535,7 @@ var NETDATA = window.NETDATA || {}; var tooltipClassname = NETDATA.dataAttribute(state.element, 'sparkline-tooltipclassname', undefined); var tooltipFormat = NETDATA.dataAttribute(state.element, 'sparkline-tooltipformat', undefined); var tooltipPrefix = NETDATA.dataAttribute(state.element, 'sparkline-tooltipprefix', undefined); - var tooltipSuffix = NETDATA.dataAttribute(state.element, 'sparkline-tooltipsuffix', ' ' + state.units); + var tooltipSuffix = NETDATA.dataAttribute(state.element, 'sparkline-tooltipsuffix', ' ' + state.units_current); var tooltipSkipNull = NETDATA.dataAttributeBoolean(state.element, 'sparkline-tooltipskipnull', true); var tooltipValueLookups = NETDATA.dataAttribute(state.element, 'sparkline-tooltipvaluelookups', undefined); var tooltipFormatFieldlist = NETDATA.dataAttribute(state.element, 'sparkline-tooltipformatfieldlist', undefined); @@ -4444,6 +5604,7 @@ var NETDATA = window.NETDATA || {}; }; $(state.element_chart).sparkline(data.result, state.sparkline_options); + return true; }; @@ -4462,10 +5623,11 @@ var NETDATA = window.NETDATA || {}; before = state.netdata_last; state.setMode('zoom'); - state.globalSelectionSyncStop(); - state.globalSelectionSyncDelay(); + NETDATA.globalSelectionSync.stop(); + NETDATA.globalSelectionSync.delay(); state.tmp.dygraph_user_action = true; state.tmp.dygraph_force_zoom = true; + // state.log('toolboxPanAndZoom'); state.updateChartPanOrZoom(after, before); NETDATA.globalPanAndZoom.setMaster(state, after, before); }; @@ -4473,15 +5635,17 @@ var NETDATA = window.NETDATA || {}; NETDATA.dygraphSetSelection = function(state, t) { if(typeof state.tmp.dygraph_instance !== 'undefined') { var r = state.calculateRowForTime(t); - if(r !== -1) + if(r !== -1) { state.tmp.dygraph_instance.setSelection(r); + return true; + } else { state.tmp.dygraph_instance.clearSelection(); state.legendShowUndefined(); } } - return true; + return false; }; NETDATA.dygraphClearSelection = function(state) { @@ -4562,6 +5726,10 @@ var NETDATA = window.NETDATA || {}; visibility: state.dimensions_visibility.selected2BooleanArray(state.data.dimension_names) }; + if(!NETDATA.chartLibraries.dygraph.isSparkline(state)) { + options.ylabel = state.units_current; // (state.units_desired === 'auto')?"":state.units_current; + } + if(state.tmp.dygraph_force_zoom === true) { if(NETDATA.options.debug.dygraph === true || state.debug === true) state.log('dygraphChartUpdate() forced zoom update'); @@ -4602,6 +5770,12 @@ var NETDATA = window.NETDATA || {}; } } + if(netdataSnapshotData !== null && NETDATA.globalPanAndZoom.isActive() === true && NETDATA.globalPanAndZoom.isMaster(state) === false) { + // pan and zoom on snapshots + options.dateWindow = [ NETDATA.globalPanAndZoom.force_after_ms, NETDATA.globalPanAndZoom.force_before_ms ]; + options.isZoomedIgnoreProgrammaticZoom = true; + } + dygraph.updateOptions(options); var redraw = false; @@ -4662,7 +5836,7 @@ var NETDATA = window.NETDATA || {}; xRangePad: NETDATA.dataAttribute(state.element, 'dygraph-xrangepad', 0), yRangePad: NETDATA.dataAttribute(state.element, 'dygraph-yrangepad', 1), valueRange: NETDATA.dataAttribute(state.element, 'dygraph-valuerange', [ null, null ]), - ylabel: state.units, + ylabel: state.units_current, // (state.units_desired === 'auto')?"":state.units_current, yLabelWidth: NETDATA.dataAttribute(state.element, 'dygraph-ylabelwidth', 12), // the function to plot the chart @@ -4724,7 +5898,7 @@ var NETDATA = window.NETDATA || {}; ticker: Dygraph.dateTicker, axisLabelFormatter: function (d, gran) { void(gran); - return NETDATA.zeropad(d.getHours()) + ":" + NETDATA.zeropad(d.getMinutes()) + ":" + NETDATA.zeropad(d.getSeconds()); + return NETDATA.dateTime.xAxisTimeString(d); } }, y: { @@ -4737,11 +5911,41 @@ var NETDATA = window.NETDATA || {}; this.axes_[0].extremeRange[1] ); - return state.legendFormatValue(y); + var old_units = this.user_attrs_.ylabel; + var v = state.legendFormatValue(y); + var new_units = state.units_current; + + if(state.units_desired === 'auto' && typeof old_units !== 'undefined' && new_units !== old_units && !NETDATA.chartLibraries.dygraph.isSparkline(state)) { + // console.log(this); + // state.log('units discrepancy: old = ' + old_units + ', new = ' + new_units); + var len = this.plugins_.length; + while(len--) { + // console.log(this.plugins_[len]); + if(typeof this.plugins_[len].plugin.ylabel_div_ !== 'undefined' + && this.plugins_[len].plugin.ylabel_div_ !== null + && typeof this.plugins_[len].plugin.ylabel_div_.children !== 'undefined' + && this.plugins_[len].plugin.ylabel_div_.children !== null + && typeof this.plugins_[len].plugin.ylabel_div_.children[0].children !== 'undefined' + && this.plugins_[len].plugin.ylabel_div_.children[0].children !== null + ) { + this.plugins_[len].plugin.ylabel_div_.children[0].children[0].innerHTML = new_units; + this.user_attrs_.ylabel = new_units; + break; + } + } + + if(len < 0) + state.log('units discrepancy, but cannot find dygraphs div to change: old = ' + old_units + ', new = ' + new_units); + } + + return v; } } }, legendFormatter: function(data) { + if(state.tmp.dygraph_mouse_down === true) + return; + var elements = state.element_legend_childs; // if the hidden div is not there @@ -4763,6 +5967,16 @@ var NETDATA = window.NETDATA || {}; return ''; }, drawCallback: function(dygraph, is_initial) { + + // the user has panned the chart and this is called to re-draw the chart + // 1. refresh this chart by adding data to it + // 2. notify all the other charts about the update they need + + // to prevent an infinite loop (feedback), we use + // state.tmp.dygraph_user_action + // - when true, this is initiated by a user + // - when false, this is feedback + if(state.current.name !== 'auto' && state.tmp.dygraph_user_action === true) { state.tmp.dygraph_user_action = false; @@ -4771,20 +5985,27 @@ var NETDATA = window.NETDATA || {}; var before = Math.round(x_range[1]); if(NETDATA.options.debug.dygraph === true) - state.log('dygraphDrawCallback(dygraph, ' + is_initial + '): ' + (after / 1000).toString() + ' - ' + (before / 1000).toString()); + state.log('dygraphDrawCallback(dygraph, ' + is_initial + '): mode ' + state.current.name + ' ' + (after / 1000).toString() + ' - ' + (before / 1000).toString()); + //console.log(state); if(before <= state.netdata_last && after >= state.netdata_first) + // update only when we are within the data limits state.updateChartPanOrZoom(after, before); } }, zoomCallback: function(minDate, maxDate, yRanges) { + + // the user has selected a range on the chart + // 1. refresh this chart by adding data to it + // 2. notify all the other charts about the update they need + void(yRanges); if(NETDATA.options.debug.dygraph === true) - state.log('dygraphZoomCallback()'); + state.log('dygraphZoomCallback(): ' + state.current.name); - state.globalSelectionSyncStop(); - state.globalSelectionSyncDelay(); + NETDATA.globalSelectionSync.stop(); + NETDATA.globalSelectionSync.delay(); state.setMode('zoom'); // refresh it to the greatest possible zoom level @@ -4795,9 +6016,6 @@ var NETDATA = window.NETDATA || {}; highlightCallback: function(event, x, points, row, seriesName) { void(seriesName); - if(NETDATA.options.debug.dygraph === true || state.debug === true) - state.log('dygraphHighlightCallback()'); - state.pauseChart(); // there is a bug in dygraph when the chart is zoomed enough @@ -4807,7 +6025,8 @@ var NETDATA = window.NETDATA || {}; // var t = state.data_after + row * state.data_update_every; // console.log('row = ' + row + ', x = ' + x + ', t = ' + t + ' ' + ((t === x)?'SAME':(Math.abs(x-t)<=state.data_update_every)?'SIMILAR':'DIFFERENT') + ', rows in db: ' + state.data_points + ' visible(x) = ' + state.timeIsVisible(x) + ' visible(t) = ' + state.timeIsVisible(t) + ' r(x) = ' + state.calculateRowForTime(x) + ' r(t) = ' + state.calculateRowForTime(t) + ' range: ' + state.data_after + ' - ' + state.data_before + ' real: ' + state.data.after + ' - ' + state.data.before + ' every: ' + state.data_update_every); - state.globalSelectionSync(x); + if(state.tmp.dygraph_mouse_down !== true) + NETDATA.globalSelectionSync.sync(state, x); // fix legend zIndex using the internal structures of dygraph legend module // this works, but it is a hack! @@ -4816,11 +6035,41 @@ var NETDATA = window.NETDATA || {}; unhighlightCallback: function(event) { void(event); + if(state.tmp.dygraph_mouse_down === true) + return; + if(NETDATA.options.debug.dygraph === true || state.debug === true) state.log('dygraphUnhighlightCallback()'); state.unpauseChart(); - state.globalSelectionSyncStop(); + NETDATA.globalSelectionSync.stop(); + }, + underlayCallback: function(canvas, area, g) { + + // the chart is about to be drawn + // this function renders global highlighted time-frame + + if(NETDATA.globalChartUnderlay.isActive()) { + var after = NETDATA.globalChartUnderlay.after; + var before = NETDATA.globalChartUnderlay.before; + + if(after < state.view_after) + after = state.view_after; + + if(before > state.view_before) + before = state.view_before; + + if(after < before) { + var bottom_left = g.toDomCoords(after, -20); + var top_right = g.toDomCoords(before, +20); + + var left = bottom_left[0]; + var right = top_right[0]; + + canvas.fillStyle = NETDATA.themes.current.highlight; + canvas.fillRect(left, area.y, right - left, area.h); + } + } }, interactionModel : { mousedown: function(event, dygraph, context) { @@ -4828,37 +6077,73 @@ var NETDATA = window.NETDATA || {}; state.log('interactionModel.mousedown()'); state.tmp.dygraph_user_action = true; - state.globalSelectionSyncStop(); if(NETDATA.options.debug.dygraph === true) state.log('dygraphMouseDown()'); - // Right-click should not initiate a zoom. + // Right-click should not initiate anything. if(event.button && event.button === 2) return; + NETDATA.globalSelectionSync.stop(); + NETDATA.globalSelectionSync.delay(); + + state.tmp.dygraph_mouse_down = true; context.initializeMouseDown(event, dygraph, context); + //console.log(event); if(event.button && event.button === 1) { - if (event.altKey || event.shiftKey) { + if (event.shiftKey) { + //console.log('middle mouse button dragging (PAN)'); + state.setMode('pan'); - state.globalSelectionSyncDelay(); + // NETDATA.globalSelectionSync.delay(); + state.tmp.dygraph_highlight_after = null; Dygraph.startPan(event, dygraph, context); } + else if(event.altKey || event.ctrlKey || event.metaKey) { + //console.log('middle mouse button highlight'); + + if (!(event.offsetX && event.offsetY)) { + event.offsetX = event.layerX - event.target.offsetLeft; + event.offsetY = event.layerY - event.target.offsetTop; + } + state.tmp.dygraph_highlight_after = dygraph.toDataXCoord(event.offsetX); + Dygraph.startZoom(event, dygraph, context); + } else { + //console.log('middle mouse button selection for zoom (ZOOM)'); + state.setMode('zoom'); - state.globalSelectionSyncDelay(); + // NETDATA.globalSelectionSync.delay(); + state.tmp.dygraph_highlight_after = null; Dygraph.startZoom(event, dygraph, context); } } else { - if (event.altKey || event.shiftKey) { + if (event.shiftKey) { + //console.log('left mouse button selection for zoom (ZOOM)'); + state.setMode('zoom'); - state.globalSelectionSyncDelay(); + // NETDATA.globalSelectionSync.delay(); + state.tmp.dygraph_highlight_after = null; + Dygraph.startZoom(event, dygraph, context); + } + else if(event.altKey || event.ctrlKey || event.metaKey) { + //console.log('left mouse button highlight'); + + if (!(event.offsetX && event.offsetY)) { + event.offsetX = event.layerX - event.target.offsetLeft; + event.offsetY = event.layerY - event.target.offsetTop; + } + state.tmp.dygraph_highlight_after = dygraph.toDataXCoord(event.offsetX); Dygraph.startZoom(event, dygraph, context); } else { + //console.log('left mouse button dragging (PAN)'); + state.setMode('pan'); - state.globalSelectionSyncDelay(); + // NETDATA.globalSelectionSync.delay(); + state.tmp.dygraph_highlight_after = null; Dygraph.startPan(event, dygraph, context); } } @@ -4867,35 +6152,98 @@ var NETDATA = window.NETDATA || {}; if(NETDATA.options.debug.dygraph === true || state.debug === true) state.log('interactionModel.mousemove()'); - if(context.isPanning) { + if(state.tmp.dygraph_highlight_after !== null) { + //console.log('highlight selection...'); + + NETDATA.globalSelectionSync.stop(); + NETDATA.globalSelectionSync.delay(); + state.tmp.dygraph_user_action = true; - state.globalSelectionSyncStop(); - state.globalSelectionSyncDelay(); + Dygraph.moveZoom(event, dygraph, context); + event.preventDefault(); + } + else if(context.isPanning) { + //console.log('panning...'); + + NETDATA.globalSelectionSync.stop(); + NETDATA.globalSelectionSync.delay(); + + state.tmp.dygraph_user_action = true; + //NETDATA.globalSelectionSync.stop(); + //NETDATA.globalSelectionSync.delay(); state.setMode('pan'); context.is2DPan = false; Dygraph.movePan(event, dygraph, context); } else if(context.isZooming) { + //console.log('zooming...'); + + NETDATA.globalSelectionSync.stop(); + NETDATA.globalSelectionSync.delay(); + state.tmp.dygraph_user_action = true; - state.globalSelectionSyncStop(); - state.globalSelectionSyncDelay(); + //NETDATA.globalSelectionSync.stop(); + //NETDATA.globalSelectionSync.delay(); state.setMode('zoom'); Dygraph.moveZoom(event, dygraph, context); } }, mouseup: function(event, dygraph, context) { + state.tmp.dygraph_mouse_down = false; + if(NETDATA.options.debug.dygraph === true || state.debug === true) state.log('interactionModel.mouseup()'); - if (context.isPanning) { + if(state.tmp.dygraph_highlight_after !== null) { + //console.log('done highlight selection'); + + NETDATA.globalSelectionSync.stop(); + NETDATA.globalSelectionSync.delay(); + + if (!(event.offsetX && event.offsetY)){ + event.offsetX = event.layerX - event.target.offsetLeft; + event.offsetY = event.layerY - event.target.offsetTop; + } + + NETDATA.globalChartUnderlay.set(state + , state.tmp.dygraph_highlight_after + , dygraph.toDataXCoord(event.offsetX) + , state.view_after + , state.view_before + ); + + state.tmp.dygraph_highlight_after = null; + + context.isZooming = false; + dygraph.clearZoomRect_(); + dygraph.drawGraph_(false); + + // refresh all the charts immediately + NETDATA.options.auto_refresher_stop_until = 0; + } + else if (context.isPanning) { + //console.log('done panning'); + + NETDATA.globalSelectionSync.stop(); + NETDATA.globalSelectionSync.delay(); + state.tmp.dygraph_user_action = true; - state.globalSelectionSyncDelay(); Dygraph.endPan(event, dygraph, context); + + // refresh all the charts immediately + NETDATA.options.auto_refresher_stop_until = 0; } else if (context.isZooming) { + //console.log('done zomming'); + + NETDATA.globalSelectionSync.stop(); + NETDATA.globalSelectionSync.delay(); + state.tmp.dygraph_user_action = true; - state.globalSelectionSyncDelay(); Dygraph.endZoom(event, dygraph, context); + + // refresh all the charts immediately + NETDATA.options.auto_refresher_stop_until = 0; } }, click: function(event, dygraph, context) { @@ -4984,8 +6332,8 @@ var NETDATA = window.NETDATA || {}; if(event.altKey || event.shiftKey) { state.tmp.dygraph_user_action = true; - state.globalSelectionSyncStop(); - state.globalSelectionSyncDelay(); + NETDATA.globalSelectionSync.stop(); + NETDATA.globalSelectionSync.delay(); // http://dygraphs.com/gallery/interaction-api.js var normal_def; @@ -5024,13 +6372,16 @@ var NETDATA = window.NETDATA || {}; } state.setMode('zoom'); - if(state.updateChartPanOrZoom(after, before) === true) + state.updateChartPanOrZoom(after, before, function() { dygraph.updateOptions({ dateWindow: [ after, before ] }); + }); event.preventDefault(); } }, touchstart: function(event, dygraph, context) { + state.tmp.dygraph_mouse_down = true; + if(NETDATA.options.debug.dygraph === true || state.debug === true) state.log('interactionModel.touchstart()'); @@ -5038,6 +6389,9 @@ var NETDATA = window.NETDATA || {}; state.setMode('zoom'); state.pauseChart(); + NETDATA.globalSelectionSync.stop(); + NETDATA.globalSelectionSync.delay(); + Dygraph.defaultInteractionModel.touchstart(event, dygraph, context); // we overwrite the touch directions at the end, to overwrite @@ -5056,25 +6410,39 @@ var NETDATA = window.NETDATA || {}; if(NETDATA.options.debug.dygraph === true || state.debug === true) state.log('interactionModel.touchmove()'); + NETDATA.globalSelectionSync.stop(); + NETDATA.globalSelectionSync.delay(); + state.tmp.dygraph_user_action = true; Dygraph.defaultInteractionModel.touchmove(event, dygraph, context); state.dygraph_last_touch_move = Date.now(); }, touchend: function(event, dygraph, context) { + state.tmp.dygraph_mouse_down = false; + if(NETDATA.options.debug.dygraph === true || state.debug === true) state.log('interactionModel.touchend()'); + NETDATA.globalSelectionSync.stop(); + NETDATA.globalSelectionSync.delay(); + state.tmp.dygraph_user_action = true; Dygraph.defaultInteractionModel.touchend(event, dygraph, context); // if it didn't move, it is a selection if(state.dygraph_last_touch_move === 0 && state.dygraph_last_touch_page_x !== 0) { + NETDATA.globalSelectionSync.dont_sync_before = 0; + NETDATA.globalSelectionSync.setMaster(state); + // internal api of dygraph var pct = (state.dygraph_last_touch_page_x - (dygraph.plotter_.area.x + state.element.getBoundingClientRect().left)) / dygraph.plotter_.area.w; - var t = Math.round(state.data_after + (state.data_before - state.data_after) * pct); - if(NETDATA.dygraphSetSelection(state, t) === true) - state.globalSelectionSync(t); + console.log('pct: ' + pct.toString()); + + var t = Math.round(state.view_after + (state.view_before - state.view_after) * pct); + if(NETDATA.dygraphSetSelection(state, t) === true) { + NETDATA.globalSelectionSync.sync(state, t); + } } // if it was double tap within double click time, reset the charts @@ -5089,6 +6457,9 @@ var NETDATA = window.NETDATA || {}; // remember the timestamp of the last touch end state.dygraph_last_touch_end = now; + + // refresh all the charts immediately + NETDATA.options.auto_refresher_stop_until = 0; } } }; @@ -5114,12 +6485,19 @@ var NETDATA = window.NETDATA || {}; } else state.tmp.dygraph_smooth_eligible = false; + if(netdataSnapshotData !== null && NETDATA.globalPanAndZoom.isActive() === true && NETDATA.globalPanAndZoom.isMaster(state) === false) { + // pan and zoom on snapshots + state.tmp.dygraph_options.dateWindow = [ NETDATA.globalPanAndZoom.force_after_ms, NETDATA.globalPanAndZoom.force_before_ms ]; + state.tmp.dygraph_options.isZoomedIgnoreProgrammaticZoom = true; + } + state.tmp.dygraph_instance = new Dygraph(state.element_chart, data.result.data, state.tmp.dygraph_options); state.tmp.dygraph_force_zoom = false; state.tmp.dygraph_user_action = false; state.tmp.dygraph_last_rendered = Date.now(); + state.tmp.dygraph_highlight_after = null; if(state.tmp.dygraph_options.valueRange[0] === null && state.tmp.dygraph_options.valueRange[1] === null) { if (typeof state.tmp.dygraph_instance.axes_[0].extremeRange !== 'undefined') { @@ -5356,7 +6734,7 @@ var NETDATA = window.NETDATA || {}; type: 'timeseries', tick: { format: function(x) { - return NETDATA.zeropad(x.getHours()) + ":" + NETDATA.zeropad(x.getMinutes()) + ":" + NETDATA.zeropad(x.getSeconds()); + return NETDATA.dateTime.xAxisTimeString(x); } } } @@ -5496,7 +6874,7 @@ var NETDATA = window.NETDATA || {}; } }, vAxis: { - title: state.units, + title: state.units_current, viewWindowMode: 'pretty', minValue: -0.1, maxValue: 0.1, @@ -5578,6 +6956,8 @@ var NETDATA = window.NETDATA || {}; if(min > value) min = value; if(max < value) max = value; + state.legendFormatValueDecimalsFromMinMax(min, max); + if(state.tmp.easyPieChartMin === null && min > 0) min = 0; if(state.tmp.easyPieChartMax === null && max < 0) max = 0; @@ -5635,8 +7015,8 @@ var NETDATA = window.NETDATA || {}; NETDATA.easypiechartClearSelection = function(state) { if(typeof state.tmp.easyPieChartEvent !== 'undefined') { - if(state.tmp.easyPieChartEvent.timer !== undefined) { - clearTimeout(state.tmp.easyPieChartEvent.timer); + if(state.tmp.easyPieChartEvent.timer) { + NETDATA.timeout.clear(state.tmp.easyPieChartEvent.timer); } state.tmp.easyPieChartEvent.timer = undefined; @@ -5682,10 +7062,10 @@ var NETDATA = window.NETDATA || {}; if(state.tmp.easyPieChartEvent.timer === undefined) { state.tmp.easyPieChart_instance.disableAnimation(); - state.tmp.easyPieChartEvent.timer = setTimeout(function() { + state.tmp.easyPieChartEvent.timer = NETDATA.timeout.set(function() { state.tmp.easyPieChartEvent.timer = undefined; state.tmp.easyPieChart_instance.update(state.tmp.easyPieChartEvent.pcent); - }, NETDATA.options.current.charts_selection_animation_delay); + }, 0); } return true; @@ -5731,10 +7111,6 @@ var NETDATA = window.NETDATA || {}; else state.tmp.easyPieChartMax = max; - var pcent = NETDATA.easypiechartPercentFromValueMinMax(state, value, min, max); - - chart.data('data-percent', pcent); - var size = state.chartWidth(); var stroke = Math.floor(size / 22); if(stroke < 3) stroke = 2; @@ -5762,7 +7138,7 @@ var NETDATA = window.NETDATA || {}; var unittop = Math.round(valuetop + (valuefontsize + unitfontsize) + (size / 40)); state.tmp.easyPieChartUnits = document.createElement('span'); state.tmp.easyPieChartUnits.className = 'easyPieChartUnits'; - state.tmp.easyPieChartUnits.innerText = state.units; + state.tmp.easyPieChartUnits.innerText = state.units_current; state.tmp.easyPieChartUnits.style.fontSize = unitfontsize + 'px'; state.tmp.easyPieChartUnits.style.top = unittop.toString() + 'px'; state.element_chart.appendChild(state.tmp.easyPieChartUnits); @@ -5777,6 +7153,9 @@ var NETDATA = window.NETDATA || {}; barColor = tmp; } + var pcent = NETDATA.easypiechartPercentFromValueMinMax(state, value, min, max); + chart.data('data-percent', pcent); + chart.easyPieChart({ barColor: barColor, trackColor: NETDATA.dataAttribute(state.element, 'easypiechart-trackcolor', NETDATA.themes.current.easypiechart_track), @@ -5801,6 +7180,16 @@ var NETDATA = window.NETDATA || {}; if(animate === false) state.tmp.easyPieChart_instance.disableAnimation(); state.tmp.easyPieChart_instance.update(pcent); if(animate === false) state.tmp.easyPieChart_instance.enableAnimation(); + + state.legendSetUnitsString = function(units) { + if(typeof state.tmp.easyPieChartUnits !== 'undefined') + state.tmp.easyPieChartUnits.innerText = units; + }; + state.legendShowUndefined = function() { + if(typeof state.tmp.easyPieChart_instance !== 'undefined') + NETDATA.easypiechartClearSelection(state); + }; + return true; }; @@ -5861,6 +7250,8 @@ var NETDATA = window.NETDATA || {}; else if(min === max) max = min + 1; + state.legendFormatValueDecimalsFromMinMax(min, max); + // gauge.js has an issue if the needle // is smaller than min or larger than max // when we set the new values @@ -5901,8 +7292,8 @@ var NETDATA = window.NETDATA || {}; NETDATA.gaugeClearSelection = function(state) { if(typeof state.tmp.gaugeEvent !== 'undefined') { - if(state.tmp.gaugeEvent.timer !== undefined) { - clearTimeout(state.tmp.gaugeEvent.timer); + if(state.tmp.gaugeEvent.timer) { + NETDATA.timeout.clear(state.tmp.gaugeEvent.timer); } state.tmp.gaugeEvent.timer = undefined; @@ -5955,10 +7346,10 @@ var NETDATA = window.NETDATA || {}; if(state.tmp.gaugeEvent.timer === undefined) { NETDATA.gaugeAnimation(state, false); - state.tmp.gaugeEvent.timer = setTimeout(function() { + state.tmp.gaugeEvent.timer = NETDATA.timeout.set(function() { state.tmp.gaugeEvent.timer = undefined; NETDATA.gaugeSet(state, state.tmp.gaugeEvent.value, state.tmp.gaugeEvent.min, state.tmp.gaugeEvent.max); - }, NETDATA.options.current.charts_selection_animation_delay); + }, 0); } return true; @@ -5968,10 +7359,8 @@ var NETDATA = window.NETDATA || {}; var value, min, max; if(NETDATA.globalPanAndZoom.isActive() === true || state.isAutoRefreshable() === false) { - value = 0; - min = 0; - max = 1; NETDATA.gaugeSetLabels(state, null, null, null); + state.tmp.gauge_instance.set(0); } else { value = data.result[0]; @@ -5985,10 +7374,10 @@ var NETDATA = window.NETDATA || {}; if(state.tmp.gaugeMin === null && min > 0) min = 0; if(state.tmp.gaugeMax === null && max < 0) max = 0; + NETDATA.gaugeSet(state, value, min, max); NETDATA.gaugeSetLabels(state, value, min, max); } - NETDATA.gaugeSet(state, value, min, max); return true; }; @@ -6003,7 +7392,7 @@ var NETDATA = window.NETDATA || {}; var strokeColor = NETDATA.dataAttribute(state.element, 'gauge-stroke-color', NETDATA.themes.current.gauge_stroke); var startColor = NETDATA.dataAttribute(state.element, 'gauge-start-color', state.chartCustomColors()[0]); var stopColor = NETDATA.dataAttribute(state.element, 'gauge-stop-color', void 0); - var generateGradient = NETDATA.dataAttributeBoolean(state.element, 'gauge-generate-gradient', false); + var generateGradient = NETDATA.dataAttribute(state.element, 'gauge-generate-gradient', false); if(min === null) { min = NETDATA.commonMin.get(state); @@ -6122,7 +7511,7 @@ var NETDATA = window.NETDATA || {}; var unitfontsize = Math.round(titlefontsize * 0.9); state.tmp.gaugeChartUnits = document.createElement('span'); state.tmp.gaugeChartUnits.className = 'gaugeChartUnits'; - state.tmp.gaugeChartUnits.innerText = state.units; + state.tmp.gaugeChartUnits.innerText = state.units_current; state.tmp.gaugeChartUnits.style.fontSize = unitfontsize + 'px'; state.element_chart.appendChild(state.tmp.gaugeChartUnits); @@ -6161,6 +7550,20 @@ var NETDATA = window.NETDATA || {}; NETDATA.gaugeSet(state, value, min, max); NETDATA.gaugeSetLabels(state, value, min, max); NETDATA.gaugeAnimation(state, true); + + state.legendSetUnitsString = function(units) { + if(typeof state.tmp.gaugeChartUnits !== 'undefined') { + state.tmp.gaugeChartUnits.innerText = units; + state.tmp.___gaugeOld__.valueLabel = null; + state.tmp.___gaugeOld__.minLabel = null; + state.tmp.___gaugeOld__.maxLabel = null; + } + }; + state.legendShowUndefined = function() { + if(typeof state.tmp.gauge_instance !== 'undefined') + NETDATA.gaugeClearSelection(state); + }; + return true; }; @@ -6173,7 +7576,7 @@ var NETDATA = window.NETDATA || {}; create: NETDATA.dygraphChartCreate, update: NETDATA.dygraphChartUpdate, resize: function(state) { - if(typeof state.tmp.dygraph_instance.resize === 'function') + if(typeof state.tmp.dygraph_instance !== 'undefined' && typeof state.tmp.dygraph_instance.resize === 'function') state.tmp.dygraph_instance.resize(); }, setSelection: NETDATA.dygraphSetSelection, @@ -6394,7 +7797,7 @@ var NETDATA = window.NETDATA || {}; NETDATA.requiredJs = [ { - url: NETDATA.serverDefault + 'lib/bootstrap-3.3.7.min.js', + url: NETDATA.serverStatic + 'lib/bootstrap-3.3.7.min.js', async: false, isAlreadyLoaded: function() { // check if bootstrap is loaded @@ -6406,7 +7809,12 @@ var NETDATA = window.NETDATA || {}; } }, { - url: NETDATA.serverDefault + 'lib/perfect-scrollbar-0.6.15.min.js', + url: NETDATA.serverStatic + 'lib/fontawesome-all-5.0.1.min.js', + async: true, + isAlreadyLoaded: function() { return false; } + }, + { + url: NETDATA.serverStatic + 'lib/perfect-scrollbar-0.6.15.min.js', isAlreadyLoaded: function() { return false; } } ]; @@ -6419,10 +7827,6 @@ var NETDATA = window.NETDATA || {}; } }, { - url: NETDATA.serverDefault + 'css/font-awesome.min.css?v4.7.0', - isAlreadyLoaded: function() { return false; } - }, - { url: NETDATA.themes.current.dashboard_css, isAlreadyLoaded: function() { return false; } } @@ -6619,7 +8023,7 @@ var NETDATA = window.NETDATA || {}; body: entry.hostname + ' - ' + entry.chart + ' (' + entry.family + ') - ' + status + ': ' + entry.info, tag: tag, requireInteraction: interaction, - icon: NETDATA.serverDefault + icon, + icon: NETDATA.serverStatic + icon, data: data }); @@ -6753,6 +8157,9 @@ var NETDATA = window.NETDATA || {}; }, update_forever: function() { + if(netdataShowAlarms !== true || netdataSnapshotData !== null) + return; + NETDATA.alarms.get('active', function(data) { if(data !== null) { NETDATA.alarms.current = data; diff --git a/web/dashboard.slate.css b/web/dashboard.slate.css index 7445d532..00e0d0dc 100644 --- a/web/dashboard.slate.css +++ b/web/dashboard.slate.css @@ -58,6 +58,8 @@ code { display: inline-block; overflow: hidden; + transform: translate3d(0,0,0); + /* required for child elements to have absolute position */ position: relative; @@ -68,6 +70,8 @@ code { display: inline-block; overflow: hidden; + transform: translate3d(0,0,0); + /* required for child elements to have absolute position */ position: relative; @@ -84,6 +88,8 @@ code { display: inline-block; overflow: hidden; + transform: translate3d(0,0,0); + /* required for child elements to have absolute position */ position: relative; @@ -107,6 +113,8 @@ code { display: inline-block; overflow: hidden; + transform: translate3d(0,0,0); + /* fix minimum scrollbar issue in firefox */ min-height: 99px; @@ -122,9 +130,9 @@ code { bottom: 0px; right: 0px; height: 15px; - width: 30px; + width: 20px; background-color: #272b30; - font-size: 12px; + font-size: 15px; vertical-align: middle; line-height: 15px; cursor: ns-resize; @@ -300,6 +308,7 @@ code { white-space: nowrap; display: inline-block; cursor: pointer; + -webkit-print-color-adjust: exact; } .netdata-legend-value { diff --git a/web/dashboard_info.js b/web/dashboard_info.js index bb2f9599..a3c48640 100644 --- a/web/dashboard_info.js +++ b/web/dashboard_info.js @@ -9,142 +9,142 @@ var netdataDashboard = window.netdataDashboard || {}; netdataDashboard.menu = { 'system': { title: 'System Overview', - icon: '<i class="fa fa-bookmark" aria-hidden="true"></i>', + icon: '<i class="fas fa-bookmark"></i>', info: 'Overview of the key system metrics.' }, 'services': { title: 'systemd Services', - icon: '<i class="fa fa-cogs" aria-hidden="true"></i>', + icon: '<i class="fas fa-cogs"></i>', info: 'Resources utilization of systemd services. netdata monitors all systemd services via cgroups (the resources accounting used by containers). ' }, 'ap': { title: 'Access Points', - icon: '<i class="fa fa-wifi" aria-hidden="true"></i>', + icon: '<i class="fas fa-wifi"></i>', info: 'Performance metrics for the access points (i.e. wireless interfaces in AP mode) found on the system.' }, 'tc': { title: 'Quality of Service', - icon: '<i class="fa fa-globe" aria-hidden="true"></i>', + icon: '<i class="fas fa-globe"></i>', info: 'Netdata collects and visualizes <code>tc</code> class utilization using its <a href="https://github.com/firehol/netdata/blob/master/plugins.d/tc-qos-helper.sh" target="_blank">tc-helper plugin</a>. If you also use <a href="http://firehol.org/#fireqos" target="_blank">FireQOS</a> for setting up QoS, netdata automatically collects interface and class names. If your QoS configuration includes overheads calculation, the values shown here will include these overheads (the total bandwidth for the same interface as reported in the Network Interfaces section, will be lower than the total bandwidth reported here). QoS data collection may have a slight time difference compared to the interface (QoS data collection uses a BASH script, so a shift in data collection of a few milliseconds should be justified).' }, 'net': { title: 'Network Interfaces', - icon: '<i class="fa fa-share-alt" aria-hidden="true"></i>', + icon: '<i class="fas fa-share-alt"></i>', info: 'Performance metrics for network interfaces.' }, 'ipv4': { title: 'IPv4 Networking', - icon: '<i class="fa fa-cloud" aria-hidden="true"></i>', + icon: '<i class="fas fa-cloud"></i>', info: 'Metrics for the IPv4 stack of the system. <a href="https://en.wikipedia.org/wiki/IPv4" target="_blank">Internet Protocol version 4 (IPv4)</a> is the fourth version of the Internet Protocol (IP). It is one of the core protocols of standards-based internetworking methods in the Internet. IPv4 is a connectionless protocol for use on packet-switched networks. It operates on a best effort delivery model, in that it does not guarantee delivery, nor does it assure proper sequencing or avoidance of duplicate delivery. These aspects, including data integrity, are addressed by an upper layer transport protocol, such as the Transmission Control Protocol (TCP).' }, 'ipv6': { title: 'IPv6 Networking', - icon: '<i class="fa fa-cloud" aria-hidden="true"></i>', + icon: '<i class="fas fa-cloud"></i>', info: 'Metrics for the IPv6 stack of the system. <a href="https://en.wikipedia.org/wiki/IPv6" target="_blank">Internet Protocol version 6 (IPv6)</a> is the most recent version of the Internet Protocol (IP), the communications protocol that provides an identification and location system for computers on networks and routes traffic across the Internet. IPv6 was developed by the Internet Engineering Task Force (IETF) to deal with the long-anticipated problem of IPv4 address exhaustion. IPv6 is intended to replace IPv4.' }, 'ipvs': { title: 'IP Virtual Server', - icon: '<i class="fa fa-eye" aria-hidden="true"></i>', + icon: '<i class="fas fa-eye"></i>', info: '<a href="http://www.linuxvirtualserver.org/software/ipvs.html" target="_blank">IPVS (IP Virtual Server)</a> implements transport-layer load balancing inside the Linux kernel, so called Layer-4 switching. IPVS running on a host acts as a load balancer at the front of a cluster of real servers, it can direct requests for TCP/UDP based services to the real servers, and makes services of the real servers to appear as a virtual service on a single IP address.' }, 'netfilter': { title: 'Firewall (netfilter)', - icon: '<i class="fa fa-shield" aria-hidden="true"></i>', + icon: '<i class="fas fa-shield-alt"></i>', info: 'Performance metrics of the netfilter components.' }, 'ipfw': { title: 'Firewall (ipfw)', - icon: '<i class="fa fa-shield" aria-hidden="true"></i>', + icon: '<i class="fas fa-shield-alt"></i>', info: 'Counters and memory usage for the ipfw rules.' }, 'cpu': { title: 'CPUs', - icon: '<i class="fa fa-bolt" aria-hidden="true"></i>', + icon: '<i class="fas fa-bolt"></i>', info: 'Detailed information for each CPU of the system. A summary of the system for all CPUs can be found at the <a href="#menu_system">System Overview</a> section.' }, 'mem': { title: 'Memory', - icon: '<i class="fa fa-bolt" aria-hidden="true"></i>', + icon: '<i class="fas fa-microchip"></i>', info: 'Detailed information about the memory management of the system.' }, 'disk': { title: 'Disks', - icon: '<i class="fa fa-folder" aria-hidden="true"></i>', + icon: '<i class="fas fa-hdd"></i>', info: 'Charts with performance information for all the system disks. Special care has been given to present disk performance metrics in a way compatible with <code>iostat -x</code>. netdata by default prevents rendering performance charts for individual partitions and unmounted virtual disks. Disabled charts can still be enabled by configuring the relative settings in the netdata configuration file.' }, 'sensors': { title: 'Sensors', - icon: '<i class="fa fa-leaf" aria-hidden="true"></i>', + icon: '<i class="fas fa-leaf"></i>', info: 'Readings of the configured system sensors.' }, 'ipmi': { title: 'IPMI', - icon: '<i class="fa fa-leaf" aria-hidden="true"></i>', + icon: '<i class="fas fa-leaf"></i>', info: 'The Intelligent Platform Management Interface (IPMI) is a set of computer interface specifications for an autonomous computer subsystem that provides management and monitoring capabilities independently of the host system\'s CPU, firmware (BIOS or UEFI) and operating system.' }, 'samba': { title: 'Samba', - icon: "<i class=\"fa fa-folder-open\" aria-hidden=\"true\"></i>", + icon: '<i class="fas fa-folder-open"></i>', info: 'Performance metrics of the Samba file share operations of this system. Samba is a implementation of Windows services, including Windows SMB protocol file shares.' }, 'nfsd': { title: 'NFS Server', - icon: '<i class="fa fa-folder-open" aria-hidden="true"></i>', + icon: '<i class="fas fa-folder-open"></i>', info: 'Performance metrics of the Network File Server. NFS is a distributed file system protocol, allowing a user on a client computer to access files over a network, much like local storage is accessed. NFS, like many other protocols, builds on the Open Network Computing Remote Procedure Call (ONC RPC) system. The NFS is an open standard defined in Request for Comments (RFC).' }, 'nfs': { title: 'NFS Client', - icon: '<i class="fa fa-folder-open" aria-hidden="true"></i>', + icon: '<i class="fas fa-folder-open"></i>', info: 'Performance metrics of the NFS operations of this system, acting as an NFS client.' }, 'zfs': { title: 'ZFS filesystem', - icon: '<i class="fa fa-folder-open" aria-hidden="true"></i>', + icon: '<i class="fas fa-folder-open"></i>', info: 'Performance metrics of the ZFS filesystem. The following charts visualize all metrics reported by <a href="https://github.com/zfsonlinux/zfs/blob/master/cmd/arcstat/arcstat.py" target="_blank">arcstat.py</a> and <a href="https://github.com/zfsonlinux/zfs/blob/master/cmd/arc_summary/arc_summary.py" target="_blank">arc_summary.py</a>.' }, 'apps': { title: 'Applications', - icon: '<i class="fa fa-heartbeat" aria-hidden="true"></i>', + icon: '<i class="fas fa-heartbeat"></i>', info: 'Per application statistics are collected using netdata\'s <code>apps.plugin</code>. This plugin walks through all processes and aggregates statistics for applications of interest, defined in <code>/etc/netdata/apps_groups.conf</code> (the default is <a href="https://github.com/firehol/netdata/blob/master/conf.d/apps_groups.conf" target="_blank">here</a>). The plugin internally builds a process tree (much like <code>ps fax</code> does), and groups processes together (evaluating both child and parent processes) so that the result is always a chart with a predefined set of dimensions (of course, only application groups found running are reported). The reported values are compatible with <code>top</code>, although the netdata plugin counts also the resources of exited children (unlike <code>top</code> which shows only the resources of the currently running processes). So for processes like shell scripts, the reported values include the resources used by the commands these scripts run within each timeframe.', height: 1.5 }, 'users': { title: 'Users', - icon: '<i class="fa fa-user" aria-hidden="true"></i>', + icon: '<i class="fas fa-user"></i>', info: 'Per user statistics are collected using netdata\'s <code>apps.plugin</code>. This plugin walks through all processes and aggregates statistics per user. The reported values are compatible with <code>top</code>, although the netdata plugin counts also the resources of exited children (unlike <code>top</code> which shows only the resources of the currently running processes). So for processes like shell scripts, the reported values include the resources used by the commands these scripts run within each timeframe.', height: 1.5 }, 'groups': { title: 'User Groups', - icon: '<i class="fa fa-users" aria-hidden="true"></i>', + icon: '<i class="fas fa-users"></i>', info: 'Per user group statistics are collected using netdata\'s <code>apps.plugin</code>. This plugin walks through all processes and aggregates statistics per user group. The reported values are compatible with <code>top</code>, although the netdata plugin counts also the resources of exited children (unlike <code>top</code> which shows only the resources of the currently running processes). So for processes like shell scripts, the reported values include the resources used by the commands these scripts run within each timeframe.', height: 1.5 }, 'netdata': { title: 'Netdata Monitoring', - icon: '<i class="fa fa-bar-chart" aria-hidden="true"></i>', + icon: '<i class="fas fa-chart-bar"></i>', info: 'Performance metrics for the operation of netdata itself and its plugins.' }, @@ -155,163 +155,175 @@ netdataDashboard.menu = { 'cgroup': { title: '', - icon: '<i class="fa fa-th" aria-hidden="true"></i>', + icon: '<i class="fas fa-th"></i>', info: 'Container resource utilization metrics. Netdata reads this information from <b>cgroups</b> (abbreviated from <b>control groups</b>), a Linux kernel feature that limits and accounts resource usage (CPU, memory, disk I/O, network, etc.) of a collection of processes. <b>cgroups</b> together with <b>namespaces</b> (that offer isolation between processes) provide what we usually call: <b>containers</b>.' }, 'cgqemu': { title: '', - icon: '<i class="fa fa-th-large" aria-hidden="true"></i>', + icon: '<i class="fas fa-th-large"></i>', info: 'QEMU virtual machine resource utilization metrics. QEMU (short for Quick Emulator) is a free and open-source hosted hypervisor that performs hardware virtualization.' }, 'fping': { title: 'fping', - icon: '<i class="fa fa-exchange" aria-hidden="true"></i>', + icon: '<i class="fas fa-exchange-alt"></i>', info: 'Network latency statistics, via <b>fping</b>. <b>fping</b> is a program to send ICMP echo probes to network hosts, similar to <code>ping</code>, but much better performing when pinging multiple hosts. fping versions after 3.15 can be directly used as netdata plugins.' }, 'memcached': { title: 'memcached', - icon: '<i class="fa fa-database" aria-hidden="true"></i>', + icon: '<i class="fas fa-database"></i>', info: 'Performance metrics for <b>memcached</b>. Memcached is a general-purpose distributed memory caching system. It is often used to speed up dynamic database-driven websites by caching data and objects in RAM to reduce the number of times an external data source (such as a database or API) must be read.' }, 'mysql': { title: 'MySQL', - icon: '<i class="fa fa-database" aria-hidden="true"></i>', + icon: '<i class="fas fa-database"></i>', info: 'Performance metrics for <b>mysql</b>, the open-source relational database management system (RDBMS).' }, 'postgres': { title: 'Postgres', - icon: '<i class="fa fa-database" aria-hidden="true"></i>', + icon: '<i class="fas fa-database"></i>', info: 'Performance metrics for <b>PostgresSQL</b>, the object-relational database (ORDBMS).' }, 'redis': { title: 'Redis', - icon: '<i class="fa fa-database" aria-hidden="true"></i>', + icon: '<i class="fas fa-database"></i>', info: 'Performance metrics for <b>redis</b>. Redis (REmote DIctionary Server) is a software project that implements data structure servers. It is open-source, networked, in-memory, and stores keys with optional durability.' }, 'retroshare': { title: 'RetroShare', - icon: '<i class="fa fa-share-alt" aria-hidden="true"></i>', + icon: '<i class="fas fa-share-alt"></i>', info: 'Performance metrics for <b>RetroShare</b>. RetroShare is open source software for encrypted filesharing, serverless email, instant messaging, online chat, and BBS, based on a friend-to-friend network built on GNU Privacy Guard (GPG).' }, 'ipfs': { title: 'IPFS', - icon: '<i class="fa fa-folder-open" aria-hidden="true"></i>', + icon: '<i class="fas fa-folder-open"></i>', info: 'Performance metrics for the InterPlanetary File System (IPFS), a content-addressable, peer-to-peer hypermedia distribution protocol.' }, 'phpfpm': { title: 'PHP-FPM', - icon: '<i class="fa fa-eye" aria-hidden="true"></i>', + icon: '<i class="fas fa-eye"></i>', info: 'Performance metrics for <b>PHP-FPM</b>, an alternative FastCGI implementation for PHP.' }, 'postfix': { title: 'postfix', - icon: '<i class="fa fa-envelope" aria-hidden="true"></i>', + icon: '<i class="fas fa-envelope"></i>', info: undefined }, 'dovecot': { title: 'Dovecot', - icon: '<i class="fa fa-envelope" aria-hidden="true"></i>', + icon: '<i class="fas fa-envelope"></i>', info: undefined }, 'hddtemp': { title: 'HDD Temp', - icon: '<i class="fa fa-thermometer-full" aria-hidden="true"></i>', + icon: '<i class="fas fa-thermometer-half"></i>', info: undefined }, 'nginx': { title: 'nginx', - icon: '<i class="fa fa-eye" aria-hidden="true"></i>', + icon: '<i class="fas fa-eye"></i>', info: undefined }, 'apache': { title: 'Apache', - icon: '<i class="fa fa-eye" aria-hidden="true"></i>', + icon: '<i class="fas fa-eye"></i>', info: undefined }, 'lighttpd': { title: 'Lighttpd', - icon: '<i class="fa fa-eye" aria-hidden="true"></i>', + icon: '<i class="fas fa-eye"></i>', info: undefined }, 'web_log': { title: undefined, - icon: '<i class="fa fa-file-text-o" aria-hidden="true"></i>', + icon: '<i class="fas fa-file-alt"></i>', info: 'Information extracted from a server log file. <code>web_log</code> plugin incrementally parses the server log file to provide, in real-time, a break down of key server performance metrics. For web servers, an extended log file format may optionally be used (for <code>nginx</code> and <code>apache</code>) offering timing information and bandwidth for both requests and responses. <code>web_log</code> plugin may also be configured to provide a break down of requests per URL pattern (check <a href="https://github.com/firehol/netdata/blob/master/conf.d/python.d/web_log.conf" target="_blank"><code>/etc/netdata/python.d/web_log.conf</code></a>).' }, 'named': { title: 'named', - icon: '<i class="fa fa-tag" aria-hidden="true"></i>', + icon: '<i class="fas fa-tag"></i>', info: undefined }, 'squid': { title: 'squid', - icon: '<i class="fa fa-exchange" aria-hidden="true"></i>', + icon: '<i class="fas fa-exchange-alt"></i>', info: undefined }, 'nut': { title: 'UPS', - icon: '<i class="fa fa-battery-half" aria-hidden="true"></i>', + icon: '<i class="fas fa-battery-half"></i>', info: undefined }, 'apcupsd': { title: 'UPS', - icon: '<i class="fa fa-battery-half" aria-hidden="true"></i>', + icon: '<i class="fas fa-battery-half"></i>', info: undefined }, 'smawebbox': { title: 'Solar Power', - icon: '<i class="fa fa-sun-o" aria-hidden="true"></i>', + icon: '<i class="fas fa-sun"></i>', info: undefined }, 'fronius': { title: 'Fronius', - icon: '<i class="fa fa-sun-o" aria-hidden="true"></i>', + icon: '<i class="fas fa-sun"></i>', info: undefined }, 'stiebeleltron': { title: 'Stiebel Eltron', - icon: '<i class="fa fa-thermometer-full" aria-hidden="true"></i>', + icon: '<i class="fas fa-thermometer-half"></i>', info: undefined }, 'snmp': { title: 'SNMP', - icon: '<i class="fa fa-random" aria-hidden="true"></i>', + icon: '<i class="fas fa-random"></i>', info: undefined }, 'go_expvar': { title: 'Go - expvars', - icon: '<i class="fa fa-eye" aria-hidden="true"></i>', + icon: '<i class="fas fa-eye"></i>', info: 'Statistics about running Go applications exposed by the <a href="https://golang.org/pkg/expvar/" target="_blank">expvar package</a>.' }, 'chrony': { - icon: '<i class="fa fa-clock-o" aria-hidden="true"></i>', + icon: '<i class="fas fa-clock"></i>', info: 'chronyd parameters about the system’s clock performance.' + }, + + 'couchdb': { + icon: '<i class="fas fa-database"></i>', + info: 'Performance metrics for <b><a href="https://couchdb.apache.org/">CouchDB</a></b>, the open-source, JSON document-based database with an HTTP API and multi-master replication.' + }, + + + 'beanstalk': { + title: 'Beanstalkd', + icon: '<i class="fas fa-tasks"></i>', + info: 'Provides statistics on the <b><a href="http://kr.github.io/beanstalkd/">beanstalkd</a></b> server and any tubes available on that server using data pulled from beanstalkc' } }; @@ -434,6 +446,30 @@ netdataDashboard.submenu = { 'go_expvar.memstats': { title: 'Memory statistics', info: 'Go runtime memory statistics. See <a href="https://golang.org/pkg/runtime/#MemStats" target="_blank">runtime.MemStats</a> documentation for more info about each chart and the values.' + }, + + 'couchdb.dbactivity': { + title: 'DB activity', + info: 'Overall database reads and writes for the entire server. This includes any external HTTP traffic, as well as internal replication traffic performed in a cluster to ensure node consistency.' + }, + + 'couchdb.httptraffic': { + title: 'HTTP traffic breakdown', + info: 'All HTTP traffic, broken down by type of request (<tt>GET</tt>, <tt>PUT</tt>, <tt>POST</tt>, etc.) and response status code (<tt>200</tt>, <tt>201</tt>, <tt>4xx</tt>, etc.)<br/><br/>Any <tt>5xx</tt> errors here indicate a likely CouchDB bug; check the logfile for further information.' + }, + + 'couchdb.ops': { + title: 'Server operations' + }, + + 'couchdb.perdbstats': { + title: 'Per-DB statistics', + info: 'Statistics per database. This includes <a href="http://docs.couchdb.org/en/latest/api/database/common.html#get--db">3 size graphs per database</a>: active (the size of live data in the database), external (the uncompressed size of the database contents), and file (the size of the file on disk, exclusive of any views and indexes). It also includes the number of documents and number of deleted documents per database.' + }, + + 'couchdb.erlang': { + title: 'Erlang statistics', + info: 'Detailed information about the status of the Erlang VM that hosts CouchDB. These are intended for advanced users only. High values of the peak message queue (>10e6) generally indicate an overload condition.' } }; @@ -468,7 +504,18 @@ netdataDashboard.context = { }, 'system.io': { - info: 'Total Disk I/O, for all disks. You can get detailed information about each disk at the <a href="#menu_disk">Disks</a> section and per application Disk usage at the <a href="#menu_apps">Applications Monitoring</a> section.' + info: function(os) { + var s = 'Total Disk I/O, for all physical disks. You can get detailed information about each disk at the <a href="#menu_disk">Disks</a> section and per application Disk usage at the <a href="#menu_apps">Applications Monitoring</a> section.'; + + if(os === 'linux') + return s + ' Physical are all the disks that are listed in <code>/sys/block</code>, but do not exist in <code>/sys/devices/virtual/block</code>.'; + else + return s; + } + }, + + 'system.pgpgio': { + info: 'Memory paged from/to disk. This is usually the total disk I/O of the system.' }, 'system.swapio': { @@ -518,6 +565,17 @@ netdataDashboard.context = { info: 'Idle jitter is calculated by netdata. A thread is spawned that requests to sleep for a few microseconds. When the system wakes it up, it measures how many microseconds have passed. The difference between the requested and the actual duration of the sleep, is the <b>idle jitter</b>. This number is useful in real-time environments, where CPU jitter can affect the quality of the service (like VoIP media gateways).' }, + 'system.net': { + info: function(os) { + var s = 'Total bandwidth of all physical network interfaces. This does not include <code>lo</code>, VPNs, network bridges, IFB devices, bond interfaces, etc. Only the bandwidth of physical network interfaces is aggregated.'; + + if(os === 'linux') + return s + ' Physical are all the network interfaces that are listed in <code>/proc/net/dev</code>, but do not exist in <code>/sys/devices/virtual/net</code>.'; + else + return s; + } + }, + 'system.ipv4': { info: 'Total IPv4 Traffic.' }, @@ -1151,6 +1209,63 @@ netdataDashboard.context = { } ] }, + + // ------------------------------------------------------------------------ + // beanstalkd + // system charts + 'beanstalk.cpu_usage': { + info: 'Amount of CPU Time for user and system used by beanstalkd.' + }, + + // This is also a per-tube stat + 'beanstalk.jobs_rate': { + info: 'The rate of jobs processed by the beanstalkd served.' + }, + + 'beanstalk.connections_rate': { + info: 'Tthe rate of connections opened to beanstalkd.' + }, + + 'beanstalk.commands_rate': { + info: 'The rate of commands received by beanstalkd.' + }, + + 'beanstalk.current_tubes': { + info: 'Total number of current tubes on the server including the default tube (which always exists).' + }, + + 'beanstalk.current_jobs': { + info: 'Current number of jobs in all tubes grouped by status: urgent, ready, reserved, delayed and buried.' + }, + + 'beanstalk.current_connections': { + info: 'Current number of connections group by connection type: written, producers, workers, waiting.' + }, + + 'beanstalk.binlog': { + info: 'The rate of records <code>written</code> to binlog and <code>migrated</code> as part of compaction.' + }, + + 'beanstalk.uptime': { + info: 'Total time beanstalkd server has been up for.' + }, + + // tube charts + 'beanstalk.jobs': { + info: 'Number of jobs currently in the tube grouped by status: urgent, ready, reserved, delayed and buried.' + }, + + 'beanstalk.connections': { + info: 'The current number of connections to this tube grouped by connection type; using, waiting and watching.' + }, + + 'beanstalk.commands': { + info: 'The rate of <code>delete</code> and <code>pause</code> commands executed by beanstalkd.' + }, + + 'beanstalk.pause': { + info: 'Shows info on how long the tube has been paused for, and how long is left remaining on the pause.' + }, // ------------------------------------------------------------------------ // web_log @@ -1534,5 +1649,17 @@ netdataDashboard.context = { info: 'The estimated error bound on the frequency.', height: 0.5, colors: NETDATA.colors[5] + }, + + 'couchdb.active_tasks': { + info: 'Active tasks running on this CouchDB <b>cluster</b>. Four types of tasks currently exist: indexer (view building), replication, database compaction and view compaction.' + }, + + 'couchdb.replicator_jobs': { + info: 'Detailed breakdown of any replication jobs in progress on this node. For more information, see the <a href="http://docs.couchdb.org/en/latest/replication/replicator.html">replicator documentation</a>.' + }, + + 'couchdb.open_files': { + info: 'Count of all files held open by CouchDB. If this value seems pegged at 1024 or 4096, your server process is probably hitting the open file handle limit and <a href="http://docs.couchdb.org/en/latest/maintenance/performance.html#pam-and-ulimit">needs to be increased.</a>' } }; diff --git a/web/index.html b/web/index.html index cd8239d2..e3c03909 100644 --- a/web/index.html +++ b/web/index.html @@ -46,6 +46,12 @@ <meta name="twitter:image" content="https://cloud.githubusercontent.com/assets/2662304/14092712/93b039ea-f551-11e5-822c-beadbf2b2a2e.gif" /> <style> + + /* force the vertical window scrollbar */ + html { + overflow-y: scroll; + } + /* prevent body from hiding under the navbar */ body { padding-top: 50px; @@ -65,6 +71,42 @@ text-align: center; } + .navbar-highlight { + display: none; + position: fixed; + margin-top: 5px; + height: 26px; + width: 100%; + text-align: center; + overflow: hidden; + z-index: 30; + pointer-events: none !important; + } + + .navbar-highlight-content { + position: relative; + display: inline-block; + margin: 0 auto; + height: 26px; + min-width: 500px; + background-color:rgba(0, 0, 0, 0.7); + padding-top: 2px; + padding-bottom: 2px; + padding-left: 15px; + padding-right: 15px; + border-radius:10px; + color: lightgrey; + pointer-events: auto !important; + } + + .navbar-highlight-bar { + cursor: pointer; + } + .navbar-highlight-button-right { + cursor: pointer; + padding-left: 10px; + } + .modal-wide .modal-dialog { width: 80%; } @@ -105,7 +147,12 @@ padding: 10px; } - .chart-message { + .dashboard-submenu-info { + display: block; + margin-top: 10px; + } + + .dashboard-context-info { display: block; margin-top: 10px; } @@ -265,6 +312,11 @@ max-height: 80vh; overflow-x: hidden; } + .scrollable-menu-50 { + height: auto; + max-height: 50vh; + overflow-x: hidden; + } /* Back to top (hidden on mobile) */ .back-to-top, @@ -300,6 +352,70 @@ display: none; } + .dashboard-section-container { + display: block; + width: 100%; + page-break-before: auto; + page-break-after: auto; + page-break-inside: auto; + } + + .dashboard-print-row { + display: block; + width: 100%; + page-break-before: auto; + page-break-after: auto; + page-break-inside: avoid; + } + + .netdata-chartblock-container { + display: inline-block; + } + + /* https://github.com/seiyria/bootstrap-slider/issues/746 */ + .tooltip { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + } + + @media print { + body { + overflow: visible !important; + -webkit-print-color-adjust: exact; + page-break-inside: auto; + page-break-before: auto; + page-break-after: auto; + } + + .dashboard-section { + page-break-inside: auto; + page-break-before: auto; + page-break-after: auto; + } + + .dashboard-subsection { + page-break-before: avoid; + page-break-after: auto; + page-break-inside: auto; + } + + .charts-body { + padding-left: 0%; + padding-right: 0%; + display: block; + page-break-inside: auto; + page-break-before: auto; + page-break-after: auto; + } + + .back-to-top, + .dashboard-theme-toggle { + display: block; + } + } + @media (min-width: 768px) { .charts-body { padding-left: 0%; @@ -405,12 +521,18 @@ <!-- check which theme to use --> <script type="text/javascript"> + // netdata snapshot data + var netdataSnapshotData = null; + // enable alarms checking and notifications var netdataShowAlarms = true; // enable registry updates var netdataRegistry = true; + // control the welcome modal and analytics + var this_is_demo = null; + // -------------------------------------------------------------------- // urlOptions @@ -418,10 +540,15 @@ hash: '#', theme: null, help: null, + mode: 'live', // 'live', 'print' update_always: false, pan_and_zoom: false, + server: null, after: 0, before: 0, + highlight: false, + highlight_after: 0, + highlight_before: 0, nowelcome: false, show_alarms: false, chart: null, @@ -436,12 +563,17 @@ return typeof this[property] !== 'undefined'; }, - genHash: function() { + genHash: function(forReload) { var hash = urlOptions.hash; if(urlOptions.pan_and_zoom === true) { hash += ';after=' + urlOptions.after.toString() + - ';before=' + urlOptions.before.toString(); + ';before=' + urlOptions.before.toString(); + } + + if(urlOptions.highlight === true) { + hash += ';highlight_after=' + urlOptions.highlight_after.toString() + + ';highlight_before=' + urlOptions.highlight_before.toString(); } if(urlOptions.theme !== null) @@ -453,6 +585,12 @@ if(urlOptions.update_always === true) hash += ';update_always=true'; + if(forReload === true && urlOptions.server !== null) + hash += ';server=' + urlOptions.server.toString(); + + if(urlOptions.mode !== 'live') + hash += ';mode=' + urlOptions.mode; + return hash; }, @@ -471,7 +609,7 @@ } } - var booleans = [ 'nowelcome', 'show_alarms', 'pan_and_zoom', 'update_always' ]; + var booleans = [ 'nowelcome', 'show_alarms', 'update_always' ]; len = booleans.length; while(len--) { if(urlOptions[booleans[len]] === 'true' || urlOptions[booleans[len]] === true || urlOptions[booleans[len]] === '1' || urlOptions[booleans[len]] === 1) @@ -480,6 +618,27 @@ urlOptions[booleans[len]] = false; } + var numeric = [ 'after', 'before', 'highlight_after', 'highlight_before' ]; + len = numeric.length; + while(len--) { + if(typeof urlOptions[numeric[len]] === 'string') { + try { + urlOptions[numeric[len]] = parseInt(urlOptions[numeric[len]]); + } + catch(e) { + console.log('failed to parse URL hash parameter ' + numeric[len]); + urlOptions[numeric[len]] = 0; + } + } + } + + if(urlOptions.server !== null && urlOptions.server !== '') { + netdataServerStatic = document.location.origin.toString() + document.location.pathname.toString(); + netdataServer = urlOptions.server; + } + else + urlOptions.server = null; + if(urlOptions.before > 0 && urlOptions.after > 0) { urlOptions.pan_and_zoom = true; urlOptions.nowelcome = true; @@ -487,20 +646,111 @@ else urlOptions.pan_and_zoom = false; + if(urlOptions.highlight_before > 0 && urlOptions.highlight_after > 0) { + urlOptions.highlight = true; + } + else + urlOptions.highlight = false + + switch(urlOptions.mode) { + case 'print': + urlOptions.theme = 'white'; + urlOptions.welcome = false; + urlOptions.help = false; + urlOptions.show_alarms = false; + + if(urlOptions.pan_and_zoom === false) { + urlOptions.pan_and_zoom = true; + urlOptions.before = Date.now(); + urlOptions.after = urlOptions.before - 600000; + } + + netdataShowAlarms = false; + netdataRegistry = false; + this_is_demo = false; + break; + + case 'live': + default: + urlOptions.mode = 'live'; + break; + } + // console.log(urlOptions); }, hashUpdate: function() { - history.replaceState(null, '', urlOptions.genHash()); + history.replaceState(null, '', urlOptions.genHash(true)); }, netdataPanAndZoomCallback: function(status, after, before) { - urlOptions.pan_and_zoom = status; - urlOptions.after = after; - urlOptions.before = before; + //console.log(1); + //console.log(new Error().stack); + + if(netdataSnapshotData === null) { + urlOptions.pan_and_zoom = status; + urlOptions.after = after; + urlOptions.before = before; + urlOptions.hashUpdate(); + } + }, + + netdataHighlightCallback: function(status, after, before) { + //console.log(2); + //console.log(new Error().stack); + + if(status === true && (after === null || before === null || after <= 0 || before <= 0 || after >= before)) { + status = false; + after = 0; + before = 0; + } + + if(netdataSnapshotData === null) + urlOptions.highlight = status; + else + urlOptions.highlight = false; + + urlOptions.highlight_after = Math.round(after); + urlOptions.highlight_before = Math.round(before); urlOptions.hashUpdate(); - } + var show_eye = NETDATA.globalChartUnderlay.hasViewport(); + + if(status === true && after > 0 && before > 0 && after < before) { + var d1 = NETDATA.dateTime.localeDateString(after); + var d2 = NETDATA.dateTime.localeDateString(before); + if(d1 === d2) d2 = ''; + document.getElementById('navbar-highlight-content').innerHTML = + ((show_eye === true)?'<span class="navbar-highlight-bar highlight-tooltip" onclick="urlOptions.showHighlight();" title="restore the highlighted view" data-toggle="tooltip" data-placement="bottom">':'<span>').toString() + + 'highlighted time-frame' + + ' <b>' + d1 + ' <code>' + NETDATA.dateTime.localeTimeString(after) + '</code></b> to ' + + ' <b>' + d2 + ' <code>' + NETDATA.dateTime.localeTimeString(before) + '</code></b>, ' + + 'duration <b>' + NETDATA.seconds4human(Math.round((before - after) / 1000)) + '</b>' + + '</span>' + + '<span class="navbar-highlight-button-right highlight-tooltip" onclick="urlOptions.clearHighlight();" title="clear the highlighted time-frame" data-toggle="tooltip" data-placement="bottom"><i class="fas fa-times"></i></span>'; + + $('.navbar-highlight').show(); + + $('.highlight-tooltip').tooltip({ + html: true, + delay: {show: 500, hide: 0}, + container: 'body' + }); + } + else + $('.navbar-highlight').hide(); + }, + + clearHighlight: function() { + NETDATA.globalChartUnderlay.clear(); + + if(NETDATA.globalPanAndZoom.isActive() === true) + NETDATA.globalPanAndZoom.clearMaster(); + }, + + showHighlight: function() { + NETDATA.globalChartUnderlay.focus(); + } }; urlOptions.parseHash(); @@ -521,6 +771,7 @@ localStorageTested = true; } catch (e) { + console.log(e); localStorageTested = false; } } @@ -536,8 +787,13 @@ try { if(localStorageTest() === true) ret = localStorage.getItem(name); + else + console.log('localStorage is not available'); + } + catch(error) { + console.log(error); + return null; } - catch(error) {} if(typeof ret === 'undefined' || ret === null) return null; @@ -555,12 +811,17 @@ return true; } } - catch(error) {} + catch(error) { + console.log(error); + } return false; } function getTheme(def) { + if(urlOptions.mode === 'print') + return 'white'; + var ret = loadLocalStorage('netdataTheme'); if(typeof ret === 'undefined' || ret === null || ret === 'undefined') return def; @@ -569,6 +830,8 @@ } function setTheme(theme) { + if(urlOptions.mode === 'print') return false; + if(theme === netdataTheme) return false; return saveLocalStorage('netdataTheme', theme); } @@ -600,7 +863,7 @@ var x = 0, y = -1, n = 0, i, j; while (i = (j = t.charAt(x++)).charCodeAt(0)) { - var m = (i === 46 || (i >= 48 && i <= 57)); + var m = (i >= 48 && i <= 57); if (m !== n) { tz[++y] = ""; n = m; @@ -629,6 +892,35 @@ } // -------------------------------------------------------------------- + // saving files to client + + function saveTextToClient(data, filename) { + var blob = new Blob( [ data ], { + type: 'application/octet-stream' + }); + + var url = URL.createObjectURL( blob ); + var link = document.createElement( 'a' ); + link.setAttribute( 'href', url ); + link.setAttribute( 'download', filename ); + + var el = document.getElementById('hiddenDownloadLinks'); + el.innerHTML = ''; + el.appendChild(link); + + setTimeout(function(){ + el.removeChild(link); + URL.revokeObjectURL(url); + }, 60); + + link.click(); + } + + function saveObjectToClient(data, filename) { + saveTextToClient(JSON.stringify(data), filename); + } + + // -------------------------------------------------------------------- // registry call back to render my-netdata menu var netdataRegistryCallback = function(machines_array) { @@ -641,7 +933,7 @@ // there are mirrored hosts here el += '<li><a href="#" onClick="return false;" style="color: #666;" target="_blank">databases available on this host</a></li>'; - a1 += '<li><a href="#" onClick="return false;"><i class="fa fa-info-circle" aria-hidden="true" style="color: #666;"></i></a></li>'; + a1 += '<li><a href="#" onClick="return false;"><i class="fas fa-info-circle" style="color: #666;"></i></a></li>'; var base = document.location.origin.toString() + document.location.pathname.toString(); if(base.endsWith("/host/" + options.hostname + "/")) @@ -669,8 +961,8 @@ icon = "window-restore"; } - el += '<li id="registry_server_hosted_' + len.toString() + '"><a class="registry_link" href="' + url + '" onClick="return gotoHostedModalHandler(\'' + url + '\');">' + hostname + '</a></li>'; - a1 += '<li id="registry_action_hosted_' + len.toString() + '"><a class="registry_link" href="' + url + '" onClick="return gotoHostedModalHandler(\'' + url + '\');"><i class="fa fa-' + icon + '" aria-hidden="true" style="color: #999;"></i></a></li>'; + el += '<li id="registry_server_hosted_' + len.toString() + '"><a class="registry_link" href="' + url + '#" onClick="return gotoHostedModalHandler(\'' + url + '\');">' + hostname + '</a></li>'; + a1 += '<li id="registry_action_hosted_' + len.toString() + '"><a class="registry_link" href="' + url + '#" onClick="return gotoHostedModalHandler(\'' + url + '\');"><i class="fas fa-' + icon + '" style="color: #999;"></i></a></li>'; hosted++; i++; } @@ -699,8 +991,8 @@ while(len--) { var u = machines[i++]; found++; - el += '<li id="registry_server_' + u.guid + '"><a class="registry_link" href="' + u.url + '" onClick="return gotoServerModalHandler(\'' + u.guid + '\');">' + u.name + '</a></li>'; - a1 += '<li id="registry_action_' + u.guid + '"><a href="#" onclick="deleteRegistryModalHandler(\'' + u.guid + '\',\'' + u.name + '\',\'' + u.url + '\'); return false;"><i class="fa fa-trash-o" aria-hidden="true" style="color: #999;"></i></a></li>'; + el += '<li id="registry_server_' + u.guid + '"><a class="registry_link" href="' + u.url + '#" onClick="return gotoServerModalHandler(\'' + u.guid + '\');">' + u.name + '</a></li>'; + a1 += '<li id="registry_action_' + u.guid + '"><a href="#" onclick="deleteRegistryModalHandler(\'' + u.guid + '\',\'' + u.name + '\',\'' + u.url + '\'); return false;"><i class="fas fa-trash" style="color: #999;"></i></a></li>'; } } @@ -736,7 +1028,7 @@ a1 += '<li role="separator" class="divider"></li>'; el += '<li><a href="https://github.com/firehol/netdata/wiki/mynetdata-menu-item" style="color: #999;" target="_blank">What is this?</a></li>'; - a1 += '<li><a href="#" style="color: #999;" onclick="switchRegistryModalHandler(); return false;"><i class="fa fa-sliders" aria-hidden="true" style="color: #999;"></i></a></li>' + a1 += '<li><a href="#" style="color: #999;" onclick="switchRegistryModalHandler(); return false;"><i class="fas fa-cog" style="color: #999;"></i></a></li>' document.getElementById('mynetdata_servers').innerHTML = el; document.getElementById('mynetdata_servers2').innerHTML = el; @@ -745,7 +1037,6 @@ gotoServerInit(); }; - var this_is_demo = null; // FIXME function isdemo() { if(this_is_demo !== null) return this_is_demo; this_is_demo = false; @@ -764,14 +1055,14 @@ return this_is_demo; } - function netdataURL(url) { + function netdataURL(url, forReload) { if(typeof url === 'undefined') url = document.location.toString(); if(url.indexOf('#') !== -1) url = url.substring(0, url.indexOf('#')); - var hash = urlOptions.genHash(); + var hash = urlOptions.genHash(forReload); // console.log('netdataURL: ' + url + hash); @@ -779,7 +1070,7 @@ } function netdataReload(url) { - document.location = netdataURL(url); + document.location = netdataURL(url, true); // since we play with hash // this is needed to reload the page @@ -958,15 +1249,14 @@ data: null, hostname: 'netdata_server', // will be overwritten by the netdata server version: 'unknown', - categories: [], - categories_idx: {}, - families: [], - families_idx: {}, hosts: [], + duration: 0, // the default duration of the charts + update_every: 1, + chartsPerRow: 0, // chartsMinWidth: 1450, - chartsHeight: 180 + chartsHeight: 180, }; function chartsPerRow(total) { @@ -1016,8 +1306,10 @@ function scrollToId(hash) { if(hash && hash !== '' && document.getElementById(hash) !== null) { var offset = $('#' + hash).offset(); - if(typeof offset !== 'undefined') - $('html, body').animate({ scrollTop: offset.top - 30 }, 0); + if(typeof offset !== 'undefined') { + //console.log('scrolling to ' + hash + ' at ' + offset.top.toString()); + $('html, body').animate({scrollTop: offset.top - 30}, 0); + } } // we must return false to prevent the default action @@ -1120,9 +1412,9 @@ menuIcon: function(chart) { if(typeof chart.menu_pattern !== 'undefined') - return this.anyAttribute(this.menu, 'icon', chart.menu_pattern, '<i class="fa fa-puzzle-piece" aria-hidden="true"></i>').toString(); + return this.anyAttribute(this.menu, 'icon', chart.menu_pattern, '<i class="fas fa-puzzle-piece"></i>').toString(); - return this.anyAttribute(this.menu, 'icon', chart.menu, '<i class="fa fa-puzzle-piece" aria-hidden="true"></i>'); + return this.anyAttribute(this.menu, 'icon', chart.menu, '<i class="fas fa-puzzle-piece"></i>'); }, menuInfo: function(chart) { @@ -1165,7 +1457,7 @@ var x = this.anyAttribute(this.context, 'info', id, null); if(x !== null) - return '<div class="chart-message netdata-chart-alignment" role="document">' + x + '</div>'; + return '<div class="shorten dashboard-context-info netdata-chart-alignment" role="document">' + x + '</div>'; else return ''; }, @@ -1307,120 +1599,178 @@ function headMain(os, charts, duration) { void(os); + if(urlOptions.mode === 'print') + return ''; + var head = ''; if(typeof charts['system.swap'] !== 'undefined') head += '<div class="netdata-container" style="margin-right: 10px;" data-netdata="system.swap"' - + ' data-dimensions="used"' - + ' data-append-options="percentage"' - + ' data-chart-library="easypiechart"' - + ' data-title="Used Swap"' - + ' data-units="%"' - + ' data-easypiechart-max-value="100"' - + ' data-width="9%"' - + ' data-before="0"' - + ' data-after="-' + duration.toString() + '"' - + ' data-points="' + duration.toString() + '"' - + ' data-colors="#DD4400"' - + ' role="application"></div>'; + + ' data-dimensions="used"' + + ' data-append-options="percentage"' + + ' data-chart-library="easypiechart"' + + ' data-title="Used Swap"' + + ' data-units="%"' + + ' data-easypiechart-max-value="100"' + + ' data-width="9%"' + + ' data-before="0"' + + ' data-after="-' + duration.toString() + '"' + + ' data-points="' + duration.toString() + '"' + + ' data-colors="#DD4400"' + + ' role="application"></div>'; if(typeof charts['system.io'] !== 'undefined') { head += '<div class="netdata-container" style="margin-right: 10px;" data-netdata="system.io"' - + ' data-dimensions="in"' - + ' data-chart-library="easypiechart"' - + ' data-title="Disk Read"' - + ' data-width="11%"' - + ' data-before="0"' - + ' data-after="-' + duration.toString() + '"' - + ' data-points="' + duration.toString() + '"' - + ' role="application"></div>'; + + ' data-dimensions="in"' + + ' data-chart-library="easypiechart"' + + ' data-title="Disk Read"' + + ' data-width="11%"' + + ' data-before="0"' + + ' data-after="-' + duration.toString() + '"' + + ' data-points="' + duration.toString() + '"' + + ' data-common-units="system.io.mainhead"' + + ' role="application"></div>'; head += '<div class="netdata-container" style="margin-right: 10px;" data-netdata="system.io"' - + ' data-dimensions="out"' - + ' data-chart-library="easypiechart"' - + ' data-title="Disk Write"' - + ' data-width="11%"' - + ' data-before="0"' - + ' data-after="-' + duration.toString() + '"' - + ' data-points="' + duration.toString() + '"' - + ' role="application"></div>'; + + ' data-dimensions="out"' + + ' data-chart-library="easypiechart"' + + ' data-title="Disk Write"' + + ' data-width="11%"' + + ' data-before="0"' + + ' data-after="-' + duration.toString() + '"' + + ' data-points="' + duration.toString() + '"' + + ' data-common-units="system.io.mainhead"' + + ' role="application"></div>'; + } + else if(typeof charts['system.pgpgio'] !== 'undefined') { + head += '<div class="netdata-container" style="margin-right: 10px;" data-netdata="system.pgpgio"' + + ' data-dimensions="in"' + + ' data-chart-library="easypiechart"' + + ' data-title="Disk Read"' + + ' data-width="11%"' + + ' data-before="0"' + + ' data-after="-' + duration.toString() + '"' + + ' data-points="' + duration.toString() + '"' + + ' data-common-units="system.pgpgio.mainhead"' + + ' role="application"></div>'; + + head += '<div class="netdata-container" style="margin-right: 10px;" data-netdata="system.pgpgio"' + + ' data-dimensions="out"' + + ' data-chart-library="easypiechart"' + + ' data-title="Disk Write"' + + ' data-width="11%"' + + ' data-before="0"' + + ' data-after="-' + duration.toString() + '"' + + ' data-points="' + duration.toString() + '"' + + ' data-common-units="system.pgpgio.mainhead"' + + ' role="application"></div>'; } if(typeof charts['system.cpu'] !== 'undefined') head += '<div class="netdata-container" style="margin-right: 10px;" data-netdata="system.cpu"' - + ' data-chart-library="gauge"' - + ' data-title="CPU"' - + ' data-units="%"' - + ' data-gauge-max-value="100"' - + ' data-width="20%"' - + ' data-after="-' + duration.toString() + '"' - + ' data-points="' + duration.toString() + '"' - + ' data-colors="' + NETDATA.colors[12] + '"' - + ' role="application"></div>'; - - if(typeof charts['system.ipv4'] !== 'undefined') { + + ' data-chart-library="gauge"' + + ' data-title="CPU"' + + ' data-units="%"' + + ' data-gauge-max-value="100"' + + ' data-width="20%"' + + ' data-after="-' + duration.toString() + '"' + + ' data-points="' + duration.toString() + '"' + + ' data-colors="' + NETDATA.colors[12] + '"' + + ' role="application"></div>'; + + if(typeof charts['system.net'] !== 'undefined') { + head += '<div class="netdata-container" style="margin-right: 10px;" data-netdata="system.net"' + + ' data-dimensions="received"' + + ' data-chart-library="easypiechart"' + + ' data-title="Net Inbound"' + + ' data-width="11%"' + + ' data-before="0"' + + ' data-after="-' + duration.toString() + '"' + + ' data-points="' + duration.toString() + '"' + + ' data-common-units="system.net.mainhead"' + + ' role="application"></div>'; + + head += '<div class="netdata-container" style="margin-right: 10px;" data-netdata="system.net"' + + ' data-dimensions="sent"' + + ' data-chart-library="easypiechart"' + + ' data-title="Net Outbound"' + + ' data-width="11%"' + + ' data-before="0"' + + ' data-after="-' + duration.toString() + '"' + + ' data-points="' + duration.toString() + '"' + + ' data-common-units="system.net.mainhead"' + + ' role="application"></div>'; + } + else if(typeof charts['system.ipv4'] !== 'undefined') { head += '<div class="netdata-container" style="margin-right: 10px;" data-netdata="system.ipv4"' - + ' data-dimensions="received"' - + ' data-chart-library="easypiechart"' - + ' data-title="IPv4 Inbound"' - + ' data-width="11%"' - + ' data-before="0"' - + ' data-after="-' + duration.toString() + '"' - + ' data-points="' + duration.toString() + '"' - + ' role="application"></div>'; + + ' data-dimensions="received"' + + ' data-chart-library="easypiechart"' + + ' data-title="IPv4 Inbound"' + + ' data-width="11%"' + + ' data-before="0"' + + ' data-after="-' + duration.toString() + '"' + + ' data-points="' + duration.toString() + '"' + + ' data-common-units="system.ipv4.mainhead"' + + ' role="application"></div>'; head += '<div class="netdata-container" style="margin-right: 10px;" data-netdata="system.ipv4"' - + ' data-dimensions="sent"' - + ' data-chart-library="easypiechart"' - + ' data-title="IPv4 Outbound"' - + ' data-width="11%"' - + ' data-before="0"' - + ' data-after="-' + duration.toString() + '"' - + ' data-points="' + duration.toString() + '"' - + ' role="application"></div>'; + + ' data-dimensions="sent"' + + ' data-chart-library="easypiechart"' + + ' data-title="IPv4 Outbound"' + + ' data-width="11%"' + + ' data-before="0"' + + ' data-after="-' + duration.toString() + '"' + + ' data-points="' + duration.toString() + '"' + + ' data-common-units="system.ipv4.mainhead"' + + ' role="application"></div>'; } else if(typeof charts['system.ipv6'] !== 'undefined') { head += '<div class="netdata-container" style="margin-right: 10px;" data-netdata="system.ipv6"' - + ' data-dimensions="received"' - + ' data-chart-library="easypiechart"' - + ' data-title="IPv6 Inbound"' - + ' data-units="kbps"' - + ' data-width="11%"' - + ' data-before="0"' - + ' data-after="-' + duration.toString() + '"' - + ' data-points="' + duration.toString() + '"' - + ' role="application"></div>'; + + ' data-dimensions="received"' + + ' data-chart-library="easypiechart"' + + ' data-title="IPv6 Inbound"' + + ' data-units="kbps"' + + ' data-width="11%"' + + ' data-before="0"' + + ' data-after="-' + duration.toString() + '"' + + ' data-points="' + duration.toString() + '"' + + ' data-common-units="system.ipv6.mainhead"' + + ' role="application"></div>'; head += '<div class="netdata-container" style="margin-right: 10px;" data-netdata="system.ipv6"' - + ' data-dimensions="sent"' - + ' data-chart-library="easypiechart"' - + ' data-title="IPv6 Outbound"' - + ' data-units="kbps"' - + ' data-width="11%"' - + ' data-before="0"' - + ' data-after="-' + duration.toString() + '"' - + ' data-points="' + duration.toString() + '"' - + ' role="application"></div>'; + + ' data-dimensions="sent"' + + ' data-chart-library="easypiechart"' + + ' data-title="IPv6 Outbound"' + + ' data-units="kbps"' + + ' data-width="11%"' + + ' data-before="0"' + + ' data-after="-' + duration.toString() + '"' + + ' data-points="' + duration.toString() + '"' + + ' data-common-units="system.ipv6.mainhead"' + + ' role="application"></div>'; } if(typeof charts['system.ram'] !== 'undefined') head += '<div class="netdata-container" style="margin-right: 10px;" data-netdata="system.ram"' - + ' data-dimensions="used|buffers|active|wired"' // active and wired are FreeBSD stats - + ' data-append-options="percentage"' - + ' data-chart-library="easypiechart"' - + ' data-title="Used RAM"' - + ' data-units="%"' - + ' data-easypiechart-max-value="100"' - + ' data-width="9%"' - + ' data-after="-' + duration.toString() + '"' - + ' data-points="' + duration.toString() + '"' - + ' data-colors="' + NETDATA.colors[7] + '"' - + ' role="application"></div>'; + + ' data-dimensions="used|buffers|active|wired"' // active and wired are FreeBSD stats + + ' data-append-options="percentage"' + + ' data-chart-library="easypiechart"' + + ' data-title="Used RAM"' + + ' data-units="%"' + + ' data-easypiechart-max-value="100"' + + ' data-width="9%"' + + ' data-after="-' + duration.toString() + '"' + + ' data-points="' + duration.toString() + '"' + + ' data-colors="' + NETDATA.colors[7] + '"' + + ' role="application"></div>'; return head; } function generateHeadCharts(type, chart, duration) { + if(urlOptions.mode === 'print') + return ''; + var head = ''; var hcharts = netdataDashboard.anyAttribute(netdataDashboard.context, type, chart.context, []); if(hcharts.length > 0) { @@ -1442,6 +1792,9 @@ // find the proper duration for per-second updates var duration = Math.round(($(div).width() * pcent_width / 100 * data.update_every / 3) / 60) * 60; + options.duration = duration; + options.update_every = data.update_every; + var html = ''; var sidebar = '<ul class="nav dashboard-sidenav" data-spy="affix" id="sidebar_ul">'; var mainhead = headMain(netdataDashboard.os, data.charts, duration); @@ -1456,7 +1809,7 @@ var menuid = NETDATA.name2id('menu_' + menu); sidebar += '<li class=""><a href="#' + menuid + '" onClick="return scrollToId(\'' + menuid + '\');">' + menus[menu].icon + ' ' + menus[menu].title + '</a><ul class="nav">'; - html += '<div role="section"><div role="sectionhead"><h1 id="' + menuid + '" role="heading">' + menus[menu].title + '</h1></div><div role="document">'; + html += '<div role="section" class="dashboard-section"><div role="sectionhead"><h1 id="' + menuid + '" role="heading">' + menus[menu].icon + ' ' + menus[menu].title + '</h1></div><div role="section" class="dashboard-subsection">'; if(menus[menu].info !== null) html += menus[menu].info; @@ -1476,10 +1829,10 @@ // generate an entry at the submenu var submenuid = NETDATA.name2id('menu_' + menu + '_submenu_' + submenu); sidebar += '<li class><a href="#' + submenuid + '" onClick="return scrollToId(\'' + submenuid + '\');">' + menus[menu].submenus[submenu].title + '</a></li>'; - shtml += '<div class="netdata-group-container" id="' + submenuid + '" style="display: inline-block; width: ' + pcent_width.toString() + '%"><h2 id="' + submenuid + '" class="netdata-chart-alignment" role="heading">' + menus[menu].submenus[submenu].title + '</h2>'; + shtml += '<div role="section" class="dashboard-section-container" id="' + submenuid + '"><h2 id="' + submenuid + '" class="netdata-chart-alignment" role="heading">' + menus[menu].submenus[submenu].title + '</h2>'; if(menus[menu].submenus[submenu].info !== null) - shtml += '<div class="chart-message netdata-chart-alignment" role="document">' + menus[menu].submenus[submenu].info + '</div>'; + shtml += '<div class="dashboard-submenu-info netdata-chart-alignment" role="document">' + menus[menu].submenus[submenu].info + '</div>'; var head = '<div class="netdata-chart-row">'; var chtml = ''; @@ -1513,8 +1866,11 @@ } // generate the chart - chtml += netdataDashboard.contextInfo(chart.context) + '<div class="netdata-container" id="chart_' + NETDATA.name2id(chart.id) + '" data-netdata="' + chart.id + '"' - + ' data-width="' + pcent_width.toString() + '%"' + if(urlOptions.mode === 'print') + chtml += '<div role="row" class="dashboard-print-row">'; + + chtml += '<div class="netdata-chartblock-container" style="width: ' + pcent_width.toString() + '%;">' + netdataDashboard.contextInfo(chart.context) + '<div class="netdata-container" id="chart_' + NETDATA.name2id(chart.id) + '" data-netdata="' + chart.id + '"' + + ' data-width="100%"' + ' data-height="' + netdataDashboard.contextHeight(chart.context, options.chartsHeight).toString() + 'px"' + ' data-dygraph-valuerange="' + netdataDashboard.contextValueRange(chart.context) + '"' + ' data-before="0"' @@ -1524,7 +1880,10 @@ + ' data-decimal-digits="' + netdataDashboard.contextDecimalDigits(chart.context, -1) + '"' + chartCommonMin(chart.family, chart.context, chart.units) + chartCommonMax(chart.family, chart.context, chart.units) - + ' role="application"></div>'; + + ' role="application"></div></div>'; + + if(urlOptions.mode === 'print') + chtml += '</div>'; // console.log(' \------- ' + chart.id + ' (' + chart.priority + '): ' + chart.context + ' height: ' + menus[menu].submenus[submenu].height); } @@ -1538,16 +1897,33 @@ html += mhead + shtml + '</div></div><hr role="separator"/>'; } - sidebar += '<li class="" style="padding-top:15px;"><a href="https://github.com/firehol/netdata/wiki/Add-more-charts-to-netdata" target="_blank"><i class="fa fa-plus" aria-hidden="true"></i> add more charts</a></li>'; - sidebar += '<li class=""><a href="https://github.com/firehol/netdata/wiki/Add-more-alarms-to-netdata" target="_blank"><i class="fa fa-plus" aria-hidden="true"></i> add more alarms</a></li>'; - sidebar += '<li class="" style="margin:20px;color:#666;"><small>netdata on <b>' + data.hostname.toString() + '</b>, collects every ' + ((data.update_every === 1)?'second':data.update_every.toString() + ' seconds') + ' <b>' + data.dimensions_count.toLocaleString() + '</b> metrics, presented as <b>' + data.charts_count.toLocaleString() + '</b> charts and monitored by <b>' + data.alarms_count.toLocaleString() + '</b> alarms, using ' + Math.round(data.rrd_memory_bytes / 1024 / 1024).toLocaleString() + ' MB of memory for ' + seconds4human(data.update_every * data.history) + ' of real-time history.<br/> <br/><b>netdata</b><br/>v' + data.version.toString() +'</small></li>'; + sidebar += '<li class="" style="padding-top:15px;"><a href="https://github.com/firehol/netdata/wiki/Add-more-charts-to-netdata" target="_blank"><i class="fas fa-plus"></i> add more charts</a></li>'; + sidebar += '<li class=""><a href="https://github.com/firehol/netdata/wiki/Add-more-alarms-to-netdata" target="_blank"><i class="fas fa-plus"></i> add more alarms</a></li>'; + sidebar += '<li class="" style="margin:20px;color:#666;"><small>netdata on <b>' + data.hostname.toString() + '</b>, collects every ' + ((data.update_every === 1)?'second':data.update_every.toString() + ' seconds') + ' <b>' + data.dimensions_count.toLocaleString() + '</b> metrics, presented as <b>' + data.charts_count.toLocaleString() + '</b> charts and monitored by <b>' + data.alarms_count.toLocaleString() + '</b> alarms, using ' + Math.round(data.rrd_memory_bytes / 1024 / 1024).toLocaleString() + ' MB of memory for ' + NETDATA.seconds4human(data.update_every * data.history, { space: ' ' }) + ' of real-time history.<br/> <br/><b>netdata</b><br/>v' + data.version.toString() +'</small></li>'; sidebar += '</ul>'; div.innerHTML = html; document.getElementById('sidebar').innerHTML = sidebar; - finalizePage(); + + if(urlOptions.highlight === true) + NETDATA.globalChartUnderlay.init(null + , urlOptions.highlight_after + , urlOptions.highlight_before + , (urlOptions.after > 0) ? urlOptions.after : null + , (urlOptions.before > 0) ? urlOptions.before : null + ); + else + NETDATA.globalChartUnderlay.clear(); + + if(urlOptions.mode === 'print') + printPage(); + else + finalizePage(); } function renderChartsAndMenu(data) { + options.menus = {}; + options.submenu_names = {}; + var menus = options.menus; var charts = data.charts; var m, menu_key; @@ -1644,15 +2020,49 @@ function loadBootstrapTable(callback) { if(bootstrapTableLoaded === false) { bootstrapTableLoaded = true; - loadJs(NETDATA.serverDefault + 'lib/bootstrap-table-1.11.0.min.js', function() { - loadJs(NETDATA.serverDefault + 'lib/bootstrap-table-export-1.11.0.min.js', function() { - loadJs(NETDATA.serverDefault + 'lib/tableExport-1.6.0.min.js', callback); + loadJs('lib/bootstrap-table-1.11.0.min.js', function() { + loadJs('lib/bootstrap-table-export-1.11.0.min.js', function() { + loadJs('lib/tableExport-1.6.0.min.js', callback); }) }); } else callback(); } + var bootstrapSliderLoaded = false; + function loadBootstrapSlider(callback) { + if(bootstrapSliderLoaded === false) { + bootstrapSliderLoaded = true; + loadJs('lib/bootstrap-slider-10.0.0.min.js', function() { + NETDATA._loadCSS('css/bootstrap-slider-10.0.0.min.css'); + callback(); + }); + } + else callback(); + } + + var lzStringLoaded = false; + function loadLzString(callback) { + if(lzStringLoaded === false) { + lzStringLoaded = true; + loadJs('lib/lz-string-1.4.4.min.js', function() { + callback(); + }); + } + else callback(); + } + + var pakoLoaded = false; + function loadPako(callback) { + if(pakoLoaded === false) { + pakoLoaded = true; + loadJs('lib/pako-1.0.6.min.js', function() { + callback(); + }); + } + else callback(); + } + function alarmsUpdateModal() { var active = '<h3>Raised Alarms</h3><table class="table">'; var all = '<h3>All Running Alarms</h3><div class="panel-group" id="alarms_all_accordion" role="tablist" aria-multiselectable="true">'; @@ -1711,7 +2121,7 @@ return '<code>' + alarm.lookup_method + '</code> ' + dimensions + ', of chart <code>' + alarm.chart + '</code>' - + ', starting <code>' + seconds4human(alarm.lookup_after + alarm.lookup_before) + '</code> and up to <code>' + seconds4human(alarm.lookup_before) + '</code>' + + ', starting <code>' + NETDATA.seconds4human(alarm.lookup_after + alarm.lookup_before, { space: ' ' }) + '</code> and up to <code>' + NETDATA.seconds4human(alarm.lookup_before, { space: ' ' }) + '</code>' + ((alarm.lookup_options)?(', with options <code>' + alarm.lookup_options.replace(' ', ', ') + '</code>'):'') + '.'; } @@ -1727,7 +2137,7 @@ var has_alarm = (typeof alarm.warn !== 'undefined' || typeof alarm.crit !== 'undefined'); - var role_href = ((has_alarm === true)?('<br/> <br/>role: <b>' + alarm.recipient + '</b><br/> <br/><b><i class="fa fa-line-chart" aria-hidden="true"></i></b><small> <a href="#" onClick="NETDATA.alarms.scrollToChart(\'' + alarm.chart + '\'); $(\'#alarmsModal\').modal(\'hide\'); return false;">jump to chart</a></small>'):(' ')); + var role_href = ((has_alarm === true)?('<br/> <br/>role: <b>' + alarm.recipient + '</b><br/> <br/><b><i class="fas fa-chart-line"></i></b><small> <a href="#" onClick="scrollToChartAfterHidingModal(\'' + alarm.chart + '\'); $(\'#alarmsModal\').modal(\'hide\'); return false;">jump to chart</a></small>'):(' ')); var html = '<tr><td class="text-center" style="vertical-align:middle" width="40%"><b>' + alarm.chart + '</b><br/> <br/><embed src="' + NETDATA.alarms.server + '/api/v1/badge.svg?chart=' + alarm.chart + '&alarm=' + alarm.name + '&refresh=auto" type="image/svg+xml" height="20"/><br/> <br/><span style="font-size: 18px">' + alarm.info + '</span>' + role_href + '</td>' + '<td><table class="table">' @@ -1747,25 +2157,25 @@ var delay = ''; if((alarm.delay_up_duration > 0 || alarm.delay_down_duration > 0) && alarm.delay_multiplier !== 0 && alarm.delay_max_duration > 0) { if(alarm.delay_up_duration === alarm.delay_down_duration) { - delay += '<small><br/>hysteresis ' + seconds4human(alarm.delay_up_duration, { negative_suffix: '' }); + delay += '<small><br/>hysteresis ' + NETDATA.seconds4human(alarm.delay_up_duration, { space: ' ', negative_suffix: '' }); } else { delay = '<small><br/>hysteresis '; if(alarm.delay_up_duration > 0) { - delay += 'on escalation <code>' + seconds4human(alarm.delay_up_duration, { negative_suffix: '' }) + '</code>, '; + delay += 'on escalation <code>' + NETDATA.seconds4human(alarm.delay_up_duration, { space: ' ', negative_suffix: '' }) + '</code>, '; } if(alarm.delay_down_duration > 0) { - delay += 'on recovery <code>' + seconds4human(alarm.delay_down_duration, { negative_suffix: '' }) + '</code>, '; + delay += 'on recovery <code>' + NETDATA.seconds4human(alarm.delay_down_duration, { space: ' ', negative_suffix: '' }) + '</code>, '; } } if(alarm.delay_multiplier !== 1.0) { delay += 'multiplied by <code>' + alarm.delay_multiplier.toString() + '</code>'; - delay += ', up to <code>' + seconds4human(alarm.delay_max_duration, { negative_suffix: '' }) + '</code>'; + delay += ', up to <code>' + NETDATA.seconds4human(alarm.delay_max_duration, { space: ' ', negative_suffix: '' }) + '</code>'; } delay += '</small>'; } - html += '<tr><td width="10%" style="text-align:right">check every</td><td>' + seconds4human(alarm.update_every, { negative_suffix: '' }) + '</td></tr>' + html += '<tr><td width="10%" style="text-align:right">check every</td><td>' + NETDATA.seconds4human(alarm.update_every, { space: ' ', negative_suffix: '' }) + '</td></tr>' + ((has_alarm === true)?('<tr><td width="10%" style="text-align:right">execute</td><td><span style="font-family: monospace;">' + alarm.exec + '</span>' + delay + '</td></tr>'):'') + '<tr><td width="10%" style="text-align:right">source</td><td><span style="font-family: monospace;">' + alarm.source + '</span></td></tr>' + '</table></td></tr>'; @@ -1880,7 +2290,7 @@ all += "</div>"; if(!count_active) - active += "<h4>Everything is normal. No raised alarms.</h4>"; + active += '<div style="width:100%; height: 100px; text-align: center;"><span style="font-size: 50px;"><i class="fas fa-thumbs-up"></i></span><br/>Everything is normal. No raised alarms.</div>'; else active += footer; @@ -2103,7 +2513,7 @@ formatter: function(value, row, index) { void(row); void(index); - return seconds4human(value, { negative_suffix: '', space: ' ', now: 'no time' }); + return NETDATA.seconds4human(value, { negative_suffix: '', space: ' ', now: 'no time' }); }, align: 'center', valign: 'middle', @@ -2117,7 +2527,7 @@ formatter: function(value, row, index) { void(row); void(index); - return seconds4human(value, { negative_suffix: '', space: ' ', now: 'no time' }); + return NETDATA.seconds4human(value, { negative_suffix: '', space: ' ', now: 'no time' }); }, align: 'center', valign: 'middle', @@ -2234,7 +2644,7 @@ void(row); void(index); - return seconds4human(value, { negative_suffix: '', space: ' ', now: 'no time' }); + return NETDATA.seconds4human(value, { negative_suffix: '', space: ' ', now: 'no time' }); }, align: 'center', valign: 'middle', @@ -2276,70 +2686,6 @@ }); } - function seconds4human(seconds, options) { - var default_options = { - now: 'now', - space: ' ', - negative_suffix: 'ago', - hour: 'hour', - hours: 'hours', - minute: 'minute', - minutes: 'minutes', - second: 'second', - seconds: 'seconds', - and: 'and' - }; - - if(typeof options !== 'object') - options = default_options; - else { - var x; - for(x in default_options) { - if(typeof options[x] !== 'string') - options[x] = default_options[x]; - } - } - - if(typeof seconds === 'string') - seconds = parseInt(seconds); - - if(seconds === 0) - return options.now; - - var suffix = ''; - if(seconds < 0) { - seconds = -seconds; - if(options.negative_suffix !== '') suffix = options.space + options.negative_suffix; - } - - var hours = Math.floor(seconds / 3600); - seconds -= (hours * 3600); - - var minutes = Math.floor(seconds / 60); - seconds -= (minutes * 60); - - var txt = ''; - - if(hours > 1) txt += hours.toString() + options.space + options.hours; - else if(hours === 1) txt += hours.toString() + options.space + options.hour; - - if(hours > 0 && minutes > 0 && seconds === 0) - txt += options.space + options.and + options.space; - else if(hours > 0 && minutes > 0 && seconds > 0) - txt += ',' + options.space; - - if(minutes > 1) txt += minutes.toString() + options.space + options.minutes; - else if(minutes === 1) txt += minutes.toString() + options.space + options.minute; - - if((minutes > 0 || minutes > 0) && seconds > 0) - txt += options.space + options.and + options.space; - - if(seconds > 1) txt += Math.floor(seconds).toString() + options.space + options.seconds; - else if(seconds === 1) txt += Math.floor(seconds).toString() + options.space + options.second; - - return txt + suffix; - } - function alarmsCallback(data) { var count = 0; for(x in data.alarms) { @@ -2367,10 +2713,18 @@ options.hosts = data.hosts; // update the dashboard hostname - document.getElementById('hostname').innerHTML = options.hostname; + document.getElementById('hostname').innerHTML = options.hostname + ((netdataSnapshotData !== null)?' (snap)':'').toString(); document.getElementById('hostname').href = NETDATA.serverDefault; document.getElementById('netdataVersion').innerHTML = options.version; + if(netdataSnapshotData !== null) { + $('#alarmsButton').hide(); + $('#updateButton').hide(); + // $('#loadButton').hide(); + $('#saveButton').hide(); + $('#printButton').hide(); + } + // update the dashboard title document.title = options.hostname + ' netdata dashboard'; @@ -2408,8 +2762,8 @@ // download all the charts the server knows NETDATA.chartRegistry.downloadAll(netdata_url, function(data) { if(data !== null) { - if(typeof data.custom_info !== 'undefined' && data.custom_info !== "") { - loadJs(data.custom_info, function () { + if(typeof data.custom_info !== 'undefined' && data.custom_info !== "" && netdataSnapshotData === null) { + loadJs(NETDATA.serverDefault + data.custom_info, function () { $.extend(true, netdataDashboard, customDashboard); initializeDynamicDashboardWithData(data); }); @@ -2542,7 +2896,7 @@ } else if(sha1 === sha2) { save = true; - versionLog('<p><big>You already have the latest netdata!</big></p><p>No update yet?<br/>Probably, we need some motivation to keep going on!</p><p>If you haven\'t already, <a href="https://github.com/firehol/netdata" target="_blank">give netdata a <b>Star</b> at its github page</a>.</p>'); + versionLog('<p><big>You already have the latest netdata!</big></p><p>No update yet?<br/>Probably, we need some motivation to keep going on!</p><p>If you haven\'t already, <a href="https://github.com/firehol/netdata" target="_blank">give netdata a <b><i class="fas fa-star"></i></b> at its github page</a>.</p>'); } else { save = true; @@ -2559,19 +2913,1133 @@ } // ---------------------------------------------------------------------------- + // printing dashboards - function finalizePage() { - // resize all charts - without starting the background thread - // this has to be done while NETDATA is paused - // if we ommit this, the affix menu will be wrong, since all - // the Dom elements are initially zero-sized - NETDATA.parseDom(); + function showPageFooter() { + document.getElementById('footer').style.display = 'block'; + } + + + function printPreflight() { + var url = document.location.origin + document.location.search + '#' + urlOptions.genHash() + ';mode=print'; + var width = 990; + var height = screen.height * 90 / 100; + //console.log(url); + //console.log(document.location); + window.open(url, '', 'width=' + width.toString() + ',height=' + height.toString() + ',menubar=no,toolbar=no,personalbar=no,location=no,resizable=no,scrollbars=yes,status=no,chrome=yes,centerscreen=yes,attention=yes,dialog=yes'); + $('#printPreflightModal').modal('hide'); + } + + function printPage() { + var print_is_rendering = true; + + $('#printModal').on('hide.bs.modal', function(e) { + if(print_is_rendering === true) { + e.preventDefault(); + return false; + } + + return true; + }); + + $('#printModal').on('show.bs.modal', function() { + var print_options = { + stop_updates_when_focus_is_lost: false, + update_only_visible: false, + sync_selection: false, + eliminate_zero_dimensions: false, + pan_and_zoom_data_padding: false, + show_help: false, + legend_toolbox: false, + resize_charts: false, + pixels_per_point: 1 + }; - if(urlOptions.pan_and_zoom === true) + var x; + for(x in print_options) { + if (print_options.hasOwnProperty(x)) + NETDATA.options.current[x] = print_options[x]; + } + + NETDATA.parseDom(); + showPageFooter(); + + NETDATA.globalSelectionSync.stop(); NETDATA.globalPanAndZoom.setMaster(NETDATA.options.targets[0], urlOptions.after, urlOptions.before); + // NETDATA.onresize(); + + var el = document.getElementById('printModalProgressBar'); + var eltxt = document.getElementById('printModalProgressBarText'); + + function update_chart(idx) { + var state = NETDATA.options.targets[--idx]; + + var pcent = (NETDATA.options.targets.length - idx) * 100 / NETDATA.options.targets.length; + $(el).css('width', pcent+'%').attr('aria-valuenow', pcent); + eltxt.innerText = Math.round(pcent).toString() + '%, ' + state.id; + + setTimeout(function() { + state.updateChart(function () { + NETDATA.options.targets[idx].resizeForPrint(); + + if (idx > 0) { + update_chart(idx); + } + else { + print_is_rendering = false; + $('#printModal').modal('hide'); + window.print(); + window.close(); + } + }) + }, 0); + } + + print_is_rendering = true; + update_chart(NETDATA.options.targets.length); + }); + + $('#printModal').modal('show'); + } + + // -------------------------------------------------------------------- + + function jsonStringifyFn(obj) { + return JSON.stringify(obj, function (key, value) { + return (typeof value === 'function' ) ? value.toString() : value; + }); + } + + function jsonParseFn(str) { + return JSON.parse(str, function (key, value) { + if (typeof value != 'string') return value; + return ( value.substring(0, 8) == 'function') ? eval('(' + value + ')') : value; + }); + } + + // -------------------------------------------------------------------- + + var snapshotOptions = { + bytes_per_chart: 2048, + compressionDefault: 'pako.deflate.base64', + + compressions: { + 'none': { + bytes_per_point_memory: 5.2, + bytes_per_point_disk: 5.6, + + compress: function (s) { + return s; + }, + + compressed_length: function (s) { + return s.length; + }, + + uncompress: function (s) { + return s; + } + }, + + 'pako.deflate.base64': { + bytes_per_point_memory: 1.8, + bytes_per_point_disk: 1.9, + + compress: function (s) { + return btoa(pako.deflate(s, { to: 'string' })); + }, + + compressed_length: function (s) { + return s.length; + }, + + uncompress: function (s) { + return pako.inflate(atob(s), {to: 'string'}); + } + }, + + 'pako.deflate': { + bytes_per_point_memory: 1.4, + bytes_per_point_disk: 3.2, + + compress: function (s) { + return pako.deflate(s, { to: 'string' }); + }, + + compressed_length: function (s) { + return s.length; + }, + + uncompress: function (s) { + return pako.inflate(s, {to: 'string'}); + } + }, + + 'lzstring.utf16': { + bytes_per_point_memory: 1.7, + bytes_per_point_disk: 2.6, + + compress: function (s) { + return LZString.compressToUTF16(s); + }, + + compressed_length: function (s) { + return s.length * 2; + }, + + uncompress: function (s) { + return LZString.decompressFromUTF16(s); + } + }, + + 'lzstring.base64': { + bytes_per_point_memory: 2.1, + bytes_per_point_disk: 2.3, + + compress: function (s) { + return LZString.compressToBase64(s); + }, + + compressed_length: function (s) { + return s.length; + }, + + uncompress: function (s) { + return LZString.decompressFromBase64(s); + } + }, + + 'lzstring.uri': { + bytes_per_point_memory: 2.1, + bytes_per_point_disk: 2.3, + + compress: function (s) { + return LZString.compressToEncodedURIComponent(s); + }, + + compressed_length: function (s) { + return s.length; + }, + + uncompress: function (s) { + return LZString.decompressFromEncodedURIComponent(s); + } + } + } + }; + + // -------------------------------------------------------------------- + // loading snapshots + + function loadSnapshotModalLog(priority, msg) { + document.getElementById('loadSnapshotStatus').className = "alert alert-" + priority; + document.getElementById('loadSnapshotStatus').innerHTML = msg; + } + + var tmpSnapshotData = null; + function loadSnapshot() { + $('#loadSnapshotImport').addClass('disabled'); + + if(tmpSnapshotData === null) { + loadSnapshotModalLog('danger', 'no data have been loaded'); + return; + } + + loadPako(function() { + loadLzString(function () { + loadSnapshotModalLog('info', 'Please wait, activating snapshot...'); + $('#loadSnapshotModal').modal('hide'); + + netdataShowAlarms === false; + netdataRegistry = false; + netdataServer = tmpSnapshotData.server; + NETDATA.serverDefault = netdataServer; + + document.getElementById('charts_div').innerHTML = ''; + document.getElementById('sidebar').innerHTML = ''; + NETDATA.globalReset(); + + if (typeof tmpSnapshotData.hash !== 'undefined') + urlOptions.hash = tmpSnapshotData.hash; + else + urlOptions.hash = '#'; + + if (typeof tmpSnapshotData.info !== 'undefined') { + var info = jsonParseFn(tmpSnapshotData.info); + if (typeof info.menu !== 'undefined') + netdataDashboard.menu = info.menu; + + if (typeof info.submenu !== 'undefined') + netdataDashboard.submenu = info.submenu; + + if (typeof info.context !== 'undefined') + netdataDashboard.context = info.context; + } + + if (typeof tmpSnapshotData.compression !== 'string') + tmpSnapshotData.compression = 'none'; + + if (typeof snapshotOptions.compressions[tmpSnapshotData.compression] === 'undefined') { + alert('unknown compression method: ' + tmpSnapshotData.compression); + tmpSnapshotData.compression = 'none'; + } + + tmpSnapshotData.uncompress = snapshotOptions.compressions[tmpSnapshotData.compression].uncompress; + netdataSnapshotData = tmpSnapshotData; + + urlOptions.after = tmpSnapshotData.after_ms; + urlOptions.before = tmpSnapshotData.before_ms; + + if( typeof tmpSnapshotData.highlight_after_ms !== 'undefined' + && tmpSnapshotData.highlight_after_ms !== null + && tmpSnapshotData.highlight_after_ms > 0 + && typeof tmpSnapshotData.highlight_before_ms !== 'undefined' + && tmpSnapshotData.highlight_before_ms !== null + && tmpSnapshotData.highlight_before_ms > 0 + ) { + urlOptions.highlight_after = tmpSnapshotData.highlight_after_ms; + urlOptions.highlight_before = tmpSnapshotData.highlight_before_ms; + urlOptions.highlight = true; + } + else { + urlOptions.highlight_after = 0; + urlOptions.highlight_before = 0; + urlOptions.highlight = false; + } + + initializeDynamicDashboard(); + }); + }); + }; + + + function loadSnapshotPreflightFile(file) { + var fr = new FileReader(); + fr.onload = function(e) { + document.getElementById('loadSnapshotFilename').innerHTML = file.name; + var result = null; + try { + result = JSON.parse(e.target.result); + //console.log(result); + var date_after = new Date(result.after_ms); + var date_before = new Date(result.before_ms); + + if (typeof result.charts_ok === 'undefined') + result.charts_ok = 'unknown'; + + if (typeof result.charts_failed === 'undefined') + result.charts_failed = 0; + + if (typeof result.compression === 'undefined') + result.compression = 'none'; + + if (typeof result.data_size === 'undefined') + result.data_size = 0; + + document.getElementById('loadSnapshotFilename').innerHTML = '<code>' + file.name + '</code>'; + document.getElementById('loadSnapshotHostname').innerHTML = '<b>' + result.hostname + '</b>, netdata version: <b>' + result.netdata_version.toString() + '</b>'; + document.getElementById('loadSnapshotURL').innerHTML = result.url; + document.getElementById('loadSnapshotCharts').innerHTML = result.charts.charts_count.toString() + ' charts, ' + result.charts.dimensions_count.toString() + ' dimensions, ' + result.data_points.toString() + ' points per dimension, ' + Math.round(result.duration_ms / result.data_points).toString() + ' ms per point'; + document.getElementById('loadSnapshotInfo').innerHTML = 'version: <b>' + result.snapshot_version.toString() + '</b>, includes <b>' + result.charts_ok.toString() + '</b> unique chart data queries ' + ((result.charts_failed > 0) ? ('<b>' + result.charts_failed.toString() + '</b> failed') : '').toString() + ', compressed with <code>' + result.compression.toString() + '</code>, data size ' + (Math.round(result.data_size * 100 / 1024 / 1024) / 100).toString() + ' MB'; + document.getElementById('loadSnapshotTimeRange').innerHTML = '<b>' + NETDATA.dateTime.localeDateString(date_after) + ' ' + NETDATA.dateTime.localeTimeString(date_after) + '</b> to <b>' + NETDATA.dateTime.localeDateString(date_before) + ' ' + NETDATA.dateTime.localeTimeString(date_before) + '</b>'; + document.getElementById('loadSnapshotComments').innerHTML = ((result.comments) ? result.comments : '').toString(); + loadSnapshotModalLog('success', 'File loaded, click <b>Import</b> to render it!'); + $('#loadSnapshotImport').removeClass('disabled'); + + tmpSnapshotData = result; + } + catch (e) { + console.log(e); + document.getElementById('loadSnapshotStatus').className = "alert alert-danger"; + document.getElementById('loadSnapshotStatus').innerHTML = "Failed to parse this file!"; + $('#loadSnapshotImport').addClass('disabled'); + } + } + + //console.log(file); + fr.readAsText(file); + }; + + function loadSnapshotPreflightEmpty() { + document.getElementById('loadSnapshotFilename').innerHTML = ''; + document.getElementById('loadSnapshotHostname').innerHTML = ''; + document.getElementById('loadSnapshotURL').innerHTML = ''; + document.getElementById('loadSnapshotCharts').innerHTML = ''; + document.getElementById('loadSnapshotInfo').innerHTML = ''; + document.getElementById('loadSnapshotTimeRange').innerHTML = ''; + document.getElementById('loadSnapshotComments').innerHTML = ''; + $('#loadSnapshotImport').addClass('disabled'); + }; + + var loadSnapshotDragAndDropInitialized = false; + function loadSnapshotDragAndDropSetup() { + if(loadSnapshotDragAndDropInitialized === false) { + loadSnapshotDragAndDropInitialized = true; + $('#loadSnapshotDragAndDrop') + .on('drag dragstart dragend dragover dragenter dragleave drop', function (e) { + e.preventDefault(); + e.stopPropagation(); + }) + .on('drop', function (e) { + if(e.originalEvent.dataTransfer.files.length) { + loadSnapshotPreflightFile(e.originalEvent.dataTransfer.files.item(0)); + } + else { + loadSnapshotPreflightEmpty(); + loadSnapshotModalLog('danger', 'No file selected'); + } + }); + } + }; + + function loadSnapshotPreflight() { + var files = document.getElementById('loadSnapshotSelectFiles').files; + if (files.length <= 0) { + loadSnapshotPreflightEmpty(); + loadSnapshotModalLog('danger', 'No file selected'); + return; + } + + loadSnapshotModalLog('info', 'Loading file...'); + + loadSnapshotPreflightFile(files.item(0)); + } + + // -------------------------------------------------------------------- + // saving snapshots + + var saveSnapshotStop = false; + function saveSnapshotCancel() { + saveSnapshotStop = true; + } + + var saveSnapshotModalInitialized = false; + function saveSnapshotModalSetup() { + if(saveSnapshotModalInitialized === false) { + saveSnapshotModalInitialized = true; + $('#saveSnapshotModal') + .on('hide.bs.modal', saveSnapshotCancel) + .on('show.bs.modal', saveSnapshotModalInit) + .on('shown.bs.modal', function() { + $('#saveSnapshotResolutionSlider').find(".slider-handle:first").attr("tabindex", 1); + document.getElementById('saveSnapshotComments').focus(); + }); + } + }; + + function saveSnapshotModalLog(priority, msg) { + document.getElementById('saveSnapshotStatus').className = "alert alert-" + priority; + document.getElementById('saveSnapshotStatus').innerHTML = msg; + } + + function saveSnapshotModalShowExpectedSize() { + var points = Math.round(saveSnapshotViewDuration / saveSnapshotSelectedSecondsPerPoint); + var priority = 'info'; + var msg = 'A moderate snapshot.'; + + var sizemb = Math.round( + (options.data.charts_count * snapshotOptions.bytes_per_chart + + options.data.dimensions_count * points * snapshotOptions.compressions[saveSnapshotCompression].bytes_per_point_disk) + * 10 / 1024 / 1024) / 10; + + var memmb = Math.round( + (options.data.charts_count * snapshotOptions.bytes_per_chart + + options.data.dimensions_count * points * snapshotOptions.compressions[saveSnapshotCompression].bytes_per_point_memory) + * 10 / 1024 / 1024) / 10; + + if(sizemb < 10) { + priority = 'success'; + msg = 'A nice small snapshot!'; + } + if(sizemb > 50) { + priority = 'warning'; + msg = 'Will stress your browser...'; + } + if(sizemb > 100) { + priority = 'danger'; + msg = 'Hm... good luck...'; + } + + saveSnapshotModalLog(priority, 'The snapshot will have ' + points.toString() + ' points per dimension. Expected size on disk ' + sizemb + ' MB, at browser memory ' + memmb + ' MB.<br/>' + msg); + } + + var saveSnapshotCompression = snapshotOptions.compressionDefault; + function saveSnapshotSetCompression(name) { + saveSnapshotCompression = name; + document.getElementById('saveSnapshotCompressionName').innerHTML = saveSnapshotCompression; + saveSnapshotModalShowExpectedSize(); + } + + var saveSnapshotSlider = null; + var saveSnapshotSelectedSecondsPerPoint = 1; + var saveSnapshotViewDuration = 1; + function saveSnapshotModalInit() { + $('#saveSnapshotModalProgressSection').hide(); + $('#saveSnapshotResolutionRadio').show(); + saveSnapshotModalLog('info', 'Select resolution and click <b>Save</b>'); + $('#saveSnapshotExport').removeClass('disabled'); + + loadBootstrapSlider(function() { + saveSnapshotViewDuration = options.duration; + var start_ms = Math.round(Date.now() - saveSnapshotViewDuration * 1000); + + if(NETDATA.globalPanAndZoom.isActive() === true) { + saveSnapshotViewDuration = Math.round((NETDATA.globalPanAndZoom.force_before_ms - NETDATA.globalPanAndZoom.force_after_ms) / 1000); + start_ms = NETDATA.globalPanAndZoom.force_after_ms; + } + + var start_date = new Date(start_ms); + var yyyymmddhhssmm = start_date.getFullYear() + NETDATA.zeropad(start_date.getMonth() + 1) + NETDATA.zeropad(start_date.getDate()) + '-' + NETDATA.zeropad(start_date.getHours()) + NETDATA.zeropad(start_date.getMinutes()) + NETDATA.zeropad(start_date.getSeconds()); + + document.getElementById('saveSnapshotFilename').value = 'netdata-' + options.hostname.toString() + '-' + yyyymmddhhssmm.toString() + '-' + saveSnapshotViewDuration.toString() + '.snapshot' + saveSnapshotSetCompression(saveSnapshotCompression); + + var min = options.update_every; + var max = Math.round(saveSnapshotViewDuration / 100); + + if(NETDATA.globalPanAndZoom.isActive() === false) + max = Math.round(saveSnapshotViewDuration / 50); + + var view = Math.round(saveSnapshotViewDuration / Math.round($(document.getElementById('charts_div')).width() / 2)); + + // console.log('view duration: ' + saveSnapshotViewDuration + ', min: ' + min + ', max: ' + max + ', view: ' + view); + + if(max < 10) max = 10; + if(max < min) max = min; + if(view < min) view = min; + if(view > max) view = max; + + if(saveSnapshotSlider !== null) + saveSnapshotSlider.destroy(); + + saveSnapshotSlider = new Slider('#saveSnapshotResolutionSlider', { + ticks: [ min, view, max ], + min: min, + max: max, + step: options.update_every, + value: view, + scale: (max > 100)?'logarithmic':'linear', + tooltip: 'always', + formatter: function(value) { + if(value < 1) + value = 1; + + if(value < options.data.update_every) + value = options.data.update_every; + + saveSnapshotSelectedSecondsPerPoint = value; + saveSnapshotModalShowExpectedSize(); + + var seconds = ' seconds '; + if(value === 1) + seconds = ' second '; + + return value + seconds + 'per point' + ((value === options.data.update_every)?', server default':'').toString(); + } + }); + }); + } + + function saveSnapshot() { + loadPako(function () { + loadLzString(function () { + saveSnapshotStop = false; + $('#saveSnapshotModalProgressSection').show(); + $('#saveSnapshotResolutionRadio').hide(); + $('#saveSnapshotExport').addClass('disabled'); + + var filename = document.getElementById('saveSnapshotFilename').value; + // console.log(filename); + saveSnapshotModalLog('info', 'Generating snapshot as <code>' + filename.toString() + '</code>'); + + var save_options = { + stop_updates_when_focus_is_lost: false, + update_only_visible: false, + sync_selection: false, + eliminate_zero_dimensions: true, + pan_and_zoom_data_padding: false, + show_help: false, + legend_toolbox: false, + resize_charts: false, + pixels_per_point: 1 + }; + var backedup_options = {}; + + var x; + for (x in save_options) { + if (save_options.hasOwnProperty(x)) { + backedup_options[x] = NETDATA.options.current[x]; + NETDATA.options.current[x] = save_options[x]; + } + } + + var el = document.getElementById('saveSnapshotModalProgressBar'); + var eltxt = document.getElementById('saveSnapshotModalProgressBarText'); + + options.data.charts_by_name = null; + + var saveData = { + hostname: options.hostname, + server: NETDATA.serverDefault, + netdata_version: options.data.version, + snapshot_version: 1, + after_ms: Date.now() - options.duration * 1000, + before_ms: Date.now(), + highlight_after_ms: urlOptions.highlight_after, + highlight_before_ms: urlOptions.highlight_before, + duration_ms: options.duration * 1000, + update_every_ms: options.update_every * 1000, + data_points: 0, + url: ((urlOptions.server !== null) ? urlOptions.server : document.location.origin.toString() + document.location.pathname.toString() + document.location.search.toString()).toString(), + comments: document.getElementById('saveSnapshotComments').value.toString(), + hash: urlOptions.hash, + charts: options.data, + info: jsonStringifyFn({ + menu: netdataDashboard.menu, + submenu: netdataDashboard.submenu, + context: netdataDashboard.context + }), + charts_ok: 0, + charts_failed: 0, + compression: saveSnapshotCompression, + data_size: 0, + data: {} + }; + + if(typeof snapshotOptions.compressions[saveData.compression] === 'undefined') { + alert('unknown compression method: ' + saveData.compression); + saveData.compression = 'none'; + } + + var compress = snapshotOptions.compressions[saveData.compression].compress; + var compressed_length = snapshotOptions.compressions[saveData.compression].compressed_length; + + function pack_api1_v1_chart_data(state) { + if (state.library_name === null || state.data === null) + return; + + var data = state.data; + state.data = null; + data.state = null; + str = JSON.stringify(data); + + if (typeof str === 'string') { + var cstr = compress(str); + saveData.data[state.chartDataUniqueID()] = cstr; + return compressed_length(cstr); + } + else + return 0; + } + + var clearPanAndZoom = false; + if (NETDATA.globalPanAndZoom.isActive() === false) { + NETDATA.globalPanAndZoom.setMaster(NETDATA.options.targets[0], saveData.after_ms, saveData.before_ms); + clearPanAndZoom = true; + } + + saveData.after_ms = NETDATA.globalPanAndZoom.force_after_ms; + saveData.before_ms = NETDATA.globalPanAndZoom.force_before_ms; + saveData.duration_ms = saveData.before_ms - saveData.after_ms; + saveData.data_points = Math.round((saveData.before_ms - saveData.after_ms) / (saveSnapshotSelectedSecondsPerPoint * 1000)); + saveSnapshotModalLog('info', 'Generating snapshot with ' + saveData.data_points.toString() + ' data points per dimension...'); + + var charts_count = 0; + var charts_ok = 0; + var charts_failed = 0; + + function saveSnapshotRestore() { + $('#saveSnapshotModal').modal('hide'); + + // restore the options + var x; + for (x in backedup_options) { + if (backedup_options.hasOwnProperty(x)) + NETDATA.options.current[x] = backedup_options[x]; + } + + $(el).css('width', '0%').attr('aria-valuenow', 0); + eltxt.innerText = '0%'; + + if (clearPanAndZoom) + NETDATA.globalPanAndZoom.clearMaster(); + + NETDATA.options.force_data_points = 0; + NETDATA.options.fake_chart_rendering = false; + NETDATA.onscroll_updater_enabled = true; + NETDATA.onresize(); + NETDATA.unpause(); + + $('#saveSnapshotExport').removeClass('disabled'); + } + + NETDATA.globalSelectionSync.stop(); + NETDATA.options.force_data_points = saveData.data_points; + NETDATA.options.fake_chart_rendering = true; + NETDATA.onscroll_updater_enabled = false; + NETDATA.abort_all_refreshes(); + + var size = 0; + var info = ' Resolution: <b>' + saveSnapshotSelectedSecondsPerPoint.toString() + ((saveSnapshotSelectedSecondsPerPoint === 1)?' second ':' seconds ').toString() + 'per point</b>.'; + + function update_chart(idx) { + if (saveSnapshotStop === true) { + saveSnapshotModalLog('info', 'Cancelled!'); + saveSnapshotRestore(); + return; + } + + var state = NETDATA.options.targets[--idx]; + + var pcent = (NETDATA.options.targets.length - idx) * 100 / NETDATA.options.targets.length; + $(el).css('width', pcent + '%').attr('aria-valuenow', pcent); + eltxt.innerText = Math.round(pcent).toString() + '%, ' + state.id; + + setTimeout(function () { + charts_count++; + state.isVisible(true); + state.current.force_after_ms = saveData.after_ms; + state.current.force_before_ms = saveData.before_ms; + + state.updateChart(function (status, reason) { + state.current.force_after_ms = null; + state.current.force_before_ms = null; + + if (status === true) { + charts_ok++; + // state.log('ok'); + size += pack_api1_v1_chart_data(state); + } + else { + charts_failed++; + state.log('failed to be updated: ' + reason); + } + + saveSnapshotModalLog((charts_failed) ? 'danger' : 'info', 'Generated snapshot data size <b>' + (Math.round(size * 100 / 1024 / 1024) / 100).toString() + ' MB</b>. ' + ((charts_failed) ? (charts_failed.toString() + ' charts have failed to be downloaded') : '').toString() + info); + + if (idx > 0) { + update_chart(idx); + } + else { + saveData.charts_ok = charts_ok; + saveData.charts_failed = charts_failed; + saveData.data_size = size; + // console.log(saveData.compression + ': ' + (size / (options.data.dimensions_count * Math.round(saveSnapshotViewDuration / saveSnapshotSelectedSecondsPerPoint))).toString()); + + // save it + // console.log(saveData); + saveObjectToClient(saveData, filename); + + if (charts_failed > 0) + alert(charts_failed.toString() + ' failed to be downloaded'); + + saveSnapshotRestore(); + saveData = null; + } + }) + }, 0); + } + + update_chart(NETDATA.options.targets.length); + }); + }); + } + + // -------------------------------------------------------------------- + // activate netdata on the page + + function dashboardSettingsSetup() { + var update_options_modal = function() { + // console.log('update_options_modal'); + + var sync_option = function(option) { + var self = $('#' + option); + + if(self.prop('checked') !== NETDATA.getOption(option)) { + // console.log('switching ' + option.toString()); + self.bootstrapToggle(NETDATA.getOption(option)?'on':'off'); + } + }; + + var theme_sync_option = function(option) { + var self = $('#' + option); + + self.bootstrapToggle(netdataTheme === 'slate'?'on':'off'); + }; + var units_sync_option = function(option) { + var self = $('#' + option); + + if(self.prop('checked') !== (NETDATA.getOption('units') === 'auto')) { + self.bootstrapToggle(NETDATA.getOption('units') === 'auto' ? 'on' : 'off'); + } + + if(self.prop('checked') === true) { + $('#settingsLocaleTempRow').show(); + $('#settingsLocaleTimeRow').show(); + } + else { + $('#settingsLocaleTempRow').hide(); + $('#settingsLocaleTimeRow').hide(); + } + }; + var temp_sync_option = function(option) { + var self = $('#' + option); + + if(self.prop('checked') !== (NETDATA.getOption('temperature') === 'celsius')) { + self.bootstrapToggle(NETDATA.getOption('temperature') === 'celsius' ? 'on' : 'off'); + } + }; + var timezone_sync_option = function(option) { + var self = $('#' + option); + + document.getElementById('browser_timezone').innerText = NETDATA.options.browser_timezone; + document.getElementById('server_timezone').innerText = NETDATA.options.server_timezone; + document.getElementById('current_timezone').innerText = (NETDATA.options.current.timezone === 'default')?'unset, using browser default':NETDATA.options.current.timezone; + + if(self.prop('checked') === NETDATA.dateTime.using_timezone) { + self.bootstrapToggle(NETDATA.dateTime.using_timezone ? 'off' : 'on'); + } + }; + + sync_option('eliminate_zero_dimensions'); + sync_option('destroy_on_hide'); + sync_option('async_on_scroll'); + sync_option('parallel_refresher'); + sync_option('concurrent_refreshes'); + sync_option('sync_selection'); + sync_option('sync_pan_and_zoom'); + sync_option('stop_updates_when_focus_is_lost'); + sync_option('smooth_plot'); + sync_option('pan_and_zoom_data_padding'); + sync_option('show_help'); + sync_option('seconds_as_time'); + theme_sync_option('netdata_theme_control'); + units_sync_option('units_conversion'); + temp_sync_option('units_temp'); + timezone_sync_option('local_timezone'); + + if(NETDATA.getOption('parallel_refresher') === false) { + $('#concurrent_refreshes_row').hide(); + } + else { + $('#concurrent_refreshes_row').show(); + } + }; + NETDATA.setOption('setOptionCallback', update_options_modal); + + // handle options changes + $('#eliminate_zero_dimensions').change(function() { NETDATA.setOption('eliminate_zero_dimensions', $(this).prop('checked')); }); + $('#destroy_on_hide').change(function() { NETDATA.setOption('destroy_on_hide', $(this).prop('checked')); }); + $('#async_on_scroll').change(function() { NETDATA.setOption('async_on_scroll', $(this).prop('checked')); }); + $('#parallel_refresher').change(function() { NETDATA.setOption('parallel_refresher', $(this).prop('checked')); }); + $('#concurrent_refreshes').change(function() { NETDATA.setOption('concurrent_refreshes', $(this).prop('checked')); }); + $('#sync_selection').change(function() { NETDATA.setOption('sync_selection', $(this).prop('checked')); }); + $('#sync_pan_and_zoom').change(function() { NETDATA.setOption('sync_pan_and_zoom', $(this).prop('checked')); }); + $('#stop_updates_when_focus_is_lost').change(function() { + urlOptions.update_always = !$(this).prop('checked'); + urlOptions.hashUpdate(); + + NETDATA.setOption('stop_updates_when_focus_is_lost', !urlOptions.update_always); + }); + $('#smooth_plot').change(function() { NETDATA.setOption('smooth_plot', $(this).prop('checked')); }); + $('#pan_and_zoom_data_padding').change(function() { NETDATA.setOption('pan_and_zoom_data_padding', $(this).prop('checked')); }); + $('#seconds_as_time').change(function() { NETDATA.setOption('seconds_as_time', $(this).prop('checked')); }); + $('#local_timezone').change(function() { + if($(this).prop('checked')) + selected_server_timezone('default', true); + else + selected_server_timezone('default', false); + }); + + + $('#units_conversion').change(function() { + NETDATA.setOption('units', $(this).prop('checked')?'auto':'original'); + }); + $('#units_temp').change(function() { + NETDATA.setOption('temperature', $(this).prop('checked')?'celsius':'fahrenheit'); + }); + + $('#show_help').change(function() { + urlOptions.help = $(this).prop('checked'); + urlOptions.hashUpdate(); + + NETDATA.setOption('show_help', urlOptions.help); + netdataReload(); + }); + + // this has to be the last + // it reloads the page + $('#netdata_theme_control').change(function() { + urlOptions.theme = $(this).prop('checked')?'slate':'white'; + urlOptions.hashUpdate(); + + if(setTheme(urlOptions.theme)) + netdataReload(); + }); + } + + function scrollDashboardTo() { + if(netdataSnapshotData !== null && typeof netdataSnapshotData.hash !== 'undefined') { + //console.log(netdataSnapshotData.hash); + scrollToId(netdataSnapshotData.hash.replace('#','')); + } + else { + // check if we have to jump to a specific section + scrollToId(urlOptions.hash.replace('#', '')); + + if (urlOptions.chart !== null) { + NETDATA.alarms.scrollToChart(urlOptions.chart); + //urlOptions.hash = '#' + NETDATA.name2id('menu_' + charts[c].menu + '_submenu_' + charts[c].submenu); + //urlOptions.hash = '#chart_' + NETDATA.name2id(urlOptions.chart); + //console.log('hash = ' + urlOptions.hash); + } + } + } + + var modalHiddenCallback = null; + function scrollToChartAfterHidingModal(chart) { + modalHiddenCallback = function() { + NETDATA.alarms.scrollToChart(chart); + }; + } + + var runOnceOnDashboardLastRun = 0; + function runOnceOnDashboardWithjQuery() { + if(runOnceOnDashboardLastRun !== 0) { + scrollDashboardTo(); + + // restore the scrollspy at the proper position + $(document.body).scrollspy('refresh'); + $(document.body).scrollspy('process'); + + return; + } + + runOnceOnDashboardLastRun = Date.now(); + + // ------------------------------------------------------------------------ + // bootstrap modals + + // prevent bootstrap modals from scrolling the page + // maintains the current scroll position + // https://stackoverflow.com/a/34754029/4525767 + + var scrollPos = 0; + var modal_depth = 0; // how many modals are currently open + var modal_shown = false; // set to true, if a modal is shown + var netdata_paused_on_modal = false; // set to true, if the modal paused netdata + var scrollspyOffset = $(window).height() / 3; // will be updated below - the offset of scrollspy to select an item + + $('.modal') + .on('show.bs.modal', function () { + if(modal_depth === 0) { + scrollPos = window.scrollY; + + $('body').css({ + overflow: 'hidden', + position: 'fixed', + top: -scrollPos + }); + + modal_shown = true; + + if (NETDATA.options.pauseCallback === null) { + NETDATA.pause(function () {}); + netdata_paused_on_modal = true; + } + else + netdata_paused_on_modal = false; + } + + modal_depth++; + //console.log(urlOptions.after); + + }) + .on('hide.bs.modal', function () { + + modal_depth--; + + if(modal_depth <= 0) { + modal_depth = 0; + + $('body') + .css({ + overflow: '', + position: '', + top: '' + }); + + // scroll to the position we had open before the modal + $('html, body') + .animate({scrollTop: scrollPos}, 0); + + // unpause netdata, if we paused it + if (netdata_paused_on_modal === true) { + NETDATA.unpause(); + netdata_paused_on_modal = false; + } + + // restore the scrollspy at the proper position + $(document.body).scrollspy('process'); + } + //console.log(urlOptions.after); + }) + .on('hidden.bs.modal', function () { + if(modal_depth === 0) + modal_shown = false; + + if(typeof modalHiddenCallback === 'function') + modalHiddenCallback(); + + modalHiddenCallback = null; + //console.log(urlOptions.after); + }); + + // ------------------------------------------------------------------------ + // sidebar / affix + + $('#sidebar') + .affix({ + offset: { + top: (isdemo())?150:0, + bottom: 0 + } + }) + .on('affixed.bs.affix', function() { + // fix scrolling of very long affix lists + // http://stackoverflow.com/questions/21691585/bootstrap-3-1-0-affix-too-long + + $(this).removeAttr('style'); + }) + .on( 'affix-top.bs.affix', function() { + // fix bootstrap affix click bug + // https://stackoverflow.com/a/37847981/4525767 + + if(modal_shown) return false; + }) + .on('activate.bs.scrollspy', function (e) { + // change the URL based on the current position of the screen + + if(modal_shown === false) { + var el = $(e.target); + var hash = el.find('a').attr('href'); + if (typeof hash === 'string' && hash.substring(0, 1) === '#' && urlOptions.hash.startsWith(hash + '_submenu_') === false) { + urlOptions.hash = hash; + urlOptions.hashUpdate(); + } + } + }); + + Ps.initialize(document.getElementById('sidebar'), { + wheelSpeed: 0.5, + wheelPropagation: true, + swipePropagation: true, + minScrollbarLength: null, + maxScrollbarLength: null, + useBothWheelAxes: false, + suppressScrollX: true, + suppressScrollY: false, + scrollXMarginOffset: 0, + scrollYMarginOffset: 0, + theme: 'default' + }); + + + // ------------------------------------------------------------------------ + // scrollspy + + if(scrollspyOffset > 250) scrollspyOffset = 250; + if(scrollspyOffset < 75) scrollspyOffset = 75; + document.body.setAttribute('data-offset', scrollspyOffset); + + // scroll the dashboard, before activating the scrollspy, so that our + // hash will not be updated before we got the chance to scroll to it + scrollDashboardTo(); + + $(document.body).scrollspy({ + target: '#sidebar', + offset: scrollspyOffset // controls the diff of the <hX> element to the top, to select it + }); + + + // ------------------------------------------------------------------------ + // my-netdata menu + + Ps.initialize(document.getElementById('myNetdataDropdownUL'), { + wheelSpeed: 1, + wheelPropagation: false, + swipePropagation: false, + minScrollbarLength: null, + maxScrollbarLength: null, + useBothWheelAxes: false, + suppressScrollX: true, + suppressScrollY: false, + scrollXMarginOffset: 0, + scrollYMarginOffset: 0, + theme: 'default' + }); + + $('#myNetdataDropdownParent') + .on('show.bs.dropdown', function () { + var hash = urlOptions.genHash(); + $('.registry_link').each(function(idx) { + this.setAttribute('href', this.getAttribute("href").replace(/#.*$/, hash)); + }); + + NETDATA.pause(function() {}); + }) + .on('shown.bs.dropdown', function () { + Ps.update(document.getElementById('myNetdataDropdownUL')); + }) + .on('hidden.bs.dropdown', function () { + NETDATA.unpause(); + }); + + + $('#deleteRegistryModal') + .on('hidden.bs.modal', function() { + deleteRegistryGuid = null; + }); + + + // ------------------------------------------------------------------------ + // update modal + + $('#updateModal') + .on('show.bs.modal', function() { + versionLog('checking, please wait...'); + }) + .on('shown.bs.modal', function() { + notifyForUpdate(true); + }); + + + // ------------------------------------------------------------------------ + // alarms modal + + $('#alarmsModal') + .on('shown.bs.modal', function() { + alarmsUpdateModal(); + }) + .on('hidden.bs.modal', function() { + document.getElementById('alarms_active').innerHTML = + document.getElementById('alarms_all').innerHTML = + document.getElementById('alarms_log').innerHTML = + 'loading...'; + }); + + + // ------------------------------------------------------------------------ + + dashboardSettingsSetup(); + loadSnapshotDragAndDropSetup(); + saveSnapshotModalSetup(); + showPageFooter(); + // ------------------------------------------------------------------------ // https://github.com/viralpatel/jquery.shorten/blob/master/src/jquery.shorten.js + $.fn.shorten = function(settings) { "use strict"; @@ -2579,8 +4047,8 @@ showChars: 750, minHideChars: 10, ellipsesText: "...", - moreText: '<i class="fa fa-expand" aria-hidden="true"></i> show more information', - lessText: '<i class="fa fa-compress" aria-hidden="true"></i> show less information', + moreText: '<i class="fas fa-expand"></i> show more information', + lessText: '<i class="fas fa-compress"></i> show less information', onLess: function() { NETDATA.onscroll(); }, onMore: function() { NETDATA.onscroll(); }, errMsg: null, @@ -2692,178 +4160,53 @@ } var html = '<div class="shortcontent">' + c + - '</div><div class="allcontent">' + content + - '</div><span><a href="javascript://nop/" class="morelink">' + config.moreText + '</a></span>'; + '</div><div class="allcontent">' + content + + '</div><span><a href="javascript://nop/" class="morelink">' + config.moreText + '</a></span>'; $this.html(html); $this.find(".allcontent").hide(); // Hide all text $('.shortcontent p:last', $this).css('margin-bottom', 0); //Remove bottom margin on last paragraph as it's likely shortened } }); - }; - $(".chart-message").shorten(); - // ------------------------------------------------------------------------ - - // callback for us to track PanAndZoom operations - NETDATA.globalPanAndZoom.callback = urlOptions.netdataPanAndZoomCallback; - - // let it run (update the charts) - NETDATA.unpause(); - - // check if we have to jump to a specific section - scrollToId(urlOptions.hash.replace('#','')); - - if(urlOptions.chart !== null) { - NETDATA.alarms.scrollToChart(urlOptions.chart); - //urlOptions.hash = '#' + NETDATA.name2id('menu_' + charts[c].menu + '_submenu_' + charts[c].submenu); - //urlOptions.hash = '#chart_' + NETDATA.name2id(urlOptions.chart); - //console.log('hash = ' + urlOptions.hash); - } - - var $sidebar = $('#sidebar'); - /* activate bootstrap sidebar (affix) */ - $sidebar.affix({ - offset: { - top: (isdemo())?150:0, - bottom: 0 - } - }); - - /* fix scrolling of very long affix lists - http://stackoverflow.com/questions/21691585/bootstrap-3-1-0-affix-too-long - */ - $sidebar.on('affixed.bs.affix', function() { - $(this).removeAttr('style'); - }); - - /* activate bootstrap scrollspy (needed for sidebar) */ - var scrollspyOffset = $(window).height() / 5; - if(scrollspyOffset > 200) scrollspyOffset = 200; - if(scrollspyOffset < 50) scrollspyOffset = 50; - $(document.body).scrollspy({ - target: '#sidebar', - offset: scrollspyOffset // controls the diff of the <hX> element to the top, to select it - }); - - // change the URL based on the current position of the screen - $sidebar.on('activate.bs.scrollspy', function (e) { - //console.log(e); - var el = $(e.target); - //if(el.find('ul').size() === 0) { - var hash = el.find('a').attr('href'); - // console.log(hash); - if(typeof hash === 'string' && hash.substring(0, 1) === '#' && urlOptions.hash.startsWith(hash + '_submenu_') === false) { - urlOptions.hash = hash; - //console.log(urlOptions.hash); - urlOptions.hashUpdate(); - } - //else console.log('hash: not accepting ' + hash); - //} - //else console.log('el.find(): not found'); - }); - - document.getElementById('footer').style.display = 'block'; - - var update_options_modal = function() { - // console.log('update_options_modal'); - - var sync_option = function(option) { - var self = $('#' + option); - - if(self.prop('checked') !== NETDATA.getOption(option)) { - // console.log('switching ' + option.toString()); - self.bootstrapToggle(NETDATA.getOption(option)?'on':'off'); - } - }; - - var theme_sync_option = function(option) { - var self = $('#' + option); - - self.bootstrapToggle(netdataTheme === 'slate'?'on':'off'); - }; - - sync_option('eliminate_zero_dimensions'); - sync_option('destroy_on_hide'); - sync_option('async_on_scroll'); - sync_option('parallel_refresher'); - sync_option('concurrent_refreshes'); - sync_option('sync_selection'); - sync_option('sync_pan_and_zoom'); - sync_option('stop_updates_when_focus_is_lost'); - sync_option('smooth_plot'); - sync_option('pan_and_zoom_data_padding'); - sync_option('show_help'); - theme_sync_option('netdata_theme_control'); + } - if(NETDATA.getOption('parallel_refresher') === false) { - $('#concurrent_refreshes_row').hide(); - } - else { - $('#concurrent_refreshes_row').show(); - } - }; - NETDATA.setOption('setOptionCallback', update_options_modal); + function finalizePage() { + // resize all charts - without starting the background thread + // this has to be done while NETDATA is paused + // if we ommit this, the affix menu will be wrong, since all + // the Dom elements are initially zero-sized + NETDATA.parseDom(); - // handle options changes - $('#eliminate_zero_dimensions').change(function() { NETDATA.setOption('eliminate_zero_dimensions', $(this).prop('checked')); }); - $('#destroy_on_hide').change(function() { NETDATA.setOption('destroy_on_hide', $(this).prop('checked')); }); - $('#async_on_scroll').change(function() { NETDATA.setOption('async_on_scroll', $(this).prop('checked')); }); - $('#parallel_refresher').change(function() { NETDATA.setOption('parallel_refresher', $(this).prop('checked')); }); - $('#concurrent_refreshes').change(function() { NETDATA.setOption('concurrent_refreshes', $(this).prop('checked')); }); - $('#sync_selection').change(function() { NETDATA.setOption('sync_selection', $(this).prop('checked')); }); - $('#sync_pan_and_zoom').change(function() { NETDATA.setOption('sync_pan_and_zoom', $(this).prop('checked')); }); - $('#stop_updates_when_focus_is_lost').change(function() { - urlOptions.update_always = !$(this).prop('checked'); - urlOptions.hashUpdate(); + // ------------------------------------------------------------------------ - NETDATA.setOption('stop_updates_when_focus_is_lost', !urlOptions.update_always); - }); - $('#smooth_plot').change(function() { NETDATA.setOption('smooth_plot', $(this).prop('checked')); }); - $('#pan_and_zoom_data_padding').change(function() { NETDATA.setOption('pan_and_zoom_data_padding', $(this).prop('checked')); }); - $('#show_help').change(function() { - urlOptions.help = $(this).prop('checked'); - urlOptions.hashUpdate(); + NETDATA.globalPanAndZoom.callback = null; + NETDATA.globalChartUnderlay.callback = null; - NETDATA.setOption('show_help', urlOptions.help); - netdataReload(); - }); + if(urlOptions.pan_and_zoom === true && NETDATA.options.targets.length > 0) + NETDATA.globalPanAndZoom.setMaster(NETDATA.options.targets[0], urlOptions.after, urlOptions.before); - // this has to be the last - // it reloads the page - $('#netdata_theme_control').change(function() { - urlOptions.theme = $(this).prop('checked')?'slate':'white'; - urlOptions.hashUpdate(); + // callback for us to track PanAndZoom operations + NETDATA.globalPanAndZoom.callback = urlOptions.netdataPanAndZoomCallback; + NETDATA.globalChartUnderlay.callback = urlOptions.netdataHighlightCallback; - if(setTheme(urlOptions.theme)) - netdataReload(); - }); + // ------------------------------------------------------------------------ - var $updateModal = $('#updateModal'); - $updateModal.on('show.bs.modal', function() { - versionLog('checking, please wait...'); - }); + // let it run (update the charts) + NETDATA.unpause(); - $updateModal.on('shown.bs.modal', function() { - notifyForUpdate(true); - }); + runOnceOnDashboardWithjQuery(); + $(".shorten").shorten(); - var $alarmsModal = $('#alarmsModal'); - $alarmsModal.on('shown.bs.modal', function() { - NETDATA.pause(alarmsUpdateModal); + $('[data-toggle="tooltip"]').tooltip({ + animated: 'fade', + trigger: 'hover', + html: true, + delay: {show: 500, hide: 0}, + container: 'body' }); + $('[data-toggle="popover"]').popover(); - $alarmsModal.on('hidden.bs.modal', function() { - NETDATA.unpause(); - document.getElementById('alarms_active').innerHTML = - document.getElementById('alarms_all').innerHTML = - document.getElementById('alarms_log').innerHTML = - 'loading...'; - }); - - $('#deleteRegistryModal').on('hidden.bs.modal', function() { - deleteRegistryGuid = null; - }); if(isdemo()) { // do not to give errors on netdata demo servers for 60 seconds @@ -2892,53 +4235,15 @@ if(urlOptions.show_alarms === true) setTimeout(function() { $('#alarmsModal').modal('show'); }, 1000); - var sidebar = document.getElementById('sidebar'); - Ps.initialize(sidebar, { - wheelSpeed: 0.5, - wheelPropagation: true, - swipePropagation: true, - minScrollbarLength: null, - maxScrollbarLength: null, - useBothWheelAxes: false, - suppressScrollX: true, - suppressScrollY: false, - scrollXMarginOffset: 0, - scrollYMarginOffset: 0, - theme: 'default' - }); - Ps.update(sidebar); - - var registry = document.getElementById('myNetdataDropdownUL'); - Ps.initialize(registry, { - wheelSpeed: 1, - wheelPropagation: false, - swipePropagation: false, - minScrollbarLength: null, - maxScrollbarLength: null, - useBothWheelAxes: false, - suppressScrollX: true, - suppressScrollY: false, - scrollXMarginOffset: 0, - scrollYMarginOffset: 0, - theme: 'default' - }); - Ps.update(registry); - NETDATA.onresizeCallback = function() { - Ps.update(sidebar); - Ps.update(registry); + Ps.update(document.getElementById('sidebar')); + Ps.update(document.getElementById('myNetdataDropdownUL')); }; + NETDATA.onresizeCallback(); - $('#myNetdataDropdownParent') - .on('show.bs.dropdown', function () { - NETDATA.pause(function() {}); - }) - .on('shown.bs.dropdown', function () { - Ps.update(registry); - }) - .on('hidden.bs.dropdown', function () { - NETDATA.unpause(); - }); + if(netdataSnapshotData !== null) { + NETDATA.globalPanAndZoom.setMaster(NETDATA.options.targets[0], netdataSnapshotData.after_ms, netdataSnapshotData.before_ms); + } // var netdataEnded = performance.now(); // console.log('start up time: ' + (netdataEnded - netdataStarted).toString() + ' ms'); @@ -2959,17 +4264,17 @@ // parallel javascript downloader in netdata var netdataPrepCallback = function() { NETDATA.requiredCSS.push({ - url: NETDATA.serverDefault + 'css/bootstrap-toggle-2.2.2.min.css', + url: NETDATA.serverStatic + 'css/bootstrap-toggle-2.2.2.min.css', isAlreadyLoaded: function() { return false; } }); NETDATA.requiredJs.push({ - url: NETDATA.serverDefault + 'lib/bootstrap-toggle-2.2.2.min.js', + url: NETDATA.serverStatic + 'lib/bootstrap-toggle-2.2.2.min.js', isAlreadyLoaded: function() { return false; } }); NETDATA.requiredJs.push({ - url: NETDATA.serverDefault + 'dashboard_info.js?v20170916-1', + url: NETDATA.serverStatic + 'dashboard_info.js?v20171208-1', async: false, isAlreadyLoaded: function() { return false; } }); @@ -2983,13 +4288,68 @@ } }; + var selected_server_timezone = function(timezone, status) { + //console.log('called with timezone: ' + timezone + ", status: " + ((typeof status === 'undefined')?'undefined':status).toString()); + + // clear the error + document.getElementById('timezone_error_message').innerHTML = ''; + + if (typeof status === 'undefined') { + // the user selected a timezone from the menu + + NETDATA.setOption('user_set_server_timezone', timezone); + + if (NETDATA.dateTime.init(timezone) === false) { + NETDATA.dateTime.init(); + + if(!$('#local_timezone').prop('checked')) + $('#local_timezone').bootstrapToggle('on'); + + document.getElementById('timezone_error_message').innerHTML = 'Ooops! That timezone was not accepted by your browser. Please open a github issue to help us fix it.'; + NETDATA.setOption('user_set_server_timezone', NETDATA.options.server_timezone); + } + else { + if($('#local_timezone').prop('checked')) + $('#local_timezone').bootstrapToggle('off'); + } + } + else if (status === true) { + // the user wants the browser default timezone to be activated + + NETDATA.dateTime.init(); + } + else { + // the user wants the server default timezone to be activated + //console.log('found ' + NETDATA.options.current.user_set_server_timezone); + + if (NETDATA.options.current.user_set_server_timezone === 'default') + NETDATA.options.current.user_set_server_timezone = NETDATA.options.server_timezone; + + timezone = NETDATA.options.current.user_set_server_timezone; + + if (NETDATA.dateTime.init(timezone) === false) { + NETDATA.dateTime.init(); + + if(!$('#local_timezone').prop('checked')) + $('#local_timezone').bootstrapToggle('on'); + + document.getElementById('timezone_error_message').innerHTML = 'Sorry. The timezone "' + timezone.toString() + '" is not accepted by your browser. Please select one from the list.'; + NETDATA.setOption('user_set_server_timezone', NETDATA.options.server_timezone); + } + } + + document.getElementById('current_timezone').innerText = (NETDATA.options.current.timezone === 'default')?'unset, using browser default':NETDATA.options.current.timezone; + return false; + } + // our entry point // var netdataStarted = performance.now(); + var netdataCallback = initializeDynamicDashboard; </script> </head> -<body data-spy="scroll" data-target="#sidebar"> +<body data-spy="scroll" data-target="#sidebar" data-offset="100"> <div id="loadOverlay" class="loadOverlay" style="background-color: #888; color: #888;"> netdata<br/><div style="font-size: 3vh;">Real-time performance monitoring, done right!</div> </div> @@ -3001,7 +4361,7 @@ <div class="container"> <nav id="mynetdata_nav" class="collapse navbar-collapse navbar-left hidden-sm hidden-xs" role="navigation" style="padding-right: 20px;"> <ul class="nav navbar-nav"> - <li class="dropdown" id="myNetdataDropdownParent"> + <li class="dropdown" id="myNetdataDropdownParent" title="your other netdata servers" data-toggle="tooltip" data-placement="right"> <a href="#" class="dropdown-toggle" data-toggle="dropdown">my-netdata <strong class="caret"></strong></a> <ul class="dropdown-menu scrollable-menu inpagemenu multi-column columns-2" role="menu" id="myNetdataDropdownUL"> <div class="row"> @@ -3027,17 +4387,20 @@ <span class="icon-bar"></span> <span class="icon-bar"></span> </button> - <a href="/" class="navbar-brand" id="hostname" title="reload the dashboard">netdata</a> + <a href="/" class="navbar-brand" id="hostname" title="server hostname<br/>click it to reload the dashboard" data-toggle="tooltip" data-placement="bottom">netdata</a> </div> <nav class="collapse navbar-collapse navbar-right" role="navigation"> <ul class="nav navbar-nav"> - <li><a href="#" class="btn" data-toggle="modal" data-target="#alarmsModal" title="alarms"><i class="fa fa-bell"></i> <span class="hidden-sm">Alarms </span><span id="alarms_count_badge" class="badge"></span></a></li> - <li><a href="#" class="btn" data-toggle="modal" data-target="#optionsModal" title="dashboard settings"><i class="fa fa-sliders"></i> <span class="hidden-sm">Settings</span></a></li> - <li class="hidden-sm" id="updateButton"><a href="#" class="btn" data-toggle="modal" data-target="#updateModal" title="check for update"><i class="fa fa-cloud-download"></i> <span class="hidden-sm hidden-md">Update </span><span id="update_badge" class="badge"></span></a></li> - <li><a href="https://github.com/firehol/netdata/wiki" class="btn" target="_blank" title="netdata on github"><i class="fa fa-github"></i></a></li> - <li><a href="https://twitter.com/linuxnetdata" class="btn" target="_blank" title="netdata on twitter"><i class="fa fa-twitter" aria-hidden="true"></i></a></li> - <li><a href="https://www.facebook.com/linuxnetdata/" class="btn" target="_blank" title="netdata on facebook"><i class="fa fa-facebook-official" aria-hidden="true"></i></a></li> - <li class="hidden-sm"><a href="#" class="btn" data-toggle="modal" data-target="#helpModal" title="dashboard help"><i class="fa fa-question-circle"></i> <span class="hidden-sm hidden-md">Help</span></a></li> + <li id="alarmsButton" title="check the health monitoring alarms and their log" data-toggle="tooltip" data-placement="bottom"><a href="#" class="btn" data-toggle="modal" data-target="#alarmsModal"><i class="fas fa-bell"></i> <span class="hidden-sm hidden-md">Alarms </span><span id="alarms_count_badge" class="badge"></span></a></li> + <li title="change dashboard settings" data-toggle="tooltip" data-placement="bottom"><a href="#" class="btn" data-toggle="modal" data-target="#optionsModal"><i class="fas fa-cog"></i> <span class="hidden-sm hidden-md">Settings</span></a></li> + <li title="check for netdata updates<br/>you should keep your netdata updated" data-toggle="tooltip" data-placement="bottom" class="hidden-sm" id="updateButton"><a href="#" class="btn" data-toggle="modal" data-target="#updateModal"><i class="fas fa-cloud-download-alt"></i> <span class="hidden-sm hidden-md">Update </span><span id="update_badge" class="badge"></span></a></li> + <li title="the netdata wiki home at github<br/>remember to <b>give netdata a <i class="fas fa-star"></i></b> !" data-toggle="tooltip" data-placement="bottom" class="hidden-sm hidden-md"><a href="https://github.com/firehol/netdata/wiki" class="btn" target="_blank"><i class="fab fa-github"></i></a></li> + <li title="follow netdata on twitter" data-toggle="tooltip" data-placement="bottom" class="hidden-sm hidden-md"><a href="https://twitter.com/linuxnetdata" class="btn" target="_blank"><i class="fab fa-twitter"></i></a></li> + <li title="like netdata on facebook" data-toggle="tooltip" data-placement="bottom" class="hidden-sm hidden-md"><a href="https://www.facebook.com/linuxnetdata/" class="btn" target="_blank"><i class="fab fa-facebook"></i></a></li> + <li title="import / load a netdata snapshot" data-toggle="tooltip" data-placement="bottom" id="loadButton"><a href="#" class="btn" data-toggle="modal" data-target="#loadSnapshotModal"><i class="fas fa-download"></i> <span class="hidden-sm hidden-md hidden-lg">Import</span></a></li> + <li title="export / save a netdata snapshot" data-toggle="tooltip" data-placement="bottom" id="saveButton"><a href="#" class="btn" data-toggle="modal" data-target="#saveSnapshotModal"><i class="fas fa-upload"></i> <span class="hidden-sm hidden-md hidden-lg">Export</span></a></li> + <li title="print this dashboard to PDF" data-toggle="tooltip" data-placement="bottom" id="printButton"><a href="#" class="btn" data-toggle="modal" data-target="#printPreflightModal"><i class="fas fa-print"></i> <span class="hidden-sm hidden-md hidden-lg">Print</span></a></li> + <li title="get help on using the charts" data-toggle="tooltip" data-placement="bottom" class="hidden-sm"><a href="#" class="btn" data-toggle="modal" data-target="#helpModal"><i class="fas fa-question-circle"></i> <span class="hidden-sm hidden-md">Help</span></a></li> <li class="dropdown hidden-sm hidden-md hidden-lg"> <a href="#" class="dropdown-toggle" data-toggle="dropdown">my-netdata <strong class="caret"></strong></a> <ul id="mynetdata_servers2" class="dropdown-menu scrollable-menu inpagemenu" role="menu"> @@ -3048,6 +4411,9 @@ </nav> </div> </nav> + <div class="navbar-highlight"> + <div id="navbar-highlight-content" class="navbar-highlight-content"></div> + </div> <div id="masthead" style="display: none;"> <div class="container"> @@ -3081,7 +4447,7 @@ <div class="charts-body" role="main"> <div id="charts_div"></div> </div> - <div class="sidebar-body hidden-xs hidden-sm" id="sidebar-body" role="complementary"> + <div class="sidebar-body hidden-xs hidden-sm hidden-print" id="sidebar-body" role="complementary"> <nav class="dashboard-sidebar hidden-print hidden-xs hidden-sm" id="sidebar" role="menu"></nav> </div> </div> @@ -3092,44 +4458,44 @@ <div class="col-md-10" role="main"> <div class="p"> <big><a href="https://github.com/firehol/netdata/wiki" target="_blank">netdata</a></big><br/> - <i class="fa fa-copyright"></i> Copyright 2016-2017, <a href="mailto:costa@tsaousis.gr">Costa Tsaousis</a>.<br/> + <i class="fas fa-copyright"></i> Copyright 2016-2017, <a href="mailto:costa@tsaousis.gr">Costa Tsaousis</a>.<br/> Released under <a href="http://www.gnu.org/licenses/gpl-3.0.en.html" target="_blank">GPL v3 or later</a>.<br/> </div> <div class="p"> <small> <a href="https://github.com/firehol/netdata/wiki" target="_blank">netdata</a> re-distributes these software tools: - <i class="fa fa-circle"></i> The excellent <a href="http://dygraphs.com/" target="_blank">Dygraphs.com</a> web chart library, - <i class="fa fa-copyright"></i> Copyright 2009, Dan Vanderkam, <a href="http://dygraphs.com/legal.html" target="_blank">MIT License</a> + <i class="fas fa-circle"></i> The excellent <a href="http://dygraphs.com/" target="_blank">Dygraphs.com</a> web chart library, + <i class="fas fa-copyright"></i> Copyright 2009, Dan Vanderkam, <a href="http://dygraphs.com/legal.html" target="_blank">MIT License</a> - <i class="fa fa-circle"></i> <a href="https://rendro.github.io/easy-pie-chart/" target="_blank">Easy Pie Chart</a> web chart library, - <i class="fa fa-copyright"></i> Copyright 2013, Robert Fleischmann, <a href="https://github.com/rendro/easy-pie-chart/blob/master/LICENSE" target="_blank">MIT License</a> + <i class="fas fa-circle"></i> <a href="https://rendro.github.io/easy-pie-chart/" target="_blank">Easy Pie Chart</a> web chart library, + <i class="fas fa-copyright"></i> Copyright 2013, Robert Fleischmann, <a href="https://github.com/rendro/easy-pie-chart/blob/master/LICENSE" target="_blank">MIT License</a> - <i class="fa fa-circle"></i> <a href="http://bernii.github.io/gauge.js/" target="_blank">Gauge.js</a> web chart library, - <i class="fa fa-copyright"></i> Copyright, Bernard Kobos, <a href="http://bernii.github.io/gauge.js/" target="_blank">MIT License</a> + <i class="fas fa-circle"></i> <a href="http://bernii.github.io/gauge.js/" target="_blank">Gauge.js</a> web chart library, + <i class="fas fa-copyright"></i> Copyright, Bernard Kobos, <a href="http://bernii.github.io/gauge.js/" target="_blank">MIT License</a> - <i class="fa fa-circle"></i> <a href="https://jquery.org/" target="_blank">jQuery</a>, - <i class="fa fa-copyright"></i> Copyright 2015, jQuery Foundation, <a href="https://jquery.org/license/" target="_blank">MIT License</a> + <i class="fas fa-circle"></i> <a href="https://jquery.org/" target="_blank">jQuery</a>, + <i class="fas fa-copyright"></i> Copyright 2015, jQuery Foundation, <a href="https://jquery.org/license/" target="_blank">MIT License</a> - <i class="fa fa-circle"></i> <a href="http://getbootstrap.com/getting-started/" target="_blank">Bootstrap</a>, - <i class="fa fa-copyright"></i> Copyright 2015, Twitter, <a href="http://getbootstrap.com/getting-started/#license-faqs" target="_blank">MIT License</a> + <i class="fas fa-circle"></i> <a href="http://getbootstrap.com/getting-started/" target="_blank">Bootstrap</a>, + <i class="fas fa-copyright"></i> Copyright 2015, Twitter, <a href="http://getbootstrap.com/getting-started/#license-faqs" target="_blank">MIT License</a> - <i class="fa fa-circle"></i> <a href="http://www.bootstraptoggle.com/" target="_blank">Bootstrap Toggle</a>, - <i class="fa fa-copyright"></i> Copyright (c) 2011-2014 Min Hur, The New York Times Company, <a href="https://github.com/minhur/bootstrap-toggle/blob/master/LICENSE" target="_blank">MIT License</a> + <i class="fas fa-circle"></i> <a href="http://www.bootstraptoggle.com/" target="_blank">Bootstrap Toggle</a>, + <i class="fas fa-copyright"></i> Copyright (c) 2011-2014 Min Hur, The New York Times Company, <a href="https://github.com/minhur/bootstrap-toggle/blob/master/LICENSE" target="_blank">MIT License</a> - <i class="fa fa-circle"></i> <a href="https://github.com/noraesae/perfect-scrollbar" target="_blank">perfect-scrollbar</a>, - <i class="fa fa-copyright"></i> Copyright 2016, Hyunje Alex Jun and other contributors, <a href="https://github.com/noraesae/perfect-scrollbar/blob/master/LICENSE" target="_blank">MIT License</a> + <i class="fas fa-circle"></i> <a href="https://github.com/noraesae/perfect-scrollbar" target="_blank">perfect-scrollbar</a>, + <i class="fas fa-copyright"></i> Copyright 2016, Hyunje Alex Jun and other contributors, <a href="https://github.com/noraesae/perfect-scrollbar/blob/master/LICENSE" target="_blank">MIT License</a> - <i class="fa fa-circle"></i> <a href="https://fortawesome.github.io/Font-Awesome/" target="_blank">FontAwesome</a>, - <i class="fa fa-copyright"></i> Created by Dave Gandy, Font: <a href="http://scripts.sil.org/OFL" target="_blank">SIL OFL 1.1 License</a>, CSS: <a href="http://opensource.org/licenses/mit-license.html" target="_blank">MIT License</a> + <i class="fas fa-circle"></i> <a href="https://fortawesome.github.io/Font-Awesome/" target="_blank">FontAwesome</a>, + <i class="fas fa-copyright"></i> Created by Dave Gandy, Font: <a href="http://scripts.sil.org/OFL" target="_blank">SIL OFL 1.1 License</a>, CSS: <a href="http://opensource.org/licenses/mit-license.html" target="_blank">MIT License</a> - <i class="fa fa-circle"></i> <a href="http://www.iconsdb.com/soylent-red-icons/seo-performance-icon.html" target="_blank">IconsDB.com Icons</a>, Icons provided as CC0 1.0 Universal (CC0 1.0) Public Domain Dedication. + <i class="fas fa-circle"></i> <a href="http://www.iconsdb.com/soylent-red-icons/seo-performance-icon.html" target="_blank">IconsDB.com Icons</a>, Icons provided as CC0 1.0 Universal (CC0 1.0) Public Domain Dedication. - <i class="fa fa-circle"></i> <a href="http://bootstrap-table.wenzhixin.net.cn/" target="_blank">bootstrap-table</a>, - <i class="fa fa-copyright"></i> Copyright (c) 2012-2016 Zhixin Wen, <a href="https://github.com/wenzhixin/bootstrap-table/blob/master/LICENSE" target="_blank">MIT License</a> + <i class="fas fa-circle"></i> <a href="http://bootstrap-table.wenzhixin.net.cn/" target="_blank">bootstrap-table</a>, + <i class="fas fa-copyright"></i> Copyright (c) 2012-2016 Zhixin Wen, <a href="https://github.com/wenzhixin/bootstrap-table/blob/master/LICENSE" target="_blank">MIT License</a> - <i class="fa fa-circle"></i> <a href="https://github.com/hhurz/tableExport.jquery.plugin" target="_blank">tableExport.jquery.plugin</a>, - <i class="fa fa-copyright"></i> Copyright (c) 2015,2016 hhurz, <a href="http://rawgit.com/hhurz/tableExport.jquery.plugin/master/tableExport.js" target="_blank">MIT License</a> + <i class="fas fa-circle"></i> <a href="https://github.com/hhurz/tableExport.jquery.plugin" target="_blank">tableExport.jquery.plugin</a>, + <i class="fas fa-copyright"></i> Copyright (c) 2015,2016 hhurz, <a href="http://rawgit.com/hhurz/tableExport.jquery.plugin/master/tableExport.js" target="_blank">MIT License</a> </small> </div> @@ -3137,6 +4503,182 @@ </div> </div> + <div class="modal fade" id="printPreflightModal" tabindex="-1" role="dialog" aria-labelledby="printPreflightModalLabel"> + <div class="modal-dialog modal-lg" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> + <h4 class="modal-title" id="printPreflightModalLabel">Print this netdata dashboard</h4> + </div> + <div class="modal-body"> + <p> + netdata dashboards cannot be captured, since we are lazy loading and hiding all but the visible charts. + <br/> + To capture the whole page with all the charts rendered, a new browser window will pop-up that will render all the charts at once. + The new browser window will maintain the current pan and zoom settings of the charts. So, align the charts before proceeding. + </p> + <p> + <small> + This process will put some CPU and memory pressure on your browser.<br/> + For the netdata server, we will sequencially download all the charts, to avoid congesting network and server resources.<br/> + <b>Please, do not print netdata dashboards on paper!</b> + </small> + </p> + </div> + <div class="modal-footer"> + <a href="#" onclick="printPreflight(); return false;" type="button" class="btn btn-default">Print</a> + <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> + </div> + </div> + </div> + </div> + + <div class="modal fade" id="printModal" tabindex="-1" role="dialog" aria-labelledby="printModalLabel" data-keyboard="false" data-backdrop="static"> + <div class="modal-dialog modal-lg" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> + <h4 class="modal-title" id="printModalLabel">Preparing dashboard for printing...</h4> + </div> + <div class="modal-body"> + Please wait while we initialize and render all the charts on the dashboard. + <div class="progress progress-striped active" style="height: 2em !important;"> + <div id="printModalProgressBar" class="progress-bar progress-bar-info" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="min-width: 2em;"> + <span id="printModalProgressBarText" style="padding-left: 10px; padding-top: 4px; font-size: 1.2em; text-align: left; width: 100%; position: absolute; display: block; color: black;"></span> + </div> + </div> + The print dialog will appear as soon as we finish rendering the page. + </div> + <div class="modal-footer"> + </div> + </div> + </div> + </div> + + <div class="modal fade" id="loadSnapshotModal" tabindex="-1" role="dialog" aria-labelledby="loadSnapshotModalLabel"> + <div class="modal-dialog modal-lg" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> + <h4 class="modal-title" id="loadSnapshotModalLabel">Import a netdata snapshot</h4> + </div> + <div id="loadSnapshotDragAndDrop" class="modal-body"> + <p> + netdata can export and import dashboard snapshots. + Any netdata can import the snapshot of any other netdata. + The snapshots are not uploaded to a server. They are handled entirely by your web browser, on your computer. + </p> + <p style="text-align: center;"> + <label class="btn btn-default"> + Click here to select the netdata snapshot file to import + <input type="file" id="loadSnapshotSelectFiles" value="Import" style="display: none;" + onchange="loadSnapshotPreflight();"> + </label> + </p> + <div id="loadSnapshotStatus" class="alert alert-info" role="alert"> + Browse for a snapshot file (or drag it and drop it here), then click <b>Import</b> to render it. + </div> + <p> + <table class="table"> + <tbody> + <tr><th>Filename</th><td id="loadSnapshotFilename"></td></tr> + <tr><th>Hostname</th><td id="loadSnapshotHostname"></td></tr> + <tr><th>Origin URL</th><td id="loadSnapshotURL"></td></tr> + <tr><th>Charts Info</th><td id="loadSnapshotCharts"></td></tr> + <tr><th>Snapshot Info</th><td id="loadSnapshotInfo"></td></tr> + <tr><th>Time Range</th><td id="loadSnapshotTimeRange"></td></tr> + <tr><th>Comments</th><td id="loadSnapshotComments"></td></tr> + </tbody> + </table> + </p> + </div> + <div class="modal-footer"> + <a id="loadSnapshotImport" href="#" onclick="loadSnapshot(); return false;" type="button" class="btn btn-success disabled">Import</a> + <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> + </div> + </div> + </div> + </div> + + <div class="modal fade" id="saveSnapshotModal" tabindex="-1" role="dialog" aria-labelledby="saveSnapshotModalLabel" data-keyboard="false" data-backdrop="static"> + <div class="modal-dialog modal-lg" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> + <h4 class="modal-title" id="saveSnapshotModalLabel">Export a snapshot</h4> + </div> + <div class="modal-body"> + <div id="saveSnapshotModalProgressSection" hidden> + Please wait while we collect all the dashboard data... + <div class="progress progress-striped active" style="height: 2em !important;"> + <div id="saveSnapshotModalProgressBar" class="progress-bar progress-bar-info" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="min-width: 2em;"> + <span id="saveSnapshotModalProgressBarText" style="padding-left: 10px; padding-top: 4px; font-size: 1.2em; text-align: left; width: 100%; position: absolute; display: block;"></span> + </div> + </div> + </div> + + <div id="saveSnapshotResolutionRadio" style="text-align: center;"> + Select the desired resolution of the snapshot. This is the <b>seconds of data per point</b>. + <br/> + + <br/> + + <br/> + <input id="saveSnapshotResolutionSlider" data-slider-id='saveSnapshotResolutionSlider' type="text" style="width: 80%;" tabindex="0"/> + <br/> <br/> + <div class="input-group"> + <span class="input-group-addon" id="sizing-saveSnapshotFilename" style="width: 100px;">Filename</span> + <input id="saveSnapshotFilename" class="form-control" placeholder="Filename of the generated snapshot" aria-describedby="sizing-saveSnapshotFilename" tabindex="2"/> + <div class="input-group-btn"> + <div class="input-group-btn"> + <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><span id="saveSnapshotCompressionName">Compression</span> <span class="caret"></span></button> + <ul class="dropdown-menu dropdown-menu-right"> + <li class="disabled"><a href="#" class="disabled">Select Compression</a></li> + <li role="separator" class="divider"></li> + <li><a href="#" onclick="saveSnapshotSetCompression('none'); return false;">uncompressed</a></li> + <li role="separator" class="divider"></li> + <li><a href="#" onclick="saveSnapshotSetCompression('pako.deflate'); return false;">pako.deflate (gzip, binary)</a></li> + <li><a href="#" onclick="saveSnapshotSetCompression('pako.deflate.base64'); return false;">pako.deflate.base64 (gzip, ascii)</a></li> + <li role="separator" class="divider"></li> + <li><a href="#" onclick="saveSnapshotSetCompression('lzstring.uri'); return false;">lzstring.uri (LZ, ascii)</a></li> + <li><a href="#" onclick="saveSnapshotSetCompression('lzstring.utf16'); return false;">lzstring.utf16 (LZ, utf16)</a></li> + <li><a href="#" onclick="saveSnapshotSetCompression('lzstring.base64'); return false;">lzstring.base64 (LZ, ascii)</a></li> + </ul> + </div><!-- /btn-group --> + </div> + </div> + <div class="input-group" style="padding-top: 10px; width: 100%"> + <span class="input-group-addon" id="sizing-saveSnapshotComments" style="width: 100px;">Comments</span> + <input id="saveSnapshotComments" class="form-control" placeholder="Any comments about this snapshot?" aria-describedby="sizing-saveSnapshotComments" tabindex="3"/> + </div> + </div> + + + <div id="saveSnapshotStatus" class="alert alert-info" role="alert"> + Select snaphost resolution. This controls the size the snapshot file. + </div> + <p> + The generated snapshot will include all charts of this dashboard, <b>for the visible timeframe</b>, so align, pan and zoom the charts as needed. + The scroll position of the dashboard will also be saved. + The snapshot will be downloaded as a file, to your computer, that can be imported back into any netdata dashboard (no need to import it back on this server). + </p> + <p> + <small> + Snapshot files include all the information of the dashboard, including the URL of the origin server, its netdata unique ID, etc. + So, if you share the snapshot file with third parties, they will be able to access the origin server, if this server is exposed on the internet. + <br/> + Snapshots are handled entirely by the web browser. The netdata servers are not aware of them. + </small> + </p> + </div> + <div class="modal-footer"> + <a id="saveSnapshotExport" href="#" onclick="saveSnapshot(); return false;" type="button" class="btn btn-success" tabindex="4">Export</a> + <button type="button" class="btn btn-default" data-dismiss="modal" tabindex="5">Cancel</button> + </div> + </div> + </div> + </div> + <div class="modal fade" id="welcomeModal" tabindex="-1" role="dialog" aria-labelledby="welcomeModalLabel"> <div class="modal-dialog modal-lg" role="document"> <div class="modal-content"> @@ -3216,7 +4758,7 @@ <hr/> <div class="p"> <h4>Drag Chart Contents</h4> - Drag the contents of a chart to pan it horizontally. + Drag the contents of a chart, by pressing the left mouse button and moving the mouse, to pan it horizontally. <br/> All the charts will follow soon after you let the chart alone (this little delay is by design: it speeds up your browser and lets you focus on what you are exploring). <br/> @@ -3230,7 +4772,7 @@ <hr/> <div class="p"> <h4>SHIFT + Drag</h4> - While pressing the shift key, click on the contents of a chart and move the mouse to select an area, to zoom in. The other charts will follow too. Zooming is performed in two phases: + While pressing the <code>SHIFT</code> key, press the left mouse button on the contents of a chart and move the mouse to select an area, to zoom in. The other charts will follow too. Zooming is performed in two phases: <ul> <li>The already loaded chart contents are zoomed (low resolution)</li> <li>New data are transferred from the netdata server, to refresh the chart with possibly more detail.</li> @@ -3239,8 +4781,13 @@ </div> <hr/> <div class="p"> + <h4>Highlight Timeframe</h4> + While pressing the <code>ALT</code> key, press the left mouse button on the contents of a chart and move the mouse to select an area. The selected are will be highlighted on all charts. + </div> + <hr/> + <div class="p"> <h4>SHIFT + Mouse Wheel</h4> - While pressing the shift key and the mouse pointer is over the contents of a chart, scroll the mouse wheel to zoom in or out. This kind of zooming is aligned to center below the mouse pointer. The other charts will follow too. + While pressing the <code>SHIFT</code> key and the mouse pointer is over the contents of a chart, scroll the mouse wheel to zoom in or out. This kind of zooming is aligned to center below the mouse pointer. The other charts will follow too. <br/> Once a chart is zoomed, auto refreshing stops for all charts. To enable it again, <b>double click</b> a zoomed chart. </div> @@ -3353,6 +4900,7 @@ <li role="presentation" class="active"><a href="#settings_performance" aria-controls="settings_performance" role="tab" data-toggle="tab">Performance</a></li> <li role="presentation"><a href="#settings_sync" aria-controls="settings_sync" role="tab" data-toggle="tab">Synchronization</a></li> <li role="presentation"><a href="#settings_visual" aria-controls="settings_visual" role="tab" data-toggle="tab">Visual</a></li> + <li role="presentation"><a href="#settings_locale" aria-controls="settings_locale" role="tab" data-toggle="tab">Locale</a></li> </ul> <!-- Tab panes --> @@ -3384,7 +4932,7 @@ <tr class="option-row"> <td class="option-control"><input id="async_on_scroll" type="checkbox" data-toggle="toggle" data-on="Async" data-off="Sync" data-width="110px"></td> <td class="option-info"><strong>Page scroll handling?</strong><br/> - <small>When set to <b>Sync</b>, charts will be examined for their visibility synchronously. On slow computers this may impact the smoothness of page scrolling. To work asynchronously set it to <b>Async</b>. When set to <b>Sync</b>, the performance of page scrolling is monitored and this setting switches automatically to <b>Async</b> if the browser is found slow. Set it to <b>Sync</b> for best visual experience. Set it to <b>Async</b> for smoother page scrolling.</small> + <small>When set to <b>Sync</b>, charts will be examined for their visibility immediately after scrolling. On slow computers this may impact the smoothness of page scrolling. To update the page when scrolling ends, set it to <b>Async</b>. Set it to <b>Sync</b> for immediate chart updates when scrolling. Set it to <b>Async</b> for smoother page scrolling on slower computers.</small> </td> </tr> </table> @@ -3463,6 +5011,416 @@ </div> </form> </div> + <div role="tabpanel" class="tab-pane" id="settings_locale"> + <form id="optionsForm4" method="get" class="form-horizontal"> + <div class="form-group"> + <table> + <tr class="option-row"> + <td colspan="2" align="center"> + <small> + <b>These settings are applied gradually, as charts are updated. To force them, refresh the dashboard now</b>. + </small> + </td> + </tr> + <tr class="option-row"> + <td class="option-control"><input id="units_conversion" type="checkbox" checked data-toggle="toggle" data-on="Scale Units" data-off="Fixed Units" data-onstyle="success" data-width="110px"></td> + <td class="option-info"><strong>Enable auto-scaling of select units?</strong><br/> + <small>When set to <b>Scale Units</b> the values shown will dynamically be scaled (e.g. 1000 kilobits will be shown as 1 megabit). + Netdata can auto-scale these original units: <code>kilobits/s</code>, <code>kilobytes/s</code>, <code>KB/s</code>, + <code>KB</code>, <code>MB</code>, and <code>GB</code>. + When set to <b>Fixed Units</b> all the values will be rendered using the original units maintained by the netdata server. + </small> + </td> + </tr> + <tr id="settingsLocaleTempRow" class="option-row"> + <td class="option-control"><input id="units_temp" type="checkbox" checked data-toggle="toggle" data-on="Celsius" data-off="Fahrenheit" data-width="110px"></td> + <td class="option-info"><strong>Which units to use for temperatures?</strong><br/> + <small>Set the temperature units of the dashboard. + </small> + </td> + </tr> + <tr id="settingsLocaleTimeRow" class="option-row"> + <td class="option-control"><input id="seconds_as_time" type="checkbox" checked data-toggle="toggle" data-on="Time" data-off="Seconds" data-onstyle="success" data-width="110px"></td> + <td class="option-info"><strong>Convert seconds to time?</strong><br/> + <small>When set to <b>Time</b>, charts that present <code>seconds</code> will show <code>DDd:HH:MM:SS</code>. + When set to <b>Seconds</b>, the raw number of seconds will be presented. + </small> + </td> + </tr> + <tr class="option-row"> + <td class="option-control"><input id="local_timezone" type="checkbox" checked data-toggle="toggle" data-on="Your Time" data-off="Server Time" data-onstyle="success" data-offstyle="danger" data-width="110px"></td> + <td class="option-info"><strong>Show browser local time or server time?</strong><br/> + <small>When set to <b>Your Time</b>, the charts will use your browser local time. When set to <b>Server Time</b> the charts will use the server time. + <br/> + Set it to <b>Your Time</b> to have a common time-reference, no matter where the server is and which time zone it uses (all your dashboards will report your local time). + Set it to <b>Server Time</b> when you need to compare netdata charts with server log files. + <br/> + Your browser time zone is: <b><span id="browser_timezone">-</span></b>.<br/> + The server reported timezone is: <b><span id="server_timezone">-</span></b> (you can set this in netdata.conf <code>[global].timezone</code>).<br/> + The current time zone on the dashboard is: <b><span id="current_timezone">-</span></b>. + <br/> + <div class="dropup"> + <button class="btn btn-default dropdown-toggle" type="button" id="dropdownTimeZone" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true"> + Select Server Time Zone + <span class="caret"></span> + </button> + <ul class="dropdown-menu scrollable-menu-50" aria-labelledby="dropdownTimeZone"> + <li><a href=# onclick="return selected_server_timezone('Africa/Abidjan');">Africa/Abidjan</a></li> + <li><a href=# onclick="return selected_server_timezone('Africa/Accra');">Africa/Accra</a></li> + <li><a href=# onclick="return selected_server_timezone('Africa/Algiers');">Africa/Algiers</a></li> + <li><a href=# onclick="return selected_server_timezone('Africa/Bissau');">Africa/Bissau</a></li> + <li><a href=# onclick="return selected_server_timezone('Africa/Cairo');">Africa/Cairo</a></li> + <li><a href=# onclick="return selected_server_timezone('Africa/Casablanca');">Africa/Casablanca</a></li> + <li><a href=# onclick="return selected_server_timezone('Africa/Ceuta');">Africa/Ceuta</a></li> + <li><a href=# onclick="return selected_server_timezone('Africa/El_Aaiun');">Africa/El_Aaiun</a></li> + <li><a href=# onclick="return selected_server_timezone('Africa/Johannesburg');">Africa/Johannesburg</a></li> + <li><a href=# onclick="return selected_server_timezone('Africa/Khartoum');">Africa/Khartoum</a></li> + <li><a href=# onclick="return selected_server_timezone('Africa/Lagos');">Africa/Lagos</a></li> + <li><a href=# onclick="return selected_server_timezone('Africa/Maputo');">Africa/Maputo</a></li> + <li><a href=# onclick="return selected_server_timezone('Africa/Monrovia');">Africa/Monrovia</a></li> + <li><a href=# onclick="return selected_server_timezone('Africa/Nairobi');">Africa/Nairobi</a></li> + <li><a href=# onclick="return selected_server_timezone('Africa/Ndjamena');">Africa/Ndjamena</a></li> + <li><a href=# onclick="return selected_server_timezone('Africa/Tripoli');">Africa/Tripoli</a></li> + <li><a href=# onclick="return selected_server_timezone('Africa/Tunis');">Africa/Tunis</a></li> + <li><a href=# onclick="return selected_server_timezone('Africa/Windhoek');">Africa/Windhoek</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Adak');">America/Adak</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Anchorage');">America/Anchorage</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Araguaina');">America/Araguaina</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Argentina/Buenos_Aires');">America/Argentina/Buenos_Aires</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Argentina/Catamarca');">America/Argentina/Catamarca</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Argentina/Cordoba');">America/Argentina/Cordoba</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Argentina/Jujuy');">America/Argentina/Jujuy</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Argentina/La_Rioja');">America/Argentina/La_Rioja</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Argentina/Mendoza');">America/Argentina/Mendoza</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Argentina/Rio_Gallegos');">America/Argentina/Rio_Gallegos</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Argentina/Salta');">America/Argentina/Salta</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Argentina/San_Juan');">America/Argentina/San_Juan</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Argentina/San_Luis');">America/Argentina/San_Luis</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Argentina/Tucuman');">America/Argentina/Tucuman</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Argentina/Ushuaia');">America/Argentina/Ushuaia</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Asuncion');">America/Asuncion</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Atikokan');">America/Atikokan</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Bahia');">America/Bahia</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Bahia_Banderas');">America/Bahia_Banderas</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Barbados');">America/Barbados</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Belem');">America/Belem</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Belize');">America/Belize</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Blanc-Sablon');">America/Blanc-Sablon</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Boa_Vista');">America/Boa_Vista</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Bogota');">America/Bogota</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Boise');">America/Boise</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Cambridge_Bay');">America/Cambridge_Bay</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Campo_Grande');">America/Campo_Grande</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Cancun');">America/Cancun</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Caracas');">America/Caracas</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Cayenne');">America/Cayenne</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Chicago');">America/Chicago</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Chihuahua');">America/Chihuahua</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Costa_Rica');">America/Costa_Rica</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Creston');">America/Creston</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Cuiaba');">America/Cuiaba</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Curacao');">America/Curacao</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Danmarkshavn');">America/Danmarkshavn</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Dawson');">America/Dawson</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Dawson_Creek');">America/Dawson_Creek</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Denver');">America/Denver</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Detroit');">America/Detroit</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Edmonton');">America/Edmonton</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Eirunepe');">America/Eirunepe</a></li> + <li><a href=# onclick="return selected_server_timezone('America/El_Salvador');">America/El_Salvador</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Fortaleza');">America/Fortaleza</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Fort_Nelson');">America/Fort_Nelson</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Glace_Bay');">America/Glace_Bay</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Godthab');">America/Godthab</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Goose_Bay');">America/Goose_Bay</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Grand_Turk');">America/Grand_Turk</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Guatemala');">America/Guatemala</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Guayaquil');">America/Guayaquil</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Guyana');">America/Guyana</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Halifax');">America/Halifax</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Havana');">America/Havana</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Hermosillo');">America/Hermosillo</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Indiana/Indianapolis');">America/Indiana/Indianapolis</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Indiana/Knox');">America/Indiana/Knox</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Indiana/Marengo');">America/Indiana/Marengo</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Indiana/Petersburg');">America/Indiana/Petersburg</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Indiana/Tell_City');">America/Indiana/Tell_City</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Indiana/Vevay');">America/Indiana/Vevay</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Indiana/Vincennes');">America/Indiana/Vincennes</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Indiana/Winamac');">America/Indiana/Winamac</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Inuvik');">America/Inuvik</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Iqaluit');">America/Iqaluit</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Jamaica');">America/Jamaica</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Juneau');">America/Juneau</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Kentucky/Louisville');">America/Kentucky/Louisville</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Kentucky/Monticello');">America/Kentucky/Monticello</a></li> + <li><a href=# onclick="return selected_server_timezone('America/La_Paz');">America/La_Paz</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Lima');">America/Lima</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Los_Angeles');">America/Los_Angeles</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Maceio');">America/Maceio</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Managua');">America/Managua</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Manaus');">America/Manaus</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Martinique');">America/Martinique</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Matamoros');">America/Matamoros</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Mazatlan');">America/Mazatlan</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Menominee');">America/Menominee</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Merida');">America/Merida</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Metlakatla');">America/Metlakatla</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Mexico_City');">America/Mexico_City</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Miquelon');">America/Miquelon</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Moncton');">America/Moncton</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Monterrey');">America/Monterrey</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Montevideo');">America/Montevideo</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Nassau');">America/Nassau</a></li> + <li><a href=# onclick="return selected_server_timezone('America/New_York');">America/New_York</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Nipigon');">America/Nipigon</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Nome');">America/Nome</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Noronha');">America/Noronha</a></li> + <li><a href=# onclick="return selected_server_timezone('America/North_Dakota/Beulah');">America/North_Dakota/Beulah</a></li> + <li><a href=# onclick="return selected_server_timezone('America/North_Dakota/Center');">America/North_Dakota/Center</a></li> + <li><a href=# onclick="return selected_server_timezone('America/North_Dakota/New_Salem');">America/North_Dakota/New_Salem</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Ojinaga');">America/Ojinaga</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Panama');">America/Panama</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Pangnirtung');">America/Pangnirtung</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Paramaribo');">America/Paramaribo</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Phoenix');">America/Phoenix</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Port-au-Prince');">America/Port-au-Prince</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Port_of_Spain');">America/Port_of_Spain</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Porto_Velho');">America/Porto_Velho</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Puerto_Rico');">America/Puerto_Rico</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Punta_Arenas');">America/Punta_Arenas</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Rainy_River');">America/Rainy_River</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Rankin_Inlet');">America/Rankin_Inlet</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Recife');">America/Recife</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Regina');">America/Regina</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Resolute');">America/Resolute</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Rio_Branco');">America/Rio_Branco</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Santarem');">America/Santarem</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Santiago');">America/Santiago</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Santo_Domingo');">America/Santo_Domingo</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Sao_Paulo');">America/Sao_Paulo</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Scoresbysund');">America/Scoresbysund</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Sitka');">America/Sitka</a></li> + <li><a href=# onclick="return selected_server_timezone('America/St_Johns');">America/St_Johns</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Swift_Current');">America/Swift_Current</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Tegucigalpa');">America/Tegucigalpa</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Thule');">America/Thule</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Thunder_Bay');">America/Thunder_Bay</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Tijuana');">America/Tijuana</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Toronto');">America/Toronto</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Vancouver');">America/Vancouver</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Whitehorse');">America/Whitehorse</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Winnipeg');">America/Winnipeg</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Yakutat');">America/Yakutat</a></li> + <li><a href=# onclick="return selected_server_timezone('America/Yellowknife');">America/Yellowknife</a></li> + <li><a href=# onclick="return selected_server_timezone('Antarctica/Casey');">Antarctica/Casey</a></li> + <li><a href=# onclick="return selected_server_timezone('Antarctica/Davis');">Antarctica/Davis</a></li> + <li><a href=# onclick="return selected_server_timezone('Antarctica/DumontDUrville');">Antarctica/DumontDUrville</a></li> + <li><a href=# onclick="return selected_server_timezone('Antarctica/Macquarie');">Antarctica/Macquarie</a></li> + <li><a href=# onclick="return selected_server_timezone('Antarctica/Mawson');">Antarctica/Mawson</a></li> + <li><a href=# onclick="return selected_server_timezone('Antarctica/Palmer');">Antarctica/Palmer</a></li> + <li><a href=# onclick="return selected_server_timezone('Antarctica/Rothera');">Antarctica/Rothera</a></li> + <li><a href=# onclick="return selected_server_timezone('Antarctica/Syowa');">Antarctica/Syowa</a></li> + <li><a href=# onclick="return selected_server_timezone('Antarctica/Troll');">Antarctica/Troll</a></li> + <li><a href=# onclick="return selected_server_timezone('Antarctica/Vostok');">Antarctica/Vostok</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Almaty');">Asia/Almaty</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Amman');">Asia/Amman</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Anadyr');">Asia/Anadyr</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Aqtau');">Asia/Aqtau</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Aqtobe');">Asia/Aqtobe</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Ashgabat');">Asia/Ashgabat</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Atyrau');">Asia/Atyrau</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Baghdad');">Asia/Baghdad</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Baku');">Asia/Baku</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Bangkok');">Asia/Bangkok</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Barnaul');">Asia/Barnaul</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Beirut');">Asia/Beirut</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Bishkek');">Asia/Bishkek</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Brunei');">Asia/Brunei</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Chita');">Asia/Chita</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Choibalsan');">Asia/Choibalsan</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Colombo');">Asia/Colombo</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Damascus');">Asia/Damascus</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Dhaka');">Asia/Dhaka</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Dili');">Asia/Dili</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Dubai');">Asia/Dubai</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Dushanbe');">Asia/Dushanbe</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Famagusta');">Asia/Famagusta</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Gaza');">Asia/Gaza</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Hebron');">Asia/Hebron</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Ho_Chi_Minh');">Asia/Ho_Chi_Minh</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Hong_Kong');">Asia/Hong_Kong</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Hovd');">Asia/Hovd</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Irkutsk');">Asia/Irkutsk</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Jakarta');">Asia/Jakarta</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Jayapura');">Asia/Jayapura</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Jerusalem');">Asia/Jerusalem</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Kabul');">Asia/Kabul</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Kamchatka');">Asia/Kamchatka</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Karachi');">Asia/Karachi</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Kathmandu');">Asia/Kathmandu</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Khandyga');">Asia/Khandyga</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Kolkata');">Asia/Kolkata</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Krasnoyarsk');">Asia/Krasnoyarsk</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Kuala_Lumpur');">Asia/Kuala_Lumpur</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Kuching');">Asia/Kuching</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Macau');">Asia/Macau</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Magadan');">Asia/Magadan</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Makassar');">Asia/Makassar</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Manila');">Asia/Manila</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Nicosia');">Asia/Nicosia</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Novokuznetsk');">Asia/Novokuznetsk</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Novosibirsk');">Asia/Novosibirsk</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Omsk');">Asia/Omsk</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Oral');">Asia/Oral</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Pontianak');">Asia/Pontianak</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Pyongyang');">Asia/Pyongyang</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Qatar');">Asia/Qatar</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Qyzylorda');">Asia/Qyzylorda</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Riyadh');">Asia/Riyadh</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Sakhalin');">Asia/Sakhalin</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Samarkand');">Asia/Samarkand</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Seoul');">Asia/Seoul</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Shanghai');">Asia/Shanghai</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Singapore');">Asia/Singapore</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Srednekolymsk');">Asia/Srednekolymsk</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Taipei');">Asia/Taipei</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Tashkent');">Asia/Tashkent</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Tbilisi');">Asia/Tbilisi</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Tehran');">Asia/Tehran</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Thimphu');">Asia/Thimphu</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Tokyo');">Asia/Tokyo</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Tomsk');">Asia/Tomsk</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Ulaanbaatar');">Asia/Ulaanbaatar</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Urumqi');">Asia/Urumqi</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Ust-Nera');">Asia/Ust-Nera</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Vladivostok');">Asia/Vladivostok</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Yakutsk');">Asia/Yakutsk</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Yangon');">Asia/Yangon</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Yekaterinburg');">Asia/Yekaterinburg</a></li> + <li><a href=# onclick="return selected_server_timezone('Asia/Yerevan');">Asia/Yerevan</a></li> + <li><a href=# onclick="return selected_server_timezone('Atlantic/Azores');">Atlantic/Azores</a></li> + <li><a href=# onclick="return selected_server_timezone('Atlantic/Bermuda');">Atlantic/Bermuda</a></li> + <li><a href=# onclick="return selected_server_timezone('Atlantic/Canary');">Atlantic/Canary</a></li> + <li><a href=# onclick="return selected_server_timezone('Atlantic/Cape_Verde');">Atlantic/Cape_Verde</a></li> + <li><a href=# onclick="return selected_server_timezone('Atlantic/Faroe');">Atlantic/Faroe</a></li> + <li><a href=# onclick="return selected_server_timezone('Atlantic/Madeira');">Atlantic/Madeira</a></li> + <li><a href=# onclick="return selected_server_timezone('Atlantic/Reykjavik');">Atlantic/Reykjavik</a></li> + <li><a href=# onclick="return selected_server_timezone('Atlantic/South_Georgia');">Atlantic/South_Georgia</a></li> + <li><a href=# onclick="return selected_server_timezone('Atlantic/Stanley');">Atlantic/Stanley</a></li> + <li><a href=# onclick="return selected_server_timezone('Australia/Adelaide');">Australia/Adelaide</a></li> + <li><a href=# onclick="return selected_server_timezone('Australia/Brisbane');">Australia/Brisbane</a></li> + <li><a href=# onclick="return selected_server_timezone('Australia/Broken_Hill');">Australia/Broken_Hill</a></li> + <li><a href=# onclick="return selected_server_timezone('Australia/Currie');">Australia/Currie</a></li> + <li><a href=# onclick="return selected_server_timezone('Australia/Darwin');">Australia/Darwin</a></li> + <li><a href=# onclick="return selected_server_timezone('Australia/Eucla');">Australia/Eucla</a></li> + <li><a href=# onclick="return selected_server_timezone('Australia/Hobart');">Australia/Hobart</a></li> + <li><a href=# onclick="return selected_server_timezone('Australia/Lindeman');">Australia/Lindeman</a></li> + <li><a href=# onclick="return selected_server_timezone('Australia/Lord_Howe');">Australia/Lord_Howe</a></li> + <li><a href=# onclick="return selected_server_timezone('Australia/Melbourne');">Australia/Melbourne</a></li> + <li><a href=# onclick="return selected_server_timezone('Australia/Perth');">Australia/Perth</a></li> + <li><a href=# onclick="return selected_server_timezone('Australia/Sydney');">Australia/Sydney</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Amsterdam');">Europe/Amsterdam</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Andorra');">Europe/Andorra</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Astrakhan');">Europe/Astrakhan</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Athens');">Europe/Athens</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Belgrade');">Europe/Belgrade</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Berlin');">Europe/Berlin</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Brussels');">Europe/Brussels</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Bucharest');">Europe/Bucharest</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Budapest');">Europe/Budapest</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Chisinau');">Europe/Chisinau</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Copenhagen');">Europe/Copenhagen</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Dublin');">Europe/Dublin</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Gibraltar');">Europe/Gibraltar</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Helsinki');">Europe/Helsinki</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Istanbul');">Europe/Istanbul</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Kaliningrad');">Europe/Kaliningrad</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Kiev');">Europe/Kiev</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Kirov');">Europe/Kirov</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Lisbon');">Europe/Lisbon</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/London');">Europe/London</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Luxembourg');">Europe/Luxembourg</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Madrid');">Europe/Madrid</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Malta');">Europe/Malta</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Minsk');">Europe/Minsk</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Monaco');">Europe/Monaco</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Moscow');">Europe/Moscow</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Oslo');">Europe/Oslo</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Paris');">Europe/Paris</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Prague');">Europe/Prague</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Riga');">Europe/Riga</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Rome');">Europe/Rome</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Samara');">Europe/Samara</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Saratov');">Europe/Saratov</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Simferopol');">Europe/Simferopol</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Sofia');">Europe/Sofia</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Stockholm');">Europe/Stockholm</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Tallinn');">Europe/Tallinn</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Tirane');">Europe/Tirane</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Ulyanovsk');">Europe/Ulyanovsk</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Uzhgorod');">Europe/Uzhgorod</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Vienna');">Europe/Vienna</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Vilnius');">Europe/Vilnius</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Volgograd');">Europe/Volgograd</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Warsaw');">Europe/Warsaw</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Zaporozhye');">Europe/Zaporozhye</a></li> + <li><a href=# onclick="return selected_server_timezone('Europe/Zurich');">Europe/Zurich</a></li> + <li><a href=# onclick="return selected_server_timezone('Indian/Chagos');">Indian/Chagos</a></li> + <li><a href=# onclick="return selected_server_timezone('Indian/Christmas');">Indian/Christmas</a></li> + <li><a href=# onclick="return selected_server_timezone('Indian/Cocos');">Indian/Cocos</a></li> + <li><a href=# onclick="return selected_server_timezone('Indian/Kerguelen');">Indian/Kerguelen</a></li> + <li><a href=# onclick="return selected_server_timezone('Indian/Mahe');">Indian/Mahe</a></li> + <li><a href=# onclick="return selected_server_timezone('Indian/Maldives');">Indian/Maldives</a></li> + <li><a href=# onclick="return selected_server_timezone('Indian/Mauritius');">Indian/Mauritius</a></li> + <li><a href=# onclick="return selected_server_timezone('Indian/Reunion');">Indian/Reunion</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Apia');">Pacific/Apia</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Auckland');">Pacific/Auckland</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Bougainville');">Pacific/Bougainville</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Chatham');">Pacific/Chatham</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Chuuk');">Pacific/Chuuk</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Easter');">Pacific/Easter</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Efate');">Pacific/Efate</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Enderbury');">Pacific/Enderbury</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Fakaofo');">Pacific/Fakaofo</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Fiji');">Pacific/Fiji</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Funafuti');">Pacific/Funafuti</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Galapagos');">Pacific/Galapagos</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Gambier');">Pacific/Gambier</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Guadalcanal');">Pacific/Guadalcanal</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Guam');">Pacific/Guam</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Honolulu');">Pacific/Honolulu</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Kiritimati');">Pacific/Kiritimati</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Kosrae');">Pacific/Kosrae</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Kwajalein');">Pacific/Kwajalein</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Majuro');">Pacific/Majuro</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Marquesas');">Pacific/Marquesas</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Nauru');">Pacific/Nauru</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Niue');">Pacific/Niue</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Norfolk');">Pacific/Norfolk</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Noumea');">Pacific/Noumea</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Pago_Pago');">Pacific/Pago_Pago</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Palau');">Pacific/Palau</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Pitcairn');">Pacific/Pitcairn</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Pohnpei');">Pacific/Pohnpei</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Port_Moresby');">Pacific/Port_Moresby</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Rarotonga');">Pacific/Rarotonga</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Tahiti');">Pacific/Tahiti</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Tarawa');">Pacific/Tarawa</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Tongatapu');">Pacific/Tongatapu</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Wake');">Pacific/Wake</a></li> + <li><a href=# onclick="return selected_server_timezone('Pacific/Wallis');">Pacific/Wallis</a></li> + </ul> + </div> + <b><span id="timezone_error_message"></span></b> + + </small> + </td> + </tr> + </table> + </div> + </form> + </div> </div> </div> <div class="modal-footer"> @@ -3490,12 +5448,10 @@ <hr/> </div> <div> - For progress reports and key netdata updates: <strong><a href="https://twitter.com/linuxnetdata" target="_blank">follow netdata on <i class="fa fa-twitter" aria-hidden="true"></i> twitter</a></strong>. + For progress reports and key netdata updates: <strong><a href="https://twitter.com/linuxnetdata" target="_blank">follow netdata on <i class="fab fa-twitter"></i> twitter</a></strong>. <br/> - <small> - You can also <a href="https://www.facebook.com/linuxnetdata/" target="_blank">follow netdata on <i class="fa fa-facebook" aria-hidden="true"></i> facebook</a>, - or <a href="https://github.com/firehol/netdata" target="_blank">watch netdata on <i class="fa fa-github" aria-hidden="true"></i> github</a>. - </small> + You can also <a href="https://www.facebook.com/linuxnetdata/" target="_blank">follow netdata on <i class="fab fa-facebook"></i> facebook</a>, + or <a href="https://github.com/firehol/netdata" target="_blank">watch netdata on <i class="fab fa-github"></i> github</a>. </div> </div> <div class="modal-footer"> @@ -3546,13 +5502,13 @@ You can copy and paste the following ID to all your browsers (e.g. work and home). <br/> All the browsers with the same ID will identify <b>you</b>, so please don't share this with others. - <p style="text-align: center; padding-top: 10px; padding-bottom: 10px; line-height: 2;"> + <div style="text-align: center; padding-top: 10px; padding-bottom: 10px; line-height: 2;"> <form action="#"> <input type="text" class="form-control" id="switchRegistryPersonGUID" placeholder="your personal ID" maxlength="36" autocomplete="off" style="text-align: center; font-size: 1.4em;"> </form> - </p> + </div> Either copy this ID and paste it to another browser, or paste here the ID you have taken from another browser. - <p style="padding-top: 10px;"><small> + <div style="padding-top: 10px;"><small> Keep in mind that: <ul> <li>when you switch ID, your previous ID will be lost forever - this is irreversible.</li> @@ -3560,7 +5516,7 @@ <li>both IDs have to be known by the registry: <b><span id="switchRegistryURL"></span></b>.</li> <li>to get a new ID, just clear your browser cookies.</li> </ul> - </small></p> + </small></div> <div id="switchRegistryResponse" style="display: block; width: 100%; text-align: center; padding-top: 20px;"></div> </div> <div class="modal-footer"> @@ -3595,6 +5551,7 @@ </div> </div> </div> + <div id="hiddenDownloadLinks" style="display: none;" hidden></div> + <script type="text/javascript" src="dashboard.js?v20171208-5"></script> </body> </html> -<script type="text/javascript" src="dashboard.js?v20170815-14"></script> diff --git a/web/lib/bootstrap-slider-10.0.0.min.js b/web/lib/bootstrap-slider-10.0.0.min.js new file mode 100644 index 00000000..2b98449b --- /dev/null +++ b/web/lib/bootstrap-slider-10.0.0.min.js @@ -0,0 +1,5 @@ +/*! ======================================================= + VERSION 10.0.0 +========================================================= */ +"use strict";var _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(a){return typeof a}:function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a},windowIsDefined="object"===("undefined"==typeof window?"undefined":_typeof(window));!function(a){if("function"==typeof define&&define.amd)define(["jquery"],a);else if("object"===("undefined"==typeof module?"undefined":_typeof(module))&&module.exports){var b;try{b=require("jquery")}catch(c){b=null}module.exports=a(b)}else window&&(window.Slider=a(window.jQuery))}(function(a){var b="slider",c="bootstrapSlider";windowIsDefined&&!window.console&&(window.console={}),windowIsDefined&&!window.console.log&&(window.console.log=function(){}),windowIsDefined&&!window.console.warn&&(window.console.warn=function(){});var d;return function(a){function b(){}function c(a){function c(b){b.prototype.option||(b.prototype.option=function(b){a.isPlainObject(b)&&(this.options=a.extend(!0,this.options,b))})}function e(b,c){a.fn[b]=function(e){if("string"==typeof e){for(var g=d.call(arguments,1),h=0,i=this.length;i>h;h++){var j=this[h],k=a.data(j,b);if(k)if(a.isFunction(k[e])&&"_"!==e.charAt(0)){var l=k[e].apply(k,g);if(void 0!==l&&l!==k)return l}else f("no such method '"+e+"' for "+b+" instance");else f("cannot call methods on "+b+" prior to initialization; attempted to call '"+e+"'")}return this}var m=this.map(function(){var d=a.data(this,b);return d?(d.option(e),d._init()):(d=new c(this,e),a.data(this,b,d)),a(this)});return!m||m.length>1?m:m[0]}}if(a){var f="undefined"==typeof console?b:function(a){console.error(a)};return a.bridget=function(a,b){c(b),e(a,b)},a.bridget}}var d=Array.prototype.slice;c(a)}(a),function(a){function e(b,c){function d(a,b){var c="data-slider-"+b.replace(/_/g,"-"),d=a.getAttribute(c);try{return JSON.parse(d)}catch(e){return d}}this._state={value:null,enabled:null,offset:null,size:null,percentage:null,inDrag:!1,over:!1},this.ticksCallbackMap={},this.handleCallbackMap={},"string"==typeof b?this.element=document.querySelector(b):b instanceof HTMLElement&&(this.element=b),c=c?c:{};for(var e=Object.keys(this.defaultOptions),f=0;f<e.length;f++){var h=e[f],i=c[h];i="undefined"!=typeof i?i:d(this.element,h),i=null!==i?i:this.defaultOptions[h],this.options||(this.options={}),this.options[h]=i}"auto"===this.options.rtl&&(this.options.rtl="rtl"===window.getComputedStyle(this.element).direction),"vertical"!==this.options.orientation||"top"!==this.options.tooltip_position&&"bottom"!==this.options.tooltip_position?"horizontal"!==this.options.orientation||"left"!==this.options.tooltip_position&&"right"!==this.options.tooltip_position||(this.options.tooltip_position="top"):this.options.rtl?this.options.tooltip_position="left":this.options.tooltip_position="right";var j,k,l,m,n,o=this.element.style.width,p=!1,q=this.element.parentNode;if(this.sliderElem)p=!0;else{this.sliderElem=document.createElement("div"),this.sliderElem.className="slider";var r=document.createElement("div");r.className="slider-track",k=document.createElement("div"),k.className="slider-track-low",j=document.createElement("div"),j.className="slider-selection",l=document.createElement("div"),l.className="slider-track-high",m=document.createElement("div"),m.className="slider-handle min-slider-handle",m.setAttribute("role","slider"),m.setAttribute("aria-valuemin",this.options.min),m.setAttribute("aria-valuemax",this.options.max),n=document.createElement("div"),n.className="slider-handle max-slider-handle",n.setAttribute("role","slider"),n.setAttribute("aria-valuemin",this.options.min),n.setAttribute("aria-valuemax",this.options.max),r.appendChild(k),r.appendChild(j),r.appendChild(l),this.rangeHighlightElements=[];var s=this.options.rangeHighlights;if(Array.isArray(s)&&s.length>0)for(var t=0;t<s.length;t++){var u=document.createElement("div"),v=s[t]["class"]||"";u.className="slider-rangeHighlight slider-selection "+v,this.rangeHighlightElements.push(u),r.appendChild(u)}var w=Array.isArray(this.options.labelledby);if(w&&this.options.labelledby[0]&&m.setAttribute("aria-labelledby",this.options.labelledby[0]),w&&this.options.labelledby[1]&&n.setAttribute("aria-labelledby",this.options.labelledby[1]),!w&&this.options.labelledby&&(m.setAttribute("aria-labelledby",this.options.labelledby),n.setAttribute("aria-labelledby",this.options.labelledby)),this.ticks=[],Array.isArray(this.options.ticks)&&this.options.ticks.length>0){for(this.ticksContainer=document.createElement("div"),this.ticksContainer.className="slider-tick-container",f=0;f<this.options.ticks.length;f++){var x=document.createElement("div");if(x.className="slider-tick",this.options.ticks_tooltip){var y=this._addTickListener(),z=y.addMouseEnter(this,x,f),A=y.addMouseLeave(this,x);this.ticksCallbackMap[f]={mouseEnter:z,mouseLeave:A}}this.ticks.push(x),this.ticksContainer.appendChild(x)}j.className+=" tick-slider-selection"}if(this.tickLabels=[],Array.isArray(this.options.ticks_labels)&&this.options.ticks_labels.length>0)for(this.tickLabelContainer=document.createElement("div"),this.tickLabelContainer.className="slider-tick-label-container",f=0;f<this.options.ticks_labels.length;f++){var B=document.createElement("div"),C=0===this.options.ticks_positions.length,D=this.options.reversed&&C?this.options.ticks_labels.length-(f+1):f;B.className="slider-tick-label",B.innerHTML=this.options.ticks_labels[D],this.tickLabels.push(B),this.tickLabelContainer.appendChild(B)}var E=function(a){var b=document.createElement("div");b.className="tooltip-arrow";var c=document.createElement("div");c.className="tooltip-inner",a.appendChild(b),a.appendChild(c)},F=document.createElement("div");F.className="tooltip tooltip-main",F.setAttribute("role","presentation"),E(F);var G=document.createElement("div");G.className="tooltip tooltip-min",G.setAttribute("role","presentation"),E(G);var H=document.createElement("div");H.className="tooltip tooltip-max",H.setAttribute("role","presentation"),E(H),this.sliderElem.appendChild(r),this.sliderElem.appendChild(F),this.sliderElem.appendChild(G),this.sliderElem.appendChild(H),this.tickLabelContainer&&this.sliderElem.appendChild(this.tickLabelContainer),this.ticksContainer&&this.sliderElem.appendChild(this.ticksContainer),this.sliderElem.appendChild(m),this.sliderElem.appendChild(n),q.insertBefore(this.sliderElem,this.element),this.element.style.display="none"}if(a&&(this.$element=a(this.element),this.$sliderElem=a(this.sliderElem)),this.eventToCallbackMap={},this.sliderElem.id=this.options.id,this.touchCapable="ontouchstart"in window||window.DocumentTouch&&document instanceof window.DocumentTouch,this.touchX=0,this.touchY=0,this.tooltip=this.sliderElem.querySelector(".tooltip-main"),this.tooltipInner=this.tooltip.querySelector(".tooltip-inner"),this.tooltip_min=this.sliderElem.querySelector(".tooltip-min"),this.tooltipInner_min=this.tooltip_min.querySelector(".tooltip-inner"),this.tooltip_max=this.sliderElem.querySelector(".tooltip-max"),this.tooltipInner_max=this.tooltip_max.querySelector(".tooltip-inner"),g[this.options.scale]&&(this.options.scale=g[this.options.scale]),p===!0&&(this._removeClass(this.sliderElem,"slider-horizontal"),this._removeClass(this.sliderElem,"slider-vertical"),this._removeClass(this.sliderElem,"slider-rtl"),this._removeClass(this.tooltip,"hide"),this._removeClass(this.tooltip_min,"hide"),this._removeClass(this.tooltip_max,"hide"),["left","right","top","width","height"].forEach(function(a){this._removeProperty(this.trackLow,a),this._removeProperty(this.trackSelection,a),this._removeProperty(this.trackHigh,a)},this),[this.handle1,this.handle2].forEach(function(a){this._removeProperty(a,"left"),this._removeProperty(a,"right"),this._removeProperty(a,"top")},this),[this.tooltip,this.tooltip_min,this.tooltip_max].forEach(function(a){this._removeProperty(a,"left"),this._removeProperty(a,"right"),this._removeProperty(a,"top"),this._removeClass(a,"right"),this._removeClass(a,"left"),this._removeClass(a,"top")},this)),"vertical"===this.options.orientation?(this._addClass(this.sliderElem,"slider-vertical"),this.stylePos="top",this.mousePos="pageY",this.sizePos="offsetHeight"):(this._addClass(this.sliderElem,"slider-horizontal"),this.sliderElem.style.width=o,this.options.orientation="horizontal",this.options.rtl?this.stylePos="right":this.stylePos="left",this.mousePos="pageX",this.sizePos="offsetWidth"),this.options.rtl&&this._addClass(this.sliderElem,"slider-rtl"),this._setTooltipPosition(),Array.isArray(this.options.ticks)&&this.options.ticks.length>0&&(this.options.max=Math.max.apply(Math,this.options.ticks),this.options.min=Math.min.apply(Math,this.options.ticks)),Array.isArray(this.options.value)?(this.options.range=!0,this._state.value=this.options.value):this.options.range?this._state.value=[this.options.value,this.options.max]:this._state.value=this.options.value,this.trackLow=k||this.trackLow,this.trackSelection=j||this.trackSelection,this.trackHigh=l||this.trackHigh,"none"===this.options.selection?(this._addClass(this.trackLow,"hide"),this._addClass(this.trackSelection,"hide"),this._addClass(this.trackHigh,"hide")):("after"===this.options.selection||"before"===this.options.selection)&&(this._removeClass(this.trackLow,"hide"),this._removeClass(this.trackSelection,"hide"),this._removeClass(this.trackHigh,"hide")),this.handle1=m||this.handle1,this.handle2=n||this.handle2,p===!0)for(this._removeClass(this.handle1,"round triangle"),this._removeClass(this.handle2,"round triangle hide"),f=0;f<this.ticks.length;f++)this._removeClass(this.ticks[f],"round triangle hide");var I=["round","triangle","custom"],J=-1!==I.indexOf(this.options.handle);if(J)for(this._addClass(this.handle1,this.options.handle),this._addClass(this.handle2,this.options.handle),f=0;f<this.ticks.length;f++)this._addClass(this.ticks[f],this.options.handle);if(this._state.offset=this._offset(this.sliderElem),this._state.size=this.sliderElem[this.sizePos],this.setValue(this._state.value),this.handle1Keydown=this._keydown.bind(this,0),this.handle1.addEventListener("keydown",this.handle1Keydown,!1),this.handle2Keydown=this._keydown.bind(this,1),this.handle2.addEventListener("keydown",this.handle2Keydown,!1),this.mousedown=this._mousedown.bind(this),this.touchstart=this._touchstart.bind(this),this.touchmove=this._touchmove.bind(this),this.touchCapable){var K=!1;try{var L=Object.defineProperty({},"passive",{get:function(){K=!0}});window.addEventListener("test",null,L)}catch(M){}var N=K?{passive:!0}:!1;this.sliderElem.addEventListener("touchstart",this.touchstart,N),this.sliderElem.addEventListener("touchmove",this.touchmove,N)}if(this.sliderElem.addEventListener("mousedown",this.mousedown,!1),this.resize=this._resize.bind(this),window.addEventListener("resize",this.resize,!1),"hide"===this.options.tooltip)this._addClass(this.tooltip,"hide"),this._addClass(this.tooltip_min,"hide"),this._addClass(this.tooltip_max,"hide");else if("always"===this.options.tooltip)this._showTooltip(),this._alwaysShowTooltip=!0;else{if(this.showTooltip=this._showTooltip.bind(this),this.hideTooltip=this._hideTooltip.bind(this),this.options.ticks_tooltip){var O=this._addTickListener(),P=O.addMouseEnter(this,this.handle1),Q=O.addMouseLeave(this,this.handle1);this.handleCallbackMap.handle1={mouseEnter:P,mouseLeave:Q},P=O.addMouseEnter(this,this.handle2),Q=O.addMouseLeave(this,this.handle2),this.handleCallbackMap.handle2={mouseEnter:P,mouseLeave:Q}}else this.sliderElem.addEventListener("mouseenter",this.showTooltip,!1),this.sliderElem.addEventListener("mouseleave",this.hideTooltip,!1);this.handle1.addEventListener("focus",this.showTooltip,!1),this.handle1.addEventListener("blur",this.hideTooltip,!1),this.handle2.addEventListener("focus",this.showTooltip,!1),this.handle2.addEventListener("blur",this.hideTooltip,!1)}this.options.enabled?this.enable():this.disable()}var f={formatInvalidInputErrorMsg:function(a){return"Invalid input value '"+a+"' passed in"},callingContextNotSliderInstance:"Calling context element does not have instance of Slider bound to it. Check your code to make sure the JQuery object returned from the call to the slider() initializer is calling the method"},g={linear:{toValue:function(a){var b=a/100*(this.options.max-this.options.min),c=!0;if(this.options.ticks_positions.length>0){for(var d,e,f,g=0,h=1;h<this.options.ticks_positions.length;h++)if(a<=this.options.ticks_positions[h]){d=this.options.ticks[h-1],f=this.options.ticks_positions[h-1],e=this.options.ticks[h],g=this.options.ticks_positions[h];break}var i=(a-f)/(g-f);b=d+i*(e-d),c=!1}var j=c?this.options.min:0,k=j+Math.round(b/this.options.step)*this.options.step;return k<this.options.min?this.options.min:k>this.options.max?this.options.max:k},toPercentage:function(a){if(this.options.max===this.options.min)return 0;if(this.options.ticks_positions.length>0){for(var b,c,d,e=0,f=0;f<this.options.ticks.length;f++)if(a<=this.options.ticks[f]){b=f>0?this.options.ticks[f-1]:0,d=f>0?this.options.ticks_positions[f-1]:0,c=this.options.ticks[f],e=this.options.ticks_positions[f];break}if(f>0){var g=(a-b)/(c-b);return d+g*(e-d)}}return 100*(a-this.options.min)/(this.options.max-this.options.min)}},logarithmic:{toValue:function(a){var b=0===this.options.min?0:Math.log(this.options.min),c=Math.log(this.options.max),d=Math.exp(b+(c-b)*a/100);return Math.round(d)===this.options.max?this.options.max:(d=this.options.min+Math.round((d-this.options.min)/this.options.step)*this.options.step,d<this.options.min?this.options.min:d>this.options.max?this.options.max:d)},toPercentage:function(a){if(this.options.max===this.options.min)return 0;var b=Math.log(this.options.max),c=0===this.options.min?0:Math.log(this.options.min),d=0===a?0:Math.log(a);return 100*(d-c)/(b-c)}}};if(d=function(a,b){return e.call(this,a,b),this},d.prototype={_init:function(){},constructor:d,defaultOptions:{id:"",min:0,max:10,step:1,precision:0,orientation:"horizontal",value:5,range:!1,selection:"before",tooltip:"show",tooltip_split:!1,handle:"round",reversed:!1,rtl:"auto",enabled:!0,formatter:function(a){return Array.isArray(a)?a[0]+" : "+a[1]:a},natural_arrow_keys:!1,ticks:[],ticks_positions:[],ticks_labels:[],ticks_snap_bounds:0,ticks_tooltip:!1,scale:"linear",focus:!1,tooltip_position:null,labelledby:null,rangeHighlights:[]},getElement:function(){return this.sliderElem},getValue:function(){return this.options.range?this._state.value:this._state.value[0]},setValue:function(a,b,c){a||(a=0);var d=this.getValue();this._state.value=this._validateInputValue(a);var e=this._applyPrecision.bind(this);this.options.range?(this._state.value[0]=e(this._state.value[0]),this._state.value[1]=e(this._state.value[1]),this._state.value[0]=Math.max(this.options.min,Math.min(this.options.max,this._state.value[0])),this._state.value[1]=Math.max(this.options.min,Math.min(this.options.max,this._state.value[1]))):(this._state.value=e(this._state.value),this._state.value=[Math.max(this.options.min,Math.min(this.options.max,this._state.value))],this._addClass(this.handle2,"hide"),"after"===this.options.selection?this._state.value[1]=this.options.max:this._state.value[1]=this.options.min),this.options.max>this.options.min?this._state.percentage=[this._toPercentage(this._state.value[0]),this._toPercentage(this._state.value[1]),100*this.options.step/(this.options.max-this.options.min)]:this._state.percentage=[0,0,100],this._layout();var f=this.options.range?this._state.value:this._state.value[0];return this._setDataVal(f),b===!0&&this._trigger("slide",f),d!==f&&c===!0&&this._trigger("change",{oldValue:d,newValue:f}),this},destroy:function(){this._removeSliderEventHandlers(),this.sliderElem.parentNode.removeChild(this.sliderElem),this.element.style.display="",this._cleanUpEventCallbacksMap(),this.element.removeAttribute("data"),a&&(this._unbindJQueryEventHandlers(),this.$element.removeData("slider"))},disable:function(){return this._state.enabled=!1,this.handle1.removeAttribute("tabindex"),this.handle2.removeAttribute("tabindex"),this._addClass(this.sliderElem,"slider-disabled"),this._trigger("slideDisabled"),this},enable:function(){return this._state.enabled=!0,this.handle1.setAttribute("tabindex",0),this.handle2.setAttribute("tabindex",0),this._removeClass(this.sliderElem,"slider-disabled"),this._trigger("slideEnabled"),this},toggle:function(){return this._state.enabled?this.disable():this.enable(),this},isEnabled:function(){return this._state.enabled},on:function(a,b){return this._bindNonQueryEventHandler(a,b),this},off:function(b,c){a?(this.$element.off(b,c),this.$sliderElem.off(b,c)):this._unbindNonQueryEventHandler(b,c)},getAttribute:function(a){return a?this.options[a]:this.options},setAttribute:function(a,b){return this.options[a]=b,this},refresh:function(){return this._removeSliderEventHandlers(),e.call(this,this.element,this.options),a&&a.data(this.element,"slider",this),this},relayout:function(){return this._resize(),this._layout(),this},_removeSliderEventHandlers:function(){if(this.handle1.removeEventListener("keydown",this.handle1Keydown,!1),this.handle2.removeEventListener("keydown",this.handle2Keydown,!1),this.options.ticks_tooltip){for(var a=this.ticksContainer.getElementsByClassName("slider-tick"),b=0;b<a.length;b++)a[b].removeEventListener("mouseenter",this.ticksCallbackMap[b].mouseEnter,!1),a[b].removeEventListener("mouseleave",this.ticksCallbackMap[b].mouseLeave,!1);this.handle1.removeEventListener("mouseenter",this.handleCallbackMap.handle1.mouseEnter,!1),this.handle2.removeEventListener("mouseenter",this.handleCallbackMap.handle2.mouseEnter,!1),this.handle1.removeEventListener("mouseleave",this.handleCallbackMap.handle1.mouseLeave,!1),this.handle2.removeEventListener("mouseleave",this.handleCallbackMap.handle2.mouseLeave,!1)}this.handleCallbackMap=null,this.ticksCallbackMap=null,this.showTooltip&&(this.handle1.removeEventListener("focus",this.showTooltip,!1),this.handle2.removeEventListener("focus",this.showTooltip,!1)),this.hideTooltip&&(this.handle1.removeEventListener("blur",this.hideTooltip,!1),this.handle2.removeEventListener("blur",this.hideTooltip,!1)),this.showTooltip&&this.sliderElem.removeEventListener("mouseenter",this.showTooltip,!1),this.hideTooltip&&this.sliderElem.removeEventListener("mouseleave",this.hideTooltip,!1),this.sliderElem.removeEventListener("touchstart",this.touchstart,!1),this.sliderElem.removeEventListener("touchmove",this.touchmove,!1),this.sliderElem.removeEventListener("mousedown",this.mousedown,!1),window.removeEventListener("resize",this.resize,!1)},_bindNonQueryEventHandler:function(a,b){void 0===this.eventToCallbackMap[a]&&(this.eventToCallbackMap[a]=[]),this.eventToCallbackMap[a].push(b)},_unbindNonQueryEventHandler:function(a,b){var c=this.eventToCallbackMap[a];if(void 0!==c)for(var d=0;d<c.length;d++)if(c[d]===b){c.splice(d,1);break}},_cleanUpEventCallbacksMap:function(){for(var a=Object.keys(this.eventToCallbackMap),b=0;b<a.length;b++){var c=a[b];delete this.eventToCallbackMap[c]}},_showTooltip:function(){this.options.tooltip_split===!1?(this._addClass(this.tooltip,"in"),this.tooltip_min.style.display="none",this.tooltip_max.style.display="none"):(this._addClass(this.tooltip_min,"in"),this._addClass(this.tooltip_max,"in"),this.tooltip.style.display="none"),this._state.over=!0},_hideTooltip:function(){this._state.inDrag===!1&&this.alwaysShowTooltip!==!0&&(this._removeClass(this.tooltip,"in"),this._removeClass(this.tooltip_min,"in"),this._removeClass(this.tooltip_max,"in")),this._state.over=!1},_setToolTipOnMouseOver:function(a){function b(a,b){return b?[100-a.percentage[0],this.options.range?100-a.percentage[1]:a.percentage[1]]:[a.percentage[0],a.percentage[1]]}var c=this.options.formatter(a?a.value[0]:this._state.value[0]),d=a?b(a,this.options.reversed):b(this._state,this.options.reversed);this._setText(this.tooltipInner,c),this.tooltip.style[this.stylePos]=d[0]+"%"},_addTickListener:function(){return{addMouseEnter:function(a,b,c){var d=function(){var b=a._state,d=c>=0?c:this.attributes["aria-valuenow"].value,e=parseInt(d,10);b.value[0]=e,b.percentage[0]=a.options.ticks_positions[e],a._setToolTipOnMouseOver(b),a._showTooltip()};return b.addEventListener("mouseenter",d,!1),d},addMouseLeave:function(a,b){var c=function(){a._hideTooltip()};return b.addEventListener("mouseleave",c,!1),c}}},_layout:function(){var a;if(a=this.options.reversed?[100-this._state.percentage[0],this.options.range?100-this._state.percentage[1]:this._state.percentage[1]]:[this._state.percentage[0],this._state.percentage[1]],this.handle1.style[this.stylePos]=a[0]+"%",this.handle1.setAttribute("aria-valuenow",this._state.value[0]),isNaN(this.options.formatter(this._state.value[0]))&&this.handle1.setAttribute("aria-valuetext",this.options.formatter(this._state.value[0])),this.handle2.style[this.stylePos]=a[1]+"%",this.handle2.setAttribute("aria-valuenow",this._state.value[1]),isNaN(this.options.formatter(this._state.value[1]))&&this.handle2.setAttribute("aria-valuetext",this.options.formatter(this._state.value[1])),this.rangeHighlightElements.length>0&&Array.isArray(this.options.rangeHighlights)&&this.options.rangeHighlights.length>0)for(var b=0;b<this.options.rangeHighlights.length;b++){var c=this._toPercentage(this.options.rangeHighlights[b].start),d=this._toPercentage(this.options.rangeHighlights[b].end);if(this.options.reversed){var e=100-d;d=100-c,c=e}var f=this._createHighlightRange(c,d);f?"vertical"===this.options.orientation?(this.rangeHighlightElements[b].style.top=f.start+"%",this.rangeHighlightElements[b].style.height=f.size+"%"):(this.options.rtl?this.rangeHighlightElements[b].style.right=f.start+"%":this.rangeHighlightElements[b].style.left=f.start+"%",this.rangeHighlightElements[b].style.width=f.size+"%"):this.rangeHighlightElements[b].style.display="none"}if(Array.isArray(this.options.ticks)&&this.options.ticks.length>0){var g,h="vertical"===this.options.orientation?"height":"width";g="vertical"===this.options.orientation?"marginTop":this.options.rtl?"marginRight":"marginLeft";var i=this._state.size/(this.options.ticks.length-1);if(this.tickLabelContainer){var j=0;if(0===this.options.ticks_positions.length)"vertical"!==this.options.orientation&&(this.tickLabelContainer.style[g]=-i/2+"px"),j=this.tickLabelContainer.offsetHeight;else for(k=0;k<this.tickLabelContainer.childNodes.length;k++)this.tickLabelContainer.childNodes[k].offsetHeight>j&&(j=this.tickLabelContainer.childNodes[k].offsetHeight);"horizontal"===this.options.orientation&&(this.sliderElem.style.marginBottom=j+"px")}for(var k=0;k<this.options.ticks.length;k++){var l=this.options.ticks_positions[k]||this._toPercentage(this.options.ticks[k]);this.options.reversed&&(l=100-l),this.ticks[k].style[this.stylePos]=l+"%",this._removeClass(this.ticks[k],"in-selection"),this.options.range?l>=a[0]&&l<=a[1]&&this._addClass(this.ticks[k],"in-selection"):"after"===this.options.selection&&l>=a[0]?this._addClass(this.ticks[k],"in-selection"):"before"===this.options.selection&&l<=a[0]&&this._addClass(this.ticks[k],"in-selection"),this.tickLabels[k]&&(this.tickLabels[k].style[h]=i+"px","vertical"!==this.options.orientation&&void 0!==this.options.ticks_positions[k]?(this.tickLabels[k].style.position="absolute",this.tickLabels[k].style[this.stylePos]=l+"%",this.tickLabels[k].style[g]=-i/2+"px"):"vertical"===this.options.orientation&&(this.options.rtl?this.tickLabels[k].style.marginRight=this.sliderElem.offsetWidth+"px":this.tickLabels[k].style.marginLeft=this.sliderElem.offsetWidth+"px",this.tickLabelContainer.style[g]=this.sliderElem.offsetWidth/2*-1+"px"))}}var m;if(this.options.range){m=this.options.formatter(this._state.value),this._setText(this.tooltipInner,m),this.tooltip.style[this.stylePos]=(a[1]+a[0])/2+"%";var n=this.options.formatter(this._state.value[0]);this._setText(this.tooltipInner_min,n);var o=this.options.formatter(this._state.value[1]);this._setText(this.tooltipInner_max,o),this.tooltip_min.style[this.stylePos]=a[0]+"%",this.tooltip_max.style[this.stylePos]=a[1]+"%"}else m=this.options.formatter(this._state.value[0]),this._setText(this.tooltipInner,m),this.tooltip.style[this.stylePos]=a[0]+"%";if("vertical"===this.options.orientation)this.trackLow.style.top="0",this.trackLow.style.height=Math.min(a[0],a[1])+"%",this.trackSelection.style.top=Math.min(a[0],a[1])+"%",this.trackSelection.style.height=Math.abs(a[0]-a[1])+"%",this.trackHigh.style.bottom="0",this.trackHigh.style.height=100-Math.min(a[0],a[1])-Math.abs(a[0]-a[1])+"%";else{"right"===this.stylePos?this.trackLow.style.right="0":this.trackLow.style.left="0",this.trackLow.style.width=Math.min(a[0],a[1])+"%","right"===this.stylePos?this.trackSelection.style.right=Math.min(a[0],a[1])+"%":this.trackSelection.style.left=Math.min(a[0],a[1])+"%",this.trackSelection.style.width=Math.abs(a[0]-a[1])+"%","right"===this.stylePos?this.trackHigh.style.left="0":this.trackHigh.style.right="0",this.trackHigh.style.width=100-Math.min(a[0],a[1])-Math.abs(a[0]-a[1])+"%";var p=this.tooltip_min.getBoundingClientRect(),q=this.tooltip_max.getBoundingClientRect();"bottom"===this.options.tooltip_position?p.right>q.left?(this._removeClass(this.tooltip_max,"bottom"),this._addClass(this.tooltip_max,"top"),this.tooltip_max.style.top="",this.tooltip_max.style.bottom="22px"):(this._removeClass(this.tooltip_max,"top"),this._addClass(this.tooltip_max,"bottom"),this.tooltip_max.style.top=this.tooltip_min.style.top,this.tooltip_max.style.bottom=""):p.right>q.left?(this._removeClass(this.tooltip_max,"top"),this._addClass(this.tooltip_max,"bottom"),this.tooltip_max.style.top="18px"):(this._removeClass(this.tooltip_max,"bottom"),this._addClass(this.tooltip_max,"top"),this.tooltip_max.style.top=this.tooltip_min.style.top)}},_createHighlightRange:function(a,b){return this._isHighlightRange(a,b)?a>b?{start:b,size:a-b}:{start:a,size:b-a}:null},_isHighlightRange:function(a,b){return a>=0&&100>=a&&b>=0&&100>=b?!0:!1},_resize:function(a){this._state.offset=this._offset(this.sliderElem),this._state.size=this.sliderElem[this.sizePos],this._layout()},_removeProperty:function(a,b){a.style.removeProperty?a.style.removeProperty(b):a.style.removeAttribute(b)},_mousedown:function(a){if(!this._state.enabled)return!1;this._state.offset=this._offset(this.sliderElem),this._state.size=this.sliderElem[this.sizePos];var b=this._getPercentage(a);if(this.options.range){var c=Math.abs(this._state.percentage[0]-b),d=Math.abs(this._state.percentage[1]-b);this._state.dragged=d>c?0:1,this._adjustPercentageForRangeSliders(b)}else this._state.dragged=0;this._state.percentage[this._state.dragged]=b,this._layout(),this.touchCapable&&(document.removeEventListener("touchmove",this.mousemove,!1),document.removeEventListener("touchend",this.mouseup,!1)),this.mousemove&&document.removeEventListener("mousemove",this.mousemove,!1),this.mouseup&&document.removeEventListener("mouseup",this.mouseup,!1),this.mousemove=this._mousemove.bind(this),this.mouseup=this._mouseup.bind(this),this.touchCapable&&(document.addEventListener("touchmove",this.mousemove,!1),document.addEventListener("touchend",this.mouseup,!1)),document.addEventListener("mousemove",this.mousemove,!1),document.addEventListener("mouseup",this.mouseup,!1),this._state.inDrag=!0;var e=this._calculateValue();return this._trigger("slideStart",e),this._setDataVal(e),this.setValue(e,!1,!0),a.returnValue=!1,this.options.focus&&this._triggerFocusOnHandle(this._state.dragged),!0},_touchstart:function(a){if(void 0===a.changedTouches)return void this._mousedown(a);var b=a.changedTouches[0];this.touchX=b.pageX,this.touchY=b.pageY},_triggerFocusOnHandle:function(a){0===a&&this.handle1.focus(),1===a&&this.handle2.focus()},_keydown:function(a,b){if(!this._state.enabled)return!1;var c;switch(b.keyCode){case 37:case 40:c=-1;break;case 39:case 38:c=1}if(c){if(this.options.natural_arrow_keys){var d="vertical"===this.options.orientation&&!this.options.reversed,e="horizontal"===this.options.orientation&&this.options.reversed;(d||e)&&(c=-c)}var f=this._state.value[a]+c*this.options.step,g=f/this.options.max*100;if(this._state.keyCtrl=a,this.options.range){this._adjustPercentageForRangeSliders(g);var h=this._state.keyCtrl?this._state.value[0]:f,i=this._state.keyCtrl?f:this._state.value[1];f=[h,i]}return this._trigger("slideStart",f),this._setDataVal(f),this.setValue(f,!0,!0),this._setDataVal(f),this._trigger("slideStop",f),this._layout(),this._pauseEvent(b),delete this._state.keyCtrl,!1}},_pauseEvent:function(a){a.stopPropagation&&a.stopPropagation(),a.preventDefault&&a.preventDefault(),a.cancelBubble=!0,a.returnValue=!1},_mousemove:function(a){if(!this._state.enabled)return!1;var b=this._getPercentage(a);this._adjustPercentageForRangeSliders(b),this._state.percentage[this._state.dragged]=b,this._layout();var c=this._calculateValue(!0);return this.setValue(c,!0,!0),!1},_touchmove:function(a){if(void 0!==a.changedTouches){var b=a.changedTouches[0],c=b.pageX-this.touchX,d=b.pageY-this.touchY;this._state.inDrag||("vertical"===this.options.orientation&&5>=c&&c>=-5&&(d>=15||-15>=d)?this._mousedown(a):5>=d&&d>=-5&&(c>=15||-15>=c)&&this._mousedown(a))}},_adjustPercentageForRangeSliders:function(a){if(this.options.range){var b=this._getNumDigitsAfterDecimalPlace(a);b=b?b-1:0;var c=this._applyToFixedAndParseFloat(a,b);0===this._state.dragged&&this._applyToFixedAndParseFloat(this._state.percentage[1],b)<c?(this._state.percentage[0]=this._state.percentage[1],this._state.dragged=1):1===this._state.dragged&&this._applyToFixedAndParseFloat(this._state.percentage[0],b)>c?(this._state.percentage[1]=this._state.percentage[0],this._state.dragged=0):0===this._state.keyCtrl&&this._state.value[1]/this.options.max*100<a?(this._state.percentage[0]=this._state.percentage[1],this._state.keyCtrl=1,this.handle2.focus()):1===this._state.keyCtrl&&this._state.value[0]/this.options.max*100>a&&(this._state.percentage[1]=this._state.percentage[0],this._state.keyCtrl=0,this.handle1.focus())}},_mouseup:function(){if(!this._state.enabled)return!1;this.touchCapable&&(document.removeEventListener("touchmove",this.mousemove,!1),document.removeEventListener("touchend",this.mouseup,!1)),document.removeEventListener("mousemove",this.mousemove,!1),document.removeEventListener("mouseup",this.mouseup,!1),this._state.inDrag=!1,this._state.over===!1&&this._hideTooltip();var a=this._calculateValue(!0);return this._layout(),this._setDataVal(a),this._trigger("slideStop",a),!1},_calculateValue:function(a){var b;if(this.options.range?(b=[this.options.min,this.options.max],0!==this._state.percentage[0]&&(b[0]=this._toValue(this._state.percentage[0]),b[0]=this._applyPrecision(b[0])),100!==this._state.percentage[1]&&(b[1]=this._toValue(this._state.percentage[1]),b[1]=this._applyPrecision(b[1]))):(b=this._toValue(this._state.percentage[0]),b=parseFloat(b),b=this._applyPrecision(b)),a){for(var c=[b,1/0],d=0;d<this.options.ticks.length;d++){var e=Math.abs(this.options.ticks[d]-b);e<=c[1]&&(c=[this.options.ticks[d],e])}if(c[1]<=this.options.ticks_snap_bounds)return c[0]}return b},_applyPrecision:function(a){var b=this.options.precision||this._getNumDigitsAfterDecimalPlace(this.options.step);return this._applyToFixedAndParseFloat(a,b)},_getNumDigitsAfterDecimalPlace:function(a){var b=(""+a).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/);return b?Math.max(0,(b[1]?b[1].length:0)-(b[2]?+b[2]:0)):0},_applyToFixedAndParseFloat:function(a,b){var c=a.toFixed(b);return parseFloat(c)},_getPercentage:function(a){!this.touchCapable||"touchstart"!==a.type&&"touchmove"!==a.type||(a=a.touches[0]);var b=a[this.mousePos],c=this._state.offset[this.stylePos],d=b-c;"right"===this.stylePos&&(d=-d);var e=d/this._state.size*100;return e=Math.round(e/this._state.percentage[2])*this._state.percentage[2],this.options.reversed&&(e=100-e),Math.max(0,Math.min(100,e))},_validateInputValue:function(a){if(isNaN(+a)){if(Array.isArray(a))return this._validateArray(a),a;throw new Error(f.formatInvalidInputErrorMsg(a))}return+a},_validateArray:function(a){for(var b=0;b<a.length;b++){ +var c=a[b];if("number"!=typeof c)throw new Error(f.formatInvalidInputErrorMsg(c))}},_setDataVal:function(a){this.element.setAttribute("data-value",a),this.element.setAttribute("value",a),this.element.value=a},_trigger:function(b,c){c=c||0===c?c:void 0;var d=this.eventToCallbackMap[b];if(d&&d.length)for(var e=0;e<d.length;e++){var f=d[e];f(c)}a&&this._triggerJQueryEvent(b,c)},_triggerJQueryEvent:function(a,b){var c={type:a,value:b};this.$element.trigger(c),this.$sliderElem.trigger(c)},_unbindJQueryEventHandlers:function(){this.$element.off(),this.$sliderElem.off()},_setText:function(a,b){"undefined"!=typeof a.textContent?a.textContent=b:"undefined"!=typeof a.innerText&&(a.innerText=b)},_removeClass:function(a,b){for(var c=b.split(" "),d=a.className,e=0;e<c.length;e++){var f=c[e],g=new RegExp("(?:\\s|^)"+f+"(?:\\s|$)");d=d.replace(g," ")}a.className=d.trim()},_addClass:function(a,b){for(var c=b.split(" "),d=a.className,e=0;e<c.length;e++){var f=c[e],g=new RegExp("(?:\\s|^)"+f+"(?:\\s|$)"),h=g.test(d);h||(d+=" "+f)}a.className=d.trim()},_offsetLeft:function(a){return a.getBoundingClientRect().left},_offsetRight:function(a){return a.getBoundingClientRect().right},_offsetTop:function(a){for(var b=a.offsetTop;(a=a.offsetParent)&&!isNaN(a.offsetTop);)b+=a.offsetTop,"BODY"!==a.tagName&&(b-=a.scrollTop);return b},_offset:function(a){return{left:this._offsetLeft(a),right:this._offsetRight(a),top:this._offsetTop(a)}},_css:function(b,c,d){if(a)a.style(b,c,d);else{var e=c.replace(/^-ms-/,"ms-").replace(/-([\da-z])/gi,function(a,b){return b.toUpperCase()});b.style[e]=d}},_toValue:function(a){return this.options.scale.toValue.apply(this,[a])},_toPercentage:function(a){return this.options.scale.toPercentage.apply(this,[a])},_setTooltipPosition:function(){var a=[this.tooltip,this.tooltip_min,this.tooltip_max];if("vertical"===this.options.orientation){var b;b=this.options.tooltip_position?this.options.tooltip_position:this.options.rtl?"left":"right";var c="left"===b?"right":"left";a.forEach(function(a){this._addClass(a,b),a.style[c]="100%"}.bind(this))}else"bottom"===this.options.tooltip_position?a.forEach(function(a){this._addClass(a,"bottom"),a.style.top="22px"}.bind(this)):a.forEach(function(a){this._addClass(a,"top"),a.style.top=-this.tooltip.outerHeight-14+"px"}.bind(this))}},a&&a.fn){var h=void 0;a.fn.slider?(windowIsDefined&&window.console.warn("bootstrap-slider.js - WARNING: $.fn.slider namespace is already bound. Use the $.fn.bootstrapSlider namespace instead."),h=c):(a.bridget(b,d),h=b),a.bridget(c,d),a(function(){a("input[data-provide=slider]")[h]()})}}(a),d});
\ No newline at end of file diff --git a/web/lib/fontawesome-all-5.0.1.min.js b/web/lib/fontawesome-all-5.0.1.min.js new file mode 100644 index 00000000..3dbd3be8 --- /dev/null +++ b/web/lib/fontawesome-all-5.0.1.min.js @@ -0,0 +1,5 @@ +/*! + * Font Awesome Free 5.0.1 by @fontawesome - http://fontawesome.com + * License - http://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + */ +!function(){"use strict";function c(c){"function"==typeof s.hooks.addPack?s.hooks.addPack(c,m):s.styles[c]=r({},s.styles[c]||{},m)}var l={};try{"undefined"!=typeof window&&(l=window)}catch(c){}var h=(l.navigator||{}).userAgent,v=void 0===h?"":h,z=l,e=(~v.indexOf("MSIE")||v.indexOf("Trident/"),[1,2,3,4,5,6,7,8,9,10]),a=e.concat([11,12,13,14,15,16,17,18,19,20]),m=(["xs","sm","lg","fw","ul","li","border","pull-left","pull-right","spin","pulse","rotate-90","rotate-180","rotate-270","flip-horizontal","flip-vertical","stack","stack-1x","stack-2x","inverse","layers","layers-text","layers-counter"].concat(e.map(function(c){return c+"x"})).concat(a.map(function(c){return"w-"+c})),{"500px":[448,512,[],"f26e","M103.3 344.3c-6.5-14.2-6.9-18.3 7.4-23.1 25.6-8 8 9.2 43.2 49.2h.3v-93.9c1.2-50.2 44-92.2 97.7-92.2 53.9 0 97.7 43.5 97.7 96.8 0 63.4-60.8 113.2-128.5 93.3-10.5-4.2-2.1-31.7 8.5-28.6 53 0 89.4-10.1 89.4-64.4 0-61-77.1-89.6-116.9-44.6-23.5 26.4-17.6 42.1-17.6 157.6 50.7 31 118.3 22 160.4-20.1 24.8-24.8 38.5-58 38.5-93 0-35.2-13.8-68.2-38.8-93.3-24.8-24.8-57.8-38.5-93.3-38.5s-68.8 13.8-93.5 38.5c-.3.3-16 16.5-21.2 23.9l-.5.6c-3.3 4.7-6.3 9.1-20.1 6.1-6.9-1.7-14.3-5.8-14.3-11.8V20c0-5 3.9-10.5 10.5-10.5h241.3c8.3 0 8.3 11.6 8.3 15.1 0 3.9 0 15.1-8.3 15.1H130.3v132.9h.3c104.2-109.8 282.8-36 282.8 108.9 0 178.1-244.8 220.3-310.1 62.8zm63.3-260.8c-.5 4.2 4.6 24.5 14.6 20.6C306 56.6 384 144.5 390.6 144.5c4.8 0 22.8-15.3 14.3-22.8-93.2-89-234.5-57-238.3-38.2zM393 414.7C283 524.6 94 475.5 61 310.5c0-12.2-30.4-7.4-28.9 3.3 24 173.4 246 256.9 381.6 121.3 6.9-7.8-12.6-28.4-20.7-20.4zM213.6 306.6c0 4 4.3 7.3 5.5 8.5 3 3 6.1 4.4 8.5 4.4 3.8 0 2.6.2 22.3-19.5 19.6 19.3 19.1 19.5 22.3 19.5 5.4 0 18.5-10.4 10.7-18.2L265.6 284l18.2-18.2c6.3-6.8-10.1-21.8-16.2-15.7L249.7 268c-18.6-18.8-18.4-19.5-21.5-19.5-5 0-18 11.7-12.4 17.3L234 284c-18.1 17.9-20.4 19.2-20.4 22.6z"],"accessible-icon":[448,512,[],"f368","M423.9 255.8L411 413.1c-3.3 40.7-63.9 35.1-60.6-4.9l10-122.5-41.1 2.3c10.1 20.7 15.8 43.9 15.8 68.5 0 41.2-16.1 78.7-42.3 106.5l-39.3-39.3c57.9-63.7 13.1-167.2-74-167.2-25.9 0-49.5 9.9-67.2 26L73 243.2c22-20.7 50.1-35.1 81.4-40.2l75.3-85.7-42.6-24.8-51.6 46c-30 26.8-70.6-18.5-40.5-45.4l68-60.7c9.8-8.8 24.1-10.2 35.5-3.6 0 0 139.3 80.9 139.5 81.1 16.2 10.1 20.7 36 6.1 52.6L285.7 229l106.1-5.9c18.5-1.1 33.6 14.4 32.1 32.7zm-64.9-154c28.1 0 50.9-22.8 50.9-50.9C409.9 22.8 387.1 0 359 0c-28.1 0-50.9 22.8-50.9 50.9 0 28.1 22.8 50.9 50.9 50.9zM179.6 456.5c-80.6 0-127.4-90.6-82.7-156.1l-39.7-39.7C36.4 287 24 320.3 24 356.4c0 130.7 150.7 201.4 251.4 122.5l-39.7-39.7c-16 10.9-35.3 17.3-56.1 17.3z"],accusoft:[640,512,[],"f369","M482.2 372.1C476.5 365.2 250 75 242.3 65.5c-13.7-17.2 0-16.8 19.2-16.9 9.7-.1 106.3-.6 116.5-.6 24.1-.1 28.7.6 38.4 12.8 2.1 2.7 205.1 245.8 207.2 248.3 5.5 6.7 15.2 19.1 7.2 23.4-2.4 1.3-114.6 47.7-117.8 48.9-10.1 4-17.5 6.8-30.8-9.3m114.7-5.6s-115 50.4-117.5 51.6c-16 7.3-26.9-3.2-36.7-14.6l-57.1-74c-5.4-.9-60.4-9.6-65.3-9.3-3.1.2-9.6.8-14.4 2.9-4.9 2.1-145.2 52.8-150.2 54.7-5.1 2-11.4 3.6-11.1 7.6.2 2.5 2 2.6 4.6 3.5 2.7.8 300.9 67.6 308 69.1 15.6 3.3 38.5 10.5 53.6 1.7 2.1-1.2 123.8-76.4 125.8-77.8 5.4-4 4.3-6.8-1.7-8.2-2.3-.3-24.6-4.7-38-7.2m-326-181.3s-12 1.6-25 15.1c-9 9.3-242.1 239.1-243.4 240.9-7 10 1.6 6.8 15.7 1.7.8 0 114.5-36.6 114.5-36.6.5-.6-.1-.1.6-.6-.4-5.1-.8-26.2-1-27.7-.6-5.2 2.2-6.9 7-8.9l92.6-33.8c.6-.8 88.5-81.7 90.2-83.3v-1l-51.2-65.8"],adn:[496,512,[],"f170","M248 167.5l64.9 98.8H183.1l64.9-98.8zM496 256c0 136.9-111.1 248-248 248S0 392.9 0 256 111.1 8 248 8s248 111.1 248 248zm-99.8 82.7L248 115.5 99.8 338.7h30.4l33.6-51.7h168.6l33.6 51.7h30.2z"],adversal:[512,512,[],"f36a","M482.1 32H28.7C5.8 32 0 37.9 0 60.9v390.2C0 474.4 5.8 480 28.7 480h453.4c24.4 0 29.9-5.2 29.9-29.7V62.2c0-24.6-5.4-30.2-29.9-30.2zM178.4 220.3c-27.5-20.2-72.1-8.7-84.2 23.4-4.3 11.1-9.3 9.5-17.5 8.3-9.7-1.5-17.2-3.2-22.5-5.5-28.8-11.4 8.6-55.3 24.9-64.3 41.1-21.4 83.4-22.2 125.3-4.8 40.9 16.8 34.5 59.2 34.5 128.5 2.7 25.8-4.3 58.3 9.3 88.8 1.9 4.4.4 7.9-2.7 10.7-8.4 6.7-39.3 2.2-46.6-7.4-1.9-2.2-1.8-3.6-3.9-6.2-3.6-3.9-7.3-2.2-11.9 1-57.4 36.4-140.3 21.4-147-43.3-3.1-29.3 12.4-57.1 39.6-71 38.2-19.5 112.2-11.8 114-30.9 1.1-10.2-1.9-20.1-11.3-27.3zm286.7 222c0 15.1-11.1 9.9-17.8 9.9H52.4c-7.4 0-18.2 4.8-17.8-10.7.4-13.9 10.5-9.1 17.1-9.1 132.3-.4 264.5-.4 396.8 0 6.8 0 16.6-4.4 16.6 9.9zm3.8-340.5v291c0 5.7-.7 13.9-8.1 13.9-12.4-.4-27.5 7.1-36.1-5.6-5.8-8.7-7.8-4-12.4-1.2-53.4 29.7-128.1 7.1-144.4-85.2-6.1-33.4-.7-67.1 15.7-100 11.8-23.9 56.9-76.1 136.1-30.5v-71c0-26.2-.1-26.2 26-26.2 3.1 0 6.6.4 9.7 0 10.1-.8 13.6 4.4 13.6 14.3-.1.2-.1.3-.1.5zm-51.5 232.3c-19.5 47.6-72.9 43.3-90 5.2-15.1-33.3-15.5-68.2.4-101.5 16.3-34.1 59.7-35.7 81.5-4.8 20.6 28.8 14.9 84.6 8.1 101.1zm-294.8 35.3c-7.5-1.3-33-3.3-33.7-27.8-.4-13.9 7.8-23 19.8-25.8 24.4-5.9 49.3-9.9 73.7-14.7 8.9-2 7.4 4.4 7.8 9.5 1.4 33-26.1 59.2-67.6 58.8z"],affiliatetheme:[512,512,[],"f36b","M159.7 237.4C108.4 308.3 43.1 348.2 14 326.6-15.2 304.9 2.8 230 54.2 159.1c51.3-70.9 116.6-110.8 145.7-89.2 29.1 21.6 11.1 96.6-40.2 167.5zm351.2-57.3C437.1 303.5 319 367.8 246.4 323.7c-25-15.2-41.3-41.2-49-73.8-33.6 64.8-92.8 113.8-164.1 133.2 49.8 59.3 124.1 96.9 207 96.9 150 0 271.6-123.1 271.6-274.9.1-8.5-.3-16.8-1-25z"],algolia:[448,512,[],"f36c","M229.3 182.6c-49.3 0-89.2 39.9-89.2 89.2 0 49.3 39.9 89.2 89.2 89.2s89.2-39.9 89.2-89.2c0-49.3-40-89.2-89.2-89.2zm62.7 56.6l-58.9 30.6c-1.8.9-3.8-.4-3.8-2.3V201c0-1.5 1.3-2.7 2.7-2.6 26.2 1 48.9 15.7 61.1 37.1.7 1.3.2 3-1.1 3.7zM389.1 32H58.9C26.4 32 0 58.4 0 90.9V421c0 32.6 26.4 59 58.9 59H389c32.6 0 58.9-26.4 58.9-58.9V90.9C448 58.4 421.6 32 389.1 32zm-202.6 84.7c0-10.8 8.7-19.5 19.5-19.5h45.3c10.8 0 19.5 8.7 19.5 19.5v15.4c0 1.8-1.7 3-3.3 2.5-12.3-3.4-25.1-5.1-38.1-5.1-13.5 0-26.7 1.8-39.4 5.5-1.7.5-3.4-.8-3.4-2.5v-15.8zm-84.4 37l9.2-9.2c7.6-7.6 19.9-7.6 27.5 0l7.7 7.7c1.1 1.1 1 3-.3 4-6.2 4.5-12.1 9.4-17.6 14.9-5.4 5.4-10.4 11.3-14.8 17.4-1 1.3-2.9 1.5-4 .3l-7.7-7.7c-7.6-7.5-7.6-19.8 0-27.4zm127.2 244.8c-70 0-126.6-56.7-126.6-126.6s56.7-126.6 126.6-126.6c70 0 126.6 56.6 126.6 126.6 0 69.8-56.7 126.6-126.6 126.6z"],amazon:[448,512,[],"f270","M257.2 162.7c-48.7 1.8-169.5 15.5-169.5 117.5 0 109.5 138.3 114 183.5 43.2 6.5 10.2 35.4 37.5 45.3 46.8l56.8-56S341 288.9 341 261.4V114.3C341 89 316.5 32 228.7 32 140.7 32 94 87 94 136.3l73.5 6.8c16.3-49.5 54.2-49.5 54.2-49.5 40.7-.1 35.5 29.8 35.5 69.1zm0 86.8c0 80-84.2 68-84.2 17.2 0-47.2 50.5-56.7 84.2-57.8v40.6zm136 163.5c-7.7 10-70 67-174.5 67S34.2 408.5 9.7 379c-6.8-7.7 1-11.3 5.5-8.3C88.5 415.2 203 488.5 387.7 401c7.5-3.7 13.3 2 5.5 12zm39.8 2.2c-6.5 15.8-16 26.8-21.2 31-5.5 4.5-9.5 2.7-6.5-3.8s19.3-46.5 12.7-55c-6.5-8.3-37-4.3-48-3.2-10.8 1-13 2-14-.3-2.3-5.7 21.7-15.5 37.5-17.5 15.7-1.8 41-.8 46 5.7 3.7 5.1 0 27.1-6.5 43.1z"],amilia:[448,512,[],"f36d","M240.1 32c-61.9 0-131.5 16.9-184.2 55.4-5.1 3.1-9.1 9.2-7.2 19.4 1.1 5.1 5.1 27.4 10.2 39.6 4.1 10.2 14.2 10.2 20.3 6.1 32.5-22.3 96.5-47.7 152.3-47.7 57.9 0 58.9 28.4 58.9 73.1v38.5C203 227.7 78.2 251 46.7 264.2 11.2 280.5 16.3 357.7 16.3 376s15.2 104 124.9 104c47.8 0 113.7-20.7 153.3-42.1v25.4c0 3 2.1 8.2 6.1 9.1 3.1 1 50.7 2 59.9 2s62.5.3 66.5-.7c4.1-1 5.1-6.1 5.1-9.1V168c-.1-80.3-57.9-136-192-136zm-87.9 327.7c0-12.2-3-42.7 18.3-52.9 24.3-13.2 75.1-29.4 119.8-33.5V380c-21.4 13.2-48.7 24.4-79.1 24.4-52.8 0-58.9-33.5-59-44.7"],android:[448,512,[],"f17b","M89.6 204.5v115.8c0 15.4-12.1 27.7-27.5 27.7-15.3 0-30.1-12.4-30.1-27.7V204.5c0-15.1 14.8-27.5 30.1-27.5 15.1 0 27.5 12.4 27.5 27.5zm10.8 157c0 16.4 13.2 29.6 29.6 29.6h19.9l.3 61.1c0 36.9 55.2 36.6 55.2 0v-61.1h37.2v61.1c0 36.7 55.5 36.8 55.5 0v-61.1h20.2c16.2 0 29.4-13.2 29.4-29.6V182.1H100.4v179.4zm248-189.1H99.3c0-42.8 25.6-80 63.6-99.4l-19.1-35.3c-2.8-4.9 4.3-8 6.7-3.8l19.4 35.6c34.9-15.5 75-14.7 108.3 0L297.5 34c2.5-4.3 9.5-1.1 6.7 3.8L285.1 73c37.7 19.4 63.3 56.6 63.3 99.4zm-170.7-55.5c0-5.7-4.6-10.5-10.5-10.5-5.7 0-10.2 4.8-10.2 10.5s4.6 10.5 10.2 10.5c5.9 0 10.5-4.8 10.5-10.5zm113.4 0c0-5.7-4.6-10.5-10.2-10.5-5.9 0-10.5 4.8-10.5 10.5s4.6 10.5 10.5 10.5c5.6 0 10.2-4.8 10.2-10.5zm94.8 60.1c-15.1 0-27.5 12.1-27.5 27.5v115.8c0 15.4 12.4 27.7 27.5 27.7 15.4 0 30.1-12.4 30.1-27.7V204.5c0-15.4-14.8-27.5-30.1-27.5z"],angellist:[448,512,[],"f209","M347.1 215.4c11.7-32.6 45.4-126.9 45.4-157.1 0-26.6-15.7-48.9-43.7-48.9-44.6 0-84.6 131.7-97.1 163.1C242 144 196.6 0 156.6 0c-31.1 0-45.7 22.9-45.7 51.7 0 35.3 34.2 126.8 46.6 162-6.3-2.3-13.1-4.3-20-4.3-23.4 0-48.3 29.1-48.3 52.6 0 8.9 4.9 21.4 8 29.7-36.9 10-51.1 34.6-51.1 71.7C46 435.6 114.4 512 210.6 512c118 0 191.4-88.6 191.4-202.9 0-43.1-6.9-82-54.9-93.7zM311.7 108c4-12.3 21.1-64.3 37.1-64.3 8.6 0 10.9 8.9 10.9 16 0 19.1-38.6 124.6-47.1 148l-34-6 33.1-93.7zM142.3 48.3c0-11.9 14.5-45.7 46.3 47.1l34.6 100.3c-15.6-1.3-27.7-3-35.4 1.4-10.9-28.8-45.5-119.7-45.5-148.8zM140 244c29.3 0 67.1 94.6 67.1 107.4 0 5.1-4.9 11.4-10.6 11.4-20.9 0-76.9-76.9-76.9-97.7.1-7.7 12.7-21.1 20.4-21.1zm184.3 186.3c-29.1 32-66.3 48.6-109.7 48.6-59.4 0-106.3-32.6-128.9-88.3-17.1-43.4 3.8-68.3 20.6-68.3 11.4 0 54.3 60.3 54.3 73.1 0 4.9-7.7 8.3-11.7 8.3-16.1 0-22.4-15.5-51.1-51.4-29.7 29.7 20.5 86.9 58.3 86.9 26.1 0 43.1-24.2 38-42 3.7 0 8.3.3 11.7-.6 1.1 27.1 9.1 59.4 41.7 61.7 0-.9 2-7.1 2-7.4 0-17.4-10.6-32.6-10.6-50.3 0-28.3 21.7-55.7 43.7-71.7 8-6 17.7-9.7 27.1-13.1 9.7-3.7 20-8 27.4-15.4-1.1-11.2-5.7-21.1-16.9-21.1-27.7 0-120.6 4-120.6-39.7 0-6.7.1-13.1 17.4-13.1 32.3 0 114.3 8 138.3 29.1 18.1 16.1 24.3 113.2-31 174.7zm-98.6-126c9.7 3.1 19.7 4 29.7 6-7.4 5.4-14 12-20.3 19.1-2.8-8.5-6.2-16.8-9.4-25.1z"],angrycreative:[640,512,[],"f36e","M640 238.2l-3.2 28.2-34.5 2.3-2 18.1 34.5-2.3-3.2 28.2-34.4 2.2-2.3 20.1 34.4-2.2-3 26.1-64.7 4.1 12.7-113.2L527 365.2l-31.9 2-23.8-117.8 30.3-2 13.6 79.4 31.7-82.4 93.1-6.2zM426.8 371.5l28.3-1.8L468 249.6l-28.4 1.9-12.8 120zM162 388.1l-19.4-36-3.5 37.4-28.2 1.7 2.7-29.1c-11 18-32 34.3-56.9 35.8C23.9 399.9-3 377 .3 339.7c2.6-29.3 26.7-62.8 67.5-65.4 37.7-2.4 47.6 23.2 51.3 28.8l2.8-30.8 38.9-2.5c20.1-1.3 38.7 3.7 42.5 23.7l2.6-26.6 64.8-4.2-2.7 27.9-36.4 2.4-1.7 17.9 36.4-2.3-2.7 27.9-36.4 2.3-1.9 19.9 36.3-2.3-2.1 20.8 55-117.2 23.8-1.6L370.4 369l8.9-85.6-22.3 1.4 2.9-27.9 75-4.9-3 28-24.3 1.6-9.7 91.9-58 3.7-4.3-15.6-39.4 2.5-8 16.3-126.2 7.7zm-44.3-70.2l-26.4 1.7C84.6 307.2 76.9 303 65 303.8c-19 1.2-33.3 17.5-34.6 33.3-1.4 16 7.3 32.5 28.7 31.2 12.8-.8 21.3-8.6 28.9-18.9l27-1.7 2.7-29.8zm56.1-7.7c1.2-12.9-7.6-13.6-26.1-12.4l-2.7 28.5c14.2-.9 27.5-2.1 28.8-16.1zm21.1 70.8l5.8-60c-5 13.5-14.7 21.1-27.9 26.6l22.1 33.4zm135.4-45l-7.9-37.8-15.8 39.3 23.7-1.5zm-170.1-74.6l-4.3-17.5-39.6 2.6-8.1 18.2-31.9 2.1 57-121.9 23.9-1.6 30.7 102 9.9-104.7 27-1.8 37.8 63.6 6.5-66.6 28.5-1.9-4 41.2c7.4-13.5 22.9-44.7 63.6-47.5 40.5-2.8 52.4 29.3 53.4 30.3l3.3-32 39.3-2.7c12.7-.9 27.8.3 36.3 9.7l-4.4-11.9 32.2-2.2 12.9 43.2 23-45.7 31-2.2-43.6 78.4-4.8 44.3-28.4 1.9 4.8-44.3-15.8-43c1 22.3-9.2 40.1-32 49.6l25.2 38.8-36.4 2.4-19.2-36.8-4 38.3-28.4 1.9 3.3-31.5c-6.7 9.3-19.7 35.4-59.6 38-26.2 1.7-45.6-10.3-55.4-39.2l-4 40.3-25 1.6-37.6-63.3-6.3 66.2-56.8 3.7zm276.6-82.1c10.2-.7 17.5-2.1 21.6-4.3 4.5-2.4 7-6.4 7.6-12.1.6-5.3-.6-8.8-3.4-10.4-3.6-2.1-10.6-2.8-22.9-2l-2.9 28.8zM327.7 214c5.6 5.9 12.7 8.5 21.3 7.9 4.7-.3 9.1-1.8 13.3-4.1 5.5-3 10.6-8 15.1-14.3l-34.2 2.3 2.4-23.9 63.1-4.3 1.2-12-31.2 2.1c-4.1-3.7-7.8-6.6-11.1-8.1-4-1.7-8.1-2.8-12.2-2.5-8 .5-15.3 3.6-22 9.2-7.7 6.4-12 14.5-12.9 24.4-1.1 9.6 1.4 17.3 7.2 23.3zm-201.3 8.2l23.8-1.6-8.3-37.6-15.5 39.2z"],angular:[415,512,[],"f420","M169.7 268.1h76.2l-38.1-91.6-38.1 91.6zM207.8 32L0 106.4l31.8 275.7 176 97.9 176-97.9 31.8-275.7L207.8 32zM338 373.8h-48.6l-26.2-65.4H152.6l-26.2 65.4H77.7L207.8 81.5 338 373.8z"],"app-store":[512,512,[],"f36f","M255.9 120.9l9.1-15.7c5.6-9.8 18.1-13.1 27.9-7.5 9.8 5.6 13.1 18.1 7.5 27.9l-87.5 151.5h63.3c20.5 0 32 24.1 23.1 40.8H113.8c-11.3 0-20.4-9.1-20.4-20.4 0-11.3 9.1-20.4 20.4-20.4h52l66.6-115.4-20.8-36.1c-5.6-9.8-2.3-22.2 7.5-27.9 9.8-5.6 22.2-2.3 27.9 7.5l8.9 15.7zm-78.7 218l-19.6 34c-5.6 9.8-18.1 13.1-27.9 7.5-9.8-5.6-13.1-18.1-7.5-27.9l14.6-25.2c16.4-5.1 29.8-1.2 40.4 11.6zm168.9-61.7h53.1c11.3 0 20.4 9.1 20.4 20.4 0 11.3-9.1 20.4-20.4 20.4h-29.5l19.9 34.5c5.6 9.8 2.3 22.2-7.5 27.9-9.8 5.6-22.2 2.3-27.9-7.5-33.5-58.1-58.7-101.6-75.4-130.6-17.1-29.5-4.9-59.1 7.2-69.1 13.4 23 33.4 57.7 60.1 104zM256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm216 248c0 118.7-96.1 216-216 216-118.7 0-216-96.1-216-216 0-118.7 96.1-216 216-216 118.7 0 216 96.1 216 216z"],"app-store-ios":[448,512,[],"f370","M400 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48zM127 384.5c-5.5 9.6-17.8 12.8-27.3 7.3-9.6-5.5-12.8-17.8-7.3-27.3l14.3-24.7c16.1-4.9 29.3-1.1 39.6 11.4L127 384.5zm138.9-53.9H84c-11 0-20-9-20-20s9-20 20-20h51l65.4-113.2-20.5-35.4c-5.5-9.6-2.2-21.8 7.3-27.3 9.6-5.5 21.8-2.2 27.3 7.3l8.9 15.4 8.9-15.4c5.5-9.6 17.8-12.8 27.3-7.3 9.6 5.5 12.8 17.8 7.3 27.3l-85.8 148.6h62.1c20.2 0 31.5 23.7 22.7 40zm98.1 0h-29l19.6 33.9c5.5 9.6 2.2 21.8-7.3 27.3-9.6 5.5-21.8 2.2-27.3-7.3-32.9-56.9-57.5-99.7-74-128.1-16.7-29-4.8-58 7.1-67.8 13.1 22.7 32.7 56.7 58.9 102h52c11 0 20 9 20 20 0 11.1-9 20-20 20z"],apper:[640,512,[],"f371","M42.1 239.1c22.2 0 29 2.8 33.5 14.6h.8v-22.9c0-11.3-4.8-15.4-17.9-15.4-11.3 0-14.4 2.5-15.1 12.8H4.8c.3-13.9 1.5-19.1 5.8-24.4C17.9 195 29.5 192 56.7 192c33 0 47.1 5 53.9 18.9 2 4.3 4 15.6 4 23.7v76.3H76.3l1.3-19.1h-1c-5.3 15.6-13.6 20.4-35.5 20.4-30.3 0-41.1-10.1-41.1-37.3 0-25.2 12.3-35.8 42.1-35.8zm17.1 48.1c13.1 0 16.9-3 16.9-13.4 0-9.1-4.3-11.6-19.6-11.6-13.1 0-17.9 3-17.9 12.1-.1 10.4 3.7 12.9 20.6 12.9zm77.8-94.9h38.3l-1.5 20.6h.8c9.1-17.1 15.9-20.9 37.5-20.9 14.4 0 24.7 3 31.5 9.1 9.8 8.6 12.8 20.4 12.8 48.1 0 30-3 43.1-12.1 52.9-6.8 7.3-16.4 10.1-33.2 10.1-20.4 0-29.2-5.5-33.8-21.2h-.8v70.3H137v-169zm80.9 60.7c0-27.5-3.3-32.5-20.7-32.5-16.9 0-20.7 5-20.7 28.7 0 28 3.5 33.5 21.2 33.5 16.4 0 20.2-5.6 20.2-29.7zm57.9-60.7h38.3l-1.5 20.6h.8c9.1-17.1 15.9-20.9 37.5-20.9 14.4 0 24.7 3 31.5 9.1 9.8 8.6 12.8 20.4 12.8 48.1 0 30-3 43.1-12.1 52.9-6.8 7.3-16.4 10.1-33.3 10.1-20.4 0-29.2-5.5-33.8-21.2h-.8v70.3h-39.5v-169zm80.9 60.7c0-27.5-3.3-32.5-20.7-32.5-16.9 0-20.7 5-20.7 28.7 0 28 3.5 33.5 21.2 33.5 16.4 0 20.2-5.6 20.2-29.7zm53.8-3.8c0-25.4 3.3-37.8 12.3-45.8 8.8-8.1 22.2-11.3 45.1-11.3 42.8 0 55.7 12.8 55.7 55.7v11.1h-75.3c-.3 2-.3 4-.3 4.8 0 16.9 4.5 21.9 20.1 21.9 13.9 0 17.9-3 17.9-13.9h37.5v2.3c0 9.8-2.5 18.9-6.8 24.7-7.3 9.8-19.6 13.6-44.3 13.6-27.5 0-41.6-3.3-50.6-12.3-8.5-8.5-11.3-21.3-11.3-50.8zm76.4-11.6c-.3-1.8-.3-3.3-.3-3.8 0-12.3-3.3-14.6-19.6-14.6-14.4 0-17.1 3-18.1 15.1l-.3 3.3h38.3zm55.6-45.3h38.3l-1.8 19.9h.7c6.8-14.9 14.4-20.2 29.7-20.2 10.8 0 19.1 3.3 23.4 9.3 5.3 7.3 6.8 14.4 6.8 34 0 1.5 0 5 .2 9.3h-35c.3-1.8.3-3.3.3-4 0-15.4-2-19.4-10.3-19.4-6.3 0-10.8 3.3-13.1 9.3-1 3-1 4.3-1 12.3v68h-38.3V192.3z"],apple:[448,512,[],"f179","M247.2 137.6c-6.2 1.9-15.3 3.5-27.9 4.6 1.1-56.7 29.9-96.6 88-110.1 9.3 41.6-26.1 94.1-60.1 105.5zm121.3 72.7c6.4-9.4 16.6-19.9 30.6-31.7-22.3-27.6-48.1-44.3-85.1-44.3-35.4 0-65.2 18.2-87 18.2-18.5 0-51.9-16.1-84.5-16.1-69.6 0-106.5 68.1-106.5 139C36 354.2 95.7 480 156.2 480c23.8 0 45.2-18 73.5-18 29.3 0 52.8 17.2 80.3 17.2 46 0 88.6-77.5 102-119.7-46.8-14.3-84.4-90.2-43.5-149.2z"],"apple-pay":[640,512,[],"f415","M116.9 158.5c-7.5 8.9-19.5 15.9-31.5 14.9-1.5-12 4.4-24.8 11.3-32.6 7.5-9.1 20.6-15.6 31.3-16.1 1.2 12.4-3.7 24.7-11.1 33.8m10.9 17.2c-17.4-1-32.3 9.9-40.5 9.9-8.4 0-21-9.4-34.8-9.1-17.9.3-34.5 10.4-43.6 26.5-18.8 32.3-4.9 80 13.3 106.3 8.9 13 19.5 27.3 33.5 26.8 13.3-.5 18.5-8.6 34.5-8.6 16.1 0 20.8 8.6 34.8 8.4 14.5-.3 23.6-13 32.5-26 10.1-14.8 14.3-29.1 14.5-29.9-.3-.3-28-10.9-28.3-42.9-.3-26.8 21.9-39.5 22.9-40.3-12.5-18.6-32-20.6-38.8-21.1m100.4-36.2v194.9h30.3v-66.6h41.9c38.3 0 65.1-26.3 65.1-64.3s-26.4-64-64.1-64h-73.2zm30.3 25.5h34.9c26.3 0 41.3 14 41.3 38.6s-15 38.8-41.4 38.8h-34.8V165zm162.2 170.9c19 0 36.6-9.6 44.6-24.9h.6v23.4h28v-97c0-28.1-22.5-46.3-57.1-46.3-32.1 0-55.9 18.4-56.8 43.6h27.3c2.3-12 13.4-19.9 28.6-19.9 18.5 0 28.9 8.6 28.9 24.5v10.8l-37.8 2.3c-35.1 2.1-54.1 16.5-54.1 41.5.1 25.2 19.7 42 47.8 42zm8.2-23.1c-16.1 0-26.4-7.8-26.4-19.6 0-12.3 9.9-19.4 28.8-20.5l33.6-2.1v11c0 18.2-15.5 31.2-36 31.2zm102.5 74.6c29.5 0 43.4-11.3 55.5-45.4L640 193h-30.8l-35.6 115.1h-.6L537.4 193h-31.6L557 334.9l-2.8 8.6c-4.6 14.6-12.1 20.3-25.5 20.3-2.4 0-7-.3-8.9-.5v23.4c1.8.4 9.3.7 11.6.7z"],asymmetrik:[576,512,[],"f372","M517.5 309.2c38.8-40 58.1-80 58.5-116.1.8-65.5-59.4-118.2-169.4-135C277.9 38.4 118.1 73.6 0 140.5 52 114 110.6 92.3 170.7 82.3c74.5-20.5 153-25.4 221.3-14.8C544.5 91.3 588.8 195 490.8 299.2c-10.2 10.8-22 21.1-35 30.6L304.9 103.4 114.7 388.9c-65.6-29.4-76.5-90.2-19.1-151.2 20.8-22.2 48.3-41.9 79.5-58.1 20-12.2 39.7-22.6 62-30.7-65.1 20.3-122.7 52.9-161.6 92.9-27.7 28.6-41.4 57.1-41.7 82.9-.5 35.1 23.4 65.1 68.4 83l-34.5 51.7h101.6l22-34.4c22.2 1 45.3 0 68.6-2.7l-22.8 37.1h135.5L340 406.3c18.6-5.3 36.9-11.5 54.5-18.7l45.9 71.8H542L468.6 349c18.5-12.1 35-25.5 48.9-39.8zm-187.6 80.5l-25-40.6-32.7 53.3c-23.4 3.5-46.7 5.1-69.2 4.4l101.9-159.3 78.7 123c-17.2 7.4-35.3 13.9-53.7 19.2z"],audible:[640,512,[],"f373","M640 199.9v54l-320 200L0 254v-54l320 200 320-200.1zm-194.5 72l47.1-29.4c-37.2-55.8-100.7-92.6-172.7-92.6-72 0-135.5 36.7-172.6 92.4h.3c2.5-2.3 5.1-4.5 7.7-6.7 89.7-74.4 219.4-58.1 290.2 36.3zm-220.1 18.8c16.9-11.9 36.5-18.7 57.4-18.7 34.4 0 65.2 18.4 86.4 47.6l45.4-28.4c-20.9-29.9-55.6-49.5-94.8-49.5-38.9 0-73.4 19.4-94.4 49zM103.6 161.1c131.8-104.3 318.2-76.4 417.5 62.1l.7 1 48.8-30.4C517.1 112.1 424.8 58.1 319.9 58.1c-103.5 0-196.6 53.5-250.5 135.6 9.9-10.5 22.7-23.5 34.2-32.6zm467 32.7z"],autoprefixer:[640,512,[],"f41c","M318.4 16l-161 480h77.5l25.4-81.4h119.5L405 496h77.5L318.4 16zm-40.3 341.9l41.2-130.4h1.5l40.9 130.4h-83.6zM640 405l-10-31.4L462.1 358l19.4 56.5L640 405zm-462.1-47L10 373.7 0 405l158.5 9.4 19.4-56.4z"],avianex:[512,512,[],"f374","M453.1 32h-312c-38.9 0-76.2 31.2-83.3 69.7L1.2 410.3C-5.9 448.8 19.9 480 58.9 480h312c38.9 0 76.2-31.2 83.3-69.7l56.7-308.5c7-38.6-18.8-69.8-57.8-69.8zm-58.2 347.3l-32 13.5-115.4-110c-14.7 10-29.2 19.5-41.7 27.1l22.1 64.2-17.9 12.7-40.6-61-52.4-48.1 15.7-15.4 58 31.1c9.3-10.5 20.8-22.6 32.8-34.9L203 228.9l-68.8-99.8 18.8-28.9 8.9-4.8L265 207.8l4.9 4.5c19.4-18.8 33.8-32.4 33.8-32.4 7.7-6.5 21.5-2.9 30.7 7.9 9 10.5 10.6 24.7 2.7 31.3-1.8 1.3-15.5 11.4-35.3 25.6l4.5 7.3 94.9 119.4-6.3 7.9z"],aviato:[640,512,[],"f421","M107.2 283.5l-19-41.8H36.1l-19 41.8H0l62.2-131.4 62.2 131.4h-17.2zm-45-98.1l-19.6 42.5h39.2l-19.6-42.5zm112.7 102.4l-62.2-131.4h17.1l45.1 96 45.1-96h17l-62.1 131.4zm80.6-4.3V156.4H271v127.1h-15.5zm209.1-115.6v115.6h-17.3V167.9h-41.2v-11.5h99.6v11.5h-41.1zM640 218.8c0 9.2-1.7 17.8-5.1 25.8-3.4 8-8.2 15.1-14.2 21.1-6 6-13.1 10.8-21.1 14.2-8 3.4-16.6 5.1-25.8 5.1s-17.8-1.7-25.8-5.1c-8-3.4-15.1-8.2-21.1-14.2-6-6-10.8-13-14.2-21.1-3.4-8-5.1-16.6-5.1-25.8s1.7-17.8 5.1-25.8c3.4-8 8.2-15.1 14.2-21.1 6-6 13-8.4 21.1-11.9 8-3.4 16.6-5.1 25.8-5.1s17.8 1.7 25.8 5.1c8 3.4 15.1 5.8 21.1 11.9 6 6 10.7 13.1 14.2 21.1 3.4 8 5.1 16.6 5.1 25.8zm-15.5 0c0-7.3-1.3-14-3.9-20.3-2.6-6.3-6.2-11.7-10.8-16.3-4.6-4.6-10-8.2-16.2-10.9-6.2-2.7-12.8-4-19.8-4s-13.6 1.3-19.8 4c-6.2 2.7-11.6 6.3-16.2 10.9-4.6 4.6-8.2 10-10.8 16.3-2.6 6.3-3.9 13.1-3.9 20.3 0 7.3 1.3 14 3.9 20.3 2.6 6.3 6.2 11.7 10.8 16.3 4.6 4.6 10 8.2 16.2 10.9 6.2 2.7 12.8 4 19.8 4s13.6-1.3 19.8-4c6.2-2.7 11.6-6.3 16.2-10.9 4.6-4.6 8.2-10 10.8-16.3 2.6-6.3 3.9-13.1 3.9-20.3zm-94.8 96.7v-6.3l88.9-10-242.9 13.4c.6-2.2 1.1-4.6 1.4-7.2.3-2 .5-4.2.6-6.5l64.8-8.1-64.9 1.9c0-.4-.1-.7-.1-1.1-2.8-17.2-25.5-23.7-25.5-23.7l-1.1-26.3h23.8l19 41.8h17.1L348.6 152l-62.2 131.4h17.1l19-41.8h23.6L345 268s-22.7 6.5-25.5 23.7c-.1.3-.1.7-.1 1.1l-64.9-1.9 64.8 8.1c.1 2.3.3 4.4.6 6.5.3 2.6.8 5 1.4 7.2L78.4 299.2l88.9 10v6.3c-5.9.9-10.5 6-10.5 12.2 0 6.8 5.6 12.4 12.4 12.4 6.8 0 12.4-5.6 12.4-12.4 0-6.2-4.6-11.3-10.5-12.2v-5.8l80.3 9v5.4c-5.7 1.1-9.9 6.2-9.9 12.1 0 6.8 5.6 10.2 12.4 10.2 6.8 0 12.4-3.4 12.4-10.2 0-6-4.3-11-9.9-12.1v-4.9l28.4 3.2v23.7h-5.9V360h5.9v-6.6h5v6.6h5.9v-13.8h-5.9V323l38.3 4.3c8.1 11.4 19 13.6 19 13.6l-.1 6.7-5.1.2-.1 12.1h4.1l.1-5h5.2l.1 5h4.1l-.1-12.1-5.1-.2-.1-6.7s10.9-2.1 19-13.6l38.3-4.3v23.2h-5.9V360h5.9v-6.6h5v6.6h5.9v-13.8h-5.9v-23.7l28.4-3.2v4.9c-5.7 1.1-9.9 6.2-9.9 12.1 0 6.8 5.6 10.2 12.4 10.2 6.8 0 12.4-3.4 12.4-10.2 0-6-4.3-11-9.9-12.1v-5.4l80.3-9v5.8c-5.9.9-10.5 6-10.5 12.2 0 6.8 5.6 12.4 12.4 12.4 6.8 0 12.4-5.6 12.4-12.4-.2-6.3-4.7-11.4-10.7-12.3zm-200.8-87.6l19.6-42.5 19.6 42.5h-17.9l-1.7-40.3-1.7 40.3h-17.9z"],aws:[512,512,[],"f375","M261.2 136.1c-14 57.5-13.1 54.4-25.8 107-1.6 6.5-4.1 8.4-10.7 8.5h-14.4c-5.8-.1-8.2-1.6-9.9-7.3-12.3-39.4-28.8-94.1-39.9-130.7-4.1-13.5-1.4-13.2 9.3-12.9 3.7.1 7.3 0 11 0 5.1.1 7.7 2 9.1 7.1 3.6 12.9 6 22.8 26.6 104.1.4 1.6.9 3.1 1.4 4.6h1.1c.5-2 1.1-3.9 1.6-5.9 7.8-32.9 15.5-65.9 23.3-98.8 2.4-10.2 6.7-11.2 17-11.2h7.6c6.9.1 9 1.5 10.7 8.3 6 23.4 23.5 101.8 26.7 110.4 5.1-18.3-1.8 7.9 28.5-109 2.1-8.1 4.1-9.7 12.3-9.7h12.7c5.4.1 7 1.8 5.7 7.1-2.4 9.5-2.9 9.9-41.3 132.9-3.1 9.9-4.2 10.8-14.6 10.8h-10.6c-7.3 0-9.2-1.3-11-8.4-4.3-16.2-23.3-95.7-26.4-106.9zM125.4 247.3c4.2 5.8 8.1 6.3 14.1 2.4l6.3-4.2c6.8-4.5 7.3-6.3 3.6-13.5-4.3-8.4-6.4-17.3-6.3-26.9 0-3.1.6-55.7-.9-66.8-2.7-19.3-12.5-32.8-31.7-38.7-10.7-3.4-21.7-3.3-32.7-3-15.1.4-29.4 4.6-42.8 11.4-1.8.9-3.7 3.1-4.1 4.9-.8 3.9-1.1 8.1-.7 12.1.6 5.9 2.6 7 8.2 5.1 5.1-1.7 10-3.9 15.1-5.4 14.5-4.4 29.2-6.4 44.1-1.7 7.1 2.2 11.7 6.9 14.3 13.8 3 7.9 2.4 16.1 2.4 24.2 0 5.5-.1 5.5-5.5 4.5-13.9-2.6-27.7-5-41.9-3.1-15.2 2.1-28.6 7.3-38.2 20-9.1 12-10 25.6-7.4 39.5 2.8 15 11.8 25.7 26.4 30.4 20.6 6.7 40.1 3.3 57.7-9.5 3.8-2.8 7.2-6.2 11.1-9.5 3.1 5 5.8 9.7 8.9 14zm-15.3-61.6c3 .4 4.5 1.9 4.3 5.1-.2 3.8.1 7.6-.3 11.4-1.2 11.7-7.7 19.7-17.9 24.9-8.2 4.2-16.9 5.8-26.1 5-15.2-1.3-21-13.1-19.6-26.3C51.8 193.2 59 186.2 72 184c13.8-2.4 16-1.1 38.1 1.7zm348.8 65.1c21.3-8.6 32.9-26.2 29.2-50-2.2-14.6-11.8-24.2-25.2-29.5-14.7-5.9-33.8-10.3-48.1-18.2-4.4-2.4-7.4-6.3-7.6-11.9-.4-11.1 4.2-17.2 15.4-19.8 9.3-2.1 18.8-2.2 28.1-.4 7.3 1.4 14.3 4.2 21.4 6.3 2.8.9 5.9 2.1 7.8-1.6 3.8-7.3.4-18.7-7.3-21.8-22.5-9-45.5-11.6-68.2-1.6-14.6 6.4-24.6 17.4-26 34.2-1.6 19.3 6.9 33.4 24.1 41.7 7.7 3.7 16.1 5.9 24.2 8.9 8.1 3 16.2 5.8 24.1 9.1 12.3 5.3 11.6 24.2 1.2 30-27.7 15.3-64.9-2.4-69.2-3.8-3.3-1.1-5.3.2-6.3 3.7-3 11.3.7 18.8 11.6 22.7 21.7 7.9 49.6 10.5 70.8 2zM296 413.5c50.8-5.8 98.7-20.8 142.7-47 8-4.7 15.5-10.3 23.1-15.7 7.3-5.2 3.2-18.4-11.3-12.2-54.4 23.2-111.2 36.1-170.2 38.9-30.5 1.5-60.8-.3-91.1-4.7-63.1-9.2-122.4-29.2-177.6-61.2-2.1-1.2-4.2-2.5-6.5-3-4.9-1.1-7.7 4.7-2.4 9.7 24 22.1 50.3 40.8 79.1 55.7 53.7 27.7 110.5 42.7 171.2 42 14.4-.8 28.8-.9 43-2.5zm174.7-92.2c14.8.8 19.4 5.9 15.7 20.2-3.8 14.8-9.3 29.2-13.9 43.8-.9 2.9-4.2 6.3-.8 8.8 3.7 2.6 6.5-1 9-3.3 10.2-9.5 17.4-21 22.5-33.8 5.4-13.4 9.3-27.2 8.7-41.9-.2-6.2-1.8-8.8-7.8-10.5-5.4-1.5-11-2.8-16.5-3.2-21.6-1.8-42.5.5-62 10.6-3.1 1.6-6 3.7-8.7 5.9-1.1.9-3.2 5.3 2.4 6.1 1.9.3 3.9-.1 5.9-.3 16.9-1.6 28.6-3.3 45.5-2.4z"],bandcamp:[496,512,[],"f2d5","M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm48.2 326.1h-181L199.9 178h181l-84.7 156.1z"],behance:[576,512,[],"f1b4","M232 237.2c31.8-15.2 48.4-38.2 48.4-74 0-70.6-52.6-87.8-113.3-87.8H0v354.4h171.8c64.4 0 124.9-30.9 124.9-102.9 0-44.5-21.1-77.4-64.7-89.7zM77.9 135.9H151c28.1 0 53.4 7.9 53.4 40.5 0 30.1-19.7 42.2-47.5 42.2h-79v-82.7zm83.3 233.7H77.9V272h84.9c34.3 0 56 14.3 56 50.6 0 35.8-25.9 47-57.6 47zm358.5-240.7H376V94h143.7v34.9zM576 305.2c0-75.9-44.4-139.2-124.9-139.2-78.2 0-131.3 58.8-131.3 135.8 0 79.9 50.3 134.7 131.3 134.7 61.3 0 101-27.6 120.1-86.3H509c-6.7 21.9-34.3 33.5-55.7 33.5-41.3 0-63-24.2-63-65.3h185.1c.3-4.2.6-8.7.6-13.2zM390.4 274c2.3-33.7 24.7-54.8 58.5-54.8 35.4 0 53.2 20.8 56.2 54.8H390.4z"],"behance-square":[512,512,[],"f1b5","M186.5 293c0 19.3-14 25.4-31.2 25.4h-45.1v-52.9h46c18.6.1 30.3 7.8 30.3 27.5zm-7.7-82.3c0-17.7-13.7-21.9-28.9-21.9h-39.6v44.8H153c15.1 0 25.8-6.6 25.8-22.9zm132.3 23.2c-18.3 0-30.5 11.4-31.7 29.7h62.2c-1.7-18.5-11.3-29.7-30.5-29.7zM448 80v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V80c0-26.5 21.5-48 48-48h352c26.5 0 48 21.5 48 48zM271.7 185h77.8v-18.9h-77.8V185zm-43 110.3c0-24.1-11.4-44.9-35-51.6 17.2-8.2 26.2-17.7 26.2-37 0-38.2-28.5-47.5-61.4-47.5H68v192h93.1c34.9-.2 67.6-16.9 67.6-55.9zM380 280.5c0-41.1-24.1-75.4-67.6-75.4-42.4 0-71.1 31.8-71.1 73.6 0 43.3 27.3 73 71.1 73 33.2 0 54.7-14.9 65.1-46.8h-33.7c-3.7 11.9-18.6 18.1-30.2 18.1-22.4 0-34.1-13.1-34.1-35.3h100.2c.1-2.3.3-4.8.3-7.2z"],bimobject:[448,512,[],"f378","M416 32H32C14.4 32 0 46.4 0 64v384c0 17.6 14.4 32 32 32h384c17.6 0 32-14.4 32-32V64c0-17.6-14.4-32-32-32zm-64 257.4c0 49.4-11.4 82.6-103.8 82.6h-16.9c-44.1 0-62.4-14.9-70.4-38.8h-.9V368H96V136h64v74.7h1.1c4.6-30.5 39.7-38.8 69.7-38.8h17.3c92.4 0 103.8 33.1 103.8 82.5v35zm-64-28.9v22.9c0 21.7-3.4 33.8-38.4 33.8h-45.3c-28.9 0-44.1-6.5-44.1-35.7v-19c0-29.3 15.2-35.7 44.1-35.7h45.3c35-.2 38.4 12 38.4 33.7z"],bitbucket:[512,512,[],"f171","M23.1 32C14.2 31.9 7 38.9 6.9 47.8c0 .9.1 1.8.2 2.8L74.9 462c1.7 10.4 10.7 18 21.2 18.1h325.1c7.9.1 14.7-5.6 16-13.4l67.8-416c1.4-8.7-4.5-16.9-13.2-18.3-.9-.1-1.8-.2-2.8-.2L23.1 32zm285.3 297.3H204.6l-28.1-146.8h157l-25.1 146.8z"],bitcoin:[512,512,[],"f379","M504 256c0 136.967-111.033 248-248 248S8 392.967 8 256 119.033 8 256 8s248 111.033 248 248zm-141.651-35.33c4.937-32.999-20.191-50.739-54.55-62.573l11.146-44.702-27.213-6.781-10.851 43.524c-7.154-1.783-14.502-3.464-21.803-5.13l10.929-43.81-27.198-6.781-11.153 44.686c-5.922-1.349-11.735-2.682-17.377-4.084l.031-.14-37.53-9.37-7.239 29.062s20.191 4.627 19.765 4.913c11.022 2.751 13.014 10.044 12.68 15.825l-12.696 50.925c.76.194 1.744.473 2.829.907-.907-.225-1.876-.473-2.876-.713l-17.796 71.338c-1.349 3.348-4.767 8.37-12.471 6.464.271.395-19.78-4.937-19.78-4.937l-13.51 31.147 35.414 8.827c6.588 1.651 13.045 3.379 19.4 5.006l-11.262 45.213 27.182 6.781 11.153-44.733a1038.209 1038.209 0 0 0 21.687 5.627l-11.115 44.523 27.213 6.781 11.262-45.128c46.404 8.781 81.299 5.239 95.986-36.727 11.836-33.79-.589-53.281-25.004-65.991 17.78-4.098 31.174-15.792 34.747-39.949zm-62.177 87.179c-8.41 33.79-65.308 15.523-83.755 10.943l14.944-59.899c18.446 4.603 77.6 13.717 68.811 48.956zm8.417-87.667c-7.673 30.736-55.031 15.12-70.393 11.292l13.548-54.327c15.363 3.828 64.836 10.973 56.845 43.035z"],bity:[496,512,[],"f37a","M78.4 67.2C173.8-22 324.5-24 421.5 71c14.3 14.1-6.4 37.1-22.4 21.5-84.8-82.4-215.8-80.3-298.9-3.2-16.3 15.1-36.5-8.3-21.8-22.1zm98.9 418.6c19.3 5.7 29.3-23.6 7.9-30C73 421.9 9.4 306.1 37.7 194.8c5-19.6-24.9-28.1-30.2-7.1-32.1 127.4 41.1 259.8 169.8 298.1zm148.1-2c121.9-40.2 192.9-166.9 164.4-291-4.5-19.7-34.9-13.8-30 7.9 24.2 107.7-37.1 217.9-143.2 253.4-21.2 7-10.4 36 8.8 29.7zm-62.9-79l.2-71.8c0-8.2-6.6-14.8-14.8-14.8-8.2 0-14.8 6.7-14.8 14.8l-.2 71.8c0 8.2 6.6 14.8 14.8 14.8s14.8-6.6 14.8-14.8zm71-269c2.1 90.9 4.7 131.9-85.5 132.5-92.5-.7-86.9-44.3-85.5-132.5 0-21.8-32.5-19.6-32.5 0v71.6c0 69.3 60.7 90.9 118 90.1 57.3.8 118-20.8 118-90.1v-71.6c0-19.6-32.5-21.8-32.5 0z"],"black-tie":[448,512,[],"f27e","M0 32v448h448V32H0zm316.5 325.2L224 445.9l-92.5-88.7 64.5-184-64.5-86.6h184.9L252 173.2l64.5 184z"],blackberry:[512,512,[],"f37b","M166 116.9c0 23.4-16.4 49.1-72.5 49.1H23.4l21-88.8h67.8c42.1 0 53.8 23.3 53.8 39.7zm126.2-39.7h-67.8L205.7 166h70.1c53.8 0 70.1-25.7 70.1-49.1.1-16.4-11.6-39.7-53.7-39.7zM88.8 208.1H21L0 296.9h70.1c56.1 0 72.5-23.4 72.5-49.1 0-16.3-11.7-39.7-53.8-39.7zm180.1 0h-67.8l-18.7 88.8h70.1c53.8 0 70.1-23.4 70.1-49.1 0-16.3-11.7-39.7-53.7-39.7zm189.3-53.8h-67.8l-18.7 88.8h70.1c53.8 0 70.1-23.4 70.1-49.1.1-16.3-11.6-39.7-53.7-39.7zm-28 137.9h-67.8L343.7 381h70.1c56.1 0 70.1-23.4 70.1-49.1 0-16.3-11.6-39.7-53.7-39.7zM240.8 346H173l-18.7 88.8h70.1c56.1 0 70.1-25.7 70.1-49.1.1-16.3-11.6-39.7-53.7-39.7z"],blogger:[448,512,[],"f37c","M162.4 196c4.8-4.9 6.2-5.1 36.4-5.1 27.2 0 28.1.1 32.1 2.1 5.8 2.9 8.3 7 8.3 13.6 0 5.9-2.4 10-7.6 13.4-2.8 1.8-4.5 1.9-31.1 2.1-16.4.1-29.5-.2-31.5-.8-10.3-2.9-14.1-17.7-6.6-25.3zm61.4 94.5c-53.9 0-55.8.2-60.2 4.1-3.5 3.1-5.7 9.4-5.1 13.9.7 4.7 4.8 10.1 9.2 12 2.2 1 14.1 1.7 56.3 1.2l47.9-.6 9.2-1.5c9-5.1 10.5-17.4 3.1-24.4-5.3-4.7-5-4.7-60.4-4.7zm223.4 130.1c-3.5 28.4-23 50.4-51.1 57.5-7.2 1.8-9.7 1.9-172.9 1.8-157.8 0-165.9-.1-172-1.8-8.4-2.2-15.6-5.5-22.3-10-5.6-3.8-13.9-11.8-17-16.4-3.8-5.6-8.2-15.3-10-22C.1 423 0 420.3 0 256.3 0 93.2 0 89.7 1.8 82.6 8.1 57.9 27.7 39 53 33.4c7.3-1.6 332.1-1.9 340-.3 21.2 4.3 37.9 17.1 47.6 36.4 7.7 15.3 7-1.5 7.3 180.6.2 115.8 0 164.5-.7 170.5zm-85.4-185.2c-1.1-5-4.2-9.6-7.7-11.5-1.1-.6-8-1.3-15.5-1.7-12.4-.6-13.8-.8-17.8-3.1-6.2-3.6-7.9-7.6-8-18.3 0-20.4-8.5-39.4-25.3-56.5-12-12.2-25.3-20.5-40.6-25.1-3.6-1.1-11.8-1.5-39.2-1.8-42.9-.5-52.5.4-67.1 6.2-27 10.7-46.3 33.4-53.4 62.4-1.3 5.4-1.6 14.2-1.9 64.3-.4 62.8 0 72.1 4 84.5 9.7 30.7 37.1 53.4 64.6 58.4 9.2 1.7 122.2 2.1 133.7.5 20.1-2.7 35.9-10.8 50.7-25.9 10.7-10.9 17.4-22.8 21.8-38.5 3.2-10.9 2.9-88.4 1.7-93.9z"],"blogger-b":[448,512,[],"f37d","M446.6 222.7c-1.8-8-6.8-15.4-12.5-18.5-1.8-1-13-2.2-25-2.7-20.1-.9-22.3-1.3-28.7-5-10.1-5.9-12.8-12.3-12.9-29.5-.1-33-13.8-63.7-40.9-91.3-19.3-19.7-40.9-33-65.5-40.5-5.9-1.8-19.1-2.4-63.3-2.9-69.4-.8-84.8.6-108.4 10C45.9 59.5 14.7 96.1 3.3 142.9 1.2 151.7.7 165.8.2 246.8c-.6 101.5.1 116.4 6.4 136.5 15.6 49.6 59.9 86.3 104.4 94.3 14.8 2.7 197.3 3.3 216 .8 32.5-4.4 58-17.5 81.9-41.9 17.3-17.7 28.1-36.8 35.2-62.1 4.9-17.6 4.5-142.8 2.5-151.7zm-322.1-63.6c7.8-7.9 10-8.2 58.8-8.2 43.9 0 45.4.1 51.8 3.4 9.3 4.7 13.4 11.3 13.4 21.9 0 9.5-3.8 16.2-12.3 21.6-4.6 2.9-7.3 3.1-50.3 3.3-26.5.2-47.7-.4-50.8-1.2-16.6-4.7-22.8-28.5-10.6-40.8zm191.8 199.8l-14.9 2.4-77.5.9c-68.1.8-87.3-.4-90.9-2-7.1-3.1-13.8-11.7-14.9-19.4-1.1-7.3 2.6-17.3 8.2-22.4 7.1-6.4 10.2-6.6 97.3-6.7 89.6-.1 89.1-.1 97.6 7.8 12.1 11.3 9.5 31.2-4.9 39.4z"],bluetooth:[448,512,[],"f293","M292.6 171.1L249.7 214l-.3-86 43.2 43.1m-43.2 219.8l43.1-43.1-42.9-42.9-.2 86zM416 259.4C416 465 344.1 512 230.9 512S32 465 32 259.4 115.4 0 228.6 0 416 53.9 416 259.4zm-158.5 0l79.4-88.6L211.8 36.5v176.9L138 139.6l-27 26.9 92.7 93-92.7 93 26.9 26.9 73.8-73.8 2.3 170 127.4-127.5-83.9-88.7z"],"bluetooth-b":[320,512,[],"f294","M196.48 260.023l92.626-103.333L143.125 0v206.33l-86.111-86.111-31.406 31.405 108.061 108.399L25.608 368.422l31.406 31.405 86.111-86.111L145.84 512l148.552-148.644-97.912-103.333zm40.86-102.996l-49.977 49.978-.338-100.295 50.315 50.317zM187.363 313.04l49.977 49.978-50.315 50.316.338-100.294z"],btc:[384,512,[],"f15a","M310.204 242.638c27.73-14.18 45.377-39.39 41.28-81.3-5.358-57.351-52.458-76.573-114.85-81.929V0h-48.528v77.203c-12.605 0-25.525.315-38.444.63V0h-48.528v79.409c-17.842.539-38.622.276-97.37 0v51.678c38.314-.678 58.417-3.14 63.023 21.427v217.429c-2.925 19.492-18.524 16.685-53.255 16.071L3.765 443.68c88.481 0 97.37.315 97.37.315V512h48.528v-67.06c13.234.315 26.154.315 38.444.315V512h48.528v-68.005c81.299-4.412 135.647-24.894 142.895-101.467 5.671-61.446-23.32-88.862-69.326-99.89zM150.608 134.553c27.415 0 113.126-8.507 113.126 48.528 0 54.515-85.71 48.212-113.126 48.212v-96.74zm0 251.776V279.821c32.772 0 133.127-9.138 133.127 53.255-.001 60.186-100.355 53.253-133.127 53.253z"],buromobelexperte:[448,512,[],"f37f","M0 32v128h128V32H0zm120 120H8V40h112v112zm40-120v128h128V32H160zm120 120H168V40h112v112zm40-120v128h128V32H320zm120 120H328V40h112v112zM0 192v128h128V192H0zm120 120H8V200h112v112zm40-120v128h128V192H160zm120 120H168V200h112v112zm40-120v128h128V192H320zm120 120H328V200h112v112zM0 352v128h128V352H0zm120 120H8V360h112v112zm40-120v128h128V352H160zm120 120H168V360h112v112zm40-120v128h128V352H320z"],buysellads:[448,512,[],"f20d","M224 150.7l42.9 160.7h-85.8L224 150.7zM448 80v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V80c0-26.5 21.5-48 48-48h352c26.5 0 48 21.5 48 48zm-65.3 325.3l-94.5-298.7H159.8L65.3 405.3H156l111.7-91.6 24.2 91.6h90.8z"],"cc-amex":[576,512,[],"f1f3","M576 255.4c-37.9-.2-44.2-.9-54.5 5v-5c-45.3 0-53.5-1.7-64.9 5.2v-5.2h-78.2v5.1c-11.4-6.5-21.4-5.1-75.7-5.1v5.6c-6.3-3.7-14.5-5.6-24.3-5.6h-58c-3.5 3.8-12.5 13.7-15.7 17.2-12.7-14.1-10.5-11.6-15.5-17.2h-83.1v92.3h82c3.3-3.5 12.9-13.9 16.1-17.4 12.7 14.3 10.3 11.7 15.4 17.4h48.9c0-14.7.1-8.3.1-23 11.5.2 24.3-.2 34.3-6.2 0 13.9-.1 17.1-.1 29.2h39.6c0-18.5.1-7.4.1-25.3 6.2 0 7.7 0 9.4.1.1 1.3 0 0 0 25.2 152.8 0 145.9 1.1 156.7-4.5v4.5c34.8 0 54.8 2.2 67.5-6.1V432c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V228.3h26.6c4.2-10.1 2.2-5.3 6.4-15.3h19.2c4.2 10 2.2 5.2 6.4 15.3h52.9v-11.4c2.2 5 1.1 2.5 5.1 11.4h29.5c2.4-5.5 2.6-5.8 5.1-11.4v11.4h135.5v-25.1c6.4 0 8-.1 9.8.2 0 0-.2 10.9.1 24.8h66.5v-8.9c7.4 5.9 17.4 8.9 29.7 8.9h26.8c4.2-10.1 2.2-5.3 6.4-15.3h19c6.5 15 .2.5 6.6 15.3h52.8v-21.9c11.8 19.7 7.8 12.9 13.2 21.9h41.6v-92h-39.9v18.4c-12.2-20.2-6.3-10.4-11.2-18.4h-43.3v20.6c-6.2-14.6-4.6-10.8-8.8-20.6h-32.4c-.4 0-2.3.2-2.3-.3h-27.6c-12.8 0-23.1 3.2-30.7 9.3v-9.3h-39.9v5.3c-10.8-6.1-20.7-5.1-64.4-5.3-.1 0-11.6-.1-11.6 0h-103c-2.5 6.1-6.8 16.4-12.6 30-2.8-6-11-23.8-13.9-30h-46V157c-7.4-17.4-4.7-11-9-21.1H22.9c-3.4 7.9-13.7 32-23.1 53.9V80c0-26.5 21.5-48 48-48h480c26.5 0 48 21.5 48 48v175.4zm-186.6-80.6c-.3.2-1.4 2.2-1.4 7.6 0 6 .9 7.7 1.1 7.9.2.1 1.1.5 3.4.5l7.3-16.9c-1.1 0-2.1-.1-3.1-.1-5.6 0-7 .7-7.3 1zm-19.9 130.9c9.2 3.3 11 9.5 11 18.4l-.1 13.8h-16.6l.1-11.5c0-11.8-3.8-13.8-14.8-13.8h-17.6l-.1 25.3h-16.6l.1-69.3h39.4c13 0 27.1 2.3 27.1 18.7-.1 7.6-4.2 15.3-11.9 18.4zm-6.3-15.4c0-6.4-5.6-7.4-10.7-7.4h-21v15.6h20.7c5.6 0 11-1.3 11-8.2zm181.7-7.1H575v-14.6h-32.9c-12.8 0-23.8 6.6-23.8 20.7 0 33 42.7 12.8 42.7 27.4 0 5.1-4.3 6.4-8.4 6.4h-32l-.1 14.8h32c8.4 0 17.6-1.8 22.5-8.9v-25.8c-10.5-13.8-39.3-1.3-39.3-13.5 0-5.8 4.6-6.5 9.2-6.5zm-99.2-.3v-14.3h-55.2l-.1 69.3h55.2l.1-14.3-38.6-.3v-13.8H445v-14.1h-37.8v-12.5h38.5zm42.2 40.1h-32.2l-.1 14.8h32.2c14.8 0 26.2-5.6 26.2-22 0-33.2-42.9-11.2-42.9-26.3 0-5.6 4.9-6.4 9.2-6.4h30.4v-14.6h-33.2c-12.8 0-23.5 6.6-23.5 20.7 0 33 42.7 12.5 42.7 27.4-.1 5.4-4.7 6.4-8.8 6.4zm-78.1-158.7c-17.4-.3-33.2-4.1-33.2 19.7 0 11.8 2.8 19.9 16.1 19.9h7.4l23.5-54.5h24.8l27.9 65.4v-65.4h25.3l29.1 48.1v-48.1h16.9v69H524l-31.2-51.9v51.9h-33.7l-6.6-15.3h-34.3l-6.4 15.3h-19.2c-22.8 0-33-11.8-33-34 0-23.3 10.5-35.3 34-35.3h16.1v15.2zm14.3 24.5h22.8l-11.2-27.6-11.6 27.6zm-72.6-39.6h-16.9v69.3h16.9v-69.3zm-38.1 37.3c9.5 3.3 11 9.2 11 18.4v13.5h-16.6c-.3-14.8 3.6-25.1-14.8-25.1h-18v25.1h-16.4v-69.3l39.1.3c13.3 0 27.4 2 27.4 18.4.1 8-4.3 15.7-11.7 18.7zm-6.7-15.3c0-6.4-5.6-7.4-10.7-7.4h-21v15.3h20.7c5.7 0 11-1.3 11-7.9zm-59.5-7.4v-14.6h-55.5v69.3h55.5v-14.3h-38.9v-13.8h37.8v-14.1h-37.8v-12.5h38.9zm-84.6 54.7v-54.2l-24 54.2H124l-24-54.2v54.2H66.2l-6.4-15.3H25.3l-6.4 15.3H1l29.7-69.3h24.5l28.1 65.7v-65.7h27.1l21.7 47 19.7-47h27.6v69.3h-16.8zM53.9 188.8l-11.5-27.6-11.2 27.6h22.7zm253 102.5c0 27.9-30.4 23.3-49.3 23.3l-.1 23.3h-32.2l-20.4-23-21.3 23h-65.4l.1-69.3h66.5l20.5 22.8 21-22.8H279c15.6 0 27.9 5.4 27.9 22.7zm-112.7 11.8l-17.9-20.2h-41.7v12.5h36.3v14.1h-36.3v13.8h40.6l19-20.2zM241 276l-25.3 27.4 25.3 28.1V276zm48.3 15.3c0-6.1-4.6-8.4-10.2-8.4h-21.5v17.6h21.2c5.9 0 10.5-2.8 10.5-9.2z"],"cc-apple-pay":[576,512,[],"f416","M302.2 218.4c0 17.2-10.5 27.1-29 27.1h-24.3v-54.2h24.4c18.4 0 28.9 9.8 28.9 27.1zm47.5 62.6c0 8.3 7.2 13.7 18.5 13.7 14.4 0 25.2-9.1 25.2-21.9v-7.7l-23.5 1.5c-13.3.9-20.2 5.8-20.2 14.4zM576 79v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V79c0-26.5 21.5-48 48-48h480c26.5 0 48 21.5 48 48zM127.8 197.2c8.4.7 16.8-4.2 22.1-10.4 5.2-6.4 8.6-15 7.7-23.7-7.4.3-16.6 4.9-21.9 11.3-4.8 5.5-8.9 14.4-7.9 22.8zm60.6 74.5c-.2-.2-19.6-7.6-19.8-30-.2-18.7 15.3-27.7 16-28.2-8.8-13-22.4-14.4-27.1-14.7-12.2-.7-22.6 6.9-28.4 6.9-5.9 0-14.7-6.6-24.3-6.4-12.5.2-24.2 7.3-30.5 18.6-13.1 22.6-3.4 56 9.3 74.4 6.2 9.1 13.7 19.1 23.5 18.7 9.3-.4 13-6 24.2-6 11.3 0 14.5 6 24.3 5.9 10.2-.2 16.5-9.1 22.8-18.2 6.9-10.4 9.8-20.4 10-21zm135.4-53.4c0-26.6-18.5-44.8-44.9-44.8h-51.2v136.4h21.2v-46.6h29.3c26.8 0 45.6-18.4 45.6-45zm90 23.7c0-19.7-15.8-32.4-40-32.4-22.5 0-39.1 12.9-39.7 30.5h19.1c1.6-8.4 9.4-13.9 20-13.9 13 0 20.2 6 20.2 17.2v7.5l-26.4 1.6c-24.6 1.5-37.9 11.6-37.9 29.1 0 17.7 13.7 29.4 33.4 29.4 13.3 0 25.6-6.7 31.2-17.4h.4V310h19.6v-68zM516 210.9h-21.5l-24.9 80.6h-.4l-24.9-80.6H422l35.9 99.3-1.9 6c-3.2 10.2-8.5 14.2-17.9 14.2-1.7 0-4.9-.2-6.2-.3v16.4c1.2.4 6.5.5 8.1.5 20.7 0 30.4-7.9 38.9-31.8L516 210.9z"],"cc-diners-club":[576,512,[],"f24c","M239.7 79.9c-96.9 0-175.8 78.6-175.8 175.8 0 96.9 78.9 175.8 175.8 175.8 97.2 0 175.8-78.9 175.8-175.8 0-97.2-78.6-175.8-175.8-175.8zm-39.9 279.6c-41.7-15.9-71.4-56.4-71.4-103.8s29.7-87.9 71.4-104.1v207.9zm79.8.3V151.6c41.7 16.2 71.4 56.7 71.4 104.1s-29.7 87.9-71.4 104.1zM528 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h480c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48zM329.7 448h-90.3c-106.2 0-193.8-85.5-193.8-190.2C45.6 143.2 133.2 64 239.4 64h90.3c105 0 200.7 79.2 200.7 193.8 0 104.7-95.7 190.2-200.7 190.2z"],"cc-discover":[576,512,[],"f1f2","M83 212.1c0 7.9-3.2 15.5-8.9 20.7-4.9 4.4-11.6 6.4-21.9 6.4H48V185h4.2c10.3 0 16.7 1.7 21.9 6.6 5.7 5 8.9 12.6 8.9 20.5zM504.8 184h-4.9v24.9h4.7c10.3 0 15.8-4.4 15.8-12.8 0-7.9-5.5-12.1-15.6-12.1zM576 80v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V80c0-26.5 21.5-48 48-48h480c26.5 0 48 21.5 48 48zM428 253h45.3v-13.8H444V217h28.3v-13.8H444V185h29.3v-14H428v82zm-86.2-82l35 84.2h8.6l35.5-84.2h-17.5l-22.2 55.2-21.9-55.2h-17.5zm-83 41.6c0 24.6 19.9 44.6 44.6 44.6 24.6 0 44.6-19.9 44.6-44.6 0-24.6-19.9-44.6-44.6-44.6-24.6 0-44.6 19.9-44.6 44.6zm-68-.5c0 32.5 33.6 52.5 63.3 38.2v-19c-19.3 19.3-46.8 5.8-46.8-19.2 0-23.7 26.7-39.1 46.8-19v-19c-30.2-15-63.3 6.8-63.3 38zm-33.9 28.3c-7.6 0-13.8-3.7-17.5-10.8l-10.3 9.9c17.8 26.1 56.6 18.2 56.6-11.3 0-13.1-5.4-19-23.6-25.6-9.6-3.4-12.3-5.9-12.3-10.3 0-8.7 14.5-14.1 24.9-2.5l8.4-10.8c-19.1-17.1-49.7-8.9-49.7 14.3 0 11.3 5.2 17.2 20.2 22.7 25.7 9.1 14.7 24.4 3.3 24.4zm-57.4-28.3c0-24.1-18-41.1-44.1-41.1H32v82h23.4c30.9 0 44.1-22.4 44.1-40.9zm23.4-41.1h-16v82h16v-82zM544 288c-33.3 20.8-226.4 124.4-416 160h401c8.2 0 15-6.8 15-15V288zm0-35l-25.9-34.5c12.1-2.5 18.7-10.6 18.7-23.2 0-28.5-30.3-24.4-52.9-24.4v82h16v-32.8h2.2l22.2 32.8H544z"],"cc-jcb":[576,512,[],"f24b","M431.5 244.3V212c41.2 0 38.5.2 38.5.2 7.3 1.3 13.3 7.3 13.3 16 0 8.8-6 14.5-13.3 15.8-1.2.4-3.3.3-38.5.3zm42.8 20.2c-2.8-.7-3.3-.5-42.8-.5v35c39.6 0 40 .2 42.8-.5 7.5-1.5 13.5-8 13.5-17 0-8.7-6-15.5-13.5-17zM576 80v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V80c0-26.5 21.5-48 48-48h480c26.5 0 48 21.5 48 48zM182 192.3h-57c0 67.1 10.7 109.7-35.8 109.7-19.5 0-38.8-5.7-57.2-14.8v28c30 8.3 68 8.3 68 8.3 97.9 0 82-47.7 82-131.2zm178.5 4.5c-63.4-16-165-14.9-165 59.3 0 77.1 108.2 73.6 165 59.2V287C312.9 311.7 253 309 253 256s59.8-55.6 107.5-31.2v-28zM544 286.5c0-18.5-16.5-30.5-38-32v-.8c19.5-2.7 30.3-15.5 30.3-30.2 0-19-15.7-30-37-31 0 0 6.3-.3-120.3-.3v127.5h122.7c24.3.1 42.3-12.9 42.3-33.2z"],"cc-mastercard":[576,512,[],"f1f1","M482.9 410.3c0 6.8-4.6 11.7-11.2 11.7-6.8 0-11.2-5.2-11.2-11.7 0-6.5 4.4-11.7 11.2-11.7 6.6 0 11.2 5.2 11.2 11.7zm-310.8-11.7c-7.1 0-11.2 5.2-11.2 11.7 0 6.5 4.1 11.7 11.2 11.7 6.5 0 10.9-4.9 10.9-11.7-.1-6.5-4.4-11.7-10.9-11.7zm117.5-.3c-5.4 0-8.7 3.5-9.5 8.7h19.1c-.9-5.7-4.4-8.7-9.6-8.7zm107.8.3c-6.8 0-10.9 5.2-10.9 11.7 0 6.5 4.1 11.7 10.9 11.7 6.8 0 11.2-4.9 11.2-11.7 0-6.5-4.4-11.7-11.2-11.7zm105.9 26.1c0 .3.3.5.3 1.1 0 .3-.3.5-.3 1.1-.3.3-.3.5-.5.8-.3.3-.5.5-1.1.5-.3.3-.5.3-1.1.3-.3 0-.5 0-1.1-.3-.3 0-.5-.3-.8-.5-.3-.3-.5-.5-.5-.8-.3-.5-.3-.8-.3-1.1 0-.5 0-.8.3-1.1 0-.5.3-.8.5-1.1.3-.3.5-.3.8-.5.5-.3.8-.3 1.1-.3.5 0 .8 0 1.1.3.5.3.8.3 1.1.5s.2.6.5 1.1zm-2.2 1.4c.5 0 .5-.3.8-.3.3-.3.3-.5.3-.8 0-.3 0-.5-.3-.8-.3 0-.5-.3-1.1-.3h-1.6v3.5h.8V426h.3l1.1 1.4h.8l-1.1-1.3zM576 81v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V81c0-26.5 21.5-48 48-48h480c26.5 0 48 21.5 48 48zM64 220.6c0 76.5 62.1 138.5 138.5 138.5 27.2 0 53.9-8.2 76.5-23.1-72.9-59.3-72.4-171.2 0-230.5-22.6-15-49.3-23.1-76.5-23.1-76.4-.1-138.5 62-138.5 138.2zm224 108.8c70.5-55 70.2-162.2 0-217.5-70.2 55.3-70.5 162.6 0 217.5zm-142.3 76.3c0-8.7-5.7-14.4-14.7-14.7-4.6 0-9.5 1.4-12.8 6.5-2.4-4.1-6.5-6.5-12.2-6.5-3.8 0-7.6 1.4-10.6 5.4V392h-8.2v36.7h8.2c0-18.9-2.5-30.2 9-30.2 10.2 0 8.2 10.2 8.2 30.2h7.9c0-18.3-2.5-30.2 9-30.2 10.2 0 8.2 10 8.2 30.2h8.2v-23zm44.9-13.7h-7.9v4.4c-2.7-3.3-6.5-5.4-11.7-5.4-10.3 0-18.2 8.2-18.2 19.3 0 11.2 7.9 19.3 18.2 19.3 5.2 0 9-1.9 11.7-5.4v4.6h7.9V392zm40.5 25.6c0-15-22.9-8.2-22.9-15.2 0-5.7 11.9-4.8 18.5-1.1l3.3-6.5c-9.4-6.1-30.2-6-30.2 8.2 0 14.3 22.9 8.3 22.9 15 0 6.3-13.5 5.8-20.7.8l-3.5 6.3c11.2 7.6 32.6 6 32.6-7.5zm35.4 9.3l-2.2-6.8c-3.8 2.1-12.2 4.4-12.2-4.1v-16.6h13.1V392h-13.1v-11.2h-8.2V392h-7.6v7.3h7.6V416c0 17.6 17.3 14.4 22.6 10.9zm13.3-13.4h27.5c0-16.2-7.4-22.6-17.4-22.6-10.6 0-18.2 7.9-18.2 19.3 0 20.5 22.6 23.9 33.8 14.2l-3.8-6c-7.8 6.4-19.6 5.8-21.9-4.9zm59.1-21.5c-4.6-2-11.6-1.8-15.2 4.4V392h-8.2v36.7h8.2V408c0-11.6 9.5-10.1 12.8-8.4l2.4-7.6zm10.6 18.3c0-11.4 11.6-15.1 20.7-8.4l3.8-6.5c-11.6-9.1-32.7-4.1-32.7 15 0 19.8 22.4 23.8 32.7 15l-3.8-6.5c-9.2 6.5-20.7 2.6-20.7-8.6zm66.7-18.3H408v4.4c-8.3-11-29.9-4.8-29.9 13.9 0 19.2 22.4 24.7 29.9 13.9v4.6h8.2V392zm33.7 0c-2.4-1.2-11-2.9-15.2 4.4V392h-7.9v36.7h7.9V408c0-11 9-10.3 12.8-8.4l2.4-7.6zm40.3-14.9h-7.9v19.3c-8.2-10.9-29.9-5.1-29.9 13.9 0 19.4 22.5 24.6 29.9 13.9v4.6h7.9v-51.7zm7.6-75.1v4.6h.8V302h1.9v-.8h-4.6v.8h1.9zm6.6 123.8c0-.5 0-1.1-.3-1.6-.3-.3-.5-.8-.8-1.1-.3-.3-.8-.5-1.1-.8-.5 0-1.1-.3-1.6-.3-.3 0-.8.3-1.4.3-.5.3-.8.5-1.1.8-.5.3-.8.8-.8 1.1-.3.5-.3 1.1-.3 1.6 0 .3 0 .8.3 1.4 0 .3.3.8.8 1.1.3.3.5.5 1.1.8.5.3 1.1.3 1.4.3.5 0 1.1 0 1.6-.3.3-.3.8-.5 1.1-.8.3-.3.5-.8.8-1.1.3-.6.3-1.1.3-1.4zm3.2-124.7h-1.4l-1.6 3.5-1.6-3.5h-1.4v5.4h.8v-4.1l1.6 3.5h1.1l1.4-3.5v4.1h1.1v-5.4zm4.4-80.5c0-76.2-62.1-138.3-138.5-138.3-27.2 0-53.9 8.2-76.5 23.1 72.1 59.3 73.2 171.5 0 230.5 22.6 15 49.5 23.1 76.5 23.1 76.4.1 138.5-61.9 138.5-138.4z"],"cc-paypal":[576,512,[],"f1f4","M186.3 258.2c0 12.2-9.7 21.5-22 21.5-9.2 0-16-5.2-16-15 0-12.2 9.5-22 21.7-22 9.3 0 16.3 5.7 16.3 15.5zM80.5 209.7h-4.7c-1.5 0-3 1-3.2 2.7l-4.3 26.7 8.2-.3c11 0 19.5-1.5 21.5-14.2 2.3-13.4-6.2-14.9-17.5-14.9zm284 0H360c-1.8 0-3 1-3.2 2.7l-4.2 26.7 8-.3c13 0 22-3 22-18-.1-10.6-9.6-11.1-18.1-11.1zM576 80v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V80c0-26.5 21.5-48 48-48h480c26.5 0 48 21.5 48 48zM128.3 215.4c0-21-16.2-28-34.7-28h-40c-2.5 0-5 2-5.2 4.7L32 294.2c-.3 2 1.2 4 3.2 4h19c2.7 0 5.2-2.9 5.5-5.7l4.5-26.6c1-7.2 13.2-4.7 18-4.7 28.6 0 46.1-17 46.1-45.8zm84.2 8.8h-19c-3.8 0-4 5.5-4.2 8.2-5.8-8.5-14.2-10-23.7-10-24.5 0-43.2 21.5-43.2 45.2 0 19.5 12.2 32.2 31.7 32.2 9 0 20.2-4.9 26.5-11.9-.5 1.5-1 4.7-1 6.2 0 2.3 1 4 3.2 4H200c2.7 0 5-2.9 5.5-5.7l10.2-64.3c.3-1.9-1.2-3.9-3.2-3.9zm40.5 97.9l63.7-92.6c.5-.5.5-1 .5-1.7 0-1.7-1.5-3.5-3.2-3.5h-19.2c-1.7 0-3.5 1-4.5 2.5l-26.5 39-11-37.5c-.8-2.2-3-4-5.5-4h-18.7c-1.7 0-3.2 1.8-3.2 3.5 0 1.2 19.5 56.8 21.2 62.1-2.7 3.8-20.5 28.6-20.5 31.6 0 1.8 1.5 3.2 3.2 3.2h19.2c1.8-.1 3.5-1.1 4.5-2.6zm159.3-106.7c0-21-16.2-28-34.7-28h-39.7c-2.7 0-5.2 2-5.5 4.7l-16.2 102c-.2 2 1.3 4 3.2 4h20.5c2 0 3.5-1.5 4-3.2l4.5-29c1-7.2 13.2-4.7 18-4.7 28.4 0 45.9-17 45.9-45.8zm84.2 8.8h-19c-3.8 0-4 5.5-4.3 8.2-5.5-8.5-14-10-23.7-10-24.5 0-43.2 21.5-43.2 45.2 0 19.5 12.2 32.2 31.7 32.2 9.3 0 20.5-4.9 26.5-11.9-.3 1.5-1 4.7-1 6.2 0 2.3 1 4 3.2 4H484c2.7 0 5-2.9 5.5-5.7l10.2-64.3c.3-1.9-1.2-3.9-3.2-3.9zm47.5-33.3c0-2-1.5-3.5-3.2-3.5h-18.5c-1.5 0-3 1.2-3.2 2.7l-16.2 104-.3.5c0 1.8 1.5 3.5 3.5 3.5h16.5c2.5 0 5-2.9 5.2-5.7L544 191.2v-.3zm-90 51.8c-12.2 0-21.7 9.7-21.7 22 0 9.7 7 15 16.2 15 12 0 21.7-9.2 21.7-21.5.1-9.8-6.9-15.5-16.2-15.5z"],"cc-stripe":[576,512,[],"f1f5","M396.9 256.5c0 19.1-8.8 33.4-21.9 33.4-8.3 0-13.3-3-16.8-6.7l-.2-52.8c3.7-4.1 8.8-7 17-7 12.9-.1 21.9 14.5 21.9 33.1zM576 80v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V80c0-26.5 21.5-48 48-48h480c26.5 0 48 21.5 48 48zM122.2 281.1c0-42.3-54.3-34.7-54.3-50.7 0-5.5 4.6-7.7 12.1-7.7 10.8 0 24.5 3.3 35.3 9.1v-33.4c-11.8-4.7-23.5-6.5-35.3-6.5-28.8 0-48 15-48 40.2 0 39.3 54 32.9 54 49.9 0 6.6-5.7 8.7-13.6 8.7-11.8 0-26.9-4.9-38.9-11.3v33.9c13.2 5.7 26.6 8.1 38.8 8.1 29.6-.2 49.9-14.7 49.9-40.3zm68.9-86.9h-27v-30.8l-34.7 7.4-.2 113.9c0 21 15.8 36.5 36.9 36.5 11.6 0 20.2-2.1 24.9-4.7v-28.9c-4.5 1.8-27 8.3-27-12.6v-50.5h27v-30.3zm73.8 0c-4.7-1.7-21.3-4.8-29.6 10.5l-2.2-10.5h-30.7v124.5h35.5v-84.4c8.4-11 22.6-8.9 27.1-7.4v-32.7zm44.2 0h-35.7v124.5h35.7V194.2zm0-47.3l-35.7 7.6v28.9l35.7-7.6v-28.9zm122.7 108.8c0-41.3-23.5-63.8-48.4-63.8-13.9 0-22.9 6.6-27.8 11.1l-1.8-8.8h-31.3V360l35.5-7.5.1-40.2c5.1 3.7 12.7 9 25.1 9 25.4-.1 48.6-20.5 48.6-65.6zm112.2 1.2c0-36.4-17.6-65.1-51.3-65.1-33.8 0-54.3 28.7-54.3 64.9 0 42.8 24.2 64.5 58.8 64.5 17 0 29.7-3.9 39.4-9.2v-28.6c-9.7 4.9-20.8 7.9-34.9 7.9-13.8 0-26-4.9-27.6-21.5h69.5c.1-2 .4-9.4.4-12.9zm-51.6-36.1c-8.9 0-18.7 6.7-18.7 22.7h36.7c0-16-9.3-22.7-18-22.7z"],"cc-visa":[576,512,[],"f1f0","M470.1 231.3s7.6 37.2 9.3 45H446c3.3-8.9 16-43.5 16-43.5-.2.3 3.3-9.1 5.3-14.9l2.8 13.4zM576 80v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V80c0-26.5 21.5-48 48-48h480c26.5 0 48 21.5 48 48zM152.5 331.2L215.7 176h-42.5l-39.3 106-4.3-21.5-14-71.4c-2.3-9.9-9.4-12.7-18.2-13.1H32.7l-.7 3.1c15.8 4 29.9 9.8 42.2 17.1l35.8 135h42.5zm94.4.2L272.1 176h-40.2l-25.1 155.4h40.1zm139.9-50.8c.2-17.7-10.6-31.2-33.7-42.3-14.1-7.1-22.7-11.9-22.7-19.2.2-6.6 7.3-13.4 23.1-13.4 13.1-.3 22.7 2.8 29.9 5.9l3.6 1.7 5.5-33.6c-7.9-3.1-20.5-6.6-36-6.6-39.7 0-67.6 21.2-67.8 51.4-.3 22.3 20 34.7 35.2 42.2 15.5 7.6 20.8 12.6 20.8 19.3-.2 10.4-12.6 15.2-24.1 15.2-16 0-24.6-2.5-37.7-8.3l-5.3-2.5-5.6 34.9c9.4 4.3 26.8 8.1 44.8 8.3 42.2.1 69.7-20.8 70-53zM528 331.4L495.6 176h-31.1c-9.6 0-16.9 2.8-21 12.9l-59.7 142.5H426s6.9-19.2 8.4-23.3H486c1.2 5.5 4.8 23.3 4.8 23.3H528z"],centercode:[512,512,[],"f380","M329.2 268.6c-3.8 35.2-35.4 60.6-70.6 56.8-35.2-3.8-60.6-35.4-56.8-70.6 3.8-35.2 35.4-60.6 70.6-56.8 35.1 3.8 60.6 35.4 56.8 70.6zm-85.8 235.1C96.7 496-8.2 365.5 10.1 224.3c11.2-86.6 65.8-156.9 139.1-192 161-77.1 349.7 37.4 354.7 216.6 4.1 147-118.4 262.2-260.5 254.8zm179.9-180c27.9-118-160.5-205.9-237.2-234.2-57.5 56.3-69.1 188.6-33.8 344.4 68.8 15.8 169.1-26.4 271-110.2z"],chrome:[496,512,[],"f268","M131.5 217.5L55.1 100.1c47.6-59.2 119-91.8 192-92.1 42.3-.3 85.5 10.5 124.8 33.2 43.4 25.2 76.4 61.4 97.4 103L264 133.4c-58.1-3.4-113.4 29.3-132.5 84.1zm32.9 38.5c0 46.2 37.4 83.6 83.6 83.6s83.6-37.4 83.6-83.6-37.4-83.6-83.6-83.6-83.6 37.3-83.6 83.6zm314.9-89.2L339.6 174c37.9 44.3 38.5 108.2 6.6 157.2L234.1 503.6c46.5 2.5 94.4-7.7 137.8-32.9 107.4-62 150.9-192 107.4-303.9zM133.7 303.6L40.4 120.1C14.9 159.1 0 205.9 0 256c0 124 90.8 226.7 209.5 244.9l63.7-124.8c-57.6 10.8-113.2-20.8-139.5-72.5z"],cloudscale:[448,512,[],"f383","M318.1 154l-9.4 7.6c-22.5-19.3-51.5-33.6-83.3-33.6C153.8 128 96 188.8 96 260.3c0 6.6.4 13.1 1.4 19.4-2-56 41.8-97.4 92.6-97.4 24.2 0 46.2 9.4 62.6 24.7l-25.2 20.4c-8.3-.9-16.8 1.8-23.1 8.1-11.1 11-11.1 28.9 0 40 11.1 11 28.9 11 40 0 6.3-6.3 9-14.9 8.1-23.1l75.2-88.8c6.3-6.5-3.3-15.9-9.5-9.6zm-83.8 111.5c-5.6 5.5-14.6 5.5-20.2 0-5.6-5.6-5.6-14.6 0-20.2s14.6-5.6 20.2 0 5.6 14.7 0 20.2zM224 32C100.5 32 0 132.5 0 256s100.5 224 224 224 224-100.5 224-224S347.5 32 224 32zm0 384c-88.2 0-160-71.8-160-160S135.8 96 224 96s160 71.8 160 160-71.8 160-160 160z"],cloudsmith:[332,512,[],"f384","M332.5 419.9c0 46.4-37.6 84.1-84 84.1s-84-37.7-84-84.1 37.6-84 84-84 84 37.6 84 84zm-84-243.9c46.4 0 80-37.6 80-84s-33.6-84-80-84-88 37.6-88 84-29.6 76-76 76-84 41.6-84 88 37.6 80 84 80 84-33.6 84-80 33.6-80 80-80z"],cloudversify:[616,512,[],"f385","M148.6 304c8.2 68.5 67.4 115.5 146 111.3 51.2 43.3 136.8 45.8 186.4-5.6 69.2 1.1 118.5-44.6 131.5-99.5 14.8-62.5-18.2-132.5-92.1-155.1-33-88.1-131.4-101.5-186.5-85-57.3 17.3-84.3 53.2-99.3 109.7-7.8 2.7-26.5 8.9-45 24.1 11.7 0 15.2 8.9 15.2 19.5v20.4c0 10.7-8.7 19.5-19.5 19.5h-20.2c-10.7 0-19.5-6-19.5-16.7V240H98.8C95 240 88 244.3 88 251.9v40.4c0 6.4 5.3 11.8 11.7 11.8h48.9zm227.4 8c-10.7 46.3 21.7 72.4 55.3 86.8C324.1 432.6 259.7 348 296 288c-33.2 21.6-33.7 71.2-29.2 92.9-17.9-12.4-53.8-32.4-57.4-79.8-3-39.9 21.5-75.7 57-93.9C297 191.4 369.9 198.7 400 248c-14.1-48-53.8-70.1-101.8-74.8 30.9-30.7 64.4-50.3 114.2-43.7 69.8 9.3 133.2 82.8 67.7 150.5 35-16.3 48.7-54.4 47.5-76.9l10.5 19.6c11.8 22 15.2 47.6 9.4 72-9.2 39-40.6 68.8-79.7 76.5-32.1 6.3-83.1-5.1-91.8-59.2zM128 208H88.2c-8.9 0-16.2-7.3-16.2-16.2v-39.6c0-8.9 7.3-16.2 16.2-16.2H128c8.9 0 16.2 7.3 16.2 16.2v39.6c0 8.9-7.3 16.2-16.2 16.2zM10.1 168C4.5 168 0 163.5 0 157.9v-27.8c0-5.6 4.5-10.1 10.1-10.1h27.7c5.5 0 10.1 4.5 10.1 10.1v27.8c0 5.6-4.5 10.1-10.1 10.1H10.1zM168 142.7v-21.4c0-5.1 4.2-9.3 9.3-9.3h21.4c5.1 0 9.3 4.2 9.3 9.3v21.4c0 5.1-4.2 9.3-9.3 9.3h-21.4c-5.1 0-9.3-4.2-9.3-9.3zM56 235.5v25c0 6.3-5.1 11.5-11.4 11.5H19.4C13.1 272 8 266.8 8 260.5v-25c0-6.3 5.1-11.5 11.4-11.5h25.1c6.4 0 11.5 5.2 11.5 11.5z"],codepen:[512,512,[],"f1cb","M502.285 159.704l-234-156c-7.987-4.915-16.511-4.96-24.571 0l-234 156C3.714 163.703 0 170.847 0 177.989v155.999c0 7.143 3.714 14.286 9.715 18.286l234 156.022c7.987 4.915 16.511 4.96 24.571 0l234-156.022c6-3.999 9.715-11.143 9.715-18.286V177.989c-.001-7.142-3.715-14.286-9.716-18.285zM278 63.131l172.286 114.858-76.857 51.429L278 165.703V63.131zm-44 0v102.572l-95.429 63.715-76.857-51.429L234 63.131zM44 219.132l55.143 36.857L44 292.846v-73.714zm190 229.715L61.714 333.989l76.857-51.429L234 346.275v102.572zm22-140.858l-77.715-52 77.715-52 77.715 52-77.715 52zm22 140.858V346.275l95.429-63.715 76.857 51.429L278 448.847zm190-156.001l-55.143-36.857L468 219.132v73.714z"],codiepie:[472,512,[],"f284","M422.5 202.9c30.7 0 33.5 53.1-.3 53.1h-10.8v44.3h-26.6v-97.4h37.7zM472 352.6C429.9 444.5 350.4 504 248 504 111 504 0 393 0 256S111 8 248 8c97.4 0 172.8 53.7 218.2 138.4l-186 108.8L472 352.6zm-38.5 12.5l-60.3-30.7c-27.1 44.3-70.4 71.4-122.4 71.4-82.5 0-149.2-66.7-149.2-148.9 0-82.5 66.7-149.2 149.2-149.2 48.4 0 88.9 23.5 116.9 63.4l59.5-34.6c-40.7-62.6-104.7-100-179.2-100-121.2 0-219.5 98.3-219.5 219.5S126.8 475.5 248 475.5c78.6 0 146.5-42.1 185.5-110.4z"],connectdevelop:[576,512,[],"f20e","M550.5 241l-50.089-86.786c1.071-2.142 1.875-4.553 1.875-7.232 0-8.036-6.696-14.733-14.732-15.001l-55.447-95.893c.536-1.607 1.071-3.214 1.071-4.821 0-8.571-6.964-15.268-15.268-15.268-4.821 0-8.839 2.143-11.786 5.625H299.518C296.839 18.143 292.821 16 288 16s-8.839 2.143-11.518 5.625H170.411C167.464 18.143 163.447 16 158.625 16c-8.303 0-15.268 6.696-15.268 15.268 0 1.607.536 3.482 1.072 4.821l-55.983 97.233c-5.356 2.41-9.107 7.5-9.107 13.661 0 .535.268 1.071.268 1.607l-53.304 92.143c-7.232 1.339-12.59 7.5-12.59 15 0 7.232 5.089 13.393 12.054 15l55.179 95.358c-.536 1.607-.804 2.946-.804 4.821 0 7.232 5.089 13.393 12.054 14.732l51.697 89.732c-.536 1.607-1.071 3.482-1.071 5.357 0 8.571 6.964 15.268 15.268 15.268 4.821 0 8.839-2.143 11.518-5.357h106.875C279.161 493.857 283.447 496 288 496s8.839-2.143 11.518-5.357h107.143c2.678 2.946 6.696 4.821 10.982 4.821 8.571 0 15.268-6.964 15.268-15.268 0-1.607-.267-2.946-.803-4.285l51.697-90.268c6.964-1.339 12.054-7.5 12.054-14.732 0-1.607-.268-3.214-.804-4.821l54.911-95.358c6.964-1.339 12.322-7.5 12.322-15-.002-7.232-5.092-13.393-11.788-14.732zM153.535 450.732l-43.66-75.803h43.66v75.803zm0-83.839h-43.66c-.268-1.071-.804-2.142-1.339-3.214l44.999-47.41v50.624zm0-62.411l-50.357 53.304c-1.339-.536-2.679-1.34-4.018-1.607L43.447 259.75c.535-1.339.535-2.679.535-4.018s0-2.41-.268-3.482l51.965-90c2.679-.268 5.357-1.072 7.768-2.679l50.089 51.965v92.946zm0-102.322l-45.803-47.41c1.339-2.143 2.143-4.821 2.143-7.767 0-.268-.268-.804-.268-1.072l43.928-15.804v72.053zm0-80.625l-43.66 15.804 43.66-75.536v59.732zm326.519 39.108l.804 1.339L445.5 329.125l-63.75-67.232 98.036-101.518.268.268zM291.75 355.107l11.518 11.786H280.5l11.25-11.786zm-.268-11.25l-83.303-85.446 79.553-84.375 83.036 87.589-79.286 82.232zm5.357 5.893l79.286-82.232 67.5 71.25-5.892 28.125H313.714l-16.875-17.143zM410.411 44.393c1.071.536 2.142 1.072 3.482 1.34l57.857 100.714v.536c0 2.946.803 5.624 2.143 7.767L376.393 256l-83.035-87.589L410.411 44.393zm-9.107-2.143L287.732 162.518l-57.054-60.268 166.339-60h4.287zm-123.483 0c2.678 2.678 6.16 4.285 10.179 4.285s7.5-1.607 10.179-4.285h75L224.786 95.821 173.893 42.25h103.928zm-116.249 5.625l1.071-2.142a33.834 33.834 0 0 0 2.679-.804l51.161 53.84-54.911 19.821V47.875zm0 79.286l60.803-21.964 59.732 63.214-79.553 84.107-40.982-42.053v-83.304zm0 92.678L198 257.607l-36.428 38.304v-76.072zm0 87.858l42.053-44.464 82.768 85.982-17.143 17.678H161.572v-59.196zm6.964 162.053c-1.607-1.607-3.482-2.678-5.893-3.482l-1.071-1.607v-89.732h99.91l-91.607 94.821h-1.339zm129.911 0c-2.679-2.41-6.428-4.285-10.447-4.285s-7.767 1.875-10.447 4.285h-96.429l91.607-94.821h38.304l91.607 94.821H298.447zm120-11.786l-4.286 7.5c-1.339.268-2.41.803-3.482 1.339l-89.196-91.875h114.376l-17.412 83.036zm12.856-22.232l12.858-60.803h21.964l-34.822 60.803zm34.822-68.839h-20.357l4.553-21.16 17.143 18.214c-.535.803-1.071 1.874-1.339 2.946zm66.161-107.411l-55.447 96.697c-1.339.535-2.679 1.071-4.018 1.874l-20.625-21.964 34.554-163.928 45.803 79.286c-.267 1.339-.803 2.678-.803 4.285 0 1.339.268 2.411.536 3.75z"],contao:[512,512,[],"f26d","M45.4 305c14.4 67.1 26.4 129 68.2 175H34c-18.7 0-34-15.2-34-34V66c0-18.7 15.2-34 34-34h57.7C77.9 44.6 65.6 59.2 54.8 75.6c-45.4 70-27 146.8-9.4 229.4zM478 32h-90.2c21.4 21.4 39.2 49.5 52.7 84.1l-137.1 29.3c-14.9-29-37.8-53.3-82.6-43.9-24.6 5.3-41 19.3-48.3 34.6-8.8 18.7-13.2 39.8 8.2 140.3 21.1 100.2 33.7 117.7 49.5 131.2 12.9 11.1 33.4 17 58.3 11.7 44.5-9.4 55.7-40.7 57.4-73.2l137.4-29.6c3.2 71.5-18.7 125.2-57.4 163.6H478c18.7 0 34-15.2 34-34V66c0-18.8-15.2-34-34-34z"],cpanel:[640,512,[],"f388","M52.9 213.7h40l-6.2 23.6c-1.9 6.5-7.4 10.9-14.3 10.9H53.8c-24.9 0-24.7 37.4 0 37.4h11.3c4.2 0 7.6 3.9 6.4 8.3L64.4 320H52c-33.5 0-59-31.4-50.3-65.2 7.3-27 28.3-41.1 51.2-41.1M73.1 320L108 189.9c1.8-6.4 7.2-10.9 14.3-10.9h37c24.1 0 45.4 16.4 51 41.2 6.6 29.1-14.5 65.3-51.7 65.3h-32l6.4-23.8c1.8-6.2 7.3-10.8 14.3-10.8h10.3c12.4 0 20.8-11.7 18.3-22.6-2.1-9.2-9.9-14.8-18.3-14.8h-19.8L112 309.2c-1.9 6.2-7.4 10.7-14.2 10.7l-24.7.1m220.6-69.4c.3-1 1.9-5.3-2.1-5.3h-57.5c-9.7 0-16.6-8.9-14.2-18.5l3.5-13.4h77.9c18.8 0 33.3 17.6 28.5 36.8l-14 51.8c-2.8 10.6-12.2 17.8-23.4 17.8l-57.5-.2c-42.9 0-38.5-63.8.7-63.8H284l-3.5 13.2c-1.9 6.2-7.4 10.8-14.2 10.8h-21.6c-5.3 0-5.3 7.9 0 7.9h34.9c4.6 0 5.1-3.9 5.5-5.3l8.6-31.8m103.1-36.9c34.4 0 59.3 32.3 50.3 65.4l-8.8 33.1c-1.2 4.9-5.7 7.8-10.3 7.8h-19.1c-4.5 0-7.6-4-6.4-8.3l10.6-40c3.3-11.6-5.6-23.4-18.1-23.4h-19.8l-17.2 64c-1.2 4.8-5.6 7.8-10.4 7.8h-18.9c-4.2 0-7.6-3.9-6.4-8.3l26.2-98h48.3M498 251.6l-8 30c-.9 3.3 1.5 6.7 5.1 6.7h73.3l-5.7 21c-1.9 6.2-7.4 10.7-14.2 10.7h-66.7c-20 0-33.3-19-28.3-36.7l10.8-40c4.8-17.6 20.7-29.6 38.6-29.6h47.3c19 0 33.2 17.7 28.3 36.8l-3.2 12c-2.9 11-12.7 17.6-23.2 17.6h-53.4l3.5-13c1.6-6.2 7.2-10.8 14.2-10.8H538c2 0 3.3-1 3.9-3l.7-2.6c.7-2.7-1.3-5.1-3.9-5.1h-32.9c-4.1 0-6.9 2.1-7.8 6zm70.2 68.4l35.6-133.1c1.2-4.7 5.5-7.9 10.4-7.9h18.9c4.5 0 7.7 4 6.5 8.3l-26.5 98.2c-5.1 20.7-24.2 34.5-44.9 34.5"],"creative-commons":[512,512,[],"f25e","M255.547 8C392.884 8 504 114.439 504 256.004 504 405.979 381.106 504 255.562 504 122.319 504 8 394.557 8 256.004 8 124.825 113.486 8 255.547 8zm.899 44.734c-120.341 0-203.727 100.568-203.727 203.278 0 106.515 88.984 202.394 203.727 202.394 101.528 0 202.821-79.442 202.821-202.387-.001-114.773-91.773-203.285-202.821-203.285zm-3.108 162.093l-33.225 17.275c-5.395-11.203-15.25-19.926-27.459-19.926-22.134 0-33.217 14.609-33.217 43.842 0 23.842 9.446 43.842 33.217 43.842 14.469 0 24.653-7.091 30.566-21.259l30.551 15.5c-12.813 23.899-36.887 38.975-65.101 38.975-43.162 0-73.959-27.272-73.959-77.052 0-49.541 32.706-77.059 72.634-77.059 30.714-.013 52.701 11.946 65.993 35.862zm143.044 0l-32.775 17.275c-5.517-11.482-15.324-19.926-27.9-19.926-22.142 0-33.225 14.609-33.225 43.842 0 23.906 9.502 43.842 33.225 43.842 14.454 0 24.645-7.091 30.543-21.259l31 15.5c-13.363 23.869-37.451 38.975-65.086 38.975-43.439 0-73.959-26.988-73.959-77.052 0-49.523 32.698-77.059 72.626-77.059 30.706-.013 52.569 11.946 65.551 35.862z"],css3:[512,512,[],"f13c","M480 32l-64 368-223.3 80L0 400l19.6-94.8h82l-8 40.6L210 390.2l134.1-44.4 18.8-97.1H29.5l16-82h333.7l10.5-52.7H56.3l16.3-82H480z"],"css3-alt":[384,512,[],"f38b","M0 32l34.9 395.8L192 480l157.1-52.2L384 32H0zm313.1 80l-4.8 47.3L193 208.6l-.3.1h111.5l-12.8 146.6-98.2 28.7-98.8-29.2-6.4-73.9h48.9l3.2 38.3 52.6 13.3 54.7-15.4 3.7-61.6-166.3-.5v-.1l-.2.1-3.6-46.3L193.1 162l6.5-2.7H76.7L70.9 112h242.2z"],cuttlefish:[440,512,[],"f38c","M344 305.5c-17.5 31.6-57.4 54.5-96 54.5-56.6 0-104-47.4-104-104s47.4-104 104-104c38.6 0 78.5 22.9 96 54.5 13.7-50.9 41.7-93.3 87-117.8C385.7 39.1 320.5 8 248 8 111 8 0 119 0 256s111 248 248 248c72.5 0 137.7-31.1 183-80.7-45.3-24.5-73.3-66.9-87-117.8z"],"d-and-d":[576,512,[],"f38d","M82.5 98.9c-.6-17.2 2-33.8 12.7-48.2.3 7.4 1.2 14.5 4.2 21.6 5.9-27.5 19.7-49.3 42.3-65.5-1.9 5.9-3.5 11.8-3 17.7 8.7-7.4 18.8-17.8 44.4-22.7 14.7-2.8 29.7-2 42.1 1 38.5 9.3 61 34.3 69.7 72.3 5.3 23.1.7 45-8.3 66.4-5.2 12.4-12 24.4-20.7 35.1-2-1.9-3.9-3.8-5.8-5.6-42.8-40.8-26.8-25.2-37.4-37.4-1.1-1.2-1-2.2-.1-3.6 8.3-13.5 11.8-28.2 10-44-1.1-9.8-4.3-18.9-11.3-26.2-14.5-15.3-39.2-15-53.5.6-11.4 12.5-14.1 27.4-10.9 43.6.2 1.3.4 2.7 0 3.9-3.4 13.7-4.6 27.6-2.5 41.6.1.5.1 1.1.1 1.6 0 .3-.1.5-.2 1.1-21.8-11-36-28.3-43.2-52.2-8.3 17.8-11.1 35.5-6.6 54.1-15.6-15.2-21.3-34.3-22-55.2zm469.6 123.2c-11.6-11.6-25-20.4-40.1-26.6-12.8-5.2-26-7.9-39.9-7.1-10 .6-19.6 3.1-29 6.4-2.5.9-5.1 1.6-7.7 2.2-4.9 1.2-7.3-3.1-4.7-6.8 3.2-4.6 3.4-4.2 15-12 .6-.4 1.2-.8 2.2-1.5h-2.5c-.6 0-1.2.2-1.9.3-19.3 3.3-30.7 15.5-48.9 29.6-10.4 8.1-13.8 3.8-12-.5 1.4-3.5 3.3-6.7 5.1-10 1-1.8 2.3-3.4 3.5-5.1-.2-.2-.5-.3-.7-.5-27 18.3-46.7 42.4-57.7 73.3.3.3.7.6 1 .9.3-.6.5-1.2.9-1.7 10.4-12.1 22.8-21.8 36.6-29.8 18.2-10.6 37.5-18.3 58.7-20.2 4.3-.4 8.7-.1 13.1-.1-1.8.7-3.5.9-5.3 1.1-18.5 2.4-35.5 9-51.5 18.5-30.2 17.9-54.5 42.2-75.1 70.4-.3.4-.4.9-.7 1.3 14.5 5.3 24 17.3 36.1 25.6.2-.1.3-.2.4-.4l1.2-2.7c12.2-26.9 27-52.3 46.7-74.5 16.7-18.8 38-25.3 62.5-20 5.9 1.3 11.4 4.4 17.2 6.8 2.3-1.4 5.1-3.2 8-4.7 8.4-4.3 17.4-7 26.7-9 14.7-3.1 29.5-4.9 44.5-1.3v-.5c-.5-.4-1.2-.8-1.7-1.4zM316.7 397.6c-39.4-33-22.8-19.5-42.7-35.6-.8.9 0-.2-1.9 3-11.2 19.1-25.5 35.3-44 47.6-10.3 6.8-21.5 11.8-34.1 11.8-21.6 0-38.2-9.5-49.4-27.8-12-19.5-13.3-40.7-8.2-62.6 7.8-33.8 30.1-55.2 38.6-64.3-18.7-6.2-33 1.7-46.4 13.9.8-13.9 4.3-26.2 11.8-37.3-24.3 10.6-45.9 25-64.8 43.9-.3-5.8 5.4-43.7 5.6-44.7.3-2.7-.6-5.3-3-7.4-24.2 24.7-44.5 51.8-56.1 84.6 7.4-5.9 14.9-11.4 23.6-16.2-8.3 22.3-19.6 52.8-7.8 101.1 4.6 19 11.9 36.8 24.1 52.3 2.9 3.7 6.3 6.9 9.5 10.3.2-.2.4-.3.6-.5-1.4-7-2.2-14.1-1.5-21.9 2.2 3.2 3.9 6 5.9 8.6 12.6 16 28.7 27.4 47.2 35.6 25 11.3 51.1 13.3 77.9 8.6 54.9-9.7 90.7-48.6 116-98.8 1-1.8.6-2.9-.9-4.2zm172-46.4c-9.5-3.1-22.2-4.2-28.7-2.9 9.9 4 14.1 6.6 18.8 12 12.6 14.4 10.4 34.7-5.4 45.6-11.7 8.1-24.9 10.5-38.9 9.1-1.2-.1-2.3-.4-3-.6 2.8-3.7 6-7 8.1-10.8 9.4-16.8 5.4-42.1-8.7-56.1-2.1-2.1-4.6-3.9-7-5.9-.3 1.3-.1 2.1.1 2.8 4.2 16.6-8.1 32.4-24.8 31.8-7.6-.3-13.9-3.8-19.6-8.5-19.5-16.1-39.1-32.1-58.5-48.3-5.9-4.9-12.5-8.1-20.1-8.7-4.6-.4-9.3-.6-13.9-.9-5.9-.4-8.8-2.8-10.4-8.4-.9-3.4-1.5-6.8-2.2-10.2-1.5-8.1-6.2-13-14.3-14.2-4.4-.7-8.9-1-13.3-1.5-13-1.4-19.8-7.4-22.6-20.3-5 11-1.6 22.4 7.3 29.9 4.5 3.8 9.3 7.3 13.8 11.2 4.6 3.8 7.4 8.7 7.9 14.8.4 4.7.8 9.5 1.8 14.1 2.2 10.6 8.9 18.4 17 25.1 16.5 13.7 33 27.3 49.5 41.1 17.9 15 13.9 32.8 13 56-.9 22.9 12.2 42.9 33.5 51.2 1 .4 2 .6 3.6 1.1-15.7-18.2-10.1-44.1.7-52.3.3 2.2.4 4.3.9 6.4 9.4 44.1 45.4 64.2 85 56.9 16-2.9 30.6-8.9 42.9-19.8 2-1.8 3.7-4.1 5.9-6.5-19.3 4.6-35.8.1-50.9-10.6.7-.3 1.3-.3 1.9-.3 21.3 1.8 40.6-3.4 57-17.4 19.5-16.6 26.6-42.9 17.4-66-8.3-20.1-23.6-32.3-43.8-38.9zM99.4 179.3c-5.3-9.2-13.2-15.6-22.1-21.3 13.7-.5 26.6.2 39.6 3.7-7-12.2-8.5-24.7-5-38.7 5.3 11.9 13.7 20.1 23.6 26.8 19.7 13.2 35.7 19.6 46.7 30.2 3.4 3.3 6.3 7.1 9.6 10.9-.8-2.1-1.4-4.1-2.2-6-5-10.6-13-18.6-22.6-25-1.8-1.2-2.8-2.5-3.4-4.5-3.3-12.5-3-25.1-.7-37.6 1-5.5 2.8-10.9 4.5-16.3.8-2.4 2.3-4.6 4-6.6.6 6.9 0 25.5 19.6 46 10.8 11.3 22.4 21.9 33.9 32.7 9 8.5 18.3 16.7 25.5 26.8 1.1 1.6 2.2 3.3 3.8 4.7-5-13-14.2-24.1-24.2-33.8-9.6-9.3-19.4-18.4-29.2-27.4-3.3-3-4.6-6.7-5.1-10.9-1.2-10.4 0-20.6 4.3-30.2.5-1 1.1-2 1.9-3.3.5 4.2.6 7.9 1.4 11.6 4.8 23.1 20.4 36.3 49.3 63.5 10 9.4 19.3 19.2 25.6 31.6 4.8 9.3 7.3 19 5.7 29.6-.1.6.5 1.7 1.1 2 6.2 2.6 10 6.9 9.7 14.3 7.7-2.6 12.5-8 16.4-14.5 4.2 20.2-9.1 50.3-27.2 58.7.4-4.5 5-23.4-16.5-27.7-6.8-1.3-12.8-1.3-22.9-2.1 4.7-9 10.4-20.6.5-22.4-24.9-4.6-52.8 1.9-57.8 4.6 8.2.4 16.3 1 23.5 3.3-2 6.5-4 12.7-5.8 18.9-1.9 6.5 2.1 14.6 9.3 9.6 1.2-.9 2.3-1.9 3.3-2.7-3.1 17.9-2.9 15.9-2.8 18.3.3 10.2 9.5 7.8 15.7 7.3-2.5 11.8-29.5 27.3-45.4 25.8 7-4.7 12.7-10.3 15.9-17.9-6.5.8-12.9 1.6-19.2 2.4l-.3-.9c4.7-3.4 8-7.8 10.2-13.1 8.7-21.1-3.6-38-25-39.9-9.1-.8-17.8.8-25.9 5.5 6.2-15.6 17.2-26.6 32.6-34.5-15.2-4.3-8.9-2.7-24.6-6.3 14.6-9.3 30.2-13.2 46.5-14.6-5.2-3.2-48.1-3.6-70.2 20.9 7.9 1.4 15.5 2.8 23.2 4.2-23.8 7-44 19.7-62.4 35.6 1.1-4.8 2.7-9.5 3.3-14.3.6-4.5.8-9.2.1-13.6-1.5-9.4-8.9-15.1-19.7-16.3-7.9-.9-15.6.1-23.3 1.3-.9.1-1.7.3-2.9 0 15.8-14.8 36-21.7 53.1-33.5 6-4.5 6.8-8.2 3-14.9zm128.4 26.8c3.3 16 12.6 25.5 23.8 24.3-4.6-11.3-12.1-19.5-23.8-24.3z"],dashcube:[384,512,[],"f210","M288.1 97.5H85.5C37.6 97.5 0 138.1 0 185.2v215.1C0 447.7 37.6 480 85.5 480h213c47.9 0 85.5-32.3 85.5-79.7V0l-95.9 97.5zm-161.9 293c-16.6 0-30.4-14.2-30.4-30.8v-134c0-16.6 13.8-30.5 30.4-30.5h131.9c16.6 0 30 13.9 30 30.5v115.7l47.9 49H126.2z"],delicious:[448,512,[],"f1a5","M446.5 68c-.4-1.5-.9-3-1.4-4.5-.9-2.5-2-4.8-3.3-7.1-1.4-2.4-3-4.8-4.7-6.9-2.1-2.5-4.4-4.8-6.9-6.8-1.1-.9-2.2-1.7-3.3-2.5-1.3-.9-2.6-1.7-4-2.4-1.8-1-3.6-1.8-5.5-2.5-1.7-.7-3.5-1.3-5.4-1.7-3.8-1-7.9-1.5-12-1.5H48C21.5 32 0 53.5 0 80v352c0 4.1.5 8.2 1.5 12 2 7.7 5.8 14.6 11 20.3 1 1.1 2.1 2.2 3.3 3.3 5.7 5.2 12.6 9 20.3 11 3.8 1 7.9 1.5 12 1.5h352c26.5 0 48-21.5 48-48V80c-.1-4.1-.6-8.2-1.6-12zM416 432c0 8.8-7.2 16-16 16H224V256H32V80c0-8.8 7.2-16 16-16h176v192h192v176z"],deploydog:[512,512,[],"f38e","M382.2 136h51.7v239.6h-51.7v-20.7c-19.8 24.8-52.8 24.1-73.8 14.7-26.2-11.7-44.3-38.1-44.3-71.8 0-29.8 14.8-57.9 43.3-70.8 20.2-9.1 52.7-10.6 74.8 12.9V136zm-64.7 161.8c0 18.2 13.6 33.5 33.2 33.5 19.8 0 33.2-16.4 33.2-32.9 0-17.1-13.7-33.2-33.2-33.2-19.6 0-33.2 16.4-33.2 32.6zM188.5 136h51.7v239.6h-51.7v-20.7c-19.8 24.8-52.8 24.1-73.8 14.7-26.2-11.7-44.3-38.1-44.3-71.8 0-29.8 14.8-57.9 43.3-70.8 20.2-9.1 52.7-10.6 74.8 12.9V136zm-64.7 161.8c0 18.2 13.6 33.5 33.2 33.5 19.8 0 33.2-16.4 33.2-32.9 0-17.1-13.7-33.2-33.2-33.2-19.7 0-33.2 16.4-33.2 32.6zM448 96c17.5 0 32 14.4 32 32v256c0 17.5-14.4 32-32 32H64c-17.5 0-32-14.4-32-32V128c0-17.5 14.4-32 32-32h384m0-32H64C28.8 64 0 92.8 0 128v256c0 35.2 28.8 64 64 64h384c35.2 0 64-28.8 64-64V128c0-35.2-28.8-64-64-64z"],deskpro:[480,512,[],"f38f","M205.9 512l31.1-38.4c12.3-.2 25.6-1.4 36.5-6.6 38.9-18.6 38.4-61.9 38.3-63.8-.1-5-.8-4.4-28.9-37.4H362c-.2 50.1-7.3 68.5-10.2 75.7-9.4 23.7-43.9 62.8-95.2 69.4-8.7 1.1-32.8 1.2-50.7 1.1zm200.4-167.7c38.6 0 58.5-13.6 73.7-30.9l-175.5-.3-17.4 31.3 119.2-.1zm-43.6-223.9v168.3h-73.5l-32.7 55.5H250c-52.3 0-58.1-56.5-58.3-58.9-1.2-13.2-21.3-11.6-20.1 1.8 1.4 15.8 8.8 40 26.4 57.1h-91c-25.5 0-110.8-26.8-107-114V16.9C0 .9 9.7.3 15 .1h82c.2 0 .3.1.5.1 4.3-.4 50.1-2.1 50.1 43.7 0 13.3 20.2 13.4 20.2 0 0-18.2-5.5-32.8-15.8-43.7h84.2c108.7-.4 126.5 79.4 126.5 120.2zm-132.5 56l64 29.3c13.3-45.5-42.2-71.7-64-29.3z"],deviantart:[320,512,[],"f1bd","M320 93.2l-98.2 179.1 7.4 9.5H320v127.7H159.1l-13.5 9.2-43.7 84c-.3 0-8.6 8.6-9.2 9.2H0v-93.2l93.2-179.4-7.4-9.2H0V102.5h156l13.5-9.2 43.7-84c.3 0 8.6-8.6 9.2-9.2H320v93.1z"],digg:[512,512,[],"f1a6","M81.7 172.3H0v174.4h132.7V96h-51v76.3zm0 133.4H50.9v-92.3h30.8v92.3zm297.2-133.4v174.4h81.8v28.5h-81.8V416H512V172.3H378.9zm81.8 133.4h-30.8v-92.3h30.8v92.3zm-235.6 41h82.1v28.5h-82.1V416h133.3V172.3H225.1v174.4zm51.2-133.3h30.8v92.3h-30.8v-92.3zM153.3 96h51.3v51h-51.3V96zm0 76.3h51.3v174.4h-51.3V172.3z"],"digital-ocean":[512,512,[],"f391","M256 504v-96.1c101.8 0 180.8-100.9 141.7-208-14.3-39.6-46.1-71.4-85.8-85.7-107.1-38.8-208.1 39.9-208.1 141.7H8C8 93.7 164.9-32.8 335 20.3c74.2 23.3 133.6 82.4 156.6 156.6C544.8 347.2 418.6 504 256 504zm.3-191.4h-95.6v95.6h95.6v-95.6zm-95.6 95.6H87v73.6h73.7v-73.6zM87 346.6H25.4v61.6H87v-61.6z"],discord:[448,512,[],"f392","M297.216 243.2c0 15.616-11.52 28.416-26.112 28.416-14.336 0-26.112-12.8-26.112-28.416s11.52-28.416 26.112-28.416c14.592 0 26.112 12.8 26.112 28.416zm-119.552-28.416c-14.592 0-26.112 12.8-26.112 28.416s11.776 28.416 26.112 28.416c14.592 0 26.112-12.8 26.112-28.416.256-15.616-11.52-28.416-26.112-28.416zM448 52.736V512c-64.494-56.994-43.868-38.128-118.784-107.776l13.568 47.36H52.48C23.552 451.584 0 428.032 0 398.848V52.736C0 23.552 23.552 0 52.48 0h343.04C424.448 0 448 23.552 448 52.736zm-72.96 242.688c0-82.432-36.864-149.248-36.864-149.248-36.864-27.648-71.936-26.88-71.936-26.88l-3.584 4.096c43.52 13.312 63.744 32.512 63.744 32.512-60.811-33.329-132.244-33.335-191.232-7.424-9.472 4.352-15.104 7.424-15.104 7.424s21.248-20.224 67.328-33.536l-2.56-3.072s-35.072-.768-71.936 26.88c0 0-36.864 66.816-36.864 149.248 0 0 21.504 37.12 78.08 38.912 0 0 9.472-11.52 17.152-21.248-32.512-9.728-44.8-30.208-44.8-30.208 3.766 2.636 9.976 6.053 10.496 6.4 43.21 24.198 104.588 32.126 159.744 8.96 8.96-3.328 18.944-8.192 29.44-15.104 0 0-12.8 20.992-46.336 30.464 7.68 9.728 16.896 20.736 16.896 20.736 56.576-1.792 78.336-38.912 78.336-38.912z"],discourse:[448,512,[],"f393","M225.9 32C103.3 32 0 130.5 0 252.1 0 256 .1 480 .1 480l225.8-.2c122.7 0 222.1-102.3 222.1-223.9C448 134.3 348.6 32 225.9 32zM224 384c-19.4 0-37.9-4.3-54.4-12.1L88.5 392l22.9-75c-9.8-18.1-15.4-38.9-15.4-61 0-70.7 57.3-128 128-128s128 57.3 128 128-57.3 128-128 128z"],dochub:[416,512,[],"f394","M397.9 160H256V19.6L397.9 160zM304 192v130c0 66.8-36.5 100.1-113.3 100.1H96V84.8h94.7c12 0 23.1.8 33.1 2.5v-84C212.9 1.1 201.4 0 189.2 0H0v512h189.2C329.7 512 400 447.4 400 318.1V192h-96z"],docker:[640,512,[],"f395","M349.9 236.3h-66.1v-59.4h66.1v59.4zm0-204.3h-66.1v60.7h66.1V32zm78.2 144.8H362v59.4h66.1v-59.4zm-156.3-72.1h-66.1v60.1h66.1v-60.1zm78.1 0h-66.1v60.1h66.1v-60.1zm276.8 100c-14.4-9.7-47.6-13.2-73.1-8.4-3.3-24-16.7-44.9-41.1-63.7l-14-9.3-9.3 14c-18.4 27.8-23.4 73.6-3.7 103.8-8.7 4.7-25.8 11.1-48.4 10.7H2.4c-8.7 50.8 5.8 116.8 44 162.1 37.1 43.9 92.7 66.2 165.4 66.2 157.4 0 273.9-72.5 328.4-204.2 21.4.4 67.6.1 91.3-45.2 1.5-2.5 6.6-13.2 8.5-17.1l-13.3-8.9zm-511.1-27.9h-66v59.4h66.1v-59.4zm78.1 0h-66.1v59.4h66.1v-59.4zm78.1 0h-66.1v59.4h66.1v-59.4zm-78.1-72.1h-66.1v60.1h66.1v-60.1z"],draft2digital:[480,512,[],"f396","M369.9 425.4V371l47.1 27.2-47.1 27.2zM82.4 380.6c25.5-27.3 97.7-104.7 150.9-170 35.1-43.1 40.3-82.4 28.4-112.7-7.4-18.8-17.5-30.2-24.3-35.7 45.3 2.1 68 23.4 82.2 38.3 0 0 42.4 48.2 5.8 113.3-37 65.9-110.9 147.5-128.5 166.7H82.4zm51.8-219.2c0 12.4-10 22.4-22.4 22.4-12.4 0-22.4-10-22.4-22.4 0-12.4 10-22.4 22.4-22.4 12.4 0 22.4 10.1 22.4 22.4M336 315.9v64.7h-91.3c30.8-35 81.8-95.9 111.8-149.3 35.2-62.6 16.1-123.4-12.8-153.3-4.4-4.6-62.2-62.9-166-41.2-59.1 12.4-89.4 43.4-104.3 67.3-13.1 20.9-17 39.8-18.2 47.7-5.5 33 19.4 67.1 56.7 67.1 31.7 0 57.3-25.7 57.3-57.4 0-27.1-19.7-52.1-48-56.8 1.8-7.3 17.7-21.1 26.3-24.7 41.1-17.3 78 5.2 83.3 33.5 8.3 44.3-37.1 90.4-69.7 127.6C84.5 328.1 18.3 396.8 0 415.9l336-.1V480l144-81.9-144-82.2z"],dribbble:[512,512,[],"f17d","M256 8C119.252 8 8 119.252 8 256s111.252 248 248 248 248-111.252 248-248S392.748 8 256 8zm163.97 114.366c29.503 36.046 47.369 81.957 47.835 131.955-6.984-1.477-77.018-15.682-147.502-6.818-5.752-14.041-11.181-26.393-18.617-41.614 78.321-31.977 113.818-77.482 118.284-83.523zM396.421 97.87c-3.81 5.427-35.697 48.286-111.021 76.519-34.712-63.776-73.185-116.168-79.04-124.008 67.176-16.193 137.966 1.27 190.061 47.489zm-230.48-33.25c5.585 7.659 43.438 60.116 78.537 122.509-99.087 26.313-186.36 25.934-195.834 25.809C62.38 147.205 106.678 92.573 165.941 64.62zM44.17 256.323c0-2.166.043-4.322.108-6.473 9.268.19 111.92 1.513 217.706-30.146 6.064 11.868 11.857 23.915 17.174 35.949-76.599 21.575-146.194 83.527-180.531 142.306C64.794 360.405 44.17 310.73 44.17 256.323zm81.807 167.113c22.127-45.233 82.178-103.622 167.579-132.756 29.74 77.283 42.039 142.053 45.189 160.638-68.112 29.013-150.015 21.053-212.768-27.882zm248.38 8.489c-2.171-12.886-13.446-74.897-41.152-151.033 66.38-10.626 124.7 6.768 131.947 9.055-9.442 58.941-43.273 109.844-90.795 141.978z"],"dribbble-square":[448,512,[],"f397","M90.2 228.2c8.9-42.4 37.4-77.7 75.7-95.7 3.6 4.9 28 38.8 50.7 79-64 17-120.3 16.8-126.4 16.7zM314.6 154c-33.6-29.8-79.3-41.1-122.6-30.6 3.8 5.1 28.6 38.9 51 80 48.6-18.3 69.1-45.9 71.6-49.4zM140.1 364c40.5 31.6 93.3 36.7 137.3 18-2-12-10-53.8-29.2-103.6-55.1 18.8-93.8 56.4-108.1 85.6zm98.8-108.2c-3.4-7.8-7.2-15.5-11.1-23.2C159.6 253 93.4 252.2 87.4 252c0 1.4-.1 2.8-.1 4.2 0 35.1 13.3 67.1 35.1 91.4 22.2-37.9 67.1-77.9 116.5-91.8zm34.9 16.3c17.9 49.1 25.1 89.1 26.5 97.4 30.7-20.7 52.5-53.6 58.6-91.6-4.6-1.5-42.3-12.7-85.1-5.8zm-20.3-48.4c4.8 9.8 8.3 17.8 12 26.8 45.5-5.7 90.7 3.4 95.2 4.4-.3-32.3-11.8-61.9-30.9-85.1-2.9 3.9-25.8 33.2-76.3 53.9zM448 80v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V80c0-26.5 21.5-48 48-48h352c26.5 0 48 21.5 48 48zm-64 176c0-88.2-71.8-160-160-160S64 167.8 64 256s71.8 160 160 160 160-71.8 160-160z"],dropbox:[528,512,[],"f16b","M264.4 116.3l-132 84.3 132 84.3-132 84.3L0 284.1l132.3-84.3L0 116.3 132.3 32l132.1 84.3zM131.6 395.7l132-84.3 132 84.3-132 84.3-132-84.3zm132.8-111.6l132-84.3-132-83.6L395.7 32 528 116.3l-132.3 84.3L528 284.8l-132.3 84.3-131.3-85z"],drupal:[448,512,[],"f1a9","M319.5 114.7c-22.2-14-43.5-19.5-64.7-33.5-13-8.8-31.3-30-46.5-48.3-2.7 29.3-11.5 41.2-22 49.5-21.3 17-34.8 22.2-53.5 32.3C117 123 32 181.5 32 290.5 32 399.7 123.8 480 225.8 480 327.5 480 416 406 416 294c0-112.3-83-171-96.5-179.3zm2.5 325.6c-20.1 20.1-90.1 28.7-116.7 4.2-4.8-4.8.3-12 6.5-12 0 0 17 13.3 51.5 13.3 27 0 46-7.7 54.5-14 6.1-4.6 8.4 4.3 4.2 8.5zm-54.5-52.6c8.7-3.6 29-3.8 36.8 1.3 4.1 2.8 16.1 18.8 6.2 23.7-8.4 4.2-1.2-15.7-26.5-15.7-14.7 0-19.5 5.2-26.7 11-7 6-9.8 8-12.2 4.7-6-8.2 15.9-22.3 22.4-25zM360 405c-15.2-1-45.5-48.8-65-49.5-30.9-.9-104.1 80.7-161.3 42-38.8-26.6-14.6-104.8 51.8-105.2 49.5-.5 83.8 49 108.5 48.5 21.3-.3 61.8-41.8 81.8-41.8 48.7 0 23.3 109.3-15.8 106z"],dyalog:[416,512,[],"f399","M0 32v119.2h64V96h107.2C284.6 96 352 176.2 352 255.9 352 332 293.4 416 171.2 416H0v64h171.2C331.9 480 416 367.3 416 255.9c0-58.7-22.1-113.4-62.3-154.3C308.9 56 245.7 32 171.2 32H0z"],earlybirds:[480,512,[],"f39a","M313.2 47.5c1.2-13 21.3-14 36.6-8.7.9.3 26.2 9.7 19 15.2-27.9-7.4-56.4 18.2-55.6-6.5zm-201 6.9c30.7-8.1 62 20 61.1-7.1-1.3-14.2-23.4-15.3-40.2-9.6-1 .3-28.7 10.5-20.9 16.7zM319.4 160c-8.8 0-16 7.2-16 16s7.2 16 16 16 16-7.2 16-16-7.2-16-16-16zm-159.7 0c-8.8 0-16 7.2-16 16s7.2 16 16 16 16-7.2 16-16-7.2-16-16-16zm318.5 163.2c-9.9 24-40.7 11-63.9-1.2-13.5 69.1-58.1 111.4-126.3 124.2.3.9-2-.1 24 1 33.6 1.4 63.8-3.1 97.4-8-19.8-13.8-11.4-37.1-9.8-38.1 1.4-.9 14.7 1.7 21.6 11.5 8.6-12.5 28.4-14.8 30.2-13.6 1.6 1.1 6.6 20.9-6.9 34.6 4.7-.9 8.2-1.6 9.8-2.1 2.6-.8 17.7 11.3 3.1 13.3-14.3 2.3-22.6 5.1-47.1 10.8-45.9 10.7-85.9 11.8-117.7 12.8l1 11.6c3.8 18.1-23.4 24.3-27.6 6.2.8 17.9-27.1 21.8-28.4-1l-.5 5.3c-.7 18.4-28.4 17.9-28.3-.6-7.5 13.5-28.1 6.8-26.4-8.5l1.2-12.4c-36.7.9-59.7 3.1-61.8 3.1-20.9 0-20.9-31.6 0-31.6 2.4 0 27.7 1.3 63.2 2.8-61.1-15.5-103.7-55-114.9-118.2-25 12.8-57.5 26.8-68.2.8-10.5-25.4 21.5-42.6 66.8-73.4.7-6.6 1.6-13.3 2.7-19.8-14.4-19.6-11.6-36.3-16.1-60.4-16.8 2.4-23.2-9.1-23.6-23.1.3-7.3 2.1-14.9 2.4-15.4 1.1-1.8 10.1-2 12.7-2.6 6-31.7 50.6-33.2 90.9-34.5 19.7-21.8 45.2-41.5 80.9-48.3C203.3 29 215.2 8.5 216.2 8c1.7-.8 21.2 4.3 26.3 23.2 5.2-8.8 18.3-11.4 19.6-10.7 1.1.6 6.4 15-4.9 25.9 40.3 3.5 72.2 24.7 96 50.7 36.1 1.5 71.8 5.9 77.1 34 2.7.6 11.6.8 12.7 2.6.3.5 2.1 8.1 2.4 15.4-.5 13.9-6.8 25.4-23.6 23.1-3.2 17.3-2.7 32.9-8.7 47.7 2.4 11.7 4 23.8 4.8 36.4 37 25.4 70.3 42.5 60.3 66.9zM207.4 159.9c.9-44-37.9-42.2-78.6-40.3-21.7 1-38.9 1.9-45.5 13.9-11.4 20.9 5.9 92.9 23.2 101.2 9.8 4.7 73.4 7.9 86.3-7.1 8.2-9.4 15-49.4 14.6-67.7zm52 58.3c-4.3-12.4-6-30.1-15.3-32.7-2-.5-9-.5-11 0-10 2.8-10.8 22.1-17 37.2 15.4 0 19.3 9.7 23.7 9.7 4.3 0 6.3-11.3 19.6-14.2zm135.7-84.7c-6.6-12.1-24.8-12.9-46.5-13.9-40.2-1.9-78.2-3.8-77.3 40.3-.5 18.3 5 58.3 13.2 67.8 13 14.9 76.6 11.8 86.3 7.1 15.8-7.6 36.5-78.9 24.3-101.3z"],edge:[512,512,[],"f282","M25.714 228.163c.111-.162.23-.323.342-.485-.021.162-.045.323-.065.485h-.277zm460.572 15.508c0-44.032-7.754-84.465-28.801-122.405C416.498 47.879 343.912 8.001 258.893 8.001 118.962 7.724 40.617 113.214 26.056 227.679c42.429-61.312 117.073-121.376 220.375-124.966 0 0 109.666 0 99.419 104.957H169.997c6.369-37.386 18.554-58.986 34.339-78.926-75.048 34.893-121.85 96.096-120.742 188.315.83 71.448 50.124 144.836 120.743 171.976 83.357 31.847 192.776 7.2 240.132-21.324V363.307c-80.864 56.494-270.871 60.925-272.255-67.572h314.073v-52.064z"],ember:[640,512,[],"f423","M639.9 311.7c-1.1-10.7-10.7-6.8-10.7-6.8s-15.6 12.1-29.3 10.7c-13.7-1.3-9.4-32-9.4-32s3-28.1-5.1-30.4c-8.1-2.4-18 7.3-18 7.3s-12.4 13.7-18.3 31.2l-1.6.5s1.9-30.6-.3-37.6c-1.6-3.5-16.4-3.2-18.8 3-2.4 6.2-14.2 49.2-15 67.2 0 0-23.1 19.6-43.3 22.8-20.2 3.2-25-9.4-25-9.4s54.8-15.3 52.9-59.1c-1.9-43.8-44.2-27.6-49-24-4.6 3.5-29.4 18.4-36.6 59.7-.2 1.4-.7 7.5-.7 7.5s-21.2 14.2-33 18c0 0 33-55.6-7.3-80.9-18.3-11-32.8 12.1-32.8 12.1s54.5-60.7 42.5-112c-5.8-24.4-18-27.1-29.2-23.1-17 6.7-23.5 16.7-23.5 16.7s-22 32-27.1 79.5-12.6 105.1-12.6 105.1-10.5 10.2-20.2 10.7-5.4-28.7-5.4-28.7 7.5-44.6 7-52.1-1.1-11.6-9.9-14.2c-8.9-2.7-18.5 8.6-18.5 8.6s-25.5 38.7-27.7 44.6l-1.3 2.4-1.3-1.6s18-52.7.8-53.5-28.5 18.8-28.5 18.8-19.6 32.8-20.4 36.5l-1.3-1.6s8.1-38.2 6.4-47.6c-1.6-9.4-10.5-7.5-10.5-7.5s-11.3-1.3-14.2 5.9c-3 7.3-13.7 55.3-15 70.7 0 0-28.2 20.2-46.8 20.4s-16.7-11.8-16.7-11.8 68-23.3 49.4-69.2c-8.3-11.8-18-15.5-31.7-15.3-13.7.3-30.3 8.6-41.3 33.3-5.3 11.8-6.8 23-7.8 31.5 0 0-12.3 2.4-18.8-2.9-6.4-5.4-10 0-10 0s-11.2 13.9-.1 18.2c11 4.3 28.1 6.1 28.1 6.1 1.6 7.5 6.2 19.5 19.6 29.7 20.2 15.3 58.8-1.3 58.8-1.3l15.9-8.8s.5 14.6 12.1 16.7c11.6 2.1 16.4 1 36.5-47.9 11.8-25 12.6-23.6 12.6-23.6l1.3-.3s-9.1 46.8-5.6 59.7c3.5 12.9 18.8 11.6 18.8 11.6s8.3 2.4 15-21.2c6.7-23.6 19.6-49.9 19.6-49.9h1.6s-5.6 48.1 3 63.7c8.6 15.6 30.9 5.3 30.9 5.3s15.6-7.8 18-10.2c0 0 18.5 15.8 44.6 12.9 58.3-11.5 79.1-25.9 79.1-25.9s10 24.4 41.1 26.7c35.5 2.7 54.8-18.6 54.8-18.6s-.3 13.5 12.1 18.6c12.4 5.1 20.7-22.8 20.7-22.8l20.7-57.2h1.9s1.1 37.3 21.5 43.2c20.4 5.9 47-13.7 47-13.7s6.4-3.7 5.3-14.4zm-578 5.3c.8-32 21.8-45.9 29-39 7.3 7 4.6 22-9.1 31.4-13.7 9.5-19.9 7.6-19.9 7.6zm272.8-123.9s19.1-49.7 23.6-25.5-40 96.2-40 96.2c.5-16.1 16.4-70.7 16.4-70.7zm22.8 138.4c-12.6 33-43.3 19.6-43.3 19.6s-3.5-11.8 6.4-44.9 33.3-20.2 33.3-20.2 16.2 12.5 3.6 45.5zm84.6-14.5s-3-10.5 8.1-30.6c11-20.2 19.6-9.1 19.6-9.1s9.4 10.2-1.3 25.5c-10.8 15.3-26.4 14.2-26.4 14.2z"],empire:[496,512,[],"f1d1","M287.6 54.2c-10.8-2.2-22.1-3.3-33.5-3.6V32.4c78.1 2.2 146.1 44 184.6 106.6l-15.8 9.1c-6.1-9.7-12.7-18.8-20.2-27.1l-18 15.5c-26-29.6-61.4-50.7-101.9-58.4l4.8-23.9zM53.4 322.4l23-7.7c-6.4-18.3-10-38.2-10-58.7s3.3-40.4 9.7-58.7l-22.7-7.7c3.6-10.8 8.3-21.3 13.6-31l-15.8-9.1C34 181 24.1 217.5 24.1 256s10 75 27.1 106.6l15.8-9.1c-5.3-10-9.7-20.3-13.6-31.1zM213.1 434c-40.4-8-75.8-29.1-101.9-58.7l-18 15.8c-7.5-8.6-14.4-17.7-20.2-27.4l-16 9.4c38.5 62.3 106.8 104.3 184.9 106.6v-18.3c-11.3-.3-22.7-1.7-33.5-3.6l4.7-23.8zM93.3 120.9l18 15.5c26-29.6 61.4-50.7 101.9-58.4l-4.7-23.8c10.8-2.2 22.1-3.3 33.5-3.6V32.4C163.9 34.6 95.9 76.4 57.4 139l15.8 9.1c6-9.7 12.6-18.9 20.1-27.2zm309.4 270.2l-18-15.8c-26 29.6-61.4 50.7-101.9 58.7l4.7 23.8c-10.8 1.9-22.1 3.3-33.5 3.6v18.3c78.1-2.2 146.4-44.3 184.9-106.6l-16.1-9.4c-5.7 9.7-12.6 18.8-20.1 27.4zM496 256c0 137-111 248-248 248S0 393 0 256 111 8 248 8s248 111 248 248zm-12.2 0c0-130.1-105.7-235.8-235.8-235.8S12.2 125.9 12.2 256 117.9 491.8 248 491.8 483.8 386.1 483.8 256zm-39-106.6l-15.8 9.1c5.3 9.7 10 20.2 13.6 31l-22.7 7.7c6.4 18.3 9.7 38.2 9.7 58.7s-3.6 40.4-10 58.7l23 7.7c-3.9 10.8-8.3 21-13.6 31l15.8 9.1C462 331 471.9 294.5 471.9 256s-9.9-75-27.1-106.6zm-183 177.7c16.3-3.3 30.4-11.6 40.7-23.5l51.2 44.8c11.9-13.6 21.3-29.3 27.1-46.8l-64.2-22.1c2.5-7.5 3.9-15.2 3.9-23.5s-1.4-16.1-3.9-23.5l64.5-22.1c-6.1-17.4-15.5-33.2-27.4-46.8l-51.2 44.8c-10.2-11.9-24.4-20.5-40.7-23.8l13.3-66.4c-8.6-1.9-17.7-2.8-27.1-2.8-9.4 0-18.5.8-27.1 2.8l13.3 66.4c-16.3 3.3-30.4 11.9-40.7 23.8l-51.2-44.8c-11.9 13.6-21.3 29.3-27.4 46.8l64.5 22.1c-2.5 7.5-3.9 15.2-3.9 23.5s1.4 16.1 3.9 23.5l-64.2 22.1c5.8 17.4 15.2 33.2 27.1 46.8l51.2-44.8c10.2 11.9 24.4 20.2 40.7 23.5l-13.3 66.7c8.6 1.7 17.7 2.8 27.1 2.8 9.4 0 18.5-1.1 27.1-2.8l-13.3-66.7z"],envira:[448,512,[],"f299","M0 32c477.6 0 366.6 317.3 367.1 366.3L448 480h-26l-70.4-71.2c-39 4.2-124.4 34.5-214.4-37C47 300.3 52 214.7 0 32zm79.7 46c-49.7-23.5-5.2 9.2-5.2 9.2 45.2 31.2 66 73.7 90.2 119.9 31.5 60.2 79 139.7 144.2 167.7 65 28 34.2 12.5 6-8.5-28.2-21.2-68.2-87-91-130.2-31.7-60-61-118.6-144.2-158.1z"],erlang:[640,512,[],"f39d","M21.7 193c-.1 86.8 29 159.5 78.7 212.1H0V.1h87.2C45.7 50.3 21.6 116.2 21.7 193zM640 .1h-83.6c31.4 42.7 48.7 97.5 46.2 162.7.5 6 .5 11.7 0 24.1H230.2c-.2 109.7 38.9 194.9 138.6 195.3 68.5-.3 118-51 151.9-106.1l96.4 48.2c-17.4 30.9-36.5 57.8-57.9 80.8H640V.1zm-80.8 405h-.2.2zM556.1.1h.3l-.1-.1-.2.1zM325.4 9.8c-45.9.1-85.1 33.5-89.2 83.2h169.9C405 43.3 371.6 9.9 325.4 9.8z"],etsy:[384,512,[],"f2d7","M384 348c-1.75 10.75-13.75 110-15.5 132-117.879-4.299-219.895-4.743-368.5 0v-25.5c45.457-8.948 60.627-8.019 61-35.25 1.793-72.322 3.524-244.143 0-322-1.029-28.46-12.13-26.765-61-36v-25.5c73.886 2.358 255.933 8.551 362.999-3.75-3.5 38.25-7.75 126.5-7.75 126.5H332C320.947 115.665 313.241 68 277.25 68h-137c-10.25 0-10.75 3.5-10.75 9.75V241.5c58 .5 88.5-2.5 88.5-2.5 29.77-.951 27.56-8.502 40.75-65.251h25.75c-4.407 101.351-3.91 61.829-1.75 160.25H257c-9.155-40.086-9.065-61.045-39.501-61.5 0 0-21.5-2-88-2v139c0 26 14.25 38.25 44.25 38.25H263c63.636 0 66.564-24.996 98.751-99.75H384z"],expeditedssl:[496,512,[],"f23e","M248 43.4C130.6 43.4 35.4 138.6 35.4 256S130.6 468.6 248 468.6 460.6 373.4 460.6 256 365.4 43.4 248 43.4zm-97.4 132.9c0-53.7 43.7-97.4 97.4-97.4s97.4 43.7 97.4 97.4v26.6c0 5-3.9 8.9-8.9 8.9h-17.7c-5 0-8.9-3.9-8.9-8.9v-26.6c0-82.1-124-82.1-124 0v26.6c0 5-3.9 8.9-8.9 8.9h-17.7c-5 0-8.9-3.9-8.9-8.9v-26.6zM389.7 380c0 9.7-8 17.7-17.7 17.7H124c-9.7 0-17.7-8-17.7-17.7V238.3c0-9.7 8-17.7 17.7-17.7h248c9.7 0 17.7 8 17.7 17.7V380zm-248-137.3v132.9c0 2.5-1.9 4.4-4.4 4.4h-8.9c-2.5 0-4.4-1.9-4.4-4.4V242.7c0-2.5 1.9-4.4 4.4-4.4h8.9c2.5 0 4.4 1.9 4.4 4.4zm141.7 48.7c0 13-7.2 24.4-17.7 30.4v31.6c0 5-3.9 8.9-8.9 8.9h-17.7c-5 0-8.9-3.9-8.9-8.9v-31.6c-10.5-6.1-17.7-17.4-17.7-30.4 0-19.7 15.8-35.4 35.4-35.4s35.5 15.8 35.5 35.4zM248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm0 478.3C121 486.3 17.7 383 17.7 256S121 25.7 248 25.7 478.3 129 478.3 256 375 486.3 248 486.3z"],facebook:[448,512,[],"f09a","M448 56.7v398.5c0 13.7-11.1 24.7-24.7 24.7H309.1V306.5h58.2l8.7-67.6h-67v-43.2c0-19.6 5.4-32.9 33.5-32.9h35.8v-60.5c-6.2-.8-27.4-2.7-52.2-2.7-51.6 0-87 31.5-87 89.4v49.9h-58.4v67.6h58.4V480H24.7C11.1 480 0 468.9 0 455.3V56.7C0 43.1 11.1 32 24.7 32h398.5c13.7 0 24.8 11.1 24.8 24.7z"],"facebook-f":[264,512,[],"f39e","M76.7 512V283H0v-91h76.7v-71.7C76.7 42.4 124.3 0 193.8 0c33.3 0 61.9 2.5 70.2 3.6V85h-48.2c-37.8 0-45.1 18-45.1 44.3V192H256l-11.7 91h-73.6v229"],"facebook-messenger":[448,512,[],"f39f","M224 32C15.9 32-77.5 278 84.6 400.6V480l75.7-42c142.2 39.8 285.4-59.9 285.4-198.7C445.8 124.8 346.5 32 224 32zm23.4 278.1L190 250.5 79.6 311.6l121.1-128.5 57.4 59.6 110.4-61.1-121.1 128.5z"],"facebook-square":[448,512,[],"f082","M448 80v352c0 26.5-21.5 48-48 48h-85.3V302.8h60.6l8.7-67.6h-69.3V192c0-19.6 5.4-32.9 33.5-32.9H384V98.7c-6.2-.8-27.4-2.7-52.2-2.7-51.6 0-87 31.5-87 89.4v49.9H184v67.6h60.9V480H48c-26.5 0-48-21.5-48-48V80c0-26.5 21.5-48 48-48h352c26.5 0 48 21.5 48 48z"],firefox:[480,512,[],"f269","M478.1 235.3c-.7-4.5-1.4-7.1-1.4-7.1s-1.8 2-4.7 5.9c-.9-10.7-2.8-21.2-5.8-31.6-3.7-12.9-8.5-25.4-14.5-37.4-3.8-8-8.2-15.6-13.3-22.8-1.8-2.7-3.7-5.4-5.6-7.9-8.8-14.4-19-23.3-30.7-40-7.6-12.8-12.9-26.9-15.4-41.6-3.2 8.9-5.7 18-7.4 27.3-12.1-12.2-22.5-20.8-28.9-26.7C319.4 24.2 323 9.1 323 9.1S264.7 74.2 289.9 142c8.7 23 23.8 43.1 43.4 57.9 24.4 20.2 50.8 36 64.7 76.6-11.2-21.3-28.1-39.2-48.8-51.5 6.2 14.7 9.4 30.6 9.3 46.5 0 61-49.6 110.5-110.6 110.4-8.3 0-16.5-.9-24.5-2.8-9.5-1.8-18.7-4.9-27.4-9.3-12.9-7.8-24-18.1-32.8-30.3l-.2-.3 2 .7c4.6 1.6 9.2 2.8 14 3.7 18.7 4 38.3 1.7 55.6-6.6 17.5-9.7 28-16.9 36.6-14h.2c8.4 2.7 15-5.5 9-14-10.4-13.4-27.4-20-44.2-17-17.5 2.5-33.5 15-56.4 2.9-1.5-.8-2.9-1.6-4.3-2.5-1.6-.9 4.9 1.3 3.4.3-5-2.5-9.8-5.4-14.4-8.6-.3-.3 3.5 1.1 3.1.8-5.9-4-11-9.2-15-15.2-4.1-7.4-4.5-16.4-1-24.1 2.1-3.8 5.4-6.9 9.3-8.7 3 1.5 4.8 2.6 4.8 2.6s-1.3-2.5-2.1-3.8c.3-.1.5 0 .8-.2 2.6 1.1 8.3 4 11.4 5.8 2.1 1.1 3.8 2.7 5.2 4.7 0 0 1-.5.3-2.7-1.1-2.7-2.9-5-5.4-6.6h.2c2.3 1.2 4.5 2.6 6.6 4.1 1.9-4.4 2.8-9.2 2.6-14 .2-2.6-.2-5.3-1.1-7.8-.8-1.6.5-2.2 1.9-.5-.2-1.3-.7-2.5-1.2-3.7v-.1s.8-1.1 1.2-1.5c1-1 2.1-1.9 3.4-2.7 7.2-4.5 14.8-8.4 22.7-11.6 6.4-2.8 11.7-4.9 12.8-5.6 1.6-1 3.1-2.2 4.5-3.5 5.3-4.5 9-10.8 10.2-17.7.1-.9.2-1.8.3-2.8v-1.5c-.9-3.5-6.9-6.1-38.4-9.1-11.1-1.8-20-10.1-22.5-21.1v.1c-.4 1.1-.9 2.3-1.3 3.5.4-1.2.8-2.3 1.3-3.5v-.2c6-15.7 16.8-29.1 30.8-38.3.8-.7-3.2.2-2.4-.5 2.7-1.3 5.4-2.5 8.2-3.5 1.4-.6-6-3.4-12.6-2.7-4 .2-8 1.2-11.7 2.8 1.6-1.3 6.2-3.1 5.1-3.1-8.4 1.6-16.5 4.7-23.9 9 0-.8.1-1.5.5-2.2-5.9 2.5-11 6.5-15 11.5.1-.9.2-1.8.2-2.7-2.7 2-5.2 4.3-7.3 6.9l-.1.1c-17.4-6.7-36.3-8.3-54.6-4.7l-.2-.1h.2c-3.8-3.1-7.1-6.7-9.7-10.9l-.2.1-.4-.2c-1.2-1.8-2.4-3.8-3.7-6-.9-1.6-1.8-3.4-2.7-5.2 0-.1-.1-.2-.2-.2-.4 0-.6 1.7-.9 1.3v-.1c-3.2-8.3-4.7-17.2-4.4-26.2l-.2.1c-5.1 3.5-9 8.6-11.1 14.5-.9 2.1-1.6 3.3-2.2 4.5v-.5c.1-1.1.6-3.3.5-3.1-.1.2-.2.3-.3.4-1.5 1.7-2.9 3.7-3.9 5.8-.9 1.9-1.7 3.9-2.3 5.9-.1.3 0-.3 0-1s.1-2 0-1.7l-.3.7c-6.7 14.9-10.9 30.8-12.4 47.1-.4 2.8-.6 5.6-.5 8.3v.2c-4.8 5.2-9 11-12.7 17.1-12.1 20.4-21.1 42.5-26.8 65.6 4-8.8 8.8-17.2 14.3-25.1C5.5 228.5 0 257.4 0 286.6c1.8-8.6 4.2-17 7-25.3-1.7 34.5 4.9 68.9 19.4 100.3 19.4 43.5 51.6 80 92.3 104.7 16.6 11.2 34.7 19.9 53.8 25.8 2.5.9 5.1 1.8 7.7 2.7-.8-.3-1.6-.7-2.4-1 22.6 6.8 46.2 10.3 69.8 10.3 83.7 0 111.3-31.9 113.8-35 4.1-3.7 7.5-8.2 9.9-13.3 1.6-.7 3.2-1.4 4.9-2.1l1-.5 1.9-.9c12.6-5.9 24.5-13.4 35.3-22.1 16.3-11.7 27.9-28.7 32.9-48.1 3-7.1 3.1-15 .4-22.2.9-1.4 1.7-2.8 2.7-4.3 18-28.9 28.2-61.9 29.6-95.9v-2.8c0-7.3-.6-14.5-1.9-21.6z"],"first-order":[448,512,[],"f2b0","M12.9 229.2c.1-.1.2-.3.3-.4 0 .1 0 .3-.1.4h-.2zM224 96.6c-7.1 0-14.6.6-21.4 1.7l3.7 67.4-22-64c-14.3 3.7-27.7 9.4-40 16.6l29.4 61.4-45.1-50.9c-11.4 8.9-21.7 19.1-30.6 30.9l50.6 45.4-61.1-29.7c-7.1 12.3-12.9 25.7-16.6 40l64.3 22.6-68-4c-.9 7.1-1.4 14.6-1.4 22s.6 14.6 1.4 21.7l67.7-4-64 22.6c3.7 14.3 9.4 27.7 16.6 40.3l61.1-29.7L97.7 352c8.9 11.7 19.1 22.3 30.9 30.9l44.9-50.9-29.5 61.4c12.3 7.4 25.7 13.1 40 16.9l22.3-64.6-4 68c7.1 1.1 14.6 1.7 21.7 1.7 7.4 0 14.6-.6 21.7-1.7l-4-68.6 22.6 65.1c14.3-4 27.7-9.4 40-16.9L274.9 332l44.9 50.9c11.7-8.9 22-19.1 30.6-30.9l-50.6-45.1 61.1 29.4c7.1-12.3 12.9-25.7 16.6-40.3l-64-22.3 67.4 4c1.1-7.1 1.4-14.3 1.4-21.7s-.3-14.9-1.4-22l-67.7 4 64-22.3c-3.7-14.3-9.1-28-16.6-40.3l-60.9 29.7 50.6-45.4c-8.9-11.7-19.1-22-30.6-30.9l-45.1 50.9 29.4-61.1c-12.3-7.4-25.7-13.1-40-16.9L241.7 166l4-67.7c-7.1-1.2-14.3-1.7-21.7-1.7zM443.4 128v256L224 512 4.6 384V128L224 0l219.4 128zm-17.1 10.3L224 20.9 21.7 138.3v235.1L224 491.1l202.3-117.7V138.3zM224 37.1l187.7 109.4v218.9L224 474.9 36.3 365.4V146.6L224 37.1zm0 50.9c-92.3 0-166.9 75.1-166.9 168 0 92.6 74.6 167.7 166.9 167.7 92 0 166.9-75.1 166.9-167.7 0-92.9-74.9-168-166.9-168z"],firstdraft:[384,512,[],"f3a1","M384 192h-64v128H192v128H0v-25.6h166.4v-128h128v-128H384V192zm-25.6 38.4v128h-128v128H64V512h192V384h128V230.4h-25.6zm25.6 192h-89.6V512H320v-64h64v-25.6zM0 0v384h128V256h128V128h128V0H0z"],flickr:[448,512,[],"f16e","M400 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48zM144.5 319c-35.1 0-63.5-28.4-63.5-63.5s28.4-63.5 63.5-63.5 63.5 28.4 63.5 63.5-28.4 63.5-63.5 63.5zm159 0c-35.1 0-63.5-28.4-63.5-63.5s28.4-63.5 63.5-63.5 63.5 28.4 63.5 63.5-28.4 63.5-63.5 63.5z"],fly:[384,512,[],"f417","M197.8 427.8c12.9 11.7 33.7 33.3 33.2 50.7 0 .8-.1 1.6-.1 2.5-1.8 19.8-18.8 31.1-39.1 31-25-.1-39.9-16.8-38.7-35.8 1-16.2 20.5-36.7 32.4-47.6 2.3-2.1 2.7-2.7 5.6-3.6 3.4 0 3.9.3 6.7 2.8zM331.9 67.3c-16.3-25.7-38.6-40.6-63.3-52.1C243.1 4.5 214-.2 192 0c-44.1 0-71.2 13.2-81.1 17.3C57.3 45.2 26.5 87.2 28 158.6c7.1 82.2 97 176 155.8 233.8 1.7 1.6 4.5 4.5 6.2 5.1l3.3.1c2.1-.7 1.8-.5 3.5-2.1 52.3-49.2 140.7-145.8 155.9-215.7 7-39.2 3.1-72.5-20.8-112.5zM186.8 351.9c-28-51.1-65.2-130.7-69.3-189-3.4-47.5 11.4-131.2 69.3-136.7v325.7zM328.7 180c-16.4 56.8-77.3 128-118.9 170.3C237.6 298.4 275 217 277 158.4c1.6-45.9-9.8-105.8-48-131.4 88.8 18.3 115.5 98.1 99.7 153z"],"font-awesome":[448,512,[],"f2b4","M397.8 32H50.2C22.7 32 0 54.7 0 82.2v347.6C0 457.3 22.7 480 50.2 480h347.6c27.5 0 50.2-22.7 50.2-50.2V82.2c0-27.5-22.7-50.2-50.2-50.2zm-45.4 284.3c0 4.2-3.6 6-7.8 7.8-16.7 7.2-34.6 13.7-53.8 13.7-26.9 0-39.4-16.7-71.7-16.7-23.3 0-47.8 8.4-67.5 17.3-1.2.6-2.4.6-3.6 1.2V385c0 1.8 0 3.6-.6 4.8v1.2c-2.4 8.4-10.2 14.3-19.1 14.3-11.3 0-20.3-9-20.3-20.3V166.4c-7.8-6-13.1-15.5-13.1-26.3 0-18.5 14.9-33.5 33.5-33.5 18.5 0 33.5 14.9 33.5 33.5 0 10.8-4.8 20.3-13.1 26.3v18.5c1.8-.6 3.6-1.2 5.4-2.4 18.5-7.8 40.6-14.3 61.5-14.3 22.7 0 40.6 6 60.9 13.7 4.2 1.8 8.4 2.4 13.1 2.4 22.7 0 47.8-16.1 53.8-16.1 4.8 0 9 3.6 9 7.8v140.3z"],"font-awesome-alt":[448,512,[],"f35c","M397.8 67.8c7.8 0 14.3 6.6 14.3 14.3v347.6c0 7.8-6.6 14.3-14.3 14.3H50.2c-7.8 0-14.3-6.6-14.3-14.3V82.2c0-7.8 6.6-14.3 14.3-14.3h347.6m0-35.9H50.2C22.7 32 0 54.7 0 82.2v347.6C0 457.3 22.7 480 50.2 480h347.6c27.5 0 50.2-22.7 50.2-50.2V82.2c0-27.5-22.7-50.2-50.2-50.2zm-58.5 139.2c-6 0-29.9 15.5-52.6 15.5-4.2 0-8.4-.6-12.5-2.4-19.7-7.8-37-13.7-59.1-13.7-20.3 0-41.8 6.6-59.7 13.7-1.8.6-3.6 1.2-4.8 1.8v-17.9c7.8-6 12.5-14.9 12.5-25.7 0-17.9-14.3-32.3-32.3-32.3s-32.3 14.3-32.3 32.3c0 10.2 4.8 19.7 12.5 25.7v212.1c0 10.8 9 19.7 19.7 19.7 9 0 16.1-6 18.5-13.7V385c.6-1.8.6-3 .6-4.8V336c1.2 0 2.4-.6 3-1.2 19.7-8.4 43-16.7 65.7-16.7 31.1 0 43 16.1 69.3 16.1 18.5 0 36.4-6.6 52-13.7 4.2-1.8 7.2-3.6 7.2-7.8V178.3c1.8-4.1-2.3-7.1-7.7-7.1z"],"font-awesome-flag":[448,512,[],"f425","M444.373 359.424c0 7.168-6.144 10.24-13.312 13.312-28.672 12.288-59.392 23.552-92.16 23.552-46.08 0-67.584-28.672-122.88-28.672-39.936 0-81.92 14.336-115.712 29.696-2.048 1.024-4.096 1.024-6.144 2.048v77.824c0 21.405-16.122 34.816-33.792 34.816-19.456 0-34.816-15.36-34.816-34.816V102.4C12.245 92.16 3.029 75.776 3.029 57.344 3.029 25.6 28.629 0 60.373 0s57.344 25.6 57.344 57.344c0 18.432-8.192 34.816-22.528 45.056v31.744c4.124-1.374 58.768-28.672 114.688-28.672 65.27 0 97.676 27.648 126.976 27.648 38.912 0 81.92-27.648 92.16-27.648 8.192 0 15.36 6.144 15.36 13.312v240.64z"],fonticons:[448,512,[],"f280","M0 32v448h448V32H0zm167.4 196h67.4l-11.1 37.3H168v112.9c0 5.8-2 6.7 3.2 7.3l43.5 4.1v25.1H84V389l21.3-2c5.2-.6 6.7-2.3 6.7-7.9V267.7c0-2.3-2.9-2.3-5.8-2.3H84V228h28v-21c0-49.6 26.5-70 77.3-70 34.1 0 64.7 8.2 64.7 52.8l-50.7 6.1c.3-18.7-4.4-23-16.3-23-18.4 0-19 9.9-19 27.4v23.3c0 2.4-3.5 4.4-.6 4.4zM364 414.7H261.3v-25.1l20.4-2.6c5.2-.6 7.6-1.7 7.6-7.3V271.8c0-4.1-2.9-6.7-6.7-7.9l-24.2-6.4 6.7-29.5h80.2v151.7c0 5.8-2.6 6.4 2.9 7.3l15.7 2.6v25.1zm-21.9-255.5l9 33.2-7.3 7.3-31.2-16.6-31.2 16.6-7.3-7.3 9-33.2-21.8-24.2 3.5-9.6h27.7l15.5-28h9.3l15.5 28h27.7l3.5 9.6-21.9 24.2z"],"fonticons-fi":[384,512,[],"f3a2","M114.4 224h92.4l-15.2 51.2h-76.4V433c0 8-2.8 9.2 4.4 10l59.6 5.6V483H0v-35.2l29.2-2.8c7.2-.8 9.2-3.2 9.2-10.8V278.4c0-3.2-4-3.2-8-3.2H0V224h38.4v-28.8c0-68 36.4-96 106-96 46.8 0 88.8 11.2 88.8 72.4l-69.6 8.4c.4-25.6-6-31.6-22.4-31.6-25.2 0-26 13.6-26 37.6v32c0 3.2-4.8 6-.8 6zM384 483H243.2v-34.4l28-3.6c7.2-.8 10.4-2.4 10.4-10V287c0-5.6-4-9.2-9.2-10.8l-33.2-8.8 9.2-40.4h110v208c0 8-3.6 8.8 4 10l21.6 3.6V483zm-30-347.2l12.4 45.6-10 10-42.8-22.8-42.8 22.8-10-10 12.4-45.6-30-36.4 4.8-10h38L307.2 51H320l21.2 38.4h38l4.8 13.2-30 33.2z"],"fort-awesome":[448,512,[],"f286","M412 284h-24c-2.25 0-4 1.75-4 4v28h-32V160c0-2.25-1.75-4-4-4h-24c-2.25 0-4 1.75-4 4v28h-32v-28c0-2.25-1.75-4-4-4h-24c-2.25 0-4 1.75-4 4v28h-32v-28c0-5.25-7-4-10.25-4v-33.25c7.25-1.75 15-3 22.5-3 9.501 0 18.251 3.75 27.5 3.75 4 0 24.25-1 24.25-7V64c0-2.25-1.75-4-4-4-4.5 0-13.25 3.75-21 3.75-8.499 0-18.25-3.75-28.501-3.75-7 0-14 1-20.75 2.5v-4.25c4.75-2.25 8-7.25 8-12.5 0-18.149-27.499-18.167-27.499 0 0 5.25 3.25 10.25 8 12.5V156c-3.25 0-10.25-1.25-10.25 4v28h-32v-28c0-2.25-1.75-4-4-4h-24c-2.25 0-4 1.75-4 4v28H96v-28c0-2.25-1.75-4-4-4H68c-2.25 0-4 1.75-4 4v156H32v-28c0-2.25-1.75-4-4-4H4c-2.25 0-4 1.75-4 4v192h160v-84c0-63.507 96-63.525 96 0v84h160V288c0-2.25-1.75-4-4-4zm-252-4.001c0 2.25-1.75 4-4 4h-24c-2.25 0-4-1.75-4-4V224c0-2.25 1.75-4 4-4h24c2.25 0 4 1.75 4 4v55.999zm128 0c0 2.25-1.75 4-4 4h-24c-2.25 0-4-1.75-4-4V224c0-2.25 1.75-4 4-4h24c2.25 0 4 1.75 4 4v55.999z"],"fort-awesome-alt":[512,512,[],"f3a3","M211.7 241.1v51.7c0 2.1-1.6 3.7-3.7 3.7h-22.2c-2.1 0-3.7-1.6-3.7-3.7v-51.7c0-2.1 1.6-3.7 3.7-3.7H208c2.1 0 3.7 1.6 3.7 3.7zm114.5-3.7H304c-2.1 0-3.7 1.6-3.7 3.7v51.7c0 2.1 1.6 3.7 3.7 3.7h22.2c2.1 0 3.7-1.6 3.7-3.7v-51.7c-.1-2.1-1.7-3.7-3.7-3.7zm-29.1 263.2c-.9.1-1.7.3-2.6.4-1 .2-2.1.3-3.1.5-.9.1-1.8.3-2.8.4-1 .1-2 .3-3 .4-1 .1-2 .2-2.9.3-1 .1-1.9.2-2.9.3-1 .1-2.1.2-3.1.3-.9.1-1.8.2-2.7.2-1.1.1-2.3.1-3.4.2-.8 0-1.7.1-2.5.1-1.3.1-2.6.1-3.9.1-.7 0-1.4.1-2.1.1-2 0-4 .1-6 .1s-4 0-6-.1c-.7 0-1.4 0-2.1-.1-1.3 0-2.6-.1-3.9-.1-.8 0-1.7-.1-2.5-.1-1.1-.1-2.3-.1-3.4-.2-.9-.1-1.8-.1-2.7-.2-1-.1-2.1-.2-3.1-.3-1-.1-1.9-.2-2.9-.3-1-.1-2-.2-2.9-.3-1-.1-2-.2-3-.4-.9-.1-1.8-.3-2.8-.4-1-.1-2.1-.3-3.1-.5-.9-.1-1.7-.3-2.6-.4-65.6-10.9-122.5-47.7-160-99.4-.2-.2-.3-.5-.5-.7-.8-1.1-1.6-2.2-2.3-3.3-.3-.4-.6-.8-.8-1.2-.7-1.1-1.4-2.1-2.1-3.2-.3-.5-.6-.9-.9-1.4-.7-1.1-1.4-2.1-2-3.2-.3-.5-.6-.9-.9-1.4-.7-1.1-1.3-2.2-2-3.3-.2-.4-.5-.8-.7-1.2-2.4-4-4.6-8.1-6.8-12.2-.1-.2-.2-.3-.3-.5-.6-1.1-1.1-2.2-1.7-3.3-.3-.6-.6-1.1-.8-1.7-.5-1-1-2.1-1.5-3.1-.3-.7-.6-1.3-.9-2-.5-1-.9-2-1.4-3l-.9-2.1c-.4-1-.9-2-1.3-3-.3-.7-.6-1.5-.9-2.2l-1.2-3c-.3-.8-.6-1.5-.9-2.3-.4-1-.8-2-1.1-3-.3-.9-.6-1.8-1-2.8-.6-1.6-1.1-3.3-1.7-4.9-.3-.9-.6-1.8-.9-2.8-.3-.9-.5-1.8-.8-2.7-.3-.9-.6-1.9-.8-2.8-.3-.9-.5-1.8-.8-2.7-.3-1-.5-1.9-.8-2.9-.2-.9-.5-1.8-.7-2.7-.3-1-.5-2-.7-3-.2-.9-.4-1.7-.6-2.6-.2-1.1-.5-2.2-.7-3.2-.2-.8-.3-1.6-.5-2.4-.3-1.3-.5-2.7-.8-4-.1-.6-.2-1.1-.3-1.7l-.9-5.7c-.1-.6-.2-1.3-.3-1.9-.2-1.3-.4-2.6-.5-3.9-.1-.8-.2-1.5-.3-2.3-.1-1.2-.3-2.4-.4-3.6-.1-.8-.2-1.6-.2-2.4-.1-1.2-.2-2.4-.3-3.5-.1-.8-.1-1.6-.2-2.4-.1-1.2-.2-2.4-.2-3.7 0-.8-.1-1.5-.1-2.3-.1-1.3-.1-2.7-.2-4 0-.7 0-1.3-.1-2 0-2-.1-4-.1-6 0-53.5 16.9-103 45.8-143.6 2.3-3.2 4.7-6.4 7.1-9.5 4.9-6.2 10.1-12.3 15.6-18 2.7-2.9 5.5-5.7 8.4-8.4 2.9-2.7 5.8-5.4 8.8-8 4.5-3.9 9.1-7.6 13.9-11.2 1.6-1.2 3.2-2.4 4.8-3.5C140 34.2 171.7 20.1 206 13c16.1-3.3 32.9-5 50-5s33.8 1.7 50 5c34.3 7 66 21.1 93.6 40.7 1.6 1.2 3.2 2.3 4.8 3.5 4.8 3.6 9.4 7.3 13.9 11.2 12 10.4 23 21.9 32.8 34.4 2.5 3.1 4.8 6.3 7.1 9.5C487.1 153 504 202.5 504 256c0 2 0 4-.1 6 0 .7 0 1.3-.1 2 0 1.3-.1 2.7-.2 4 0 .8-.1 1.5-.1 2.3-.1 1.2-.1 2.4-.2.7-.1.8-.1 1.6-.2 2.4-.1 1.2-.2 2.4-.3 3.5-.1.8-.2 1.6-.2 2.4-.1 1.2-.3 2.4-.4 3.6-.1.8-.2 1.5-.3 2.3-.2 1.3-.4 2.6-.5 3.9-.1.6-.2 1.3-.3 1.9l-.9 5.7c-.1.6-.2 1.1-.3 1.7-.2 1.3-.5 2.7-.8 4-.2.8-.3 1.6-.5 2.4-.2 1.1-.5 2.2-.7 3.2-.2.9-.4 1.7-.6 2.6-.2 1-.5 2-.7 3-.2.9-.5 1.8-.7 2.7-.3 1-.5 1.9-.8 2.9-.2.9-.5 1.8-.8 2.7-.3.9-.6 1.9-.8 2.8-.3.9-.5 1.8-.8 2.7-.3.9-.6 1.8-.9 2.8-.5 1.6-1.1 3.3-1.7 4.9-.3.9-.6 1.8-1 2.8-.4 1-.7 2-1.1 3-.3.8-.6 1.5-.9 2.3l-1.2 3c-.3.7-.6 1.5-.9 2.2-.4 1-.8 2-1.3 3l-.9 2.1c-.4 1-.9 2-1.4 3-.3.7-.6 1.3-.9 2-.5 1-1 2.1-1.5 3.1-.3.6-.6 1.1-.8 1.7-.6 1.1-1.1 2.2-1.7 3.3-.1.2-.2.3-.3.5-2.2 4.1-4.4 8.2-6.8 12.2-.2.4-.5.8-.7 1.2-.7 1.1-1.3 2.2-2 3.3-.3.5-.6.9-.9 1.4-.7 1.1-1.4 2.1-2 3.2-.3.5-.6.9-.9 1.4-.7 1.1-1.4 2.1-2.1 3.2-.3.4-.6.8-.8 1.2-.8 1.1-1.5 2.2-2.3 3.3-.2.2-.3.5-.5.7-37.6 54.7-94.5 91.4-160.1 102.4zm117.3-86.2c13-13 24.2-27.4 33.6-42.9v-71.3c0-2.1-1.6-3.7-3.7-3.7h-22.2c-2.1 0-3.7 1.6-3.7 3.7V326h-29.5V182c0-2.1-1.6-3.7-3.7-3.7h-22.1c-2.1 0-3.7 1.6-3.7 3.7v25.9h-29.5V182c0-2.1-1.6-3.7-3.7-3.7H304c-2.1 0-3.7 1.6-3.7 3.7v25.9h-29.5V182c0-4.8-6.5-3.7-9.5-3.7v-30.7c6.7-1.6 13.8-2.8 20.8-2.8 8.8 0 16.8 3.5 25.4 3.5 3.7 0 22.4-.9 22.4-6.5V93.4c0-2.1-1.6-3.7-3.7-3.7-4.2 0-12.2 3.5-19.4 3.5-7.9 0-16.9-3.5-26.3-3.5-6.5 0-12.9.9-19.2 2.3v-3.9c4.4-2.1 7.4-6.7 7.4-11.5 0-16.8-25.4-16.8-25.4 0 0 4.8 3 9.5 7.4 11.5v90.2c-3 0-9.5-1.1-9.5 3.7v25.9h-29.5V182c0-2.1-1.6-3.7-3.7-3.7h-22.2c-2.1 0-3.7 1.6-3.7 3.7v25.9h-29.5V182c0-2.1-1.6-3.7-3.7-3.7h-22.1c-2.1 0-3.7 1.6-3.7 3.7v144H93.5v-25.8c0-2.1-1.6-3.7-3.7-3.7H67.7c-2.1 0-3.7 1.6-3.7 3.7v71.3c9.4 15.5 20.6 29.9 33.6 42.9 20.6 20.6 44.5 36.7 71.2 48 13.9 5.9 28.2 10.3 42.9 13.2v-75.8c0-58.6 88.6-58.6 88.6 0v75.8c14.7-2.9 29-7.4 42.9-13.2 26.7-11.3 50.6-27.4 71.2-48"],forumbee:[448,512,[],"f211","M5.8 309.7C2 292.7 0 275.5 0 258.3 0 135 99.8 35 223.1 35c16.6 0 33.3 2 49.3 5.5C149 87.5 51.9 186 5.8 309.7zm392.9-189.2C385 103 369 87.8 350.9 75.2c-149.6 44.3-266.3 162.1-309.7 312 12.5 18.1 28 35.6 45.2 49 43.1-151.3 161.2-271.7 312.3-315.7zm15.8 252.7c15.2-25.1 25.4-53.7 29.5-82.8-79.4 42.9-145 110.6-187.6 190.3 30-4.4 58.9-15.3 84.6-31.3 35 13.1 70.9 24.3 107 33.6-9.3-36.5-20.4-74.5-33.5-109.8zm29.7-145.5c-2.6-19.5-7.9-38.7-15.8-56.8C290.5 216.7 182 327.5 137.1 466c18.1 7.6 37 12.5 56.6 15.2C240 367.1 330.5 274.4 444.2 227.7z"],foursquare:[368,512,[],"f180","M323.1 3H49.9C12.4 3 0 31.3 0 49.1v433.8c0 20.3 12.1 27.7 18.2 30.1 6.2 2.5 22.8 4.6 32.9-7.1C180 356.5 182.2 354 182.2 354c3.1-3.4 3.4-3.1 6.8-3.1h83.4c35.1 0 40.6-25.2 44.3-39.7l48.6-243C373.8 25.8 363.1 3 323.1 3zm-16.3 73.8l-11.4 59.7c-1.2 6.5-9.5 13.2-16.9 13.2H172.1c-12 0-20.6 8.3-20.6 20.3v13c0 12 8.6 20.6 20.6 20.6h90.4c8.3 0 16.6 9.2 14.8 18.2-1.8 8.9-10.5 53.8-11.4 58.8-.9 4.9-6.8 13.5-16.9 13.5h-73.5c-13.5 0-17.2 1.8-26.5 12.6 0 0-8.9 11.4-89.5 108.3-.9.9-1.8.6-1.8-.3V75.9c0-7.7 6.8-16.6 16.6-16.6h219c8.2 0 15.6 7.7 13.5 17.5z"],"free-code-camp":[576,512,[],"f2c5","M69.3 144.5c-41 68.5-36.4 163 1 227C92.5 409.7 120 423.9 120 438c0 6.8-6 13-12.8 13C87.7 451 8 375.5 8 253.2c0-111.5 78-186 97.1-186 6 0 14.9 4.8 14.9 11.1 0 12.7-28.3 28.6-50.7 66.2zm195.8 213.8c4.5 1.8 12.3 5.2 12.3-1.2 0-2.7-2.2-2.9-4.3-3.6-8.5-3.4-14-7.7-19.1-15.2-8.2-12.1-10.1-24.2-10.1-38.6 0-32.1 44.2-37.9 44.2-70 0-12.3-7.7-15.9-7.7-19.3 0-2.2.7-2.2 2.9-2.2 8 0 19.1 13.3 22.5 19.8 2.2 4.6 2.4 6 2.4 11.1 0 7-.7 14.2-.7 21.3 0 27 31.9 19.8 31.9 6.8 0-6-3.6-11.6-3.6-17.4 0-.7 0-1.2.7-1.2 3.4 0 9.4 7.7 11.1 10.1 5.8 8.9 8.5 20.8 8.5 31.4 0 32.4-29.5 49-29.5 56 0 1 2.9 7.7 12.1 1.9 29.7-15.1 53.1-47.6 53.1-89.8 0-33.6-8.7-57.7-32.1-82.6-3.9-4.1-16.4-16.9-22.5-16.9-8.2 0 7.2 18.6 7.2 31.2 0 7.2-4.8 12.3-12.3 12.3-11.6 0-14.5-25.4-15.9-33.3-5.8-33.8-12.8-58.2-46.4-74.1-10.4-5-36.5-11.8-36.5-2.2 0 2.4 2.7 4.1 4.6 5.1 9.2 5.6 19.6 21.4 19.6 38.2 0 46.1-57.7 88.2-57.7 136.2-.2 40.3 28.1 72.6 65.3 86.2zM470.4 67c-6 0-14.4 6.5-14.4 12.6 0 8.7 12.1 19.6 17.6 25.4 81.6 85.1 78.6 214.3 17.6 291-7 8.9-35.3 35.3-35.3 43.5 0 5.1 8.2 11.4 13.2 11.4 25.4 0 98.8-80.8 98.8-185.7C568 145.9 491.8 67 470.4 67zm-42.3 323.1H167c-9.4 0-15.5 7.5-15.5 16.4 0 8.5 7 15.5 15.5 15.5h261.1c9.4 0 11.9-7.5 11.9-16.4 0-8.5-3.5-15.5-11.9-15.5z"],freebsd:[448,512,[],"f3a4","M303.7 96.2c11.1-11.1 115.5-77 139.2-53.2 23.7 23.7-42.1 128.1-53.2 139.2-11.1 11.1-39.4.9-63.1-22.9-23.8-23.7-34.1-52-22.9-63.1zM109.9 68.1C73.6 47.5 22 24.6 5.6 41.1c-16.6 16.6 7.1 69.4 27.9 105.7 18.5-32.2 44.8-59.3 76.4-78.7zM406.7 174c3.3 11.3 2.7 20.7-2.7 26.1-20.3 20.3-87.5-27-109.3-70.1-18-32.3-11.1-53.4 14.9-48.7 5.7-3.6 12.3-7.6 19.6-11.6-29.8-15.5-63.6-24.3-99.5-24.3-119.1 0-215.6 96.5-215.6 215.6 0 119 96.5 215.6 215.6 215.6S445.3 380.1 445.3 261c0-38.4-10.1-74.5-27.7-105.8-3.9 7-7.6 13.3-10.9 18.8z"],"get-pocket":[448,512,[],"f265","M407.6 64h-367C18.5 64 0 82.5 0 104.6v135.2C0 364.5 99.7 464 224.2 464c124 0 223.8-99.5 223.8-224.2V104.6c0-22.4-17.7-40.6-40.4-40.6zm-162 268.5c-12.4 11.8-31.4 11.1-42.4 0C89.5 223.6 88.3 227.4 88.3 209.3c0-16.9 13.8-30.7 30.7-30.7 17 0 16.1 3.8 105.2 89.3 90.6-86.9 88.6-89.3 105.5-89.3 16.9 0 30.7 13.8 30.7 30.7 0 17.8-2.9 15.7-114.8 123.2z"],gg:[512,512,[],"f260","M179.2 230.4l102.4 102.4-102.4 102.4L0 256 179.2 76.8l44.8 44.8-25.6 25.6-19.2-19.2-128 128 128 128 51.5-51.5-77.1-76.5 25.6-25.6zM332.8 76.8L230.4 179.2l102.4 102.4 25.6-25.6-77.1-76.5 51.5-51.5 128 128-128 128-19.2-19.2-25.6 25.6 44.8 44.8L512 256 332.8 76.8z"],"gg-circle":[512,512,[],"f261","M257 8C120 8 9 119 9 256s111 248 248 248 248-111 248-248S394 8 257 8zm-49.5 374.8L81.8 257.1l125.7-125.7 35.2 35.4-24.2 24.2-11.1-11.1-77.2 77.2 77.2 77.2 26.6-26.6-53.1-52.9 24.4-24.4 77.2 77.2-75 75.2zm99-2.2l-35.2-35.2 24.1-24.4 11.1 11.1 77.2-77.2-77.2-77.2-26.5 26.5 53.1 52.9-24.4 24.4-77.2-77.2 75-75L432.2 255 306.5 380.6z"],git:[448,512,[],"f1d3","M18.8 221.7c0 25.3 16.2 60 41.5 68.5v1c-18.8 8.3-24 50.6 1 65.8v1C34 367 16 384.3 16 414.2c0 51.5 48.8 65.8 91.5 65.8 52 0 90.7-18.7 90.7-76 0-70.5-101-44.5-101-82.8 0-13.5 7.2-18.7 19.7-21.3 41.5-7.7 67.5-40 67.5-82.2 0-7.3-1.5-14.2-4-21 6.7-1.5 13.2-3.3 19.7-5.5v-50.5c-17.2 6.8-35.7 11.8-54.5 11.8-53.8-31-126.8 1.3-126.8 69.2zm87.7 163.8c17 0 41.2 3 41.2 25 0 21.8-19.5 26.3-37.7 26.3-17.3 0-43.3-2.7-43.3-25.2.1-22.3 22.1-26.1 39.8-26.1zM103.3 256c-22 0-31.3-13-31.3-33.8 0-49.3 61-48.8 61-.5 0 20.3-8 34.3-29.7 34.3zM432 305.5v49c-13.3 7.3-30.5 9.8-45.5 9.8-53.5 0-59.8-42.2-59.8-85.7v-87.7h.5v-1c-7 0-7.3-1.6-24 1v-47.5h24c0-22.3.3-31-1.5-41.2h56.7c-2 13.8-1.5 27.5-1.5 41.2h51v47.5s-19.3-1-51-1V281c0 14.8 3.3 32.8 21.8 32.8 9.8 0 21.3-2.8 29.3-8.3zM286 68.7c0 18.7-14.5 36.2-33.8 36.2-19.8 0-34.5-17.2-34.5-36.2 0-19.3 14.5-36.7 34.5-36.7C272 32 286 50 286 68.7zm-6.2 74.5c-1.8 14.6-1.6 199.8 0 217.8h-55.5c1.6-18.1 1.8-203 0-217.8h55.5z"],"git-square":[448,512,[],"f1d2","M140.1 348.5c12.1 0 29.5 2.1 29.5 17.9 0 15.5-13.9 18.8-27 18.8-12.3 0-30.9-2-30.9-18s15.7-18.7 28.4-18.7zm-24.7-116.6c0 14.8 6.6 24.1 22.3 24.1 15.5 0 21.2-10 21.2-24.5.1-34.4-43.5-34.8-43.5.4zM448 80v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V80c0-26.5 21.5-48 48-48h352c26.5 0 48 21.5 48 48zm-241 93.7c-12.3 4.8-25.5 8.4-38.9 8.4-38.5-22.1-90.7.9-90.7 49.5 0 18 11.6 42.9 29.6 48.9v.7c-13.4 5.9-17.1 36.1.7 47v.7c-19.5 6.4-32.3 18.8-32.3 40.2 0 36.8 34.8 47 65.4 47 37.1 0 64.8-13.4 64.8-54.3 0-50.4-72.1-31.8-72.1-59.1 0-9.6 5.2-13.4 14.1-15.2 29.6-5.5 48.2-28.6 48.2-58.7 0-5.2-1.1-10.2-2.9-15 4.8-1.1 9.5-2.3 14.1-3.9v-36.2zm56.8 1.8h-39.6c1.3 10.6 1.1 142.6 0 155.5h39.6c-1.1-12.8-1.2-145.1 0-155.5zm4.5-53.3c0-13.4-10-26.2-24.1-26.2-14.3 0-24.6 12.5-24.6 26.2 0 13.6 10.5 25.9 24.6 25.9 13.7 0 24.1-12.5 24.1-25.9zm104.3 53.3h-36.4c0-9.8-.4-19.6 1.1-29.5h-40.5c1.3 7.3 1.1 13.6 1.1 29.5h-17.1v33.9c11.9-1.9 12.1-.7 17.1-.7v.7h-.4v62.7c0 31.1 4.5 61.2 42.7 61.2 10.7 0 23-1.8 32.5-7v-35c-5.7 3.9-13.9 5.9-20.9 5.9-13.2 0-15.5-12.9-15.5-23.4v-65.2c22.7 0 36.4.7 36.4.7v-33.8z"],github:[496,512,[],"f09b","M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"],"github-alt":[480,512,[],"f113","M186.1 328.7c0 20.9-10.9 55.1-36.7 55.1s-36.7-34.2-36.7-55.1 10.9-55.1 36.7-55.1 36.7 34.2 36.7 55.1zM480 278.2c0 31.9-3.2 65.7-17.5 95-37.9 76.6-142.1 74.8-216.7 74.8-75.8 0-186.2 2.7-225.6-74.8-14.6-29-20.2-63.1-20.2-95 0-41.9 13.9-81.5 41.5-113.6-5.2-15.8-7.7-32.4-7.7-48.8 0-21.5 4.9-32.3 14.6-51.8 45.3 0 74.3 9 108.8 36 29-6.9 58.8-10 88.7-10 27 0 54.2 2.9 80.4 9.2 34-26.7 63-35.2 107.8-35.2 9.8 19.5 14.6 30.3 14.6 51.8 0 16.4-2.6 32.7-7.7 48.2 27.5 32.4 39 72.3 39 114.2zm-64.3 50.5c0-43.9-26.7-82.6-73.5-82.6-18.9 0-37 3.4-56 6-14.9 2.3-29.8 3.2-45.1 3.2-15.2 0-30.1-.9-45.1-3.2-18.7-2.6-37-6-56-6-46.8 0-73.5 38.7-73.5 82.6 0 87.8 80.4 101.3 150.4 101.3h48.2c70.3 0 150.6-13.4 150.6-101.3zm-82.6-55.1c-25.8 0-36.7 34.2-36.7 55.1s10.9 55.1 36.7 55.1 36.7-34.2 36.7-55.1-10.9-55.1-36.7-55.1z"],"github-square":[448,512,[],"f092","M400 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48zM277.3 415.7c-8.4 1.5-11.5-3.7-11.5-8 0-5.4.2-33 .2-55.3 0-15.6-5.2-25.5-11.3-30.7 37-4.1 76-9.2 76-73.1 0-18.2-6.5-27.3-17.1-39 1.7-4.3 7.4-22-1.7-45-13.9-4.3-45.7 17.9-45.7 17.9-13.2-3.7-27.5-5.6-41.6-5.6-14.1 0-28.4 1.9-41.6 5.6 0 0-31.8-22.2-45.7-17.9-9.1 22.9-3.5 40.6-1.7 45-10.6 11.7-15.6 20.8-15.6 39 0 63.6 37.3 69 74.3 73.1-4.8 4.3-9.1 11.7-10.6 22.3-9.5 4.3-33.8 11.7-48.3-13.9-9.1-15.8-25.5-17.1-25.5-17.1-16.2-.2-1.1 10.2-1.1 10.2 10.8 5 18.4 24.2 18.4 24.2 9.7 29.7 56.1 19.7 56.1 19.7 0 13.9.2 36.5.2 40.6 0 4.3-3 9.5-11.5 8-66-22.1-112.2-84.9-112.2-158.3 0-91.8 70.2-161.5 162-161.5S388 165.6 388 257.4c.1 73.4-44.7 136.3-110.7 158.3zm-98.1-61.1c-1.9.4-3.7-.4-3.9-1.7-.2-1.5 1.1-2.8 3-3.2 1.9-.2 3.7.6 3.9 1.9.3 1.3-1 2.6-3 3zm-9.5-.9c0 1.3-1.5 2.4-3.5 2.4-2.2.2-3.7-.9-3.7-2.4 0-1.3 1.5-2.4 3.5-2.4 1.9-.2 3.7.9 3.7 2.4zm-13.7-1.1c-.4 1.3-2.4 1.9-4.1 1.3-1.9-.4-3.2-1.9-2.8-3.2.4-1.3 2.4-1.9 4.1-1.5 2 .6 3.3 2.1 2.8 3.4zm-12.3-5.4c-.9 1.1-2.8.9-4.3-.6-1.5-1.3-1.9-3.2-.9-4.1.9-1.1 2.8-.9 4.3.6 1.3 1.3 1.8 3.3.9 4.1zm-9.1-9.1c-.9.6-2.6 0-3.7-1.5s-1.1-3.2 0-3.9c1.1-.9 2.8-.2 3.7 1.3 1.1 1.5 1.1 3.3 0 4.1zm-6.5-9.7c-.9.9-2.4.4-3.5-.6-1.1-1.3-1.3-2.8-.4-3.5.9-.9 2.4-.4 3.5.6 1.1 1.3 1.3 2.8.4 3.5zm-6.7-7.4c-.4.9-1.7 1.1-2.8.4-1.3-.6-1.9-1.7-1.5-2.6.4-.6 1.5-.9 2.8-.4 1.3.7 1.9 1.8 1.5 2.6z"],gitkraken:[592,512,[],"f3a6","M565.7 118.1c-2.3-6.1-9.3-9.2-15.3-6.6-5.7 2.4-8.5 8.9-6.3 14.6 10.9 29 16.9 60.5 16.9 93.3 0 134.6-100.3 245.7-230.2 262.7V358.4c7.9-1.5 15.5-3.6 23-6.2v104c106.7-25.9 185.9-122.1 185.9-236.8 0-91.8-50.8-171.8-125.8-213.3-5.7-3.2-13-.9-15.9 5-2.7 5.5-.6 12.2 4.7 15.1 67.9 37.6 113.9 110 113.9 193.2 0 93.3-57.9 173.1-139.8 205.4v-92.2c14.2-4.5 24.9-17.7 24.9-33.5 0-13.1-6.8-24.4-17.3-30.5 8.3-79.5 44.5-58.6 44.5-83.9V170c0-38-87.9-161.8-129-164.7-2.5-.2-5-.2-7.6 0C251.1 8.3 163.2 132 163.2 170v14.8c0 25.3 36.3 4.3 44.5 83.9-10.6 6.1-17.3 17.4-17.3 30.5 0 15.8 10.6 29 24.8 33.5v92.2c-81.9-32.2-139.8-112-139.8-205.4 0-83.1 46-155.5 113.9-193.2 5.4-3 7.4-9.6 4.7-15.1-2.9-5.9-10.1-8.2-15.9-5-75 41.5-125.8 121.5-125.8 213.3 0 114.7 79.2 210.8 185.9 236.8v-104c7.6 2.5 15.1 4.6 23 6.2v123.7C131.4 465.2 31 354.1 31 219.5c0-32.8 6-64.3 16.9-93.3 2.2-5.8-.6-12.2-6.3-14.6-6-2.6-13 .4-15.3 6.6C14.5 149.7 8 183.8 8 219.5c0 155.1 122.6 281.6 276.3 287.8V361.4c6.8.4 15 .5 23.4 0v145.8C461.4 501.1 584 374.6 584 219.5c0-35.7-6.5-69.8-18.3-101.4zM365.9 275.5c13 0 23.7 10.5 23.7 23.7 0 13.1-10.6 23.7-23.7 23.7-13 0-23.7-10.5-23.7-23.7 0-13.1 10.6-23.7 23.7-23.7zm-139.8 47.3c-13.2 0-23.7-10.7-23.7-23.7s10.5-23.7 23.7-23.7c13.1 0 23.7 10.6 23.7 23.7 0 13-10.5 23.7-23.7 23.7z"],gitlab:[512,512,[],"f296","M29.782 199.732L256 493.714 8.074 309.699c-6.856-5.142-9.712-13.996-7.141-21.993l28.849-87.974zm75.405-174.806c-3.142-8.854-15.709-8.854-18.851 0L29.782 199.732h131.961L105.187 24.926zm56.556 174.806L256 493.714l94.257-293.982H161.743zm349.324 87.974l-28.849-87.974L256 493.714l247.926-184.015c6.855-5.142 9.711-13.996 7.141-21.993zm-85.404-262.78c-3.142-8.854-15.709-8.854-18.851 0l-56.555 174.806h131.961L425.663 24.926z"],gitter:[384,512,[],"f426","M66.4 322.5H16V0h50.4v322.5zM166.9 76.1h-50.4V512h50.4V76.1zm100.6 0h-50.4V512h50.4V76.1zM368 76h-50.4v247H368V76z"],glide:[448,512,[],"f2a5","M252.8 148.6c0 8.8-1.6 17.7-3.4 26.4-5.8 27.8-11.6 55.8-17.3 83.6-1.4 6.3-8.3 4.9-13.7 4.9-23.8 0-30.5-26-30.5-45.5 0-29.3 11.2-68.1 38.5-83.1 4.3-2.5 9.2-4.2 14.1-4.2 11.4 0 12.3 8.3 12.3 17.9zM448 80v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V80c0-26.5 21.5-48 48-48h352c26.5 0 48 21.5 48 48zm-64 187c0-5.1-20.8-37.7-25.5-39.5-2.2-.9-7.2-2.3-9.6-2.3-23.1 0-38.7 10.5-58.2 21.5l-.5-.5c4.3-29.4 14.6-57.2 14.6-87.4 0-44.6-23.8-62.7-67.5-62.7-71.7 0-108 70.8-108 123.5 0 54.7 32 85 86.3 85 7.5 0 6.9-.6 6.9 2.3-10.5 80.3-56.5 82.9-56.5 58.9 0-24.4 28-36.5 28.3-38-.2-7.6-29.3-17.2-36.7-17.2-21.1 0-32.7 33-32.7 50.6 0 32.3 20.4 54.7 53.3 54.7 48.2 0 83.4-49.7 94.3-91.7 9.4-37.7 7-39.4 12.3-42.1 20-10.1 35.8-16.8 58.4-16.8 11.1 0 19 2.3 36.7 5.2 1.8.1 4.1-1.7 4.1-3.5z"],"glide-g":[448,512,[],"f2a6","M407.1 211.2c-3.5-1.4-11.6-3.8-15.4-3.8-37.1 0-62.2 16.8-93.5 34.5l-.9-.9c7-47.3 23.5-91.9 23.5-140.4C320.8 29.1 282.6 0 212.4 0 97.3 0 39 113.7 39 198.4 39 286.3 90.3 335 177.6 335c12 0 11-1 11 3.8-16.9 128.9-90.8 133.1-90.8 94.6 0-39.2 45-58.6 45.5-61-.3-12.2-47-27.6-58.9-27.6-33.9.1-52.4 51.2-52.4 79.3C32 476 64.8 512 117.5 512c77.4 0 134-77.8 151.4-145.4 15.1-60.5 11.2-63.3 19.7-67.6 32.2-16.2 57.5-27 93.8-27 17.8 0 30.5 3.7 58.9 8.4 2.9 0 6.7-2.9 6.7-5.8 0-8-33.4-60.5-40.9-63.4zm-175.3-84.4c-9.3 44.7-18.6 89.6-27.8 134.3-2.3 10.2-13.3 7.8-22 7.8-38.3 0-49-41.8-49-73.1 0-47 18-109.3 61.8-133.4 7-4.1 14.8-6.7 22.6-6.7 18.6 0 20 13.3 20 28.7-.1 14.3-2.7 28.5-5.6 42.4z"],gofore:[400,512,[],"f3a7","M324 319.8h-13.2v34.7c-24.5 23.1-56.3 35.8-89.9 35.8-73.2 0-132.4-60.2-132.4-134.4 0-74.1 59.2-134.4 132.4-134.4 35.3 0 68.6 14 93.6 39.4l62.3-63.3C335 55.3 279.7 32 220.7 32 98 32 0 132.6 0 256c0 122.5 97 224 220.7 224 63.2 0 124.5-26.2 171-82.5-2-27.6-13.4-77.7-67.7-77.7zm-12.1-112.5H205.6v89H324c33.5 0 60.5 15.1 76 41.8v-30.6c0-65.2-40.4-100.2-88.1-100.2z"],goodreads:[448,512,[],"f3a8","M299.9 191.2c5.1 37.3-4.7 79-35.9 100.7-22.3 15.5-52.8 14.1-70.8 5.7-37.1-17.3-49.5-58.6-46.8-97.2 4.3-60.9 40.9-87.9 75.3-87.5 46.9-.2 71.8 31.8 78.2 78.3zM448 88v336c0 30.9-25.1 56-56 56H56c-30.9 0-56-25.1-56-56V88c0-30.9 25.1-56 56-56h336c30.9 0 56 25.1 56 56zM330 313.2s-.1-34-.1-217.3h-29v40.3c-.8.3-1.2-.5-1.6-1.2-9.6-20.7-35.9-46.3-76-46-51.9.4-87.2 31.2-100.6 77.8-4.3 14.9-5.8 30.1-5.5 45.6 1.7 77.9 45.1 117.8 112.4 115.2 28.9-1.1 54.5-17 69-45.2.5-1 1.1-1.9 1.7-2.9.2.1.4.1.6.2.3 3.8.2 30.7.1 34.5-.2 14.8-2 29.5-7.2 43.5-7.8 21-22.3 34.7-44.5 39.5-17.8 3.9-35.6 3.8-53.2-1.2-21.5-6.1-36.5-19-41.1-41.8-.3-1.6-1.3-1.3-2.3-1.3h-26.8c.8 10.6 3.2 20.3 8.5 29.2 24.2 40.5 82.7 48.5 128.2 37.4 49.9-12.3 67.3-54.9 67.4-106.3z"],"goodreads-g":[384,512,[],"f3a9","M42.6 403.3h2.8c12.7 0 25.5 0 38.2.1 1.6 0 3.1-.4 3.6 2.1 7.1 34.9 30 54.6 62.9 63.9 26.9 7.6 54.1 7.8 81.3 1.8 33.8-7.4 56-28.3 68-60.4 8-21.5 10.7-43.8 11-66.5.1-5.8.3-47-.2-52.8l-.9-.3c-.8 1.5-1.7 2.9-2.5 4.4-22.1 43.1-61.3 67.4-105.4 69.1-103 4-169.4-57-172-176.2-.5-23.7 1.8-46.9 8.3-69.7C58.3 47.7 112.3.6 191.6 0c61.3-.4 101.5 38.7 116.2 70.3.5 1.1 1.3 2.3 2.4 1.9V10.6h44.3c0 280.3.1 332.2.1 332.2-.1 78.5-26.7 143.7-103 162.2-69.5 16.9-159 4.8-196-57.2-8-13.5-11.8-28.3-13-44.5zM188.9 36.5c-52.5-.5-108.5 40.7-115 133.8-4.1 59 14.8 122.2 71.5 148.6 27.6 12.9 74.3 15 108.3-8.7 47.6-33.2 62.7-97 54.8-154-9.7-71.1-47.8-120-119.6-119.7z"],google:[488,512,[],"f1a0","M488 261.8C488 403.3 391.1 504 248 504 110.8 504 0 393.2 0 256S110.8 8 248 8c66.8 0 123 24.5 166.3 64.9l-67.5 64.9C258.5 52.6 94.3 116.6 94.3 256c0 86.5 69.1 156.6 153.7 156.6 98.2 0 135-70.4 140.8-106.9H248v-85.3h236.1c2.3 12.7 3.9 24.9 3.9 41.4z"],"google-drive":[512,512,[],"f3aa","M339 314.9L175.4 32h161.2l163.6 282.9H339zm-137.5 23.6L120.9 480h310.5L512 338.5H201.5zM154.1 67.4L0 338.5 80.6 480 237 208.8 154.1 67.4z"],"google-play":[512,512,[],"f3ab","M325.3 234.3L104.6 13l280.8 161.2-60.1 60.1zM47 0C34 6.8 25.3 19.2 25.3 35.3v441.3c0 16.1 8.7 28.5 21.7 35.3l256.6-256L47 0zm425.2 225.6l-58.9-34.1-65.7 64.5 65.7 64.5 60.1-34.1c18-14.3 18-46.5-1.2-60.8zM104.6 499l280.8-161.2-60.1-60.1L104.6 499z"],"google-plus":[496,512,[],"f2b3","M248 8C111.1 8 0 119.1 0 256s111.1 248 248 248 248-111.1 248-248S384.9 8 248 8zm-70.7 372c-68.8 0-124-55.5-124-124s55.2-124 124-124c31.3 0 60.1 11 83 32.3l-33.6 32.6c-13.2-12.9-31.3-19.1-49.4-19.1-42.9 0-77.2 35.5-77.2 78.1s34.2 78.1 77.2 78.1c32.6 0 64.9-19.1 70.1-53.3h-70.1v-42.6h116.9c1.3 6.8 1.9 13.6 1.9 20.7 0 70.8-47.5 121.2-118.8 121.2zm230.2-106.2v35.5H372v-35.5h-35.5v-35.5H372v-35.5h35.5v35.5h35.2v35.5h-35.2z"],"google-plus-g":[640,512,[],"f0d5","M386.061 228.496c1.834 9.692 3.143 19.384 3.143 31.956C389.204 370.205 315.599 448 204.8 448c-106.084 0-192-85.915-192-192s85.916-192 192-192c51.864 0 95.083 18.859 128.611 50.292l-52.126 50.03c-14.145-13.621-39.028-29.599-76.485-29.599-65.484 0-118.92 54.221-118.92 121.277 0 67.056 53.436 121.277 118.92 121.277 75.961 0 104.513-54.745 108.965-82.773H204.8v-66.009h181.261zm185.406 6.437V179.2h-56.001v55.733h-55.733v56.001h55.733v55.733h56.001v-55.733H627.2v-56.001h-55.733z"],"google-plus-square":[448,512,[],"f0d4","M400 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48zM164 356c-55.3 0-100-44.7-100-100s44.7-100 100-100c27 0 49.5 9.8 67 26.2l-27.1 26.1c-7.4-7.1-20.3-15.4-39.8-15.4-34.1 0-61.9 28.2-61.9 63.2 0 34.9 27.8 63.2 61.9 63.2 39.6 0 54.4-28.5 56.8-43.1H164v-34.4h94.4c1 5 1.6 10.1 1.6 16.6 0 57.1-38.3 97.6-96 97.6zm220-81.8h-29v29h-29.2v-29h-29V245h29v-29H355v29h29v29.2z"],"google-wallet":[448,512,[],"f1ee","M156.8 126.8c37.6 60.6 64.2 113.1 84.3 162.5-8.3 33.8-18.8 66.5-31.3 98.3-13.2-52.3-26.5-101.3-56-148.5 6.5-36.4 2.3-73.6 3-112.3zM109.3 200H16.1c-6.5 0-10.5 7.5-6.5 12.7C51.8 267 81.3 330.5 101.3 400h103.5c-16.2-69.7-38.7-133.7-82.5-193.5-3-4-8-6.5-13-6.5zm47.8-88c68.5 108 130 234.5 138.2 368H409c-12-138-68.4-265-143.2-368H157.1zm251.8-68.5c-1.8-6.8-8.2-11.5-15.2-11.5h-88.3c-5.3 0-9 5-7.8 10.3 13.2 46.5 22.3 95.5 26.5 146 48.2 86.2 79.7 178.3 90.6 270.8 15.8-60.5 25.3-133.5 25.3-203 0-73.6-12.1-145.1-31.1-212.6z"],gratipay:[496,512,[],"f184","M248 8C111.1 8 0 119.1 0 256s111.1 248 248 248 248-111.1 248-248S384.9 8 248 8zm114.6 226.4l-113 152.7-112.7-152.7c-8.7-11.9-19.1-50.4 13.6-72 28.1-18.1 54.6-4.2 68.5 11.9 15.9 17.9 46.6 16.9 61.7 0 13.9-16.1 40.4-30 68.1-11.9 32.9 21.6 22.6 60 13.8 72z"],grav:[512,512,[],"f2d6","M301.1 212c4.4 4.4 4.4 11.9 0 16.3l-9.7 9.7c-4.4 4.7-11.9 4.7-16.6 0l-10.5-10.5c-4.4-4.7-4.4-11.9 0-16.6l9.7-9.7c4.4-4.4 11.9-4.4 16.6 0l10.5 10.8zm-30.2-19.7c3-3 3-7.8 0-10.5-2.8-3-7.5-3-10.5 0-2.8 2.8-2.8 7.5 0 10.5 3.1 2.8 7.8 2.8 10.5 0zm-26 5.3c-3 2.8-3 7.5 0 10.2 2.8 3 7.5 3 10.5 0 2.8-2.8 2.8-7.5 0-10.2-3-3-7.7-3-10.5 0zm72.5-13.3c-19.9-14.4-33.8-43.2-11.9-68.1 21.6-24.9 40.7-17.2 59.8.8 11.9 11.3 29.3 24.9 17.2 48.2-12.5 23.5-45.1 33.2-65.1 19.1zm47.7-44.5c-8.9-10-23.3 6.9-15.5 16.1 7.4 9 32.1 2.4 15.5-16.1zM504 256c0 137-111 248-248 248S8 393 8 256 119 8 256 8s248 111 248 248zm-66.2 42.6c2.5-16.1-20.2-16.6-25.2-25.7-13.6-24.1-27.7-36.8-54.5-30.4 11.6-8 23.5-6.1 23.5-6.1.3-6.4 0-13-9.4-24.9 3.9-12.5.3-22.4.3-22.4 15.5-8.6 26.8-24.4 29.1-43.2 3.6-31-18.8-59.2-49.8-62.8-22.1-2.5-43.7 7.7-54.3 25.7-23.2 40.1 1.4 70.9 22.4 81.4-14.4-1.4-34.3-11.9-40.1-34.3-6.6-25.7 2.8-49.8 8.9-61.4 0 0-4.4-5.8-8-8.9 0 0-13.8 0-24.6 5.3 11.9-15.2 25.2-14.4 25.2-14.4 0-6.4-.6-14.9-3.6-21.6-5.4-11-23.8-12.9-31.7 2.8.1-.2.3-.4.4-.5-5 11.9-1.1 55.9 16.9 87.2-2.5 1.4-9.1 6.1-13 10-21.6 9.7-56.2 60.3-56.2 60.3-28.2 10.8-77.2 50.9-70.6 79.7.3 3 1.4 5.5 3 7.5-2.8 2.2-5.5 5-8.3 8.3-11.9 13.8-5.3 35.2 17.7 24.4 15.8-7.2 29.6-20.2 36.3-30.4 0 0-5.5-5-16.3-4.4 27.7-6.6 34.3-9.4 46.2-9.1 8 3.9 8-34.3 8-34.3 0-14.7-2.2-31-11.1-41.5 12.5 12.2 29.1 32.7 28 60.6-.8 18.3-15.2 23-15.2 23-9.1 16.6-43.2 65.9-30.4 106 0 0-9.7-14.9-10.2-22.1-17.4 19.4-46.5 52.3-24.6 64.5 26.6 14.7 108.8-88.6 126.2-142.3 34.6-20.8 55.4-47.3 63.9-65 22 43.5 95.3 94.5 101.1 59z"],gripfire:[384,512,[],"f3ac","M171.8 503.8c0-5.3 4.8-12.2 4.8-22.3 0-15.2-13-39.9-78.1-86.6C64.2 365.8 32 336.4 32 286.6 32 171.9 179.1 110.1 179.1 18c0-3.3-.2-6.7-.6-10 5.1 2.4 39.1 43.3 39.1 90.4 0 80.5-105.1 129.2-105.1 203 0 26.9 16.6 47.2 32.6 69.5 22.5 30.2 44.2 56.9 44.2 86.5-.1 14.5-4.4 29.7-17.5 46.4zm146-241.4c1.5 8.4 2.2 16.6 2.2 24.6 0 51.8-29.4 97.5-67.3 136.8-1 1-2.2 2.4-3.2 2.4-3.6 0-35.5-41.6-35.5-53.2 0 0 41.8-55.7 41.8-96.9 0-10.8-2.7-21.7-9.1-33.4-1.5 32.3-55.7 87.7-58.1 87.7-2.7 0-17.9-22-17.9-42.1 0-5.3 1-10.7 3.2-15.8 2.4-5.5 56.6-72 56.6-116.7 0-6.2-1-12-3.4-17.1l-4-7.2c16.7 6.5 82.6 64.1 94.7 130.9"],grunt:[384,512,[],"f3ad","M61.3 189.3c-1.1 10 5.2 19.1 5.2 19.1.7-7.5 2.2-12.8 4-16.6.4 10.3 3.2 23.5 12.8 34.1 6.9 7.6 35.6 23.3 54.9 6.1 1 2.4 2.1 5.3 3 8.5 2.9 10.3-2.7 25.3-2.7 25.3s15.1-17.1 13.9-32.5c10.8-.5 21.4-8.4 21.1-19.5 0 0-18.9 10.4-35.5-8.8-9.7-11.2-40.9-42-83.1-31.8 4.3 1 8.9 2.4 13.5 4.1h-.1c-4.2 2-6.5 7.1-7 12zm28.3-1.8c19.5 11 37.4 25.7 44.9 37-5.7 3.3-21.7 10.4-38-1.7-10.3-7.6-9.8-26.2-6.9-35.3zm79.2 233.7c2.2 2.3 1.5 5.3.9 6.8-1.1 2.7-5.5 11.6-13 19.8-2.7 2.9-6.6 4.6-11 4.6-4.3 0-8.7-1.6-11.8-4.3-2.3-2.1-10.2-9.5-13.7-18.6-1.3-3.4-1-6.1.9-8.1 1.3-1.3 4-2.9 9.5-2.9H160c4.1 0 7 .9 8.8 2.7zm62.9-187.9c-1.2 15.5 13.9 32.5 13.9 32.5s-5.6-15-2.7-25.3c.9-3.2 2-6 3-8.5 19.3 17.3 48 1.5 54.8-6.1 9.6-10.6 12.3-23.8 12.8-34.1 1.8 3.8 3.4 9.1 4 16.6 0 0 6.4-9.1 5.2-19.1-.6-5-2.9-10-7-11.8h-.1c4.6-1.8 9.2-3.2 13.5-4.1-42.3-10.2-73.4 20.6-83.1 31.8-16.7 19.2-35.5 8.8-35.5 8.8-.2 10.9 10.4 18.9 21.2 19.3zm17.8-8.8c7.5-11.4 25.4-26 44.9-37 3 9.1 3.4 27.7-7 35.4-16.3 12.1-32.2 5-37.9 1.6-.1.1 0 0 0 0zM263 421.4c1.9 1.9 2.2 4.6.9 7.9-3.5 8.9-11.4 16.1-13.7 18.1-3.1 2.6-7.4 4.2-11.8 4.2s-8.3-1.6-11-4.5c-7.5-8-12-16.7-13-19.3-.6-1.5-1.3-4.4.9-6.7 1.7-1.8 4.7-2.7 8.9-2.7h29.4c5.4.1 8.1 1.7 9.4 3zm-98.3-251.5c9.9 6 18.8 8.1 27.3 8.3 8.5-.2 17.4-2.3 27.3-8.3 0 0-14.5 17.7-27.2 17.8h-.2c-12.7-.2-27.2-17.8-27.2-17.8zm184.5 147.4c-2.4 17.9-13 33.8-24.6 43.7-3.1-22.7-3.7-55.5-3.7-62.4 0-14.7 9.5-24.5 12.2-26.1 2.5-1.5 5.4-3 8.3-4.6 18-9.6 40.4-21.6 40.4-43.7 0-16.2-9.3-23.2-15.4-27.8-.8-.6-1.5-1.1-2.2-1.7-2.1-1.7-3.7-3-4.3-4.4-4.4-9.8-3.6-34.2-1.7-37.6.6-.6 16.7-20.9 11.8-39.2-2-7.4-6.9-13.3-14.1-17-5.3-2.7-11.9-4.2-19.5-4.5-.1-2-.5-3.9-.9-5.9-.6-2.6-1.1-5.3-.9-8.1.4-4.7.8-9 2.2-11.3 8.4-13.3 28.8-17.6 29-17.6l12.3-2.4-8.1-9.5c-.1-.2-17.3-17.5-46.3-17.5-7.9 0-16 1.3-24.1 3.9-24.2 7.8-42.9 30.5-49.4 39.3-3.1-1-6.3-1.9-9.6-2.7-4.2-15.8 9-38.5 9-38.5s-13.6-3-33.7 15.2c-2.6-6.5-8.1-20.5-1.8-37.2C184.6 10.1 177.2 26 175 40.4c-7.6-5.4-6.7-23.1-7.2-27.6-7.5.9-29.2 21.9-28.2 48.3-2 .5-3.9 1.1-5.9 1.7-6.5-8.8-25.1-31.5-49.4-39.3-7.9-2.2-16-3.5-23.9-3.5-29 0-46.1 17.3-46.3 17.5L6 46.9l12.3 2.4c.2 0 20.6 4.3 29 17.6 1.4 2.2 1.8 6.6 2.2 11.3.2 2.8-.4 5.5-.9 8.1-.4 1.9-.8 3.9-.9 5.9-7.7.3-14.2 1.8-19.5 4.5-7.2 3.7-12.1 9.6-14.1 17-5 18.2 11.2 38.5 11.8 39.2 1.9 3.4 2.7 27.8-1.7 37.6-.6 1.4-2.2 2.7-4.3 4.4-.7.5-1.4 1.1-2.2 1.7-6.1 4.6-15.4 11.7-15.4 27.8 0 22.1 22.4 34.1 40.4 43.7 3 1.6 5.8 3.1 8.3 4.6 2.7 1.6 12.2 11.4 12.2 26.1 0 6.9-.6 39.7-3.7 62.4-11.6-9.9-22.2-25.9-24.6-43.8 0 0-29.2 22.6-20.6 70.8 5.2 29.5 23.2 46.1 47 54.7 8.8 19.1 29.4 45.7 67.3 49.6C143 504.3 163 512 192.2 512h.2c29.1 0 49.1-7.7 63.6-19.5 37.9-3.9 58.5-30.5 67.3-49.6 23.8-8.7 41.7-25.2 47-54.7 8.2-48.4-21.1-70.9-21.1-70.9zM305.7 37.7c5.6-1.8 11.6-2.7 17.7-2.7 11 0 19.9 3 24.7 5-3.1 1.4-6.4 3.2-9.7 5.3-2.4-.4-5.6-.8-9.2-.8-10.5 0-20.5 3.1-28.7 8.9-12.3 8.7-18 16.9-20.7 22.4-2.2-1.3-4.5-2.5-7.1-3.7-1.6-.8-3.1-1.5-4.7-2.2 6.1-9.1 19.9-26.5 37.7-32.2zm21 18.2c-.8 1-1.6 2.1-2.3 3.2-3.3 5.2-3.9 11.6-4.4 17.8-.5 6.4-1.1 12.5-4.4 17-4.2.8-8.1 1.7-11.5 2.7-2.3-3.1-5.6-7-10.5-11.2 1.4-4.8 5.5-16.1 13.5-22.5 5.6-4.3 12.2-6.7 19.6-7zM45.6 45.3c-3.3-2.2-6.6-4-9.7-5.3 4.8-2 13.7-5 24.7-5 6.1 0 12 .9 17.7 2.7 17.8 5.8 31.6 23.2 37.7 32.1-1.6.7-3.2 1.4-4.8 2.2-2.5 1.2-4.9 2.5-7.1 3.7-2.6-5.4-8.3-13.7-20.7-22.4-8.3-5.8-18.2-8.9-28.8-8.9-3.4.1-6.6.5-9 .9zm44.7 40.1c-4.9 4.2-8.3 8-10.5 11.2-3.4-.9-7.3-1.9-11.5-2.7C65 89.5 64.5 83.4 64 77c-.5-6.2-1.1-12.6-4.4-17.8-.7-1.1-1.5-2.2-2.3-3.2 7.4.3 14 2.6 19.5 7 8 6.3 12.1 17.6 13.5 22.4zM58.1 259.9c-2.7-1.6-5.6-3.1-8.4-4.6-14.9-8-30.2-16.3-30.2-30.5 0-11.1 4.3-14.6 8.9-18.2l.5-.4c.7-.6 1.4-1.2 2.2-1.8-.9 7.2-1.9 13.3-2.7 14.9 0 0 12.1-15 15.7-44.3 1.4-11.5-1.1-34.3-5.1-43 .2 4.9 0 9.8-.3 14.4-.4-.8-.8-1.6-1.3-2.2-3.2-4-11.8-17.5-9.4-26.6.9-3.5 3.1-6 6.7-7.8 3.8-1.9 8.8-2.9 15.1-2.9 12.3 0 25.9 3.7 32.9 6 25.1 8 55.4 30.9 64.1 37.7.2.2.4.3.4.3l5.6 3.9-3.5-5.8c-.2-.3-19.1-31.4-53.2-46.5 2-2.9 7.4-8.1 21.6-15.1 21.4-10.5 46.5-15.8 74.3-15.8 27.9 0 52.9 5.3 74.3 15.8 14.2 6.9 19.6 12.2 21.6 15.1-34 15.1-52.9 46.2-53.1 46.5l-3.5 5.8 5.6-3.9s.2-.1.4-.3c8.7-6.8 39-29.8 64.1-37.7 7-2.2 20.6-6 32.9-6 6.3 0 11.3 1 15.1 2.9 3.5 1.8 5.7 4.4 6.7 7.8 2.5 9.1-6.1 22.6-9.4 26.6-.5.6-.9 1.3-1.3 2.2-.3-4.6-.5-9.5-.3-14.4-4 8.8-6.5 31.5-5.1 43 3.6 29.3 15.7 44.3 15.7 44.3-.8-1.6-1.8-7.7-2.7-14.9.7.6 1.5 1.2 2.2 1.8l.5.4c4.6 3.7 8.9 7.1 8.9 18.2 0 14.2-15.4 22.5-30.2 30.5-2.9 1.5-5.7 3.1-8.4 4.6-8.7 5-18 16.7-19.1 34.2-.9 14.6.9 49.9 3.4 75.9-12.4 4.8-26.7 6.4-39.7 6.8-2-4.1-3.9-8.5-5.5-13.1-.7-2-19.6-51.1-26.4-62.2 5.5 39 17.5 73.7 23.5 89.6-3.5-.5-7.3-.7-11.7-.7h-117c-4.4 0-8.3.3-11.7.7 6-15.9 18.1-50.6 23.5-89.6-6.8 11.2-25.7 60.3-26.4 62.2-1.6 4.6-3.5 9-5.5 13.1-13-.4-27.2-2-39.7-6.8 2.5-26 4.3-61.2 3.4-75.9-.9-17.4-10.3-29.2-19-34.2zM34.8 404.6c-12.1-20-8.7-54.1-3.7-59.1 10.9 34.4 47.2 44.3 74.4 45.4-2.7 4.2-5.2 7.6-7 10l-1.4 1.4c-7.2 7.8-8.6 18.5-4.1 31.8-22.7-.1-46.3-9.8-58.2-29.5zm45.7 43.5c6 1.1 12.2 1.9 18.6 2.4 3.5 8 7.4 15.9 12.3 23.1-14.4-5.9-24.4-16-30.9-25.5zM192 498.2c-60.6-.1-78.3-45.8-84.9-64.7-3.7-10.5-3.4-18.2.9-23.1 2.9-3.3 9.5-7.2 24.6-7.2h118.8c15.1 0 21.8 3.9 24.6 7.2 4.2 4.8 4.5 12.6.9 23.1-6.6 18.8-24.3 64.6-84.9 64.7zm80.6-24.6c4.9-7.2 8.8-15.1 12.3-23.1 6.4-.5 12.6-1.3 18.6-2.4-6.5 9.5-16.5 19.6-30.9 25.5zm76.6-69c-12 19.7-35.6 29.3-58.1 29.7 4.5-13.3 3.1-24.1-4.1-31.8-.4-.5-.9-1-1.4-1.5-1.8-2.4-4.3-5.8-7-10 27.2-1.2 63.5-11 74.4-45.4 5 5 8.4 39.1-3.8 59z"],gulp:[256,512,[],"f3ae","M209.8 391.1l-14.1 24.6-4.6 80.2c0 8.9-28.3 16.1-63.1 16.1s-63.1-7.2-63.1-16.1l-5.8-79.4-14.9-25.4c41.2 17.3 126 16.7 165.6 0zm-196-253.3l13.6 125.5c5.9-20 20.8-47 40-55.2 6.3-2.7 12.7-2.7 18.7.9 5.2 3 9.6 9.3 10.1 11.8 1.2 6.5-2 9.1-4.5 9.1-3 0-5.3-4.6-6.8-7.3-4.1-7.3-10.3-7.6-16.9-2.8-6.9 5-12.9 13.4-17.1 20.7-5.1 8.8-9.4 18.5-12 28.2-1.5 5.6-2.9 14.6-.6 19.9 1 2.2 2.5 3.6 4.9 3.6 5 0 12.3-6.6 15.8-10.1 4.5-4.5 10.3-11.5 12.5-16l5.2-15.5c2.6-6.8 9.9-5.6 9.9 0 0 10.2-3.7 13.6-10 34.7-5.8 19.5-7.6 25.8-7.6 25.8-.7 2.8-3.4 7.5-6.3 7.5-1.2 0-2.1-.4-2.6-1.2-1-1.4-.9-5.3-.8-6.3.2-3.2 6.3-22.2 7.3-25.2-2 2.2-4.1 4.4-6.4 6.6-5.4 5.1-14.1 11.8-21.5 11.8-3.4 0-5.6-.9-7.7-2.4l7.6 79.6c2 5 39.2 17.1 88.2 17.1 49.1 0 86.3-12.2 88.2-17.1l10.9-94.6c-5.7 5.2-12.3 11.6-19.6 14.8-5.4 2.3-17.4 3.8-17.4-5.7 0-5.2 9.1-14.8 14.4-21.5 1.4-1.7 4.7-5.9 4.7-8.1 0-2.9-6-2.2-11.7 2.5-3.2 2.7-6.2 6.3-8.7 9.7-4.3 6-6.6 11.2-8.5 15.5-6.2 14.2-4.1 8.6-9.1 22-5 13.3-4.2 11.8-5.2 14-.9 1.9-2.2 3.5-4 4.5-1.9 1-4.5.9-6.1-.3-.9-.6-1.3-1.9-1.3-3.7 0-.9.1-1.8.3-2.7 1.5-6.1 7.8-18.1 15-34.3 1.6-3.7 1-2.6.8-2.3-6.2 6-10.9 8.9-14.4 10.5-5.8 2.6-13 2.6-14.5-4.1-.1-.4-.1-.8-.2-1.2-11.8 9.2-24.3 11.7-20-8.1-4.6 8.2-12.6 14.9-22.4 14.9-4.1 0-7.1-1.4-8.6-5.1-2.3-5.5 1.3-14.9 4.6-23.8 1.7-4.5 4-9.9 7.1-16.2 1.6-3.4 4.2-5.4 7.6-4.5.6.2 1.1.4 1.6.7 2.6 1.8 1.6 4.5.3 7.2-3.8 7.5-7.1 13-9.3 20.8-.9 3.3-2 9 1.5 9 2.4 0 4.7-.8 6.9-2.4 4.6-3.4 8.3-8.5 11.1-13.5 2-3.6 4.4-8.3 5.6-12.3.5-1.7 1.1-3.3 1.8-4.8 1.1-2.5 2.6-5.1 5.2-5.1 1.3 0 2.4.5 3.2 1.5 1.7 2.2 1.3 4.5.4 6.9-2 5.6-4.7 10.6-6.9 16.7-1.3 3.5-2.7 8-2.7 11.7 0 3.4 3.7 2.6 6.8 1.2 2.4-1.1 4.8-2.8 6.8-4.5 1.2-4.9.9-3.8 26.4-68.2 1.3-3.3 3.7-4.7 6.1-4.7 1.2 0 2.2.4 3.2 1.1 1.7 1.3 1.7 4.1 1 6.2-.7 1.9-.6 1.3-4.5 10.5-5.2 12.1-8.6 20.8-13.2 31.9-1.9 4.6-7.7 18.9-8.7 22.3-.6 2.2-1.3 5.8 1 5.8 5.4 0 19.3-13.1 23.1-17 .2-.3.5-.4.9-.6.6-1.9 1.2-3.7 1.7-5.5 1.4-3.8 2.7-8.2 5.3-11.3.8-1 1.7-1.6 2.7-1.6 2.8 0 4.2 1.2 4.2 4 0 1.1-.7 5.1-1.1 6.2 1.4-1.5 2.9-3 4.5-4.5 15-13.9 25.7-6.8 25.7.2 0 7.4-8.9 17.7-13.8 23.4-1.6 1.9-4.9 5.4-5 6.4 0 1.3.9 1.8 2.2 1.8 2 0 6.4-3.5 8-4.7 5-3.9 11.8-9.9 16.6-14.1l14.8-136.8c-30.5 17.1-197.6 17.2-228.3.2zm229.7-8.5c0 21-231.2 21-231.2 0 0-8.8 51.8-15.9 115.6-15.9 9 0 17.8.1 26.3.4l12.6-48.7L228.1.6c1.4-1.4 5.8-.2 9.9 3.5s6.6 7.9 5.3 9.3l-.1.1L185.9 74l-10 40.7c39.9 2.6 67.6 8.1 67.6 14.6zm-69.4 4.6c0-.8-.9-1.5-2.5-2.1l-.2.8c0 1.3-5 2.4-11.1 2.4s-11.1-1.1-11.1-2.4c0-.1 0-.2.1-.3l.2-.7c-1.8.6-3 1.4-3 2.3 0 2.1 6.2 3.7 13.7 3.7 7.7.1 13.9-1.6 13.9-3.7z"],"hacker-news":[448,512,[],"f1d4","M0 32v448h448V32H0zm21.2 197.2H21c.1-.1.2-.3.3-.4 0 .1 0 .3-.1.4zm218 53.9V384h-31.4V281.3L128 128h37.3c52.5 98.3 49.2 101.2 59.3 125.6 12.3-27 5.8-24.4 60.6-125.6H320l-80.8 155.1z"],"hacker-news-square":[448,512,[],"f3af","M400 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48zM21.2 229.2H21c.1-.1.2-.3.3-.4 0 .1 0 .3-.1.4zm218 53.9V384h-31.4V281.3L128 128h37.3c52.5 98.3 49.2 101.2 59.3 125.6 12.3-27 5.8-24.4 60.6-125.6H320l-80.8 155.1z"],"hire-a-helper":[512,512,[],"f3b0","M443.1 0H71.9C67.9 37.3 37.4 67.8 0 71.7v371.5c37.4 4.9 66 32.4 71.9 68.8h372.2c3-36.4 32.5-65.8 67.9-69.8V71.7c-36.4-5.9-65-35.3-68.9-71.7zm-37 404.9c-36.3 0-18.8-2-55.1-2-35.8 0-21 2-56.1 2-5.9 0-4.9-8.2 0-9.8 22.8-7.6 22.9-10.2 24.6-12.8 10.4-15.6 5.9-83 5.9-113 0-5.3-6.4-12.8-13.8-12.8H200.4c-7.4 0-13.8 7.5-13.8 12.8 0 30-4.5 97.4 5.9 113 1.7 2.5 1.8 5.2 24.6 12.8 4.9 1.6 6 9.8 0 9.8-35.1 0-20.3-2-56.1-2-36.3 0-18.8 2-55.1 2-7.9 0-5.8-10.8 0-10.8 10.2-3.4 13.5-3.5 21.7-13.8 7.7-12.9 7.9-44.4 7.9-127.8V151.3c0-22.2-12.2-28.3-28.6-32.4-8.8-2.2-4-11.8 1-11.8 36.5 0 20.6 2 57.1 2 32.7 0 16.5-2 49.2-2 3.3 0 8.5 8.3 1 10.8-4.9 1.6-27.6 3.7-27.6 39.3 0 45.6-.2 55.8 1 68.8 0 1.3 2.3 12.8 12.8 12.8h109.2c10.5 0 12.8-11.5 12.8-12.8 1.2-13 1-23.2 1-68.8 0-35.6-22.7-37.7-27.6-39.3-7.5-2.5-2.3-10.8 1-10.8 32.7 0 16.5 2 49.2 2 36.5 0 20.6-2 57.1-2 4.9 0 9.9 9.6 1 11.8-16.4 4.1-28.6 10.3-28.6 32.4v101.2c0 83.4.1 114.9 7.9 127.8 8.2 10.2 11.4 10.4 21.7 13.8 5.8 0 7.8 10.8 0 10.8z"],hooli:[640,512,[],"f427","M508.4 352h57.9V156.7L508.4 184v168zm73.7-110.5V352H640V241.5h-57.9zm-250.7-8.9c-18.2-18.2-50.4-17.1-50.4-17.1s-32.2-1.1-50.4 17.1c-1.9 1.9-3.7 3.9-5.3 6-38.2-29.6-72.5-46.5-102.1-61.1v-20.7l-22.5 10.6c-54.4-22.1-89-18.2-97.3.1 0 0-24.9 32.8 61.9 110.9v-31c-48.8-54.6-39-76.1-35.3-79.2 13.5-11.4 37.5-8 64.4 2.1L65.2 184v63.3c13.1 14.7 30.5 31.5 53.5 50.4l4.5 3.6v-29.8c0-6.9 1.7-18.2 10.8-18.2s10.6 6.9 10.6 15V317c18 12.2 37.3 22.1 57.7 29.6v-93.9c0-18.7-13.4-37.4-40.6-37.4-15.8-.1-30.5 8.2-38.5 21.9v-54.3c41.9 20.9 83.9 46.5 99.9 58.3-10.2 14.6-9.3 28.1-9.3 43.7 0 18.7-1.4 34.3 16.8 52.5 18.2 18.2 50.4 17.1 50.4 17.1s32.3 1.1 50.4-17.1c18.2-18.2 16.7-33.8 16.7-52.5 0-18.5 1.5-34.2-16.7-52.3zm-39.7 71.9c0 3.6-1.8 12.5-10.7 12.5-8.9 0-10.7-8.9-10.7-12.5v-40.4c0-8.7 7.3-10.9 10.7-10.9 3.4 0 10.7 2.1 10.7 10.9v40.4zm185.7-71.9c-18.2-18.2-50.4-17.1-50.4-17.1s-32.3-1.1-50.4 17.1c-18.2 18.2-16.8 33.9-16.8 52.6 0 18.7-1.4 34.3 16.8 52.5 18.2 18.2 50.4 17.1 50.4 17.1s32.3 1.1 50.4-17.1c18.2-18.2 16.8-33.8 16.8-52.5-.1-18.8 1.3-34.5-16.8-52.6zm-39.8 71.9c0 3.6-1.8 12.5-10.7 12.5-8.9 0-10.7-8.9-10.7-12.5v-40.4c0-8.7 7.3-10.9 10.7-10.9 3.4 0 10.7 2.1 10.7 10.9v40.4zm173.5-73c15.9 0 28.9-12.9 28.9-28.9s-12.9-24.5-28.9-24.5c-15.9 0-28.9 8.6-28.9 24.5s12.9 28.9 28.9 28.9zM144.5 352l38.3.8c-13.2-4.6-26-10.2-38.3-16.8v16zm-21.4 0v-28.6c-6.5-4.2-13-8.7-19.4-13.6-14.8-11.2-27.5-21.7-38.5-31.5V352h57.9zm59.7.8c36.5 12.5 69.9 14.2 94.7 7.2-19.9.2-45.8-2.6-75.3-13.3v5.3l-19.4.8z"],hotjar:[448,512,[],"f3b1","M414.9 161.5C340.2 29 121.1 0 121.1 0S222.2 110.4 93 197.7C11.3 252.8-21 324.4 14 402.6c26.8 59.9 83.5 84.3 144.6 93.4-29.2-55.1-6.6-122.4-4.1-129.6 57.1 86.4 165 0 110.8-93.9 71 15.4 81.6 138.6 27.1 215.5 80.5-25.3 134.1-88.9 148.8-145.6 15.5-59.3 3.7-127.9-26.3-180.9z"],houzz:[320,512,[],"f27c","M12.2 256L160 341.1 12.2 426.6V256M160 512l147.8-85.4V256L160 341.1V512zm0-512L12.2 85.4V256L160 170.6V0zm0 170.6L307.8 256V85.4L160 170.6z"],html5:[384,512,[],"f13b","M0 32l34.9 395.8L191.5 480l157.6-52.2L384 32H0zm308.2 127.9H124.4l4.1 49.4h175.6l-13.6 148.4-97.9 27v.3h-1.1l-98.7-27.3-6-75.8h47.7L138 320l53.5 14.5 53.7-14.5 6-62.2H84.3L71.5 112.2h241.1l-4.4 47.7z"],hubspot:[512,512,[],"f3b2","M267.4 211.6c-25.1 23.7-40.8 57.3-40.8 94.6 0 29.3 9.7 56.3 26 78L203.1 434c-4.4-1.6-9.1-2.5-14-2.5-10.8 0-20.9 4.2-28.5 11.8-7.6 7.6-11.8 17.8-11.8 28.6s4.2 20.9 11.8 28.5c7.6 7.6 17.8 11.6 28.5 11.6 10.8 0 20.9-3.9 28.6-11.6 7.6-7.6 11.8-17.8 11.8-28.5 0-4.2-.6-8.2-1.9-12.1l50-50.2c22 16.9 49.4 26.9 79.3 26.9 71.9 0 130-58.3 130-130.2 0-65.2-47.7-119.2-110.2-128.7V116c17.5-7.4 28.2-23.8 28.2-42.9 0-26.1-20.9-47.9-47-47.9S311.2 47 311.2 73.1c0 19.1 10.7 35.5 28.2 42.9v61.2c-15.2 2.1-29.6 6.7-42.7 13.6-27.6-20.9-117.5-85.7-168.9-124.8 1.2-4.4 2-9 2-13.8C129.8 23.4 106.3 0 77.4 0 48.6 0 25.2 23.4 25.2 52.2c0 28.9 23.4 52.3 52.2 52.3 9.8 0 18.9-2.9 26.8-7.6l163.2 114.7zm89.5 163.6c-38.1 0-69-30.9-69-69s30.9-69 69-69 69 30.9 69 69-30.9 69-69 69z"],imdb:[448,512,[],"f2d8","M350.5 288.7c0 5.4 1.6 14.4-6.2 14.4-1.6 0-3-.8-3.8-2.4-2.2-5.1-1.1-44.1-1.1-44.7 0-3.8-1.1-12.7 4.9-12.7 7.3 0 6.2 7.3 6.2 12.7v32.7zM265 229.9c0-9.7 1.6-16-10.3-16v83.7c12.2.3 10.3-8.7 10.3-18.4v-49.3zM448 80v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V80c0-26.5 21.5-48 48-48h352c26.5 0 48 21.5 48 48zM21.3 228.8c-.1.1-.2.3-.3.4h.3v-.4zM97 192H64v127.8h33V192zm113.3 0h-43.1l-7.6 59.9c-2.7-20-5.4-40.1-8.7-59.9h-42.8v127.8h29v-84.5l12.2 84.5h20.6l11.6-86.4v86.4h28.7V192zm86.3 45.3c0-8.1.3-16.8-1.4-24.4-4.3-22.5-31.4-20.9-49-20.9h-24.6v127.8c86.1.1 75 6 75-82.5zm85.9 17.3c0-17.3-.8-30.1-22.2-30.1-8.9 0-14.9 2.7-20.9 9.2V192h-31.7v127.8h29.8l1.9-8.1c5.7 6.8 11.9 9.8 20.9 9.8 19.8 0 22.2-15.2 22.2-30.9v-36z"],instagram:[448,512,[],"f16d","M224.1 141c-63.6 0-114.9 51.3-114.9 114.9s51.3 114.9 114.9 114.9S339 319.5 339 255.9 287.7 141 224.1 141zm0 189.6c-41.1 0-74.7-33.5-74.7-74.7s33.5-74.7 74.7-74.7 74.7 33.5 74.7 74.7-33.6 74.7-74.7 74.7zm146.4-194.3c0 14.9-12 26.8-26.8 26.8-14.9 0-26.8-12-26.8-26.8s12-26.8 26.8-26.8 26.8 12 26.8 26.8zm76.1 27.2c-1.7-35.9-9.9-67.7-36.2-93.9-26.2-26.2-58-34.4-93.9-36.2-37-2.1-147.9-2.1-184.9 0-35.8 1.7-67.6 9.9-93.9 36.1s-34.4 58-36.2 93.9c-2.1 37-2.1 147.9 0 184.9 1.7 35.9 9.9 67.7 36.2 93.9s58 34.4 93.9 36.2c37 2.1 147.9 2.1 184.9 0 35.9-1.7 67.7-9.9 93.9-36.2 26.2-26.2 34.4-58 36.2-93.9 2.1-37 2.1-147.8 0-184.8zM398.8 388c-7.8 19.6-22.9 34.7-42.6 42.6-29.5 11.7-99.5 9-132.1 9s-102.7 2.6-132.1-9c-19.6-7.8-34.7-22.9-42.6-42.6-11.7-29.5-9-99.5-9-132.1s-2.6-102.7 9-132.1c7.8-19.6 22.9-34.7 42.6-42.6 29.5-11.7 99.5-9 132.1-9s102.7-2.6 132.1 9c19.6 7.8 34.7 22.9 42.6 42.6 11.7 29.5 9 99.5 9 132.1s2.7 102.7-9 132.1z"],"internet-explorer":[512,512,[],"f26b","M483.049 159.706c10.855-24.575 21.424-60.438 21.424-87.871 0-72.722-79.641-98.371-209.673-38.577-107.632-7.181-211.221 73.67-237.098 186.457 30.852-34.862 78.271-82.298 121.977-101.158C125.404 166.85 79.128 228.002 43.992 291.725 23.246 329.651 0 390.94 0 436.747c0 98.575 92.854 86.5 180.251 42.006 31.423 15.43 66.559 15.573 101.695 15.573 97.124 0 184.249-54.294 216.814-146.022H377.927c-52.509 88.593-196.819 52.996-196.819-47.436H509.9c6.407-43.581-1.655-95.715-26.851-141.162zM64.559 346.877c17.711 51.15 53.703 95.871 100.266 123.304-88.741 48.94-173.267 29.096-100.266-123.304zm115.977-108.873c2-55.151 50.276-94.871 103.98-94.871 53.418 0 101.981 39.72 103.981 94.871H180.536zm184.536-187.6c21.425-10.287 48.563-22.003 72.558-22.003 31.422 0 54.274 21.717 54.274 53.722 0 20.003-7.427 49.007-14.569 67.867-26.28-42.292-65.986-81.584-112.263-99.586z"],ioxhost:[640,512,[],"f208","M616 160h-67.3C511.2 70.7 422.9 8 320 8 183 8 72 119 72 256c0 16.4 1.6 32.5 4.7 48H24c-13.3 0-24 10.8-24 24 0 13.3 10.7 24 24 24h67.3c37.5 89.3 125.8 152 228.7 152 137 0 248-111 248-248 0-16.4-1.6-32.5-4.7-48H616c13.3 0 24-10.8 24-24 0-13.3-10.7-24-24-24zm-96 96c0 110.5-89.5 200-200 200-75.7 0-141.6-42-175.5-104H424c13.3 0 24-10.8 24-24 0-13.3-10.7-24-24-24H125.8c-3.8-15.4-5.8-31.4-5.8-48 0-110.5 89.5-200 200-200 75.7 0 141.6 42 175.5 104H216c-13.3 0-24 10.8-24 24 0 13.3 10.7 24 24 24h298.2c3.8 15.4 5.8 31.4 5.8 48zm-304-24h208c13.3 0 24 10.7 24 24 0 13.2-10.7 24-24 24H216c-13.3 0-24-10.7-24-24 0-13.2 10.7-24 24-24z"],itunes:[448,512,[],"f3b4","M223.6 80.3C129 80.3 52.5 157 52.5 251.5S129 422.8 223.6 422.8s171.2-76.7 171.2-171.2c0-94.6-76.7-171.3-171.2-171.3zm79.4 240c-3.2 13.6-13.5 21.2-27.3 23.8-12.1 2.2-22.2 2.8-31.9-5-11.8-10-12-26.4-1.4-36.8 8.4-8 20.3-9.6 38-12.8 3-.5 5.6-1.2 7.7-3.7 3.2-3.6 2.2-2 2.2-80.8 0-5.6-2.7-7.1-8.4-6.1-4 .7-91.9 17.1-91.9 17.1-5 1.1-6.7 2.6-6.7 8.3 0 116.1.5 110.8-1.2 118.5-2.1 9-7.6 15.8-14.9 19.6-8.3 4.6-23.4 6.6-31.4 5.2-21.4-4-28.9-28.7-14.4-42.9 8.4-8 20.3-9.6 38-12.8 3-.5 5.6-1.2 7.7-3.7 5-5.7.9-127 2.6-133.7.4-2.6 1.5-4.8 3.5-6.4 2.1-1.7 5.8-2.7 6.7-2.7 101-19 113.3-21.4 115.1-21.4 5.7-.4 9 3 9 8.7-.1 170.6.4 161.4-1 167.6zM345.2 32H102.8C45.9 32 0 77.9 0 134.8v242.4C0 434.1 45.9 480 102.8 480h242.4c57 0 102.8-45.9 102.8-102.8V134.8C448 77.9 402.1 32 345.2 32zM223.6 444c-106.3 0-192.5-86.2-192.5-192.5S117.3 59 223.6 59s192.5 86.2 192.5 192.5S329.9 444 223.6 444z"],"itunes-note":[384,512,[],"f3b5","M381.9 388.2c-6.4 27.4-27.2 42.8-55.1 48-24.5 4.5-44.9 5.6-64.5-10.2-23.9-20.1-24.2-53.4-2.7-74.4 17-16.2 40.9-19.5 76.8-25.8 6-1.1 11.2-2.5 15.6-7.4 6.4-7.2 4.4-4.1 4.4-163.2 0-11.2-5.5-14.3-17-12.3-8.2 1.4-185.7 34.6-185.7 34.6-10.2 2.2-13.4 5.2-13.4 16.7 0 234.7 1.1 223.9-2.5 239.5-4.2 18.2-15.4 31.9-30.2 39.5-16.8 9.3-47.2 13.4-63.4 10.4-43.2-8.1-58.4-58-29.1-86.6 17-16.2 40.9-19.5 76.8-25.8 6-1.1 11.2-2.5 15.6-7.4 10.1-11.5 1.8-256.6 5.2-270.2.8-5.2 3-9.6 7.1-12.9 4.2-3.5 11.8-5.5 13.4-5.5 204-38.2 228.9-43.1 232.4-43.1 11.5-.8 18.1 6 18.1 17.6.2 344.5 1.1 326-1.8 338.5z"],jenkins:[512,512,[],"f3b6","M487.1 425c-1.4-11.2-19-23.1-28.2-31.9-5.1-5-29-23.1-30.4-29.9-1.4-6.6 9.7-21.5 13.3-28.9 5.1-10.7 8.8-23.7 11.3-32.6 18.8-66.1 20.7-156.9-6.2-211.2-10.2-20.6-38.6-49-56.4-62.5-42-31.7-119.6-35.3-170.1-16.6-14.1 5.2-27.8 9.8-40.1 17.1-33.1 19.4-68.3 32.5-78.1 71.6-24.2 10.8-31.5 41.8-30.3 77.8.2 7 4.1 15.8 2.7 22.4-.7 3.3-5.2 7.6-6.1 9.8-11.6 27.7-2.3 64 11.1 83.7 8.1 11.9 21.5 22.4 39.2 25.2.7 10.6 3.3 19.7 8.2 30.4 3.1 6.8 14.7 19 10.4 27.7-2.2 4.4-21 13.8-27.3 17.6C89 407.2 73.7 415 54.2 429c-12.6 9-32.3 10.2-29.2 31.1 2.1 14.1 10.1 31.6 14.7 45.8.7 2 1.4 4.1 2.1 6h422c4.9-15.3 9.7-30.9 14.6-47.2 3.4-11.4 10.2-27.8 8.7-39.7zM205.9 33.7c1.8-.5 3.4.7 4.9 2.4-.2 5.2-5.4 5.1-8.9 6.8-5.4 6.7-13.4 9.8-20 17.2-6.8 7.5-14.4 27.7-23.4 30-4.5 1.1-9.7-.8-13.6-.5-10.4.7-17.7 6-28.3 7.5 13.6-29.9 56.1-54 89.3-63.4zm-104.8 93.6c13.5-14.9 32.1-24.1 54.8-25.9 11.7 29.7-8.4 65-.9 97.6 2.3 9.9 10.2 25.4-2.4 25.7.3-28.3-34.8-46.3-61.3-29.6-1.8-21.5-4.9-51.7 9.8-67.8zm36.7 200.2c-1-4.1-2.7-12.9-2.3-15.1 1.6-8.7 17.1-12.5 11-24.7-11.3-.1-13.8 10.2-24.1 11.3-26.7 2.6-45.6-35.4-44.4-58.4 1-19.5 17.6-38.2 40.1-35.8 16 1.8 21.4 19.2 24.5 34.7 9.2.5 22.5-.4 26.9-7.6-.6-17.5-8.8-31.6-8.2-47.7 1-30.3 17.5-57.6 4.8-87.4 13.6-30.9 53.5-55.3 83.1-70 36.6-18.3 94.9-3.7 129.3 15.8 19.7 11.1 34.4 32.7 48.3 50.7-19.5-5.8-36.1 4.2-33.1 20.3 16.3-14.9 44.2-.2 52.5 16.4 7.9 15.8 7.8 39.3 9 62.8 2.9 57-10.4 115.9-39.1 157.1-7.7 11-14.1 23-24.9 30.6-26 18.2-65.4 34.7-99.2 23.4-44.7-15-65-44.8-89.5-78.8.7 18.7 13.8 34.1 26.8 48.4 11.3 12.5 25 26.6 39.7 32.4-12.3-2.9-31.1-3.8-36.2 7.2-28.6-1.9-55.1-4.8-68.7-24.2-10.6-15.4-21.4-41.4-26.3-61.4zm222 124.1c4.1-3 11.1-2.9 17.4-3.6-5.4-2.7-13-3.7-19.3-2.2-.1-4.2-2-6.8-3.2-10.2 10.6-3.8 35.5-28.5 49.6-20.3 6.7 3.9 9.5 26.2 10.1 37 .4 9-.8 18-4.5 22.8-18.8-.6-35.8-2.8-50.7-7 .9-6.1-1-12.1.6-16.5zm-17.2-20c-16.8.8-26-1.2-38.3-10.8.2-.8 1.4-.5 1.5-1.4 18 8 40.8-3.3 59-4.9-7.9 5.1-14.6 11.6-22.2 17.1zm-12.1 33.2c-1.6-9.4-3.5-12-2.8-20.2 25-16.6 29.7 28.6 2.8 20.2zM226 438.6c-11.6-.7-48.1-14-38.5-23.7 9.4 6.5 27.5 4.9 41.3 7.3.8 4.4-2.8 10.2-2.8 16.4zM57.7 497.1c-4.3-12.7-9.2-25.1-14.8-36.9 30.8-23.8 65.3-48.9 102.2-63.5 2.8-1.1 23.2 25.4 26.2 27.6 16.5 11.7 37 21 56.2 30.2 1.2 8.8 3.9 20.2 8.7 35.5.7 2.3 1.4 4.7 2.2 7.2H57.7zm240.6 5.7h-.8c.3-.2.5-.4.8-.5v.5zm7.5-5.7c2.1-1.4 4.3-2.8 6.4-4.3 1.1 1.4 2.2 2.8 3.2 4.3h-9.6zm15.1-24.7c-10.8 7.3-20.6 18.3-33.3 25.2-6 3.3-27 11.7-33.4 10.2-3.6-.8-3.9-5.3-5.4-9.5-3.1-9-10.1-23.4-10.8-37-.8-17.2-2.5-46 16-42.4 14.9 2.9 32.3 9.7 43.9 16.1 7.1 3.9 11.1 8.6 21.9 9.5-.1 1.4-.1 2.8-.2 4.3-5.9 3.9-15.3 3.8-21.8 7.1 9.5.4 17 2.7 23.5 5.9-.1 3.4-.3 7-.4 10.6zm53.4 24.7h-14c-.1-3.2-2.8-5.8-6.1-5.8s-5.9 2.6-6.1 5.8h-17.4c-2.8-4.4-5.7-8.6-8.9-12.5 2.1-2.2 4-4.7 6-6.9 9 3.7 14.8-4.9 21.7-4.2 7.9.8 14.2 11.7 25.4 11l-.6 12.6zm8.7 0c.2-4 .4-7.8.6-11.5 15.6-7.3 29 1.3 35.7 11.5H383zm83.4-37c-2.3 11.2-5.8 24-9.9 37.1-.2-.1-.4-.1-.6-.1H428c.6-1.1 1.2-2.2 1.9-3.3-2.6-6.1-9-8.7-10.9-15.5 12.1-22.7 6.5-93.4-24.2-78.5 4.3-6.3 15.6-11.5 20.8-19.3 13 10.4 20.8 20.3 33.2 31.4 6.8 6 20 13.3 21.4 23.1.8 5.5-2.6 18.9-3.8 25.1zM222.2 130.5c5.4-14.9 27.2-34.7 45-32 7.7 1.2 18 8.2 12.2 17.7-30.2-7-45.2 12.6-54.4 33.1-8.1-2-4.9-13.1-2.8-18.8zm184.1 63.1c8.2-3.6 22.4-.7 29.6-5.3-4.2-11.5-10.3-21.4-9.3-37.7.5 0 1 0 1.4.1 6.8 14.2 12.7 29.2 21.4 41.7-5.7 13.5-43.6 25.4-43.1 1.2zm20.4-43zm-117.2 45.7c-6.8-10.9-19-32.5-14.5-45.3 6.5 11.9 8.6 24.4 17.8 33.3 4.1 4 12.2 9 8.2 20.2-.9 2.7-7.8 8.6-11.7 9.7-14.4 4.3-47.9.9-36.6-17.1 11.9.7 27.9 7.8 36.8-.8zm27.3 70c3.8 6.6 1.4 18.7 12.1 20.6 20.2 3.4 43.6-12.3 58.1-17.8 9-15.2-.8-20.7-8.9-30.5-16.6-20-38.8-44.8-38-74.7 6.7-4.9 7.3 7.4 8.2 9.7 8.7 20.3 30.4 46.2 46.3 63.5 3.9 4.3 10.3 8.4 11 11.2 2.1 8.2-5.4 18-4.5 23.5-21.7 13.9-45.8 29.1-81.4 25.6-7.4-6.7-10.3-21.4-2.9-31.1zm-201.3-9.2c-6.8-3.9-8.4-21-16.4-21.4-11.4-.7-9.3 22.2-9.3 35.5-7.8-7.1-9.2-29.1-3.5-40.3-6.6-3.2-9.5 3.6-13.1 5.9 4.7-34.1 49.8-15.8 42.3 20.3zm299.6 28.8c-10.1 19.2-24.4 40.4-54 41-.6-6.2-1.1-15.6 0-19.4 22.7-2.2 36.6-13.7 54-21.6zm-141.9 12.4c18.9 9.9 53.6 11 79.3 10.2 1.4 5.6 1.3 12.6 1.4 19.4-33 1.8-72-6.4-80.7-29.6zm92.2 46.7c-1.7 4.3-5.3 9.3-9.8 11.1-12.1 4.9-45.6 8.7-62.4-.3-10.7-5.7-17.5-18.5-23.4-26-2.8-3.6-16.9-12.9-.2-12.9 13.1 32.7 58 29 95.8 28.1z"],joget:[496,512,[],"f3b7","M227.5 468.7c-9-13.6-19.9-33.3-23.7-42.4-5.7-13.7-27.2-45.6 31.2-67.1 51.7-19.1 176.7-16.5 208.8-17.6-4 9-8.6 17.9-13.9 26.6-40.4 65.5-110.4 101.5-182 101.5-6.8 0-13.6-.4-20.4-1M66.1 143.9C128 43.4 259.6 12.2 360.1 74.1c74.8 46.1 111.2 130.9 99.3 212.7-24.9-.5-179.3-3.6-230.3-4.9-55.5-1.4-81.7-20.8-58.5-48.2 23.2-27.4 51.1-40.7 68.9-51.2 17.9-10.5 27.3-33.7-23.6-29.7C87.3 161.5 48.6 252.1 37.6 293c-8.8-49.7-.1-102.7 28.5-149.1m-29.2-18c-71.9 116.6-35.6 269.3 81 341.2 116.6 71.9 269.3 35.6 341.2-80.9 71.9-116.6 35.6-269.4-81-341.2-40.5-25.1-85.5-37-129.9-37C165 8 83.8 49.9 36.9 125.9m244.4 110.4c-31.5 20.5-65.3 31.3-65.3 31.3l169.5-1.6 46.5-23.4s3.6-9.5-19.1-15.5c-22.7-6-57 11.3-86.7 27.2-29.7 15.8-31.1 8.2-31.1 8.2s40.2-28.1 50.7-34.5c10.5-6.4 31.9-14 13.4-24.6-3.2-1.8-6.7-2.7-10.4-2.7-17.8 0-41.5 18.7-67.5 35.6"],joomla:[448,512,[],"f1aa","M.6 92.1C.6 58.8 27.4 32 60.4 32c30 0 54.5 21.9 59.2 50.2 32.6-7.6 67.1.6 96.5 30l-44.3 44.3c-20.5-20.5-42.6-16.3-55.4-3.5-14.3 14.3-14.3 37.9 0 52.2l99.5 99.5-44 44.3c-87.7-87.2-49.7-49.7-99.8-99.7-26.8-26.5-35-64.8-24.8-98.9C20.4 144.6.6 120.7.6 92.1zm129.5 116.4l44.3 44.3c10-10 89.7-89.7 99.7-99.8 14.3-14.3 37.6-14.3 51.9 0 12.8 12.8 17 35-3.5 55.4l44 44.3c31.2-31.2 38.5-67.6 28.9-101.2 29.2-4.1 51.9-29.2 51.9-59.5 0-33.2-26.8-60.1-59.8-60.1-30.3 0-55.4 22.5-59.5 51.6-33.8-9.9-71.7-1.5-98.3 25.1-18.3 19.1-71.1 71.5-99.6 99.9zm266.3 152.2c8.2-32.7-.9-68.5-26.3-93.9-11.8-12.2 5 4.7-99.5-99.7l-44.3 44.3 99.7 99.7c14.3 14.3 14.3 37.6 0 51.9-12.8 12.8-35 17-55.4-3.5l-44 44.3c27.6 30.2 68 38.8 102.7 28 5.5 27.4 29.7 48.1 58.9 48.1 33 0 59.8-26.8 59.8-60.1 0-30.2-22.5-55-51.6-59.1zm-84.3-53.1l-44-44.3c-87 86.4-50.4 50.4-99.7 99.8-14.3 14.3-37.6 14.3-51.9 0-13.1-13.4-16.9-35.3 3.2-55.4l-44-44.3c-30.2 30.2-38 65.2-29.5 98.3-26.7 6-46.2 29.9-46.2 58.2C0 453.2 26.8 480 59.8 480c28.6 0 52.5-19.8 58.6-46.7 32.7 8.2 68.5-.6 94.2-26 32.1-32 12.2-12.4 99.5-99.7z"],js:[448,512,[],"f3b8","M0 32v448h448V32H0zm243.8 349.4c0 43.6-25.6 63.5-62.9 63.5-33.7 0-53.2-17.4-63.2-38.5l34.3-20.7c6.6 11.7 12.6 21.6 27.1 21.6 13.8 0 22.6-5.4 22.6-26.5V237.7h42.1v143.7zm99.6 63.5c-39.1 0-64.4-18.6-76.7-43l34.3-19.8c9 14.7 20.8 25.6 41.5 25.6 17.4 0 28.6-8.7 28.6-20.8 0-14.4-11.4-19.5-30.7-28l-10.5-4.5c-30.4-12.9-50.5-29.2-50.5-63.5 0-31.6 24.1-55.6 61.6-55.6 26.8 0 46 9.3 59.8 33.7L368 290c-7.2-12.9-15-18-27.1-18-12.3 0-20.1 7.8-20.1 18 0 12.6 7.8 17.7 25.9 25.6l10.5 4.5c35.8 15.3 55.9 31 55.9 66.2 0 37.8-29.8 58.6-69.7 58.6z"],"js-square":[512,512,[],"f3b9","M432 32H80c-26.5 0-48 21.5-48 48v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48zM275.8 381.4c0 43.6-25.6 63.5-62.9 63.5-33.7 0-53.2-17.4-63.2-38.5l34.3-20.7c6.6 11.7 12.6 21.6 27.1 21.6 13.8 0 22.6-5.4 22.6-26.5V237.7h42.1v143.7zm99.6 63.5c-39.1 0-64.4-18.6-76.7-43l34.3-19.8c9 14.7 20.8 25.6 41.5 25.6 17.4 0 28.6-8.7 28.6-20.8 0-14.4-11.4-19.5-30.7-28l-10.5-4.5c-30.4-12.9-50.5-29.2-50.5-63.5 0-31.6 24.1-55.6 61.6-55.6 26.8 0 46 9.3 59.8 33.7L400 290c-7.2-12.9-15-18-27.1-18-12.3 0-20.1 7.8-20.1 18 0 12.6 7.8 17.7 25.9 25.6l10.5 4.5c35.8 15.3 55.9 31 55.9 66.2 0 37.8-29.8 58.6-69.7 58.6z"],jsfiddle:[576,512,[],"f1cc","M510.634 237.462c-4.727-2.621-5.664-5.748-6.381-10.776-2.352-16.488-3.539-33.619-9.097-49.095-35.895-99.957-153.99-143.386-246.849-91.646-27.37 15.25-48.971 36.369-65.493 63.903-3.184-1.508-5.458-2.71-7.824-3.686-30.102-12.421-59.049-10.121-85.331 9.167-25.531 18.737-36.422 44.548-32.676 76.408.355 3.025-1.967 7.621-4.514 9.545-39.712 29.992-56.031 78.065-41.902 124.615 13.831 45.569 57.514 79.796 105.608 81.433 30.291 1.031 60.637.546 90.959.539 84.041-.021 168.09.531 252.12-.48 52.664-.634 96.108-36.873 108.212-87.293 11.54-48.074-11.144-97.3-56.832-122.634zm21.107 156.88c-18.23 22.432-42.343 35.253-71.28 35.65-56.874.781-113.767.23-170.652.23 0 .7-163.028.159-163.728.154-43.861-.332-76.739-19.766-95.175-59.995-18.902-41.245-4.004-90.848 34.186-116.106 9.182-6.073 12.505-11.566 10.096-23.136-5.49-26.361 4.453-47.956 26.42-62.981 22.987-15.723 47.422-16.146 72.034-3.083 10.269 5.45 14.607 11.564 22.198-2.527 14.222-26.399 34.557-46.727 60.671-61.294 97.46-54.366 228.37 7.568 230.24 132.697.122 8.15 2.412 12.428 9.848 15.894 57.56 26.829 74.456 96.122 35.142 144.497zm-87.789-80.499c-5.848 31.157-34.622 55.096-66.666 55.095-16.953-.001-32.058-6.545-44.079-17.705-27.697-25.713-71.141-74.98-95.937-93.387-20.056-14.888-41.99-12.333-60.272 3.782-49.996 44.071 15.859 121.775 67.063 77.188 4.548-3.96 7.84-9.543 12.744-12.844 8.184-5.509 20.766-.884 13.168 10.622-17.358 26.284-49.33 38.197-78.863 29.301-28.897-8.704-48.84-35.968-48.626-70.179 1.225-22.485 12.364-43.06 35.414-55.965 22.575-12.638 46.369-13.146 66.991 2.474C295.68 280.7 320.467 323.97 352.185 343.47c24.558 15.099 54.254 7.363 68.823-17.506 28.83-49.209-34.592-105.016-78.868-63.46-3.989 3.744-6.917 8.932-11.41 11.72-10.975 6.811-17.333-4.113-12.809-10.353 20.703-28.554 50.464-40.44 83.271-28.214 31.429 11.714 49.108 44.366 42.76 78.186z"],keycdn:[512,512,[],"f3ba","M63.8 409.3l60.5-59c32.1 42.8 71.1 66 126.6 67.4 30.5.7 60.3-7 86.4-22.4 5.1 5.3 18.5 19.5 20.9 22-32.2 20.7-69.6 31.1-108.1 30.2-43.3-1.1-84.6-16.7-117.7-44.4.3-.6-38.2 37.5-38.6 37.9 9.5 29.8-13.1 62.4-46.3 62.4C20.7 503.3 0 481.7 0 454.9c0-34.3 33.1-56.6 63.8-45.6zm354.9-252.4c19.1 31.3 29.6 67.4 28.7 104-1.1 44.8-19 87.5-48.6 121 .3.3 23.8 25.2 24.1 25.5 9.6-1.3 19.2 2 25.9 9.1 11.3 12 10.9 30.9-1.1 42.4-12 11.3-30.9 10.9-42.4-1.1-6.7-7-9.4-16.8-7.6-26.3-24.9-26.6-44.4-47.2-44.4-47.2 42.7-34.1 63.3-79.6 64.4-124.2.7-28.9-7.2-57.2-21.1-82.2l22.1-21zM104 53.1c6.7 7 9.4 16.8 7.6 26.3l45.9 48.1c-4.7 3.8-13.3 10.4-22.8 21.3-25.4 28.5-39.6 64.8-40.7 102.9-.7 28.9 6.1 57.2 20 82.4l-22 21.5C72.7 324 63.1 287.9 64.2 250.9c1-44.6 18.3-87.6 47.5-121.1l-25.3-26.4c-9.6 1.3-19.2-2-25.9-9.1-11.3-12-10.9-30.9 1.1-42.4C73.5 40.7 92.2 41 104 53.1zM464.9 8c26 0 47.1 22.4 47.1 48.3S490.9 104 464.9 104c-6.3.1-14-1.1-15.9-1.8l-62.9 59.7c-32.7-43.6-76.7-65.9-126.9-67.2-30.5-.7-60.3 6.8-86.2 22.4l-21.1-22C184.1 74.3 221.5 64 260 64.9c43.3 1.1 84.6 16.7 117.7 44.6l41.1-38.6c-1.5-4.7-2.2-9.6-2.2-14.5C416.5 29.7 438.9 8 464.9 8zM256.7 113.4c5.5 0 10.9.4 16.4 1.1 78.1 9.8 133.4 81.1 123.8 159.1-9.8 78.1-81.1 133.4-159.1 123.8-78.1-9.8-133.4-81.1-123.8-159.2 9.3-72.4 70.1-124.6 142.7-124.8zm-59 119.4c.6 22.7 12.2 41.8 32.4 52.2l-11 51.7h73.7l-11-51.7c20.1-10.9 32.1-29 32.4-52.2-.4-32.8-25.8-57.5-58.3-58.3-32.1.8-57.3 24.8-58.2 58.3zM256 160"],kickstarter:[448,512,[],"f3bb","M400 480H48c-26.4 0-48-21.6-48-48V80c0-26.4 21.6-48 48-48h352c26.4 0 48 21.6 48 48v352c0 26.4-21.6 48-48 48zM199.6 178.5c0-30.7-17.6-45.1-39.7-45.1-25.8 0-40 19.8-40 44.5v154.8c0 25.8 13.7 45.6 40.5 45.6 21.5 0 39.2-14 39.2-45.6v-41.8l60.6 75.7c12.3 14.9 39 16.8 55.8 0 14.6-15.1 14.8-36.8 4-50.4l-49.1-62.8 40.5-58.7c9.4-13.5 9.5-34.5-5.6-49.1-16.4-15.9-44.6-17.3-61.4 7l-44.8 64.7v-38.8z"],"kickstarter-k":[384,512,[],"f3bc","M147.3 114.4c0-56.2-32.5-82.4-73.4-82.4C26.2 32 0 68.2 0 113.4v283c0 47.3 25.3 83.4 74.9 83.4 39.8 0 72.4-25.6 72.4-83.4v-76.5l112.1 138.3c22.7 27.2 72.1 30.7 103.2 0 27-27.6 27.3-67.4 7.4-92.2l-90.8-114.8 74.9-107.4c17.4-24.7 17.5-63.1-10.4-89.8-30.3-29-82.4-31.6-113.6 12.8L147.3 185v-70.6z"],laravel:[640,512,[],"f3bd","M637.5 204.7c-4.2-4.8-62.8-78.1-73.1-90.5-10.3-12.4-15.4-10.2-21.7-9.3s-80.5 13.4-89.1 14.8c-8.6 1.5-14 4.9-8.7 12.3 4.7 6.6 53.4 75.7 64.2 90.9l-193.7 46.4L161.2 11.7C155.1 2.6 153.8-.6 139.8.1 125.9.7 19 9.6 11.4 10.2c-7.6.6-16 4-8.4 22s129 279.6 132.4 287.2c3.4 7.6 12.2 20 32.8 15 21.1-5.1 94.3-24.2 134.3-34.7 21.1 38.3 64.2 115.9 72.2 127 10.6 14.9 18 12.4 34.3 7.4 12.8-3.9 199.6-71.1 208-74.5 8.4-3.5 13.6-5.9 7.9-14.4-4.2-6.2-53.5-72.2-79.3-106.8 17.7-4.7 80.6-21.4 87.3-23.3 7.8-1.8 8.9-5.7 4.6-10.4zm-352.2 72c-2.3.5-110.8 26.5-116.6 27.8-5.8 1.3-5.8.7-6.5-1.3-.7-2-129-266.7-130.8-270-1.8-3.3-1.7-5.9 0-5.9s102.5-9 106-9.2c3.6-.2 3.2.6 4.5 2.8 0 0 142.2 245.4 144.6 249.7 2.6 4.3 1.1 5.6-1.2 6.1zm306 57.3c1.7 2.7 3.5 4.5-2 6.4-5.4 2-183.7 62.1-187.1 63.6-3.5 1.5-6.2 2-10.6-4.5-4.5-6.4-62.4-106.8-62.4-106.8l188.8-49c4.7-1.5 6.2-2.5 9.2 2.2 2.9 4.7 62.4 85.4 64.1 88.1zm12.1-134.1c-4.2.9-73.6 18.1-73.6 18.1l-56.7-77.8c-1.6-2.2-2.9-4.5 1.1-5s68.4-12.2 71.3-12.8c2.9-.7 5.4-1.5 9 3.4 3.6 4.9 52.6 67 54.5 69.4 1.8 2.3-1.4 3.8-5.6 4.7z"],lastfm:[512,512,[],"f202","M225.8 367.1l-18.8-51s-30.5 34-76.2 34c-40.5 0-69.2-35.2-69.2-91.5 0-72.1 36.4-97.9 72.1-97.9 66.5 0 74.8 53.3 100.9 134.9 18.8 56.9 54 102.6 155.4 102.6 72.7 0 122-22.3 122-80.9 0-72.9-62.7-80.6-115-92.1-25.8-5.9-33.4-16.4-33.4-34 0-19.9 15.8-31.7 41.6-31.7 28.2 0 43.4 10.6 45.7 35.8l58.6-7c-4.7-52.8-41.1-74.5-100.9-74.5-52.8 0-104.4 19.9-104.4 83.9 0 39.9 19.4 65.1 68 76.8 44.9 10.6 79.8 13.8 79.8 45.7 0 21.7-21.1 30.5-61 30.5-59.2 0-83.9-31.1-97.9-73.9-32-96.8-43.6-163-161.3-163C45.7 113.8 0 168.3 0 261c0 89.1 45.7 137.2 127.9 137.2 66.2 0 97.9-31.1 97.9-31.1z"],"lastfm-square":[448,512,[],"f203","M400 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48zm-92.2 312.9c-63.4 0-85.4-28.6-97.1-64.1-16.3-51-21.5-84.3-63-84.3-22.4 0-45.1 16.1-45.1 61.2 0 35.2 18 57.2 43.3 57.2 28.6 0 47.6-21.3 47.6-21.3l11.7 31.9s-19.8 19.4-61.2 19.4c-51.3 0-79.9-30.1-79.9-85.8 0-57.9 28.6-92 82.5-92 73.5 0 80.8 41.4 100.8 101.9 8.8 26.8 24.2 46.2 61.2 46.2 24.9 0 38.1-5.5 38.1-19.1 0-19.9-21.8-22-49.9-28.6-30.4-7.3-42.5-23.1-42.5-48 0-40 32.3-52.4 65.2-52.4 37.4 0 60.1 13.6 63 46.6l-36.7 4.4c-1.5-15.8-11-22.4-28.6-22.4-16.1 0-26 7.3-26 19.8 0 11 4.8 17.6 20.9 21.3 32.7 7.1 71.8 12 71.8 57.5.1 36.7-30.7 50.6-76.1 50.6z"],leanpub:[576,512,[],"f212","M386.539 111.485l15.096 248.955-10.979-.275c-36.232-.824-71.64 8.783-102.657 27.997-31.016-19.214-66.424-27.997-102.657-27.997-45.564 0-82.07 10.705-123.516 27.723L93.117 129.6c28.546-11.803 61.484-18.115 92.226-18.115 41.173 0 73.836 13.175 102.657 42.544 27.723-28.271 59.013-41.721 98.539-42.544zM569.07 448c-25.526 0-47.485-5.215-70.542-15.645-34.31-15.645-69.993-24.978-107.871-24.978-38.977 0-74.934 12.901-102.657 40.623-27.723-27.723-63.68-40.623-102.657-40.623-37.878 0-73.561 9.333-107.871 24.978C55.239 442.236 32.731 448 8.303 448H6.93L49.475 98.859C88.726 76.626 136.486 64 181.775 64 218.83 64 256.984 71.685 288 93.095 319.016 71.685 357.17 64 394.225 64c45.289 0 93.049 12.626 132.3 34.859L569.07 448zm-43.368-44.741l-34.036-280.246c-30.742-13.999-67.248-21.41-101.009-21.41-38.428 0-74.385 12.077-102.657 38.702-28.272-26.625-64.228-38.702-102.657-38.702-33.761 0-70.267 7.411-101.009 21.41L50.298 403.259c47.211-19.487 82.894-33.486 135.045-33.486 37.604 0 70.817 9.606 102.657 29.644 31.84-20.038 65.052-29.644 102.657-29.644 52.151 0 87.834 13.999 135.045 33.486z"],less:[640,512,[],"f41d","M612.7 219c0-20.5 3.2-32.6 3.2-54.6 0-34.2-12.6-45.2-40.5-45.2h-20.5v24.2h6.3c14.2 0 17.3 4.7 17.3 22.1 0 16.3-1.6 32.6-1.6 51.5 0 24.2 7.9 33.6 23.6 37.3v1.6c-15.8 3.7-23.6 13.1-23.6 37.3 0 18.9 1.6 34.2 1.6 51.5 0 17.9-3.7 22.6-17.3 22.6v.5h-6.3V393h20.5c27.8 0 40.5-11 40.5-45.2 0-22.6-3.2-34.2-3.2-54.6 0-11 6.8-22.6 27.3-23.6v-27.3c-20.5-.7-27.3-12.3-27.3-23.3zm-105.6 32c-15.8-6.3-30.5-10-30.5-20.5 0-7.9 6.3-12.6 17.9-12.6s22.1 4.7 33.6 13.1l21-27.8c-13.1-10-31-20.5-55.2-20.5-35.7 0-59.9 20.5-59.9 49.4 0 25.7 22.6 38.9 41.5 46.2 16.3 6.3 32.1 11.6 32.1 22.1 0 7.9-6.3 13.1-20.5 13.1-13.1 0-26.3-5.3-40.5-16.3l-21 30.5c15.8 13.1 39.9 22.1 59.9 22.1 42 0 64.6-22.1 64.6-51s-22.5-41-43-47.8zm-358.9 59.4c-3.7 0-8.4-3.2-8.4-13.1V119.1H65.2c-28.4 0-41 11-41 45.2 0 22.6 3.2 35.2 3.2 54.6 0 11-6.8 22.6-27.3 23.6v27.3c20.5.5 27.3 12.1 27.3 23.1 0 19.4-3.2 31-3.2 53.6 0 34.2 12.6 45.2 40.5 45.2h20.5v-24.2h-6.3c-13.1 0-17.3-5.3-17.3-22.6s1.6-32.1 1.6-51.5c0-24.2-7.9-33.6-23.6-37.3v-1.6c15.8-3.7 23.6-13.1 23.6-37.3 0-18.9-1.6-34.2-1.6-51.5s3.7-22.1 17.3-22.1H93v150.8c0 32.1 11 53.1 43.1 53.1 10 0 17.9-1.6 23.6-3.7l-5.3-34.2c-3.1.8-4.6.8-6.2.8zM379.9 251c-16.3-6.3-31-10-31-20.5 0-7.9 6.3-12.6 17.9-12.6 11.6 0 22.1 4.7 33.6 13.1l21-27.8c-13.1-10-31-20.5-55.2-20.5-35.7 0-59.9 20.5-59.9 49.4 0 25.7 22.6 38.9 41.5 46.2 16.3 6.3 32.1 11.6 32.1 22.1 0 7.9-6.3 13.1-20.5 13.1-13.1 0-26.3-5.3-40.5-16.3l-20.5 30.5c15.8 13.1 39.9 22.1 59.9 22.1 42 0 64.6-22.1 64.6-51 .1-28.9-22.5-41-43-47.8zm-155-68.8c-38.4 0-75.1 32.1-74.1 82.5 0 52 34.2 82.5 79.3 82.5 18.9 0 39.9-6.8 56.2-17.9l-15.8-27.8c-11.6 6.8-22.6 10-34.2 10-21 0-37.3-10-41.5-34.2H290c.5-3.7 1.6-11 1.6-19.4.6-42.6-22.6-75.7-66.7-75.7zm-30 66.2c3.2-21 15.8-31 30.5-31 18.9 0 26.3 13.1 26.3 31h-56.8z"],line:[448,512,[],"f3c0","M272.1 204.2v71.1c0 1.8-1.4 3.2-3.2 3.2h-11.4c-1.1 0-2.1-.6-2.6-1.3l-32.6-44v42.2c0 1.8-1.4 3.2-3.2 3.2h-11.4c-1.8 0-3.2-1.4-3.2-3.2v-71.1c0-1.8 1.4-3.2 3.2-3.2H219c1 0 2.1.5 2.6 1.4l32.6 44v-42.2c0-1.8 1.4-3.2 3.2-3.2h11.4c1.8-.1 3.3 1.4 3.3 3.1zm-82-3.2h-11.4c-1.8 0-3.2 1.4-3.2 3.2v71.1c0 1.8 1.4 3.2 3.2 3.2h11.4c1.8 0 3.2-1.4 3.2-3.2v-71.1c0-1.7-1.4-3.2-3.2-3.2zm-27.5 59.6h-31.1v-56.4c0-1.8-1.4-3.2-3.2-3.2h-11.4c-1.8 0-3.2 1.4-3.2 3.2v71.1c0 .9.3 1.6.9 2.2.6.5 1.3.9 2.2.9h45.7c1.8 0 3.2-1.4 3.2-3.2v-11.4c0-1.7-1.4-3.2-3.1-3.2zM332.1 201h-45.7c-1.7 0-3.2 1.4-3.2 3.2v71.1c0 1.7 1.4 3.2 3.2 3.2h45.7c1.8 0 3.2-1.4 3.2-3.2v-11.4c0-1.8-1.4-3.2-3.2-3.2H301v-12h31.1c1.8 0 3.2-1.4 3.2-3.2V234c0-1.8-1.4-3.2-3.2-3.2H301v-12h31.1c1.8 0 3.2-1.4 3.2-3.2v-11.4c-.1-1.7-1.5-3.2-3.2-3.2zM448 113.7V399c-.1 44.8-36.8 81.1-81.7 81H81c-44.8-.1-81.1-36.9-81-81.7V113c.1-44.8 36.9-81.1 81.7-81H367c44.8.1 81.1 36.8 81 81.7zm-61.6 122.6c0-73-73.2-132.4-163.1-132.4-89.9 0-163.1 59.4-163.1 132.4 0 65.4 58 120.2 136.4 130.6 19.1 4.1 16.9 11.1 12.6 36.8-.7 4.1-3.3 16.1 14.1 8.8 17.4-7.3 93.9-55.3 128.2-94.7 23.6-26 34.9-52.3 34.9-81.5z"],linkedin:[448,512,[],"f08c","M416 32H31.9C14.3 32 0 46.5 0 64.3v383.4C0 465.5 14.3 480 31.9 480H416c17.6 0 32-14.5 32-32.3V64.3c0-17.8-14.4-32.3-32-32.3zM135.4 416H69V202.2h66.5V416zm-33.2-243c-21.3 0-38.5-17.3-38.5-38.5S80.9 96 102.2 96c21.2 0 38.5 17.3 38.5 38.5 0 21.3-17.2 38.5-38.5 38.5zm282.1 243h-66.4V312c0-24.8-.5-56.7-34.5-56.7-34.6 0-39.9 27-39.9 54.9V416h-66.4V202.2h63.7v29.2h.9c8.9-16.8 30.6-34.5 62.9-34.5 67.2 0 79.7 44.3 79.7 101.9V416z"],"linkedin-in":[448,512,[],"f0e1","M100.3 480H7.4V180.9h92.9V480zM53.8 140.1C24.1 140.1 0 115.5 0 85.8 0 56.1 24.1 32 53.8 32c29.7 0 53.8 24.1 53.8 53.8 0 29.7-24.1 54.3-53.8 54.3zM448 480h-92.7V334.4c0-34.7-.7-79.2-48.3-79.2-48.3 0-55.7 37.7-55.7 76.7V480h-92.8V180.9h89.1v40.8h1.3c12.4-23.5 42.7-48.3 87.9-48.3 94 0 111.3 61.9 111.3 142.3V480z"],linode:[448,512,[],"f2b8","M437.4 226.3c-.3-.9-.9-1.4-1.4-2l-70-38.6c-.9-.6-2-.6-3.1 0l-58.9 36c-.9.6-1.4 1.7-1.4 2.6l-.9 31.4-24-16c-.9-.6-2.3-.6-3.1 0L240 260.9l-1.4-35.1c0-.9-.6-2-1.4-2.3l-36-24.3 33.7-17.4c1.1-.6 1.7-1.7 1.7-2.9l-5.7-132.3c0-.9-.9-2-1.7-2.6L138.6.3c-.9-.3-1.7-.3-2.3-.3L12.6 38.6c-1.4.6-2.3 2-2 3.7L38 175.4c.9 3.4 34 27.4 38.6 30.9l-26.9 12.9c-1.4.9-2 2.3-1.7 3.4l20.6 100.3c.6 2.9 23.7 23.1 27.1 26.3l-17.4 10.6c-.9.6-1.7 2-1.4 3.1 1.4 7.1 15.4 77.7 16.9 79.1l65.1 69.1c.6.6 1.4.6 2.3.9.6 0 1.1-.3 1.7-.6l83.7-66.9c.9-.6 1.1-1.4 1.1-2.3l-2-46 28 23.7c1.1.9 2.9.9 4 0l66.9-53.4c.9-.6 1.1-1.4 1.1-2.3l2.3-33.4 20.3 14c1.1.9 2.6.9 3.7 0l54.6-43.7c.6-.3 1.1-1.1 1.1-2 .9-6.5 10.3-70.8 9.7-72.8zm-204.8 4.8l4 92.6-90.6 61.2-14-96.6 100.6-57.2zm-7.7-180l5.4 126-106.6 55.4L104 97.7l120.9-46.6zM44 173.1L18 48l79.7 49.4 19.4 132.9L44 173.1zm30.6 147.8L55.7 230l70 58.3 13.7 93.4-64.8-60.8zm24.3 117.7l-13.7-67.1 61.7 60.9 9.7 67.4-57.7-61.2zm64.5 64.5l-10.6-70.9 85.7-61.4 3.1 70-78.2 62.3zm82-115.1c0-3.4.9-22.9-2-25.1l-24.3-20 22.3-14.9c2.3-1.7 1.1-5.7 1.1-8l29.4 22.6.6 68.3-27.1-22.9zm94.3-25.4l-60.9 48.6-.6-68.6 65.7-46.9-4.2 66.9zm27.7-25.7l-19.1-13.4 2-34c.3-.9-.3-2-1.1-2.6L308 259.7l.6-30 64.6 40.6-5.8 66.6zm54.6-39.8l-48.3 38.3 5.7-65.1 51.1-36.6-8.5 63.4z"],linux:[448,512,[],"f17c","M196.1 123.6c-.2-1.4 1.9-2.3 3.2-2.9 1.7-.7 3.9-1 5.5-.1.4.2.8.7.6 1.1-.4 1.2-2.4 1-3.5 1.6-1 .5-1.8 1.7-3 1.7-1 .1-2.7-.4-2.8-1.4zm24.7-.3c1 .5 1.8 1.7 3 1.7 1.1 0 2.8-.4 2.9-1.5.2-1.4-1.9-2.3-3.2-2.9-1.7-.7-3.9-1-5.5-.1-.4.2-.8.7-.6 1.1.3 1.3 2.3 1.1 3.4 1.7zm214.7 310.2c-.5 8.2-6.5 13.8-13.9 18.3-14.9 9-37.3 15.8-50.9 32.2l-2.6-2.2 2.6 2.2c-14.2 16.9-31.7 26.6-48.3 27.9-16.5 1.3-32-6.3-40.3-23v-.1c-1.1-2.1-1.9-4.4-2.5-6.7-21.5 1.2-40.2-5.3-55.1-4.1-22 1.2-35.8 6.5-48.3 6.6-4.8 10.6-14.3 17.6-25.9 20.2-16 3.7-36.1 0-55.9-10.4l1.6-3-1.6 3c-18.5-9.8-42-8.9-59.3-12.5-8.7-1.8-16.3-5-20.1-12.3-3.7-7.3-3-17.3 2.2-31.7 1.7-5.1.4-12.7-.8-20.8-.6-3.9-1.2-7.9-1.2-11.8 0-4.3.7-8.5 2.8-12.4 4.5-8.5 11.8-12.1 18.5-14.5 6.7-2.4 12.8-4 17-8.3 5.2-5.5 10.1-14.4 16.6-20.2-2.6-17.2.2-35.4 6.2-53.3 12.6-37.9 39.2-74.2 58.1-96.7 16.1-22.9 20.8-41.3 22.5-64.7C158 103.4 132.4-.2 234.8 0c80.9.1 76.3 85.4 75.8 131.3-.3 30.1 16.3 50.5 33.4 72 15.2 18 35.1 44.3 46.5 74.4 9.3 24.6 12.9 51.8 3.7 79.1 1.4.5 2.8 1.2 4.1 2 1.4.8 2.7 1.8 4 2.9 6.6 5.6 8.7 14.3 10.5 22.4 1.9 8.1 3.6 15.7 7.2 19.7 11.1 12.4 15.9 21.5 15.5 29.7zM220.8 109.1c3.6.9 8.9 2.4 13 4.4-2.1-12.2 4.5-23.5 11.8-23 8.9.3 13.9 15.5 9.1 27.3-.8 1.9-2.8 3.4-3.9 4.6 6.7 2.3 11 4.1 12.6 4.9 7.9-9.5 10.8-26.2 4.3-40.4-9.8-21.4-34.2-21.8-44 .4-3.2 7.2-3.9 14.9-2.9 21.8zm-46.2 18.8c7.8-5.7 6.9-4.7 5.9-5.5-8-6.9-6.6-27.4 1.8-28.1 6.3-.5 10.8 10.7 9.6 19.6 3.1-2.1 6.7-3.6 10.2-4.6 1.7-19.3-9-33.5-19.1-33.5-18.9 0-24 37.5-8.4 52.1zm-9.4 20.9c1.5 4.9 6.1 10.5 14.7 15.3 7.8 4.6 12 11.5 20 15 2.6 1.1 5.7 1.9 9.6 2.1 18.4 1.1 27.1-11.3 38.2-14.9 11.7-3.7 20.1-11 22.7-18.1 3.2-8.5-2.1-14.7-10.5-18.2-11.3-4.9-16.3-5.2-22.6-9.3-10.3-6.6-18.8-8.9-25.9-8.9-14.4 0-23.2 9.8-27.9 14.2-.5.5-7.9 5.9-14.1 10.5-4.2 3.3-5.6 7.4-4.2 12.3zm-33.5 252.8L112.1 366c-6.8-9.2-13.8-14.8-21.9-16-7.7-1.2-12.6 1.4-17.7 6.9-4.8 5.1-8.8 12.3-14.3 18-7.8 6.5-9.3 6.2-19.6 9.9-6.3 2.2-11.3 4.6-14.8 11.3-2.7 5-2.1 12.2-.9 20 1.2 7.9 3 16.3.6 23.9v.2c-5 13.7-5 21.7-2.6 26.4 7.9 15.4 46.6 6.1 76.5 21.9 31.4 16.4 72.6 17.1 75.3-18 2.1-20.5-31.5-49-41-68.9zm153.9 35.8c3.2-11 6.3-21.3 6.8-29 .8-15.2 1.6-28.7 4.4-39.9 3.1-12.6 9.3-23.1 21.4-27.3 2.3-21.1 18.7-21.1 38.3-12.5 18.9 8.5 26 16 22.8 26.1 1 0 2-.1 4.2 0 5.2-16.9-14.3-28-30.7-34.8 2.9-12 2.4-24.1-.4-35.7-6-25.3-22.6-47.8-35.2-59-2.3-.1-2.1 1.9 2.6 6.5 11.6 10.7 37.1 49.2 23.3 84.9-3.9-1-7.6-1.5-10.9-1.4-5.3-29.1-17.5-53.2-23.6-64.6-11.5-21.4-29.5-65.3-37.2-95.7-4.5 6.4-12.4 11.9-22.3 15-4.7 1.5-9.7 5.5-15.9 9-13.9 8-30 8.8-42.4-1.2-4.5-3.6-8-7.6-12.6-10.3-1.6-.9-5.1-3.3-6.2-4.1-2 37.8-27.3 85.3-39.3 112.7-8.3 19.7-13.2 40.8-13.8 61.5-21.8-29.1-5.9-66.3 2.6-82.4 9.5-17.6 11-22.5 8.7-20.8-8.6 14-22 36.3-27.2 59.2-2.7 11.9-3.2 24 .3 35.2 3.5 11.2 11.1 21.5 24.6 29.9 0 0 24.8 14.3 38.3 32.5 7.4 10 9.7 18.7 7.4 24.9-2.5 6.7-9.6 8.9-16.7 8.9 4.8 6 10.3 13 14.4 19.6 37.6 25.7 82.2 15.7 114.3-7.2zM415 408.5c-10-11.3-7.2-33.1-17.1-41.6-6.9-6-13.6-5.4-22.6-5.1-7.7 8.8-25.8 19.6-38.4 16.3-11.5-2.9-18-16.3-18.8-29.5-.3.2-.7.3-1 .5-7.1 3.9-11.1 10.8-13.7 21.1-2.5 10.2-3.4 23.5-4.2 38.7-.7 11.8-6.2 26.4-9.9 40.6-3.5 13.2-5.8 25.2-1.1 36.3 7.2 14.5 19.5 20.4 33.7 19.3 14.2-1.1 30.4-9.8 43.6-25.5 22-26.6 62.3-29.7 63.2-46.5.3-5.1-3.1-13-13.7-24.6zM173.3 148.7c2 1.9 4.7 4.5 8 7.1 6.6 5.2 15.8 10.6 27.3 10.6 11.6 0 22.5-5.9 31.8-10.8 4.9-2.6 10.9-7 14.8-10.4 3.9-3.4 5.9-6.3 3.1-6.6-2.8-.3-2.6 2.6-6 5.1-4.4 3.2-9.7 7.4-13.9 9.8-7.4 4.2-19.5 10.2-29.9 10.2-10.4 0-18.7-4.8-24.9-9.7-3.1-2.5-5.7-5-7.7-6.9-1.5-1.4-1.9-4.6-4.3-4.9-1.4-.1-1.8 3.7 1.7 6.5z"],lyft:[512,512,[],"f3c3","M0 81.1h77.8v208.7c0 33.1 15 52.8 27.2 61-12.7 11.1-51.2 20.9-80.2-2.8C7.8 334 0 310.7 0 289V81.1zm485.9 173.5v-22h23.8v-76.8h-26.1c-10.1-46.3-51.2-80.7-100.3-80.7-56.6 0-102.7 46-102.7 102.7V357c16 2.3 35.4-.3 51.7-14 17.1-14 24.8-37.2 24.8-59v-6.7h38.8v-76.8h-38.8v-23.3c0-34.6 52.2-34.6 52.2 0v77.1c0 56.6 46 102.7 102.7 102.7v-76.5c-14.5 0-26.1-11.7-26.1-25.9zm-294.3-99v113c0 15.4-23.8 15.4-23.8 0v-113H91v132.7c0 23.8 8 54 45 63.9 37 9.8 58.2-10.6 58.2-10.6-2.1 13.4-14.5 23.3-34.9 25.3-15.5 1.6-35.2-3.6-45-7.8v70.3c25.1 7.5 51.5 9.8 77.6 4.7 47.1-9.1 76.8-48.4 76.8-100.8V155.1h-77.1v.5z"],magento:[448,512,[],"f3c4","M445.7 127.9V384l-63.4 36.5V164.7L223.8 73.1 65.2 164.7l.4 255.9L2.3 384V128.1L224.2 0l221.5 127.9zM255.6 420.5L224 438.9l-31.8-18.2v-256l-63.3 36.6.1 255.9 94.9 54.9 95.1-54.9v-256l-63.4-36.6v255.9z"],maxcdn:[512,512,[],"f136","M461.1 442.7h-97.4L415.6 200c2.3-10.2.9-19.5-4.4-25.7-5-6.1-13.7-9.6-24.2-9.6h-49.3l-59.5 278h-97.4l59.5-278h-83.4l-59.5 278H0l59.5-278-44.6-95.4H387c39.4 0 75.3 16.3 98.3 44.9 23.3 28.6 31.8 67.4 23.6 105.9l-47.8 222.6z"],medapps:[320,512,[],"f3c6","M118.3 238.4c3.5-12.5 6.9-33.6 13.2-33.6 8.3 1.8 9.6 23.4 18.6 36.6 4.6-23.5 5.3-85.1 14.1-86.7 9-.7 19.7 66.5 22 77.5 9.9 4.1 48.9 6.6 48.9 6.6 1.9 7.3-24 7.6-40 7.8-4.6 14.8-5.4 27.7-11.4 28-4.7.2-8.2-28.8-17.5-49.6l-9.4 65.5c-4.4 13-15.5-22.5-21.9-39.3-3.3-.1-62.4-1.6-47.6-7.8l31-5zM228 448c21.2 0 21.2-32 0-32H92c-21.2 0-21.2 32 0 32h136zm-24 64c21.2 0 21.2-32 0-32h-88c-21.2 0-21.2 32 0 32h88zm34.2-141.5c3.2-18.9 5.2-36.4 11.9-48.8 7.9-14.7 16.1-28.1 24-41 24.6-40.4 45.9-75.2 45.9-125.5C320 69.6 248.2 0 160 0S0 69.6 0 155.2c0 50.2 21.3 85.1 45.9 125.5 7.9 12.9 16 26.3 24 41 6.7 12.5 8.7 29.8 11.9 48.9 3.5 21 36.1 15.7 32.6-5.1-3.6-21.7-5.6-40.7-15.3-58.6C66.5 246.5 33 211.3 33 155.2 33 87.3 90 32 160 32s127 55.3 127 123.2c0 56.1-33.5 91.3-66.1 151.6-9.7 18-11.7 37.4-15.3 58.6-3.4 20.6 29 26.4 32.6 5.1z"],medium:[448,512,[],"f23a","M0 32v448h448V32H0zm372.2 106.1l-24 23c-2.1 1.6-3.1 4.2-2.7 6.7v169.3c-.4 2.6.6 5.2 2.7 6.7l23.5 23v5.1h-118V367l24.3-23.6c2.4-2.4 2.4-3.1 2.4-6.7V199.8l-67.6 171.6h-9.1L125 199.8v115c-.7 4.8 1 9.7 4.4 13.2l31.6 38.3v5.1H71.2v-5.1l31.6-38.3c3.4-3.5 4.9-8.4 4.1-13.2v-133c.4-3.7-1-7.3-3.8-9.8L75 138.1V133h87.3l67.4 148L289 133.1h83.2v5z"],"medium-m":[512,512,[],"f3c7","M71.5 142.3c.6-5.9-1.7-11.8-6.1-15.8L20.3 72.1V64h140.2l108.4 237.7L364.2 64h133.7v8.1l-38.6 37c-3.3 2.5-5 6.7-4.3 10.8v272c-.7 4.1 1 8.3 4.3 10.8l37.7 37v8.1H307.3v-8.1l39.1-37.9c3.8-3.8 3.8-5 3.8-10.8V171.2L241.5 447.1h-14.7L100.4 171.2v184.9c-1.1 7.8 1.5 15.6 7 21.2l50.8 61.6v8.1h-144v-8L65 377.3c5.4-5.6 7.9-13.5 6.5-21.2V142.3z"],medrt:[544,512,[],"f3c8","M113.7 256c0 121.8 83.9 222.8 193.5 241.1-18.7 4.5-38.2 6.9-58.2 6.9C111.4 504 0 393 0 256S111.4 8 248.9 8c20.1 0 39.6 2.4 58.2 6.9C197.5 33.2 113.7 134.2 113.7 256m297.4 100.3c-77.7 55.4-179.6 47.5-240.4-14.6 5.5 14.1 12.7 27.7 21.7 40.5 61.6 88.2 182.4 109.3 269.7 47 87.3-62.3 108.1-184.3 46.5-272.6-9-12.9-19.3-24.3-30.5-34.2 37.4 78.8 10.7 178.5-67 233.9m-218.8-244c-1.4 1-2.7 2.1-4 3.1 64.3-17.8 135.9 4 178.9 60.5 35.7 47 42.9 106.6 24.4 158 56.7-56.2 67.6-142.1 22.3-201.8-50-65.5-149.1-74.4-221.6-19.8M296 224c-4.4 0-8-3.6-8-8v-40c0-4.4-3.6-8-8-8h-48c-4.4 0-8 3.6-8 8v40c0 4.4-3.6 8-8 8h-40c-4.4 0-8 3.6-8 8v48c0 4.4 3.6 8 8 8h40c4.4 0 8 3.6 8 8v40c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8v-40c0-4.4 3.6-8 8-8h40c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8h-40z"],meetup:[512,512,[],"f2e0","M99 414.3c1.1 5.7-2.3 11.1-8 12.3-5.4 1.1-10.9-2.3-12-8-1.1-5.4 2.3-11.1 7.7-12.3 5.4-1.2 11.1 2.3 12.3 8zm143.1 71.4c-6.3 4.6-8 13.4-3.7 20 4.6 6.6 13.4 8.3 20 3.7 6.3-4.6 8-13.4 3.4-20-4.2-6.5-13.1-8.3-19.7-3.7zm-86-462.3c6.3-1.4 10.3-7.7 8.9-14-1.1-6.6-7.4-10.6-13.7-9.1-6.3 1.4-10.3 7.7-9.1 14 1.4 6.6 7.6 10.6 13.9 9.1zM34.4 226.3c-10-6.9-23.7-4.3-30.6 6-6.9 10-4.3 24 5.7 30.9 10 7.1 23.7 4.6 30.6-5.7 6.9-10.4 4.3-24.1-5.7-31.2zm272-170.9c10.6-6.3 13.7-20 7.7-30.3-6.3-10.6-19.7-14-30-7.7s-13.7 20-7.4 30.6c6 10.3 19.4 13.7 29.7 7.4zm-191.1 58c7.7-5.4 9.4-16 4.3-23.7s-15.7-9.4-23.1-4.3c-7.7 5.4-9.4 16-4.3 23.7 5.1 7.8 15.6 9.5 23.1 4.3zm372.3 156c-7.4 1.7-12.3 9.1-10.6 16.9 1.4 7.4 8.9 12.3 16.3 10.6 7.4-1.4 12.3-8.9 10.6-16.6-1.5-7.4-8.9-12.3-16.3-10.9zm39.7-56.8c-1.1-5.7-6.6-9.1-12-8-5.7 1.1-9.1 6.9-8 12.6 1.1 5.4 6.6 9.1 12.3 8 5.4-1.5 9.1-6.9 7.7-12.6zM447 138.9c-8.6 6-10.6 17.7-4.9 26.3 5.7 8.6 17.4 10.6 26 4.9 8.3-6 10.3-17.7 4.6-26.3-5.7-8.7-17.4-10.9-25.7-4.9zm-6.3 139.4c26.3 43.1 15.1 100-26.3 129.1-17.4 12.3-37.1 17.7-56.9 17.1-12 47.1-69.4 64.6-105.1 32.6-1.1.9-2.6 1.7-3.7 2.9-39.1 27.1-92.3 17.4-119.4-22.3-9.7-14.3-14.6-30.6-15.1-46.9-65.4-10.9-90-94-41.1-139.7-28.3-46.9.6-107.4 53.4-114.9C151.6 70 234.1 38.6 290.1 82c67.4-22.3 136.3 29.4 130.9 101.1 41.1 12.6 52.8 66.9 19.7 95.2zm-70 74.3c-3.1-20.6-40.9-4.6-43.1-27.1-3.1-32 43.7-101.1 40-128-3.4-24-19.4-29.1-33.4-29.4-13.4-.3-16.9 2-21.4 4.6-2.9 1.7-6.6 4.9-11.7-.3-6.3-6-11.1-11.7-19.4-12.9-12.3-2-17.7 2-26.6 9.7-3.4 2.9-12 12.9-20 9.1-3.4-1.7-15.4-7.7-24-11.4-16.3-7.1-40 4.6-48.6 20-12.9 22.9-38 113.1-41.7 125.1-8.6 26.6 10.9 48.6 36.9 47.1 11.1-.6 18.3-4.6 25.4-17.4 4-7.4 41.7-107.7 44.6-112.6 2-3.4 8.9-8 14.6-5.1 5.7 3.1 6.9 9.4 6 15.1-1.1 9.7-28 70.9-28.9 77.7-3.4 22.9 26.9 26.6 38.6 4 3.7-7.1 45.7-92.6 49.4-98.3 4.3-6.3 7.4-8.3 11.7-8 3.1 0 8.3.9 7.1 10.9-1.4 9.4-35.1 72.3-38.9 87.7-4.6 20.6 6.6 41.4 24.9 50.6 11.4 5.7 62.5 15.7 58.5-11.1zm5.7 92.3c-10.3 7.4-12.9 22-5.7 32.6 7.1 10.6 21.4 13.1 32 6 10.6-7.4 13.1-22 6-32.6-7.4-10.6-21.7-13.5-32.3-6z"],microsoft:[448,512,[],"f3ca","M0 32h214.6v214.6H0V32zm233.4 0H448v214.6H233.4V32zM0 265.4h214.6V480H0V265.4zm233.4 0H448V480H233.4V265.4z"],mix:[416,512,[],"f3cb","M0 64v348.9c0 56.2 88 58.1 88 0V174.3c7.9-52.9 88-50.4 88 6.5v175.3c0 57.9 96 58 96 0V240c5.3-54.7 88-52.5 88 4.3v23.8c0 59.9 88 56.6 88 0V64H0z"],mixcloud:[640,512,[],"f289","M424.43 219.729C416.124 134.727 344.135 68 256.919 68c-72.266 0-136.224 46.516-159.205 114.074-54.545 8.029-96.63 54.822-96.63 111.582 0 62.298 50.668 112.966 113.243 112.966h289.614c52.329 0 94.969-42.362 94.969-94.693 0-45.131-32.118-83.063-74.48-92.2zm-20.489 144.53H114.327c-39.04 0-70.881-31.564-70.881-70.604s31.841-70.604 70.881-70.604c18.827 0 36.548 7.475 49.838 20.766 19.963 19.963 50.133-10.227 30.18-30.18-14.675-14.398-32.672-24.365-52.053-29.349 19.935-44.3 64.79-73.926 114.628-73.926 69.496 0 125.979 56.483 125.979 125.702 0 13.568-2.215 26.857-6.369 39.594-8.943 27.517 32.133 38.939 40.147 13.29 2.769-8.306 4.984-16.889 6.369-25.472 19.381 7.476 33.502 26.303 33.502 48.453 0 28.795-23.535 52.33-52.607 52.33zm235.069-52.33c0 44.024-12.737 86.386-37.102 122.657-4.153 6.092-10.798 9.414-17.72 9.414-16.317 0-27.127-18.826-17.443-32.949 19.381-29.349 29.903-63.682 29.903-99.122s-10.521-69.773-29.903-98.845c-15.655-22.831 19.361-47.24 35.163-23.534 24.366 35.993 37.102 78.356 37.102 122.379zm-70.88 0c0 31.565-9.137 62.021-26.857 88.325-4.153 6.091-10.798 9.136-17.72 9.136-17.201 0-27.022-18.979-17.443-32.948 13.013-19.104 19.658-41.255 19.658-64.513 0-22.981-6.645-45.408-19.658-64.512-15.761-22.986 19.008-47.095 35.163-23.535 17.719 26.026 26.857 56.483 26.857 88.047z"],mizuni:[496,512,[],"f3cc","M248 8C111 8 0 119.1 0 256c0 137 111 248 248 248s248-111 248-248C496 119.1 385 8 248 8zm-80 351.9c-31.4 10.6-58.8 27.3-80 48.2V136c0-22.1 17.9-40 40-40s40 17.9 40 40v223.9zm120-9.9c-12.9-2-26.2-3.1-39.8-3.1-13.8 0-27.2 1.1-40.2 3.1V136c0-22.1 17.9-40 40-40s40 17.9 40 40v214zm120 57.7c-21.2-20.8-48.6-37.4-80-48V136c0-22.1 17.9-40 40-40s40 17.9 40 40v271.7z"],modx:[448,512,[],"f285","M356 241.8l36.7 23.7V480l-133-83.8L356 241.8zM440 75H226.3l-23 37.8 153.5 96.5L440 75zm-89 142.8L55.2 32v214.5l46 29L351 217.8zM97 294.2L8 437h213.7l125-200.5L97 294.2z"],monero:[496,512,[],"f3d0","M352 384h108.4C417 455.9 338.1 504 248 504S79 455.9 35.6 384H144V256.2L248 361l104-105v128zM88 336V128l159.4 159.4L408 128v208h74.8c8.5-25.1 13.2-52 13.2-80C496 119 385 8 248 8S0 119 0 256c0 28 4.6 54.9 13.2 80H88z"],napster:[496,512,[],"f3d2","M298.3 373.6c-14.2 13.6-31.3 24.1-50.4 30.5-19-6.4-36.2-16.9-50.3-30.5h100.7zm44-199.6c20-16.9 43.6-29.2 69.6-36.2V299c0 219.4-328 217.6-328 .3V137.7c25.9 6.9 49.6 19.6 69.5 36.4 56.8-40 132.5-39.9 188.9-.1zm-208.8-58.5c64.4-60 164.3-60.1 228.9-.2-7.1 3.5-13.9 7.3-20.6 11.5-58.7-30.5-129.2-30.4-187.9.1-6.3-4-13.9-8.2-20.4-11.4zM43.8 93.2v69.3c-58.4 36.5-58.4 121.1.1 158.3 26.4 245.1 381.7 240.3 407.6 1.5l.3-1.7c58.7-36.3 58.9-121.7.2-158.2V93.2c-17.3.5-34 3-50.1 7.4-82-91.5-225.5-91.5-307.5.1-16.3-4.4-33.1-7-50.6-7.5zM259.2 352s36-.3 61.3-1.5c10.2-.5 21.1-4 25.5-6.5 26.3-15.1 25.4-39.2 26.2-47.4-79.5-.6-99.9-3.9-113 55.4zm-135.5-55.3c.8 8.2-.1 32.3 26.2 47.4 4.4 2.5 15.2 6 25.5 6.5 25.3 1.1 61.3 1.5 61.3 1.5-13.2-59.4-33.7-56.1-113-55.4zm169.1 123.4c-3.2-5.3-6.9-7.3-6.9-7.3-24.8 7.3-52.2 6.9-75.9 0 0 0-2.9 1.5-6.4 6.6-2.8 4.1-3.7 9.6-3.7 9.6 29.1 17.6 67.1 17.6 96.2 0-.1-.1-.3-4-3.3-8.9z"],"nintendo-switch":[448,512,[],"f418","M95.9 33.5c-44.6 8-80.5 41-91.8 84.4C0 133.6-.3 142.8.2 264.4.4 376 .5 378.6 2.4 387.3c10.3 46.5 43.3 79.6 90.3 90.5 6.1 1.4 13.9 1.7 64.1 1.9 51.9.4 57.3.3 58.7-1.1 1.4-1.4 1.5-19.3 1.5-222.2 0-150.5-.3-221.3-.9-222.6-.9-1.7-2.5-1.8-56.9-1.7-44.2.1-57.5.4-63.3 1.4zm83.9 222.6V444l-37.8-.5c-34.8-.4-38.5-.6-45.5-2.3-29.9-7.7-52-30.7-58.3-60.7-2-9.4-2-240.1-.1-249.3 5.6-26.1 23.7-47.7 48-57.4 12.2-4.9 17.9-5.5 57.6-5.6l35.9-.1v188zm-75.9-131.2c-5.8 1.1-14.7 5.6-19.5 9.7-9.7 8.4-14.6 20.4-13.8 34.5.4 7.3.8 9.3 3.8 15.2 4.4 9 10.9 15.6 19.9 20 6.2 3.1 7.8 3.4 15.9 3.7 7.3.3 9.9 0 14.8-1.7 20.1-6.8 32.3-26.3 28.8-46.4-3.9-23.7-26.6-39.7-49.9-35zm158.2-92.3c-.4.3-.6 100.8-.6 223.5 0 202.3.1 222.8 1.5 223.4 2.5.9 74.5.6 83.4-.4 37.7-4.3 71-27.2 89-61.2 2.3-4.4 5.4-11.7 7-16.2 5.8-17.4 5.7-12.8 5.7-146.1 0-106.4-.2-122.3-1.5-129-9.2-48.3-46.1-84.8-94.5-93.1-6.5-1.1-16.5-1.4-48.8-1.4-22.4-.1-40.9.2-41.2.5zm99.1 202.1c14.5 3.8 26.3 14.8 31.2 28.9 3.1 8.7 3 21.5-.1 29.5-5.7 14.7-16.8 25-31.1 28.8-23.2 6-47.9-8-54.6-31-2-7-1.9-18.9.4-26.2 6.9-22.7 31-36.1 54.2-30z"],node:[640,512,[],"f419","M316.3 452c-2.1 0-4.2-.6-6.1-1.6L291 439c-2.9-1.6-1.5-2.2-.5-2.5 3.8-1.3 4.6-1.6 8.7-4 .4-.2 1-.1 1.4.1l14.8 8.8c.5.3 1.3.3 1.8 0L375 408c.5-.3.9-.9.9-1.6v-66.7c0-.7-.3-1.3-.9-1.6l-57.8-33.3c-.5-.3-1.2-.3-1.8 0l-57.8 33.3c-.6.3-.9 1-.9 1.6v66.7c0 .6.4 1.2.9 1.5l15.8 9.1c8.6 4.3 13.9-.8 13.9-5.8v-65.9c0-.9.7-1.7 1.7-1.7h7.3c.9 0 1.7.7 1.7 1.7v65.9c0 11.5-6.2 18-17.1 18-3.3 0-6 0-13.3-3.6l-15.2-8.7c-3.7-2.2-6.1-6.2-6.1-10.5v-66.7c0-4.3 2.3-8.4 6.1-10.5l57.8-33.4c3.7-2.1 8.5-2.1 12.1 0l57.8 33.4c3.7 2.2 6.1 6.2 6.1 10.5v66.7c0 4.3-2.3 8.4-6.1 10.5l-57.8 33.4c-1.7 1.1-3.8 1.7-6 1.7zm46.7-65.8c0-12.5-8.4-15.8-26.2-18.2-18-2.4-19.8-3.6-19.8-7.8 0-3.5 1.5-8.1 14.8-8.1 11.9 0 16.3 2.6 18.1 10.6.2.8.8 1.3 1.6 1.3h7.5c.5 0 .9-.2 1.2-.5.3-.4.5-.8.4-1.3-1.2-13.8-10.3-20.2-28.8-20.2-16.5 0-26.3 7-26.3 18.6 0 12.7 9.8 16.1 25.6 17.7 18.9 1.9 20.4 4.6 20.4 8.3 0 6.5-5.2 9.2-17.4 9.2-15.3 0-18.7-3.8-19.8-11.4-.1-.8-.8-1.4-1.7-1.4h-7.5c-.9 0-1.7.7-1.7 1.7 0 9.7 5.3 21.3 30.6 21.3 18.5 0 29-7.2 29-19.8zm54.5-50.1c0 6.1-5 11.1-11.1 11.1s-11.1-5-11.1-11.1c0-6.3 5.2-11.1 11.1-11.1 6-.1 11.1 4.8 11.1 11.1zm-1.8 0c0-5.2-4.2-9.3-9.4-9.3-5.1 0-9.3 4.1-9.3 9.3 0 5.2 4.2 9.4 9.3 9.4 5.2-.1 9.4-4.3 9.4-9.4zm-4.5 6.2h-2.6c-.1-.6-.5-3.8-.5-3.9-.2-.7-.4-1.1-1.3-1.1h-2.2v5h-2.4v-12.5h4.3c1.5 0 4.4 0 4.4 3.3 0 2.3-1.5 2.8-2.4 3.1 1.7.1 1.8 1.2 2.1 2.8.1 1 .3 2.7.6 3.3zm-2.8-8.8c0-1.7-1.2-1.7-1.8-1.7h-2v3.5h1.9c1.6 0 1.9-1.1 1.9-1.8zM137.3 191c0-2.7-1.4-5.1-3.7-6.4l-61.3-35.3c-1-.6-2.2-.9-3.4-1h-.6c-1.2 0-2.3.4-3.4 1L3.7 184.6C1.4 185.9 0 188.4 0 191l.1 95c0 1.3.7 2.5 1.8 3.2 1.1.7 2.5.7 3.7 0L42 268.3c2.3-1.4 3.7-3.8 3.7-6.4v-44.4c0-2.6 1.4-5.1 3.7-6.4l15.5-8.9c1.2-.7 2.4-1 3.7-1 1.3 0 2.6.3 3.7 1l15.5 8.9c2.3 1.3 3.7 3.8 3.7 6.4v44.4c0 2.6 1.4 5.1 3.7 6.4l36.4 20.9c1.1.7 2.6.7 3.7 0 1.1-.6 1.8-1.9 1.8-3.2l.2-95zM472.5 87.3v176.4c0 2.6-1.4 5.1-3.7 6.4l-61.3 35.4c-2.3 1.3-5.1 1.3-7.4 0l-61.3-35.4c-2.3-1.3-3.7-3.8-3.7-6.4v-70.8c0-2.6 1.4-5.1 3.7-6.4l61.3-35.4c2.3-1.3 5.1-1.3 7.4 0l15.3 8.8c1.7 1 3.9-.3 3.9-2.2v-94c0-2.8 3-4.6 5.5-3.2l36.5 20.4c2.3 1.2 3.8 3.7 3.8 6.4zm-46 128.9c0-.7-.4-1.3-.9-1.6l-21-12.2c-.6-.3-1.3-.3-1.9 0l-21 12.2c-.6.3-.9.9-.9 1.6v24.3c0 .7.4 1.3.9 1.6l21 12.1c.6.3 1.3.3 1.8 0l21-12.1c.6-.3.9-.9.9-1.6v-24.3zm209.8-.7c2.3-1.3 3.7-3.8 3.7-6.4V192c0-2.6-1.4-5.1-3.7-6.4l-60.9-35.4c-2.3-1.3-5.1-1.3-7.4 0l-61.3 35.4c-2.3 1.3-3.7 3.8-3.7 6.4v70.8c0 2.7 1.4 5.1 3.7 6.4l60.9 34.7c2.2 1.3 5 1.3 7.3 0l36.8-20.5c2.5-1.4 2.5-5 0-6.4L550 241.6c-1.2-.7-1.9-1.9-1.9-3.2v-22.2c0-1.3.7-2.5 1.9-3.2l19.2-11.1c1.1-.7 2.6-.7 3.7 0l19.2 11.1c1.1.7 1.9 1.9 1.9 3.2v17.4c0 2.8 3.1 4.6 5.6 3.2l36.7-21.3zM559 219c-.4.3-.7.7-.7 1.2v13.6c0 .5.3 1 .7 1.2l11.8 6.8c.4.3 1 .3 1.4 0L584 235c.4-.3.7-.7.7-1.2v-13.6c0-.5-.3-1-.7-1.2l-11.8-6.8c-.4-.3-1-.3-1.4 0L559 219zm-254.2 43.5v-70.4c0-2.6-1.6-5.1-3.9-6.4l-61.1-35.2c-2.1-1.2-5-1.4-7.4 0l-61.1 35.2c-2.3 1.3-3.9 3.7-3.9 6.4v70.4c0 2.8 1.9 5.2 4 6.4l61.2 35.2c2.4 1.4 5.2 1.3 7.4 0l61-35.2c1.8-1 3.1-2.7 3.6-4.7.1-.5.2-1.1.2-1.7zm-74.3-124.9l-.8.5h1.1l-.3-.5zm76.2 130.2l-.4-.7v.9l.4-.2z"],"node-js":[448,512,[],"f3d3","M224 480c-6 0-12-1.6-17.2-4.6L151.9 443c-8.2-4.6-4.2-6.2-1.5-7.1 10.9-3.8 13.1-4.7 24.8-11.3 1.2-.7 2.8-.4 4.1.3l42.1 25c1.5.8 3.7.8 5.1 0l164.2-94.8c1.5-.9 2.5-2.6 2.5-4.4V161.2c0-1.9-1-3.6-2.5-4.5L226.5 62c-1.5-.9-3.5-.9-5.1 0l-164 94.7c-1.6.9-2.6 2.7-2.6 4.5v189.5c0 1.8 1 3.5 2.6 4.4l45 26c24.4 12.2 39.3-2.2 39.3-16.6V177.4c0-2.6 2.1-4.7 4.8-4.7h20.8c2.6 0 4.8 2.1 4.8 4.7v187.1c0 32.6-17.7 51.2-48.6 51.2-9.5 0-17 0-37.8-10.3l-43.1-24.8C32 374.5 25.4 363 25.4 350.7V161.2c0-12.3 6.6-23.8 17.2-29.9l164.2-94.9c10.4-5.9 24.2-5.9 34.5 0l164.2 94.9c10.6 6.1 17.2 17.6 17.2 29.9v189.5c0 12.3-6.6 23.8-17.2 29.9l-164.2 94.8c-5.3 3-11.3 4.6-17.3 4.6zm132.5-186.8c0-35.5-24-44.9-74.4-51.6-51-6.7-56.2-10.2-56.2-22.2 0-9.9 4.4-23 42.2-23 33.7 0 46.2 7.3 51.3 30 .4 2.1 2.4 3.7 4.6 3.7h21.3c1.3 0 2.6-.6 3.5-1.5.9-1 1.4-2.3 1.3-3.7-3.3-39.2-29.3-57.4-81.9-57.4-46.8 0-74.7 19.8-74.7 52.9 0 35.9 27.8 45.9 72.7 50.3 53.8 5.3 57.9 13.1 57.9 23.7 0 18.3-14.7 26.2-49.3 26.2-43.4 0-53-10.9-56.2-32.5-.4-2.3-2.3-4-4.7-4h-21.2c-2.6 0-4.7 2.1-4.7 4.7 0 27.7 15.1 60.6 86.9 60.6 51.8.1 81.6-20.4 81.6-56.2z"],npm:[576,512,[],"f3d4","M288 288h-32v-64h32v64zm288-128v192H288v32H160v-32H0V160h576zm-416 32H32v128h64v-96h32v96h32V192zm160 0H192v160h64v-32h64V192zm224 0H352v128h64v-96h32v96h32v-96h32v96h32V192z"],ns8:[640,512,[],"f3d5","M187.1 159.9l-34.2 113.7-54.5-113.7H49L0 320h44.9L76 213.5 126.6 320h56.9L232 159.9h-44.9zm452.5-.9c-2.9-18-23.9-28.1-42.1-31.3-44.6-7.8-101.9 16.3-88.5 58.8v.1c-43.8 8.7-74.3 26.8-94.2 48.2-3-9.8-13.6-16.6-34-16.6h-87.6c-9.3 0-12.9-2.3-11.5-7.4 1.6-5.5 1.9-6.8 3.7-12.2 2.1-6.4 7.8-7.1 13.3-7.1h133.5l9.7-31.5c-139.7 0-144.5-.5-160.1 1.2-12.3 1.3-23.5 4.8-30.6 15-6.8 9.9-14.4 35.6-17.6 47.1-5.4 19.4-.6 28.6 32.8 28.6h87.3c7.8 0 8.8 2.7 7.7 6.6-1.1 4.4-2.8 10-4.5 14.6-1.6 4.2-4.7 7.4-13.8 7.4H216.3L204.7 320c139.9 0 145.3-.6 160.9-2.3 6.6-.7 13-2.1 18.5-4.9.2 3.7.5 7.3 1.2 10.8 5.4 30.5 27.4 52.3 56.8 59.5 48.6 11.9 108.7-16.8 135.1-68 18.7-36.2 14.1-76.2-3.4-105.5h.1c29.6-5.9 70.3-22 65.7-50.6zM530.7 263.7c-5.9 29.5-36.6 47.8-61.6 43.9-30.9-4.8-38.5-39.5-14.1-64.8 16.2-16.8 45.2-24 68.5-26.9 6.7 14.1 10.3 32 7.2 47.8zm21.8-83.1c-4.2-6-9.8-18.5-2.5-26.3 6.7-7.2 20.9-10.1 31.8-7.7 15.3 3.4 19.7 15.9 4.9 24.4-10.7 6.1-23.6 8.1-34.2 9.6z"],nutritionix:[400,512,[],"f3d6","M88 8.1S221.4-.1 209 112.5c0 0 19.1-74.9 103-40.6 0 0-17.7 74-88 56 0 0 14.6-54.6 66.1-56.6 0 0-39.9-10.3-82.1 48.8 0 0-19.8-94.5-93.6-99.7 0 0 75.2 19.4 77.6 107.5 0 .1-106.4 7-104-119.8zm312 315.6c0 48.5-9.7 95.3-32 132.3-42.2 30.9-105 48-168 48-62.9 0-125.8-17.1-168-48C9.7 419 0 372.2 0 323.7 0 275.3 17.7 229 40 192c42.2-30.9 97.1-48.6 160-48.6 63 0 117.8 17.6 160 48.6 22.3 37 40 83.3 40 131.7zM120 428c0-15.5-12.5-28-28-28s-28 12.5-28 28 12.5 28 28 28 28-12.5 28-28zm0-66.2c0-15.5-12.5-28-28-28s-28 12.5-28 28 12.5 28 28 28 28-12.5 28-28zm0-66.2c0-15.5-12.5-28-28-28s-28 12.5-28 28 12.5 28 28 28 28-12.5 28-28zM192 428c0-15.5-12.5-28-28-28s-28 12.5-28 28 12.5 28 28 28 28-12.5 28-28zm0-66.2c0-15.5-12.5-28-28-28s-28 12.5-28 28 12.5 28 28 28 28-12.5 28-28zm0-66.2c0-15.5-12.5-28-28-28s-28 12.5-28 28 12.5 28 28 28 28-12.5 28-28zM264 428c0-15.5-12.5-28-28-28s-28 12.5-28 28 12.5 28 28 28 28-12.5 28-28zm0-66.2c0-15.5-12.5-28-28-28s-28 12.5-28 28 12.5 28 28 28 28-12.5 28-28zm0-66.2c0-15.5-12.5-28-28-28s-28 12.5-28 28 12.5 28 28 28 28-12.5 28-28zM336 428c0-15.5-12.5-28-28-28s-28 12.5-28 28 12.5 28 28 28 28-12.5 28-28zm0-66.2c0-15.5-12.5-28-28-28s-28 12.5-28 28 12.5 28 28 28 28-12.5 28-28zm0-66.2c0-15.5-12.5-28-28-28s-28 12.5-28 28 12.5 28 28 28 28-12.5 28-28zm24-39.6c-4.8-22.3-7.4-36.9-16-56-38.8-19.9-90.5-32-144-32S94.8 180.1 56 200c-8.8 19.5-11.2 33.9-16 56 42.2-7.9 98.7-14.8 160-14.8s117.8 6.9 160 14.8z"],odnoklassniki:[320,512,[],"f263","M275.1 334c-27.4 17.4-65.1 24.3-90 26.9l20.9 20.6 76.3 76.3c27.9 28.6-17.5 73.3-45.7 45.7-19.1-19.4-47.1-47.4-76.3-76.6L84 503.4c-28.2 27.5-73.6-17.6-45.4-45.7 19.4-19.4 47.1-47.4 76.3-76.3l20.6-20.6c-24.6-2.6-62.9-9.1-90.6-26.9-32.6-21-46.9-33.3-34.3-59 7.4-14.6 27.7-26.9 54.6-5.7 0 0 36.3 28.9 94.9 28.9s94.9-28.9 94.9-28.9c26.9-21.1 47.1-8.9 54.6 5.7 12.4 25.7-1.9 38-34.5 59.1zM30.3 129.7C30.3 58 88.6 0 160 0s129.7 58 129.7 129.7c0 71.4-58.3 129.4-129.7 129.4s-129.7-58-129.7-129.4zm66 0c0 35.1 28.6 63.7 63.7 63.7s63.7-28.6 63.7-63.7c0-35.4-28.6-64-63.7-64s-63.7 28.6-63.7 64z"],"odnoklassniki-square":[448,512,[],"f264","M184.2 177.1c0-22.1 17.9-40 39.8-40s39.8 17.9 39.8 40c0 22-17.9 39.8-39.8 39.8s-39.8-17.9-39.8-39.8zM448 80v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V80c0-26.5 21.5-48 48-48h352c26.5 0 48 21.5 48 48zm-305.1 97.1c0 44.6 36.4 80.9 81.1 80.9s81.1-36.2 81.1-80.9c0-44.8-36.4-81.1-81.1-81.1s-81.1 36.2-81.1 81.1zm174.5 90.7c-4.6-9.1-17.3-16.8-34.1-3.6 0 0-22.7 18-59.3 18s-59.3-18-59.3-18c-16.8-13.2-29.5-5.5-34.1 3.6-7.9 16.1 1.1 23.7 21.4 37 17.3 11.1 41.2 15.2 56.6 16.8l-12.9 12.9c-18.2 18-35.5 35.5-47.7 47.7-17.6 17.6 10.7 45.8 28.4 28.6l47.7-47.9c18.2 18.2 35.7 35.7 47.7 47.9 17.6 17.2 46-10.7 28.6-28.6l-47.7-47.7-13-12.9c15.5-1.6 39.1-5.9 56.2-16.8 20.4-13.3 29.3-21 21.5-37z"],opencart:[640,512,[],"f23d","M423.3 440.7c0 25.3-20.3 45.6-45.6 45.6s-45.8-20.3-45.8-45.6 20.6-45.8 45.8-45.8c25.4 0 45.6 20.5 45.6 45.8zm-253.9-45.8c-25.3 0-45.6 20.6-45.6 45.8s20.3 45.6 45.6 45.6 45.8-20.3 45.8-45.6-20.5-45.8-45.8-45.8zm291.7-270C158.9 124.9 81.9 112.1 0 25.7c34.4 51.7 53.3 148.9 373.1 144.2 333.3-5 130 86.1 70.8 188.9 186.7-166.7 319.4-233.9 17.2-233.9z"],openid:[448,512,[],"f19b","M271.5 432l-68 32C88.5 453.7 0 392.5 0 318.2c0-71.5 82.5-131 191.7-144.3v43c-71.5 12.5-124 53-124 101.3 0 51 58.5 93.3 135.7 103v-340l68-33.2v384zM448 291l-131.3-28.5 36.8-20.7c-19.5-11.5-43.5-20-70-24.8v-43c46.2 5.5 87.7 19.5 120.3 39.3l35-19.8L448 291z"],opera:[496,512,[],"f26a","M313.9 32.7c-170.2 0-252.6 223.8-147.5 355.1 36.5 45.4 88.6 75.6 147.5 75.6 36.3 0 70.3-11.1 99.4-30.4-43.8 39.2-101.9 63-165.3 63-3.9 0-8 0-11.9-.3C104.6 489.6 0 381.1 0 248 0 111 111 0 248 0h.8c63.1.3 120.7 24.1 164.4 63.1-29-19.4-63.1-30.4-99.3-30.4zm101.8 397.7c-40.9 24.7-90.7 23.6-132-5.8 56.2-20.5 97.7-91.6 97.7-176.6 0-84.7-41.2-155.8-97.4-176.6 41.8-29.2 91.2-30.3 132.9-5 105.9 98.7 105.5 265.7-1.2 364z"],"optin-monster":[576,512,[],"f23c","M550.671 450.303c0 11.62-15.673 19.457-32.158 14.863-12.16-3.243-31.346-17.565-36.211-27.294-5.674-11.62 4.054-32.698 18.916-30.806 15.674 1.621 49.453 25.401 49.453 43.237zM372.86 75.223c-3.783-72.151-100.796-79.718-125.928-23.51 44.588-24.321 90.257-15.673 125.928 23.51zM74.795 407.066c-15.673 1.621-49.452 25.401-49.452 43.237 0 11.62 15.673 19.457 32.157 14.863 12.16-3.243 31.076-17.565 35.94-27.294 5.946-11.62-3.782-32.698-18.645-30.806zm497.765 14.322c1.081 3.513 1.892 7.026 1.892 10.809.81 31.616-44.317 64.045-73.503 65.125-17.295.81-34.59-8.377-42.696-23.51-113.497 4.053-226.994 4.864-340.22 0-8.377 15.133-25.672 24.05-42.967 23.51-28.915-1.081-74.043-33.509-73.503-65.125.27-3.783.811-7.296 1.892-10.809-5.566-9.463-4.845-15.282 5.405-11.62 3.243-5.134 7.026-9.458 11.08-13.782-2.57-10.917 1.27-14.094 11.079-9.188 4.594-3.243 9.998-6.485 15.944-9.188 0-15.757 11.839-11.131 17.295-5.675 12.467-1.78 20.129.709 26.753 5.675v-19.726c-12.987 0-40.641-11.375-45.94-36.212-4.974-20.725 2.607-38.075 25.132-47.56.81-5.945 8.107-14.052 14.862-15.944 7.567-1.892 12.431 4.594 14.052 10.269 7.425 0 17.757 1.465 21.078 8.107 5.405-.541 11.079-1.352 16.484-1.892-2.432-1.892-5.134-3.513-8.107-4.594-5.134-8.917-13.782-11.079-24.591-11.62 0-.81 0-1.621.27-2.702-19.727-.541-44.048-5.675-54.857-17.835-21.321-23.638-15.935-83.577 12.16-103.498 8.377-5.675 21.618-.811 22.699 9.728 2.425 20.598.399 26.833 26.212 25.942 8.107-7.836 16.755-14.592 26.483-19.997-14.862-1.352-28.914 1.621-43.778 3.783 12.752-12.48 23.953-25.442 56.748-42.427 23.511-11.89 49.993-20.808 76.205-23.239-18.646-7.837-39.993-11.891-59.721-16.484 76.475-16.214 174.569-22.159 244.289 37.562 18.105 15.403 32.427 36.211 42.696 59.992 39.799 4.853 36.47-5.581 38.643-25.132 1.081-10.269 14.322-15.403 22.699-9.458 14.862 10.539 22.159 30.806 24.59 48.101 2.162 17.835.27 41.345-12.43 55.127-10.809 12.16-34.32 17.565-53.776 18.105v2.703c-11.08.27-20.268 2.432-25.673 11.62-2.972 1.081-5.674 2.703-8.377 4.594 5.675.54 11.35 1.351 16.755 1.891 1.869-5.619 12.535-8.377 21.077-8.377 1.621-5.405 6.756-11.89 14.052-10.269s14.052 9.998 14.863 15.944c10.809 4.324 22.159 12.16 25.131 25.672 1.892 8.107 1.621 15.133.27 21.888-5.726 25.262-33.361 36.212-45.939 36.212 0 6.756 0 13.241-.27 19.726 8.01-6.006 16.367-7.158 26.752-5.675 5.919-5.919 17.565-9.41 17.565 5.675 5.675 2.703 11.349 5.945 15.944 9.188 10.1-5.051 13.669-.539 10.809 9.188 4.053 4.323 8.107 8.917 11.079 13.782 10.136-3.62 11.021 2.078 5.409 11.62zm-73.773-254.016c17.295 6.756 26.212 22.159 30.265 35.67 1.081-10.539-2.702-39.453-13.782-51.073-7.296-7.296-14.052-5.134-14.052.81.001 6.216-1.35 11.62-2.431 14.593zm-18.646 12.43c12.971 15.673 17.024 41.615 12.7 62.963 10.809-2.162 20.537-6.215 26.212-12.16 1.892-2.162 3.783-4.864 4.864-7.566-1.081-21.348-10.269-42.697-29.725-48.912-3.242 3.243-9.187 4.864-14.051 5.675zm-21.889.811c7.567 20.537 12.431 42.696 14.322 64.585 3.513 0 7.567-.27 11.62-.811 5.945-24.321-.27-51.614-14.052-63.504-3.783 0-8.107 0-11.89-.27zM77.768 167.372c-1.081-2.973-2.432-8.377-2.432-14.593 0-5.945-7.026-8.107-14.052-.81-11.35 11.62-14.863 40.534-13.782 51.073 4.053-13.512 12.971-28.915 30.266-35.67zm5.675 75.394c-4.324-21.348-.27-47.291 12.701-62.963-4.865-.811-10.809-2.432-14.052-5.675-19.457 6.215-28.375 27.563-29.726 48.912 1.351 2.702 2.972 5.404 4.864 7.566 5.675 6.215 15.403 9.998 26.213 12.16zm41.345-61.073c-5.134 1.081-9.998 2.973-14.862 4.865l-12.16 5.134v-.27c-7.296 14.052-9.999 34.319-5.405 52.965 4.594.541 8.647.811 12.7.811 2.432-22.159 9.188-43.778 19.727-63.505zm88.095-23.239c0 42.155 34.319 76.205 76.205 76.205s76.205-34.05 76.205-76.205c0-41.886-34.319-75.935-76.205-75.935s-76.205 34.049-76.205 75.935zm152.41 97.283c9.969 50.608 3.299 64.692 16.484 58.099 15.944-8.107 22.699-39.183 22.97-57.019-12.971-.81-26.213-.81-39.454-1.08zm-71.611-.541v-.27c-.27 5.134.27 38.103 4.324 41.075 11.079 5.405 39.453 4.594 51.073 1.081 5.405-1.621 2.432-37.022 1.621-41.886-18.916-.27-38.102-.27-57.018 0zm-14.053 0v-.27c-19.456.27-38.642.27-57.829.811-1.892 9.187-4.594 48.911 1.892 51.614 12.971 5.675 41.616 5.134 54.586 1.621 4.595-2.432 2.433-45.399 1.351-53.776zm-85.662 57.56c5.405 2.432 8.647 2.432 9.728-4.324 1.892-8.647 2.432-36.752 4.865-52.155-12.16.27-24.591.811-36.752 1.621-5.405 19.727.27 45.129 22.159 54.858zm-65.666-11.08c43.778 47.02 92.689 85.663 155.923 106.47 67.558-19.186 115.659-59.991 163.219-107.011-11.095-4.315-7.715-10.363-7.296-11.62-8.918-.81-17.835-1.892-26.483-2.702-9.458 32.968-35.94 52.965-46.75 31.616-2.702-5.134-3.513-11.62-4.594-16.754-3.783 8.377-13.242 8.107-24.591 8.918-13.241 1.081-31.617 1.351-44.048-2.972-2.972 12.971-11.079 12.971-26.752 14.322-14.052 1.352-48.642 4.054-54.857-10.809-1.081 28.644-35.13 9.998-45.129-7.026-3.243-5.675-5.405-11.35-7.026-17.565-7.837.81-15.673 1.621-23.511 2.702 2.443 3.663 1.549 9.052-8.105 12.431zM115.6 453.545c-5.674-23.239-18.646-49.722-33.508-54.046-22.429-6.756-68.909 23.51-66.207 54.586 12.701 19.457 39.994 35.67 59.181 36.481 17.835.81 35.94-11.08 39.724-28.914.539-2.432.81-5.134.81-8.107zm7.296-5.944c33.509-19.457 69.179-35.671 105.931-47.02-38.643-20.537-68.098-47.831-97.283-77.016-2.162 1.352-5.134 2.432-7.836 3.513-1.637 4.91 8.718 5.33 5.405 12.431-2.162 4.054-8.648 7.567-15.133 9.188-2.161 2.702-5.134 4.864-7.836 6.485h-.27c-.27 13.511-.27 27.024.27 40.535 8.939 15.964 15.426 33.314 16.752 51.884zm320.764 12.7c-36.752-21.348-74.044-41.345-115.659-52.965-13.782 6.215-27.833 11.349-42.155 15.403-2.162.811-2.162.811-4.324 0-11.89-3.783-23.239-8.107-34.859-13.241-40.265 11.62-77.286 29.185-112.416 50.803h-.27v.27c.27 0 .27 0 .27-.27 103.227 4.054 206.455 3.513 309.413 0zm27.023-64.045l-.27.27c.541-13.782.811-27.563.811-41.345-2.973-1.621-5.675-4.054-8.107-6.756-6.485-1.351-12.971-5.134-15.133-8.918-1.892-4.053 1.351-7.566 5.945-10.269-.27-.541-.541-1.621-.541-2.432-2.972-.811-5.405-1.892-7.567-3.243-31.616 29.455-65.396 56.749-103.498 76.746 38.914 11.62 75.935 28.104 111.875 47.561 1.05-14.692 7.231-35.749 16.485-51.614zm23.24 3.244c-14.593 4.323-27.834 30.806-33.509 54.046 0 23.826 21.278 37.897 40.534 37.022 19.186-.811 46.48-17.024 59.181-36.481 2.973-31.077-43.507-61.344-66.206-54.587zM290.709 134.133c.045 0 .089.003.134.003.046 0 .09-.003.136-.003h-.27zm0 96.743c28.645 0 51.884-21.618 51.884-48.371 0-36.092-40.507-58.079-72.151-44.318 9.458 2.972 16.484 11.62 16.484 21.618 0 23.257-33.291 31.955-46.48 11.35-7.297 34.067 19.368 59.721 50.263 59.721zM68.039 474.083c.54 6.486 12.16 12.701 21.618 9.458 6.756-2.703 14.593-10.539 17.295-16.214 2.973-7.026-1.081-19.997-9.728-18.375-8.917 1.621-29.725 16.754-29.185 25.131zm410.75-25.131c-8.377-1.621-12.431 11.349-9.458 18.375 2.432 5.675 10.269 13.511 17.295 16.214 9.187 3.243 21.078-2.972 21.348-9.458.811-8.377-20.267-23.51-29.185-25.131z"],osi:[495,512,[],"f41a","M0 259.2C2.3 123.4 97.4 26.8 213.8 11.1c138.8-18.6 255.6 75.8 278 201.1 21.3 118.8-44 230-151.6 274-9.3 3.8-14.4 1.7-18-7.7-17.8-46.3-35.6-92.7-53.4-139-3.1-8.1-1-13.2 7-16.8 24.2-11 39.3-29.4 43.3-55.8 6.4-42.4-24.5-78.7-64.5-82.2-39-3.4-71.8 23.7-77.5 59.7-5.2 33 11.1 63.7 41.9 77.7 9.6 4.4 11.5 8.6 7.8 18.4-17.9 46.6-35.8 93.2-53.7 139.9-2.6 6.9-8.3 9.3-15.5 6.5-52.6-20.3-101.4-61-130.8-119C1.9 318.7 1.6 280.2 0 259.2zm20.9-1.9c.4 6.6.6 14.3 1.3 22.1 6.3 71.9 49.6 143.5 131 183.1 3.2 1.5 4.4.8 5.6-2.3 14.9-39.1 29.9-78.2 45-117.3 1.3-3.3.6-4.8-2.4-6.7-31.6-19.9-47.3-48.5-45.6-86 1-21.6 9.3-40.5 23.8-56.3 30-32.7 77-39.8 115.5-17.6 31.9 18.4 49.5 53.8 45.2 90.4-3.6 30.6-19.3 53.9-45.7 69.8-2.7 1.6-3.5 2.9-2.3 6 15.2 39.2 30.2 78.4 45.2 117.7 1.2 3.1 2.4 3.8 5.6 2.3 35.5-16.6 65.2-40.3 88.1-72 34.8-48.2 49.1-101.9 42.3-161C459.8 112 354.1 14.7 218 31.5 111.9 44.5 22.7 134 20.9 257.3z"],page4:[496,512,[],"f3d7","M248 504C111 504 0 393 0 256S111 8 248 8c20.9 0 41.3 2.6 60.7 7.5L42.3 392H248v112zm0-143.6V146.8L98.6 360.4H248zm96 31.6v92.7c45.7-19.2 84.5-51.7 111.4-92.7H344zm57.4-138.2l-21.2 8.4 21.2 8.3v-16.7zm-20.3 54.5c-6.7 0-8 6.3-8 12.9v7.7h16.2v-10c0-5.9-2.3-10.6-8.2-10.6zM496 256c0 37.3-8.2 72.7-23 104.4H344V27.3C433.3 64.8 496 153.1 496 256zM360.4 143.6h68.2V96h-13.9v32.6h-13.9V99h-13.9v29.6h-12.7V96h-13.9v47.6zm68.1 185.3H402v-11c0-15.4-5.6-25.2-20.9-25.2-15.4 0-20.7 10.6-20.7 25.9v25.3h68.2v-15zm0-103l-68.2 29.7V268l68.2 29.5v-16.6l-14.4-5.7v-26.5l14.4-5.9v-16.9zm-4.8-68.5h-35.6V184H402v-12.2h11c8.6 15.8 1.3 35.3-18.6 35.3-22.5 0-28.3-25.3-15.5-37.7l-11.6-10.6c-16.2 17.5-12.2 63.9 27.1 63.9 34 0 44.7-35.9 29.3-65.3z"],pagelines:[384,512,[],"f18c","M384 312.7c-55.1 136.7-187.1 54-187.1 54-40.5 81.8-107.4 134.4-184.6 134.7-16.1 0-16.6-24.4 0-24.4 64.4-.3 120.5-42.7 157.2-110.1-41.1 15.9-118.6 27.9-161.6-82.2 109-44.9 159.1 11.2 178.3 45.5 9.9-24.4 17-50.9 21.6-79.7 0 0-139.7 21.9-149.5-98.1 119.1-47.9 152.6 76.7 152.6 76.7 1.6-16.7 3.3-52.6 3.3-53.4 0 0-106.3-73.7-38.1-165.2 124.6 43 61.4 162.4 61.4 162.4.5 1.6.5 23.8 0 33.4 0 0 45.2-89 136.4-57.5-4.2 134-141.9 106.4-141.9 106.4-4.4 27.4-11.2 53.4-20 77.5 0 0 83-91.8 172-20z"],palfed:[560,512,[],"f3d8","M376.9 194.1c0-47.4-55.2-44.2-95.4-29.8-1.3 39.4-2.5 80.7-3 119.8.7 2.8 2.6 6.2 15.1 6.2 36.7-.1 83.3-42.9 83.3-96.2zm-194.5 72.2c.2 0 6.5-2.7 11.2-2.7 26.6 0 20.7 44.1-14.4 44.1-21.5 0-37.1-18.1-37.1-43 0-42 42.9-95.6 100.7-126.5 1-12.4 3-22 10.5-28.2 11.2-9 26.6-3.5 29.5 11.1 72.2-22.2 135.2 1 135.2 72 0 77.9-79.3 152.6-140.1 138.2-.1 39.4.9 74.4 2.7 100v.2c.2 3.4.6 12.5-5.3 19.1-9.6 10.6-33.4 10-36.4-22.3-4.1-44.4.2-206.1 1.4-242.5-21.5 15-58.5 50.3-58.5 75.9.1 2.4.3 3.9.6 4.6zM0 181.3s-.1 37.4 38.4 37.4h30l22.4 217.2s0 44.3 44.7 44.3h288.9s44.7-.4 44.7-44.3l22.4-217.2h30s38.4 1.2 38.4-37.4c0 0 .1-37.4-38.4-37.4h-30.1c-7.3-25.6-30.2-74.3-119.4-74.3h-28V50.5s-2.7-18.4-21.1-18.4h-85.8s-21.1 0-21.1 18.4v19.1h-28.1s-105 4.2-120.5 74.3h-29S0 142.7 0 181.3z"],patreon:[512,512,[],"f3d9","M489.6 200.2c0 92.5-75.2 167.7-167.7 167.7-92.7 0-168.2-75.2-168.2-167.7 0-92.7 75.5-168.2 168.2-168.2 92.5 0 167.7 75.4 167.7 168.2zM22.4 480h82.1V32H22.4v448z"],paypal:[384,512,[],"f1ed","M111.4 295.9c-3.5 19.2-17.4 108.7-21.5 134-.3 1.8-1 2.5-3 2.5H12.3c-7.6 0-13.1-6.6-12.1-13.9L58.8 46.6c1.5-9.6 10.1-16.9 20-16.9 152.3 0 165.1-3.7 204 11.4 60.1 23.3 65.6 79.5 44 140.3-21.5 62.6-72.5 89.5-140.1 90.3-43.4.7-69.5-7-75.3 24.2zM357.1 152c-1.8-1.3-2.5-1.8-3 1.3-2 11.4-5.1 22.5-8.8 33.6-39.9 113.8-150.5 103.9-204.5 103.9-6.1 0-10.1 3.3-10.9 9.4-22.6 140.4-27.1 169.7-27.1 169.7-1 7.1 3.5 12.9 10.6 12.9h63.5c8.6 0 15.7-6.3 17.4-14.9.7-5.4-1.1 6.1 14.4-91.3 4.6-22 14.3-19.7 29.3-19.7 71 0 126.4-28.8 142.9-112.3 6.5-34.8 4.6-71.4-23.8-92.6z"],periscope:[448,512,[],"f3da","M370 63.6C331.4 22.6 280.5 0 226.6 0 111.9 0 18.5 96.2 18.5 214.4c0 75.1 57.8 159.8 82.7 192.7C137.8 455.5 192.6 512 226.6 512c41.6 0 112.9-94.2 120.9-105 24.6-33.1 82-118.3 82-192.6 0-56.5-21.1-110.1-59.5-150.8zM226.6 493.9c-42.5 0-190-167.3-190-279.4 0-107.4 83.9-196.3 190-196.3 100.8 0 184.7 89 184.7 196.3.1 112.1-147.4 279.4-184.7 279.4zM338 206.8c0 59.1-51.1 109.7-110.8 109.7-100.6 0-150.7-108.2-92.9-181.8v.4c0 24.5 20.1 44.4 44.8 44.4 24.7 0 44.8-19.9 44.8-44.4 0-18.2-11.1-33.8-26.9-40.7 76.6-19.2 141 39.3 141 112.4z"],phabricator:[496,512,[],"f3db","M323 262.1l-.1-13s21.7-19.8 21.1-21.2l-9.5-20c-.6-1.4-29.5-.5-29.5-.5l-9.4-9.3s.2-28.5-1.2-29.1l-20.1-9.2c-1.4-.6-20.7 21-20.7 21l-13.1-.2s-20.5-21.4-21.9-20.8l-20 8.3c-1.4.5.2 28.9.2 28.9l-9.1 9.1s-29.2-.9-29.7.4l-8.1 19.8c-.6 1.4 21 21 21 21l.1 12.9s-21.7 19.8-21.1 21.2l9.5 20c.6 1.4 29.5.5 29.5.5l9.4 9.3s-.2 31.8 1.2 32.3l20.1 8.3c1.4.6 20.7-23.5 20.7-23.5l13.1.2s20.5 23.8 21.8 23.3l20-7.5c1.4-.6-.2-32.1-.2-32.1l9.1-9.1s29.2.9 29.7-.5l8.1-19.8c.7-1.1-20.9-20.7-20.9-20.7zm-44.9-8.7c.7 17.1-12.8 31.6-30.1 32.4-17.3.8-32.1-12.5-32.8-29.6-.7-17.1 12.8-31.6 30.1-32.3 17.3-.8 32.1 12.5 32.8 29.5zm201.2-37.9l-97-97-.1.1c-75.1-73.3-195.4-72.8-269.8 1.6-50.9 51-27.8 27.9-95.7 95.3-22.3 22.3-22.3 58.7 0 81 69.9 69.4 46.4 46 97.4 97l.1-.1c75.1 73.3 195.4 72.9 269.8-1.6 51-50.9 27.9-27.9 95.3-95.3 22.3-22.3 22.3-58.7 0-81zM140.4 363.8c-59.6-59.5-59.6-156 0-215.5 59.5-59.6 156-59.5 215.6 0 59.5 59.5 59.6 156 0 215.6-59.6 59.5-156 59.4-215.6-.1z"],"phoenix-framework":[640,512,[],"f3dc","M213.2 339.2c3.8-.1 22.9-1.4 25.6-2.2-2.4-2.7-43.6-1-68.1-49.7-4.3-8.7-7.5-17.6-6.4-27.6 2.9-25.5 32.9-30 52.1-18.5 36 21.6 63.4 91.5 113.8 97.6 37.1 4.5 84.7-17 108.3-45.4-.6-.1-.8-.2-1-.1-.4.1-.8.2-1.1.3-33.4 12.1-94.4 9.7-134.8-14.8-37.7-22.8-53.2-58.8-51.9-74.7 1.8-21.4 22.9-23.2 36-19.6 14.4 4 24.4 17.6 39 27.4 15.6 10.4 33 13.7 51.3 10.3 14.9-2.7 34.4-12.3 36.5-14.5-1.1-.1-1.8-.1-2.5-.2-6.2-.6-12.4-.8-18.6-1.7C280.1 189.3 262.5 42 138.7 32.5c-44.4-3.4-99.6 8.1-136.5 35-.8.6-1.5 1.2-2.2 1.8.1.2.1.3.2.5.8-.1 1.6-.1 2.4-.2 6.3-1 12.5-.8 18.8.3 23.9 4.3 47.8 23.1 56 76.6 5.3 34.3-.7 50.9 8 86.2 18.9 77.2 91 107.8 127.8 106.5zM75.4 59.5c-.9-1-.9-1.2-1.3-2 12.1-2.6 24.3-4.1 36.7-4.8-1.1 14.7-22.3 21.4-35.4 6.8zm197.2 350.9c-42.9 1.2-92.1-26.8-123.7-61.5-4.6-5-16.8-20.3-18.6-23.4l.4-.4c6.6 4.1 25.7 18.7 54.9 27.1 24.2 7 48.1 6.3 71.7-3.3 22.7-9.3 41-.5 43.1 2.9-18.5 3.8-20.1 4.4-24.1 7.9-5.1 4.4-4.6 11.7 7 17.2 26.2 12.4 63-2.8 97.3 25.4 2.4 2 8.1 7.8 10.1 10.7-.1.2-.3.3-.4.5-4.8-1.5-16.5-7.5-40.2-9.3-24.7-2-46.3 5.4-77.5 6.2zm175-252.2c16.4-5.2 41.4-13.4 66.6-3.3 16.1 6.5 26.2 18.7 32.1 34.7 3.5 9.4 5.1 19.7 5.1 28.8-.2 0-.4 0-.6.1-.2-.4-.4-.9-.5-1.3-5-22-29.9-43.8-67.7-29.9-50.2 18.6-130.5 9.7-177.2-48-.7-.9-2.4-1.7-1.3-3.2.1-.2 2.1.6 3 1.3 18.1 13.5 38.3 21.9 60.4 26.2 30.6 5.9 54.7 2.6 80.1-5.4zm102.8 117.6c-32.4.2-33.8 50.2-103.7 64.4-18.3 3.7-38.7 4.6-45 4.2v-.4c2.8-1.5 14.7-2.6 29.7-16.6 7.9-7.3 15.3-15.2 22.8-22.9 19.6-20.3 41.5-42.3 82-39 23.1 1.8 29.3 8.2 36.2 12.7.3.2.4.5.7.9-.5 0-.7.1-.9 0-7-2.7-14.3-3.3-21.8-3.3zm-12.3-24.2c-.1.2-.1.4-.2.6-29-4.4-48.1-7.9-68.6 4-17 9.9-31.5 20.6-62.1 24.4-27.1 3.4-45.2 2.4-66.2-8-.3-.2-.6-.4-1-.6 0-.2.1-.3.1-.5 24.9 3.8 36.5 5.2 55.6-5.9 22.4-12.9 40.2-26.7 71.4-31 29.6-3.9 51.3 2.7 71 17zM269 91.9c-.6-.6-1.1-1.2-2.1-2.3 7.6 0 29.7-1.2 53.4 8.4 19.7 8 32.3 21.1 50.3 33 11.1 7.3 23.5 9.3 36.5 8.1 4.3-.4 8.5-1.2 12.8-1.7.4-.1.9 0 1.5.3-.6.4-1.2.9-1.8 1.2-8.1 4-16.7 6.3-25.6 7.2-26.1 2.6-50.4-3.7-73.5-15.4-19.4-10-36.5-23-51.5-38.8zm371.8 238.7c-3.5 3.1-22.7 11.6-42.8 5.3-12.3-3.9-19.5-14.9-31.6-24.1-10-7.6-20.9-7.9-28.2-8.4.6-.8.9-1.2 1.2-1.4 14.8-9.2 30.5-12.2 47.4-6.5 12.5 4.2 19.3 13.5 30.4 24.2 10.8 10.4 21 9.9 23.2 10.5.1-.1.2.1.4.4zM428 467.8c2.2 1.2 1.6 1.5 1.5 2-18.5-1.4-33.9-7.6-46.8-22.2-21.8-24.7-41.8-27.9-48.7-29.7.5-.2.8-.4 1.1-.4 13.1.1 26.2.7 39 3.9 25.3 6.4 35 25.4 41.6 35.4 3.2 4.7 7.4 8.3 12.3 11z"],"pied-piper":[640,512,[],"f2ae","M640 24.9c-80.8 53.6-89.4 92.5-96.4 104.4-6.7 12.2-11.7 60.3-23.3 83.6-11.7 23.6-54.2 42.2-66.1 50-11.7 7.8-28.3 38.1-41.9 64.2-108.1-4.4-167.4 38.8-259.2 93.6 29.4-9.7 43.3-16.7 43.3-16.7 94.2-36 139.3-68.3 281.1-49.2 1.1 0 1.9.6 2.8.8 3.9 2.2 5.3 6.9 3.1 10.8l-53.9 95.8c-2.5 4.7-7.8 7.2-13.1 6.1-126.8-23.8-226.9 17.3-318.9 18.6C24.1 488 0 453.4 0 451.8c0-1.1.6-1.7 1.7-1.7 0 0 38.3 0 103.1-15.3C178.4 294.5 244 245.4 315.4 245.4c0 0 71.7 0 90.6 61.9 22.8-39.7 28.3-49.2 28.3-49.2 5.3-9.4 35-77.2 86.4-141.4 51.5-64 90.4-79.9 119.3-91.8z"],"pied-piper-alt":[576,512,[],"f1a8","M242 187c6.3-11.8 13.2-17 25.9-21.8 27.3-10.3 40.2-30.5 58.9-51.1 11.9 8.4 12 24.6 31.6 23v21.8l6.3.3c37.4-14.4 74.7-30.2 106.6-54.6 48.3-36.8 52.9-50 81.3-100l2-2.6c-.6 14.1-6.3 27.3-12.4 39.9-30.5 63.8-78.7 100.3-146.8 116.7-12.4 2.9-26.4 3.2-37.6 8.9 1.4 9.8 13.2 18.1 13.2 23 0 3.4-5.5 7.2-7.5 8.6-11.2-12.9-16.1-19.3-22.7-22.1-7.6-3.5-63.9-6.4-98.8 10zm137.9 256.9c-19 0-64.1 9.5-79.9 19.8l6.9 45.1c35.7 6.1 70.1 3.6 106-9.8-4.8-10-23.5-55.1-33-55.1zM244 246c-3.2-2-6.3-2.9-10.1-2.9-6.6 0-12.6 3.2-19.3 3.7l1.7 4.9L244 246zm-12.6 31.8l24.1 61.2 21-13.8-31.3-50.9-13.8 3.5zM555.5 0l-.6 1.1-.3.9.6-.6.3-1.4zm-59.2 382.1c-33.9-56.9-75.3-118.4-150-115.5l-.3-6c-1.1-13.5 32.8 3.2 35.1-31l-14.4 7.2c-19.8-45.7-8.6-54.3-65.5-54.3-14.7 0-26.7 1.7-41.4 4.6 2.9 18.6 2.2 36.7-10.9 50.3l19.5 5.5c-1.7 3.2-2.9 6.3-2.9 9.8 0 21 42.8 2.9 42.8 33.6 0 18.4-36.8 60.1-54.9 60.1-8 0-53.7-50-53.4-60.1l.3-4.6 52.3-11.5c13-2.6 12.3-22.7-2.9-22.7-3.7 0-43.1 9.2-49.4 10.6-2-5.2-7.5-14.1-13.8-14.1-3.2 0-6.3 3.2-9.5 4-9.2 2.6-31 2.9-21.5 20.1L15.9 298.5c-5.5 1.1-8.9 6.3-8.9 11.8 0 6 5.5 10.9 11.5 10.9 8 0 131.3-28.4 147.4-32.2 2.6 3.2 4.6 6.3 7.8 8.6 20.1 14.4 59.8 85.9 76.4 85.9 24.1 0 58-22.4 71.3-41.9 3.2-4.3 6.9-7.5 12.4-6.9.6 13.8-31.6 34.2-33 43.7-1.4 10.2-1 35.2-.3 41.1 26.7 8.1 52-3.6 77.9-2.9 4.3-21 10.6-41.9 9.8-63.5l-.3-9.5c-1.4-34.2-10.9-38.5-34.8-58.6-1.1-1.1-2.6-2.6-3.7-4 2.2-1.4 1.1-1 4.6-1.7 88.5 0 56.3 183.6 111.5 229.9 33.1-15 72.5-27.9 103.5-47.2-29-25.6-52.6-45.7-72.7-79.9zm-196.2 46v27.3l11.8-3.4-2.9-23.8h-8.9zm76.1 2.9c0-1.4-.6-3.2-.9-4.6-26.8 0-36.9 3.8-59.5 6.3l2 12.4c9-1.5 58.4-6.6 58.4-14.1z"],"pied-piper-pp":[448,512,[],"f1a7","M205.3 174.6c0 21.1-14.2 38.1-31.7 38.1-7.1 0-12.8-1.2-17.2-3.7v-68c4.4-2.7 10.1-4.2 17.2-4.2 17.5 0 31.7 16.9 31.7 37.8zm52.6 67c-7.1 0-12.8 1.5-17.2 4.2v68c4.4 2.5 10.1 3.7 17.2 3.7 17.4 0 31.7-16.9 31.7-37.8 0-21.1-14.3-38.1-31.7-38.1zM448 80v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V80c0-26.5 21.5-48 48-48h352c26.5 0 48 21.5 48 48zM185 255.1c41 0 74.2-35.6 74.2-79.6 0-44-33.2-79.6-74.2-79.6-12 0-24.1 3.2-34.6 8.8h-45.7V311l51.8-10.1v-50.6c8.6 3.1 18.1 4.8 28.5 4.8zm158.4 25.3c0-44-33.2-79.6-73.9-79.6-3.2 0-6.4.2-9.6.7-3.7 12.5-10.1 23.8-19.2 33.4-13.8 15-32.2 23.8-51.8 24.8V416l51.8-10.1v-50.6c8.6 3.2 18.2 4.7 28.7 4.7 40.8 0 74-35.6 74-79.6z"],pinterest:[496,512,[],"f0d2","M496 256c0 137-111 248-248 248-25.6 0-50.2-3.9-73.4-11.1 10.1-16.5 25.2-43.5 30.8-65 3-11.6 15.4-59 15.4-59 8.1 15.4 31.7 28.5 56.8 28.5 74.8 0 128.7-68.8 128.7-154.3 0-81.9-66.9-143.2-152.9-143.2-107 0-163.9 71.8-163.9 150.1 0 36.4 19.4 81.7 50.3 96.1 4.7 2.2 7.2 1.2 8.3-3.3.8-3.4 5-20.3 6.9-28.1.6-2.5.3-4.7-1.7-7.1-10.1-12.5-18.3-35.3-18.3-56.6 0-54.7 41.4-107.6 112-107.6 60.9 0 103.6 41.5 103.6 100.9 0 67.1-33.9 113.6-78 113.6-24.3 0-42.6-20.1-36.7-44.8 7-29.5 20.5-61.3 20.5-82.6 0-19-10.2-34.9-31.4-34.9-24.9 0-44.9 25.7-44.9 60.2 0 22 7.4 36.8 7.4 36.8s-24.5 103.8-29 123.2c-5 21.4-3 51.6-.9 71.2C65.4 450.9 0 361.1 0 256 0 119 111 8 248 8s248 111 248 248z"],"pinterest-p":[384,512,[],"f231","M204 6.5C101.4 6.5 0 74.9 0 185.6 0 256 39.6 296 63.6 296c9.9 0 15.6-27.6 15.6-35.4 0-9.3-23.7-29.1-23.7-67.8 0-80.4 61.2-137.4 140.4-137.4 68.1 0 118.5 38.7 118.5 109.8 0 53.1-21.3 152.7-90.3 152.7-24.9 0-46.2-18-46.2-43.8 0-37.8 26.4-74.4 26.4-113.4 0-66.2-93.9-54.2-93.9 25.8 0 16.8 2.1 35.4 9.6 50.7-13.8 59.4-42 147.9-42 209.1 0 18.9 2.7 37.5 4.5 56.4 3.4 3.8 1.7 3.4 6.9 1.5 50.4-69 48.6-82.5 71.4-172.8 12.3 23.4 44.1 36 69.3 36 106.2 0 153.9-103.5 153.9-196.8C384 71.3 298.2 6.5 204 6.5z"],"pinterest-square":[448,512,[],"f0d3","M448 80v352c0 26.5-21.5 48-48 48H154.4c9.8-16.4 22.4-40 27.4-59.3 3-11.5 15.3-58.4 15.3-58.4 8 15.3 31.4 28.2 56.3 28.2 74.1 0 127.4-68.1 127.4-152.7 0-81.1-66.2-141.8-151.4-141.8-106 0-162.2 71.1-162.2 148.6 0 36 19.2 80.8 49.8 95.1 4.7 2.2 7.1 1.2 8.2-3.3.8-3.4 5-20.1 6.8-27.8.6-2.5.3-4.6-1.7-7-10.1-12.3-18.3-34.9-18.3-56 0-54.2 41-106.6 110.9-106.6 60.3 0 102.6 41.1 102.6 99.9 0 66.4-33.5 112.4-77.2 112.4-24.1 0-42.1-19.9-36.4-44.4 6.9-29.2 20.3-60.7 20.3-81.8 0-53-75.5-45.7-75.5 25 0 21.7 7.3 36.5 7.3 36.5-31.4 132.8-36.1 134.5-29.6 192.6l2.2.8H48c-26.5 0-48-21.5-48-48V80c0-26.5 21.5-48 48-48h352c26.5 0 48 21.5 48 48z"],playstation:[576,512,[],"f3df","M570.9 372.3c-11.3 14.2-38.8 24.3-38.8 24.3L327 470.2v-54.3l150.9-53.8c17.1-6.1 19.8-14.8 5.8-19.4-13.9-4.6-39.1-3.3-56.2 2.9L327 381.1v-56.4c23.2-7.8 47.1-13.6 75.7-16.8 40.9-4.5 90.9.6 130.2 15.5 44.2 14 49.2 34.7 38 48.9zm-224.4-92.5v-139c0-16.3-3-31.3-18.3-35.6-11.7-3.8-19 7.1-19 23.4v347.9l-93.8-29.8V32c39.9 7.4 98 24.9 129.2 35.4C424.1 94.7 451 128.7 451 205.2c0 74.5-46 102.8-104.5 74.6zM43.2 410.2c-45.4-12.8-53-39.5-32.3-54.8 19.1-14.2 51.7-24.9 51.7-24.9l134.5-47.8v54.5l-96.8 34.6c-17.1 6.1-19.7 14.8-5.8 19.4 13.9 4.6 39.1 3.3 56.2-2.9l46.4-16.9v48.8c-51.6 9.3-101.4 7.3-153.9-10z"],"product-hunt":[512,512,[],"f288","M326.3 218.8c0 20.5-16.7 37.2-37.2 37.2h-70.3v-74.4h70.3c20.5 0 37.2 16.7 37.2 37.2zM504 256c0 137-111 248-248 248S8 393 8 256 119 8 256 8s248 111 248 248zm-128.1-37.2c0-47.9-38.9-86.8-86.8-86.8H169.2v248h49.6v-74.4h70.3c47.9 0 86.8-38.9 86.8-86.8z"],pushed:[432,512,[],"f3e1","M407 111.9l-98.5-9 14-33.4c10.4-23.5-10.8-40.4-28.7-37L22.5 76.9c-15.1 2.7-26 18.3-21.4 36.6l105.1 348.3c6.5 21.3 36.7 24.2 47.7 7l35.3-80.8 235.2-231.3c16.4-16.8 4.3-42.9-17.4-44.8zM297.6 53.6c5.1-.7 7.5 2.5 5.2 7.4L286 100.9 108.6 84.6l189-31zM22.7 107.9c-3.1-5.1 1-10 6.1-9.1l248.7 22.7-96.9 230.7L22.7 107.9zM136 456.4c-2.6 4-7.9 3.1-9.4-1.2L43.5 179.7l127.7 197.6c-7 15-35.2 79.1-35.2 79.1zm272.8-314.5L210.1 337.3l89.7-213.7 106.4 9.7c4 1.1 5.7 5.3 2.6 8.6z"],python:[448,512,[],"f3e2","M167.8 36.4c-45.2 8-53.4 24.7-53.4 55.6v40.7h106.9v13.6h-147c-31.1 0-58.3 18.7-66.8 54.2-9.8 40.7-10.2 66.1 0 108.6 7.6 31.6 25.7 54.2 56.8 54.2H101v-48.8c0-35.3 30.5-66.4 66.8-66.4h106.8c29.7 0 53.4-24.5 53.4-54.3V91.9c0-29-24.4-50.7-53.4-55.6-35.8-5.9-74.7-5.6-106.8.1zm-6.7 28.4c11 0 20.1 9.2 20.1 20.4s-9 20.3-20.1 20.3c-11.1 0-20.1-9.1-20.1-20.3.1-11.3 9-20.4 20.1-20.4zm185.2 81.4v47.5c0 36.8-31.2 67.8-66.8 67.8H172.7c-29.2 0-53.4 25-53.4 54.3v101.8c0 29 25.2 46 53.4 54.3 33.8 9.9 66.3 11.7 106.8 0 26.9-7.8 53.4-23.5 53.4-54.3v-40.7H226.2v-13.6h160.2c31.1 0 42.6-21.7 53.4-54.2 11.2-33.5 10.7-65.7 0-108.6-7.7-30.9-22.3-54.2-53.4-54.2h-40.1zM286.2 404c11.1 0 20.1 9.1 20.1 20.3 0 11.3-9 20.4-20.1 20.4-11 0-20.1-9.2-20.1-20.4.1-11.3 9.1-20.3 20.1-20.3z"],qq:[448,512,[],"f1d6","M433.754 420.445c-11.526 1.393-44.86-52.741-44.86-52.741 0 31.345-16.136 72.247-51.051 101.786 16.842 5.192 54.843 19.167 45.803 34.421-7.316 12.343-125.51 7.881-159.632 4.037-34.122 3.844-152.316 8.306-159.632-4.037-9.045-15.25 28.918-29.214 45.783-34.415-34.92-29.539-51.059-70.445-51.059-101.792 0 0-33.334 54.134-44.859 52.741-5.37-.65-12.424-29.644 9.347-99.704 10.261-33.024 21.995-60.478 40.144-105.779C60.683 98.063 108.982.006 224 0c113.737.006 163.156 96.133 160.264 214.963 18.118 45.223 29.912 72.85 40.144 105.778 21.768 70.06 14.716 99.053 9.346 99.704z"],quora:[448,512,[],"f2c4","M440.5 386.7h-29.3c-1.5 13.5-10.5 30.8-33 30.8-20.5 0-35.3-14.2-49.5-35.8 44.2-34.2 74.7-87.5 74.7-153C403.5 111.2 306.8 32 205 32 105.3 32 7.3 111.7 7.3 228.7c0 134.1 131.3 221.6 249 189C276 451.3 302 480 351.5 480c81.8 0 90.8-75.3 89-93.3zM297 329.2C277.5 300 253.3 277 205.5 277c-30.5 0-54.3 10-69 22.8l12.2 24.3c6.2-3 13-4 19.8-4 35.5 0 53.7 30.8 69.2 61.3-10 3-20.7 4.2-32.7 4.2-75 0-107.5-53-107.5-156.7C97.5 124.5 130 71 205 71c76.2 0 108.7 53.5 108.7 157.7.1 41.8-5.4 75.6-16.7 100.5z"],ravelry:[512,512,[],"f2d9","M407.4 61.5C331.6 22.1 257.8 31 182.9 66c-11.3 5.2-15.5 10.6-19.9 19-10.3 19.2-16.2 37.4-19.9 52.7-21.2 25.6-36.4 56.1-43.3 89.9-10.6 18-20.9 41.4-23.1 71.4 0 0-.7 7.6-.5 7.9-35.3-4.6-76.2-27-76.2-27 9.1 14.5 61.3 32.3 76.3 37.9 0 0 1.7 98 64.5 131.2-11.3-17.2-13.3-20.2-13.3-20.2S94.8 369 100.4 324.7c.7 0 1.5.2 2.2.2 23.9 87.4 103.2 151.4 196.9 151.4 6.2 0 12.1-.2 18-.7 14 1.5 27.6.5 40.1-3.9 6.9-2.2 13.8-6.4 20.2-10.8 70.2-39.1 100.9-82 123.1-147.7 5.4-16 8.1-35.5 9.8-52.2 8.7-82.3-30.6-161.6-103.3-199.5zM138.8 163.2s-1.2 12.3-.7 19.7c-3.4 2.5-10.1 8.1-18.2 16.7 5.2-12.8 11.3-25.1 18.9-36.4zm-31.2 121.9c4.4-17.2 13.3-39.1 29.8-55.1 0 0 1.7 48 15.8 90.1l-41.4-6.9c-2.2-9.2-3.5-18.5-4.2-28.1zm7.9 42.8c14.8 3.2 34 7.6 43.1 9.1 27.3 76.8 108.3 124.3 108.3 124.3 1 .5 1.7.7 2.7 1-73.1-11.6-132.7-64.7-154.1-134.4zM386 444.1c-14.5 4.7-36.2 8.4-64.7 3.7 0 0-91.1-23.1-127.5-107.8 38.2.7 52.4-.2 78-3.9 39.4-5.7 79-16.2 115-33 11.8-5.4 11.1-19.4 9.6-29.8-2-12.8-11.1-12.1-21.4-4.7 0 0-82 58.6-189.8 53.7-18.7-32-26.8-110.8-26.8-110.8 41.4-35.2 83.2-59.6 168.4-52.4.2-6.4 3-27.1-20.4-28.1 0 0-93.5-11.1-146 33.5 2.5-16.5 5.9-29.3 11.1-39.4 34.2-30.8 79-49.5 128.3-49.5 106.4 0 193 87.1 193 194.5-.2 76-43.8 142-106.8 174z"],react:[512,512,[],"f41b","M418.2 177.2c-5.4-1.8-10.8-3.5-16.2-5.1.9-3.7 1.7-7.4 2.5-11.1 12.3-59.6 4.2-107.5-23.1-123.3-26.3-15.1-69.2.6-112.6 38.4-4.3 3.7-8.5 7.6-12.5 11.5-2.7-2.6-5.5-5.2-8.3-7.7-45.5-40.4-91.1-57.4-118.4-41.5-26.2 15.2-34 60.3-23 116.7 1.1 5.6 2.3 11.1 3.7 16.7-6.4 1.8-12.7 3.8-18.6 5.9C38.3 196.2 0 225.4 0 255.6c0 31.2 40.8 62.5 96.3 81.5 4.5 1.5 9 3 13.6 4.3-1.5 6-2.8 11.9-4 18-10.5 55.5-2.3 99.5 23.9 114.6 27 15.6 72.4-.4 116.6-39.1 3.5-3.1 7-6.3 10.5-9.7 4.4 4.3 9 8.4 13.6 12.4 42.8 36.8 85.1 51.7 111.2 36.6 27-15.6 35.8-62.9 24.4-120.5-.9-4.4-1.9-8.9-3-13.5 3.2-.9 6.3-1.9 9.4-2.9 57.7-19.1 99.5-50 99.5-81.7 0-30.3-39.4-59.7-93.8-78.4zM282.9 92.3c37.2-32.4 71.9-45.1 87.7-36 16.9 9.7 23.4 48.9 12.8 100.4-.7 3.4-1.4 6.7-2.3 10-22.2-5-44.7-8.6-67.3-10.6-13-18.6-27.2-36.4-42.6-53.1 3.9-3.7 7.7-7.2 11.7-10.7zm-130 189.1c4.6 8.8 9.3 17.5 14.3 26.1 5.1 8.7 10.3 17.4 15.8 25.9-15.6-1.7-31.1-4.2-46.4-7.5 4.4-14.4 9.9-29.3 16.3-44.5zm0-50.6c-6.3-14.9-11.6-29.5-16-43.6 14.4-3.2 29.7-5.8 45.6-7.8-5.3 8.3-10.5 16.8-15.4 25.4-4.9 8.5-9.7 17.2-14.2 26zm11.4 25.3c6.6-13.8 13.8-27.3 21.4-40.6 7.6-13.3 15.8-26.2 24.4-38.9 15-1.1 30.3-1.7 45.9-1.7 15.6 0 31 .6 45.9 1.7 8.5 12.6 16.6 25.5 24.3 38.7 7.7 13.2 14.9 26.7 21.7 40.4-6.7 13.8-13.9 27.4-21.6 40.8-7.6 13.3-15.7 26.2-24.2 39-14.9 1.1-30.4 1.6-46.1 1.6-15.7 0-30.9-.5-45.6-1.4-8.7-12.7-16.9-25.7-24.6-39-7.7-13.3-14.8-26.8-21.5-40.6zm180.6 51.2c5.1-8.8 9.9-17.7 14.6-26.7 6.4 14.5 12 29.2 16.9 44.3-15.5 3.5-31.2 6.2-47 8 5.4-8.4 10.5-17 15.5-25.6zm14.4-76.5c-4.7-8.8-9.5-17.6-14.5-26.2-4.9-8.5-10-16.9-15.3-25.2 16.1 2 31.5 4.7 45.9 8-4.6 14.8-10 29.2-16.1 43.4zM256.2 118.3c10.5 11.4 20.4 23.4 29.6 35.8-19.8-.9-39.7-.9-59.5 0 9.8-12.9 19.9-24.9 29.9-35.8zM140.2 57c16.8-9.8 54.1 4.2 93.4 39 2.5 2.2 5 4.6 7.6 7-15.5 16.7-29.8 34.5-42.9 53.1-22.6 2-45 5.5-67.2 10.4-1.3-5.1-2.4-10.3-3.5-15.5-9.4-48.4-3.2-84.9 12.6-94zm-24.5 263.6c-4.2-1.2-8.3-2.5-12.4-3.9-21.3-6.7-45.5-17.3-63-31.2-10.1-7-16.9-17.8-18.8-29.9 0-18.3 31.6-41.7 77.2-57.6 5.7-2 11.5-3.8 17.3-5.5 6.8 21.7 15 43 24.5 63.6-9.6 20.9-17.9 42.5-24.8 64.5zm116.6 98c-16.5 15.1-35.6 27.1-56.4 35.3-11.1 5.3-23.9 5.8-35.3 1.3-15.9-9.2-22.5-44.5-13.5-92 1.1-5.6 2.3-11.2 3.7-16.7 22.4 4.8 45 8.1 67.9 9.8 13.2 18.7 27.7 36.6 43.2 53.4-3.2 3.1-6.4 6.1-9.6 8.9zm24.5-24.3c-10.2-11-20.4-23.2-30.3-36.3 9.6.4 19.5.6 29.5.6 10.3 0 20.4-.2 30.4-.7-9.2 12.7-19.1 24.8-29.6 36.4zm130.7 30c-.9 12.2-6.9 23.6-16.5 31.3-15.9 9.2-49.8-2.8-86.4-34.2-4.2-3.6-8.4-7.5-12.7-11.5 15.3-16.9 29.4-34.8 42.2-53.6 22.9-1.9 45.7-5.4 68.2-10.5 1 4.1 1.9 8.2 2.7 12.2 4.9 21.6 5.7 44.1 2.5 66.3zm18.2-107.5c-2.8.9-5.6 1.8-8.5 2.6-7-21.8-15.6-43.1-25.5-63.8 9.6-20.4 17.7-41.4 24.5-62.9 5.2 1.5 10.2 3.1 15 4.7 46.6 16 79.3 39.8 79.3 58 0 19.6-34.9 44.9-84.8 61.4zM256 210.2c25.3 0 45.8 20.5 45.8 45.8 0 25.3-20.5 45.8-45.8 45.8-25.3 0-45.8-20.5-45.8-45.8 0-25.3 20.5-45.8 45.8-45.8"],rebel:[512,512,[],"f1d0","M256.5 504C117.2 504 9 387.8 13.2 249.9 16 170.7 56.4 97.7 129.7 49.5c.3 0 1.9-.6 1.1.8-5.8 5.5-111.3 129.8-14.1 226.4 49.8 49.5 90 2.5 90 2.5 38.5-50.1-.6-125.9-.6-125.9-10-24.9-45.7-40.1-45.7-40.1l28.8-31.8c24.4 10.5 43.2 38.7 43.2 38.7.8-29.6-21.9-61.4-21.9-61.4L255.1 8l44.3 50.1c-20.5 28.8-21.9 62.6-21.9 62.6 13.8-23 43.5-39.3 43.5-39.3l28.5 31.8c-27.4 8.9-45.4 39.9-45.4 39.9-15.8 28.5-27.1 89.4.6 127.3 32.4 44.6 87.7-2.8 87.7-2.8 102.7-91.9-10.5-225-10.5-225-6.1-5.5.8-2.8.8-2.8 50.1 36.5 114.6 84.4 116.2 204.8C500.9 400.2 399 504 256.5 504z"],"red-river":[448,512,[],"f3e3","M353.2 32H94.8C42.4 32 0 74.4 0 126.8v258.4C0 437.6 42.4 480 94.8 480h258.4c52.4 0 94.8-42.4 94.8-94.8V126.8c0-52.4-42.4-94.8-94.8-94.8zM144.9 200.9v56.3c0 27-21.9 48.9-48.9 48.9V151.9c0-13.2 10.7-23.9 23.9-23.9h154.2c0 27-21.9 48.9-48.9 48.9h-56.3c-12.3-.6-24.6 11.6-24 24zm176.3 72h-56.3c-12.3-.6-24.6 11.6-24 24v56.3c0 27-21.9 48.9-48.9 48.9V247.9c0-13.2 10.7-23.9 23.9-23.9h154.2c0 27-21.9 48.9-48.9 48.9z"],reddit:[512,512,[],"f1a1","M201.5 305.5c-13.8 0-24.9-11.1-24.9-24.6 0-13.8 11.1-24.9 24.9-24.9 13.6 0 24.6 11.1 24.6 24.9 0 13.6-11.1 24.6-24.6 24.6zM504 256c0 137-111 248-248 248S8 393 8 256 119 8 256 8s248 111 248 248zm-132.3-41.2c-9.4 0-17.7 3.9-23.8 10-22.4-15.5-52.6-25.5-86.1-26.6l17.4-78.3 55.4 12.5c0 13.6 11.1 24.6 24.6 24.6 13.8 0 24.9-11.3 24.9-24.9s-11.1-24.9-24.9-24.9c-9.7 0-18 5.8-22.1 13.8l-61.2-13.6c-3-.8-6.1 1.4-6.9 4.4l-19.1 86.4c-33.2 1.4-63.1 11.3-85.5 26.8-6.1-6.4-14.7-10.2-24.1-10.2-34.9 0-46.3 46.9-14.4 62.8-1.1 5-1.7 10.2-1.7 15.5 0 52.6 59.2 95.2 132 95.2 73.1 0 132.3-42.6 132.3-95.2 0-5.3-.6-10.8-1.9-15.8 31.3-16 19.8-62.5-14.9-62.5zM302.8 331c-18.2 18.2-76.1 17.9-93.6 0-2.2-2.2-6.1-2.2-8.3 0-2.5 2.5-2.5 6.4 0 8.6 22.8 22.8 87.3 22.8 110.2 0 2.5-2.2 2.5-6.1 0-8.6-2.2-2.2-6.1-2.2-8.3 0zm7.7-75c-13.6 0-24.6 11.1-24.6 24.9 0 13.6 11.1 24.6 24.6 24.6 13.8 0 24.9-11.1 24.9-24.6 0-13.8-11-24.9-24.9-24.9z"],"reddit-alien":[512,512,[],"f281","M440.3 203.5c-15 0-28.2 6.2-37.9 15.9-35.7-24.7-83.8-40.6-137.1-42.3L293 52.3l88.2 19.8c0 21.6 17.6 39.2 39.2 39.2 22 0 39.7-18.1 39.7-39.7s-17.6-39.7-39.7-39.7c-15.4 0-28.7 9.3-35.3 22l-97.4-21.6c-4.9-1.3-9.7 2.2-11 7.1L246.3 177c-52.9 2.2-100.5 18.1-136.3 42.8-9.7-10.1-23.4-16.3-38.4-16.3-55.6 0-73.8 74.6-22.9 100.1-1.8 7.9-2.6 16.3-2.6 24.7 0 83.8 94.4 151.7 210.3 151.7 116.4 0 210.8-67.9 210.8-151.7 0-8.4-.9-17.2-3.1-25.1 49.9-25.6 31.5-99.7-23.8-99.7zM129.4 308.9c0-22 17.6-39.7 39.7-39.7 21.6 0 39.2 17.6 39.2 39.7 0 21.6-17.6 39.2-39.2 39.2-22 .1-39.7-17.6-39.7-39.2zm214.3 93.5c-36.4 36.4-139.1 36.4-175.5 0-4-3.5-4-9.7 0-13.7 3.5-3.5 9.7-3.5 13.2 0 27.8 28.5 120 29 149 0 3.5-3.5 9.7-3.5 13.2 0 4.1 4 4.1 10.2.1 13.7zm-.8-54.2c-21.6 0-39.2-17.6-39.2-39.2 0-22 17.6-39.7 39.2-39.7 22 0 39.7 17.6 39.7 39.7-.1 21.5-17.7 39.2-39.7 39.2z"],"reddit-square":[448,512,[],"f1a2","M283.2 345.5c2.7 2.7 2.7 6.8 0 9.2-24.5 24.5-93.8 24.6-118.4 0-2.7-2.4-2.7-6.5 0-9.2 2.4-2.4 6.5-2.4 8.9 0 18.7 19.2 81 19.6 100.5 0 2.4-2.3 6.6-2.3 9 0zm-91.3-53.8c0-14.9-11.9-26.8-26.5-26.8-14.9 0-26.8 11.9-26.8 26.8 0 14.6 11.9 26.5 26.8 26.5 14.6 0 26.5-11.9 26.5-26.5zm90.7-26.8c-14.6 0-26.5 11.9-26.5 26.8 0 14.6 11.9 26.5 26.5 26.5 14.9 0 26.8-11.9 26.8-26.5 0-14.9-11.9-26.8-26.8-26.8zM448 80v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V80c0-26.5 21.5-48 48-48h352c26.5 0 48 21.5 48 48zm-99.7 140.6c-10.1 0-19 4.2-25.6 10.7-24.1-16.7-56.5-27.4-92.5-28.6l18.7-84.2 59.5 13.4c0 14.6 11.9 26.5 26.5 26.5 14.9 0 26.8-12.2 26.8-26.8 0-14.6-11.9-26.8-26.8-26.8-10.4 0-19.3 6.2-23.8 14.9l-65.7-14.6c-3.3-.9-6.5 1.5-7.4 4.8l-20.5 92.8c-35.7 1.5-67.8 12.2-91.9 28.9-6.5-6.8-15.8-11-25.9-11-37.5 0-49.8 50.4-15.5 67.5-1.2 5.4-1.8 11-1.8 16.7 0 56.5 63.7 102.3 141.9 102.3 78.5 0 142.2-45.8 142.2-102.3 0-5.7-.6-11.6-2.1-17 33.6-17.2 21.2-67.2-16.1-67.2z"],rendact:[496,512,[],"f3e4","M248 8C111 8 0 119 0 256s111 248 248 248c18.6 0 36.7-2.1 54.1-5.9-5.6-7.4-10.8-14.4-15.9-21.3-12.4 2.1-25.2 3.3-38.3 3.3C124.3 480 24 379.7 24 256S124.3 32 248 32s224 100.3 224 224c0 71-33 134.2-84.5 175.3-25.9 18.8-39.1 21.4-83.5-44.2-78.7-112.9-48-71.1-73.7-108.3 72.8 8.9 228.5-72 168.6-168.6C314-26.8 15 93.8 59.7 226.4c3.2 9.8 14.4 38.6 45.6 38.6 2 0 2.6-.6 2-1.7-4.4-8.7-20.1-9.8-20.1-37.4 0-40.5 40.5-89.6 100.3-120 66.1-32.3 131.9-30.2 158.2 5.4 27.2 38.3-20.9 119.2-120.4 136.9 7.5-9.4 57-75.2 62.8-84 22.7-34.6 23.6-49 14-59.2-15.5-16.9-29.5-10.3-50.7-11.7-10.8-.9-113.7 181.2-136.4 216.9-5.9 9-21.2 34.1-21.2 50.9 0 21.3 2.8 51.4 20.6 51.4 10.6 0 8-18.7 8-26.6 0-12.9 27.4-49.4 74.8-104.6 20.4 36.1 57.7 114.3 130.2 209.7 98-33.1 168.5-125.8 168.5-235C496 119 385 8 248 8z"],renren:[512,512,[],"f18b","M214 169.1c0 110.4-61 205.4-147.6 247.4C30 373.2 8 317.7 8 256.6 8 133.9 97.1 32.2 214 12.5v156.6zM255 504c-42.9 0-83.3-11-118.5-30.4C193.7 437.5 239.9 382.9 255 319c15.5 63.9 61.7 118.5 118.8 154.7C338.7 493 298.3 504 255 504zm190.6-87.5C359 374.5 298 279.6 298 169.1V12.5c116.9 19.7 206 121.4 206 244.1 0 61.1-22 116.6-58.4 159.9z"],replyd:[448,512,[],"f3e6","M320 480H128C57.6 480 0 422.4 0 352V160C0 89.6 57.6 32 128 32h192c70.4 0 128 57.6 128 128v192c0 70.4-57.6 128-128 128zM193.4 273.2c-6.1-2-11.6-3.1-16.4-3.1-7.2 0-13.5 1.9-18.9 5.6-5.4 3.7-9.6 9-12.8 15.8h-1.1l-4.2-18.3h-28v138.9h36.1v-89.7c1.5-5.4 4.4-9.8 8.7-13.2 4.3-3.4 9.8-5.1 16.2-5.1 4.6 0 9.8 1 15.6 3.1l4.8-34zm115.2 103.4c-3.2 2.4-7.7 4.8-13.7 7.1-6 2.3-12.8 3.5-20.4 3.5-12.2 0-21.1-3-26.5-8.9-5.5-5.9-8.5-14.7-9-26.4h83.3c.9-4.8 1.6-9.4 2.1-13.9.5-4.4.7-8.6.7-12.5 0-10.7-1.6-19.7-4.7-26.9-3.2-7.2-7.3-13-12.5-17.2-5.2-4.3-11.1-7.3-17.8-9.2-6.7-1.8-13.5-2.8-20.6-2.8-21.1 0-37.5 6.1-49.2 18.3s-17.5 30.5-17.5 55c0 22.8 5.2 40.7 15.6 53.7 10.4 13.1 26.8 19.6 49.2 19.6 10.7 0 20.9-1.5 30.4-4.6 9.5-3.1 17.1-6.8 22.6-11.2l-12-23.6zm-21.8-70.3c3.8 5.4 5.3 13.1 4.6 23.1h-51.7c.9-9.4 3.7-17 8.2-22.6 4.5-5.6 11.5-8.5 21-8.5 8.2-.1 14.1 2.6 17.9 8zm79.9 2.5c4.1 3.9 9.4 5.8 16.1 5.8 7 0 12.6-1.9 16.7-5.8s6.1-9.1 6.1-15.6-2-11.6-6.1-15.4c-4.1-3.8-9.6-5.7-16.7-5.7-6.7 0-12 1.9-16.1 5.7-4.1 3.8-6.1 8.9-6.1 15.4s2 11.7 6.1 15.6zm0 100.5c4.1 3.9 9.4 5.8 16.1 5.8 7 0 12.6-1.9 16.7-5.8s6.1-9.1 6.1-15.6-2-11.6-6.1-15.4c-4.1-3.8-9.6-5.7-16.7-5.7-6.7 0-12 1.9-16.1 5.7-4.1 3.8-6.1 8.9-6.1 15.4 0 6.6 2 11.7 6.1 15.6z"],resolving:[496,512,[],"f3e7","M281.2 278.2c46-13.3 49.6-23.5 44-43.4L314 195.5c-6.1-20.9-18.4-28.1-71.1-12.8L54.7 236.8l28.6 98.6 197.9-57.2zM248.5 8C131.4 8 33.2 88.7 7.2 197.5l221.9-63.9c34.8-10.2 54.2-11.7 79.3-8.2 36.3 6.1 52.7 25 61.4 55.2l10.7 37.8c8.2 28.1 1 50.6-23.5 73.6-19.4 17.4-31.2 24.5-61.4 33.2L203 351.8l220.4 27.1 9.7 34.2-48.1 13.3-286.8-37.3 23 80.2c36.8 22 80.3 34.7 126.3 34.7 137 0 248.5-111.4 248.5-248.3C497 119.4 385.5 8 248.5 8zM38.3 388.6L0 256.8c0 48.5 14.3 93.4 38.3 131.8z"],rocketchat:[448,512,[],"f3e8","M448 256.2c0-87.2-99.6-153.3-219.8-153.3-18.8 0-37.3 1.6-55.3 4.8-11.1-10.5-24.2-20-38-27.4C61.2 44.2 0 79.4 0 79.4s56.9 47.1 47.6 88.3c-52.3 52.3-52.5 124.1 0 176.6C56.9 385.6 0 432.6 0 432.6s61.2 35.2 134.9-.8c13.8-7.5 26.9-16.9 38-27.4 18 3.2 36.5 4.8 55.3 4.8 120.3-.1 219.8-65.8 219.8-153zm-219.7 124c-23.7 0-46.3-2.8-67.3-7.8-21.3 25.8-68.1 61.7-113.6 50.1 14.8-16 36.7-43.1 32-87.6-27.3-21.4-43.6-48.7-43.6-78.5 0-68.4 86.2-123.9 192.5-123.9S420.8 188 420.8 256.4c0 68.3-86.2 123.8-192.5 123.8zm25.6-123.9c0 14.2-11.5 25.8-25.6 25.8-14.1 0-25.6-11.5-25.6-25.8 0-14.2 11.5-25.8 25.6-25.8 14.1 0 25.6 11.6 25.6 25.8zm88.9 0c0 14.2-11.4 25.8-25.6 25.8-14.1 0-25.6-11.5-25.6-25.8 0-14.2 11.4-25.8 25.6-25.8 14.1 0 25.6 11.6 25.6 25.8zm-177.9 0c0 14.2-11.4 25.8-25.6 25.8-14.1 0-25.6-11.5-25.6-25.8 0-14.2 11.4-25.8 25.6-25.8 14.2 0 25.6 11.6 25.6 25.8z"],rockrms:[496,512,[],"f3e9","M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm157.4 419.5h-90l-112-131.3c-17.9-20.4-3.9-56.1 26.6-56.1h75.3l-84.6-99.3-84.3 98.9h-90L193.5 67.2c14.4-18.4 41.3-17.3 54.5 0l157.7 185.1c19 22.8 2 57.2-27.6 56.1-.6 0-74.2.2-74.2.2l101.5 118.9z"],safari:[512,512,[],"f267","M236.9 256.8c0-9.1 6.6-17.7 16.3-17.7 8.9 0 17.4 6.4 17.4 16.1 0 9.1-6.4 17.7-16.1 17.7-9 0-17.6-6.7-17.6-16.1zM504 256c0 137-111 248-248 248S8 393 8 256 119 8 256 8s248 111 248 248zm-26.6 0c0-122.3-99.1-221.4-221.4-221.4S34.6 133.7 34.6 256 133.7 477.4 256 477.4 477.4 378.3 477.4 256zm-72.5 96.6c0 3.6 13 10.2 16.3 12.2-27.4 41.5-69.8 71.4-117.9 83.3l-4.4-18.5c-.3-2.5-1.9-2.8-4.2-2.8-1.9 0-3 2.8-2.8 4.2l4.4 18.8c-13.3 2.8-26.8 4.2-40.4 4.2-36.3 0-72-10.2-103-29.1 1.7-2.8 12.2-18 12.2-20.2 0-1.9-1.7-3.6-3.6-3.6-3.9 0-12.2 16.6-14.7 19.9-41.8-27.7-72-70.6-83.6-119.6l19.1-4.2c2.2-.6 2.8-2.2 2.8-4.2 0-1.9-2.8-3-4.4-2.8L62 294.5c-2.5-12.7-3.9-25.5-3.9-38.5 0-37.1 10.5-73.6 30.2-104.9 2.8 1.7 16.1 10.8 18.3 10.8 1.9 0 3.6-1.4 3.6-3.3 0-3.9-14.7-11.3-18-13.6 28.2-41.2 71.1-70.9 119.8-81.9l4.2 18.5c.6 2.2 2.2 2.8 4.2 2.8s3-2.8 2.8-4.4L219 61.7c12.2-2.2 24.6-3.6 37.1-3.6 37.1 0 73.3 10.5 104.9 30.2-1.9 2.8-10.8 15.8-10.8 18 0 1.9 1.4 3.6 3.3 3.6 3.9 0 11.3-14.4 13.3-17.7 41 27.7 70.3 70 81.7 118.2l-15.5 3.3c-2.5.6-2.8 2.2-2.8 4.4 0 1.9 2.8 3 4.2 2.8l15.8-3.6c2.5 12.7 3.9 25.7 3.9 38.7 0 36.3-10 72-28.8 102.7-2.8-1.4-14.4-9.7-16.6-9.7-2.1 0-3.8 1.7-3.8 3.6zm-33.2-242.2c-13 12.2-134.2 123.7-137.6 129.5l-96.6 160.5c12.7-11.9 134.2-124 137.3-129.3l96.9-160.7z"],sass:[640,512,[],"f41e","M551.1 291.9c-22.4.1-41.8 5.5-58 13.5-5.9-11.9-12-22.3-13-30.1-1.2-9.1-2.5-14.5-1.1-25.3s7.7-26.1 7.6-27.2c-.1-1.1-1.4-6.6-14.3-6.7-12.9-.1-24 2.5-25.3 5.9-1.3 3.4-3.8 11.1-5.3 19.1-2.3 11.7-25.8 53.5-39.1 75.3-4.4-8.5-8.1-16-8.9-22-1.2-9.1-2.5-14.5-1.1-25.3s7.7-26.1 7.6-27.2c-.1-1.1-1.4-6.6-14.3-6.7-12.9-.1-24 2.5-25.3 5.9-1.3 3.4-2.7 11.4-5.3 19.1-2.6 7.7-33.9 77.3-42.1 95.4-4.2 9.2-7.8 16.6-10.4 21.6s-.2.3-.4.9c-2.2 4.3-3.5 6.7-3.5 6.7v.1c-1.7 3.2-3.6 6.1-4.5 6.1-.6 0-1.9-8.4.3-19.9 4.7-24.2 15.8-61.8 15.7-63.1-.1-.7 2.1-7.2-7.3-10.7-9.1-3.3-12.4 2.2-13.2 2.2-.8 0-1.4 2-1.4 2s10.1-42.4-19.4-42.4c-18.4 0-44 20.2-56.6 38.5-7.9 4.3-25 13.6-43 23.5-6.9 3.8-14 7.7-20.7 11.4-.5-.5-.9-1-1.4-1.5-35.8-38.2-101.9-65.2-99.1-116.5 1-18.7 7.5-67.8 127.1-127.4 98-48.8 176.4-35.4 189.9-5.6 19.4 42.5-41.9 121.6-143.7 133-38.8 4.3-59.2-10.7-64.3-16.3-5.3-5.9-6.1-6.2-8.1-5.1-3.3 1.8-1.2 7 0 10.1 3 7.9 15.5 21.9 36.8 28.9 18.7 6.1 64.2 9.5 119.2-11.8C367 196.5 415.1 130.2 401 74.7 386.6 18.3 293.1-.2 204.6 31.2 151.9 49.9 94.9 79.3 53.9 117.6 5.2 163.2-2.6 202.9.6 219.5c11.4 58.9 92.6 97.3 125.1 125.7-1.6.9-3.1 1.7-4.5 2.5-16.3 8.1-78.2 40.5-93.7 74.7-17.5 38.8 2.9 66.6 16.3 70.4 41.8 11.6 84.6-9.3 107.6-43.6s20.2-79.1 9.6-99.5c-.1-.3-.3-.5-.4-.8 4.2-2.5 8.5-5 12.8-7.5 8.3-4.9 16.4-9.4 23.5-13.3-4 10.8-6.9 23.8-8.4 42.6-1.8 22 7.3 50.5 19.1 61.7 5.2 4.9 11.5 5 15.4 5 13.8 0 20-11.4 26.9-25 8.5-16.6 16-35.9 16-35.9s-9.4 52.2 16.3 52.2c9.4 0 18.8-12.1 23-18.3v.1s.2-.4.7-1.2c1-1.5 1.5-2.4 1.5-2.4v-.3c3.8-6.5 12.1-21.4 24.6-46 16.2-31.8 31.7-71.5 31.7-71.5s1.4 9.7 6.2 25.8c2.8 9.5 8.7 19.9 13.4 30-3.8 5.2-6.1 8.2-6.1 8.2s0 .1.1.2c-3 4-6.4 8.3-9.9 12.5-12.8 15.2-28 32.6-30 37.6-2.4 5.9-1.8 10.3 2.8 13.7 3.4 2.6 9.4 3 15.7 2.5 11.5-.8 19.6-3.6 23.5-5.4 6.2-2.2 13.4-5.7 20.2-10.6 12.5-9.2 20.1-22.4 19.4-39.8-.4-9.6-3.5-19.2-7.3-28.2 1.1-1.6 2.3-3.3 3.4-5 19.8-28.9 35.1-60.6 35.1-60.6s1.4 9.7 6.2 25.8c2.4 8.1 7.1 17 11.4 25.7-18.6 15.1-30.1 32.6-34.1 44.1-7.4 21.3-1.6 30.9 9.3 33.1 4.9 1 11.9-1.3 17.1-3.5 6.5-2.2 14.3-5.7 21.6-11.1 12.5-9.2 24.6-22.1 23.8-39.6-.3-7.9-2.5-15.8-5.4-23.4 15.7-6.6 36.1-10.2 62.1-7.2 55.7 6.5 66.6 41.3 64.5 55.8-2.1 14.6-13.8 22.6-17.7 25-3.9 2.4-5.1 3.3-4.8 5.1.5 2.6 2.3 2.5 5.6 1.9 4.6-.8 29.2-11.8 30.3-38.7 1.6-34-31.1-71.4-89-71.1zM121.8 436.6c-18.4 20.1-44.2 27.7-55.3 21.3C54.6 451 59.3 421.4 82 400c13.8-13 31.6-25 43.4-32.4 2.7-1.6 6.6-4 11.4-6.9.8-.5 1.2-.7 1.2-.7.9-.6 1.9-1.1 2.9-1.7 8.3 30.4.3 57.2-19.1 78.3zm134.4-91.4c-6.4 15.7-19.9 55.7-28.1 53.6-7-1.8-11.3-32.3-1.4-62.3 5-15.1 15.6-33.1 21.9-40.1 10.1-11.3 21.2-14.9 23.8-10.4 3.5 5.9-12.2 49.4-16.2 59.2zm111 53c-2.7 1.4-5.2 2.3-6.4 1.6-.9-.5 1.1-2.4 1.1-2.4s13.9-14.9 19.4-21.7c3.2-4 6.9-8.7 10.9-13.9 0 .5.1 1 .1 1.6-.1 17.9-17.3 30-25.1 34.8zm85.6-19.5c-2-1.4-1.7-6.1 5-20.7 2.6-5.7 8.6-15.3 19-24.5 1.2 3.8 1.9 7.4 1.9 10.8-.1 22.5-16.2 30.9-25.9 34.4z"],schlix:[448,512,[],"f3ea","M350.5 157.7l-54.2-46.1 73.4-39 78.3 44.2-97.5 40.9zM192 122.1l45.7-28.2 34.7 34.6-55.4 29-25-35.4zm-65.1 6.6l31.9-22.1L176 135l-36.7 22.5-12.4-28.8zm-23.3 88.2l-8.8-34.8 29.6-18.3 13.1 35.3-33.9 17.8zm-21.2-83.7l23.9-18.1 8.9 24-26.7 18.3-6.1-24.2zM59 206.5l-3.6-28.4 22.3-15.5 6.1 28.7L59 206.5zm-30.6 16.6l20.8-12.8 3.3 33.4-22.9 12-1.2-32.6zM1.4 268l19.2-10.2.4 38.2-21 8.8L1.4 268zm59.1 59.3l-28.3 8.3-1.6-46.8 25.1-10.7 4.8 49.2zM99 263.2l-31.1 13-5.2-40.8L90.1 221l8.9 42.2zM123.2 377l-41.6 5.9-8.1-63.5 35.2-10.8 14.5 68.4zm28.5-139.9l21.2 57.1-46.2 13.6-13.7-54.1 38.7-16.6zm85.7 230.5l-70.9-3.3-24.3-95.8 55.2-8.6 40 107.7zm-84.9-279.7l42.2-22.4 28 45.9-50.8 21.3-19.4-44.8zm41 94.9l61.3-18.7 52.8 86.6-79.8 11.3-34.3-79.2zm51.4-85.6l67.3-28.8 65.5 65.4-88.6 26.2-44.2-62.8z"],scribd:[384,512,[],"f28a","M42.3 252.7c-16.1-19-24.7-45.9-24.8-79.9 0-100.4 75.2-153.1 167.2-153.1 98.6-1.6 156.8 49 184.3 70.6l-50.5 72.1-37.3-24.6 26.9-38.6c-36.5-24-79.4-36.5-123-35.8-50.7-.8-111.7 27.2-111.7 76.2 0 18.7 11.2 20.7 28.6 15.6 23.3-5.3 41.9.6 55.8 14 26.4 24.3 23.2 67.6-.7 91.9-29.2 29.5-85.2 27.3-114.8-8.4zm317.7 5.9c-15.5-18.8-38.9-29.4-63.2-28.6-38.1-2-71.1 28-70.5 67.2-.7 16.8 6 33 18.4 44.3 14.1 13.9 33 19.7 56.3 14.4 17.4-5.1 28.6-3.1 28.6 15.6 0 4.3-.5 8.5-1.4 12.7-16.7 40.9-59.5 64.4-121.4 64.4-51.9.2-102.4-16.4-144.1-47.3l33.7-39.4-35.6-27.4L0 406.3l15.4 13.8c52.5 46.8 120.4 72.5 190.7 72.2 51.4 0 94.4-10.5 133.6-44.1 57.1-51.4 54.2-149.2 20.3-189.6z"],searchengin:[460,512,[],"f3eb","M220.6 130.3l-67.2 28.2V43.2L98.7 233.5l54.7-24.2v130.3l67.2-209.3zm-83.2-96.7l-1.3 4.7-15.2 52.9C80.6 106.7 52 145.8 52 191.5c0 52.3 34.3 95.9 83.4 105.5v53.6C57.5 340.1 0 272.4 0 191.6c0-80.5 59.8-147.2 137.4-158zm311.4 447.2c-11.2 11.2-23.1 12.3-28.6 10.5-5.4-1.8-27.1-19.9-60.4-44.4-33.3-24.6-33.6-35.7-43-56.7-9.4-20.9-30.4-42.6-57.5-52.4l-9.7-14.7c-24.7 16.9-53 26.9-81.3 28.7l2.1-6.6 15.9-49.5c46.5-11.9 80.9-54 80.9-104.2 0-54.5-38.4-102.1-96-107.1V32.3C254.4 37.4 320 106.8 320 191.6c0 33.6-11.2 64.7-29 90.4l14.6 9.6c9.8 27.1 31.5 48 52.4 57.4s32.2 9.7 56.8 43c24.6 33.2 42.7 54.9 44.5 60.3s.7 17.3-10.5 28.5zm-9.9-17.9c0-4.4-3.6-8-8-8s-8 3.6-8 8 3.6 8 8 8 8-3.6 8-8z"],sellcast:[448,512,[],"f2da","M353.4 32H94.7C42.6 32 0 74.6 0 126.6v258.7C0 437.4 42.6 480 94.7 480h258.7c52.1 0 94.7-42.6 94.7-94.6V126.6c0-52-42.6-94.6-94.7-94.6zm-50 316.4c-27.9 48.2-89.9 64.9-138.2 37.2-22.9 39.8-54.9 8.6-42.3-13.2l15.7-27.2c5.9-10.3 19.2-13.9 29.5-7.9 18.6 10.8-.1-.1 18.5 10.7 27.6 15.9 63.4 6.3 79.4-21.3 15.9-27.6 6.3-63.4-21.3-79.4-17.8-10.2-.6-.4-18.6-10.6-24.6-14.2-3.4-51.9 21.6-37.5 18.6 10.8-.1-.1 18.5 10.7 48.4 28 65.1 90.3 37.2 138.5zm21.8-208.8c-17 29.5-16.3 28.8-19 31.5-6.5 6.5-16.3 8.7-26.5 3.6-18.6-10.8.1.1-18.5-10.7-27.6-15.9-63.4-6.3-79.4 21.3s-6.3 63.4 21.3 79.4c0 0 18.5 10.6 18.6 10.6 24.6 14.2 3.4 51.9-21.6 37.5-18.6-10.8.1.1-18.5-10.7-48.2-27.8-64.9-90.1-37.1-138.4 27.9-48.2 89.9-64.9 138.2-37.2l4.8-8.4c14.3-24.9 52-3.3 37.7 21.5z"],sellsy:[640,512,[],"f213","M539.71 237.308c3.064-12.257 4.29-24.821 4.29-37.384C544 107.382 468.618 32 376.076 32c-77.22 0-144.634 53.012-163.02 127.781-15.322-13.176-34.934-20.53-55.157-20.53-46.271 0-83.962 37.69-83.962 83.961 0 7.354.92 15.015 3.065 22.369-42.9 20.225-70.785 63.738-70.785 111.234C6.216 424.843 61.68 480 129.401 480h381.198c67.72 0 123.184-55.157 123.184-123.184.001-56.384-38.916-106.025-94.073-119.508zM199.88 401.554c0 8.274-7.048 15.321-15.321 15.321H153.61c-8.274 0-15.321-7.048-15.321-15.321V290.626c0-8.273 7.048-15.321 15.321-15.321h30.949c8.274 0 15.321 7.048 15.321 15.321v110.928zm89.477 0c0 8.274-7.048 15.321-15.322 15.321h-30.949c-8.274 0-15.321-7.048-15.321-15.321V270.096c0-8.274 7.048-15.321 15.321-15.321h30.949c8.274 0 15.322 7.048 15.322 15.321v131.458zm89.477 0c0 8.274-7.047 15.321-15.321 15.321h-30.949c-8.274 0-15.322-7.048-15.322-15.321V238.84c0-8.274 7.048-15.321 15.322-15.321h30.949c8.274 0 15.321 7.048 15.321 15.321v162.714zm87.027 0c0 8.274-7.048 15.321-15.322 15.321h-28.497c-8.274 0-15.321-7.048-15.321-15.321V176.941c0-8.579 7.047-15.628 15.321-15.628h28.497c8.274 0 15.322 7.048 15.322 15.628v224.613z"],servicestack:[496,512,[],"f3ec","M88 216c81.7 10.2 273.7 102.3 304 232H0c99.5-8.1 184.5-137 88-232zm32-152c32.3 35.6 47.7 83.9 46.4 133.6C249.3 231.3 373.7 321.3 400 448h96C455.3 231.9 222.8 79.5 120 64z"],shirtsinbulk:[448,512,[],"f214","M395.208 221.583H406v33.542h-10.792v-33.542zm0-9.625H406v-33.542h-10.792v33.542zm0 86.333H406V264.75h-10.792v33.541zM358.75 135.25h-33.542v10.5h33.542v-10.5zm36.458 206.208H406v-33.542h-10.792v33.542zM311.5 135.25h-33.542v10.5H311.5v-10.5zm-47.25 0H231v10.5h33.25v-10.5zm-47.25 0h-33.25v10.5H217v-10.5zm178.208 33.542H406V135.25h-33.542v10.5h22.75v23.042zm-255.792 259l30.625 13.417 4.375-9.917-30.625-13.417-4.375 9.917zM179.083 445l30.334 13.708 4.374-9.916-30.333-13.417-4.375 9.625zm216.125-60.375H406v-33.542h-10.792v33.542zm-334.833 8.167L91 406.208l4.375-9.624-30.625-13.709-4.375 9.917zm39.666 17.499l30.625 13.417 4.375-9.917-30.625-13.416-4.375 9.916zm132.417 38.501l4.375 9.916L267.459 445l-4.375-9.625-30.626 13.417zm118.417-52.208l4.375 9.624 30.624-13.416-4.374-9.917-30.625 13.709zM311.5 413.791l4.375 9.917 30.625-13.417-4.374-9.916-30.626 13.416zm-39.667 17.501l4.375 9.917 30.625-13.417-4.375-9.917-30.625 13.417zM311.5 46.583h-33.542v10.5H311.5v-10.5zm94.209 0h-33.251v10.5h33.251v-10.5zm-188.709 0h-33.25v10.5H217v-10.5zm141.75 0h-33.542v10.5h33.542v-10.5zm-94.5 0H231v10.5h33.25v-10.5zM448 3.708v406l-226.334 98.584L0 409.708v-406h448zm-29.166 116.958H29.166V390.75l192.792 85.75 196.875-85.75V120.666zm0-87.791H29.166V91.5h389.667V32.875zM75.542 46.583H42.291v10.5h33.251v-10.5zm94.5 0H136.5v10.5h33.542v-10.5zm-47.251 0H89.25v10.5h33.542v-10.5zm7.584 236.542c0-50.167 41.125-91.292 91.292-91.292 50.458 0 91.292 41.125 91.292 91.292 0 50.458-40.833 91.292-91.292 91.292-50.167-.001-91.292-40.834-91.292-91.292zm120.75 18.084c0 13.125-23.917 14.291-32.666 14.291-12.25 0-29.75-2.625-35.875-14.875h-.875L172.666 319c14.876 9.333 29.167 12.25 47.25 12.25 19.542 0 51.042-5.833 51.042-31.209 0-48.125-78.458-16.333-78.458-37.916 0-13.125 20.708-14.875 29.75-14.875 10.791 0 29.166 3.208 35.583 13.124h.875l8.751-16.916c-15.167-6.125-27.417-11.959-44.334-11.959-20.125 0-49.583 6.417-49.583 31.792 0 44.334 77.583 11.959 77.583 37.918zM122.791 135.25H89.25v10.5h33.542v-10.5zm-69.999 10.5h22.75v-10.5H42v33.542h10.792V145.75zm0 32.666H42v33.542h10.792v-33.542zm117.25-43.166H136.5v10.5h33.542v-10.5zm-117.25 86.333H42v33.542h10.792v-33.542zm0 86.334H42v33.542h10.792v-33.542zm0-43.167H42v33.542h10.792V264.75zm0 86.333H42v33.542h10.792v-33.542z"],simplybuilt:[512,512,[],"f215","M481.2 64h-106c-14.5 0-26.6 11.8-26.6 26.3v39.6H163.3V90.3c0-14.5-12-26.3-26.6-26.3h-106C16.1 64 4.3 75.8 4.3 90.3v331.4c0 14.5 11.8 26.3 26.6 26.3h450.4c14.8 0 26.6-11.8 26.6-26.3V90.3c-.2-14.5-12-26.3-26.7-26.3zM149.8 355.8c-36.6 0-66.4-29.7-66.4-66.4 0-36.9 29.7-66.6 66.4-66.6 36.9 0 66.6 29.7 66.6 66.6 0 36.7-29.7 66.4-66.6 66.4zm212.4 0c-36.9 0-66.6-29.7-66.6-66.6 0-36.6 29.7-66.4 66.6-66.4 36.6 0 66.4 29.7 66.4 66.4 0 36.9-29.8 66.6-66.4 66.6z"],sistrix:[448,512,[],"f3ee","M448 449L301.2 300.2c20-27.9 31.9-62.2 31.9-99.2 0-93.1-74.7-168.9-166.5-168.9C74.7 32 0 107.8 0 200.9s74.7 168.9 166.5 168.9c39.8 0 76.3-14.2 105-37.9l146 148.1 30.5-31zM166.5 330.8c-70.6 0-128.1-58.3-128.1-129.9S95.9 71 166.5 71s128.1 58.3 128.1 129.9-57.4 129.9-128.1 129.9z"],skyatlas:[576,512,[],"f216","M545.7 318.5c0 56.2-44.8 97.5-100.2 97.5-141.5 0-167.6-212.9-306.7-212.9-125.2 0-125.4 180.9 4.8 180.9 36.2 0 77.5-15.2 106.8-36.2 4.8-3.5 14.4-13.9 19.5-13.9s9.3 4.3 9.3 9.3c0 6.7-11.2 16.3-16 20.5-34.9 30.4-85.5 52.2-131.9 52.2C60.2 416 0 365.6 0 292.4s57.6-127.1 130.3-127.1c158 0 189.7 209.7 308.5 209.7 85.2 0 80.8-119.1 2.9-119.1-14.9 0-29.8 9.9-40 9.9-7.2 0-13.6-6.1-13.6-13.3 0-9.9 4.5-20.2 4.5-30.9 0-56.8-43.4-97.8-99.7-97.8-45.3 0-68.2 31.4-75.7 31.4-5.3 0-9.6-4.3-9.6-9.6 0-4.8 3.5-8.8 6.7-12.3C235.9 108.8 269.5 96 302 96c67.7 0 118.6 49.8 118.6 117.5 0 5.9-.3 11.7-1.1 17.6 10.1-2.7 20.5-4 30.6-4 51.9 0 95.6 38.6 95.6 91.4z"],skype:[448,512,[],"f17e","M424.7 299.8c2.9-14 4.7-28.9 4.7-43.8 0-113.5-91.9-205.3-205.3-205.3-14.9 0-29.7 1.7-43.8 4.7C161.3 40.7 137.7 32 112 32 50.2 32 0 82.2 0 144c0 25.7 8.7 49.3 23.3 68.2-2.9 14-4.7 28.9-4.7 43.8 0 113.5 91.9 205.3 205.3 205.3 14.9 0 29.7-1.7 43.8-4.7 19 14.6 42.6 23.3 68.2 23.3 61.8 0 112-50.2 112-112 .1-25.6-8.6-49.2-23.2-68.1zm-194.6 91.5c-65.6 0-120.5-29.2-120.5-65 0-16 9-30.6 29.5-30.6 31.2 0 34.1 44.9 88.1 44.9 25.7 0 42.3-11.4 42.3-26.3 0-18.7-16-21.6-42-28-62.5-15.4-117.8-22-117.8-87.2 0-59.2 58.6-81.1 109.1-81.1 55.1 0 110.8 21.9 110.8 55.4 0 16.9-11.4 31.8-30.3 31.8-28.3 0-29.2-33.5-75-33.5-25.7 0-42 7-42 22.5 0 19.8 20.8 21.8 69.1 33 41.4 9.3 90.7 26.8 90.7 77.6 0 59.1-57.1 86.5-112 86.5z"],slack:[448,512,[],"f198","M244.2 217.5l19.3 57.7-59.8 20-19.3-57.7 59.8-20zm41.4 243.7C131.6 507.4 65 471.6 18.8 317.6S8.4 97 162.4 50.8C316.4 4.6 383 40.4 429.2 194.4c46.2 154 10.4 220.6-143.6 266.8zM366.2 265c-3.9-12.2-17.2-18.6-29.4-14.7l-29 9.7-19.3-57.7 29-9.7c12.2-3.9 18.6-17.2 14.7-29.4-3.9-12.2-17.2-18.6-29.4-14.7l-29 9.7-10-30.1c-3.9-12.2-17.2-18.6-29.4-14.7-12.2 3.9-18.6 17.2-14.7 29.4l10 30.1-59.8 20.1-10-30.1c-3.9-12.2-17.2-18.6-29.4-14.7-12.2 3.9-18.6 17.2-14.7 29.4l10 30.1-29 9.7c-12.2 3.9-18.6 17.2-14.7 29.4 3.2 9.3 12.2 15.4 21.5 15.8 4.3.6 7.7-1 36.9-10.7l19.3 57.7-29 9.7c-12.2 3.9-18.6 17.2-14.7 29.4 3.2 9.3 12.2 15.4 21.5 15.8 4.3.6 7.7-1 36.9-10.7l10 30.1c3.7 10.8 15.8 18.6 29.4 14.7 12.2-3.9 18.6-17.2 14.7-29.4l-10-30.1 59.8-20.1 10 30.1c3.7 10.8 15.8 18.6 29.4 14.7 12.2-3.9 18.6-17.2 14.7-29.4l-10-30.1 29-9.7c12.2-4.2 18.6-17.5 14.7-29.6z"],"slack-hash":[448,512,[],"f3ef","M446.2 270.4c-6.2-19-26.9-29.1-46-22.9l-45.4 15.1-30.3-90 45.4-15.1c19.1-6.2 29.1-26.8 23-45.9-6.2-19-26.9-29.1-46-22.9l-45.4 15.1-15.7-47c-6.2-19-26.9-29.1-46-22.9-19.1 6.2-29.1 26.8-23 45.9l15.7 47-93.4 31.2-15.7-47c-6.2-19-26.9-29.1-46-22.9-19.1 6.2-29.1 26.8-23 45.9l15.7 47-45.3 15c-19.1 6.2-29.1 26.8-23 45.9 5 14.5 19.1 24 33.6 24.6 6.8 1 12-1.6 57.7-16.8l30.3 90L78 354.8c-19 6.2-29.1 26.9-23 45.9 5 14.5 19.1 24 33.6 24.6 6.8 1 12-1.6 57.7-16.8l15.7 47c5.9 16.9 24.7 29 46 22.9 19.1-6.2 29.1-26.8 23-45.9l-15.7-47 93.6-31.3 15.7 47c5.9 16.9 24.7 29 46 22.9 19.1-6.2 29.1-26.8 23-45.9l-15.7-47 45.4-15.1c19-6 29.1-26.7 22.9-45.7zm-254.1 47.2l-30.3-90.2 93.5-31.3 30.3 90.2-93.5 31.3z"],slideshare:[512,512,[],"f1e7","M249.429 211.436c0 31.716-27.715 57.717-61.717 57.717-34.001 0-61.716-26.001-61.716-57.717 0-32.001 27.715-57.716 61.716-57.716 34.001 0 61.717 25.715 61.717 57.716zm254.294 50.002c-18.286 22.573-53.144 50.288-106.289 72.003C453.722 525.163 260 555.735 263.143 457.446c0 1.714-.286-52.859-.286-93.432-4.285-.858-8.571-2-13.714-3.143 0 40.858-.286 98.289-.286 96.575C252 555.735 58.278 525.163 114.566 333.441c-53.145-21.715-88.003-49.43-106.29-72.003-9.143-13.714.858-28.287 16.001-17.715 2 1.428 4.285 2.857 6.285 4.285V49.716C30.563 22.287 51.135 0 76.565 0h359.157c25.429 0 46.002 22.287 46.002 49.716v198.293l6-4.285c15.143-10.573 25.143 4 15.999 17.714zm-46.572-189.15c0-32.858-10.572-45.716-40.859-45.716H98.566c-31.716 0-40.573 10.858-40.573 45.716v192.293c67.717 35.43 125.72 29.144 157.435 28.001 13.429-.286 22.001 2.286 27.144 7.715 1.689 1.687 10.023 9.446 20.287 17.143 1.143-15.715 10.001-25.715 33.716-24.858 32.287 1.428 91.718 7.715 160.577-29.716V72.288zM331.146 153.72c-34.002 0-61.716 25.715-61.716 57.716 0 31.716 27.715 57.717 61.716 57.717 34.287 0 61.716-26.001 61.716-57.717 0-32.001-27.429-57.716-61.716-57.716z"],snapchat:[496,512,[],"f2ab","M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm169.5 338.9c-3.5 8.1-18.1 14-44.8 18.2-1.4 1.9-2.5 9.8-4.3 15.9-1.1 3.7-3.7 5.9-8.1 5.9h-.2c-6.2 0-12.8-2.9-25.8-2.9-17.6 0-23.7 4-37.4 13.7-14.5 10.3-28.4 19.1-49.2 18.2-21 1.6-38.6-11.2-48.5-18.2-13.8-9.7-19.8-13.7-37.4-13.7-12.5 0-20.4 3.1-25.8 3.1-5.4 0-7.5-3.3-8.3-6-1.8-6.1-2.9-14.1-4.3-16-13.8-2.1-44.8-7.5-45.5-21.4-.2-3.6 2.3-6.8 5.9-7.4 46.3-7.6 67.1-55.1 68-57.1 0-.1.1-.2.2-.3 2.5-5 3-9.2 1.6-12.5-3.4-7.9-17.9-10.7-24-13.2-15.8-6.2-18-13.4-17-18.3 1.6-8.5 14.4-13.8 21.9-10.3 5.9 2.8 11.2 4.2 15.7 4.2 3.3 0 5.5-.8 6.6-1.4-1.4-23.9-4.7-58 3.8-77.1C183.1 100 230.7 96 244.7 96c.6 0 6.1-.1 6.7-.1 34.7 0 68 17.8 84.3 54.3 8.5 19.1 5.2 53.1 3.8 77.1 1.1.6 2.9 1.3 5.7 1.4 4.3-.2 9.2-1.6 14.7-4.2 4-1.9 9.6-1.6 13.6 0 6.3 2.3 10.3 6.8 10.4 11.9.1 6.5-5.7 12.1-17.2 16.6-1.4.6-3.1 1.1-4.9 1.7-6.5 2.1-16.4 5.2-19 11.5-1.4 3.3-.8 7.5 1.6 12.5.1.1.1.2.2.3.9 2 21.7 49.5 68 57.1 4 1 7.1 5.5 4.9 10.8z"],"snapchat-ghost":[512,512,[],"f2ac","M510.846 392.673c-5.211 12.157-27.239 21.089-67.36 27.318-2.064 2.786-3.775 14.686-6.507 23.956-1.625 5.566-5.623 8.869-12.128 8.869l-.297-.005c-9.395 0-19.203-4.323-38.852-4.323-26.521 0-35.662 6.043-56.254 20.588-21.832 15.438-42.771 28.764-74.027 27.399-31.646 2.334-58.025-16.908-72.871-27.404-20.714-14.643-29.828-20.582-56.241-20.582-18.864 0-30.736 4.72-38.852 4.72-8.073 0-11.213-4.922-12.422-9.04-2.703-9.189-4.404-21.263-6.523-24.13-20.679-3.209-67.31-11.344-68.498-32.15a10.627 10.627 0 0 1 8.877-11.069c69.583-11.455 100.924-82.901 102.227-85.934.074-.176.155-.344.237-.515 3.713-7.537 4.544-13.849 2.463-18.753-5.05-11.896-26.872-16.164-36.053-19.796-23.715-9.366-27.015-20.128-25.612-27.504 2.437-12.836 21.725-20.735 33.002-15.453 8.919 4.181 16.843 6.297 23.547 6.297 5.022 0 8.212-1.204 9.96-2.171-2.043-35.936-7.101-87.29 5.687-115.969C158.122 21.304 229.705 15.42 250.826 15.42c.944 0 9.141-.089 10.11-.089 52.148 0 102.254 26.78 126.723 81.643 12.777 28.65 7.749 79.792 5.695 116.009 1.582.872 4.357 1.942 8.599 2.139 6.397-.286 13.815-2.389 22.069-6.257 6.085-2.846 14.406-2.461 20.48.058l.029.01c9.476 3.385 15.439 10.215 15.589 17.87.184 9.747-8.522 18.165-25.878 25.018-2.118.835-4.694 1.655-7.434 2.525-9.797 3.106-24.6 7.805-28.616 17.271-2.079 4.904-1.256 11.211 2.46 18.748.087.168.166.342.239.515 1.301 3.03 32.615 74.46 102.23 85.934 6.427 1.058 11.163 7.877 7.725 15.859z"],"snapchat-square":[448,512,[],"f2ad","M400 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48zm-6.5 314.9c-3.5 8.1-18.1 14-44.8 18.2-1.4 1.9-2.5 9.8-4.3 15.9-1.1 3.7-3.7 5.9-8.1 5.9h-.2c-6.2 0-12.8-2.9-25.8-2.9-17.6 0-23.7 4-37.4 13.7-14.5 10.3-28.4 19.1-49.2 18.2-21 1.6-38.6-11.2-48.5-18.2-13.8-9.7-19.8-13.7-37.4-13.7-12.5 0-20.4 3.1-25.8 3.1-5.4 0-7.5-3.3-8.3-6-1.8-6.1-2.9-14.1-4.3-16-13.8-2.1-44.8-7.5-45.5-21.4-.2-3.6 2.3-6.8 5.9-7.4 46.3-7.6 67.1-55.1 68-57.1 0-.1.1-.2.2-.3 2.5-5 3-9.2 1.6-12.5-3.4-7.9-17.9-10.7-24-13.2-15.8-6.2-18-13.4-17-18.3 1.6-8.5 14.4-13.8 21.9-10.3 5.9 2.8 11.2 4.2 15.7 4.2 3.3 0 5.5-.8 6.6-1.4-1.4-23.9-4.7-58 3.8-77.1C159.1 100 206.7 96 220.7 96c.6 0 6.1-.1 6.7-.1 34.7 0 68 17.8 84.3 54.3 8.5 19.1 5.2 53.1 3.8 77.1 1.1.6 2.9 1.3 5.7 1.4 4.3-.2 9.2-1.6 14.7-4.2 4-1.9 9.6-1.6 13.6 0 6.3 2.3 10.3 6.8 10.4 11.9.1 6.5-5.7 12.1-17.2 16.6-1.4.6-3.1 1.1-4.9 1.7-6.5 2.1-16.4 5.2-19 11.5-1.4 3.3-.8 7.5 1.6 12.5.1.1.1.2.2.3.9 2 21.7 49.5 68 57.1 4 1 7.1 5.5 4.9 10.8z"],soundcloud:[640,512,[],"f1be","M111.4 256.3l5.8 65-5.8 68.3c-.3 2.5-2.2 4.4-4.4 4.4s-4.2-1.9-4.2-4.4l-5.6-68.3 5.6-65c0-2.2 1.9-4.2 4.2-4.2 2.2 0 4.1 2 4.4 4.2zm21.4-45.6c-2.8 0-4.7 2.2-5 5l-5 105.6 5 68.3c.3 2.8 2.2 5 5 5 2.5 0 4.7-2.2 4.7-5l5.8-68.3-5.8-105.6c0-2.8-2.2-5-4.7-5zm25.5-24.1c-3.1 0-5.3 2.2-5.6 5.3l-4.4 130 4.4 67.8c.3 3.1 2.5 5.3 5.6 5.3 2.8 0 5.3-2.2 5.3-5.3l5.3-67.8-5.3-130c0-3.1-2.5-5.3-5.3-5.3zM7.2 283.2c-1.4 0-2.2 1.1-2.5 2.5L0 321.3l4.7 35c.3 1.4 1.1 2.5 2.5 2.5s2.2-1.1 2.5-2.5l5.6-35-5.6-35.6c-.3-1.4-1.1-2.5-2.5-2.5zm23.6-21.9c-1.4 0-2.5 1.1-2.5 2.5l-6.4 57.5 6.4 56.1c0 1.7 1.1 2.8 2.5 2.8s2.5-1.1 2.8-2.5l7.2-56.4-7.2-57.5c-.3-1.4-1.4-2.5-2.8-2.5zm25.3-11.4c-1.7 0-3.1 1.4-3.3 3.3L47 321.3l5.8 65.8c.3 1.7 1.7 3.1 3.3 3.1 1.7 0 3.1-1.4 3.1-3.1l6.9-65.8-6.9-68.1c0-1.9-1.4-3.3-3.1-3.3zm25.3-2.2c-1.9 0-3.6 1.4-3.6 3.6l-5.8 70 5.8 67.8c0 2.2 1.7 3.6 3.6 3.6s3.6-1.4 3.9-3.6l6.4-67.8-6.4-70c-.3-2.2-2-3.6-3.9-3.6zm241.4-110.9c-1.1-.8-2.8-1.4-4.2-1.4-2.2 0-4.2.8-5.6 1.9-1.9 1.7-3.1 4.2-3.3 6.7v.8l-3.3 176.7 1.7 32.5 1.7 31.7c.3 4.7 4.2 8.6 8.9 8.6s8.6-3.9 8.6-8.6l3.9-64.2-3.9-177.5c-.4-3-2-5.8-4.5-7.2zm-26.7 15.3c-1.4-.8-2.8-1.4-4.4-1.4s-3.1.6-4.4 1.4c-2.2 1.4-3.6 3.9-3.6 6.7l-.3 1.7-2.8 160.8s0 .3 3.1 65.6v.3c0 1.7.6 3.3 1.7 4.7 1.7 1.9 3.9 3.1 6.4 3.1 2.2 0 4.2-1.1 5.6-2.5 1.7-1.4 2.5-3.3 2.5-5.6l.3-6.7 3.1-58.6-3.3-162.8c-.3-2.8-1.7-5.3-3.9-6.7zm-111.4 22.5c-3.1 0-5.8 2.8-5.8 6.1l-4.4 140.6 4.4 67.2c.3 3.3 2.8 5.8 5.8 5.8 3.3 0 5.8-2.5 6.1-5.8l5-67.2-5-140.6c-.2-3.3-2.7-6.1-6.1-6.1zm376.7 62.8c-10.8 0-21.1 2.2-30.6 6.1-6.4-70.8-65.8-126.4-138.3-126.4-17.8 0-35 3.3-50.3 9.4-6.1 2.2-7.8 4.4-7.8 9.2v249.7c0 5 3.9 8.6 8.6 9.2h218.3c43.3 0 78.6-35 78.6-78.3.1-43.6-35.2-78.9-78.5-78.9zm-296.7-60.3c-4.2 0-7.5 3.3-7.8 7.8l-3.3 136.7 3.3 65.6c.3 4.2 3.6 7.5 7.8 7.5 4.2 0 7.5-3.3 7.5-7.5l3.9-65.6-3.9-136.7c-.3-4.5-3.3-7.8-7.5-7.8zm-53.6-7.8c-3.3 0-6.4 3.1-6.4 6.7l-3.9 145.3 3.9 66.9c.3 3.6 3.1 6.4 6.4 6.4 3.6 0 6.4-2.8 6.7-6.4l4.4-66.9-4.4-145.3c-.3-3.6-3.1-6.7-6.7-6.7zm26.7 3.4c-3.9 0-6.9 3.1-6.9 6.9L227 321.3l3.9 66.4c.3 3.9 3.1 6.9 6.9 6.9s6.9-3.1 6.9-6.9l4.2-66.4-4.2-141.7c0-3.9-3-6.9-6.9-6.9z"],speakap:[448,512,[],"f3f3","M352 32H96C43.2 32 0 75.2 0 128v256c0 52.8 43.2 96 96 96h256c52.8 0 96-43.2 96-96V128c0-52.8-43.2-96-96-96zM221 382.9c-39.6 0-81.9-17.8-81.9-53.7V302H179v17.8c0 15.1 19.5 24.5 41.9 24.5 24.2 0 41.3-10.4 41.3-29.5 0-23.8-27.2-31.9-54.7-42.6-31.9-12.4-63.1-26.2-63.1-69.1 0-48 38.6-66.4 79.9-66.4 37.6 0 75.5 14.1 75.5 41.9v31.2h-39.9v-16.1c0-12.1-17.8-18.5-35.6-18.5-19.5 0-35.6 8.1-35.6 26.2 0 22.1 22.5 29.2 47 38.9 35.9 12.4 71.1 27.2 71.1 71.5.1 48.6-40.8 71.1-85.8 71.1z"],spotify:[496,512,[],"f1bc","M248 8C111.1 8 0 119.1 0 256s111.1 248 248 248 248-111.1 248-248S384.9 8 248 8zm100.7 364.9c-4.2 0-6.8-1.3-10.7-3.6-62.4-37.6-135-39.2-206.7-24.5-3.9 1-9 2.6-11.9 2.6-9.7 0-15.8-7.7-15.8-15.8 0-10.3 6.1-15.2 13.6-16.8 81.9-18.1 165.6-16.5 237 26.2 6.1 3.9 9.7 7.4 9.7 16.5s-7.1 15.4-15.2 15.4zm26.9-65.6c-5.2 0-8.7-2.3-12.3-4.2-62.5-37-155.7-51.9-238.6-29.4-4.8 1.3-7.4 2.6-11.9 2.6-10.7 0-19.4-8.7-19.4-19.4s5.2-17.8 15.5-20.7c27.8-7.8 56.2-13.6 97.8-13.6 64.9 0 127.6 16.1 177 45.5 8.1 4.8 11.3 11 11.3 19.7-.1 10.8-8.5 19.5-19.4 19.5zm31-76.2c-5.2 0-8.4-1.3-12.9-3.9-71.2-42.5-198.5-52.7-280.9-29.7-3.6 1-8.1 2.6-12.9 2.6-13.2 0-23.3-10.3-23.3-23.6 0-13.6 8.4-21.3 17.4-23.9 35.2-10.3 74.6-15.2 117.5-15.2 73 0 149.5 15.2 205.4 47.8 7.8 4.5 12.9 10.7 12.9 22.6 0 13.6-11 23.3-23.2 23.3z"],"stack-exchange":[448,512,[],"f18d","M43.5 322.8h361.1V342c0 33-25.7 59.5-57.2 59.5h-16.6L254.9 480v-78.5H100.6c-31.5 0-57.2-26.5-57.2-59.5v-19.2zm0-20.7h361.1v-74.4H43.5v74.4zm0-95.7h361.1V132H43.5v74.4zM347.4 32H100.6c-31.5 0-57.2 26.5-57.2 59.2v19.5h361.1V91.2c0-32.7-25.6-59.2-57.1-59.2z"],"stack-overflow":[384,512,[],"f16c","M293.7 300l-181.2-84.5 16.7-36.5 181.3 84.7-16.8 36.3zm48-76L188.2 95.7l-25.5 30.8 153.5 128.3 25.5-30.8zm39.6-31.7L262 32l-32 24 119.3 160.3 32-24zM290.7 311L95 269.7 86.8 309l195.7 41 8.2-39zm31.6 129H42.7V320h-40v160h359.5V320h-40v120zm-39.8-80h-200v39.7h200V360z"],staylinked:[440,512,[],"f3f5","M201.6 127.4c4.1-3.2 10.3-3 13.8.5l170 167.3-2.7-2.7 44.3 41.3c3.7 3.5 3.3 9-.7 12.2l-198 163.9c-9.9 7.6-17.3.8-17.3.8L2.3 314.6c-3.5-3.5-3-9 1.2-12.2l45.8-34.9c4.2-3.2 10.4-3 13.9.5l151.9 147.5c3.7 3.5 10 3.7 14.2.4l93.2-74c4.1-3.2 4.5-8.7.9-12.2l-84-81.3c-3.6-3.5-9.9-3.7-14-.5l-.1.1c-4.1 3.2-10.4 3-14-.5l-68.1-64.3c-3.5-3.5-3.1-9 1.1-12.2l57.3-43.6m14.8 257.3c3.7 3.5 10.1 3.7 14.3.4l50.2-38.8-.3-.3 7.7-6c4.2-3.2 4.6-8.7.9-12.2l-57.1-54.4c-3.6-3.5-10-3.7-14.2-.5l-.1.1c-4.2 3.2-10.5 3.1-14.2-.4L109 180.8c-3.6-3.5-3.1-8.9 1.1-12.2l92.2-71.5c4.1-3.2 10.3-3 13.9.5l160.4 159c3.7 3.5 10 3.7 14.1.5l45.8-35.8c4.1-3.2 4.4-8.7.7-12.2L226.7 2.5c-1.5-1.2-8-5.5-16.3 1.1L3.6 165.7c-4.2 3.2-4.8 8.7-1.2 12.2l42.3 41.7"],steam:[496,512,[],"f1b6","M496 256c0 137-111.2 248-248.4 248-113.8 0-209.6-76.3-239-180.4l95.2 39.3c6.4 32.1 34.9 56.4 68.9 56.4 39.2 0 71.9-32.4 70.2-73.5l84.5-60.2c52.1 1.3 95.8-40.9 95.8-93.5 0-51.6-42-93.5-93.7-93.5s-93.7 42-93.7 93.5v1.2L176.6 279c-15.5-.9-30.7 3.4-43.5 12.1L0 236.1C10.2 108.4 117.1 8 247.6 8 384.8 8 496 119 496 256zM155.7 384.3l-30.5-12.6a52.79 52.79 0 0 0 27.2 25.8c26.9 11.2 57.8-1.6 69-28.4 5.4-13 5.5-27.3.1-40.3-5.4-13-15.5-23.2-28.5-28.6-12.9-5.4-26.7-5.2-38.9-.6l31.5 13c19.8 8.2 29.2 30.9 20.9 50.7-8.3 19.9-31 29.2-50.8 21zm173.8-129.9c-34.4 0-62.4-28-62.4-62.3s28-62.3 62.4-62.3 62.4 28 62.4 62.3-27.9 62.3-62.4 62.3zm.1-15.6c25.9 0 46.9-21 46.9-46.8 0-25.9-21-46.8-46.9-46.8s-46.9 21-46.9 46.8c.1 25.8 21.1 46.8 46.9 46.8z"],"steam-square":[448,512,[],"f1b7","M185.2 356.5c7.7-18.5-1-39.7-19.6-47.4l-29.5-12.2c11.4-4.3 24.3-4.5 36.4.5 12.2 5.1 21.6 14.6 26.7 26.7 5 12.2 5 25.6-.1 37.7-10.5 25.1-39.4 37-64.6 26.5-11.6-4.8-20.4-13.6-25.4-24.2l28.5 11.8c18.6 7.8 39.9-.9 47.6-19.4zM400 32H48C21.5 32 0 53.5 0 80v160.7l116.6 48.1c12-8.2 26.2-12.1 40.7-11.3l55.4-80.2v-1.1c0-48.2 39.3-87.5 87.6-87.5s87.6 39.3 87.6 87.5c0 49.2-40.9 88.7-89.6 87.5l-79 56.3c1.6 38.5-29.1 68.8-65.7 68.8-31.8 0-58.5-22.7-64.5-52.7L0 319.2V432c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48zm-99.7 222.5c-32.2 0-58.4-26.1-58.4-58.3s26.2-58.3 58.4-58.3 58.4 26.2 58.4 58.3-26.2 58.3-58.4 58.3zm.1-14.6c24.2 0 43.9-19.6 43.9-43.8 0-24.2-19.6-43.8-43.9-43.8-24.2 0-43.9 19.6-43.9 43.8 0 24.2 19.7 43.8 43.9 43.8z"],"steam-symbol":[448,512,[],"f3f6","M395.5 177.5c0 33.8-27.5 61-61 61-33.8 0-61-27.3-61-61s27.3-61 61-61c33.5 0 61 27.2 61 61zm52.5.2c0 63-51 113.8-113.7 113.8L225 371.3c-4 43-40.5 76.8-84.5 76.8-40.5 0-74.7-28.8-83-67L0 358V250.7L97.2 290c15.1-9.2 32.2-13.3 52-11.5l71-101.7c.5-62.3 51.5-112.8 114-112.8C397 64 448 115 448 177.7zM203 363c0-34.7-27.8-62.5-62.5-62.5-4.5 0-9 .5-13.5 1.5l26 10.5c25.5 10.2 38 39 27.7 64.5-10.2 25.5-39.2 38-64.7 27.5-10.2-4-20.5-8.3-30.7-12.2 10.5 19.7 31.2 33.2 55.2 33.2 34.7 0 62.5-27.8 62.5-62.5zm207.5-185.3c0-42-34.3-76.2-76.2-76.2-42.3 0-76.5 34.2-76.5 76.2 0 42.2 34.3 76.2 76.5 76.2 41.9.1 76.2-33.9 76.2-76.2z"],"sticker-mule":[576,512,[],"f3f7","M353.1 509.8c-5.9 2.9-32.1 3.2-36.5-.5-4.1-3-2.2-11.9-1.5-15 2.2-15-2.5-7.9-9.8-11.5-3.1-1.5-4.1-5.5-4.6-10-.5-1.5-1-2.5-1.5-3.5-1.7-10.7 6.8-33.6 8.2-43.4 4.9-23.7-.7-37.2 1.5-46.9 3.7-16.2 4.1-3.5 4.1-29.9-1.4-25.9 3.3-36.9.5-38.9-14.8 0-64.3 10.7-112.2 2-46.1-8.9-59.4-29-65.4-30.9-10.3-4.5-23.2.5-27.3 7-.1.1-35 70.6-39.6 87.8-6.2 20.5-.5 47.4 4.1 66.8 0 .1 4.5 14.6 10.3 19.5 2.1 1.5 5.1 2.5 7.2 4.5 2.8 2.7 9.4 15.2 9.8 16 2.6 4.5 3.6 8-1.5 10.5-3.6 2-9.3 2.5-14.4 2.5-2.6.5-1.5 3.5-3.1 5-2.9 2.8-20.7 6.1-29.9 2.5-2.6-1-5.7-3-6.2-5-1.5-4 2.1-9-1-12.5-4.5-2.9-13.1-2-17-12-2.2-5.4-2.6-7.6-2.6-49.4 0-9.7-5.9-38.7-8.2-46.9-1.5-5.5-1.5-11.5 0-16 .3-.9 4.1-4.6 4.1-13-1-1.5-4.6-.5-5.1-1.5-10.4-80.6-5.9-79-7.7-98.3-1.5-16-10.9-43.9-6.7-64.3.5-2.4 3.4-21 24.2-38.9 31-26.7 48.4-38.3 159-11.5 1.1.4 66.3 21.1 110.7-9 15.5-11.3 28.8-11.3 35.5-16 .1-.1 61.7-52.1 87-65.3 47.2-29.4 69.9-16.7 75.1-18 4.7-1 13.4-25.8 17-25.8 5.5 0 1.6 20.2 3.6 25.9.5 2 3.6 5 6.2 5 2.3 0 1.7-.8 10.3-5 8.4-5.4 14.9-17.6 20.6-17 11.7 1.6-19 41.6-19 46.9 0 2 .2.8 4.6 9.5 2.6 5.5 4.6 13.5 6.2 20 8.3 29.7 5.7 14.6 13.4 36.9 20.2 50.1 20.6 45.2 20.6 52.9 0 7.5-4.1 11-7.2 16.5-1.5 3-4.6 7.5-7.2 8-2.7.7 7-1.5-13.4 2.5-7.2 1-13.4-4.5-14.9-9.5-1.6-4.7 2.8-10.1-11.8-22.9-10.3-10-21.1-11.3-31.9-17-9.8-5.7-11.9 1-18 8-18 22.9-34 46.9-52 69.8-11.8 15-24.2 30.4-33.5 47.4-3.9 6.8-9.5 28.1-10.3 29.9-6.2 17.7-5.5 25.8-16.5 68.3-3.1 10-5.7 21.4-8.7 32.4-2.2 6.8-7.4 49.3-.5 59.4 2.1 3.5 8.7 4.5 11.3 8 .1.1 9.6 18.2 9.3 20 0 6.1-9.4 5.6-11.3 6.5-4.8 2.9-3.8 5.9-6.4 7.4"],strava:[369,512,[],"f428","M301.6 292l-43.9 88.2-44.6-88.2h-67.6l112.2 220 111.5-220h-67.6zM151.4 0L0 292h89.2l62.2-116.1L213.1 292h88.5L151.4 0z"],stripe:[640,512,[],"f429","M640 233.6c0-45.5-22-81.4-64.2-81.4s-67.9 35.9-67.9 81.1c0 53.5 30.3 78.2 73.5 78.2 21.2 0 37.1-4.8 49.2-11.5v-33.4c-12.1 6.1-26 9.8-43.6 9.8-17.3 0-32.5-6.1-34.5-26.9h86.9c.2-2.3.6-11.6.6-15.9m-87.9-16.8c0-20 12.3-28.4 23.4-28.4 10.9 0 22.5 8.4 22.5 28.4h-45.9zm-112.9-64.6c-17.4 0-28.6 8.2-34.8 13.9l-2.3-11H363v204.8l44.4-9.4.1-50.2c6.4 4.7 15.9 11.2 31.4 11.2 31.8 0 60.8-23.2 60.8-79.6.1-51.6-29.3-79.7-60.5-79.7m-10.6 122.5c-10.4 0-16.6-3.8-20.9-8.4l-.3-66c4.6-5.1 11-8.8 21.2-8.8 16.2 0 27.4 18.2 27.4 41.4.1 23.9-10.9 41.8-27.4 41.8M346.4 96v36.2l-44.6 9.5v-36.2l44.6-9.5m-44.5 59.2h44.6v153.2h-44.6V155.2zm-47.8 13.1c10.4-19.1 31.1-15.2 37.1-13.1V196c-5.7-1.8-23.4-4.5-33.9 9.3v103.1H213V155.2h38.4l2.7 13.1m-89-13.1h33.7V193h-33.7v63.2c0 26.2 28 18 33.7 15.7v33.8c-5.9 3.2-16.6 5.9-31.2 5.9-26.3 0-46.1-17-46.1-43.3l.2-142.4 43.3-9.2.1 38.5zM44.9 200.3c0 20 67.9 10.5 67.9 63.4 0 32-25.4 47.8-62.3 47.8-15.3 0-32-3-48.5-10.1v-40c14.9 8.1 33.9 14.2 48.6 14.2 9.9 0 17-2.7 17-10.9 0-21.2-67.5-13.2-67.5-62.4 0-31.4 24-50.2 60-50.2 14.7 0 29.4 2.3 44.1 8.1V202c-13.5-7.3-30.7-11.4-44.2-11.4-9.3.1-15.1 2.8-15.1 9.7"],"stripe-s":[362,512,[],"f42a","M144.3 154.6c0-22.3 18.6-30.9 48.4-30.9 43.4 0 98.5 13.3 141.9 36.7V26.1C287.3 7.2 240.1 0 192.8 0 77.1 0 0 60.4 0 161.4c0 157.9 216.8 132.3 216.8 200.4 0 26.4-22.9 34.9-54.7 34.9-47.2 0-108.2-19.5-156.1-45.5v128.5c53 22.8 106.8 32.4 156 32.4 118.6 0 200.3-51 200.3-153.6 0-170.2-218-139.7-218-203.9"],studiovinari:[512,512,[],"f3f8","M480.3 187.7l4.2 28v28l-25.1 44.1-39.8 78.4-56.1 67.5-79.1 37.8-17.7 24.5-7.7 12-9.6 4s17.3-63.6 19.4-63.6c2.1 0 20.3.7 20.3.7l66.7-38.6-92.5 26.1-55.9 36.8-22.8 28-6.6 1.4 20.8-73.6 6.9-5.5 20.7 12.9 88.3-45.2 56.8-51.5 14.8-68.4-125.4 23.3 15.2-18.2-173.4-53.3 81.9-10.5-166-122.9L133.5 108 32.2 0l252.9 126.6-31.5-38L378 163 234.7 64l18.7 38.4-49.6-18.1L158.3 0l194.6 122L310 66.2l108 96.4 12-8.9-21-16.4 4.2-37.8L451 89.1l29.2 24.7 11.5 4.2-7 6.2 8.5 12-13.1 7.4-10.3 20.2 10.5 23.9z"],stumbleupon:[512,512,[],"f1a4","M502.9 266v69.7c0 62.1-50.3 112.4-112.4 112.4-61.8 0-112.4-49.8-112.4-111.3v-70.2l34.3 16 51.1-15.2V338c0 14.7 12 26.5 26.7 26.5S417 352.7 417 338v-72h85.9zm-224.7-58.2l34.3 16 51.1-15.2V173c0-60.5-51.1-109-112.1-109-60.8 0-112.1 48.2-112.1 108.2v162.4c0 14.9-12 26.7-26.7 26.7S86 349.5 86 334.6V266H0v69.7C0 397.7 50.3 448 112.4 448c61.6 0 112.4-49.5 112.4-110.8V176.9c0-14.7 12-26.7 26.7-26.7s26.7 12 26.7 26.7v30.9z"],"stumbleupon-circle":[496,512,[],"f1a3","M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm0 177.5c-9.8 0-17.8 8-17.8 17.8v106.9c0 40.9-33.9 73.9-74.9 73.9-41.4 0-74.9-33.5-74.9-74.9v-46.5h57.3v45.8c0 10 8 17.8 17.8 17.8s17.8-7.9 17.8-17.8V200.1c0-40 34.2-72.1 74.7-72.1 40.7 0 74.7 32.3 74.7 72.6v23.7l-34.1 10.1-22.9-10.7v-20.6c.1-9.6-7.9-17.6-17.7-17.6zm167.6 123.6c0 41.4-33.5 74.9-74.9 74.9-41.2 0-74.9-33.2-74.9-74.2V263l22.9 10.7 34.1-10.1v47.1c0 9.8 8 17.6 17.8 17.6s17.8-7.9 17.8-17.6v-48h57.3c-.1 45.9-.1 46.4-.1 46.4z"],superpowers:[448,512,[],"f2dd","M448 32c-83.3 11-166.8 22-250 33-92 12.5-163.3 86.7-169 180-3.3 55.5 18 109.5 57.8 148.2L0 480c83.3-11 166.5-22 249.8-33 91.8-12.5 163.3-86.8 168.7-179.8 3.5-55.5-18-109.5-57.7-148.2L448 32zm-79.7 232.3c-4.2 79.5-74 139.2-152.8 134.5-79.5-4.7-140.7-71-136.3-151 4.5-79.2 74.3-139.3 153-134.5 79.3 4.7 140.5 71 136.1 151z"],supple:[640,512,[],"f3f9","M640 262.5c0 64.1-109 116.1-243.5 116.1-24.8 0-48.6-1.8-71.1-5 7.7.4 15.5.6 23.4.6 134.5 0 243.5-56.9 243.5-127.1 0-29.4-19.1-56.4-51.2-78 60 21.1 98.9 55.1 98.9 93.4zM47.7 227.9c-.1-70.2 108.8-127.3 243.3-127.6 7.9 0 15.6.2 23.3.5-22.5-3.2-46.3-4.9-71-4.9C108.8 96.3-.1 148.5 0 212.6c.1 38.3 39.1 72.3 99.3 93.3-32.3-21.5-51.5-48.6-51.6-78zm60.2 39.9s10.5 13.2 29.3 13.2c17.9 0 28.4-11.5 28.4-25.1 0-28-40.2-25.1-40.2-39.7 0-5.4 5.3-9.1 12.5-9.1 5.7 0 11.3 2.6 11.3 6.6v3.9h14.2v-7.9c0-12.1-15.4-16.8-25.4-16.8-16.5 0-28.5 10.2-28.5 24.1 0 26.6 40.2 25.4 40.2 39.9 0 6.6-5.8 10.1-12.3 10.1-11.9 0-20.7-10.1-20.7-10.1l-8.8 10.9zm120.8-73.6v54.4c0 11.3-7.1 17.8-17.8 17.8-10.7 0-17.8-6.5-17.8-17.7v-54.5h-15.8v55c0 18.9 13.4 31.9 33.7 31.9 20.1 0 33.4-13 33.4-31.9v-55h-15.7zm34.4 85.4h15.8v-29.5h15.5c16 0 27.2-11.5 27.2-28.1s-11.2-27.8-27.2-27.8h-39.1v13.4h7.8v72zm15.8-43v-29.1h12.9c8.7 0 13.7 5.7 13.7 14.4 0 8.9-5.1 14.7-14 14.7h-12.6zm57 43h15.8v-29.5h15.5c16 0 27.2-11.5 27.2-28.1s-11.2-27.8-27.2-27.8h-39.1v13.4h7.8v72zm15.7-43v-29.1h12.9c8.7 0 13.7 5.7 13.7 14.4 0 8.9-5 14.7-14 14.7h-12.6zm57.1 34.8c0 5.8 2.4 8.2 8.2 8.2h37.6c5.8 0 8.2-2.4 8.2-8.2v-13h-14.3v5.2c0 1.7-1 2.6-2.6 2.6h-18.6c-1.7 0-2.6-1-2.6-2.6v-61.2c0-5.7-2.4-8.2-8.2-8.2H401v13.4h5.2c1.7 0 2.6 1 2.6 2.6v61.2zm63.4 0c0 5.8 2.4 8.2 8.2 8.2H519c5.7 0 8.2-2.4 8.2-8.2v-13h-14.3v5.2c0 1.7-1 2.6-2.6 2.6h-19.7c-1.7 0-2.6-1-2.6-2.6v-20.3h27.7v-13.4H488v-22.4h19.2c1.7 0 2.6 1 2.6 2.6v5.2H524v-13c0-5.7-2.5-8.2-8.2-8.2h-51.6v13.4h7.8v63.9zm58.9-76v5.9h1.6v-5.9h2.7v-1.2h-7v1.2h2.7zm5.7-1.2v7.1h1.5v-5.7l2.3 5.7h1.3l2.3-5.7v5.7h1.5v-7.1h-2.3l-2.1 5.1-2.1-5.1h-2.4z"],telegram:[496,512,[],"f2c6","M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm121.8 169.9l-40.7 191.8c-3 13.6-11.1 16.9-22.4 10.5l-62-45.7-29.9 28.8c-3.3 3.3-6.1 6.1-12.5 6.1l4.4-63.1 114.9-103.8c5-4.4-1.1-6.9-7.7-2.5l-142 89.4-61.2-19.1c-13.3-4.2-13.6-13.3 2.8-19.7l239.1-92.2c11.1-4 20.8 2.7 17.2 19.5z"],"telegram-plane":[448,512,[],"f3fe","M446.7 98.6l-67.6 318.8c-5.1 22.5-18.4 28.1-37.3 17.5l-103-75.9-49.7 47.8c-5.5 5.5-10.1 10.1-20.7 10.1l7.4-104.9 190.9-172.5c8.3-7.4-1.8-11.5-12.9-4.1L117.8 284 16.2 252.2c-22.1-6.9-22.5-22.1 4.6-32.7L418.2 66.4c18.4-6.9 34.5 4.1 28.5 32.2z"],"tencent-weibo":[384,512,[],"f1d5","M72.3 495.8c1.4 19.9-27.6 22.2-29.7 2.9C31 368.8 73.7 259.2 144 185.5c-15.6-34 9.2-77.1 50.6-77.1 30.3 0 55.1 24.6 55.1 55.1 0 44-49.5 70.8-86.9 45.1-65.7 71.3-101.4 169.8-90.5 287.2zM192 .1C66.1.1-12.3 134.3 43.7 242.4 52.4 259.8 79 246.9 70 229 23.7 136.4 91 29.8 192 29.8c75.4 0 136.9 61.4 136.9 136.9 0 90.8-86.9 153.9-167.7 133.1-19.1-4.1-25.6 24.4-6.6 29.1 110.7 23.2 204-60 204-162.3C358.6 74.7 284 .1 192 .1z"],themeisle:[512,512,[],"f2b2","M208 88.286c0-10 6.286-21.714 17.715-21.714 11.142 0 17.714 11.714 17.714 21.714 0 10.285-6.572 21.714-17.714 21.714C214.286 110 208 98.571 208 88.286zm304 160c0 36.001-11.429 102.286-36.286 129.714-22.858 24.858-87.428 61.143-120.857 70.572l-1.143.286v32.571c0 16.286-12.572 30.571-29.143 30.571-10 0-19.429-5.714-24.572-14.286-5.427 8.572-14.856 14.286-24.856 14.286-10 0-19.429-5.714-24.858-14.286-5.142 8.572-14.571 14.286-24.57 14.286-10.286 0-19.429-5.714-24.858-14.286-5.143 8.572-14.571 14.286-24.571 14.286-18.857 0-29.429-15.714-29.429-32.857-16.286 12.285-35.715 19.428-56.571 19.428-22 0-43.429-8.285-60.286-22.857 10.285-.286 20.571-2.286 30.285-5.714-20.857-5.714-39.428-18.857-52-36.286 21.37 4.645 46.209 1.673 67.143-11.143-22-22-56.571-58.857-68.572-87.428C1.143 321.714 0 303.714 0 289.429c0-49.714 20.286-160 86.286-160 10.571 0 18.857 4.858 23.143 14.857a158.792 158.792 0 0 1 12-15.428c2-2.572 5.714-5.429 7.143-8.286 7.999-12.571 11.714-21.142 21.714-34C182.571 45.428 232 17.143 285.143 17.143c6 0 12 .285 17.714 1.143C313.714 6.571 328.857 0 344.572 0c14.571 0 29.714 6 40 16.286.857.858 1.428 2.286 1.428 3.428 0 3.714-10.285 13.429-12.857 16.286 4.286 1.429 15.714 6.858 15.714 12 0 2.857-2.857 5.143-4.571 7.143 31.429 27.714 49.429 67.143 56.286 108 4.286-5.143 10.285-8.572 17.143-8.572 10.571 0 20.857 7.144 28.571 14.001C507.143 187.143 512 221.714 512 248.286zM188 89.428c0 18.286 12.571 37.143 32.286 37.143 19.714 0 32.285-18.857 32.285-37.143 0-18-12.571-36.857-32.285-36.857-19.715 0-32.286 18.858-32.286 36.857zM237.714 194c0-19.714 3.714-39.143 8.571-58.286-52.039 79.534-13.531 184.571 68.858 184.571 21.428 0 42.571-7.714 60-20 2-7.429 3.714-14.857 3.714-22.572 0-14.286-6.286-21.428-20.572-21.428-4.571 0-9.143.857-13.429 1.714-63.343 12.668-107.142 3.669-107.142-63.999zm-41.142 254.858c0-11.143-8.858-20.857-20.286-20.857-11.429 0-20 9.715-20 20.857v32.571c0 11.143 8.571 21.142 20 21.142 11.428 0 20.286-9.715 20.286-21.142v-32.571zm49.143 0c0-11.143-8.572-20.857-20-20.857-11.429 0-20.286 9.715-20.286 20.857v32.571c0 11.143 8.857 21.142 20.286 21.142 11.428 0 20-10 20-21.142v-32.571zm49.713 0c0-11.143-8.857-20.857-20.285-20.857-11.429 0-20.286 9.715-20.286 20.857v32.571c0 11.143 8.857 21.142 20.286 21.142 11.428 0 20.285-9.715 20.285-21.142v-32.571zm49.715 0c0-11.143-8.857-20.857-20.286-20.857-11.428 0-20.286 9.715-20.286 20.857v32.571c0 11.143 8.858 21.142 20.286 21.142 11.429 0 20.286-10 20.286-21.142v-32.571zM421.714 286c-30.857 59.142-90.285 102.572-158.571 102.572-96.571 0-160.571-84.572-160.571-176.572 0-16.857 2-33.429 6-49.714-20 33.715-29.714 72.572-29.714 111.429 0 60.286 24.857 121.715 71.429 160.857 5.143-9.714 14.857-16.286 26-16.286 10 0 19.428 5.714 24.571 14.286 5.429-8.571 14.571-14.286 24.858-14.286 10 0 19.428 5.714 24.571 14.286 5.429-8.571 14.857-14.286 24.858-14.286 10 0 19.428 5.714 24.857 14.286 5.143-8.571 14.571-14.286 24.572-14.286 10.857 0 20.857 6.572 25.714 16 43.427-36.286 68.569-92 71.426-148.286zm10.572-99.714c0-53.714-34.571-105.714-92.572-105.714-30.285 0-58.571 15.143-78.857 36.857C240.862 183.812 233.41 254 302.286 254c28.805 0 97.357-28.538 84.286 36.857 28.857-26 45.714-65.714 45.714-104.571z"],trello:[448,512,[],"f181","M392 32H56C25.1 32 0 57.1 0 88v336c0 30.9 25.1 56 56 56h336c30.9 0 56-25.1 56-56V88c0-30.9-25.1-56-56-56zM194.9 371.4c0 14.8-12 26.9-26.9 26.9H85.1c-14.8 0-26.9-12-26.9-26.9V117.1c0-14.8 12-26.9 26.9-26.9H168c14.8 0 26.9 12 26.9 26.9v254.3zm194.9-112c0 14.8-12 26.9-26.9 26.9H280c-14.8 0-26.9-12-26.9-26.9V117.1c0-14.8 12-26.9 26.9-26.9h82.9c14.8 0 26.9 12 26.9 26.9v142.3z"],tripadvisor:[576,512,[],"f262","M166.4 280.521c0 13.236-10.73 23.966-23.966 23.966s-23.966-10.73-23.966-23.966 10.73-23.966 23.966-23.966 23.966 10.729 23.966 23.966zm264.962-23.956c-13.23 0-23.956 10.725-23.956 23.956 0 13.23 10.725 23.956 23.956 23.956 13.23 0 23.956-10.725 23.956-23.956-.001-13.231-10.726-23.956-23.956-23.956zm89.388 139.49c-62.667 49.104-153.276 38.109-202.379-24.559l-30.979 46.325-30.683-45.939c-48.277 60.39-135.622 71.891-197.885 26.055-64.058-47.158-77.759-137.316-30.601-201.374A186.762 186.762 0 0 0 0 139.416l90.286-.05a358.48 358.48 0 0 1 197.065-54.03 350.382 350.382 0 0 1 192.181 53.349l96.218.074a185.713 185.713 0 0 0-28.352 57.649c46.793 62.747 34.964 151.37-26.648 199.647zM259.366 281.761c-.007-63.557-51.535-115.075-115.092-115.068C80.717 166.7 29.2 218.228 29.206 281.785c.007 63.557 51.535 115.075 115.092 115.068 63.513-.075 114.984-51.539 115.068-115.052v-.04zm28.591-10.455c5.433-73.44 65.51-130.884 139.12-133.022a339.146 339.146 0 0 0-139.727-27.812 356.31 356.31 0 0 0-140.164 27.253c74.344 1.582 135.299 59.424 140.771 133.581zm251.706-28.767c-21.992-59.634-88.162-90.148-147.795-68.157-59.634 21.992-90.148 88.162-68.157 147.795v.032c22.038 59.607 88.198 90.091 147.827 68.113 59.615-22.004 90.113-88.162 68.125-147.783zm-326.039 37.975v.115c-.057 39.328-31.986 71.163-71.314 71.106-39.328-.057-71.163-31.986-71.106-71.314.057-39.328 31.986-71.163 71.314-71.106 39.259.116 71.042 31.94 71.106 71.199zm-24.512 0v-.084c-.051-25.784-20.994-46.645-46.778-46.594-25.784.051-46.645 20.994-46.594 46.777.051 25.784 20.994 46.645 46.777 46.594 25.726-.113 46.537-20.968 46.595-46.693zm313.423 0v.048c-.02 39.328-31.918 71.194-71.247 71.173s-71.194-31.918-71.173-71.247c.02-39.328 31.918-71.194 71.247-71.173 39.29.066 71.121 31.909 71.173 71.199zm-24.504-.008c-.009-25.784-20.918-46.679-46.702-46.67-25.784.009-46.679 20.918-46.67 46.702.009 25.784 20.918 46.678 46.702 46.67 25.765-.046 46.636-20.928 46.67-46.693v-.009z"],tumblr:[320,512,[],"f173","M309.8 480.3c-13.6 14.5-50 31.7-97.4 31.7-120.8 0-147-88.8-147-140.6v-144H17.9c-5.5 0-10-4.5-10-10v-68c0-7.2 4.5-13.6 11.3-16 62-21.8 81.5-76 84.3-117.1.8-11 6.5-16.3 16.1-16.3h70.9c5.5 0 10 4.5 10 10v115.2h83c5.5 0 10 4.4 10 9.9v81.7c0 5.5-4.5 10-10 10h-83.4V360c0 34.2 23.7 53.6 68 35.8 4.8-1.9 9-3.2 12.7-2.2 3.5.9 5.8 3.4 7.4 7.9l22 64.3c1.8 5 3.3 10.6-.4 14.5z"],"tumblr-square":[448,512,[],"f174","M400 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48zm-82.3 364.2c-8.5 9.1-31.2 19.8-60.9 19.8-75.5 0-91.9-55.5-91.9-87.9v-90h-29.7c-3.4 0-6.2-2.8-6.2-6.2v-42.5c0-4.5 2.8-8.5 7.1-10 38.8-13.7 50.9-47.5 52.7-73.2.5-6.9 4.1-10.2 10-10.2h44.3c3.4 0 6.2 2.8 6.2 6.2v72h51.9c3.4 0 6.2 2.8 6.2 6.2v51.1c0 3.4-2.8 6.2-6.2 6.2h-52.1V321c0 21.4 14.8 33.5 42.5 22.4 3-1.2 5.6-2 8-1.4 2.2.5 3.6 2.1 4.6 4.9l13.8 40.2c1 3.2 2 6.7-.3 9.1z"],twitch:[448,512,[],"f1e8","M40.1 32L10 108.9v314.3h107V480h60.2l56.8-56.8h87l117-117V32H40.1zm357.8 254.1L331 353H224l-56.8 56.8V353H76.9V72.1h321v214zM331 149v116.9h-40.1V149H331zm-107 0v116.9h-40.1V149H224z"],twitter:[512,512,[],"f099","M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z"],"twitter-square":[448,512,[],"f081","M400 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48zm-48.9 158.8c.2 2.8.2 5.7.2 8.5 0 86.7-66 186.6-186.6 186.6-37.2 0-71.7-10.8-100.7-29.4 5.3.6 10.4.8 15.8.8 30.7 0 58.9-10.4 81.4-28-28.8-.6-53-19.5-61.3-45.5 10.1 1.5 19.2 1.5 29.6-1.2-30-6.1-52.5-32.5-52.5-64.4v-.8c8.7 4.9 18.9 7.9 29.6 8.3a65.447 65.447 0 0 1-29.2-54.6c0-12.2 3.2-23.4 8.9-33.1 32.3 39.8 80.8 65.8 135.2 68.6-9.3-44.5 24-80.6 64-80.6 18.9 0 35.9 7.9 47.9 20.7 14.8-2.8 29-8.3 41.6-15.8-4.9 15.2-15.2 28-28.8 36.1 13.2-1.4 26-5.1 37.8-10.2-8.9 13.1-20.1 24.7-32.9 34z"],typo3:[433,512,[],"f42b","M330.8 341c-7 2.3-11.6 2.3-18.5 2.3-57.2 0-140.6-198.5-140.6-264.9 0-24.7 5.4-32.4 13.9-39.4-69.5 8.5-149.3 34-176.3 66.4-5.4 7.7-9.3 20.8-9.3 37.1C0 246 106.8 480 184.1 480c36.3 0 97.3-59.5 146.7-139M294.5 32c71.8 0 138.8 11.6 138.8 52.5 0 82.6-52.5 182.3-78.8 182.3-47.9 0-101.7-132.1-101.7-198.5 0-30.9 11.6-36.3 41.7-36.3"],uber:[448,512,[],"f402","M414.1 32H33.9C15.2 32 0 47.2 0 65.9V446c0 18.8 15.2 34 33.9 34H414c18.7 0 33.9-15.2 33.9-33.9V65.9C448 47.2 432.8 32 414.1 32zM237.6 391.1C163 398.6 96.4 344.2 88.9 269.6h94.4V290c0 3.7 3 6.8 6.8 6.8H258c3.7 0 6.8-3 6.8-6.8v-67.9c0-3.7-3-6.8-6.8-6.8h-67.9c-3.7 0-6.8 3-6.8 6.8v20.4H88.9c7-69.4 65.4-122.2 135.1-122.2 69.7 0 128.1 52.8 135.1 122.2 7.5 74.5-46.9 141.1-121.5 148.6z"],uikit:[448,512,[],"f403","M443.9 128v256L218 512 0 384V169.7l87.6 45.1v117l133.5 75.5 135.8-75.5v-151l-101.1-57.6 87.6-53.1L443.9 128zM308.6 49.1L223.8 0l-88.6 54.8 86 47.3 87.4-53z"],uniregistry:[384,512,[],"f404","M281.1 220.1H384v-14.8H281.1v14.8zm0-37.1H384v-12.4H281.1V183zm0 74.2H384v-17.3H281.1v17.3zm-157.7 86.7H8.5c2.6 8.5 5.8 16.8 9.6 24.8h138.3c-12.9-5.7-24.1-14.2-33-24.8m145.7-12.4h109.7c1.8-7.3 3.1-14.7 3.9-22.3H278.3c-2.1 7.9-5.2 15.4-9.2 22.3m-41.5 37.1H367c3.7-8 5.8-16.2 8.5-24.8h-115c-8.8 10.7-20.1 19.2-32.9 24.8M384 32H281.1v2.5H384V32zM192 480c39.5 0 76.2-11.8 106.8-32.2H85.3C115.8 468.2 152.5 480 192 480m89.1-334.2H384V136H281.1v9.8zm0-37.1H384v-7.4H281.1v7.4zm0-37.1H384v-4.9H281.1v4.9zm-178.2 99H0V183h102.9v-12.4zM38.8 405.7h305.3c6.7-8.5 12.6-17.6 17.8-27.2H23c5.2 9.6 9.2 18.7 15.8 27.2m64.1-118.8v-12.4H0v12.4c0 2.5 0 5 .1 7.4h103.1c-.2-2.4-.3-4.9-.3-7.4m178.2 0c0 2.5-.1 5-.4 7.4h103.1c.1-2.5.2-4.9.2-7.4v-12.4H281.1v12.4zm-203 156h227.7c11.8-8.7 22.7-18.6 32.2-29.7H44.9c9.6 11 21.4 21 33.2 29.7m24.8-376.2H0v4.9h102.9v-4.9zm0-34.7H0v2.5h102.9V32zm0 173.3H0v14.8h102.9v-14.8zm0 34.6H0v17.3h102.9v-17.3zm0-103.9H0v9.9h102.9V136zm0-34.7H0v7.4h102.9v-7.4zm2.8 207.9H1.3c.9 7.6 2.2 15 3.9 22.3h109.7c-4-6.9-7.2-14.4-9.2-22.3"],untappd:[640,512,[],"f405","M401.3 49.9c-79.8 160.1-84.6 152.5-87.9 173.2l-5.2 32.8c-1.9 12-6.6 23.5-13.7 33.4L145.6 497.1c-7.6 10.6-20.4 16.2-33.4 14.6-40.3-5-77.8-32.2-95.3-68.5-5.7-11.8-4.5-25.8 3.1-36.4l148.9-207.9c7.1-9.9 16.4-18 27.2-23.7l29.3-15.5c18.5-9.8 9.7-11.9 135.6-138.9 1-4.8 1-7.3 3.6-8 3-.7 6.6-1 6.3-4.6l-.4-4.6c-.2-1.9 1.3-3.6 3.2-3.6 4.5-.1 13.2 1.2 25.6 10 12.3 8.9 16.4 16.8 17.7 21.1.6 1.8-.6 3.7-2.4 4.2l-4.5 1.1c-3.4.9-2.5 4.4-2.3 7.4.1 2.8-2.3 3.6-6.5 6.1zM230.1 36.4c3.4.9 2.5 4.4 2.3 7.4-.2 2.7 2.1 3.5 6.4 6 7.9 15.9 15.3 30.5 22.2 44 .7 1.3 2.3 1.5 3.3.5 11.2-12 24.6-26.2 40.5-42.6 1.3-1.4 1.4-3.5.1-4.9-8-8.2-16.5-16.9-25.6-26.1-1-4.7-1-7.3-3.6-8-3-.8-6.6-1-6.3-4.6.3-3.3 1.4-8.1-2.8-8.2-4.5-.1-13.2 1.1-25.6 10-12.3 8.9-16.4 16.8-17.7 21.1-1.4 4.2 3.6 4.6 6.8 5.4zM620 406.7L471.2 198.8c-13.2-18.5-26.6-23.4-56.4-39.1-11.2-5.9-14.2-10.9-30.5-28.9-1-1.1-2.9-.9-3.6.5-46.3 88.8-47.1 82.8-49 94.8-1.7 10.7-1.3 20 .3 29.8 1.9 12 6.6 23.5 13.7 33.4l148.9 207.9c7.6 10.6 20.2 16.2 33.1 14.7 40.3-4.9 78-32 95.7-68.6 5.4-11.9 4.3-25.9-3.4-36.6z"],usb:[640,512,[],"f287","M641.5 256c0 3.1-1.7 6.1-4.5 7.5L547.9 317c-1.4.8-2.8 1.4-4.5 1.4-1.4 0-3.1-.3-4.5-1.1-2.8-1.7-4.5-4.5-4.5-7.8v-35.6H295.7c25.3 39.6 40.5 106.9 69.6 106.9H392V354c0-5 3.9-8.9 8.9-8.9H490c5 0 8.9 3.9 8.9 8.9v89.1c0 5-3.9 8.9-8.9 8.9h-89.1c-5 0-8.9-3.9-8.9-8.9v-26.7h-26.7c-75.4 0-81.1-142.5-124.7-142.5H140.3c-8.1 30.6-35.9 53.5-69 53.5C32 327.3 0 295.3 0 256s32-71.3 71.3-71.3c33.1 0 61 22.8 69 53.5 39.1 0 43.9 9.5 74.6-60.4C255 88.7 273 95.7 323.8 95.7c7.5-20.9 27-35.6 50.4-35.6 29.5 0 53.5 23.9 53.5 53.5s-23.9 53.5-53.5 53.5c-23.4 0-42.9-14.8-50.4-35.6H294c-29.1 0-44.3 67.4-69.6 106.9h310.1v-35.6c0-3.3 1.7-6.1 4.5-7.8 2.8-1.7 6.4-1.4 8.9.3l89.1 53.5c2.8 1.1 4.5 4.1 4.5 7.2z"],ussunnah:[512,512,[],"f407","M156.8 285.1l5.7 14.4h-8.2c-1.3-3.2-3.1-7.7-3.8-9.5-2.5-6.3-1.1-8.4 0-10 1.9-2.7 3.2-4.4 3.6-5.2 0 2.2.8 5.7 2.7 10.3zm297.3 18.8c-2.1 13.8-5.7 27.1-10.5 39.7l43 23.4-44.8-18.8c-5.3 13.2-12 25.6-19.9 37.2l34.2 30.2-36.8-26.4c-8.4 11.8-18 22.6-28.7 32.3l24.9 34.7-28.1-31.8c-11 9.6-23.1 18-36.1 25.1l15.7 37.2-19.3-35.3c-13.1 6.8-27 12.1-41.6 15.9l6.7 38.4-10.5-37.4c-14.3 3.4-29.2 5.3-44.5 5.4L256 512l-1.9-38.4c-15.3-.1-30.2-2-44.5-5.3L199 505.6l6.7-38.2c-14.6-3.7-28.6-9.1-41.7-15.8l-19.2 35.1 15.6-37c-13-7-25.2-15.4-36.2-25.1l-27.9 31.6 24.7-34.4c-10.7-9.7-20.4-20.5-28.8-32.3l-36.5 26.2 33.9-29.9c-7.9-11.6-14.6-24.1-20-37.3l-44.4 18.7L67.8 344c-4.8-12.7-8.4-26.1-10.5-39.9l-51 9 50.3-14.2c-1.1-8.5-1.7-17.1-1.7-25.9 0-4.7.2-9.4.5-14.1L0 256l56-2.8c1.3-13.1 3.8-25.8 7.5-38.1L6.4 199l58.9 10.4c4-12 9.1-23.5 15.2-34.4l-55.1-30 58.3 24.6C90 159 97.2 149.2 105.3 140L55.8 96.4l53.9 38.7c8.1-8.6 17-16.5 26.6-23.6l-40-55.6 45.6 51.6c9.5-6.6 19.7-12.3 30.3-17.2l-27.3-64.9 33.8 62.1c10.5-4.4 21.4-7.9 32.7-10.4L199 6.4l19.5 69.2c11-2.1 22.3-3.2 33.8-3.4L256 0l3.6 72.2c11.5.2 22.8 1.4 33.8 3.5L313 6.4l-12.4 70.7c11.3 2.6 22.2 6.1 32.6 10.5l33.9-62.2-27.4 65.1c10.6 4.9 20.7 10.7 30.2 17.2l45.8-51.8-40.1 55.9c9.5 7.1 18.4 15 26.5 23.6l54.2-38.9-49.7 43.9c8 9.1 15.2 18.9 21.5 29.4l58.7-24.7-55.5 30.2c6.1 10.9 11.1 22.3 15.1 34.3l59.3-10.4-57.5 16.2c3.7 12.2 6.2 24.9 7.5 37.9L512 256l-56 2.8c.3 4.6.5 9.3.5 14.1 0 8.7-.6 17.3-1.6 25.8l50.7 14.3-51.5-9.1zm-21.8-31c0-97.5-79-176.5-176.5-176.5s-176.5 79-176.5 176.5 79 176.5 176.5 176.5 176.5-79 176.5-176.5zm-24 0c0 84.3-68.3 152.6-152.6 152.6s-152.6-68.3-152.6-152.6 68.3-152.6 152.6-152.6 152.6 68.3 152.6 152.6zM195 241c0 2.1 1.3 3.8 3.6 5.1 3.3 1.9 6.2 4.6 8.2 8.2 2.8-5.7 4.3-9.5 4.3-11.2 0-2.2-1.1-4.4-3.2-7-2.1-2.5-3.2-5.2-3.3-7.7-6.5 6.8-9.6 10.9-9.6 12.6zm-40.7-19c0 2.1 1.3 3.8 3.6 5.1 3.5 1.9 6.2 4.6 8.2 8.2 2.8-5.7 4.3-9.5 4.3-11.2 0-2.2-1.1-4.4-3.2-7-2.1-2.5-3.2-5.2-3.3-7.7-6.5 6.8-9.6 10.9-9.6 12.6zm-19 0c0 2.1 1.3 3.8 3.6 5.1 3.3 1.9 6.2 4.6 8.2 8.2 2.8-5.7 4.3-9.5 4.3-11.2 0-2.2-1.1-4.4-3.2-7-2.1-2.5-3.2-5.2-3.3-7.7-6.4 6.8-9.6 10.9-9.6 12.6zm204.9 87.9c-8.4-3-8.7-6.8-8.7-15.6V182c-8.2 12.5-14.2 18.6-18 18.6 6.3 14.4 9.5 23.9 9.5 28.3v64.3c0 2.2-2.2 6.5-4.7 6.5h-18c-2.8-7.5-10.2-26.9-15.3-40.3-2 2.5-7.2 9.2-10.7 13.7 2.4 1.6 4.1 3.6 5.2 6.3 2.6 6.7 6.4 16.5 7.9 20.2h-9.2c-3.9-10.4-9.6-25.4-11.8-31.1-2 2.5-7.2 9.2-10.7 13.7 2.4 1.6 4.1 3.6 5.2 6.3.8 2 2.8 7.3 4.3 10.9H256c-1.5-4.1-5.6-14.6-8.4-22-2 2.5-7.2 9.2-10.7 13.7 2.5 1.6 4.3 3.6 5.2 6.3.2.6.5 1.4.6 1.7H225c-4.6-13.9-11.4-27.7-11.4-34.1 0-2.2.3-5.1 1.1-8.2-8.8 10.8-14 15.9-14 25 0 7.5 10.4 28.3 10.4 33.3 0 1.7-.5 3.3-1.4 4.9-9.6-12.7-15.5-20.7-18.8-20.7h-12l-11.2-28c-3.8-9.6-5.7-16-5.7-18.8 0-3.8.5-7.7 1.7-12.2-1 1.3-3.7 4.7-5.5 7.1-.8-2.1-3.1-7.7-4.6-11.5-2.1 2.5-7.5 9.1-11.2 13.6.9 2.3 3.3 8.1 4.9 12.2-2.5 3.3-9.1 11.8-13.6 17.7-4 5.3-5.8 13.3-2.7 21.8 2.5 6.7 2 7.9-1.7 14.1H191c5.5 0 14.3 14 15.5 22 13.2-16 15.4-19.6 16.8-21.6h107c3.9 0 7.2-1.9 9.9-5.8zm20.1-26.6V181.7c-9 12.5-15.9 18.6-20.7 18.6 7.1 14.4 10.7 23.9 10.7 28.3v66.3c0 17.5 8.6 20.4 24 20.4 8.1 0 12.5-.8 13.7-2.7-4.3-1.6-7.6-2.5-9.9-3.3-8.1-3.2-17.8-7.4-17.8-26z"],vaadin:[448,512,[],"f408","M224.5 140.7c1.5-17.6 4.9-52.7 49.8-52.7h98.6c20.7 0 32.1-7.8 32.1-21.6V54.1c0-12.2 9.3-22.1 21.5-22.1S448 41.9 448 54.1v36.5c0 42.9-21.5 62-66.8 62H280.7c-30.1 0-33 14.7-33 27.1 0 1.3-.1 2.5-.2 3.7-.7 12.3-10.9 22.2-23.4 22.2s-22.7-9.8-23.4-22.2c-.1-1.2-.2-2.4-.2-3.7 0-12.3-3-27.1-33-27.1H66.8c-45.3 0-66.8-19.1-66.8-62V54.1C0 41.9 9.4 32 21.6 32s21.5 9.9 21.5 22.1v12.3C43.1 80.2 54.5 88 75.2 88h98.6c44.8 0 48.3 35.1 49.8 52.7h.9zM224 456c11.5 0 21.4-7 25.7-16.3 1.1-1.8 97.1-169.6 98.2-171.4 11.9-19.6-3.2-44.3-27.2-44.3-13.9 0-23.3 6.4-29.8 20.3L224 362l-66.9-117.7c-6.4-13.9-15.9-20.3-29.8-20.3-24 0-39.1 24.6-27.2 44.3 1.1 1.9 97.1 169.6 98.2 171.4 4.3 9.3 14.2 16.3 25.7 16.3z"],viacoin:[384,512,[],"f237","M384 32h-64l-80.7 192h-94.5L64 32H0l48 112H0v48h68.5l13.8 32H0v48h102.8L192 480l89.2-208H384v-48h-82.3l13.8-32H384v-48h-48l48-112zM192 336l-27-64h54l-27 64z"],viadeo:[448,512,[],"f2a9","M276.2 150.5v.7C258.3 98.6 233.6 47.8 205.4 0c43.3 29.2 67 100 70.8 150.5zm32.7 121.7c7.6 18.2 11 37.5 11 57 0 77.7-57.8 141-137.8 139.4l3.8-.3c74.2-46.7 109.3-118.6 109.3-205.1 0-38.1-6.5-75.9-18.9-112 1 11.7 1 23.7 1 35.4 0 91.8-18.1 241.6-116.6 280C95 455.2 49.4 398 49.4 329.2c0-75.6 57.4-142.3 135.4-142.3 16.8 0 33.7 3.1 49.1 9.6 1.7-15.1 6.5-29.9 13.4-43.3-19.9-7.2-41.2-10.7-62.5-10.7-161.5 0-238.7 195.9-129.9 313.7 67.9 74.6 192 73.9 259.8 0 56.6-61.3 60.9-142.4 36.4-201-12.7 8-27.1 13.9-42.2 17zM418.1 11.7c-31 66.5-81.3 47.2-115.8 80.1-12.4 12-20.6 34-20.6 50.5 0 14.1 4.5 27.1 12 38.8 47.4-11 98.3-46 118.2-90.7-.7 5.5-4.8 14.4-7.2 19.2-20.3 35.7-64.6 65.6-99.7 84.9 14.8 14.4 33.7 25.8 55 25.8 79 0 110.1-134.6 58.1-208.6z"],"viadeo-square":[448,512,[],"f2aa","M400 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48zM280.7 381.2c-42.4 46.2-120 46.6-162.4 0-68-73.6-19.8-196.1 81.2-196.1 13.3 0 26.6 2.1 39.1 6.7-4.3 8.4-7.3 17.6-8.4 27.1-9.7-4.1-20.2-6-30.7-6-48.8 0-84.6 41.7-84.6 88.9 0 43 28.5 78.7 69.5 85.9 61.5-24 72.9-117.6 72.9-175 0-7.3 0-14.8-.6-22.1-11.2-32.9-26.6-64.6-44.2-94.5 27.1 18.3 41.9 62.5 44.2 94.1v.4c7.7 22.5 11.8 46.2 11.8 70 0 54.1-21.9 99-68.3 128.2l-2.4.2c50 1 86.2-38.6 86.2-87.2 0-12.2-2.1-24.3-6.9-35.7 9.5-1.9 18.5-5.6 26.4-10.5 15.3 36.6 12.6 87.3-22.8 125.6zM309 233.7c-13.3 0-25.1-7.1-34.4-16.1 21.9-12 49.6-30.7 62.3-53 1.5-3 4.1-8.6 4.5-12-12.5 27.9-44.2 49.8-73.9 56.7-4.7-7.3-7.5-15.5-7.5-24.3 0-10.3 5.2-24.1 12.9-31.6 21.6-20.5 53-8.5 72.4-50 32.5 46.2 13.1 130.3-36.3 130.3z"],viber:[512,512,[],"f409","M430.7 49.9C418 38.2 366.6.9 252.1.4c0 0-135.1-8.1-200.9 52.3C14.6 89.3 1.7 142.9.3 209.4c-1.4 66.5-3.1 191.1 117 224.9h.1l-.1 51.6s-.8 20.9 13 25.1c16.6 5.2 26.4-10.7 42.3-27.8 8.7-9.4 20.7-23.2 29.8-33.7 82.2 6.9 145.3-8.9 152.5-11.2 16.6-5.4 110.5-17.4 125.7-142 15.8-128.5-7.6-209.7-49.9-246.4zM444.6 287c-12.9 104-89 110.6-103 115.1-6 1.9-61.5 15.7-131.2 11.2 0 0-52 62.7-68.2 79-5.3 5.3-11.1 4.8-11-5.7 0-6.9.4-85.7.4-85.7-.1 0-.1 0 0 0C29.9 372.7 35.8 266.6 37 211.1c1.1-55.5 11.6-101 42.6-131.6C135.3 29 250 36.5 250 36.5c96.9.4 143.3 29.6 154.1 39.4 35.7 30.6 53.9 103.8 40.5 211.1zm-138.9-80.8c.4 8.6-12.5 9.2-12.9.6-1.1-22-11.4-32.7-32.6-33.9-8.6-.5-7.8-13.4.7-12.9 27.9 1.5 43.4 17.5 44.8 46.2zm20.3 11.3c1-42.4-25.5-75.6-75.8-79.3-8.5-.6-7.6-13.5.9-12.9 58 4.2 88.9 44.1 87.8 92.5-.2 8.6-13.1 8.2-12.9-.3zm46.9 13.4c.1 8.6-12.9 8.7-12.9.1-.6-81.5-54.9-125.9-120.8-126.4-8.5-.1-8.5-12.9 0-12.9 73.8.5 133.1 51.4 133.7 139.2zM361.7 329v.2c-10.8 19-31 40-51.8 33.3l-.2-.3c-21.1-5.9-70.8-31.5-102.2-56.5-16.2-12.8-31-27.9-42.4-42.4-10.3-12.9-20.7-28.2-30.8-46.6-21.3-38.5-26-55.7-26-55.7-6.7-20.8 14.2-41 33.3-51.8h.2c9.2-4.8 18-3.2 23.9 3.9 0 0 12.4 14.8 17.7 22.1 5 6.8 11.7 17.7 15.2 23.8 6.1 10.9 2.3 22-3.7 26.6l-12 9.6c-6.1 4.9-5.3 14-5.3 14s17.8 67.3 84.3 84.3c0 0 9.1.8 14-5.3l9.6-12c4.6-6 15.7-9.8 26.6-3.7 14.7 8.3 33.4 21.2 45.8 32.9 7 5.7 8.6 14.4 3.8 23.6z"],vimeo:[448,512,[],"f40a","M403.2 32H44.8C20.1 32 0 52.1 0 76.8v358.4C0 459.9 20.1 480 44.8 480h358.4c24.7 0 44.8-20.1 44.8-44.8V76.8c0-24.7-20.1-44.8-44.8-44.8zM377 180.8c-1.4 31.5-23.4 74.7-66 129.4-44 57.2-81.3 85.8-111.7 85.8-18.9 0-34.8-17.4-47.9-52.3-25.5-93.3-36.4-148-57.4-148-2.4 0-10.9 5.1-25.4 15.2l-15.2-19.6c37.3-32.8 72.9-69.2 95.2-71.2 25.2-2.4 40.7 14.8 46.5 51.7 20.7 131.2 29.9 151 67.6 91.6 13.5-21.4 20.8-37.7 21.8-48.9 3.5-33.2-25.9-30.9-45.8-22.4 15.9-52.1 46.3-77.4 91.2-76 33.3.9 49 22.5 47.1 64.7z"],"vimeo-square":[448,512,[],"f194","M400 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48zm-16.2 149.6c-1.4 31.1-23.2 73.8-65.3 127.9-43.5 56.5-80.3 84.8-110.4 84.8-18.7 0-34.4-17.2-47.3-51.6-25.2-92.3-35.9-146.4-56.7-146.4-2.4 0-10.8 5-25.1 15.1L64 192c36.9-32.4 72.1-68.4 94.1-70.4 24.9-2.4 40.2 14.6 46 51.1 20.5 129.6 29.6 149.2 66.8 90.5 13.4-21.2 20.6-37.2 21.5-48.3 3.4-32.8-25.6-30.6-45.2-22.2 15.7-51.5 45.8-76.5 90.1-75.1 32.9 1 48.4 22.4 46.5 64z"],"vimeo-v":[448,512,[],"f27d","M447.8 153.6c-2 43.6-32.4 103.3-91.4 179.1-60.9 79.2-112.4 118.8-154.6 118.8-26.1 0-48.2-24.1-66.3-72.3C100.3 250 85.3 174.3 56.2 174.3c-3.4 0-15.1 7.1-35.2 21.1L0 168.2c51.6-45.3 100.9-95.7 131.8-98.5 34.9-3.4 56.3 20.5 64.4 71.5 28.7 181.5 41.4 208.9 93.6 126.7 18.7-29.6 28.8-52.1 30.2-67.6 4.8-45.9-35.8-42.8-63.3-31 22-72.1 64.1-107.1 126.2-105.1 45.8 1.2 67.5 31.1 64.9 89.4z"],vine:[384,512,[],"f1ca","M384 254.7v52.1c-18.4 4.2-36.9 6.1-52.1 6.1-36.9 77.4-103 143.8-125.1 156.2-14 7.9-27.1 8.4-42.7-.8C137 452 34.2 367.7 0 102.7h74.5C93.2 261.8 139 343.4 189.3 404.5c27.9-27.9 54.8-65.1 75.6-106.9-49.8-25.3-80.1-80.9-80.1-145.6 0-65.6 37.7-115.1 102.2-115.1 114.9 0 106.2 127.9 81.6 181.5 0 0-46.4 9.2-63.5-20.5 3.4-11.3 8.2-30.8 8.2-48.5 0-31.3-11.3-46.6-28.4-46.6-18.2 0-30.8 17.1-30.8 50 .1 79.2 59.4 118.7 129.9 101.9z"],vk:[576,512,[],"f189","M545 117.7c3.7-12.5 0-21.7-17.8-21.7h-58.9c-15 0-21.9 7.9-25.6 16.7 0 0-30 73.1-72.4 120.5-13.7 13.7-20 18.1-27.5 18.1-3.7 0-9.4-4.4-9.4-16.9V117.7c0-15-4.2-21.7-16.6-21.7h-92.6c-9.4 0-15 7-15 13.5 0 14.2 21.2 17.5 23.4 57.5v86.8c0 19-3.4 22.5-10.9 22.5-20 0-68.6-73.4-97.4-157.4-5.8-16.3-11.5-22.9-26.6-22.9H38.8c-16.8 0-20.2 7.9-20.2 16.7 0 15.6 20 93.1 93.1 195.5C160.4 378.1 229 416 291.4 416c37.5 0 42.1-8.4 42.1-22.9 0-66.8-3.4-73.1 15.4-73.1 8.7 0 23.7 4.4 58.7 38.1 40 40 46.6 57.9 69 57.9h58.9c16.8 0 25.3-8.4 20.4-25-11.2-34.9-86.9-106.7-90.3-111.5-8.7-11.2-6.2-16.2 0-26.2.1-.1 72-101.3 79.4-135.6z"],vnv:[640,512,[],"f40b","M104.9 352c-34.1 0-46.4-30.4-46.4-30.4L2.6 210.1S-7.8 192 13 192h32.8c10.4 0 13.2 8.7 18.8 18.1l36.7 74.5s5.2 13.1 21.1 13.1 21.1-13.1 21.1-13.1l36.7-74.5c5.6-9.5 8.4-18.1 18.8-18.1h32.8c20.8 0 10.4 18.1 10.4 18.1l-55.8 111.5S174.2 352 140 352h-35.1zm395 0c-34.1 0-46.4-30.4-46.4-30.4l-55.9-111.5S387.2 192 408 192h32.8c10.4 0 13.2 8.7 18.8 18.1l36.7 74.5s5.2 13.1 21.1 13.1 21.1-13.1 21.1-13.1l36.8-74.5c5.6-9.5 8.4-18.1 18.8-18.1H627c20.8 0 10.4 18.1 10.4 18.1l-55.9 111.5S569.3 352 535.1 352h-35.2zM337.6 192c34.1 0 46.4 30.4 46.4 30.4l55.9 111.5s10.4 18.1-10.4 18.1h-32.8c-10.4 0-13.2-8.7-18.8-18.1l-36.7-74.5s-5.2-13.1-21.1-13.1c-15.9 0-21.1 13.1-21.1 13.1l-36.7 74.5c-5.6 9.4-8.4 18.1-18.8 18.1h-32.9c-20.8 0-10.4-18.1-10.4-18.1l55.9-111.5s12.2-30.4 46.4-30.4h35.1z"],vuejs:[448,512,[],"f41f","M356.9 64.3H280l-56 88.6-48-88.6H0L224 448 448 64.3h-91.1zm-301.2 32h53.8L224 294.5 338.4 96.3h53.8L224 384.5 55.7 96.3z"],weibo:[512,512,[],"f18a","M407 177.6c7.6-24-13.4-46.8-37.4-41.7-22 4.8-28.8-28.1-7.1-32.8 50.1-10.9 92.3 37.1 76.5 84.8-6.8 21.2-38.8 10.8-32-10.3zM214.8 446.7C108.5 446.7 0 395.3 0 310.4c0-44.3 28-95.4 76.3-143.7C176 67 279.5 65.8 249.9 161c-4 13.1 12.3 5.7 12.3 6 79.5-33.6 140.5-16.8 114 51.4-3.7 9.4 1.1 10.9 8.3 13.1 135.7 42.3 34.8 215.2-169.7 215.2zm143.7-146.3c-5.4-55.7-78.5-94-163.4-85.7-84.8 8.6-148.8 60.3-143.4 116s78.5 94 163.4 85.7c84.8-8.6 148.8-60.3 143.4-116zM347.9 35.1c-25.9 5.6-16.8 43.7 8.3 38.3 72.3-15.2 134.8 52.8 111.7 124-7.4 24.2 29.1 37 37.4 12 31.9-99.8-55.1-195.9-157.4-174.3zm-78.5 311c-17.1 38.8-66.8 60-109.1 46.3-40.8-13.1-58-53.4-40.3-89.7 17.7-35.4 63.1-55.4 103.4-45.1 42 10.8 63.1 50.2 46 88.5zm-86.3-30c-12.9-5.4-30 .3-38 12.9-8.3 12.9-4.3 28 8.6 34 13.1 6 30.8.3 39.1-12.9 8-13.1 3.7-28.3-9.7-34zm32.6-13.4c-5.1-1.7-11.4.6-14.3 5.4-2.9 5.1-1.4 10.6 3.7 12.9 5.1 2 11.7-.3 14.6-5.4 2.8-5.2 1.1-10.9-4-12.9z"],weixin:[576,512,[],"f1d7","M372.3 167.6c6.4 0 12.6.3 18.8 1.1C374.4 90.3 290.3 32 194.7 32 87.6 32 0 104.8 0 197.4c0 53.4 29.3 97.5 77.9 131.6l-19.3 58.6 68-34.1c24.4 4.8 43.8 9.7 68.2 9.7 6.2 0 12.1-.3 18.3-.8-4-12.9-6.2-26.6-6.2-40.8-.1-84.9 73-154 165.4-154zm-104.5-52.9c14.5 0 24.2 9.7 24.2 24.4 0 14.5-9.7 24.2-24.2 24.2-14.8 0-29.3-9.7-29.3-24.2 0-14.7 14.5-24.4 29.3-24.4zm-136.5 48.6c-14.5 0-29.3-9.7-29.3-24.2 0-14.8 14.8-24.4 29.3-24.4 14.8 0 24.4 9.7 24.4 24.4.1 14.6-9.6 24.2-24.4 24.2zm418.8 156.1c0-77.9-77.9-141.3-165.4-141.3-92.7 0-165.4 63.4-165.4 141.3S292 460.7 384.6 460.7c19.3 0 38.9-5.1 58.6-9.9l53.4 29.3-14.8-48.6c39.3-29.4 68.3-68.3 68.3-112.1zm-219.2-24.5c-9.7 0-19.3-9.7-19.3-19.6 0-9.7 9.7-19.3 19.3-19.3 14.8 0 24.4 9.7 24.4 19.3 0 10-9.6 19.6-24.4 19.6zm107.2 0c-9.7 0-19.3-9.7-19.3-19.6 0-9.7 9.7-19.3 19.3-19.3 14.5 0 24.4 9.7 24.4 19.3 0 10-9.9 19.6-24.4 19.6z"],whatsapp:[448,512,[],"f232","M380.9 97.1C339 55.1 283.2 32 223.9 32c-122.4 0-222 99.6-222 222 0 39.1 10.2 77.3 29.6 111L0 480l117.7-30.9c32.4 17.7 68.9 27 106.1 27h.1c122.3 0 224.1-99.6 224.1-222 0-59.3-25.2-115-67.1-157zm-157 341.6c-33.2 0-65.7-8.9-94-25.7l-6.7-4-69.8 18.3L72 359.2l-4.4-7c-18.5-29.4-28.2-63.3-28.2-98.2 0-101.7 82.8-184.5 184.6-184.5 49.3 0 95.6 19.2 130.4 54.1 34.8 34.9 56.2 81.2 56.1 130.5 0 101.8-84.9 184.6-186.6 184.6zm101.2-138.2c-5.5-2.8-32.8-16.2-37.9-18-5.1-1.9-8.8-2.8-12.5 2.8-3.7 5.6-14.3 18-17.6 21.8-3.2 3.7-6.5 4.2-12 1.4-32.6-16.3-54-29.1-75.5-66-5.7-9.8 5.7-9.1 16.3-30.3 1.8-3.7.9-6.9-.5-9.7-1.4-2.8-12.5-30.1-17.1-41.2-4.5-10.8-9.1-9.3-12.5-9.5-3.2-.2-6.9-.2-10.6-.2-3.7 0-9.7 1.4-14.8 6.9-5.1 5.6-19.4 19-19.4 46.3 0 27.3 19.9 53.7 22.6 57.4 2.8 3.7 39.1 59.7 94.8 83.8 35.2 15.2 49 16.5 66.6 13.9 10.7-1.6 32.8-13.4 37.4-26.4 4.6-13 4.6-24.1 3.2-26.4-1.3-2.5-5-3.9-10.5-6.6z"],"whatsapp-square":[448,512,[],"f40c","M224 122.8c-72.7 0-131.8 59.1-131.9 131.8 0 24.9 7 49.2 20.2 70.1l3.1 5-13.3 48.6 49.9-13.1 4.8 2.9c20.2 12 43.4 18.4 67.1 18.4h.1c72.6 0 133.3-59.1 133.3-131.8 0-35.2-15.2-68.3-40.1-93.2-25-25-58-38.7-93.2-38.7zm77.5 188.4c-3.3 9.3-19.1 17.7-26.7 18.8-12.6 1.9-22.4.9-47.5-9.9-39.7-17.2-65.7-57.2-67.7-59.8-2-2.6-16.2-21.5-16.2-41s10.2-29.1 13.9-33.1c3.6-4 7.9-5 10.6-5 2.6 0 5.3 0 7.6.1 2.4.1 5.7-.9 8.9 6.8 3.3 7.9 11.2 27.4 12.2 29.4s1.7 4.3.3 6.9c-7.6 15.2-15.7 14.6-11.6 21.6 15.3 26.3 30.6 35.4 53.9 47.1 4 2 6.3 1.7 8.6-1 2.3-2.6 9.9-11.6 12.5-15.5 2.6-4 5.3-3.3 8.9-2 3.6 1.3 23.1 10.9 27.1 12.9s6.6 3 7.6 4.6c.9 1.9.9 9.9-2.4 19.1zM400 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48zM223.9 413.2c-26.6 0-52.7-6.7-75.8-19.3L64 416l22.5-82.2c-13.9-24-21.2-51.3-21.2-79.3C65.4 167.1 136.5 96 223.9 96c42.4 0 82.2 16.5 112.2 46.5 29.9 30 47.9 69.8 47.9 112.2 0 87.4-72.7 158.5-160.1 158.5z"],whmcs:[448,512,[],"f40d","M448 161v-21.3l-28.5-8.8-2.2-10.4 20.1-20.7L427 80.4l-29 7.5-7.2-7.5 7.5-28.2-19.1-11.6-21.3 21-10.7-3.2-7-26.4h-22.6l-6.2 26.4-12.1 3.2-19.7-21-19.4 11 8.1 27.7-8.1 8.4-28.5-7.5-11 19.1 20.7 21-2.9 10.4-28.5 7.8-.3 21.7 28.8 7.5 2.4 12.1-20.1 19.9 10.4 18.5 29.6-7.5 7.2 8.6-8.1 26.9 19.9 11.6 19.4-20.4 11.6 2.9 6.7 28.5 22.6.3 6.7-28.8 11.6-3.5 20.7 21.6 20.4-12.1-8.8-28 7.8-8.1 28.8 8.8 10.3-20.1-20.9-18.8 2.2-12.1 29.1-7zm-119.2 45.2c-31.3 0-56.8-25.4-56.8-56.8s25.4-56.8 56.8-56.8 56.8 25.4 56.8 56.8c0 31.5-25.4 56.8-56.8 56.8zm72.3 16.4l46.9 14.5V277l-55.1 13.4-4.1 22.7 38.9 35.3-19.2 37.9-54-16.7-14.6 15.2 16.7 52.5-38.3 22.7-38.9-40.5-21.7 6.6-12.6 54-42.4-.5-12.6-53.6-21.7-5.6-36.4 38.4-37.4-21.7 15.2-50.5-13.7-16.1-55.5 14.1-19.7-34.8 37.9-37.4-4.8-22.8-54-14.1.5-40.9L54 219.9l5.7-19.7-38.9-39.4L41.5 125l53.6 14.1 15.2-15.7-15.2-52 36.4-20.7 36.8 39.4L191 84l11.6-52H245l11.6 45.9L234 72l-6.3-1.7-3.3 5.7-11 19.1-3.3 5.6 4.6 4.6 17.2 17.4-.3 1-23.8 6.5-6.2 1.7-.1 6.4-.2 12.9C153.8 161.6 118 204 118 254.7c0 58.3 47.3 105.7 105.7 105.7 50.5 0 92.7-35.4 103.2-82.8l13.2.2 6.9.1 1.6-6.7 5.6-24 1.9-.6 17.1 17.8 4.7 4.9 5.8-3.4 20.4-12.1 5.8-3.5-2-6.5-6.8-21.2z"],"wikipedia-w":[640,512,[],"f266","M640 51.2l-.3 12.2c-28.1.8-45 15.8-55.8 40.3-25 57.8-103.3 240-155.3 358.6H415l-81.9-193.1c-32.5 63.6-68.3 130-99.2 193.1-.3.3-15 0-15-.3C172 352.3 122.8 243.4 75.8 133.4 64.4 106.7 26.4 63.4.2 63.7c0-3.1-.3-10-.3-14.2h161.9v13.9c-19.2 1.1-52.8 13.3-43.3 34.2 21.9 49.7 103.6 240.3 125.6 288.6 15-29.7 57.8-109.2 75.3-142.8-13.9-28.3-58.6-133.9-72.8-160-9.7-17.8-36.1-19.4-55.8-19.7V49.8l142.5.3v13.1c-19.4.6-38.1 7.8-29.4 26.1 18.9 40 30.6 68.1 48.1 104.7 5.6-10.8 34.7-69.4 48.1-100.8 8.9-20.6-3.9-28.6-38.6-29.4.3-3.6 0-10.3.3-13.6 44.4-.3 111.1-.3 123.1-.6v13.6c-22.5.8-45.8 12.8-58.1 31.7l-59.2 122.8c6.4 16.1 63.3 142.8 69.2 156.7L559.2 91.8c-8.6-23.1-36.4-28.1-47.2-28.3V49.6l127.8 1.1.2.5z"],windows:[448,512,[],"f17a","M0 93.7l183.6-25.3v177.4H0V93.7zm0 324.6l183.6 25.3V268.4H0v149.9zm203.8 28L448 480V268.4H203.8v177.9zm0-380.6v180.1H448V32L203.8 65.7z"],wordpress:[512,512,[],"f19a","M61.7 169.4l101.5 278C92.2 413 43.3 340.2 43.3 256c0-30.9 6.6-60.1 18.4-86.6zm337.9 75.9c0-26.3-9.4-44.5-17.5-58.7-10.8-17.5-20.9-32.4-20.9-49.9 0-19.6 14.8-37.8 35.7-37.8.9 0 1.8.1 2.8.2-37.9-34.7-88.3-55.9-143.7-55.9-74.3 0-139.7 38.1-177.8 95.9 5 .2 9.7.3 13.7.3 22.2 0 56.7-2.7 56.7-2.7 11.5-.7 12.8 16.2 1.4 17.5 0 0-11.5 1.3-24.3 2l77.5 230.4L249.8 247l-33.1-90.8c-11.5-.7-22.3-2-22.3-2-11.5-.7-10.1-18.2 1.3-17.5 0 0 35.1 2.7 56 2.7 22.2 0 56.7-2.7 56.7-2.7 11.5-.7 12.8 16.2 1.4 17.5 0 0-11.5 1.3-24.3 2l76.9 228.7 21.2-70.9c9-29.4 16-50.5 16-68.7zm-139.9 29.3l-63.8 185.5c19.1 5.6 39.2 8.7 60.1 8.7 24.8 0 48.5-4.3 70.6-12.1-.6-.9-1.1-1.9-1.5-2.9l-65.4-179.2zm183-120.7c.9 6.8 1.4 14 1.4 21.9 0 21.6-4 45.8-16.2 76.2l-65 187.9C426.2 403 468.7 334.5 468.7 256c0-37-9.4-71.8-26-102.1zM504 256c0 136.8-111.3 248-248 248C119.2 504 8 392.7 8 256 8 119.2 119.2 8 256 8c136.7 0 248 111.2 248 248zm-11.4 0c0-130.5-106.2-236.6-236.6-236.6C125.5 19.4 19.4 125.5 19.4 256S125.6 492.6 256 492.6c130.5 0 236.6-106.1 236.6-236.6z"],"wordpress-simple":[512,512,[],"f411","M256 8C119.3 8 8 119.2 8 256c0 136.7 111.3 248 248 248s248-111.3 248-248C504 119.2 392.7 8 256 8zM33 256c0-32.3 6.9-63 19.3-90.7l106.4 291.4C84.3 420.5 33 344.2 33 256zm223 223c-21.9 0-43-3.2-63-9.1l66.9-194.4 68.5 187.8c.5 1.1 1 2.1 1.6 3.1-23.1 8.1-48 12.6-74 12.6zm30.7-327.5c13.4-.7 25.5-2.1 25.5-2.1 12-1.4 10.6-19.1-1.4-18.4 0 0-36.1 2.8-59.4 2.8-21.9 0-58.7-2.8-58.7-2.8-12-.7-13.4 17.7-1.4 18.4 0 0 11.4 1.4 23.4 2.1l34.7 95.2L200.6 393l-81.2-241.5c13.4-.7 25.5-2.1 25.5-2.1 12-1.4 10.6-19.1-1.4-18.4 0 0-36.1 2.8-59.4 2.8-4.2 0-9.1-.1-14.4-.3C109.6 73 178.1 33 256 33c58 0 110.9 22.2 150.6 58.5-1-.1-1.9-.2-2.9-.2-21.9 0-37.4 19.1-37.4 39.6 0 18.4 10.6 33.9 21.9 52.3 8.5 14.8 18.4 33.9 18.4 61.5 0 19.1-7.3 41.2-17 72.1l-22.2 74.3-80.7-239.6zm81.4 297.2l68.1-196.9c12.7-31.8 17-57.2 17-79.9 0-8.2-.5-15.8-1.5-22.9 17.4 31.8 27.3 68.2 27.3 107 0 82.3-44.6 154.1-110.9 192.7z"],wpbeginner:[512,512,[],"f297","M462.799 322.374C519.01 386.682 466.961 480 370.944 480c-39.602 0-78.824-17.687-100.142-50.04-6.887.356-22.702.356-29.59 0C219.848 462.381 180.588 480 141.069 480c-95.49 0-148.348-92.996-91.855-157.626C-29.925 190.523 80.479 32 256.006 32c175.632 0 285.87 158.626 206.793 290.374zm-339.647-82.972h41.529v-58.075h-41.529v58.075zm217.18 86.072v-23.839c-60.506 20.915-132.355 9.198-187.589-33.971l.246 24.897c51.101 46.367 131.746 57.875 187.343 32.913zm-150.753-86.072h166.058v-58.075H189.579v58.075z"],wpexplorer:[512,512,[],"f2de","M512 256c0 141.2-114.7 256-256 256C114.8 512 0 397.3 0 256S114.7 0 256 0s256 114.7 256 256zm-32 0c0-123.2-100.3-224-224-224C132.5 32 32 132.5 32 256s100.5 224 224 224 224-100.5 224-224zM160.9 124.6l86.9 37.1-37.1 86.9-86.9-37.1 37.1-86.9zm110 169.1l46.6 94h-14.6l-50-100-48.9 100h-14l51.1-106.9-22.3-9.4 6-14 68.6 29.1-6 14.3-16.5-7.1zm-11.8-116.3l68.6 29.4-29.4 68.3L230 246l29.1-68.6zm80.3 42.9l54.6 23.1-23.4 54.3-54.3-23.1 23.1-54.3z"],wpforms:[448,512,[],"f298","M448 75.2v361.7c0 24.3-19 43.2-43.2 43.2H43.2C19.3 480 0 461.4 0 436.8V75.2C0 51.1 18.8 32 43.2 32h361.7c24 0 43.1 18.8 43.1 43.2zm-37.3 361.6V75.2c0-3-2.6-5.8-5.8-5.8h-9.3L285.3 144 224 94.1 162.8 144 52.5 69.3h-9.3c-3.2 0-5.8 2.8-5.8 5.8v361.7c0 3 2.6 5.8 5.8 5.8h361.7c3.2.1 5.8-2.7 5.8-5.8zM150.2 186v37H76.7v-37h73.5zm0 74.4v37.3H76.7v-37.3h73.5zm11.1-147.3l54-43.7H96.8l64.5 43.7zm210 72.9v37h-196v-37h196zm0 74.4v37.3h-196v-37.3h196zm-84.6-147.3l64.5-43.7H232.8l53.9 43.7zM371.3 335v37.3h-99.4V335h99.4z"],xbox:[512,512,[],"f412","M369.9 318.2c44.3 54.3 64.7 98.8 54.4 118.7-7.9 15.1-56.7 44.6-92.6 55.9-29.6 9.3-68.4 13.3-100.4 10.2-38.2-3.7-76.9-17.4-110.1-39C93.3 445.8 87 438.3 87 423.4c0-29.9 32.9-82.3 89.2-142.1 32-33.9 76.5-73.7 81.4-72.6 9.4 2.1 84.3 75.1 112.3 109.5zM188.6 143.8c-29.7-26.9-58.1-53.9-86.4-63.4-15.2-5.1-16.3-4.8-28.7 8.1-29.2 30.4-53.5 79.7-60.3 122.4-5.4 34.2-6.1 43.8-4.2 60.5 5.6 50.5 17.3 85.4 40.5 120.9 9.5 14.6 12.1 17.3 9.3 9.9-4.2-11-.3-37.5 9.5-64 14.3-39 53.9-112.9 120.3-194.4zm311.6 63.5C483.3 127.3 432.7 77 425.6 77c-7.3 0-24.2 6.5-36 13.9-23.3 14.5-41 31.4-64.3 52.8C367.7 197 427.5 283.1 448.2 346c6.8 20.7 9.7 41.1 7.4 52.3-1.7 8.5-1.7 8.5 1.4 4.6 6.1-7.7 19.9-31.3 25.4-43.5 7.4-16.2 15-40.2 18.6-58.7 4.3-22.5 3.9-70.8-.8-93.4zM141.3 43C189 40.5 251 77.5 255.6 78.4c.7.1 10.4-4.2 21.6-9.7 63.9-31.1 94-25.8 107.4-25.2-63.9-39.3-152.7-50-233.9-11.7-23.4 11.1-24 11.9-9.4 11.2z"],xing:[384,512,[],"f168","M162.7 210c-1.8 3.3-25.2 44.4-70.1 123.5-4.9 8.3-10.8 12.5-17.7 12.5H9.8c-7.7 0-12.1-7.5-8.5-14.4l69-121.3c.2 0 .2-.1 0-.3l-43.9-75.6c-4.3-7.8.3-14.1 8.5-14.1H100c7.3 0 13.3 4.1 18 12.2l44.7 77.5zM382.6 46.1l-144 253v.3L330.2 466c3.9 7.1.2 14.1-8.5 14.1h-65.2c-7.6 0-13.6-4-18-12.2l-92.4-168.5c3.3-5.8 51.5-90.8 144.8-255.2 4.6-8.1 10.4-12.2 17.5-12.2h65.7c8 0 12.3 6.7 8.5 14.1z"],"xing-square":[448,512,[],"f169","M400 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48zM140.4 320.2H93.8c-5.5 0-8.7-5.3-6-10.3l49.3-86.7c.1 0 .1-.1 0-.2l-31.4-54c-3-5.6.2-10.1 6-10.1h46.6c5.2 0 9.5 2.9 12.9 8.7l31.9 55.3c-1.3 2.3-18 31.7-50.1 88.2-3.5 6.2-7.7 9.1-12.6 9.1zm219.7-214.1L257.3 286.8v.2l65.5 119c2.8 5.1.1 10.1-6 10.1h-46.6c-5.5 0-9.7-2.9-12.9-8.7l-66-120.3c2.3-4.1 36.8-64.9 103.4-182.3 3.3-5.8 7.4-8.7 12.5-8.7h46.9c5.7-.1 8.8 4.7 6 10z"],"y-combinator":[448,512,[],"f23b","M448 32v448H0V32h448zM236 287.5L313.5 142h-32.7L235 233c-4.7 9.3-9 18.3-12.8 26.8L210 233l-45.2-91h-35l76.7 143.8v94.5H236v-92.8z"],yahoo:[360,512,[],"f19e","M204.9 288l3.5 195.5c-11.3-2-20.9-3.5-28.7-3.5-7.5 0-17 1.5-28.7 3.5l3.5-195.5C105.7 203.7 56.5 113.1 0 28.5 10.6 31.3 20.4 32 29.5 32c8 0 18.1-.7 30.3-3.5 36.4 64.2 72.9 123.2 119.9 200.4 33.2-54.7 80.9-128.1 119.9-200.4 9.8 2.6 19.6 3.5 29.2 3.5 10.2 0 20.6-.9 31.1-3.5C329.4 71.1 243 221.3 204.9 288z"],yandex:[256,512,[],"f413","M153.1 315.8L65.7 512H2l96-209.8c-45.1-22.9-75.2-64.4-75.2-141.1C22.7 53.7 90.8 0 171.7 0H254v512h-55.1V315.8h-45.8zm45.8-269.3h-29.4c-44.4 0-87.4 29.4-87.4 114.6 0 82.3 39.4 108.8 87.4 108.8h29.4V46.5z"],"yandex-international":[320,512,[],"f414","M129.5 512V345.9L18.5 48h55.8l81.8 229.7L250.2 0h51.3L180.8 347.8V512h-51.3z"],yelp:[384,512,[],"f1e9","M136.9 328c-1 .3-109.2 35.7-115.8 35.7-15.2-.9-18.5-16.2-19.9-31.2-1.5-14.2-1.4-29.8.3-46.8 1.9-18.8 5.5-45.1 24.2-44 4.8 0 67.1 25.9 112.7 44.4 17.1 6.8 18.6 35.8-1.5 41.9zm57.9-113.9c1.8 38.2-25.5 48.5-47.2 14.3L41.3 60.4c-1.5-6.6.3-12.4 5.3-17.4C62.2 26.5 146 3.2 168.1 8.9c7.5 1.9 12.1 6.1 13.8 12.6 1.3 8.3 11.5 167.4 12.9 192.6zm-1.4 164.8c0 4.6.2 116.4-1.7 121.5-2.3 6-7 9.7-14.3 11.2-10.1 1.7-27.1-1.9-51-10.7-22-8.1-56.7-21.5-49.3-42.5 2.8-6.9 51.4-62.8 77.3-93.6 12-15.2 39.8-5.5 39 14.1zm180.2-117.8c-5.6 3.7-110.8 28.2-118.1 30.6l.3-.6c-18.1 4.7-35.4-18.5-23.3-34.6 3.7-3.7 65.9-92.4 72.8-97 5.2-3.6 11.3-3.8 18.3-.6 18.4 8.8 55.1 63.1 57.4 84.6-.1 2.9 1.2 11.7-7.4 17.6zm10.1 130.7c-2.7 20.6-44.5 73.4-63.8 81-6.9 2.6-12.9 2-17.7-2-5-3.5-61.8-97.1-64.9-102.3-10.9-16.2 6.8-39.8 25.6-33.2 0 0 110.5 35.7 114.7 39.4 5.2 4.1 7.2 9.8 6.1 17.1z"],yoast:[448,512,[],"f2b1","M91.265 96h186.043l-7.008 18.878H91.265c-39.658 0-71.889 31.556-71.889 70.292v205.373c0 35.401 24.882 70.311 84.001 70.311V480H91.265C41.165 480 0 439.83 0 390.544V185.17C0 135.937 40.709 96 91.265 96zm229.114-56h66.49C243.146 418.092 241.192 438.918 202.18 479.331c-20.779 21.646-49.294 31.719-78.328 32.669v-51.146c49.234-7.662 64.606-49.855 64.606-75.284 0-20.078.577-12.645-82.117-223.219h61.386l50.354 156.58L320.379 40zM448 181.465V480H233.963c6.635-9.621 10.679-16.277 12.112-19.413h182.529V181.465c0-32.543-17.097-51.945-48.194-62.914l6.733-17.578C428.763 114.636 448 144.059 448 181.465z"],youtube:[576,512,[],"f167","M549.655 124.083c-6.281-23.65-24.787-42.276-48.284-48.597C458.781 64 288 64 288 64S117.22 64 74.629 75.486c-23.497 6.322-42.003 24.947-48.284 48.597-11.412 42.867-11.412 132.305-11.412 132.305s0 89.438 11.412 132.305c6.281 23.65 24.787 41.5 48.284 47.821C117.22 448 288 448 288 448s170.78 0 213.371-11.486c23.497-6.321 42.003-24.171 48.284-47.821 11.412-42.867 11.412-132.305 11.412-132.305s0-89.438-11.412-132.305zm-317.51 213.508V175.185l142.739 81.205-142.739 81.201z"]}),t=z||{};t.___FONT_AWESOME___||(t.___FONT_AWESOME___={}),t.___FONT_AWESOME___.styles||(t.___FONT_AWESOME___.styles={}),t.___FONT_AWESOME___.hooks||(t.___FONT_AWESOME___.hooks={}),t.___FONT_AWESOME___.shims||(t.___FONT_AWESOME___.shims=[]);var s=t.___FONT_AWESOME___,r=Object.assign||function(c){for(var l=1;l<arguments.length;l++){var h=arguments[l];for(var v in h)Object.prototype.hasOwnProperty.call(h,v)&&(c[v]=h[v])}return c};!function(c){try{c()}catch(c){}}(function(){c("fab")})}(),function(){"use strict";function c(c){"function"==typeof s.hooks.addPack?s.hooks.addPack(c,m):s.styles[c]=r({},s.styles[c]||{},m)}var l={};try{"undefined"!=typeof window&&(l=window)}catch(c){}var h=(l.navigator||{}).userAgent,v=void 0===h?"":h,z=l,e=(~v.indexOf("MSIE")||v.indexOf("Trident/"),[1,2,3,4,5,6,7,8,9,10]),a=e.concat([11,12,13,14,15,16,17,18,19,20]),m=(["xs","sm","lg","fw","ul","li","border","pull-left","pull-right","spin","pulse","rotate-90","rotate-180","rotate-270","flip-horizontal","flip-vertical","stack","stack-1x","stack-2x","inverse","layers","layers-text","layers-counter"].concat(e.map(function(c){return c+"x"})).concat(a.map(function(c){return"w-"+c})),{"address-book":[448,512,[],"f2b9","M320 320v72c0 13.255-10.745 24-24 24H152c-13.255 0-24-10.745-24-24v-72c0-21.431 14.207-40.266 34.813-46.153l18.064-5.161C193.629 275.884 208.342 280 224 280s30.371-4.116 43.122-11.314l18.064 5.161C305.793 279.734 320 298.569 320 320zm-96-64c35.346 0 64-28.654 64-64s-28.654-64-64-64-64 28.654-64 64 28.654 64 64 64zm192-96v64h20c6.627 0 12 5.373 12 12v40c0 6.627-5.373 12-12 12h-20v64h20c6.627 0 12 5.373 12 12v40c0 6.627-5.373 12-12 12h-20v48c0 26.51-21.49 48-48 48H80c-26.51 0-48-21.49-48-48V48C32 21.49 53.49 0 80 0h288c26.51 0 48 21.49 48 48v48h20c6.627 0 12 5.373 12 12v40c0 6.627-5.373 12-12 12h-20zm-48 298V54a6 6 0 0 0-6-6H86a6 6 0 0 0-6 6v404a6 6 0 0 0 6 6h276a6 6 0 0 0 6-6z"],"address-card":[512,512,[],"f2bb","M464 64H48C21.49 64 0 85.49 0 112v288c0 26.51 21.49 48 48 48h416c26.51 0 48-21.49 48-48V112c0-26.51-21.49-48-48-48zm-6 336H54a6 6 0 0 1-6-6V118a6 6 0 0 1 6-6h404a6 6 0 0 1 6 6v276a6 6 0 0 1-6 6zm-54-176H300c-6.627 0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h104c6.627 0 12 5.373 12 12v24c0 6.627-5.373 12-12 12zm0 80H300c-6.627 0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h104c6.627 0 12 5.373 12 12v24c0 6.627-5.373 12-12 12zm-284-96c0-30.928 25.072-56 56-56s56 25.072 56 56-25.072 56-56 56-56-25.072-56-56zm136 89.857V340c0 6.627-5.373 12-12 12H108c-6.627 0-12-5.373-12-12v-42.143a24 24 0 0 1 17.104-22.988l13.464-4.039C140.186 281.568 157.351 288 176 288s35.814-6.432 49.433-17.17l13.464 4.039A24 24 0 0 1 256 297.857z"],"arrow-alt-circle-down":[512,512,[],"f358","M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm0 448c-110.5 0-200-89.5-200-200S145.5 56 256 56s200 89.5 200 200-89.5 200-200 200zm-32-316v116h-67c-10.7 0-16 12.9-8.5 20.5l99 99c4.7 4.7 12.3 4.7 17 0l99-99c7.6-7.6 2.2-20.5-8.5-20.5h-67V140c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12z"],"arrow-alt-circle-left":[512,512,[],"f359","M8 256c0 137 111 248 248 248s248-111 248-248S393 8 256 8 8 119 8 256zm448 0c0 110.5-89.5 200-200 200S56 366.5 56 256 145.5 56 256 56s200 89.5 200 200zm-72-20v40c0 6.6-5.4 12-12 12H256v67c0 10.7-12.9 16-20.5 8.5l-99-99c-4.7-4.7-4.7-12.3 0-17l99-99c7.6-7.6 20.5-2.2 20.5 8.5v67h116c6.6 0 12 5.4 12 12z"],"arrow-alt-circle-right":[512,512,[],"f35a","M504 256C504 119 393 8 256 8S8 119 8 256s111 248 248 248 248-111 248-248zm-448 0c0-110.5 89.5-200 200-200s200 89.5 200 200-89.5 200-200 200S56 366.5 56 256zm72 20v-40c0-6.6 5.4-12 12-12h116v-67c0-10.7 12.9-16 20.5-8.5l99 99c4.7 4.7 4.7 12.3 0 17l-99 99c-7.6 7.6-20.5 2.2-20.5-8.5v-67H140c-6.6 0-12-5.4-12-12z"],"arrow-alt-circle-up":[512,512,[],"f35b","M256 504c137 0 248-111 248-248S393 8 256 8 8 119 8 256s111 248 248 248zm0-448c110.5 0 200 89.5 200 200s-89.5 200-200 200S56 366.5 56 256 145.5 56 256 56zm20 328h-40c-6.6 0-12-5.4-12-12V256h-67c-10.7 0-16-12.9-8.5-20.5l99-99c4.7-4.7 12.3-4.7 17 0l99 99c7.6 7.6 2.2 20.5-8.5 20.5h-67v116c0 6.6-5.4 12-12 12z"],bell:[448,512,[],"f0f3","M425.403 330.939c-16.989-16.785-34.546-34.143-34.546-116.083 0-83.026-60.958-152.074-140.467-164.762A31.843 31.843 0 0 0 256 32c0-17.673-14.327-32-32-32s-32 14.327-32 32a31.848 31.848 0 0 0 5.609 18.095C118.101 62.783 57.143 131.831 57.143 214.857c0 81.933-17.551 99.292-34.543 116.078C-25.496 378.441 9.726 448 66.919 448H160c0 35.346 28.654 64 64 64 35.346 0 64-28.654 64-64h93.08c57.19 0 92.415-69.583 44.323-117.061zM224 472c-13.234 0-24-10.766-24-24h48c0 13.234-10.766 24-24 24zm157.092-72H66.9c-16.762 0-25.135-20.39-13.334-32.191 28.585-28.585 51.577-55.724 51.577-152.952C105.143 149.319 158.462 96 224 96s118.857 53.319 118.857 118.857c0 97.65 23.221 124.574 51.568 152.952C406.278 379.661 397.783 400 381.092 400z"],"bell-slash":[576,512,[],"f1f6","M130.9 400c-16.762 0-25.135-20.39-13.334-32.191 25.226-25.226 46.094-49.338 50.649-121.48l-46.777-41.274a168.48 168.48 0 0 0-.296 9.802c0 81.933-17.551 99.292-34.543 116.078C38.504 378.441 73.726 448 130.919 448H224c0 35.346 28.654 64 64 64s64-28.654 64-64h44.777l-54.4-48H130.9zM288 472c-13.234 0-24-10.766-24-24h48c0 13.234-10.766 24-24 24zm283.867.553l-67.931-59.571c13.104-24.118 11.524-56.318-14.532-82.042-16.989-16.785-34.546-34.143-34.546-116.083 0-83.026-60.958-152.074-140.467-164.762A31.848 31.848 0 0 0 320 32c0-17.673-14.327-32-32-32s-32 14.327-32 32a31.848 31.848 0 0 0 5.609 18.095c-41.471 6.618-77.891 28.571-103.249 59.841L36.459 3.037c-5.058-4.436-12.777-3.956-17.24 1.071L3.056 22.313C-1.407 27.34-.925 35.012 4.134 39.447l535.408 469.516c5.058 4.436 12.777 3.956 17.24-1.071l16.163-18.205c4.462-5.027 3.98-12.699-1.078-17.134zM288 96c65.538 0 118.857 53.319 118.857 118.857 0 97.65 23.221 124.574 51.568 152.952 2.908 2.908 4.573 6.328 5.209 9.832L194.482 141.612C216.258 113.867 250.075 96 288 96z"],bookmark:[384,512,[],"f02e","M336 0H48C21.49 0 0 21.49 0 48v464l192-112 192 112V48c0-26.51-21.49-48-48-48zm0 428.43l-144-84-144 84V54a6 6 0 0 1 6-6h276c3.314 0 6 2.683 6 5.996V428.43z"],building:[448,512,[],"f1ad","M128 148v-40c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12h-40c-6.6 0-12-5.4-12-12zm140 12h40c6.6 0 12-5.4 12-12v-40c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12zm-128 96h40c6.6 0 12-5.4 12-12v-40c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12zm128 0h40c6.6 0 12-5.4 12-12v-40c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12zm-76 84v-40c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12zm76 12h40c6.6 0 12-5.4 12-12v-40c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12zm180 124v36H0v-36c0-6.6 5.4-12 12-12h19.5V24c0-13.3 10.7-24 24-24h337c13.3 0 24 10.7 24 24v440H436c6.6 0 12 5.4 12 12zM79.5 463H192v-67c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v67h112.5V49L80 48l-.5 415z"],calendar:[448,512,[],"f133","M400 64h-48V12c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v52H160V12c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v52H48C21.5 64 0 85.5 0 112v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V112c0-26.5-21.5-48-48-48zm-6 400H54c-3.3 0-6-2.7-6-6V160h352v298c0 3.3-2.7 6-6 6z"],"calendar-alt":[448,512,[],"f073","M148 288h-40c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12zm108-12v-40c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12zm96 0v-40c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12zm-96 96v-40c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12zm-96 0v-40c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12zm192 0v-40c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12zm96-260v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V112c0-26.5 21.5-48 48-48h48V12c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v52h128V12c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v52h48c26.5 0 48 21.5 48 48zm-48 346V160H48v298c0 3.3 2.7 6 6 6h340c3.3 0 6-2.7 6-6z"],"calendar-check":[448,512,[],"f274","M400 64h-48V12c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v52H160V12c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v52H48C21.49 64 0 85.49 0 112v352c0 26.51 21.49 48 48 48h352c26.51 0 48-21.49 48-48V112c0-26.51-21.49-48-48-48zm-6 400H54a6 6 0 0 1-6-6V160h352v298a6 6 0 0 1-6 6zm-52.849-200.65L198.842 404.519c-4.705 4.667-12.303 4.637-16.971-.068l-75.091-75.699c-4.667-4.705-4.637-12.303.068-16.971l22.719-22.536c4.705-4.667 12.303-4.637 16.97.069l44.104 44.461 111.072-110.181c4.705-4.667 12.303-4.637 16.971.068l22.536 22.718c4.667 4.705 4.636 12.303-.069 16.97z"],"calendar-minus":[448,512,[],"f272","M124 328c-6.6 0-12-5.4-12-12v-24c0-6.6 5.4-12 12-12h200c6.6 0 12 5.4 12 12v24c0 6.6-5.4 12-12 12H124zm324-216v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V112c0-26.5 21.5-48 48-48h48V12c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v52h128V12c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v52h48c26.5 0 48 21.5 48 48zm-48 346V160H48v298c0 3.3 2.7 6 6 6h340c3.3 0 6-2.7 6-6z"],"calendar-plus":[448,512,[],"f271","M336 292v24c0 6.6-5.4 12-12 12h-76v76c0 6.6-5.4 12-12 12h-24c-6.6 0-12-5.4-12-12v-76h-76c-6.6 0-12-5.4-12-12v-24c0-6.6 5.4-12 12-12h76v-76c0-6.6 5.4-12 12-12h24c6.6 0 12 5.4 12 12v76h76c6.6 0 12 5.4 12 12zm112-180v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V112c0-26.5 21.5-48 48-48h48V12c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v52h128V12c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v52h48c26.5 0 48 21.5 48 48zm-48 346V160H48v298c0 3.3 2.7 6 6 6h340c3.3 0 6-2.7 6-6z"],"calendar-times":[448,512,[],"f273","M311.7 374.7l-17 17c-4.7 4.7-12.3 4.7-17 0L224 337.9l-53.7 53.7c-4.7 4.7-12.3 4.7-17 0l-17-17c-4.7-4.7-4.7-12.3 0-17l53.7-53.7-53.7-53.7c-4.7-4.7-4.7-12.3 0-17l17-17c4.7-4.7 12.3-4.7 17 0l53.7 53.7 53.7-53.7c4.7-4.7 12.3-4.7 17 0l17 17c4.7 4.7 4.7 12.3 0 17L257.9 304l53.7 53.7c4.8 4.7 4.8 12.3.1 17zM448 112v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V112c0-26.5 21.5-48 48-48h48V12c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v52h128V12c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v52h48c26.5 0 48 21.5 48 48zm-48 346V160H48v298c0 3.3 2.7 6 6 6h340c3.3 0 6-2.7 6-6z"],"caret-square-down":[448,512,[],"f150","M125.1 208h197.8c10.7 0 16.1 13 8.5 20.5l-98.9 98.3c-4.7 4.7-12.2 4.7-16.9 0l-98.9-98.3c-7.7-7.5-2.3-20.5 8.4-20.5zM448 80v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V80c0-26.5 21.5-48 48-48h352c26.5 0 48 21.5 48 48zm-48 346V86c0-3.3-2.7-6-6-6H54c-3.3 0-6 2.7-6 6v340c0 3.3 2.7 6 6 6h340c3.3 0 6-2.7 6-6z"],"caret-square-left":[448,512,[],"f191","M272 157.1v197.8c0 10.7-13 16.1-20.5 8.5l-98.3-98.9c-4.7-4.7-4.7-12.2 0-16.9l98.3-98.9c7.5-7.7 20.5-2.3 20.5 8.4zM448 80v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V80c0-26.5 21.5-48 48-48h352c26.5 0 48 21.5 48 48zm-48 346V86c0-3.3-2.7-6-6-6H54c-3.3 0-6 2.7-6 6v340c0 3.3 2.7 6 6 6h340c3.3 0 6-2.7 6-6z"],"caret-square-right":[448,512,[],"f152","M176 354.9V157.1c0-10.7 13-16.1 20.5-8.5l98.3 98.9c4.7 4.7 4.7 12.2 0 16.9l-98.3 98.9c-7.5 7.7-20.5 2.3-20.5-8.4zM448 80v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V80c0-26.5 21.5-48 48-48h352c26.5 0 48 21.5 48 48zm-48 346V86c0-3.3-2.7-6-6-6H54c-3.3 0-6 2.7-6 6v340c0 3.3 2.7 6 6 6h340c3.3 0 6-2.7 6-6z"],"caret-square-up":[448,512,[],"f151","M322.9 304H125.1c-10.7 0-16.1-13-8.5-20.5l98.9-98.3c4.7-4.7 12.2-4.7 16.9 0l98.9 98.3c7.7 7.5 2.3 20.5-8.4 20.5zM448 80v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V80c0-26.5 21.5-48 48-48h352c26.5 0 48 21.5 48 48zm-48 346V86c0-3.3-2.7-6-6-6H54c-3.3 0-6 2.7-6 6v340c0 3.3 2.7 6 6 6h340c3.3 0 6-2.7 6-6z"],"chart-bar":[512,512,[],"f080","M500 400c6.6 0 12 5.4 12 12v24c0 6.6-5.4 12-12 12H12c-6.6 0-12-5.4-12-12V76c0-6.6 5.4-12 12-12h24c6.6 0 12 5.4 12 12v324h452zm-356-60v-72c0-6.6-5.4-12-12-12h-24c-6.6 0-12 5.4-12 12v72c0 6.6 5.4 12 12 12h24c6.6 0 12-5.4 12-12zm96 0V140c0-6.6-5.4-12-12-12h-24c-6.6 0-12 5.4-12 12v200c0 6.6 5.4 12 12 12h24c6.6 0 12-5.4 12-12zm96 0V204c0-6.6-5.4-12-12-12h-24c-6.6 0-12 5.4-12 12v136c0 6.6 5.4 12 12 12h24c6.6 0 12-5.4 12-12zm96 0V108c0-6.6-5.4-12-12-12h-24c-6.6 0-12 5.4-12 12v232c0 6.6 5.4 12 12 12h24c6.6 0 12-5.4 12-12z"],"check-circle":[512,512,[],"f058","M256 8C119.033 8 8 119.033 8 256s111.033 248 248 248 248-111.033 248-248S392.967 8 256 8zm0 48c110.532 0 200 89.451 200 200 0 110.532-89.451 200-200 200-110.532 0-200-89.451-200-200 0-110.532 89.451-200 200-200m140.204 130.267l-22.536-22.718c-4.667-4.705-12.265-4.736-16.97-.068L215.346 303.697l-59.792-60.277c-4.667-4.705-12.265-4.736-16.97-.069l-22.719 22.536c-4.705 4.667-4.736 12.265-.068 16.971l90.781 91.516c4.667 4.705 12.265 4.736 16.97.068l172.589-171.204c4.704-4.668 4.734-12.266.067-16.971z"],"check-square":[448,512,[],"f14a","M400 32H48C21.49 32 0 53.49 0 80v352c0 26.51 21.49 48 48 48h352c26.51 0 48-21.49 48-48V80c0-26.51-21.49-48-48-48zm0 400H48V80h352v352zm-35.864-241.724L191.547 361.48c-4.705 4.667-12.303 4.637-16.97-.068l-90.781-91.516c-4.667-4.705-4.637-12.303.069-16.971l22.719-22.536c4.705-4.667 12.303-4.637 16.97.069l59.792 60.277 141.352-140.216c4.705-4.667 12.303-4.637 16.97.068l22.536 22.718c4.667 4.706 4.637 12.304-.068 16.971z"],circle:[512,512,[],"f111","M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm0 448c-110.5 0-200-89.5-200-200S145.5 56 256 56s200 89.5 200 200-89.5 200-200 200z"],clipboard:[384,512,[],"f328","M336 64h-80c0-35.29-28.71-64-64-64s-64 28.71-64 64H48C21.49 64 0 85.49 0 112v352c0 26.51 21.49 48 48 48h288c26.51 0 48-21.49 48-48V112c0-26.51-21.49-48-48-48zm-6 400H54a6 6 0 0 1-6-6V118a6 6 0 0 1 6-6h42v36c0 6.627 5.373 12 12 12h168c6.627 0 12-5.373 12-12v-36h42a6 6 0 0 1 6 6v340a6 6 0 0 1-6 6zM192 40c13.255 0 24 10.745 24 24s-10.745 24-24 24-24-10.745-24-24 10.745-24 24-24"],clock:[512,512,[],"f017","M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm0 448c-110.5 0-200-89.5-200-200S145.5 56 256 56s200 89.5 200 200-89.5 200-200 200zm61.8-104.4l-84.9-61.7c-3.1-2.3-4.9-5.9-4.9-9.7V116c0-6.6 5.4-12 12-12h32c6.6 0 12 5.4 12 12v141.7l66.8 48.6c5.4 3.9 6.5 11.4 2.6 16.8L334.6 349c-3.9 5.3-11.4 6.5-16.8 2.6z"],clone:[512,512,[],"f24d","M464 0H144c-26.51 0-48 21.49-48 48v48H48c-26.51 0-48 21.49-48 48v320c0 26.51 21.49 48 48 48h320c26.51 0 48-21.49 48-48v-48h48c26.51 0 48-21.49 48-48V48c0-26.51-21.49-48-48-48zM362 464H54a6 6 0 0 1-6-6V150a6 6 0 0 1 6-6h42v224c0 26.51 21.49 48 48 48h224v42a6 6 0 0 1-6 6zm96-96H150a6 6 0 0 1-6-6V54a6 6 0 0 1 6-6h308a6 6 0 0 1 6 6v308a6 6 0 0 1-6 6z"],"closed-captioning":[512,512,[],"f20a","M464 64H48C21.5 64 0 85.5 0 112v288c0 26.5 21.5 48 48 48h416c26.5 0 48-21.5 48-48V112c0-26.5-21.5-48-48-48zm-6 336H54c-3.3 0-6-2.7-6-6V118c0-3.3 2.7-6 6-6h404c3.3 0 6 2.7 6 6v276c0 3.3-2.7 6-6 6zm-211.1-85.7c1.7 2.4 1.5 5.6-.5 7.7-53.6 56.8-172.8 32.1-172.8-67.9 0-97.3 121.7-119.5 172.5-70.1 2.1 2 2.5 3.2 1 5.7l-17.5 30.5c-1.9 3.1-6.2 4-9.1 1.7-40.8-32-94.6-14.9-94.6 31.2 0 48 51 70.5 92.2 32.6 2.8-2.5 7.1-2.1 9.2.9l19.6 27.7zm190.4 0c1.7 2.4 1.5 5.6-.5 7.7-53.6 56.9-172.8 32.1-172.8-67.9 0-97.3 121.7-119.5 172.5-70.1 2.1 2 2.5 3.2 1 5.7L420 220.2c-1.9 3.1-6.2 4-9.1 1.7-40.8-32-94.6-14.9-94.6 31.2 0 48 51 70.5 92.2 32.6 2.8-2.5 7.1-2.1 9.2.9l19.6 27.7z"],comment:[576,512,[],"f075","M288 32C129 32 0 125.1 0 240c0 49.3 23.7 94.5 63.3 130.2-8.7 23.3-22.1 32.7-37.1 43.1C15.1 421-6 433 1.6 456.5c5.1 15.4 20.9 24.7 38.1 23.3 57.7-4.6 111.2-19.2 157-42.5 28.7 6.9 59.4 10.7 91.2 10.7 159.1 0 288-93 288-208C576 125.1 447.1 32 288 32zm0 368c-32.5 0-65.4-4.4-97.3-14-32.3 19-78.7 46-134.7 54 32-24 56.8-61.6 61.2-88.4C79.1 325.6 48 286.7 48 240c0-70.9 86.3-160 240-160s240 89.1 240 160c0 71-86.3 160-240 160z"],"comment-alt":[576,512,[],"f27a","M288 32C129 32 0 125.1 0 240c0 49.3 23.7 94.5 63.3 130.2-8.7 23.3-22.1 32.7-37.1 43.1C15.1 421-6 433 1.6 456.5c5.1 15.4 20.9 24.7 38.1 23.3 57.7-4.6 111.2-19.2 157-42.5 28.7 6.9 59.4 10.7 91.2 10.7 159.1 0 288-93 288-208C576 125.1 447.1 32 288 32zm0 368c-32.5 0-65.4-4.4-97.3-14-32.3 19-78.7 46-134.7 54 32-24 56.8-61.6 61.2-88.4C79.1 325.6 48 286.7 48 240c0-70.9 86.3-160 240-160s240 89.1 240 160c0 71-86.3 160-240 160zm-64-160c0 26.5-21.5 48-48 48s-48-21.5-48-48 21.5-48 48-48 48 21.5 48 48zm112 0c0 26.5-21.5 48-48 48s-48-21.5-48-48 21.5-48 48-48 48 21.5 48 48zm112 0c0 26.5-21.5 48-48 48s-48-21.5-48-48 21.5-48 48-48 48 21.5 48 48z"],comments:[576,512,[],"f086","M574.507 443.86c-5.421 21.261-24.57 36.14-46.511 36.14-32.246 0-66.511-9.99-102.1-29.734-50.64 11.626-109.151 7.877-157.96-13.437 41.144-2.919 80.361-12.339 116.331-28.705 16.322-1.22 32.674-4.32 48.631-9.593C454.404 412.365 490.663 432 527.996 432c-32-17.455-43.219-38.958-46.159-58.502 25.443-18.848 46.159-47.183 46.159-81.135 0-10.495-2.383-21.536-7.041-32.467 7.405-25.93 8.656-50.194 5.185-73.938 32.164 30.461 49.856 69.128 49.856 106.405 0 33.893-12.913 65.047-34.976 91.119 2.653 2.038 5.924 4.176 9.962 6.378 19.261 10.508 28.947 32.739 23.525 54zM240.002 80C117.068 80 48.004 152.877 48.004 210.909c0 38.196 24.859 70.072 55.391 91.276-3.527 21.988-16.991 46.179-55.391 65.815 44.8 0 88.31-22.089 114.119-37.653 25.52 7.906 51.883 11.471 77.879 11.471C362.998 341.818 432 268.976 432 210.909 432 152.882 362.943 80 240.002 80m0-48C390.193 32 480 126.026 480 210.909c0 22.745-6.506 46.394-18.816 68.391-11.878 21.226-28.539 40.294-49.523 56.674-21.593 16.857-46.798 30.045-74.913 39.197-29.855 9.719-62.405 14.646-96.746 14.646-24.449 0-48.34-2.687-71.292-8.004C126.311 404.512 85.785 416 48.004 416c-22.18 0-41.472-15.197-46.665-36.761-5.194-21.563 5.064-43.878 24.811-53.976 7.663-3.918 13.324-7.737 17.519-11.294-7.393-7.829-13.952-16.124-19.634-24.844C8.09 264.655.005 238.339.005 210.909.005 126.259 89.508 32 240.002 32z"],compass:[512,512,[],"f14e","M256 8C119.033 8 8 119.033 8 256s111.033 248 248 248 248-111.033 248-248S392.967 8 256 8zm0 448c-110.532 0-200-89.451-200-200 0-110.531 89.451-200 200-200 110.532 0 200 89.451 200 200 0 110.532-89.451 200-200 200zm91.326-312.131l-33.359 137.779a24.005 24.005 0 0 1-6.772 11.729l-102.64 97.779c-17.104 16.293-45.56.434-39.88-23.024l33.359-137.779a23.997 23.997 0 0 1 6.772-11.729l102.642-97.779c17.285-16.47 45.494-.175 39.878 23.024zM256 224c-17.673 0-32 14.327-32 32s14.327 32 32 32 32-14.327 32-32-14.327-32-32-32z"],copy:[448,512,[],"f0c5","M433.941 65.941l-51.882-51.882A48 48 0 0 0 348.118 0H176c-26.51 0-48 21.49-48 48v48H48c-26.51 0-48 21.49-48 48v320c0 26.51 21.49 48 48 48h224c26.51 0 48-21.49 48-48v-48h80c26.51 0 48-21.49 48-48V99.882a48 48 0 0 0-14.059-33.941zM266 464H54a6 6 0 0 1-6-6V150a6 6 0 0 1 6-6h74v224c0 26.51 21.49 48 48 48h96v42a6 6 0 0 1-6 6zm128-96H182a6 6 0 0 1-6-6V54a6 6 0 0 1 6-6h106v88c0 13.255 10.745 24 24 24h88v202a6 6 0 0 1-6 6zm6-256h-64V48h9.632c1.591 0 3.117.632 4.243 1.757l48.368 48.368a6 6 0 0 1 1.757 4.243V112z"],copyright:[512,512,[],"f1f9","M256 8C119.033 8 8 119.033 8 256s111.033 248 248 248 248-111.033 248-248S392.967 8 256 8zm0 448c-110.532 0-200-89.451-200-200 0-110.531 89.451-200 200-200 110.532 0 200 89.451 200 200 0 110.532-89.451 200-200 200zm107.351-101.064c-9.614 9.712-45.53 41.396-104.065 41.396-82.43 0-140.484-61.425-140.484-141.567 0-79.152 60.275-139.401 139.762-139.401 55.531 0 88.738 26.62 97.593 34.779a11.965 11.965 0 0 1 1.936 15.322l-18.155 28.113c-3.841 5.95-11.966 7.282-17.499 2.921-8.595-6.776-31.814-22.538-61.708-22.538-48.303 0-77.916 35.33-77.916 80.082 0 41.589 26.888 83.692 78.277 83.692 32.657 0 56.843-19.039 65.726-27.225 5.27-4.857 13.596-4.039 17.82 1.738l19.865 27.17a11.947 11.947 0 0 1-1.152 15.518z"],"credit-card":[576,512,[],"f09d","M527.9 32H48.1C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48.1 48h479.8c26.6 0 48.1-21.5 48.1-48V80c0-26.5-21.5-48-48.1-48zM54.1 80h467.8c3.3 0 6 2.7 6 6v42H48.1V86c0-3.3 2.7-6 6-6zm467.8 352H54.1c-3.3 0-6-2.7-6-6V256h479.8v170c0 3.3-2.7 6-6 6zM192 332v40c0 6.6-5.4 12-12 12h-72c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h72c6.6 0 12 5.4 12 12zm192 0v40c0 6.6-5.4 12-12 12H236c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h136c6.6 0 12 5.4 12 12z"],"dot-circle":[512,512,[],"f192","M256 56c110.532 0 200 89.451 200 200 0 110.532-89.451 200-200 200-110.532 0-200-89.451-200-200 0-110.532 89.451-200 200-200m0-48C119.033 8 8 119.033 8 256s111.033 248 248 248 248-111.033 248-248S392.967 8 256 8zm0 168c-44.183 0-80 35.817-80 80s35.817 80 80 80 80-35.817 80-80-35.817-80-80-80z"],edit:[576,512,[],"f044","M402.3 344.9l32-32c5-5 13.7-1.5 13.7 5.7V464c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V112c0-26.5 21.5-48 48-48h273.5c7.1 0 10.7 8.6 5.7 13.7l-32 32c-1.5 1.5-3.5 2.3-5.7 2.3H48v352h352V350.5c0-2.1.8-4.1 2.3-5.6zm156.6-201.8L296.3 405.7l-90.4 10c-26.2 2.9-48.5-19.2-45.6-45.6l10-90.4L432.9 17.1c22.9-22.9 59.9-22.9 82.7 0l43.2 43.2c22.9 22.9 22.9 60 .1 82.8zM460.1 174L402 115.9 216.2 301.8l-7.3 65.3 65.3-7.3L460.1 174zm64.8-79.7l-43.2-43.2c-4.1-4.1-10.8-4.1-14.8 0L436 82l58.1 58.1 30.9-30.9c4-4.2 4-10.8-.1-14.9z"],envelope:[512,512,[],"f0e0","M464 64H48C21.49 64 0 85.49 0 112v288c0 26.51 21.49 48 48 48h416c26.51 0 48-21.49 48-48V112c0-26.51-21.49-48-48-48zm0 48v40.805c-22.422 18.259-58.168 46.651-134.587 106.49-16.841 13.247-50.201 45.072-73.413 44.701-23.208.375-56.579-31.459-73.413-44.701C106.18 199.465 70.425 171.067 48 152.805V112h416zM48 400V214.398c22.914 18.251 55.409 43.862 104.938 82.646 21.857 17.205 60.134 55.186 103.062 54.955 42.717.231 80.509-37.199 103.053-54.947 49.528-38.783 82.032-64.401 104.947-82.653V400H48z"],"envelope-open":[512,512,[],"f2b6","M494.586 164.516c-4.697-3.883-111.723-89.95-135.251-108.657C337.231 38.191 299.437 0 256 0c-43.205 0-80.636 37.717-103.335 55.859-24.463 19.45-131.07 105.195-135.15 108.549A48.004 48.004 0 0 0 0 201.485V464c0 26.51 21.49 48 48 48h416c26.51 0 48-21.49 48-48V201.509a48 48 0 0 0-17.414-36.993zM464 458a6 6 0 0 1-6 6H54a6 6 0 0 1-6-6V204.347c0-1.813.816-3.526 2.226-4.665 15.87-12.814 108.793-87.554 132.364-106.293C200.755 78.88 232.398 48 256 48c23.693 0 55.857 31.369 73.41 45.389 23.573 18.741 116.503 93.493 132.366 106.316a5.99 5.99 0 0 1 2.224 4.663V458zm-31.991-187.704c4.249 5.159 3.465 12.795-1.745 16.981-28.975 23.283-59.274 47.597-70.929 56.863C336.636 362.283 299.205 400 256 400c-43.452 0-81.287-38.237-103.335-55.86-11.279-8.967-41.744-33.413-70.927-56.865-5.21-4.187-5.993-11.822-1.745-16.981l15.258-18.528c4.178-5.073 11.657-5.843 16.779-1.726 28.618 23.001 58.566 47.035 70.56 56.571C200.143 320.631 232.307 352 256 352c23.602 0 55.246-30.88 73.41-45.389 11.994-9.535 41.944-33.57 70.563-56.568 5.122-4.116 12.601-3.346 16.778 1.727l15.258 18.526z"],"eye-slash":[576,512,[],"f070","M272.702 359.139c-80.483-9.011-136.212-86.886-116.93-167.042l116.93 167.042zM288 392c-102.556 0-192.092-54.701-240-136 21.755-36.917 52.1-68.342 88.344-91.658l-27.541-39.343C67.001 152.234 31.921 188.741 6.646 231.631a47.999 47.999 0 0 0 0 48.739C63.004 376.006 168.14 440 288 440a332.89 332.89 0 0 0 39.648-2.367l-32.021-45.744A284.16 284.16 0 0 1 288 392zm281.354-111.631c-33.232 56.394-83.421 101.742-143.554 129.492l48.116 68.74c3.801 5.429 2.48 12.912-2.949 16.712L450.23 509.83c-5.429 3.801-12.912 2.48-16.712-2.949L102.084 33.399c-3.801-5.429-2.48-12.912 2.949-16.712L125.77 2.17c5.429-3.801 12.912-2.48 16.712 2.949l55.526 79.325C226.612 76.343 256.808 72 288 72c119.86 0 224.996 63.994 281.354 159.631a48.002 48.002 0 0 1 0 48.738zM528 256c-44.157-74.933-123.677-127.27-216.162-135.007C302.042 131.078 296 144.83 296 160c0 30.928 25.072 56 56 56s56-25.072 56-56l-.001-.042c30.632 57.277 16.739 130.26-36.928 171.719l26.695 38.135C452.626 346.551 498.308 306.386 528 256z"],file:[384,512,[],"f15b","M369.9 97.9L286 14C277 5 264.8-.1 252.1-.1H48C21.5 0 0 21.5 0 48v416c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48V131.9c0-12.7-5.1-25-14.1-34zM332.1 128H256V51.9l76.1 76.1zM48 464V48h160v104c0 13.3 10.7 24 24 24h104v288H48z"],"file-alt":[384,512,[],"f15c","M288 248v28c0 6.6-5.4 12-12 12H108c-6.6 0-12-5.4-12-12v-28c0-6.6 5.4-12 12-12h168c6.6 0 12 5.4 12 12zm-12 72H108c-6.6 0-12 5.4-12 12v28c0 6.6 5.4 12 12 12h168c6.6 0 12-5.4 12-12v-28c0-6.6-5.4-12-12-12zm108-188.1V464c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V48C0 21.5 21.5 0 48 0h204.1C264.8 0 277 5.1 286 14.1L369.9 98c9 8.9 14.1 21.2 14.1 33.9zm-128-80V128h76.1L256 51.9zM336 464V176H232c-13.3 0-24-10.7-24-24V48H48v416h288z"],"file-archive":[384,512,[],"f1c6","M369.941 97.941l-83.882-83.882A48 48 0 0 0 252.118 0H48C21.49 0 0 21.49 0 48v416c0 26.51 21.49 48 48 48h288c26.51 0 48-21.49 48-48V131.882a48 48 0 0 0-14.059-33.941zM256 51.882L332.118 128H256V51.882zM336 464H48V48h79.714v16h32V48H208v104c0 13.255 10.745 24 24 24h104v288zM192.27 96h-32V64h32v32zm-32 0v32h-32V96h32zm0 64v32h-32v-32h32zm32 0h-32v-32h32v32zm1.909 105.678A12 12 0 0 0 182.406 256H160.27v-32h-32v32l-19.69 97.106C101.989 385.611 126.834 416 160 416c33.052 0 57.871-30.192 51.476-62.62l-17.297-87.702zM160.27 390.073c-17.918 0-32.444-12.105-32.444-27.036 0-14.932 14.525-27.036 32.444-27.036s32.444 12.105 32.444 27.036c0 14.931-14.526 27.036-32.444 27.036zm32-166.073h-32v-32h32v32z"],"file-audio":[384,512,[],"f1c7","M369.941 97.941l-83.882-83.882A48 48 0 0 0 252.118 0H48C21.49 0 0 21.49 0 48v416c0 26.51 21.49 48 48 48h288c26.51 0 48-21.49 48-48V131.882a48 48 0 0 0-14.059-33.941zM332.118 128H256V51.882L332.118 128zM48 464V48h160v104c0 13.255 10.745 24 24 24h104v288H48zm144-76.024c0 10.691-12.926 16.045-20.485 8.485L136 360.486h-28c-6.627 0-12-5.373-12-12v-56c0-6.627 5.373-12 12-12h28l35.515-36.947c7.56-7.56 20.485-2.206 20.485 8.485v135.952zm41.201-47.13c9.051-9.297 9.06-24.133.001-33.439-22.149-22.752 12.235-56.246 34.395-33.481 27.198 27.94 27.212 72.444.001 100.401-21.793 22.386-56.947-10.315-34.397-33.481z"],"file-code":[384,512,[],"f1c9","M369.941 97.941l-83.882-83.882A48 48 0 0 0 252.118 0H48C21.49 0 0 21.49 0 48v416c0 26.51 21.49 48 48 48h288c26.51 0 48-21.49 48-48V131.882a48 48 0 0 0-14.059-33.941zM332.118 128H256V51.882L332.118 128zM48 464V48h160v104c0 13.255 10.745 24 24 24h104v288H48zm101.677-115.115L116.854 320l32.822-28.885a8.793 8.793 0 0 0 .605-12.624l-17.403-18.564c-3.384-3.613-8.964-3.662-12.438-.401L62.78 313.58c-3.703 3.474-3.704 9.367.001 12.84l57.659 54.055a8.738 8.738 0 0 0 6.012 2.381 8.746 8.746 0 0 0 6.427-2.782l17.403-18.563a8.795 8.795 0 0 0-.605-12.626zm84.284-127.85l-24.401-7.084a8.796 8.796 0 0 0-10.905 5.998L144.04 408.061c-1.353 4.66 1.338 9.552 5.998 10.905l24.403 7.084c4.68 1.355 9.557-1.354 10.905-5.998l54.612-188.112c1.354-4.66-1.337-9.552-5.997-10.905zm87.258 92.545l-57.658-54.055c-3.526-3.307-9.099-3.165-12.439.401l-17.403 18.563a8.795 8.795 0 0 0 .605 12.625L267.146 320l-32.822 28.885a8.793 8.793 0 0 0-.605 12.624l17.403 18.564a8.797 8.797 0 0 0 12.439.401h-.001l57.66-54.055c3.703-3.473 3.703-9.366-.001-12.839z"],"file-excel":[384,512,[],"f1c3","M369.9 97.9L286 14C277 5 264.8-.1 252.1-.1H48C21.5 0 0 21.5 0 48v416c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48V131.9c0-12.7-5.1-25-14.1-34zM332.1 128H256V51.9l76.1 76.1zM48 464V48h160v104c0 13.3 10.7 24 24 24h104v288H48zm212-240h-28.8c-4.4 0-8.4 2.4-10.5 6.3-18 33.1-22.2 42.4-28.6 57.7-13.9-29.1-6.9-17.3-28.6-57.7-2.1-3.9-6.2-6.3-10.6-6.3H124c-9.3 0-15 10-10.4 18l46.3 78-46.3 78c-4.7 8 1.1 18 10.4 18h28.9c4.4 0 8.4-2.4 10.5-6.3 21.7-40 23-45 28.6-57.7 14.9 30.2 5.9 15.9 28.6 57.7 2.1 3.9 6.2 6.3 10.6 6.3H260c9.3 0 15-10 10.4-18L224 320c.7-1.1 30.3-50.5 46.3-78 4.7-8-1.1-18-10.3-18z"],"file-image":[384,512,[],"f1c5","M369.9 97.9L286 14C277 5 264.8-.1 252.1-.1H48C21.5 0 0 21.5 0 48v416c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48V131.9c0-12.7-5.1-25-14.1-34zM332.1 128H256V51.9l76.1 76.1zM48 464V48h160v104c0 13.3 10.7 24 24 24h104v288H48zm32-48h224V288l-23.5-23.5c-4.7-4.7-12.3-4.7-17 0L176 352l-39.5-39.5c-4.7-4.7-12.3-4.7-17 0L80 352v64zm48-240c-26.5 0-48 21.5-48 48s21.5 48 48 48 48-21.5 48-48-21.5-48-48-48z"],"file-pdf":[384,512,[],"f1c1","M369.9 97.9L286 14C277 5 264.8-.1 252.1-.1H48C21.5 0 0 21.5 0 48v416c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48V131.9c0-12.7-5.1-25-14.1-34zM332.1 128H256V51.9l76.1 76.1zM48 464V48h160v104c0 13.3 10.7 24 24 24h104v288H48zm250.2-143.7c-12.2-12-47-8.7-64.4-6.5-17.2-10.5-28.7-25-36.8-46.3 3.9-16.1 10.1-40.6 5.4-56-4.2-26.2-37.8-23.6-42.6-5.9-4.4 16.1-.4 38.5 7 67.1-10 23.9-24.9 56-35.4 74.4-20 10.3-47 26.2-51 46.2-3.3 15.8 26 55.2 76.1-31.2 22.4-7.4 46.8-16.5 68.4-20.1 18.9 10.2 41 17 55.8 17 25.5 0 28-28.2 17.5-38.7zm-198.1 77.8c5.1-13.7 24.5-29.5 30.4-35-19 30.3-30.4 35.7-30.4 35zm81.6-190.6c7.4 0 6.7 32.1 1.8 40.8-4.4-13.9-4.3-40.8-1.8-40.8zm-24.4 136.6c9.7-16.9 18-37 24.7-54.7 8.3 15.1 18.9 27.2 30.1 35.5-20.8 4.3-38.9 13.1-54.8 19.2zm131.6-5s-5 6-37.3-7.8c35.1-2.6 40.9 5.4 37.3 7.8z"],"file-powerpoint":[384,512,[],"f1c4","M369.9 97.9L286 14C277 5 264.8-.1 252.1-.1H48C21.5 0 0 21.5 0 48v416c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48V131.9c0-12.7-5.1-25-14.1-34zM332.1 128H256V51.9l76.1 76.1zM48 464V48h160v104c0 13.3 10.7 24 24 24h104v288H48zm72-60V236c0-6.6 5.4-12 12-12h69.2c36.7 0 62.8 27 62.8 66.3 0 74.3-68.7 66.5-95.5 66.5V404c0 6.6-5.4 12-12 12H132c-6.6 0-12-5.4-12-12zm48.5-87.4h23c7.9 0 13.9-2.4 18.1-7.2 8.5-9.8 8.4-28.5.1-37.8-4.1-4.6-9.9-7-17.4-7h-23.9v52z"],"file-video":[384,512,[],"f1c8","M369.941 97.941l-83.882-83.882A48 48 0 0 0 252.118 0H48C21.49 0 0 21.49 0 48v416c0 26.51 21.49 48 48 48h288c26.51 0 48-21.49 48-48V131.882a48 48 0 0 0-14.059-33.941zM332.118 128H256V51.882L332.118 128zM48 464V48h160v104c0 13.255 10.745 24 24 24h104v288H48zm228.687-211.303L224 305.374V268c0-11.046-8.954-20-20-20H100c-11.046 0-20 8.954-20 20v104c0 11.046 8.954 20 20 20h104c11.046 0 20-8.954 20-20v-37.374l52.687 52.674C286.704 397.318 304 390.28 304 375.986V264.011c0-14.311-17.309-21.319-27.313-11.314z"],"file-word":[384,512,[],"f1c2","M369.9 97.9L286 14C277 5 264.8-.1 252.1-.1H48C21.5 0 0 21.5 0 48v416c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48V131.9c0-12.7-5.1-25-14.1-34zM332.1 128H256V51.9l76.1 76.1zM48 464V48h160v104c0 13.3 10.7 24 24 24h104v288H48zm220.1-208c-5.7 0-10.6 4-11.7 9.5-20.6 97.7-20.4 95.4-21 103.5-.2-1.2-.4-2.6-.7-4.3-.8-5.1.3.2-23.6-99.5-1.3-5.4-6.1-9.2-11.7-9.2h-13.3c-5.5 0-10.3 3.8-11.7 9.1-24.4 99-24 96.2-24.8 103.7-.1-1.1-.2-2.5-.5-4.2-.7-5.2-14.1-73.3-19.1-99-1.1-5.6-6-9.7-11.8-9.7h-16.8c-7.8 0-13.5 7.3-11.7 14.8 8 32.6 26.7 109.5 33.2 136 1.3 5.4 6.1 9.1 11.7 9.1h25.2c5.5 0 10.3-3.7 11.6-9.1l17.9-71.4c1.5-6.2 2.5-12 3-17.3l2.9 17.3c.1.4 12.6 50.5 17.9 71.4 1.3 5.3 6.1 9.1 11.6 9.1h24.7c5.5 0 10.3-3.7 11.6-9.1 20.8-81.9 30.2-119 34.5-136 1.9-7.6-3.8-14.9-11.6-14.9h-15.8z"],flag:[512,512,[],"f024","M336.174 80c-49.132 0-93.305-32-161.913-32-31.301 0-58.303 6.482-80.721 15.168a48.04 48.04 0 0 0 2.142-20.727C93.067 19.575 74.167 1.594 51.201.104 23.242-1.71 0 20.431 0 48c0 17.764 9.657 33.262 24 41.562V496c0 8.837 7.163 16 16 16h16c8.837 0 16-7.163 16-16v-83.443C109.869 395.28 143.259 384 199.826 384c49.132 0 93.305 32 161.913 32 58.479 0 101.972-22.617 128.548-39.981C503.846 367.161 512 352.051 512 335.855V95.937c0-34.459-35.264-57.768-66.904-44.117C409.193 67.309 371.641 80 336.174 80zM464 336c-21.783 15.412-60.824 32-102.261 32-59.945 0-102.002-32-161.913-32-43.361 0-96.379 9.403-127.826 24V128c21.784-15.412 60.824-32 102.261-32 59.945 0 102.002 32 161.913 32 43.271 0 96.32-17.366 127.826-32v240z"],folder:[512,512,[],"f07b","M464 128H272l-64-64H48C21.49 64 0 85.49 0 112v288c0 26.51 21.49 48 48 48h416c26.51 0 48-21.49 48-48V176c0-26.51-21.49-48-48-48zm-6 272H54c-3.314 0-6-2.678-6-5.992V117.992A5.993 5.993 0 0 1 54 112h134.118l64 64H458a6 6 0 0 1 6 6v212a6 6 0 0 1-6 6z"],"folder-open":[576,512,[],"f07c","M527.943 224H480v-48c0-26.51-21.49-48-48-48H272l-64-64H48C21.49 64 0 85.49 0 112v288c0 26.51 21.49 48 48 48h400a48.001 48.001 0 0 0 40.704-22.56l79.942-128c19.948-31.917-3.038-73.44-40.703-73.44zM54 112h134.118l64 64H426a6 6 0 0 1 6 6v42H152a48 48 0 0 0-41.098 23.202L48 351.449V117.993A5.993 5.993 0 0 1 54 112zm394 288H72l77.234-128H528l-80 128z"],frown:[512,512,[],"f119","M256 56c110.532 0 200 89.451 200 200 0 110.532-89.451 200-200 200-110.532 0-200-89.451-200-200 0-110.532 89.451-200 200-200m0-48C119.033 8 8 119.033 8 256s111.033 248 248 248 248-111.033 248-248S392.967 8 256 8zm64 136c-9.535 0-18.512 2.386-26.37 6.589h.017c12.735 0 23.059 10.324 23.059 23.059 0 12.735-10.324 23.059-23.059 23.059s-23.059-10.324-23.059-23.059v-.017C266.386 181.488 264 190.465 264 200c0 30.928 25.072 56 56 56s56-25.072 56-56-25.072-56-56-56zm-128 0c-9.535 0-18.512 2.386-26.37 6.589h.017c12.735 0 23.059 10.324 23.059 23.059 0 12.735-10.324 23.059-23.059 23.059-12.735 0-23.059-10.324-23.059-23.059v-.017C138.386 181.488 136 190.465 136 200c0 30.928 25.072 56 56 56s56-25.072 56-56-25.072-56-56-56zm171.547 201.782c-56.595-76.964-158.383-77.065-215.057-.001-18.82 25.593 19.858 54.018 38.67 28.438 37.511-51.01 100.365-50.796 137.717-.001 18.509 25.172 57.821-2.395 38.67-28.436z"],futbol:[512,512,[],"f1e3","M207.898 325.571l-29.894-91.312L256 177.732l77.996 56.527-29.622 91.312h-96.476zM504 256c0 136.967-111.033 248-248 248S8 392.967 8 256 119.033 8 256 8s248 111.033 248 248zm-455.998-.19L48 256c0 44.7 14.015 87.242 39.95 122.626l7.982-35.118 88.595 10.871 37.775 80.985-30.978 18.427c41.832 13.631 87.598 13.606 129.354 0L289.7 435.364l37.775-80.985 88.594-10.871 7.982 35.118C449.985 343.242 464 300.7 464 256l-.002-.19-27.003 23.561-65.223-60.875 17.122-87.779 35.538 3.183c-25.216-34.63-61.309-62.053-104.577-75.951l14.143 33.091L256 134.25l-77.996-43.21 14.144-33.091C148.868 71.851 112.782 99.277 87.57 133.9l35.81-3.183 16.849 87.779-65.223 60.875-27.004-23.561z"],gem:[576,512,[],"f3a5","M464 0H112c-4 0-7.8 2-10 5.4L2 152.6c-2.9 4.4-2.6 10.2.7 14.2l276 340.8c4.8 5.9 13.8 5.9 18.6 0l276-340.8c3.3-4.1 3.6-9.8.7-14.2L474.1 5.4C471.8 2 468.1 0 464 0zm-19.3 48l63.3 96h-68.4l-51.7-96h56.8zm-202.1 0h90.7l51.7 96H191l51.6-96zm-111.3 0h56.8l-51.7 96H68l63.3-96zm-43 144h51.4L208 352 88.3 192zm102.9 0h193.6L288 435.3 191.2 192zM368 352l68.2-160h51.4L368 352z"],"hand-lizard":[576,512,[],"f258","M556.686 290.542L410.328 64.829C397.001 44.272 374.417 32 349.917 32H56C25.121 32 0 57.122 0 88v8c0 44.112 35.888 80 80 80h196.042l-18.333 48H144c-48.523 0-88 39.477-88 88 0 30.879 25.121 56 56 56h131.552c2.987 0 5.914.549 8.697 1.631L352 408.418V480h224V355.829c0-23.225-6.679-45.801-19.314-65.287zM528 432H400v-23.582c0-19.948-12.014-37.508-30.604-44.736l-99.751-38.788A71.733 71.733 0 0 0 243.552 320H112c-4.411 0-8-3.589-8-8 0-22.056 17.944-40 40-40h113.709c19.767 0 37.786-12.407 44.84-30.873l24.552-64.281c8.996-23.553-8.428-48.846-33.63-48.846H80c-17.645 0-32-14.355-32-32v-8c0-4.411 3.589-8 8-8h293.917c8.166 0 15.693 4.09 20.137 10.942l146.358 225.715A71.84 71.84 0 0 1 528 355.829V432z"],"hand-paper":[448,512,[],"f256","M372.57 112.641v-10.825c0-43.612-40.52-76.691-83.039-65.546-25.629-49.5-94.09-47.45-117.982.747C130.269 26.456 89.144 57.945 89.144 102v126.13c-19.953-7.427-43.308-5.068-62.083 8.871-29.355 21.796-35.794 63.333-14.55 93.153L132.48 498.569a32 32 0 0 0 26.062 13.432h222.897c14.904 0 27.835-10.289 31.182-24.813l30.184-130.958A203.637 203.637 0 0 0 448 310.564V179c0-40.62-35.523-71.992-75.43-66.359zm27.427 197.922c0 11.731-1.334 23.469-3.965 34.886L368.707 464h-201.92L51.591 302.303c-14.439-20.27 15.023-42.776 29.394-22.605l27.128 38.079c8.995 12.626 29.031 6.287 29.031-9.283V102c0-25.645 36.571-24.81 36.571.691V256c0 8.837 7.163 16 16 16h6.856c8.837 0 16-7.163 16-16V67c0-25.663 36.571-24.81 36.571.691V256c0 8.837 7.163 16 16 16h6.856c8.837 0 16-7.163 16-16V101.125c0-25.672 36.57-24.81 36.57.691V256c0 8.837 7.163 16 16 16h6.857c8.837 0 16-7.163 16-16v-76.309c0-26.242 36.57-25.64 36.57-.691v131.563z"],"hand-peace":[448,512,[],"f25b","M362.146 191.976c-13.71-21.649-38.761-34.016-65.006-30.341V74c0-40.804-32.811-74-73.141-74-40.33 0-73.14 33.196-73.14 74L160 168l-18.679-78.85C126.578 50.843 83.85 32.11 46.209 47.208 8.735 62.238-9.571 104.963 5.008 142.85l55.757 144.927c-30.557 24.956-43.994 57.809-24.733 92.218l54.853 97.999C102.625 498.97 124.73 512 148.575 512h205.702c30.744 0 57.558-21.44 64.555-51.797l27.427-118.999a67.801 67.801 0 0 0 1.729-15.203L448 256c0-44.956-43.263-77.343-85.854-64.024zM399.987 326c0 1.488-.169 2.977-.502 4.423l-27.427 119.001c-1.978 8.582-9.29 14.576-17.782 14.576H148.575c-6.486 0-12.542-3.621-15.805-9.449l-54.854-98c-4.557-8.141-2.619-18.668 4.508-24.488l26.647-21.764a16 16 0 0 0 4.812-18.139l-64.09-166.549C37.226 92.956 84.37 74.837 96.51 106.389l59.784 155.357A16 16 0 0 0 171.227 272h11.632c8.837 0 16-7.163 16-16V74c0-34.375 50.281-34.43 50.281 0v182c0 8.837 7.163 16 16 16h6.856c8.837 0 16-7.163 16-16v-28c0-25.122 36.567-25.159 36.567 0v28c0 8.837 7.163 16 16 16h6.856c8.837 0 16-7.163 16-16 0-25.12 36.567-25.16 36.567 0v70z"],"hand-point-down":[448,512,[],"f0a7","M188.8 512c45.616 0 83.2-37.765 83.2-83.2v-35.647a93.148 93.148 0 0 0 22.064-7.929c22.006 2.507 44.978-3.503 62.791-15.985C409.342 368.1 448 331.841 448 269.299V248c0-60.063-40-98.512-40-127.2v-2.679c4.952-5.747 8-13.536 8-22.12V32c0-17.673-12.894-32-28.8-32H156.8C140.894 0 128 14.327 128 32v64c0 8.584 3.048 16.373 8 22.12v2.679c0 6.964-6.193 14.862-23.668 30.183l-.148.129-.146.131c-9.937 8.856-20.841 18.116-33.253 25.851C48.537 195.798 0 207.486 0 252.8c0 56.928 35.286 92 83.2 92 8.026 0 15.489-.814 22.4-2.176V428.8c0 45.099 38.101 83.2 83.2 83.2zm0-48c-18.7 0-35.2-16.775-35.2-35.2V270.4c-17.325 0-35.2 26.4-70.4 26.4-26.4 0-35.2-20.625-35.2-44 0-8.794 32.712-20.445 56.1-34.926 14.575-9.074 27.225-19.524 39.875-30.799 18.374-16.109 36.633-33.836 39.596-59.075h176.752C364.087 170.79 400 202.509 400 248v21.299c0 40.524-22.197 57.124-61.325 50.601-8.001 14.612-33.979 24.151-53.625 12.925-18.225 19.365-46.381 17.787-61.05 4.95V428.8c0 18.975-16.225 35.2-35.2 35.2zM328 64c0-13.255 10.745-24 24-24s24 10.745 24 24-10.745 24-24 24-24-10.745-24-24z"],"hand-point-left":[512,512,[],"f0a5","M0 220.8C0 266.416 37.765 304 83.2 304h35.647a93.148 93.148 0 0 0 7.929 22.064c-2.507 22.006 3.503 44.978 15.985 62.791C143.9 441.342 180.159 480 242.701 480H264c60.063 0 98.512-40 127.2-40h2.679c5.747 4.952 13.536 8 22.12 8h64c17.673 0 32-12.894 32-28.8V188.8c0-15.906-14.327-28.8-32-28.8h-64c-8.584 0-16.373 3.048-22.12 8H391.2c-6.964 0-14.862-6.193-30.183-23.668l-.129-.148-.131-.146c-8.856-9.937-18.116-20.841-25.851-33.253C316.202 80.537 304.514 32 259.2 32c-56.928 0-92 35.286-92 83.2 0 8.026.814 15.489 2.176 22.4H83.2C38.101 137.6 0 175.701 0 220.8zm48 0c0-18.7 16.775-35.2 35.2-35.2h158.4c0-17.325-26.4-35.2-26.4-70.4 0-26.4 20.625-35.2 44-35.2 8.794 0 20.445 32.712 34.926 56.1 9.074 14.575 19.524 27.225 30.799 39.875 16.109 18.374 33.836 36.633 59.075 39.596v176.752C341.21 396.087 309.491 432 264 432h-21.299c-40.524 0-57.124-22.197-50.601-61.325-14.612-8.001-24.151-33.979-12.925-53.625-19.365-18.225-17.787-46.381-4.95-61.05H83.2C64.225 256 48 239.775 48 220.8zM448 360c13.255 0 24 10.745 24 24s-10.745 24-24 24-24-10.745-24-24 10.745-24 24-24z"],"hand-point-right":[512,512,[],"f0a4","M428.8 137.6h-86.177a115.52 115.52 0 0 0 2.176-22.4c0-47.914-35.072-83.2-92-83.2-45.314 0-57.002 48.537-75.707 78.784-7.735 12.413-16.994 23.317-25.851 33.253l-.131.146-.129.148C135.662 161.807 127.764 168 120.8 168h-2.679c-5.747-4.952-13.536-8-22.12-8H32c-17.673 0-32 12.894-32 28.8v230.4C0 435.106 14.327 448 32 448h64c8.584 0 16.373-3.048 22.12-8h2.679c28.688 0 67.137 40 127.2 40h21.299c62.542 0 98.8-38.658 99.94-91.145 12.482-17.813 18.491-40.785 15.985-62.791A93.148 93.148 0 0 0 393.152 304H428.8c45.435 0 83.2-37.584 83.2-83.2 0-45.099-38.101-83.2-83.2-83.2zm0 118.4h-91.026c12.837 14.669 14.415 42.825-4.95 61.05 11.227 19.646 1.687 45.624-12.925 53.625 6.524 39.128-10.076 61.325-50.6 61.325H248c-45.491 0-77.21-35.913-120-39.676V215.571c25.239-2.964 42.966-21.222 59.075-39.596 11.275-12.65 21.725-25.3 30.799-39.875C232.355 112.712 244.006 80 252.8 80c23.375 0 44 8.8 44 35.2 0 35.2-26.4 53.075-26.4 70.4h158.4c18.425 0 35.2 16.5 35.2 35.2 0 18.975-16.225 35.2-35.2 35.2zM88 384c0 13.255-10.745 24-24 24s-24-10.745-24-24 10.745-24 24-24 24 10.745 24 24z"],"hand-point-up":[448,512,[],"f0a6","M105.6 83.2v86.177a115.52 115.52 0 0 0-22.4-2.176c-47.914 0-83.2 35.072-83.2 92 0 45.314 48.537 57.002 78.784 75.707 12.413 7.735 23.317 16.994 33.253 25.851l.146.131.148.129C129.807 376.338 136 384.236 136 391.2v2.679c-4.952 5.747-8 13.536-8 22.12v64c0 17.673 12.894 32 28.8 32h230.4c15.906 0 28.8-14.327 28.8-32v-64c0-8.584-3.048-16.373-8-22.12V391.2c0-28.688 40-67.137 40-127.2v-21.299c0-62.542-38.658-98.8-91.145-99.94-17.813-12.482-40.785-18.491-62.791-15.985A93.148 93.148 0 0 0 272 118.847V83.2C272 37.765 234.416 0 188.8 0c-45.099 0-83.2 38.101-83.2 83.2zm118.4 0v91.026c14.669-12.837 42.825-14.415 61.05 4.95 19.646-11.227 45.624-1.687 53.625 12.925 39.128-6.524 61.325 10.076 61.325 50.6V264c0 45.491-35.913 77.21-39.676 120H183.571c-2.964-25.239-21.222-42.966-39.596-59.075-12.65-11.275-25.3-21.725-39.875-30.799C80.712 279.645 48 267.994 48 259.2c0-23.375 8.8-44 35.2-44 35.2 0 53.075 26.4 70.4 26.4V83.2c0-18.425 16.5-35.2 35.2-35.2 18.975 0 35.2 16.225 35.2 35.2zM352 424c13.255 0 24 10.745 24 24s-10.745 24-24 24-24-10.745-24-24 10.745-24 24-24z"],"hand-pointer":[448,512,[],"f25a","M358.182 179.361c-19.493-24.768-52.679-31.945-79.872-19.098-15.127-15.687-36.182-22.487-56.595-19.629V67c0-36.944-29.736-67-66.286-67S89.143 30.056 89.143 67v161.129c-19.909-7.41-43.272-5.094-62.083 8.872-29.355 21.795-35.793 63.333-14.55 93.152l109.699 154.001C134.632 501.59 154.741 512 176 512h178.286c30.802 0 57.574-21.5 64.557-51.797l27.429-118.999A67.873 67.873 0 0 0 448 326v-84c0-46.844-46.625-79.273-89.818-62.639zM80.985 279.697l27.126 38.079c8.995 12.626 29.031 6.287 29.031-9.283V67c0-25.12 36.571-25.16 36.571 0v175c0 8.836 7.163 16 16 16h6.857c8.837 0 16-7.164 16-16v-35c0-25.12 36.571-25.16 36.571 0v35c0 8.836 7.163 16 16 16H272c8.837 0 16-7.164 16-16v-21c0-25.12 36.571-25.16 36.571 0v21c0 8.836 7.163 16 16 16h6.857c8.837 0 16-7.164 16-16 0-25.121 36.571-25.16 36.571 0v84c0 1.488-.169 2.977-.502 4.423l-27.43 119.001c-1.978 8.582-9.29 14.576-17.782 14.576H176c-5.769 0-11.263-2.878-14.697-7.697l-109.712-154c-14.406-20.223 14.994-42.818 29.394-22.606zM176.143 400v-96c0-8.837 6.268-16 14-16h6c7.732 0 14 7.163 14 16v96c0 8.837-6.268 16-14 16h-6c-7.733 0-14-7.163-14-16zm75.428 0v-96c0-8.837 6.268-16 14-16h6c7.732 0 14 7.163 14 16v96c0 8.837-6.268 16-14 16h-6c-7.732 0-14-7.163-14-16zM327 400v-96c0-8.837 6.268-16 14-16h6c7.732 0 14 7.163 14 16v96c0 8.837-6.268 16-14 16h-6c-7.732 0-14-7.163-14-16z"],"hand-rock":[512,512,[],"f255","M408.864 79.052c-22.401-33.898-66.108-42.273-98.813-23.588-29.474-31.469-79.145-31.093-108.334-.022-47.16-27.02-108.71 5.055-110.671 60.806C44.846 105.407 0 140.001 0 187.429v56.953c0 32.741 14.28 63.954 39.18 85.634l97.71 85.081c4.252 3.702 3.11 5.573 3.11 32.903 0 17.673 14.327 32 32 32h252c17.673 0 32-14.327 32-32 0-23.513-1.015-30.745 3.982-42.37l42.835-99.656c6.094-14.177 9.183-29.172 9.183-44.568V146.963c0-52.839-54.314-88.662-103.136-67.911zM464 261.406a64.505 64.505 0 0 1-5.282 25.613l-42.835 99.655c-5.23 12.171-7.883 25.04-7.883 38.25V432H188v-10.286c0-16.37-7.14-31.977-19.59-42.817l-97.71-85.08C56.274 281.255 48 263.236 48 244.381v-56.953c0-33.208 52-33.537 52 .677v41.228a16 16 0 0 0 5.493 12.067l7 6.095A16 16 0 0 0 139 235.429V118.857c0-33.097 52-33.725 52 .677v26.751c0 8.836 7.164 16 16 16h7c8.836 0 16-7.164 16-16v-41.143c0-33.134 52-33.675 52 .677v40.466c0 8.836 7.163 16 16 16h7c8.837 0 16-7.164 16-16v-27.429c0-33.03 52-33.78 52 .677v26.751c0 8.836 7.163 16 16 16h7c8.837 0 16-7.164 16-16 0-33.146 52-33.613 52 .677v114.445z"],"hand-scissors":[512,512,[],"f257","M256 480l70-.013c5.114 0 10.231-.583 15.203-1.729l118.999-27.427C490.56 443.835 512 417.02 512 386.277V180.575c0-23.845-13.03-45.951-34.005-57.69l-97.999-54.853c-34.409-19.261-67.263-5.824-92.218 24.733L142.85 37.008c-37.887-14.579-80.612 3.727-95.642 41.201-15.098 37.642 3.635 80.37 41.942 95.112L168 192l-94-9.141c-40.804 0-74 32.811-74 73.14 0 40.33 33.196 73.141 74 73.141h87.635c-3.675 26.245 8.692 51.297 30.341 65.006C178.657 436.737 211.044 480 256 480zm0-48.013c-25.16 0-25.12-36.567 0-36.567 8.837 0 16-7.163 16-16v-6.856c0-8.837-7.163-16-16-16h-28c-25.159 0-25.122-36.567 0-36.567h28c8.837 0 16-7.163 16-16v-6.856c0-8.837-7.163-16-16-16H74c-34.43 0-34.375-50.281 0-50.281h182c8.837 0 16-7.163 16-16v-11.632a16 16 0 0 0-10.254-14.933L106.389 128.51c-31.552-12.14-13.432-59.283 19.222-46.717l166.549 64.091a16.001 16.001 0 0 0 18.139-4.812l21.764-26.647c5.82-7.127 16.348-9.064 24.488-4.508l98 54.854c5.828 3.263 9.449 9.318 9.449 15.805v205.701c0 8.491-5.994 15.804-14.576 17.782l-119.001 27.427a19.743 19.743 0 0 1-4.423.502h-70z"],"hand-spock":[512,512,[],"f259","M21.096 381.79l129.092 121.513a32 32 0 0 0 21.932 8.698h237.6c14.17 0 26.653-9.319 30.68-22.904l31.815-107.313A115.955 115.955 0 0 0 477 348.811v-36.839c0-4.051.476-8.104 1.414-12.045l31.73-133.41c10.099-42.412-22.316-82.738-65.544-82.525-4.144-24.856-22.543-47.165-49.85-53.992-35.803-8.952-72.227 12.655-81.25 48.75L296.599 184 274.924 52.01c-8.286-36.07-44.303-58.572-80.304-50.296-29.616 6.804-50.138 32.389-51.882 61.295-42.637.831-73.455 40.563-64.071 81.844l31.04 136.508c-27.194-22.515-67.284-19.992-91.482 5.722-25.376 26.961-24.098 69.325 2.871 94.707zm32.068-61.811l.002-.001c7.219-7.672 19.241-7.98 26.856-.813l53.012 49.894C143.225 378.649 160 371.4 160 357.406v-69.479c0-1.193-.134-2.383-.397-3.546l-34.13-150.172c-5.596-24.617 31.502-32.86 37.054-8.421l30.399 133.757a16 16 0 0 0 15.603 12.454h8.604c10.276 0 17.894-9.567 15.594-19.583l-41.62-181.153c-5.623-24.469 31.39-33.076 37.035-8.508l45.22 196.828A16 16 0 0 0 288.956 272h13.217a16 16 0 0 0 15.522-12.119l42.372-169.49c6.104-24.422 42.962-15.159 36.865 9.217L358.805 252.12c-2.521 10.088 5.115 19.88 15.522 19.88h9.694a16 16 0 0 0 15.565-12.295L426.509 146.6c5.821-24.448 42.797-15.687 36.966 8.802L431.72 288.81a100.094 100.094 0 0 0-2.72 23.162v36.839c0 6.548-.943 13.051-2.805 19.328L397.775 464h-219.31L53.978 346.836c-7.629-7.18-7.994-19.229-.814-26.857z"],handshake:[640,512,[],"f2b5","M616 96h-48c-7.107 0-13.49 3.091-17.884 8H526.59l-31.13-36.3-.16-.18A103.974 103.974 0 0 0 417.03 32h-46.55c-17.75 0-34.9 4.94-49.69 14.01C304.33 36.93 285.67 32 266.62 32h-32.11c-28.903 0-57.599 11.219-79.2 32.8L116.12 104H89.884C85.49 99.091 79.107 96 72 96H24c-13.255 0-24 10.745-24 24v240c0 13.255 10.745 24 24 24h48c10.449 0 19.334-6.68 22.629-16h18.801l75.35 67.57c25.542 26.45 59.925 44.43 96.58 44.43 16.39 0 32.28-3.85 46.1-10.93 24.936.496 51.101-10.368 69.07-31.41 19.684-5.579 37.503-17.426 50.72-34.6 20.989-4.401 40.728-16.492 53.42-35.06h40.701c3.295 9.32 12.18 16 22.629 16h48c13.255 0 24-10.745 24-24V120c0-13.255-10.745-24-24-24zM48 352c-8.837 0-16-7.163-16-16s7.163-16 16-16 16 7.163 16 16-7.163 16-16 16zm412.52-5.76c-15.35 14.295-36.884 11.328-39.95 8 1.414 13.382-18.257 41.043-49.08 38.88-5.541 18.523-28.218 33.826-51.49 25.75-8.89 8.89-22.46 13.13-34.64 13.13-24.95 0-47.77-14.54-63.14-30.91l-81.3-72.91a31.976 31.976 0 0 0-21.36-8.18H96V152h26.75c8.48 0 16.62-3.37 22.62-9.37l43.88-43.88A64.004 64.004 0 0 1 234.51 80h32.11c5.8 0 11.51.79 17 2.3l-43.27 50.49c-23.56 27.48-23.84 67.62-.66 95.44 32.388 38.866 91.378 39.228 124.48 1.98l25.98-30.08L462.59 296c13.44 14.6 10.95 38.13-2.07 50.24zM544 320h-24.458c.104-20.261-6.799-39.33-19.762-54.4L421.7 162.28c4.51-9.51 2.34-21.23-6.01-28.45-10.075-8.691-25.23-7.499-33.86 2.48l-53.63 62.12c-13.828 15.41-38.223 15.145-51.64-.93a25.857 25.857 0 0 1 .23-33.47l57.92-67.58A47.09 47.09 0 0 1 370.48 80h46.55c16.11 0 31.44 6.94 42.07 19.04L504.52 152H544v168zm48 32c-8.837 0-16-7.163-16-16s7.163-16 16-16 16 7.163 16 16-7.163 16-16 16z"],hdd:[576,512,[],"f0a0","M567.403 235.642L462.323 84.589A48 48 0 0 0 422.919 64H153.081a48 48 0 0 0-39.404 20.589L8.597 235.642A48.001 48.001 0 0 0 0 263.054V400c0 26.51 21.49 48 48 48h480c26.51 0 48-21.49 48-48V263.054c0-9.801-3-19.366-8.597-27.412zM153.081 112h269.838l77.913 112H75.168l77.913-112zM528 400H48V272h480v128zm-32-64c0 17.673-14.327 32-32 32s-32-14.327-32-32 14.327-32 32-32 32 14.327 32 32zm-96 0c0 17.673-14.327 32-32 32s-32-14.327-32-32 14.327-32 32-32 32 14.327 32 32z"],heart:[576,512,[],"f004","M257.3 475.4L92.5 313.6C85.4 307 24 248.1 24 174.8 24 84.1 80.8 24 176 24c41.4 0 80.6 22.8 112 49.8 31.3-27 70.6-49.8 112-49.8 91.7 0 152 56.5 152 150.8 0 52-31.8 103.5-68.1 138.7l-.4.4-164.8 161.5a43.7 43.7 0 0 1-61.4 0zM125.9 279.1L288 438.3l161.8-158.7c27.3-27 54.2-66.3 54.2-104.8C504 107.9 465.8 72 400 72c-47.2 0-92.8 49.3-112 68.4-17-17-64-68.4-112-68.4-65.9 0-104 35.9-104 102.8 0 37.3 26.7 78.9 53.9 104.3z"],hospital:[448,512,[],"f0f8","M128 244v-40c0-6.627 5.373-12 12-12h40c6.627 0 12 5.373 12 12v40c0 6.627-5.373 12-12 12h-40c-6.627 0-12-5.373-12-12zm140 12h40c6.627 0 12-5.373 12-12v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12zm-76 84v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm76 12h40c6.627 0 12-5.373 12-12v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12zm180 124v36H0v-36c0-6.627 5.373-12 12-12h19.5V85.035C31.5 73.418 42.245 64 55.5 64H144V24c0-13.255 10.745-24 24-24h112c13.255 0 24 10.745 24 24v40h88.5c13.255 0 24 9.418 24 21.035V464H436c6.627 0 12 5.373 12 12zM79.5 463H192v-67c0-6.627 5.373-12 12-12h40c6.627 0 12 5.373 12 12v67h112.5V112H304v24c0 13.255-10.745 24-24 24H168c-13.255 0-24-10.745-24-24v-24H79.5v351zM266 64h-26V38a6 6 0 0 0-6-6h-20a6 6 0 0 0-6 6v26h-26a6 6 0 0 0-6 6v20a6 6 0 0 0 6 6h26v26a6 6 0 0 0 6 6h20a6 6 0 0 0 6-6V96h26a6 6 0 0 0 6-6V70a6 6 0 0 0-6-6z"],hourglass:[384,512,[],"f254","M368 48h4c6.627 0 12-5.373 12-12V12c0-6.627-5.373-12-12-12H12C5.373 0 0 5.373 0 12v24c0 6.627 5.373 12 12 12h4c0 80.564 32.188 165.807 97.18 208C47.899 298.381 16 383.9 16 464h-4c-6.627 0-12 5.373-12 12v24c0 6.627 5.373 12 12 12h360c6.627 0 12-5.373 12-12v-24c0-6.627-5.373-12-12-12h-4c0-80.564-32.188-165.807-97.18-208C336.102 213.619 368 128.1 368 48zM64 48h256c0 101.62-57.307 184-128 184S64 149.621 64 48zm256 416H64c0-101.62 57.308-184 128-184s128 82.38 128 184z"],"id-badge":[384,512,[],"f2c1","M192 128c35.346 0 64 28.654 64 64s-28.654 64-64 64-64-28.654-64-64 28.654-64 64-64m61.187 145.847l-18.064-5.161C222.371 275.884 207.658 280 192 280s-30.371-4.116-43.122-11.314l-18.064 5.161C110.207 279.734 96 298.569 96 320v72c0 13.255 10.745 24 24 24h144c13.255 0 24-10.745 24-24v-72c0-21.431-14.207-40.266-34.813-46.153zM0 48v416c0 26.51 21.49 48 48 48h288c26.51 0 48-21.49 48-48V48c0-26.51-21.49-48-48-48H48C21.49 0 0 21.49 0 48zm336 32v378a6 6 0 0 1-6 6H54a6 6 0 0 1-6-6V80h288z"],"id-card":[512,512,[],"f2c2","M404 256H300c-6.627 0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h104c6.627 0 12 5.373 12 12v24c0 6.627-5.373 12-12 12zm12 68v-24c0-6.627-5.373-12-12-12H300c-6.627 0-12 5.373-12 12v24c0 6.627 5.373 12 12 12h104c6.627 0 12-5.373 12-12zm96-212v288c0 26.51-21.49 48-48 48H48c-26.51 0-48-21.49-48-48V112c0-26.51 21.49-48 48-48h416c26.51 0 48 21.49 48 48zm-48 282V144H48v250a6 6 0 0 0 6 6h404a6 6 0 0 0 6-6zm-288-98c30.928 0 56-25.072 56-56s-25.072-56-56-56-56 25.072-56 56 25.072 56 56 56zm62.896 10.869l-13.464-4.039C211.814 313.568 194.649 320 176 320s-35.814-6.432-49.433-17.17l-13.464 4.039A24 24 0 0 0 96 329.857V372c0 6.627 5.373 12 12 12h136c6.627 0 12-5.373 12-12v-42.143a24 24 0 0 0-17.104-22.988z"],image:[512,512,[],"f03e","M464 64H48C21.49 64 0 85.49 0 112v288c0 26.51 21.49 48 48 48h416c26.51 0 48-21.49 48-48V112c0-26.51-21.49-48-48-48zm-6 336H54a6 6 0 0 1-6-6V118a6 6 0 0 1 6-6h404a6 6 0 0 1 6 6v276a6 6 0 0 1-6 6zM128 152c-22.091 0-40 17.909-40 40s17.909 40 40 40 40-17.909 40-40-17.909-40-40-40zM96 352h320v-80l-87.515-87.515c-4.686-4.686-12.284-4.686-16.971 0L192 304l-39.515-39.515c-4.686-4.686-12.284-4.686-16.971 0L96 304v48z"],images:[576,512,[],"f302","M480 416v16c0 26.51-21.49 48-48 48H48c-26.51 0-48-21.49-48-48V176c0-26.51 21.49-48 48-48h16v48H54a6 6 0 0 0-6 6v244a6 6 0 0 0 6 6h372a6 6 0 0 0 6-6v-10h48zm42-336H150a6 6 0 0 0-6 6v244a6 6 0 0 0 6 6h372a6 6 0 0 0 6-6V86a6 6 0 0 0-6-6zm6-48c26.51 0 48 21.49 48 48v256c0 26.51-21.49 48-48 48H144c-26.51 0-48-21.49-48-48V80c0-26.51 21.49-48 48-48h384zM264 144c0 22.091-17.909 40-40 40s-40-17.909-40-40 17.909-40 40-40 40 17.909 40 40zm-72 96l39.515-39.515c4.686-4.686 12.284-4.686 16.971 0L288 240l103.515-103.515c4.686-4.686 12.284-4.686 16.971 0L480 208v80H192v-48z"],keyboard:[576,512,[],"f11c","M528 64H48C21.49 64 0 85.49 0 112v288c0 26.51 21.49 48 48 48h480c26.51 0 48-21.49 48-48V112c0-26.51-21.49-48-48-48zm8 336c0 4.411-3.589 8-8 8H48c-4.411 0-8-3.589-8-8V112c0-4.411 3.589-8 8-8h480c4.411 0 8 3.589 8 8v288zM170 270v-28c0-6.627-5.373-12-12-12h-28c-6.627 0-12 5.373-12 12v28c0 6.627 5.373 12 12 12h28c6.627 0 12-5.373 12-12zm96 0v-28c0-6.627-5.373-12-12-12h-28c-6.627 0-12 5.373-12 12v28c0 6.627 5.373 12 12 12h28c6.627 0 12-5.373 12-12zm96 0v-28c0-6.627-5.373-12-12-12h-28c-6.627 0-12 5.373-12 12v28c0 6.627 5.373 12 12 12h28c6.627 0 12-5.373 12-12zm96 0v-28c0-6.627-5.373-12-12-12h-28c-6.627 0-12 5.373-12 12v28c0 6.627 5.373 12 12 12h28c6.627 0 12-5.373 12-12zm-336 82v-28c0-6.627-5.373-12-12-12H82c-6.627 0-12 5.373-12 12v28c0 6.627 5.373 12 12 12h28c6.627 0 12-5.373 12-12zm384 0v-28c0-6.627-5.373-12-12-12h-28c-6.627 0-12 5.373-12 12v28c0 6.627 5.373 12 12 12h28c6.627 0 12-5.373 12-12zM122 188v-28c0-6.627-5.373-12-12-12H82c-6.627 0-12 5.373-12 12v28c0 6.627 5.373 12 12 12h28c6.627 0 12-5.373 12-12zm96 0v-28c0-6.627-5.373-12-12-12h-28c-6.627 0-12 5.373-12 12v28c0 6.627 5.373 12 12 12h28c6.627 0 12-5.373 12-12zm96 0v-28c0-6.627-5.373-12-12-12h-28c-6.627 0-12 5.373-12 12v28c0 6.627 5.373 12 12 12h28c6.627 0 12-5.373 12-12zm96 0v-28c0-6.627-5.373-12-12-12h-28c-6.627 0-12 5.373-12 12v28c0 6.627 5.373 12 12 12h28c6.627 0 12-5.373 12-12zm96 0v-28c0-6.627-5.373-12-12-12h-28c-6.627 0-12 5.373-12 12v28c0 6.627 5.373 12 12 12h28c6.627 0 12-5.373 12-12zm-98 158v-16c0-6.627-5.373-12-12-12H180c-6.627 0-12 5.373-12 12v16c0 6.627 5.373 12 12 12h216c6.627 0 12-5.373 12-12z"],lemon:[512,512,[],"f094","M484.112 27.889C455.989-.233 416.108-8.057 387.059 8.865 347.604 31.848 223.504-41.111 91.196 91.197-41.277 223.672 31.923 347.472 8.866 387.058c-16.922 29.051-9.1 68.932 19.022 97.054 28.135 28.135 68.011 35.938 97.057 19.021 39.423-22.97 163.557 49.969 295.858-82.329 132.474-132.477 59.273-256.277 82.331-295.861 16.922-29.05 9.1-68.931-19.022-97.054zm-22.405 72.894c-38.8 66.609 45.6 165.635-74.845 286.08-120.44 120.443-219.475 36.048-286.076 74.843-22.679 13.207-64.035-27.241-50.493-50.488 38.8-66.609-45.6-165.635 74.845-286.08C245.573 4.702 344.616 89.086 411.219 50.292c22.73-13.24 64.005 27.288 50.488 50.491zm-169.861 8.736c1.37 10.96-6.404 20.957-17.365 22.327-54.846 6.855-135.779 87.787-142.635 142.635-1.373 10.989-11.399 18.734-22.326 17.365-10.961-1.37-18.735-11.366-17.365-22.326 9.162-73.286 104.167-168.215 177.365-177.365 10.953-1.368 20.956 6.403 22.326 17.364z"],"life-ring":[512,512,[],"f1cd","M256 504c136.967 0 248-111.033 248-248S392.967 8 256 8 8 119.033 8 256s111.033 248 248 248zm-103.398-76.72l53.411-53.411c31.806 13.506 68.128 13.522 99.974 0l53.411 53.411c-63.217 38.319-143.579 38.319-206.796 0zM336 256c0 44.112-35.888 80-80 80s-80-35.888-80-80 35.888-80 80-80 80 35.888 80 80zm91.28 103.398l-53.411-53.411c13.505-31.806 13.522-68.128 0-99.974l53.411-53.411c38.319 63.217 38.319 143.579 0 206.796zM359.397 84.72l-53.411 53.411c-31.806-13.505-68.128-13.522-99.973 0L152.602 84.72c63.217-38.319 143.579-38.319 206.795 0zM84.72 152.602l53.411 53.411c-13.506 31.806-13.522 68.128 0 99.974L84.72 359.398c-38.319-63.217-38.319-143.579 0-206.796z"],lightbulb:[384,512,[],"f0eb","M272 428v28c0 10.449-6.68 19.334-16 22.629V488c0 13.255-10.745 24-24 24h-80c-13.255 0-24-10.745-24-24v-9.371c-9.32-3.295-16-12.18-16-22.629v-28c0-6.627 5.373-12 12-12h136c6.627 0 12 5.373 12 12zM128 176c0-35.29 28.71-64 64-64 8.837 0 16-7.164 16-16s-7.163-16-16-16c-52.935 0-96 43.065-96 96 0 8.836 7.164 16 16 16s16-7.164 16-16zm64-128c70.734 0 128 57.254 128 128 0 77.602-37.383 60.477-80.98 160h-94.04C101.318 236.33 64 253.869 64 176c0-70.735 57.254-128 128-128m0-48C94.805 0 16 78.803 16 176c0 101.731 51.697 91.541 90.516 192.674 3.55 9.249 12.47 15.326 22.376 15.326h126.215c9.906 0 18.826-6.078 22.376-15.326C316.303 267.541 368 277.731 368 176 368 78.803 289.195 0 192 0z"],"list-alt":[512,512,[],"f022","M464 32H48C21.49 32 0 53.49 0 80v352c0 26.51 21.49 48 48 48h416c26.51 0 48-21.49 48-48V80c0-26.51-21.49-48-48-48zm-6 400H54a6 6 0 0 1-6-6V86a6 6 0 0 1 6-6h404a6 6 0 0 1 6 6v340a6 6 0 0 1-6 6zm-42-92v24c0 6.627-5.373 12-12 12H204c-6.627 0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h200c6.627 0 12 5.373 12 12zm0-96v24c0 6.627-5.373 12-12 12H204c-6.627 0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h200c6.627 0 12 5.373 12 12zm0-96v24c0 6.627-5.373 12-12 12H204c-6.627 0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h200c6.627 0 12 5.373 12 12zm-252 12c0 19.882-16.118 36-36 36s-36-16.118-36-36 16.118-36 36-36 36 16.118 36 36zm0 96c0 19.882-16.118 36-36 36s-36-16.118-36-36 16.118-36 36-36 36 16.118 36 36zm0 96c0 19.882-16.118 36-36 36s-36-16.118-36-36 16.118-36 36-36 36 16.118 36 36z"],map:[576,512,[],"f279","M508.505 36.17L381.517 92.576 207.179 34.463a47.992 47.992 0 0 0-34.674 1.674l-144 64A48 48 0 0 0 0 144v287.967c0 34.938 35.991 57.864 67.495 43.863l126.988-56.406 174.339 58.113a47.992 47.992 0 0 0 34.674-1.674l144-64A48 48 0 0 0 576 368V80.033c0-34.938-35.991-57.864-67.495-43.863zM360 424l-144-48V88l144 48v288zm-312 8V144l120-53.333v288L48 432zm480-64l-120 53.333v-288L528 80v288z"],meh:[512,512,[],"f11a","M256 56c110.532 0 200 89.451 200 200 0 110.532-89.451 200-200 200-110.532 0-200-89.451-200-200 0-110.532 89.451-200 200-200m0-48C119.033 8 8 119.033 8 256s111.033 248 248 248 248-111.033 248-248S392.967 8 256 8zm64 136c-9.535 0-18.512 2.386-26.37 6.589h.017c12.735 0 23.059 10.324 23.059 23.059 0 12.735-10.324 23.059-23.059 23.059s-23.059-10.324-23.059-23.059v-.017C266.386 181.488 264 190.465 264 200c0 30.928 25.072 56 56 56s56-25.072 56-56-25.072-56-56-56zm-128 0c-9.535 0-18.512 2.386-26.37 6.589h.017c12.735 0 23.059 10.324 23.059 23.059 0 12.735-10.324 23.059-23.059 23.059-12.735 0-23.059-10.324-23.059-23.059v-.017C138.386 181.488 136 190.465 136 200c0 30.928 25.072 56 56 56s56-25.072 56-56-25.072-56-56-56zm136 184H184c-31.776 0-31.749 48 0 48h144c31.776 0 31.749-48 0-48z"],"minus-square":[448,512,[],"f146","M108 284c-6.6 0-12-5.4-12-12v-32c0-6.6 5.4-12 12-12h232c6.6 0 12 5.4 12 12v32c0 6.6-5.4 12-12 12H108zM448 80v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V80c0-26.5 21.5-48 48-48h352c26.5 0 48 21.5 48 48zm-48 346V86c0-3.3-2.7-6-6-6H54c-3.3 0-6 2.7-6 6v340c0 3.3 2.7 6 6 6h340c3.3 0 6-2.7 6-6z"],"money-bill-alt":[640,512,[],"f3d1","M320 144c-53.021 0-96 50.143-96 112 0 61.847 42.977 112 96 112 53 0 96-50.13 96-112 0-61.857-42.979-112-96-112zm48 164.428c0 7.477-3.917 11.572-11.572 11.572h-67.293c-7.656 0-11.573-4.095-11.573-11.572v-8.901c0-7.477 3.917-11.572 11.573-11.572h15.131v-39.878c0-5.163.534-10.503.534-10.503h-.356s-1.779 2.67-2.848 3.738c-4.451 4.273-10.504 4.451-15.666-1.068l-5.518-6.231c-5.342-5.341-4.984-11.216.534-16.379l21.72-19.939c4.449-4.095 8.366-5.697 14.42-5.697h12.105c7.656 0 11.75 3.916 11.75 11.572v84.384h15.488c7.655 0 11.572 4.094 11.572 11.572v8.902zM616 64H24C10.745 64 0 74.745 0 88v335c0 13.255 10.745 24 24 24h592c13.255 0 24-10.745 24-24V88c0-13.255-10.745-24-24-24zM512 400H128c0-44.183-35.817-80-80-80V192c44.183 0 80-35.817 80-80h384c0 44.183 35.817 80 80 80v128c-44.183 0-80 35.817-80 80z"],moon:[512,512,[],"f186","M279.135 512c78.756 0 150.982-35.804 198.844-94.775 28.27-34.831-2.558-85.722-46.249-77.401-82.348 15.683-158.272-47.268-158.272-130.792 0-48.424 26.06-92.292 67.434-115.836 38.745-22.05 28.999-80.788-15.022-88.919A257.936 257.936 0 0 0 279.135 0c-141.36 0-256 114.575-256 256 0 141.36 114.576 256 256 256zm0-464c12.985 0 25.689 1.201 38.016 3.478-54.76 31.163-91.693 90.042-91.693 157.554 0 113.848 103.641 199.2 215.252 177.944C402.574 433.964 344.366 464 279.135 464c-114.875 0-208-93.125-208-208s93.125-208 208-208z"],newspaper:[576,512,[],"f1ea","M552 64H112c-20.858 0-38.643 13.377-45.248 32H24c-13.255 0-24 10.745-24 24v272c0 30.928 25.072 56 56 56h496c13.255 0 24-10.745 24-24V88c0-13.255-10.745-24-24-24zM48 392V144h16v248c0 4.411-3.589 8-8 8s-8-3.589-8-8zm480 8H111.422c.374-2.614.578-5.283.578-8V112h416v288zM172 280h136c6.627 0 12-5.373 12-12v-96c0-6.627-5.373-12-12-12H172c-6.627 0-12 5.373-12 12v96c0 6.627 5.373 12 12 12zm28-80h80v40h-80v-40zm-40 140v-24c0-6.627 5.373-12 12-12h136c6.627 0 12 5.373 12 12v24c0 6.627-5.373 12-12 12H172c-6.627 0-12-5.373-12-12zm192 0v-24c0-6.627 5.373-12 12-12h104c6.627 0 12 5.373 12 12v24c0 6.627-5.373 12-12 12H364c-6.627 0-12-5.373-12-12zm0-144v-24c0-6.627 5.373-12 12-12h104c6.627 0 12 5.373 12 12v24c0 6.627-5.373 12-12 12H364c-6.627 0-12-5.373-12-12zm0 72v-24c0-6.627 5.373-12 12-12h104c6.627 0 12 5.373 12 12v24c0 6.627-5.373 12-12 12H364c-6.627 0-12-5.373-12-12z"],"object-group":[512,512,[],"f247","M500 128c6.627 0 12-5.373 12-12V44c0-6.627-5.373-12-12-12h-72c-6.627 0-12 5.373-12 12v12H96V44c0-6.627-5.373-12-12-12H12C5.373 32 0 37.373 0 44v72c0 6.627 5.373 12 12 12h12v256H12c-6.627 0-12 5.373-12 12v72c0 6.627 5.373 12 12 12h72c6.627 0 12-5.373 12-12v-12h320v12c0 6.627 5.373 12 12 12h72c6.627 0 12-5.373 12-12v-72c0-6.627-5.373-12-12-12h-12V128h12zm-52-64h32v32h-32V64zM32 64h32v32H32V64zm32 384H32v-32h32v32zm416 0h-32v-32h32v32zm-40-64h-12c-6.627 0-12 5.373-12 12v12H96v-12c0-6.627-5.373-12-12-12H72V128h12c6.627 0 12-5.373 12-12v-12h320v12c0 6.627 5.373 12 12 12h12v256zm-36-192h-84v-52c0-6.628-5.373-12-12-12H108c-6.627 0-12 5.372-12 12v168c0 6.628 5.373 12 12 12h84v52c0 6.628 5.373 12 12 12h200c6.627 0 12-5.372 12-12V204c0-6.628-5.373-12-12-12zm-268-24h144v112H136V168zm240 176H232v-24h76c6.627 0 12-5.372 12-12v-76h56v112z"],"object-ungroup":[576,512,[],"f248","M564 224c6.627 0 12-5.373 12-12v-72c0-6.627-5.373-12-12-12h-72c-6.627 0-12 5.373-12 12v12h-88v-24h12c6.627 0 12-5.373 12-12V44c0-6.627-5.373-12-12-12h-72c-6.627 0-12 5.373-12 12v12H96V44c0-6.627-5.373-12-12-12H12C5.373 32 0 37.373 0 44v72c0 6.627 5.373 12 12 12h12v160H12c-6.627 0-12 5.373-12 12v72c0 6.627 5.373 12 12 12h72c6.627 0 12-5.373 12-12v-12h88v24h-12c-6.627 0-12 5.373-12 12v72c0 6.627 5.373 12 12 12h72c6.627 0 12-5.373 12-12v-12h224v12c0 6.627 5.373 12 12 12h72c6.627 0 12-5.373 12-12v-72c0-6.627-5.373-12-12-12h-12V224h12zM352 64h32v32h-32V64zm0 256h32v32h-32v-32zM64 352H32v-32h32v32zm0-256H32V64h32v32zm32 216v-12c0-6.627-5.373-12-12-12H72V128h12c6.627 0 12-5.373 12-12v-12h224v12c0 6.627 5.373 12 12 12h12v160h-12c-6.627 0-12 5.373-12 12v12H96zm128 136h-32v-32h32v32zm280-64h-12c-6.627 0-12 5.373-12 12v12H256v-12c0-6.627-5.373-12-12-12h-12v-24h88v12c0 6.627 5.373 12 12 12h72c6.627 0 12-5.373 12-12v-72c0-6.627-5.373-12-12-12h-12v-88h88v12c0 6.627 5.373 12 12 12h12v160zm40 64h-32v-32h32v32zm0-256h-32v-32h32v32z"],"paper-plane":[512,512,[],"f1d8","M440 6.5L24 246.4c-34.4 19.9-31.1 70.8 5.7 85.9L144 379.6V464c0 46.4 59.2 65.5 86.6 28.6l43.8-59.1 111.9 46.2c5.9 2.4 12.1 3.6 18.3 3.6 8.2 0 16.3-2.1 23.6-6.2 12.8-7.2 21.6-20 23.9-34.5l59.4-387.2c6.1-40.1-36.9-68.8-71.5-48.9zM192 464v-64.6l36.6 15.1L192 464zm212.6-28.7l-153.8-63.5L391 169.5c10.7-15.5-9.5-33.5-23.7-21.2L155.8 332.6 48 288 464 48l-59.4 387.3z"],"pause-circle":[512,512,[],"f28b","M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm0 448c-110.5 0-200-89.5-200-200S145.5 56 256 56s200 89.5 200 200-89.5 200-200 200zm96-280v160c0 8.8-7.2 16-16 16h-48c-8.8 0-16-7.2-16-16V176c0-8.8 7.2-16 16-16h48c8.8 0 16 7.2 16 16zm-112 0v160c0 8.8-7.2 16-16 16h-48c-8.8 0-16-7.2-16-16V176c0-8.8 7.2-16 16-16h48c8.8 0 16 7.2 16 16z"],"play-circle":[512,512,[],"f144","M371.7 238l-176-107c-15.8-8.8-35.7 2.5-35.7 21v208c0 18.4 19.8 29.8 35.7 21l176-101c16.4-9.1 16.4-32.8 0-42zM504 256C504 119 393 8 256 8S8 119 8 256s111 248 248 248 248-111 248-248zm-448 0c0-110.5 89.5-200 200-200s200 89.5 200 200-89.5 200-200 200S56 366.5 56 256z"],"plus-square":[448,512,[],"f0fe","M352 240v32c0 6.6-5.4 12-12 12h-88v88c0 6.6-5.4 12-12 12h-32c-6.6 0-12-5.4-12-12v-88h-88c-6.6 0-12-5.4-12-12v-32c0-6.6 5.4-12 12-12h88v-88c0-6.6 5.4-12 12-12h32c6.6 0 12 5.4 12 12v88h88c6.6 0 12 5.4 12 12zm96-160v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V80c0-26.5 21.5-48 48-48h352c26.5 0 48 21.5 48 48zm-48 346V86c0-3.3-2.7-6-6-6H54c-3.3 0-6 2.7-6 6v340c0 3.3 2.7 6 6 6h340c3.3 0 6-2.7 6-6z"],"question-circle":[512,512,[],"f059","M256 8C119.043 8 8 119.083 8 256c0 136.997 111.043 248 248 248s248-111.003 248-248C504 119.083 392.957 8 256 8zm0 448c-110.532 0-200-89.431-200-200 0-110.495 89.472-200 200-200 110.491 0 200 89.471 200 200 0 110.53-89.431 200-200 200zm107.244-255.2c0 67.052-72.421 68.084-72.421 92.863V300c0 6.627-5.373 12-12 12h-45.647c-6.627 0-12-5.373-12-12v-8.659c0-35.745 27.1-50.034 47.579-61.516 17.561-9.845 28.324-16.541 28.324-29.579 0-17.246-21.999-28.693-39.784-28.693-23.189 0-33.894 10.977-48.942 29.969-4.057 5.12-11.46 6.071-16.666 2.124l-27.824-21.098c-5.107-3.872-6.251-11.066-2.644-16.363C184.846 131.491 214.94 112 261.794 112c49.071 0 101.45 38.304 101.45 88.8zM298 368c0 23.159-18.841 42-42 42s-42-18.841-42-42 18.841-42 42-42 42 18.841 42 42z"],registered:[512,512,[],"f25d","M256 8C119.033 8 8 119.033 8 256s111.033 248 248 248 248-111.033 248-248S392.967 8 256 8zm0 448c-110.532 0-200-89.451-200-200 0-110.531 89.451-200 200-200 110.532 0 200 89.451 200 200 0 110.532-89.451 200-200 200zm110.442-81.791c-53.046-96.284-50.25-91.468-53.271-96.085 24.267-13.879 39.482-41.563 39.482-73.176 0-52.503-30.247-85.252-101.498-85.252h-78.667c-6.617 0-12 5.383-12 12V380c0 6.617 5.383 12 12 12h38.568c6.617 0 12-5.383 12-12v-83.663h31.958l47.515 89.303a11.98 11.98 0 0 0 10.593 6.36h42.81c9.14 0 14.914-9.799 10.51-17.791zM256.933 239.906h-33.875v-64.14h27.377c32.417 0 38.929 12.133 38.929 31.709-.001 20.913-11.518 32.431-32.431 32.431z"],save:[448,512,[],"f0c7","M433.941 129.941l-83.882-83.882A48 48 0 0 0 316.118 32H48C21.49 32 0 53.49 0 80v352c0 26.51 21.49 48 48 48h352c26.51 0 48-21.49 48-48V163.882a48 48 0 0 0-14.059-33.941zM272 80v80H144V80h128zm122 352H54a6 6 0 0 1-6-6V86a6 6 0 0 1 6-6h42v104c0 13.255 10.745 24 24 24h176c13.255 0 24-10.745 24-24V83.882l78.243 78.243a6 6 0 0 1 1.757 4.243V426a6 6 0 0 1-6 6zM224 232c-48.523 0-88 39.477-88 88s39.477 88 88 88 88-39.477 88-88-39.477-88-88-88zm0 128c-22.056 0-40-17.944-40-40s17.944-40 40-40 40 17.944 40 40-17.944 40-40 40z"],"share-square":[576,512,[],"f14d","M561.938 158.06L417.94 14.092C387.926-15.922 336 5.097 336 48.032v57.198c-42.45 1.88-84.03 6.55-120.76 17.99-35.17 10.95-63.07 27.58-82.91 49.42C108.22 199.2 96 232.6 96 271.94c0 61.697 33.178 112.455 84.87 144.76 37.546 23.508 85.248-12.651 71.02-55.74-15.515-47.119-17.156-70.923 84.11-78.76V336c0 42.993 51.968 63.913 81.94 33.94l143.998-144c18.75-18.74 18.75-49.14 0-67.88zM384 336V232.16C255.309 234.082 166.492 255.35 206.31 376 176.79 357.55 144 324.08 144 271.94c0-109.334 129.14-118.947 240-119.85V48l144 144-144 144zm24.74 84.493a82.658 82.658 0 0 0 20.974-9.303c7.976-4.952 18.286.826 18.286 10.214V464c0 26.51-21.49 48-48 48H48c-26.51 0-48-21.49-48-48V112c0-26.51 21.49-48 48-48h132c6.627 0 12 5.373 12 12v4.486c0 4.917-2.987 9.369-7.569 11.152-13.702 5.331-26.396 11.537-38.05 18.585a12.138 12.138 0 0 1-6.28 1.777H54a6 6 0 0 0-6 6v340a6 6 0 0 0 6 6h340a6 6 0 0 0 6-6v-25.966c0-5.37 3.579-10.059 8.74-11.541z"],smile:[512,512,[],"f118","M256 56c110.532 0 200 89.451 200 200 0 110.532-89.451 200-200 200-110.532 0-200-89.451-200-200 0-110.532 89.451-200 200-200m0-48C119.033 8 8 119.033 8 256s111.033 248 248 248 248-111.033 248-248S392.967 8 256 8zm64 136c-9.535 0-18.512 2.386-26.37 6.589h.017c12.735 0 23.059 10.324 23.059 23.059 0 12.735-10.324 23.059-23.059 23.059s-23.059-10.324-23.059-23.059v-.017C266.386 181.488 264 190.465 264 200c0 30.928 25.072 56 56 56s56-25.072 56-56-25.072-56-56-56zm-128 0c-9.535 0-18.512 2.386-26.37 6.589h.017c12.735 0 23.059 10.324 23.059 23.059 0 12.735-10.324 23.059-23.059 23.059-12.735 0-23.059-10.324-23.059-23.059v-.017C138.386 181.488 136 190.465 136 200c0 30.928 25.072 56 56 56s56-25.072 56-56-25.072-56-56-56zm195.372 182.219c18.819-25.592-19.856-54.017-38.67-28.438-50.135 68.177-135.229 68.18-185.367 0-18.828-25.601-57.478 2.861-38.67 28.438 69.298 94.231 193.323 94.351 262.707 0z"],snowflake:[448,512,[],"f2dc","M438.237 355.927l-66.574-38.54 59.448-10.327c5.846-1.375 10.609-5.183 13.458-10.13 2.48-4.307 3.506-9.478 2.524-14.651-2.11-11.115-12.686-18.039-23.621-15.467l-85.423 31.115L255.914 256l82.136-41.926 85.423 31.115c10.936 2.572 21.512-4.352 23.621-15.467 2.111-11.115-5.046-22.209-15.981-24.781l-59.448-10.327 66.573-38.54c9.54-5.523 12.615-18.092 6.867-28.074-5.748-9.982-18.14-13.596-27.68-8.074l-66.574 38.54 20.805-56.787c3.246-10.782-2.758-22.542-13.413-26.268-10.654-3.725-21.922 1.997-25.168 12.779l-15.838 89.735-72.423 41.926V136l69.585-58.621c7.689-8.21 6.997-20.856-1.548-28.245-8.545-7.391-21.705-6.723-29.394 1.486l-38.644 46.46V20c0-11.046-9.318-20-20.813-20s-20.813 8.954-20.813 20v77.08l-38.644-46.46c-7.689-8.21-20.849-8.876-29.394-1.486-8.544 7.389-9.236 20.035-1.547 28.245L203.187 136v83.853l-72.423-41.926-15.838-89.736c-3.247-10.782-14.515-16.504-25.169-12.779-10.656 3.725-16.659 15.486-13.413 26.268l20.805 56.787-66.573-38.54c-9.54-5.523-21.933-1.908-27.68 8.074s-2.673 22.551 6.867 28.074l66.574 38.54-59.449 10.328C5.953 207.515-1.202 218.609.907 229.724c2.11 11.114 12.686 18.038 23.622 15.466l85.422-31.115L192.086 256l-82.136 41.926-85.423-31.115c-10.936-2.572-21.511 4.352-23.622 15.466-2.109 11.113 5.046 22.209 15.981 24.781l59.449 10.328-66.574 38.54C.223 361.449-2.852 374.018 2.896 384s18.14 13.597 27.68 8.074l66.574-38.54-20.805 56.786c-1.735 5.764-.828 11.805 2.02 16.751 2.48 4.307 6.433 7.784 11.392 9.517 10.655 3.725 21.923-1.997 25.169-12.779l15.838-89.736 72.423-41.926V376l-69.585 58.621c-7.69 8.21-6.997 20.855 1.547 28.245 8.544 7.388 21.705 6.723 29.394-1.487l38.644-46.46V492c0 11.046 9.318 20 20.813 20s20.813-8.954 20.813-20v-77.081l38.644 46.46c4.111 4.389 9.782 6.621 15.478 6.621 4.96 0 9.939-1.694 13.916-5.134 8.545-7.39 9.237-20.035 1.548-28.245L244.813 376v-83.853l72.423 41.926 15.838 89.736c3.246 10.782 14.514 16.504 25.168 12.779 10.653-3.726 16.659-15.487 13.412-26.268l-20.805-56.787 66.574 38.54c9.54 5.523 21.933 1.908 27.68-8.074 5.749-9.981 2.675-22.55-6.866-28.072z"],square:[448,512,[],"f0c8","M400 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48zm-6 400H54c-3.3 0-6-2.7-6-6V86c0-3.3 2.7-6 6-6h340c3.3 0 6 2.7 6 6v340c0 3.3-2.7 6-6 6z"],star:[576,512,[],"f005","M528.1 171.5L382 150.2 316.7 17.8c-11.7-23.6-45.6-23.9-57.4 0L194 150.2 47.9 171.5c-26.2 3.8-36.7 36.1-17.7 54.6l105.7 103-25 145.5c-4.5 26.3 23.2 46 46.4 33.7L288 439.6l130.7 68.7c23.2 12.2 50.9-7.4 46.4-33.7l-25-145.5 105.7-103c19-18.5 8.5-50.8-17.7-54.6zM388.6 312.3l23.7 138.4L288 385.4l-124.3 65.3 23.7-138.4-100.6-98 139-20.2 62.2-126 62.2 126 139 20.2-100.6 98z"],"star-half":[576,512,[],"f089","M288 385.3l-124.3 65.4 23.7-138.4-100.6-98 139-20.2 62.2-126V0c-11.4 0-22.8 5.9-28.7 17.8L194 150.2 47.9 171.4c-26.2 3.8-36.7 36.1-17.7 54.6l105.7 103-25 145.5c-4.5 26.1 23 46 46.4 33.7L288 439.6v-54.3z"],"sticky-note":[448,512,[],"f249","M448 348.106V80c0-26.51-21.49-48-48-48H48C21.49 32 0 53.49 0 80v351.988c0 26.51 21.49 48 48 48h268.118a48 48 0 0 0 33.941-14.059l83.882-83.882A48 48 0 0 0 448 348.106zm-128 80v-76.118h76.118L320 428.106zM400 80v223.988H296c-13.255 0-24 10.745-24 24v104H48V80h352z"],"stop-circle":[512,512,[],"f28d","M504 256C504 119 393 8 256 8S8 119 8 256s111 248 248 248 248-111 248-248zm-448 0c0-110.5 89.5-200 200-200s200 89.5 200 200-89.5 200-200 200S56 366.5 56 256zm296-80v160c0 8.8-7.2 16-16 16H176c-8.8 0-16-7.2-16-16V176c0-8.8 7.2-16 16-16h160c8.8 0 16 7.2 16 16z"],sun:[512,512,[],"f185","M220.116 487.936l-20.213-49.425a3.992 3.992 0 0 0-5.808-1.886l-45.404 28.104c-29.466 18.24-66.295-8.519-58.054-42.179l12.699-51.865a3.993 3.993 0 0 0-3.59-4.941l-53.251-3.951c-34.554-2.562-48.632-45.855-22.174-68.247L65.08 259.05a3.992 3.992 0 0 0 0-6.106l-40.76-34.497c-26.45-22.384-12.39-65.682 22.174-68.246l53.251-3.951a3.993 3.993 0 0 0 3.59-4.941L90.637 89.443c-8.239-33.656 28.581-60.42 58.054-42.179l45.403 28.104a3.993 3.993 0 0 0 5.808-1.887l20.213-49.425c13.116-32.071 58.638-32.081 71.758 0l20.212 49.424a3.994 3.994 0 0 0 5.809 1.887l45.403-28.104c29.464-18.236 66.297 8.513 58.054 42.179l-12.699 51.865a3.995 3.995 0 0 0 3.59 4.941l53.251 3.951c34.553 2.563 48.633 45.854 22.175 68.246l-40.76 34.497a3.993 3.993 0 0 0 0 6.107l40.76 34.496c26.511 22.441 12.322 65.689-22.175 68.247l-53.251 3.951a3.993 3.993 0 0 0-3.589 4.942l12.698 51.864c8.241 33.658-28.583 60.421-58.054 42.18l-45.403-28.104a3.994 3.994 0 0 0-5.809 1.887l-20.212 49.424c-13.159 32.178-58.675 31.993-71.757 0zm16.814-64.568l19.064 46.616 19.064-46.615c10.308-25.2 40.778-35.066 63.892-20.759l42.822 26.507-11.976-48.919c-6.475-26.444 12.38-52.339 39.487-54.349l50.226-3.726-38.444-32.536c-20.782-17.591-20.747-49.621.001-67.18l38.442-32.536-50.225-3.727c-27.151-2.015-45.95-27.948-39.488-54.349l11.978-48.919-42.823 26.507c-23.151 14.327-53.603 4.4-63.892-20.76l-19.064-46.615-19.064 46.617c-10.305 25.198-40.778 35.066-63.891 20.76l-42.823-26.508 11.977 48.918c6.474 26.446-12.381 52.338-39.488 54.35l-50.224 3.726 38.443 32.537c20.782 17.588 20.747 49.619 0 67.178L52.48 322.123l50.226 3.726c27.151 2.014 45.95 27.947 39.487 54.349l-11.977 48.919 42.823-26.507c23.188-14.355 53.622-4.352 63.891 20.758zM256 384c-70.58 0-128-57.421-128-128 0-70.58 57.42-128 128-128 70.579 0 128 57.42 128 128 0 70.579-57.421 128-128 128zm0-208c-44.112 0-80 35.888-80 80s35.888 80 80 80 80-35.888 80-80-35.888-80-80-80z"],"thumbs-down":[512,512,[],"f165","M466.27 225.31c4.674-22.647.864-44.538-8.99-62.99 2.958-23.868-4.021-48.565-17.34-66.99C438.986 39.423 404.117 0 327 0c-7 0-15 .01-22.22.01C201.195.01 168.997 40 128 40h-10.845c-5.64-4.975-13.042-8-21.155-8H32C14.327 32 0 46.327 0 64v240c0 17.673 14.327 32 32 32h64c11.842 0 22.175-6.438 27.708-16h7.052c19.146 16.953 46.013 60.653 68.76 83.4 13.667 13.667 10.153 108.6 71.76 108.6 57.58 0 95.27-31.936 95.27-104.73 0-18.41-3.93-33.73-8.85-46.54h36.48c48.602 0 85.82-41.565 85.82-85.58 0-19.15-4.96-34.99-13.73-49.84zM64 296c-13.255 0-24-10.745-24-24s10.745-24 24-24 24 10.745 24 24-10.745 24-24 24zm330.18 16.73H290.19c0 37.82 28.36 55.37 28.36 94.54 0 23.75 0 56.73-47.27 56.73-18.91-18.91-9.46-66.18-37.82-94.54C206.9 342.89 167.28 272 138.92 272H128V85.83c53.611 0 100.001-37.82 171.64-37.82h37.82c35.512 0 60.82 17.12 53.12 65.9 15.2 8.16 26.5 36.44 13.94 57.57 21.581 20.384 18.699 51.065 5.21 65.62 9.45 0 22.36 18.91 22.27 37.81-.09 18.91-16.71 37.82-37.82 37.82z"],"thumbs-up":[512,512,[],"f164","M466.27 286.69C475.04 271.84 480 256 480 236.85c0-44.015-37.218-85.58-85.82-85.58H357.7c4.92-12.81 8.85-28.13 8.85-46.54C366.55 31.936 328.86 0 271.28 0c-61.607 0-58.093 94.933-71.76 108.6-22.747 22.747-49.615 66.447-68.76 83.4H32c-17.673 0-32 14.327-32 32v240c0 17.673 14.327 32 32 32h64c14.893 0 27.408-10.174 30.978-23.95 44.509 1.001 75.06 39.94 177.802 39.94 7.22 0 15.22.01 22.22.01 77.117 0 111.986-39.423 112.94-95.33 13.319-18.425 20.299-43.122 17.34-66.99 9.854-18.452 13.664-40.343 8.99-62.99zm-61.75 53.83c12.56 21.13 1.26 49.41-13.94 57.57 7.7 48.78-17.608 65.9-53.12 65.9h-37.82c-71.639 0-118.029-37.82-171.64-37.82V240h10.92c28.36 0 67.98-70.89 94.54-97.46 28.36-28.36 18.91-75.63 37.82-94.54 47.27 0 47.27 32.98 47.27 56.73 0 39.17-28.36 56.72-28.36 94.54h103.99c21.11 0 37.73 18.91 37.82 37.82.09 18.9-12.82 37.81-22.27 37.81 13.489 14.555 16.371 45.236-5.21 65.62zM88 432c0 13.255-10.745 24-24 24s-24-10.745-24-24 10.745-24 24-24 24 10.745 24 24z"],"times-circle":[512,512,[],"f057","M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm0 448c-110.5 0-200-89.5-200-200S145.5 56 256 56s200 89.5 200 200-89.5 200-200 200zm101.8-262.2L295.6 256l62.2 62.2c4.7 4.7 4.7 12.3 0 17l-22.6 22.6c-4.7 4.7-12.3 4.7-17 0L256 295.6l-62.2 62.2c-4.7 4.7-12.3 4.7-17 0l-22.6-22.6c-4.7-4.7-4.7-12.3 0-17l62.2-62.2-62.2-62.2c-4.7-4.7-4.7-12.3 0-17l22.6-22.6c4.7-4.7 12.3-4.7 17 0l62.2 62.2 62.2-62.2c4.7-4.7 12.3-4.7 17 0l22.6 22.6c4.7 4.7 4.7 12.3 0 17z"],"trash-alt":[448,512,[],"f2ed","M192 188v216c0 6.627-5.373 12-12 12h-24c-6.627 0-12-5.373-12-12V188c0-6.627 5.373-12 12-12h24c6.627 0 12 5.373 12 12zm100-12h-24c-6.627 0-12 5.373-12 12v216c0 6.627 5.373 12 12 12h24c6.627 0 12-5.373 12-12V188c0-6.627-5.373-12-12-12zm132-96c13.255 0 24 10.745 24 24v12c0 6.627-5.373 12-12 12h-20v336c0 26.51-21.49 48-48 48H80c-26.51 0-48-21.49-48-48V128H12c-6.627 0-12-5.373-12-12v-12c0-13.255 10.745-24 24-24h74.411l34.018-56.696A48 48 0 0 1 173.589 0h100.823a48 48 0 0 1 41.16 23.304L349.589 80H424zm-269.611 0h139.223L276.16 50.913A6 6 0 0 0 271.015 48h-94.028a6 6 0 0 0-5.145 2.913L154.389 80zM368 128H80v330a6 6 0 0 0 6 6h276a6 6 0 0 0 6-6V128z"],user:[512,512,[],"f007","M399.326 288.908C422.188 258.886 436 221.085 436 180 436 80.591 355.414 0 256 0 156.591 0 76 80.586 76 180c0 41.073 13.806 78.878 36.674 108.908C50.028 296.336 0 349.651 0 416v28.5C0 481.72 30.28 512 67.5 512h377c37.22 0 67.5-30.28 67.5-67.5V416c0-66.374-50.052-119.667-112.674-127.092zM256 48c72.902 0 132 59.098 132 132s-59.098 132-132 132-132-59.098-132-132S183.098 48 256 48zm208 396.5c0 10.77-8.73 19.5-19.5 19.5h-377c-10.77 0-19.5-8.73-19.5-19.5V416c0-44.183 35.817-80 80-80h38.14c55.486 31.968 124.026 32.087 179.72 0H384c44.183 0 80 35.817 80 80v28.5z"],"user-circle":[512,512,[],"f2bd","M256 8C119.033 8 8 119.033 8 256s111.033 248 248 248 248-111.033 248-248S392.967 8 256 8zm0 48c110.532 0 200 89.451 200 200 0 34.48-8.706 66.909-24.04 95.213-13.403-26.393-37.525-47.542-67.384-56.572C378.19 273.809 385.5 249.468 385.5 224c0-71.569-57.919-129.5-129.5-129.5-71.569 0-129.5 57.919-129.5 129.5 0 25.468 7.31 49.809 20.924 70.641-29.821 9.018-53.962 30.142-67.385 56.572C64.706 322.911 56 290.482 56 256c0-110.531 89.451-200 200-200zm-80 168c0-44.183 35.817-80 80-80s80 35.817 80 80-35.817 80-80 80-80-35.817-80-80zm-59.927 174.943c1.519-33.998 29.554-61.097 63.927-61.097h14.171c38.337 20.889 85.337 20.881 123.659 0H332c34.373 0 62.408 27.099 63.927 61.097-77.746 76.114-202.156 76.065-279.854 0z"],"window-close":[512,512,[],"f410","M464 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h416c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48zm0 394c0 3.3-2.7 6-6 6H54c-3.3 0-6-2.7-6-6V86c0-3.3 2.7-6 6-6h404c3.3 0 6 2.7 6 6v340zM356.5 194.6L295.1 256l61.4 61.4c4.6 4.6 4.6 12.1 0 16.8l-22.3 22.3c-4.6 4.6-12.1 4.6-16.8 0L256 295.1l-61.4 61.4c-4.6 4.6-12.1 4.6-16.8 0l-22.3-22.3c-4.6-4.6-4.6-12.1 0-16.8l61.4-61.4-61.4-61.4c-4.6-4.6-4.6-12.1 0-16.8l22.3-22.3c4.6-4.6 12.1-4.6 16.8 0l61.4 61.4 61.4-61.4c4.6-4.6 12.1-4.6 16.8 0l22.3 22.3c4.7 4.6 4.7 12.1 0 16.8z"],"window-maximize":[512,512,[],"f2d0","M464 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h416c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48zm0 394c0 3.3-2.7 6-6 6H54c-3.3 0-6-2.7-6-6V192h416v234z"],"window-restore":[512,512,[],"f2d2","M464 0H144c-26.5 0-48 21.5-48 48v48H48c-26.5 0-48 21.5-48 48v320c0 26.5 21.5 48 48 48h320c26.5 0 48-21.5 48-48v-48h48c26.5 0 48-21.5 48-48V48c0-26.5-21.5-48-48-48zm-96 464H48V256h320v208zm96-96h-48V144c0-26.5-21.5-48-48-48H144V48h320v320z"]}),t=z||{};t.___FONT_AWESOME___||(t.___FONT_AWESOME___={}),t.___FONT_AWESOME___.styles||(t.___FONT_AWESOME___.styles={}),t.___FONT_AWESOME___.hooks||(t.___FONT_AWESOME___.hooks={}),t.___FONT_AWESOME___.shims||(t.___FONT_AWESOME___.shims=[]);var s=t.___FONT_AWESOME___,r=Object.assign||function(c){for(var l=1;l<arguments.length;l++){var h=arguments[l];for(var v in h)Object.prototype.hasOwnProperty.call(h,v)&&(c[v]=h[v])}return c};!function(c){try{c()}catch(c){}}(function(){c("far")})}(),function(){"use strict";function c(c){"function"==typeof s.hooks.addPack?s.hooks.addPack(c,m):s.styles[c]=r({},s.styles[c]||{},m)}var l={};try{"undefined"!=typeof window&&(l=window)}catch(c){}var h=(l.navigator||{}).userAgent,v=void 0===h?"":h,z=l,e=(~v.indexOf("MSIE")||v.indexOf("Trident/"),[1,2,3,4,5,6,7,8,9,10]),a=e.concat([11,12,13,14,15,16,17,18,19,20]),m=(["xs","sm","lg","fw","ul","li","border","pull-left","pull-right","spin","pulse","rotate-90","rotate-180","rotate-270","flip-horizontal","flip-vertical","stack","stack-1x","stack-2x","inverse","layers","layers-text","layers-counter"].concat(e.map(function(c){return c+"x"})).concat(a.map(function(c){return"w-"+c})),{"address-book":[448,512,[],"f2b9","M436 160c6.627 0 12-5.373 12-12v-40c0-6.627-5.373-12-12-12h-20V48c0-26.51-21.49-48-48-48H80C53.49 0 32 21.49 32 48v416c0 26.51 21.49 48 48 48h288c26.51 0 48-21.49 48-48v-48h20c6.627 0 12-5.373 12-12v-40c0-6.627-5.373-12-12-12h-20v-64h20c6.627 0 12-5.373 12-12v-40c0-6.627-5.373-12-12-12h-20v-64h20zM224 96c53.019 0 96 42.981 96 96s-42.981 96-96 96-96-42.981-96-96 42.981-96 96-96zm128 304c0 26.51-21.49 48-48 48H144c-26.51 0-48-21.49-48-48v-48.711c0-20.994 13.644-39.553 33.683-45.815l22.954-7.173C173.563 312.413 198.198 320 224 320s50.437-7.587 71.363-21.699l22.954 7.173C338.356 311.736 352 330.295 352 351.289V400z"],"address-card":[512,512,[],"f2bb","M464 64H48C21.49 64 0 85.49 0 112v288c0 26.51 21.49 48 48 48h416c26.51 0 48-21.49 48-48V112c0-26.51-21.49-48-48-48zm-288 64c44.183 0 80 35.817 80 80s-35.817 80-80 80-80-35.817-80-80 35.817-80 80-80zm112 232c0 13.255-10.745 24-24 24H88c-13.255 0-24-10.745-24-24v-29.897a24 24 0 0 1 17.407-23.077l28.938-8.268C129.323 312.549 152.087 320 176 320s46.677-7.451 65.656-21.241l28.938 8.268A23.999 23.999 0 0 1 288 330.103V360zm160-52c0 6.627-5.373 12-12 12H332c-6.627 0-12-5.373-12-12v-8c0-6.627 5.373-12 12-12h104c6.627 0 12 5.373 12 12v8zm0-64c0 6.627-5.373 12-12 12H332c-6.627 0-12-5.373-12-12v-8c0-6.627 5.373-12 12-12h104c6.627 0 12 5.373 12 12v8zm0-64c0 6.627-5.373 12-12 12H332c-6.627 0-12-5.373-12-12v-8c0-6.627 5.373-12 12-12h104c6.627 0 12 5.373 12 12v8z"],adjust:[512,512,[],"f042","M8 256c0 136.966 111.033 248 248 248s248-111.034 248-248S392.966 8 256 8 8 119.033 8 256zm248 184V72c101.705 0 184 82.311 184 184 0 101.705-82.311 184-184 184z"],"align-center":[448,512,[],"f037","M352 44v40c0 8.837-7.163 16-16 16H112c-8.837 0-16-7.163-16-16V44c0-8.837 7.163-16 16-16h224c8.837 0 16 7.163 16 16zM16 228h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zm0 256h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zm320-200H112c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16h224c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16z"],"align-justify":[448,512,[],"f039","M0 84V44c0-8.837 7.163-16 16-16h416c8.837 0 16 7.163 16 16v40c0 8.837-7.163 16-16 16H16c-8.837 0-16-7.163-16-16zm16 144h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zm0 256h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zm0-128h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16z"],"align-left":[448,512,[],"f036","M288 44v40c0 8.837-7.163 16-16 16H16c-8.837 0-16-7.163-16-16V44c0-8.837 7.163-16 16-16h256c8.837 0 16 7.163 16 16zM0 172v40c0 8.837 7.163 16 16 16h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16zm16 312h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zm256-200H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16h256c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16z"],"align-right":[448,512,[],"f038","M160 84V44c0-8.837 7.163-16 16-16h256c8.837 0 16 7.163 16 16v40c0 8.837-7.163 16-16 16H176c-8.837 0-16-7.163-16-16zM16 228h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zm0 256h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zm160-128h256c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H176c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16z"],ambulance:[640,512,[],"f0f9","M592 0H272c-26.51 0-48 21.49-48 48v48h-44.118a48 48 0 0 0-33.941 14.059l-99.882 99.882A48 48 0 0 0 32 243.882V352h-8c-13.255 0-24 10.745-24 24v16c0 13.255 10.745 24 24 24h40c0 53.019 42.981 96 96 96s96-42.981 96-96h128c0 53.019 42.981 96 96 96s96-42.981 96-96h40c13.255 0 24-10.745 24-24V48c0-26.51-21.49-48-48-48zM160 464c-26.467 0-48-21.533-48-48s21.533-48 48-48 48 21.533 48 48-21.533 48-48 48zm64-208H80v-12.118L179.882 144H224v112zm256 208c-26.467 0-48-21.533-48-48s21.533-48 48-48 48 21.533 48 48-21.533 48-48 48zm32-288v32c0 6.627-5.373 12-12 12h-56v56c0 6.627-5.373 12-12 12h-32c-6.627 0-12-5.373-12-12v-56h-56c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h56v-56c0-6.627 5.373-12 12-12h32c6.627 0 12 5.373 12 12v56h56c6.627 0 12 5.373 12 12z"],"american-sign-language-interpreting":[640,512,[],"f2a3","M290.547 189.039c-20.295-10.149-44.147-11.199-64.739-3.89 42.606 0 71.208 20.475 85.578 50.576 8.576 17.899-5.148 38.071-23.617 38.071 18.429 0 32.211 20.136 23.617 38.071-14.725 30.846-46.123 50.854-80.298 50.854-.557 0-94.471-8.615-94.471-8.615l-66.406 33.347c-9.384 4.693-19.815.379-23.895-7.781L1.86 290.747c-4.167-8.615-1.111-18.897 6.946-23.621l58.072-33.069L108 159.861c6.39-57.245 34.731-109.767 79.743-146.726 11.391-9.448 28.341-7.781 37.51 3.613 9.446 11.394 7.78 28.067-3.612 37.516-12.503 10.559-23.618 22.509-32.509 35.57 21.672-14.729 46.679-24.732 74.186-28.067 14.725-1.945 28.063 8.336 29.73 23.065 1.945 14.728-8.336 28.067-23.062 29.734-16.116 1.945-31.12 7.503-44.178 15.284 26.114-5.713 58.712-3.138 88.079 11.115 13.336 6.669 18.893 22.509 12.224 35.848-6.389 13.06-22.504 18.617-35.564 12.226zm-27.229 69.472c-6.112-12.505-18.338-20.286-32.231-20.286a35.46 35.46 0 0 0-35.565 35.57c0 21.428 17.808 35.57 35.565 35.57 13.893 0 26.119-7.781 32.231-20.286 4.446-9.449 13.614-15.006 23.339-15.284-9.725-.277-18.893-5.835-23.339-15.284zm374.821-37.237c4.168 8.615 1.111 18.897-6.946 23.621l-58.071 33.069L532 352.16c-6.39 57.245-34.731 109.767-79.743 146.726-10.932 9.112-27.799 8.144-37.51-3.613-9.446-11.394-7.78-28.067 3.613-37.516 12.503-10.559 23.617-22.509 32.508-35.57-21.672 14.729-46.679 24.732-74.186 28.067-10.021 2.506-27.552-5.643-29.73-23.065-1.945-14.728 8.336-28.067 23.062-29.734 16.116-1.946 31.12-7.503 44.178-15.284-26.114 5.713-58.712 3.138-88.079-11.115-13.336-6.669-18.893-22.509-12.224-35.848 6.389-13.061 22.505-18.619 35.565-12.227 20.295 10.149 44.147 11.199 64.739 3.89-42.606 0-71.208-20.475-85.578-50.576-8.576-17.899 5.148-38.071 23.617-38.071-18.429 0-32.211-20.136-23.617-38.071 14.033-29.396 44.039-50.887 81.966-50.854l92.803 8.615 66.406-33.347c9.408-4.704 19.828-.354 23.894 7.781l44.455 88.926zm-229.227-18.618c-13.893 0-26.119 7.781-32.231 20.286-4.446 9.449-13.614 15.006-23.339 15.284 9.725.278 18.893 5.836 23.339 15.284 6.112 12.505 18.338 20.286 32.231 20.286a35.46 35.46 0 0 0 35.565-35.57c0-21.429-17.808-35.57-35.565-35.57z"],anchor:[576,512,[],"f13d","M12.971 352h32.394C67.172 454.735 181.944 512 288 512c106.229 0 220.853-57.38 242.635-160h32.394c10.691 0 16.045-12.926 8.485-20.485l-67.029-67.029c-4.686-4.686-12.284-4.686-16.971 0l-67.029 67.029c-7.56 7.56-2.206 20.485 8.485 20.485h35.146c-20.29 54.317-84.963 86.588-144.117 94.015V256h52c6.627 0 12-5.373 12-12v-40c0-6.627-5.373-12-12-12h-52v-5.47c37.281-13.178 63.995-48.725 64-90.518C384.005 43.772 341.605.738 289.37.01 235.723-.739 192 42.525 192 96c0 41.798 26.716 77.35 64 90.53V192h-52c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h52v190.015c-58.936-7.399-123.82-39.679-144.117-94.015h35.146c10.691 0 16.045-12.926 8.485-20.485l-67.029-67.029c-4.686-4.686-12.284-4.686-16.971 0L4.485 331.515C-3.074 339.074 2.28 352 12.971 352zM288 64c17.645 0 32 14.355 32 32s-14.355 32-32 32-32-14.355-32-32 14.355-32 32-32z"],"angle-double-down":[320,512,[],"f103","M143 256.3L7 120.3c-9.4-9.4-9.4-24.6 0-33.9l22.6-22.6c9.4-9.4 24.6-9.4 33.9 0l96.4 96.4 96.4-96.4c9.4-9.4 24.6-9.4 33.9 0L313 86.3c9.4 9.4 9.4 24.6 0 33.9l-136 136c-9.4 9.5-24.6 9.5-34 .1zm34 192l136-136c9.4-9.4 9.4-24.6 0-33.9l-22.6-22.6c-9.4-9.4-24.6-9.4-33.9 0L160 352.1l-96.4-96.4c-9.4-9.4-24.6-9.4-33.9 0L7 278.3c-9.4 9.4-9.4 24.6 0 33.9l136 136c9.4 9.5 24.6 9.5 34 .1z"],"angle-double-left":[448,512,[],"f100","M223.7 239l136-136c9.4-9.4 24.6-9.4 33.9 0l22.6 22.6c9.4 9.4 9.4 24.6 0 33.9L319.9 256l96.4 96.4c9.4 9.4 9.4 24.6 0 33.9L393.7 409c-9.4 9.4-24.6 9.4-33.9 0l-136-136c-9.5-9.4-9.5-24.6-.1-34zm-192 34l136 136c9.4 9.4 24.6 9.4 33.9 0l22.6-22.6c9.4-9.4 9.4-24.6 0-33.9L127.9 256l96.4-96.4c9.4-9.4 9.4-24.6 0-33.9L201.7 103c-9.4-9.4-24.6-9.4-33.9 0l-136 136c-9.5 9.4-9.5 24.6-.1 34z"],"angle-double-right":[448,512,[],"f101","M224.3 273l-136 136c-9.4 9.4-24.6 9.4-33.9 0l-22.6-22.6c-9.4-9.4-9.4-24.6 0-33.9l96.4-96.4-96.4-96.4c-9.4-9.4-9.4-24.6 0-33.9L54.3 103c9.4-9.4 24.6-9.4 33.9 0l136 136c9.5 9.4 9.5 24.6.1 34zm192-34l-136-136c-9.4-9.4-24.6-9.4-33.9 0l-22.6 22.6c-9.4 9.4-9.4 24.6 0 33.9l96.4 96.4-96.4 96.4c-9.4 9.4-9.4 24.6 0 33.9l22.6 22.6c9.4 9.4 24.6 9.4 33.9 0l136-136c9.4-9.2 9.4-24.4 0-33.8z"],"angle-double-up":[320,512,[],"f102","M177 255.7l136 136c9.4 9.4 9.4 24.6 0 33.9l-22.6 22.6c-9.4 9.4-24.6 9.4-33.9 0L160 351.9l-96.4 96.4c-9.4 9.4-24.6 9.4-33.9 0L7 425.7c-9.4-9.4-9.4-24.6 0-33.9l136-136c9.4-9.5 24.6-9.5 34-.1zm-34-192L7 199.7c-9.4 9.4-9.4 24.6 0 33.9l22.6 22.6c9.4 9.4 24.6 9.4 33.9 0l96.4-96.4 96.4 96.4c9.4 9.4 24.6 9.4 33.9 0l22.6-22.6c9.4-9.4 9.4-24.6 0-33.9l-136-136c-9.2-9.4-24.4-9.4-33.8 0z"],"angle-down":[320,512,[],"f107","M143 352.3L7 216.3c-9.4-9.4-9.4-24.6 0-33.9l22.6-22.6c9.4-9.4 24.6-9.4 33.9 0l96.4 96.4 96.4-96.4c9.4-9.4 24.6-9.4 33.9 0l22.6 22.6c9.4 9.4 9.4 24.6 0 33.9l-136 136c-9.2 9.4-24.4 9.4-33.8 0z"],"angle-left":[256,512,[],"f104","M31.7 239l136-136c9.4-9.4 24.6-9.4 33.9 0l22.6 22.6c9.4 9.4 9.4 24.6 0 33.9L127.9 256l96.4 96.4c9.4 9.4 9.4 24.6 0 33.9L201.7 409c-9.4 9.4-24.6 9.4-33.9 0l-136-136c-9.5-9.4-9.5-24.6-.1-34z"],"angle-right":[256,512,[],"f105","M224.3 273l-136 136c-9.4 9.4-24.6 9.4-33.9 0l-22.6-22.6c-9.4-9.4-9.4-24.6 0-33.9l96.4-96.4-96.4-96.4c-9.4-9.4-9.4-24.6 0-33.9L54.3 103c9.4-9.4 24.6-9.4 33.9 0l136 136c9.5 9.4 9.5 24.6.1 34z"],"angle-up":[320,512,[],"f106","M177 159.7l136 136c9.4 9.4 9.4 24.6 0 33.9l-22.6 22.6c-9.4 9.4-24.6 9.4-33.9 0L160 255.9l-96.4 96.4c-9.4 9.4-24.6 9.4-33.9 0L7 329.7c-9.4-9.4-9.4-24.6 0-33.9l136-136c9.4-9.5 24.6-9.5 34-.1z"],archive:[512,512,[],"f187","M488 128H24c-13.255 0-24-10.745-24-24V56c0-13.255 10.745-24 24-24h464c13.255 0 24 10.745 24 24v48c0 13.255-10.745 24-24 24zm-8 328V184c0-13.255-10.745-24-24-24H56c-13.255 0-24 10.745-24 24v272c0 13.255 10.745 24 24 24h400c13.255 0 24-10.745 24-24zM308 256H204c-6.627 0-12-5.373-12-12v-8c0-6.627 5.373-12 12-12h104c6.627 0 12 5.373 12 12v8c0 6.627-5.373 12-12 12z"],"arrow-alt-circle-down":[512,512,[],"f358","M504 256c0 137-111 248-248 248S8 393 8 256 119 8 256 8s248 111 248 248zM212 140v116h-70.9c-10.7 0-16.1 13-8.5 20.5l114.9 114.3c4.7 4.7 12.2 4.7 16.9 0l114.9-114.3c7.6-7.6 2.2-20.5-8.5-20.5H300V140c0-6.6-5.4-12-12-12h-64c-6.6 0-12 5.4-12 12z"],"arrow-alt-circle-left":[512,512,[],"f359","M256 504C119 504 8 393 8 256S119 8 256 8s248 111 248 248-111 248-248 248zm116-292H256v-70.9c0-10.7-13-16.1-20.5-8.5L121.2 247.5c-4.7 4.7-4.7 12.2 0 16.9l114.3 114.9c7.6 7.6 20.5 2.2 20.5-8.5V300h116c6.6 0 12-5.4 12-12v-64c0-6.6-5.4-12-12-12z"],"arrow-alt-circle-right":[512,512,[],"f35a","M256 8c137 0 248 111 248 248S393 504 256 504 8 393 8 256 119 8 256 8zM140 300h116v70.9c0 10.7 13 16.1 20.5 8.5l114.3-114.9c4.7-4.7 4.7-12.2 0-16.9l-114.3-115c-7.6-7.6-20.5-2.2-20.5 8.5V212H140c-6.6 0-12 5.4-12 12v64c0 6.6 5.4 12 12 12z"],"arrow-alt-circle-up":[512,512,[],"f35b","M8 256C8 119 119 8 256 8s248 111 248 248-111 248-248 248S8 393 8 256zm292 116V256h70.9c10.7 0 16.1-13 8.5-20.5L264.5 121.2c-4.7-4.7-12.2-4.7-16.9 0l-115 114.3c-7.6 7.6-2.2 20.5 8.5 20.5H212v116c0 6.6 5.4 12 12 12h64c6.6 0 12-5.4 12-12z"],"arrow-circle-down":[512,512,[],"f0ab","M504 256c0 137-111 248-248 248S8 393 8 256 119 8 256 8s248 111 248 248zm-143.6-28.9L288 302.6V120c0-13.3-10.7-24-24-24h-16c-13.3 0-24 10.7-24 24v182.6l-72.4-75.5c-9.3-9.7-24.8-9.9-34.3-.4l-10.9 11c-9.4 9.4-9.4 24.6 0 33.9L239 404.3c9.4 9.4 24.6 9.4 33.9 0l132.7-132.7c9.4-9.4 9.4-24.6 0-33.9l-10.9-11c-9.5-9.5-25-9.3-34.3.4z"],"arrow-circle-left":[512,512,[],"f0a8","M256 504C119 504 8 393 8 256S119 8 256 8s248 111 248 248-111 248-248 248zm28.9-143.6L209.4 288H392c13.3 0 24-10.7 24-24v-16c0-13.3-10.7-24-24-24H209.4l75.5-72.4c9.7-9.3 9.9-24.8.4-34.3l-11-10.9c-9.4-9.4-24.6-9.4-33.9 0L107.7 239c-9.4 9.4-9.4 24.6 0 33.9l132.7 132.7c9.4 9.4 24.6 9.4 33.9 0l11-10.9c9.5-9.5 9.3-25-.4-34.3z"],"arrow-circle-right":[512,512,[],"f0a9","M256 8c137 0 248 111 248 248S393 504 256 504 8 393 8 256 119 8 256 8zm-28.9 143.6l75.5 72.4H120c-13.3 0-24 10.7-24 24v16c0 13.3 10.7 24 24 24h182.6l-75.5 72.4c-9.7 9.3-9.9 24.8-.4 34.3l11 10.9c9.4 9.4 24.6 9.4 33.9 0L404.3 273c9.4-9.4 9.4-24.6 0-33.9L271.6 106.3c-9.4-9.4-24.6-9.4-33.9 0l-11 10.9c-9.5 9.6-9.3 25.1.4 34.4z"],"arrow-circle-up":[512,512,[],"f0aa","M8 256C8 119 119 8 256 8s248 111 248 248-111 248-248 248S8 393 8 256zm143.6 28.9l72.4-75.5V392c0 13.3 10.7 24 24 24h16c13.3 0 24-10.7 24-24V209.4l72.4 75.5c9.3 9.7 24.8 9.9 34.3.4l10.9-11c9.4-9.4 9.4-24.6 0-33.9L273 107.7c-9.4-9.4-24.6-9.4-33.9 0L106.3 240.4c-9.4 9.4-9.4 24.6 0 33.9l10.9 11c9.6 9.5 25.1 9.3 34.4-.4z"],"arrow-down":[448,512,[],"f063","M413.1 222.5l22.2 22.2c9.4 9.4 9.4 24.6 0 33.9L241 473c-9.4 9.4-24.6 9.4-33.9 0L12.7 278.6c-9.4-9.4-9.4-24.6 0-33.9l22.2-22.2c9.5-9.5 25-9.3 34.3.4L184 343.4V56c0-13.3 10.7-24 24-24h32c13.3 0 24 10.7 24 24v287.4l114.8-120.5c9.3-9.8 24.8-10 34.3-.4z"],"arrow-left":[448,512,[],"f060","M257.5 445.1l-22.2 22.2c-9.4 9.4-24.6 9.4-33.9 0L7 273c-9.4-9.4-9.4-24.6 0-33.9L201.4 44.7c9.4-9.4 24.6-9.4 33.9 0l22.2 22.2c9.5 9.5 9.3 25-.4 34.3L136.6 216H424c13.3 0 24 10.7 24 24v32c0 13.3-10.7 24-24 24H136.6l120.5 114.8c9.8 9.3 10 24.8.4 34.3z"],"arrow-right":[448,512,[],"f061","M190.5 66.9l22.2-22.2c9.4-9.4 24.6-9.4 33.9 0L441 239c9.4 9.4 9.4 24.6 0 33.9L246.6 467.3c-9.4 9.4-24.6 9.4-33.9 0l-22.2-22.2c-9.5-9.5-9.3-25 .4-34.3L311.4 296H24c-13.3 0-24-10.7-24-24v-32c0-13.3 10.7-24 24-24h287.4L190.9 101.2c-9.8-9.3-10-24.8-.4-34.3z"],"arrow-up":[448,512,[],"f062","M34.9 289.5l-22.2-22.2c-9.4-9.4-9.4-24.6 0-33.9L207 39c9.4-9.4 24.6-9.4 33.9 0l194.3 194.3c9.4 9.4 9.4 24.6 0 33.9L413 289.4c-9.5 9.5-25 9.3-34.3-.4L264 168.6V456c0 13.3-10.7 24-24 24h-32c-13.3 0-24-10.7-24-24V168.6L69.2 289.1c-9.3 9.8-24.8 10-34.3.4z"],"arrows-alt":[512,512,[],"f0b2","M352.201 425.775l-79.196 79.196c-9.373 9.373-24.568 9.373-33.941 0l-79.196-79.196c-15.119-15.119-4.411-40.971 16.971-40.97h51.162L228 284H127.196v51.162c0 21.382-25.851 32.09-40.971 16.971L7.029 272.937c-9.373-9.373-9.373-24.569 0-33.941L86.225 159.8c15.119-15.119 40.971-4.411 40.971 16.971V228H228V127.196h-51.23c-21.382 0-32.09-25.851-16.971-40.971l79.196-79.196c9.373-9.373 24.568-9.373 33.941 0l79.196 79.196c15.119 15.119 4.411 40.971-16.971 40.971h-51.162V228h100.804v-51.162c0-21.382 25.851-32.09 40.97-16.971l79.196 79.196c9.373 9.373 9.373 24.569 0 33.941L425.773 352.2c-15.119 15.119-40.971 4.411-40.97-16.971V284H284v100.804h51.23c21.382 0 32.09 25.851 16.971 40.971z"],"arrows-alt-h":[512,512,[],"f337","M377.941 169.941V216H134.059v-46.059c0-21.382-25.851-32.09-40.971-16.971L7.029 239.029c-9.373 9.373-9.373 24.568 0 33.941l86.059 86.059c15.119 15.119 40.971 4.411 40.971-16.971V296h243.882v46.059c0 21.382 25.851 32.09 40.971 16.971l86.059-86.059c9.373-9.373 9.373-24.568 0-33.941l-86.059-86.059c-15.119-15.12-40.971-4.412-40.971 16.97z"],"arrows-alt-v":[256,512,[],"f338","M214.059 377.941H168V134.059h46.059c21.382 0 32.09-25.851 16.971-40.971L144.971 7.029c-9.373-9.373-24.568-9.373-33.941 0L24.971 93.088c-15.119 15.119-4.411 40.971 16.971 40.971H88v243.882H41.941c-21.382 0-32.09 25.851-16.971 40.971l86.059 86.059c9.373 9.373 24.568 9.373 33.941 0l86.059-86.059c15.12-15.119 4.412-40.971-16.97-40.971z"],"assistive-listening-systems":[512,512,[],"f2a2","M216 260c0 15.464-12.536 28-28 28s-28-12.536-28-28c0-44.112 35.888-80 80-80s80 35.888 80 80c0 15.464-12.536 28-28 28s-28-12.536-28-28c0-13.234-10.767-24-24-24s-24 10.766-24 24zm24-176c-97.047 0-176 78.953-176 176 0 15.464 12.536 28 28 28s28-12.536 28-28c0-66.168 53.832-120 120-120s120 53.832 120 120c0 75.164-71.009 70.311-71.997 143.622L288 404c0 28.673-23.327 52-52 52-15.464 0-28 12.536-28 28s12.536 28 28 28c59.475 0 107.876-48.328 108-107.774.595-34.428 72-48.24 72-144.226 0-97.047-78.953-176-176-176zm-80 236c-17.673 0-32 14.327-32 32s14.327 32 32 32 32-14.327 32-32-14.327-32-32-32zM32 448c-17.673 0-32 14.327-32 32s14.327 32 32 32 32-14.327 32-32-14.327-32-32-32zm480-187.993c0-1.518-.012-3.025-.045-4.531C510.076 140.525 436.157 38.47 327.994 1.511c-14.633-4.998-30.549 2.809-35.55 17.442-5 14.633 2.81 30.549 17.442 35.55 85.906 29.354 144.61 110.513 146.077 201.953l.003.188c.026 1.118.033 2.236.033 3.363 0 15.464 12.536 28 28 28s28.001-12.536 28.001-28zM152.971 439.029l-80-80L39.03 392.97l80 80 33.941-33.941z"],asterisk:[512,512,[],"f069","M478.21 334.093L336 256l142.21-78.093c11.795-6.477 15.961-21.384 9.232-33.037l-19.48-33.741c-6.728-11.653-21.72-15.499-33.227-8.523L296 186.718l3.475-162.204C299.763 11.061 288.937 0 275.48 0h-38.96c-13.456 0-24.283 11.061-23.994 24.514L216 186.718 77.265 102.607c-11.506-6.976-26.499-3.13-33.227 8.523l-19.48 33.741c-6.728 11.653-2.562 26.56 9.233 33.037L176 256 33.79 334.093c-11.795 6.477-15.961 21.384-9.232 33.037l19.48 33.741c6.728 11.653 21.721 15.499 33.227 8.523L216 325.282l-3.475 162.204C212.237 500.939 223.064 512 236.52 512h38.961c13.456 0 24.283-11.061 23.995-24.514L296 325.282l138.735 84.111c11.506 6.976 26.499 3.13 33.227-8.523l19.48-33.741c6.728-11.653 2.563-26.559-9.232-33.036z"],at:[512,512,[],"f1fa","M256 8C118.941 8 8 118.919 8 256c0 137.059 110.919 248 248 248 48.154 0 95.342-14.14 135.408-40.223 12.005-7.815 14.625-24.288 5.552-35.372l-10.177-12.433c-7.671-9.371-21.179-11.667-31.373-5.129C325.92 429.757 291.314 440 256 440c-101.458 0-184-82.542-184-184S154.542 72 256 72c100.139 0 184 57.619 184 160 0 38.786-21.093 79.742-58.17 83.693-17.349-.454-16.91-12.857-13.476-30.024l23.433-121.11C394.653 149.75 383.308 136 368.225 136h-44.981a13.518 13.518 0 0 0-13.432 11.993l-.01.092c-14.697-17.901-40.448-21.775-59.971-21.775-74.58 0-137.831 62.234-137.831 151.46 0 65.303 36.785 105.87 96 105.87 26.984 0 57.369-15.637 74.991-38.333 9.522 34.104 40.613 34.103 70.71 34.103C462.609 379.41 504 307.798 504 232 504 95.653 394.023 8 256 8zm-21.68 304.43c-22.249 0-36.07-15.623-36.07-40.771 0-44.993 30.779-72.729 58.63-72.729 22.292 0 35.601 15.241 35.601 40.77 0 45.061-33.875 72.73-58.161 72.73z"],"audio-description":[512,512,[],"f29e","M162.925 238.709l8.822 30.655h-25.606l9.041-30.652c1.277-4.421 2.651-9.994 3.872-15.245 1.22 5.251 2.594 10.823 3.871 15.242zm166.474-32.099h-14.523v98.781h14.523c29.776 0 46.175-17.678 46.175-49.776 0-32.239-17.49-49.005-46.175-49.005zM512 112v288c0 26.51-21.49 48-48 48H48c-26.51 0-48-21.49-48-48V112c0-26.51 21.49-48 48-48h416c26.51 0 48 21.49 48 48zM245.459 336.139l-57.097-168A12.001 12.001 0 0 0 177 160h-35.894a12.001 12.001 0 0 0-11.362 8.139l-57.097 168C70.003 343.922 75.789 352 84.009 352h29.133a12 12 0 0 0 11.535-8.693l8.574-29.906h51.367l8.793 29.977A12 12 0 0 0 204.926 352h29.172c8.22 0 14.006-8.078 11.361-15.861zm184.701-80.525c0-58.977-37.919-95.614-98.96-95.614h-57.366c-6.627 0-12 5.373-12 12v168c0 6.627 5.373 12 12 12H331.2c61.041 0 98.96-36.933 98.96-96.386z"],backward:[512,512,[],"f04a","M11.5 280.6l192 160c20.6 17.2 52.5 2.8 52.5-24.6V96c0-27.4-31.9-41.8-52.5-24.6l-192 160c-15.3 12.8-15.3 36.4 0 49.2zm256 0l192 160c20.6 17.2 52.5 2.8 52.5-24.6V96c0-27.4-31.9-41.8-52.5-24.6l-192 160c-15.3 12.8-15.3 36.4 0 49.2z"],"balance-scale":[640,512,[],"f24e","M352 448h168c13.255 0 24 10.745 24 24v16c0 13.255-10.745 24-24 24H120c-13.255 0-24-10.745-24-24v-16c0-13.255 10.745-24 24-24h168V153.324C264.469 143.04 246.836 121.778 241.603 96H120c-13.255 0-24-10.745-24-24V56c0-13.255 10.745-24 24-24h135.999C270.594 12.57 293.828 0 320 0s49.406 12.57 64.001 32H520c13.255 0 24 10.745 24 24v16c0 13.255-10.745 24-24 24H398.397c-5.233 25.778-22.866 47.04-46.397 57.324V448zm287.981-112c.001-16.182 1.342-8.726-85.048-181.506-17.647-35.294-68.186-35.358-85.865 0C381.94 328.75 384.019 320.331 384.019 336H384c0 44.183 57.308 80 128 80s128-35.817 128-80h-.019zM512 176l72 144H440l72-144zM255.981 336c.001-16.182 1.342-8.726-85.048-181.506-17.647-35.294-68.186-35.358-85.865 0C-2.06 328.75.019 320.331.019 336H0c0 44.183 57.308 80 128 80s128-35.817 128-80h-.019zM128 176l72 144H56l72-144z"],ban:[512,512,[],"f05e","M256 8C119.034 8 8 119.033 8 256s111.034 248 248 248 248-111.034 248-248S392.967 8 256 8zm130.108 117.892c65.448 65.448 70 165.481 20.677 235.637L150.47 105.216c70.204-49.356 170.226-44.735 235.638 20.676zM125.892 386.108c-65.448-65.448-70-165.481-20.677-235.637L361.53 406.784c-70.203 49.356-170.226 44.736-235.638-20.676z"],barcode:[512,512,[],"f02a","M0 448V64h18v384H0zm26.857-.273V64H36v383.727h-9.143zm27.143 0V64h8.857v383.727H54zm44.857 0V64h8.857v383.727h-8.857zm36 0V64h17.714v383.727h-17.714zm44.857 0V64h8.857v383.727h-8.857zm18 0V64h8.857v383.727h-8.857zm18 0V64h8.857v383.727h-8.857zm35.715 0V64h18v383.727h-18zm44.857 0V64h18v383.727h-18zm35.999 0V64h18.001v383.727h-18.001zm36.001 0V64h18.001v383.727h-18.001zm26.857 0V64h18v383.727h-18zm45.143 0V64h26.857v383.727h-26.857zm35.714 0V64h9.143v383.727H476zm18 .273V64h18v384h-18z"],bars:[448,512,[],"f0c9","M16 132h416c8.837 0 16-7.163 16-16V76c0-8.837-7.163-16-16-16H16C7.163 60 0 67.163 0 76v40c0 8.837 7.163 16 16 16zm0 160h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zm0 160h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16z"],bath:[512,512,[],"f2cd","M488 256H80V112c0-17.645 14.355-32 32-32 11.351 0 21.332 5.945 27.015 14.88-16.492 25.207-14.687 59.576 6.838 83.035-4.176 4.713-4.021 11.916.491 16.428l11.314 11.314c4.686 4.686 12.284 4.686 16.971 0l95.03-95.029c4.686-4.686 4.686-12.284 0-16.971l-11.314-11.314c-4.512-4.512-11.715-4.666-16.428-.491-17.949-16.469-42.294-21.429-64.178-15.365C163.281 45.667 139.212 32 112 32c-44.112 0-80 35.888-80 80v144h-8c-13.255 0-24 10.745-24 24v16c0 13.255 10.745 24 24 24h8v32c0 28.43 12.362 53.969 32 71.547V456c0 13.255 10.745 24 24 24h16c13.255 0 24-10.745 24-24v-8h256v8c0 13.255 10.745 24 24 24h16c13.255 0 24-10.745 24-24v-32.453c19.638-17.578 32-43.117 32-71.547v-32h8c13.255 0 24-10.745 24-24v-16c0-13.255-10.745-24-24-24z"],"battery-empty":[640,512,[],"f244","M544 160v64h32v64h-32v64H64V160h480m16-64H48c-26.51 0-48 21.49-48 48v224c0 26.51 21.49 48 48 48h512c26.51 0 48-21.49 48-48v-16h8c13.255 0 24-10.745 24-24V184c0-13.255-10.745-24-24-24h-8v-16c0-26.51-21.49-48-48-48z"],"battery-full":[640,512,[],"f240","M544 160v64h32v64h-32v64H64V160h480m16-64H48c-26.51 0-48 21.49-48 48v224c0 26.51 21.49 48 48 48h512c26.51 0 48-21.49 48-48v-16h8c13.255 0 24-10.745 24-24V184c0-13.255-10.745-24-24-24h-8v-16c0-26.51-21.49-48-48-48zm-48 96H96v128h416V192z"],"battery-half":[640,512,[],"f242","M544 160v64h32v64h-32v64H64V160h480m16-64H48c-26.51 0-48 21.49-48 48v224c0 26.51 21.49 48 48 48h512c26.51 0 48-21.49 48-48v-16h8c13.255 0 24-10.745 24-24V184c0-13.255-10.745-24-24-24h-8v-16c0-26.51-21.49-48-48-48zm-240 96H96v128h224V192z"],"battery-quarter":[640,512,[],"f243","M544 160v64h32v64h-32v64H64V160h480m16-64H48c-26.51 0-48 21.49-48 48v224c0 26.51 21.49 48 48 48h512c26.51 0 48-21.49 48-48v-16h8c13.255 0 24-10.745 24-24V184c0-13.255-10.745-24-24-24h-8v-16c0-26.51-21.49-48-48-48zm-336 96H96v128h128V192z"],"battery-three-quarters":[640,512,[],"f241","M544 160v64h32v64h-32v64H64V160h480m16-64H48c-26.51 0-48 21.49-48 48v224c0 26.51 21.49 48 48 48h512c26.51 0 48-21.49 48-48v-16h8c13.255 0 24-10.745 24-24V184c0-13.255-10.745-24-24-24h-8v-16c0-26.51-21.49-48-48-48zm-144 96H96v128h320V192z"],bed:[576,512,[],"f236","M552 288c13.255 0 24 10.745 24 24v136h-96v-64H96v64H0V88c0-13.255 10.745-24 24-24h48c13.255 0 24 10.745 24 24v200h456zM192 96c-44.183 0-80 35.817-80 80s35.817 80 80 80 80-35.817 80-80-35.817-80-80-80zm384 128c0-53.019-42.981-96-96-96H312c-13.255 0-24 10.745-24 24v104h288v-32z"],beer:[448,512,[],"f0fc","M368 96h-48V56c0-13.255-10.745-24-24-24H24C10.745 32 0 42.745 0 56v400c0 13.255 10.745 24 24 24h272c13.255 0 24-10.745 24-24v-42.11l80.606-35.977C429.396 365.063 448 336.388 448 304.86V176c0-44.112-35.888-80-80-80zm16 208.86a16.018 16.018 0 0 1-9.479 14.611L320 343.805V160h48c8.822 0 16 7.178 16 16v128.86zM208 384c-8.836 0-16-7.164-16-16V144c0-8.836 7.164-16 16-16s16 7.164 16 16v224c0 8.836-7.164 16-16 16zm-96 0c-8.836 0-16-7.164-16-16V144c0-8.836 7.164-16 16-16s16 7.164 16 16v224c0 8.836-7.164 16-16 16z"],bell:[448,512,[],"f0f3","M433.884 366.059C411.634 343.809 384 316.118 384 208c0-79.394-57.831-145.269-133.663-157.83A31.845 31.845 0 0 0 256 32c0-17.673-14.327-32-32-32s-32 14.327-32 32c0 6.75 2.095 13.008 5.663 18.17C121.831 62.731 64 128.606 64 208c0 108.118-27.643 135.809-49.893 158.059C-16.042 396.208 5.325 448 48.048 448H160c0 35.346 28.654 64 64 64s64-28.654 64-64h111.943c42.638 0 64.151-51.731 33.941-81.941zM224 472a8 8 0 0 1 0 16c-22.056 0-40-17.944-40-40h16c0 13.234 10.766 24 24 24z"],"bell-slash":[576,512,[],"f1f6","M78.107 366.059C47.958 396.208 69.325 448 112.048 448H224c0 35.346 28.654 64 64 64 35.346 0 64-28.654 64-64h32.685L127.848 221.379c-2.198 97.078-28.439 123.378-49.741 144.68zM264 448c0 13.234 10.766 24 24 24a8 8 0 0 1 0 16c-22.056 0-40-17.944-40-40h16zm305.896 43.733l-10.762 12.086c-8.915 10.012-24.333 10.967-34.437 2.133L8.256 54.393C-1.848 45.558-2.811 30.28 6.104 20.267L16.865 8.181C25.781-1.831 41.199-2.786 51.303 6.049l113.81 99.512c24.017-28.778 57.946-48.996 96.55-55.39A31.85 31.85 0 0 1 256 32c0-17.673 14.327-32 32-32s32 14.327 32 32c0 6.75-2.095 13.008-5.663 18.17C390.169 62.731 448 128.606 448 208c0 108.118 27.634 135.809 49.884 158.059 12.149 12.149 15.923 27.776 13.33 42.121l56.53 49.427c10.104 8.835 11.067 24.113 2.152 34.126z"],bicycle:[640,512,[],"f206","M512.509 192.001c-16.373-.064-32.03 2.955-46.436 8.495l-77.68-125.153A24 24 0 0 0 368.001 64h-64c-8.837 0-16 7.163-16 16v16c0 8.837 7.163 16 16 16h50.649l14.896 24H256.002v-16c0-8.837-7.163-16-16-16h-87.459c-13.441 0-24.777 10.999-24.536 24.437.232 13.044 10.876 23.563 23.995 23.563h48.726l-29.417 47.52c-13.433-4.83-27.904-7.483-42.992-7.52C58.094 191.83.412 249.012.002 319.236-.413 390.279 57.055 448 128.002 448c59.642 0 109.758-40.793 123.967-96h52.033a24 24 0 0 0 20.406-11.367L410.37 201.77l14.938 24.067c-25.455 23.448-41.385 57.081-41.307 94.437.145 68.833 57.899 127.051 126.729 127.719 70.606.685 128.181-55.803 129.255-125.996 1.086-70.941-56.526-129.72-127.476-129.996zM186.75 265.772c9.727 10.529 16.673 23.661 19.642 38.228h-43.306l23.664-38.228zM128.002 400c-44.112 0-80-35.888-80-80s35.888-80 80-80c5.869 0 11.586.653 17.099 1.859l-45.505 73.509C89.715 331.327 101.213 352 120.002 352h81.3c-12.37 28.225-40.562 48-73.3 48zm162.63-96h-35.624c-3.96-31.756-19.556-59.894-42.383-80.026L237.371 184h127.547l-74.286 120zm217.057 95.886c-41.036-2.165-74.049-35.692-75.627-76.755-.812-21.121 6.633-40.518 19.335-55.263l44.433 71.586c4.66 7.508 14.524 9.816 22.032 5.156l13.594-8.437c7.508-4.66 9.817-14.524 5.156-22.032l-44.468-71.643a79.901 79.901 0 0 1 19.858-2.497c44.112 0 80 35.888 80 80-.001 45.54-38.252 82.316-84.313 79.885z"],binoculars:[512,512,[],"f1e5","M192 104H96V56c0-13.255 10.745-24 24-24h48c13.255 0 24 10.745 24 24v48zm224-48c0-13.255-10.745-24-24-24h-48c-13.255 0-24 10.745-24 24v48h96V56zM0 456c0 13.255 10.745 24 24 24h120c13.255 0 24-10.745 24-24v-16H0v16zm88-328c-13.255 0-24 10.745-24 24C64 256 0 272 0 416h168V312c0-13.255 10.745-24 24-24V128H88zm256 328c0 13.255 10.745 24 24 24h120c13.255 0 24-10.745 24-24v-16H344v16zM216 128v160h80V128h-80zm128 288h168c0-144-64-160-64-264 0-13.255-10.745-24-24-24H320v160c13.255 0 24 10.745 24 24v104z"],"birthday-cake":[448,512,[],"f1fd","M448 384c-28.02 0-31.26-32-74.5-32-43.43 0-46.825 32-74.75 32-27.695 0-31.454-32-74.75-32-42.842 0-47.218 32-74.5 32-28.148 0-31.202-32-74.75-32-43.547 0-46.653 32-74.75 32v-80c0-26.5 21.5-48 48-48h16V112h64v144h64V112h64v144h64V112h64v144h16c26.5 0 48 21.5 48 48v80zm0 128H0v-96c43.356 0 46.767-32 74.75-32 27.951 0 31.253 32 74.75 32 42.843 0 47.217-32 74.5-32 28.148 0 31.201 32 74.75 32 43.357 0 46.767-32 74.75-32 27.488 0 31.252 32 74.5 32v96zM96 96c-17.75 0-32-14.25-32-32 0-31 32-23 32-64 12 0 32 29.5 32 56s-14.25 40-32 40zm128 0c-17.75 0-32-14.25-32-32 0-31 32-23 32-64 12 0 32 29.5 32 56s-14.25 40-32 40zm128 0c-17.75 0-32-14.25-32-32 0-31 32-23 32-64 12 0 32 29.5 32 56s-14.25 40-32 40z"],blind:[384,512,[],"f29d","M380.15 510.837a8 8 0 0 1-10.989-2.687l-125.33-206.427a31.923 31.923 0 0 0 12.958-9.485l126.048 207.608a8 8 0 0 1-2.687 10.991zM142.803 314.338l-32.54 89.485 36.12 88.285c6.693 16.36 25.377 24.192 41.733 17.501 16.357-6.692 24.193-25.376 17.501-41.734l-62.814-153.537zM96 88c24.301 0 44-19.699 44-44S120.301 0 96 0 52 19.699 52 44s19.699 44 44 44zm154.837 169.128l-120-152c-4.733-5.995-11.75-9.108-18.837-9.112V96H80v.026c-7.146.003-14.217 3.161-18.944 9.24L0 183.766v95.694c0 13.455 11.011 24.791 24.464 24.536C37.505 303.748 48 293.1 48 280v-79.766l16-20.571v140.698L9.927 469.055c-6.04 16.609 2.528 34.969 19.138 41.009 16.602 6.039 34.968-2.524 41.009-19.138L136 309.638V202.441l-31.406-39.816a4 4 0 1 1 6.269-4.971l102.3 129.217c9.145 11.584 24.368 11.339 33.708 3.965 10.41-8.216 12.159-23.334 3.966-33.708z"],bold:[384,512,[],"f032","M304.793 243.891c33.639-18.537 53.657-54.16 53.657-95.693 0-48.236-26.25-87.626-68.626-104.179C265.138 34.01 240.849 32 209.661 32H24c-8.837 0-16 7.163-16 16v33.049c0 8.837 7.163 16 16 16h33.113v318.53H24c-8.837 0-16 7.163-16 16V464c0 8.837 7.163 16 16 16h195.69c24.203 0 44.834-1.289 66.866-7.584C337.52 457.193 376 410.647 376 350.014c0-52.168-26.573-91.684-71.207-106.123zM142.217 100.809h67.444c16.294 0 27.536 2.019 37.525 6.717 15.828 8.479 24.906 26.502 24.906 49.446 0 35.029-20.32 56.79-53.029 56.79h-76.846V100.809zm112.642 305.475c-10.14 4.056-22.677 4.907-31.409 4.907h-81.233V281.943h84.367c39.645 0 63.057 25.38 63.057 63.057.001 28.425-13.66 52.483-34.782 61.284z"],bolt:[320,512,[],"f0e7","M295.973 160H180.572L215.19 30.184C219.25 14.956 207.756 0 192 0H56C43.971 0 33.8 8.905 32.211 20.828l-31.996 240C-1.704 275.217 9.504 288 24.004 288h118.701L96.646 482.466C93.05 497.649 104.659 512 119.992 512c8.35 0 16.376-4.374 20.778-11.978l175.973-303.997c9.244-15.967-2.288-36.025-20.77-36.025z"],bomb:[512,512,[],"f1e2","M440.5 88.5l-52 52L415 167c9.4 9.4 9.4 24.6 0 33.9l-17.4 17.4c11.8 26.1 18.4 55.1 18.4 85.6 0 114.9-93.1 208-208 208S0 418.9 0 304 93.1 96 208 96c30.5 0 59.5 6.6 85.6 18.4L311 97c9.4-9.4 24.6-9.4 33.9 0l26.5 26.5 52-52 17.1 17zM500 60h-24c-6.6 0-12 5.4-12 12s5.4 12 12 12h24c6.6 0 12-5.4 12-12s-5.4-12-12-12zM440 0c-6.6 0-12 5.4-12 12v24c0 6.6 5.4 12 12 12s12-5.4 12-12V12c0-6.6-5.4-12-12-12zm33.9 55l17-17c4.7-4.7 4.7-12.3 0-17-4.7-4.7-12.3-4.7-17 0l-17 17c-4.7 4.7-4.7 12.3 0 17 4.8 4.7 12.4 4.7 17 0zm-67.8 0c4.7 4.7 12.3 4.7 17 0 4.7-4.7 4.7-12.3 0-17l-17-17c-4.7-4.7-12.3-4.7-17 0-4.7 4.7-4.7 12.3 0 17l17 17zm67.8 34c-4.7-4.7-12.3-4.7-17 0-4.7 4.7-4.7 12.3 0 17l17 17c4.7 4.7 12.3 4.7 17 0 4.7-4.7 4.7-12.3 0-17l-17-17zM112 272c0-35.3 28.7-64 64-64 8.8 0 16-7.2 16-16s-7.2-16-16-16c-52.9 0-96 43.1-96 96 0 8.8 7.2 16 16 16s16-7.2 16-16z"],book:[448,512,[],"f02d","M448 360V24c0-13.3-10.7-24-24-24H96C43 0 0 43 0 96v320c0 53 43 96 96 96h328c13.3 0 24-10.7 24-24v-16c0-7.5-3.5-14.3-8.9-18.7-4.2-15.4-4.2-59.3 0-74.7 5.4-4.3 8.9-11.1 8.9-18.6zM128 134c0-3.3 2.7-6 6-6h212c3.3 0 6 2.7 6 6v20c0 3.3-2.7 6-6 6H134c-3.3 0-6-2.7-6-6v-20zm0 64c0-3.3 2.7-6 6-6h212c3.3 0 6 2.7 6 6v20c0 3.3-2.7 6-6 6H134c-3.3 0-6-2.7-6-6v-20zm253.4 250H96c-17.7 0-32-14.3-32-32 0-17.6 14.4-32 32-32h285.4c-1.9 17.1-1.9 46.9 0 64z"],bookmark:[384,512,[],"f02e","M0 512V48C0 21.49 21.49 0 48 0h288c26.51 0 48 21.49 48 48v464L192 400 0 512z"],braille:[640,512,[],"f2a1","M128 256c0 35.346-28.654 64-64 64S0 291.346 0 256s28.654-64 64-64 64 28.654 64 64zM64 384c-17.673 0-32 14.327-32 32s14.327 32 32 32 32-14.327 32-32-14.327-32-32-32zm0-352C28.654 32 0 60.654 0 96s28.654 64 64 64 64-28.654 64-64-28.654-64-64-64zm160 192c-17.673 0-32 14.327-32 32s14.327 32 32 32 32-14.327 32-32-14.327-32-32-32zm0 160c-17.673 0-32 14.327-32 32s14.327 32 32 32 32-14.327 32-32-14.327-32-32-32zm0-352c-35.346 0-64 28.654-64 64s28.654 64 64 64 64-28.654 64-64-28.654-64-64-64zm224 192c-17.673 0-32 14.327-32 32s14.327 32 32 32 32-14.327 32-32-14.327-32-32-32zm0 160c-17.673 0-32 14.327-32 32s14.327 32 32 32 32-14.327 32-32-14.327-32-32-32zm0-352c-35.346 0-64 28.654-64 64s28.654 64 64 64 64-28.654 64-64-28.654-64-64-64zm160 192c-17.673 0-32 14.327-32 32s14.327 32 32 32 32-14.327 32-32-14.327-32-32-32zm0 160c-17.673 0-32 14.327-32 32s14.327 32 32 32 32-14.327 32-32-14.327-32-32-32zm0-320c-17.673 0-32 14.327-32 32s14.327 32 32 32 32-14.327 32-32-14.327-32-32-32z"],briefcase:[512,512,[],"f0b1","M320 288h192v144c0 26.51-21.49 48-48 48H48c-26.51 0-48-21.49-48-48V288h192v20c0 6.627 5.373 12 12 12h104c6.627 0 12-5.373 12-12v-20zm192-112v80H0v-80c0-26.51 21.49-48 48-48h80V80c0-26.51 21.49-48 48-48h160c26.51 0 48 21.49 48 48v48h80c26.51 0 48 21.49 48 48zM320 96H192v32h128V96z"],bug:[512,512,[],"f188","M511.988 288.9c-.478 17.43-15.217 31.1-32.653 31.1H424v16c0 21.864-4.882 42.584-13.6 61.145l60.228 60.228c12.496 12.497 12.496 32.758 0 45.255-12.498 12.497-32.759 12.496-45.256 0l-54.736-54.736C345.886 467.965 314.351 480 280 480V236c0-6.627-5.373-12-12-12h-24c-6.627 0-12 5.373-12 12v244c-34.351 0-65.886-12.035-90.636-32.108l-54.736 54.736c-12.498 12.497-32.759 12.496-45.256 0-12.496-12.497-12.496-32.758 0-45.255l60.228-60.228C92.882 378.584 88 357.864 88 336v-16H32.666C15.23 320 .491 306.33.013 288.9-.484 270.816 14.028 256 32 256h56v-58.745l-46.628-46.628c-12.496-12.497-12.496-32.758 0-45.255 12.498-12.497 32.758-12.497 45.256 0L141.255 160h229.489l54.627-54.627c12.498-12.497 32.758-12.497 45.256 0 12.496 12.497 12.496 32.758 0 45.255L424 197.255V256h56c17.972 0 32.484 14.816 31.988 32.9zM257 0c-61.856 0-112 50.144-112 112h224C369 50.144 318.856 0 257 0z"],building:[448,512,[],"f1ad","M436 480h-20V24c0-13.255-10.745-24-24-24H56C42.745 0 32 10.745 32 24v456H12c-6.627 0-12 5.373-12 12v20h448v-20c0-6.627-5.373-12-12-12zM128 76c0-6.627 5.373-12 12-12h40c6.627 0 12 5.373 12 12v40c0 6.627-5.373 12-12 12h-40c-6.627 0-12-5.373-12-12V76zm0 96c0-6.627 5.373-12 12-12h40c6.627 0 12 5.373 12 12v40c0 6.627-5.373 12-12 12h-40c-6.627 0-12-5.373-12-12v-40zm52 148h-40c-6.627 0-12-5.373-12-12v-40c0-6.627 5.373-12 12-12h40c6.627 0 12 5.373 12 12v40c0 6.627-5.373 12-12 12zm76 160h-64v-84c0-6.627 5.373-12 12-12h40c6.627 0 12 5.373 12 12v84zm64-172c0 6.627-5.373 12-12 12h-40c-6.627 0-12-5.373-12-12v-40c0-6.627 5.373-12 12-12h40c6.627 0 12 5.373 12 12v40zm0-96c0 6.627-5.373 12-12 12h-40c-6.627 0-12-5.373-12-12v-40c0-6.627 5.373-12 12-12h40c6.627 0 12 5.373 12 12v40zm0-96c0 6.627-5.373 12-12 12h-40c-6.627 0-12-5.373-12-12V76c0-6.627 5.373-12 12-12h40c6.627 0 12 5.373 12 12v40z"],bullhorn:[576,512,[],"f0a1","M576 224c0-20.896-13.36-38.666-32-45.258V64c0-35.346-28.654-64-64-64-64.985 56-142.031 128-272 128H48c-26.51 0-48 21.49-48 48v96c0 26.51 21.49 48 48 48h43.263c-18.742 64.65 2.479 116.379 18.814 167.44 1.702 5.32 5.203 9.893 9.922 12.88 20.78 13.155 68.355 15.657 93.773 5.151 16.046-6.633 19.96-27.423 7.522-39.537-18.508-18.026-30.136-36.91-19.795-60.858a12.278 12.278 0 0 0-1.045-11.673c-16.309-24.679-3.581-62.107 28.517-72.752C346.403 327.887 418.591 395.081 480 448c35.346 0 64-28.654 64-64V269.258c18.64-6.592 32-24.362 32-45.258zm-96 139.855c-54.609-44.979-125.033-92.94-224-104.982v-69.747c98.967-12.042 169.391-60.002 224-104.982v279.711z"],bullseye:[512,512,[],"f140","M256 72c101.689 0 184 82.295 184 184 0 101.689-82.295 184-184 184-101.689 0-184-82.295-184-184 0-101.689 82.295-184 184-184m0-64C119.033 8 8 119.033 8 256s111.033 248 248 248 248-111.033 248-248S392.967 8 256 8zm0 184c35.29 0 64 28.71 64 64s-28.71 64-64 64-64-28.71-64-64 28.71-64 64-64m0-64c-70.692 0-128 57.308-128 128s57.308 128 128 128 128-57.308 128-128-57.308-128-128-128z"],bus:[512,512,[],"f207","M512 152v80c0 13.255-10.745 24-24 24h-8v168c0 13.255-10.745 24-24 24h-8v40c0 13.255-10.745 24-24 24h-48c-13.255 0-24-10.745-24-24v-40H160v40c0 13.255-10.745 24-24 24H88c-13.255 0-24-10.745-24-24v-40h-8c-13.255 0-24-10.745-24-24V256h-8c-13.255 0-24-10.745-24-24v-80c0-13.255 10.745-24 24-24h8V80C32 35.817 132.288 0 256 0s224 35.817 224 80v48h8c13.255 0 24 10.745 24 24zM112 320c-22.091 0-40 17.909-40 40s17.909 40 40 40 40-17.909 40-40-17.909-40-40-40zm288 0c-22.091 0-40 17.909-40 40s17.909 40 40 40 40-17.909 40-40-17.909-40-40-40zm32-56V120c0-13.255-10.745-24-24-24H104c-13.255 0-24 10.745-24 24v144c0 13.255 10.745 24 24 24h304c13.255 0 24-10.745 24-24z"],calculator:[448,512,[],"f1ec","M0 464V48C0 21.49 21.49 0 48 0h352c26.51 0 48 21.49 48 48v416c0 26.51-21.49 48-48 48H48c-26.51 0-48-21.49-48-48zm384-284V76c0-6.627-5.373-12-12-12H76c-6.627 0-12 5.373-12 12v104c0 6.627 5.373 12 12 12h296c6.627 0 12-5.373 12-12zM128 308v-40c0-6.627-5.373-12-12-12H76c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm256 128V268c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v168c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm-256 0v-40c0-6.627-5.373-12-12-12H76c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm128-128v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm0 128v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12z"],calendar:[448,512,[],"f133","M12 192h424c6.6 0 12 5.4 12 12v260c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V204c0-6.6 5.4-12 12-12zm436-44v-36c0-26.5-21.5-48-48-48h-48V12c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v52H160V12c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v52H48C21.5 64 0 85.5 0 112v36c0 6.6 5.4 12 12 12h424c6.6 0 12-5.4 12-12z"],"calendar-alt":[448,512,[],"f073","M436 160H12c-6.6 0-12-5.4-12-12v-36c0-26.5 21.5-48 48-48h48V12c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v52h128V12c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v52h48c26.5 0 48 21.5 48 48v36c0 6.6-5.4 12-12 12zM12 192h424c6.6 0 12 5.4 12 12v260c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V204c0-6.6 5.4-12 12-12zm116 204c0-6.6-5.4-12-12-12H76c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12v-40zm0-128c0-6.6-5.4-12-12-12H76c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12v-40zm128 128c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12v-40zm0-128c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12v-40zm128 128c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12v-40zm0-128c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12v-40z"],"calendar-check":[448,512,[],"f274","M436 160H12c-6.627 0-12-5.373-12-12v-36c0-26.51 21.49-48 48-48h48V12c0-6.627 5.373-12 12-12h40c6.627 0 12 5.373 12 12v52h128V12c0-6.627 5.373-12 12-12h40c6.627 0 12 5.373 12 12v52h48c26.51 0 48 21.49 48 48v36c0 6.627-5.373 12-12 12zM12 192h424c6.627 0 12 5.373 12 12v260c0 26.51-21.49 48-48 48H48c-26.51 0-48-21.49-48-48V204c0-6.627 5.373-12 12-12zm333.296 95.947l-28.169-28.398c-4.667-4.705-12.265-4.736-16.97-.068L194.12 364.665l-45.98-46.352c-4.667-4.705-12.266-4.736-16.971-.068l-28.397 28.17c-4.705 4.667-4.736 12.265-.068 16.97l82.601 83.269c4.667 4.705 12.265 4.736 16.97.068l142.953-141.805c4.705-4.667 4.736-12.265.068-16.97z"],"calendar-minus":[448,512,[],"f272","M436 160H12c-6.6 0-12-5.4-12-12v-36c0-26.5 21.5-48 48-48h48V12c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v52h128V12c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v52h48c26.5 0 48 21.5 48 48v36c0 6.6-5.4 12-12 12zM12 192h424c6.6 0 12 5.4 12 12v260c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V204c0-6.6 5.4-12 12-12zm304 192c6.6 0 12-5.4 12-12v-40c0-6.6-5.4-12-12-12H132c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h184z"],"calendar-plus":[448,512,[],"f271","M436 160H12c-6.6 0-12-5.4-12-12v-36c0-26.5 21.5-48 48-48h48V12c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v52h128V12c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v52h48c26.5 0 48 21.5 48 48v36c0 6.6-5.4 12-12 12zM12 192h424c6.6 0 12 5.4 12 12v260c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V204c0-6.6 5.4-12 12-12zm316 140c0-6.6-5.4-12-12-12h-60v-60c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v60h-60c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h60v60c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12v-60h60c6.6 0 12-5.4 12-12v-40z"],"calendar-times":[448,512,[],"f273","M436 160H12c-6.6 0-12-5.4-12-12v-36c0-26.5 21.5-48 48-48h48V12c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v52h128V12c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v52h48c26.5 0 48 21.5 48 48v36c0 6.6-5.4 12-12 12zM12 192h424c6.6 0 12 5.4 12 12v260c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V204c0-6.6 5.4-12 12-12zm257.3 160l48.1-48.1c4.7-4.7 4.7-12.3 0-17l-28.3-28.3c-4.7-4.7-12.3-4.7-17 0L224 306.7l-48.1-48.1c-4.7-4.7-12.3-4.7-17 0l-28.3 28.3c-4.7 4.7-4.7 12.3 0 17l48.1 48.1-48.1 48.1c-4.7 4.7-4.7 12.3 0 17l28.3 28.3c4.7 4.7 12.3 4.7 17 0l48.1-48.1 48.1 48.1c4.7 4.7 12.3 4.7 17 0l28.3-28.3c4.7-4.7 4.7-12.3 0-17L269.3 352z"],camera:[512,512,[],"f030","M512 144v288c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V144c0-26.5 21.5-48 48-48h88l12.3-32.9c7-18.7 24.9-31.1 44.9-31.1h125.5c20 0 37.9 12.4 44.9 31.1L376 96h88c26.5 0 48 21.5 48 48zM376 288c0-66.2-53.8-120-120-120s-120 53.8-120 120 53.8 120 120 120 120-53.8 120-120zm-32 0c0 48.5-39.5 88-88 88s-88-39.5-88-88 39.5-88 88-88 88 39.5 88 88z"],"camera-retro":[512,512,[],"f083","M48 32C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h416c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48H48zm0 32h106c3.3 0 6 2.7 6 6v20c0 3.3-2.7 6-6 6H38c-3.3 0-6-2.7-6-6V80c0-8.8 7.2-16 16-16zm426 96H38c-3.3 0-6-2.7-6-6v-36c0-3.3 2.7-6 6-6h138l30.2-45.3c1.1-1.7 3-2.7 5-2.7H464c8.8 0 16 7.2 16 16v74c0 3.3-2.7 6-6 6zM256 424c-66.2 0-120-53.8-120-120s53.8-120 120-120 120 53.8 120 120-53.8 120-120 120zm0-208c-48.5 0-88 39.5-88 88s39.5 88 88 88 88-39.5 88-88-39.5-88-88-88zm-48 104c-8.8 0-16-7.2-16-16 0-35.3 28.7-64 64-64 8.8 0 16 7.2 16 16s-7.2 16-16 16c-17.6 0-32 14.4-32 32 0 8.8-7.2 16-16 16z"],car:[512,512,[],"f1b9","M499.991 168h-54.815l-7.854-20.944c-9.192-24.513-25.425-45.351-46.942-60.263S343.651 64 317.472 64H194.528c-26.18 0-51.391 7.882-72.908 22.793-21.518 14.912-37.75 35.75-46.942 60.263L66.824 168H12.009c-8.191 0-13.974 8.024-11.384 15.795l8 24A12 12 0 0 0 20.009 216h28.815l-.052.14C29.222 227.093 16 247.997 16 272v48c0 16.225 6.049 31.029 16 42.309V424c0 13.255 10.745 24 24 24h48c13.255 0 24-10.745 24-24v-40h256v40c0 13.255 10.745 24 24 24h48c13.255 0 24-10.745 24-24v-61.691c9.951-11.281 16-26.085 16-42.309v-48c0-24.003-13.222-44.907-32.772-55.86l-.052-.14h28.815a12 12 0 0 0 11.384-8.205l8-24c2.59-7.771-3.193-15.795-11.384-15.795zm-365.388 1.528C143.918 144.689 168 128 194.528 128h122.944c26.528 0 50.61 16.689 59.925 41.528L391.824 208H120.176l14.427-38.472zM88 328c-17.673 0-32-14.327-32-32 0-17.673 14.327-32 32-32s48 30.327 48 48-30.327 16-48 16zm336 0c-17.673 0-48 1.673-48-16 0-17.673 30.327-48 48-48s32 14.327 32 32c0 17.673-14.327 32-32 32z"],"caret-down":[320,512,[],"f0d7","M31.3 192h257.3c17.8 0 26.7 21.5 14.1 34.1L174.1 354.8c-7.8 7.8-20.5 7.8-28.3 0L17.2 226.1C4.6 213.5 13.5 192 31.3 192z"],"caret-left":[192,512,[],"f0d9","M192 127.338v257.324c0 17.818-21.543 26.741-34.142 14.142L29.196 270.142c-7.81-7.81-7.81-20.474 0-28.284l128.662-128.662c12.599-12.6 34.142-3.676 34.142 14.142z"],"caret-right":[192,512,[],"f0da","M0 384.662V127.338c0-17.818 21.543-26.741 34.142-14.142l128.662 128.662c7.81 7.81 7.81 20.474 0 28.284L34.142 398.804C21.543 411.404 0 402.48 0 384.662z"],"caret-square-down":[448,512,[],"f150","M448 80v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V80c0-26.5 21.5-48 48-48h352c26.5 0 48 21.5 48 48zM92.5 220.5l123 123c4.7 4.7 12.3 4.7 17 0l123-123c7.6-7.6 2.2-20.5-8.5-20.5H101c-10.7 0-16.1 12.9-8.5 20.5z"],"caret-square-left":[448,512,[],"f191","M400 480H48c-26.51 0-48-21.49-48-48V80c0-26.51 21.49-48 48-48h352c26.51 0 48 21.49 48 48v352c0 26.51-21.49 48-48 48zM259.515 124.485l-123.03 123.03c-4.686 4.686-4.686 12.284 0 16.971l123.029 123.029c7.56 7.56 20.485 2.206 20.485-8.485V132.971c.001-10.691-12.925-16.045-20.484-8.486z"],"caret-square-right":[448,512,[],"f152","M48 32h352c26.51 0 48 21.49 48 48v352c0 26.51-21.49 48-48 48H48c-26.51 0-48-21.49-48-48V80c0-26.51 21.49-48 48-48zm140.485 355.515l123.029-123.029c4.686-4.686 4.686-12.284 0-16.971l-123.029-123.03c-7.56-7.56-20.485-2.206-20.485 8.485v246.059c0 10.691 12.926 16.045 20.485 8.486z"],"caret-square-up":[448,512,[],"f151","M0 432V80c0-26.51 21.49-48 48-48h352c26.51 0 48 21.49 48 48v352c0 26.51-21.49 48-48 48H48c-26.51 0-48-21.49-48-48zm355.515-140.485l-123.03-123.03c-4.686-4.686-12.284-4.686-16.971 0L92.485 291.515c-7.56 7.56-2.206 20.485 8.485 20.485h246.059c10.691 0 16.045-12.926 8.486-20.485z"],"caret-up":[320,512,[],"f0d8","M288.662 352H31.338c-17.818 0-26.741-21.543-14.142-34.142l128.662-128.662c7.81-7.81 20.474-7.81 28.284 0l128.662 128.662c12.6 12.599 3.676 34.142-14.142 34.142z"],"cart-arrow-down":[576,512,[],"f218","M504.717 320H211.572l6.545 32h268.418c15.401 0 26.816 14.301 23.403 29.319l-5.517 24.276C523.112 414.668 536 433.828 536 456c0 31.202-25.519 56.444-56.824 55.994-29.823-.429-54.35-24.631-55.155-54.447-.44-16.287 6.085-31.049 16.803-41.548H231.176C241.553 426.165 248 440.326 248 456c0 31.813-26.528 57.431-58.67 55.938-28.54-1.325-51.751-24.385-53.251-52.917-1.158-22.034 10.436-41.455 28.051-51.586L93.883 64H24C10.745 64 0 53.255 0 40V24C0 10.745 10.745 0 24 0h102.529c11.401 0 21.228 8.021 23.513 19.19L159.208 64H551.99c15.401 0 26.816 14.301 23.403 29.319l-47.273 208C525.637 312.246 515.923 320 504.717 320zM403.029 192H360v-60c0-6.627-5.373-12-12-12h-24c-6.627 0-12 5.373-12 12v60h-43.029c-10.691 0-16.045 12.926-8.485 20.485l67.029 67.029c4.686 4.686 12.284 4.686 16.971 0l67.029-67.029c7.559-7.559 2.205-20.485-8.486-20.485z"],"cart-plus":[576,512,[],"f217","M504.717 320H211.572l6.545 32h268.418c15.401 0 26.816 14.301 23.403 29.319l-5.517 24.276C523.112 414.668 536 433.828 536 456c0 31.202-25.519 56.444-56.824 55.994-29.823-.429-54.35-24.631-55.155-54.447-.44-16.287 6.085-31.049 16.803-41.548H231.176C241.553 426.165 248 440.326 248 456c0 31.813-26.528 57.431-58.67 55.938-28.54-1.325-51.751-24.385-53.251-52.917-1.158-22.034 10.436-41.455 28.051-51.586L93.883 64H24C10.745 64 0 53.255 0 40V24C0 10.745 10.745 0 24 0h102.529c11.401 0 21.228 8.021 23.513 19.19L159.208 64H551.99c15.401 0 26.816 14.301 23.403 29.319l-47.273 208C525.637 312.246 515.923 320 504.717 320zM408 168h-48v-40c0-8.837-7.163-16-16-16h-16c-8.837 0-16 7.163-16 16v40h-48c-8.837 0-16 7.163-16 16v16c0 8.837 7.163 16 16 16h48v40c0 8.837 7.163 16 16 16h16c8.837 0 16-7.163 16-16v-40h48c8.837 0 16-7.163 16-16v-16c0-8.837-7.163-16-16-16z"],certificate:[512,512,[],"f0a3","M458.622 255.92l45.985-45.005c13.708-12.977 7.316-36.039-10.664-40.339l-62.65-15.99 17.661-62.015c4.991-17.838-11.829-34.663-29.661-29.671l-61.994 17.667-15.984-62.671C337.085.197 313.765-6.276 300.99 7.228L256 53.57 211.011 7.229c-12.63-13.351-36.047-7.234-40.325 10.668l-15.984 62.671-61.995-17.667C74.87 57.907 58.056 74.738 63.046 92.572l17.661 62.015-62.65 15.99C.069 174.878-6.31 197.944 7.392 210.915l45.985 45.005-45.985 45.004c-13.708 12.977-7.316 36.039 10.664 40.339l62.65 15.99-17.661 62.015c-4.991 17.838 11.829 34.663 29.661 29.671l61.994-17.667 15.984 62.671c4.439 18.575 27.696 24.018 40.325 10.668L256 458.61l44.989 46.001c12.5 13.488 35.987 7.486 40.325-10.668l15.984-62.671 61.994 17.667c17.836 4.994 34.651-11.837 29.661-29.671l-17.661-62.015 62.65-15.99c17.987-4.302 24.366-27.367 10.664-40.339l-45.984-45.004z"],"chart-area":[512,512,[],"f1fe","M500 384c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12H12c-6.6 0-12-5.4-12-12V76c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v308h436zM372.7 159.5L288 216l-85.3-113.7c-5.1-6.8-15.5-6.3-19.9 1L96 248v104h384l-89.9-187.8c-3.2-6.5-11.4-8.7-17.4-4.7z"],"chart-bar":[512,512,[],"f080","M500 384c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12H12c-6.6 0-12-5.4-12-12V76c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v308h436zm-308-44v-72c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v72c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12zm192 0V204c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v136c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12zm-96 0V140c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v200c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12zm192 0V108c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v232c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12z"],"chart-line":[512,512,[],"f201","M500 384c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12H12c-6.6 0-12-5.4-12-12V76c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v308h436zM456 96H344c-21.4 0-32.1 25.9-17 41l32.9 32.9-72 72.9-55.6-55.6c-4.7-4.7-12.2-4.7-16.9 0L96.4 305c-4.7 4.6-4.8 12.2-.2 16.9l28.5 29.4c4.7 4.8 12.4 4.9 17.1.1l82.1-82.1 55.5 55.5c4.7 4.7 12.3 4.7 17 0l109.2-109.2L439 249c15.1 15.1 41 4.4 41-17V120c0-13.3-10.7-24-24-24z"],"chart-pie":[576,512,[],"f200","M288 12.3V240h227.7c6.9 0 12.3-5.8 12-12.7-6.4-122.4-104.5-220.6-227-227-6.9-.3-12.7 5.1-12.7 12zM552.7 288c6.9 0 12.3 5.8 12 12.7-2.8 53.2-23.2 105.6-61.2 147.8-4.6 5.1-12.6 5.4-17.5.5L325 288h227.7zM401 433c4.8 4.8 4.7 12.8-.4 17.3-42.6 38.4-99 61.7-160.8 61.7C107.6 511.9-.2 403.8 0 271.5.2 143.4 100.8 38.9 227.3 32.3c6.9-.4 12.7 5.1 12.7 12V272l161 161z"],check:[512,512,[],"f00c","M173.898 439.404l-166.4-166.4c-9.997-9.997-9.997-26.206 0-36.204l36.203-36.204c9.997-9.998 26.207-9.998 36.204 0L192 312.69 432.095 72.596c9.997-9.997 26.207-9.997 36.204 0l36.203 36.204c9.997 9.997 9.997 26.206 0 36.204l-294.4 294.401c-9.998 9.997-26.207 9.997-36.204-.001z"],"check-circle":[512,512,[],"f058","M504 256c0 136.967-111.033 248-248 248S8 392.967 8 256 119.033 8 256 8s248 111.033 248 248zM227.314 387.314l184-184c6.248-6.248 6.248-16.379 0-22.627l-22.627-22.627c-6.248-6.249-16.379-6.249-22.628 0L216 308.118l-70.059-70.059c-6.248-6.248-16.379-6.248-22.628 0l-22.627 22.627c-6.248 6.248-6.248 16.379 0 22.627l104 104c6.249 6.249 16.379 6.249 22.628.001z"],"check-square":[448,512,[],"f14a","M400 480H48c-26.51 0-48-21.49-48-48V80c0-26.51 21.49-48 48-48h352c26.51 0 48 21.49 48 48v352c0 26.51-21.49 48-48 48zm-204.686-98.059l184-184c6.248-6.248 6.248-16.379 0-22.627l-22.627-22.627c-6.248-6.248-16.379-6.249-22.628 0L184 302.745l-70.059-70.059c-6.248-6.248-16.379-6.248-22.628 0l-22.627 22.627c-6.248 6.248-6.248 16.379 0 22.627l104 104c6.249 6.25 16.379 6.25 22.628.001z"],"chevron-circle-down":[512,512,[],"f13a","M504 256c0 137-111 248-248 248S8 393 8 256 119 8 256 8s248 111 248 248zM273 369.9l135.5-135.5c9.4-9.4 9.4-24.6 0-33.9l-17-17c-9.4-9.4-24.6-9.4-33.9 0L256 285.1 154.4 183.5c-9.4-9.4-24.6-9.4-33.9 0l-17 17c-9.4 9.4-9.4 24.6 0 33.9L239 369.9c9.4 9.4 24.6 9.4 34 0z"],"chevron-circle-left":[512,512,[],"f137","M256 504C119 504 8 393 8 256S119 8 256 8s248 111 248 248-111 248-248 248zM142.1 273l135.5 135.5c9.4 9.4 24.6 9.4 33.9 0l17-17c9.4-9.4 9.4-24.6 0-33.9L226.9 256l101.6-101.6c9.4-9.4 9.4-24.6 0-33.9l-17-17c-9.4-9.4-24.6-9.4-33.9 0L142.1 239c-9.4 9.4-9.4 24.6 0 34z"],"chevron-circle-right":[512,512,[],"f138","M256 8c137 0 248 111 248 248S393 504 256 504 8 393 8 256 119 8 256 8zm113.9 231L234.4 103.5c-9.4-9.4-24.6-9.4-33.9 0l-17 17c-9.4 9.4-9.4 24.6 0 33.9L285.1 256 183.5 357.6c-9.4 9.4-9.4 24.6 0 33.9l17 17c9.4 9.4 24.6 9.4 33.9 0L369.9 273c9.4-9.4 9.4-24.6 0-34z"],"chevron-circle-up":[512,512,[],"f139","M8 256C8 119 119 8 256 8s248 111 248 248-111 248-248 248S8 393 8 256zm231-113.9L103.5 277.6c-9.4 9.4-9.4 24.6 0 33.9l17 17c9.4 9.4 24.6 9.4 33.9 0L256 226.9l101.6 101.6c9.4 9.4 24.6 9.4 33.9 0l17-17c9.4-9.4 9.4-24.6 0-33.9L273 142.1c-9.4-9.4-24.6-9.4-34 0z"],"chevron-down":[448,512,[],"f078","M207.029 381.476L12.686 187.132c-9.373-9.373-9.373-24.569 0-33.941l22.667-22.667c9.357-9.357 24.522-9.375 33.901-.04L224 284.505l154.745-154.021c9.379-9.335 24.544-9.317 33.901.04l22.667 22.667c9.373 9.373 9.373 24.569 0 33.941L240.971 381.476c-9.373 9.372-24.569 9.372-33.942 0z"],"chevron-left":[320,512,[],"f053","M34.52 239.03L228.87 44.69c9.37-9.37 24.57-9.37 33.94 0l22.67 22.67c9.36 9.36 9.37 24.52.04 33.9L131.49 256l154.02 154.75c9.34 9.38 9.32 24.54-.04 33.9l-22.67 22.67c-9.37 9.37-24.57 9.37-33.94 0L34.52 272.97c-9.37-9.37-9.37-24.57 0-33.94z"],"chevron-right":[320,512,[],"f054","M285.476 272.971L91.132 467.314c-9.373 9.373-24.569 9.373-33.941 0l-22.667-22.667c-9.357-9.357-9.375-24.522-.04-33.901L188.505 256 34.484 101.255c-9.335-9.379-9.317-24.544.04-33.901l22.667-22.667c9.373-9.373 24.569-9.373 33.941 0L285.475 239.03c9.373 9.372 9.373 24.568.001 33.941z"],"chevron-up":[448,512,[],"f077","M240.971 130.524l194.343 194.343c9.373 9.373 9.373 24.569 0 33.941l-22.667 22.667c-9.357 9.357-24.522 9.375-33.901.04L224 227.495 69.255 381.516c-9.379 9.335-24.544 9.317-33.901-.04l-22.667-22.667c-9.373-9.373-9.373-24.569 0-33.941L207.03 130.525c9.372-9.373 24.568-9.373 33.941-.001z"],child:[384,512,[],"f1ae","M120 72c0-39.765 32.235-72 72-72s72 32.235 72 72c0 39.764-32.235 72-72 72s-72-32.236-72-72zm254.627 1.373c-12.496-12.497-32.758-12.497-45.254 0L242.745 160H141.254L54.627 73.373c-12.496-12.497-32.758-12.497-45.254 0-12.497 12.497-12.497 32.758 0 45.255L104 213.254V480c0 17.673 14.327 32 32 32h16c17.673 0 32-14.327 32-32V368h16v112c0 17.673 14.327 32 32 32h16c17.673 0 32-14.327 32-32V213.254l94.627-94.627c12.497-12.497 12.497-32.757 0-45.254z"],circle:[512,512,[],"f111","M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8z"],"circle-notch":[512,512,[],"f1ce","M288 39.056v16.659c0 10.804 7.281 20.159 17.686 23.066C383.204 100.434 440 171.518 440 256c0 101.689-82.295 184-184 184-101.689 0-184-82.295-184-184 0-84.47 56.786-155.564 134.312-177.219C216.719 75.874 224 66.517 224 55.712V39.064c0-15.709-14.834-27.153-30.046-23.234C86.603 43.482 7.394 141.206 8.003 257.332c.72 137.052 111.477 246.956 248.531 246.667C393.255 503.711 504 392.788 504 256c0-115.633-79.14-212.779-186.211-240.236C302.678 11.889 288 23.456 288 39.056z"],clipboard:[384,512,[],"f328","M384 112v352c0 26.51-21.49 48-48 48H48c-26.51 0-48-21.49-48-48V112c0-26.51 21.49-48 48-48h80c0-35.29 28.71-64 64-64s64 28.71 64 64h80c26.51 0 48 21.49 48 48zM192 40c-13.255 0-24 10.745-24 24s10.745 24 24 24 24-10.745 24-24-10.745-24-24-24m96 114v-20a6 6 0 0 0-6-6H102a6 6 0 0 0-6 6v20a6 6 0 0 0 6 6h180a6 6 0 0 0 6-6z"],clock:[512,512,[],"f017","M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm57.1 350.1L224.9 294c-3.1-2.3-4.9-5.9-4.9-9.7V116c0-6.6 5.4-12 12-12h48c6.6 0 12 5.4 12 12v137.7l63.5 46.2c5.4 3.9 6.5 11.4 2.6 16.8l-28.2 38.8c-3.9 5.3-11.4 6.5-16.8 2.6z"],clone:[512,512,[],"f24d","M464 0c26.51 0 48 21.49 48 48v288c0 26.51-21.49 48-48 48H176c-26.51 0-48-21.49-48-48V48c0-26.51 21.49-48 48-48h288M176 416c-44.112 0-80-35.888-80-80V128H48c-26.51 0-48 21.49-48 48v288c0 26.51 21.49 48 48 48h288c26.51 0 48-21.49 48-48v-48H176z"],"closed-captioning":[512,512,[],"f20a","M464 64H48C21.5 64 0 85.5 0 112v288c0 26.5 21.5 48 48 48h416c26.5 0 48-21.5 48-48V112c0-26.5-21.5-48-48-48zM218.1 287.7c2.8-2.5 7.1-2.1 9.2.9l19.5 27.7c1.7 2.4 1.5 5.6-.5 7.7-53.6 56.8-172.8 32.1-172.8-67.9 0-97.3 121.7-119.5 172.5-70.1 2.1 2 2.5 3.2 1 5.7l-17.5 30.5c-1.9 3.1-6.2 4-9.1 1.7-40.8-32-94.6-14.9-94.6 31.2.1 48 51.1 70.5 92.3 32.6zm190.4 0c2.8-2.5 7.1-2.1 9.2.9l19.5 27.7c1.7 2.4 1.5 5.6-.5 7.7-53.5 56.9-172.7 32.1-172.7-67.9 0-97.3 121.7-119.5 172.5-70.1 2.1 2 2.5 3.2 1 5.7L420 222.2c-1.9 3.1-6.2 4-9.1 1.7-40.8-32-94.6-14.9-94.6 31.2 0 48 51 70.5 92.2 32.6z"],cloud:[640,512,[],"f0c2","M537.585 226.56C541.725 215.836 544 204.184 544 192c0-53.019-42.981-96-96-96-19.729 0-38.065 5.954-53.316 16.159C367.042 64.248 315.288 32 256 32c-88.366 0-160 71.634-160 160 0 2.728.07 5.439.204 8.133C40.171 219.845 0 273.227 0 336c0 79.529 64.471 144 144 144h368c70.692 0 128-57.308 128-128 0-61.93-43.983-113.586-102.415-125.44z"],"cloud-download-alt":[640,512,[],"f381","M640 352c0 70.692-57.308 128-128 128H144C64.471 480 0 415.529 0 336c0-62.773 40.171-116.155 96.204-135.867A163.68 163.68 0 0 1 96 192c0-88.366 71.634-160 160-160 59.288 0 111.042 32.248 138.684 80.159C409.935 101.954 428.271 96 448 96c53.019 0 96 42.981 96 96 0 12.184-2.275 23.836-6.415 34.56C596.017 238.414 640 290.07 640 352zm-246.627-64H328V176c0-8.837-7.164-16-16-16h-48c-8.836 0-16 7.163-16 16v112h-65.373c-14.254 0-21.393 17.234-11.314 27.314l105.373 105.373c6.248 6.248 16.379 6.248 22.627 0l105.373-105.373c10.08-10.08 2.941-27.314-11.313-27.314z"],"cloud-upload-alt":[640,512,[],"f382","M640 352c0 70.692-57.308 128-128 128H144C64.471 480 0 415.529 0 336c0-62.773 40.171-116.155 96.204-135.867A163.68 163.68 0 0 1 96 192c0-88.366 71.634-160 160-160 59.288 0 111.042 32.248 138.684 80.159C409.935 101.954 428.271 96 448 96c53.019 0 96 42.981 96 96 0 12.184-2.275 23.836-6.415 34.56C596.017 238.414 640 290.07 640 352zm-235.314-91.314L299.314 155.314c-6.248-6.248-16.379-6.248-22.627 0L171.314 260.686c-10.08 10.08-2.941 27.314 11.313 27.314H248v112c0 8.837 7.164 16 16 16h48c8.836 0 16-7.163 16-16V288h65.373c14.254 0 21.393-17.234 11.313-27.314z"],code:[640,512,[],"f121","M278.9 511.5l-61-17.7c-6.4-1.8-10-8.5-8.2-14.9L346.2 8.7c1.8-6.4 8.5-10 14.9-8.2l61 17.7c6.4 1.8 10 8.5 8.2 14.9L293.8 503.3c-1.9 6.4-8.5 10.1-14.9 8.2zm-114-112.2l43.5-46.4c4.6-4.9 4.3-12.7-.8-17.2L117 256l90.6-79.7c5.1-4.5 5.5-12.3.8-17.2l-43.5-46.4c-4.5-4.8-12.1-5.1-17-.5L3.8 247.2c-5.1 4.7-5.1 12.8 0 17.5l144.1 135.1c4.9 4.6 12.5 4.4 17-.5zm327.2.6l144.1-135.1c5.1-4.7 5.1-12.8 0-17.5L492.1 112.1c-4.8-4.5-12.4-4.3-17 .5L431.6 159c-4.6 4.9-4.3 12.7.8 17.2L523 256l-90.6 79.7c-5.1 4.5-5.5 12.3-.8 17.2l43.5 46.4c4.5 4.9 12.1 5.1 17 .6z"],"code-branch":[384,512,[],"f126","M384 144c0-44.2-35.8-80-80-80s-80 35.8-80 80c0 36.4 24.3 67.1 57.5 76.8-.6 16.1-4.2 28.5-11 36.9-15.4 19.2-49.3 22.4-85.2 25.7-28.2 2.6-57.4 5.4-81.3 16.9v-144c32.5-10.2 56-40.5 56-76.3 0-44.2-35.8-80-80-80S0 35.8 0 80c0 35.8 23.5 66.1 56 76.3v199.3C23.5 365.9 0 396.2 0 432c0 44.2 35.8 80 80 80s80-35.8 80-80c0-34-21.2-63.1-51.2-74.6 3.1-5.2 7.8-9.8 14.9-13.4 16.2-8.2 40.4-10.4 66.1-12.8 42.2-3.9 90-8.4 118.2-43.4 14-17.4 21.1-39.8 21.6-67.9 31.6-10.8 54.4-40.7 54.4-75.9zM80 64c8.8 0 16 7.2 16 16s-7.2 16-16 16-16-7.2-16-16 7.2-16 16-16zm0 384c-8.8 0-16-7.2-16-16s7.2-16 16-16 16 7.2 16 16-7.2 16-16 16zm224-320c8.8 0 16 7.2 16 16s-7.2 16-16 16-16-7.2-16-16 7.2-16 16-16z"],coffee:[640,512,[],"f0f4","M192 384h192c53 0 96-43 96-96h32c70.6 0 128-57.4 128-128S582.6 32 512 32H120c-13.3 0-24 10.7-24 24v232c0 53 43 96 96 96zM512 96c35.3 0 64 28.7 64 64s-28.7 64-64 64h-32V96h32zm47.7 384H48.3c-47.6 0-61-64-36-64h583.3c25 0 11.8 64-35.9 64z"],cog:[512,512,[],"f013","M444.788 291.1l42.616 24.599c4.867 2.809 7.126 8.618 5.459 13.985-11.07 35.642-29.97 67.842-54.689 94.586a12.016 12.016 0 0 1-14.832 2.254l-42.584-24.595a191.577 191.577 0 0 1-60.759 35.13v49.182a12.01 12.01 0 0 1-9.377 11.718c-34.956 7.85-72.499 8.256-109.219.007-5.49-1.233-9.403-6.096-9.403-11.723v-49.184a191.555 191.555 0 0 1-60.759-35.13l-42.584 24.595a12.016 12.016 0 0 1-14.832-2.254c-24.718-26.744-43.619-58.944-54.689-94.586-1.667-5.366.592-11.175 5.459-13.985L67.212 291.1a193.48 193.48 0 0 1 0-70.199l-42.616-24.599c-4.867-2.809-7.126-8.618-5.459-13.985 11.07-35.642 29.97-67.842 54.689-94.586a12.016 12.016 0 0 1 14.832-2.254l42.584 24.595a191.577 191.577 0 0 1 60.759-35.13V25.759a12.01 12.01 0 0 1 9.377-11.718c34.956-7.85 72.499-8.256 109.219-.007 5.49 1.233 9.403 6.096 9.403 11.723v49.184a191.555 191.555 0 0 1 60.759 35.13l42.584-24.595a12.016 12.016 0 0 1 14.832 2.254c24.718 26.744 43.619 58.944 54.689 94.586 1.667 5.366-.592 11.175-5.459 13.985L444.788 220.9a193.485 193.485 0 0 1 0 70.2zM336 256c0-44.112-35.888-80-80-80s-80 35.888-80 80 35.888 80 80 80 80-35.888 80-80z"],cogs:[640,512,[],"f085","M512.1 191l-8.2 14.3c-3 5.3-9.4 7.5-15.1 5.4-11.8-4.4-22.6-10.7-32.1-18.6-4.6-3.8-5.8-10.5-2.8-15.7l8.2-14.3c-6.9-8-12.3-17.3-15.9-27.4h-16.5c-6 0-11.2-4.3-12.2-10.3-2-12-2.1-24.6 0-37.1 1-6 6.2-10.4 12.2-10.4h16.5c3.6-10.1 9-19.4 15.9-27.4l-8.2-14.3c-3-5.2-1.9-11.9 2.8-15.7 9.5-7.9 20.4-14.2 32.1-18.6 5.7-2.1 12.1.1 15.1 5.4l8.2 14.3c10.5-1.9 21.2-1.9 31.7 0L552 6.3c3-5.3 9.4-7.5 15.1-5.4 11.8 4.4 22.6 10.7 32.1 18.6 4.6 3.8 5.8 10.5 2.8 15.7l-8.2 14.3c6.9 8 12.3 17.3 15.9 27.4h16.5c6 0 11.2 4.3 12.2 10.3 2 12 2.1 24.6 0 37.1-1 6-6.2 10.4-12.2 10.4h-16.5c-3.6 10.1-9 19.4-15.9 27.4l8.2 14.3c3 5.2 1.9 11.9-2.8 15.7-9.5 7.9-20.4 14.2-32.1 18.6-5.7 2.1-12.1-.1-15.1-5.4l-8.2-14.3c-10.4 1.9-21.2 1.9-31.7 0zm-10.5-58.8c38.5 29.6 82.4-14.3 52.8-52.8-38.5-29.7-82.4 14.3-52.8 52.8zM386.3 286.1l33.7 16.8c10.1 5.8 14.5 18.1 10.5 29.1-8.9 24.2-26.4 46.4-42.6 65.8-7.4 8.9-20.2 11.1-30.3 5.3l-29.1-16.8c-16 13.7-34.6 24.6-54.9 31.7v33.6c0 11.6-8.3 21.6-19.7 23.6-24.6 4.2-50.4 4.4-75.9 0-11.5-2-20-11.9-20-23.6V418c-20.3-7.2-38.9-18-54.9-31.7L74 403c-10 5.8-22.9 3.6-30.3-5.3-16.2-19.4-33.3-41.6-42.2-65.7-4-10.9.4-23.2 10.5-29.1l33.3-16.8c-3.9-20.9-3.9-42.4 0-63.4L12 205.8c-10.1-5.8-14.6-18.1-10.5-29 8.9-24.2 26-46.4 42.2-65.8 7.4-8.9 20.2-11.1 30.3-5.3l29.1 16.8c16-13.7 34.6-24.6 54.9-31.7V57.1c0-11.5 8.2-21.5 19.6-23.5 24.6-4.2 50.5-4.4 76-.1 11.5 2 20 11.9 20 23.6v33.6c20.3 7.2 38.9 18 54.9 31.7l29.1-16.8c10-5.8 22.9-3.6 30.3 5.3 16.2 19.4 33.2 41.6 42.1 65.8 4 10.9.1 23.2-10 29.1l-33.7 16.8c3.9 21 3.9 42.5 0 63.5zm-117.6 21.1c59.2-77-28.7-164.9-105.7-105.7-59.2 77 28.7 164.9 105.7 105.7zm243.4 182.7l-8.2 14.3c-3 5.3-9.4 7.5-15.1 5.4-11.8-4.4-22.6-10.7-32.1-18.6-4.6-3.8-5.8-10.5-2.8-15.7l8.2-14.3c-6.9-8-12.3-17.3-15.9-27.4h-16.5c-6 0-11.2-4.3-12.2-10.3-2-12-2.1-24.6 0-37.1 1-6 6.2-10.4 12.2-10.4h16.5c3.6-10.1 9-19.4 15.9-27.4l-8.2-14.3c-3-5.2-1.9-11.9 2.8-15.7 9.5-7.9 20.4-14.2 32.1-18.6 5.7-2.1 12.1.1 15.1 5.4l8.2 14.3c10.5-1.9 21.2-1.9 31.7 0l8.2-14.3c3-5.3 9.4-7.5 15.1-5.4 11.8 4.4 22.6 10.7 32.1 18.6 4.6 3.8 5.8 10.5 2.8 15.7l-8.2 14.3c6.9 8 12.3 17.3 15.9 27.4h16.5c6 0 11.2 4.3 12.2 10.3 2 12 2.1 24.6 0 37.1-1 6-6.2 10.4-12.2 10.4h-16.5c-3.6 10.1-9 19.4-15.9 27.4l8.2 14.3c3 5.2 1.9 11.9-2.8 15.7-9.5 7.9-20.4 14.2-32.1 18.6-5.7 2.1-12.1-.1-15.1-5.4l-8.2-14.3c-10.4 1.9-21.2 1.9-31.7 0zM501.6 431c38.5 29.6 82.4-14.3 52.8-52.8-38.5-29.6-82.4 14.3-52.8 52.8z"],columns:[512,512,[],"f0db","M464 32H48C21.49 32 0 53.49 0 80v352c0 26.51 21.49 48 48 48h416c26.51 0 48-21.49 48-48V80c0-26.51-21.49-48-48-48zM224 416H64V160h160v256zm224 0H288V160h160v256z"],comment:[576,512,[],"f075","M576 240c0 115-129 208-288 208-48.3 0-93.9-8.6-133.9-23.8-40.3 31.2-89.8 50.3-142.4 55.7-5.2.6-10.2-2.8-11.5-7.7-1.3-5 2.7-8.1 6.6-11.8 19.3-18.4 42.7-32.8 51.9-94.6C21.9 330.9 0 287.3 0 240 0 125.1 129 32 288 32s288 93.1 288 208z"],"comment-alt":[576,512,[],"f27a","M576 240c0 115-129 208-288 208-48.3 0-93.9-8.6-133.9-23.8-40.3 31.2-89.8 50.3-142.4 55.7-5.2.6-10.2-2.8-11.5-7.7-1.3-5 2.7-8.1 6.6-11.8 19.3-18.4 42.7-32.8 51.9-94.6C21.9 330.9 0 287.3 0 240 0 125.1 129 32 288 32s288 93.1 288 208zm-416-48c-26.5 0-48 21.5-48 48s21.5 48 48 48 48-21.5 48-48-21.5-48-48-48zm128 0c-26.5 0-48 21.5-48 48s21.5 48 48 48 48-21.5 48-48-21.5-48-48-48zm128 0c-26.5 0-48 21.5-48 48s21.5 48 48 48 48-21.5 48-48-21.5-48-48-48z"],comments:[576,512,[],"f086","M224 358.857c-37.599 0-73.027-6.763-104.143-18.7-31.375 24.549-69.869 39.508-110.764 43.796a8.632 8.632 0 0 1-.89.047c-3.736 0-7.111-2.498-8.017-6.061-.98-3.961 2.088-6.399 5.126-9.305 15.017-14.439 33.222-25.79 40.342-74.297C17.015 266.886 0 232.622 0 195.429 0 105.16 100.297 32 224 32s224 73.159 224 163.429c-.001 90.332-100.297 163.428-224 163.428zm347.067 107.174c-13.944-13.127-30.849-23.446-37.46-67.543 68.808-64.568 52.171-156.935-37.674-207.065.031 1.334.066 2.667.066 4.006 0 122.493-129.583 216.394-284.252 211.222 38.121 30.961 93.989 50.492 156.252 50.492 34.914 0 67.811-6.148 96.704-17 29.134 22.317 64.878 35.916 102.853 39.814 3.786.395 7.363-1.973 8.27-5.467.911-3.601-1.938-5.817-4.759-8.459z"],compass:[512,512,[],"f14e","M504 256c0 136.967-111.033 248-248 248S8 392.967 8 256 119.033 8 256 8s248 111.033 248 248zM307.446 120.844l-102.642 97.779a23.997 23.997 0 0 0-6.772 11.729l-33.359 137.779c-5.68 23.459 22.777 39.318 39.88 23.024l102.64-97.779a23.99 23.99 0 0 0 6.772-11.729l33.359-137.779c5.618-23.198-22.591-39.493-39.878-23.024zM256 224c-17.673 0-32 14.327-32 32s14.327 32 32 32 32-14.327 32-32-14.327-32-32-32z"],compress:[448,512,[],"f066","M436 192H312c-13.3 0-24-10.7-24-24V44c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v84h84c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12zm-276-24V44c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v84H12c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h124c13.3 0 24-10.7 24-24zm0 300V344c0-13.3-10.7-24-24-24H12c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h84v84c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12zm192 0v-84h84c6.6 0 12-5.4 12-12v-40c0-6.6-5.4-12-12-12H312c-13.3 0-24 10.7-24 24v124c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12z"],copy:[448,512,[],"f0c5","M320 448v40c0 13.255-10.745 24-24 24H24c-13.255 0-24-10.745-24-24V120c0-13.255 10.745-24 24-24h72v296c0 30.879 25.121 56 56 56h168zm0-344V0H152c-13.255 0-24 10.745-24 24v368c0 13.255 10.745 24 24 24h272c13.255 0 24-10.745 24-24V128H344c-13.2 0-24-10.8-24-24zm120.971-31.029L375.029 7.029A24 24 0 0 0 358.059 0H352v96h96v-6.059a24 24 0 0 0-7.029-16.97z"],copyright:[512,512,[],"f1f9","M256 8C119.033 8 8 119.033 8 256s111.033 248 248 248 248-111.033 248-248S392.967 8 256 8zm117.134 346.753c-1.592 1.867-39.776 45.731-109.851 45.731-84.692 0-144.484-63.26-144.484-145.567 0-81.303 62.004-143.401 143.762-143.401 66.957 0 101.965 37.315 103.422 38.904a12 12 0 0 1 1.238 14.623l-22.38 34.655c-4.049 6.267-12.774 7.351-18.234 2.295-.233-.214-26.529-23.88-61.88-23.88-46.116 0-73.916 33.575-73.916 76.082 0 39.602 25.514 79.692 74.277 79.692 38.697 0 65.28-28.338 65.544-28.625 5.132-5.565 14.059-5.033 18.508 1.053l24.547 33.572a12.001 12.001 0 0 1-.553 14.866z"],"credit-card":[576,512,[],"f09d","M0 432c0 26.5 21.5 48 48 48h480c26.5 0 48-21.5 48-48V256H0v176zm192-68c0-6.6 5.4-12 12-12h136c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12H204c-6.6 0-12-5.4-12-12v-40zm-128 0c0-6.6 5.4-12 12-12h72c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12H76c-6.6 0-12-5.4-12-12v-40zM576 80v48H0V80c0-26.5 21.5-48 48-48h480c26.5 0 48 21.5 48 48z"],crop:[512,512,[],"f125","M488 352h-40V109.3l57-57c9.4-9.4 9.4-24.6 0-33.9L493.7 7c-9.4-9.4-24.6-9.4-33.9 0l-57 57H160V24c0-13.3-10.7-24-24-24H88C74.7 0 64 10.7 64 24v40H24C10.7 64 0 74.7 0 88v48c0 13.3 10.7 24 24 24h40v264c0 13.3 10.7 24 24 24h264v40c0 13.3 10.7 24 24 24h48c13.3 0 24-10.7 24-24v-40h40c13.3 0 24-10.7 24-24v-48c0-13.3-10.7-24-24-24zM306.7 160L160 306.7V160h146.7zM205.3 352L352 205.3V352H205.3z"],crosshairs:[512,512,[],"f05b","M500 224h-30.364C455.724 130.325 381.675 56.276 288 42.364V12c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v30.364C130.325 56.276 56.276 130.325 42.364 224H12c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h30.364C56.276 381.675 130.325 455.724 224 469.636V500c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12v-30.364C381.675 455.724 455.724 381.675 469.636 288H500c6.627 0 12-5.373 12-12v-40c0-6.627-5.373-12-12-12zM288 404.634V364c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40.634C165.826 392.232 119.783 346.243 107.366 288H148c6.627 0 12-5.373 12-12v-40c0-6.627-5.373-12-12-12h-40.634C119.768 165.826 165.757 119.783 224 107.366V148c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12v-40.634C346.174 119.768 392.217 165.757 404.634 224H364c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40.634C392.232 346.174 346.243 392.217 288 404.634zM288 256c0 17.673-14.327 32-32 32s-32-14.327-32-32c0-17.673 14.327-32 32-32s32 14.327 32 32z"],cube:[512,512,[],"f1b2","M239.1 6.3l-208 78c-18.7 7-31.1 25-31.1 45v225.1c0 18.2 10.3 34.8 26.5 42.9l208 104c13.5 6.8 29.4 6.8 42.9 0l208-104c16.3-8.1 26.5-24.8 26.5-42.9V129.3c0-20-12.4-37.9-31.1-44.9l-208-78C262 2.2 250 2.2 239.1 6.3zM256 68.4l192 72v1.1l-192 78-192-78v-1.1l192-72zm32 356V275.5l160-65v133.9l-160 80z"],cubes:[512,512,[],"f1b3","M488.6 250.2L392 214V105.5c0-15-9.3-28.4-23.4-33.7l-100-37.5c-8.1-3.1-17.1-3.1-25.3 0l-100 37.5c-14.1 5.3-23.4 18.7-23.4 33.7V214l-96.6 36.2C9.3 255.5 0 268.9 0 283.9V394c0 13.6 7.7 26.1 19.9 32.2l100 50c10.1 5.1 22.1 5.1 32.2 0l103.9-52 103.9 52c10.1 5.1 22.1 5.1 32.2 0l100-50c12.2-6.1 19.9-18.6 19.9-32.2V283.9c0-15-9.3-28.4-23.4-33.7zM358 214.8l-85 31.9v-68.2l85-37v73.3zM154 104.1l102-38.2 102 38.2v.6l-102 41.4-102-41.4v-.6zm84 291.1l-85 42.5v-79.1l85-38.8v75.4zm0-112l-102 41.4-102-41.4v-.6l102-38.2 102 38.2v.6zm240 112l-85 42.5v-79.1l85-38.8v75.4zm0-112l-102 41.4-102-41.4v-.6l102-38.2 102 38.2v.6z"],cut:[448,512,[],"f0c4","M444.485 422.426c4.689 4.689 4.684 12.287 0 16.971-32.804 32.804-85.991 32.804-118.795 0L210.176 323.883l-24.859 24.859C189.63 359.657 192 371.552 192 384c0 53.019-42.981 96-96 96S0 437.019 0 384s42.981-96 96-96c4.536 0 8.995.322 13.363.93l32.93-32.93-32.93-32.93c-4.368.608-8.827.93-13.363.93-53.019 0-96-42.981-96-96s42.981-96 96-96 96 42.981 96 96c0 12.448-2.37 24.343-6.682 35.258l24.859 24.859L325.69 72.603c32.804-32.804 85.991-32.804 118.795 0 4.684 4.684 4.689 12.282 0 16.971L278.059 256l166.426 166.426zM96 96c-17.645 0-32 14.355-32 32s14.355 32 32 32 32-14.355 32-32-14.355-32-32-32m0 256c-17.645 0-32 14.355-32 32s14.355 32 32 32 32-14.355 32-32-14.355-32-32-32m112-108c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12z"],database:[448,512,[],"f1c0","M448 73.143v45.714C448 159.143 347.667 192 224 192S0 159.143 0 118.857V73.143C0 32.857 100.333 0 224 0s224 32.857 224 73.143zM448 176v102.857C448 319.143 347.667 352 224 352S0 319.143 0 278.857V176c48.125 33.143 136.208 48.572 224 48.572S399.874 209.143 448 176zm0 160v102.857C448 479.143 347.667 512 224 512S0 479.143 0 438.857V336c48.125 33.143 136.208 48.572 224 48.572S399.874 369.143 448 336z"],deaf:[512,512,[],"f2a4","M216 260c0 15.464-12.536 28-28 28s-28-12.536-28-28c0-44.112 35.888-80 80-80s80 35.888 80 80c0 15.464-12.536 28-28 28s-28-12.536-28-28c0-13.234-10.767-24-24-24s-24 10.766-24 24zm24-176c-97.047 0-176 78.953-176 176 0 15.464 12.536 28 28 28s28-12.536 28-28c0-66.168 53.832-120 120-120s120 53.832 120 120c0 75.164-71.009 70.311-71.997 143.622L288 404c0 28.673-23.327 52-52 52-15.464 0-28 12.536-28 28s12.536 28 28 28c59.475 0 107.876-48.328 108-107.774.595-34.428 72-48.24 72-144.226 0-97.047-78.953-176-176-176zm268.485-52.201L480.2 3.515c-4.687-4.686-12.284-4.686-16.971 0L376.2 90.544c-4.686 4.686-4.686 12.284 0 16.971l28.285 28.285c4.686 4.686 12.284 4.686 16.97 0l87.03-87.029c4.687-4.688 4.687-12.286 0-16.972zM168.97 314.745c-4.686-4.686-12.284-4.686-16.97 0L3.515 463.23c-4.686 4.686-4.686 12.284 0 16.971L31.8 508.485c4.687 4.686 12.284 4.686 16.971 0L197.256 360c4.686-4.686 4.686-12.284 0-16.971l-28.286-28.284z"],desktop:[576,512,[],"f108","M528 0H48C21.5 0 0 21.5 0 48v320c0 26.5 21.5 48 48 48h192l-16 48h-72c-13.3 0-24 10.7-24 24s10.7 24 24 24h272c13.3 0 24-10.7 24-24s-10.7-24-24-24h-72l-16-48h192c26.5 0 48-21.5 48-48V48c0-26.5-21.5-48-48-48zm-16 352H64V64h448v288z"],"dollar-sign":[320,512,[],"f155","M113.411 169.375c0-23.337 21.536-38.417 54.865-38.417 26.726 0 54.116 12.263 76.461 28.333 5.88 4.229 14.13 2.354 17.575-4.017l23.552-43.549c2.649-4.898 1.596-10.991-2.575-14.68-24.281-21.477-59.135-34.09-91.289-37.806V12c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v49.832c-58.627 13.29-97.299 55.917-97.299 108.639 0 123.533 184.765 110.81 184.765 169.414 0 19.823-16.311 41.158-52.124 41.158-30.751 0-62.932-15.88-87.848-35.887-5.31-4.264-13.082-3.315-17.159 2.14l-30.389 40.667c-3.627 4.854-3.075 11.657 1.302 15.847 24.049 23.02 59.249 41.255 98.751 47.973V500c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12v-47.438c65.72-10.215 106.176-59.186 106.176-116.516.001-119.688-184.764-103.707-184.764-166.671z"],"dot-circle":[512,512,[],"f192","M256 8C119.033 8 8 119.033 8 256s111.033 248 248 248 248-111.033 248-248S392.967 8 256 8zm80 248c0 44.112-35.888 80-80 80s-80-35.888-80-80 35.888-80 80-80 80 35.888 80 80z"],download:[512,512,[],"f019","M216 0h80c13.3 0 24 10.7 24 24v168h87.7c17.8 0 26.7 21.5 14.1 34.1L269.7 378.3c-7.5 7.5-19.8 7.5-27.3 0L90.1 226.1c-12.6-12.6-3.7-34.1 14.1-34.1H192V24c0-13.3 10.7-24 24-24zm296 376v112c0 13.3-10.7 24-24 24H24c-13.3 0-24-10.7-24-24V376c0-13.3 10.7-24 24-24h146.7l49 49c20.1 20.1 52.5 20.1 72.6 0l49-49H488c13.3 0 24 10.7 24 24zm-124 88c0-11-9-20-20-20s-20 9-20 20 9 20 20 20 20-9 20-20zm64 0c0-11-9-20-20-20s-20 9-20 20 9 20 20 20 20-9 20-20z"],edit:[576,512,[],"f044","M402.6 83.2l90.2 90.2c3.8 3.8 3.8 10 0 13.8L274.4 405.6l-92.8 10.3c-12.4 1.4-22.9-9.1-21.5-21.5l10.3-92.8L388.8 83.2c3.8-3.8 10-3.8 13.8 0zm162-22.9l-48.8-48.8c-15.2-15.2-39.9-15.2-55.2 0l-35.4 35.4c-3.8 3.8-3.8 10 0 13.8l90.2 90.2c3.8 3.8 10 3.8 13.8 0l35.4-35.4c15.2-15.3 15.2-40 0-55.2zM384 346.2V448H64V128h229.8c3.2 0 6.2-1.3 8.5-3.5l40-40c7.6-7.6 2.2-20.5-8.5-20.5H48C21.5 64 0 85.5 0 112v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V306.2c0-10.7-12.9-16-20.5-8.5l-40 40c-2.2 2.3-3.5 5.3-3.5 8.5z"],eject:[448,512,[],"f052","M448 384v64c0 17.673-14.327 32-32 32H32c-17.673 0-32-14.327-32-32v-64c0-17.673 14.327-32 32-32h384c17.673 0 32 14.327 32 32zM48.053 320h351.886c41.651 0 63.581-49.674 35.383-80.435L259.383 47.558c-19.014-20.743-51.751-20.744-70.767 0L12.67 239.565C-15.475 270.268 6.324 320 48.053 320z"],"ellipsis-h":[512,512,[],"f141","M328 256c0 39.8-32.2 72-72 72s-72-32.2-72-72 32.2-72 72-72 72 32.2 72 72zm104-72c-39.8 0-72 32.2-72 72s32.2 72 72 72 72-32.2 72-72-32.2-72-72-72zm-352 0c-39.8 0-72 32.2-72 72s32.2 72 72 72 72-32.2 72-72-32.2-72-72-72z"],"ellipsis-v":[192,512,[],"f142","M96 184c39.8 0 72 32.2 72 72s-32.2 72-72 72-72-32.2-72-72 32.2-72 72-72zM24 80c0 39.8 32.2 72 72 72s72-32.2 72-72S135.8 8 96 8 24 40.2 24 80zm0 352c0 39.8 32.2 72 72 72s72-32.2 72-72-32.2-72-72-72-72 32.2-72 72z"],envelope:[512,512,[],"f0e0","M502.3 190.8c3.9-3.1 9.7-.2 9.7 4.7V400c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V195.6c0-5 5.7-7.8 9.7-4.7 22.4 17.4 52.1 39.5 154.1 113.6 21.1 15.4 56.7 47.8 92.2 47.6 35.7.3 72-32.8 92.3-47.6 102-74.1 131.6-96.3 154-113.7zM256 320c23.2.4 56.6-29.2 73.4-41.4 132.7-96.3 142.8-104.7 173.4-128.7 5.8-4.5 9.2-11.5 9.2-18.9v-19c0-26.5-21.5-48-48-48H48C21.5 64 0 85.5 0 112v19c0 7.4 3.4 14.3 9.2 18.9 30.6 23.9 40.7 32.4 173.4 128.7 16.8 12.2 50.2 41.8 73.4 41.4z"],"envelope-open":[512,512,[],"f2b6","M512 464c0 26.51-21.49 48-48 48H48c-26.51 0-48-21.49-48-48V200.724a48 48 0 0 1 18.387-37.776c24.913-19.529 45.501-35.365 164.2-121.511C199.412 29.17 232.797-.347 256 .003c23.198-.354 56.596 29.172 73.413 41.433 118.687 86.137 139.303 101.995 164.2 121.512A48 48 0 0 1 512 200.724V464zm-65.666-196.605c-2.563-3.728-7.7-4.595-11.339-1.907-22.845 16.873-55.462 40.705-105.582 77.079-16.825 12.266-50.21 41.781-73.413 41.43-23.211.344-56.559-29.143-73.413-41.43-50.114-36.37-82.734-60.204-105.582-77.079-3.639-2.688-8.776-1.821-11.339 1.907l-9.072 13.196a7.998 7.998 0 0 0 1.839 10.967c22.887 16.899 55.454 40.69 105.303 76.868 20.274 14.781 56.524 47.813 92.264 47.573 35.724.242 71.961-32.771 92.263-47.573 49.85-36.179 82.418-59.97 105.303-76.868a7.998 7.998 0 0 0 1.839-10.967l-9.071-13.196z"],"envelope-square":[448,512,[],"f199","M400 32H48C21.49 32 0 53.49 0 80v352c0 26.51 21.49 48 48 48h352c26.51 0 48-21.49 48-48V80c0-26.51-21.49-48-48-48zM178.117 262.104C87.429 196.287 88.353 196.121 64 177.167V152c0-13.255 10.745-24 24-24h272c13.255 0 24 10.745 24 24v25.167c-24.371 18.969-23.434 19.124-114.117 84.938-10.5 7.655-31.392 26.12-45.883 25.894-14.503.218-35.367-18.227-45.883-25.895zM384 217.775V360c0 13.255-10.745 24-24 24H88c-13.255 0-24-10.745-24-24V217.775c13.958 10.794 33.329 25.236 95.303 70.214 14.162 10.341 37.975 32.145 64.694 32.01 26.887.134 51.037-22.041 64.72-32.025 61.958-44.965 81.325-59.406 95.283-70.199z"],eraser:[512,512,[],"f12d","M497.941 273.941c18.745-18.745 18.745-49.137 0-67.882l-160-160c-18.745-18.745-49.136-18.746-67.883 0l-256 256c-18.745 18.745-18.745 49.137 0 67.882l96 96A48.004 48.004 0 0 0 144 480h356c6.627 0 12-5.373 12-12v-40c0-6.627-5.373-12-12-12H355.883l142.058-142.059zm-302.627-62.627l137.373 137.373L265.373 416H150.628l-80-80 124.686-124.686z"],"euro-sign":[320,512,[],"f153","M310.706 413.765c-1.314-6.63-7.835-10.872-14.424-9.369-10.692 2.439-27.422 5.413-45.426 5.413-56.763 0-101.929-34.79-121.461-85.449h113.689a12 12 0 0 0 11.708-9.369l6.373-28.36c1.686-7.502-4.019-14.631-11.708-14.631H115.22c-1.21-14.328-1.414-28.287.137-42.245H261.95a12 12 0 0 0 11.723-9.434l6.512-29.755c1.638-7.484-4.061-14.566-11.723-14.566H130.184c20.633-44.991 62.69-75.03 117.619-75.03 14.486 0 28.564 2.25 37.851 4.145 6.216 1.268 12.347-2.498 14.002-8.623l11.991-44.368c1.822-6.741-2.465-13.616-9.326-14.917C290.217 34.912 270.71 32 249.635 32 152.451 32 74.03 92.252 45.075 176H12c-6.627 0-12 5.373-12 12v29.755c0 6.627 5.373 12 12 12h21.569c-1.009 13.607-1.181 29.287-.181 42.245H12c-6.627 0-12 5.373-12 12v28.36c0 6.627 5.373 12 12 12h30.114C67.139 414.692 145.264 480 249.635 480c26.301 0 48.562-4.544 61.101-7.788 6.167-1.595 10.027-7.708 8.788-13.957l-8.818-44.49z"],"exchange-alt":[512,512,[],"f362","M0 168v-16c0-13.255 10.745-24 24-24h360V80c0-21.367 25.899-32.042 40.971-16.971l80 80c9.372 9.373 9.372 24.569 0 33.941l-80 80C409.956 271.982 384 261.456 384 240v-48H24c-13.255 0-24-10.745-24-24zm488 152H128v-48c0-21.314-25.862-32.08-40.971-16.971l-80 80c-9.372 9.373-9.372 24.569 0 33.941l80 80C102.057 463.997 128 453.437 128 432v-48h360c13.255 0 24-10.745 24-24v-16c0-13.255-10.745-24-24-24z"],exclamation:[192,512,[],"f12a","M176 432c0 44.112-35.888 80-80 80s-80-35.888-80-80 35.888-80 80-80 80 35.888 80 80zM25.26 25.199l13.6 272C39.499 309.972 50.041 320 62.83 320h66.34c12.789 0 23.331-10.028 23.97-22.801l13.6-272C167.425 11.49 156.496 0 142.77 0H49.23C35.504 0 24.575 11.49 25.26 25.199z"],"exclamation-circle":[512,512,[],"f06a","M504 256c0 136.997-111.043 248-248 248S8 392.997 8 256C8 119.083 119.043 8 256 8s248 111.083 248 248zm-248 50c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z"],"exclamation-triangle":[576,512,[],"f071","M569.517 440.013C587.975 472.007 564.806 512 527.94 512H48.054c-36.937 0-59.999-40.055-41.577-71.987L246.423 23.985c18.467-32.009 64.72-31.951 83.154 0l239.94 416.028zM288 354c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z"],expand:[448,512,[],"f065","M0 180V56c0-13.3 10.7-24 24-24h124c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12H64v84c0 6.6-5.4 12-12 12H12c-6.6 0-12-5.4-12-12zM288 44v40c0 6.6 5.4 12 12 12h84v84c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12V56c0-13.3-10.7-24-24-24H300c-6.6 0-12 5.4-12 12zm148 276h-40c-6.6 0-12 5.4-12 12v84h-84c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h124c13.3 0 24-10.7 24-24V332c0-6.6-5.4-12-12-12zM160 468v-40c0-6.6-5.4-12-12-12H64v-84c0-6.6-5.4-12-12-12H12c-6.6 0-12 5.4-12 12v124c0 13.3 10.7 24 24 24h124c6.6 0 12-5.4 12-12z"],"expand-arrows-alt":[448,512,[],"f31e","M448.1 344v112c0 13.3-10.7 24-24 24h-112c-21.4 0-32.1-25.9-17-41l36.2-36.2L224 295.6 116.8 402.9 153 439c15.1 15.1 4.4 41-17 41H24c-13.3 0-24-10.7-24-24V344c0-21.4 25.9-32.1 41-17l36.2 36.2L184.5 256 77.2 148.7 41 185c-15.1 15.1-41 4.4-41-17V56c0-13.3 10.7-24 24-24h112c21.4 0 32.1 25.9 17 41l-36.2 36.2L224 216.4l107.3-107.3L295.1 73c-15.1-15.1-4.4-41 17-41h112c13.3 0 24 10.7 24 24v112c0 21.4-25.9 32.1-41 17l-36.2-36.2L263.6 256l107.3 107.3 36.2-36.2c15.1-15.2 41-4.5 41 16.9z"],"external-link-alt":[576,512,[],"f35d","M576 24v127.984c0 21.461-25.96 31.98-40.971 16.971l-35.707-35.709-243.523 243.523c-9.373 9.373-24.568 9.373-33.941 0l-22.627-22.627c-9.373-9.373-9.373-24.569 0-33.941L442.756 76.676l-35.703-35.705C391.982 25.9 402.656 0 424.024 0H552c13.255 0 24 10.745 24 24zM407.029 270.794l-16 16A23.999 23.999 0 0 0 384 303.765V448H64V128h264a24.003 24.003 0 0 0 16.97-7.029l16-16C376.089 89.851 365.381 64 344 64H48C21.49 64 0 85.49 0 112v352c0 26.51 21.49 48 48 48h352c26.51 0 48-21.49 48-48V287.764c0-21.382-25.852-32.09-40.971-16.97z"],"external-link-square-alt":[448,512,[],"f360","M448 80v352c0 26.51-21.49 48-48 48H48c-26.51 0-48-21.49-48-48V80c0-26.51 21.49-48 48-48h352c26.51 0 48 21.49 48 48zm-88 16H248.029c-21.313 0-32.08 25.861-16.971 40.971l31.984 31.987L67.515 364.485c-4.686 4.686-4.686 12.284 0 16.971l31.029 31.029c4.687 4.686 12.285 4.686 16.971 0l195.526-195.526 31.988 31.991C358.058 263.977 384 253.425 384 231.979V120c0-13.255-10.745-24-24-24z"],eye:[576,512,[],"f06e","M569.354 231.631C512.969 135.949 407.81 72 288 72 168.14 72 63.004 135.994 6.646 231.631a47.999 47.999 0 0 0 0 48.739C63.031 376.051 168.19 440 288 440c119.86 0 224.996-63.994 281.354-159.631a47.997 47.997 0 0 0 0-48.738zM288 392c-75.162 0-136-60.827-136-136 0-75.162 60.826-136 136-136 75.162 0 136 60.826 136 136 0 75.162-60.826 136-136 136zm104-136c0 57.438-46.562 104-104 104s-104-46.562-104-104c0-17.708 4.431-34.379 12.236-48.973l-.001.032c0 23.651 19.173 42.823 42.824 42.823s42.824-19.173 42.824-42.823c0-23.651-19.173-42.824-42.824-42.824l-.032.001C253.621 156.431 270.292 152 288 152c57.438 0 104 46.562 104 104z"],"eye-dropper":[512,512,[],"f1fb","M177.38 206.64L39.03 344.97A24.01 24.01 0 0 0 32 361.94V424L0 480l32 32 56-32h62.06c6.36 0 12.47-2.53 16.97-7.03l138.35-138.33-128-128zm225.552 30.47l16.952 16.95c9.37 9.37 9.37 24.57 0 33.94l-40.973 40.97c-9.292 9.312-24.506 9.434-33.94 0L183.028 167.03c-9.37-9.37-9.37-24.57 0-33.94L224 92.12c9.289-9.309 24.502-9.438 33.94 0l16.992 16.99 82.606-82.601c35.19-35.19 92.5-35.5 128 0 40.49 48.08 29.66 98.34 0 128l-82.606 82.601z"],"eye-slash":[576,512,[],"f070","M286.693 391.984l32.579 46.542A333.958 333.958 0 0 1 288 440C168.19 440 63.031 376.051 6.646 280.369a47.999 47.999 0 0 1 0-48.739c24.023-40.766 56.913-75.775 96.024-102.537l57.077 81.539C154.736 224.82 152 240.087 152 256c0 74.736 60.135 135.282 134.693 135.984zm282.661-111.615c-31.667 53.737-78.747 97.46-135.175 125.475l.011.015 41.47 59.2c7.6 10.86 4.96 25.82-5.9 33.42l-13.11 9.18c-10.86 7.6-25.82 4.96-33.42-5.9L100.34 46.94c-7.6-10.86-4.96-25.82 5.9-33.42l13.11-9.18c10.86-7.6 25.82-4.96 33.42 5.9l51.038 72.617C230.68 75.776 258.905 72 288 72c119.81 0 224.969 63.949 281.354 159.631a48.002 48.002 0 0 1 0 48.738zM424 256c0-75.174-60.838-136-136-136-17.939 0-35.056 3.473-50.729 9.772l19.299 27.058c25.869-8.171 55.044-6.163 80.4 7.41h-.03c-23.65 0-42.82 19.17-42.82 42.82 0 23.626 19.147 42.82 42.82 42.82 23.65 0 42.82-19.17 42.82-42.82v-.03c18.462 34.49 16.312 77.914-8.25 110.95v.01l19.314 27.061C411.496 321.2 424 290.074 424 256zM262.014 356.727l-77.53-110.757c-5.014 52.387 29.314 98.354 77.53 110.757z"],"fast-backward":[512,512,[],"f049","M0 436V76c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v151.9L235.5 71.4C256.1 54.3 288 68.6 288 96v131.9L459.5 71.4C480.1 54.3 512 68.6 512 96v320c0 27.4-31.9 41.7-52.5 24.6L288 285.3V416c0 27.4-31.9 41.7-52.5 24.6L64 285.3V436c0 6.6-5.4 12-12 12H12c-6.6 0-12-5.4-12-12z"],"fast-forward":[512,512,[],"f050","M512 76v360c0 6.6-5.4 12-12 12h-40c-6.6 0-12-5.4-12-12V284.1L276.5 440.6c-20.6 17.2-52.5 2.8-52.5-24.6V284.1L52.5 440.6C31.9 457.8 0 443.4 0 416V96c0-27.4 31.9-41.7 52.5-24.6L224 226.8V96c0-27.4 31.9-41.7 52.5-24.6L448 226.8V76c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12z"],fax:[512,512,[],"f1ac","M128 144v320c0 26.51-21.49 48-48 48H48c-26.51 0-48-21.49-48-48V144c0-26.51 21.49-48 48-48h32c26.51 0 48 21.49 48 48zm384 64v256c0 26.51-21.49 48-48 48H192c-26.51 0-48-21.49-48-48V40c0-22.091 17.909-40 40-40h207.432a39.996 39.996 0 0 1 28.284 11.716l48.569 48.569A39.999 39.999 0 0 1 480 88.568v74.174c18.641 6.591 32 24.36 32 45.258zm-320-16h240V96h-24c-13.203 0-24-10.797-24-24V48H192v144zm96 204c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12v-40zm0-128c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12v-40zm128 128c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12v-40zm0-128c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12v-40z"],female:[256,512,[],"f182","M128 0c35.346 0 64 28.654 64 64s-28.654 64-64 64c-35.346 0-64-28.654-64-64S92.654 0 128 0m119.283 354.179l-48-192A24 24 0 0 0 176 144h-11.36c-22.711 10.443-49.59 10.894-73.28 0H80a24 24 0 0 0-23.283 18.179l-48 192C4.935 369.305 16.383 384 32 384h56v104c0 13.255 10.745 24 24 24h32c13.255 0 24-10.745 24-24V384h56c15.591 0 27.071-14.671 23.283-29.821z"],"fighter-jet":[640,512,[],"f0fb","M544 224l-128-16-48-16h-24L227.158 44h39.509C278.333 44 288 41.375 288 38s-9.667-6-21.333-6H152v12h16v164h-48l-66.667-80H18.667L8 138.667V208h8v16h48v2.666l-64 8v42.667l64 8V288H16v16H8v69.333L18.667 384h34.667L120 304h48v164h-16v12h114.667c11.667 0 21.333-2.625 21.333-6s-9.667-6-21.333-6h-39.509L344 320h24l48-16 128-16c96-21.333 96-26.583 96-32 0-5.417 0-10.667-96-32z"],file:[384,512,[],"f15b","M224 136V0H24C10.7 0 0 10.7 0 24v464c0 13.3 10.7 24 24 24h336c13.3 0 24-10.7 24-24V160H248c-13.2 0-24-10.8-24-24zm160-14.1v6.1H256V0h6.1c6.4 0 12.5 2.5 17 7l97.9 98c4.5 4.5 7 10.6 7 16.9z"],"file-alt":[384,512,[],"f15c","M224 136V0H24C10.7 0 0 10.7 0 24v464c0 13.3 10.7 24 24 24h336c13.3 0 24-10.7 24-24V160H248c-13.2 0-24-10.8-24-24zm64 236c0 6.6-5.4 12-12 12H108c-6.6 0-12-5.4-12-12v-8c0-6.6 5.4-12 12-12h168c6.6 0 12 5.4 12 12v8zm0-64c0 6.6-5.4 12-12 12H108c-6.6 0-12-5.4-12-12v-8c0-6.6 5.4-12 12-12h168c6.6 0 12 5.4 12 12v8zm0-72v8c0 6.6-5.4 12-12 12H108c-6.6 0-12-5.4-12-12v-8c0-6.6 5.4-12 12-12h168c6.6 0 12 5.4 12 12zm96-114.1v6.1H256V0h6.1c6.4 0 12.5 2.5 17 7l97.9 98c4.5 4.5 7 10.6 7 16.9z"],"file-archive":[384,512,[],"f1c6","M224 136V0h-63.6v32h-32V0H24C10.7 0 0 10.7 0 24v464c0 13.3 10.7 24 24 24h336c13.3 0 24-10.7 24-24V160H248c-13.2 0-24-10.8-24-24zM95.9 32h32v32h-32V32zm32.3 384c-33.2 0-58-30.4-51.4-62.9L96.4 256v-32h32v-32h-32v-32h32v-32h-32V96h32V64h32v32h-32v32h32v32h-32v32h32v32h-32v32h22.1c5.7 0 10.7 4.1 11.8 9.7l17.3 87.7c6.4 32.4-18.4 62.6-51.4 62.6zm32.7-53c0 14.9-14.5 27-32.4 27S96 378 96 363c0-14.9 14.5-27 32.4-27s32.5 12.1 32.5 27zM384 121.9v6.1H256V0h6.1c6.4 0 12.5 2.5 17 7l97.9 98c4.5 4.5 7 10.6 7 16.9z"],"file-audio":[384,512,[],"f1c7","M224 136V0H24C10.7 0 0 10.7 0 24v464c0 13.3 10.7 24 24 24h336c13.3 0 24-10.7 24-24V160H248c-13.2 0-24-10.8-24-24zm-64 268c0 10.7-12.9 16-20.5 8.5L104 376H76c-6.6 0-12-5.4-12-12v-56c0-6.6 5.4-12 12-12h28l35.5-36.5c7.6-7.6 20.5-2.2 20.5 8.5v136zm33.2-47.6c9.1-9.3 9.1-24.1 0-33.4-22.1-22.8 12.2-56.2 34.4-33.5 27.2 27.9 27.2 72.4 0 100.4-21.8 22.3-56.9-10.4-34.4-33.5zm86-117.1c54.4 55.9 54.4 144.8 0 200.8-21.8 22.4-57-10.3-34.4-33.5 36.2-37.2 36.3-96.5 0-133.8-22.1-22.8 12.3-56.3 34.4-33.5zM384 121.9v6.1H256V0h6.1c6.4 0 12.5 2.5 17 7l97.9 98c4.5 4.5 7 10.6 7 16.9z"],"file-code":[384,512,[],"f1c9","M384 121.941V128H256V0h6.059c6.365 0 12.47 2.529 16.971 7.029l97.941 97.941A24.005 24.005 0 0 1 384 121.941zM248 160c-13.2 0-24-10.8-24-24V0H24C10.745 0 0 10.745 0 24v464c0 13.255 10.745 24 24 24h336c13.255 0 24-10.745 24-24V160H248zM123.206 400.505a5.4 5.4 0 0 1-7.633.246l-64.866-60.812a5.4 5.4 0 0 1 0-7.879l64.866-60.812a5.4 5.4 0 0 1 7.633.246l19.579 20.885a5.4 5.4 0 0 1-.372 7.747L101.65 336l40.763 35.874a5.4 5.4 0 0 1 .372 7.747l-19.579 20.884zm51.295 50.479l-27.453-7.97a5.402 5.402 0 0 1-3.681-6.692l61.44-211.626a5.402 5.402 0 0 1 6.692-3.681l27.452 7.97a5.4 5.4 0 0 1 3.68 6.692l-61.44 211.626a5.397 5.397 0 0 1-6.69 3.681zm160.792-111.045l-64.866 60.812a5.4 5.4 0 0 1-7.633-.246l-19.58-20.885a5.4 5.4 0 0 1 .372-7.747L284.35 336l-40.763-35.874a5.4 5.4 0 0 1-.372-7.747l19.58-20.885a5.4 5.4 0 0 1 7.633-.246l64.866 60.812a5.4 5.4 0 0 1-.001 7.879z"],"file-excel":[384,512,[],"f1c3","M224 136V0H24C10.7 0 0 10.7 0 24v464c0 13.3 10.7 24 24 24h336c13.3 0 24-10.7 24-24V160H248c-13.2 0-24-10.8-24-24zm60.1 106.5L224 336l60.1 93.5c5.1 8-.6 18.5-10.1 18.5h-34.9c-4.4 0-8.5-2.4-10.6-6.3C208.9 405.5 192 373 192 373c-6.4 14.8-10 20-36.6 68.8-2.1 3.9-6.1 6.3-10.5 6.3H110c-9.5 0-15.2-10.5-10.1-18.5l60.3-93.5-60.3-93.5c-5.2-8 .6-18.5 10.1-18.5h34.8c4.4 0 8.5 2.4 10.6 6.3 26.1 48.8 20 33.6 36.6 68.5 0 0 6.1-11.7 36.6-68.5 2.1-3.9 6.2-6.3 10.6-6.3H274c9.5-.1 15.2 10.4 10.1 18.4zM384 121.9v6.1H256V0h6.1c6.4 0 12.5 2.5 17 7l97.9 98c4.5 4.5 7 10.6 7 16.9z"],"file-image":[384,512,[],"f1c5","M384 121.941V128H256V0h6.059a24 24 0 0 1 16.97 7.029l97.941 97.941a24.002 24.002 0 0 1 7.03 16.971zM248 160c-13.2 0-24-10.8-24-24V0H24C10.745 0 0 10.745 0 24v464c0 13.255 10.745 24 24 24h336c13.255 0 24-10.745 24-24V160H248zm-135.455 16c26.51 0 48 21.49 48 48s-21.49 48-48 48-48-21.49-48-48 21.491-48 48-48zm208 240h-256l.485-48.485L104.545 328c4.686-4.686 11.799-4.201 16.485.485L160.545 368 264.06 264.485c4.686-4.686 12.284-4.686 16.971 0L320.545 304v112z"],"file-pdf":[384,512,[],"f1c1","M181.9 256.1c-5-16-4.9-46.9-2-46.9 8.4 0 7.6 36.9 2 46.9zm-1.7 47.2c-7.7 20.2-17.3 43.3-28.4 62.7 18.3-7 39-17.2 62.9-21.9-12.7-9.6-24.9-23.4-34.5-40.8zM86.1 428.1c0 .8 13.2-5.4 34.9-40.2-6.7 6.3-29.1 24.5-34.9 40.2zM248 160h136v328c0 13.3-10.7 24-24 24H24c-13.3 0-24-10.7-24-24V24C0 10.7 10.7 0 24 0h200v136c0 13.2 10.8 24 24 24zm-8 171.8c-20-12.2-33.3-29-42.7-53.8 4.5-18.5 11.6-46.6 6.2-64.2-4.7-29.4-42.4-26.5-47.8-6.8-5 18.3-.4 44.1 8.1 77-11.6 27.6-28.7 64.6-40.8 85.8-.1 0-.1.1-.2.1-27.1 13.9-73.6 44.5-54.5 68 5.6 6.9 16 10 21.5 10 17.9 0 35.7-18 61.1-61.8 25.8-8.5 54.1-19.1 79-23.2 21.7 11.8 47.1 19.5 64 19.5 29.2 0 31.2-32 19.7-43.4-13.9-13.6-54.3-9.7-73.6-7.2zM377 105L279 7c-4.5-4.5-10.6-7-17-7h-6v128h128v-6.1c0-6.3-2.5-12.4-7-16.9zm-74.1 255.3c4.1-2.7-2.5-11.9-42.8-9 37.1 15.8 42.8 9 42.8 9z"],"file-powerpoint":[384,512,[],"f1c4","M193.7 271.2c8.8 0 15.5 2.7 20.3 8.1 9.6 10.9 9.8 32.7-.2 44.1-4.9 5.6-11.9 8.5-21.1 8.5h-26.9v-60.7h27.9zM377 105L279 7c-4.5-4.5-10.6-7-17-7h-6v128h128v-6.1c0-6.3-2.5-12.4-7-16.9zm-153 31V0H24C10.7 0 0 10.7 0 24v464c0 13.3 10.7 24 24 24h336c13.3 0 24-10.7 24-24V160H248c-13.2 0-24-10.8-24-24zm53 165.2c0 90.3-88.8 77.6-111.1 77.6V436c0 6.6-5.4 12-12 12h-30.8c-6.6 0-12-5.4-12-12V236.2c0-6.6 5.4-12 12-12h81c44.5 0 72.9 32.8 72.9 77z"],"file-video":[384,512,[],"f1c8","M384 121.941V128H256V0h6.059c6.365 0 12.47 2.529 16.971 7.029l97.941 97.941A24.005 24.005 0 0 1 384 121.941zM224 136V0H24C10.745 0 0 10.745 0 24v464c0 13.255 10.745 24 24 24h336c13.255 0 24-10.745 24-24V160H248c-13.2 0-24-10.8-24-24zm96 144.016v111.963c0 21.445-25.943 31.998-40.971 16.971L224 353.941V392c0 13.255-10.745 24-24 24H88c-13.255 0-24-10.745-24-24V280c0-13.255 10.745-24 24-24h112c13.255 0 24 10.745 24 24v38.059l55.029-55.013c15.011-15.01 40.971-4.491 40.971 16.97z"],"file-word":[384,512,[],"f1c2","M224 136V0H24C10.7 0 0 10.7 0 24v464c0 13.3 10.7 24 24 24h336c13.3 0 24-10.7 24-24V160H248c-13.2 0-24-10.8-24-24zm57.1 120H305c7.7 0 13.4 7.1 11.7 14.7l-38 168c-1.2 5.5-6.1 9.3-11.7 9.3h-38c-5.5 0-10.3-3.8-11.6-9.1-25.8-103.5-20.8-81.2-25.6-110.5h-.5c-1.1 14.3-2.4 17.4-25.6 110.5-1.3 5.3-6.1 9.1-11.6 9.1H117c-5.6 0-10.5-3.9-11.7-9.4l-37.8-168c-1.7-7.5 4-14.6 11.7-14.6h24.5c5.7 0 10.7 4 11.8 9.7 15.6 78 20.1 109.5 21 122.2 1.6-10.2 7.3-32.7 29.4-122.7 1.3-5.4 6.1-9.1 11.7-9.1h29.1c5.6 0 10.4 3.8 11.7 9.2 24 100.4 28.8 124 29.6 129.4-.2-11.2-2.6-17.8 21.6-129.2 1-5.6 5.9-9.5 11.5-9.5zM384 121.9v6.1H256V0h6.1c6.4 0 12.5 2.5 17 7l97.9 98c4.5 4.5 7 10.6 7 16.9z"],film:[512,512,[],"f008","M488 64h-8v20c0 6.6-5.4 12-12 12h-40c-6.6 0-12-5.4-12-12V64H96v20c0 6.6-5.4 12-12 12H44c-6.6 0-12-5.4-12-12V64h-8C10.7 64 0 74.7 0 88v336c0 13.3 10.7 24 24 24h8v-20c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v20h320v-20c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v20h8c13.3 0 24-10.7 24-24V88c0-13.3-10.7-24-24-24zM96 372c0 6.6-5.4 12-12 12H44c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40zm0-96c0 6.6-5.4 12-12 12H44c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40zm0-96c0 6.6-5.4 12-12 12H44c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40zm272 208c0 6.6-5.4 12-12 12H156c-6.6 0-12-5.4-12-12v-96c0-6.6 5.4-12 12-12h200c6.6 0 12 5.4 12 12v96zm0-168c0 6.6-5.4 12-12 12H156c-6.6 0-12-5.4-12-12v-96c0-6.6 5.4-12 12-12h200c6.6 0 12 5.4 12 12v96zm112 152c0 6.6-5.4 12-12 12h-40c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40zm0-96c0 6.6-5.4 12-12 12h-40c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40zm0-96c0 6.6-5.4 12-12 12h-40c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40z"],filter:[512,512,[],"f0b0","M487.976 0H24.028C2.71 0-8.047 25.866 7.058 40.971L192 225.941V432c0 7.831 3.821 15.17 10.237 19.662l80 55.98C298.02 518.69 320 507.493 320 487.98V225.941l184.947-184.97C520.021 25.896 509.338 0 487.976 0z"],fire:[384,512,[],"f06d","M216 23.858c0-23.802-30.653-32.765-44.149-13.038C48 191.851 224 200 224 288c0 35.629-29.114 64.458-64.85 63.994C123.98 351.538 96 322.22 96 287.046v-85.51c0-21.703-26.471-32.225-41.432-16.504C27.801 213.158 0 261.332 0 320c0 105.869 86.131 192 192 192s192-86.131 192-192c0-170.29-168-193.003-168-296.142z"],"fire-extinguisher":[448,512,[],"f134","M434.027 26.329l-168 28C254.693 56.218 256 67.8 256 72h-58.332C208.353 36.108 181.446 0 144 0c-39.435 0-66.368 39.676-52.228 76.203-52.039 13.051-75.381 54.213-90.049 90.884-4.923 12.307 1.063 26.274 13.37 31.197 12.317 4.926 26.279-1.075 31.196-13.37C75.058 112.99 106.964 120 168 120v27.076c-41.543 10.862-72 49.235-72 94.129V488c0 13.255 10.745 24 24 24h144c13.255 0 24-10.745 24-24V240c0-44.731-30.596-82.312-72-92.97V120h40c0 2.974-1.703 15.716 10.027 17.671l168 28C441.342 166.89 448 161.25 448 153.834V38.166c0-7.416-6.658-13.056-13.973-11.837zM144 72c-8.822 0-16-7.178-16-16s7.178-16 16-16 16 7.178 16 16-7.178 16-16 16z"],flag:[512,512,[],"f024","M349.565 98.783C295.978 98.783 251.721 64 184.348 64c-24.955 0-47.309 4.384-68.045 12.013a55.947 55.947 0 0 0 3.586-23.562C118.117 24.015 94.806 1.206 66.338.048 34.345-1.254 8 24.296 8 56c0 19.026 9.497 35.825 24 45.945V488c0 13.255 10.745 24 24 24h16c13.255 0 24-10.745 24-24v-94.4c28.311-12.064 63.582-22.122 114.435-22.122 53.588 0 97.844 34.783 165.217 34.783 48.169 0 86.667-16.294 122.505-40.858C506.84 359.452 512 349.571 512 339.045v-243.1c0-23.393-24.269-38.87-45.485-29.016-34.338 15.948-76.454 31.854-116.95 31.854z"],"flag-checkered":[512,512,[],"f11e","M466.515 66.928C487.731 57.074 512 72.551 512 95.944v243.1c0 10.526-5.161 20.407-13.843 26.358-35.837 24.564-74.335 40.858-122.505 40.858-67.373 0-111.63-34.783-165.217-34.783-50.853 0-86.124 10.058-114.435 22.122V488c0 13.255-10.745 24-24 24H56c-13.255 0-24-10.745-24-24V101.945C17.497 91.825 8 75.026 8 56 8 24.296 34.345-1.254 66.338.048c28.468 1.158 51.779 23.968 53.551 52.404.52 8.342-.81 16.31-3.586 23.562C137.039 68.384 159.393 64 184.348 64c67.373 0 111.63 34.783 165.217 34.783 40.496 0 82.612-15.906 116.95-31.855zM96 134.63v70.49c29-10.67 51.18-17.83 73.6-20.91v-71.57c-23.5 2.17-40.44 9.79-73.6 21.99zm220.8 9.19c-26.417-4.672-49.886-13.979-73.6-21.34v67.42c24.175 6.706 47.566 16.444 73.6 22.31v-68.39zm-147.2 40.39v70.04c32.796-2.978 53.91-.635 73.6 3.8V189.9c-25.247-7.035-46.581-9.423-73.6-5.69zm73.6 142.23c26.338 4.652 49.732 13.927 73.6 21.34v-67.41c-24.277-6.746-47.54-16.45-73.6-22.32v68.39zM96 342.1c23.62-8.39 47.79-13.84 73.6-16.56v-71.29c-26.11 2.35-47.36 8.04-73.6 17.36v70.49zm368-221.6c-21.3 8.85-46.59 17.64-73.6 22.47v71.91c27.31-4.36 50.03-14.1 73.6-23.89V120.5zm0 209.96v-70.49c-22.19 14.2-48.78 22.61-73.6 26.02v71.58c25.07-2.38 48.49-11.04 73.6-27.11zM316.8 212.21v68.16c25.664 7.134 46.616 9.342 73.6 5.62v-71.11c-25.999 4.187-49.943 2.676-73.6-2.67z"],flask:[448,512,[],"f0c3","M437.2 403.5L320 215V64h8c13.3 0 24-10.7 24-24V24c0-13.3-10.7-24-24-24H120c-13.3 0-24 10.7-24 24v16c0 13.3 10.7 24 24 24h8v151L10.8 403.5C-18.5 450.6 15.3 512 70.9 512h306.2c55.7 0 89.4-61.5 60.1-108.5zM137.9 320l48.2-77.6c3.7-5.2 5.8-11.6 5.8-18.4V64h64v160c0 6.9 2.2 13.2 5.8 18.4l48.2 77.6h-172z"],folder:[512,512,[],"f07b","M464 128H272l-64-64H48C21.49 64 0 85.49 0 112v288c0 26.51 21.49 48 48 48h416c26.51 0 48-21.49 48-48V176c0-26.51-21.49-48-48-48z"],"folder-open":[576,512,[],"f07c","M572.694 292.093L500.27 416.248A63.997 63.997 0 0 1 444.989 448H45.025c-18.523 0-30.064-20.093-20.731-36.093l72.424-124.155A64 64 0 0 1 152 256h399.964c18.523 0 30.064 20.093 20.73 36.093zM152 224h328v-48c0-26.51-21.49-48-48-48H272l-64-64H48C21.49 64 0 85.49 0 112v278.046l69.077-118.418C86.214 242.25 117.989 224 152 224z"],font:[448,512,[],"f031","M152 416h-24.013l26.586-80.782H292.8L319.386 416H296c-8.837 0-16 7.163-16 16v32c0 8.837 7.163 16 16 16h136c8.837 0 16-7.163 16-16v-32c0-8.837-7.163-16-16-16h-26.739L275.495 42.746A16 16 0 0 0 260.382 32h-72.766a16 16 0 0 0-15.113 10.746L42.739 416H16c-8.837 0-16 7.163-16 16v32c0 8.837 7.163 16 16 16h136c8.837 0 16-7.163 16-16v-32c0-8.837-7.163-16-16-16zm64.353-271.778c4.348-15.216 6.61-28.156 7.586-34.644.839 6.521 2.939 19.476 7.727 34.706l41.335 124.006h-98.619l41.971-124.068z"],forward:[512,512,[],"f04e","M500.5 231.4l-192-160C287.9 54.3 256 68.6 256 96v320c0 27.4 31.9 41.8 52.5 24.6l192-160c15.3-12.8 15.3-36.4 0-49.2zm-256 0l-192-160C31.9 54.3 0 68.6 0 96v320c0 27.4 31.9 41.8 52.5 24.6l192-160c15.3-12.8 15.3-36.4 0-49.2z"],frown:[512,512,[],"f119","M504 256c0 136.967-111.033 248-248 248S8 392.967 8 256 119.033 8 256 8s248 111.033 248 248zm-396-64c0 37.497 30.503 68 68 68s68-30.503 68-68-30.503-68-68-68-68 30.503-68 68zm160.5 0c0 37.221 30.279 67.5 67.5 67.5s67.5-30.279 67.5-67.5-30.279-67.5-67.5-67.5-67.5 30.279-67.5 67.5zm67.5-48a47.789 47.789 0 0 0-22.603 5.647h.015c10.916 0 19.765 8.849 19.765 19.765s-8.849 19.765-19.765 19.765-19.765-8.849-19.765-19.765v-.015A47.789 47.789 0 0 0 288 192c0 26.51 21.49 48 48 48s48-21.49 48-48-21.49-48-48-48zm-160 0a47.789 47.789 0 0 0-22.603 5.647h.015c10.916 0 19.765 8.849 19.765 19.765s-8.849 19.765-19.765 19.765-19.765-8.849-19.765-19.765v-.015A47.789 47.789 0 0 0 128 192c0 26.51 21.49 48 48 48s48-21.49 48-48-21.49-48-48-48zm192.551 212.66c-59.128-91.455-165.846-91.594-225.064 0-11.502 17.79 15.383 35.148 26.873 17.374 46.626-72.118 124.862-71.855 171.318 0 11.328 17.524 38.548.684 26.873-17.374z"],futbol:[512,512,[],"f1e3","M504 256c0 136.967-111.033 248-248 248S8 392.967 8 256 119.033 8 256 8s248 111.033 248 248zm-48 0l-.003-.282-26.064 22.741-62.679-58.5 16.454-84.355 34.303 3.072c-24.889-34.216-60.004-60.089-100.709-73.141l13.651 31.939L256 139l-74.953-41.525 13.651-31.939c-40.631 13.028-75.78 38.87-100.709 73.141l34.565-3.073 16.192 84.355-62.678 58.5-26.064-22.741-.003.282c0 43.015 13.497 83.952 38.472 117.991l7.704-33.897 85.138 10.447 36.301 77.826-29.902 17.786c40.202 13.122 84.29 13.148 124.572 0l-29.902-17.786 36.301-77.826 85.138-10.447 7.704 33.897C442.503 339.952 456 299.015 456 256zm-248.102 69.571l-29.894-91.312L256 177.732l77.996 56.527-29.622 91.312h-96.476z"],gamepad:[640,512,[],"f11b","M480 96H160C71.6 96 0 167.6 0 256s71.6 160 160 160c44.8 0 85.2-18.4 114.2-48h91.5c29 29.6 69.5 48 114.2 48 88.4 0 160-71.6 160-160S568.4 96 480 96zM256 276c0 6.6-5.4 12-12 12h-52v52c0 6.6-5.4 12-12 12h-40c-6.6 0-12-5.4-12-12v-52H76c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h52v-52c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v52h52c6.6 0 12 5.4 12 12v40zm184 68c-26.5 0-48-21.5-48-48s21.5-48 48-48 48 21.5 48 48-21.5 48-48 48zm80-80c-26.5 0-48-21.5-48-48s21.5-48 48-48 48 21.5 48 48-21.5 48-48 48z"],gavel:[512,512,[],"f0e3","M504.971 199.362l-22.627-22.627c-9.373-9.373-24.569-9.373-33.941 0l-5.657 5.657L329.608 69.255l5.657-5.657c9.373-9.373 9.373-24.569 0-33.941L312.638 7.029c-9.373-9.373-24.569-9.373-33.941 0L154.246 131.48c-9.373 9.373-9.373 24.569 0 33.941l22.627 22.627c9.373 9.373 24.569 9.373 33.941 0l5.657-5.657 39.598 39.598-81.04 81.04-5.657-5.657c-12.497-12.497-32.758-12.497-45.255 0L9.373 412.118c-12.497 12.497-12.497 32.758 0 45.255l45.255 45.255c12.497 12.497 32.758 12.497 45.255 0l114.745-114.745c12.497-12.497 12.497-32.758 0-45.255l-5.657-5.657 81.04-81.04 39.598 39.598-5.657 5.657c-9.373 9.373-9.373 24.569 0 33.941l22.627 22.627c9.373 9.373 24.569 9.373 33.941 0l124.451-124.451c9.372-9.372 9.372-24.568 0-33.941z"],gem:[576,512,[],"f3a5","M485.5 0L576 160H474.9L405.7 0h79.8zm-128 0l69.2 160H149.3L218.5 0h139zm-267 0h79.8l-69.2 160H0L90.5 0zM0 192h100.7l123 251.7c1.5 3.1-2.7 5.9-5 3.3L0 192zm148.2 0h279.6l-137 318.2c-1 2.4-4.5 2.4-5.5 0L148.2 192zm204.1 251.7l123-251.7H576L357.3 446.9c-2.3 2.7-6.5-.1-5-3.2z"],genderless:[288,512,[],"f22d","M144 176c44.1 0 80 35.9 80 80s-35.9 80-80 80-80-35.9-80-80 35.9-80 80-80m0-64C64.5 112 0 176.5 0 256s64.5 144 144 144 144-64.5 144-144-64.5-144-144-144z"],gift:[512,512,[],"f06b","M488 192h-64.512C438.72 175.003 448 152.566 448 128c0-52.935-43.065-96-96-96-41.997 0-68.742 20.693-95.992 54.15C226.671 50.192 199.613 32 160 32c-52.935 0-96 43.065-96 96 0 24.566 9.28 47.003 24.512 64H24c-13.255 0-24 10.745-24 24v80c0 13.255 10.745 24 24 24h8v112c0 26.51 21.49 48 48 48h352c26.51 0 48-21.49 48-48V320h8c13.255 0 24-10.745 24-24v-80c0-13.255-10.745-24-24-24zm-208-32c24-56 55.324-64 72-64 17.645 0 32 14.355 32 32s-14.355 32-32 32h-72zM160 96c16.676 0 48 8 72 64h-72c-17.645 0-32-14.355-32-32s14.355-32 32-32zm48 128h96v184c0 13.255-10.745 24-24 24h-48c-13.255 0-24-10.745-24-24V224z"],"glass-martini":[512,512,[],"f000","M507.3 27.3c10-10 2.9-27.3-11.3-27.3H16C1.8 0-5.4 17.2 4.7 27.3L216 238.6V472h-92c-15.5 0-28 12.5-28 28 0 6.6 5.4 12 12 12h296c6.6 0 12-5.4 12-12 0-15.5-12.5-28-28-28h-92V238.6L507.3 27.3z"],globe:[512,512,[],"f0ac","M364.215 192h131.43c5.439 20.419 8.354 41.868 8.354 64s-2.915 43.581-8.354 64h-131.43c5.154-43.049 4.939-86.746 0-128zM185.214 352c10.678 53.68 33.173 112.514 70.125 151.992.221.001.44.008.661.008s.44-.008.661-.008c37.012-39.543 59.467-98.414 70.125-151.992H185.214zm174.13-192h125.385C452.802 84.024 384.128 27.305 300.95 12.075c30.238 43.12 48.821 96.332 58.394 147.925zm-27.35 32H180.006c-5.339 41.914-5.345 86.037 0 128h151.989c5.339-41.915 5.345-86.037-.001-128zM152.656 352H27.271c31.926 75.976 100.6 132.695 183.778 147.925-30.246-43.136-48.823-96.35-58.393-147.925zm206.688 0c-9.575 51.605-28.163 104.814-58.394 147.925 83.178-15.23 151.852-71.949 183.778-147.925H359.344zm-32.558-192c-10.678-53.68-33.174-112.514-70.125-151.992-.221 0-.44-.008-.661-.008s-.44.008-.661.008C218.327 47.551 195.872 106.422 185.214 160h141.572zM16.355 192C10.915 212.419 8 233.868 8 256s2.915 43.581 8.355 64h131.43c-4.939-41.254-5.154-84.951 0-128H16.355zm136.301-32c9.575-51.602 28.161-104.81 58.394-147.925C127.872 27.305 59.198 84.024 27.271 160h125.385z"],"graduation-cap":[640,512,[],"f19d","M622.884 199.005l-275.817 85.1a96 96 0 0 1-54.134 0L92.398 222.232c-8.564 11.438-11.018 23.05-11.918 38.335C89.778 266.165 96 276.355 96 288c0 11.952-6.557 22.366-16.265 27.861l16.197 123.096c.63 4.786-3.1 9.043-7.932 9.043H40c-4.828 0-8.562-4.253-7.932-9.044L48.265 315.86C38.557 310.366 32 299.952 32 288c0-12.034 6.646-22.511 16.465-27.976.947-17.951 3.974-33.231 12.152-47.597l-43.502-13.422c-22.876-6.801-22.766-39.241 0-46.01l275.817-85.1a96 96 0 0 1 54.134 0l275.817 85.1c22.877 6.801 22.767 39.241.001 46.01zM356.503 314.682l-.207.064-.207.061a127.998 127.998 0 0 1-72.177 0l-.207-.061-.207-.064-150.914-46.57L120 352c0 35.346 89.543 64 200 64s200-28.654 200-64l-12.583-83.888-150.914 46.57z"],"h-square":[448,512,[],"f0fd","M448 80v352c0 26.51-21.49 48-48 48H48c-26.51 0-48-21.49-48-48V80c0-26.51 21.49-48 48-48h352c26.51 0 48 21.49 48 48zm-112 48h-32c-8.837 0-16 7.163-16 16v80H160v-80c0-8.837-7.163-16-16-16h-32c-8.837 0-16 7.163-16 16v224c0 8.837 7.163 16 16 16h32c8.837 0 16-7.163 16-16v-80h128v80c0 8.837 7.163 16 16 16h32c8.837 0 16-7.163 16-16V144c0-8.837-7.163-16-16-16z"],"hand-lizard":[576,512,[],"f258","M384 480h192V363.778a95.998 95.998 0 0 0-14.833-51.263L398.127 54.368A48 48 0 0 0 357.544 32H24C10.745 32 0 42.745 0 56v16c0 30.928 25.072 56 56 56h229.981c12.844 0 21.556 13.067 16.615 24.923l-21.41 51.385A32 32 0 0 1 251.648 224H128c-35.346 0-64 28.654-64 64v8c0 13.255 10.745 24 24 24h147.406a47.995 47.995 0 0 1 25.692 7.455l111.748 70.811A24.001 24.001 0 0 1 384 418.539V480z"],"hand-paper":[448,512,[],"f256","M408.781 128.007C386.356 127.578 368 146.36 368 168.79V256h-8V79.79c0-22.43-18.356-41.212-40.781-40.783C297.488 39.423 280 57.169 280 79v177h-8V40.79C272 18.36 253.644-.422 231.219.007 209.488.423 192 18.169 192 40v216h-8V80.79c0-22.43-18.356-41.212-40.781-40.783C121.488 40.423 104 58.169 104 80v235.992l-31.648-43.519c-12.993-17.866-38.009-21.817-55.877-8.823-17.865 12.994-21.815 38.01-8.822 55.877l125.601 172.705A48 48 0 0 0 172.073 512h197.59c22.274 0 41.622-15.324 46.724-37.006l26.508-112.66a192.011 192.011 0 0 0 5.104-43.975V168c.001-21.831-17.487-39.577-39.218-39.993z"],"hand-peace":[448,512,[],"f25b","M408 216c-22.092 0-40 17.909-40 40h-8v-32c0-22.091-17.908-40-40-40s-40 17.909-40 40v32h-8V48c0-26.51-21.49-48-48-48s-48 21.49-48 48v208h-13.572L92.688 78.449C82.994 53.774 55.134 41.63 30.461 51.324 5.787 61.017-6.356 88.877 3.337 113.551l74.765 190.342-31.09 24.872c-15.381 12.306-19.515 33.978-9.741 51.081l64 112A39.998 39.998 0 0 0 136 512h240c18.562 0 34.686-12.77 38.937-30.838l32-136A39.97 39.97 0 0 0 448 336v-80c0-22.091-17.908-40-40-40z"],"hand-point-down":[384,512,[],"f0a7","M91.826 467.2V317.966c-8.248 5.841-16.558 10.57-24.918 14.153C35.098 345.752-.014 322.222 0 288c.008-18.616 10.897-32.203 29.092-40 28.286-12.122 64.329-78.648 77.323-107.534 7.956-17.857 25.479-28.453 43.845-28.464l.001-.002h171.526c11.812 0 21.897 8.596 23.703 20.269 7.25 46.837 38.483 61.76 38.315 123.731-.007 2.724.195 13.254.195 16 0 50.654-22.122 81.574-71.263 72.6-9.297 18.597-39.486 30.738-62.315 16.45-21.177 24.645-53.896 22.639-70.944 6.299V467.2c0 24.15-20.201 44.8-43.826 44.8-23.283 0-43.826-21.35-43.826-44.8zM112 72V24c0-13.255 10.745-24 24-24h192c13.255 0 24 10.745 24 24v48c0 13.255-10.745 24-24 24H136c-13.255 0-24-10.745-24-24zm212-24c0-11.046-8.954-20-20-20s-20 8.954-20 20 8.954 20 20 20 20-8.954 20-20z"],"hand-point-left":[512,512,[],"f0a5","M44.8 155.826h149.234c-5.841-8.248-10.57-16.558-14.153-24.918C166.248 99.098 189.778 63.986 224 64c18.616.008 32.203 10.897 40 29.092 12.122 28.286 78.648 64.329 107.534 77.323 17.857 7.956 28.453 25.479 28.464 43.845l.002.001v171.526c0 11.812-8.596 21.897-20.269 23.703-46.837 7.25-61.76 38.483-123.731 38.315-2.724-.007-13.254.195-16 .195-50.654 0-81.574-22.122-72.6-71.263-18.597-9.297-30.738-39.486-16.45-62.315-24.645-21.177-22.639-53.896-6.299-70.944H44.8c-24.15 0-44.8-20.201-44.8-43.826 0-23.283 21.35-43.826 44.8-43.826zM440 176h48c13.255 0 24 10.745 24 24v192c0 13.255-10.745 24-24 24h-48c-13.255 0-24-10.745-24-24V200c0-13.255 10.745-24 24-24zm24 212c11.046 0 20-8.954 20-20s-8.954-20-20-20-20 8.954-20 20 8.954 20 20 20z"],"hand-point-right":[512,512,[],"f0a4","M512 199.652c0 23.625-20.65 43.826-44.8 43.826h-99.851c16.34 17.048 18.346 49.766-6.299 70.944 14.288 22.829 2.147 53.017-16.45 62.315C353.574 425.878 322.654 448 272 448c-2.746 0-13.276-.203-16-.195-61.971.168-76.894-31.065-123.731-38.315C120.596 407.683 112 397.599 112 385.786V214.261l.002-.001c.011-18.366 10.607-35.889 28.464-43.845 28.886-12.994 95.413-49.038 107.534-77.323 7.797-18.194 21.384-29.084 40-29.092 34.222-.014 57.752 35.098 44.119 66.908-3.583 8.359-8.312 16.67-14.153 24.918H467.2c23.45 0 44.8 20.543 44.8 43.826zM96 200v192c0 13.255-10.745 24-24 24H24c-13.255 0-24-10.745-24-24V200c0-13.255 10.745-24 24-24h48c13.255 0 24 10.745 24 24zM68 368c0-11.046-8.954-20-20-20s-20 8.954-20 20 8.954 20 20 20 20-8.954 20-20z"],"hand-point-up":[384,512,[],"f0a6","M135.652 0c23.625 0 43.826 20.65 43.826 44.8v99.851c17.048-16.34 49.766-18.346 70.944 6.299 22.829-14.288 53.017-2.147 62.315 16.45C361.878 158.426 384 189.346 384 240c0 2.746-.203 13.276-.195 16 .168 61.971-31.065 76.894-38.315 123.731C343.683 391.404 333.599 400 321.786 400H150.261l-.001-.002c-18.366-.011-35.889-10.607-43.845-28.464C93.421 342.648 57.377 276.122 29.092 264 10.897 256.203.008 242.616 0 224c-.014-34.222 35.098-57.752 66.908-44.119 8.359 3.583 16.67 8.312 24.918 14.153V44.8c0-23.45 20.543-44.8 43.826-44.8zM136 416h192c13.255 0 24 10.745 24 24v48c0 13.255-10.745 24-24 24H136c-13.255 0-24-10.745-24-24v-48c0-13.255 10.745-24 24-24zm168 28c-11.046 0-20 8.954-20 20s8.954 20 20 20 20-8.954 20-20-8.954-20-20-20z"],"hand-pointer":[448,512,[],"f25a","M448 240v96c0 3.084-.356 6.159-1.063 9.162l-32 136C410.686 499.23 394.562 512 376 512H168a40.004 40.004 0 0 1-32.35-16.473l-127.997-176c-12.993-17.866-9.043-42.883 8.822-55.876 17.867-12.994 42.884-9.043 55.877 8.823L104 315.992V40c0-22.091 17.908-40 40-40s40 17.909 40 40v200h8v-40c0-22.091 17.908-40 40-40s40 17.909 40 40v40h8v-24c0-22.091 17.908-40 40-40s40 17.909 40 40v24h8c0-22.091 17.908-40 40-40s40 17.909 40 40zm-256 80h-8v96h8v-96zm88 0h-8v96h8v-96zm88 0h-8v96h8v-96z"],"hand-rock":[512,512,[],"f255","M512 128.79c0-26.322-20.861-48.344-47.18-48.783C437.935 79.558 416 101.217 416 128h-8V96.79c0-26.322-20.861-48.344-47.18-48.783C333.935 47.558 312 69.217 312 96v32h-8V80.79c0-26.322-20.861-48.344-47.18-48.783C229.935 31.558 208 53.217 208 80v48h-8V96.79c0-26.322-20.861-48.344-47.18-48.783C125.935 47.558 104 69.217 104 96v136l-8-7.111V176.79c0-26.322-20.861-48.344-47.18-48.783C21.935 127.558 0 149.217 0 176v66.445a95.998 95.998 0 0 0 32.221 71.751l111.668 99.261A47.999 47.999 0 0 1 160 449.333V456c0 13.255 10.745 24 24 24h240c13.255 0 24-10.745 24-24v-2.921a96.01 96.01 0 0 1 7.523-37.254l48.954-116.265A96.002 96.002 0 0 0 512 262.306V128.79z"],"hand-scissors":[512,512,[],"f257","M216 440c0-22.092 17.909-40 40-40v-8h-32c-22.091 0-40-17.908-40-40s17.909-40 40-40h32v-8H48c-26.51 0-48-21.49-48-48s21.49-48 48-48h208v-13.572l-177.551-69.74c-24.674-9.694-36.818-37.555-27.125-62.228 9.693-24.674 37.554-36.817 62.228-27.124l190.342 74.765 24.872-31.09c12.306-15.381 33.978-19.515 51.081-9.741l112 64A40.002 40.002 0 0 1 512 168v240c0 18.562-12.77 34.686-30.838 38.937l-136 32A39.982 39.982 0 0 1 336 480h-80c-22.091 0-40-17.908-40-40z"],"hand-spock":[512,512,[],"f259","M10.872 316.585c15.139-16.086 40.454-16.854 56.543-1.713L128 371.893v-79.405L88.995 120.865c-4.896-21.542 8.598-42.974 30.14-47.87 21.549-4.894 42.975 8.599 47.87 30.141L201.747 256h9.833L164.016 48.966c-4.946-21.531 8.498-42.994 30.028-47.94 21.532-4.95 42.994 8.498 47.94 30.028L293.664 256h15.105l48.425-193.702c5.357-21.432 27.075-34.462 48.507-29.104 21.432 5.358 34.463 27.075 29.104 48.507L391.231 256h11.08l30.768-129.265c5.117-21.491 26.685-34.768 48.177-29.647 21.491 5.117 34.765 26.686 29.647 48.177l-36.292 152.467A96.024 96.024 0 0 0 472 319.967v42.102a96.002 96.002 0 0 1-3.96 27.287l-26.174 88.287C435.825 498.022 417.101 512 395.846 512H179.172a48.002 48.002 0 0 1-32.898-13.046L12.585 373.128c-16.087-15.141-16.853-40.456-1.713-56.543z"],handshake:[640,512,[],"f2b5","M72 112H24c-13.255 0-24 10.745-24 24v208c0 13.255 10.745 24 24 24h48c13.255 0 24-10.745 24-24V136c0-13.255-10.745-24-24-24zM48 340c-11.046 0-20-8.954-20-20s8.954-20 20-20 20 8.954 20 20-8.954 20-20 20zm568-228h-48c-13.255 0-24 10.745-24 24v208c0 13.255 10.745 24 24 24h48c13.255 0 24-10.745 24-24V136c0-13.255-10.745-24-24-24zm-24 228c-11.046 0-20-8.954-20-20s8.954-20 20-20 20 8.954 20 20-8.954 20-20 20zM485.94 92.67L528 140.74V320h-19.17c.56-14.96-4.38-28.98-14-39.71l-80.92-98.91c2.93-3.2 2.76-8.16-.38-11.16-2.82-2.7-7.08-2.92-10.14-.76-.42.3-60.35 62.93-60.35 62.93l-.2.21c-23.904 26.905-66.127 26.204-89.15-1.42-15.48-18.58-15.29-45.39.45-63.76l66.57-77.67C334.304 73.88 354.534 64 376.7 64h46.05a83.98 83.98 0 0 1 63.19 28.67zm-3.37 197.92c15.46 16.78 12.59 43.83-2.37 57.75-17.711 16.462-42.433 13.004-45.93 9.2 1.653 15.658-21.389 47.249-56.42 44.68-6.325 21.185-32.298 38.909-59.18 29.61-10.22 10.21-25.82 14.97-39.81 14.97-28.69 0-54.92-11.99-72.58-30.8L112 320V135.52l61.36-50.57A71.52 71.52 0 0 1 223.93 64h37.42c16.73 0 32.68 6.84 44.21 18.85l-63.57 74.16c-20.84 24.31-21.09 59.81-.59 84.42 29.375 35.247 83.007 35.853 113.31 1.92L402.82 193l79.75 97.59z"],hashtag:[448,512,[],"f292","M440.667 182.109l7.143-40c1.313-7.355-4.342-14.109-11.813-14.109h-74.81l14.623-81.891C377.123 38.754 371.468 32 363.997 32h-40.632a12 12 0 0 0-11.813 9.891L296.175 128H197.54l14.623-81.891C213.477 38.754 207.822 32 200.35 32h-40.632a12 12 0 0 0-11.813 9.891L132.528 128H53.432a12 12 0 0 0-11.813 9.891l-7.143 40C33.163 185.246 38.818 192 46.289 192h74.81L98.242 320H19.146a12 12 0 0 0-11.813 9.891l-7.143 40C-1.123 377.246 4.532 384 12.003 384h74.81L72.19 465.891C70.877 473.246 76.532 480 84.003 480h40.632a12 12 0 0 0 11.813-9.891L151.826 384h98.634l-14.623 81.891C234.523 473.246 240.178 480 247.65 480h40.632a12 12 0 0 0 11.813-9.891L315.472 384h79.096a12 12 0 0 0 11.813-9.891l7.143-40c1.313-7.355-4.342-14.109-11.813-14.109h-74.81l22.857-128h79.096a12 12 0 0 0 11.813-9.891zM261.889 320h-98.634l22.857-128h98.634l-22.857 128z"],hdd:[576,512,[],"f0a0","M576 304v96c0 26.51-21.49 48-48 48H48c-26.51 0-48-21.49-48-48v-96c0-26.51 21.49-48 48-48h480c26.51 0 48 21.49 48 48zm-48-80a79.557 79.557 0 0 1 30.777 6.165L462.25 85.374A48.003 48.003 0 0 0 422.311 64H153.689a48 48 0 0 0-39.938 21.374L17.223 230.165A79.557 79.557 0 0 1 48 224h480zm-48 96c-17.673 0-32 14.327-32 32s14.327 32 32 32 32-14.327 32-32-14.327-32-32-32zm-96 0c-17.673 0-32 14.327-32 32s14.327 32 32 32 32-14.327 32-32-14.327-32-32-32z"],heading:[512,512,[],"f1dc","M496 80V48c0-8.837-7.163-16-16-16H320c-8.837 0-16 7.163-16 16v32c0 8.837 7.163 16 16 16h37.621v128H154.379V96H192c8.837 0 16-7.163 16-16V48c0-8.837-7.163-16-16-16H32c-8.837 0-16 7.163-16 16v32c0 8.837 7.163 16 16 16h37.275v320H32c-8.837 0-16 7.163-16 16v32c0 8.837 7.163 16 16 16h160c8.837 0 16-7.163 16-16v-32c0-8.837-7.163-16-16-16h-37.621V288H357.62v128H320c-8.837 0-16 7.163-16 16v32c0 8.837 7.163 16 16 16h160c8.837 0 16-7.163 16-16v-32c0-8.837-7.163-16-16-16h-37.275V96H480c8.837 0 16-7.163 16-16z"],headphones:[512,512,[],"f025","M256 32C114.52 32 0 146.496 0 288v48a32 32 0 0 0 17.689 28.622l14.383 7.191C34.083 431.903 83.421 480 144 480h24c13.255 0 24-10.745 24-24V280c0-13.255-10.745-24-24-24h-24c-31.342 0-59.671 12.879-80 33.627V288c0-105.869 86.131-192 192-192s192 86.131 192 192v1.627C427.671 268.879 399.342 256 368 256h-24c-13.255 0-24 10.745-24 24v176c0 13.255 10.745 24 24 24h24c60.579 0 109.917-48.098 111.928-108.187l14.382-7.191A32 32 0 0 0 512 336v-48c0-141.479-114.496-256-256-256z"],heart:[576,512,[],"f004","M414.9 24C361.8 24 312 65.7 288 89.3 264 65.7 214.2 24 161.1 24 70.3 24 16 76.9 16 165.5c0 72.6 66.8 133.3 69.2 135.4l187 180.8c8.8 8.5 22.8 8.5 31.6 0l186.7-180.2c2.7-2.7 69.5-63.5 69.5-136C560 76.9 505.7 24 414.9 24z"],heartbeat:[576,512,[],"f21e","M47.9 257C31.6 232.7 16 200.5 16 165.5 16 76.9 70.3 24 161.1 24 214.2 24 264 65.7 288 89.3 312 65.7 361.8 24 414.9 24 505.7 24 560 76.9 560 165.5c0 35-15.5 67.2-31.9 91.5H408l-26.4-58.6c-4.7-8.9-17.6-8.5-21.6.7l-53.3 134.6L235.4 120c-3.7-10.6-18.7-10.7-22.6-.2l-48 137.2H47.9zm348 32c-4.5 0-8.6-2.5-10.6-6.4l-12.8-32.5-56.9 142.8c-4.4 9.9-18.7 9.4-22.3-.9l-69.7-209.2-33.6 98.4c-1.7 4.7-6.2 7.8-11.2 7.8H73.4c5.3 5.7-12.8-12 198.9 192.6 8.8 8.5 22.8 8.5 31.6 0 204.3-197.2 191-184 199-192.6h-107z"],history:[512,512,[],"f1da","M504 255.531c.253 136.64-111.18 248.372-247.82 248.468-59.015.042-113.223-20.53-155.822-54.911-11.077-8.94-11.905-25.541-1.839-35.607l11.267-11.267c8.609-8.609 22.353-9.551 31.891-1.984C173.062 425.135 212.781 440 256 440c101.705 0 184-82.311 184-184 0-101.705-82.311-184-184-184-48.814 0-93.149 18.969-126.068 49.932l50.754 50.754c10.08 10.08 2.941 27.314-11.313 27.314H24c-8.837 0-16-7.163-16-16V38.627c0-14.254 17.234-21.393 27.314-11.314l49.372 49.372C129.209 34.136 189.552 8 256 8c136.81 0 247.747 110.78 248 247.531zm-180.912 78.784l9.823-12.63c8.138-10.463 6.253-25.542-4.21-33.679L288 256.349V152c0-13.255-10.745-24-24-24h-16c-13.255 0-24 10.745-24 24v135.651l65.409 50.874c10.463 8.137 25.541 6.253 33.679-4.21z"],home:[576,512,[],"f015","M488 312.7V456c0 13.3-10.7 24-24 24H348c-6.6 0-12-5.4-12-12V356c0-6.6-5.4-12-12-12h-72c-6.6 0-12 5.4-12 12v112c0 6.6-5.4 12-12 12H112c-13.3 0-24-10.7-24-24V312.7c0-3.6 1.6-7 4.4-9.3l188-154.8c4.4-3.6 10.8-3.6 15.3 0l188 154.8c2.7 2.3 4.3 5.7 4.3 9.3zm83.6-60.9L488 182.9V44.4c0-6.6-5.4-12-12-12h-56c-6.6 0-12 5.4-12 12V117l-89.5-73.7c-17.7-14.6-43.3-14.6-61 0L4.4 251.8c-5.1 4.2-5.8 11.8-1.6 16.9l25.5 31c4.2 5.1 11.8 5.8 16.9 1.6l235.2-193.7c4.4-3.6 10.8-3.6 15.3 0l235.2 193.7c5.1 4.2 12.7 3.5 16.9-1.6l25.5-31c4.2-5.2 3.4-12.7-1.7-16.9z"],hospital:[448,512,[],"f0f8","M448 492v20H0v-20c0-6.627 5.373-12 12-12h20V120c0-13.255 10.745-24 24-24h88V24c0-13.255 10.745-24 24-24h112c13.255 0 24 10.745 24 24v72h88c13.255 0 24 10.745 24 24v360h20c6.627 0 12 5.373 12 12zM308 192h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12v-40c0-6.627-5.373-12-12-12zm-168 64h40c6.627 0 12-5.373 12-12v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12zm104 128h-40c-6.627 0-12 5.373-12 12v84h64v-84c0-6.627-5.373-12-12-12zm64-96h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12v-40c0-6.627-5.373-12-12-12zm-116 12c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12v-40zM182 96h26v26a6 6 0 0 0 6 6h20a6 6 0 0 0 6-6V96h26a6 6 0 0 0 6-6V70a6 6 0 0 0-6-6h-26V38a6 6 0 0 0-6-6h-20a6 6 0 0 0-6 6v26h-26a6 6 0 0 0-6 6v20a6 6 0 0 0 6 6z"],hourglass:[384,512,[],"f254","M360 64c13.255 0 24-10.745 24-24V24c0-13.255-10.745-24-24-24H24C10.745 0 0 10.745 0 24v16c0 13.255 10.745 24 24 24 0 90.965 51.016 167.734 120.842 192C75.016 280.266 24 357.035 24 448c-13.255 0-24 10.745-24 24v16c0 13.255 10.745 24 24 24h336c13.255 0 24-10.745 24-24v-16c0-13.255-10.745-24-24-24 0-90.965-51.016-167.734-120.842-192C308.984 231.734 360 154.965 360 64z"],"hourglass-end":[384,512,[],"f253","M360 64c13.255 0 24-10.745 24-24V24c0-13.255-10.745-24-24-24H24C10.745 0 0 10.745 0 24v16c0 13.255 10.745 24 24 24 0 90.965 51.016 167.734 120.842 192C75.016 280.266 24 357.035 24 448c-13.255 0-24 10.745-24 24v16c0 13.255 10.745 24 24 24h336c13.255 0 24-10.745 24-24v-16c0-13.255-10.745-24-24-24 0-90.965-51.016-167.734-120.842-192C308.984 231.734 360 154.965 360 64zM192 208c-57.787 0-104-66.518-104-144h208c0 77.945-46.51 144-104 144z"],"hourglass-half":[384,512,[],"f252","M360 0H24C10.745 0 0 10.745 0 24v16c0 13.255 10.745 24 24 24 0 90.965 51.016 167.734 120.842 192C75.016 280.266 24 357.035 24 448c-13.255 0-24 10.745-24 24v16c0 13.255 10.745 24 24 24h336c13.255 0 24-10.745 24-24v-16c0-13.255-10.745-24-24-24 0-90.965-51.016-167.734-120.842-192C308.984 231.734 360 154.965 360 64c13.255 0 24-10.745 24-24V24c0-13.255-10.745-24-24-24zm-75.078 384H99.08c17.059-46.797 52.096-80 92.92-80 40.821 0 75.862 33.196 92.922 80zm.019-256H99.078C91.988 108.548 88 86.748 88 64h208c0 22.805-3.987 44.587-11.059 64z"],"hourglass-start":[384,512,[],"f251","M360 0H24C10.745 0 0 10.745 0 24v16c0 13.255 10.745 24 24 24 0 90.965 51.016 167.734 120.842 192C75.016 280.266 24 357.035 24 448c-13.255 0-24 10.745-24 24v16c0 13.255 10.745 24 24 24h336c13.255 0 24-10.745 24-24v-16c0-13.255-10.745-24-24-24 0-90.965-51.016-167.734-120.842-192C308.984 231.734 360 154.965 360 64c13.255 0 24-10.745 24-24V24c0-13.255-10.745-24-24-24zm-64 448H88c0-77.458 46.204-144 104-144 57.786 0 104 66.517 104 144z"],"i-cursor":[256,512,[],"f246","M256 52.048V12.065C256 5.496 250.726.148 244.158.066 211.621-.344 166.469.011 128 37.959 90.266.736 46.979-.114 11.913.114 5.318.157 0 5.519 0 12.114v39.645c0 6.687 5.458 12.078 12.145 11.998C38.111 63.447 96 67.243 96 112.182V224H60c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h36v112c0 44.932-56.075 48.031-83.95 47.959C5.404 447.942 0 453.306 0 459.952v39.983c0 6.569 5.274 11.917 11.842 11.999 32.537.409 77.689.054 116.158-37.894 37.734 37.223 81.021 38.073 116.087 37.845 6.595-.043 11.913-5.405 11.913-12V460.24c0-6.687-5.458-12.078-12.145-11.998C217.889 448.553 160 444.939 160 400V288h36c6.627 0 12-5.373 12-12v-40c0-6.627-5.373-12-12-12h-36V112.182c0-44.932 56.075-48.213 83.95-48.142 6.646.018 12.05-5.346 12.05-11.992z"],"id-badge":[384,512,[],"f2c1","M0 464V48C0 21.49 21.49 0 48 0h288c26.51 0 48 21.49 48 48v416c0 26.51-21.49 48-48 48H48c-26.51 0-48-21.49-48-48zm192-144c53.019 0 96-42.981 96-96s-42.981-96-96-96-96 42.981-96 96 42.981 96 96 96zm94.317 17.474l-22.954-7.173C242.437 344.413 217.802 352 192 352s-50.437-7.587-71.363-21.699l-22.954 7.173C77.644 343.736 64 362.295 64 383.289V424c0 13.255 10.745 24 24 24h208c13.255 0 24-10.745 24-24v-40.711c0-20.994-13.644-39.553-33.683-45.815zM352 52v-8c0-6.627-5.373-12-12-12H44c-6.627 0-12 5.373-12 12v8c0 6.627 5.373 12 12 12h296c6.627 0 12-5.373 12-12z"],"id-card":[512,512,[],"f2c2","M464 448H48c-26.51 0-48-21.49-48-48V112c0-26.51 21.49-48 48-48h416c26.51 0 48 21.49 48 48v288c0 26.51-21.49 48-48 48zM160 160c-35.346 0-64 28.654-64 64s28.654 64 64 64 64-28.654 64-64-28.654-64-64-64m79.589 154.53l-28.281-9.427C196.458 314.532 178.856 320 160 320s-36.458-5.468-51.309-14.897L80.41 314.53A24 24 0 0 0 64 337.298V360c0 13.255 10.745 24 24 24h144c13.255 0 24-10.745 24-24v-22.702a24 24 0 0 0-16.411-22.768zM448 340v-8c0-6.627-5.373-12-12-12H300c-6.627 0-12 5.373-12 12v8c0 6.627 5.373 12 12 12h136c6.627 0 12-5.373 12-12zm0-64v-8c0-6.627-5.373-12-12-12H300c-6.627 0-12 5.373-12 12v8c0 6.627 5.373 12 12 12h136c6.627 0 12-5.373 12-12zm0-64v-8c0-6.627-5.373-12-12-12H300c-6.627 0-12 5.373-12 12v8c0 6.627 5.373 12 12 12h136c6.627 0 12-5.373 12-12zm32-96v-8c0-6.627-5.373-12-12-12H44c-6.627 0-12 5.373-12 12v8c0 6.627 5.373 12 12 12h424c6.627 0 12-5.373 12-12z"],image:[512,512,[],"f03e","M464 448H48c-26.51 0-48-21.49-48-48V112c0-26.51 21.49-48 48-48h416c26.51 0 48 21.49 48 48v288c0 26.51-21.49 48-48 48zM112 120c-30.928 0-56 25.072-56 56s25.072 56 56 56 56-25.072 56-56-25.072-56-56-56zM64 384h384V272l-87.515-87.515c-4.686-4.686-12.284-4.686-16.971 0L208 320l-55.515-55.515c-4.686-4.686-12.284-4.686-16.971 0L64 336v48z"],images:[576,512,[],"f302","M480 416v16c0 26.51-21.49 48-48 48H48c-26.51 0-48-21.49-48-48V176c0-26.51 21.49-48 48-48h16v208c0 44.112 35.888 80 80 80h336zm96-80V80c0-26.51-21.49-48-48-48H144c-26.51 0-48 21.49-48 48v256c0 26.51 21.49 48 48 48h384c26.51 0 48-21.49 48-48zM256 128c0 26.51-21.49 48-48 48s-48-21.49-48-48 21.49-48 48-48 48 21.49 48 48zm-96 144l55.515-55.515c4.686-4.686 12.284-4.686 16.971 0L272 256l135.515-135.515c4.686-4.686 12.284-4.686 16.971 0L512 208v112H160v-48z"],inbox:[576,512,[],"f01c","M567.938 243.908L462.25 85.374A48.003 48.003 0 0 0 422.311 64H153.689a48 48 0 0 0-39.938 21.374L8.062 243.908A47.994 47.994 0 0 0 0 270.533V400c0 26.51 21.49 48 48 48h480c26.51 0 48-21.49 48-48V270.533a47.994 47.994 0 0 0-8.062-26.625zM162.252 128h251.497l85.333 128H376l-32 64H232l-32-64H76.918l85.334-128z"],indent:[448,512,[],"f03c","M0 84V44c0-8.837 7.163-16 16-16h416c8.837 0 16 7.163 16 16v40c0 8.837-7.163 16-16 16H16c-8.837 0-16-7.163-16-16zm176 144h256c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H176c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zM16 484h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zm160-128h256c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H176c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zm-52.687-111.313l-96-95.984C17.266 138.652 0 145.776 0 160.016v191.975c0 14.329 17.325 21.304 27.313 11.313l96-95.992c6.249-6.247 6.249-16.377 0-22.625z"],industry:[512,512,[],"f275","M475.115 163.781L336 252.309v-68.28c0-18.916-20.931-30.399-36.885-20.248L160 252.309V56c0-13.255-10.745-24-24-24H24C10.745 32 0 42.745 0 56v400c0 13.255 10.745 24 24 24h464c13.255 0 24-10.745 24-24V184.029c0-18.917-20.931-30.399-36.885-20.248z"],info:[192,512,[],"f129","M20 424.229h20V279.771H20c-11.046 0-20-8.954-20-20V212c0-11.046 8.954-20 20-20h112c11.046 0 20 8.954 20 20v212.229h20c11.046 0 20 8.954 20 20V492c0 11.046-8.954 20-20 20H20c-11.046 0-20-8.954-20-20v-47.771c0-11.046 8.954-20 20-20zM96 0C56.235 0 24 32.235 24 72s32.235 72 72 72 72-32.235 72-72S135.764 0 96 0z"],"info-circle":[512,512,[],"f05a","M256 8C119.043 8 8 119.083 8 256c0 136.997 111.043 248 248 248s248-111.003 248-248C504 119.083 392.957 8 256 8zm0 110c23.196 0 42 18.804 42 42s-18.804 42-42 42-42-18.804-42-42 18.804-42 42-42zm56 254c0 6.627-5.373 12-12 12h-88c-6.627 0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h12v-64h-12c-6.627 0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h64c6.627 0 12 5.373 12 12v100h12c6.627 0 12 5.373 12 12v24z"],italic:[320,512,[],"f033","M204.758 416h-33.849l62.092-320h40.725a16 16 0 0 0 15.704-12.937l6.242-32C297.599 41.184 290.034 32 279.968 32H120.235a16 16 0 0 0-15.704 12.937l-6.242 32C96.362 86.816 103.927 96 113.993 96h33.846l-62.09 320H46.278a16 16 0 0 0-15.704 12.935l-6.245 32C22.402 470.815 29.967 480 40.034 480h158.479a16 16 0 0 0 15.704-12.935l6.245-32c1.927-9.88-5.638-19.065-15.704-19.065z"],key:[512,512,[],"f084","M512 176.001C512 273.203 433.202 352 336 352c-11.22 0-22.19-1.062-32.827-3.069l-24.012 27.014A23.999 23.999 0 0 1 261.223 384H224v40c0 13.255-10.745 24-24 24h-40v40c0 13.255-10.745 24-24 24H24c-13.255 0-24-10.745-24-24v-78.059c0-6.365 2.529-12.47 7.029-16.971l161.802-161.802C163.108 213.814 160 195.271 160 176 160 78.798 238.797.001 335.999 0 433.488-.001 512 78.511 512 176.001zM336 128c0 26.51 21.49 48 48 48s48-21.49 48-48-21.49-48-48-48-48 21.49-48 48z"],keyboard:[576,512,[],"f11c","M528 448H48c-26.51 0-48-21.49-48-48V112c0-26.51 21.49-48 48-48h480c26.51 0 48 21.49 48 48v288c0 26.51-21.49 48-48 48zM128 180v-40c0-6.627-5.373-12-12-12H76c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm-336 96v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm-336 96v-40c0-6.627-5.373-12-12-12H76c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm288 0v-40c0-6.627-5.373-12-12-12H172c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h232c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12z"],language:[640,512,[],"f1ab","M304 416H24c-13.255 0-24-10.745-24-24V120c0-13.255 10.745-24 24-24h280v320zm-120.676-72.622A12 12 0 0 0 194.839 352h22.863c8.22 0 14.007-8.078 11.362-15.861L171.61 167.085a12 12 0 0 0-11.362-8.139h-32.489a12.001 12.001 0 0 0-11.362 8.139L58.942 336.139C56.297 343.922 62.084 352 70.304 352h22.805a12 12 0 0 0 11.535-8.693l9.118-31.807h60.211l9.351 31.878zm-39.051-140.42s4.32 21.061 7.83 33.21l10.8 37.531h-38.07l11.07-37.531c3.51-12.15 7.83-33.21 7.83-33.21h.54zM616 416H336V96h280c13.255 0 24 10.745 24 24v272c0 13.255-10.745 24-24 24zm-36-228h-64v-16c0-6.627-5.373-12-12-12h-16c-6.627 0-12 5.373-12 12v16h-64c-6.627 0-12 5.373-12 12v16c0 6.627 5.373 12 12 12h114.106c-6.263 14.299-16.518 28.972-30.023 43.206-6.56-6.898-12.397-13.91-17.365-20.933-3.639-5.144-10.585-6.675-15.995-3.446l-7.28 4.346-6.498 3.879c-5.956 3.556-7.693 11.421-3.735 17.117 6.065 8.729 13.098 17.336 20.984 25.726-8.122 6.226-16.841 12.244-26.103 17.964-5.521 3.41-7.381 10.556-4.162 16.19l7.941 13.896c3.362 5.883 10.935 7.826 16.706 4.276 12.732-7.831 24.571-16.175 35.443-24.891 10.917 8.761 22.766 17.102 35.396 24.881 5.774 3.556 13.353 1.618 16.717-4.27l7.944-13.903c3.213-5.623 1.37-12.76-4.135-16.171a312.737 312.737 0 0 1-26.06-18.019c21.024-22.425 35.768-46.289 42.713-69.85H580c6.627 0 12-5.373 12-12v-16c0-6.625-5.373-11.998-12-11.998z"],laptop:[640,512,[],"f109","M512 64v256H128V64h384m16-64H112C85.5 0 64 21.5 64 48v288c0 26.5 21.5 48 48 48h416c26.5 0 48-21.5 48-48V48c0-26.5-21.5-48-48-48zm100 416H389.5c-3 0-5.5 2.1-5.9 5.1C381.2 436.3 368 448 352 448h-64c-16 0-29.2-11.7-31.6-26.9-.5-2.9-3-5.1-5.9-5.1H12c-6.6 0-12 5.4-12 12v36c0 26.5 21.5 48 48 48h544c26.5 0 48-21.5 48-48v-36c0-6.6-5.4-12-12-12z"],leaf:[576,512,[],"f06c","M395.4 420.8c-43.4 21.6-91.9 34.4-140.8 34.4-82.2 0-151.1-40.1-151.1-40.1-16.1 0-35.4 64.9-63.3 64.9-27 0-40.2-24-40.2-38.5 0-33.1 63.6-58.9 63.6-77.3 0 0-12.5-21.2-12.5-59.2 0-101.2 81.3-173.4 172.6-203.3 65.9-21.6 206 3.5 250.7-38.5C492.1 47 500.8 32 527.8 32c36.3 0 48.2 93.2 48.2 120.3 0 110.9-54.5 206.5-180.6 268.5zm-254.3-75.6c63.5-89.9 144.5-128.8 257.7-120 8.8.7 16.5-5.9 17.2-14.7.7-8.8-5.9-16.5-14.7-17.2-124-9.6-215.9 33.9-286.3 133.5-5.1 7.2-3.4 17.2 3.8 22.3 7.2 5.1 17.2 3.4 22.3-3.9z"],lemon:[512,512,[],"f094","M489.038 22.963C465.944-.13 434.648-5.93 413.947 6.129c-58.906 34.312-181.25-53.077-321.073 86.746S40.441 355.041 6.129 413.945c-12.059 20.702-6.26 51.999 16.833 75.093 23.095 23.095 54.392 28.891 75.095 16.832 58.901-34.31 181.246 53.079 321.068-86.743S471.56 156.96 505.871 98.056c12.059-20.702 6.261-51.999-16.833-75.093zM243.881 95.522c-58.189 14.547-133.808 90.155-148.358 148.358-1.817 7.27-8.342 12.124-15.511 12.124-1.284 0-2.59-.156-3.893-.481-8.572-2.144-13.784-10.83-11.642-19.403C81.901 166.427 166.316 81.93 236.119 64.478c8.575-2.143 17.261 3.069 19.403 11.642s-3.069 17.259-11.641 19.402z"],"level-down-alt":[320,512,[],"f3be","M313.553 392.331L209.587 504.334c-9.485 10.214-25.676 10.229-35.174 0L70.438 392.331C56.232 377.031 67.062 352 88.025 352H152V80H68.024a11.996 11.996 0 0 1-8.485-3.515l-56-56C-4.021 12.926 1.333 0 12.024 0H208c13.255 0 24 10.745 24 24v328h63.966c20.878 0 31.851 24.969 17.587 40.331z"],"level-up-alt":[320,512,[],"f3bf","M313.553 119.669L209.587 7.666c-9.485-10.214-25.676-10.229-35.174 0L70.438 119.669C56.232 134.969 67.062 160 88.025 160H152v272H68.024a11.996 11.996 0 0 0-8.485 3.515l-56 56C-4.021 499.074 1.333 512 12.024 512H208c13.255 0 24-10.745 24-24V160h63.966c20.878 0 31.851-24.969 17.587-40.331z"],"life-ring":[512,512,[],"f1cd","M256 8C119.033 8 8 119.033 8 256s111.033 248 248 248 248-111.033 248-248S392.967 8 256 8zm173.696 119.559l-63.399 63.399c-10.987-18.559-26.67-34.252-45.255-45.255l63.399-63.399a218.396 218.396 0 0 1 45.255 45.255zM256 352c-53.019 0-96-42.981-96-96s42.981-96 96-96 96 42.981 96 96-42.981 96-96 96zM127.559 82.304l63.399 63.399c-18.559 10.987-34.252 26.67-45.255 45.255l-63.399-63.399a218.372 218.372 0 0 1 45.255-45.255zM82.304 384.441l63.399-63.399c10.987 18.559 26.67 34.252 45.255 45.255l-63.399 63.399a218.396 218.396 0 0 1-45.255-45.255zm302.137 45.255l-63.399-63.399c18.559-10.987 34.252-26.67 45.255-45.255l63.399 63.399a218.403 218.403 0 0 1-45.255 45.255z"],lightbulb:[384,512,[],"f0eb","M272 428v28c0 10.449-6.68 19.334-16 22.629V488c0 13.255-10.745 24-24 24h-80c-13.255 0-24-10.745-24-24v-9.371c-9.32-3.295-16-12.18-16-22.629v-28c0-6.627 5.373-12 12-12h136c6.627 0 12 5.373 12 12zm-143.107-44c-9.907 0-18.826-6.078-22.376-15.327C67.697 267.541 16 277.731 16 176 16 78.803 94.805 0 192 0s176 78.803 176 176c0 101.731-51.697 91.541-90.516 192.673-3.55 9.249-12.47 15.327-22.376 15.327H128.893zM112 176c0-44.112 35.888-80 80-80 8.837 0 16-7.164 16-16s-7.163-16-16-16c-61.757 0-112 50.243-112 112 0 8.836 7.164 16 16 16s16-7.164 16-16z"],link:[512,512,[],"f0c1","M326.612 185.391c59.747 59.809 58.927 155.698.36 214.59-.11.12-.24.25-.36.37l-67.2 67.2c-59.27 59.27-155.699 59.262-214.96 0-59.27-59.26-59.27-155.7 0-214.96l37.106-37.106c9.84-9.84 26.786-3.3 27.294 10.606.648 17.722 3.826 35.527 9.69 52.721 1.986 5.822.567 12.262-3.783 16.612l-13.087 13.087c-28.026 28.026-28.905 73.66-1.155 101.96 28.024 28.579 74.086 28.749 102.325.51l67.2-67.19c28.191-28.191 28.073-73.757 0-101.83-3.701-3.694-7.429-6.564-10.341-8.569a16.037 16.037 0 0 1-6.947-12.606c-.396-10.567 3.348-21.456 11.698-29.806l21.054-21.055c5.521-5.521 14.182-6.199 20.584-1.731a152.482 152.482 0 0 1 20.522 17.197zM467.547 44.449c-59.261-59.262-155.69-59.27-214.96 0l-67.2 67.2c-.12.12-.25.25-.36.37-58.566 58.892-59.387 154.781.36 214.59a152.454 152.454 0 0 0 20.521 17.196c6.402 4.468 15.064 3.789 20.584-1.731l21.054-21.055c8.35-8.35 12.094-19.239 11.698-29.806a16.037 16.037 0 0 0-6.947-12.606c-2.912-2.005-6.64-4.875-10.341-8.569-28.073-28.073-28.191-73.639 0-101.83l67.2-67.19c28.239-28.239 74.3-28.069 102.325.51 27.75 28.3 26.872 73.934-1.155 101.96l-13.087 13.087c-4.35 4.35-5.769 10.79-3.783 16.612 5.864 17.194 9.042 34.999 9.69 52.721.509 13.906 17.454 20.446 27.294 10.606l37.106-37.106c59.271-59.259 59.271-155.699.001-214.959z"],"lira-sign":[384,512,[],"f195","M371.994 256h-48.019C317.64 256 312 260.912 312 267.246 312 368 230.179 416 144 416V256.781l134.603-29.912A12 12 0 0 0 288 215.155v-40.976c0-7.677-7.109-13.38-14.603-11.714L144 191.219V160.78l134.603-29.912A12 12 0 0 0 288 119.154V78.179c0-7.677-7.109-13.38-14.603-11.714L144 95.219V44c0-6.627-5.373-12-12-12H76c-6.627 0-12 5.373-12 12v68.997L9.397 125.131A12 12 0 0 0 0 136.845v40.976c0 7.677 7.109 13.38 14.603 11.714L64 178.558v30.439L9.397 221.131A12 12 0 0 0 0 232.845v40.976c0 7.677 7.109 13.38 14.603 11.714L64 274.558V468c0 6.627 5.373 12 12 12h79.583c134.091 0 223.255-77.834 228.408-211.592.261-6.782-5.211-12.408-11.997-12.408z"],list:[512,512,[],"f03a","M128 116V76c0-8.837 7.163-16 16-16h352c8.837 0 16 7.163 16 16v40c0 8.837-7.163 16-16 16H144c-8.837 0-16-7.163-16-16zm16 176h352c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H144c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zm0 160h352c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H144c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zM16 144h64c8.837 0 16-7.163 16-16V64c0-8.837-7.163-16-16-16H16C7.163 48 0 55.163 0 64v64c0 8.837 7.163 16 16 16zm0 160h64c8.837 0 16-7.163 16-16v-64c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v64c0 8.837 7.163 16 16 16zm0 160h64c8.837 0 16-7.163 16-16v-64c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v64c0 8.837 7.163 16 16 16z"],"list-alt":[512,512,[],"f022","M464 480H48c-26.51 0-48-21.49-48-48V80c0-26.51 21.49-48 48-48h416c26.51 0 48 21.49 48 48v352c0 26.51-21.49 48-48 48zM128 120c-22.091 0-40 17.909-40 40s17.909 40 40 40 40-17.909 40-40-17.909-40-40-40zm0 96c-22.091 0-40 17.909-40 40s17.909 40 40 40 40-17.909 40-40-17.909-40-40-40zm0 96c-22.091 0-40 17.909-40 40s17.909 40 40 40 40-17.909 40-40-17.909-40-40-40zm288-136v-32c0-6.627-5.373-12-12-12H204c-6.627 0-12 5.373-12 12v32c0 6.627 5.373 12 12 12h200c6.627 0 12-5.373 12-12zm0 96v-32c0-6.627-5.373-12-12-12H204c-6.627 0-12 5.373-12 12v32c0 6.627 5.373 12 12 12h200c6.627 0 12-5.373 12-12zm0 96v-32c0-6.627-5.373-12-12-12H204c-6.627 0-12 5.373-12 12v32c0 6.627 5.373 12 12 12h200c6.627 0 12-5.373 12-12z"],"list-ol":[512,512,[],"f0cb","M3.263 139.527c0-7.477 3.917-11.572 11.573-11.572h15.131V88.078c0-5.163.534-10.503.534-10.503h-.356s-1.779 2.67-2.848 3.738c-4.451 4.273-10.504 4.451-15.666-1.068l-5.518-6.231c-5.342-5.341-4.984-11.216.534-16.379l21.72-19.938C32.815 33.602 36.732 32 42.785 32H54.89c7.656 0 11.749 3.916 11.749 11.572v84.384h15.488c7.655 0 11.572 4.094 11.572 11.572v8.901c0 7.477-3.917 11.572-11.572 11.572H14.836c-7.656 0-11.573-4.095-11.573-11.572v-8.902zM2.211 304.591c0-47.278 50.955-56.383 50.955-69.165 0-7.18-5.954-8.755-9.28-8.755-3.153 0-6.479 1.051-9.455 3.852-5.079 4.903-10.507 7.004-16.111 2.451l-8.579-6.829c-5.779-4.553-7.18-9.805-2.803-15.409C13.592 201.981 26.025 192 47.387 192c19.437 0 44.476 10.506 44.476 39.573 0 38.347-46.753 46.402-48.679 56.909h39.049c7.529 0 11.557 4.027 11.557 11.382v8.755c0 7.354-4.028 11.382-11.557 11.382h-67.94c-7.005 0-12.083-4.028-12.083-11.382v-4.028zM5.654 454.61l5.603-9.28c3.853-6.654 9.105-7.004 15.584-3.152 4.903 2.101 9.63 3.152 14.359 3.152 10.155 0 14.358-3.502 14.358-8.23 0-6.654-5.604-9.106-15.934-9.106h-4.728c-5.954 0-9.28-2.101-12.258-7.88l-1.05-1.926c-2.451-4.728-1.226-9.806 2.801-14.884l5.604-7.004c6.829-8.405 12.257-13.483 12.257-13.483v-.35s-4.203 1.051-12.608 1.051H16.685c-7.53 0-11.383-4.028-11.383-11.382v-8.755c0-7.53 3.853-11.382 11.383-11.382h58.484c7.529 0 11.382 4.027 11.382 11.382v3.327c0 5.778-1.401 9.806-5.079 14.183l-17.509 20.137c19.611 5.078 28.716 20.487 28.716 34.845 0 21.363-14.358 44.126-48.503 44.126-16.636 0-28.192-4.728-35.896-9.455-5.779-4.202-6.304-9.805-2.626-15.934zM144 132h352c8.837 0 16-7.163 16-16V76c0-8.837-7.163-16-16-16H144c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zm0 160h352c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H144c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zm0 160h352c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H144c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16z"],"list-ul":[512,512,[],"f0ca","M96 96c0 26.51-21.49 48-48 48S0 122.51 0 96s21.49-48 48-48 48 21.49 48 48zM48 208c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.49-48-48-48zm0 160c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.49-48-48-48zm96-236h352c8.837 0 16-7.163 16-16V76c0-8.837-7.163-16-16-16H144c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zm0 160h352c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H144c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zm0 160h352c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H144c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16z"],"location-arrow":[512,512,[],"f124","M443.683 4.529L27.818 196.418C-18.702 217.889-3.39 288 47.933 288H224v175.993c0 51.727 70.161 66.526 91.582 20.115L507.38 68.225c18.905-40.961-23.752-82.133-63.697-63.696z"],lock:[448,512,[],"f023","M400 224h-24v-72C376 68.2 307.8 0 224 0S72 68.2 72 152v72H48c-26.5 0-48 21.5-48 48v192c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V272c0-26.5-21.5-48-48-48zm-104 0H152v-72c0-39.7 32.3-72 72-72s72 32.3 72 72v72z"],"lock-open":[576,512,[],"f3c1","M423.5 0C339.5.3 272 69.5 272 153.5V224H48c-26.5 0-48 21.5-48 48v192c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V272c0-26.5-21.5-48-48-48h-48v-71.1c0-39.6 31.7-72.5 71.3-72.9 40-.4 72.7 32.1 72.7 72v80c0 13.3 10.7 24 24 24h32c13.3 0 24-10.7 24-24v-80C576 68 507.5-.3 423.5 0z"],"long-arrow-alt-down":[256,512,[],"f309","M168 345.941V44c0-6.627-5.373-12-12-12h-56c-6.627 0-12 5.373-12 12v301.941H41.941c-21.382 0-32.09 25.851-16.971 40.971l86.059 86.059c9.373 9.373 24.569 9.373 33.941 0l86.059-86.059c15.119-15.119 4.411-40.971-16.971-40.971H168z"],"long-arrow-alt-left":[448,512,[],"f30a","M134.059 296H436c6.627 0 12-5.373 12-12v-56c0-6.627-5.373-12-12-12H134.059v-46.059c0-21.382-25.851-32.09-40.971-16.971L7.029 239.029c-9.373 9.373-9.373 24.569 0 33.941l86.059 86.059c15.119 15.119 40.971 4.411 40.971-16.971V296z"],"long-arrow-alt-right":[448,512,[],"f30b","M313.941 216H12c-6.627 0-12 5.373-12 12v56c0 6.627 5.373 12 12 12h301.941v46.059c0 21.382 25.851 32.09 40.971 16.971l86.059-86.059c9.373-9.373 9.373-24.569 0-33.941l-86.059-86.059c-15.119-15.119-40.971-4.411-40.971 16.971V216z"],"long-arrow-alt-up":[256,512,[],"f30c","M88 166.059V468c0 6.627 5.373 12 12 12h56c6.627 0 12-5.373 12-12V166.059h46.059c21.382 0 32.09-25.851 16.971-40.971l-86.059-86.059c-9.373-9.373-24.569-9.373-33.941 0l-86.059 86.059c-15.119 15.119-4.411 40.971 16.971 40.971H88z"],"low-vision":[576,512,[],"f2a8","M569.344 231.631C512.96 135.949 407.81 72 288 72c-28.468 0-56.102 3.619-82.451 10.409L152.778 10.24c-7.601-10.858-22.564-13.5-33.423-5.9l-13.114 9.178c-10.86 7.601-13.502 22.566-5.9 33.426l43.131 58.395C89.449 131.73 40.228 174.683 6.682 231.581c-.01.017-.023.033-.034.05-8.765 14.875-8.964 33.528 0 48.739 38.5 65.332 99.742 115.862 172.859 141.349L55.316 244.302A272.194 272.194 0 0 1 83.61 208.39l119.4 170.58h.01l40.63 58.04a330.055 330.055 0 0 0 78.94 1.17l-189.98-271.4a277.628 277.628 0 0 1 38.777-21.563l251.836 356.544c7.601 10.858 22.564 13.499 33.423 5.9l13.114-9.178c10.86-7.601 13.502-22.567 5.9-33.426l-43.12-58.377-.007-.009c57.161-27.978 104.835-72.04 136.81-126.301a47.938 47.938 0 0 0 .001-48.739zM390.026 345.94l-19.066-27.23c24.682-32.567 27.711-76.353 8.8-111.68v.03c0 23.65-19.17 42.82-42.82 42.82-23.828 0-42.82-19.349-42.82-42.82 0-23.65 19.17-42.82 42.82-42.82h.03c-24.75-13.249-53.522-15.643-79.51-7.68l-19.068-27.237C253.758 123.306 270.488 120 288 120c75.162 0 136 60.826 136 136 0 34.504-12.833 65.975-33.974 89.94z"],magic:[512,512,[],"f0d0","M101.1 505L7 410.9c-9.4-9.4-9.4-24.6 0-33.9L377 7c9.4-9.4 24.6-9.4 33.9 0l94.1 94.1c9.4 9.4 9.4 24.6 0 33.9L135 505c-9.3 9.3-24.5 9.3-33.9 0zM304 159.2l48.8 48.8 89.9-89.9-48.8-48.8-89.9 89.9zM138.9 39.3l-11.7 23.8-26.2 3.8c-4.7.7-6.6 6.5-3.2 9.8l19 18.5-4.5 26.1c-.8 4.7 4.1 8.3 8.3 6.1L144 115l23.4 12.3c4.2 2.2 9.1-1.4 8.3-6.1l-4.5-26.1 19-18.5c3.4-3.3 1.5-9.1-3.2-9.8L160.8 63l-11.7-23.8c-2-4.1-8.1-4.1-10.2.1zm97.7-20.7l-7.8 15.8-17.5 2.6c-3.1.5-4.4 4.3-2.1 6.5l12.6 12.3-3 17.4c-.5 3.1 2.8 5.5 5.6 4L240 69l15.6 8.2c2.8 1.5 6.1-.9 5.6-4l-3-17.4 12.6-12.3c2.3-2.2 1-6.1-2.1-6.5l-17.5-2.5-7.8-15.8c-1.4-3-5.4-3-6.8-.1zm-192 0l-7.8 15.8L19.3 37c-3.1.5-4.4 4.3-2.1 6.5l12.6 12.3-3 17.4c-.5 3.1 2.8 5.5 5.6 4L48 69l15.6 8.2c2.8 1.5 6.1-.9 5.6-4l-3-17.4 12.6-12.3c2.3-2.2 1-6.1-2.1-6.5l-17.5-2.5-7.8-15.8c-1.4-3-5.4-3-6.8-.1zm416 223.5l-7.8 15.8-17.5 2.5c-3.1.5-4.4 4.3-2.1 6.5l12.6 12.3-3 17.4c-.5 3.1 2.8 5.5 5.6 4l15.6-8.2 15.6 8.2c2.8 1.5 6.1-.9 5.6-4l-3-17.4 12.6-12.3c2.3-2.2 1-6.1-2.1-6.5l-17.5-2.5-7.8-15.8c-1.4-2.8-5.4-2.8-6.8 0z"],magnet:[512,512,[],"f076","M164.1 160H12c-6.6 0-12-5.4-12-12V68c0-19.9 16.1-36 36-36h104c19.9 0 36 16.1 36 36v80c.1 6.6-5.3 12-11.9 12zm348-12V67.9c0-19.9-16.1-36-36-36h-104c-19.9 0-36 16.1-36 36v80c0 6.6 5.4 12 12 12h152c6.6.1 12-5.3 12-11.9zm-164 44c-6.6 0-12 5.4-12 12v52c0 128.1-160 127.9-160 0v-52c0-6.6-5.4-12-12-12h-152c-6.7 0-12 5.4-12 12.1.1 21.4.6 40.3 0 53.3C.1 408 136.3 504 256.9 504 377.5 504 512 408 512 257.3c-.6-12.8-.2-33 0-53.2 0-6.7-5.3-12.1-12-12.1H348.1z"],male:[192,512,[],"f183","M96 0c35.346 0 64 28.654 64 64s-28.654 64-64 64-64-28.654-64-64S60.654 0 96 0m48 144h-11.36c-22.711 10.443-49.59 10.894-73.28 0H48c-26.51 0-48 21.49-48 48v136c0 13.255 10.745 24 24 24h16v136c0 13.255 10.745 24 24 24h64c13.255 0 24-10.745 24-24V352h16c13.255 0 24-10.745 24-24V192c0-26.51-21.49-48-48-48z"],map:[576,512,[],"f279","M576 56.015v335.97a23.998 23.998 0 0 1-13.267 21.466l-128 64C418.948 485.344 400 473.992 400 455.985v-335.97a23.998 23.998 0 0 1 13.267-21.466l128-64C557.052 26.656 576 38.008 576 56.015zm-206.253 42.07l-144-64c-15.751-7-33.747 4.461-33.747 21.932v335.967a24 24 0 0 0 14.253 21.931l144 64c15.751 7 33.747-4.461 33.747-21.931V120.017a24 24 0 0 0-14.253-21.932zm-228.48-63.536l-128 63.985A23.998 23.998 0 0 0 0 120v335.985c0 18.007 18.948 29.359 34.733 21.466l128-63.985A23.998 23.998 0 0 0 176 392V56.015c0-18.007-18.948-29.359-34.733-21.466z"],"map-marker":[384,512,[],"f041","M172.268 501.67C26.97 291.031 0 269.413 0 192 0 85.961 85.961 0 192 0s192 85.961 192 192c0 77.413-26.97 99.031-172.268 309.67-9.535 13.774-29.93 13.773-39.464 0z"],"map-marker-alt":[384,512,[],"f3c5","M172.268 501.67C26.97 291.031 0 269.413 0 192 0 85.961 85.961 0 192 0s192 85.961 192 192c0 77.413-26.97 99.031-172.268 309.67-9.535 13.774-29.93 13.773-39.464 0zM192 272c44.183 0 80-35.817 80-80s-35.817-80-80-80-80 35.817-80 80 35.817 80 80 80z"],"map-pin":[320,512,[],"f276","M192 300.813v172.82l-22.015 33.023c-4.75 7.125-15.219 7.125-19.969 0L128 473.633v-172.82a162.221 162.221 0 0 0 64 0zM160 0c79.529 0 144 64.471 144 144s-64.471 144-144 144S16 223.529 16 144 80.471 0 160 0M80 136c0-39.701 32.299-72 72-72a8 8 0 0 0 0-16c-48.523 0-88 39.477-88 88a8 8 0 0 0 16 0z"],"map-signs":[512,512,[],"f277","M487.515 104.485L439.03 152.97a23.998 23.998 0 0 1-16.97 7.029H56c-13.255 0-24-10.745-24-24V56c0-13.255 10.745-24 24-24h160v-8c0-13.255 10.745-24 24-24h32c13.255 0 24 10.745 24 24v8h126.059a24 24 0 0 1 16.97 7.029l48.485 48.485c4.687 4.687 4.687 12.285.001 16.971zM216 368v120c0 13.255 10.745 24 24 24h32c13.255 0 24-10.745 24-24V368h-80zm240-144H296v-48h-80v48H89.941a24 24 0 0 0-16.97 7.029l-48.485 48.485c-4.686 4.686-4.686 12.284 0 16.971l48.485 48.485a23.998 23.998 0 0 0 16.97 7.029H456c13.255 0 24-10.745 24-24v-80C480 234.745 469.255 224 456 224z"],mars:[384,512,[],"f222","M372 64h-79c-10.7 0-16 12.9-8.5 20.5l16.9 16.9-80.7 80.7c-22.2-14-48.5-22.1-76.7-22.1C64.5 160 0 224.5 0 304s64.5 144 144 144 144-64.5 144-144c0-28.2-8.1-54.5-22.1-76.7l80.7-80.7 16.9 16.9c7.6 7.6 20.5 2.2 20.5-8.5V76c0-6.6-5.4-12-12-12zM144 384c-44.1 0-80-35.9-80-80s35.9-80 80-80 80 35.9 80 80-35.9 80-80 80z"],"mars-double":[512,512,[],"f227","M340 0h-79c-10.7 0-16 12.9-8.5 20.5l16.9 16.9-48.7 48.7C198.5 72.1 172.2 64 144 64 64.5 64 0 128.5 0 208s64.5 144 144 144 144-64.5 144-144c0-28.2-8.1-54.5-22.1-76.7l48.7-48.7 16.9 16.9c2.4 2.4 5.5 3.5 8.4 3.5 6.2 0 12.1-4.8 12.1-12V12c0-6.6-5.4-12-12-12zM144 288c-44.1 0-80-35.9-80-80s35.9-80 80-80 80 35.9 80 80-35.9 80-80 80zm356-128.1h-79c-10.7 0-16 12.9-8.5 20.5l16.9 16.9-48.7 48.7c-18.2-11.4-39-18.9-61.5-21.3-2.1 21.8-8.2 43.3-18.4 63.3 1.1 0 2.2-.1 3.2-.1 44.1 0 80 35.9 80 80s-35.9 80-80 80-80-35.9-80-80c0-1.1 0-2.2.1-3.2-20 10.2-41.5 16.4-63.3 18.4C168.4 455.6 229.6 512 304 512c79.5 0 144-64.5 144-144 0-28.2-8.1-54.5-22.1-76.7l48.7-48.7 16.9 16.9c2.4 2.4 5.4 3.5 8.4 3.5 6.2 0 12.1-4.8 12.1-12v-79c0-6.7-5.4-12.1-12-12.1z"],"mars-stroke":[384,512,[],"f229","M372 64h-79c-10.7 0-16 12.9-8.5 20.5l16.9 16.9-17.5 17.5-14.1-14.1c-4.7-4.7-12.3-4.7-17 0L224.5 133c-4.7 4.7-4.7 12.3 0 17l14.1 14.1-18 18c-22.2-14-48.5-22.1-76.7-22.1C64.5 160 0 224.5 0 304s64.5 144 144 144 144-64.5 144-144c0-28.2-8.1-54.5-22.1-76.7l18-18 14.1 14.1c4.7 4.7 12.3 4.7 17 0l28.3-28.3c4.7-4.7 4.7-12.3 0-17L329.2 164l17.5-17.5 16.9 16.9c7.6 7.6 20.5 2.2 20.5-8.5V76c-.1-6.6-5.5-12-12.1-12zM144 384c-44.1 0-80-35.9-80-80s35.9-80 80-80 80 35.9 80 80-35.9 80-80 80z"],"mars-stroke-h":[480,512,[],"f22b","M476.2 247.5l-55.9-55.9c-7.6-7.6-20.5-2.2-20.5 8.5V224H376v-20c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v20h-27.6c-5.8-25.6-18.7-49.9-38.6-69.8C189.6 98 98.4 98 42.2 154.2c-56.2 56.2-56.2 147.4 0 203.6 56.2 56.2 147.4 56.2 203.6 0 19.9-19.9 32.8-44.2 38.6-69.8H312v20c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12v-20h23.9v23.9c0 10.7 12.9 16 20.5 8.5l55.9-55.9c4.6-4.7 4.6-12.3-.1-17zm-275.6 65.1c-31.2 31.2-81.9 31.2-113.1 0-31.2-31.2-31.2-81.9 0-113.1 31.2-31.2 81.9-31.2 113.1 0 31.2 31.1 31.2 81.9 0 113.1z"],"mars-stroke-v":[288,512,[],"f22a","M245.8 234.2c-19.9-19.9-44.2-32.8-69.8-38.6v-25.4h20c6.6 0 12-5.4 12-12v-40c0-6.6-5.4-12-12-12h-20V81.4h23.9c10.7 0 16-12.9 8.5-20.5L152.5 5.1c-4.7-4.7-12.3-4.7-17 0L79.6 61c-7.6 7.6-2.2 20.5 8.5 20.5H112v24.7H92c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h20v25.4c-25.6 5.8-49.9 18.7-69.8 38.6-56.2 56.2-56.2 147.4 0 203.6 56.2 56.2 147.4 56.2 203.6 0 56.3-56.2 56.3-147.4 0-203.6zm-45.2 158.4c-31.2 31.2-81.9 31.2-113.1 0-31.2-31.2-31.2-81.9 0-113.1 31.2-31.2 81.9-31.2 113.1 0 31.2 31.1 31.2 81.9 0 113.1z"],medkit:[512,512,[],"f0fa","M96 480h320V128h-32V80c0-26.51-21.49-48-48-48H176c-26.51 0-48 21.49-48 48v48H96v352zm96-384h128v32H192V96zm320 80v256c0 26.51-21.49 48-48 48h-16V128h16c26.51 0 48 21.49 48 48zM64 480H48c-26.51 0-48-21.49-48-48V176c0-26.51 21.49-48 48-48h16v352zm288-208v32c0 8.837-7.163 16-16 16h-48v48c0 8.837-7.163 16-16 16h-32c-8.837 0-16-7.163-16-16v-48h-48c-8.837 0-16-7.163-16-16v-32c0-8.837 7.163-16 16-16h48v-48c0-8.837 7.163-16 16-16h32c8.837 0 16 7.163 16 16v48h48c8.837 0 16 7.163 16 16z"],meh:[512,512,[],"f11a","M504 256c0 136.967-111.033 248-248 248S8 392.967 8 256 119.033 8 256 8s248 111.033 248 248zm-396-64c0 37.497 30.503 68 68 68s68-30.503 68-68-30.503-68-68-68-68 30.503-68 68zm160.5 0c0 37.221 30.279 67.5 67.5 67.5s67.5-30.279 67.5-67.5-30.279-67.5-67.5-67.5-67.5 30.279-67.5 67.5zm67.5-48a47.789 47.789 0 0 0-22.603 5.647h.015c10.916 0 19.765 8.849 19.765 19.765s-8.849 19.765-19.765 19.765-19.765-8.849-19.765-19.765v-.015A47.789 47.789 0 0 0 288 192c0 26.51 21.49 48 48 48s48-21.49 48-48-21.49-48-48-48zm-160 0a47.789 47.789 0 0 0-22.603 5.647h.015c10.916 0 19.765 8.849 19.765 19.765s-8.849 19.765-19.765 19.765-19.765-8.849-19.765-19.765v-.015A47.789 47.789 0 0 0 128 192c0 26.51 21.49 48 48 48s48-21.49 48-48-21.49-48-48-48zm160 208H176c-21.178 0-21.169 32 0 32h160c21.178 0 21.169-32 0-32z"],mercury:[288,512,[],"f223","M288 208c0-44.2-19.9-83.7-51.2-110.1 2.5-1.8 4.9-3.8 7.2-5.8 24.7-21.2 39.8-48.8 43.2-78.8.9-7.1-4.7-13.3-11.9-13.3h-40.5C229 0 224.1 4.1 223 9.8c-2.4 12.5-9.6 24.3-20.7 33.8C187 56.8 166.3 64 144 64s-43-7.2-58.4-20.4C74.5 34.1 67.4 22.3 64.9 9.8 63.8 4.1 58.9 0 53.2 0H12.7C5.5 0-.1 6.2.8 13.3 4.2 43.4 19.2 71 44 92.2c2.3 2 4.7 3.9 7.2 5.8C19.9 124.3 0 163.8 0 208c0 68.5 47.9 125.9 112 140.4V400H76c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h36v36c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12v-36h36c6.6 0 12-5.4 12-12v-40c0-6.6-5.4-12-12-12h-36v-51.6c64.1-14.5 112-71.9 112-140.4zm-224 0c0-44.1 35.9-80 80-80s80 35.9 80 80-35.9 80-80 80-80-35.9-80-80z"],microchip:[512,512,[],"f2db","M416 48v416c0 26.51-21.49 48-48 48H144c-26.51 0-48-21.49-48-48V48c0-26.51 21.49-48 48-48h224c26.51 0 48 21.49 48 48zm96 58v12a6 6 0 0 1-6 6h-18v6a6 6 0 0 1-6 6h-42V88h42a6 6 0 0 1 6 6v6h18a6 6 0 0 1 6 6zm0 96v12a6 6 0 0 1-6 6h-18v6a6 6 0 0 1-6 6h-42v-48h42a6 6 0 0 1 6 6v6h18a6 6 0 0 1 6 6zm0 96v12a6 6 0 0 1-6 6h-18v6a6 6 0 0 1-6 6h-42v-48h42a6 6 0 0 1 6 6v6h18a6 6 0 0 1 6 6zm0 96v12a6 6 0 0 1-6 6h-18v6a6 6 0 0 1-6 6h-42v-48h42a6 6 0 0 1 6 6v6h18a6 6 0 0 1 6 6zM30 376h42v48H30a6 6 0 0 1-6-6v-6H6a6 6 0 0 1-6-6v-12a6 6 0 0 1 6-6h18v-6a6 6 0 0 1 6-6zm0-96h42v48H30a6 6 0 0 1-6-6v-6H6a6 6 0 0 1-6-6v-12a6 6 0 0 1 6-6h18v-6a6 6 0 0 1 6-6zm0-96h42v48H30a6 6 0 0 1-6-6v-6H6a6 6 0 0 1-6-6v-12a6 6 0 0 1 6-6h18v-6a6 6 0 0 1 6-6zm0-96h42v48H30a6 6 0 0 1-6-6v-6H6a6 6 0 0 1-6-6v-12a6 6 0 0 1 6-6h18v-6a6 6 0 0 1 6-6z"],microphone:[384,512,[],"f130","M96 256V96c0-53.019 42.981-96 96-96s96 42.981 96 96v160c0 53.019-42.981 96-96 96s-96-42.981-96-96zm252-56h-24c-6.627 0-12 5.373-12 12v42.68c0 66.217-53.082 120.938-119.298 121.318C126.213 376.38 72 322.402 72 256v-44c0-6.627-5.373-12-12-12H36c-6.627 0-12 5.373-12 12v44c0 84.488 62.693 154.597 144 166.278V468h-68c-6.627 0-12 5.373-12 12v20c0 6.627 5.373 12 12 12h184c6.627 0 12-5.373 12-12v-20c0-6.627-5.373-12-12-12h-68v-45.722c81.307-11.681 144-81.79 144-166.278v-44c0-6.627-5.373-12-12-12z"],"microphone-slash":[512,512,[],"f131","M421.45 285.195L376 239.746V212c0-6.627 5.373-12 12-12h24c6.627 0 12 5.373 12 12v44c0 9.957-.881 19.71-2.55 29.195zM352 96c0-53.019-42.981-96-96-96-32.574 0-61.354 16.227-78.71 41.035L352 215.746V96zm152.971 363.716L52.284 7.029c-9.373-9.373-24.569-9.373-33.941 0L7.029 18.343c-9.372 9.373-9.372 24.568 0 33.941L160 205.254v49.577c0 53.089 43.436 97.452 96.524 97.167 14.626-.078 28.471-3.44 40.854-9.366l17.746 17.746c-17.529 9.971-37.794 15.666-59.372 15.622C189.355 375.864 136 321.053 136 254.656V212c0-6.627-5.373-12-12-12h-24c-6.627 0-12 5.373-12 12v44c0 84.488 62.693 154.597 144 166.278V468h-68c-6.627 0-12 5.373-12 12v20c0 6.627 5.373 12 12 12h184c6.627 0 12-5.373 12-12v-20c0-6.627-5.373-12-12-12h-68v-45.722c25.625-3.682 49.396-13.172 69.942-27.083L459.717 504.97c9.373 9.373 24.569 9.373 33.941 0l11.313-11.313c9.372-9.373 9.372-24.568 0-33.941z"],minus:[448,512,[],"f068","M424 318.2c13.3 0 24-10.7 24-24v-76.4c0-13.3-10.7-24-24-24H24c-13.3 0-24 10.7-24 24v76.4c0 13.3 10.7 24 24 24h400z"],"minus-circle":[512,512,[],"f056","M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zM124 296c-6.6 0-12-5.4-12-12v-56c0-6.6 5.4-12 12-12h264c6.6 0 12 5.4 12 12v56c0 6.6-5.4 12-12 12H124z"],"minus-square":[448,512,[],"f146","M400 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48zM92 296c-6.6 0-12-5.4-12-12v-56c0-6.6 5.4-12 12-12h264c6.6 0 12 5.4 12 12v56c0 6.6-5.4 12-12 12H92z"],mobile:[320,512,[],"f10b","M272 0H48C21.5 0 0 21.5 0 48v416c0 26.5 21.5 48 48 48h224c26.5 0 48-21.5 48-48V48c0-26.5-21.5-48-48-48zM160 480c-17.7 0-32-14.3-32-32s14.3-32 32-32 32 14.3 32 32-14.3 32-32 32z"],"mobile-alt":[320,512,[],"f3cd","M272 0H48C21.5 0 0 21.5 0 48v416c0 26.5 21.5 48 48 48h224c26.5 0 48-21.5 48-48V48c0-26.5-21.5-48-48-48zM160 480c-17.7 0-32-14.3-32-32s14.3-32 32-32 32 14.3 32 32-14.3 32-32 32zm112-108c0 6.6-5.4 12-12 12H60c-6.6 0-12-5.4-12-12V60c0-6.6 5.4-12 12-12h200c6.6 0 12 5.4 12 12v312z"],"money-bill-alt":[640,512,[],"f3d1","M640 120v272c0 13.255-10.745 24-24 24H24c-13.255 0-24-10.745-24-24V120c0-13.255 10.745-24 24-24h592c13.255 0 24 10.745 24 24zM96 384c0-35.346-28.654-64-64-64v64h64zm0-256H32v64c35.346 0 64-28.654 64-64zm304 128c0-53.021-35.816-96-80-96s-80 42.979-80 96c0 53.012 35.814 96 80 96 44.167 0 80-42.969 80-96zm208 64c-35.346 0-64 28.654-64 64h64v-64zm0-192h-64c0 35.346 28.654 64 64 64v-64zM277.563 299.527c0-7.477 3.917-11.572 11.573-11.572h15.131v-39.878c0-5.163.534-10.503.534-10.503h-.356s-1.779 2.67-2.848 3.738c-4.451 4.273-10.504 4.451-15.666-1.068l-5.518-6.231c-5.342-5.341-4.984-11.216.534-16.379l21.72-19.939c4.449-4.095 8.366-5.697 14.42-5.697h12.105c7.656 0 11.749 3.916 11.749 11.572v84.384h15.488c7.655 0 11.572 4.094 11.572 11.572v8.901c0 7.477-3.917 11.572-11.572 11.572h-67.293c-7.656 0-11.573-4.095-11.573-11.572v-8.9z"],moon:[512,512,[],"f186","M283.211 512c78.962 0 151.079-35.925 198.857-94.792 7.068-8.708-.639-21.43-11.562-19.35-124.203 23.654-238.262-71.576-238.262-196.954 0-72.222 38.662-138.635 101.498-174.394 9.686-5.512 7.25-20.197-3.756-22.23A258.156 258.156 0 0 0 283.211 0c-141.309 0-256 114.511-256 256 0 141.309 114.511 256 256 256z"],motorcycle:[640,512,[],"f21c","M512.949 192.003c-14.862-.108-29.14 2.322-42.434 6.874L437.589 144H520c13.255 0 24-10.745 24-24V88c0-13.255-10.745-24-24-24h-45.311a24 24 0 0 0-17.839 7.945l-37.496 41.663-22.774-37.956A24 24 0 0 0 376 64h-80c-8.837 0-16 7.163-16 16v16c0 8.837 7.163 16 16 16h66.411l19.2 32H227.904c-17.727-23.073-44.924-40-99.904-40H72.54c-13.455 0-24.791 11.011-24.536 24.464C48.252 141.505 58.9 152 72 152h56c24.504 0 38.686 10.919 47.787 24.769l-11.291 20.529c-13.006-3.865-26.871-5.736-41.251-5.21C55.857 194.549 1.565 249.605.034 317.021-1.603 389.076 56.317 448 128 448c59.642 0 109.744-40.794 123.953-96h84.236c13.673 0 24.589-11.421 23.976-25.077-2.118-47.12 17.522-93.665 56.185-125.026l12.485 20.808c-27.646 23.654-45.097 58.88-44.831 98.179.47 69.556 57.203 126.452 126.758 127.11 71.629.678 129.839-57.487 129.234-129.099-.588-69.591-57.455-126.386-127.047-126.892zM128 400c-44.112 0-80-35.888-80-80s35.888-80 80-80c4.242 0 8.405.341 12.469.982L98.97 316.434C90.187 332.407 101.762 352 120 352h81.297c-12.37 28.225-40.56 48-73.297 48zm388.351-.116C470.272 402.337 432 365.554 432 320c0-21.363 8.434-40.781 22.125-55.144l49.412 82.352c4.546 7.577 14.375 10.034 21.952 5.488l13.72-8.232c7.577-4.546 10.034-14.375 5.488-21.952l-48.556-80.927A80.005 80.005 0 0 1 512 240c45.554 0 82.338 38.273 79.884 84.352-2.16 40.558-34.974 73.372-75.533 75.532z"],"mouse-pointer":[320,512,[],"f245","M302.189 329.126H196.105l55.831 135.993c3.889 9.428-.555 19.999-9.444 23.999l-49.165 21.427c-9.165 4-19.443-.571-23.332-9.714l-53.053-129.136-86.664 89.138C18.729 472.71 0 463.554 0 447.977V18.299C0 1.899 19.921-6.096 30.277 5.443l284.412 292.542c11.472 11.179 3.007 31.141-12.5 31.141z"],music:[512,512,[],"f001","M470.4 1.5l-304 96C153.1 101.7 144 114 144 128v264.6c-14.1-5.4-30.5-8.6-48-8.6-53 0-96 28.7-96 64s43 64 96 64 96-28.7 96-64V220.5l272-85.9v194c-14.1-5.4-30.5-8.6-48-8.6-53 0-96 28.7-96 64s43 64 96 64 96-28.7 96-64V32c0-21.7-21.1-37-41.6-30.5z"],neuter:[288,512,[],"f22c","M288 176c0-79.5-64.5-144-144-144S0 96.5 0 176c0 68.5 47.9 125.9 112 140.4V468c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12V316.4c64.1-14.5 112-71.9 112-140.4zm-144 80c-44.1 0-80-35.9-80-80s35.9-80 80-80 80 35.9 80 80-35.9 80-80 80z"],newspaper:[576,512,[],"f1ea","M552 64H88c-13.255 0-24 10.745-24 24v8H24c-13.255 0-24 10.745-24 24v272c0 30.928 25.072 56 56 56h472c26.51 0 48-21.49 48-48V88c0-13.255-10.745-24-24-24zM56 400a8 8 0 0 1-8-8V144h16v248a8 8 0 0 1-8 8zm236-16H140c-6.627 0-12-5.373-12-12v-8c0-6.627 5.373-12 12-12h152c6.627 0 12 5.373 12 12v8c0 6.627-5.373 12-12 12zm208 0H348c-6.627 0-12-5.373-12-12v-8c0-6.627 5.373-12 12-12h152c6.627 0 12 5.373 12 12v8c0 6.627-5.373 12-12 12zm-208-96H140c-6.627 0-12-5.373-12-12v-8c0-6.627 5.373-12 12-12h152c6.627 0 12 5.373 12 12v8c0 6.627-5.373 12-12 12zm208 0H348c-6.627 0-12-5.373-12-12v-8c0-6.627 5.373-12 12-12h152c6.627 0 12 5.373 12 12v8c0 6.627-5.373 12-12 12zm0-96H140c-6.627 0-12-5.373-12-12v-40c0-6.627 5.373-12 12-12h360c6.627 0 12 5.373 12 12v40c0 6.627-5.373 12-12 12z"],"object-group":[512,512,[],"f247","M480 128V96h20c6.627 0 12-5.373 12-12V44c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v20H64V44c0-6.627-5.373-12-12-12H12C5.373 32 0 37.373 0 44v40c0 6.627 5.373 12 12 12h20v320H12c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12v-20h384v20c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12v-40c0-6.627-5.373-12-12-12h-20V128zM96 276V140c0-6.627 5.373-12 12-12h168c6.627 0 12 5.373 12 12v136c0 6.627-5.373 12-12 12H108c-6.627 0-12-5.373-12-12zm320 96c0 6.627-5.373 12-12 12H236c-6.627 0-12-5.373-12-12v-52h72c13.255 0 24-10.745 24-24v-72h84c6.627 0 12 5.373 12 12v136z"],"object-ungroup":[576,512,[],"f248","M64 320v26a6 6 0 0 1-6 6H6a6 6 0 0 1-6-6v-52a6 6 0 0 1 6-6h26V96H6a6 6 0 0 1-6-6V38a6 6 0 0 1 6-6h52a6 6 0 0 1 6 6v26h288V38a6 6 0 0 1 6-6h52a6 6 0 0 1 6 6v52a6 6 0 0 1-6 6h-26v192h26a6 6 0 0 1 6 6v52a6 6 0 0 1-6 6h-52a6 6 0 0 1-6-6v-26H64zm480-64v-32h26a6 6 0 0 0 6-6v-52a6 6 0 0 0-6-6h-52a6 6 0 0 0-6 6v26H408v72h8c13.255 0 24 10.745 24 24v64c0 13.255-10.745 24-24 24h-64c-13.255 0-24-10.745-24-24v-8H192v72h-26a6 6 0 0 0-6 6v52a6 6 0 0 0 6 6h52a6 6 0 0 0 6-6v-26h288v26a6 6 0 0 0 6 6h52a6 6 0 0 0 6-6v-52a6 6 0 0 0-6-6h-26V256z"],outdent:[448,512,[],"f03b","M0 84V44c0-8.837 7.163-16 16-16h416c8.837 0 16 7.163 16 16v40c0 8.837-7.163 16-16 16H16c-8.837 0-16-7.163-16-16zm208 144h224c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H208c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zM16 484h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zm192-128h224c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H208c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zM4.687 267.313l96 95.984C110.734 373.348 128 366.224 128 351.984V160.008c0-14.329-17.325-21.304-27.313-11.313l-96 95.992c-6.249 6.248-6.249 16.378 0 22.626z"],"paint-brush":[512,512,[],"f1fc","M269.9 364.6c1.4 6.4 2.1 13 2.1 19.7 0 81.2-54.2 127.7-134.8 127.7C41.5 512 0 435.1 0 347.6c10.4 7.1 46.9 36.5 58.7 36.5 7 0 13-4 15.5-10.6 23.6-62.2 66.5-76.5 112.9-77.4 15.6 33.8 46.1 59.6 82.8 68.5zM460.6 0c-14.4 0-27.9 6.4-38.2 15.7C228.2 190 208 194.1 208 245.4c0 48.8 40.5 90.6 90.2 90.6 59 0 93.2-43.4 200.6-244.8 7-13.7 13.2-28.5 13.2-43.9C512 19.7 487.3 0 460.6 0z"],"paper-plane":[512,512,[],"f1d8","M476 3.2L12.5 270.6c-18.1 10.4-15.8 35.6 2.2 43.2L121 358.4l287.3-253.2c5.5-4.9 13.3 2.6 8.6 8.3L176 407v80.5c0 23.6 28.5 32.9 42.5 15.8L282 426l124.6 52.2c14.2 6 30.4-2.9 33-18.2l72-432C515 7.8 493.3-6.8 476 3.2z"],paperclip:[448,512,[],"f0c6","M43.246 466.142c-58.43-60.289-57.341-157.511 1.386-217.581L254.392 34c44.316-45.332 116.351-45.336 160.671 0 43.89 44.894 43.943 117.329 0 162.276L232.214 383.128c-29.855 30.537-78.633 30.111-107.982-.998-28.275-29.97-27.368-77.473 1.452-106.953l143.743-146.835c6.182-6.314 16.312-6.422 22.626-.241l22.861 22.379c6.315 6.182 6.422 16.312.241 22.626L171.427 319.927c-4.932 5.045-5.236 13.428-.648 18.292 4.372 4.634 11.245 4.711 15.688.165l182.849-186.851c19.613-20.062 19.613-52.725-.011-72.798-19.189-19.627-49.957-19.637-69.154 0L90.39 293.295c-34.763 35.56-35.299 93.12-1.191 128.313 34.01 35.093 88.985 35.137 123.058.286l172.06-175.999c6.177-6.319 16.307-6.433 22.626-.256l22.877 22.364c6.319 6.177 6.434 16.307.256 22.626l-172.06 175.998c-59.576 60.938-155.943 60.216-214.77-.485z"],paragraph:[448,512,[],"f1dd","M408 32H177.531C88.948 32 16.045 103.335 16 191.918 15.956 280.321 87.607 352 176 352v104c0 13.255 10.745 24 24 24h32c13.255 0 24-10.745 24-24V112h32v344c0 13.255 10.745 24 24 24h32c13.255 0 24-10.745 24-24V112h40c13.255 0 24-10.745 24-24V56c0-13.255-10.745-24-24-24z"],paste:[448,512,[],"f0ea","M128 184c0-30.879 25.122-56 56-56h136V56c0-13.255-10.745-24-24-24h-80.61C204.306 12.89 183.637 0 160 0s-44.306 12.89-55.39 32H24C10.745 32 0 42.745 0 56v336c0 13.255 10.745 24 24 24h104V184zm32-144c13.255 0 24 10.745 24 24s-10.745 24-24 24-24-10.745-24-24 10.745-24 24-24zm184 248h104v200c0 13.255-10.745 24-24 24H184c-13.255 0-24-10.745-24-24V184c0-13.255 10.745-24 24-24h136v104c0 13.2 10.8 24 24 24zm104-38.059V256h-96v-96h6.059a24 24 0 0 1 16.97 7.029l65.941 65.941a24.002 24.002 0 0 1 7.03 16.971z"],pause:[448,512,[],"f04c","M144 479H48c-26.5 0-48-21.5-48-48V79c0-26.5 21.5-48 48-48h96c26.5 0 48 21.5 48 48v352c0 26.5-21.5 48-48 48zm304-48V79c0-26.5-21.5-48-48-48h-96c-26.5 0-48 21.5-48 48v352c0 26.5 21.5 48 48 48h96c26.5 0 48-21.5 48-48z"],"pause-circle":[512,512,[],"f28b","M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm-16 328c0 8.8-7.2 16-16 16h-48c-8.8 0-16-7.2-16-16V176c0-8.8 7.2-16 16-16h48c8.8 0 16 7.2 16 16v160zm112 0c0 8.8-7.2 16-16 16h-48c-8.8 0-16-7.2-16-16V176c0-8.8 7.2-16 16-16h48c8.8 0 16 7.2 16 16v160z"],paw:[512,512,[],"f1b0","M85.231 330.958C36 330.958 0 273.792 0 231.5c0-28.292 16-58.042 49.538-58.042 49.231 0 85.231 57.458 85.231 99.75 0 28.292-15.692 57.75-49.538 57.75zm348 106.167c0 37.042-32 42.875-63.385 42.875-41.231 0-74.462-26.25-113.846-26.25-41.231 0-76.308 25.958-120.923 25.958-29.847 0-56.308-9.625-56.308-42.583C78.769 368 180.616 265.333 256 265.333s177.231 102.959 177.231 171.792zM182.462 203.792c-49.847 0-80-59.5-80-100.333C102.462 70.792 120.308 32 160 32c50.154 0 80 59.5 80 100.333 0 32.667-17.846 71.459-57.538 71.459zM272 132.333C272 91.5 301.846 32 352 32c39.692 0 57.539 38.792 57.539 71.458 0 40.833-30.154 100.333-80.001 100.333C289.846 203.792 272 165 272 132.333zM512 231.5c0 42.292-36 99.458-85.231 99.458-33.847 0-49.538-29.458-49.538-57.75 0-42.291 35.999-99.75 85.231-99.75C496 173.458 512 203.208 512 231.5z"],"pen-square":[448,512,[],"f14b","M400 480H48c-26.5 0-48-21.5-48-48V80c0-26.5 21.5-48 48-48h352c26.5 0 48 21.5 48 48v352c0 26.5-21.5 48-48 48zM238.1 177.9L102.4 313.6l-6.3 57.1c-.8 7.6 5.6 14.1 13.3 13.3l57.1-6.3L302.2 242c2.3-2.3 2.3-6.1 0-8.5L246.7 178c-2.5-2.4-6.3-2.4-8.6-.1zM345 165.1L314.9 135c-9.4-9.4-24.6-9.4-33.9 0l-23.1 23.1c-2.3 2.3-2.3 6.1 0 8.5l55.5 55.5c2.3 2.3 6.1 2.3 8.5 0L345 199c9.3-9.3 9.3-24.5 0-33.9z"],"pencil-alt":[512,512,[],"f303","M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"],percent:[448,512,[],"f295","M112 224c61.9 0 112-50.1 112-112S173.9 0 112 0 0 50.1 0 112s50.1 112 112 112zm0-160c26.5 0 48 21.5 48 48s-21.5 48-48 48-48-21.5-48-48 21.5-48 48-48zm224 224c-61.9 0-112 50.1-112 112s50.1 112 112 112 112-50.1 112-112-50.1-112-112-112zm0 160c-26.5 0-48-21.5-48-48s21.5-48 48-48 48 21.5 48 48-21.5 48-48 48zM392.3.2l31.6-.1c19.4-.1 30.9 21.8 19.7 37.8L77.4 501.6a23.95 23.95 0 0 1-19.6 10.2l-33.4.1c-19.5 0-30.9-21.9-19.7-37.8l368-463.7C377.2 4 384.5.2 392.3.2z"],phone:[512,512,[],"f095","M493.397 24.615l-104-23.997c-11.314-2.611-22.879 3.252-27.456 13.931l-48 111.997a24 24 0 0 0 6.862 28.029l60.617 49.596c-35.973 76.675-98.938 140.508-177.249 177.248l-49.596-60.616a24 24 0 0 0-28.029-6.862l-111.997 48C3.873 366.516-1.994 378.08.618 389.397l23.997 104C27.109 504.204 36.748 512 48 512c256.087 0 464-207.532 464-464 0-11.176-7.714-20.873-18.603-23.385z"],"phone-square":[448,512,[],"f098","M400 32H48C21.49 32 0 53.49 0 80v352c0 26.51 21.49 48 48 48h352c26.51 0 48-21.49 48-48V80c0-26.51-21.49-48-48-48zM94 416c-7.033 0-13.057-4.873-14.616-11.627l-14.998-65a15 15 0 0 1 8.707-17.16l69.998-29.999a15 15 0 0 1 17.518 4.289l30.997 37.885c48.944-22.963 88.297-62.858 110.781-110.78l-37.886-30.997a15.001 15.001 0 0 1-4.289-17.518l30-69.998a15 15 0 0 1 17.16-8.707l65 14.998A14.997 14.997 0 0 1 384 126c0 160.292-129.945 290-290 290z"],"phone-volume":[384,512,[],"f2a0","M97.333 506.966c-129.874-129.874-129.681-340.252 0-469.933 5.698-5.698 14.527-6.632 21.263-2.422l64.817 40.513a17.187 17.187 0 0 1 6.849 20.958l-32.408 81.021a17.188 17.188 0 0 1-17.669 10.719l-55.81-5.58c-21.051 58.261-20.612 122.471 0 179.515l55.811-5.581a17.188 17.188 0 0 1 17.669 10.719l32.408 81.022a17.188 17.188 0 0 1-6.849 20.958l-64.817 40.513a17.19 17.19 0 0 1-21.264-2.422zM247.126 95.473c11.832 20.047 11.832 45.008 0 65.055-3.95 6.693-13.108 7.959-18.718 2.581l-5.975-5.726c-3.911-3.748-4.793-9.622-2.261-14.41a32.063 32.063 0 0 0 0-29.945c-2.533-4.788-1.65-10.662 2.261-14.41l5.975-5.726c5.61-5.378 14.768-4.112 18.718 2.581zm91.787-91.187c60.14 71.604 60.092 175.882 0 247.428-4.474 5.327-12.53 5.746-17.552.933l-5.798-5.557c-4.56-4.371-4.977-11.529-.93-16.379 49.687-59.538 49.646-145.933 0-205.422-4.047-4.85-3.631-12.008.93-16.379l5.798-5.557c5.022-4.813 13.078-4.394 17.552.933zm-45.972 44.941c36.05 46.322 36.108 111.149 0 157.546-4.39 5.641-12.697 6.251-17.856 1.304l-5.818-5.579c-4.4-4.219-4.998-11.095-1.285-15.931 26.536-34.564 26.534-82.572 0-117.134-3.713-4.836-3.115-11.711 1.285-15.931l5.818-5.579c5.159-4.947 13.466-4.337 17.856 1.304z"],plane:[576,512,[],"f072","M472 200H360.211L256.013 5.711A12 12 0 0 0 245.793 0h-57.787c-7.85 0-13.586 7.413-11.616 15.011L209.624 200H99.766l-34.904-58.174A12 12 0 0 0 54.572 136H12.004c-7.572 0-13.252 6.928-11.767 14.353l21.129 105.648L.237 361.646c-1.485 7.426 4.195 14.354 11.768 14.353l42.568-.002c4.215 0 8.121-2.212 10.289-5.826L99.766 312h109.858L176.39 496.989c-1.97 7.599 3.766 15.011 11.616 15.011h57.787a12 12 0 0 0 10.22-5.711L360.212 312H472c57.438 0 104-25.072 104-56s-46.562-56-104-56z"],play:[448,512,[],"f04b","M424.4 214.7L72.4 6.6C43.8-10.3 0 6.1 0 47.9V464c0 37.5 40.7 60.1 72.4 41.3l352-208c31.4-18.5 31.5-64.1 0-82.6z"],"play-circle":[512,512,[],"f144","M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm115.7 272l-176 101c-15.8 8.8-35.7-2.5-35.7-21V152c0-18.4 19.8-29.8 35.7-21l176 107c16.4 9.2 16.4 32.9 0 42z"],plug:[384,512,[],"f1e6","M256 144V32c0-17.673 14.327-32 32-32s32 14.327 32 32v112h-64zm112 16H16c-8.837 0-16 7.163-16 16v32c0 8.837 7.163 16 16 16h16v32c0 77.406 54.969 141.971 128 156.796V512h64v-99.204c73.031-14.825 128-79.39 128-156.796v-32h16c8.837 0 16-7.163 16-16v-32c0-8.837-7.163-16-16-16zm-240-16V32c0-17.673-14.327-32-32-32S64 14.327 64 32v112h64z"],plus:[448,512,[],"f067","M448 294.2v-76.4c0-13.3-10.7-24-24-24H286.2V56c0-13.3-10.7-24-24-24h-76.4c-13.3 0-24 10.7-24 24v137.8H24c-13.3 0-24 10.7-24 24v76.4c0 13.3 10.7 24 24 24h137.8V456c0 13.3 10.7 24 24 24h76.4c13.3 0 24-10.7 24-24V318.2H424c13.3 0 24-10.7 24-24z"],"plus-circle":[512,512,[],"f055","M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm144 276c0 6.6-5.4 12-12 12h-92v92c0 6.6-5.4 12-12 12h-56c-6.6 0-12-5.4-12-12v-92h-92c-6.6 0-12-5.4-12-12v-56c0-6.6 5.4-12 12-12h92v-92c0-6.6 5.4-12 12-12h56c6.6 0 12 5.4 12 12v92h92c6.6 0 12 5.4 12 12v56z"],"plus-square":[448,512,[],"f0fe","M400 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48zm-32 252c0 6.6-5.4 12-12 12h-92v92c0 6.6-5.4 12-12 12h-56c-6.6 0-12-5.4-12-12v-92H92c-6.6 0-12-5.4-12-12v-56c0-6.6 5.4-12 12-12h92v-92c0-6.6 5.4-12 12-12h56c6.6 0 12 5.4 12 12v92h92c6.6 0 12 5.4 12 12v56z"],podcast:[448,512,[],"f2ce","M267.429 488.563C262.286 507.573 242.858 512 224 512c-18.857 0-38.286-4.427-43.428-23.437C172.927 460.134 160 388.898 160 355.75c0-35.156 31.142-43.75 64-43.75s64 8.594 64 43.75c0 32.949-12.871 104.179-20.571 132.813zM156.867 288.554c-18.693-18.308-29.958-44.173-28.784-72.599 2.054-49.724 42.395-89.956 92.124-91.881C274.862 121.958 320 165.807 320 220c0 26.827-11.064 51.116-28.866 68.552-2.675 2.62-2.401 6.986.628 9.187 9.312 6.765 16.46 15.343 21.234 25.363 1.741 3.654 6.497 4.66 9.449 1.891 28.826-27.043 46.553-65.783 45.511-108.565-1.855-76.206-63.595-138.208-139.793-140.369C146.869 73.753 80 139.215 80 220c0 41.361 17.532 78.7 45.55 104.989 2.953 2.771 7.711 1.77 9.453-1.887 4.774-10.021 11.923-18.598 21.235-25.363 3.029-2.2 3.304-6.566.629-9.185zM224 0C100.204 0 0 100.185 0 224c0 89.992 52.602 165.647 125.739 201.408 4.333 2.118 9.267-1.544 8.535-6.31-2.382-15.512-4.342-30.946-5.406-44.339-.146-1.836-1.149-3.486-2.678-4.512-47.4-31.806-78.564-86.016-78.187-147.347.592-96.237 79.29-174.648 175.529-174.899C320.793 47.747 400 126.797 400 224c0 61.932-32.158 116.49-80.65 147.867-.999 14.037-3.069 30.588-5.624 47.23-.732 4.767 4.203 8.429 8.535 6.31C395.227 389.727 448 314.187 448 224 448 100.205 347.815 0 224 0zm0 160c-35.346 0-64 28.654-64 64s28.654 64 64 64 64-28.654 64-64-28.654-64-64-64z"],"pound-sign":[320,512,[],"f154","M308 352h-45.495c-6.627 0-12 5.373-12 12v50.848H128V288h84c6.627 0 12-5.373 12-12v-40c0-6.627-5.373-12-12-12h-84v-63.556c0-32.266 24.562-57.086 61.792-57.086 23.658 0 45.878 11.505 57.652 18.849 5.151 3.213 11.888 2.051 15.688-2.685l28.493-35.513c4.233-5.276 3.279-13.005-2.119-17.081C273.124 54.56 236.576 32 187.931 32 106.026 32 48 84.742 48 157.961V224H20c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h28v128H12c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h296c6.627 0 12-5.373 12-12V364c0-6.627-5.373-12-12-12z"],"power-off":[512,512,[],"f011","M400 54.1c63 45 104 118.6 104 201.9 0 136.8-110.8 247.7-247.5 248C120 504.3 8.2 393 8 256.4 7.9 173.1 48.9 99.3 111.8 54.2c11.7-8.3 28-4.8 35 7.7L162.6 90c5.9 10.5 3.1 23.8-6.6 31-41.5 30.8-68 79.6-68 134.9-.1 92.3 74.5 168.1 168 168.1 91.6 0 168.6-74.2 168-169.1-.3-51.8-24.7-101.8-68.1-134-9.7-7.2-12.4-20.5-6.5-30.9l15.8-28.1c7-12.4 23.2-16.1 34.8-7.8zM296 264V24c0-13.3-10.7-24-24-24h-32c-13.3 0-24 10.7-24 24v240c0 13.3 10.7 24 24 24h32c13.3 0 24-10.7 24-24z"],print:[512,512,[],"f02f","M464 192h-16V81.941a24 24 0 0 0-7.029-16.97L383.029 7.029A24 24 0 0 0 366.059 0H88C74.745 0 64 10.745 64 24v168H48c-26.51 0-48 21.49-48 48v132c0 6.627 5.373 12 12 12h52v104c0 13.255 10.745 24 24 24h336c13.255 0 24-10.745 24-24V384h52c6.627 0 12-5.373 12-12V240c0-26.51-21.49-48-48-48zm-80 256H128v-96h256v96zM128 224V64h192v40c0 13.2 10.8 24 24 24h40v96H128zm304 72c-13.254 0-24-10.746-24-24s10.746-24 24-24 24 10.746 24 24-10.746 24-24 24z"],"puzzle-piece":[576,512,[],"f12e","M519.442 288.651c-41.519 0-59.5 31.593-82.058 31.593C377.409 320.244 432 144 432 144s-196.288 80-196.288-3.297c0-35.827 36.288-46.25 36.288-85.985C272 19.216 243.885 0 210.539 0c-34.654 0-66.366 18.891-66.366 56.346 0 41.364 31.711 59.277 31.711 81.75C175.885 207.719 0 166.758 0 166.758v333.237s178.635 41.047 178.635-28.662c0-22.473-40-40.107-40-81.471 0-37.456 29.25-56.346 63.577-56.346 33.673 0 61.788 19.216 61.788 54.717 0 39.735-36.288 50.158-36.288 85.985 0 60.803 129.675 25.73 181.23 25.73 0 0-34.725-120.101 25.827-120.101 35.962 0 46.423 36.152 86.308 36.152C556.712 416 576 387.99 576 354.443c0-34.199-18.962-65.792-56.558-65.792z"],qrcode:[448,512,[],"f029","M0 224h192V32H0v192zM64 96h64v64H64V96zm192-64v192h192V32H256zm128 128h-64V96h64v64zM0 480h192V288H0v192zm64-128h64v64H64v-64zm352-64h32v128h-96v-32h-32v96h-64V288h96v32h64v-32zm0 160h32v32h-32v-32zm-64 0h32v32h-32v-32z"],question:[384,512,[],"f128","M202.021 0C122.202 0 70.503 32.703 29.914 91.026c-7.363 10.58-5.093 25.086 5.178 32.874l43.138 32.709c10.373 7.865 25.132 6.026 33.253-4.148 25.049-31.381 43.63-49.449 82.757-49.449 30.764 0 68.816 19.799 68.816 49.631 0 22.552-18.617 34.134-48.993 51.164-35.423 19.86-82.299 44.576-82.299 106.405V320c0 13.255 10.745 24 24 24h72.471c13.255 0 24-10.745 24-24v-5.773c0-42.86 125.268-44.645 125.268-160.627C377.504 66.256 286.902 0 202.021 0zM192 373.459c-38.196 0-69.271 31.075-69.271 69.271 0 38.195 31.075 69.27 69.271 69.27s69.271-31.075 69.271-69.271-31.075-69.27-69.271-69.27z"],"question-circle":[512,512,[],"f059","M504 256c0 136.997-111.043 248-248 248S8 392.997 8 256C8 119.083 119.043 8 256 8s248 111.083 248 248zM262.655 90c-54.497 0-89.255 22.957-116.549 63.758-3.536 5.286-2.353 12.415 2.715 16.258l34.699 26.31c5.205 3.947 12.621 3.008 16.665-2.122 17.864-22.658 30.113-35.797 57.303-35.797 20.429 0 45.698 13.148 45.698 32.958 0 14.976-12.363 22.667-32.534 33.976C247.128 238.528 216 254.941 216 296v4c0 6.627 5.373 12 12 12h56c6.627 0 12-5.373 12-12v-1.333c0-28.462 83.186-29.647 83.186-106.667 0-58.002-60.165-102-116.531-102zM256 338c-25.365 0-46 20.635-46 46 0 25.364 20.635 46 46 46s46-20.636 46-46c0-25.365-20.635-46-46-46z"],"quote-left":[512,512,[],"f10d","M0 432V304C0 166.982 63.772 67.676 193.827 32.828 209.052 28.748 224 40.265 224 56.027v33.895c0 10.057-6.228 19.133-15.687 22.55C142.316 136.312 104 181.946 104 256h72c26.51 0 48 21.49 48 48v128c0 26.51-21.49 48-48 48H48c-26.51 0-48-21.49-48-48zm336 48h128c26.51 0 48-21.49 48-48V304c0-26.51-21.49-48-48-48h-72c0-74.054 38.316-119.688 104.313-143.528C505.772 109.055 512 99.979 512 89.922V56.027c0-15.762-14.948-27.279-30.173-23.199C351.772 67.676 288 166.982 288 304v128c0 26.51 21.49 48 48 48z"],"quote-right":[512,512,[],"f10e","M512 80v128c0 137.018-63.772 236.324-193.827 271.172-15.225 4.08-30.173-7.437-30.173-23.199v-33.895c0-10.057 6.228-19.133 15.687-22.55C369.684 375.688 408 330.054 408 256h-72c-26.51 0-48-21.49-48-48V80c0-26.51 21.49-48 48-48h128c26.51 0 48 21.49 48 48zM176 32H48C21.49 32 0 53.49 0 80v128c0 26.51 21.49 48 48 48h72c0 74.054-38.316 119.688-104.313 143.528C6.228 402.945 0 412.021 0 422.078v33.895c0 15.762 14.948 27.279 30.173 23.199C160.228 444.324 224 345.018 224 208V80c0-26.51-21.49-48-48-48z"],random:[512,512,[],"f074","M504.971 359.029c9.373 9.373 9.373 24.569 0 33.941l-80 79.984c-15.01 15.01-40.971 4.49-40.971-16.971V416h-58.785a12.004 12.004 0 0 1-8.773-3.812l-70.556-75.596 53.333-57.143L352 336h32v-39.981c0-21.438 25.943-31.998 40.971-16.971l80 79.981zM12 176h84l52.781 56.551 53.333-57.143-70.556-75.596A11.999 11.999 0 0 0 122.785 96H12c-6.627 0-12 5.373-12 12v56c0 6.627 5.373 12 12 12zm372 0v39.984c0 21.46 25.961 31.98 40.971 16.971l80-79.984c9.373-9.373 9.373-24.569 0-33.941l-80-79.981C409.943 24.021 384 34.582 384 56.019V96h-58.785a12.004 12.004 0 0 0-8.773 3.812L96 336H12c-6.627 0-12 5.373-12 12v56c0 6.627 5.373 12 12 12h110.785c3.326 0 6.503-1.381 8.773-3.812L352 176h32z"],recycle:[512,512,[],"f1b8","M184.561 261.903c3.232 13.997-12.123 24.635-24.068 17.168l-40.736-25.455-50.867 81.402C55.606 356.273 70.96 384 96.012 384H148c6.627 0 12 5.373 12 12v40c0 6.627-5.373 12-12 12H96.115c-75.334 0-121.302-83.048-81.408-146.88l50.822-81.388-40.725-25.448c-12.081-7.547-8.966-25.961 4.879-29.158l110.237-25.45c8.611-1.988 17.201 3.381 19.189 11.99l25.452 110.237zm98.561-182.915l41.289 66.076-40.74 25.457c-12.051 7.528-9 25.953 4.879 29.158l110.237 25.45c8.672 1.999 17.215-3.438 19.189-11.99l25.45-110.237c3.197-13.844-11.99-24.719-24.068-17.168l-40.687 25.424-41.263-66.082c-37.521-60.033-125.209-60.171-162.816 0l-17.963 28.766c-3.51 5.62-1.8 13.021 3.82 16.533l33.919 21.195c5.62 3.512 13.024 1.803 16.536-3.817l17.961-28.743c12.712-20.341 41.973-19.676 54.257-.022zM497.288 301.12l-27.515-44.065c-3.511-5.623-10.916-7.334-16.538-3.821l-33.861 21.159c-5.62 3.512-7.33 10.915-3.818 16.536l27.564 44.112c13.257 21.211-2.057 48.96-27.136 48.96H320V336.02c0-14.213-17.242-21.383-27.313-11.313l-80 79.981c-6.249 6.248-6.249 16.379 0 22.627l80 79.989C302.689 517.308 320 510.3 320 495.989V448h95.88c75.274 0 121.335-82.997 81.408-146.88z"],redo:[512,512,[],"f01e","M500.333 0h-47.411c-6.853 0-12.314 5.729-11.986 12.574l3.966 82.759C399.416 41.899 331.672 8 256.001 8 119.34 8 7.899 119.526 8 256.187 8.101 393.068 119.096 504 256 504c63.926 0 122.202-24.187 166.178-63.908 5.113-4.618 5.354-12.561.482-17.433l-33.971-33.971c-4.466-4.466-11.64-4.717-16.38-.543C341.308 415.448 300.606 432 256 432c-97.267 0-176-78.716-176-176 0-97.267 78.716-176 176-176 60.892 0 114.506 30.858 146.099 77.8l-101.525-4.865c-6.845-.328-12.574 5.133-12.574 11.986v47.411c0 6.627 5.373 12 12 12h200.333c6.627 0 12-5.373 12-12V12c0-6.627-5.373-12-12-12z"],"redo-alt":[512,512,[],"f2f9","M256.455 8c66.269.119 126.437 26.233 170.859 68.685l35.715-35.715C478.149 25.851 504 36.559 504 57.941V192c0 13.255-10.745 24-24 24H345.941c-21.382 0-32.09-25.851-16.971-40.971l41.75-41.75c-30.864-28.899-70.801-44.907-113.23-45.273-92.398-.798-170.283 73.977-169.484 169.442C88.764 348.009 162.184 424 256 424c41.127 0 79.997-14.678 110.629-41.556 4.743-4.161 11.906-3.908 16.368.553l39.662 39.662c4.872 4.872 4.631 12.815-.482 17.433C378.202 479.813 319.926 504 256 504 119.034 504 8.001 392.967 8 256.002 7.999 119.193 119.646 7.755 256.455 8z"],registered:[512,512,[],"f25d","M285.363 207.475c0 18.6-9.831 28.431-28.431 28.431h-29.876v-56.14h23.378c28.668 0 34.929 8.773 34.929 27.709zM504 256c0 136.967-111.033 248-248 248S8 392.967 8 256 119.033 8 256 8s248 111.033 248 248zM363.411 360.414c-46.729-84.825-43.299-78.636-44.702-80.98 23.432-15.172 37.945-42.979 37.945-74.486 0-54.244-31.5-89.252-105.498-89.252h-70.667c-13.255 0-24 10.745-24 24V372c0 13.255 10.745 24 24 24h22.567c13.255 0 24-10.745 24-24v-71.663h25.556l44.129 82.937a24.001 24.001 0 0 0 21.188 12.727h24.464c18.261-.001 29.829-19.591 21.018-35.587z"],reply:[512,512,[],"f3e5","M8.309 189.836L184.313 37.851C199.719 24.546 224 35.347 224 56.015v80.053c160.629 1.839 288 34.032 288 186.258 0 61.441-39.581 122.309-83.333 154.132-13.653 9.931-33.111-2.533-28.077-18.631 45.344-145.012-21.507-183.51-176.59-185.742V360c0 20.7-24.3 31.453-39.687 18.164l-176.004-152c-11.071-9.562-11.086-26.753 0-36.328z"],"reply-all":[576,512,[],"f122","M136.309 189.836L312.313 37.851C327.72 24.546 352 35.348 352 56.015v82.763c129.182 10.231 224 52.212 224 183.548 0 61.441-39.582 122.309-83.333 154.132-13.653 9.931-33.111-2.533-28.077-18.631 38.512-123.162-3.922-169.482-112.59-182.015v84.175c0 20.701-24.3 31.453-39.687 18.164L136.309 226.164c-11.071-9.561-11.086-26.753 0-36.328zm-128 36.328L184.313 378.15C199.7 391.439 224 380.687 224 359.986v-15.818l-108.606-93.785A55.96 55.96 0 0 1 96 207.998a55.953 55.953 0 0 1 19.393-42.38L224 71.832V56.015c0-20.667-24.28-31.469-39.687-18.164L8.309 189.836c-11.086 9.575-11.071 26.767 0 36.328z"],retweet:[640,512,[],"f079","M629.657 343.598L528.971 444.284c-9.373 9.372-24.568 9.372-33.941 0L394.343 343.598c-9.373-9.373-9.373-24.569 0-33.941l10.823-10.823c9.562-9.562 25.133-9.34 34.419.492L480 342.118V160H292.451a24.005 24.005 0 0 1-16.971-7.029l-16-16C244.361 121.851 255.069 96 276.451 96H520c13.255 0 24 10.745 24 24v222.118l40.416-42.792c9.285-9.831 24.856-10.054 34.419-.492l10.823 10.823c9.372 9.372 9.372 24.569-.001 33.941zm-265.138 15.431A23.999 23.999 0 0 0 347.548 352H160V169.881l40.416 42.792c9.286 9.831 24.856 10.054 34.419.491l10.822-10.822c9.373-9.373 9.373-24.569 0-33.941L144.971 67.716c-9.373-9.373-24.569-9.373-33.941 0L10.343 168.402c-9.373 9.373-9.373 24.569 0 33.941l10.822 10.822c9.562 9.562 25.133 9.34 34.419-.491L96 169.881V392c0 13.255 10.745 24 24 24h243.549c21.382 0 32.09-25.851 16.971-40.971l-16.001-16z"],road:[576,512,[],"f018","M567.3 383.6L429.9 78.2C426 69.5 417.4 64 408 64h-96.1l1.9 18.8c.7 7.1-4.8 13.2-11.9 13.2H274c-7.1 0-12.7-6.2-11.9-13.2L264 64h-96c-9.4 0-18 5.5-21.9 14.2L8.7 383.6C3.2 395.8 0 409.6 0 424c0 13.3 10.7 24 24 24h213.6c-7.1 0-12.7-6.2-11.9-13.2l10.8-104c.6-6.1 5.8-10.8 11.9-10.8h79.2c6.1 0 11.3 4.6 11.9 10.8l10.8 104c.7 7.1-4.8 13.2-11.9 13.2H552c13.2 0 24-10.7 24-24 0-13.9-3-27.7-8.7-40.4zM254.7 154.8l3.3-32c.6-6.1 5.8-10.8 11.9-10.8h36.2c6.1 0 11.3 4.6 11.9 10.8l3.3 32c.7 7.1-4.8 13.2-11.9 13.2h-42.8c-7.1 0-12.7-6.2-11.9-13.2zM321.8 288h-67.6c-7.1 0-12.7-6.2-11.9-13.2l7.4-72c.6-6.1 5.8-10.8 11.9-10.8h52.7c6.1 0 11.3 4.6 11.9 10.8l7.4 72c.9 7-4.7 13.2-11.8 13.2z"],rocket:[512,512,[],"f135","M505.1 19.1C503.8 13 499 8.2 492.9 6.9 460.7 0 435.5 0 410.4 0 307.2 0 245.3 55.2 199.1 128H94.9c-18.2 0-34.8 10.3-42.9 26.5L2.6 253.3c-8 16 3.6 34.7 21.5 34.7h95.1c-5.9 12.8-11.9 25.5-18 37.7-3.1 6.2-1.9 13.6 3 18.5l63.6 63.6c4.9 4.9 12.3 6.1 18.5 3 12.2-6.1 24.9-12 37.7-17.9V488c0 17.8 18.8 29.4 34.7 21.5l98.7-49.4c16.3-8.1 26.5-24.8 26.5-42.9V312.8c72.6-46.3 128-108.4 128-211.1.1-25.2.1-50.4-6.8-82.6zM400 160c-26.5 0-48-21.5-48-48s21.5-48 48-48 48 21.5 48 48-21.5 48-48 48z"],rss:[448,512,[],"f09e","M128.081 415.959c0 35.369-28.672 64.041-64.041 64.041S0 451.328 0 415.959s28.672-64.041 64.041-64.041 64.04 28.673 64.04 64.041zm175.66 47.25c-8.354-154.6-132.185-278.587-286.95-286.95C7.656 175.765 0 183.105 0 192.253v48.069c0 8.415 6.49 15.472 14.887 16.018 111.832 7.284 201.473 96.702 208.772 208.772.547 8.397 7.604 14.887 16.018 14.887h48.069c9.149.001 16.489-7.655 15.995-16.79zm144.249.288C439.596 229.677 251.465 40.445 16.503 32.01 7.473 31.686 0 38.981 0 48.016v48.068c0 8.625 6.835 15.645 15.453 15.999 191.179 7.839 344.627 161.316 352.465 352.465.353 8.618 7.373 15.453 15.999 15.453h48.068c9.034-.001 16.329-7.474 16.005-16.504z"],"rss-square":[448,512,[],"f143","M400 32H48C21.49 32 0 53.49 0 80v352c0 26.51 21.49 48 48 48h352c26.51 0 48-21.49 48-48V80c0-26.51-21.49-48-48-48zM112 416c-26.51 0-48-21.49-48-48s21.49-48 48-48 48 21.49 48 48-21.49 48-48 48zm157.533 0h-34.335c-6.011 0-11.051-4.636-11.442-10.634-5.214-80.05-69.243-143.92-149.123-149.123-5.997-.39-10.633-5.431-10.633-11.441v-34.335c0-6.535 5.468-11.777 11.994-11.425 110.546 5.974 198.997 94.536 204.964 204.964.352 6.526-4.89 11.994-11.425 11.994zm103.027 0h-34.334c-6.161 0-11.175-4.882-11.427-11.038-5.598-136.535-115.204-246.161-251.76-251.76C68.882 152.949 64 147.935 64 141.774V107.44c0-6.454 5.338-11.664 11.787-11.432 167.83 6.025 302.21 141.191 308.205 308.205.232 6.449-4.978 11.787-11.432 11.787z"],"ruble-sign":[384,512,[],"f158","M239.36 320C324.48 320 384 260.542 384 175.071S324.48 32 239.36 32H76c-6.627 0-12 5.373-12 12v206.632H12c-6.627 0-12 5.373-12 12V308c0 6.627 5.373 12 12 12h52v32H12c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h52v52c0 6.627 5.373 12 12 12h58.56c6.627 0 12-5.373 12-12v-52H308c6.627 0 12-5.373 12-12v-40c0-6.627-5.373-12-12-12H146.56v-32h92.8zm-92.8-219.252h78.72c46.72 0 74.88 29.11 74.88 74.323 0 45.832-28.16 75.561-76.16 75.561h-77.44V100.748z"],"rupee-sign":[320,512,[],"f156","M308 96c6.627 0 12-5.373 12-12V44c0-6.627-5.373-12-12-12H12C5.373 32 0 37.373 0 44v44.748c0 6.627 5.373 12 12 12h85.28c27.308 0 48.261 9.958 60.97 27.252H12c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h158.757c-6.217 36.086-32.961 58.632-74.757 58.632H12c-6.627 0-12 5.373-12 12v53.012c0 3.349 1.4 6.546 3.861 8.818l165.052 152.356a12.001 12.001 0 0 0 8.139 3.182h82.562c10.924 0 16.166-13.408 8.139-20.818L116.871 319.906c76.499-2.34 131.144-53.395 138.318-127.906H308c6.627 0 12-5.373 12-12v-40c0-6.627-5.373-12-12-12h-58.69c-3.486-11.541-8.28-22.246-14.252-32H308z"],save:[448,512,[],"f0c7","M433.941 129.941l-83.882-83.882A48 48 0 0 0 316.118 32H48C21.49 32 0 53.49 0 80v352c0 26.51 21.49 48 48 48h352c26.51 0 48-21.49 48-48V163.882a48 48 0 0 0-14.059-33.941zM224 416c-35.346 0-64-28.654-64-64 0-35.346 28.654-64 64-64s64 28.654 64 64c0 35.346-28.654 64-64 64zm96-304.52V212c0 6.627-5.373 12-12 12H76c-6.627 0-12-5.373-12-12V108c0-6.627 5.373-12 12-12h228.52c3.183 0 6.235 1.264 8.485 3.515l3.48 3.48A11.996 11.996 0 0 1 320 111.48z"],search:[512,512,[],"f002","M505 442.7L405.3 343c-4.5-4.5-10.6-7-17-7H372c27.6-35.3 44-79.7 44-128C416 93.1 322.9 0 208 0S0 93.1 0 208s93.1 208 208 208c48.3 0 92.7-16.4 128-44v16.3c0 6.4 2.5 12.5 7 17l99.7 99.7c9.4 9.4 24.6 9.4 33.9 0l28.3-28.3c9.4-9.4 9.4-24.6.1-34zM208 336c-70.7 0-128-57.2-128-128 0-70.7 57.2-128 128-128 70.7 0 128 57.2 128 128 0 70.7-57.2 128-128 128z"],"search-minus":[512,512,[],"f010","M304 192v32c0 6.6-5.4 12-12 12H124c-6.6 0-12-5.4-12-12v-32c0-6.6 5.4-12 12-12h168c6.6 0 12 5.4 12 12zm201 284.7L476.7 505c-9.4 9.4-24.6 9.4-33.9 0L343 405.3c-4.5-4.5-7-10.6-7-17V372c-35.3 27.6-79.7 44-128 44C93.1 416 0 322.9 0 208S93.1 0 208 0s208 93.1 208 208c0 48.3-16.4 92.7-44 128h16.3c6.4 0 12.5 2.5 17 7l99.7 99.7c9.3 9.4 9.3 24.6 0 34zM344 208c0-75.2-60.8-136-136-136S72 132.8 72 208s60.8 136 136 136 136-60.8 136-136z"],"search-plus":[512,512,[],"f00e","M304 192v32c0 6.6-5.4 12-12 12h-56v56c0 6.6-5.4 12-12 12h-32c-6.6 0-12-5.4-12-12v-56h-56c-6.6 0-12-5.4-12-12v-32c0-6.6 5.4-12 12-12h56v-56c0-6.6 5.4-12 12-12h32c6.6 0 12 5.4 12 12v56h56c6.6 0 12 5.4 12 12zm201 284.7L476.7 505c-9.4 9.4-24.6 9.4-33.9 0L343 405.3c-4.5-4.5-7-10.6-7-17V372c-35.3 27.6-79.7 44-128 44C93.1 416 0 322.9 0 208S93.1 0 208 0s208 93.1 208 208c0 48.3-16.4 92.7-44 128h16.3c6.4 0 12.5 2.5 17 7l99.7 99.7c9.3 9.4 9.3 24.6 0 34zM344 208c0-75.2-60.8-136-136-136S72 132.8 72 208s60.8 136 136 136 136-60.8 136-136z"],server:[512,512,[],"f233","M480 160H32c-17.673 0-32-14.327-32-32V64c0-17.673 14.327-32 32-32h448c17.673 0 32 14.327 32 32v64c0 17.673-14.327 32-32 32zm-48-88c-13.255 0-24 10.745-24 24s10.745 24 24 24 24-10.745 24-24-10.745-24-24-24zm-64 0c-13.255 0-24 10.745-24 24s10.745 24 24 24 24-10.745 24-24-10.745-24-24-24zm112 248H32c-17.673 0-32-14.327-32-32v-64c0-17.673 14.327-32 32-32h448c17.673 0 32 14.327 32 32v64c0 17.673-14.327 32-32 32zm-48-88c-13.255 0-24 10.745-24 24s10.745 24 24 24 24-10.745 24-24-10.745-24-24-24zm-64 0c-13.255 0-24 10.745-24 24s10.745 24 24 24 24-10.745 24-24-10.745-24-24-24zm112 248H32c-17.673 0-32-14.327-32-32v-64c0-17.673 14.327-32 32-32h448c17.673 0 32 14.327 32 32v64c0 17.673-14.327 32-32 32zm-48-88c-13.255 0-24 10.745-24 24s10.745 24 24 24 24-10.745 24-24-10.745-24-24-24zm-64 0c-13.255 0-24 10.745-24 24s10.745 24 24 24 24-10.745 24-24-10.745-24-24-24z"],share:[512,512,[],"f064","M503.691 189.836L327.687 37.851C312.281 24.546 288 35.347 288 56.015v80.053C127.371 137.907 0 170.1 0 322.326c0 61.441 39.581 122.309 83.333 154.132 13.653 9.931 33.111-2.533 28.077-18.631C66.066 312.814 132.917 274.316 288 272.085V360c0 20.7 24.3 31.453 39.687 18.164l176.004-152c11.071-9.562 11.086-26.753 0-36.328z"],"share-alt":[448,512,[],"f1e0","M352 320c-22.608 0-43.387 7.819-59.79 20.895l-102.486-64.054a96.551 96.551 0 0 0 0-41.683l102.486-64.054C308.613 184.181 329.392 192 352 192c53.019 0 96-42.981 96-96S405.019 0 352 0s-96 42.981-96 96c0 7.158.79 14.13 2.276 20.841L155.79 180.895C139.387 167.819 118.608 160 96 160c-53.019 0-96 42.981-96 96s42.981 96 96 96c22.608 0 43.387-7.819 59.79-20.895l102.486 64.054A96.301 96.301 0 0 0 256 416c0 53.019 42.981 96 96 96s96-42.981 96-96-42.981-96-96-96z"],"share-alt-square":[448,512,[],"f1e1","M448 80v352c0 26.51-21.49 48-48 48H48c-26.51 0-48-21.49-48-48V80c0-26.51 21.49-48 48-48h352c26.51 0 48 21.49 48 48zM304 296c-14.562 0-27.823 5.561-37.783 14.671l-67.958-40.775a56.339 56.339 0 0 0 0-27.793l67.958-40.775C276.177 210.439 289.438 216 304 216c30.928 0 56-25.072 56-56s-25.072-56-56-56-56 25.072-56 56c0 4.797.605 9.453 1.74 13.897l-67.958 40.775C171.823 205.561 158.562 200 144 200c-30.928 0-56 25.072-56 56s25.072 56 56 56c14.562 0 27.823-5.561 37.783-14.671l67.958 40.775a56.088 56.088 0 0 0-1.74 13.897c0 30.928 25.072 56 56 56s56-25.072 56-56C360 321.072 334.928 296 304 296z"],"share-square":[576,512,[],"f14d","M568.482 177.448L424.479 313.433C409.3 327.768 384 317.14 384 295.985v-71.963c-144.575.97-205.566 35.113-164.775 171.353 4.483 14.973-12.846 26.567-25.006 17.33C155.252 383.105 120 326.488 120 269.339c0-143.937 117.599-172.5 264-173.312V24.012c0-21.174 25.317-31.768 40.479-17.448l144.003 135.988c10.02 9.463 10.028 25.425 0 34.896zM384 379.128V448H64V128h50.916a11.99 11.99 0 0 0 8.648-3.693c14.953-15.568 32.237-27.89 51.014-37.676C185.708 80.83 181.584 64 169.033 64H48C21.49 64 0 85.49 0 112v352c0 26.51 21.49 48 48 48h352c26.51 0 48-21.49 48-48v-88.806c0-8.288-8.197-14.066-16.011-11.302a71.83 71.83 0 0 1-34.189 3.377c-7.27-1.046-13.8 4.514-13.8 11.859z"],"shekel-sign":[448,512,[],"f20b","M170.12 96H80v372c0 6.627-5.373 12-12 12H12c-6.627 0-12-5.373-12-12V44c0-6.627 5.373-12 12-12h168.36C265.48 32 325 89.6 325 175.071V359c0 6.627-5.373 12-12 12h-44c-13.255 0-24-10.745-24-24V170.323C245 125.11 216.839 96 170.12 96zM436 32h-56c-6.627 0-12 5.373-12 12v372h-90.12c-46.72 0-74.88-29.11-74.88-74.323V165c0-13.255-10.745-24-24-24h-44c-6.627 0-12 5.373-12 12v183.929C123 422.4 182.52 480 267.64 480H436c6.627 0 12-5.373 12-12V44c0-6.627-5.373-12-12-12z"],"shield-alt":[512,512,[],"f3ed","M496 128c0 221.282-135.934 344.645-221.539 380.308a48 48 0 0 1-36.923 0C130.495 463.713 16 326.487 16 128a48 48 0 0 1 29.539-44.308l192-80a48 48 0 0 1 36.923 0l192 80A48 48 0 0 1 496 128zM256 446.313l.066.034c93.735-46.689 172.497-156.308 175.817-307.729L256 65.333v380.98z"],ship:[640,512,[],"f21a","M496.616 372.639l70.012-70.012c16.899-16.9 9.942-45.771-12.836-53.092L512 236.102V96c0-17.673-14.327-32-32-32h-64V24c0-13.255-10.745-24-24-24H248c-13.255 0-24 10.745-24 24v40h-64c-17.673 0-32 14.327-32 32v140.102l-41.792 13.433c-22.753 7.313-29.754 36.173-12.836 53.092l70.012 70.012C125.828 416.287 85.587 448 24 448c-13.255 0-24 10.745-24 24v16c0 13.255 10.745 24 24 24 61.023 0 107.499-20.61 143.258-59.396C181.677 487.432 216.021 512 256 512h128c39.979 0 74.323-24.568 88.742-59.396C508.495 491.384 554.968 512 616 512c13.255 0 24-10.745 24-24v-16c0-13.255-10.745-24-24-24-60.817 0-101.542-31.001-119.384-75.361zM192 128h256v87.531l-118.208-37.995a31.995 31.995 0 0 0-19.584 0L192 215.531V128z"],"shopping-bag":[448,512,[],"f290","M352 160v-32C352 57.42 294.579 0 224 0 153.42 0 96 57.42 96 128v32H0v272c0 44.183 35.817 80 80 80h288c44.183 0 80-35.817 80-80V160h-96zm-192-32c0-35.29 28.71-64 64-64s64 28.71 64 64v32H160v-32zm160 120c-13.255 0-24-10.745-24-24s10.745-24 24-24 24 10.745 24 24-10.745 24-24 24zm-192 0c-13.255 0-24-10.745-24-24s10.745-24 24-24 24 10.745 24 24-10.745 24-24 24z"],"shopping-basket":[576,512,[],"f291","M576 216v16c0 13.255-10.745 24-24 24h-8l-26.113 182.788C514.509 462.435 494.257 480 470.37 480H105.63c-23.887 0-44.139-17.565-47.518-41.212L32 256h-8c-13.255 0-24-10.745-24-24v-16c0-13.255 10.745-24 24-24h67.341l106.78-146.821c10.395-14.292 30.407-17.453 44.701-7.058 14.293 10.395 17.453 30.408 7.058 44.701L170.477 192h235.046L326.12 82.821c-10.395-14.292-7.234-34.306 7.059-44.701 14.291-10.395 34.306-7.235 44.701 7.058L484.659 192H552c13.255 0 24 10.745 24 24zM312 392V280c0-13.255-10.745-24-24-24s-24 10.745-24 24v112c0 13.255 10.745 24 24 24s24-10.745 24-24zm112 0V280c0-13.255-10.745-24-24-24s-24 10.745-24 24v112c0 13.255 10.745 24 24 24s24-10.745 24-24zm-224 0V280c0-13.255-10.745-24-24-24s-24 10.745-24 24v112c0 13.255 10.745 24 24 24s24-10.745 24-24z"],"shopping-cart":[576,512,[],"f07a","M528.12 301.319l47.273-208C578.806 78.301 567.391 64 551.99 64H159.208l-9.166-44.81C147.758 8.021 137.93 0 126.529 0H24C10.745 0 0 10.745 0 24v16c0 13.255 10.745 24 24 24h69.883l70.248 343.435C147.325 417.1 136 435.222 136 456c0 30.928 25.072 56 56 56s56-25.072 56-56c0-15.674-6.447-29.835-16.824-40h209.647C430.447 426.165 424 440.326 424 456c0 30.928 25.072 56 56 56s56-25.072 56-56c0-22.172-12.888-41.332-31.579-50.405l5.517-24.276c3.413-15.018-8.002-29.319-23.403-29.319H218.117l-6.545-32h293.145c11.206 0 20.92-7.754 23.403-18.681z"],shower:[512,512,[],"f2cc","M389.66 135.6L231.6 293.66c-9.37 9.37-24.57 9.37-33.94 0l-11.32-11.32c-9.37-9.37-9.37-24.57 0-33.94l.11-.11c-34.03-40.21-35.16-98.94-3.39-140.38-11.97-7.55-26.14-11.91-41.3-11.91C98.88 96 64 130.88 64 173.76V480H0V173.76C0 95.59 63.59 32 141.76 32c36.93 0 70.61 14.2 95.86 37.42 35.9-11.51 76.5-4.5 106.67 21.03l.11-.11c9.37-9.37 24.57-9.37 33.94 0l11.32 11.32c9.37 9.37 9.37 24.57 0 33.94zM384 208c0 8.837-7.163 16-16 16s-16-7.163-16-16 7.163-16 16-16 16 7.163 16 16zm32 0c0-8.837 7.163-16 16-16s16 7.163 16 16-7.163 16-16 16-16-7.163-16-16zm96 0c0 8.837-7.163 16-16 16s-16-7.163-16-16 7.163-16 16-16 16 7.163 16 16zm-160 32c0 8.837-7.163 16-16 16s-16-7.163-16-16 7.163-16 16-16 16 7.163 16 16zm48-16c8.837 0 16 7.163 16 16s-7.163 16-16 16-16-7.163-16-16 7.163-16 16-16zm80 16c0 8.837-7.163 16-16 16s-16-7.163-16-16 7.163-16 16-16 16 7.163 16 16zm-160 32c0 8.837-7.163 16-16 16s-16-7.163-16-16 7.163-16 16-16 16 7.163 16 16zm32 0c0-8.837 7.163-16 16-16s16 7.163 16 16-7.163 16-16 16-16-7.163-16-16zm96 0c0 8.837-7.163 16-16 16s-16-7.163-16-16 7.163-16 16-16 16 7.163 16 16zm-128 32c0-8.837 7.163-16 16-16s16 7.163 16 16-7.163 16-16 16-16-7.163-16-16zm96 0c0 8.837-7.163 16-16 16s-16-7.163-16-16 7.163-16 16-16 16 7.163 16 16zm-96 32c0 8.837-7.163 16-16 16s-16-7.163-16-16 7.163-16 16-16 16 7.163 16 16zm64 0c0 8.837-7.163 16-16 16s-16-7.163-16-16 7.163-16 16-16 16 7.163 16 16zm-32 32c0 8.837-7.163 16-16 16s-16-7.163-16-16 7.163-16 16-16 16 7.163 16 16zm-32 32c0 8.837-7.163 16-16 16s-16-7.163-16-16 7.163-16 16-16 16 7.163 16 16z"],"sign-in-alt":[512,512,[],"f2f6","M416 448h-84c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h84c17.7 0 32-14.3 32-32V160c0-17.7-14.3-32-32-32h-84c-6.6 0-12-5.4-12-12V76c0-6.6 5.4-12 12-12h84c53 0 96 43 96 96v192c0 53-43 96-96 96zm-47-201L201 79c-15-15-41-4.5-41 17v96H24c-13.3 0-24 10.7-24 24v96c0 13.3 10.7 24 24 24h136v96c0 21.5 26 32 41 17l168-168c9.3-9.4 9.3-24.6 0-34z"],"sign-language":[448,512,[],"f2a7","M91.434 483.987c-.307-16.018 13.109-29.129 29.13-29.129h62.293v-5.714H56.993c-16.021 0-29.437-13.111-29.13-29.129C28.16 404.491 40.835 392 56.428 392h126.429v-5.714H29.136c-16.021 0-29.437-13.111-29.13-29.129.297-15.522 12.973-28.013 28.566-28.013h154.286v-5.714H57.707c-16.021 0-29.437-13.111-29.13-29.129.297-15.522 12.973-28.013 28.566-28.013h168.566l-31.085-22.606c-12.762-9.281-15.583-27.149-6.302-39.912 9.281-12.761 27.15-15.582 39.912-6.302l123.361 89.715a34.287 34.287 0 0 1 14.12 27.728v141.136c0 15.91-10.946 29.73-26.433 33.374l-80.471 18.934a137.16 137.16 0 0 1-31.411 3.646H120c-15.593-.001-28.269-12.492-28.566-28.014zm73.249-225.701h36.423l-11.187-8.136c-18.579-13.511-20.313-40.887-3.17-56.536l-13.004-16.7c-9.843-12.641-28.43-15.171-40.88-5.088-12.065 9.771-14.133 27.447-4.553 39.75l36.371 46.71zm283.298-2.103l-5.003-152.452c-.518-15.771-13.722-28.136-29.493-27.619-15.773.518-28.137 13.722-27.619 29.493l1.262 38.415L283.565 11.019c-9.58-12.303-27.223-14.63-39.653-5.328-12.827 9.599-14.929 28.24-5.086 40.881l76.889 98.745-4.509 3.511-94.79-121.734c-9.58-12.303-27.223-14.63-39.653-5.328-12.827 9.599-14.929 28.24-5.086 40.881l94.443 121.288-4.509 3.511-77.675-99.754c-9.58-12.303-27.223-14.63-39.653-5.328-12.827 9.599-14.929 28.24-5.086 40.881l52.053 66.849c12.497-8.257 29.055-8.285 41.69.904l123.36 89.714c10.904 7.93 17.415 20.715 17.415 34.198v16.999l61.064-47.549a34.285 34.285 0 0 0 13.202-28.177z"],"sign-out-alt":[512,512,[],"f2f5","M497 273L329 441c-15 15-41 4.5-41-17v-96H152c-13.3 0-24-10.7-24-24v-96c0-13.3 10.7-24 24-24h136V88c0-21.4 25.9-32 41-17l168 168c9.3 9.4 9.3 24.6 0 34zM192 436v-40c0-6.6-5.4-12-12-12H96c-17.7 0-32-14.3-32-32V160c0-17.7 14.3-32 32-32h84c6.6 0 12-5.4 12-12V76c0-6.6-5.4-12-12-12H96c-53 0-96 43-96 96v192c0 53 43 96 96 96h84c6.6 0 12-5.4 12-12z"],signal:[640,512,[],"f012","M36 384h56c6.6 0 12 5.4 12 12v104c0 6.6-5.4 12-12 12H36c-6.6 0-12-5.4-12-12V396c0-6.6 5.4-12 12-12zm116-36v152c0 6.6 5.4 12 12 12h56c6.6 0 12-5.4 12-12V348c0-6.6-5.4-12-12-12h-56c-6.6 0-12 5.4-12 12zm128-80v232c0 6.6 5.4 12 12 12h56c6.6 0 12-5.4 12-12V268c0-6.6-5.4-12-12-12h-56c-6.6 0-12 5.4-12 12zm128-112v344c0 6.6 5.4 12 12 12h56c6.6 0 12-5.4 12-12V156c0-6.6-5.4-12-12-12h-56c-6.6 0-12 5.4-12 12zM536 12v488c0 6.6 5.4 12 12 12h56c6.6 0 12-5.4 12-12V12c0-6.6-5.4-12-12-12h-56c-6.6 0-12 5.4-12 12z"],sitemap:[640,512,[],"f0e8","M616 320h-48v-48c0-22.056-17.944-40-40-40H344v-40h48c13.255 0 24-10.745 24-24V24c0-13.255-10.745-24-24-24H248c-13.255 0-24 10.745-24 24v144c0 13.255 10.745 24 24 24h48v40H112c-22.056 0-40 17.944-40 40v48H24c-13.255 0-24 10.745-24 24v144c0 13.255 10.745 24 24 24h144c13.255 0 24-10.745 24-24V344c0-13.255-10.745-24-24-24h-48v-40h176v40h-48c-13.255 0-24 10.745-24 24v144c0 13.255 10.745 24 24 24h144c13.255 0 24-10.745 24-24V344c0-13.255-10.745-24-24-24h-48v-40h176v40h-48c-13.255 0-24 10.745-24 24v144c0 13.255 10.745 24 24 24h144c13.255 0 24-10.745 24-24V344c0-13.255-10.745-24-24-24z"],"sliders-h":[576,512,[],"f1de","M576 80v40c0 6.6-5.4 12-12 12H160v8c0 13.3-10.7 24-24 24h-16c-13.3 0-24-10.7-24-24v-8H12c-6.6 0-12-5.4-12-12V80c0-6.6 5.4-12 12-12h84v-8c0-13.3 10.7-24 24-24h16c13.3 0 24 10.7 24 24v8h404c6.6 0 12 5.4 12 12zm-12 148h-84v-8c0-13.3-10.7-24-24-24h-16c-13.3 0-24 10.7-24 24v8H12c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h404v8c0 13.3 10.7 24 24 24h16c13.3 0 24-10.7 24-24v-8h84c6.6 0 12-5.4 12-12v-40c0-6.6-5.4-12-12-12zm0 160H288v-8c0-13.3-10.7-24-24-24h-16c-13.3 0-24 10.7-24 24v8H12c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h212v8c0 13.3 10.7 24 24 24h16c13.3 0 24-10.7 24-24v-8h276c6.6 0 12-5.4 12-12v-40c0-6.6-5.4-12-12-12z"],smile:[512,512,[],"f118","M504 256c0 136.967-111.033 248-248 248S8 392.967 8 256 119.033 8 256 8s248 111.033 248 248zm-122.526 75.34c11.479-17.755-15.349-35.194-26.873-17.374-53.418 82.627-143.71 82.681-197.164 0-11.502-17.79-38.364-.401-26.873 17.374 66.014 102.107 184.795 102.265 250.91 0zM108 192c0 37.497 30.503 68 68 68s68-30.503 68-68-30.503-68-68-68-68 30.503-68 68zm160.5 0c0 37.221 30.279 67.5 67.5 67.5s67.5-30.279 67.5-67.5-30.279-67.5-67.5-67.5-67.5 30.279-67.5 67.5zm67.5-48a47.789 47.789 0 0 0-22.603 5.647h.015c10.916 0 19.765 8.849 19.765 19.765s-8.849 19.765-19.765 19.765-19.765-8.849-19.765-19.765v-.015A47.789 47.789 0 0 0 288 192c0 26.51 21.49 48 48 48s48-21.49 48-48-21.49-48-48-48zm-160 0a47.789 47.789 0 0 0-22.603 5.647h.015c10.916 0 19.765 8.849 19.765 19.765s-8.849 19.765-19.765 19.765-19.765-8.849-19.765-19.765v-.015A47.789 47.789 0 0 0 128 192c0 26.51 21.49 48 48 48s48-21.49 48-48-21.49-48-48-48z"],snowflake:[448,512,[],"f2dc","M444.816 301.639a24.12 24.12 0 0 0 2.661-16.978c-2.725-12.966-15.339-21.245-28.174-18.492l-87.407 25.046L264 256l67.896-35.215 87.407 25.046c12.835 2.753 25.449-5.526 28.174-18.492 2.725-12.966-5.471-25.708-18.305-28.461l-47.477-7.137 53.077-30.956c11.363-6.627 15.257-21.306 8.696-32.785-6.561-11.479-21.091-15.412-32.454-8.785l-53.077 30.956 17.621-45.104c4.057-12.606-2.768-26.146-15.247-30.245-12.478-4.099-25.883 2.797-29.94 15.402l-22.232 88.99-60.38 35.215V144l65.175-63.945c8.778-9.852 7.987-25.027-1.766-33.894-9.753-8.867-24.775-8.068-33.552 1.784l-29.857 37.967V24c0-13.255-10.637-24-23.758-24s-23.758 10.745-23.758 24v61.912l-29.857-37.967c-8.779-9.852-23.799-10.652-33.552-1.784-9.753 8.867-10.543 24.042-1.766 33.894L200.242 144v70.431l-60.38-35.215-22.232-88.99c-4.057-12.605-17.462-19.501-29.94-15.402-12.478 4.099-19.304 17.64-15.247 30.245l17.62 45.104-53.077-30.956c-11.363-6.627-25.893-2.694-32.454 8.785s-2.667 26.157 8.696 32.785l53.077 30.956-47.477 7.137C5.993 201.634-2.203 214.375.523 227.341c2.725 12.965 15.339 21.245 28.174 18.492l87.407-25.046L184 256l-67.896 35.215-87.406-25.045c-12.835-2.753-25.449 5.526-28.174 18.492-2.725 12.967 5.47 25.708 18.305 28.461l47.477 7.137-53.077 30.956C1.866 357.843-2.027 372.521 4.533 384s21.091 15.412 32.454 8.785l53.077-30.956-17.62 45.104a24.157 24.157 0 0 0 2.022 19.428c2.831 4.953 7.416 8.909 13.224 10.816 12.478 4.099 25.883-2.797 29.94-15.402l22.232-88.99 60.38-35.215V368l-65.175 63.945c-8.778 9.852-7.987 25.027 1.766 33.894 9.754 8.868 24.774 8.068 33.552-1.784l29.857-37.967V488c0 13.255 10.637 24 23.758 24s23.758-10.745 23.758-24v-61.912l29.857 37.967A23.59 23.59 0 0 0 295.282 472a23.534 23.534 0 0 0 15.885-6.161c9.753-8.867 10.544-24.042 1.766-33.894L247.758 368v-70.431l60.38 35.215 22.232 88.99c4.057 12.605 17.462 19.501 29.94 15.402 12.479-4.099 19.304-17.64 15.247-30.245l-17.621-45.104 53.077 30.956c11.363 6.627 25.893 2.694 32.454-8.785s2.667-26.157-8.696-32.785l-53.077-30.956 47.477-7.137c6.86-1.469 12.394-5.793 15.645-11.481z"],sort:[320,512,[],"f0dc","M41 288h238c21.4 0 32.1 25.9 17 41L177 448c-9.4 9.4-24.6 9.4-33.9 0L24 329c-15.1-15.1-4.4-41 17-41zm255-105L177 64c-9.4-9.4-24.6-9.4-33.9 0L24 183c-15.1 15.1-4.4 41 17 41h238c21.4 0 32.1-25.9 17-41z"],"sort-alpha-down":[448,512,[],"f15d","M187.298 395.314l-79.984 80.002c-6.248 6.247-16.383 6.245-22.627 0L4.705 395.314C-5.365 385.244 1.807 368 16.019 368H64V48c0-8.837 7.163-16 16-16h32c8.837 0 16 7.163 16 16v320h47.984c14.241 0 21.363 17.264 11.314 27.314zm119.075-180.007A12 12 0 0 1 294.838 224h-35.717c-8.22 0-14.007-8.078-11.362-15.861l57.096-168A12 12 0 0 1 316.217 32h39.566c5.139 0 9.708 3.273 11.362 8.139l57.096 168C426.886 215.922 421.1 224 412.879 224h-35.735a12 12 0 0 1-11.515-8.622l-8.301-28.299h-42.863l-8.092 28.228zm22.857-78.697h13.367l-6.6-22.937-6.767 22.937zm12.575 287.323l67.451-95.698a12 12 0 0 0 2.192-6.913V300c0-6.627-5.373-12-12-12H274.522c-6.627 0-12 5.373-12 12v28.93c0 6.627 5.373 12 12 12h56.469c-.739.991-1.497 2.036-2.27 3.133l-67.203 95.205a12.001 12.001 0 0 0-2.196 6.92V468c0 6.627 5.373 12 12 12h129.355c6.627 0 12-5.373 12-12v-28.93c0-6.627-5.373-12-12-12h-61.146c.74-.993 1.5-2.039 2.274-3.137z"],"sort-alpha-up":[448,512,[],"f15e","M4.702 116.686l79.984-80.002c6.248-6.247 16.383-6.245 22.627 0l79.981 80.002c10.07 10.07 2.899 27.314-11.314 27.314H128v320c0 8.837-7.163 16-16 16H80c-8.837 0-16-7.163-16-16V144H16.016c-14.241 0-21.363-17.264-11.314-27.314zm301.671 98.621A12 12 0 0 1 294.838 224h-35.717c-8.22 0-14.007-8.078-11.362-15.861l57.096-168A12 12 0 0 1 316.217 32h39.566c5.139 0 9.708 3.273 11.362 8.139l57.096 168C426.886 215.922 421.1 224 412.879 224h-35.735a12 12 0 0 1-11.515-8.622l-8.301-28.299h-42.863l-8.092 28.228zm22.857-78.697h13.367l-6.6-22.937-6.767 22.937zm12.575 287.323l67.451-95.698a12 12 0 0 0 2.192-6.913V300c0-6.627-5.373-12-12-12H274.522c-6.627 0-12 5.373-12 12v28.93c0 6.627 5.373 12 12 12h56.469c-.739.991-1.497 2.036-2.27 3.133l-67.203 95.205a12.001 12.001 0 0 0-2.196 6.92V468c0 6.627 5.373 12 12 12h129.355c6.627 0 12-5.373 12-12v-28.93c0-6.627-5.373-12-12-12h-61.146c.74-.993 1.5-2.039 2.274-3.137z"],"sort-amount-down":[512,512,[],"f160","M187.298 395.314l-79.984 80.002c-6.248 6.247-16.383 6.245-22.627 0L4.705 395.314C-5.365 385.244 1.807 368 16.019 368H64V48c0-8.837 7.163-16 16-16h32c8.837 0 16 7.163 16 16v320h47.984c14.241 0 21.363 17.264 11.314 27.314zM240 96h256c8.837 0 16-7.163 16-16V48c0-8.837-7.163-16-16-16H240c-8.837 0-16 7.163-16 16v32c0 8.837 7.163 16 16 16zm-16 112v-32c0-8.837 7.163-16 16-16h192c8.837 0 16 7.163 16 16v32c0 8.837-7.163 16-16 16H240c-8.837 0-16-7.163-16-16zm0 256v-32c0-8.837 7.163-16 16-16h64c8.837 0 16 7.163 16 16v32c0 8.837-7.163 16-16 16h-64c-8.837 0-16-7.163-16-16zm0-128v-32c0-8.837 7.163-16 16-16h128c8.837 0 16 7.163 16 16v32c0 8.837-7.163 16-16 16H240c-8.837 0-16-7.163-16-16z"],"sort-amount-up":[512,512,[],"f161","M4.702 116.686l79.984-80.002c6.248-6.247 16.383-6.245 22.627 0l79.981 80.002c10.07 10.07 2.899 27.314-11.314 27.314H128v320c0 8.837-7.163 16-16 16H80c-8.837 0-16-7.163-16-16V144H16.016c-14.241 0-21.363-17.264-11.314-27.314zM240 96h256c8.837 0 16-7.163 16-16V48c0-8.837-7.163-16-16-16H240c-8.837 0-16 7.163-16 16v32c0 8.837 7.163 16 16 16zm-16 112v-32c0-8.837 7.163-16 16-16h192c8.837 0 16 7.163 16 16v32c0 8.837-7.163 16-16 16H240c-8.837 0-16-7.163-16-16zm0 256v-32c0-8.837 7.163-16 16-16h64c8.837 0 16 7.163 16 16v32c0 8.837-7.163 16-16 16h-64c-8.837 0-16-7.163-16-16zm0-128v-32c0-8.837 7.163-16 16-16h128c8.837 0 16 7.163 16 16v32c0 8.837-7.163 16-16 16H240c-8.837 0-16-7.163-16-16z"],"sort-down":[320,512,[],"f0dd","M41 288h238c21.4 0 32.1 25.9 17 41L177 448c-9.4 9.4-24.6 9.4-33.9 0L24 329c-15.1-15.1-4.4-41 17-41z"],"sort-numeric-down":[448,512,[],"f162","M308.811 113.787l-19.448-20.795c-4.522-4.836-4.274-12.421.556-16.95l43.443-40.741a11.999 11.999 0 0 1 8.209-3.247h31.591c6.627 0 12 5.373 12 12v127.07h25.66c6.627 0 12 5.373 12 12v28.93c0 6.627-5.373 12-12 12H301.649c-6.627 0-12-5.373-12-12v-28.93c0-6.627 5.373-12 12-12h25.414v-57.938c-7.254 6.58-14.211 4.921-18.252.601zm-30.57 238.569c0-32.653 23.865-67.356 68.094-67.356 38.253 0 79.424 28.861 79.424 92.228 0 51.276-32.237 105.772-91.983 105.772-17.836 0-30.546-3.557-38.548-6.781-5.79-2.333-8.789-8.746-6.922-14.703l9.237-29.48c2.035-6.496 9.049-9.983 15.467-7.716 13.029 4.602 27.878 5.275 38.103-4.138-38.742 5.072-72.872-25.36-72.872-67.826zm92.273 19.338c0-22.285-15.302-36.505-25.835-36.505-8.642 0-13.164 7.965-13.164 15.832 0 5.669 1.815 24.168 25.168 24.168 9.973 0 13.377-2.154 13.744-2.731.021-.046.087-.291.087-.764zM175.984 368H128V48c0-8.837-7.163-16-16-16H80c-8.837 0-16 7.163-16 16v320H16.019c-14.212 0-21.384 17.244-11.314 27.314l79.981 80.002c6.245 6.245 16.38 6.247 22.627 0l79.984-80.002c10.05-10.05 2.928-27.314-11.313-27.314z"],"sort-numeric-up":[448,512,[],"f163","M308.811 113.787l-19.448-20.795c-4.522-4.836-4.274-12.421.556-16.95l43.443-40.741a11.999 11.999 0 0 1 8.209-3.247h31.591c6.627 0 12 5.373 12 12v127.07h25.66c6.627 0 12 5.373 12 12v28.93c0 6.627-5.373 12-12 12H301.649c-6.627 0-12-5.373-12-12v-28.93c0-6.627 5.373-12 12-12h25.414v-57.938c-7.254 6.58-14.211 4.921-18.252.601zm-30.57 238.569c0-32.653 23.865-67.356 68.094-67.356 38.253 0 79.424 28.861 79.424 92.228 0 51.276-32.237 105.772-91.983 105.772-17.836 0-30.546-3.557-38.548-6.781-5.79-2.333-8.789-8.746-6.922-14.703l9.237-29.48c2.035-6.496 9.049-9.983 15.467-7.716 13.029 4.602 27.878 5.275 38.103-4.138-38.742 5.072-72.872-25.36-72.872-67.826zm92.273 19.338c0-22.285-15.302-36.505-25.835-36.505-8.642 0-13.164 7.965-13.164 15.832 0 5.669 1.815 24.168 25.168 24.168 9.973 0 13.377-2.154 13.744-2.731.021-.046.087-.291.087-.764zM16.016 144H64v320c0 8.837 7.163 16 16 16h32c8.837 0 16-7.163 16-16V144h47.981c14.212 0 21.384-17.244 11.314-27.314l-79.981-80.002c-6.245-6.245-16.38-6.247-22.627 0L4.702 116.686C-5.347 126.736 1.775 144 16.016 144z"],"sort-up":[320,512,[],"f0de","M279 224H41c-21.4 0-32.1-25.9-17-41L143 64c9.4-9.4 24.6-9.4 33.9 0l119 119c15.2 15.1 4.5 41-16.9 41z"],"space-shuttle":[640,512,[],"f197","M592.604 208.244C559.735 192.836 515.777 184 472 184H186.327c-4.952-6.555-10.585-11.978-16.72-16H376C229.157 137.747 219.403 32 96.003 32H96v128H80V32c-26.51 0-48 28.654-48 64v64c-23.197 0-32 10.032-32 24v40c0 13.983 8.819 24 32 24v16c-23.197 0-32 10.032-32 24v40c0 13.983 8.819 24 32 24v64c0 35.346 21.49 64 48 64V352h16v128h.003c123.4 0 133.154-105.747 279.997-136H169.606c6.135-4.022 11.768-9.445 16.72-16H472c43.777 0 87.735-8.836 120.604-24.244C622.282 289.845 640 271.992 640 256s-17.718-33.845-47.396-47.756zM488 296a8 8 0 0 1-8-8v-64a8 8 0 0 1 8-8c31.909 0 31.942 80 0 80z"],spinner:[512,512,[],"f110","M304 48c0 26.51-21.49 48-48 48s-48-21.49-48-48 21.49-48 48-48 48 21.49 48 48zm-48 368c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.49-48-48-48zm208-208c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.49-48-48-48zM96 256c0-26.51-21.49-48-48-48S0 229.49 0 256s21.49 48 48 48 48-21.49 48-48zm12.922 99.078c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48c0-26.509-21.491-48-48-48zm294.156 0c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48c0-26.509-21.49-48-48-48zM108.922 60.922c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.491-48-48-48z"],square:[448,512,[],"f0c8","M400 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48z"],star:[576,512,[],"f005","M259.3 17.8L194 150.2 47.9 171.5c-26.2 3.8-36.7 36.1-17.7 54.6l105.7 103-25 145.5c-4.5 26.3 23.2 46 46.4 33.7L288 439.6l130.7 68.7c23.2 12.2 50.9-7.4 46.4-33.7l-25-145.5 105.7-103c19-18.5 8.5-50.8-17.7-54.6L382 150.2 316.7 17.8c-11.7-23.6-45.6-23.9-57.4 0z"],"star-half":[576,512,[],"f089","M288 0c-11.4 0-22.8 5.9-28.7 17.8L194 150.2 47.9 171.4c-26.2 3.8-36.7 36.1-17.7 54.6l105.7 103-25 145.5c-4.5 26.1 23 46 46.4 33.7L288 439.6V0z"],"step-backward":[448,512,[],"f048","M64 468V44c0-6.6 5.4-12 12-12h48c6.6 0 12 5.4 12 12v176.4l195.5-181C352.1 22.3 384 36.6 384 64v384c0 27.4-31.9 41.7-52.5 24.6L136 292.7V468c0 6.6-5.4 12-12 12H76c-6.6 0-12-5.4-12-12z"],"step-forward":[448,512,[],"f051","M384 44v424c0 6.6-5.4 12-12 12h-48c-6.6 0-12-5.4-12-12V291.6l-195.5 181C95.9 489.7 64 475.4 64 448V64c0-27.4 31.9-41.7 52.5-24.6L312 219.3V44c0-6.6 5.4-12 12-12h48c6.6 0 12 5.4 12 12z"],stethoscope:[512,512,[],"f0f1","M512 176c0-35.659-29.164-64.507-64.941-63.993-34.21.492-62.296 28.357-63.043 62.562-.531 24.282 12.476 45.558 31.984 56.848V344c0 57.346-50.243 104-112 104-60.039 0-109.189-44.096-111.878-99.24C265.005 333.847 320 269.225 320 192V36.584c0-11.44-8.075-21.29-19.293-23.534L237.81.471c-12.997-2.599-25.641 5.83-28.241 18.827l-3.138 15.689c-2.6 12.997 5.83 25.641 18.827 28.241L256 69.376v121.4c0 52.852-42.203 96.707-95.053 97.22C107.58 288.513 64 245.25 64 192V69.376l30.742-6.149c12.997-2.6 21.427-15.243 18.827-28.241l-3.138-15.689C107.831 6.3 95.188-2.129 82.19.471L19.293 13.05C8.075 15.294 0 25.144 0 36.584V192c0 77.295 55.096 141.961 128.076 156.798C130.747 439.223 208.634 512 304 512c97.047 0 176-75.364 176-168V231.417c19.124-11.068 32-31.732 32-55.417zm-64-16c8.822 0 16 7.178 16 16s-7.178 16-16 16-16-7.178-16-16 7.178-16 16-16z"],"sticky-note":[448,512,[],"f249","M312 320h136V56c0-13.3-10.7-24-24-24H24C10.7 32 0 42.7 0 56v400c0 13.3 10.7 24 24 24h264V344c0-13.2 10.8-24 24-24zm129 55l-98 98c-4.5 4.5-10.6 7-17 7h-6V352h128v6.1c0 6.3-2.5 12.4-7 16.9z"],stop:[448,512,[],"f04d","M400 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48z"],"stop-circle":[512,512,[],"f28d","M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm96 328c0 8.8-7.2 16-16 16H176c-8.8 0-16-7.2-16-16V176c0-8.8 7.2-16 16-16h160c8.8 0 16 7.2 16 16v160z"],"street-view":[512,512,[],"f21d","M192 64c0-35.346 28.654-64 64-64s64 28.654 64 64c0 35.346-28.654 64-64 64s-64-28.654-64-64zm112 80h-11.36c-22.711 10.443-49.59 10.894-73.28 0H208c-26.51 0-48 21.49-48 48v104c0 13.255 10.745 24 24 24h16v104c0 13.255 10.745 24 24 24h64c13.255 0 24-10.745 24-24V320h16c13.255 0 24-10.745 24-24V192c0-26.51-21.49-48-48-48zm85.642 189.152a72.503 72.503 0 0 1-29.01 27.009C391.133 365.251 480 385.854 480 416c0 46.304-167.656 64-224 64-70.303 0-224-20.859-224-64 0-30.123 88.361-50.665 119.367-55.839a72.516 72.516 0 0 1-29.01-27.009C74.959 343.395 0 367.599 0 416c0 77.111 178.658 96 256 96 77.249 0 256-18.865 256-96 0-48.403-74.967-72.606-122.358-82.848z"],strikethrough:[512,512,[],"f0cc","M496 288H16c-8.837 0-16-7.163-16-16v-32c0-8.837 7.163-16 16-16h480c8.837 0 16 7.163 16 16v32c0 8.837-7.163 16-16 16zm-214.666 16c27.258 12.937 46.524 28.683 46.524 56.243 0 33.108-28.977 53.676-75.621 53.676-32.325 0-76.874-12.08-76.874-44.271V368c0-8.837-7.164-16-16-16H113.75c-8.836 0-16 7.163-16 16v19.204c0 66.845 77.717 101.82 154.487 101.82 88.578 0 162.013-45.438 162.013-134.424 0-19.815-3.618-36.417-10.143-50.6H281.334zm-30.952-96c-32.422-13.505-56.836-28.946-56.836-59.683 0-33.92 30.901-47.406 64.962-47.406 42.647 0 64.962 16.593 64.962 32.985V136c0 8.837 7.164 16 16 16h45.613c8.836 0 16-7.163 16-16v-30.318c0-52.438-71.725-79.875-142.575-79.875-85.203 0-150.726 40.972-150.726 125.646 0 22.71 4.665 41.176 12.777 56.547h129.823z"],subscript:[512,512,[],"f12c","M395.198 416c3.461-10.526 18.796-21.28 36.265-32.425 16.625-10.605 35.467-22.626 50.341-38.862 17.458-19.054 25.944-40.175 25.944-64.567 0-60.562-50.702-88.146-97.81-88.146-42.491 0-76.378 22.016-94.432 50.447-4.654 7.329-2.592 17.036 4.623 21.865l30.328 20.296c7.032 4.706 16.46 3.084 21.63-3.614 8.022-10.394 18.818-18.225 31.667-18.225 19.387 0 26.266 12.901 26.266 23.948 0 36.159-119.437 57.023-119.437 160.024 0 6.654.561 13.014 1.415 19.331 1.076 7.964 7.834 13.928 15.87 13.928H496c8.837 0 16-7.163 16-16v-32c0-8.837-7.163-16-16-16H395.198zM272 256c8.837 0 16 7.163 16 16v32c0 8.837-7.163 16-16 16h-62.399a16 16 0 0 1-13.541-7.478l-45.701-72.615c-2.297-3.352-4.422-6.969-6.195-10.209-1.65 3.244-3.647 6.937-5.874 10.582l-44.712 72.147a15.999 15.999 0 0 1-13.6 7.572H16c-8.837 0-16-7.163-16-16v-32c0-8.837 7.163-16 16-16h26.325l56.552-82.709L46.111 96H16C7.163 96 0 88.837 0 80V48c0-8.837 7.163-16 16-16h68.806a16 16 0 0 1 13.645 7.644l39.882 65.126c2.072 3.523 4.053 7.171 5.727 10.37 1.777-3.244 3.92-6.954 6.237-10.537l40.332-65.035A15.999 15.999 0 0 1 204.226 32H272c8.837 0 16 7.163 16 16v32c0 8.837-7.163 16-16 16h-27.979l-52.69 75.671L249.974 256H272z"],subway:[448,512,[],"f239","M448 96v256c0 51.815-61.624 96-130.022 96l62.98 49.721C386.905 502.417 383.562 512 376 512H72c-7.578 0-10.892-9.594-4.957-14.279L130.022 448C61.82 448 0 403.954 0 352V96C0 42.981 64 0 128 0h192c65 0 128 42.981 128 96zM200 232V120c0-13.255-10.745-24-24-24H72c-13.255 0-24 10.745-24 24v112c0 13.255 10.745 24 24 24h104c13.255 0 24-10.745 24-24zm200 0V120c0-13.255-10.745-24-24-24H272c-13.255 0-24 10.745-24 24v112c0 13.255 10.745 24 24 24h104c13.255 0 24-10.745 24-24zm-48 56c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.49-48-48-48zm-256 0c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.49-48-48-48z"],suitcase:[512,512,[],"f0f2","M96 480h320V128h-32V80c0-26.51-21.49-48-48-48H176c-26.51 0-48 21.49-48 48v48H96v352zm96-384h128v32H192V96zm320 80v256c0 26.51-21.49 48-48 48h-16V128h16c26.51 0 48 21.49 48 48zM64 480H48c-26.51 0-48-21.49-48-48V176c0-26.51 21.49-48 48-48h16v352z"],sun:[512,512,[],"f185","M274.835 12.646l25.516 62.393c4.213 10.301 16.671 14.349 26.134 8.492l57.316-35.479c15.49-9.588 34.808 4.447 30.475 22.142l-16.03 65.475c-2.647 10.81 5.053 21.408 16.152 22.231l67.224 4.987c18.167 1.348 25.546 24.057 11.641 35.826L441.81 242.26c-8.495 7.19-8.495 20.289 0 27.479l51.454 43.548c13.906 11.769 6.527 34.478-11.641 35.826l-67.224 4.987c-11.099.823-18.799 11.421-16.152 22.231l16.03 65.475c4.332 17.695-14.986 31.73-30.475 22.142l-57.316-35.479c-9.463-5.858-21.922-1.81-26.134 8.492l-25.516 62.393c-6.896 16.862-30.774 16.862-37.67 0l-25.516-62.393c-4.213-10.301-16.671-14.349-26.134-8.492l-57.317 35.479c-15.49 9.588-34.808-4.447-30.475-22.142l16.03-65.475c2.647-10.81-5.053-21.408-16.152-22.231l-67.224-4.987c-18.167-1.348-25.546-24.057-11.641-35.826L70.19 269.74c8.495-7.19 8.495-20.289 0-27.479l-51.454-43.548c-13.906-11.769-6.527-34.478 11.641-35.826l67.224-4.987c11.099-.823 18.799-11.421 16.152-22.231l-16.03-65.475c-4.332-17.695 14.986-31.73 30.475-22.142l57.317 35.479c9.463 5.858 21.921 1.81 26.134-8.492l25.516-62.393c6.896-16.861 30.774-16.861 37.67 0zM392 256c0-74.991-61.01-136-136-136-74.991 0-136 61.009-136 136s61.009 136 136 136c74.99 0 136-61.009 136-136zm-32 0c0 57.346-46.654 104-104 104s-104-46.654-104-104 46.654-104 104-104 104 46.654 104 104z"],superscript:[512,512,[],"f12b","M395.198 256c3.461-10.526 18.796-21.28 36.265-32.425 16.625-10.605 35.467-22.626 50.341-38.862 17.458-19.054 25.944-40.175 25.944-64.567 0-60.562-50.702-88.146-97.81-88.146-42.491 0-76.378 22.016-94.432 50.447-4.654 7.329-2.592 17.036 4.623 21.865l30.328 20.296c7.032 4.706 16.46 3.084 21.63-3.614 8.022-10.394 18.818-18.225 31.667-18.225 19.387 0 26.266 12.901 26.266 23.948 0 36.159-119.437 57.023-119.437 160.024 0 6.654.561 13.014 1.415 19.331 1.076 7.964 7.834 13.928 15.87 13.928H496c8.837 0 16-7.163 16-16v-32c0-8.837-7.163-16-16-16H395.198zM272 416c8.837 0 16 7.163 16 16v32c0 8.837-7.163 16-16 16h-62.399a16 16 0 0 1-13.541-7.478l-45.701-72.615c-2.297-3.352-4.422-6.969-6.195-10.209-1.65 3.244-3.647 6.937-5.874 10.582l-44.712 72.147a15.999 15.999 0 0 1-13.6 7.572H16c-8.837 0-16-7.163-16-16v-32c0-8.837 7.163-16 16-16h26.325l56.552-82.709L46.111 256H16c-8.837 0-16-7.163-16-16v-32c0-8.837 7.163-16 16-16h68.806a16 16 0 0 1 13.645 7.644l39.882 65.126c2.072 3.523 4.053 7.171 5.727 10.37 1.777-3.244 3.92-6.954 6.237-10.537l40.332-65.035a16 16 0 0 1 13.598-7.567H272c8.837 0 16 7.163 16 16v32c0 8.837-7.163 16-16 16h-27.979l-52.69 75.671L249.974 416H272z"],sync:[512,512,[],"f021","M440.935 12.574l3.966 82.766C399.416 41.904 331.674 8 256 8 134.813 8 33.933 94.924 12.296 209.824 10.908 217.193 16.604 224 24.103 224h49.084c5.57 0 10.377-3.842 11.676-9.259C103.407 137.408 172.931 80 256 80c60.893 0 114.512 30.856 146.104 77.801l-101.53-4.865c-6.845-.328-12.574 5.133-12.574 11.986v47.411c0 6.627 5.373 12 12 12h200.333c6.627 0 12-5.373 12-12V12c0-6.627-5.373-12-12-12h-47.411c-6.853 0-12.315 5.729-11.987 12.574zM256 432c-60.895 0-114.517-30.858-146.109-77.805l101.868 4.871c6.845.327 12.573-5.134 12.573-11.986v-47.412c0-6.627-5.373-12-12-12H12c-6.627 0-12 5.373-12 12V500c0 6.627 5.373 12 12 12h47.385c6.863 0 12.328-5.745 11.985-12.599l-4.129-82.575C112.725 470.166 180.405 504 256 504c121.187 0 222.067-86.924 243.704-201.824 1.388-7.369-4.308-14.176-11.807-14.176h-49.084c-5.57 0-10.377 3.842-11.676 9.259C408.593 374.592 339.069 432 256 432z"],"sync-alt":[512,512,[],"f2f1","M370.72 133.28C339.458 104.008 298.888 87.962 255.848 88c-77.458.068-144.328 53.178-162.791 126.85-1.344 5.363-6.122 9.15-11.651 9.15H24.103c-7.498 0-13.194-6.807-11.807-14.176C33.933 94.924 134.813 8 256 8c66.448 0 126.791 26.136 171.315 68.685L463.03 40.97C478.149 25.851 504 36.559 504 57.941V192c0 13.255-10.745 24-24 24H345.941c-21.382 0-32.09-25.851-16.971-40.971l41.75-41.749zM32 296h134.059c21.382 0 32.09 25.851 16.971 40.971l-41.75 41.75c31.262 29.273 71.835 45.319 114.876 45.28 77.418-.07 144.315-53.144 162.787-126.849 1.344-5.363 6.122-9.15 11.651-9.15h57.304c7.498 0 13.194 6.807 11.807 14.176C478.067 417.076 377.187 504 256 504c-66.448 0-126.791-26.136-171.315-68.685L48.97 471.03C33.851 486.149 8 475.441 8 454.059V320c0-13.255 10.745-24 24-24z"],table:[512,512,[],"f0ce","M464 32H48C21.49 32 0 53.49 0 80v352c0 26.51 21.49 48 48 48h416c26.51 0 48-21.49 48-48V80c0-26.51-21.49-48-48-48zM224 416H64v-96h160v96zm0-160H64v-96h160v96zm224 160H288v-96h160v96zm0-160H288v-96h160v96z"],tablet:[448,512,[],"f10a","M400 0H48C21.5 0 0 21.5 0 48v416c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V48c0-26.5-21.5-48-48-48zM224 480c-17.7 0-32-14.3-32-32s14.3-32 32-32 32 14.3 32 32-14.3 32-32 32z"],"tablet-alt":[448,512,[],"f3fa","M400 0H48C21.5 0 0 21.5 0 48v416c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V48c0-26.5-21.5-48-48-48zM224 480c-17.7 0-32-14.3-32-32s14.3-32 32-32 32 14.3 32 32-14.3 32-32 32zm176-108c0 6.6-5.4 12-12 12H60c-6.6 0-12-5.4-12-12V60c0-6.6 5.4-12 12-12h328c6.6 0 12 5.4 12 12v312z"],"tachometer-alt":[576,512,[],"f3fd","M75.694 480a48.02 48.02 0 0 1-42.448-25.571C12.023 414.3 0 368.556 0 320 0 160.942 128.942 32 288 32s288 128.942 288 288c0 48.556-12.023 94.3-33.246 134.429A48.018 48.018 0 0 1 500.306 480H75.694zM512 288c-17.673 0-32 14.327-32 32 0 17.673 14.327 32 32 32s32-14.327 32-32c0-17.673-14.327-32-32-32zM288 128c17.673 0 32-14.327 32-32 0-17.673-14.327-32-32-32s-32 14.327-32 32c0 17.673 14.327 32 32 32zM64 288c-17.673 0-32 14.327-32 32 0 17.673 14.327 32 32 32s32-14.327 32-32c0-17.673-14.327-32-32-32zm65.608-158.392c-17.673 0-32 14.327-32 32 0 17.673 14.327 32 32 32s32-14.327 32-32c0-17.673-14.327-32-32-32zm316.784 0c-17.673 0-32 14.327-32 32 0 17.673 14.327 32 32 32s32-14.327 32-32c0-17.673-14.327-32-32-32zm-87.078 31.534c-12.627-4.04-26.133 2.92-30.173 15.544l-45.923 143.511C250.108 322.645 224 350.264 224 384c0 35.346 28.654 64 64 64 35.346 0 64-28.654 64-64 0-19.773-8.971-37.447-23.061-49.187l45.919-143.498c4.039-12.625-2.92-26.133-15.544-30.173z"],tag:[512,512,[],"f02b","M0 252.118V48C0 21.49 21.49 0 48 0h204.118a48 48 0 0 1 33.941 14.059l211.882 211.882c18.745 18.745 18.745 49.137 0 67.882L293.823 497.941c-18.745 18.745-49.137 18.745-67.882 0L14.059 286.059A48 48 0 0 1 0 252.118zM112 64c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.49-48-48-48z"],tags:[640,512,[],"f02c","M497.941 225.941L286.059 14.059A48 48 0 0 0 252.118 0H48C21.49 0 0 21.49 0 48v204.118a48 48 0 0 0 14.059 33.941l211.882 211.882c18.744 18.745 49.136 18.746 67.882 0l204.118-204.118c18.745-18.745 18.745-49.137 0-67.882zM112 160c-26.51 0-48-21.49-48-48s21.49-48 48-48 48 21.49 48 48-21.49 48-48 48zm513.941 133.823L421.823 497.941c-18.745 18.745-49.137 18.745-67.882 0l-.36-.36L527.64 323.522c16.999-16.999 26.36-39.6 26.36-63.64s-9.362-46.641-26.36-63.64L331.397 0h48.721a48 48 0 0 1 33.941 14.059l211.882 211.882c18.745 18.745 18.745 49.137 0 67.882z"],tasks:[512,512,[],"f0ae","M208 132h288c8.8 0 16-7.2 16-16V76c0-8.8-7.2-16-16-16H208c-8.8 0-16 7.2-16 16v40c0 8.8 7.2 16 16 16zm0 160h288c8.8 0 16-7.2 16-16v-40c0-8.8-7.2-16-16-16H208c-8.8 0-16 7.2-16 16v40c0 8.8 7.2 16 16 16zm0 160h288c8.8 0 16-7.2 16-16v-40c0-8.8-7.2-16-16-16H208c-8.8 0-16 7.2-16 16v40c0 8.8 7.2 16 16 16zM64 368c-26.5 0-48.6 21.5-48.6 48s22.1 48 48.6 48 48-21.5 48-48-21.5-48-48-48zm92.5-299l-72.2 72.2-15.6 15.6c-4.7 4.7-12.9 4.7-17.6 0L3.5 109.4c-4.7-4.7-4.7-12.3 0-17l15.7-15.7c4.7-4.7 12.3-4.7 17 0l22.7 22.1 63.7-63.3c4.7-4.7 12.3-4.7 17 0l17 16.5c4.6 4.7 4.6 12.3-.1 17zm0 159.6l-72.2 72.2-15.7 15.7c-4.7 4.7-12.9 4.7-17.6 0L3.5 269c-4.7-4.7-4.7-12.3 0-17l15.7-15.7c4.7-4.7 12.3-4.7 17 0l22.7 22.1 63.7-63.7c4.7-4.7 12.3-4.7 17 0l17 17c4.6 4.6 4.6 12.2-.1 16.9z"],taxi:[512,512,[],"f1ba","M461.951 243.865l-21.816-87.268A79.885 79.885 0 0 0 362.522 96H352V56c0-13.255-10.745-24-24-24H184c-13.255 0-24 10.745-24 24v40h-10.522a79.885 79.885 0 0 0-77.612 60.597L50.05 243.865C25.515 252.823 8 276.366 8 304v48c0 20.207 9.374 38.214 24 49.943V456c0 13.255 10.745 24 24 24h48c13.255 0 24-10.745 24-24v-40h256v40c0 13.255 10.745 24 24 24h48c13.255 0 24-10.745 24-24v-54.057c14.626-11.729 24-29.737 24-49.943v-48c0-27.634-17.515-51.177-42.049-60.135zM149.478 160h213.045a15.975 15.975 0 0 1 15.522 12.12l16.97 67.88h-278.03l16.97-67.881A15.976 15.976 0 0 1 149.478 160zM132 336c0 19.882-16.118 36-36 36s-36-16.118-36-36 16.118-36 36-36 36 16.118 36 36zm320 0c0 19.882-16.118 36-36 36s-36-16.118-36-36 16.118-36 36-36 36 16.118 36 36z"],terminal:[640,512,[],"f120","M257.981 272.971L63.638 467.314c-9.373 9.373-24.569 9.373-33.941 0L7.029 444.647c-9.357-9.357-9.375-24.522-.04-33.901L161.011 256 6.99 101.255c-9.335-9.379-9.317-24.544.04-33.901l22.667-22.667c9.373-9.373 24.569-9.373 33.941 0L257.981 239.03c9.373 9.372 9.373 24.568 0 33.941zM640 456v-32c0-13.255-10.745-24-24-24H312c-13.255 0-24 10.745-24 24v32c0 13.255 10.745 24 24 24h304c13.255 0 24-10.745 24-24z"],"text-height":[576,512,[],"f034","M16 32h288c8.837 0 16 7.163 16 16v96c0 8.837-7.163 16-16 16h-35.496c-8.837 0-16-7.163-16-16V96h-54.761v320H232c8.837 0 16 7.163 16 16v32c0 8.837-7.163 16-16 16H88c-8.837 0-16-7.163-16-16v-32c0-8.837 7.163-16 16-16h34.257V96H67.496v48c0 8.837-7.163 16-16 16H16c-8.837 0-16-7.163-16-16V48c0-8.837 7.163-16 16-16zm475.308 4.685l79.995 80.001C581.309 126.693 574.297 144 559.99 144H512v224h48c15.639 0 20.635 17.991 11.313 27.314l-79.995 80.001c-6.247 6.247-16.381 6.245-22.626 0l-79.995-80.001C378.691 385.307 385.703 368 400.01 368H448V144h-48c-15.639 0-20.635-17.991-11.313-27.314l79.995-80.001c6.247-6.248 16.381-6.245 22.626 0z"],"text-width":[448,512,[],"f035","M16 32h416c8.837 0 16 7.163 16 16v96c0 8.837-7.163 16-16 16h-35.496c-8.837 0-16-7.163-16-16V96H261.743v128H296c8.837 0 16 7.163 16 16v32c0 8.837-7.163 16-16 16H152c-8.837 0-16-7.163-16-16v-32c0-8.837 7.163-16 16-16h34.257V96H67.496v48c0 8.837-7.163 16-16 16H16c-8.837 0-16-7.163-16-16V48c0-8.837 7.163-16 16-16zm427.315 340.682l-80.001-79.995C353.991 283.365 336 288.362 336 304v48H112v-47.99c0-14.307-17.307-21.319-27.314-11.313L4.685 372.692c-6.245 6.245-6.247 16.379 0 22.626l80.001 79.995C94.009 484.635 112 479.638 112 464v-48h224v47.99c0 14.307 17.307 21.319 27.314 11.313l80.001-79.995c6.245-6.245 6.248-16.379 0-22.626z"],th:[512,512,[],"f00a","M149.333 56v80c0 13.255-10.745 24-24 24H24c-13.255 0-24-10.745-24-24V56c0-13.255 10.745-24 24-24h101.333c13.255 0 24 10.745 24 24zm181.334 240v-80c0-13.255-10.745-24-24-24H205.333c-13.255 0-24 10.745-24 24v80c0 13.255 10.745 24 24 24h101.333c13.256 0 24.001-10.745 24.001-24zm32-240v80c0 13.255 10.745 24 24 24H488c13.255 0 24-10.745 24-24V56c0-13.255-10.745-24-24-24H386.667c-13.255 0-24 10.745-24 24zm-32 80V56c0-13.255-10.745-24-24-24H205.333c-13.255 0-24 10.745-24 24v80c0 13.255 10.745 24 24 24h101.333c13.256 0 24.001-10.745 24.001-24zm-205.334 56H24c-13.255 0-24 10.745-24 24v80c0 13.255 10.745 24 24 24h101.333c13.255 0 24-10.745 24-24v-80c0-13.255-10.745-24-24-24zM0 376v80c0 13.255 10.745 24 24 24h101.333c13.255 0 24-10.745 24-24v-80c0-13.255-10.745-24-24-24H24c-13.255 0-24 10.745-24 24zm386.667-56H488c13.255 0 24-10.745 24-24v-80c0-13.255-10.745-24-24-24H386.667c-13.255 0-24 10.745-24 24v80c0 13.255 10.745 24 24 24zm0 160H488c13.255 0 24-10.745 24-24v-80c0-13.255-10.745-24-24-24H386.667c-13.255 0-24 10.745-24 24v80c0 13.255 10.745 24 24 24zM181.333 376v80c0 13.255 10.745 24 24 24h101.333c13.255 0 24-10.745 24-24v-80c0-13.255-10.745-24-24-24H205.333c-13.255 0-24 10.745-24 24z"],"th-large":[512,512,[],"f009","M296 32h192c13.255 0 24 10.745 24 24v160c0 13.255-10.745 24-24 24H296c-13.255 0-24-10.745-24-24V56c0-13.255 10.745-24 24-24zm-80 0H24C10.745 32 0 42.745 0 56v160c0 13.255 10.745 24 24 24h192c13.255 0 24-10.745 24-24V56c0-13.255-10.745-24-24-24zM0 296v160c0 13.255 10.745 24 24 24h192c13.255 0 24-10.745 24-24V296c0-13.255-10.745-24-24-24H24c-13.255 0-24 10.745-24 24zm296 184h192c13.255 0 24-10.745 24-24V296c0-13.255-10.745-24-24-24H296c-13.255 0-24 10.745-24 24v160c0 13.255 10.745 24 24 24z"],"th-list":[512,512,[],"f00b","M149.333 216v80c0 13.255-10.745 24-24 24H24c-13.255 0-24-10.745-24-24v-80c0-13.255 10.745-24 24-24h101.333c13.255 0 24 10.745 24 24zM0 376v80c0 13.255 10.745 24 24 24h101.333c13.255 0 24-10.745 24-24v-80c0-13.255-10.745-24-24-24H24c-13.255 0-24 10.745-24 24zM125.333 32H24C10.745 32 0 42.745 0 56v80c0 13.255 10.745 24 24 24h101.333c13.255 0 24-10.745 24-24V56c0-13.255-10.745-24-24-24zm80 448H488c13.255 0 24-10.745 24-24v-80c0-13.255-10.745-24-24-24H205.333c-13.255 0-24 10.745-24 24v80c0 13.255 10.745 24 24 24zm-24-424v80c0 13.255 10.745 24 24 24H488c13.255 0 24-10.745 24-24V56c0-13.255-10.745-24-24-24H205.333c-13.255 0-24 10.745-24 24zm24 264H488c13.255 0 24-10.745 24-24v-80c0-13.255-10.745-24-24-24H205.333c-13.255 0-24 10.745-24 24v80c0 13.255 10.745 24 24 24z"],"thermometer-empty":[256,512,[],"f2cb","M192 384c0 35.346-28.654 64-64 64s-64-28.654-64-64c0-35.346 28.654-64 64-64s64 28.654 64 64zm32-84.653c19.912 22.563 32 52.194 32 84.653 0 70.696-57.303 128-128 128-.299 0-.609-.001-.909-.003C56.789 511.509-.357 453.636.002 383.333.166 351.135 12.225 321.755 32 299.347V96c0-53.019 42.981-96 96-96s96 42.981 96 96v203.347zM208 384c0-34.339-19.37-52.19-32-66.502V96c0-26.467-21.533-48-48-48S80 69.533 80 96v221.498c-12.732 14.428-31.825 32.1-31.999 66.08-.224 43.876 35.563 80.116 79.423 80.42L128 464c44.112 0 80-35.888 80-80z"],"thermometer-full":[256,512,[],"f2c7","M224 96c0-53.019-42.981-96-96-96S32 42.981 32 96v203.347C12.225 321.756.166 351.136.002 383.333c-.359 70.303 56.787 128.176 127.089 128.664.299.002.61.003.909.003 70.698 0 128-57.304 128-128 0-32.459-12.088-62.09-32-84.653V96zm-96 368l-.576-.002c-43.86-.304-79.647-36.544-79.423-80.42.173-33.98 19.266-51.652 31.999-66.08V96c0-26.467 21.533-48 48-48s48 21.533 48 48v221.498c12.63 14.312 32 32.164 32 66.502 0 44.112-35.888 80-80 80zm64-80c0 35.346-28.654 64-64 64s-64-28.654-64-64c0-23.685 12.876-44.349 32-55.417V96c0-17.673 14.327-32 32-32s32 14.327 32 32v232.583c19.124 11.068 32 31.732 32 55.417z"],"thermometer-half":[256,512,[],"f2c9","M192 384c0 35.346-28.654 64-64 64s-64-28.654-64-64c0-23.685 12.876-44.349 32-55.417V224c0-17.673 14.327-32 32-32s32 14.327 32 32v104.583c19.124 11.068 32 31.732 32 55.417zm32-84.653c19.912 22.563 32 52.194 32 84.653 0 70.696-57.303 128-128 128-.299 0-.609-.001-.909-.003C56.789 511.509-.357 453.636.002 383.333.166 351.135 12.225 321.755 32 299.347V96c0-53.019 42.981-96 96-96s96 42.981 96 96v203.347zM208 384c0-34.339-19.37-52.19-32-66.502V96c0-26.467-21.533-48-48-48S80 69.533 80 96v221.498c-12.732 14.428-31.825 32.1-31.999 66.08-.224 43.876 35.563 80.116 79.423 80.42L128 464c44.112 0 80-35.888 80-80z"],"thermometer-quarter":[256,512,[],"f2ca","M192 384c0 35.346-28.654 64-64 64s-64-28.654-64-64c0-23.685 12.876-44.349 32-55.417V288c0-17.673 14.327-32 32-32s32 14.327 32 32v40.583c19.124 11.068 32 31.732 32 55.417zm32-84.653c19.912 22.563 32 52.194 32 84.653 0 70.696-57.303 128-128 128-.299 0-.609-.001-.909-.003C56.789 511.509-.357 453.636.002 383.333.166 351.135 12.225 321.755 32 299.347V96c0-53.019 42.981-96 96-96s96 42.981 96 96v203.347zM208 384c0-34.339-19.37-52.19-32-66.502V96c0-26.467-21.533-48-48-48S80 69.533 80 96v221.498c-12.732 14.428-31.825 32.1-31.999 66.08-.224 43.876 35.563 80.116 79.423 80.42L128 464c44.112 0 80-35.888 80-80z"],"thermometer-three-quarters":[256,512,[],"f2c8","M192 384c0 35.346-28.654 64-64 64-35.346 0-64-28.654-64-64 0-23.685 12.876-44.349 32-55.417V160c0-17.673 14.327-32 32-32s32 14.327 32 32v168.583c19.124 11.068 32 31.732 32 55.417zm32-84.653c19.912 22.563 32 52.194 32 84.653 0 70.696-57.303 128-128 128-.299 0-.609-.001-.909-.003C56.789 511.509-.357 453.636.002 383.333.166 351.135 12.225 321.755 32 299.347V96c0-53.019 42.981-96 96-96s96 42.981 96 96v203.347zM208 384c0-34.339-19.37-52.19-32-66.502V96c0-26.467-21.533-48-48-48S80 69.533 80 96v221.498c-12.732 14.428-31.825 32.1-31.999 66.08-.224 43.876 35.563 80.116 79.423 80.42L128 464c44.112 0 80-35.888 80-80z"],"thumbs-down":[512,512,[],"f165","M0 56v240c0 13.255 10.745 24 24 24h80c13.255 0 24-10.745 24-24V56c0-13.255-10.745-24-24-24H24C10.745 32 0 42.745 0 56zm40 200c0-13.255 10.745-24 24-24s24 10.745 24 24-10.745 24-24 24-24-10.745-24-24zm272 256c-20.183 0-29.485-39.293-33.931-57.795-5.206-21.666-10.589-44.07-25.393-58.902-32.469-32.524-49.503-73.967-89.117-113.111a11.98 11.98 0 0 1-3.558-8.521V59.901c0-6.541 5.243-11.878 11.783-11.998 15.831-.29 36.694-9.079 52.651-16.178C256.189 17.598 295.709.017 343.995 0h2.844c42.777 0 93.363.413 113.774 29.737 8.392 12.057 10.446 27.034 6.148 44.632 16.312 17.053 25.063 48.863 16.382 74.757 17.544 23.432 19.143 56.132 9.308 79.469l.11.11c11.893 11.949 19.523 31.259 19.439 49.197-.156 30.352-26.157 58.098-59.553 58.098H350.723C358.03 364.34 384 388.132 384 430.548 384 504 336 512 312 512z"],"thumbs-up":[512,512,[],"f164","M104 224H24c-13.255 0-24 10.745-24 24v240c0 13.255 10.745 24 24 24h80c13.255 0 24-10.745 24-24V248c0-13.255-10.745-24-24-24zM64 472c-13.255 0-24-10.745-24-24s10.745-24 24-24 24 10.745 24 24-10.745 24-24 24zM384 81.452c0 42.416-25.97 66.208-33.277 94.548h101.723c33.397 0 59.397 27.746 59.553 58.098.084 17.938-7.546 37.249-19.439 49.197l-.11.11c9.836 23.337 8.237 56.037-9.308 79.469 8.681 25.895-.069 57.704-16.382 74.757 4.298 17.598 2.244 32.575-6.148 44.632C440.202 511.587 389.616 512 346.839 512l-2.845-.001c-48.287-.017-87.806-17.598-119.56-31.725-15.957-7.099-36.821-15.887-52.651-16.178-6.54-.12-11.783-5.457-11.783-11.998v-213.77c0-3.2 1.282-6.271 3.558-8.521 39.614-39.144 56.648-80.587 89.117-113.111 14.804-14.832 20.188-37.236 25.393-58.902C282.515 39.293 291.817 0 312 0c24 0 72 8 72 81.452z"],thumbtack:[384,512,[],"f08d","M298.028 214.267L285.793 96H328c13.255 0 24-10.745 24-24V24c0-13.255-10.745-24-24-24H56C42.745 0 32 10.745 32 24v48c0 13.255 10.745 24 24 24h42.207L85.972 214.267C37.465 236.82 0 277.261 0 328c0 13.255 10.745 24 24 24h136v104.007c0 1.242.289 2.467.845 3.578l24 48c2.941 5.882 11.364 5.893 14.311 0l24-48a8.008 8.008 0 0 0 .845-3.578V352h136c13.255 0 24-10.745 24-24-.001-51.183-37.983-91.42-85.973-113.733z"],"ticket-alt":[576,512,[],"f3ff","M128 160h320v192H128V160zm400 96c0 26.51 21.49 48 48 48v96c0 26.51-21.49 48-48 48H48c-26.51 0-48-21.49-48-48v-96c26.51 0 48-21.49 48-48s-21.49-48-48-48v-96c0-26.51 21.49-48 48-48h480c26.51 0 48 21.49 48 48v96c-26.51 0-48 21.49-48 48zm-48-104c0-13.255-10.745-24-24-24H120c-13.255 0-24 10.745-24 24v208c0 13.255 10.745 24 24 24h336c13.255 0 24-10.745 24-24V152z"],times:[384,512,[],"f00d","M323.1 441l53.9-53.9c9.4-9.4 9.4-24.5 0-33.9L279.8 256l97.2-97.2c9.4-9.4 9.4-24.5 0-33.9L323.1 71c-9.4-9.4-24.5-9.4-33.9 0L192 168.2 94.8 71c-9.4-9.4-24.5-9.4-33.9 0L7 124.9c-9.4 9.4-9.4 24.5 0 33.9l97.2 97.2L7 353.2c-9.4 9.4-9.4 24.5 0 33.9L60.9 441c9.4 9.4 24.5 9.4 33.9 0l97.2-97.2 97.2 97.2c9.3 9.3 24.5 9.3 33.9 0z"],"times-circle":[512,512,[],"f057","M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm121.6 313.1c4.7 4.7 4.7 12.3 0 17L338 377.6c-4.7 4.7-12.3 4.7-17 0L256 312l-65.1 65.6c-4.7 4.7-12.3 4.7-17 0L134.4 338c-4.7-4.7-4.7-12.3 0-17l65.6-65-65.6-65.1c-4.7-4.7-4.7-12.3 0-17l39.6-39.6c4.7-4.7 12.3-4.7 17 0l65 65.7 65.1-65.6c4.7-4.7 12.3-4.7 17 0l39.6 39.6c4.7 4.7 4.7 12.3 0 17L312 256l65.6 65.1z"],tint:[384,512,[],"f043","M192 512c-98.435 0-178.087-79.652-178.087-178.087 0-111.196 101.194-154.065 148.522-311.825 9.104-30.116 51.099-28.778 59.13 0 47.546 158.486 148.522 200.069 148.522 311.825C370.087 432.348 290.435 512 192 512zm-42.522-171.826c-1.509-5.533-9.447-5.532-10.956 0-9.223 29.425-27.913 37.645-27.913 58.435C110.609 417.13 125.478 432 144 432s33.391-14.87 33.391-33.391c0-20.839-18.673-28.956-27.913-58.435z"],"toggle-off":[576,512,[],"f204","M384 64H192C85.961 64 0 149.961 0 256s85.961 192 192 192h192c106.039 0 192-85.961 192-192S490.039 64 384 64zM64 256c0-70.741 57.249-128 128-128 70.741 0 128 57.249 128 128 0 70.741-57.249 128-128 128-70.741 0-128-57.249-128-128zm320 128h-48.905c65.217-72.858 65.236-183.12 0-256H384c70.741 0 128 57.249 128 128 0 70.74-57.249 128-128 128z"],"toggle-on":[576,512,[],"f205","M576 256c0 106.039-85.961 192-192 192H192C85.961 448 0 362.039 0 256S85.961 64 192 64h192c106.039 0 192 85.961 192 192zM384 128c-70.741 0-128 57.249-128 128 0 70.741 57.249 128 128 128 70.741 0 128-57.249 128-128 0-70.741-57.249-128-128-128"],trademark:[640,512,[],"f25c","M97.119 163.133H12c-6.627 0-12-5.373-12-12V108c0-6.627 5.373-12 12-12h248.559c6.627 0 12 5.373 12 12v43.133c0 6.627-5.373 12-12 12H175.44V404c0 6.627-5.373 12-12 12h-54.322c-6.627 0-12-5.373-12-12V163.133zM329.825 96h65.425a12 12 0 0 1 11.346 8.093l43.759 127.068c7.161 20.588 16.111 52.812 16.111 52.812h.896s8.95-32.224 16.111-52.812l43.758-127.068A12 12 0 0 1 538.577 96h65.41a12 12 0 0 1 11.961 11.03l24.012 296c.567 6.987-4.951 12.97-11.961 12.97h-54.101a12 12 0 0 1-11.972-11.182l-9.082-132.93c-1.79-24.168 0-53.706 0-53.706h-.896s-10.741 33.566-17.902 53.706l-30.7 84.731a12 12 0 0 1-11.282 7.912h-50.302a12 12 0 0 1-11.282-7.912l-30.7-84.731c-7.161-20.14-17.903-53.706-17.903-53.706h-.895s1.79 29.538 0 53.706l-9.082 132.93c-.428 6.295-5.66 11.182-11.97 11.182H305.4c-7.017 0-12.536-5.994-11.959-12.987l24.425-296A11.999 11.999 0 0 1 329.825 96z"],train:[448,512,[],"f238","M448 96v256c0 51.815-61.624 96-130.022 96l62.98 49.721C386.905 502.417 383.562 512 376 512H72c-7.578 0-10.892-9.594-4.957-14.279L130.022 448C61.82 448 0 403.954 0 352V96C0 42.981 64 0 128 0h192c65 0 128 42.981 128 96zm-48 136V120c0-13.255-10.745-24-24-24H72c-13.255 0-24 10.745-24 24v112c0 13.255 10.745 24 24 24h304c13.255 0 24-10.745 24-24zm-176 64c-30.928 0-56 25.072-56 56s25.072 56 56 56 56-25.072 56-56-25.072-56-56-56z"],transgender:[384,512,[],"f224","M372 0h-79c-10.7 0-16 12.9-8.5 20.5l16.9 16.9-80.7 80.7C198.5 104.1 172.2 96 144 96 64.5 96 0 160.5 0 240c0 68.5 47.9 125.9 112 140.4V408H76c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h36v28c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12v-28h36c6.6 0 12-5.4 12-12v-40c0-6.6-5.4-12-12-12h-36v-27.6c64.1-14.6 112-71.9 112-140.4 0-28.2-8.1-54.5-22.1-76.7l80.7-80.7 16.9 16.9c7.6 7.6 20.5 2.2 20.5-8.5V12c0-6.6-5.4-12-12-12zM144 320c-44.1 0-80-35.9-80-80s35.9-80 80-80 80 35.9 80 80-35.9 80-80 80z"],"transgender-alt":[480,512,[],"f225","M468 0h-79c-10.7 0-16 12.9-8.5 20.5l16.9 16.9-80.7 80.7C294.5 104.1 268.2 96 240 96c-28.2 0-54.5 8.1-76.7 22.1l-16.5-16.5 19.8-19.8c4.7-4.7 4.7-12.3 0-17l-28.3-28.3c-4.7-4.7-12.3-4.7-17 0l-19.8 19.8-19-19 16.9-16.9C107.1 12.9 101.7 0 91 0H12C5.4 0 0 5.4 0 12v79c0 10.7 12.9 16 20.5 8.5l16.9-16.9 19 19-19.8 19.8c-4.7 4.7-4.7 12.3 0 17l28.3 28.3c4.7 4.7 12.3 4.7 17 0l19.8-19.8 16.5 16.5C104.1 185.5 96 211.8 96 240c0 68.5 47.9 125.9 112 140.4V408h-36c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h36v28c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12v-28h36c6.6 0 12-5.4 12-12v-40c0-6.6-5.4-12-12-12h-36v-27.6c64.1-14.6 112-71.9 112-140.4 0-28.2-8.1-54.5-22.1-76.7l80.7-80.7 16.9 16.9c7.6 7.6 20.5 2.2 20.5-8.5V12c0-6.6-5.4-12-12-12zM240 320c-44.1 0-80-35.9-80-80s35.9-80 80-80 80 35.9 80 80-35.9 80-80 80z"],trash:[448,512,[],"f1f8","M0 84V56c0-13.3 10.7-24 24-24h112l9.4-18.7c4-8.2 12.3-13.3 21.4-13.3h114.3c9.1 0 17.4 5.1 21.5 13.3L312 32h112c13.3 0 24 10.7 24 24v28c0 6.6-5.4 12-12 12H12C5.4 96 0 90.6 0 84zm415.2 56.7L394.8 467c-1.6 25.3-22.6 45-47.9 45H101.1c-25.3 0-46.3-19.7-47.9-45L32.8 140.7c-.4-6.9 5.1-12.7 12-12.7h358.5c6.8 0 12.3 5.8 11.9 12.7z"],"trash-alt":[448,512,[],"f2ed","M0 84V56c0-13.3 10.7-24 24-24h112l9.4-18.7c4-8.2 12.3-13.3 21.4-13.3h114.3c9.1 0 17.4 5.1 21.5 13.3L312 32h112c13.3 0 24 10.7 24 24v28c0 6.6-5.4 12-12 12H12C5.4 96 0 90.6 0 84zm416 56v324c0 26.5-21.5 48-48 48H80c-26.5 0-48-21.5-48-48V140c0-6.6 5.4-12 12-12h360c6.6 0 12 5.4 12 12zm-272 68c0-8.8-7.2-16-16-16s-16 7.2-16 16v224c0 8.8 7.2 16 16 16s16-7.2 16-16V208zm96 0c0-8.8-7.2-16-16-16s-16 7.2-16 16v224c0 8.8 7.2 16 16 16s16-7.2 16-16V208zm96 0c0-8.8-7.2-16-16-16s-16 7.2-16 16v224c0 8.8 7.2 16 16 16s16-7.2 16-16V208z"],tree:[384,512,[],"f1bb","M377.33 375.429L293.906 288H328c21.017 0 31.872-25.207 17.448-40.479L262.79 160H296c20.878 0 31.851-24.969 17.587-40.331l-104-112.003c-9.485-10.214-25.676-10.229-35.174 0l-104 112.003C56.206 134.969 67.037 160 88 160h33.21l-82.659 87.521C24.121 262.801 34.993 288 56 288h34.094L6.665 375.429C-7.869 390.655 2.925 416 24.025 416H144c0 32.781-11.188 49.26-33.995 67.506C98.225 492.93 104.914 512 120 512h144c15.086 0 21.776-19.069 9.995-28.494-19.768-15.814-33.992-31.665-33.995-67.496V416h119.97c21.05 0 31.929-25.309 17.36-40.571z"],trophy:[576,512,[],"f091","M552 64H448V24c0-13.3-10.7-24-24-24H152c-13.3 0-24 10.7-24 24v40H24C10.7 64 0 74.7 0 88v56c0 35.7 22.5 72.4 61.9 100.7 31.5 22.7 69.8 37.1 110 41.7C203.3 338.5 240 360 240 360v72h-48c-35.3 0-64 20.7-64 56v12c0 6.6 5.4 12 12 12h296c6.6 0 12-5.4 12-12v-12c0-35.3-28.7-56-64-56h-48v-72s36.7-21.5 68.1-73.6c40.3-4.6 78.6-19 110-41.7 39.3-28.3 61.9-65 61.9-100.7V88c0-13.3-10.7-24-24-24zM99.3 192.8C74.9 175.2 64 155.6 64 144v-16h64.2c1 32.6 5.8 61.2 12.8 86.2-15.1-5.2-29.2-12.4-41.7-21.4zM512 144c0 16.1-17.7 36.1-35.3 48.8-12.5 9-26.7 16.2-41.8 21.4 7-25 11.8-53.6 12.8-86.2H512v16z"],truck:[640,512,[],"f0d1","M592 0H272c-26.51 0-48 21.49-48 48v48h-44.118a48 48 0 0 0-33.941 14.059l-99.882 99.882A48 48 0 0 0 32 243.882V352h-8c-13.255 0-24 10.745-24 24v16c0 13.255 10.745 24 24 24h40c0 53.019 42.981 96 96 96s96-42.981 96-96h128c0 53.019 42.981 96 96 96s96-42.981 96-96h40c13.255 0 24-10.745 24-24V48c0-26.51-21.49-48-48-48zM160 464c-26.467 0-48-21.533-48-48s21.533-48 48-48 48 21.533 48 48-21.533 48-48 48zm64-208H80v-12.118L179.882 144H224v112zm256 208c-26.467 0-48-21.533-48-48s21.533-48 48-48 48 21.533 48 48-21.533 48-48 48z"],tty:[512,512,[],"f1e4","M5.37 103.822c138.532-138.532 362.936-138.326 501.262 0 6.078 6.078 7.074 15.496 2.583 22.681l-43.214 69.138a18.332 18.332 0 0 1-22.356 7.305l-86.422-34.569a18.335 18.335 0 0 1-11.434-18.846L351.741 90c-62.145-22.454-130.636-21.986-191.483 0l5.953 59.532a18.331 18.331 0 0 1-11.434 18.846l-86.423 34.568a18.334 18.334 0 0 1-22.356-7.305L2.787 126.502a18.333 18.333 0 0 1 2.583-22.68zM96 308v-40c0-6.627-5.373-12-12-12H44c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm-336 96v-40c0-6.627-5.373-12-12-12H92c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zM96 500v-40c0-6.627-5.373-12-12-12H44c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm288 0v-40c0-6.627-5.373-12-12-12H140c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h232c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12z"],tv:[640,512,[],"f26c","M592 0H48C21.5 0 0 21.5 0 48v320c0 26.5 21.5 48 48 48h245.1v32h-160c-17.7 0-32 14.3-32 32s14.3 32 32 32h384c17.7 0 32-14.3 32-32s-14.3-32-32-32h-160v-32H592c26.5 0 48-21.5 48-48V48c0-26.5-21.5-48-48-48zm-16 352H64V64h512v288z"],umbrella:[576,512,[],"f0e9","M557.011 267.631c-51.432-45.217-107.572-43.698-158.567 30.731-5.298 7.861-14.906 7.165-19.736 0-2.483-3.624-32.218-60.808-90.708-60.808-45.766 0-70.542 31.378-90.709 60.808-4.829 7.165-14.436 7.861-19.734 0-50.904-74.285-106.613-76.406-158.567-30.731-10.21 8.264-20.912-1.109-18.696-9.481C32.146 134.573 158.516 64.612 288.001 64.612c128.793 0 256.546 69.961 287.706 193.538 2.206 8.322-8.426 17.793-18.696 9.481zM256 261.001V416c0 17.645-14.355 32-32 32s-32-14.355-32-32c0-17.673-14.327-32-32-32s-32 14.327-32 32c0 52.935 43.065 96 96 96s96-43.065 96-96V261.288c-21.836-10.806-45.425-9.737-64-.287zm64-211.007V32c0-17.673-14.327-32-32-32s-32 14.327-32 32v17.987a372.105 372.105 0 0 1 64 .007z"],underline:[448,512,[],"f0cd","M224.264 388.24c-91.669 0-156.603-51.165-156.603-151.392V64H39.37c-8.837 0-16-7.163-16-16V16c0-8.837 7.163-16 16-16h137.39c8.837 0 16 7.163 16 16v32c0 8.837-7.163 16-16 16h-28.813v172.848c0 53.699 28.314 79.444 76.317 79.444 46.966 0 75.796-25.434 75.796-79.965V64h-28.291c-8.837 0-16-7.163-16-16V16c0-8.837 7.163-16 16-16h136.868c8.837 0 16 7.163 16 16v32c0 8.837-7.163 16-16 16h-28.291v172.848c0 99.405-64.881 151.392-156.082 151.392zM16 448h416c8.837 0 16 7.163 16 16v32c0 8.837-7.163 16-16 16H16c-8.837 0-16-7.163-16-16v-32c0-8.837 7.163-16 16-16z"],undo:[512,512,[],"f0e2","M212.333 224.333H12c-6.627 0-12-5.373-12-12V12C0 5.373 5.373 0 12 0h48c6.627 0 12 5.373 12 12v78.112C117.773 39.279 184.26 7.47 258.175 8.007c136.906.994 246.448 111.623 246.157 248.532C504.041 393.258 393.12 504 256.333 504c-64.089 0-122.496-24.313-166.51-64.215-5.099-4.622-5.334-12.554-.467-17.42l33.967-33.967c4.474-4.474 11.662-4.717 16.401-.525C170.76 415.336 211.58 432 256.333 432c97.268 0 176-78.716 176-176 0-97.267-78.716-176-176-176-58.496 0-110.28 28.476-142.274 72.333h98.274c6.627 0 12 5.373 12 12v48c0 6.627-5.373 12-12 12z"],"undo-alt":[512,512,[],"f2ea","M255.545 8c-66.269.119-126.438 26.233-170.86 68.685L48.971 40.971C33.851 25.851 8 36.559 8 57.941V192c0 13.255 10.745 24 24 24h134.059c21.382 0 32.09-25.851 16.971-40.971l-41.75-41.75c30.864-28.899 70.801-44.907 113.23-45.273 92.398-.798 170.283 73.977 169.484 169.442C423.236 348.009 349.816 424 256 424c-41.127 0-79.997-14.678-110.63-41.556-4.743-4.161-11.906-3.908-16.368.553L89.34 422.659c-4.872 4.872-4.631 12.815.482 17.433C133.798 479.813 192.074 504 256 504c136.966 0 247.999-111.033 248-247.998C504.001 119.193 392.354 7.755 255.545 8z"],"universal-access":[512,512,[],"f29a","M256 48c114.953 0 208 93.029 208 208 0 114.953-93.029 208-208 208-114.953 0-208-93.029-208-208 0-114.953 93.029-208 208-208m0-40C119.033 8 8 119.033 8 256s111.033 248 248 248 248-111.033 248-248S392.967 8 256 8zm0 56C149.961 64 64 149.961 64 256s85.961 192 192 192 192-85.961 192-192S362.039 64 256 64zm0 44c19.882 0 36 16.118 36 36s-16.118 36-36 36-36-16.118-36-36 16.118-36 36-36zm117.741 98.023c-28.712 6.779-55.511 12.748-82.14 15.807.851 101.023 12.306 123.052 25.037 155.621 3.617 9.26-.957 19.698-10.217 23.315-9.261 3.617-19.699-.957-23.316-10.217-8.705-22.308-17.086-40.636-22.261-78.549h-9.686c-5.167 37.851-13.534 56.208-22.262 78.549-3.615 9.255-14.05 13.836-23.315 10.217-9.26-3.617-13.834-14.056-10.217-23.315 12.713-32.541 24.185-54.541 25.037-155.621-26.629-3.058-53.428-9.027-82.141-15.807-8.6-2.031-13.926-10.648-11.895-19.249s10.647-13.926 19.249-11.895c96.686 22.829 124.283 22.783 220.775 0 8.599-2.03 17.218 3.294 19.249 11.895 2.029 8.601-3.297 17.219-11.897 19.249z"],university:[512,512,[],"f19c","M480 128v16a8 8 0 0 1-8 8h-24v12c0 6.627-5.373 12-12 12H44c-6.627 0-12-5.373-12-12v-12H8a8 8 0 0 1-8-8v-16a8 8 0 0 1 4.941-7.392l232-88a7.996 7.996 0 0 1 6.118 0l232 88A8 8 0 0 1 480 128zm-24 304H24c-13.255 0-24 10.745-24 24v16a8 8 0 0 0 8 8h464a8 8 0 0 0 8-8v-16c0-13.255-10.745-24-24-24zM64 192v192H44c-6.627 0-12 5.373-12 12v20h416v-20c0-6.627-5.373-12-12-12h-20V192h-64v192h-32V192h-64v192h-32V192h-64v192h-32V192H64z"],unlink:[512,512,[],"f127","M304.083 405.907c4.686 4.686 4.686 12.284 0 16.971l-44.674 44.674c-59.263 59.262-155.693 59.266-214.961 0-59.264-59.265-59.264-155.696 0-214.96l44.675-44.675c4.686-4.686 12.284-4.686 16.971 0l39.598 39.598c4.686 4.686 4.686 12.284 0 16.971l-44.675 44.674c-28.072 28.073-28.072 73.75 0 101.823 28.072 28.072 73.75 28.073 101.824 0l44.674-44.674c4.686-4.686 12.284-4.686 16.971 0l39.597 39.598zm-56.568-260.216c4.686 4.686 12.284 4.686 16.971 0l44.674-44.674c28.072-28.075 73.75-28.073 101.824 0 28.072 28.073 28.072 73.75 0 101.823l-44.675 44.674c-4.686 4.686-4.686 12.284 0 16.971l39.598 39.598c4.686 4.686 12.284 4.686 16.971 0l44.675-44.675c59.265-59.265 59.265-155.695 0-214.96-59.266-59.264-155.695-59.264-214.961 0l-44.674 44.674c-4.686 4.686-4.686 12.284 0 16.971l39.597 39.598zm234.828 359.28l22.627-22.627c9.373-9.373 9.373-24.569 0-33.941L63.598 7.029c-9.373-9.373-24.569-9.373-33.941 0L7.029 29.657c-9.373 9.373-9.373 24.569 0 33.941l441.373 441.373c9.373 9.372 24.569 9.372 33.941 0z"],unlock:[448,512,[],"f09c","M400 256H152V152.9c0-39.6 31.7-72.5 71.3-72.9 40-.4 72.7 32.1 72.7 72v16c0 13.3 10.7 24 24 24h32c13.3 0 24-10.7 24-24v-16C376 68 307.5-.3 223.5 0 139.5.3 72 69.5 72 153.5V256H48c-26.5 0-48 21.5-48 48v160c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V304c0-26.5-21.5-48-48-48z"],"unlock-alt":[448,512,[],"f13e","M400 256H152V152.9c0-39.6 31.7-72.5 71.3-72.9 40-.4 72.7 32.1 72.7 72v16c0 13.3 10.7 24 24 24h32c13.3 0 24-10.7 24-24v-16C376 68 307.5-.3 223.5 0 139.5.3 72 69.5 72 153.5V256H48c-26.5 0-48 21.5-48 48v160c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V304c0-26.5-21.5-48-48-48zM264 408c0 22.1-17.9 40-40 40s-40-17.9-40-40v-48c0-22.1 17.9-40 40-40s40 17.9 40 40v48z"],upload:[512,512,[],"f093","M296 384h-80c-13.3 0-24-10.7-24-24V192h-87.7c-17.8 0-26.7-21.5-14.1-34.1L242.3 5.7c7.5-7.5 19.8-7.5 27.3 0l152.2 152.2c12.6 12.6 3.7 34.1-14.1 34.1H320v168c0 13.3-10.7 24-24 24zm216-8v112c0 13.3-10.7 24-24 24H24c-13.3 0-24-10.7-24-24V376c0-13.3 10.7-24 24-24h136v8c0 30.9 25.1 56 56 56h80c30.9 0 56-25.1 56-56v-8h136c13.3 0 24 10.7 24 24zm-124 88c0-11-9-20-20-20s-20 9-20 20 9 20 20 20 20-9 20-20zm64 0c0-11-9-20-20-20s-20 9-20 20 9 20 20 20 20-9 20-20z"],user:[512,512,[],"f007","M96 160C96 71.634 167.635 0 256 0s160 71.634 160 160-71.635 160-160 160S96 248.366 96 160zm304 192h-28.556c-71.006 42.713-159.912 42.695-230.888 0H112C50.144 352 0 402.144 0 464v24c0 13.255 10.745 24 24 24h464c13.255 0 24-10.745 24-24v-24c0-61.856-50.144-112-112-112z"],"user-circle":[512,512,[],"f2bd","M256 8C119.033 8 8 119.033 8 256s111.033 248 248 248 248-111.033 248-248S392.967 8 256 8zM144 208c0-61.856 50.144-112 112-112s112 50.144 112 112-50.144 112-112 112-112-50.144-112-112zm268.408 172.663c-80.346 100.411-232.375 100.53-312.817 0C117.003 362.973 141.218 352 168 352h18.204c44.03 21.336 95.495 21.368 139.592 0H344c26.782 0 50.997 10.973 68.408 28.663z"],"user-md":[448,512,[],"f0f0","M96 128C96 57.308 153.308 0 224 0s128 57.308 128 128-57.308 128-128 128S96 198.692 96 128zm256 160v33.61c36.471 7.433 64 39.756 64 78.39v49.441c0 11.44-8.075 21.29-19.293 23.534l-21.802 4.361c-6.499 1.3-12.821-2.915-14.12-9.414l-1.569-7.845c-1.3-6.499 2.915-12.821 9.414-14.12l15.37-3.074v-42.078c0-26.283-20.793-48.297-47.071-48.797C310.039 351.498 288 373.224 288 400v42.883l15.371 3.074c6.499 1.3 10.713 7.622 9.414 14.12l-1.569 7.845c-1.3 6.499-7.622 10.714-14.12 9.414l-21.802-4.361C264.075 470.732 256 460.882 256 449.441V400c0-38.634 27.529-70.957 64-78.39V288h-22.624c-45.669 20.945-99.331 21.749-146.752 0H128v66.025c28.495 7.361 49.359 33.906 47.931 64.977-1.506 32.778-28.097 59.392-60.874 60.926C78.383 481.644 48 452.303 48 416c0-29.767 20.427-54.852 48-61.975V288c-53.019 0-96 42.981-96 96v104c0 13.255 10.745 24 24 24h400c13.255 0 24-10.745 24-24V384c0-53.019-42.981-96-96-96zM80 416c0 17.645 14.355 32 32 32s32-14.355 32-32-14.355-32-32-32-32 14.355-32 32z"],"user-plus":[640,512,[],"f234","M616 332c0-6.627-5.373-12-12-12h-60v-60c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v60h-60c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h60v60c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12v-60h60c6.627 0 12-5.373 12-12v-40zM448 444v15c0 11.598-9.402 21-21 21H21c-11.598 0-21-9.402-21-21v-21c0-54.124 43.876-98 98-98h24.986c62.104 37.358 139.897 37.374 202.027 0H350a98.09 98.09 0 0 1 26 3.493V372c0 24.262 19.738 44 44 44h25.519c2.768 12.064 2.481 20.659 2.481 28zM84 172c0-77.32 62.68-140 140-140s140 62.68 140 140-62.68 140-140 140S84 249.32 84 172z"],"user-secret":[448,512,[],"f21b","M388.829 295.324l20.972-55.052c2.992-7.854-2.809-16.272-11.214-16.272H340.39c7.45-16.236 11.61-34.297 11.61-53.333 0-3.631-.16-7.224-.456-10.778C391.083 152.074 416 140.684 416 128c0-13.263-27.231-25.112-69.947-32.937-9.185-32.805-27.178-65.797-40.714-82.85-9.452-11.908-25.873-15.634-39.471-8.834l-27.557 13.779a31.997 31.997 0 0 1-28.622 0l-27.557-13.78c-13.599-6.799-30.02-3.074-39.471 8.834-13.536 17.053-31.529 50.045-40.714 82.85C59.231 102.888 32 114.737 32 128c0 12.684 24.917 24.074 64.456 31.889A129.362 129.362 0 0 0 96 170.667c0 19.037 4.159 37.098 11.608 53.333h-57.41c-8.615 0-14.423 8.809-11.029 16.727l22.906 53.447C25.799 307.882 0 342.925 0 384v104c0 13.255 10.745 24 24 24h400c13.255 0 24-10.745 24-24V384c0-39.97-24.43-74.231-59.171-88.676zM184 488l-48-192 48 24 24 40-24 128zm80 0l-24-128 24-40 48-24-48 192zm54.778-303.746c-.008.043-4.299 3.231-5.125 5.771-3.861 11.864-7.026 24.572-16.514 33.359-10.071 9.327-47.957 22.405-63.996-25.029-2.837-8.395-15.447-8.398-18.285 0-16.963 50.168-56.019 32.417-63.996 25.029-9.488-8.786-12.653-21.495-16.514-33.359-.826-2.54-5.118-5.728-5.125-5.771-.554-2.925-.981-5.884-1.22-8.85-.309-3.848 10.078-3.658 11.078-3.747 26.303-2.326 52.303-.579 78.023 5.497 2.563.606 11.553.529 13.793 0 25.72-6.076 51.72-7.824 78.023-5.497 1.002.089 11.387-.102 11.078 3.747-.239 2.966-.666 5.925-1.22 8.85z"],"user-times":[640,512,[],"f235","M599.681 411.397c4.686-4.686 4.686-12.284 0-16.971L557.255 352l42.426-42.426c4.686-4.686 4.686-12.284 0-16.971l-28.284-28.284c-4.686-4.686-12.284-4.686-16.971 0L512 306.745l-42.426-42.426c-4.686-4.686-12.284-4.686-16.971 0l-28.284 28.284c-4.686 4.686-4.686 12.284 0 16.971L466.745 352l-42.426 42.426c-4.686 4.686-4.686 12.284 0 16.971l28.284 28.284c4.686 4.686 12.284 4.686 16.971 0L512 397.255l42.426 42.426c4.686 4.686 12.284 4.686 16.971 0l28.284-28.284zM84 172c0-77.32 62.68-140 140-140s140 62.68 140 140-62.68 140-140 140S84 249.32 84 172zm359.737 299.645C439.904 476.712 433.843 480 427 480H21c-11.598 0-21-9.402-21-21v-21c0-54.124 43.876-98 98-98h24.986c62.104 37.358 139.897 37.374 202.027 0H350c23.366 0 44.818 8.183 61.658 21.832l-9.967 9.967c-17.156 17.156-17.156 45.07 0 62.225l28.284 28.284a43.946 43.946 0 0 0 13.762 9.337z"],users:[640,512,[],"f0c0","M220 164c0-55.229 44.772-100 100-100s100 44.771 100 100-44.772 100-100 100-100-44.771-100-100zM48 208c0-44.183 35.817-80 80-80s80 35.817 80 80-35.817 80-80 80-80-35.817-80-80zm384 0c0-44.183 35.817-80 80-80s80 35.817 80 80-35.817 80-80 80-80-35.817-80-80zm-22 76c38.66 0 70 31.34 70 70v70c0 13.255-10.745 24-24 24H184c-13.255 0-24-10.745-24-24v-70c0-38.66 31.34-70 70-70h17.848c44.364 26.687 99.93 26.693 144.305 0H410m-282 70c0-11.975 2.081-23.472 5.889-34.156-21.93 1.152-44.122-4.121-63.611-15.844H56c-30.928 0-56 25.072-56 56v32c0 13.255 10.745 24 24 24h104v-62zm456-50h-14.278c-19.495 11.727-41.686 16.996-63.611 15.844A101.542 101.542 0 0 1 512 354v62h104c13.255 0 24-10.745 24-24v-32c0-30.928-25.072-56-56-56z"],"utensil-spoon":[512,512,[],"f2e5","M480.1 31.9c-55-55.1-164.9-34.5-227.8 28.5-49.3 49.3-55.1 110-28.8 160.4L9 413.2c-11.6 10.5-12.1 28.5-1 39.5L59.3 504c11 11 29.1 10.5 39.5-1.1l192.4-214.4c50.4 26.3 111.1 20.5 160.4-28.8 63-62.9 83.6-172.8 28.5-227.8z"],utensils:[416,512,[],"f2e7","M207.9 15.2c.8 4.7 16.1 94.5 16.1 128.8 0 52.3-27.8 89.6-68.9 104.6L168 486.7c.7 13.7-10.2 25.3-24 25.3H80c-13.7 0-24.7-11.5-24-25.3l12.9-238.1C27.7 233.6 0 196.2 0 144 0 109.6 15.3 19.9 16.1 15.2 19.3-5.1 61.4-5.4 64 16.3v141.2c1.3 3.4 15.1 3.2 16 0 1.4-25.3 7.9-139.2 8-141.8 3.3-20.8 44.7-20.8 47.9 0 .2 2.7 6.6 116.5 8 141.8.9 3.2 14.8 3.4 16 0V16.3c2.6-21.6 44.8-21.4 48-1.1zm119.2 285.7l-15 185.1c-1.2 14 9.9 26 23.9 26h56c13.3 0 24-10.7 24-24V24c0-13.2-10.7-24-24-24-82.5 0-221.4 178.5-64.9 300.9z"],venus:[288,512,[],"f221","M288 176c0-79.5-64.5-144-144-144S0 96.5 0 176c0 68.5 47.9 125.9 112 140.4V368H76c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h36v36c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12v-36h36c6.6 0 12-5.4 12-12v-40c0-6.6-5.4-12-12-12h-36v-51.6c64.1-14.5 112-71.9 112-140.4zm-224 0c0-44.1 35.9-80 80-80s80 35.9 80 80-35.9 80-80 80-80-35.9-80-80z"],"venus-double":[512,512,[],"f226","M288 176c0-79.5-64.5-144-144-144S0 96.5 0 176c0 68.5 47.9 125.9 112 140.4V368H76c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h36v36c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12v-36h36c6.6 0 12-5.4 12-12v-40c0-6.6-5.4-12-12-12h-36v-51.6c64.1-14.5 112-71.9 112-140.4zm-224 0c0-44.1 35.9-80 80-80s80 35.9 80 80-35.9 80-80 80-80-35.9-80-80zm336 140.4V368h36c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12h-36v36c0 6.6-5.4 12-12 12h-40c-6.6 0-12-5.4-12-12v-36h-36c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h36v-51.6c-21.2-4.8-40.6-14.3-57.2-27.3 14-16.7 25-36 32.1-57.1 14.5 14.8 34.7 24 57.1 24 44.1 0 80-35.9 80-80s-35.9-80-80-80c-22.3 0-42.6 9.2-57.1 24-7.1-21.1-18-40.4-32.1-57.1C303.4 43.6 334.3 32 368 32c79.5 0 144 64.5 144 144 0 68.5-47.9 125.9-112 140.4z"],"venus-mars":[576,512,[],"f228","M564 0h-79c-10.7 0-16 12.9-8.5 20.5l16.9 16.9-48.7 48.7C422.5 72.1 396.2 64 368 64c-33.7 0-64.6 11.6-89.2 30.9 14 16.7 25 36 32.1 57.1 14.5-14.8 34.7-24 57.1-24 44.1 0 80 35.9 80 80s-35.9 80-80 80c-22.3 0-42.6-9.2-57.1-24-7.1 21.1-18 40.4-32.1 57.1 24.5 19.4 55.5 30.9 89.2 30.9 79.5 0 144-64.5 144-144 0-28.2-8.1-54.5-22.1-76.7l48.7-48.7 16.9 16.9c2.4 2.4 5.4 3.5 8.4 3.5 6.2 0 12.1-4.8 12.1-12V12c0-6.6-5.4-12-12-12zM144 64C64.5 64 0 128.5 0 208c0 68.5 47.9 125.9 112 140.4V400H76c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h36v36c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12v-36h36c6.6 0 12-5.4 12-12v-40c0-6.6-5.4-12-12-12h-36v-51.6c64.1-14.6 112-71.9 112-140.4 0-79.5-64.5-144-144-144zm0 224c-44.1 0-80-35.9-80-80s35.9-80 80-80 80 35.9 80 80-35.9 80-80 80z"],video:[576,512,[],"f03d","M528 64h-12.118a48 48 0 0 0-33.941 14.059L384 176v-64c0-26.51-21.49-48-48-48H48C21.49 64 0 85.49 0 112v288c0 26.51 21.49 48 48 48h288c26.51 0 48-21.49 48-48v-64l97.941 97.941A48 48 0 0 0 515.882 448H528c26.51 0 48-21.49 48-48V112c0-26.51-21.49-48-48-48z"],"volume-down":[384,512,[],"f027","M256 88.017v335.964c0 21.438-25.943 31.998-40.971 16.971L126.059 352H24c-13.255 0-24-10.745-24-24V184c0-13.255 10.745-24 24-24h102.059l88.971-88.954c15.01-15.01 40.97-4.49 40.97 16.971zM384 256c0-33.717-17.186-64.35-45.972-81.944-15.079-9.214-34.775-4.463-43.992 10.616s-4.464 34.775 10.615 43.992C314.263 234.538 320 244.757 320 256a32.056 32.056 0 0 1-13.802 26.332c-14.524 10.069-18.136 30.006-8.067 44.53 10.07 14.525 30.008 18.136 44.53 8.067C368.546 316.983 384 287.478 384 256z"],"volume-off":[256,512,[],"f026","M256 88.017v335.964c0 21.438-25.943 31.998-40.971 16.971L126.059 352H24c-13.255 0-24-10.745-24-24V184c0-13.255 10.745-24 24-24h102.059l88.971-88.954c15.01-15.01 40.97-4.49 40.97 16.971z"],"volume-up":[576,512,[],"f028","M256 88.017v335.964c0 21.438-25.943 31.998-40.971 16.971L126.059 352H24c-13.255 0-24-10.745-24-24V184c0-13.255 10.745-24 24-24h102.059l88.971-88.954c15.01-15.01 40.97-4.49 40.97 16.971zm182.056-77.876C422.982.92 403.283 5.668 394.061 20.745c-9.221 15.077-4.473 34.774 10.604 43.995C468.967 104.063 512 174.983 512 256c0 73.431-36.077 142.292-96.507 184.206-14.522 10.072-18.129 30.01-8.057 44.532 10.076 14.528 30.016 18.126 44.531 8.057C529.633 438.927 576 350.406 576 256c0-103.244-54.579-194.877-137.944-245.859zM480 256c0-68.547-36.15-129.777-91.957-163.901-15.076-9.22-34.774-4.471-43.994 10.607-9.22 15.078-4.471 34.774 10.607 43.994C393.067 170.188 416 211.048 416 256c0 41.964-20.62 81.319-55.158 105.276-14.521 10.073-18.128 30.01-8.056 44.532 6.216 8.96 16.185 13.765 26.322 13.765a31.862 31.862 0 0 0 18.21-5.709C449.091 377.953 480 318.938 480 256zm-96 0c0-33.717-17.186-64.35-45.972-81.944-15.079-9.214-34.775-4.463-43.992 10.616s-4.464 34.775 10.615 43.992C314.263 234.538 320 244.757 320 256a32.056 32.056 0 0 1-13.802 26.332c-14.524 10.069-18.136 30.006-8.067 44.53 10.07 14.525 30.008 18.136 44.53 8.067C368.546 316.983 384 287.478 384 256z"],wheelchair:[512,512,[],"f193","M496.101 385.669l14.227 28.663c3.929 7.915.697 17.516-7.218 21.445l-65.465 32.886c-16.049 7.967-35.556 1.194-43.189-15.055L331.679 320H192c-15.925 0-29.426-11.71-31.679-27.475C126.433 55.308 128.38 70.044 128 64c0-36.358 30.318-65.635 67.052-63.929 33.271 1.545 60.048 28.905 60.925 62.201.868 32.933-23.152 60.423-54.608 65.039l4.67 32.69H336c8.837 0 16 7.163 16 16v32c0 8.837-7.163 16-16 16H215.182l4.572 32H352a32 32 0 0 1 28.962 18.392L438.477 396.8l36.178-18.349c7.915-3.929 17.517-.697 21.446 7.218zM311.358 352h-24.506c-7.788 54.204-54.528 96-110.852 96-61.757 0-112-50.243-112-112 0-41.505 22.694-77.809 56.324-97.156-3.712-25.965-6.844-47.86-9.488-66.333C45.956 198.464 0 261.963 0 336c0 97.047 78.953 176 176 176 71.87 0 133.806-43.308 161.11-105.192L311.358 352z"],wifi:[640,512,[],"f1eb","M384 416c0 35.346-28.654 64-64 64s-64-28.654-64-64c0-35.346 28.654-64 64-64s64 28.654 64 64zm136.659-124.443c6.465-6.465 6.245-17.065-.564-23.167-113.793-101.985-286.526-101.869-400.19 0-6.809 6.102-7.029 16.702-.564 23.167l34.006 34.006c5.927 5.927 15.464 6.32 21.769.796 82.88-72.609 207.074-72.447 289.768 0 6.305 5.524 15.842 5.132 21.769-.796l34.006-34.006zm112.11-113.718c6.385-6.385 6.254-16.816-.35-22.973-175.768-163.86-449.134-163.8-624.837 0-6.604 6.157-6.735 16.589-.35 22.973l33.966 33.966c6.095 6.095 15.891 6.231 22.224.383 144.763-133.668 368.356-133.702 513.156 0 6.333 5.848 16.129 5.712 22.224-.383l33.967-33.966z"],"window-close":[512,512,[],"f410","M464 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h416c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48zm-83.6 290.5c4.8 4.8 4.8 12.6 0 17.4l-40.5 40.5c-4.8 4.8-12.6 4.8-17.4 0L256 313.3l-66.5 67.1c-4.8 4.8-12.6 4.8-17.4 0l-40.5-40.5c-4.8-4.8-4.8-12.6 0-17.4l67.1-66.5-67.1-66.5c-4.8-4.8-4.8-12.6 0-17.4l40.5-40.5c4.8-4.8 12.6-4.8 17.4 0l66.5 67.1 66.5-67.1c4.8-4.8 12.6-4.8 17.4 0l40.5 40.5c4.8 4.8 4.8 12.6 0 17.4L313.3 256l67.1 66.5z"],"window-maximize":[512,512,[],"f2d0","M464 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h416c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48zm-16 160H64v-84c0-6.6 5.4-12 12-12h360c6.6 0 12 5.4 12 12v84z"],"window-minimize":[512,512,[],"f2d1","M464 352H48c-26.5 0-48 21.5-48 48v32c0 26.5 21.5 48 48 48h416c26.5 0 48-21.5 48-48v-32c0-26.5-21.5-48-48-48z"],"window-restore":[512,512,[],"f2d2","M512 48v288c0 26.5-21.5 48-48 48h-48V176c0-44.1-35.9-80-80-80H128V48c0-26.5 21.5-48 48-48h288c26.5 0 48 21.5 48 48zM384 176v288c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V176c0-26.5 21.5-48 48-48h288c26.5 0 48 21.5 48 48zm-68 28c0-6.6-5.4-12-12-12H76c-6.6 0-12 5.4-12 12v52h252v-52z"],"won-sign":[576,512,[],"f159","M564 192c6.627 0 12-5.373 12-12v-40c0-6.627-5.373-12-12-12h-48.028l18.572-80.61c1.732-7.518-3.978-14.694-11.693-14.694h-46.107a11.998 11.998 0 0 0-11.736 9.5L450.73 128H340.839l-19.725-85.987a12 12 0 0 0-11.696-9.317H265.43a12 12 0 0 0-11.687 9.277L233.696 128H124.975L107.5 42.299a12 12 0 0 0-11.758-9.602H53.628c-7.686 0-13.39 7.124-11.709 14.624L60 128H12c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h62.342l7.171 32H12c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h83.856l40.927 182.624A12 12 0 0 0 148.492 480h56.767c5.583 0 10.428-3.85 11.689-9.288L259.335 288h55.086l42.386 182.712A12 12 0 0 0 368.496 480h56.826a12 12 0 0 0 11.694-9.306L479.108 288H564c6.627 0 12-5.373 12-12v-40c0-6.627-5.373-12-12-12h-70.146l7.373-32H564zm-425.976 0h80.757l-7.457 32h-66.776l-6.524-32zm45.796 150.029c-6.194 25.831-6.758 47.25-7.321 47.25h-1.126s-1.689-22.05-6.758-47.25L157.599 288h38.812l-12.591 54.029zM274.182 224l1.996-8.602c1.856-7.962 3.457-15.968 4.803-23.398h11.794c1.347 7.43 2.947 15.436 4.803 23.398l1.996 8.602h-25.392zm130.959 118.029c-5.068 25.2-6.758 47.25-6.758 47.25h-1.126c-.563 0-1.126-21.42-7.321-47.25L377.542 288h39.107l-11.508 54.029zM430.281 224h-67.42l-7.34-32h81.577l-6.817 32z"],wrench:[512,512,[],"f0ad","M481.156 200c9.3 0 15.12 10.155 10.325 18.124C466.295 259.992 420.419 288 368 288c-79.222 0-143.501-63.974-143.997-143.079C223.505 65.469 288.548-.001 368.002 0c52.362.001 98.196 27.949 123.4 69.743C496.24 77.766 490.523 88 481.154 88H376l-40 56 40 56h105.156zm-171.649 93.003L109.255 493.255c-24.994 24.993-65.515 24.994-90.51 0-24.993-24.994-24.993-65.516 0-90.51L218.991 202.5c16.16 41.197 49.303 74.335 90.516 90.503zM104 432c0-13.255-10.745-24-24-24s-24 10.745-24 24 10.745 24 24 24 24-10.745 24-24z"],"yen-sign":[384,512,[],"f157","M351.208 32h-65.277a12 12 0 0 0-10.778 6.724l-55.39 113.163c-14.513 34.704-27.133 71.932-27.133 71.932h-1.262s-12.62-37.228-27.133-71.932l-55.39-113.163A11.997 11.997 0 0 0 98.068 32H32.792c-9.057 0-14.85 9.65-10.59 17.643L102.322 200H44c-6.627 0-12 5.373-12 12v32c0 6.627 5.373 12 12 12h88.162L152 293.228V320H44c-6.627 0-12 5.373-12 12v32c0 6.627 5.373 12 12 12h108v92c0 6.627 5.373 12 12 12h56c6.627 0 12-5.373 12-12v-92h108c6.627 0 12-5.373 12-12v-32c0-6.627-5.373-12-12-12H232v-26.772L251.838 256H340c6.627 0 12-5.373 12-12v-32c0-6.627-5.373-12-12-12h-58.322l80.12-150.357C366.058 41.65 360.266 32 351.208 32z"]}),t=z||{};t.___FONT_AWESOME___||(t.___FONT_AWESOME___={}),t.___FONT_AWESOME___.styles||(t.___FONT_AWESOME___.styles={}),t.___FONT_AWESOME___.hooks||(t.___FONT_AWESOME___.hooks={}),t.___FONT_AWESOME___.shims||(t.___FONT_AWESOME___.shims=[]);var s=t.___FONT_AWESOME___,r=Object.assign||function(c){for(var l=1;l<arguments.length;l++){var h=arguments[l];for(var v in h)Object.prototype.hasOwnProperty.call(h,v)&&(c[v]=h[v])}return c};!function(c){try{c()}catch(c){}}(function(){c("fas"),c("fa")})}(),function(){"use strict";function c(c){var l=Object.keys(Hc);Object.keys(c).forEach(function(h){~l.indexOf(h)&&(Hc[h]=c[h])})}function l(c){return~mc.indexOf(c)}function h(c){if(c&&void 0!==K.createElement){var l=K.createElement("style");l.setAttribute("type","text/css"),l.innerHTML=c;for(var h=K.head.childNodes,v=null,z=h.length-1;z>-1;z--){var e=h[z],a=(e.tagName||"").toUpperCase();["STYLE","LINK"].indexOf(a)>-1&&(v=e)}return K.head.insertBefore(l,v),c}}function v(){return++Cc}function z(c){for(var l=[],h=(c||[]).length>>>0;h--;)l[h]=c[h];return l}function e(c){return c.classList?z(c.classList):(c.getAttribute("class")||"").split(" ").filter(function(c){return c})}function a(c,h){var v=h.split("-"),z=v[0],e=v.slice(1).join("-");return z!==c||""===e||l(e)?null:e}function m(c){return(""+c).replace(/&/g,"&").replace(/"/g,""").replace(/'/g,"'").replace(/</g,"<").replace(/>/g,">")}function t(c){return Object.keys(c||{}).reduce(function(l,h){return l+(h+'="')+m(c[h])+'" '},"").trim()}function s(c){return Object.keys(c||{}).reduce(function(l,h){return l+(h+": ")+c[h]+";"},"")}function r(c){return c.size!==Vc.size||c.x!==Vc.x||c.y!==Vc.y||c.rotate!==Vc.rotate||c.flipX||c.flipY}function f(c){var l=c.transform,h=c.containerWidth,v=c.iconWidth;return{outer:{transform:"translate("+h/2+" 256)"},inner:{transform:"translate("+32*l.x+", "+32*l.y+") "+" "+("scale("+l.size/16*(l.flipX?-1:1)+", "+l.size/16*(l.flipY?-1:1)+") ")+" "+("rotate("+l.rotate+" 0 0)")},path:{transform:"translate("+v/2*-1+" -256)"}}}function M(c){var l=c.transform,h=c.width,v=void 0===h?$:h,z=c.height,e=void 0===z?$:z,a=c.startCentered,m=void 0!==a&&a,t="";return t+=m&&Z?"translate("+(l.x/oc-v/2)+"em, "+(l.y/oc-e/2)+"em) ":m?"translate(calc(-50% + "+l.x/oc+"em), calc(-50% + "+l.y/oc+"em)) ":"translate("+l.x/oc+"em, "+l.y/oc+"em) ",t+="scale("+l.size/oc*(l.flipX?-1:1)+", "+l.size/oc*(l.flipY?-1:1)+") ",t+="rotate("+l.rotate+"deg) "}function i(c){var l,h=c.icons,z=h.main,e=h.mask,a=c.prefix,m=c.iconName,t=c.transform,s=c.symbol,r=c.title,f=c.extra,M=e.found?e:z,i=M.width,n=M.height,H="fa-w-"+Math.ceil(i/n*16),o=[Hc.replacementClass,m?Hc.familyPrefix+"-"+m:"",H].concat(f.classes).join(" "),V={children:[],attributes:fc({},f.attributes,(l={},rc(l,cc,""),rc(l,"data-prefix",a),rc(l,"data-icon",m),rc(l,"class",o),rc(l,"role","img"),rc(l,"xmlns","http://www.w3.org/2000/svg"),rc(l,"viewBox","0 0 "+i+" "+n),l))};r&&V.children.push({tag:"title",attributes:{id:V.attributes["aria-labelledby"]||"title-"+v()},children:[r]});var C=fc({},V,{prefix:a,iconName:m,main:z,mask:e,transform:t,symbol:s,styles:f.styles}),L=e.found&&z.found?uc(C):dc(C),u=L.children,d=L.attributes;return C.children=u,C.attributes=d,s?gc(C):pc(C)}function n(c){var l,h=c.content,v=c.width,z=c.height,e=c.transform,a=c.title,m=c.extra,t=fc({},m.attributes,a?{title:a}:{},(l={},rc(l,cc,""),rc(l,"class",m.classes.join(" ")),l)),f=fc({},m.styles);r(e)&&(f.transform=M({transform:e,startCentered:!0,width:v,height:z}),f["-webkit-transform"]=f.transform);var i=s(f);i.length>0&&(t.style=i);var n=[];return n.push({tag:"span",attributes:t,children:[h]}),a&&n.push({tag:"span",attributes:{class:"sr-only"},children:[a]}),n}function H(c,l){return Nc[c][l]}function o(c,l){return qc[c][l]}function V(c){return Tc[c]||{prefix:null,iconName:null}}function C(c){return c.reduce(function(c,l){var h=a(Hc.familyPrefix,l);if(Fc[l])c.prefix=l;else if(h){var v="fa"===c.prefix?V(h):{};c.iconName=v.iconName||h,c.prefix=v.prefix||c.prefix}else l!==Hc.replacementClass&&0!==l.indexOf("fa-w-")&&c.rest.push(l);return c},Wc())}function L(c,l,h){if(c&&c[l]&&c[l][h])return{prefix:l,iconName:h,icon:c[l][h]}}function u(c){var l=c.tag,h=c.attributes,v=void 0===h?{}:h,z=c.children,e=void 0===z?[]:z;return"string"==typeof c?m(c):"<"+l+" "+t(v)+">"+e.map(u).join("")+"</"+l+">"}function d(c){var l=c.getAttribute?c.getAttribute("class"):null;return!!l&&(!!~l.toString().indexOf(Hc.replacementClass)||~l.toString().indexOf("fa-layers-text"))}function p(){return!0===Hc.autoReplaceSvg?Ic.replace:Ic[Hc.autoReplaceSvg]||Ic.replace}function g(c,l){var h="function"==typeof l?l:Pc;0===c.length?h():(U.requestAnimationFrame||function(c){return c()})(function(){var l=p(),v=kc.begin("mutate");c.map(l),v(),h()})}function b(c){Rc=!0,c(),Rc=!1}function w(c){if(G){var l=c.treeCallback,h=c.nodeCallback,v=c.pseudoElementsCallback,a=new G(function(c){Rc||z(c).forEach(function(c){if("childList"===c.type&&c.addedNodes.length>0&&!d(c.addedNodes[0])&&(Hc.searchPseudoElements&&v(c.target),l(c.target)),"attributes"===c.type&&"class"===c.attributeName&&c.target.parentNode&&Hc.searchPseudoElements&&v(c.target.parentNode),"attributes"===c.type&&d(c.target)&&~ac.indexOf(c.attributeName))if("class"===c.attributeName){var z=C(e(c.target)),a=z.prefix,m=z.iconName;a&&c.target.setAttribute("data-prefix",a),m&&c.target.setAttribute("data-icon",m)}else h(c.target)})});K.getElementsByTagName&&a.observe(K.getElementsByTagName("body")[0],{childList:!0,attributes:!0,characterData:!0,subtree:!0})}}function y(c){for(var l="",h=0;h<c.length;h++)l+=("000"+c.charCodeAt(h).toString(16)).slice(-4);return l}function S(c){var l=Xc(c),h=l.iconName,v=l.prefix,z=l.rest,e=Bc(c),a=Dc(c),m=Uc(c),t=Kc(c),s=Gc(c);return{iconName:h,title:c.getAttribute("title"),prefix:v,transform:a,symbol:m,mask:s,extra:{classes:z,styles:e,attributes:t}}}function _(c){this.name="MissingIcon",this.message=c||"Icon unavailable",this.stack=(new Error).stack}function k(c,l){var h={found:!1,width:512,height:512,icon:cl};if(c&&l&&ll[l]&&ll[l][c]){var v=ll[l][c];h={found:!0,width:v[0],height:v[1],icon:{tag:"path",attributes:{fill:"currentColor",d:v.slice(4)[0]}}}}else if(c&&l&&!Hc.showMissingIcons)throw new _("Icon is missing for prefix "+l+" with icon name "+c);return h}function A(c,l){var h=l.iconName,v=l.title,z=l.prefix,e=l.transform,a=l.symbol,m=l.mask,t=l.extra;return[c,i({icons:{main:k(h,z),mask:k(m.iconName,m.prefix)},prefix:z,iconName:h,transform:e,symbol:a,mask:m,title:v,extra:t})]}function x(c,l){var h=l.title,v=l.transform,z=l.extra,e=null,a=null;if(Z){var m=parseInt(getComputedStyle(c).fontSize,10),t=c.getBoundingClientRect();e=t.width/m,a=t.height/m}return Hc.autoA11y&&!h&&(z.attributes["aria-hidden"]="true"),[c,n({content:c.innerHTML,width:e,height:a,transform:v,title:h,extra:z})]}function O(c){var l=S(c);return~l.extra.classes.indexOf(hl)?x(c,l):A(c,l)}function E(c){var l=kc.begin("searchPseudoElements");b(function(){z(c.querySelectorAll("*")).forEach(function(c){[":before",":after"].forEach(function(l){var h=U.getComputedStyle(c,l),v=h.getPropertyValue("font-family").match(vl),e=z(c.children).filter(function(c){return c.getAttribute(lc)===l})[0];if(!v&&e&&e.remove(),v&&!e){var a=h.getPropertyValue("content"),m=K.createElement("i");m.setAttribute("class",""+zl[v[1]]),m.setAttribute(lc,l),m.innerText=3===a.length?a.substr(1,1):a,":before"===l?c.insertBefore(m,c.firstChild):c.appendChild(m)}})})}),l()}function N(c){var l=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,h=K.documentElement.classList,v=function(c){return h.add(hc+"-"+c)},e=function(c){return h.remove(hc+"-"+c)},a=Object.keys(ll),m=["."+hl+":not(["+cc+"])"].concat(a.map(function(c){return"."+c+":not(["+cc+"])"})).join(", ");if(0!==m.length){var t=z(c.querySelectorAll(m));if(t.length>0){v("pending"),e("complete");var s=kc.begin("onTree"),r=t.reduce(function(c,l){try{var h=O(l);h&&c.push(h)}catch(c){vc||c instanceof _&&console.error(c)}return c},[]);s(),g(r,function(){v("active"),v("complete"),e("pending"),"function"==typeof l&&l()})}}}function q(c){var l=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,h=O(c);h&&g([h],l)}function T(c){return{found:!0,width:c[0],height:c[1],icon:{tag:"path",attributes:{fill:"currentColor",d:c.slice(4)[0]}}}}function j(){Hc.autoAddCss&&(sl||h(tl()),sl=!0)}function F(c,l){return Object.defineProperty(c,"abstract",{get:l}),Object.defineProperty(c,"html",{get:function(){return c.abstract.map(function(c){return u(c)})}}),Object.defineProperty(c,"node",{get:function(){if(K.createElement){var l=K.createElement("div");return l.innerHTML=c.html,l.children}}}),c}function W(c){var l=c.prefix,h=void 0===l?"fa":l,v=c.iconName;if(v)return L(rl.definitions,h,v)||L(wc.styles,h,v)}var P=function(){},I={},R={},B=null,X={mark:P,measure:P};try{"undefined"!=typeof window&&(I=window),"undefined"!=typeof document&&(R=document),"undefined"!=typeof MutationObserver&&(B=MutationObserver),"undefined"!=typeof performance&&(X=performance)}catch(c){}var Y=(I.navigator||{}).userAgent,D=void 0===Y?"":Y,U=I,K=R,G=B,J=X,Q=!!U.document,Z=~D.indexOf("MSIE")||~D.indexOf("Trident/"),$=16,cc="data-fa-processed",lc="data-fa-pseudo-element",hc="fontawesome-i2svg",vc=function(){try{return!0}catch(c){return!1}}(),zc=[1,2,3,4,5,6,7,8,9,10],ec=zc.concat([11,12,13,14,15,16,17,18,19,20]),ac=["class","data-prefix","data-icon","data-fa-transform","data-fa-mask"],mc=["xs","sm","lg","fw","ul","li","border","pull-left","pull-right","spin","pulse","rotate-90","rotate-180","rotate-270","flip-horizontal","flip-vertical","stack","stack-1x","stack-2x","inverse","layers","layers-text","layers-counter"].concat(zc.map(function(c){return c+"x"})).concat(ec.map(function(c){return"w-"+c})),tc=function(c,l){if(!(c instanceof l))throw new TypeError("Cannot call a class as a function")},sc=function(){function c(c,l){for(var h=0;h<l.length;h++){var v=l[h];v.enumerable=v.enumerable||!1,v.configurable=!0,"value"in v&&(v.writable=!0),Object.defineProperty(c,v.key,v)}}return function(l,h,v){return h&&c(l.prototype,h),v&&c(l,v),l}}(),rc=function(c,l,h){return l in c?Object.defineProperty(c,l,{value:h,enumerable:!0,configurable:!0,writable:!0}):c[l]=h,c},fc=Object.assign||function(c){for(var l=1;l<arguments.length;l++){var h=arguments[l];for(var v in h)Object.prototype.hasOwnProperty.call(h,v)&&(c[v]=h[v])}return c},Mc=function(c,l){var h={};for(var v in c)l.indexOf(v)>=0||Object.prototype.hasOwnProperty.call(c,v)&&(h[v]=c[v]);return h},ic=function(c){if(Array.isArray(c)){for(var l=0,h=Array(c.length);l<c.length;l++)h[l]=c[l];return h}return Array.from(c)},nc=fc({familyPrefix:"fa",replacementClass:"svg-inline--fa",autoReplaceSvg:!0,autoAddCss:!0,autoA11y:!0,searchPseudoElements:!1,observeMutations:!0,keepOriginalSource:!0,measurePerformance:!1,showMissingIcons:!0},U.FontAwesomeConfig||{});nc.autoReplaceSvg||(nc.observeMutations=!1);var Hc=fc({},nc);U.FontAwesomeConfig=Hc;var oc=$,Vc={size:16,x:0,y:0,rotate:0,flipX:!1,flipY:!1},Cc=0,Lc={x:0,y:0,width:"100%",height:"100%"},uc=function(c){var l=c.children,h=c.attributes,z=c.main,e=c.mask,a=c.transform,m=z.width,t=z.icon,s=e.width,r=e.icon,M=f({transform:a,containerWidth:s,iconWidth:m}),i={tag:"rect",attributes:fc({},Lc,{fill:"white"})},n={tag:"g",attributes:fc({},M.inner),children:[{tag:"path",attributes:fc({},t.attributes,M.path,{fill:"black"})}]},H={tag:"g",attributes:fc({},M.outer),children:[n]},o="mask-"+v(),V="clip-"+v(),C={tag:"defs",children:[{tag:"clipPath",attributes:{id:V},children:[r]},{tag:"mask",attributes:fc({},Lc,{id:o,maskUnits:"userSpaceOnUse",maskContentUnits:"userSpaceOnUse"}),children:[i,H]}]};return l.push(C,{tag:"rect",attributes:fc({fill:"currentColor","clip-path":"url(#"+V+")",mask:"url(#"+o+")"},Lc)}),{children:l,attributes:h}},dc=function(c){var l=c.children,h=c.attributes,v=c.main,z=c.transform,e=s(c.styles);if(e.length>0&&(h.style=e),r(z)){var a=f({transform:z,containerWidth:v.width,iconWidth:v.width});l.push({tag:"g",attributes:fc({},a.outer),children:[{tag:"g",attributes:fc({},a.inner),children:[{tag:v.icon.tag,children:v.icon.children,attributes:fc({},v.icon.attributes,a.path)}]}]})}else l.push(v.icon);return{children:l,attributes:h}},pc=function(c){var l=c.children,h=c.main,v=c.mask,z=c.attributes,e=c.styles,a=c.transform;if(r(a)&&h.found&&!v.found){var m={x:h.width/h.height/2,y:.5};z.style=s(fc({},e,{"transform-origin":m.x+a.x/16+"em "+(m.y+a.y/16)+"em"}))}return[{tag:"svg",attributes:z,children:l}]},gc=function(c){var l=c.prefix,h=c.iconName,v=c.children,z=c.attributes,e=c.symbol,a=!0===e?l+"-"+Hc.familyPrefix+"-"+h:e;return[{tag:"svg",attributes:{style:"display: none;"},children:[{tag:"symbol",attributes:fc({},z,{id:a}),children:v}]}]},bc=U||{};bc.___FONT_AWESOME___||(bc.___FONT_AWESOME___={}),bc.___FONT_AWESOME___.styles||(bc.___FONT_AWESOME___.styles={}),bc.___FONT_AWESOME___.hooks||(bc.___FONT_AWESOME___.hooks={}),bc.___FONT_AWESOME___.shims||(bc.___FONT_AWESOME___.shims=[]);var wc=bc.___FONT_AWESOME___,yc=function(){},Sc=Hc.measurePerformance&&J&&J.mark&&J.measure?J:{mark:yc,measure:yc},_c=function(c){Sc.mark('FA "5.0.1" '+c+" ends"),Sc.measure('FA "5.0.1" '+c,'FA "5.0.1" '+c+" begins",'FA "5.0.1" '+c+" ends")},kc={begin:function(c){return Sc.mark('FA "5.0.1" '+c+" begins"),function(){return _c(c)}},end:_c},Ac=function(c,l){return function(h,v,z,e){return c.call(l,h,v,z,e)}},xc=function(c,l,h,v){var z,e,a,m=Object.keys(c),t=m.length,s=void 0!==v?Ac(l,v):l;for(void 0===h?(z=1,a=c[m[0]]):(z=0,a=h);z<t;z++)a=s(a,c[e=m[z]],e,c);return a},Oc=wc.styles,Ec=wc.shims,Nc={},qc={},Tc={},jc=function(){var c=function(c){return xc(Oc,function(l,h,v){return l[v]=xc(h,c,{}),l},{})};Nc=c(function(c,l,h){return c[l[3]]=h,c}),qc=c(function(c,l,h){var v=l[2];return c[h]=h,v.forEach(function(l){c[l]=h}),c});var l="far"in Oc;Tc=xc(Ec,function(c,h){var v=h[0],z=h[1],e=h[2];return"far"!==z||l||(z="fas"),c[v]={prefix:z,iconName:e},c},{})};jc();var Fc=wc.styles,Wc=function(){return{prefix:null,iconName:null,rest:[]}},Pc=function(){},Ic={replace:function(c){var l=c[0],h=c[1].map(function(c){return u(c)}).join("\n");if(l.parentNode&&l.outerHTML)l.outerHTML=h+(Hc.keepOriginalSource&&"svg"!==l.tagName.toLowerCase()?"\x3c!-- "+l.outerHTML+" --\x3e":"");else if(l.parentNode){var v=document.createElement("span");l.parentNode.replaceChild(v,l),v.outerHTML=h}},nest:function(c){var l=c[0],h=c[1];if(~e(l).indexOf(Hc.replacementClass))return Ic.replace(c);var v=new RegExp(Hc.familyPrefix+"-.*");delete h[0].attributes.style;var z=h[0].attributes.class.split(" ").reduce(function(c,l){return l===Hc.replacementClass||l.match(v)?c.toSvg.push(l):c.toNode.push(l),c},{toNode:[],toSvg:[]});h[0].attributes.class=z.toSvg.join(" ");var a=h.map(function(c){return u(c)}).join("\n");l.setAttribute("class",z.toNode.join(" ")),l.setAttribute(cc,""),l.innerHTML=a}},Rc=!1,Bc=function(c){var l=c.getAttribute("style"),h=[];return l&&(h=l.split(";").reduce(function(c,l){var h=l.split(":"),v=h[0],z=h.slice(1);return v&&z.length>0&&(c[v]=z.join(":").trim()),c},{})),h},Xc=function(c){var l=c.getAttribute("data-prefix"),h=c.getAttribute("data-icon"),v=void 0!==c.innerText?c.innerText.trim():"",z=C(e(c));return l&&h&&(z.prefix=l,z.iconName=h),z.prefix&&v.length>1?z.iconName=o(z.prefix,c.innerText):z.prefix&&1===v.length&&(z.iconName=H(z.prefix,y(c.innerText))),z},Yc=function(c){var l={size:16,x:0,y:0,flipX:!1,flipY:!1,rotate:0};return c?c.toLowerCase().split(" ").reduce(function(c,l){var h=l.toLowerCase().split("-"),v=h[0],z=h.slice(1).join("-");if(v&&"h"===z)return c.flipX=!0,c;if(v&&"v"===z)return c.flipY=!0,c;if(z=parseFloat(z),isNaN(z))return c;switch(v){case"grow":c.size=c.size+z;break;case"shrink":c.size=c.size-z;break;case"left":c.x=c.x-z;break;case"right":c.x=c.x+z;break;case"up":c.y=c.y-z;break;case"down":c.y=c.y+z;break;case"rotate":c.rotate=c.rotate+z}return c},l):l},Dc=function(c){return Yc(c.getAttribute("data-fa-transform"))},Uc=function(c){var l=c.getAttribute("data-fa-symbol");return null!==l&&(""===l||l)},Kc=function(c){var l=z(c.attributes).reduce(function(c,l){return"class"!==c.name&&"style"!==c.name&&(c[l.name]=l.value),c},{}),h=c.getAttribute("title");return Hc.autoA11y&&(h?l["aria-labelledby"]=Hc.replacementClass+"-title-"+v():l["aria-hidden"]="true"),l},Gc=function(c){var l=c.getAttribute("data-fa-mask");return l?C(l.split(" ").map(function(c){return c.trim()})):Wc()};_.prototype=Object.create(Error.prototype),_.prototype.constructor=_;var Jc={fill:"currentColor"},Qc={attributeType:"XML",repeatCount:"indefinite",dur:"2s"},Zc={tag:"path",attributes:fc({},Jc,{d:"M156.5,447.7l-12.6,29.5c-18.7-9.5-35.9-21.2-51.5-34.9l22.7-22.7C127.6,430.5,141.5,440,156.5,447.7z M40.6,272H8.5 c1.4,21.2,5.4,41.7,11.7,61.1L50,321.2C45.1,305.5,41.8,289,40.6,272z M40.6,240c1.4-18.8,5.2-37,11.1-54.1l-29.5-12.6 C14.7,194.3,10,216.7,8.5,240H40.6z M64.3,156.5c7.8-14.9,17.2-28.8,28.1-41.5L69.7,92.3c-13.7,15.6-25.5,32.8-34.9,51.5 L64.3,156.5z M397,419.6c-13.9,12-29.4,22.3-46.1,30.4l11.9,29.8c20.7-9.9,39.8-22.6,56.9-37.6L397,419.6z M115,92.4 c13.9-12,29.4-22.3,46.1-30.4l-11.9-29.8c-20.7,9.9-39.8,22.6-56.8,37.6L115,92.4z M447.7,355.5c-7.8,14.9-17.2,28.8-28.1,41.5 l22.7,22.7c13.7-15.6,25.5-32.9,34.9-51.5L447.7,355.5z M471.4,272c-1.4,18.8-5.2,37-11.1,54.1l29.5,12.6 c7.5-21.1,12.2-43.5,13.6-66.8H471.4z M321.2,462c-15.7,5-32.2,8.2-49.2,9.4v32.1c21.2-1.4,41.7-5.4,61.1-11.7L321.2,462z M240,471.4c-18.8-1.4-37-5.2-54.1-11.1l-12.6,29.5c21.1,7.5,43.5,12.2,66.8,13.6V471.4z M462,190.8c5,15.7,8.2,32.2,9.4,49.2h32.1 c-1.4-21.2-5.4-41.7-11.7-61.1L462,190.8z M92.4,397c-12-13.9-22.3-29.4-30.4-46.1l-29.8,11.9c9.9,20.7,22.6,39.8,37.6,56.9 L92.4,397z M272,40.6c18.8,1.4,36.9,5.2,54.1,11.1l12.6-29.5C317.7,14.7,295.3,10,272,8.5V40.6z M190.8,50 c15.7-5,32.2-8.2,49.2-9.4V8.5c-21.2,1.4-41.7,5.4-61.1,11.7L190.8,50z M442.3,92.3L419.6,115c12,13.9,22.3,29.4,30.5,46.1 l29.8-11.9C470,128.5,457.3,109.4,442.3,92.3z M397,92.4l22.7-22.7c-15.6-13.7-32.8-25.5-51.5-34.9l-12.6,29.5 C370.4,72.1,384.4,81.5,397,92.4z"})},$c=fc({},Qc,{attributeName:"opacity"}),cl={tag:"g",children:[Zc,{tag:"circle",attributes:fc({},Jc,{cx:"256",cy:"364",r:"28"}),children:[{tag:"animate",attributes:fc({},Qc,{attributeName:"r",values:"28;14;28;28;14;28;"})},{tag:"animate",attributes:fc({},$c,{values:"1;0;1;1;0;1;"})}]},{tag:"path",attributes:fc({},Jc,{opacity:"1",d:"M263.7,312h-16c-6.6,0-12-5.4-12-12c0-71,77.4-63.9,77.4-107.8c0-20-17.8-40.2-57.4-40.2c-29.1,0-44.3,9.6-59.2,28.7 c-3.9,5-11.1,6-16.2,2.4l-13.1-9.2c-5.6-3.9-6.9-11.8-2.6-17.2c21.2-27.2,46.4-44.7,91.2-44.7c52.3,0,97.4,29.8,97.4,80.2 c0,67.6-77.4,63.5-77.4,107.8C275.7,306.6,270.3,312,263.7,312z"}),children:[{tag:"animate",attributes:fc({},$c,{values:"1;0;0;0;0;1;"})}]},{tag:"path",attributes:fc({},Jc,{opacity:"0",d:"M232.5,134.5l7,168c0.3,6.4,5.6,11.5,12,11.5h9c6.4,0,11.7-5.1,12-11.5l7-168c0.3-6.8-5.2-12.5-12-12.5h-23 C237.7,122,232.2,127.7,232.5,134.5z"}),children:[{tag:"animate",attributes:fc({},$c,{values:"0;0;1;1;0;0;"})}]}]},ll=wc.styles,hl="fa-layers-text",vl=/Font Awesome 5 (Solid|Regular|Light|Brands)/,zl={Solid:"fas",Regular:"far",Light:"fal",Brands:"fab"},el=[],al=(K.documentElement.doScroll?/^loaded|^c/:/^loaded|^i|^c/).test(K.readyState);al||K.addEventListener("DOMContentLoaded",function c(){K.removeEventListener("DOMContentLoaded",c),al=1,el.map(function(c){return c()})});var ml=function(c){K&&(al?setTimeout(c,0):el.push(c))},tl=function(){var c="svg-inline--fa",l=Hc.familyPrefix,h=Hc.replacementClass,v="svg:not(:root).svg-inline--fa{overflow:visible}.svg-inline--fa{display:inline-block;font-size:inherit;height:1em;overflow:visible;vertical-align:-.125em}.svg-inline--fa.fa-lg{vertical-align:-.225em}.svg-inline--fa.fa-w-1{width:.0625em}.svg-inline--fa.fa-w-2{width:.125em}.svg-inline--fa.fa-w-3{width:.1875em}.svg-inline--fa.fa-w-4{width:.25em}.svg-inline--fa.fa-w-5{width:.3125em}.svg-inline--fa.fa-w-6{width:.375em}.svg-inline--fa.fa-w-7{width:.4375em}.svg-inline--fa.fa-w-8{width:.5em}.svg-inline--fa.fa-w-9{width:.5625em}.svg-inline--fa.fa-w-10{width:.625em}.svg-inline--fa.fa-w-11{width:.6875em}.svg-inline--fa.fa-w-12{width:.75em}.svg-inline--fa.fa-w-13{width:.8125em}.svg-inline--fa.fa-w-14{width:.875em}.svg-inline--fa.fa-w-15{width:.9375em}.svg-inline--fa.fa-w-16{width:1em}.svg-inline--fa.fa-w-17{width:1.0625em}.svg-inline--fa.fa-w-18{width:1.125em}.svg-inline--fa.fa-w-19{width:1.1875em}.svg-inline--fa.fa-w-20{width:1.25em}.svg-inline--fa.fa-pull-left{margin-right:.3em;width:auto}.svg-inline--fa.fa-pull-right{margin-left:.3em;width:auto}.svg-inline--fa.fa-border{height:1.5em}.svg-inline--fa.fa-li{width:2em}.svg-inline--fa.fa-fw{width:1.25em}.fa-layers svg.svg-inline--fa{bottom:0;left:0;margin:auto;position:absolute;right:0;top:0}.fa-layers{display:inline-block;height:1em;position:relative;text-align:center;vertical-align:-12.5%;width:1em}.fa-layers svg.svg-inline--fa{-webkit-transform-origin:center center;transform-origin:center center}.fa-layers-counter,.fa-layers-text{display:inline-block;position:absolute;text-align:center}.fa-layers-text{left:50%;top:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);-webkit-transform-origin:center center;transform-origin:center center}.fa-layers-counter{background-color:#ff253a;border-radius:1em;color:#fff;height:1.5em;line-height:1;max-width:5em;min-width:1.5em;overflow:hidden;padding:.25em;right:0;text-overflow:ellipsis;top:0;-webkit-transform:scale(.25);transform:scale(.25);-webkit-transform-origin:top right;transform-origin:top right}.fa-layers-bottom-right{bottom:0;right:0;top:auto;-webkit-transform:scale(.25);transform:scale(.25);-webkit-transform-origin:bottom right;transform-origin:bottom right}.fa-layers-bottom-left{bottom:0;left:0;right:auto;top:auto;-webkit-transform:scale(.25);transform:scale(.25);-webkit-transform-origin:bottom left;transform-origin:bottom left}.fa-layers-top-right{right:0;top:0;-webkit-transform:scale(.25);transform:scale(.25);-webkit-transform-origin:top right;transform-origin:top right}.fa-layers-top-left{left:0;right:auto;top:0;-webkit-transform:scale(.25);transform:scale(.25);-webkit-transform-origin:top left;transform-origin:top left}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:solid .08em #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fab.fa-pull-left,.fal.fa-pull-left,.far.fa-pull-left,.fas.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fab.fa-pull-right,.fal.fa-pull-right,.far.fa-pull-right,.fas.fa-pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.fa-rotate-90{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-webkit-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-webkit-transform:scale(-1,1);transform:scale(-1,1)}.fa-flip-vertical{-webkit-transform:scale(1,-1);transform:scale(1,-1)}.fa-flip-horizontal.fa-flip-vertical{-webkit-transform:scale(-1,-1);transform:scale(-1,-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-rotate-90{-webkit-filter:none;filter:none}.fa-stack{display:inline-block;height:2em;position:relative;width:2em}.fa-stack-1x,.fa-stack-2x{bottom:0;left:0;margin:auto;position:absolute;right:0;top:0}.svg-inline--fa.fa-stack-1x{height:1em;width:1em}.svg-inline--fa.fa-stack-2x{height:2em;width:2em}.fa-inverse{color:#fff}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sr-only-focusable:active,.sr-only-focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}";if("fa"!==l||h!==c){var z=new RegExp("\\.fa\\-","g"),e=new RegExp("\\."+c,"g");v=v.replace(z,"."+l+"-").replace(e,"."+h)}return v},sl=!1,rl=new(function(){function c(){tc(this,c),this.definitions={}}return sc(c,[{key:"add",value:function(){for(var c=this,l=arguments.length,h=Array(l),v=0;v<l;v++)h[v]=arguments[v];var z=h.reduce(this._pullDefinitions,{});Object.keys(z).forEach(function(l){c.definitions[l]=fc({},c.definitions[l]||{},z[l])})}},{key:"reset",value:function(){this.definitions={}}},{key:"_pullDefinitions",value:function(c,l){var h=l.prefix&&l.iconName&&l.icon?{0:l}:l;return Object.keys(h).map(function(l){var v=h[l],z=v.prefix,e=v.iconName,a=v.icon;c[z]||(c[z]={}),c[z][e]=a}),c}}]),c}()),fl={dom:{i2svg:function(){var c=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};j();var l=c.node,h=void 0===l?K:l,v=c.callback,z=void 0===v?function(){}:v;Hc.searchPseudoElements&&E(h),N(h,z)},css:tl,insertCss:function(){h(tl())}},library:rl,parse:{transform:function(c){return Yc(c)}},findIconDefinition:W,icon:function(c){return function(l){var h=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},v=(l||{}).icon?l:W(l||{}),z=h.mask;return z&&(z=(z||{}).icon?z:W(z||{})),c(v,fc({},h,{mask:z}))}}(function(c){var l=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},h=l.transform,z=void 0===h?Vc:h,e=l.symbol,a=void 0!==e&&e,m=l.mask,t=void 0===m?null:m,s=l.title,r=void 0===s?null:s,f=l.classes,M=void 0===f?[]:f,n=l.attributes,H=void 0===n?{}:n,o=l.styles,V=void 0===o?{}:o;if(c){var C=c.prefix,L=c.iconName,u=c.icon;return F(fc({type:"icon"},c),function(){return j(),Hc.autoA11y&&(r?H["aria-labelledby"]=Hc.replacementClass+"-title-"+v():H["aria-hidden"]="true"),i({icons:{main:T(u),mask:t?T(t.icon):{found:!1,width:null,height:null,icon:{}}},prefix:C,iconName:L,transform:fc({},Vc,z),symbol:a,title:r,extra:{attributes:H,styles:V,classes:M}})})}}),text:function(c){var l=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},h=l.transform,v=void 0===h?Vc:h,z=l.title,e=void 0===z?null:z,a=l.classes,m=void 0===a?[]:a,t=l.attributes,s=void 0===t?{}:t,r=l.styles,f=void 0===r?{}:r;return F({type:"text",content:c},function(){return j(),n({content:c,transform:fc({},Vc,v),title:e,extra:{attributes:s,styles:f,classes:[Hc.familyPrefix+"-layers-text"].concat(ic(m))}})})},layer:function(c){return F({type:"layer"},function(){j();var l=[];return c(function(c){l=Array.isArray(c)?c.map(function(c){l=l.concat(c.abstract)}):l.concat(c.abstract)}),[{tag:"span",attributes:{class:Hc.familyPrefix+"-layers"},children:l}]})}};Object.defineProperty(fl,"config",{get:function(){Hc.autoReplaceSvg,Hc.observeMutations,Hc.showMissingIcons;return Mc(Hc,["autoReplaceSvg","observeMutations","showMissingIcons"])},set:function(l){c(l)}}),function(c){try{c()}catch(c){}}(function(){var c=function(){Hc.autoReplaceSvg&&fl.dom.i2svg({node:K})};Q&&(U.FontAwesome||(U.FontAwesome=fl),ml(function(){Object.keys(wc.styles).length>0&&c(),Hc.observeMutations&&"function"==typeof MutationObserver&&w({treeCallback:N,nodeCallback:q,pseudoElementsCallback:E})})),wc.hooks=fc({},wc.hooks,{addPack:function(l,h){wc.styles[l]=fc({},wc.styles[l]||{},h),jc(),c()},addShims:function(l){var h;(h=wc.shims).push.apply(h,ic(l)),jc(),c()}})})}();
\ No newline at end of file diff --git a/web/lib/lz-string-1.4.4.min.js b/web/lib/lz-string-1.4.4.min.js new file mode 100644 index 00000000..2d1900a0 --- /dev/null +++ b/web/lib/lz-string-1.4.4.min.js @@ -0,0 +1 @@ +var LZString=function(){function o(o,r){if(!t[o]){t[o]={};for(var n=0;n<o.length;n++)t[o][o.charAt(n)]=n}return t[o][r]}var r=String.fromCharCode,n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-$",t={},i={compressToBase64:function(o){if(null==o)return"";var r=i._compress(o,6,function(o){return n.charAt(o)});switch(r.length%4){default:case 0:return r;case 1:return r+"===";case 2:return r+"==";case 3:return r+"="}},decompressFromBase64:function(r){return null==r?"":""==r?null:i._decompress(r.length,32,function(e){return o(n,r.charAt(e))})},compressToUTF16:function(o){return null==o?"":i._compress(o,15,function(o){return r(o+32)})+" "},decompressFromUTF16:function(o){return null==o?"":""==o?null:i._decompress(o.length,16384,function(r){return o.charCodeAt(r)-32})},compressToUint8Array:function(o){for(var r=i.compress(o),n=new Uint8Array(2*r.length),e=0,t=r.length;t>e;e++){var s=r.charCodeAt(e);n[2*e]=s>>>8,n[2*e+1]=s%256}return n},decompressFromUint8Array:function(o){if(null===o||void 0===o)return i.decompress(o);for(var n=new Array(o.length/2),e=0,t=n.length;t>e;e++)n[e]=256*o[2*e]+o[2*e+1];var s=[];return n.forEach(function(o){s.push(r(o))}),i.decompress(s.join(""))},compressToEncodedURIComponent:function(o){return null==o?"":i._compress(o,6,function(o){return e.charAt(o)})},decompressFromEncodedURIComponent:function(r){return null==r?"":""==r?null:(r=r.replace(/ /g,"+"),i._decompress(r.length,32,function(n){return o(e,r.charAt(n))}))},compress:function(o){return i._compress(o,16,function(o){return r(o)})},_compress:function(o,r,n){if(null==o)return"";var e,t,i,s={},p={},u="",c="",a="",l=2,f=3,h=2,d=[],m=0,v=0;for(i=0;i<o.length;i+=1)if(u=o.charAt(i),Object.prototype.hasOwnProperty.call(s,u)||(s[u]=f++,p[u]=!0),c=a+u,Object.prototype.hasOwnProperty.call(s,c))a=c;else{if(Object.prototype.hasOwnProperty.call(p,a)){if(a.charCodeAt(0)<256){for(e=0;h>e;e++)m<<=1,v==r-1?(v=0,d.push(n(m)),m=0):v++;for(t=a.charCodeAt(0),e=0;8>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1}else{for(t=1,e=0;h>e;e++)m=m<<1|t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t=0;for(t=a.charCodeAt(0),e=0;16>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1}l--,0==l&&(l=Math.pow(2,h),h++),delete p[a]}else for(t=s[a],e=0;h>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1;l--,0==l&&(l=Math.pow(2,h),h++),s[c]=f++,a=String(u)}if(""!==a){if(Object.prototype.hasOwnProperty.call(p,a)){if(a.charCodeAt(0)<256){for(e=0;h>e;e++)m<<=1,v==r-1?(v=0,d.push(n(m)),m=0):v++;for(t=a.charCodeAt(0),e=0;8>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1}else{for(t=1,e=0;h>e;e++)m=m<<1|t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t=0;for(t=a.charCodeAt(0),e=0;16>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1}l--,0==l&&(l=Math.pow(2,h),h++),delete p[a]}else for(t=s[a],e=0;h>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1;l--,0==l&&(l=Math.pow(2,h),h++)}for(t=2,e=0;h>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1;for(;;){if(m<<=1,v==r-1){d.push(n(m));break}v++}return d.join("")},decompress:function(o){return null==o?"":""==o?null:i._decompress(o.length,32768,function(r){return o.charCodeAt(r)})},_decompress:function(o,n,e){var t,i,s,p,u,c,a,l,f=[],h=4,d=4,m=3,v="",w=[],A={val:e(0),position:n,index:1};for(i=0;3>i;i+=1)f[i]=i;for(p=0,c=Math.pow(2,2),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;switch(t=p){case 0:for(p=0,c=Math.pow(2,8),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;l=r(p);break;case 1:for(p=0,c=Math.pow(2,16),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;l=r(p);break;case 2:return""}for(f[3]=l,s=l,w.push(l);;){if(A.index>o)return"";for(p=0,c=Math.pow(2,m),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;switch(l=p){case 0:for(p=0,c=Math.pow(2,8),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;f[d++]=r(p),l=d-1,h--;break;case 1:for(p=0,c=Math.pow(2,16),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;f[d++]=r(p),l=d-1,h--;break;case 2:return w.join("")}if(0==h&&(h=Math.pow(2,m),m++),f[l])v=f[l];else{if(l!==d)return null;v=s+s.charAt(0)}w.push(v),f[d++]=s+v.charAt(0),h--,s=v,0==h&&(h=Math.pow(2,m),m++)}}};return i}();"function"==typeof define&&define.amd?define(function(){return LZString}):"undefined"!=typeof module&&null!=module&&(module.exports=LZString); diff --git a/web/lib/pako-1.0.6.min.js b/web/lib/pako-1.0.6.min.js new file mode 100644 index 00000000..73024f7a --- /dev/null +++ b/web/lib/pako-1.0.6.min.js @@ -0,0 +1 @@ +!function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).pako=t()}}(function(){return function t(e,a,i){function n(s,o){if(!a[s]){if(!e[s]){var l="function"==typeof require&&require;if(!o&&l)return l(s,!0);if(r)return r(s,!0);var h=new Error("Cannot find module '"+s+"'");throw h.code="MODULE_NOT_FOUND",h}var d=a[s]={exports:{}};e[s][0].call(d.exports,function(t){var a=e[s][1][t];return n(a||t)},d,d.exports,t,e,a,i)}return a[s].exports}for(var r="function"==typeof require&&require,s=0;s<i.length;s++)n(i[s]);return n}({1:[function(t,e,a){"use strict";function i(t){if(!(this instanceof i))return new i(t);this.options=s.assign({level:_,method:c,chunkSize:16384,windowBits:15,memLevel:8,strategy:u,to:""},t||{});var e=this.options;e.raw&&e.windowBits>0?e.windowBits=-e.windowBits:e.gzip&&e.windowBits>0&&e.windowBits<16&&(e.windowBits+=16),this.err=0,this.msg="",this.ended=!1,this.chunks=[],this.strm=new h,this.strm.avail_out=0;var a=r.deflateInit2(this.strm,e.level,e.method,e.windowBits,e.memLevel,e.strategy);if(a!==f)throw new Error(l[a]);if(e.header&&r.deflateSetHeader(this.strm,e.header),e.dictionary){var n;if(n="string"==typeof e.dictionary?o.string2buf(e.dictionary):"[object ArrayBuffer]"===d.call(e.dictionary)?new Uint8Array(e.dictionary):e.dictionary,(a=r.deflateSetDictionary(this.strm,n))!==f)throw new Error(l[a]);this._dict_set=!0}}function n(t,e){var a=new i(e);if(a.push(t,!0),a.err)throw a.msg||l[a.err];return a.result}var r=t("./zlib/deflate"),s=t("./utils/common"),o=t("./utils/strings"),l=t("./zlib/messages"),h=t("./zlib/zstream"),d=Object.prototype.toString,f=0,_=-1,u=0,c=8;i.prototype.push=function(t,e){var a,i,n=this.strm,l=this.options.chunkSize;if(this.ended)return!1;i=e===~~e?e:!0===e?4:0,"string"==typeof t?n.input=o.string2buf(t):"[object ArrayBuffer]"===d.call(t)?n.input=new Uint8Array(t):n.input=t,n.next_in=0,n.avail_in=n.input.length;do{if(0===n.avail_out&&(n.output=new s.Buf8(l),n.next_out=0,n.avail_out=l),1!==(a=r.deflate(n,i))&&a!==f)return this.onEnd(a),this.ended=!0,!1;0!==n.avail_out&&(0!==n.avail_in||4!==i&&2!==i)||("string"===this.options.to?this.onData(o.buf2binstring(s.shrinkBuf(n.output,n.next_out))):this.onData(s.shrinkBuf(n.output,n.next_out)))}while((n.avail_in>0||0===n.avail_out)&&1!==a);return 4===i?(a=r.deflateEnd(this.strm),this.onEnd(a),this.ended=!0,a===f):2!==i||(this.onEnd(f),n.avail_out=0,!0)},i.prototype.onData=function(t){this.chunks.push(t)},i.prototype.onEnd=function(t){t===f&&("string"===this.options.to?this.result=this.chunks.join(""):this.result=s.flattenChunks(this.chunks)),this.chunks=[],this.err=t,this.msg=this.strm.msg},a.Deflate=i,a.deflate=n,a.deflateRaw=function(t,e){return e=e||{},e.raw=!0,n(t,e)},a.gzip=function(t,e){return e=e||{},e.gzip=!0,n(t,e)}},{"./utils/common":3,"./utils/strings":4,"./zlib/deflate":8,"./zlib/messages":13,"./zlib/zstream":15}],2:[function(t,e,a){"use strict";function i(t){if(!(this instanceof i))return new i(t);this.options=s.assign({chunkSize:16384,windowBits:0,to:""},t||{});var e=this.options;e.raw&&e.windowBits>=0&&e.windowBits<16&&(e.windowBits=-e.windowBits,0===e.windowBits&&(e.windowBits=-15)),!(e.windowBits>=0&&e.windowBits<16)||t&&t.windowBits||(e.windowBits+=32),e.windowBits>15&&e.windowBits<48&&0==(15&e.windowBits)&&(e.windowBits|=15),this.err=0,this.msg="",this.ended=!1,this.chunks=[],this.strm=new d,this.strm.avail_out=0;var a=r.inflateInit2(this.strm,e.windowBits);if(a!==l.Z_OK)throw new Error(h[a]);this.header=new f,r.inflateGetHeader(this.strm,this.header)}function n(t,e){var a=new i(e);if(a.push(t,!0),a.err)throw a.msg||h[a.err];return a.result}var r=t("./zlib/inflate"),s=t("./utils/common"),o=t("./utils/strings"),l=t("./zlib/constants"),h=t("./zlib/messages"),d=t("./zlib/zstream"),f=t("./zlib/gzheader"),_=Object.prototype.toString;i.prototype.push=function(t,e){var a,i,n,h,d,f,u=this.strm,c=this.options.chunkSize,b=this.options.dictionary,g=!1;if(this.ended)return!1;i=e===~~e?e:!0===e?l.Z_FINISH:l.Z_NO_FLUSH,"string"==typeof t?u.input=o.binstring2buf(t):"[object ArrayBuffer]"===_.call(t)?u.input=new Uint8Array(t):u.input=t,u.next_in=0,u.avail_in=u.input.length;do{if(0===u.avail_out&&(u.output=new s.Buf8(c),u.next_out=0,u.avail_out=c),(a=r.inflate(u,l.Z_NO_FLUSH))===l.Z_NEED_DICT&&b&&(f="string"==typeof b?o.string2buf(b):"[object ArrayBuffer]"===_.call(b)?new Uint8Array(b):b,a=r.inflateSetDictionary(this.strm,f)),a===l.Z_BUF_ERROR&&!0===g&&(a=l.Z_OK,g=!1),a!==l.Z_STREAM_END&&a!==l.Z_OK)return this.onEnd(a),this.ended=!0,!1;u.next_out&&(0!==u.avail_out&&a!==l.Z_STREAM_END&&(0!==u.avail_in||i!==l.Z_FINISH&&i!==l.Z_SYNC_FLUSH)||("string"===this.options.to?(n=o.utf8border(u.output,u.next_out),h=u.next_out-n,d=o.buf2string(u.output,n),u.next_out=h,u.avail_out=c-h,h&&s.arraySet(u.output,u.output,n,h,0),this.onData(d)):this.onData(s.shrinkBuf(u.output,u.next_out)))),0===u.avail_in&&0===u.avail_out&&(g=!0)}while((u.avail_in>0||0===u.avail_out)&&a!==l.Z_STREAM_END);return a===l.Z_STREAM_END&&(i=l.Z_FINISH),i===l.Z_FINISH?(a=r.inflateEnd(this.strm),this.onEnd(a),this.ended=!0,a===l.Z_OK):i!==l.Z_SYNC_FLUSH||(this.onEnd(l.Z_OK),u.avail_out=0,!0)},i.prototype.onData=function(t){this.chunks.push(t)},i.prototype.onEnd=function(t){t===l.Z_OK&&("string"===this.options.to?this.result=this.chunks.join(""):this.result=s.flattenChunks(this.chunks)),this.chunks=[],this.err=t,this.msg=this.strm.msg},a.Inflate=i,a.inflate=n,a.inflateRaw=function(t,e){return e=e||{},e.raw=!0,n(t,e)},a.ungzip=n},{"./utils/common":3,"./utils/strings":4,"./zlib/constants":6,"./zlib/gzheader":9,"./zlib/inflate":11,"./zlib/messages":13,"./zlib/zstream":15}],3:[function(t,e,a){"use strict";function i(t,e){return Object.prototype.hasOwnProperty.call(t,e)}var n="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Int32Array;a.assign=function(t){for(var e=Array.prototype.slice.call(arguments,1);e.length;){var a=e.shift();if(a){if("object"!=typeof a)throw new TypeError(a+"must be non-object");for(var n in a)i(a,n)&&(t[n]=a[n])}}return t},a.shrinkBuf=function(t,e){return t.length===e?t:t.subarray?t.subarray(0,e):(t.length=e,t)};var r={arraySet:function(t,e,a,i,n){if(e.subarray&&t.subarray)t.set(e.subarray(a,a+i),n);else for(var r=0;r<i;r++)t[n+r]=e[a+r]},flattenChunks:function(t){var e,a,i,n,r,s;for(i=0,e=0,a=t.length;e<a;e++)i+=t[e].length;for(s=new Uint8Array(i),n=0,e=0,a=t.length;e<a;e++)r=t[e],s.set(r,n),n+=r.length;return s}},s={arraySet:function(t,e,a,i,n){for(var r=0;r<i;r++)t[n+r]=e[a+r]},flattenChunks:function(t){return[].concat.apply([],t)}};a.setTyped=function(t){t?(a.Buf8=Uint8Array,a.Buf16=Uint16Array,a.Buf32=Int32Array,a.assign(a,r)):(a.Buf8=Array,a.Buf16=Array,a.Buf32=Array,a.assign(a,s))},a.setTyped(n)},{}],4:[function(t,e,a){"use strict";function i(t,e){if(e<65537&&(t.subarray&&s||!t.subarray&&r))return String.fromCharCode.apply(null,n.shrinkBuf(t,e));for(var a="",i=0;i<e;i++)a+=String.fromCharCode(t[i]);return a}var n=t("./common"),r=!0,s=!0;try{String.fromCharCode.apply(null,[0])}catch(t){r=!1}try{String.fromCharCode.apply(null,new Uint8Array(1))}catch(t){s=!1}for(var o=new n.Buf8(256),l=0;l<256;l++)o[l]=l>=252?6:l>=248?5:l>=240?4:l>=224?3:l>=192?2:1;o[254]=o[254]=1,a.string2buf=function(t){var e,a,i,r,s,o=t.length,l=0;for(r=0;r<o;r++)55296==(64512&(a=t.charCodeAt(r)))&&r+1<o&&56320==(64512&(i=t.charCodeAt(r+1)))&&(a=65536+(a-55296<<10)+(i-56320),r++),l+=a<128?1:a<2048?2:a<65536?3:4;for(e=new n.Buf8(l),s=0,r=0;s<l;r++)55296==(64512&(a=t.charCodeAt(r)))&&r+1<o&&56320==(64512&(i=t.charCodeAt(r+1)))&&(a=65536+(a-55296<<10)+(i-56320),r++),a<128?e[s++]=a:a<2048?(e[s++]=192|a>>>6,e[s++]=128|63&a):a<65536?(e[s++]=224|a>>>12,e[s++]=128|a>>>6&63,e[s++]=128|63&a):(e[s++]=240|a>>>18,e[s++]=128|a>>>12&63,e[s++]=128|a>>>6&63,e[s++]=128|63&a);return e},a.buf2binstring=function(t){return i(t,t.length)},a.binstring2buf=function(t){for(var e=new n.Buf8(t.length),a=0,i=e.length;a<i;a++)e[a]=t.charCodeAt(a);return e},a.buf2string=function(t,e){var a,n,r,s,l=e||t.length,h=new Array(2*l);for(n=0,a=0;a<l;)if((r=t[a++])<128)h[n++]=r;else if((s=o[r])>4)h[n++]=65533,a+=s-1;else{for(r&=2===s?31:3===s?15:7;s>1&&a<l;)r=r<<6|63&t[a++],s--;s>1?h[n++]=65533:r<65536?h[n++]=r:(r-=65536,h[n++]=55296|r>>10&1023,h[n++]=56320|1023&r)}return i(h,n)},a.utf8border=function(t,e){var a;for((e=e||t.length)>t.length&&(e=t.length),a=e-1;a>=0&&128==(192&t[a]);)a--;return a<0?e:0===a?e:a+o[t[a]]>e?a:e}},{"./common":3}],5:[function(t,e,a){"use strict";e.exports=function(t,e,a,i){for(var n=65535&t|0,r=t>>>16&65535|0,s=0;0!==a;){a-=s=a>2e3?2e3:a;do{r=r+(n=n+e[i++]|0)|0}while(--s);n%=65521,r%=65521}return n|r<<16|0}},{}],6:[function(t,e,a){"use strict";e.exports={Z_NO_FLUSH:0,Z_PARTIAL_FLUSH:1,Z_SYNC_FLUSH:2,Z_FULL_FLUSH:3,Z_FINISH:4,Z_BLOCK:5,Z_TREES:6,Z_OK:0,Z_STREAM_END:1,Z_NEED_DICT:2,Z_ERRNO:-1,Z_STREAM_ERROR:-2,Z_DATA_ERROR:-3,Z_BUF_ERROR:-5,Z_NO_COMPRESSION:0,Z_BEST_SPEED:1,Z_BEST_COMPRESSION:9,Z_DEFAULT_COMPRESSION:-1,Z_FILTERED:1,Z_HUFFMAN_ONLY:2,Z_RLE:3,Z_FIXED:4,Z_DEFAULT_STRATEGY:0,Z_BINARY:0,Z_TEXT:1,Z_UNKNOWN:2,Z_DEFLATED:8}},{}],7:[function(t,e,a){"use strict";var i=function(){for(var t,e=[],a=0;a<256;a++){t=a;for(var i=0;i<8;i++)t=1&t?3988292384^t>>>1:t>>>1;e[a]=t}return e}();e.exports=function(t,e,a,n){var r=i,s=n+a;t^=-1;for(var o=n;o<s;o++)t=t>>>8^r[255&(t^e[o])];return-1^t}},{}],8:[function(t,e,a){"use strict";function i(t,e){return t.msg=A[e],e}function n(t){return(t<<1)-(t>4?9:0)}function r(t){for(var e=t.length;--e>=0;)t[e]=0}function s(t){var e=t.state,a=e.pending;a>t.avail_out&&(a=t.avail_out),0!==a&&(z.arraySet(t.output,e.pending_buf,e.pending_out,a,t.next_out),t.next_out+=a,e.pending_out+=a,t.total_out+=a,t.avail_out-=a,e.pending-=a,0===e.pending&&(e.pending_out=0))}function o(t,e){B._tr_flush_block(t,t.block_start>=0?t.block_start:-1,t.strstart-t.block_start,e),t.block_start=t.strstart,s(t.strm)}function l(t,e){t.pending_buf[t.pending++]=e}function h(t,e){t.pending_buf[t.pending++]=e>>>8&255,t.pending_buf[t.pending++]=255&e}function d(t,e,a,i){var n=t.avail_in;return n>i&&(n=i),0===n?0:(t.avail_in-=n,z.arraySet(e,t.input,t.next_in,n,a),1===t.state.wrap?t.adler=S(t.adler,e,n,a):2===t.state.wrap&&(t.adler=E(t.adler,e,n,a)),t.next_in+=n,t.total_in+=n,n)}function f(t,e){var a,i,n=t.max_chain_length,r=t.strstart,s=t.prev_length,o=t.nice_match,l=t.strstart>t.w_size-it?t.strstart-(t.w_size-it):0,h=t.window,d=t.w_mask,f=t.prev,_=t.strstart+at,u=h[r+s-1],c=h[r+s];t.prev_length>=t.good_match&&(n>>=2),o>t.lookahead&&(o=t.lookahead);do{if(a=e,h[a+s]===c&&h[a+s-1]===u&&h[a]===h[r]&&h[++a]===h[r+1]){r+=2,a++;do{}while(h[++r]===h[++a]&&h[++r]===h[++a]&&h[++r]===h[++a]&&h[++r]===h[++a]&&h[++r]===h[++a]&&h[++r]===h[++a]&&h[++r]===h[++a]&&h[++r]===h[++a]&&r<_);if(i=at-(_-r),r=_-at,i>s){if(t.match_start=e,s=i,i>=o)break;u=h[r+s-1],c=h[r+s]}}}while((e=f[e&d])>l&&0!=--n);return s<=t.lookahead?s:t.lookahead}function _(t){var e,a,i,n,r,s=t.w_size;do{if(n=t.window_size-t.lookahead-t.strstart,t.strstart>=s+(s-it)){z.arraySet(t.window,t.window,s,s,0),t.match_start-=s,t.strstart-=s,t.block_start-=s,e=a=t.hash_size;do{i=t.head[--e],t.head[e]=i>=s?i-s:0}while(--a);e=a=s;do{i=t.prev[--e],t.prev[e]=i>=s?i-s:0}while(--a);n+=s}if(0===t.strm.avail_in)break;if(a=d(t.strm,t.window,t.strstart+t.lookahead,n),t.lookahead+=a,t.lookahead+t.insert>=et)for(r=t.strstart-t.insert,t.ins_h=t.window[r],t.ins_h=(t.ins_h<<t.hash_shift^t.window[r+1])&t.hash_mask;t.insert&&(t.ins_h=(t.ins_h<<t.hash_shift^t.window[r+et-1])&t.hash_mask,t.prev[r&t.w_mask]=t.head[t.ins_h],t.head[t.ins_h]=r,r++,t.insert--,!(t.lookahead+t.insert<et)););}while(t.lookahead<it&&0!==t.strm.avail_in)}function u(t,e){for(var a,i;;){if(t.lookahead<it){if(_(t),t.lookahead<it&&e===Z)return _t;if(0===t.lookahead)break}if(a=0,t.lookahead>=et&&(t.ins_h=(t.ins_h<<t.hash_shift^t.window[t.strstart+et-1])&t.hash_mask,a=t.prev[t.strstart&t.w_mask]=t.head[t.ins_h],t.head[t.ins_h]=t.strstart),0!==a&&t.strstart-a<=t.w_size-it&&(t.match_length=f(t,a)),t.match_length>=et)if(i=B._tr_tally(t,t.strstart-t.match_start,t.match_length-et),t.lookahead-=t.match_length,t.match_length<=t.max_lazy_match&&t.lookahead>=et){t.match_length--;do{t.strstart++,t.ins_h=(t.ins_h<<t.hash_shift^t.window[t.strstart+et-1])&t.hash_mask,a=t.prev[t.strstart&t.w_mask]=t.head[t.ins_h],t.head[t.ins_h]=t.strstart}while(0!=--t.match_length);t.strstart++}else t.strstart+=t.match_length,t.match_length=0,t.ins_h=t.window[t.strstart],t.ins_h=(t.ins_h<<t.hash_shift^t.window[t.strstart+1])&t.hash_mask;else i=B._tr_tally(t,0,t.window[t.strstart]),t.lookahead--,t.strstart++;if(i&&(o(t,!1),0===t.strm.avail_out))return _t}return t.insert=t.strstart<et-1?t.strstart:et-1,e===N?(o(t,!0),0===t.strm.avail_out?ct:bt):t.last_lit&&(o(t,!1),0===t.strm.avail_out)?_t:ut}function c(t,e){for(var a,i,n;;){if(t.lookahead<it){if(_(t),t.lookahead<it&&e===Z)return _t;if(0===t.lookahead)break}if(a=0,t.lookahead>=et&&(t.ins_h=(t.ins_h<<t.hash_shift^t.window[t.strstart+et-1])&t.hash_mask,a=t.prev[t.strstart&t.w_mask]=t.head[t.ins_h],t.head[t.ins_h]=t.strstart),t.prev_length=t.match_length,t.prev_match=t.match_start,t.match_length=et-1,0!==a&&t.prev_length<t.max_lazy_match&&t.strstart-a<=t.w_size-it&&(t.match_length=f(t,a),t.match_length<=5&&(t.strategy===H||t.match_length===et&&t.strstart-t.match_start>4096)&&(t.match_length=et-1)),t.prev_length>=et&&t.match_length<=t.prev_length){n=t.strstart+t.lookahead-et,i=B._tr_tally(t,t.strstart-1-t.prev_match,t.prev_length-et),t.lookahead-=t.prev_length-1,t.prev_length-=2;do{++t.strstart<=n&&(t.ins_h=(t.ins_h<<t.hash_shift^t.window[t.strstart+et-1])&t.hash_mask,a=t.prev[t.strstart&t.w_mask]=t.head[t.ins_h],t.head[t.ins_h]=t.strstart)}while(0!=--t.prev_length);if(t.match_available=0,t.match_length=et-1,t.strstart++,i&&(o(t,!1),0===t.strm.avail_out))return _t}else if(t.match_available){if((i=B._tr_tally(t,0,t.window[t.strstart-1]))&&o(t,!1),t.strstart++,t.lookahead--,0===t.strm.avail_out)return _t}else t.match_available=1,t.strstart++,t.lookahead--}return t.match_available&&(i=B._tr_tally(t,0,t.window[t.strstart-1]),t.match_available=0),t.insert=t.strstart<et-1?t.strstart:et-1,e===N?(o(t,!0),0===t.strm.avail_out?ct:bt):t.last_lit&&(o(t,!1),0===t.strm.avail_out)?_t:ut}function b(t,e){for(var a,i,n,r,s=t.window;;){if(t.lookahead<=at){if(_(t),t.lookahead<=at&&e===Z)return _t;if(0===t.lookahead)break}if(t.match_length=0,t.lookahead>=et&&t.strstart>0&&(n=t.strstart-1,(i=s[n])===s[++n]&&i===s[++n]&&i===s[++n])){r=t.strstart+at;do{}while(i===s[++n]&&i===s[++n]&&i===s[++n]&&i===s[++n]&&i===s[++n]&&i===s[++n]&&i===s[++n]&&i===s[++n]&&n<r);t.match_length=at-(r-n),t.match_length>t.lookahead&&(t.match_length=t.lookahead)}if(t.match_length>=et?(a=B._tr_tally(t,1,t.match_length-et),t.lookahead-=t.match_length,t.strstart+=t.match_length,t.match_length=0):(a=B._tr_tally(t,0,t.window[t.strstart]),t.lookahead--,t.strstart++),a&&(o(t,!1),0===t.strm.avail_out))return _t}return t.insert=0,e===N?(o(t,!0),0===t.strm.avail_out?ct:bt):t.last_lit&&(o(t,!1),0===t.strm.avail_out)?_t:ut}function g(t,e){for(var a;;){if(0===t.lookahead&&(_(t),0===t.lookahead)){if(e===Z)return _t;break}if(t.match_length=0,a=B._tr_tally(t,0,t.window[t.strstart]),t.lookahead--,t.strstart++,a&&(o(t,!1),0===t.strm.avail_out))return _t}return t.insert=0,e===N?(o(t,!0),0===t.strm.avail_out?ct:bt):t.last_lit&&(o(t,!1),0===t.strm.avail_out)?_t:ut}function m(t,e,a,i,n){this.good_length=t,this.max_lazy=e,this.nice_length=a,this.max_chain=i,this.func=n}function w(t){t.window_size=2*t.w_size,r(t.head),t.max_lazy_match=x[t.level].max_lazy,t.good_match=x[t.level].good_length,t.nice_match=x[t.level].nice_length,t.max_chain_length=x[t.level].max_chain,t.strstart=0,t.block_start=0,t.lookahead=0,t.insert=0,t.match_length=t.prev_length=et-1,t.match_available=0,t.ins_h=0}function p(){this.strm=null,this.status=0,this.pending_buf=null,this.pending_buf_size=0,this.pending_out=0,this.pending=0,this.wrap=0,this.gzhead=null,this.gzindex=0,this.method=q,this.last_flush=-1,this.w_size=0,this.w_bits=0,this.w_mask=0,this.window=null,this.window_size=0,this.prev=null,this.head=null,this.ins_h=0,this.hash_size=0,this.hash_bits=0,this.hash_mask=0,this.hash_shift=0,this.block_start=0,this.match_length=0,this.prev_match=0,this.match_available=0,this.strstart=0,this.match_start=0,this.lookahead=0,this.prev_length=0,this.max_chain_length=0,this.max_lazy_match=0,this.level=0,this.strategy=0,this.good_match=0,this.nice_match=0,this.dyn_ltree=new z.Buf16(2*$),this.dyn_dtree=new z.Buf16(2*(2*Q+1)),this.bl_tree=new z.Buf16(2*(2*V+1)),r(this.dyn_ltree),r(this.dyn_dtree),r(this.bl_tree),this.l_desc=null,this.d_desc=null,this.bl_desc=null,this.bl_count=new z.Buf16(tt+1),this.heap=new z.Buf16(2*J+1),r(this.heap),this.heap_len=0,this.heap_max=0,this.depth=new z.Buf16(2*J+1),r(this.depth),this.l_buf=0,this.lit_bufsize=0,this.last_lit=0,this.d_buf=0,this.opt_len=0,this.static_len=0,this.matches=0,this.insert=0,this.bi_buf=0,this.bi_valid=0}function v(t){var e;return t&&t.state?(t.total_in=t.total_out=0,t.data_type=Y,e=t.state,e.pending=0,e.pending_out=0,e.wrap<0&&(e.wrap=-e.wrap),e.status=e.wrap?rt:dt,t.adler=2===e.wrap?0:1,e.last_flush=Z,B._tr_init(e),D):i(t,U)}function k(t){var e=v(t);return e===D&&w(t.state),e}function y(t,e,a,n,r,s){if(!t)return U;var o=1;if(e===L&&(e=6),n<0?(o=0,n=-n):n>15&&(o=2,n-=16),r<1||r>G||a!==q||n<8||n>15||e<0||e>9||s<0||s>M)return i(t,U);8===n&&(n=9);var l=new p;return t.state=l,l.strm=t,l.wrap=o,l.gzhead=null,l.w_bits=n,l.w_size=1<<l.w_bits,l.w_mask=l.w_size-1,l.hash_bits=r+7,l.hash_size=1<<l.hash_bits,l.hash_mask=l.hash_size-1,l.hash_shift=~~((l.hash_bits+et-1)/et),l.window=new z.Buf8(2*l.w_size),l.head=new z.Buf16(l.hash_size),l.prev=new z.Buf16(l.w_size),l.lit_bufsize=1<<r+6,l.pending_buf_size=4*l.lit_bufsize,l.pending_buf=new z.Buf8(l.pending_buf_size),l.d_buf=1*l.lit_bufsize,l.l_buf=3*l.lit_bufsize,l.level=e,l.strategy=s,l.method=a,k(t)}var x,z=t("../utils/common"),B=t("./trees"),S=t("./adler32"),E=t("./crc32"),A=t("./messages"),Z=0,R=1,C=3,N=4,O=5,D=0,I=1,U=-2,T=-3,F=-5,L=-1,H=1,j=2,K=3,M=4,P=0,Y=2,q=8,G=9,X=15,W=8,J=286,Q=30,V=19,$=2*J+1,tt=15,et=3,at=258,it=at+et+1,nt=32,rt=42,st=69,ot=73,lt=91,ht=103,dt=113,ft=666,_t=1,ut=2,ct=3,bt=4,gt=3;x=[new m(0,0,0,0,function(t,e){var a=65535;for(a>t.pending_buf_size-5&&(a=t.pending_buf_size-5);;){if(t.lookahead<=1){if(_(t),0===t.lookahead&&e===Z)return _t;if(0===t.lookahead)break}t.strstart+=t.lookahead,t.lookahead=0;var i=t.block_start+a;if((0===t.strstart||t.strstart>=i)&&(t.lookahead=t.strstart-i,t.strstart=i,o(t,!1),0===t.strm.avail_out))return _t;if(t.strstart-t.block_start>=t.w_size-it&&(o(t,!1),0===t.strm.avail_out))return _t}return t.insert=0,e===N?(o(t,!0),0===t.strm.avail_out?ct:bt):(t.strstart>t.block_start&&(o(t,!1),t.strm.avail_out),_t)}),new m(4,4,8,4,u),new m(4,5,16,8,u),new m(4,6,32,32,u),new m(4,4,16,16,c),new m(8,16,32,32,c),new m(8,16,128,128,c),new m(8,32,128,256,c),new m(32,128,258,1024,c),new m(32,258,258,4096,c)],a.deflateInit=function(t,e){return y(t,e,q,X,W,P)},a.deflateInit2=y,a.deflateReset=k,a.deflateResetKeep=v,a.deflateSetHeader=function(t,e){return t&&t.state?2!==t.state.wrap?U:(t.state.gzhead=e,D):U},a.deflate=function(t,e){var a,o,d,f;if(!t||!t.state||e>O||e<0)return t?i(t,U):U;if(o=t.state,!t.output||!t.input&&0!==t.avail_in||o.status===ft&&e!==N)return i(t,0===t.avail_out?F:U);if(o.strm=t,a=o.last_flush,o.last_flush=e,o.status===rt)if(2===o.wrap)t.adler=0,l(o,31),l(o,139),l(o,8),o.gzhead?(l(o,(o.gzhead.text?1:0)+(o.gzhead.hcrc?2:0)+(o.gzhead.extra?4:0)+(o.gzhead.name?8:0)+(o.gzhead.comment?16:0)),l(o,255&o.gzhead.time),l(o,o.gzhead.time>>8&255),l(o,o.gzhead.time>>16&255),l(o,o.gzhead.time>>24&255),l(o,9===o.level?2:o.strategy>=j||o.level<2?4:0),l(o,255&o.gzhead.os),o.gzhead.extra&&o.gzhead.extra.length&&(l(o,255&o.gzhead.extra.length),l(o,o.gzhead.extra.length>>8&255)),o.gzhead.hcrc&&(t.adler=E(t.adler,o.pending_buf,o.pending,0)),o.gzindex=0,o.status=st):(l(o,0),l(o,0),l(o,0),l(o,0),l(o,0),l(o,9===o.level?2:o.strategy>=j||o.level<2?4:0),l(o,gt),o.status=dt);else{var _=q+(o.w_bits-8<<4)<<8;_|=(o.strategy>=j||o.level<2?0:o.level<6?1:6===o.level?2:3)<<6,0!==o.strstart&&(_|=nt),_+=31-_%31,o.status=dt,h(o,_),0!==o.strstart&&(h(o,t.adler>>>16),h(o,65535&t.adler)),t.adler=1}if(o.status===st)if(o.gzhead.extra){for(d=o.pending;o.gzindex<(65535&o.gzhead.extra.length)&&(o.pending!==o.pending_buf_size||(o.gzhead.hcrc&&o.pending>d&&(t.adler=E(t.adler,o.pending_buf,o.pending-d,d)),s(t),d=o.pending,o.pending!==o.pending_buf_size));)l(o,255&o.gzhead.extra[o.gzindex]),o.gzindex++;o.gzhead.hcrc&&o.pending>d&&(t.adler=E(t.adler,o.pending_buf,o.pending-d,d)),o.gzindex===o.gzhead.extra.length&&(o.gzindex=0,o.status=ot)}else o.status=ot;if(o.status===ot)if(o.gzhead.name){d=o.pending;do{if(o.pending===o.pending_buf_size&&(o.gzhead.hcrc&&o.pending>d&&(t.adler=E(t.adler,o.pending_buf,o.pending-d,d)),s(t),d=o.pending,o.pending===o.pending_buf_size)){f=1;break}f=o.gzindex<o.gzhead.name.length?255&o.gzhead.name.charCodeAt(o.gzindex++):0,l(o,f)}while(0!==f);o.gzhead.hcrc&&o.pending>d&&(t.adler=E(t.adler,o.pending_buf,o.pending-d,d)),0===f&&(o.gzindex=0,o.status=lt)}else o.status=lt;if(o.status===lt)if(o.gzhead.comment){d=o.pending;do{if(o.pending===o.pending_buf_size&&(o.gzhead.hcrc&&o.pending>d&&(t.adler=E(t.adler,o.pending_buf,o.pending-d,d)),s(t),d=o.pending,o.pending===o.pending_buf_size)){f=1;break}f=o.gzindex<o.gzhead.comment.length?255&o.gzhead.comment.charCodeAt(o.gzindex++):0,l(o,f)}while(0!==f);o.gzhead.hcrc&&o.pending>d&&(t.adler=E(t.adler,o.pending_buf,o.pending-d,d)),0===f&&(o.status=ht)}else o.status=ht;if(o.status===ht&&(o.gzhead.hcrc?(o.pending+2>o.pending_buf_size&&s(t),o.pending+2<=o.pending_buf_size&&(l(o,255&t.adler),l(o,t.adler>>8&255),t.adler=0,o.status=dt)):o.status=dt),0!==o.pending){if(s(t),0===t.avail_out)return o.last_flush=-1,D}else if(0===t.avail_in&&n(e)<=n(a)&&e!==N)return i(t,F);if(o.status===ft&&0!==t.avail_in)return i(t,F);if(0!==t.avail_in||0!==o.lookahead||e!==Z&&o.status!==ft){var u=o.strategy===j?g(o,e):o.strategy===K?b(o,e):x[o.level].func(o,e);if(u!==ct&&u!==bt||(o.status=ft),u===_t||u===ct)return 0===t.avail_out&&(o.last_flush=-1),D;if(u===ut&&(e===R?B._tr_align(o):e!==O&&(B._tr_stored_block(o,0,0,!1),e===C&&(r(o.head),0===o.lookahead&&(o.strstart=0,o.block_start=0,o.insert=0))),s(t),0===t.avail_out))return o.last_flush=-1,D}return e!==N?D:o.wrap<=0?I:(2===o.wrap?(l(o,255&t.adler),l(o,t.adler>>8&255),l(o,t.adler>>16&255),l(o,t.adler>>24&255),l(o,255&t.total_in),l(o,t.total_in>>8&255),l(o,t.total_in>>16&255),l(o,t.total_in>>24&255)):(h(o,t.adler>>>16),h(o,65535&t.adler)),s(t),o.wrap>0&&(o.wrap=-o.wrap),0!==o.pending?D:I)},a.deflateEnd=function(t){var e;return t&&t.state?(e=t.state.status)!==rt&&e!==st&&e!==ot&&e!==lt&&e!==ht&&e!==dt&&e!==ft?i(t,U):(t.state=null,e===dt?i(t,T):D):U},a.deflateSetDictionary=function(t,e){var a,i,n,s,o,l,h,d,f=e.length;if(!t||!t.state)return U;if(a=t.state,2===(s=a.wrap)||1===s&&a.status!==rt||a.lookahead)return U;for(1===s&&(t.adler=S(t.adler,e,f,0)),a.wrap=0,f>=a.w_size&&(0===s&&(r(a.head),a.strstart=0,a.block_start=0,a.insert=0),d=new z.Buf8(a.w_size),z.arraySet(d,e,f-a.w_size,a.w_size,0),e=d,f=a.w_size),o=t.avail_in,l=t.next_in,h=t.input,t.avail_in=f,t.next_in=0,t.input=e,_(a);a.lookahead>=et;){i=a.strstart,n=a.lookahead-(et-1);do{a.ins_h=(a.ins_h<<a.hash_shift^a.window[i+et-1])&a.hash_mask,a.prev[i&a.w_mask]=a.head[a.ins_h],a.head[a.ins_h]=i,i++}while(--n);a.strstart=i,a.lookahead=et-1,_(a)}return a.strstart+=a.lookahead,a.block_start=a.strstart,a.insert=a.lookahead,a.lookahead=0,a.match_length=a.prev_length=et-1,a.match_available=0,t.next_in=l,t.input=h,t.avail_in=o,a.wrap=s,D},a.deflateInfo="pako deflate (from Nodeca project)"},{"../utils/common":3,"./adler32":5,"./crc32":7,"./messages":13,"./trees":14}],9:[function(t,e,a){"use strict";e.exports=function(){this.text=0,this.time=0,this.xflags=0,this.os=0,this.extra=null,this.extra_len=0,this.name="",this.comment="",this.hcrc=0,this.done=!1}},{}],10:[function(t,e,a){"use strict";e.exports=function(t,e){var a,i,n,r,s,o,l,h,d,f,_,u,c,b,g,m,w,p,v,k,y,x,z,B,S;a=t.state,i=t.next_in,B=t.input,n=i+(t.avail_in-5),r=t.next_out,S=t.output,s=r-(e-t.avail_out),o=r+(t.avail_out-257),l=a.dmax,h=a.wsize,d=a.whave,f=a.wnext,_=a.window,u=a.hold,c=a.bits,b=a.lencode,g=a.distcode,m=(1<<a.lenbits)-1,w=(1<<a.distbits)-1;t:do{c<15&&(u+=B[i++]<<c,c+=8,u+=B[i++]<<c,c+=8),p=b[u&m];e:for(;;){if(v=p>>>24,u>>>=v,c-=v,0===(v=p>>>16&255))S[r++]=65535&p;else{if(!(16&v)){if(0==(64&v)){p=b[(65535&p)+(u&(1<<v)-1)];continue e}if(32&v){a.mode=12;break t}t.msg="invalid literal/length code",a.mode=30;break t}k=65535&p,(v&=15)&&(c<v&&(u+=B[i++]<<c,c+=8),k+=u&(1<<v)-1,u>>>=v,c-=v),c<15&&(u+=B[i++]<<c,c+=8,u+=B[i++]<<c,c+=8),p=g[u&w];a:for(;;){if(v=p>>>24,u>>>=v,c-=v,!(16&(v=p>>>16&255))){if(0==(64&v)){p=g[(65535&p)+(u&(1<<v)-1)];continue a}t.msg="invalid distance code",a.mode=30;break t}if(y=65535&p,v&=15,c<v&&(u+=B[i++]<<c,(c+=8)<v&&(u+=B[i++]<<c,c+=8)),(y+=u&(1<<v)-1)>l){t.msg="invalid distance too far back",a.mode=30;break t}if(u>>>=v,c-=v,v=r-s,y>v){if((v=y-v)>d&&a.sane){t.msg="invalid distance too far back",a.mode=30;break t}if(x=0,z=_,0===f){if(x+=h-v,v<k){k-=v;do{S[r++]=_[x++]}while(--v);x=r-y,z=S}}else if(f<v){if(x+=h+f-v,(v-=f)<k){k-=v;do{S[r++]=_[x++]}while(--v);if(x=0,f<k){k-=v=f;do{S[r++]=_[x++]}while(--v);x=r-y,z=S}}}else if(x+=f-v,v<k){k-=v;do{S[r++]=_[x++]}while(--v);x=r-y,z=S}for(;k>2;)S[r++]=z[x++],S[r++]=z[x++],S[r++]=z[x++],k-=3;k&&(S[r++]=z[x++],k>1&&(S[r++]=z[x++]))}else{x=r-y;do{S[r++]=S[x++],S[r++]=S[x++],S[r++]=S[x++],k-=3}while(k>2);k&&(S[r++]=S[x++],k>1&&(S[r++]=S[x++]))}break}}break}}while(i<n&&r<o);i-=k=c>>3,u&=(1<<(c-=k<<3))-1,t.next_in=i,t.next_out=r,t.avail_in=i<n?n-i+5:5-(i-n),t.avail_out=r<o?o-r+257:257-(r-o),a.hold=u,a.bits=c}},{}],11:[function(t,e,a){"use strict";function i(t){return(t>>>24&255)+(t>>>8&65280)+((65280&t)<<8)+((255&t)<<24)}function n(){this.mode=0,this.last=!1,this.wrap=0,this.havedict=!1,this.flags=0,this.dmax=0,this.check=0,this.total=0,this.head=null,this.wbits=0,this.wsize=0,this.whave=0,this.wnext=0,this.window=null,this.hold=0,this.bits=0,this.length=0,this.offset=0,this.extra=0,this.lencode=null,this.distcode=null,this.lenbits=0,this.distbits=0,this.ncode=0,this.nlen=0,this.ndist=0,this.have=0,this.next=null,this.lens=new u.Buf16(320),this.work=new u.Buf16(288),this.lendyn=null,this.distdyn=null,this.sane=0,this.back=0,this.was=0}function r(t){var e;return t&&t.state?(e=t.state,t.total_in=t.total_out=e.total=0,t.msg="",e.wrap&&(t.adler=1&e.wrap),e.mode=N,e.last=0,e.havedict=0,e.dmax=32768,e.head=null,e.hold=0,e.bits=0,e.lencode=e.lendyn=new u.Buf32(dt),e.distcode=e.distdyn=new u.Buf32(ft),e.sane=1,e.back=-1,z):E}function s(t){var e;return t&&t.state?(e=t.state,e.wsize=0,e.whave=0,e.wnext=0,r(t)):E}function o(t,e){var a,i;return t&&t.state?(i=t.state,e<0?(a=0,e=-e):(a=1+(e>>4),e<48&&(e&=15)),e&&(e<8||e>15)?E:(null!==i.window&&i.wbits!==e&&(i.window=null),i.wrap=a,i.wbits=e,s(t))):E}function l(t,e){var a,i;return t?(i=new n,t.state=i,i.window=null,(a=o(t,e))!==z&&(t.state=null),a):E}function h(t){if(ut){var e;for(f=new u.Buf32(512),_=new u.Buf32(32),e=0;e<144;)t.lens[e++]=8;for(;e<256;)t.lens[e++]=9;for(;e<280;)t.lens[e++]=7;for(;e<288;)t.lens[e++]=8;for(m(p,t.lens,0,288,f,0,t.work,{bits:9}),e=0;e<32;)t.lens[e++]=5;m(v,t.lens,0,32,_,0,t.work,{bits:5}),ut=!1}t.lencode=f,t.lenbits=9,t.distcode=_,t.distbits=5}function d(t,e,a,i){var n,r=t.state;return null===r.window&&(r.wsize=1<<r.wbits,r.wnext=0,r.whave=0,r.window=new u.Buf8(r.wsize)),i>=r.wsize?(u.arraySet(r.window,e,a-r.wsize,r.wsize,0),r.wnext=0,r.whave=r.wsize):((n=r.wsize-r.wnext)>i&&(n=i),u.arraySet(r.window,e,a-i,n,r.wnext),(i-=n)?(u.arraySet(r.window,e,a-i,i,0),r.wnext=i,r.whave=r.wsize):(r.wnext+=n,r.wnext===r.wsize&&(r.wnext=0),r.whave<r.wsize&&(r.whave+=n))),0}var f,_,u=t("../utils/common"),c=t("./adler32"),b=t("./crc32"),g=t("./inffast"),m=t("./inftrees"),w=0,p=1,v=2,k=4,y=5,x=6,z=0,B=1,S=2,E=-2,A=-3,Z=-4,R=-5,C=8,N=1,O=2,D=3,I=4,U=5,T=6,F=7,L=8,H=9,j=10,K=11,M=12,P=13,Y=14,q=15,G=16,X=17,W=18,J=19,Q=20,V=21,$=22,tt=23,et=24,at=25,it=26,nt=27,rt=28,st=29,ot=30,lt=31,ht=32,dt=852,ft=592,_t=15,ut=!0;a.inflateReset=s,a.inflateReset2=o,a.inflateResetKeep=r,a.inflateInit=function(t){return l(t,_t)},a.inflateInit2=l,a.inflate=function(t,e){var a,n,r,s,o,l,f,_,dt,ft,_t,ut,ct,bt,gt,mt,wt,pt,vt,kt,yt,xt,zt,Bt,St=0,Et=new u.Buf8(4),At=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15];if(!t||!t.state||!t.output||!t.input&&0!==t.avail_in)return E;(a=t.state).mode===M&&(a.mode=P),o=t.next_out,r=t.output,f=t.avail_out,s=t.next_in,n=t.input,l=t.avail_in,_=a.hold,dt=a.bits,ft=l,_t=f,xt=z;t:for(;;)switch(a.mode){case N:if(0===a.wrap){a.mode=P;break}for(;dt<16;){if(0===l)break t;l--,_+=n[s++]<<dt,dt+=8}if(2&a.wrap&&35615===_){a.check=0,Et[0]=255&_,Et[1]=_>>>8&255,a.check=b(a.check,Et,2,0),_=0,dt=0,a.mode=O;break}if(a.flags=0,a.head&&(a.head.done=!1),!(1&a.wrap)||(((255&_)<<8)+(_>>8))%31){t.msg="incorrect header check",a.mode=ot;break}if((15&_)!==C){t.msg="unknown compression method",a.mode=ot;break}if(_>>>=4,dt-=4,yt=8+(15&_),0===a.wbits)a.wbits=yt;else if(yt>a.wbits){t.msg="invalid window size",a.mode=ot;break}a.dmax=1<<yt,t.adler=a.check=1,a.mode=512&_?j:M,_=0,dt=0;break;case O:for(;dt<16;){if(0===l)break t;l--,_+=n[s++]<<dt,dt+=8}if(a.flags=_,(255&a.flags)!==C){t.msg="unknown compression method",a.mode=ot;break}if(57344&a.flags){t.msg="unknown header flags set",a.mode=ot;break}a.head&&(a.head.text=_>>8&1),512&a.flags&&(Et[0]=255&_,Et[1]=_>>>8&255,a.check=b(a.check,Et,2,0)),_=0,dt=0,a.mode=D;case D:for(;dt<32;){if(0===l)break t;l--,_+=n[s++]<<dt,dt+=8}a.head&&(a.head.time=_),512&a.flags&&(Et[0]=255&_,Et[1]=_>>>8&255,Et[2]=_>>>16&255,Et[3]=_>>>24&255,a.check=b(a.check,Et,4,0)),_=0,dt=0,a.mode=I;case I:for(;dt<16;){if(0===l)break t;l--,_+=n[s++]<<dt,dt+=8}a.head&&(a.head.xflags=255&_,a.head.os=_>>8),512&a.flags&&(Et[0]=255&_,Et[1]=_>>>8&255,a.check=b(a.check,Et,2,0)),_=0,dt=0,a.mode=U;case U:if(1024&a.flags){for(;dt<16;){if(0===l)break t;l--,_+=n[s++]<<dt,dt+=8}a.length=_,a.head&&(a.head.extra_len=_),512&a.flags&&(Et[0]=255&_,Et[1]=_>>>8&255,a.check=b(a.check,Et,2,0)),_=0,dt=0}else a.head&&(a.head.extra=null);a.mode=T;case T:if(1024&a.flags&&((ut=a.length)>l&&(ut=l),ut&&(a.head&&(yt=a.head.extra_len-a.length,a.head.extra||(a.head.extra=new Array(a.head.extra_len)),u.arraySet(a.head.extra,n,s,ut,yt)),512&a.flags&&(a.check=b(a.check,n,ut,s)),l-=ut,s+=ut,a.length-=ut),a.length))break t;a.length=0,a.mode=F;case F:if(2048&a.flags){if(0===l)break t;ut=0;do{yt=n[s+ut++],a.head&&yt&&a.length<65536&&(a.head.name+=String.fromCharCode(yt))}while(yt&&ut<l);if(512&a.flags&&(a.check=b(a.check,n,ut,s)),l-=ut,s+=ut,yt)break t}else a.head&&(a.head.name=null);a.length=0,a.mode=L;case L:if(4096&a.flags){if(0===l)break t;ut=0;do{yt=n[s+ut++],a.head&&yt&&a.length<65536&&(a.head.comment+=String.fromCharCode(yt))}while(yt&&ut<l);if(512&a.flags&&(a.check=b(a.check,n,ut,s)),l-=ut,s+=ut,yt)break t}else a.head&&(a.head.comment=null);a.mode=H;case H:if(512&a.flags){for(;dt<16;){if(0===l)break t;l--,_+=n[s++]<<dt,dt+=8}if(_!==(65535&a.check)){t.msg="header crc mismatch",a.mode=ot;break}_=0,dt=0}a.head&&(a.head.hcrc=a.flags>>9&1,a.head.done=!0),t.adler=a.check=0,a.mode=M;break;case j:for(;dt<32;){if(0===l)break t;l--,_+=n[s++]<<dt,dt+=8}t.adler=a.check=i(_),_=0,dt=0,a.mode=K;case K:if(0===a.havedict)return t.next_out=o,t.avail_out=f,t.next_in=s,t.avail_in=l,a.hold=_,a.bits=dt,S;t.adler=a.check=1,a.mode=M;case M:if(e===y||e===x)break t;case P:if(a.last){_>>>=7&dt,dt-=7&dt,a.mode=nt;break}for(;dt<3;){if(0===l)break t;l--,_+=n[s++]<<dt,dt+=8}switch(a.last=1&_,_>>>=1,dt-=1,3&_){case 0:a.mode=Y;break;case 1:if(h(a),a.mode=Q,e===x){_>>>=2,dt-=2;break t}break;case 2:a.mode=X;break;case 3:t.msg="invalid block type",a.mode=ot}_>>>=2,dt-=2;break;case Y:for(_>>>=7&dt,dt-=7&dt;dt<32;){if(0===l)break t;l--,_+=n[s++]<<dt,dt+=8}if((65535&_)!=(_>>>16^65535)){t.msg="invalid stored block lengths",a.mode=ot;break}if(a.length=65535&_,_=0,dt=0,a.mode=q,e===x)break t;case q:a.mode=G;case G:if(ut=a.length){if(ut>l&&(ut=l),ut>f&&(ut=f),0===ut)break t;u.arraySet(r,n,s,ut,o),l-=ut,s+=ut,f-=ut,o+=ut,a.length-=ut;break}a.mode=M;break;case X:for(;dt<14;){if(0===l)break t;l--,_+=n[s++]<<dt,dt+=8}if(a.nlen=257+(31&_),_>>>=5,dt-=5,a.ndist=1+(31&_),_>>>=5,dt-=5,a.ncode=4+(15&_),_>>>=4,dt-=4,a.nlen>286||a.ndist>30){t.msg="too many length or distance symbols",a.mode=ot;break}a.have=0,a.mode=W;case W:for(;a.have<a.ncode;){for(;dt<3;){if(0===l)break t;l--,_+=n[s++]<<dt,dt+=8}a.lens[At[a.have++]]=7&_,_>>>=3,dt-=3}for(;a.have<19;)a.lens[At[a.have++]]=0;if(a.lencode=a.lendyn,a.lenbits=7,zt={bits:a.lenbits},xt=m(w,a.lens,0,19,a.lencode,0,a.work,zt),a.lenbits=zt.bits,xt){t.msg="invalid code lengths set",a.mode=ot;break}a.have=0,a.mode=J;case J:for(;a.have<a.nlen+a.ndist;){for(;St=a.lencode[_&(1<<a.lenbits)-1],gt=St>>>24,mt=St>>>16&255,wt=65535&St,!(gt<=dt);){if(0===l)break t;l--,_+=n[s++]<<dt,dt+=8}if(wt<16)_>>>=gt,dt-=gt,a.lens[a.have++]=wt;else{if(16===wt){for(Bt=gt+2;dt<Bt;){if(0===l)break t;l--,_+=n[s++]<<dt,dt+=8}if(_>>>=gt,dt-=gt,0===a.have){t.msg="invalid bit length repeat",a.mode=ot;break}yt=a.lens[a.have-1],ut=3+(3&_),_>>>=2,dt-=2}else if(17===wt){for(Bt=gt+3;dt<Bt;){if(0===l)break t;l--,_+=n[s++]<<dt,dt+=8}dt-=gt,yt=0,ut=3+(7&(_>>>=gt)),_>>>=3,dt-=3}else{for(Bt=gt+7;dt<Bt;){if(0===l)break t;l--,_+=n[s++]<<dt,dt+=8}dt-=gt,yt=0,ut=11+(127&(_>>>=gt)),_>>>=7,dt-=7}if(a.have+ut>a.nlen+a.ndist){t.msg="invalid bit length repeat",a.mode=ot;break}for(;ut--;)a.lens[a.have++]=yt}}if(a.mode===ot)break;if(0===a.lens[256]){t.msg="invalid code -- missing end-of-block",a.mode=ot;break}if(a.lenbits=9,zt={bits:a.lenbits},xt=m(p,a.lens,0,a.nlen,a.lencode,0,a.work,zt),a.lenbits=zt.bits,xt){t.msg="invalid literal/lengths set",a.mode=ot;break}if(a.distbits=6,a.distcode=a.distdyn,zt={bits:a.distbits},xt=m(v,a.lens,a.nlen,a.ndist,a.distcode,0,a.work,zt),a.distbits=zt.bits,xt){t.msg="invalid distances set",a.mode=ot;break}if(a.mode=Q,e===x)break t;case Q:a.mode=V;case V:if(l>=6&&f>=258){t.next_out=o,t.avail_out=f,t.next_in=s,t.avail_in=l,a.hold=_,a.bits=dt,g(t,_t),o=t.next_out,r=t.output,f=t.avail_out,s=t.next_in,n=t.input,l=t.avail_in,_=a.hold,dt=a.bits,a.mode===M&&(a.back=-1);break}for(a.back=0;St=a.lencode[_&(1<<a.lenbits)-1],gt=St>>>24,mt=St>>>16&255,wt=65535&St,!(gt<=dt);){if(0===l)break t;l--,_+=n[s++]<<dt,dt+=8}if(mt&&0==(240&mt)){for(pt=gt,vt=mt,kt=wt;St=a.lencode[kt+((_&(1<<pt+vt)-1)>>pt)],gt=St>>>24,mt=St>>>16&255,wt=65535&St,!(pt+gt<=dt);){if(0===l)break t;l--,_+=n[s++]<<dt,dt+=8}_>>>=pt,dt-=pt,a.back+=pt}if(_>>>=gt,dt-=gt,a.back+=gt,a.length=wt,0===mt){a.mode=it;break}if(32&mt){a.back=-1,a.mode=M;break}if(64&mt){t.msg="invalid literal/length code",a.mode=ot;break}a.extra=15&mt,a.mode=$;case $:if(a.extra){for(Bt=a.extra;dt<Bt;){if(0===l)break t;l--,_+=n[s++]<<dt,dt+=8}a.length+=_&(1<<a.extra)-1,_>>>=a.extra,dt-=a.extra,a.back+=a.extra}a.was=a.length,a.mode=tt;case tt:for(;St=a.distcode[_&(1<<a.distbits)-1],gt=St>>>24,mt=St>>>16&255,wt=65535&St,!(gt<=dt);){if(0===l)break t;l--,_+=n[s++]<<dt,dt+=8}if(0==(240&mt)){for(pt=gt,vt=mt,kt=wt;St=a.distcode[kt+((_&(1<<pt+vt)-1)>>pt)],gt=St>>>24,mt=St>>>16&255,wt=65535&St,!(pt+gt<=dt);){if(0===l)break t;l--,_+=n[s++]<<dt,dt+=8}_>>>=pt,dt-=pt,a.back+=pt}if(_>>>=gt,dt-=gt,a.back+=gt,64&mt){t.msg="invalid distance code",a.mode=ot;break}a.offset=wt,a.extra=15&mt,a.mode=et;case et:if(a.extra){for(Bt=a.extra;dt<Bt;){if(0===l)break t;l--,_+=n[s++]<<dt,dt+=8}a.offset+=_&(1<<a.extra)-1,_>>>=a.extra,dt-=a.extra,a.back+=a.extra}if(a.offset>a.dmax){t.msg="invalid distance too far back",a.mode=ot;break}a.mode=at;case at:if(0===f)break t;if(ut=_t-f,a.offset>ut){if((ut=a.offset-ut)>a.whave&&a.sane){t.msg="invalid distance too far back",a.mode=ot;break}ut>a.wnext?(ut-=a.wnext,ct=a.wsize-ut):ct=a.wnext-ut,ut>a.length&&(ut=a.length),bt=a.window}else bt=r,ct=o-a.offset,ut=a.length;ut>f&&(ut=f),f-=ut,a.length-=ut;do{r[o++]=bt[ct++]}while(--ut);0===a.length&&(a.mode=V);break;case it:if(0===f)break t;r[o++]=a.length,f--,a.mode=V;break;case nt:if(a.wrap){for(;dt<32;){if(0===l)break t;l--,_|=n[s++]<<dt,dt+=8}if(_t-=f,t.total_out+=_t,a.total+=_t,_t&&(t.adler=a.check=a.flags?b(a.check,r,_t,o-_t):c(a.check,r,_t,o-_t)),_t=f,(a.flags?_:i(_))!==a.check){t.msg="incorrect data check",a.mode=ot;break}_=0,dt=0}a.mode=rt;case rt:if(a.wrap&&a.flags){for(;dt<32;){if(0===l)break t;l--,_+=n[s++]<<dt,dt+=8}if(_!==(4294967295&a.total)){t.msg="incorrect length check",a.mode=ot;break}_=0,dt=0}a.mode=st;case st:xt=B;break t;case ot:xt=A;break t;case lt:return Z;case ht:default:return E}return t.next_out=o,t.avail_out=f,t.next_in=s,t.avail_in=l,a.hold=_,a.bits=dt,(a.wsize||_t!==t.avail_out&&a.mode<ot&&(a.mode<nt||e!==k))&&d(t,t.output,t.next_out,_t-t.avail_out)?(a.mode=lt,Z):(ft-=t.avail_in,_t-=t.avail_out,t.total_in+=ft,t.total_out+=_t,a.total+=_t,a.wrap&&_t&&(t.adler=a.check=a.flags?b(a.check,r,_t,t.next_out-_t):c(a.check,r,_t,t.next_out-_t)),t.data_type=a.bits+(a.last?64:0)+(a.mode===M?128:0)+(a.mode===Q||a.mode===q?256:0),(0===ft&&0===_t||e===k)&&xt===z&&(xt=R),xt)},a.inflateEnd=function(t){if(!t||!t.state)return E;var e=t.state;return e.window&&(e.window=null),t.state=null,z},a.inflateGetHeader=function(t,e){var a;return t&&t.state?0==(2&(a=t.state).wrap)?E:(a.head=e,e.done=!1,z):E},a.inflateSetDictionary=function(t,e){var a,i,n=e.length;return t&&t.state?0!==(a=t.state).wrap&&a.mode!==K?E:a.mode===K&&(i=1,(i=c(i,e,n,0))!==a.check)?A:d(t,e,n,n)?(a.mode=lt,Z):(a.havedict=1,z):E},a.inflateInfo="pako inflate (from Nodeca project)"},{"../utils/common":3,"./adler32":5,"./crc32":7,"./inffast":10,"./inftrees":12}],12:[function(t,e,a){"use strict";var i=t("../utils/common"),n=[3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,0,0],r=[16,16,16,16,16,16,16,16,17,17,17,17,18,18,18,18,19,19,19,19,20,20,20,20,21,21,21,21,16,72,78],s=[1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0],o=[16,16,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24,25,25,26,26,27,27,28,28,29,29,64,64];e.exports=function(t,e,a,l,h,d,f,_){var u,c,b,g,m,w,p,v,k,y=_.bits,x=0,z=0,B=0,S=0,E=0,A=0,Z=0,R=0,C=0,N=0,O=null,D=0,I=new i.Buf16(16),U=new i.Buf16(16),T=null,F=0;for(x=0;x<=15;x++)I[x]=0;for(z=0;z<l;z++)I[e[a+z]]++;for(E=y,S=15;S>=1&&0===I[S];S--);if(E>S&&(E=S),0===S)return h[d++]=20971520,h[d++]=20971520,_.bits=1,0;for(B=1;B<S&&0===I[B];B++);for(E<B&&(E=B),R=1,x=1;x<=15;x++)if(R<<=1,(R-=I[x])<0)return-1;if(R>0&&(0===t||1!==S))return-1;for(U[1]=0,x=1;x<15;x++)U[x+1]=U[x]+I[x];for(z=0;z<l;z++)0!==e[a+z]&&(f[U[e[a+z]]++]=z);if(0===t?(O=T=f,w=19):1===t?(O=n,D-=257,T=r,F-=257,w=256):(O=s,T=o,w=-1),N=0,z=0,x=B,m=d,A=E,Z=0,b=-1,C=1<<E,g=C-1,1===t&&C>852||2===t&&C>592)return 1;for(;;){p=x-Z,f[z]<w?(v=0,k=f[z]):f[z]>w?(v=T[F+f[z]],k=O[D+f[z]]):(v=96,k=0),u=1<<x-Z,B=c=1<<A;do{h[m+(N>>Z)+(c-=u)]=p<<24|v<<16|k|0}while(0!==c);for(u=1<<x-1;N&u;)u>>=1;if(0!==u?(N&=u-1,N+=u):N=0,z++,0==--I[x]){if(x===S)break;x=e[a+f[z]]}if(x>E&&(N&g)!==b){for(0===Z&&(Z=E),m+=B,R=1<<(A=x-Z);A+Z<S&&!((R-=I[A+Z])<=0);)A++,R<<=1;if(C+=1<<A,1===t&&C>852||2===t&&C>592)return 1;h[b=N&g]=E<<24|A<<16|m-d|0}}return 0!==N&&(h[m+N]=x-Z<<24|64<<16|0),_.bits=E,0}},{"../utils/common":3}],13:[function(t,e,a){"use strict";e.exports={2:"need dictionary",1:"stream end",0:"","-1":"file error","-2":"stream error","-3":"data error","-4":"insufficient memory","-5":"buffer error","-6":"incompatible version"}},{}],14:[function(t,e,a){"use strict";function i(t){for(var e=t.length;--e>=0;)t[e]=0}function n(t,e,a,i,n){this.static_tree=t,this.extra_bits=e,this.extra_base=a,this.elems=i,this.max_length=n,this.has_stree=t&&t.length}function r(t,e){this.dyn_tree=t,this.max_code=0,this.stat_desc=e}function s(t){return t<256?et[t]:et[256+(t>>>7)]}function o(t,e){t.pending_buf[t.pending++]=255&e,t.pending_buf[t.pending++]=e>>>8&255}function l(t,e,a){t.bi_valid>M-a?(t.bi_buf|=e<<t.bi_valid&65535,o(t,t.bi_buf),t.bi_buf=e>>M-t.bi_valid,t.bi_valid+=a-M):(t.bi_buf|=e<<t.bi_valid&65535,t.bi_valid+=a)}function h(t,e,a){l(t,a[2*e],a[2*e+1])}function d(t,e){var a=0;do{a|=1&t,t>>>=1,a<<=1}while(--e>0);return a>>>1}function f(t){16===t.bi_valid?(o(t,t.bi_buf),t.bi_buf=0,t.bi_valid=0):t.bi_valid>=8&&(t.pending_buf[t.pending++]=255&t.bi_buf,t.bi_buf>>=8,t.bi_valid-=8)}function _(t,e){var a,i,n,r,s,o,l=e.dyn_tree,h=e.max_code,d=e.stat_desc.static_tree,f=e.stat_desc.has_stree,_=e.stat_desc.extra_bits,u=e.stat_desc.extra_base,c=e.stat_desc.max_length,b=0;for(r=0;r<=K;r++)t.bl_count[r]=0;for(l[2*t.heap[t.heap_max]+1]=0,a=t.heap_max+1;a<j;a++)(r=l[2*l[2*(i=t.heap[a])+1]+1]+1)>c&&(r=c,b++),l[2*i+1]=r,i>h||(t.bl_count[r]++,s=0,i>=u&&(s=_[i-u]),o=l[2*i],t.opt_len+=o*(r+s),f&&(t.static_len+=o*(d[2*i+1]+s)));if(0!==b){do{for(r=c-1;0===t.bl_count[r];)r--;t.bl_count[r]--,t.bl_count[r+1]+=2,t.bl_count[c]--,b-=2}while(b>0);for(r=c;0!==r;r--)for(i=t.bl_count[r];0!==i;)(n=t.heap[--a])>h||(l[2*n+1]!==r&&(t.opt_len+=(r-l[2*n+1])*l[2*n],l[2*n+1]=r),i--)}}function u(t,e,a){var i,n,r=new Array(K+1),s=0;for(i=1;i<=K;i++)r[i]=s=s+a[i-1]<<1;for(n=0;n<=e;n++){var o=t[2*n+1];0!==o&&(t[2*n]=d(r[o]++,o))}}function c(){var t,e,a,i,r,s=new Array(K+1);for(a=0,i=0;i<U-1;i++)for(it[i]=a,t=0;t<1<<W[i];t++)at[a++]=i;for(at[a-1]=i,r=0,i=0;i<16;i++)for(nt[i]=r,t=0;t<1<<J[i];t++)et[r++]=i;for(r>>=7;i<L;i++)for(nt[i]=r<<7,t=0;t<1<<J[i]-7;t++)et[256+r++]=i;for(e=0;e<=K;e++)s[e]=0;for(t=0;t<=143;)$[2*t+1]=8,t++,s[8]++;for(;t<=255;)$[2*t+1]=9,t++,s[9]++;for(;t<=279;)$[2*t+1]=7,t++,s[7]++;for(;t<=287;)$[2*t+1]=8,t++,s[8]++;for(u($,F+1,s),t=0;t<L;t++)tt[2*t+1]=5,tt[2*t]=d(t,5);rt=new n($,W,T+1,F,K),st=new n(tt,J,0,L,K),ot=new n(new Array(0),Q,0,H,P)}function b(t){var e;for(e=0;e<F;e++)t.dyn_ltree[2*e]=0;for(e=0;e<L;e++)t.dyn_dtree[2*e]=0;for(e=0;e<H;e++)t.bl_tree[2*e]=0;t.dyn_ltree[2*Y]=1,t.opt_len=t.static_len=0,t.last_lit=t.matches=0}function g(t){t.bi_valid>8?o(t,t.bi_buf):t.bi_valid>0&&(t.pending_buf[t.pending++]=t.bi_buf),t.bi_buf=0,t.bi_valid=0}function m(t,e,a,i){g(t),i&&(o(t,a),o(t,~a)),A.arraySet(t.pending_buf,t.window,e,a,t.pending),t.pending+=a}function w(t,e,a,i){var n=2*e,r=2*a;return t[n]<t[r]||t[n]===t[r]&&i[e]<=i[a]}function p(t,e,a){for(var i=t.heap[a],n=a<<1;n<=t.heap_len&&(n<t.heap_len&&w(e,t.heap[n+1],t.heap[n],t.depth)&&n++,!w(e,i,t.heap[n],t.depth));)t.heap[a]=t.heap[n],a=n,n<<=1;t.heap[a]=i}function v(t,e,a){var i,n,r,o,d=0;if(0!==t.last_lit)do{i=t.pending_buf[t.d_buf+2*d]<<8|t.pending_buf[t.d_buf+2*d+1],n=t.pending_buf[t.l_buf+d],d++,0===i?h(t,n,e):(h(t,(r=at[n])+T+1,e),0!==(o=W[r])&&l(t,n-=it[r],o),h(t,r=s(--i),a),0!==(o=J[r])&&l(t,i-=nt[r],o))}while(d<t.last_lit);h(t,Y,e)}function k(t,e){var a,i,n,r=e.dyn_tree,s=e.stat_desc.static_tree,o=e.stat_desc.has_stree,l=e.stat_desc.elems,h=-1;for(t.heap_len=0,t.heap_max=j,a=0;a<l;a++)0!==r[2*a]?(t.heap[++t.heap_len]=h=a,t.depth[a]=0):r[2*a+1]=0;for(;t.heap_len<2;)r[2*(n=t.heap[++t.heap_len]=h<2?++h:0)]=1,t.depth[n]=0,t.opt_len--,o&&(t.static_len-=s[2*n+1]);for(e.max_code=h,a=t.heap_len>>1;a>=1;a--)p(t,r,a);n=l;do{a=t.heap[1],t.heap[1]=t.heap[t.heap_len--],p(t,r,1),i=t.heap[1],t.heap[--t.heap_max]=a,t.heap[--t.heap_max]=i,r[2*n]=r[2*a]+r[2*i],t.depth[n]=(t.depth[a]>=t.depth[i]?t.depth[a]:t.depth[i])+1,r[2*a+1]=r[2*i+1]=n,t.heap[1]=n++,p(t,r,1)}while(t.heap_len>=2);t.heap[--t.heap_max]=t.heap[1],_(t,e),u(r,h,t.bl_count)}function y(t,e,a){var i,n,r=-1,s=e[1],o=0,l=7,h=4;for(0===s&&(l=138,h=3),e[2*(a+1)+1]=65535,i=0;i<=a;i++)n=s,s=e[2*(i+1)+1],++o<l&&n===s||(o<h?t.bl_tree[2*n]+=o:0!==n?(n!==r&&t.bl_tree[2*n]++,t.bl_tree[2*q]++):o<=10?t.bl_tree[2*G]++:t.bl_tree[2*X]++,o=0,r=n,0===s?(l=138,h=3):n===s?(l=6,h=3):(l=7,h=4))}function x(t,e,a){var i,n,r=-1,s=e[1],o=0,d=7,f=4;for(0===s&&(d=138,f=3),i=0;i<=a;i++)if(n=s,s=e[2*(i+1)+1],!(++o<d&&n===s)){if(o<f)do{h(t,n,t.bl_tree)}while(0!=--o);else 0!==n?(n!==r&&(h(t,n,t.bl_tree),o--),h(t,q,t.bl_tree),l(t,o-3,2)):o<=10?(h(t,G,t.bl_tree),l(t,o-3,3)):(h(t,X,t.bl_tree),l(t,o-11,7));o=0,r=n,0===s?(d=138,f=3):n===s?(d=6,f=3):(d=7,f=4)}}function z(t){var e;for(y(t,t.dyn_ltree,t.l_desc.max_code),y(t,t.dyn_dtree,t.d_desc.max_code),k(t,t.bl_desc),e=H-1;e>=3&&0===t.bl_tree[2*V[e]+1];e--);return t.opt_len+=3*(e+1)+5+5+4,e}function B(t,e,a,i){var n;for(l(t,e-257,5),l(t,a-1,5),l(t,i-4,4),n=0;n<i;n++)l(t,t.bl_tree[2*V[n]+1],3);x(t,t.dyn_ltree,e-1),x(t,t.dyn_dtree,a-1)}function S(t){var e,a=4093624447;for(e=0;e<=31;e++,a>>>=1)if(1&a&&0!==t.dyn_ltree[2*e])return R;if(0!==t.dyn_ltree[18]||0!==t.dyn_ltree[20]||0!==t.dyn_ltree[26])return C;for(e=32;e<T;e++)if(0!==t.dyn_ltree[2*e])return C;return R}function E(t,e,a,i){l(t,(O<<1)+(i?1:0),3),m(t,e,a,!0)}var A=t("../utils/common"),Z=4,R=0,C=1,N=2,O=0,D=1,I=2,U=29,T=256,F=T+1+U,L=30,H=19,j=2*F+1,K=15,M=16,P=7,Y=256,q=16,G=17,X=18,W=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0],J=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13],Q=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7],V=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],$=new Array(2*(F+2));i($);var tt=new Array(2*L);i(tt);var et=new Array(512);i(et);var at=new Array(256);i(at);var it=new Array(U);i(it);var nt=new Array(L);i(nt);var rt,st,ot,lt=!1;a._tr_init=function(t){lt||(c(),lt=!0),t.l_desc=new r(t.dyn_ltree,rt),t.d_desc=new r(t.dyn_dtree,st),t.bl_desc=new r(t.bl_tree,ot),t.bi_buf=0,t.bi_valid=0,b(t)},a._tr_stored_block=E,a._tr_flush_block=function(t,e,a,i){var n,r,s=0;t.level>0?(t.strm.data_type===N&&(t.strm.data_type=S(t)),k(t,t.l_desc),k(t,t.d_desc),s=z(t),n=t.opt_len+3+7>>>3,(r=t.static_len+3+7>>>3)<=n&&(n=r)):n=r=a+5,a+4<=n&&-1!==e?E(t,e,a,i):t.strategy===Z||r===n?(l(t,(D<<1)+(i?1:0),3),v(t,$,tt)):(l(t,(I<<1)+(i?1:0),3),B(t,t.l_desc.max_code+1,t.d_desc.max_code+1,s+1),v(t,t.dyn_ltree,t.dyn_dtree)),b(t),i&&g(t)},a._tr_tally=function(t,e,a){return t.pending_buf[t.d_buf+2*t.last_lit]=e>>>8&255,t.pending_buf[t.d_buf+2*t.last_lit+1]=255&e,t.pending_buf[t.l_buf+t.last_lit]=255&a,t.last_lit++,0===e?t.dyn_ltree[2*a]++:(t.matches++,e--,t.dyn_ltree[2*(at[a]+T+1)]++,t.dyn_dtree[2*s(e)]++),t.last_lit===t.lit_bufsize-1},a._tr_align=function(t){l(t,D<<1,3),h(t,Y,$),f(t)}},{"../utils/common":3}],15:[function(t,e,a){"use strict";e.exports=function(){this.input=null,this.next_in=0,this.avail_in=0,this.total_in=0,this.output=null,this.next_out=0,this.avail_out=0,this.total_out=0,this.msg="",this.state=null,this.data_type=2,this.adler=0}},{}],"/":[function(t,e,a){"use strict";var i={};(0,t("./lib/utils/common").assign)(i,t("./lib/deflate"),t("./lib/inflate"),t("./lib/zlib/constants")),e.exports=i},{"./lib/deflate":1,"./lib/inflate":2,"./lib/utils/common":3,"./lib/zlib/constants":6}]},{},[])("/")}); diff --git a/web/netdata-swagger.json b/web/netdata-swagger.json index 404944d1..066ea832 100644 --- a/web/netdata-swagger.json +++ b/web/netdata-swagger.json @@ -314,6 +314,7 @@ "enum": [ "abs", "absolute", + "display-absolute", "absolute-sum", "null2zero", "percentage", diff --git a/web/netdata-swagger.yaml b/web/netdata-swagger.yaml index a74d66f5..ee9d243b 100644 --- a/web/netdata-swagger.yaml +++ b/web/netdata-swagger.yaml @@ -204,7 +204,7 @@ paths: type: array items: type: string - enum: [ 'abs', 'absolute', 'absolute-sum', 'null2zero', 'percentage', 'unaligned' ] + enum: [ 'abs', 'absolute', 'display-absolute', 'absolute-sum', 'null2zero', 'percentage', 'unaligned' ] collectionFormat: pipes default: ['absolute'] allowEmptyValue: true diff --git a/web/version.txt b/web/version.txt index 4d343be3..29b6c3bc 100644 --- a/web/version.txt +++ b/web/version.txt @@ -1 +1 @@ -89ed309252981ddd50f697fde4fe93019cb3e652 +8e3e6627ccd97959d64bbb4df1f377a39c0e753f |