Merge branch 'feature/service-overview-4178'

fixes #4178
fixes #4179
This commit is contained in:
Marius Hein 2013-07-22 16:45:39 +02:00
commit a98e88c45e
117 changed files with 11107 additions and 2703 deletions

View File

@ -24,10 +24,15 @@
<? if (isset($_GET['iframe']) && $_GET['iframe'] === 'true'): ?>
<base target="_parent" />
<? endif ?>
<script src="<?= $this->baseUrl('js/vendor/modernizr-2.6.2.min.js') ?>"></script>
<link rel="stylesheet" href="<?= $this->baseUrl('css/icinga.css') ?>">
<link rel="stylesheet" href="<?= $this->baseUrl('css/vendor/bootstrap-responsive.min.css') ?>">
<script data-main="<?= $this->baseUrl('js/main.js')?>" src="<?= $this->baseUrl('js/vendor/require.js') ?>"></script>
<script src="<?php echo $this->baseUrl('js/vendor/modernizr-2.6.2.min.js') ?>"></script>
<link rel="stylesheet" href="<?php echo $this->baseUrl('css.php') ?>">
<link rel="stylesheet" href="<?php echo $this->baseUrl('css/vendor/bootstrap-responsive.min.css') ?>">
<link rel="stylesheet" href="<?php echo $this->baseUrl('css/vendor/font-awesome.min.css') ?>">
<!--[if IE 7]>
<link rel="stylesheet" href="<?php echo $this->baseUrl('css/vendor/font-awesome-ie7.min.css') ?>">
<![endif]-->
<script data-main="<?php echo $this->baseUrl('js/main.js')?>" src="<?php echo $this->baseUrl('js/vendor/require.js') ?>"></script>
</head>
<body class="cranberry">

View File

@ -4,6 +4,15 @@ class Zend_View_Helper_TimeSince extends Zend_View_Helper_Abstract
{
public function timeSince($timestamp)
{
if (!is_numeric($timestamp)) {
$timestamp = strtotime($timestamp);
}
if (!is_numeric($timestamp)) {
return '?';
}
if (! $timestamp) return '-';
$duration = time() - $timestamp;
$prefix = '';
@ -33,4 +42,3 @@ class Zend_View_Helper_TimeSince extends Zend_View_Helper_Abstract
return floor($hour / 24) . 'd ' . ($hour % 24) . 'h';
}
}

View File

@ -23,7 +23,7 @@ $title_next = sprintf(
<ul>
<!-- Previous page link -->
<?php if (isset($this->previous)): ?>
<li><a href="<?= $this->url()->setParam('page', $this->previous) ?>" title="<?= $titleprev ?>">« <?= $this->translate('Back') ?></a></li>
<li><a href="<?= $this->url()->setParam('page', $this->previous) ?>" title="<?= $title_prev ?>">« <?= $this->translate('Back') ?></a></li>
<?php else: ?>
<li class="disabled"><span>« <?= $this->translate('Back') ?></span></li>
<?php endif ?>

View File

@ -1,146 +0,0 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga 2 Web.
*
* Icinga 2 Web - Head for multiple monitoring backends.
* Copyright (C) 2013 Icinga Development Team
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* @copyright 2013 Icinga Development Team <info@icinga.org>
* @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2
* @author Icinga Development Team <info@icinga.org>
*/
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Backend;
use Icinga\Application\Config;
/**
* Icinga Backend Abstract
*
* @package Icinga\Backend
*/
abstract class AbstractBackend
{
/**
* @var \Zend_Config
*/
protected $config;
/**
* @var array
*/
protected $extensions = array();
/**
* Backend constructor, should not be overwritten
*
* Makes sure that $this->config exists. Config is a Zend_Config
* object right now, only the main Config is an Icinga one
*
* return void
*/
final public function __construct(\Zend_Config $config = null)
{
if ($config == null) {
$config = new \Zend_Config(array());
}
$this->config = $config;
$this->init();
}
/**
* Override this function for initialization tasks
*
* return void
*/
protected function init()
{
}
/**
* Dummy function for fluent code
*
* return \Icinga\Backend\Ido
*/
public function select()
{
return $this;
}
/**
* Create a Query object instance for given virtual table and desired fields
*
* Leave fields empty to get all available properties
*
* @param string Virtual table name
* @param array $fields
* @throws \Exception
* @return
* @internal param \Icinga\Backend\Fields $array return \Icinga\Backend\Ido\Query* return \Icinga\Backend\Ido\Query
*/
public function from($virtual_table, $fields = array())
{
$classname = $this->tableToClassName($virtual_table);
if (!class_exists($classname)) {
throw new \Exception(sprintf('Asking for invalid virtual table %s', $classname));
}
$query = new $classname($this, $fields);
return $query;
}
/**
* @param $virtual_table
* @return bool
*/
public function hasView($virtual_table)
{
return class_exists($this->tableToClassName($virtual_table));
}
/**
* @param $virtual_table
* @return string
*/
protected function tableToClassName($virtual_table)
{
if (strpos($virtual_table, "/") !== false) {
list($module, $classname) = explode("/", $virtual_table, 2);
$class = array_pop(explode("\\", get_class($this)));
return 'Icinga\\' . ucfirst($module) . '\\Backend\\' . $class . '\\' . ucfirst($classname) . 'Query';
} else {
return get_class($this) . '\\' . ucfirst($virtual_table . 'Query');
}
}
/**
* @return mixed
*/
public function getName()
{
return preg_replace('~^.+\\\(.+?)$~', '$1', get_class($this));
}
/**
* @return mixed
*/
public function __toString()
{
return $this->getName();
}
}

View File

@ -1,53 +0,0 @@
<?php
namespace Icinga\Backend;
use Icinga\Backend;
class Combo extends AbstractBackend
{
protected $db;
protected $backends;
// TODO: Create a dummy query object to also catch errors with lazy connections
public function from($view, $fields = array())
{
$backends = $this->listMyBackends();
$query = null;
$msg = '';
while ($query === null) {
try {
$backend_name = array_shift($backends);
$msg .= "Trying $backend_name";
$backend = Backend::getInstance($backend_name);
if ($backend->hasView($view)) {
$query = $backend->from($view, $fields);
}
} catch (\Exception $e) {
$msg .= ' Failed: ' . $e->getMessage() . "\n";
}
if ($query !== null) $msg .= " Succeeded.\n";
if ($query === null && empty($backends)) {
throw new \Exception('All backends failed: ' . nl2br($msg));
}
}
return $query;
}
public function hasView($virtual_table)
{
$backends = $this->listMyBackends();
while ($backend_name = array_shift($backends)) {
if (Backend::getInstance($backend_name)->hasView($virtual_table)) {
return true;
}
}
return false;
}
protected function listMyBackends()
{
return preg_split('~,\s*~', $this->config->backends, -1, PREG_SPLIT_NO_EMPTY);
}
}

View File

@ -1,292 +0,0 @@
<?php
/**
* Icinga IDO Backend
*
* @package Icinga\Backend
*/
namespace Icinga\Backend;
/**
* This class provides an easy-to-use interface to the IDO database
*
* You should usually not directly use this class but go through Icinga\Backend.
*
* New MySQL indexes:
* <code>
* CREATE INDEX web2_index ON icinga_scheduleddowntime (object_id, is_in_effect);
* CREATE INDEX web2_index ON icinga_comments (object_id);
* CREATE INDEX web2_index ON icinga_objects (object_id, is_active); -- (not sure yet)
* </code>
*
* Other possible (history-related) indexes, still subject to tests:
* CREATE INDEX web2_index ON icinga_statehistory (object_id, state_time DESC);
* CREATE INDEX web2_index ON icinga_notifications (object_id, instance_id, start_time DESC);
* CREATE INDEX web2_index ON icinga_downtimehistory (object_id, actual_start_time, actual_end_time);
*
* @copyright Copyright (c) 2013 Icinga-Web Team <info@icinga.org>
* @author Icinga-Web Team <info@icinga.org>
* @package Icinga\Application
* @license http://www.gnu.org/copyleft/gpl.html GNU General Public License
*/
class Ido extends AbstractBackend
{
protected $db;
protected $dbtype;
protected $prefix = 'icinga_';
/**
* Backend initialization starts here
*
* return void
*/
protected function init()
{
$this->connect();
}
/**
* Get our Zend_Db connection
*
* return \Zend_Db_Adapter_Abstract
*/
public function getAdapter()
{
return $this->db;
}
public function getDbType()
{
return $this->dbtype;
}
/**
* Get our IDO table prefix
*
* return string
*/
public function getPrefix()
{
return $this->prefix;
}
// TODO: Move elsewhere. Really? Reasons may be: other backends need IDO
// access, even in environments running state details without IDO
protected function connect()
{
$this->dbtype = $this->config->get('dbtype', 'mysql');
$options = array(
\Zend_Db::AUTO_QUOTE_IDENTIFIERS => false,
\Zend_Db::CASE_FOLDING => \Zend_Db::CASE_LOWER
);
$drv_options = array(
\PDO::ATTR_TIMEOUT => 2,
// TODO: Check whether LC is useful. Zend_Db does fetchNum for Oci:
\PDO::ATTR_CASE => \PDO::CASE_LOWER
// TODO: ATTR_ERRMODE => ERRMODE_EXCEPTION vs ERRMODE_SILENT
);
switch ($this->dbtype) {
case 'mysql':
$adapter = 'Pdo_Mysql';
$drv_options[\PDO::MYSQL_ATTR_INIT_COMMAND] =
"SET SESSION SQL_MODE='STRICT_ALL_TABLES,NO_ZERO_IN_DATE,"
. "NO_ZERO_DATE,NO_ENGINE_SUBSTITUTION';";
// Not using ONLY_FULL_GROUP_BY as of performance impact
// TODO: NO_ZERO_IN_DATE as been added with 5.1.11. Is it
// ignored by other versions?
$port = $this->config->get('port', 3306);
break;
case 'pgsql':
$adapter = 'Pdo_Pgsql';
$port = $this->config->get('port', 5432);
break;
case 'oracle':
$adapter = 'Pdo_Oci';
// $adapter = 'Oracle';
$port = $this->config->get('port', 1521);
// $drv_options[\PDO::ATTR_STRINGIFY_FETCHES] = true;
if ($adapter === 'Oracle') {
putenv('ORACLE_SID=XE');
putenv('ORACLE_HOME=/u01/app/oracle/product/11.2.0/xe');
putenv('PATH=$PATH:$ORACLE_HOME/bin');
putenv('ORACLE_BASE=/u01/app/oracle');
putenv('NLS_LANG=AMERICAN_AMERICA.UTF8');
}
$this->prefix = '';
break;
default:
throw new \Exception(sprintf(
'Backend "%s" is not supported', $type
));
}
$attributes = array(
'host' => $this->config->host,
'port' => $port,
'username' => $this->config->user,
'password' => $this->config->pass,
'dbname' => $this->config->db,
'options' => $options,
'driver_options' => $drv_options
);
if ($this->dbtype === 'oracle') {
$attributes['persistent'] = true;
}
$this->db = \Zend_Db::factory($adapter, $attributes);
if ($adapter === 'Oracle') {
$this->db->setLobAsString(false);
}
$this->db->setFetchMode(\Zend_Db::FETCH_OBJ);
// $this->db->setFetchMode(\Zend_Db::FETCH_ASSOC);
}
/// *** TODO: EVERYTHING BELOW THIS LINE WILL BE MOVED AWAY *** ///
// UGLY temporary host fetch
public function fetchHost($host)
{
$object = \Icinga\Objects\Service::fromBackend(
$this->select()
->from('servicelist')
->where('so.name1 = ?', $host)
->fetchRow()
);
$object->customvars = $this->fetchCustomvars($host);
return $object;
}
// UGLY temporary service fetch
public function fetchService($host, $service)
{
$object = \Icinga\Objects\Service::fromBackend(
$this->select()
->from('servicelist')
->where('so.name1 = ?', $host)
->where('so.name2 = ?', $service)
->fetchRow()
);
$object->customvars = $this->fetchCustomvars($host, $service);
return $object;
}
public function fetchCustomvars($host, $service = null)
{
if ($this->dbtype === 'oracle') return (object) array();
$select = $this->db->select()->from(
array('cv' => $this->prefix . 'customvariablestatus'),
array(
// 'host_name' => 'cvo.name1',
// 'service_description' => 'cvo.name2',
'name' => 'cv.varname',
'value' => 'cv.varvalue',
)
)->join(
array('cvo' => $this->prefix . 'objects'),
'cvo.object_id = cv.object_id',
array()
);
$select->where('name1 = ?', $host);
if ($service === null) {
$select->where('objecttype_id = 1');
} else {
$select->where('objecttype_id = 1');
$select->where('name2 = ?', $service);
}
$select->where('is_active = 1')->order('cv.varname');
return (object) $this->db->fetchPairs($select);
}
// TODO: Move to module!
public function fetchHardStatesForBpHosts($hosts)
{
return $this->fetchStatesForBp($hosts, 'last_hard_state');
}
public function fetchSoftStatesForBpHosts($hosts)
{
return $this->fetchStatesForBp($hosts, 'current_state');
}
public function fetchStatesForBp($hosts, $state_column = 'last_hard_state')
{
$select_hosts = $this->db->select()->from(
array('hs' => $this->prefix . 'hoststatus'),
array(
'state' => 'hs.' . $state_column,
'ack' => 'hs.problem_has_been_acknowledged',
'in_downtime' => 'CASE WHEN (d.object_id IS NULL) THEN 0 ELSE 1 END',
'combined' => 'hs.current_state << 2 + hs.problem_has_been_acknowledged << 1 + CASE WHEN (d.object_id IS NULL) THEN 0 ELSE 1 END'
)
)->joinRight(
array('o' => $this->prefix . 'objects'),
'hs.host_object_id = o.object_id',
array(
'object_id' => 'o.object_id',
'hostname' => 'o.name1',
'service' => '(NULL)'
)
)->joinLeft(
array('d' => $this->prefix . 'scheduleddowntime'),
'o.object_id = d.object_id'
. ' AND d.was_started = 1'
. ' AND d.scheduled_end_time > NOW()'
. ' AND d.actual_start_time < NOW()',
array()
)->where('o.name1 IN (?)', $hosts)
->where('o.objecttype_id = 1')
->where('o.is_active = 1');
$select_services = $this->db->select()->from(
array('ss' => $this->prefix . 'servicestatus'),
array(
'state' => 'ss.' . $state_column,
'ack' => 'ss.problem_has_been_acknowledged',
'in_downtime' => 'CASE WHEN (d.object_id IS NULL) THEN 0 ELSE 1 END',
'combined' => 'ss.current_state << 2 + ss.problem_has_been_acknowledged << 1 + CASE WHEN (d.object_id IS NULL) THEN 0 ELSE 1 END'
)
)->joinRight(
array('o' => $this->prefix . 'objects'),
'ss.service_object_id = o.object_id',
array(
'object_id' => 'o.object_id',
'hostname' => 'o.name1',
'service' => 'o.name2'
)
)->joinLeft(
array('d' => $this->prefix . 'scheduleddowntime'),
'o.object_id = d.object_id'
. ' AND d.was_started = 1'
. ' AND d.scheduled_end_time > NOW()'
. ' AND d.actual_start_time < NOW()',
array()
)->where('o.name1 IN (?)', $hosts)
->where('o.is_active = 1')
->where('o.objecttype_id = 2');
$union = $this->db->select()->union(
array(
'(' . $select_hosts . ')', // ZF-4338 :-(
'(' . $select_services . ')',
),
// At least on MySQL UNION ALL seems to be faster than UNION in
// most situations, as it doesn't care about duplicates
\Zend_Db_Select::SQL_UNION_ALL
)->order('hostname')->order('service');
return $this->db->fetchAll($union);
}
}

View File

@ -1,191 +0,0 @@
<?php
namespace Icinga\Backend\Ido;
abstract class GroupsummaryQuery extends Query
{
protected $name_alias;
protected $sub_group_column;
protected $sub_query;
protected $sub_count_query;
protected $available_columns = array(
'ok' => 'SUM(CASE WHEN state = 0 THEN 1 ELSE 0 END)',
'critical' => 'SUM(CASE WHEN state = 2 AND downtime = 0 AND ack = 0 THEN 1 ELSE 0 END)',
'critical_dt' => 'SUM(CASE WHEN state = 2 AND downtime = 1 THEN 1 ELSE 0 END)',
'critical_ack' => 'SUM(CASE WHEN state = 2 AND downtime = 0 AND ack = 1 THEN 1 ELSE 0 END)',
'unknown' => 'SUM(CASE WHEN state = 3 AND downtime = 0 AND ack = 0 THEN 1 ELSE 0 END)',
'unknown_dt' => 'SUM(CASE WHEN state = 3 AND downtime = 1 THEN 1 ELSE 0 END)',
'unknown_ack' => 'SUM(CASE WHEN state = 3 AND downtime = 0 AND ack = 1 THEN 1 ELSE 0 END)',
'warning' => 'SUM(CASE WHEN state = 1 AND downtime = 0 AND ack = 0 THEN 1 ELSE 0 END)',
'warning_dt' => 'SUM(CASE WHEN state = 1 AND downtime = 1 THEN 1 ELSE 0 END)',
'warning_ack' => 'SUM(CASE WHEN state = 1 AND downtime = 0 AND ack = 1 THEN 1 ELSE 0 END)',
'last_state_change' => 'UNIX_TIMESTAMP(MAX(last_state_change))',
);
protected $order_columns = array(
'state' => array(
'ASC' => array(
'ok ASC',
'warning_dt ASC',
'warning_ack ASC',
'warning ASC',
'unknown_dt ASC',
'unknown_ack ASC',
'unknown ASC',
'critical_dt ASC',
'critical_ack ASC',
'critical ASC',
),
'DESC' => array(
'critical DESC',
'unknown DESC',
'warning DESC',
'critical_ack DESC',
'critical_dt DESC',
'unknown_ack DESC',
'unknown_dt DESC',
'warning_ack DESC',
'warning_dt DESC',
'ok DESC',
),
'default' => 'DESC'
)
);
abstract protected function addSummaryJoins($query);
protected function init()
{
parent::init();
if ($this->dbtype === 'oracle') {
$this->columns['last_state_change'] = 'localts2unixts(MAX(last_state_change))';
}
}
protected function createQuery()
{
$this->columns[$this->name_alias] = $this->name_alias;
$this->order_columns['state']['ASC'][] = $this->name_alias . ' ASC';
$this->order_columns['state']['DESC'][] = $this->name_alias . ' DESC';
$this->order_columns['name'] = array(
'ASC' => array( $this->name_alias . ' ASC'),
'DESC' => array( $this->name_alias . ' DESC'),
'default' => 'ASC'
);
$sub_query = $this->createSubQuery();
// $sub_query->group($this->sub_group_column);
// $sub_query->columns(array($this->name_alias => 'MAX(' . $this->sub_group_column . ')'));
$sub_query->columns(array($this->name_alias => $this->sub_group_column ));
$this->addSummaryJoins($sub_query);
$query = $this->db->select()->from(
array('sub' => $sub_query),
array()
);
$query->group($this->name_alias);
$this->sub_query = $sub_query;
return $query;
}
protected function createCountQuery()
{
$this->sub_count_query = $this->createCountSubQuery();
$this->sub_count_query->group($this->sub_group_column);
$this->addSummaryJoins($this->sub_count_query);
$count = $this->db->select()->from(
array('cnt' => $this->sub_count_query),
array()
);
return $count;
}
protected function createSubQuery()
{
$query = $this->db->select()
->from(
array('so' => $this->prefix . 'objects'),
array(
// MAX seems to be useless, but is required as of the GROUP below
// 'state' => 'MAX(ss.current_state)',
'state' => 'ss.current_state',
// 'ack' => 'MAX(ss.problem_has_been_acknowledged)',
'ack' => 'ss.problem_has_been_acknowledged',
// 'downtime' => 'MAX(CASE WHEN (dt.object_id IS NULL) THEN 0 ELSE 1 END)',
// 'downtime' => 'MAX(CASE WHEN (scheduled_downtime_depth = 0) THEN 0 ELSE 1 END)',
'downtime' => 'CASE WHEN (scheduled_downtime_depth = 0) THEN 0 ELSE 1 END',
// 'last_state_change' => 'MAX(ss.last_state_change)',
'last_state_change' => 'ss.last_state_change',
)
)->joinLeft(
array('ss' => $this->prefix . 'servicestatus'),
"so.$this->object_id = ss.service_object_id",
array()
)->join(
array('s' => $this->prefix . 'services'),
's.service_object_id = ss.service_object_id',
array()
)/*->joinLeft(
array('dt' => $this->prefix . 'scheduleddowntime'),
"so.$this->object_id = dt.object_id"
. ' AND dt.is_in_effect = 1',
array()
)->joinLeft(
array('co' => $this->prefix . 'comments'),
"so.$this->object_id = co.object_id",
array()
)*/
->where('so.is_active = 1')
->where('so.objecttype_id = 2')
// Group is required as there could be multiple comments:
// ->group('so.' . $this->object_id)
;
return $query;
}
protected function createCountSubQuery()
{
return $this->db->select()
->from(
array('so' => $this->prefix . 'objects'),
array('state' => 'MAX(ss.current_state)')
)->joinLeft(
array('ss' => $this->prefix . 'servicestatus'),
"so.$this->object_id = ss.service_object_id",
array()
)->join(
array('s' => $this->prefix . 'services'),
's.service_object_id = ss.service_object_id',
array()
);
}
public function where($column, $value = null)
{
if ($column === 'problems') {
if ($value === 'true') {
$this->query->having('(SUM(CASE WHEN state = 2 AND downtime = 0 AND ack = 0 THEN 1 ELSE 0 END) +
SUM(CASE WHEN state = 2 AND downtime = 1 THEN 1 ELSE 0 END) +
SUM(CASE WHEN state = 2 AND downtime = 0 AND ack = 1 THEN 1 ELSE 0 END) +
SUM(CASE WHEN state = 3 AND downtime = 0 AND ack = 0 THEN 1 ELSE 0 END) +
SUM(CASE WHEN state = 3 AND downtime = 1 THEN 1 ELSE 0 END) +
SUM(CASE WHEN state = 3 AND downtime = 0 AND ack = 1 THEN 1 ELSE 0 END) +
SUM(CASE WHEN state = 1 AND downtime = 0 AND ack = 0 THEN 1 ELSE 0 END) +
SUM(CASE WHEN state = 1 AND downtime = 1 THEN 1 ELSE 0 END) +
SUM(CASE WHEN state = 1 AND downtime = 0 AND ack = 1 THEN 1 ELSE 0 END)) > 0');
$this->sub_count_query->where('ss.current_state > 0');
$this->sub_query->where('ss.current_state > 0');
}
} elseif ($column === 'search') {
if ($value) {
// $this->sub_query->where($this->name_alias . ' LIKE ?', '%' . $value . '%');
$this->sub_query->where($this->sub_group_column . ' LIKE ?', '%' . $value . '%');
$this->sub_count_query->where($this->sub_group_column . ' LIKE ?', '%' . $value . '%');
}
} else {
parent::where($column, $value);
}
return $this;
}
}

View File

@ -1,14 +0,0 @@
<?php
namespace Icinga\Backend\Ido;
class HostgroupsummaryQuery extends GroupsummaryQuery
{
protected $name_alias = 'hostgroup_name';
protected $sub_group_column = 'hg.alias';
protected function addSummaryJoins($query)
{
$this->joinServiceHostgroups($query);
}
}

View File

@ -1,521 +0,0 @@
<?php
namespace Icinga\Backend\Ido;
abstract class Query extends \Icinga\Backend\Query
{
protected $db;
protected $prefix;
protected $query;
protected $count_query;
protected $count_columns;
protected $ordered = false;
protected $finalized = false;
protected $object_id = 'object_id';
protected $hostgroup_id = 'hostgroup_id';
protected $servicegroup_id = 'servicegroup_id';
protected $custom_cols = array();
/**
* Available sort combinations
*/
protected $order_columns = array(
'host' => array(
'ASC' => array(
'host_name ASC',
'service_description ASC'
),
'DESC' => array(
'host_name DESC',
'service_description ASC'
),
'default' => 'ASC'
),
'host_address' => array(
'ASC' => array(
'host_ipv4 ASC',
'service_description ASC'
),
'DESC' => array(
'host_ipv4 ASC',
'service_description ASC'
),
'default' => 'ASC'
),
'service' => array(
'ASC' => array(
'service_description ASC'
),
'DESC' => array(
'service_description DESC'
),
'default' => 'ASC'
),
'service_state_change' => array(
'ASC' => array(
'ss.last_state_change ASC'
),
'DESC' => array(
'ss.last_state_change DESC'
),
'default' => 'DESC'
),
'service_state' => array(
'ASC' => array(
'CASE WHEN (ss.current_state = 3) THEN 2 WHEN (ss.current_state = 2) THEN 3 ELSE ss.current_state END DESC', // TODO: distinct severity in a better way
'ss.problem_has_been_acknowledged ASC',
// 'CASE WHEN (ss.scheduled_downtime_depth = 0) THEN 0 ELSE 1 END ASC',
'service_in_downtime ASC', // TODO: Check if all dbs allow sorting by alias
'ss.last_state_change DESC',
'so.name1 ASC',
'so.name2 ASC'
),
'DESC' => array(
'CASE WHEN (ss.current_state = 3) THEN 2 WHEN (ss.current_state = 2) THEN 3 ELSE ss.current_state END ASC',
'ss.problem_has_been_acknowledged ASC',
// 'CASE WHEN (ss.scheduled_downtime_depth = 0) THEN 0 ELSE 1 END ASC',
'service_in_downtime ASC',
'ss.last_state_change DESC'
),
'default' => 'ASC'
)
);
abstract protected function createQuery();
public function dump()
{
$this->finalize();
return "QUERY\n=====\n"
. $this->query
. "\n\nCOUNT\n=====\n"
. $this->count_query
. "\n\n";
}
public function getCountQueryObject()
{
return $this->finalize()->count_query;
}
public function getQueryObject()
{
return $this->finalize()->query;
}
protected function createCountQuery()
{
return clone($this->query);
}
protected function init()
{
$this->db = $this->backend->getAdapter();
$this->dbtype = $this->backend->getDbType();
if ($this->dbtype === 'oracle') {
$this->object_id = $this->hostgroup_id = $this->servicegroup_id = 'id';
}
$this->prefix = $this->backend->getPrefix();
$this->query = $this->createQuery();
$this->count_query = $this->createCountQuery();
}
protected function finalize()
{
if ($this->finalized) return $this;
$this->finalized = true;
$this->query->columns($this->columns);
if ($this->count_columns === null) {
$this->count_columns = array('cnt' => 'COUNT(*)');
}
if (! $this->ordered) {
$this->order();
}
$this->count_query->columns($this->count_columns);
return $this;
}
protected function prepareServiceStatesQuery()
{
$query = $this->db->select()
->from(
array('hs' => $this->prefix . 'hoststatus'),
array()
)->join(
array('h' => $this->prefix . 'hosts'),
'hs.host_object_id = h.host_object_id',
array()
)->join(
array('s' => $this->prefix . 'services'),
's.host_object_id = h.host_object_id',
array()
)->join(
array('so' => $this->prefix . 'objects'),
"so.$this->object_id = s.service_object_id AND so.is_active = 1",
array()
)->joinLeft(
array('ss' => $this->prefix . 'servicestatus'),
"so.$this->object_id = ss.service_object_id",
array()
);
// $this->joinServiceDowntimes($query);
// $query->group('so.object_id');
return $query;
}
protected function prepareServicesCount()
{
// TODO: Depends on filter, some cols could be avoided
$query = $this->db->select()->from(
array('hs' => $this->prefix . 'hoststatus'),
array()
)->join(
array('h' => $this->prefix . 'hosts'),
'hs.host_object_id = h.host_object_id',
array()
)->join(
array('s' => $this->prefix . 'services'),
's.host_object_id = h.host_object_id',
array()
)->join(
array('so' => $this->prefix . 'objects'),
"so.$this->object_id = s.service_object_id AND so.is_active = 1",
"COUNT(so.$this->object_id)"
)->joinLeft(
array('ss' => $this->prefix . 'servicestatus'),
"so.$this->object_id = ss.service_object_id",
array()
);
// $this->joinServiceDowntimes($query);
return $query;
}
protected function joinHostgroups($query = null)
{
if ($query === null) $query = $this->query;
$query->join(
array('hgm' => $this->prefix . 'hostgroup_members'),
'hgm.host_object_id = h.host_object_id',
array()
)->join(
array('hg' => $this->prefix . 'hostgroups'),
"hgm.hostgroup_id = hg.$this->hostgroup_id",
array()
);
return $this;
}
protected function joinServiceHostgroups($query)
{
if ($query === null) $query = $this->query;
$query->join(
array('hgm' => $this->prefix . 'hostgroup_members'),
'hgm.host_object_id = s.host_object_id',
array()
)->join(
array('hg' => $this->prefix . 'hostgroups'),
"hgm.hostgroup_id = hg.$this->hostgroup_id",
array()
);
return $this;
}
protected function joinServicegroups($query)
{
if ($query === null) $query = $this->query;
$query->join(
array('sgm' => $this->prefix . 'servicegroup_members'),
'sgm.service_object_id = s.service_object_id',
array()
)->join(
array('sg' => $this->prefix . 'servicegroups'),
"sgm.servicegroup_id = sg.$this->servicegroup_id",
array()
);
return $this;
}
protected function joinServiceDowntimes($query)
{
$query->joinLeft(
array('dt' => $this->prefix . 'scheduleddowntime'),
"so.$this->object_id = dt.object_id"
. ' AND dt.is_in_effect = 1',
array()
);
// NDO compat (doesn't work correctly like this):
// $now = "'" . date('Y-m-d H:i:s') . "'";
// . ' AND dt.was_started = 1'
// . ' AND dt.scheduled_end_time > ' . $now
// . ' AND dt.actual_start_time < ' . $now,
return $query;
}
public function where($column, $value = null)
{
// Ugly temporary hack:
foreach (array($this->query, $this->count_query) as $query) {
if ($column === 'search') {
if ($this->dbtype === 'mysql') {
$query->where($this->db->quoteInto(
'so.name2 COLLATE latin1_general_ci LIKE ?'
. ' OR so.name1 COLLATE latin1_general_ci LIKE ?',
'%' . $value . '%',
'%' . $value . '%'
));
} else {
$query->where($this->db->quoteInto(
'LOWER(so.name2) LIKE ?'
. ' OR LOWER(so.name1) LIKE ?',
'%' . strtolower($value) . '%',
'%' . strtolower($value) . '%'
));
}
continue;
}
// TODO: Check if this also works based on column:
if ($column === 'hostgroups') {
$this->appendHostgroupLimit($query, $value);
continue;
}
if (preg_match('~^_([^_]+)_(.+)$~', $column, $m)) {
switch($m[1]) {
case 'host':
$this->appendHostCustomVarLimit($query, $m[2], $value);
break;
case 'service':
$this->appendServiceCustomVarLimit($query, $m[2], $value);
break;
}
continue;
}
//$column = preg_replace('~^current_state~', 'ss.current_state', $column);
if (array_key_exists($column, $this->available_columns)) {
$column = $this->available_columns[$column];
}
$query->where($this->prepareFilterStringForColumn($column, $value));
}
/*->orWhere('last_state_change > ?', $new)*/
return $this;
}
public function order($column = '', $dir = null)
{
$this->ordered = true;
return $this->applyOrder($column, $dir);
}
protected function applyOrder($order = '', $order_dir = null)
{
if (! array_key_exists($order, $this->order_columns)) {
$order = key($this->order_columns);
}
if ($order_dir === null) {
$order_dir = $this->order_columns[$order]['default'];
}
foreach ($this->order_columns[$order][$order_dir] as $col) {
$this->query->order($col);
}
return $this;
}
protected function addServiceComments($query = null)
{
if ($query === null) {
$query = $this->query;
}
$query->joinLeft(
array('co' => $this->prefix . 'comments'),
"so.$this->object_id = co.object_id",
array()
)
->group('so.object_id')
;
return $this;
}
/**
* $column = col
* $value = abc,cde,cd*,!egh,!*hh*
* -> (col IN ('abc', 'cde') OR col LIKE 'cd%') AND (col != 'egh' AND col NOT LIKE '%hh%')
*/
protected function prepareFilterStringForColumn($column, $value)
{
$filter = '';
$filters = array();
$or = array();
$and = array();
if (strpos($value, ',') !== false) {
$value = preg_split('~,~', $value, -1, PREG_SPLIT_NO_EMPTY);
}
if (! is_array($value)) {
$value = array($value);
}
// Go through all given values
foreach ($value as $val) {
// Value starting with - means negation
if ($val[0] === '-') {
$val = substr($val, 1);
if (strpos($val, '*') === false) {
$and[] = $this->db->quoteInto($column . ' != ?', $val);
} else {
$and[] = $this->db->quoteInto(
$column . ' NOT LIKE ?',
str_replace('*', '%', $val)
);
}
// Starting with + enforces AND
} elseif ($val[0] === '+') {
$val = substr($val, 1);
if (strpos($val, '*') === false) {
$and[] = $this->db->quoteInto($column . ' = ?', $val);
} else {
$and[] = $this->db->quoteInto(
$column . ' LIKE ?',
str_replace('*', '%', $val)
);
}
// All others ar ORs:
} else {
if (strpos($val, '*') === false) {
$or[] = $this->db->quoteInto($column . ' = ?', $val);
} else {
$or[] = $this->db->quoteInto(
$column . ' LIKE ?',
str_replace('*', '%', $val)
);
}
}
}
if (! empty($or)) { $filters[] = implode(' OR ', $or); }
if (! empty($and)) { $filters[] = implode(' AND ', $and); }
if (! empty($filters)) {
$filter = '(' . implode(') AND (', $filters) . ')';
}
return $filter;
}
protected function addCustomVarColumn($query, $alias, $name, $filter = null)
{
// TODO: Improve this:
if (! preg_match('~^[a-zA-Z0-9_]+$~', $name)) {
throw new \Exception(sprintf(
'Got invalid custom var: "%s"',
$name
));
}
$qobj = spl_object_hash($query);
if (! array_key_exists($qobj, $this->custom_cols)) {
$this->custom_cols[$qobj] = array();
}
if (array_key_exists($alias, $this->custom_cols[$qobj])) {
if ($name !== $this->custom_cols[$qobj][$alias]) {
throw new \Exception(sprintf(
'Cannot add CV alias "%s" twice with different target',
$alias
));
}
return $this;
}
$query->join(
// TODO: Allow multiple limits with different aliases
array($alias => $this->prefix . 'customvariablestatus'),
's.host_object_id = ' . $alias . '.object_id'
. ' AND ' . $alias . '.varname = '
. $this->db->quote(strtoupper($name))
//. ($filter === null ? '' : ' AND ' . $filter),
,
array()
);
$this->custom_cols[$qobj][$alias] = $name;
return $this;
}
protected function appendHostCustomVarLimit($query, $key, $value)
{
$alias = 'hcv_' . strtolower($key);
$filter = $this->prepareFilterStringForColumn($alias . '.varvalue', $value);
$this->addCustomVarColumn($query, $alias, $key);
$query->where($filter);
return $query;
}
protected function appendHostgroupLimit($query, $hostgroups)
{
return $query->join(
array('hgm' => $this->prefix . 'hostgroup_members'),
'hgm.host_object_id = s.host_object_id',
array()
)->join(
array('hg' => $this->prefix . 'hostgroups'),
"hgm.hostgroup_id = hg.$this->hostgroup_id",
array()
)
->where('hg.alias IN (?)', $hostgroups);
}
public function count()
{
return $this->db->fetchOne(
$this->finalize()->count_query
);
}
public function fetchAll()
{
return $this->db->fetchAll($this->finalize()->query);
}
public function fetchRow()
{
return $this->db->fetchRow($this->finalize()->query);
}
public function fetchOne()
{
return $this->db->fetchOne($this->finalize()->query);
}
public function fetchPairs()
{
return $this->db->fetchPairs($this->finalize()->query);
}
/**
* Sets a limit count and offset to the query
*
* @param int $count Number of rows to return
* @param int $offset Row offset to start from
* @return \Icinga\Backend\Query This Query object
*/
public function limit($count = null, $offset = null)
{
$this->query->limit($count, $offset);
return $this;
}
public function __toString()
{
$this->finalize();
return (string) $this->query;
}
}

View File

@ -1,14 +0,0 @@
<?php
namespace Icinga\Backend\Ido;
class ServicegroupsummaryQuery extends GroupsummaryQuery
{
protected $name_alias = 'servicegroup_name';
protected $sub_group_column = 'sg.alias';
protected function addSummaryJoins($query)
{
$this->joinServicegroups($query);
}
}

View File

@ -1,95 +0,0 @@
<?php
namespace Icinga\Backend\Ido;
class ServicelistQuery extends Query
{
protected $available_columns = array(
// Host config
'host_name' => 'so.name1',
'host_display_name' => 'h.display_name',
'host_alias' => 'h.alias',
'host_address' => 'h.address',
'host_ipv4' => 'INET_ATON(h.address)',
'host_icon_image' => 'h.icon_image',
// Host state
'host_state' => 'hs.current_state',
'host_output' => 'hs.output',
'host_perfdata' => 'hs.perfdata',
'host_acknowledged' => 'hs.problem_has_been_acknowledged',
'host_does_active_checks' => 'hs.active_checks_enabled',
'host_accepts_passive_checks' => 'hs.passive_checks_enabled',
'host_last_state_change' => 'UNIX_TIMESTAMP(hs.last_state_change)',
// Service config
'service_description' => 'so.name2',
'service_display_name' => 's.display_name',
// Service state
'current_state' => 'ss.current_state',
'service_state' => 'ss.current_state',
'service_output' => 'ss.output',
'service_perfdata' => 'ss.perfdata',
'service_acknowledged' => 'ss.problem_has_been_acknowledged',
'service_in_downtime' => 'CASE WHEN (ss.scheduled_downtime_depth = 0) THEN 0 ELSE 1 END',
'service_handled' => 'CASE WHEN ss.problem_has_been_acknowledged + ss.scheduled_downtime_depth > 0 THEN 1 ELSE 0 END',
'service_does_active_checks' => 'ss.active_checks_enabled',
'service_accepts_passive_checks' => 'ss.passive_checks_enabled',
'service_last_state_change' => 'UNIX_TIMESTAMP(ss.last_state_change)',
// Service comments
//'service_downtimes_with_info' => "IF(dt.object_id IS NULL, NULL, GROUP_CONCAT(CONCAT('[', dt.author_name, '] ', dt.comment_data) ORDER BY dt.entry_time DESC SEPARATOR '|'))",
//'service_comments_with_info' => "IF(co.object_id IS NULL, NULL, GROUP_CONCAT(CONCAT('[', co.author_name, '] ', co.comment_data) ORDER BY co.entry_time DESC SEPARATOR '|'))",
// SLA Example:
// 'sla' => "icinga_availability(so.object_id,"
// . " '2012-12-01 00:00:00', '2012-12-31 23:59:59')",
);
protected function init()
{
parent::init();
if ($this->dbtype === 'oracle') {
$this->columns['host_last_state_change'] =
'localts2unixts(ss.last_state_change)';
$this->columns['service_last_state_change'] =
'localts2unixts(ss.last_state_change)';
}
}
public function where($column, $value = null)
{
// Ugly temporary hack:
if ($column === 'problems') {
if ($value === true || $value === 'true') {
parent::where('current_state', '-0');
} elseif ($value === false || $value === 'false') {
parent::where('current_state', '0');
}
return $this;
}
if ($column === 'handled') $column = 'service_handled';
parent::where($column, $value);
return $this;
}
protected function createQuery()
{
$query = $this->prepareServiceStatesQuery();
if ($this->dbtype === 'mysql') {
// $this->addServiceComments($query);
} else {
$this->columns['host_ipv4'] = 'h.address';
$this->columns['service_downtimes_with_info'] = '(NULL)';
$this->columns['service_comments_with_info'] = '(NULL)';
}
return $query;
}
protected function createCountQuery()
{
return $this->prepareServicesCount();
}
}

View File

@ -1,86 +0,0 @@
<?php
namespace Icinga\Backend\Ido;
class StatehistoryQuery extends Query
{
protected $available_columns = array(
// Host config
'host_name' => 'sho.name1',
'service_description' => 'sho.name2',
'object_type' => "CASE WHEN sho.objecttype_id = 1 THEN 'host' ELSE 'service' END",
'timestamp' => 'UNIX_TIMESTAMP(sh.state_time)',
'state' => 'sh.state',
'last_state' => 'sh.last_state',
'last_hard_state' => 'sh.last_hard_state',
'attempt' => 'sh.current_check_attempt',
'max_attempts' => 'sh.max_check_attempts',
'output' => 'sh.output', // no long_output in browse
);
protected $order_columns = array(
'timestamp' => array(
'ASC' => array(
'state_time ASC',
),
'DESC' => array(
'state_time DESC',
),
'default' => 'DESC'
)
);
protected function init()
{
parent::init();
if ($this->dbtype === 'oracle') {
$this->columns['timestamp'] =
'localts2unixts(sh.state_time)';
}
}
public function where($column, $value = null)
{
if ($column === 'problems') {
if ($value === 'true') {
foreach (array($this->query, $this->count_query) as $query) {
$query->where('sh.state > 0');
}
}
return $this;
}
if ($column === 'host') {
foreach (array($this->query, $this->count_query) as $query) {
$query->where('sho.name1 = ?', $value);
}
return $this;
}
if ($column === 'service') {
foreach (array($this->query, $this->count_query) as $query) {
$query->where('sho.name2 = ?', $value);
}
return $this;
}
parent::where($column, $value);
return $this;
}
protected function createQuery()
{
$query = $this->db->select()->from(
array('sh' => $this->prefix . 'statehistory'),
array()
// )->join(
)->joinLeft( // LEFT is bullshit but greatly helps MySQL
// Problem -> has to be INNER once permissions are in effect
// Therefore this should probably be "flexible" or handled in another
// way
array('sho' => $this->prefix . 'objects'),
'sho.' . $this->object_id . ' = sh.object_id AND sho.is_active = 1',
array()
);
return $query;
}
}

View File

@ -1,45 +0,0 @@
<?php
/**
* Icinga Livestatus Backend
*
* @package Icinga\Backend
*/
namespace Icinga\Backend;
use Icinga\Protocol\Livestatus\Connection;
/**
* This class provides an easy-to-use interface to the Livestatus socket library
*
* You should usually not directly use this class but go through Icinga\Backend.
*
* @copyright Copyright (c) 2013 Icinga-Web Team <info@icinga.org>
* @author Icinga-Web Team <info@icinga.org>
* @package Icinga\Application
* @license http://www.gnu.org/copyleft/gpl.html GNU General Public License
*/
class Livestatus extends AbstractBackend
{
protected $connection;
/**
* Backend initialization starts here
*
* return void
*/
protected function init()
{
$this->connection = new Connection($this->config->socket);
}
/**
* Get our Livestatus connection
*
* return \Icinga\Protocol\Livestatus\Connection
*/
public function getConnection()
{
return $this->connection;
}
}

View File

@ -1,213 +0,0 @@
<?php
namespace Icinga\Backend\Livestatus;
abstract class Query extends \Icinga\Backend\Query
{
protected $connection;
protected $query;
protected $ordered = false;
protected $finalized = false;
/**
* Available sort combinations
*/
protected $order_columns = array(
'host' => array(
'ASC' => array(
'host_name ASC',
'service_description ASC'
),
'DESC' => array(
'host_name DESC',
'service_description ASC'
),
'default' => 'ASC'
),
'host_address' => array(
'ASC' => array(
'host_ipv4 ASC',
'service_description ASC'
),
'DESC' => array(
'host_ipv4 ASC',
'service_description ASC'
),
'default' => 'ASC'
),
'service' => array(
'ASC' => array(
'service_description ASC'
),
'DESC' => array(
'service_description DESC'
),
'default' => 'ASC'
),
'service_state_change' => array(
'ASC' => array(
'ss.last_state_change ASC'
),
'DESC' => array(
'ss.last_state_change DESC'
),
'default' => 'DESC'
),
'service_state' => array(
'ASC' => array(
'IF (ss.current_state = 3, 2, IF(ss.current_state = 2, 3, ss.current_state)) DESC',
'ss.problem_has_been_acknowledged ASC',
'IF(dt.object_id IS NULL, 0, 1) ASC',
'ss.last_state_change DESC'
),
'DESC' => array(
'IF (ss.current_state = 3, 2, IF(ss.current_state = 3, 2, ss.current_state)) DESC',
'ss.problem_has_been_acknowledged ASC',
'IF(dt.object_id IS NULL, 0, 1) ASC',
'ss.last_state_change DESC'
),
'default' => 'ASC'
)
);
abstract protected function createQuery();
protected function init()
{
$this->connection = $this->backend->getConnection();
$this->query = $this->createQuery();
}
public function where($column, $value = null)
{
if ($column === 'problems') {
if ($value === 'true') {
$this->query->where('state > 0');
} elseif ($value === 'false') {
$this->query->where('state = 0');
}
return $this;
}
if ($column === 'handled') {
if ($value === 'true') {
// TODO: Not yet
} elseif ($value === 'false') {
// TODO: Not yet
}
return $this;
}
// Ugly temporary hack:
$colcheck = preg_replace('~[\s=><].+$~', '', $column);
if (array_key_exists($colcheck, $this->available_columns)) {
$query->where(preg_replace(
'~' . $colcheck . '~',
$this->available_columns[$colcheck],
$column
), $value);
} else {
$this->query->where($column, $value);
}
return $this;
}
protected function finalize()
{
return $this;
if ($this->finalized) return $this;
$this->finalized = true;
$this->query->columns($this->columns);
if ($this->count_columns === null) {
$this->count_columns = array('cnt' => 'COUNT(*)');
}
if (! $this->ordered) {
$this->order();
}
$this->count_query->columns($this->count_columns);
return $this;
}
public function applyFilters($filters = array())
{
foreach ($filters as $key => $val) {
$this->where($key, $val);
}
return $this;
}
public function order($column = '', $dir = null)
{
$this->ordered = true;
return $this->applyOrder($column, $dir);
}
protected function applyOrder($order = '', $order_dir = null)
{
return $this;
if (! array_key_exists($order, $this->order_columns)) {
$order = key($this->order_columns);
}
if ($order_dir === null) {
$order_dir = $this->order_columns[$order]['default'];
}
foreach ($this->order_columns[$order][$order_dir] as $col) {
$this->query->order($col);
}
return $this;
}
public function count()
{
return $this->connection->count(
$this->finalize()->query
);
}
public function fetchAll()
{
return $this->connection->fetchAll($this->finalize()->query);
}
public function fetchRow()
{
return $this->db->fetchRow($this->finalize()->query);
}
public function fetchOne()
{
return $this->db->fetchOne($this->finalize()->query);
}
public function fetchPairs()
{
return $this->db->fetchPairs($this->finalize()->query);
}
/**
* Sets a limit count and offset to the query
*
* @param int $count Number of rows to return
* @param int $offset Row offset to start from
* @return \Icinga\Backend\Query This Query object
*/
public function limit($count = null, $offset = null)
{
$this->query->limit($count, $offset);
return $this;
}
// For debugging and testing only:
public function __toString()
{
$this->finalize();
return (string) $this->query;
}
}

View File

@ -1,46 +0,0 @@
<?php
namespace Icinga\Backend\Livestatus;
class ServicelistQuery extends Query
{
protected $available_columns = array(
'host_name',
'host_display_name',
'host_alias',
'host_address',
'host_ipv4' => 'host_address', // TODO
'host_icon_image',
// Host state
'host_state',
'host_output' => 'host_plugin_output',
'host_perfdata' => 'host_perf_data',
'host_acknowledged',
'host_does_active_checks' => 'host_active_checks_enabled',
'host_accepts_passive_checks' => 'host_accept_passive_checks',
'host_last_state_change',
// Service config
'service_description' => 'description',
'service_display_name' => 'display_name',
// Service state
'service_state' => 'state',
'service_output' => 'plugin_output',
'service_perfdata' => 'perf_data',
'service_acknowledged' => 'acknowledged',
'service_does_active_checks' => 'active_checks_enabled',
'service_accepts_passive_checks' => 'accept_passive_checks',
'service_last_state_change' => 'last_state_change',
// Service comments
'comments_with_info',
'downtimes_with_info',
);
protected function createQuery()
{
return $this->connection->select()->from('services', $this->available_columns);
}
}

View File

@ -1,165 +0,0 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga 2 Web.
*
* Icinga 2 Web - Head for multiple monitoring backends.
* Copyright (C) 2013 Icinga Development Team
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* @copyright 2013 Icinga Development Team <info@icinga.org>
* @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2
* @author Icinga Development Team <info@icinga.org>
*/
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Backend;
use Icinga\Web\Paginator\Adapter\QueryAdapter;
/**
* Class Query
* @package Icinga\Backend
*/
abstract class Query
{
/**
* @var AbstractBackend
*/
protected $backend;
/**
* @var array
*/
protected $columns = array();
/**
* @var array
*/
protected $available_columns = array();
/**
* @param null $count
* @param null $offset
* @return mixed
*/
abstract public function limit($count = null, $offset = null);
/**
* @param $column
* @param null $value
* @return mixed
*/
abstract public function where($column, $value = null);
/**
* @param string $column
* @param null $dir
* @return mixed
*/
abstract public function order($column = '', $dir = null);
/**
* @return mixed
*/
abstract public function fetchAll();
/**
* @return mixed
*/
abstract public function fetchRow();
/**
* @return mixed
*/
abstract public function fetchPairs();
/**
* @return mixed
*/
abstract public function fetchOne();
/**
* @return mixed
*/
abstract public function count();
/**
* @param AbstractBackend $backend
* @param array $columns
* @return \Icinga\Backend\Query
*/
public function __construct(AbstractBackend $backend, $columns = array())
{
$this->backend = $backend;
if (empty($columns) || $columns === '*') {
$this->columns = $this->available_columns;
} else {
$this->columns = $columns;
}
$this->init();
}
/**
* @param array $filters
* @return $this
*/
public function applyFilters($filters = array())
{
foreach ($filters as $key => $val) {
$this->where($key, $val);
}
return $this;
}
/**
* @return mixed
*/
abstract protected function init();
/*
*
*/
protected function finalize()
{
}
/**
* Return a pagination adapter for the current query
*
* @param null $limit
* @param null $page
* @return \Zend_Paginator
*/
public function paginate($limit = null, $page = null)
{
$this->finalize();
$request = \Zend_Controller_Front::getInstance()->getRequest();
if ($page === null) {
$page = $request->getParam('page', 0);
}
if ($limit === null) {
$limit = $request->getParam('limit', 20);
}
$paginator = new \Zend_Paginator(
new QueryAdapter($this)
);
$paginator->setItemCountPerPage($limit);
$paginator->setCurrentPageNumber($page);
return $paginator;
}
}

View File

@ -1,97 +0,0 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga 2 Web.
*
* Icinga 2 Web - Head for multiple monitoring backends.
* Copyright (C) 2013 Icinga Development Team
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* @copyright 2013 Icinga Development Team <info@icinga.org>
* @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2
* @author Icinga Development Team <info@icinga.org>
*/
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Backend\Statusdat\DataView;
use Icinga\Backend\DataView\ObjectRemappingView;
use \Icinga\Protocol\Statusdat\IReader;
/**
* Class StatusdatHostView
* @package Icinga\Backend\Statusdat\DataView
*/
class StatusdatHostView extends ObjectRemappingView
{
/**
* @var mixed
*/
private $state;
/**
* @var array
*/
protected $handlerParameters = array(
"host" => "getHost",
"downtimes_with_info" => "getDowntimes",
"comments_with_info" => "getComments"
);
/**
* @var array
*/
protected $mappedParameters = array(
"host_address" => "host_name",
"host_name" => "host_name",
"host_state" => "status.current_state",
"host_output" => "status.plugin_output",
"host_perfdata" => "status.long_plugin_output",
"host_last_state_change" => "status.last_state_change",
"host_check_command" => "check_command",
"host_last_check" => "status.last_check",
"host_next_check" => "status.next_check",
"host_check_latency" => "status.check_latency",
"host_check_execution_time" => "status.check_execution_time",
"active_checks_enabled" => "status.active_checks_enabled",
"acknowledged" => "status.problem_has_been_acknowledged",
"host_acknowledged" => "status.problem_has_been_acknowledged",
// "state" => "current_state"
);
/**
* @param $item
* @return null
*/
public function getHost(&$item)
{
if (!isset($this->state["host"][$item->host_name])) {
return null;
}
if (!isset($this->state["host"][$item->host_name])) {
return null;
}
return $this->state["host"][$item->host_name];
}
/**
* @param IReader $reader
*/
public function __construct(IReader $reader)
{
$this->state = & $reader->getState();
}
}

View File

@ -164,6 +164,7 @@ abstract class AbstractQuery
$dir = self::SORT_ASC;
}
}
$this->order_columns[] = array($col, $dir);
return $this;
}
@ -374,6 +375,11 @@ abstract class AbstractQuery
return $paginator;
}
public function getColumns()
{
return $this->columns;
}
/**
* Destructor. Remove $ds, just to be on the safe side
*/

View File

@ -57,7 +57,8 @@ class Connection implements DatasourceInterface
$adapter = 'Pdo_Mysql';
$drv_options[\PDO::MYSQL_ATTR_INIT_COMMAND] =
"SET SESSION SQL_MODE='STRICT_ALL_TABLES,NO_ZERO_IN_DATE,"
. "NO_ZERO_DATE,NO_ENGINE_SUBSTITUTION';";
."NO_ZERO_IN_DATE,ANSI,TRADITIONAL,ONLY_FULL_GROUP_BY,"
. "NO_ENGINE_SUBSTITUTION';";
// Not using ONLY_FULL_GROUP_BY as of performance impact
// TODO: NO_ZERO_IN_DATE as been added with 5.1.11. Is it
// ignored by other versions?

View File

@ -29,12 +29,12 @@
namespace Icinga\Protocol\Statusdat;
use Icinga\Protocol;
use Icinga\Data\AbstractQuery;
/**
* Class Query
* @package Icinga\Protocol\Statusdat
*/
class Query extends Protocol\AbstractQuery
class Query extends AbstractQuery
{
/**
* @var array
@ -52,6 +52,7 @@ class Query extends Protocol\AbstractQuery
"servicecomments" => array("servicecomment")
);
/**
* @var IReader|null
*/
@ -62,11 +63,6 @@ class Query extends Protocol\AbstractQuery
*/
private $source = "";
/**
* @var array
*/
private $columns = array();
/**
* @var null
*/
@ -80,7 +76,7 @@ class Query extends Protocol\AbstractQuery
/**
* @var array
*/
private $order_columns = array();
protected $order_columns = array();
/**
* @var array
@ -164,13 +160,7 @@ class Query extends Protocol\AbstractQuery
return $this->offset;
}
/**
* @param IReader $reader
*/
public function __construct(IReader $reader)
{
$this->reader = $reader;
}
/**
* @param $key
@ -247,7 +237,6 @@ class Query extends Protocol\AbstractQuery
} else {
throw new \Exception("Unknown from target for status.dat :" . $table);
}
$this->columns = $columns;
return $this;
}
@ -266,9 +255,10 @@ class Query extends Protocol\AbstractQuery
}
}
$state = $this->reader->getObjects();
$state = $this->ds->getObjects();
$result = array();
foreach (self::$VALID_TARGETS[$this->source] as $target) {
$source = self::$VALID_TARGETS[$this->source];
foreach ($source as $target) {
$indexes = & array_keys($state[$target]);
if ($baseGroup) {
$indexes = & $baseGroup->filter($state[$target]);
@ -302,11 +292,10 @@ class Query extends Protocol\AbstractQuery
*/
private function orderResult($a, $b)
{
$o1 = & $this->reader->getObjectByName($this->currentType, $a);
$o2 = & $this->reader->getObjectByName($this->currentType, $b);
$o1 = & $this->ds->getObjectByName($this->currentType, $a);
$o2 = & $this->ds->getObjectByName($this->currentType, $b);
$result = 0;
foreach ($this->order_columns as $col) {
$result += $col[1] * strnatcasecmp($o1->{$col[0]}, $o2->{$col[0]});
}
if ($result > 0) {
@ -363,7 +352,7 @@ class Query extends Protocol\AbstractQuery
$result = array();
foreach ($indices as $type => $subindices) {
foreach ($subindices as $objectIndex) {
$r = & $this->reader->getObjectByName($type, $objectIndex);
$r = & $this->ds->getObjectByName($type, $objectIndex);
$hash = "";
$cols = array();
foreach ($this->groupColumns as $col) {
@ -400,7 +389,7 @@ class Query extends Protocol\AbstractQuery
$this->limitIndices($indices);
$result = array();
$state = & $this->reader->getObjects();
$state = & $this->ds->getObjects();
foreach ($indices as $type => $subindices) {
foreach ($subindices as $index) {
@ -409,4 +398,5 @@ class Query extends Protocol\AbstractQuery
}
return $result;
}
}

View File

@ -28,15 +28,16 @@
namespace Icinga\Protocol\Statusdat;
use Icinga\Backend\MonitoringObjectList;
use Icinga\Data\DatasourceInterface;
use Icinga\Exception as Exception;
use Icinga\Benchmark as Benchmark;
use Icinga\Protocol\Statusdat\View\MonitoringObjectList;
/**
* Class Reader
* @package Icinga\Protocol\Statusdat
*/
class Reader implements IReader
class Reader implements IReader, DatasourceInterface
{
/**
*
@ -91,9 +92,12 @@ class Reader implements IReader
public function __construct($config = \Zend_Config, $parser = null, $noCache = false)
{
$this->noCache = $noCache;
if (isset($config->no_cache)) {
$this->noCache = $config->no_cache;
}
$this->config = $config;
$this->parser = $parser;
if (!$noCache) {
if (!$this->noCache) {
$this->cache = $this->initializeCaches($config);
if ($this->fromCache()) {
$this->createHostServiceConnections();
@ -104,7 +108,7 @@ class Reader implements IReader
$this->parseObjectsCacheFile();
}
if (!$this->hasRuntimeState) {
;
}
$this->parseStatusDatFile();
if (!$noCache && $this->newState) {
@ -275,10 +279,7 @@ class Reader implements IReader
*/
public function fetchAll(Query $query)
{
return new MonitoringObjectList(
$query->getResult(),
$query->getView()
);
return $query->getResult();
}
/**
@ -318,4 +319,5 @@ class Reader implements IReader
{
return isset($this->lastState[$type]) ? array_keys($this->lastState[$type]) : null;
}
}

View File

@ -26,14 +26,14 @@
*/
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Backend\DataView;
namespace Icinga\Protocol\Statusdat\View;
/**
* Class AbstractAccessorStrategy
* Basic interface for views.
* The name sound weirder than it is: Views define special get and exists operations for fields
* that are not directly available in a resultset, but exist under another name or can be
* accessed by loading an additional object during runtime.
* Interface for statusdat classes that provide a specific view on the dataset
*
* Views define special get and exists operations for fields that are not directly available
* in a resultset, but exist under another name or can be accessed by loading an additional object
* during runtime.
*
* @see Icinga\Backend\DataView\ObjectRemappingView For an implementation of mapping field names
* to storage specific names, e.g. service_state being status.current_state in status.dat views.
@ -41,9 +41,8 @@ namespace Icinga\Backend\DataView;
* @see Icinga\Backend\MonitoringObjectList For the typical usage of this class. It is not wrapped
* around the monitoring object, so we don't use __get() or __set() and always have to give the
* item we'd like to access.
* @package Icinga\Backend\DataView
*/
interface AbstractAccessorStrategy
interface AccessorStrategy
{
/**
* Returns a field for the item, or throws an Exception if the field doesn't exist

View File

@ -1,9 +1,8 @@
<?php
namespace Icinga\Backend;
/**
* Wrapper around an array of monitoring objects that can be enhanced with an optional
* object that extends AbstractAccessorStrategy. This will act as a dataview and provide
* object that extends AccessorStrategy. This will act as a dataview and provide
* normalized access to the underlying data (mapping properties, retrieving additional data)
*
* If not Accessor is set, this class just behaves like a normal Iterator and returns
@ -12,15 +11,15 @@ namespace Icinga\Backend;
* If the dataset contains arrays instead of objects, they will be cast to objects.
*
*/
use Icinga\Backend\DataView as DataView;
namespace Icinga\Protocol\Statusdat\View;
class MonitoringObjectList implements \Iterator, \Countable
class MonitoringObjectList implements \Iterator, \Countable, \ArrayAccess
{
private $dataSet = array();
private $position = 0;
private $dataView = null;
function __construct(array &$dataset, DataView\AbstractAccessorStrategy $dataView = null)
function __construct(array &$dataset, AccessorStrategy $dataView = null)
{
$this->dataSet = $dataset;
$this->position = 0;
@ -32,6 +31,11 @@ class MonitoringObjectList implements \Iterator, \Countable
return count($this->dataSet);
}
public function setPosition($pos)
{
$this->position = $pos;
}
/**
* (PHP 5 &gt;= 5.0.0)<br/>
* Return the current element
@ -98,8 +102,6 @@ class MonitoringObjectList implements \Iterator, \Countable
function __get($name)
{
return $this->dataView->get($this->dataSet[$this->position],$name);
}
function __set($name, $value)
@ -107,4 +109,26 @@ class MonitoringObjectList implements \Iterator, \Countable
throw new \Exception("Setting is currently not available for objects");
}
public function offsetExists($offset)
{
return count($this->dataSet) < $offset;
}
public function offsetGet($offset)
{
$res = new MonitoringObjectList($this->dataSet, $this->dataView);
$res->position = $offset;
return $res;
}
public function offsetSet($offset, $value)
{
// non mutable
}
public function offsetUnset($offset)
{
// non mutable
}
}

View File

@ -26,7 +26,7 @@
*/
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Backend\DataView;
namespace Icinga\Protocol\Statusdat\View;
/**
* Class ObjectRemappingView
@ -43,18 +43,23 @@ namespace Icinga\Backend\DataView;
* storage specific ones, handlerParameters determins functions that handle data retrieval for
* the specific fields.
*
* @package Icinga\Backend\DataView
*/
class ObjectRemappingView implements AbstractAccessorStrategy
class ObjectRemappingView implements AccessorStrategy
{
/**
* When implementing your own Mapper, this contains the static mapping rules.
* @see Icinga\Backend\Statusdat\DataView\StatusdatServiceView for an example
* @see Monitoring\Backend\Statusdat\DataView\StatusdatServiceView for an example
*
* @var array
*/
protected $mappedParameters = array();
public static $mappedParameters = array();
private $functionMap = array(
"TO_DATE" => "toDateFormat"
);
/**
* When implementing your own Mapper, this contains the handler for specific fields and allows you to lazy load
@ -68,7 +73,7 @@ class ObjectRemappingView implements AbstractAccessorStrategy
/**
*
* @see Icinga\Backend\DataView\AbstractAccessorStrategy
* @see Icinga\Backend\DataView\AccessorStrategy
*
* @param The $item
* @param The $field
@ -81,17 +86,8 @@ class ObjectRemappingView implements AbstractAccessorStrategy
if (isset($item->$field)) {
return $item->$field;
}
if (isset($this->mappedParameters[$field])) {
$mapped = explode(".", $this->mappedParameters[$field]);
$res = $item;
foreach ($mapped as $map) {
if (!isset($res->$map)) {
return "";
}
$res = $res->$map;
}
return $res;
if (isset(static::$mappedParameters[$field])) {
return $this->getMappedParameter($item, $field);
}
if (isset($this->handlerParameters[$field])) {
@ -101,24 +97,66 @@ class ObjectRemappingView implements AbstractAccessorStrategy
throw new \InvalidArgumentException("Field $field does not exist for status.dat services");
}
private function applyPropertyFunction($function, $value)
{
if (!isset($this->functionMap[$function]))
return $value;
$fn = $this->functionMap[$function];
return $this->$fn($value);
}
private function toDateFormat($value)
{
if (is_numeric($value)) {
return date("Y-m-d H:i:s", intval($value));
} else {
return $value;
}
}
private function getMappedParameter(&$item, $field)
{
$matches = array();
$fieldDef = static::$mappedParameters[$field];
$function = false;
if (preg_match_all('/(?P<FUNCTION>\w+)\((?P<PARAMETER>.*)\)/', $fieldDef, $matches)) {
$function = $matches["FUNCTION"][0];
$fieldDef = $matches["PARAMETER"][0];
}
$mapped = explode(".", $fieldDef);
$res = $item;
foreach ($mapped as $map) {
if (!isset($res->$map)) {
return "";
}
$res = $res->$map;
}
if ($function) {
return $this->applyPropertyFunction($function, $res);
}
return $res;
}
/**
*
* @see Icinga\Backend\DataView\AbstractAccessorStrategy
* @see Icinga\Backend\DataView\AccessorStrategy
*
* @param The $field
* @return The|string
*/
public function getNormalizedFieldName($field)
{
if (isset($this->mappedParameters[$field])) {
return $this->mappedParameters[$field];
if (isset(static::$mappedParameters[$field])) {
return static::$mappedParameters[$field];
}
return $field;
}
/**
*
* @see Icinga\Backend\DataView\AbstractAccessorStrategy
* @see Icinga\Backend\DataView\AccessorStrategy
*
* @param The $item
* @param The $field
@ -127,7 +165,7 @@ class ObjectRemappingView implements AbstractAccessorStrategy
public function exists(&$item, $field)
{
return (isset($item->$field)
|| isset($this->mappedParameters[$field])
|| isset(static::$mappedParameters[$field])
|| isset($this->handlerParameters[$field])
);
}

View File

@ -4,6 +4,7 @@ use Icinga\Web\ModuleActionController;
use Icinga\Web\Hook;
use Icinga\File\Csv;
use Monitoring\Backend;
use Icinga\Application\Benchmark;
class Monitoring_ListController extends ModuleActionController
{
@ -20,20 +21,53 @@ class Monitoring_ListController extends ModuleActionController
public function hostsAction()
{
$this->view->hosts = $this->query('hoststatus', array(
'host_name',
'host_state',
'host_acknowledged',
'host_output',
'host_in_downtime',
'host_handled',
'host_last_state_change'
));
$this->view->sort = $this->_getParam('sort');
$this->preserve('sort')->preserve('backend');
if ($this->view->compact) {
Benchmark::measure("hostsAction::query()");
$this->view->hosts = $this->backend->select()->from(
'status',
array(
'host_icon_image',
'host_name',
'host_state',
'host_address',
'host_acknowledged',
'host_output',
'host_long_output',
'host_in_downtime',
'host_is_flapping',
'host_state_type',
'host_handled',
'host_last_check',
'host_last_state_change',
'host_notifications_enabled',
'host_unhandled_service_count',
'host_action_url',
'host_notes_url',
'host_last_comment'
)
);
if ($search = $this->_getParam('search')) {
$this->_setParam('search', null);
if (strpos($search, '=') === false) {
$this->_setParam('host_name', $search);
} else {
list($key, $val) = preg_split('~\s*=\s*~', $search, 2);
if ($this->view->hosts->isValidFilterColumn($key) || $key[0] === '_') {
$this->_setParam($key, $val);
}
}
}
//$this->view->hosts->getQuery()->group('host_id');
if ($this->_getParam('dump') === 'sql') {
echo '<pre>' . htmlspecialchars(wordwrap($this->view->hosts->getQuery()->dump())) . '</pre>';
exit;
}
if ($this->_getParam('view') === 'compact') {
$this->_helper->viewRenderer('hosts_compact');
}
}
public function servicesAction()
@ -49,22 +83,36 @@ class Monitoring_ListController extends ModuleActionController
$this->view->services = $this->query('status', array(
'host_name',
'host_problems',
'host_state',
'host_state_type',
'host_last_state_change',
'host_address',
'host_handled',
'service_description',
'service_display_name',
'service_state' => $state_column,
'service_in_downtime',
'service_acknowledged',
'service_handled',
'service_output',
'service_last_state_change' => $state_change_column
'service_last_state_change' => $state_change_column,
'service_icon_image',
'service_long_output',
'service_is_flapping',
'service_state_type',
'service_handled',
'service_severity',
'service_last_check',
'service_notifications_enabled',
'service_action_url',
'service_notes_url',
'service_last_comment'
));
$this->preserve('sort')
->preserve('backend')
->preserve('extracolumns');
$this->view->sort = $this->_getParam('sort');
if ($this->view->compact) {
$this->_helper->viewRenderer('services-compact');
if ($this->_getParam('sort')) {
$this->view->sort = $this->_getParam('sort');
}
}
public function hostgroupsAction()

View File

@ -1,15 +1,30 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
use Monitoring\Backend;
use Icinga\Web\ModuleActionController;
use Icinga\Web\Hook;
use Monitoring\Object\Host;
use Monitoring\Object\Service;
use Icinga\Application\Benchmark;
/**
* Class Monitoring_ShowController
*
* Actions for show context
*/
class Monitoring_ShowController extends ModuleActionController
{
/**
* @var Backend
*/
protected $backend;
/**
* Initialize the controller
*/
public function init()
{
$host = $this->_getParam('host');
@ -27,8 +42,14 @@ class Monitoring_ShowController extends ModuleActionController
}
}
$this->backend = Backend::getInstance($this->_getParam('backend'));
if ($service !== null && $service !== '*') {
$this->view->service = $this->backend->fetchService($host, $service);
}
if ($host !== null) {
$this->view->host = $this->backend->fetchHost($host, true);
}
$this->view->compact = $this->_getParam('view') === 'compact';
if ($object === null) {
// TODO: Notification, not found
$this->redirectNow('monitoring/list/services');
@ -39,45 +60,243 @@ class Monitoring_ShowController extends ModuleActionController
$this->prepareTicketHook();
}
/**
* Service overview
*/
public function serviceAction()
{
Benchmark::measure('Entered service action');
$this->view->active = 'service';
$this->view->tabs->activate('service')->enableSpecialActions();
if ($grapher = Hook::get('grapher')) {
if ($grapher->hasGraph(
$this->view->host->host_name,
$this->view->service->service_description
)
) {
$this->view->preview_image = $grapher->getPreviewImage(
$this->view->host->host_name,
$this->view->service->service_description
);
}
}
$this->view->contacts = $this->backend->select()
->from(
'contact',
array(
'contact_name',
'contact_alias',
'contact_email',
'contact_pager',
)
)
->where('service_host_name', $this->view->host->host_name)
->where('service_description', $this->view->service->service_description)
->fetchAll();
$this->view->contactgroups = $this->backend->select()
->from(
'contactgroup',
array(
'contactgroup_name',
'contactgroup_alias',
)
)
->where('service_host_name', $this->view->host->host_name)
->where('service_description', $this->view->service->service_description)
->fetchAll();
$this->view->comments = $this->backend->select()
->from(
'comment',
array(
'comment_timestamp',
'comment_author',
'comment_data',
'comment_type',
)
)
->where('service_host_name', $this->view->host->host_name)
->where('service_description', $this->view->service->service_description)
->fetchAll();
$this->view->customvars = $this->backend->select()
->from(
'customvar',
array(
'varname',
'varvalue'
)
)
->where('varname', '-*PW*,-*PASS*')
->where('host_name', $this->view->host->host_name)
->where('service_description', $this->view->service->service_description)
->where('object_type', 'service')
->fetchPairs();
Benchmark::measure('Service action done');
$object = $this->view->object->prefetch();
$this->prepareGrapherHook();
}
/**
* Host overview
*/
public function hostAction()
{
$this->view->active = 'host';
$this->view->tabs->activate('host')->enableSpecialActions();
if ($grapher = Hook::get('grapher')) {
if ($grapher->hasGraph($this->view->host->host_name)) {
$this->view->preview_image = $grapher->getPreviewImage(
$this->view->host->host_name
);
}
}
$this->view->hostgroups = $this->backend->select()
->from(
'hostgroup',
array(
'hostgroup_name',
'hostgroup_alias'
)
)
->where('host_name', $this->view->host->host_name)
->fetchPairs();
$this->view->contacts = $this->backend->select()
->from(
'contact',
array(
'contact_name',
'contact_alias',
'contact_email',
'contact_pager',
)
)
->where('host_name', $this->view->host->host_name)
->fetchAll();
$this->view->contactgroups = $this->backend->select()
->from(
'contactgroup',
array(
'contactgroup_name',
'contactgroup_alias',
)
)
->where('host_name', $this->view->host->host_name)
->fetchAll();
$this->view->comments = $this->backend->select()
->from(
'comment',
array(
'comment_timestamp',
'comment_author',
'comment_data',
'comment_type',
)
)
->where('host_name', $this->view->host->host_name)
->fetchAll();
$this->view->downtimes = $this->backend->select()
->from(
'downtime',
array(
'host_name',
'downtime_type',
'downtime_author_name',
'downtime_comment_data',
'downtime_is_fixed',
'downtime_duration',
'downtime_scheduled_start_time',
'downtime_scheduled_end_time',
'downtime_actual_start_time',
'downtime_was_started',
'downtime_is_in_effect',
'downtime_internal_downtime_id'
)
)
->where('host_name', $this->view->host->host_name)
->fetchAll();
$this->view->customvars = $this->backend->select()
->from(
'customvar',
array(
'varname',
'varvalue'
)
)
->where('varname', '-*PW*,-*PASS*')
->where('host_name', $this->view->host->host_name)
->where('object_type', 'host')
->fetchPairs();
$this->view->object->prefetch();
$this->prepareGrapherHook();
}
/**
* History entries for objects
*/
public function historyAction()
{
$this->view->history = $this->backend->select()
->from('eventHistory', array(
'object_type',
'host_name',
'service_description',
'timestamp',
'state',
'attempt',
'max_attempts',
'output',
'type'
))->applyRequest($this->_request);
->from(
'eventHistory',
array(
'object_type',
'host_name',
'service_description',
'timestamp',
'state',
'attempt',
'max_attempts',
'output',
'type'
)
)->applyRequest($this->_request);
$this->view->preserve = $this->view->history->getAppliedFilter()->toParams();
if ($this->_getParam('dump') === 'sql') {
echo '<pre>' . htmlspecialchars($this->view->history->getQuery()->dump()) . '</pre>';
exit;
}
if ($this->_getParam('sort')) {
$this->view->preserve['sort'] = $this->_getParam('sort');
}
$this->view->preserve = $this->view->history->getAppliedFilter()->toParams();
}
/**
* Service overview
*/
public function servicesAction()
{
$this->_setParam('service', null);
// Ugly and slow:
$this->view->services = $this->view->action(
'services',
'list',
'monitoring',
array(
'host_name' => $this->view->host->host_name,
//'sort', 'service_description'
)
);
$this->view->services = $this->view->action('services', 'list', 'monitoring', array(
'view' => 'compact'
));
}
/**
* Ticets actions
*/
public function ticketAction()
{
if (Hook::has('ticket')) {
@ -85,9 +304,14 @@ class Monitoring_ShowController extends ModuleActionController
$id = $this->_getParam('ticket');
$ticketModule = 'rt';
$this->render();
$this->_forward('ticket', 'show', $ticketModule, array(
'id' => $id
));
$this->_forward(
'ticket',
'show',
$ticketModule,
array(
'id' => $id
)
);
}
}
@ -131,12 +355,21 @@ class Monitoring_ShowController extends ModuleActionController
}
}
}
/**
* Creating tabs for this controller
* @return \Icinga\Web\Widget\AbstractWidget
*/
protected function createTabs()
{
$object = $this->view->object;
$tabs = $this->widget('tabs');
$params = array('host' => $object->host_name);
if (!$this->view->host) {
return $tabs;
}
$params = array(
'host' => $this->view->host->host_name,
);
if ($backend = $this->_getParam('backend')) {
$params['backend'] = $backend;
}
@ -145,54 +378,66 @@ class Monitoring_ShowController extends ModuleActionController
} elseif ($service = $this->_getParam('service')) {
$params['service'] = $service;
}
// TODO: Work with URL
$servicesParams = $params;
unset($servicesParams['service']);
$tabs->add('host', array(
'title' => 'Host',
'icon' => 'img/classic/server.png',
'url' => 'monitoring/show/host',
'urlParams' => $params,
));
$tabs->add('services', array(
'title' => 'Services',
'icon' => 'img/classic/service.png',
'url' => 'monitoring/show/services',
'urlParams' => $servicesParams,
));
if (isset($params['service'])) {
$tabs->add('service', array(
'title' => 'Service',
'icon' => 'img/classic/service.png',
'url' => 'monitoring/show/service',
$tabs->add(
'host',
array(
'title' => 'Host',
'icon' => 'img/classic/server.png',
'url' => 'monitoring/show/host',
'urlParams' => $params,
));
)
);
$tabs->add(
'services',
array(
'title' => 'Services',
'icon' => 'img/classic/service.png',
'url' => 'monitoring/show/services',
'urlParams' => $params,
)
);
if (isset($params['service'])) {
$tabs->add(
'service',
array(
'title' => 'Service',
'icon' => 'img/classic/service.png',
'url' => 'monitoring/show/service',
'urlParams' => $params,
)
);
}
$tabs->add('history', array(
'title' => 'History',
'icon' => 'img/classic/history.gif',
'url' => 'monitoring/show/history',
'urlParams' => $params,
));
$tabs->add(
'history',
array(
'title' => 'History',
'icon' => 'img/classic/history.gif',
'url' => 'monitoring/show/history',
'urlParams' => $params,
)
);
if ($this->action_name === 'ticket') {
$tabs->add('ticket', array(
'title' => 'Ticket',
'icon' => 'img/classic/ticket.gif',
'url' => 'monitoring/show/ticket',
'urlParams' => $params + array('ticket' => $this->_getParam('ticket')),
));
$tabs->add(
'ticket',
array(
'title' => 'Ticket',
'icon' => 'img/classic/ticket.gif',
'url' => 'monitoring/show/ticket',
'urlParams' => $params + array('ticket' => $this->_getParam('ticket')),
)
);
}
$tabs->activate($this->action_name)->enableSpecialActions();
/*
/**
$tabs->add('contacts', array(
'title' => 'Contacts',
'icon' => 'img/classic/customer.png',
'url' => 'monitoring/detail/contacts',
'urlParams' => $params,
));
*/
*/
// TODO: Inventory 'img/classic/facts.gif'
// Ticket 'img/classic/ticket.gif'
// Customer 'img/classic/customer.png'

View File

@ -0,0 +1,88 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
/**
* Icinga 2 Web - Head for multiple monitoring frontends
* Copyright (C) 2013 Icinga Development Team
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* @copyright 2013 Icinga Development Team <info@icinga.org>
* @author Icinga Development Team <info@icinga.org>
*/
// {{{ICINGA_LICENSE_HEADER}}}
use \Monitoring\Command\Meta;
/**
* Class MonitoringCommands
*
* Helper which produces a list of command buttons
* depending on object states
*/
class Zend_View_Helper_MonitoringCommands extends Zend_View_Helper_Abstract
{
/**
* @param stdClass $object host or service object or something other
* @param string $type small or full
* @return string html output
*/
public function monitoringCommands(\stdClass $object, $type)
{
$commands = new Meta();
$definitions = $commands->getCommandForObject($object, $type);
$out = '<div>';
$i = 0;
foreach ($definitions as $definition) {
if ($i % 5 === 0) {
$out .= '</div><div class="command-section pull-left">';
}
if ($type === Meta::TYPE_FULL) {
$out .= '<div>';
}
$out .= sprintf(
'<button type="button" data-target="command"'
. ' data-command-id="%1$s" class="btn %5$s"'
. ' title="%3$s">'
. '<i class="%4$s"></i> %2$s'
. '</button>',
$definition->id,
$definition->shortDescription,
$definition->longDescription,
$definition->iconCls,
$definition->btnCls
);
if ($type === Meta::TYPE_FULL) {
$out .= '</div>';
}
$i++;
}
$out .= '</div>';
$out .= '<div class="clearfix"></div>';
if ($type === Meta::TYPE_FULL) {
return '<div class="command-container">'. $out. '</div>';
}
return $out;
}
}

View File

@ -0,0 +1,56 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
/**
* Class Zend_View_Helper_MonitoringFlags
*
* Rendering helper for flags depending on objects
*/
class Zend_View_Helper_MonitoringFlags extends Zend_View_Helper_Abstract
{
/**
* Key of flags without prefix (e.g. host or service)
* @var string[]
*/
private static $keys = array(
'passive_checks_enabled' => 'Passive checks',
'active_checks_enabled' => 'Active checks',
'obsess_over_host' => 'Obsessing',
'notifications_enabled' => 'Notifications',
'event_handler_enabled' => 'Event handler',
'flap_detection_enabled' => 'Flap detection',
);
/**
* Type prefix
* @param array $vars
* @return string
*/
private function getObjectType(array $vars)
{
return array_shift(explode('_', array_shift(array_keys($vars)), 2));
}
/**
* Build all existing flags to a readable array
* @param stdClass $object
* @return array
*/
public function monitoringFlags(\stdClass $object)
{
$vars = (array)$object;
$type = $this->getObjectType($vars);
$out = array();
foreach (self::$keys as $key => $name) {
$value = false;
if (array_key_exists(($realKey = $type. '_'. $key), $vars)) {
$value = $vars[$realKey] === '1' ? true : false;
}
$out[$name] = $value;
}
return $out;
}
}

View File

@ -0,0 +1,249 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
/**
* Class Zend_View_Helper_MonitoringProperties
*/
class Zend_View_Helper_MonitoringProperties extends Zend_View_Helper_Abstract
{
/**
* Value for check type active
*/
const CHECK_ACTIVE = 'ACTIVE';
/**
* Value for check type passive
*/
const CHECK_PASSIVE = 'PASSIVE';
/**
* Value for check type disabled
*/
const CHECK_DISABLED = 'DISABLED';
/**
* Return value for not available
*/
const VALUE_NA = 'N/A';
/**
* Return value for "YES"
*/
const VALUE_YES = 'YES';
/**
* Return value for "NO"
*/
const VALUE_NO = 'NO';
/**
* Label / value mapping for object keys
*
* Keys can be callables in this object
*
* @var array
*/
private static $keys = array(
'buildAttempt' => 'Current attempt',
'last_check' => 'Last check time',
'buildCheckType' => 'Check type',
'buildLatency' => 'Check latency / duration',
'buildNextCheck' => 'Next scheduled active check',
'buildLastStateChange' => 'Last state change',
'buildLastNotification' => 'Last notification',
'buildFlapping' => 'Is this %s flapping?',
'buildScheduledDowntime' => 'In scheduled downtime?',
'status_update_time' => 'Last update'
);
/**
* Return the object type
* @param stdClass $object
* @return mixed
*/
private function getObjectType(\stdClass $object)
{
return array_shift(explode('_', array_shift(array_keys(get_object_vars($object))), 2));
}
/**
* Drop all object specific attribute prefixes
* @param stdClass $object
* @param $type
* @return object
*/
private function dropObjectType(\stdClass $object, $type)
{
$vars = get_object_vars($object);
$out = array();
foreach ($vars as $name => $value) {
$name = str_replace($type. '_', '', $name);
$out[$name] = $value;
}
return (object)$out;
}
/**
* Get string for attempt
* @param stdClass $object
* @return string
*/
private function buildAttempt(\stdClass $object)
{
return sprintf(
'%s/%s (%s state)',
$object->current_check_attempt,
$object->max_check_attempts,
($object->state_type === '1') ? 'HARD' : 'SOFT'
);
}
/**
* Generic fomatter for float values
* @param $value
* @return string
*/
private function floatFormatter($value)
{
return sprintf('%.4f', $value);
}
/**
* Get the string for check type
* @param stdClass $object
* @return string
*/
private function buildCheckType(\stdClass $object)
{
if ($object->passive_checks_enabled === '1' && $object->active_checks_enabled === '0') {
return self::CHECK_PASSIVE;
} elseif ($object->passive_checks_enabled === '0' && $object->active_checks_enabled === '0') {
return self::CHECK_DISABLED;
}
return self::CHECK_ACTIVE;
}
/**
* Get string for latency
* @param stdClass $object
* @return string
*/
private function buildLatency(\stdClass $object)
{
$val = '';
if ($this->buildCheckType($object) === self::CHECK_PASSIVE) {
$val .= self::VALUE_NA;
} else {
$val .= $this->floatFormatter($object->latency);
}
$val .= ' / '. $this->floatFormatter($object->execution_time). ' seconds';
return $val;
}
/**
* Get string for next check
* @param stdClass $object
* @return string
*/
private function buildNextCheck(\stdClass $object)
{
if ($this->buildCheckType($object) === self::CHECK_PASSIVE) {
return self::VALUE_NA;
} else {
return $object->next_check;
}
}
/**
* Get date for last state change
* @param stdClass $object
* @return string
*/
private function buildLastStateChange(\stdClass $object)
{
return strftime('%Y-%m-%d %H:%M:%S', $object->last_state_change);
}
/**
* Get string for "last notification"
* @param stdClass $object
* @return string
*/
private function buildLastNotification(\stdClass $object)
{
$val = '';
if ($object->last_notification === '0000-00-00 00:00:00') {
$val .= self::VALUE_NA;
} else {
$val .= $object->last_notification;
}
$val .= sprintf(' (notification %d)', $object->current_notification_number);
return $val;
}
/**
* Get string for "is flapping"
* @param stdClass $object
* @return string
*/
private function buildFlapping(\stdClass $object)
{
$val = '';
if ($object->is_flapping === '0') {
$val .= self::VALUE_NO;
} else {
$val .= self::VALUE_YES;
}
$val .= sprintf(' (%.2f%% state change)', $object->percent_state_change);
return $val;
}
/**
* Get string for scheduled downtime
* @param stdClass $object
* @return string
*/
private function buildScheduledDowntime(\stdClass $object)
{
if ($object->in_downtime === '1') {
return self::VALUE_YES;
}
return self::VALUE_NO;
}
/**
* Get an array which represent monitoring properties
*
* @param stdClass $object
* @return array
*/
public function monitoringProperties(\stdClass $object)
{
$type = $this->getObjectType($object);
$object = $this->dropObjectType($object, $type);
$out = array();
foreach (self::$keys as $property => $label) {
$label = sprintf($label, $type);
if (is_callable(array(&$this, $property))) {
$out[$label] = $this->$property($object);
} elseif (isset($object->{$property})) {
$out[$label] = $object->{$property};
}
}
return $out;
}
}

View File

@ -6,14 +6,44 @@ class Zend_View_Helper_MonitoringState extends Zend_View_Helper_Abstract
private $servicestates = array('ok', 'warning', 'critical', 'unknown', 99 => 'pending', null => 'pending');
private $hoststates = array('up', 'down', 'unreachable', 99 => 'pending', null => 'pending');
public function monitoringState($object, $type = 'service') {
public function monitoringState($object, $type = 'service')
{
if ($type === 'service') {
return $this->servicestates[$object->service_state];
} else if ($type === 'host') {
} elseif ($type === 'host') {
return $this->hoststates[$object->host_state];
}
}
}
public function getStateFlags($object, $type = 'service')
{
$state_classes = array();
if ($type === 'host') {
$state_classes[] = $this->monitoringState($object, "host");
if ($object->host_acknowledged || $object->host_in_downtime) {
$state_classes[] = 'handled';
}
if ($object->host_last_state_change > (time() - 600)) {
$state_classes[] = 'new';
}
} else {
$state_classes[] = $this->monitoringState($object, "service");
if ($object->service_acknowledged || $object->service_in_downtime) {
$state_classes[] = 'handled';
}
if ($object->service_last_state_change > (time() - 600)) {
$state_classes[] = 'new';
}
}
return $state_classes;
}
public function getStateTitle($object, $type)
{
return strtoupper($this->monitoringState($object, $type))
. ' since '
. date('Y-m-d H:i:s', $object->{$type.'_last_state_change'});
}
}

View File

@ -0,0 +1,19 @@
<?php
class Zend_View_Helper_Trim extends Zend_View_Helper_Abstract
{
public function start()
{
ob_start("Zend_View_Helper_Trim::trimfunc");
}
public static function trimfunc($string)
{
return trim($string);
}
public function end()
{
ob_end_flush();
}
}

View File

@ -1,127 +1,128 @@
<?= $this->tabs ?>
<?php
$paginator = $hosts->paginate();
function getRowProperties(& $host, $scope) {
$icons = array();
if ($host->host_acknowledged) {
$icons['ack.gif'] = 'Problem has been acknowledged';
}
if ($host->host_in_downtime) {
$icons['downtime.gif'] = 'Host is in a scheduled downtime';
}
$state_classes = array($scope->monitoringState($host, 'host'));
if ($host->host_acknowledged || $host->host_in_downtime) {
$state_classes[] = 'handled';
}
if ($host->host_last_state_change > (time() - 600)) {
$state_classes[] = 'new';
}
$state_title = strtoupper($scope->monitoringState($host,"host"))
. ' since '
. date('Y-m-d H:i:s', $host->host_last_state_change);
return array($icons,$state_classes,$state_title);
}
// filter start
$fparams = $this->hosts->getAppliedFilter()->toParams();
if ($this->preserve === null) {
$this->preserve = $fparams;
} else {
$this->preserve += $fparams;
}
$always = array();
if (isset($_GET['sort'])) {
$always['sort'] = $_GET['sort'];
}
if (isset($_GET['dir'])) {
$always['dir'] = $_GET['dir'];
}
$hosts = $this->hosts->paginate();
$viewHelper = $this->getHelper('MonitoringState');
$trimArea = $this->getHelper('Trim');
?>
<? if (! empty($fparams)): ?>
<div style="float: right; width: 20em; font-size: 0.8em;"><b>Filters</b><br>
<? foreach ($fparams as $k => $v): ?>
<?= $this->qlink(
'x',
'monitoring/list/hosts',
$this->hosts->getAppliedFilter()->without($k)->toParams() + $always,
array(
'style' => array('color' => 'red')
)
) ?> <?= $this->escape("$k = $v") ?></br>
<? endforeach ?>
</div>
<? endif ?>
<form method="get" action="<?= $this->qUrl(
'monitoring/list/hosts?' . http_build_query(
$this->hosts->getAppliedFilter()->toParams()
),
'monitoring/list/hosts?' . http_build_query($this->hosts->getAppliedFilter()->toParams()),
array()
)
);
?>">
Sort by <?= $this->formSelect(
'sort',
$this->sort,
array('class' => 'autosubmit'),
array(
'host_severity' => 'Severity',
'host_last_state_change' => 'Last state change',
'host_name' => 'Host',
'host_last_time_up' => 'Last UP',
'host_last_time_down' => 'Last DOWN',
'host_last_time_unreachable' => 'Last UNREACHABLE',
)
) ?>
<input type="text" placeholder="Add filter..." name="search" value="<?= $this->escape($this->search) ?>" />
Sort by <?= $this->formSelect(
'sort',
$this->sort,
array('class' => 'autosubmit'),
array(
'host_severity' => 'Severity',
'host_last_state_change' => 'Last state change',
'host_name' => 'Host',
)
) ?>
<input type="search" name="filter" placeholder="Type to filter" />
<button class="btn btn-small"><i class="icon-refresh"></i></button>
</form>
<?php // end filter ?>
<? if (empty($hosts)): ?>
<?= $this->paginationControl($hosts, null, null, array('preserve' => $this->preserve)) ?>
<div class="alert alert-info fullpage_infobox">
Sorry, no host found for this search
</div>
<? return; endif ?>
<table class="statustable action hosts">
<?= $this->paginationControl($paginator, null, null, array('preserve' => $this->preserve)) ?>
<table class="action">
<tbody>
<thead>
<tr>
<th colspan="3">Status</th>
<th>Host</th>
<th>Output</th>
<th></th>
</tr>
</thead>
<tbody>
<?php foreach($hosts as $host): ?>
<tr class="<?= implode(' ', $viewHelper->getStateFlags($host, 'host')); ?>">
<td class="icons indicator">
<div class="img-box"><?php $trimArea->start(); ?>
<?php if ($host->host_icon_image) : ?>
<img src="<?= $host->host_icon_image; ?>"/>
<?php endif; ?>
<?php $trimArea->end(); ?></div>
</td>
<td class="icons indicator">
<div class="icon-box"><?php $trimArea->start(); ?>
<?php if (!$host->host_handled): ?>
<a href="#" title="<?= 'Unhandled host' ?>">
<i class="icon-warning-sign"></i>
</a>
<?php endif; ?>
<?php if ($host->host_acknowledged && !$host->host_in_downtime): ?>
<a href="#" title="<?= 'Acknowledged' ?>">
<i class="icon-ok-sign"></i>
</a>
<?php endif; ?>
<?php if ($host->host_is_flapping): ?>
<a href="#" title="<?= 'Flapping' ?>">
<i class="icon-random"></i>
</a>
<?php endif; ?>
<?php if (!$host->host_notifications_enabled): ?>
<a href="#" title="<?= 'Notifications disabled' ?>">
<i class="icon-volume-off"></i>
</a>
<?php endif; ?>
<?php if ($host->host_in_downtime): ?>
<a href="#" title="<?= 'In downtime' ?>">
<i class="icon-wrench"></i>
</a>
<?php endif; ?>
<?php $trimArea->end(); ?></div>
</td>
<td class="indicator state" title="<?= $viewHelper->getStateTitle($host, 'host'); ?>">
<div class="statetext">
<?= $this->qlink(
"<b>".ucfirst($viewHelper->monitoringState($host, 'host'))."</b>".
'<div class="nowrap"> since&nbsp;'.
$this->timeSince($host->host_last_state_change),
'monitoring/show/history', array(
'host' => $host->host_name
),
array('quote' => false)
);?>
<?php if ($host->host_state_type == 0): ?>
<a href="#" title="<?= 'Soft state' ?>">
<i class="icon-gears"></i>
</a>
<?php endif; ?>
</div>
</td>
<td class="hostname">
<?php if ($host->host_last_comment !== null): ?>
<a href="#" title="<?= 'Comments' ?>">
<i class="icon-comment"> </i>
</a>
<?php endif; ?>
<?= $this->qlink(
"<b>".$host->host_name."</b><br/>".
"<i>".$host->host_address."</i>",
'monitoring/show/host', array(
'host' => $host->host_name
), array(
'class' => 'row-action',
'quote' => false
)
); ?>
<? foreach ($hosts->fetchAll() as $host):
list($icons,$state_classes,$state_title) = getRowProperties($host,$this); ?>
<tr class="<?= implode(' ', $state_classes) ?>">
<td class="state" title="<?= $state_title ?>"><?= $this->qlink(
substr(strtoupper($this->monitoringState($host,"host")), 0, 4)
. '&nbsp;since<br /> '
. $this->timeSince($host->host_last_state_change),
'monitoring/show/history', array(
'host' => $host->host_name
),
array('quote' => false)
) ?></td>
<td><?
foreach ($icons as $icon => $alt)
echo $this->img('img/classic/' . $icon, array(
'class' => 'icon',
'title' => $alt
));
?>
<?= $this->qlink(
$host->host_name,
'monitoring/show/host', array(
'host' => $host->host_name
), array('class' => 'row-action')
) ?><br />
<span style="font-size: 0.7em"><?=
$this->escape(substr(strip_tags($host->host_output), 0, 10000))
?></span>
</td>
</tr>
<?php if ($host->host_action_url != ""): ?>
<a href="<?= $host->host_action_url; ?>">Action</a>
<?php endif; ?>
<?php if ($host->host_notes_url != ""): ?>
<a href="<?= $host->host_notes_url; ?>">Notes</a>
<?php endif; ?>
</td>
<td class="expand-full">
<?= $this->escape(substr(strip_tags($host->host_output), 0, 10000)); ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</tbody>
</table>

View File

@ -0,0 +1,171 @@
<?= $this->tabs ?>
<?php
$paginator = $services->paginate();
function getRowProperties(&$service, &$last_host, $scope) {
if ($last_host !== $service->host_name) {
$host_col = '<b>' . $scope->qlink(
$service->host_name,
'monitoring/show/host',
array('host' => $service->host_name)
) . ':</b><span style="font-size: 0.7em">'
. (isset($service->host->address) ? ' ( ' . $scope->escape($service->host->address) . ')' : '')
. '</span>';
$last_host = $service->host_name;
} else {
$host_col = '&nbsp; ';
}
$icons = array();
if ($service->service_acknowledged) {
$icons['ack.gif'] = 'Problem has been acknowledged';
}
if ($service->service_in_downtime) {
$icons['downtime.gif'] = 'Service is in a scheduled downtime';
}
if ($service->host_problems) {
$icons['server.png'] = 'This services host has a problem';
}
$state_classes = array($scope->monitoringState($service));
if ($service->service_handled) {
$state_classes[] = 'handled';
}
if ($service->service_last_state_change > (time() - 600)) {
$state_classes[] = 'new';
}
$state_title = strtoupper($scope->monitoringState($service))
. ' since '
. date('Y-m-d H:i:s', $service->service_last_state_change);
if ($scope->grapher && $scope->grapher->hasGraph($service->host_name, $service->service_description)) {
$graph = $scope->grapher->getSmallPreviewImage(
$service->host_name,
$service->service_description
);
} else {
$graph = '';
}
return array($host_col,$icons,$state_classes,$state_title,$graph);
}
$fparams = $this->services->getAppliedFilter()->toParams();
if ($this->preserve === null) {
$this->preserve = $fparams;
} else {
$this->preserve += $fparams;
}
$last_host = null;
$always = array();
if (isset($_GET['sort'])) {
$always['sort'] = $_GET['sort'];
}
if (isset($_GET['dir'])) {
$always['dir'] = $_GET['dir'];
}
?>
<div class="dontprint">
<? if (! empty($fparams)): ?>
<div style="float: right; width: 20em; font-size: 0.8em;"><b>Filters</b><br>
<? foreach ($fparams as $k => $v): ?>
<?= $this->qlink(
'x',
'monitoring/list/services',
$this->services->getAppliedFilter()->without($k)->toParams() + $always,
array(
'style' => array('color' => 'red')
)
) ?> <?= $this->escape("$k = $v") ?></br>
<? endforeach ?>
</div>
<? endif ?>
<form method="get" action="<?= $this->qUrl(
'monitoring/list/services?' . http_build_query(
$this->services->getAppliedFilter()->toParams()
),
array()
)
?>">
Sort by <?= $this->formSelect(
'sort',
$this->sort,
array(
'class' => 'autosubmit',
),
array(
'severity' => 'Severity',
'service_last_state_change' => 'Last state change',
'service_last_time_unknown' => 'Last UNKNOWN',
'service_last_time_critical' => 'Last CRITICAL',
'service_last_time_warning' => 'Last WARNING',
'service_last_time_ok' => 'Last OK',
'host_name' => 'Host',
'service_description' => 'Service',
)
) ?>
<?= $this->formText(
'search',
$this->search,
array(
'placeholder' => 'Add filllter...',
)
) ?>
</form>
</div>
<?php if (empty($services)): ?>
<div class="alert alert-info fullpage_infobox">
Sorry, no services found for this search
</div>
<?php return; endif ?>
<?= $this->paginationControl($paginator, null, null, array('preserve' => $this->preserve )); ?>
<table class="action">
<tbody>
<?php foreach ($services->fetchAll() as $service):
list($host_col,$icons,$state_classes,$state_title,$graph) = getRowProperties($service,$last_host,$this); ?>
<tr class="<?= implode(' ', $state_classes) ?>">
<td class="state" title="<?= $state_title ?>">
<?= $this->qlink(
$service->service_state == 99 ? 'PENDING' :
substr(strtoupper($this->monitoringState($service)), 0, 4)
. '&nbsp;since<br /> '
. $this->timeSince($service->service_last_state_change),
'monitoring/show/history', array(
'host' => $service->host_name,
'service' => $service->service_description
), array('quote' => false)) ?>
</td>
<td>
<?php
foreach ($icons as $icon => $alt) {
echo $this->img('img/classic/' . $icon, array(
'class' => 'icon',
'title' => $alt
));
} ?>
<?= $host_col ?>
<?= $this->qlink($service->service_description, 'monitoring/show/service', array(
'host' => $service->host_name,
'service' => $service->service_description
), array('class' => 'row-action')
)
?>
<br />
&nbsp; &nbsp; <span style="font-size: 0.7em">
<?= $this->escape(substr(strip_tags($service->service_output), 0, 900)) ?>
</span>
<?= $graph ?>
</td>
<? foreach ($this->extraColumns as $col): ?>
<td><?= $this->escape($service->$col) ?></td>
<? endforeach ?>
</tr>
<?php endforeach; ?>
</tbody>
</table>

View File

@ -1,171 +1,180 @@
<?= $this->tabs ?>
<?php
<?php
$paginator = $services->paginate();
function getRowProperties(&$service, &$last_host, $scope) {
if ($last_host !== $service->host_name) {
$host_col = '<b>' . $scope->qlink(
$service->host_name,
'monitoring/show/host',
array('host' => $service->host_name)
) . ':</b><span style="font-size: 0.7em">'
. (isset($service->host->address) ? ' ( ' . $scope->escape($service->host->address) . ')' : '')
. '</span>';
$last_host = $service->host_name;
} else {
$host_col = '&nbsp; ';
}
$icons = array();
if ($service->service_acknowledged) {
$icons['ack.gif'] = 'Problem has been acknowledged';
}
if ($service->service_in_downtime) {
$icons['downtime.gif'] = 'Service is in a scheduled downtime';
}
if ($service->host_problems) {
$icons['server.png'] = 'This services host has a problem';
}
$state_classes = array($scope->monitoringState($service));
if ($service->service_handled) {
$state_classes[] = 'handled';
}
if ($service->service_last_state_change > (time() - 600)) {
$state_classes[] = 'new';
}
$state_title = strtoupper($scope->monitoringState($service))
. ' since '
. date('Y-m-d H:i:s', $service->service_last_state_change);
if ($scope->grapher && $scope->grapher->hasGraph($service->host_name, $service->service_description)) {
$graph = $scope->grapher->getSmallPreviewImage(
$service->host_name,
$service->service_description
);
} else {
$graph = '';
}
return array($host_col,$icons,$state_classes,$state_title,$graph);
}
$fparams = $this->services->getAppliedFilter()->toParams();
if ($this->preserve === null) {
$this->preserve = $fparams;
} else {
$this->preserve += $fparams;
}
$last_host = null;
$always = array();
if (isset($_GET['sort'])) {
$always['sort'] = $_GET['sort'];
}
if (isset($_GET['dir'])) {
$always['dir'] = $_GET['dir'];
}
$viewHelper = $this->getHelper('MonitoringState');
$trimArea = $this->getHelper('Trim');
?>
<div class="dontprint">
<? if (! empty($fparams)): ?>
<div style="float: right; width: 20em; font-size: 0.8em;"><b>Filters</b><br>
<? foreach ($fparams as $k => $v): ?>
<?= $this->qlink(
'x',
'monitoring/list/services',
$this->services->getAppliedFilter()->without($k)->toParams() + $always,
array(
'style' => array('color' => 'red')
)
) ?> <?= $this->escape("$k = $v") ?></br>
<? endforeach ?>
</div>
<? endif ?>
<form method="get" action="<?= $this->qUrl(
'monitoring/list/services?' . http_build_query(
$this->services->getAppliedFilter()->toParams()
),
array()
)
?>">
Sort by <?= $this->formSelect(
'sort',
$this->sort,
array(
'class' => 'autosubmit',
),
array(
'severity' => 'Severity',
'service_last_state_change' => 'Last state change',
'service_last_time_unknown' => 'Last UNKNOWN',
'service_last_time_critical' => 'Last CRITICAL',
'service_last_time_warning' => 'Last WARNING',
'service_last_time_ok' => 'Last OK',
'host_name' => 'Host',
'service_description' => 'Service',
)
) ?>
<?= $this->formText(
'search',
$this->search,
array(
'placeholder' => 'Add filllter...',
)
) ?>
</form>
</div>
<?php if (empty($services)): ?>
<div class="alert alert-info fullpage_infobox">
Sorry, no services found for this search
</div>
<div class="alert alert-info fullpage_infobox">
Sorry, no services found for this search
</div>
<?php return; endif ?>
<?= $this->paginationControl($paginator, null, null, array('preserve' => $this->preserve )); ?>
<table class="action">
<tbody>
<?php foreach ($services->fetchAll() as $service):
list($host_col,$icons,$state_classes,$state_title,$graph) = getRowProperties($service,$last_host,$this); ?>
<tr class="<?= implode(' ', $state_classes) ?>">
<td class="state" title="<?= $state_title ?>">
<?= $this->qlink(
$service->service_state == 99 ? 'PENDING' :
substr(strtoupper($this->monitoringState($service)), 0, 4)
. '&nbsp;since<br /> '
. $this->timeSince($service->service_last_state_change),
'monitoring/show/history', array(
'host' => $service->host_name,
'service' => $service->service_description
), array('quote' => false)) ?>
</td>
<td>
<?php
foreach ($icons as $icon => $alt) {
echo $this->img('img/classic/' . $icon, array(
'class' => 'icon',
'title' => $alt
));
} ?>
<?= $host_col ?>
<?= $this->qlink($service->service_description, 'monitoring/show/service', array(
'host' => $service->host_name,
'service' => $service->service_description
), array('class' => 'row-action')
)
?>
<br />
&nbsp; &nbsp; <span style="font-size: 0.7em">
<?= $this->escape(substr(strip_tags($service->service_output), 0, 900)) ?>
</span>
<?= $graph ?>
</td>
<? foreach ($this->extraColumns as $col): ?>
<td><?= $this->escape($service->$col) ?></td>
<? endforeach ?>
</tr>
<?php endforeach; ?>
<form method="get" action="<?= $this->qUrl(
'monitoring/list/services?' . http_build_query($this->services->getAppliedFilter()->toParams()),
array()
);
?>">
Sort by <?= $this->formSelect(
'sort',
$this->sort,
array('class' => 'autosubmit'),
array(
'service_severity' => 'Severity',
'service_last_state_change' => 'Last state change',
'service_last_time_unknown' => 'Last UNKNOWN',
'service_last_time_critical' => 'Last CRITICAL',
'service_last_time_warning' => 'Last WARNING',
'service_last_time_ok' => 'Last OK',
'service_description' => 'Service',
)
) ?>
<input type="search" name="filter" placeholder="Type to filter" />
<button class="btn btn-small"><i class="icon-refresh"></i></button>
</form>
<?= $this->paginationControl($paginator, null, null, array('preserve' => $this->preserve)) ?>
<table class="statustable action services">
<thead>
<tr>
<th colspan="3">Status</th>
<th>Service</th>
<th>Host</th>
<th>Output</th>
<th></th>
</tr>
</thead>
<tbody>
<?php foreach ($services->fetchAll() as $service): ?>
<tr class="<?= implode(' ', $viewHelper->getStateFlags($service, 'service')); ?>">
<td class="icons indicator">
<div class="img-box"><?php $trimArea->start(); ?>
<?php if ($service->service_icon_image) : ?>
<img src="<?= $service->service_icon_image; ?>"/>
<?php endif; ?>
<?php $trimArea->end(); ?></div>
</td>
<td class="icons indicator">
<div class="icon-box"><?php $trimArea->start(); ?>
<?php if (!$service->service_handled && $service->service_state > 0): ?>
<a href="#" title="<?= 'Unhandled service' ?>">
<i class="icon-warning-sign"></i>
</a>
<?php endif; ?>
<?php if ($service->service_acknowledged && !$service->service_in_downtime): ?>
<a href="#" title="<?= 'Acknowledged' ?>">
<i class="icon-ok-sign"></i>
</a>
<?php endif; ?>
<?php if ($service->service_is_flapping): ?>
<a href="#" title="<?= 'Flapping' ?>">
<i class="icon-random"></i>
</a>
<?php endif; ?>
<?php if (!$service->service_notifications_enabled): ?>
<a href="#" title="<?= 'Notifications disabled' ?>">
<i class="icon-volume-off"></i>
</a>
<?php endif; ?>
<?php if ($service->service_in_downtime): ?>
<a href="#" title="<?= 'In downtime' ?>">
<i class="icon-wrench"></i>
</a>
<?php endif; ?>
<?php $trimArea->end(); ?></div>
</td>
<td class="indicator state" title="<?= $viewHelper->getStateTitle($service, 'service'); ?>">
<div class="statetext">
<?= $this->qlink(
"<b>".ucfirst($viewHelper->monitoringState($service, 'service'))."</b>".
'<div class="nowrap"> since&nbsp;'.
$this->timeSince($service->service_last_state_change),
'monitoring/show/history', array(
'host' => $service->host_name,
'service' => $service->service_description
),
array('quote' => false)
);?>
<?php if ($service->service_state_type == 0): ?>
<a href="#" title="<?= 'Soft state' ?>">
<i class="icon-gears"></i>
</a>
<?php endif; ?>
</div>
</td>
<td class="servicename">
<?php if ($service->service_last_comment !== null): ?>
<a href="#" title="<?= 'Comments' ?>">
<i class="icon-comment"> </i>
</a>
<?php endif; ?>
<?= $this->qlink(
"<b>".$service->service_display_name."</b><br/>",
'monitoring/show/service', array(
'host' => $service->host_name,
'service' => $service->service_description
), array(
'class' => 'row-action',
'quote' => false
)
); ?>
<?php if ($service->service_action_url != ""): ?>
<a href="<?= $service->service_action_url; ?>">Action</a>
<?php endif; ?>
<?php if ($service->service_notes_url != ""): ?>
<a href="<?= $service->service_notes_url; ?>">Notes</a>
<?php endif; ?>
<?php if ($service->service_state_type == 0): ?>
<a href="#" title="<?= 'Soft state' ?>">
<i class="icon-gears"></i>
</a>
<?php endif; ?>
</td>
<td class="hostname" title="<?= $viewHelper->getStateTitle($service, 'host'); ?>">
<?= $this->qlink(
$service->host_name,
'monitoring/show/host', array(
'host' => $service->host_name
), array(
'class' => 'row-action',
'quote' => false
)
); ?>
<div class="statetext">
<?= $this->qlink(
"(".ucfirst($viewHelper->monitoringState($service, 'host')).")",
'monitoring/show/history', array(
'host' => $service->host_name,
'service' => $service->service_description
),
array('quote' => false)
);?>
</div>
<span class="host_address">
<?= $service->host_address ?>
</span>
</td>
<td class="expand-full">
<?= $this->escape(substr(strip_tags($service->service_output), 0, 10000)); ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>

View File

@ -22,5 +22,11 @@ foreach ($object->comments as $comment) {
);
}
?>
<b>Comments:</b><blockquote> <?= implode('<br />', $list) ?></blockquote>
<div class="information-container">
<div class="head">
<span>Comments</span>
</div>
<blockquote> <?= implode('<br />', $list) ?></blockquote>
</div>

View File

@ -1,25 +1,33 @@
<?php
if (!empty($this->contacts)) {
$contactList = array();
foreach ($this->contacts as $contact) {
$contactList[] = $this->qlink(
$contact->contact_alias,
'monitoring/show/contact',
array(
'contact_name' => $contact->contact_name
)
);
}
if (! empty($object->contacts)) {
$list = array();
foreach ($object->contacts as $contact) {
$list[] = $this->qlink($contact->contact_alias, 'monitoring/show/contact', array(
'contact_name' => $contact->contact_name
));
echo '<strong>Contacts:</strong> ';
echo implode(', ', $contactList);
}
echo '<b>Contacts:</b> ' . implode(', ', $list) . "<br />\n";
}
if (! empty($object->contactgroups)) {
$list = array();
foreach ($object->contactgroups as $contactgroup) {
$list[] = $this->qlink(
$contactgroup->contactgroup_alias,
'monitoring/show/contactgroup',
array('contactgroup_name' => $contactgroup->contactgroup_name)
);
if (!empty($this->contactgroups)) {
$contactGroupList = array();
foreach ($this->contactgroups as $contactgroup) {
$contactGroupList[] = $this->qlink(
$contactgroup->contactgroup_alias,
'monitoring/show/contactgroup',
array(
'contactgroup_name' => $contactgroup->contactgroup_name
)
);
}
echo '<strong>Contactgroups:</strong> ';
echo implode(', ', $contactGroupList);
}
echo '<b>Contactgroups:</b> ' . implode(', ', $list) . "<br />\n";
}
?>

View File

@ -1,12 +1,22 @@
<?php
if (! $object->customvars) return;
foreach ($object->customvars as $name => $value) {
printf(
"<b>%s:</b> %s<br />\n",
$this->escape($name),
$this->escape($value)
);
}
<?php if (isset($this->customvars) && count($this->customvars)) { ?>
<div class="information-container">
<div class="head">
<span>Customvariables</span>
</div>
<div>
<table>
<tr>
<th>Name</th>
<th>Value</th>
</tr>
<?php foreach ($this->customvars as $name => $value) { ?>
<tr>
<td><?= $this->escape($name) ?></td>
<td><?= $this->escape($value) ?></td>
</tr>
<?php } ?>
</table>
</div>
</div>
<?php } ?>

View File

@ -0,0 +1,43 @@
<?php if (!empty($this->downtimes)) { ?>
<?php
$list = array();
foreach ($this->downtimes as $downtime) {
$row = array();
if ($downtime->downtime_is_in_effect === '1') {
$row[] = 'Running<br />since '. $this->timeSince($downtime->downtime_actual_start_time);
} else {
if ($downtime->downtime_is_fixed) {
$row[] = 'Scheduled<br />for '. $downtime->downtime_scheduled_start_time;
} else {
$row[] = 'Waiting';
}
}
$row[] = sprintf(
'Triggered by %s: <em>%s</em>',
$downtime->downtime_author_name,
$downtime->downtime_comment_data
);
$row[] = '<button type="button" data-target="command" class="btn btn-warning"'
. ' data-command-id="29" data-command-info="'. $downtime->downtime_internal_downtime_id. '"'
. '><i class="icon-delete"></i> Delete'
. '</button>';
$list[] = '<td>'. implode('</td><td>', $row). '</td>';
}
?>
<div class="information-container">
<div class="head">
<span>Downtimes</span>
</div>
<div>
<table>
<tr>
<?= implode('</tr><tr>', $list); ?>
</tr>
</table>
</div>
</div>
<?php } ?>

View File

@ -0,0 +1,25 @@
<?php
$object = null;
if (isset($this->service)) {
$object = $this->service;
} elseif (isset($this->host)) {
$object = $this->host;
}
$flags = $this->monitoringFlags($object);
?>
<table class="flag-container">
<?php foreach ($flags as $name => $value) { ?>
<tr>
<th><?= $name; ?></th>
<td>
<?php if ($value === true) { ?>
<span class="flag flag-enabled">ENABLED</span>
<?php } else { ?>
<span class="flag flag-disabled">DISABLED</span>
<?php } ?>
</td>
</tr>
<?php } ?>
</table>

View File

@ -0,0 +1,19 @@
<?php
$object = null;
if (isset($this->service)) {
$object = $this->service;
} elseif (isset($this->host)) {
$object = $this->host;
}
$properties = $this->monitoringProperties($object);
?>
<table>
<?php foreach ($properties as $label => $value) { ?>
<tr>
<th><?= $label ?></th>
<td><?= $value ?></td>
</tr>
<?php } ?>
</table>

View File

@ -1,30 +1,74 @@
<?php
$showService = isset($this->service) && $this->tabs->getActiveName() !== 'host';
/** @var boolean $showService */
$showService = false;
if (isset($this->service) && $this->tabs->getActiveName() !== 'host') {
$showService = true;
}
/** @var boolean $inlineCommands */
$inlineCommands = true;
if ($this->tabs->getActiveName() === 'history') {
$inlineCommands = false;
}
if (!$this->compact) {
echo $this->tabs;
}
?>
<?php if (! $this->compact): ?>
<?= $this->tabs ?>
<?php endif; ?>
<table style="margin-bottom: 1em">
<tr class="<?= $this->monitoringState($this->host, 'host') ?><?= $this->host->host_handled ? ' handled' : '' ?>">
<td><b><?= $this->escape($this->host->host_name) ?><?
if ($this->host->host_address && $this->host->host_address !== $this->host->host_name): ?>
(<?= $this->escape($this->host->host_address) ?>)
<?php endif; ?>
</b></td>
<td class="state"<?= $showService ? '' : ' rowspan="2"' ?>>
<?= $this->util()->getHostStateName($this->host->host_state); ?><br />
since <?= $this->timeSince($this->host->host_last_state_change) ?>
</td>
</tr>
<?php if ($showService): ?>
<tr class="<?= $this->monitoringState($this->service, 'service'); ?><?= $this->service->service_handled ? ' handled' : '' ?>">
<td><b>Service: <?= $this->escape($this->service->service_description) ?></b></td>
<td class="state">
<?= $this->util()->getServiceStateName($this->service->service_state); ?><br />
since <?= $this->timeSince($this->service->service_last_state_change) ?>
</td>
</tr>
<?php else: ?>
<tr><td><b>Host state</b></td></tr>
<?php endif; ?>
</table>
<div class="information-container">
<?php if ($inlineCommands === true) { ?>
<div class="pull-right">
<?=
$this->monitoringCommands(
($showService === true) ? $this->service : $this->host,
'small'
);
?>
</div>
<?php } ?>
<table>
<tr class="<?= $this->monitoringState($this->host, 'host') ?><?= $this->host->host_handled ? ' handled' : '' ?>">
<td>
<strong>
<?= $this->escape($this->host->host_name); ?>
<?php if ($this->host->host_address && $this->host->host_address !== $this->host->host_name) { ?>
(<?= $this->escape($this->host->host_address); ?>)
<?php } ?>
</strong>
<?php if (isset($this->host->host_alias) && $this->host->host_alias !== $this->host->host_name) { ?>
<br />
<sup>(<?= $this->host->host_alias; ?>)</sup>
<?php } ?>
</td>
<td class="state"<?= $showService ? '' : ' rowspan="2"'; ?>>
<?= $this->util()->getHostStateName($this->host->host_state); ?>
since <?= $this->timeSince($this->host->host_last_state_change); ?>
<?php if ($this->host->host_acknowledged === '1') { ?>
(Has been acknowledged)
<?php } ?>
</td>
</tr>
<?php if ($showService === true) { ?>
<tr class="<?= $this->monitoringState($this->service, 'service'); ?><?= $this->service->service_handled ? ' handled' : '' ?>">
<td>
<strong>
Service: <?= $this->escape($this->service->service_description); ?>
</strong>
</td>
<td class="state">
<?= $this->util()->getServiceStateName($this->service->service_state); ?>
since <?= $this->timeSince($this->service->service_last_state_change); ?>
<?php if ($this->host->service_acknowledged === '1') { ?>
(Has been acknowledged)
<?php } ?>
</td>
</tr>
<?php } else { ?>
<?php // BYPASS ?>
<?php } ?>
</table>
<div class="clearfix"></div>
</div>

View File

@ -1,11 +1,128 @@
<?= $this->render('show/components/header.phtml') ?>
<?= $this->render('show/components/output.phtml') ?>
<?= $this->render('show/components/hostgroups.phtml') ?>
<?= $this->render('show/components/contacts.phtml') ?>
<?= $this->render('show/components/comments.phtml') ?>
<?= $this->render('show/components/customvars.phtml') ?>
<?= $this->render('show/components/perfdata.phtml') ?>
<?= $this->render('show/components/checkstatistics.phtml') ?>
<?= $this->render('show/components/command.phtml') ?>
<?= $this->preview_image ?>
<?php
$hostgroupLinkList = array();
if (!empty($this->hostgroups)) {
foreach ($this->hostgroups as $name => $alias) {
$hostgroupLinkList[] = $this->qlink(
$alias,
'monitoring/list/services',
array(
'hostgroups' => $name
)
);
}
}
?>
<?=
$this->partial(
'show/header.phtml',
array(
'host' => $this->host,
'service' => $this->service,
'tabs' => $this->tabs,
'compact' => $this->compact
)
);
?>
<?= $this->preview_image ?>
<div class="information-container">
<div class="head">
<span>Plugin output</span>
</div>
<div>
<?= $this->pluginOutput($this->host->host_output); ?>
<?= $this->pluginOutput($this->host->host_long_output); ?>
</div>
</div>
<div class="information-container">
<div class="head">
<span>Command</span>
</div>
<div>
<strong>Command:</strong>
<?= array_shift(explode('!', $this->host->host_check_command, 2)); ?>
<?= $this->commandArguments($this->host->host_check_command); ?>
</div>
</div>
<div class="information-container">
<div class="head">
<span>Groups and Contacts</span>
</div>
<?php if (count($hostgroupLinkList)) { ?>
<strong>Hostgroups:</strong>
<?= implode(' ', $hostgroupLinkList); ?>
<?php } ?>
<?= $this->render('show/components/contacts.phtml') ?>
</div>
<?= $this->render('show/components/comments.phtml'); ?>
<?= $this->render('show/components/downtime.phtml'); ?>
<?= $this->render('show/components/customvars.phtml'); ?>
<?php if ($this->host->host_perfdata): ?>
<div class="information-container">
<div class="head">
<span>Perfdata</span>
</div>
<div>
<?= $this->perfdata($this->host->host_perfdata); ?>
</div>
</div>
<?php endif; ?>
<div class="information-container">
<div class="head">
<span>Flags</span>
</div>
<div>
<?= $this->render('show/components/flags.phtml'); ?>
</div>
</div>
<div class="information-container">
<div class="head">
<span>Properties</span>
</div>
<div>
<?= $this->render('show/components/properties.phtml'); ?>
</div>
</div>
<div class="information-container">
<div class="head">
<span>Groups and Contacts</span>
</div>
<?php if (count($hostgroupLinkList)) { ?>
<strong>Hostgroups:</strong>
<?= implode(' ', $hostgroupLinkList); ?>
<?php } ?>
<?= $this->render('show/components/contacts.phtml') ?>
</div>
<?= $this->render('show/components/comments.phtml'); ?>
<?= $this->render('show/components/customvars.phtml'); ?>
<?php if ($this->host->host_perfdata): ?>
<div class="information-container">
<div class="head">
<span>Perfdata</span>
</div>
<div>
<?= $this->perfdata($this->host->host_perfdata); ?>
</div>
</div>
<?php endif; ?>
<span>Commands</span>
</div>
<div>
<?= $this->monitoringCommands($this->host, 'full'); ?>
</div>
</div>

View File

@ -23,7 +23,7 @@ class AbstractBackend implements DatasourceInterface
protected function init()
{
}
/**
* Dummy function for fluent code
*
@ -46,7 +46,7 @@ class AbstractBackend implements DatasourceInterface
public function from($virtual_table, $fields = array())
{
$classname = $this->tableToClassName($virtual_table);
if (! class_exists($classname)) {
if (!class_exists($classname)) {
throw new ProgrammingError(
sprintf(
'Asking for invalid virtual table %s',
@ -54,6 +54,7 @@ class AbstractBackend implements DatasourceInterface
)
);
}
$query = new $classname($this, $fields);
return $query;
}
@ -82,4 +83,158 @@ class AbstractBackend implements DatasourceInterface
{
return $this->getName();
}
/**
* UGLY temporary host fetch
*
* @param string $host
* @param bool $fetchAll
* @return mixed
*/
public function fetchHost($host, $fetchAll = false)
{
$fields = array(
'host_name',
'host_address',
'host_state',
'host_handled',
'host_in_downtime',
'host_acknowledged',
'host_check_command',
'host_check_command',
'host_last_state_change',
'host_alias',
'host_output',
'host_long_output',
'host_perfdata'
);
if ($fetchAll === true) {
$fields = array_merge(
$fields,
array(
'host_current_check_attempt',
'host_max_check_attempts',
'host_attempt',
'host_last_check',
'host_next_check',
'host_check_type',
'host_last_state_change',
'host_last_hard_state_change',
'host_last_hard_state',
'host_last_time_up',
'host_last_time_down',
'host_last_time_unreachable',
'host_state_type',
'host_last_notification',
'host_next_notification',
'host_no_more_notifications',
'host_notifications_enabled',
'host_problem_has_been_acknowledged',
'host_acknowledgement_type',
'host_current_notification_number',
'host_passive_checks_enabled',
'host_active_checks_enabled',
'host_event_handler_enabled',
'host_flap_detection_enabled',
'host_is_flapping',
'host_percent_state_change',
'host_check_latency',
'host_check_execution_time',
'host_scheduled_downtime_depth',
'host_failure_prediction_enabled',
'host_process_performance_data',
'host_obsess_over_host',
'host_modified_host_attributes',
'host_event_handler',
'host_check_command',
'host_normal_check_interval',
'host_retry_check_interval',
'host_check_timeperiod_object_id',
'host_status_update_time'
)
);
}
$select = $this->select()
->from('status', $fields)
->where('host_name', $host);
return $select->fetchRow();
}
// UGLY temporary service fetch
public function fetchService($host, $service)
{
Benchmark::measure('Preparing service select');
$select = $this->select()
->from(
'status',
array(
'host_name',
'host_state',
'host_check_command',
'host_last_state_change',
'service_description',
'service_state',
'service_acknowledged',
'service_handled',
'service_output',
'service_long_output',
'service_perfdata',
// '_host_satellite',
'service_check_command',
'service_last_state_change',
'service_last_check',
'service_next_check',
'service_check_execution_time',
'service_check_latency',
// 'service_
)
)
->where('host_name', $host)
->where('service_description', $service);
// Benchmark::measure((string) $select->getQuery());
Benchmark::measure('Prepared service select');
return $select->fetchRow();
$object = \Icinga\Objects\Service::fromBackend(
$this->select()
->from(
'status',
array(
'host_name',
'host_state',
'host_check_command',
'host_last_state_change',
'service_description',
'service_state',
'service_acknowledged',
'service_handled',
'service_output',
'service_long_output',
'service_perfdata',
// '_host_satellite',
'service_check_command',
'service_last_state_change',
'service_last_check',
'service_next_check',
'service_check_execution_time',
'service_check_latency',
// 'service_
)
)
->where('host_name', $host)
->where('service_description', $service)
->fetchRow()
);
// $object->customvars = $this->fetchCustomvars($host, $service);
return $object;
}
}

View File

@ -153,11 +153,10 @@ abstract class AbstractQuery extends Query
} elseif ($this->hasAliasName($col)) {
$col = $this->aliasToColumnName($col);
} else {
die('SHIT');
throw new \InvalidArgumentException('Can\'t order by column '.$col);
}
$this->order_columns[] = array($col, $dir);
return $this;
return parent::order($col, $dir);
}
public function setRealColumns()

View File

@ -0,0 +1,98 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
/**
* Icinga 2 Web - Head for multiple monitoring frontends
* Copyright (C) 2013 Icinga Development Team
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* @copyright 2013 Icinga Development Team <info@icinga.org>
* @author Icinga Development Team <info@icinga.org>
*/
// {{{ICINGA_LICENSE_HEADER}}}
namespace Monitoring\Backend\Ido\Query;
/**
* Class DowntimeQuery
*/
class DowntimeQuery extends AbstractQuery
{
/**
* Column map
* @var array
*/
protected $columnMap = array(
'downtime' => array(
'downtime_type' => 'sd.downtime_type',
'downtime_author_name' => 'sd.author_name',
'downtime_comment_data' => 'sd.comment_data',
'downtime_is_fixed' => 'sd.is_fixed',
'downtime_duration' => 'sd.duration',
'downtime_scheduled_start_time' => 'sd.scheduled_start_time',
'downtime_scheduled_end_time' => 'sd.scheduled_end_time',
'downtime_was_started' => 'sd.was_started',
'downtime_actual_start_time' => 'sd.actual_start_time',
'downtime_actual_start_time_usec' => 'sd.actual_start_time_usec',
'downtime_is_in_effect' => 'sd.is_in_effect',
'downtime_trigger_time' => 'sd.trigger_time',
'downtime_internal_downtime_id' => 'sd.internal_downtime_id'
),
'hosts' => array(
'host_name' => 'ho.name1',
),
'services' => array(
'service_host_name' => 'so.name1',
'service_description' => 'so.name2',
)
);
/**
* Join with scheduleddowntime
*/
protected function joinBaseTables()
{
$this->baseQuery = $this->db->select()->from(
array('sd' => $this->prefix . 'scheduleddowntime'),
array()
);
$this->joinedVirtualTables = array('downtime' => true);
}
/**
* Join if host needed
*/
protected function joinHosts()
{
$this->baseQuery->join(
array('ho' => $this->prefix . 'objects'),
'sd.object_id = ho.object_id AND ho.is_active = 1 AND ho.objecttype_id = 1',
array()
);
}
/**
* Join if services needed
*/
protected function joinServices()
{
$this->baseQuery->join(
array('so' => $this->prefix . 'objects'),
'so.object_id = ho.object_id AND ho.is_active = 1 AND ho.objecttype_id = 2',
array()
);
}
}

View File

@ -8,39 +8,69 @@ class StatusQuery extends AbstractQuery
protected $columnMap = array(
'hosts' => array(
'host' => 'ho.name1 COLLATE latin1_general_ci',
'host_name' => 'ho.name1 COLLATE latin1_general_ci',
'host_display_name' => 'h.display_name',
'host_alias' => 'h.alias',
'host_address' => 'h.address',
'host_ipv4' => 'INET_ATON(h.address)',
'host_icon_image' => 'h.icon_image',
'host' => 'ho.name1 COLLATE latin1_general_ci',
'host_name' => 'ho.name1 COLLATE latin1_general_ci',
'host_display_name' => 'h.display_name',
'host_alias' => 'h.alias',
'host_address' => 'h.address',
'host_ipv4' => 'INET_ATON(h.address)',
'host_icon_image' => 'h.icon_image',
'host_action_url' => 'h.action_url',
'host_notes_url' => 'h.notes_url'
),
'hoststatus' => array(
'host_state' => 'CASE WHEN hs.has_been_checked = 0 OR hs.has_been_checked IS NULL THEN 99 ELSE hs.current_state END',
'host_output' => 'hs.output',
'host_long_output' => 'hs.long_output',
'host_perfdata' => 'hs.perfdata',
'host_acknowledged' => 'hs.problem_has_been_acknowledged',
'host_in_downtime' => 'CASE WHEN (hs.scheduled_downtime_depth = 0) THEN 0 ELSE 1 END',
'host_handled' => 'CASE WHEN (hs.problem_has_been_acknowledged + hs.scheduled_downtime_depth) > 0 THEN 1 ELSE 0 END',
'host_does_active_checks' => 'hs.active_checks_enabled',
'host_state' => 'CASE WHEN hs.has_been_checked = 0 OR hs.has_been_checked IS NULL THEN 99 ELSE hs.current_state END',
'host_output' => 'hs.output',
'host_long_output' => 'hs.long_output',
'host_perfdata' => 'hs.perfdata',
'host_acknowledged' => 'hs.problem_has_been_acknowledged',
'host_in_downtime' => 'CASE WHEN (hs.scheduled_downtime_depth = 0) THEN 0 ELSE 1 END',
'host_handled' => 'CASE WHEN (hs.problem_has_been_acknowledged + hs.scheduled_downtime_depth) > 0 THEN 1 ELSE 0 END',
'host_does_active_checks' => 'hs.active_checks_enabled',
'host_accepts_passive_checks' => 'hs.passive_checks_enabled',
'host_last_state_change' => 'UNIX_TIMESTAMP(hs.last_state_change)',
'host_last_hard_state' => 'hs.last_hard_state',
'host_check_command' => 'hs.check_command',
'host_last_check' => 'UNIX_TIMESTAMP(hs.last_check)',
'host_next_check' => 'CASE WHEN hs.should_be_scheduled = 1 THEN UNIX_TIMESTAMP(hs.next_check) ELSE NULL END',
'host_check_execution_time' => 'hs.execution_time',
'host_check_latency' => 'hs.latency',
'host_problems' => 'CASE WHEN hs.current_state = 0 THEN 0 ELSE 1 END',
'host_notifications_enabled' => 'hs.notifications_enabled',
'host_last_time_up' => 'hs.last_time_up',
'host_last_time_down' => 'hs.last_time_down',
'host_last_time_unreachable' => 'hs.last_time_unreachable',
'host_last_state_change' => 'UNIX_TIMESTAMP(hs.last_state_change)',
'host_check_command' => 'hs.check_command',
'host_current_check_attempt' => 'hs.current_check_attempt',
'host_max_check_attempts' => 'hs.max_check_attempts',
'host_attempt' => 'CONCAT(hs.current_check_attempt, \'/\', hs.max_check_attempts)',
'host_last_check' => 'hs.last_check',
'host_next_check' => 'hs.next_check',
'host_check_type' => 'hs.check_type',
'host_last_hard_state_change' => 'hs.last_hard_state_change',
'host_last_hard_state' => 'hs.last_hard_state',
'host_last_time_up' => 'hs.last_time_up',
'host_last_time_down' => 'hs.last_time_down',
'host_last_time_unreachable' => 'hs.last_time_unreachable',
'host_state_type' => 'hs.state_type',
'host_last_notification' => 'hs.last_notification',
'host_next_notification' => 'hs.next_notification',
'host_no_more_notifications' => 'hs.no_more_notifications',
'host_notifications_enabled' => 'hs.notifications_enabled',
'host_problem_has_been_acknowledged' => 'hs.problem_has_been_acknowledged',
'host_acknowledgement_type' => 'hs.acknowledgement_type',
'host_current_notification_number' => 'hs.current_notification_number',
'host_passive_checks_enabled' => 'hs.passive_checks_enabled',
'host_active_checks_enabled' => 'hs.active_checks_enabled',
'host_event_handler_enabled' => 'hs.event_handler_enabled',
'host_flap_detection_enabled' => 'hs.flap_detection_enabled',
'host_is_flapping' => 'hs.is_flapping',
'host_percent_state_change' => 'hs.percent_state_change',
'host_check_latency' => 'hs.latency',
'host_check_execution_time' => 'hs.execution_time',
'host_scheduled_downtime_depth' => 'hs.scheduled_downtime_depth',
'host_failure_prediction_enabled' => 'hs.failure_prediction_enabled',
'host_process_performance_data' => 'hs.process_performance_data',
'host_obsess_over_host' => 'hs.obsess_over_host',
'host_modified_host_attributes' => 'hs.modified_host_attributes',
'host_event_handler' => 'hs.event_handler',
'host_check_command' => 'hs.check_command',
'host_normal_check_interval' => 'hs.normal_check_interval',
'host_retry_check_interval' => 'hs.retry_check_interval',
'host_check_timeperiod_object_id' => 'hs.check_timeperiod_object_id',
'host_status_update_time' => 'hs.status_update_time',
'host_problem' => 'CASE WHEN hs.current_state = 0 THEN 0 ELSE 1 END',
'host_severity' => 'CASE WHEN hs.current_state = 0
THEN
THEN
CASE WHEN hs.has_been_checked = 0 OR hs.has_been_checked IS NULL
THEN 16
ELSE 0
@ -83,19 +113,23 @@ class StatusQuery extends AbstractQuery
'service_description' => 'so.name2 COLLATE latin1_general_ci',
'service_display_name' => 's.display_name',
'service_icon_image' => 's.icon_image',
'service_action_url' => 's.action_url',
'service_notes_url' => 's.notes_url'
),
'servicestatus' => array(
'current_state' => 'CASE WHEN ss.has_been_checked = 0 OR ss.has_been_checked IS NULL THEN 99 ELSE ss.current_state END',
'service_state' => 'CASE WHEN ss.has_been_checked = 0 OR ss.has_been_checked IS NULL THEN 99 ELSE ss.current_state END',
'service_hard_state' => 'CASE WHEN ss.has_been_checked = 0 OR ss.has_been_checked IS NULL THEN 99 ELSE CASE WHEN ss.state_type = 1 THEN ss.current_state ELSE ss.last_hard_state END END',
'service_state_type' => 'ss.state_type',
'service_output' => 'ss.output',
'service_long_output' => 'ss.long_output',
'service_perfdata' => 'ss.perfdata',
'service_acknowledged' => 'ss.problem_has_been_acknowledged',
'service_in_downtime' => 'CASE WHEN (ss.scheduled_downtime_depth = 0) THEN 0 ELSE 1 END',
'service_handled' => 'CASE WHEN (ss.problem_has_been_acknowledged + ss.scheduled_downtime_depth + COALESCE(hs.current_state, 0)) > 0 THEN 1 ELSE 0 END',
'service_does_active_checks' => 'ss.active_checks_enabled',
'current_state' => 'CASE WHEN ss.has_been_checked = 0 OR ss.has_been_checked IS NULL THEN 99 ELSE ss.current_state END',
'service_state' => 'CASE WHEN ss.has_been_checked = 0 OR ss.has_been_checked IS NULL THEN 99 ELSE ss.current_state END',
'service_hard_state' => 'CASE WHEN ss.has_been_checked = 0 OR ss.has_been_checked IS NULL THEN 99 ELSE CASE WHEN ss.state_type = 1 THEN ss.current_state ELSE ss.last_hard_state END END',
'service_state_type' => 'ss.state_type',
'service_output' => 'ss.output',
'service_long_output' => 'ss.long_output',
'service_perfdata' => 'ss.perfdata',
'service_is_flapping' => 'ss.is_flapping',
'service_acknowledged' => 'ss.problem_has_been_acknowledged',
'service_in_downtime' => 'CASE WHEN (ss.scheduled_downtime_depth = 0) THEN 0 ELSE 1 END',
'service_handled' => 'CASE WHEN (COALESCE(ss.current_state, 0) * ss.problem_has_been_acknowledged + ss.scheduled_downtime_depth + COALESCE(hs.current_state, 0)) > 0 THEN 1 ELSE 0 END',
'service_does_active_checks' => 'ss.active_checks_enabled',
'service_accepts_passive_checks' => 'ss.passive_checks_enabled',
'service_last_state_change' => 'UNIX_TIMESTAMP(ss.last_state_change)',
'service_last_hard_state' => 'ss.last_hard_state',
@ -111,11 +145,20 @@ class StatusQuery extends AbstractQuery
'service_last_time_critical' => 'ss.last_time_critical',
'service_last_time_unknown' => 'ss.last_time_unknown',
),
'serviceproblemsummary' => array(
'host_unhandled_service_count' => 'sps.unhandled_service_count'
),
'lasthostcomment' => array(
'host_last_comment' => 'hlc.comment_id'
),
'lastservicecomment' => array(
'service_last_comment' => 'slc.comment_id'
),
'status' => array(
'problems' => 'CASE WHEN ss.current_state = 0 THEN 0 ELSE 1 END',
'handled' => 'CASE WHEN ss.problem_has_been_acknowledged = 1 OR ss.scheduled_downtime_depth > 0 THEN 1 ELSE 0 END',
'severity' => 'CASE WHEN ss.current_state = 0
THEN
'service_problems' => 'CASE WHEN ss.current_state = 0 THEN 0 ELSE 1 END',
'service_handled' => 'CASE WHEN ss.problem_has_been_acknowledged = 1 OR ss.scheduled_downtime_depth > 0 THEN 1 ELSE 0 END',
'service_severity' => 'CASE WHEN ss.current_state = 0
THEN
CASE WHEN ss.has_been_checked = 0 OR ss.has_been_checked IS NULL
THEN 16
ELSE 0
@ -132,7 +175,7 @@ class StatusQuery extends AbstractQuery
ELSE
CASE WHEN ss.has_been_checked = 0 OR ss.has_been_checked IS NULL THEN 16
WHEN ss.current_state = 1 THEN 32
WHEN ss.current_state = 2 THEN 128
WHEN ss.current_state = 2 THEN 128
WHEN ss.current_state = 3 THEN 64
ELSE 256
END
@ -148,12 +191,12 @@ class StatusQuery extends AbstractQuery
END',
),
);
/*
public function group($col)
{
$this->baseQuery->group($col);
}
*/
public function group($col)
{
$this->baseQuery->group($col);
}
protected function getDefaultColumns()
{
return $this->columnMap['hosts'];
@ -180,16 +223,16 @@ public function group($col)
array()
);
$this->joinedVirtualTables = array(
'hosts' => true,
'hosts' => true,
'hoststatus' => true,
);
}
protected function joinStatus()
{
$this->requireVirtualTable('services');
}
protected function joinServiceStatus()
{
$this->requireVirtualTable('services');
@ -202,16 +245,17 @@ public function group($col)
's.host_object_id = h.host_object_id',
array()
)->join(
array('so' => $this->prefix . 'objects'),
"so.$this->object_id = s.service_object_id AND so.is_active = 1",
array()
)->joinLeft(
array('ss' => $this->prefix . 'servicestatus'),
"so.$this->object_id = ss.service_object_id",
array()
);
array('so' => $this->prefix . 'objects'),
'so.'.$this->object_id.' = s.service_object_id AND so.is_active = 1',
array()
)->joinLeft(
array('ss' => $this->prefix . 'servicestatus'),
'so.'.$this->object_id.' = ss.service_object_id',
array()
);
}
// TODO: Test this one, doesn't seem to work right now
protected function joinHostgroups()
{
if ($this->hasJoinedVirtualTable('services')) {
@ -228,10 +272,10 @@ public function group($col)
'hgm.host_object_id = h.host_object_id',
array()
)->join(
array('hg' => $this->prefix . 'hostgroups'),
"hgm.hostgroup_id = hg.$this->hostgroup_id",
array()
);
array('hg' => $this->prefix . 'hostgroups'),
'hgm.hostgroup_id = hg'.$this->hostgroup_id,
array()
);
return $this;
}
@ -243,15 +287,15 @@ public function group($col)
'hgm.host_object_id = s.host_object_id',
array()
)->join(
array('hg' => $this->prefix . 'hostgroups'),
'hgm.hostgroup_id = hg.' . $this->hostgroup_id,
array()
)->join(
array('hgo' => $this->prefix . 'objects'),
'hgo.' . $this->object_id. ' = hg.hostgroup_object_id'
. ' AND hgo.is_active = 1',
array()
);
array('hg' => $this->prefix . 'hostgroups'),
'hgm.hostgroup_id = hg.' . $this->hostgroup_id,
array()
)->join(
array('hgo' => $this->prefix . 'objects'),
'hgo.' . $this->object_id . ' = hg.hostgroup_object_id'
. ' AND hgo.is_active = 1',
array()
);
return $this;
}
@ -264,6 +308,7 @@ public function group($col)
'sgm.service_object_id = s.service_object_id',
array()
)->join(
array('sg' => $this->prefix . 'servicegroups'),
'sgm.servicegroup_id = sg.' . $this->servicegroup_id,
array()
@ -276,4 +321,43 @@ public function group($col)
return $this;
}
protected function joinServiceproblemsummary()
{
$this->baseQuery->joinleft(
array ('sps' => new \Zend_Db_Expr(
'(SELECT COUNT(s.service_object_id) as unhandled_service_count, s.host_object_id as host_object_id '.
'FROM icinga_services s INNER JOIN icinga_servicestatus ss ON ss.current_state != 0 AND '.
'ss.problem_has_been_acknowledged = 0 AND ss.scheduled_downtime_depth = 0 AND '.
'ss.service_object_id = s.service_object_id '.
'GROUP BY s.host_object_id'.
')')),
'sps.host_object_id = hs.host_object_id',
array()
);
}
protected function joinLasthostcomment()
{
$this->baseQuery->joinleft(
array ('hlc' => new \Zend_Db_Expr(
'(SELECT MAX(c.comment_id) as comment_id, c.object_id '.
'FROM icinga_comments c GROUP BY c.object_id)')
),
'hlc.object_id = hs.host_object_id',
array()
);
}
protected function joinLastservicecomment()
{
$this->baseQuery->joinleft(
array ('slc' => new \Zend_Db_Expr(
'(SELECT MAX(c.comment_id) as comment_id, c.object_id '.
'FROM icinga_comments c GROUP BY c.object_id)')
),
'slc.object_id = ss.service_object_id',
array()
);
}
}

View File

@ -26,10 +26,9 @@
*/
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Backend;
namespace Monitoring\Backend;
use Icinga\Backend\Statusdat\DataView\StatusdatHostView;
use Icinga\Backend\Statusdat\DataView\StatusdatServiceView;
use Icinga\Protocol\Statusdat as StatusdatProtocol;
/**

View File

@ -1,6 +1,6 @@
<?php
namespace Icinga\Backend\Criteria;
namespace Monitoring\Backend\Statusdat\Criteria;
/**
* Constants for filter definitions.

View File

@ -26,7 +26,7 @@
*/
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Backend\Criteria;
namespace Monitoring\Backend\Statusdat\Criteria;
/**
* Class Order

View File

@ -0,0 +1,135 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga 2 Web.
*
* Icinga 2 Web - Head for multiple monitoring backends.
* Copyright (C) 2013 Icinga Development Team
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* @copyright 2013 Icinga Development Team <info@icinga.org>
* @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2
* @author Icinga Development Team <info@icinga.org>
*/
// {{{ICINGA_LICENSE_HEADER}}}
namespace Monitoring\Backend\Statusdat\DataView;
use Icinga\Protocol\Statusdat\View\ObjectRemappingView;
use Icinga\Protocol\Statusdat\IReader;
/**
* Class StatusdatHostView
* @package Icinga\Backend\Statusdat\DataView
*/
class HostStatusView extends ObjectRemappingView
{
/**
* @var mixed
*/
private $state;
/**
* @var array
*/
protected $handlerParameters = array(
"host" => "getHost",
"host_unhandled_service_count" => "getNrOfUnhandledServices",
"host_last_comment" => "getLastComment",
'host_handled' => "checkIfHandled",
);
public function checkIfHandled(&$host)
{
return $host->status->current_state == 0 ||
$host->status->problem_has_been_acknowledged ||
$host->status->scheduled_downtime_depth;
}
public function getNrOfUnhandledServices(&$host)
{
$ct = 0;
foreach ($host->services as &$service) {
if ($service->status->current_state > 0
&& $service->status->problem_has_been_acknowledged == 0
&& $service->status->scheduled_downtime_depth == 0) {
$ct++;
}
}
return $ct;
}
public function getLastComment(&$host)
{
if (!isset($host->comment) || empty($host->comment)) {
return null;
}
$comment = end($host->comment);
return $comment->comment_id;
}
/**
* @var array
*/
public static $mappedParameters = array(
"host_address" => "address",
"host_name" => "host_name",
"host" => "host_name",
"host_state" => "status.current_state",
"host_output" => "status.plugin_output",
"host_long_output" => "status.long_plugin_output",
"host_perfdata" => "status.performance_data",
"host_last_state_change" => "status.last_state_change",
"host_check_command" => "check_command",
"host_last_check" => "TO_DATE(status.last_check)",
"host_next_check" => "status.next_check",
"host_check_latency" => "status.check_latency",
"host_check_execution_time" => "status.check_execution_time",
"host_active_checks_enabled" => "status.active_checks_enabled",
"host_in_downtime" => "status.scheduled_downtime_depth",
"host_is_flapping" => "status.is_flapping",
"host_notifications_enabled"=> "status.notifications_enabled",
"host_state_type" => "status.state_type",
"host_icon_image" => "icon_image",
"host_action_url" => "action_url",
"host_notes_url" => "notes_url",
"host_acknowledged" => "status.problem_has_been_acknowledged"
// "state" => "current_state"
);
/**
* @param $item
* @return null
*/
public function getHost(&$item)
{
if (!isset($this->state["service"][$item->host_name])) {
return null;
}
if (!isset($this->state["host"][$item->host_name])) {
return null;
}
return $this->state["host"][$item->host_name];
}
/**
* @param IReader $reader
*/
public function __construct(IReader $reader)
{
$this->state = & $reader->getState();
}
}

View File

@ -0,0 +1,163 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga 2 Web.
*
* Icinga 2 Web - Head for multiple monitoring backends.
* Copyright (C) 2013 Icinga Development Team
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* @copyright 2013 Icinga Development Team <info@icinga.org>
* @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2
* @author Icinga Development Team <info@icinga.org>
*/
// {{{ICINGA_LICENSE_HEADER}}}
namespace Monitoring\Backend\Statusdat\DataView;
use Icinga\Protocol\Statusdat\View\ObjectRemappingView;
use Icinga\Protocol\Statusdat\IReader;
/**
* Class StatusdatHostView
* @package Icinga\Backend\Statusdat\DataView
*/
class ServiceStatusView extends ObjectRemappingView
{
/**
* @var mixed
*/
private $state;
/**
* @var array
*/
protected $handlerParameters = array(
"host" => "getHost",
"host_last_comment" => "getLastHostComment",
'host_handled' => "checkIfHostHandled",
'service_handled' => "checkIfHandled",
"service_last_comment" => "getLastComment"
);
public function checkIfHostHandled(&$service)
{
return $service->host->status->current_state == 0 ||
$service->host->status->problem_has_been_acknowledged ||
$service->host->status->scheduled_downtime_depth;
}
public function checkIfHandled(&$service)
{
return $service->status->current_state == 0 ||
$service->status->problem_has_been_acknowledged ||
$service->status->scheduled_downtime_depth;
}
public function getLastComment(&$service)
{
if (!isset($service->comment) || empty($service->comment)) {
return null;
}
$comment = end($service->comment);
return $comment->comment_id;
}
public function getLastHostComment(&$service)
{
if (!isset($service->host->comment) || empty($service->host->comment)) {
return null;
}
$comment = end($service->host->comment);
return $comment->comment_id;
}
/**
* @var array
*/
public static $mappedParameters = array(
"host_address" => "host.address",
"host_name" => "host.host_name",
"host" => "host.host_name",
"host_state" => "host.status.current_state",
"host_output" => "host.status.plugin_output",
"host_long_output" => "host.status.long_plugin_output",
"host_perfdata" => "host.status.performance_data",
"host_last_state_change" => "host.status.last_state_change",
"host_check_command" => "host.check_command",
"host_last_check" => "TO_DATE(host.status.last_check)",
"host_next_check" => "host.status.next_check",
"host_check_latency" => "host.status.check_latency",
"host_check_execution_time" => "host.status.check_execution_time",
"host_active_checks_enabled" => "host.status.active_checks_enabled",
"host_in_downtime" => "host.status.scheduled_downtime_depth",
"host_is_flapping" => "host.status.is_flapping",
"host_notifications_enabled" => "host.status.notifications_enabled",
"host_state_type" => "host.status.state_type",
"host_icon_image" => "host.icon_image",
"host_action_url" => "host.action_url",
"host_notes_url" => "host.notes_url",
"host_acknowledged" => "host.status.problem_has_been_acknowledged",
"service" => "service_description",
"service_display_name" => "service_description",
"service_description" => "service_description",
"service_state" => "status.current_state",
"service_icon_image" => "icon_image",
"service_output" => "status.plugin_output",
"service_long_output" => "status.long_plugin_output",
"service_perfdata" => "status.performance_data",
"service_last_state_change" => "status.last_state_change",
"service_check_command" => "check_command",
"service_last_check" => "TO_DATE(status.last_check)",
"service_next_check" => "status.next_check",
"service_check_latency" => "status.check_latency",
"service_check_execution_time" => "status.check_execution_time",
"service_active_checks_enabled" => "status.active_checks_enabled",
"service_in_downtime" => "status.scheduled_downtime_depth",
"service_is_flapping" => "status.is_flapping",
"service_notifications_enabled" => "status.notifications_enabled",
"service_state_type" => "status.state_type",
"service_icon_image" => "icon_image",
"service_action_url" => "action_url",
"service_notes_url" => "notes_url",
"service_acknowledged" => "status.problem_has_been_acknowledged",
// "state" => "current_state"
);
/**
* @param $item
* @return null
*/
public function getHost(&$item)
{
if (!isset($this->state["service"][$item->host_name])) {
return null;
}
if (!isset($this->state["host"][$item->host_name])) {
return null;
}
return $this->state["host"][$item->host_name];
}
/**
* @param IReader $reader
*/
public function __construct(IReader $reader)
{
$this->state = & $reader->getState();
}
}

View File

@ -26,9 +26,9 @@
*/
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Backend\Statusdat\DataView;
namespace Monitoring\Backend\Statusdat\DataView;
use Icinga\Backend\DataView\ObjectRemappingView;
use Icinga\Protocol\Statusdat\View\ObjectRemappingView;
use \Icinga\Protocol\Statusdat\IReader;
class StatusdatServiceView extends ObjectRemappingView
@ -49,7 +49,7 @@ class StatusdatServiceView extends ObjectRemappingView
/**
* @var array
*/
protected $mappedParameters = array(
public static $mappedParameters = array(
"host_address" => "parenthost.address",
"host_name" => "host_name",
"active_checks_enabled" => "status.active_checks_enabled",

View File

@ -26,7 +26,7 @@
*/
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Backend\Statusdat;
namespace Monitoring\Backend\Statusdat\Query;
abstract class GroupsummaryQuery extends Query
{
@ -170,7 +170,7 @@ abstract class GroupsummaryQuery extends Query
*/
public function init()
{
$this->reader = $this->backend->getReader();
$this->reader = $this->ds->getReader();
$this->query = $this->reader->select()->from($this->base, array())->groupByFunction(
"groupByProblemType",
$this

View File

@ -26,7 +26,7 @@
*/
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Backend\Statusdat;
namespace Monitoring\Backend\Statusdat\Query;
/**
* Class HostgroupsummaryQuery

View File

@ -26,7 +26,7 @@
*/
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Backend\Statusdat;
namespace Monitoring\Backend\Statusdat\Query;
use Icinga\Protocol\Statusdat;
use Icinga\Exception;

View File

@ -26,41 +26,41 @@
*/
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Backend\Statusdat;
namespace Monitoring\Backend\Statusdat\Query;
use Icinga\Backend\Criteria\Order;
use Icinga\Backend\MonitoringObjectList as MList;
use Monitoring\Backend\Statusdat\Criteria\Order;
use Icinga\Protocol\Statusdat;
use Icinga\Exception;
use Icinga\Backend\Query as BaseQuery;
use Icinga\Data\AbstractQuery;
use Icinga\Protocol\Statusdat\View\MonitoringObjectList as MList;
use Icinga\Protocol\Statusdat\Query as StatusdatQuery;
/**
* Class Query
* @package Icinga\Backend\Statusdat
*/
abstract class Query extends BaseQuery
abstract class Query extends AbstractQuery
{
/**
* @var null
*/
protected $cursor = null;
private $cursor = null;
/**
* @var string
*/
protected $view = 'Icinga\Backend\Statusdat\DataView\StatusdatServiceView';
private $viewClass = '\Monitoring\Backend\Statusdat\DataView\StatusdatServiceView';
private $baseQuery = null;
public function setBaseQuery(StatusdatQuery $query)
{
$this->baseQuery = $query;
}
public function setResultViewClass($viewClass)
{
$this->viewClass = '\Monitoring\Backend\Statusdat\DataView\\'.$viewClass;
}
/**
* @var array Mapping of order to field names
* @todo Is not complete right now
*/
protected $orderColumns = array(
Order::SERVICE_STATE => "status.current_state",
Order::STATE_CHANGE => "status.last_state_change",
Order::HOST_STATE => "status.current_state",
Order::HOST_NAME => "host_name",
Order::SERVICE_NAME => "service_description"
);
/**
* Calls the apply%Filtername%Filter() method for the given filter, or simply calls
@ -114,7 +114,7 @@ abstract class Query extends BaseQuery
$text = "%$value%";
$val = array($text, $text, $text);
$this->query->where("(host_name LIKE ? OR service_description LIKE ? OR status.plugin_output LIKE ?)", $val);
$this->baseQuery->where("(host_name LIKE ? OR service_description LIKE ? OR status.plugin_output LIKE ?)", $val);
}
@ -127,7 +127,7 @@ abstract class Query extends BaseQuery
public function applyHostgroupsFilter($type, $value)
{
$filter = array($value);
$this->query->where("host.group IN ?", $filter);
$this->baseQuery->where("host.group IN ?", $filter);
}
/**
@ -139,7 +139,7 @@ abstract class Query extends BaseQuery
public function applyServicegroupsFilter($type, $value)
{
$filter = array($value);
$this->query->where("group IN ?", $filter);
$this->baseQuery->where("group IN ?", $filter);
}
/**
@ -152,7 +152,7 @@ abstract class Query extends BaseQuery
public function applyHandledFilter($type, $value)
{
$val = array($value, $value);
$this->query->where("(status.problem_has_been_acknowledged = ? )", $val);
$this->baseQuery->where("(status.problem_has_been_acknowledged = ? )", $val);
}
/**
@ -164,7 +164,7 @@ abstract class Query extends BaseQuery
if (!is_array($value)) {
$value = array($value);
}
$this->query->where("host_name LIKE ?", $value);
$this->baseQuery->where("host_name LIKE ?", $value);
}
/**
@ -173,7 +173,7 @@ abstract class Query extends BaseQuery
*/
public function applyStateFilter($type, $value)
{
$this->query->where("status.current_state = $value");
$this->baseQuery->where("status.current_state = $value");
}
/**
@ -182,7 +182,7 @@ abstract class Query extends BaseQuery
*/
public function applyHoststateFilter($type, $value)
{
$this->query->where("host.status.current_state = $value");
$this->baseQuery->where("host.status.current_state = $value");
}
/**
@ -194,7 +194,7 @@ abstract class Query extends BaseQuery
if (!is_array($value)) {
$value = array($value);
}
$this->query->where("service_description LIKE ?", $value);
$this->baseQuery->where("service_description LIKE ?", $value);
}
/**
@ -205,7 +205,7 @@ abstract class Query extends BaseQuery
*/
public function limit($count = null, $offset = null)
{
$this->query->limit($count, $offset);
$this->baseQuery->limit($count, $offset);
return $this;
}
@ -220,7 +220,8 @@ abstract class Query extends BaseQuery
{
if ($column) {
$this->query->order($this->orderColumns[$column], strtolower($dir));
$class = $this->viewClass;
$this->baseQuery->order($class::$mappedParameters[$column], strtolower($dir));
}
return $this;
}
@ -238,7 +239,7 @@ abstract class Query extends BaseQuery
if (!is_array($value)) {
$value = array($value);
}
$this->query->where($column, $value);
$this->baseQuery->where($column, $value);
return $this;
}
@ -247,9 +248,9 @@ abstract class Query extends BaseQuery
*/
public function fetchAll()
{
$view = $this->view;
$view = $this->viewClass;
if (!$this->cursor) {
$this->cursor = new MList($this->query->getResult(), new $view($this->reader));
$this->cursor = new MList($this->baseQuery->getResult(), new $view($this->reader));
}
return $this->cursor;
}
@ -283,6 +284,7 @@ abstract class Query extends BaseQuery
*/
public function count()
{
return count($this->query->getResult());
return count($this->baseQuery->getResult());
}
}

View File

@ -26,7 +26,7 @@
*/
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Backend\Statusdat;
namespace Monitoring\Backend\Statusdat\Query;
/**
* Class ServicegroupsummaryQuery

View File

@ -26,11 +26,9 @@
*/
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Backend\Statusdat;
namespace Monitoring\Backend\Statusdat\Query;
use Icinga\Backend\MonitoringObjectList as MList;
use Icinga\Protocol\Statusdat;
use Icinga\Backend\Statusdat\DataView\StatusdatServiceView as StatusdatServiceView;
use Icinga\Exception;
/**

View File

@ -0,0 +1,38 @@
<?php
/**
* Created by JetBrains PhpStorm.
* User: moja
* Date: 7/17/13
* Time: 1:29 PM
* To change this template use File | Settings | File Templates.
*/
namespace Monitoring\Backend\Statusdat\Query;
use Icinga\Protocol\Statusdat;
use Icinga\Exception;
class StatusQuery extends Query
{
private function getTarget()
{
foreach($this->getColumns() as $column) {
if(preg_match("/^service/",$column))
return "service";
}
return "host";
}
public function init()
{
$target = $this->getTarget();
$this->reader = $this->ds->getReader();
$this->setResultViewClass(ucfirst($target)."StatusView");
$this->setBaseQuery($this->reader->select()->from($target."s", array()));
}
}

View File

@ -0,0 +1,844 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
/**
* Icinga 2 Web - Head for multiple monitoring frontends
* Copyright (C) 2013 Icinga Development Team
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* @copyright 2013 Icinga Development Team <info@icinga.org>
* @author Icinga Development Team <info@icinga.org>
*/
// {{{ICINGA_LICENSE_HEADER}}}
namespace Monitoring\Command;
use Icinga\Authentication\User;
use Icinga\Exception\ProgrammingError;
/**
* Class Meta
*
* Deals with objects and available commands which can be used on the object
*/
class Meta
{
/**
* Category name which is useless
*/
const DROP_CATEGORY = 'none';
/**
* Interface type for small interfaces
*
* Only important commands
*/
const TYPE_SMALL = 'small';
/**
* Interface type for full featured interface
*
* All commands are shown
*/
const TYPE_FULL = 'full';
const CMD_DISABLE_ACTIVE_CHECKS = 1;
const CMD_ENABLE_ACTIVE_CHECKS = 2;
const CMD_RESCHEDULE_NEXT_CHECK = 3;
const CMD_SUBMIT_PASSIVE_CHECK_RESULT = 4;
const CMD_STOP_OBSESSING = 5;
const CMD_START_OBSESSING = 6;
const CMD_STOP_ACCEPTING_PASSIVE_CHECKS = 7;
const CMD_START_ACCEPTING_PASSIVE_CHECKS = 8;
const CMD_DISABLE_NOTIFICATIONS = 9;
const CMD_ENABLE_NOTIFICATIONS = 10;
const CMD_SEND_CUSTOM_NOTIFICATION = 11;
const CMD_SCHEDULE_DOWNTIME = 12;
const CMD_SCHEDULE_DOWNTIMES_TO_ALL = 13;
const CMD_REMOVE_DOWNTIMES_FROM_ALL = 14;
const CMD_DISABLE_NOTIFICATIONS_FOR_ALL = 15;
const CMD_ENABLE_NOTIFICATIONS_FOR_ALL = 16;
const CMD_RESCHEDULE_NEXT_CHECK_TO_ALL = 17;
const CMD_DISABLE_ACTIVE_CHECKS_FOR_ALL = 18;
const CMD_ENABLE_ACTIVE_CHECKS_FOR_ALL = 19;
const CMD_DISABLE_EVENT_HANDLER = 20;
const CMD_ENABLE_EVENT_HANDLER = 21;
const CMD_DISABLE_FLAP_DETECTION = 22;
const CMD_ENABLE_FLAP_DETECTION = 23;
const CMD_ADD_COMMENT = 24;
const CMD_RESET_ATTRIBUTES = 25;
const CMD_ACKNOWLEDGE_PROBLEM = 26;
const CMD_REMOVE_ACKNOWLEDGEMENT = 27;
const CMD_DELAY_NOTIFICATION = 28;
const CMD_REMOVE_DOWNTIME = 29;
/**
* Filter array for array displayed in small interfaces
* @var int[]
*/
private static $commandSmallFilter = array(
self::CMD_RESCHEDULE_NEXT_CHECK,
self::CMD_ACKNOWLEDGE_PROBLEM,
self::CMD_REMOVE_ACKNOWLEDGEMENT
);
/**
* Information about interface commands
*
* With following structure
* <pre>
* array(
* self::CMD_CONSTANT_* => array(
* '<LONG DESCRIPTION WHERE %s is the type, e.g. host or service>',
* '<SHORT DESCRIPTION WHERE %s is the type, e.g. host or service>',
* '[ICON CSS CLASS]',
* '[BUTTON CSS CLASS]',
*
* // Maybe any other options later on
* )
* )
* </pre>
*
* @var array
*/
private static $commandInformation = array(
self::CMD_DISABLE_ACTIVE_CHECKS => array(
'Disable active checks for this %s', // Long description (mandatory)
'Disable active checks', // Short description (mandatory)
'', // Icon anything (optional)
'' // Button css cls (optional)
),
self::CMD_ENABLE_ACTIVE_CHECKS => array(
'Enable active checks for this %s',
'Enable active checks',
''
),
self::CMD_RESCHEDULE_NEXT_CHECK => array(
'Reschedule next service check',
'Recheck',
'',
'btn-success'
),
self::CMD_SUBMIT_PASSIVE_CHECK_RESULT => array(
'Submit passive check result',
'Submit check result',
''
),
self::CMD_STOP_OBSESSING => array(
'Stop obsessing over this %s',
'Stop obsessing',
''
),
self::CMD_START_OBSESSING => array(
'Start obsessing over this %s',
'Start obsessing',
''
),
self::CMD_STOP_ACCEPTING_PASSIVE_CHECKS => array(
'Stop accepting passive check for this %s',
'Stop passive checks',
''
),
self::CMD_START_ACCEPTING_PASSIVE_CHECKS => array(
'Start accepting passive check for this %s',
'Start passive checks',
''
),
self::CMD_DISABLE_NOTIFICATIONS => array(
'Disable notifications for this %s',
'Disable notifications',
''
),
self::CMD_ENABLE_NOTIFICATIONS => array(
'Enable notifications for this %s',
'Enable notifications',
''
),
self::CMD_SEND_CUSTOM_NOTIFICATION => array(
'Send custom %s notification',
'Send notification',
''
),
self::CMD_SCHEDULE_DOWNTIME => array(
'Schedule downtime for this %s',
'Schedule downtime',
''
),
self::CMD_SCHEDULE_DOWNTIMES_TO_ALL => array(
'Schedule downtime for this %s and all services',
'Schedule services downtime',
''
),
self::CMD_REMOVE_DOWNTIMES_FROM_ALL => array(
'Remove downtime(s) for this %s and all services',
'Remove downtime(s)',
''
),
self::CMD_DISABLE_NOTIFICATIONS_FOR_ALL => array(
'Disable notification for all service on this %s',
'Disable service notifications',
''
),
self::CMD_ENABLE_NOTIFICATIONS_FOR_ALL => array(
'Enable notification for all service on this %s',
'Enable service notifications',
''
),
self::CMD_RESCHEDULE_NEXT_CHECK_TO_ALL => array(
'Schedule a check of all service on this %s',
'Recheck all services',
'',
'btn-success'
),
self::CMD_DISABLE_ACTIVE_CHECKS_FOR_ALL => array(
'Disable checks for all services on this %s',
'Disable service checks',
''
),
self::CMD_ENABLE_ACTIVE_CHECKS_FOR_ALL => array(
'Enable checks for all services on this %s',
'Enable service checks',
''
),
self::CMD_DISABLE_EVENT_HANDLER => array(
'Disable event handler for this %s',
'Disable event handler',
''
),
self::CMD_ENABLE_EVENT_HANDLER => array(
'Enable event handler for this %s',
'Enable event handler',
''
),
self::CMD_DISABLE_FLAP_DETECTION => array(
'Disable flap detection for this %s',
'Disable flap detection',
''
),
self::CMD_ENABLE_FLAP_DETECTION => array(
'Enable flap detection for this %s',
'Enable flap detection',
''
),
self::CMD_ADD_COMMENT => array(
'Add new %s comment',
'Add comment',
''
),
self::CMD_RESET_ATTRIBUTES => array(
'Reset modified attributes',
'Reset attributes',
'',
'btn-danger'
),
self::CMD_ACKNOWLEDGE_PROBLEM => array(
'Acknowledge %s problem',
'Acknowledge',
'',
'btn-warning'
),
self::CMD_REMOVE_ACKNOWLEDGEMENT => array(
'Remove %s acknowledgement',
'Remove acknowledgement',
'',
'btn-warning'
),
self::CMD_DELAY_NOTIFICATION => array(
'Delay next %s notification',
'Delay notification',
''
),
);
/**
* An mapping array which is valid for hosts and services
* @var array
*/
private static $defaultObjectCommands = array(
self::CMD_DISABLE_ACTIVE_CHECKS,
self::CMD_ENABLE_ACTIVE_CHECKS,
self::CMD_RESCHEDULE_NEXT_CHECK,
self::CMD_SUBMIT_PASSIVE_CHECK_RESULT,
self::CMD_STOP_OBSESSING,
self::CMD_START_OBSESSING,
self::CMD_ACKNOWLEDGE_PROBLEM,
self::CMD_REMOVE_ACKNOWLEDGEMENT,
self::CMD_STOP_ACCEPTING_PASSIVE_CHECKS,
self::CMD_START_ACCEPTING_PASSIVE_CHECKS,
self::CMD_DISABLE_NOTIFICATIONS,
self::CMD_ENABLE_NOTIFICATIONS,
self::CMD_SEND_CUSTOM_NOTIFICATION,
self::CMD_SCHEDULE_DOWNTIME,
self::CMD_SCHEDULE_DOWNTIMES_TO_ALL,
self::CMD_REMOVE_DOWNTIMES_FROM_ALL,
self::CMD_DISABLE_NOTIFICATIONS_FOR_ALL,
self::CMD_ENABLE_NOTIFICATIONS_FOR_ALL,
self::CMD_RESCHEDULE_NEXT_CHECK_TO_ALL,
self::CMD_DISABLE_ACTIVE_CHECKS_FOR_ALL,
self::CMD_ENABLE_ACTIVE_CHECKS_FOR_ALL,
self::CMD_DISABLE_EVENT_HANDLER,
self::CMD_ENABLE_EVENT_HANDLER,
self::CMD_DISABLE_FLAP_DETECTION,
self::CMD_ENABLE_FLAP_DETECTION,
self::CMD_ADD_COMMENT,
self::CMD_RESET_ATTRIBUTES,
self::CMD_DELAY_NOTIFICATION
);
/**
* Command mapper
*
* Holds information about commands for object types
*
* Please note that host and service are implicit initialized!
* see $defaultObjectCommands for definition
*
* @var array
*/
private static $objectCommands = array(
// 'host' => self::$defaultObjectCommands,
// 'service' => self::$defaultObjectCommands,
// -> this is done in self::initCommandStructure()
//
// Real other commands structures:
// NONE
);
/**
* Array of modifier methods in this class
*
* Maps object type to modifier method which rewrites
* visible commands depending on object states
*
* @var array
*/
private static $commandProcessorMethods = array(
'host' => 'defaultCommandProcessor',
'service' => 'defaultCommandProcessor'
);
/**
* Init flag for lazy, static data preparation
* @var bool
*/
private static $initialized = false;
/**
* Array of available categories
* @var array
*/
private static $rawCategories = array();
/**
* Categories to command names
* @var array
*/
private static $rawCommandCategories = array();
/**
* Command reference list
* @var array
*/
private static $rawCommands = array(
'NONE' => 'none',
'ADD_HOST_COMMENT' => 'host',
'DEL_HOST_COMMENT' => 'host',
'ADD_SVC_COMMENT' => 'service',
'DEL_SVC_COMMENT' => 'service',
'ENABLE_SVC_CHECK' => 'service',
'DISABLE_SVC_CHECK' => 'service',
'SCHEDULE_SVC_CHECK' => 'service',
'DELAY_SVC_NOTIFICATION' => 'service',
'DELAY_HOST_NOTIFICATION' => 'host',
'DISABLE_NOTIFICATIONS' => 'global',
'ENABLE_NOTIFICATIONS' => 'global',
'RESTART_PROCESS' => 'global',
'SHUTDOWN_PROCESS' => 'global',
'ENABLE_HOST_SVC_CHECKS' => 'host',
'DISABLE_HOST_SVC_CHECKS' => 'host',
'SCHEDULE_HOST_SVC_CHECKS' => 'host',
'DELAY_HOST_SVC_NOTIFICATIONS' => 'host',
'DEL_ALL_HOST_COMMENTS' => 'host',
'DEL_ALL_SVC_COMMENTS' => 'service',
'ENABLE_SVC_NOTIFICATIONS' => 'service',
'DISABLE_SVC_NOTIFICATIONS' => 'service',
'ENABLE_HOST_NOTIFICATIONS' => 'host',
'DISABLE_HOST_NOTIFICATIONS' => 'host',
'ENABLE_ALL_NOTIFICATIONS_BEYOND_HOST' => 'host',
'DISABLE_ALL_NOTIFICATIONS_BEYOND_HOST' => 'host',
'ENABLE_HOST_SVC_NOTIFICATIONS' => 'host',
'DISABLE_HOST_SVC_NOTIFICATIONS' => 'host',
'PROCESS_SERVICE_CHECK_RESULT' => 'service',
'SAVE_STATE_INFORMATION' => 'global',
'READ_STATE_INFORMATION' => 'global',
'ACKNOWLEDGE_HOST_PROBLEM' => 'host',
'ACKNOWLEDGE_SVC_PROBLEM' => 'service',
'START_EXECUTING_SVC_CHECKS' => 'service',
'STOP_EXECUTING_SVC_CHECKS' => 'service',
'START_ACCEPTING_PASSIVE_SVC_CHECKS' => 'service',
'STOP_ACCEPTING_PASSIVE_SVC_CHECKS' => 'service',
'ENABLE_PASSIVE_SVC_CHECKS' => 'service',
'DISABLE_PASSIVE_SVC_CHECKS' => 'service',
'ENABLE_EVENT_HANDLERS' => 'global',
'DISABLE_EVENT_HANDLERS' => 'global',
'ENABLE_HOST_EVENT_HANDLER' => 'host',
'DISABLE_HOST_EVENT_HANDLER' => 'host',
'ENABLE_SVC_EVENT_HANDLER' => 'service',
'DISABLE_SVC_EVENT_HANDLER' => 'service',
'ENABLE_HOST_CHECK' => 'host',
'DISABLE_HOST_CHECK' => 'host',
'START_OBSESSING_OVER_SVC_CHECKS' => 'service',
'STOP_OBSESSING_OVER_SVC_CHECKS' => 'service',
'REMOVE_HOST_ACKNOWLEDGEMENT' => 'host',
'REMOVE_SVC_ACKNOWLEDGEMENT' => 'service',
'SCHEDULE_FORCED_HOST_SVC_CHECKS' => 'host',
'SCHEDULE_FORCED_SVC_CHECK' => 'service',
'SCHEDULE_HOST_DOWNTIME' => 'host',
'SCHEDULE_SVC_DOWNTIME' => 'service',
'ENABLE_HOST_FLAP_DETECTION' => 'host',
'DISABLE_HOST_FLAP_DETECTION' => 'host',
'ENABLE_SVC_FLAP_DETECTION' => 'service',
'DISABLE_SVC_FLAP_DETECTION' => 'service',
'ENABLE_FLAP_DETECTION' => 'global',
'DISABLE_FLAP_DETECTION' => 'global',
'ENABLE_HOSTGROUP_SVC_NOTIFICATIONS' => 'hostgroup',
'DISABLE_HOSTGROUP_SVC_NOTIFICATIONS' => 'hostgroup',
'ENABLE_HOSTGROUP_HOST_NOTIFICATIONS' => 'hostgroup',
'DISABLE_HOSTGROUP_HOST_NOTIFICATIONS' => 'hostgroup',
'ENABLE_HOSTGROUP_SVC_CHECKS' => 'hostgroup',
'DISABLE_HOSTGROUP_SVC_CHECKS' => 'hostgroup',
'CANCEL_HOST_DOWNTIME' => 'host',
'CANCEL_SVC_DOWNTIME' => 'service',
'CANCEL_ACTIVE_HOST_DOWNTIME' => 'host',
'CANCEL_PENDING_HOST_DOWNTIME' => 'host',
'CANCEL_ACTIVE_SVC_DOWNTIME' => 'service',
'CANCEL_PENDING_SVC_DOWNTIME' => 'service',
'CANCEL_ACTIVE_HOST_SVC_DOWNTIME' => 'host',
'CANCEL_PENDING_HOST_SVC_DOWNTIME' => 'host',
'FLUSH_PENDING_COMMANDS' => 'global',
'DEL_HOST_DOWNTIME' => 'host',
'DEL_SVC_DOWNTIME' => 'service',
'ENABLE_FAILURE_PREDICTION' => 'global',
'DISABLE_FAILURE_PREDICTION' => 'global',
'ENABLE_PERFORMANCE_DATA' => 'global',
'DISABLE_PERFORMANCE_DATA' => 'global',
'SCHEDULE_HOSTGROUP_HOST_DOWNTIME' => 'hostgroup',
'SCHEDULE_HOSTGROUP_SVC_DOWNTIME' => 'hostgroup',
'SCHEDULE_HOST_SVC_DOWNTIME' => 'host',
'PROCESS_HOST_CHECK_RESULT' => 'host',
'START_EXECUTING_HOST_CHECKS' => 'host',
'STOP_EXECUTING_HOST_CHECKS' => 'host',
'START_ACCEPTING_PASSIVE_HOST_CHECKS' => 'host',
'STOP_ACCEPTING_PASSIVE_HOST_CHECKS' => 'host',
'ENABLE_PASSIVE_HOST_CHECKS' => 'host',
'DISABLE_PASSIVE_HOST_CHECKS' => 'host',
'START_OBSESSING_OVER_HOST_CHECKS' => 'host',
'STOP_OBSESSING_OVER_HOST_CHECKS' => 'host',
'SCHEDULE_HOST_CHECK' => 'host',
'SCHEDULE_FORCED_HOST_CHECK' => 'host',
'START_OBSESSING_OVER_SVC' => 'global',
'STOP_OBSESSING_OVER_SVC' => 'global',
'START_OBSESSING_OVER_HOST' => 'global',
'STOP_OBSESSING_OVER_HOST' => 'global',
'ENABLE_HOSTGROUP_HOST_CHECKS' => 'host',
'DISABLE_HOSTGROUP_HOST_CHECKS' => 'host',
'ENABLE_HOSTGROUP_PASSIVE_SVC_CHECKS' => 'host',
'DISABLE_HOSTGROUP_PASSIVE_SVC_CHECKS' => 'host',
'ENABLE_HOSTGROUP_PASSIVE_HOST_CHECKS' => 'host',
'DISABLE_HOSTGROUP_PASSIVE_HOST_CHECKS' => 'host',
'ENABLE_SERVICEGROUP_SVC_NOTIFICATIONS' => 'servicegroup',
'DISABLE_SERVICEGROUP_SVC_NOTIFICATIONS' => 'servicegroup',
'ENABLE_SERVICEGROUP_HOST_NOTIFICATIONS' => 'servicegroup',
'DISABLE_SERVICEGROUP_HOST_NOTIFICATIONS' => 'servicegroup',
'ENABLE_SERVICEGROUP_SVC_CHECKS' => 'servicegroup',
'DISABLE_SERVICEGROUP_SVC_CHECKS' => 'servicegroup',
'ENABLE_SERVICEGROUP_HOST_CHECKS' => 'servicegroup',
'DISABLE_SERVICEGROUP_HOST_CHECKS' => 'servicegroup',
'ENABLE_SERVICEGROUP_PASSIVE_SVC_CHECKS' => 'servicegroup',
'DISABLE_SERVICEGROUP_PASSIVE_SVC_CHECKS' => 'servicegroup',
'ENABLE_SERVICEGROUP_PASSIVE_HOST_CHECKS' => 'servicegroup',
'DISABLE_SERVICEGROUP_PASSIVE_HOST_CHECKS' => 'servicegroup',
'SCHEDULE_SERVICEGROUP_HOST_DOWNTIME' => 'servicegroup',
'SCHEDULE_SERVICEGROUP_SVC_DOWNTIME' => 'servicegroup',
'CHANGE_GLOBAL_HOST_EVENT_HANDLER' => 'global',
'CHANGE_GLOBAL_SVC_EVENT_HANDLER' => 'global',
'CHANGE_HOST_EVENT_HANDLER' => 'host',
'CHANGE_SVC_EVENT_HANDLER' => 'service',
'CHANGE_HOST_CHECK_COMMAND' => 'host',
'CHANGE_SVC_CHECK_COMMAND' => 'service',
'CHANGE_NORMAL_HOST_CHECK_INTERVAL' => 'host',
'CHANGE_NORMAL_SVC_CHECK_INTERVAL' => 'service',
'CHANGE_RETRY_SVC_CHECK_INTERVAL' => 'service',
'CHANGE_MAX_HOST_CHECK_ATTEMPTS' => 'host',
'CHANGE_MAX_SVC_CHECK_ATTEMPTS' => 'service',
'SCHEDULE_AND_PROPAGATE_TRIGGERED_HOST_DOWNTIME' => 'host',
'ENABLE_HOST_AND_CHILD_NOTIFICATIONS' => 'host',
'DISABLE_HOST_AND_CHILD_NOTIFICATIONS' => 'host',
'SCHEDULE_AND_PROPAGATE_HOST_DOWNTIME' => 'host',
'ENABLE_SERVICE_FRESHNESS_CHECKS' => 'global',
'DISABLE_SERVICE_FRESHNESS_CHECKS' => 'global',
'ENABLE_HOST_FRESHNESS_CHECKS' => 'host',
'DISABLE_HOST_FRESHNESS_CHECKS' => 'host',
'SET_HOST_NOTIFICATION_NUMBER' => 'host',
'SET_SVC_NOTIFICATION_NUMBER' => 'service',
'CHANGE_HOST_CHECK_TIMEPERIOD' => 'host',
'CHANGE_SVC_CHECK_TIMEPERIOD' => 'service',
'PROCESS_FILE' => 'global',
'CHANGE_CUSTOM_HOST_VAR' => 'host',
'CHANGE_CUSTOM_SVC_VAR' => 'service',
'CHANGE_CUSTOM_CONTACT_VAR' => 'global',
'ENABLE_CONTACT_HOST_NOTIFICATIONS' => 'host',
'DISABLE_CONTACT_HOST_NOTIFICATIONS' => 'host',
'ENABLE_CONTACT_SVC_NOTIFICATIONS' => 'service',
'DISABLE_CONTACT_SVC_NOTIFICATIONS' => 'service',
'ENABLE_CONTACTGROUP_HOST_NOTIFICATIONS' => 'host',
'DISABLE_CONTACTGROUP_HOST_NOTIFICATIONS' => 'host',
'ENABLE_CONTACTGROUP_SVC_NOTIFICATIONS' => 'service',
'DISABLE_CONTACTGROUP_SVC_NOTIFICATIONS' => 'service',
'CHANGE_RETRY_HOST_CHECK_INTERVAL' => 'host',
'SEND_CUSTOM_HOST_NOTIFICATION' => 'host',
'SEND_CUSTOM_SVC_NOTIFICATION' => 'service',
'CHANGE_HOST_NOTIFICATION_TIMEPERIOD' => 'host',
'CHANGE_SVC_NOTIFICATION_TIMEPERIOD' => 'service',
'CHANGE_CONTACT_HOST_NOTIFICATION_TIMEPERIOD' => 'host',
'CHANGE_CONTACT_SVC_NOTIFICATION_TIMEPERIOD' => 'service',
'CHANGE_HOST_MODATTR' => 'host',
'CHANGE_SVC_MODATTR' => 'service',
'CHANGE_CONTACT_MODATTR' => 'contact',
'CHANGE_CONTACT_MODHATTR' => 'contact',
'CHANGE_CONTACT_MODSATTR' => 'contact',
'SYNC_STATE_INFORMATION' => 'contact',
'DEL_DOWNTIME_BY_HOST_NAME' => 'host',
'DEL_DOWNTIME_BY_HOSTGROUP_NAME' => 'hostgroup',
'DEL_DOWNTIME_BY_START_TIME_COMMENT' => 'comment',
'ACKNOWLEDGE_HOST_PROBLEM_EXPIRE' => 'host',
'ACKNOWLEDGE_SVC_PROBLEM_EXPIRE' => 'service',
'DISABLE_NOTIFICATIONS_EXPIRE_TIME' => 'global',
'CUSTOM_COMMAND' => 'none',
);
/**
* Initialize command structures only once
*/
private static function initCommandStructure()
{
if (self::$initialized === true) {
return;
}
/*
* Build everything for raw commands
*/
$categories = array();
foreach (self::$rawCommands as $commandName => $categoryName) {
// We do not want to see useless commands
if ($categoryName === self::DROP_CATEGORY) {
unset(self::$rawCommands[$commandName]);
continue;
}
$categories[$categoryName] = null;
if (array_key_exists($categoryName, self::$rawCommandCategories) === false) {
self::$rawCommandCategories[$categoryName] = array();
}
self::$rawCommandCategories[$categoryName][] = $commandName;
}
self::$rawCategories = array_keys($categories);
sort(self::$rawCategories);
/*
* Build everything for object commands
*/
self::$objectCommands['host'] = self::$defaultObjectCommands;
self::$objectCommands['service'] = self::$defaultObjectCommands;
self::$initialized = true;
}
/**
* Creates a new object
*/
public function __construct()
{
self::initCommandStructure();
}
/**
* Return a full list of commands
* @return string[]
*/
public function getRawCommands()
{
static $commands = null;
if ($commands === null) {
$commands = array_keys(self::$rawCommands);
}
return $commands;
}
/**
* Return all commands for a category
* @param string $categoryName
* @return string[]
*/
public function getRawCommandsForCategory($categoryName)
{
$this->assertRawCategoryExistence($categoryName);
return array_values(self::$rawCommandCategories[$categoryName]);
}
/**
* Test for category existence
* @param string $categoryName
* @throws \Icinga\Exception\ProgrammingError
*/
private function assertRawCategoryExistence($categoryName)
{
if (array_key_exists($categoryName, self::$rawCommandCategories) === false) {
throw new ProgrammingError('Category does not exists: ' . $categoryName);
}
}
/**
* Return a list of all categories
* @return string[]
*/
public function getRawCategories()
{
return self::$rawCategories;
}
/**
* Returns the type of object
*
* This is made by the first key of property
* e.g.
* $object->host_state
* Type is 'host'
*
* @param \stdClass $object
* @return mixed
*/
private function getObjectType(\stdClass $object)
{
return array_shift(explode('_', array_shift(array_keys(get_object_vars($object))), 2));
}
/**
* Returns method name based on object type
* @param string $type
* @return string
* @throws \Icinga\Exception\ProgrammingError
*/
private function getCommandProcessorMethod($type)
{
if (array_key_exists($type, self::$commandProcessorMethods)) {
$method = self::$commandProcessorMethods[$type];
if (is_callable(array(&$this, $method))) {
return $method;
}
}
throw new ProgrammingError('Type has no command processor: '. $type);
}
/**
* Return interface commands by object type
* @param string $type
* @return array
* @throws \Icinga\Exception\ProgrammingError
*/
private function getCommandsByType($type)
{
if (array_key_exists($type, self::$objectCommands)) {
return self::$objectCommands[$type];
}
throw new ProgrammingError('Type has no commands defined: '. $type);
}
/**
* Modifies data objects to drop their object type
*
* - host_state will be state
* - service_state will be also state
* - And so on
*
* @param \stdClass $object
* @param $type
* @return object
*/
private function dropTypeAttributes(\stdClass $object, $type)
{
$objectData = get_object_vars($object);
foreach ($objectData as $propertyName => $propertyValue) {
$newProperty = str_replace($type. '_', '', $propertyName);
$objectData[$newProperty] = $propertyValue;
unset($objectData[$propertyName]);
}
return (object)$objectData;
}
/**
* Default processor for host and service objects
*
* Drop commands from list based on states and object properties
*
* @param \stdClass $object
* @param array $commands
* @param string $type
* @return array
*/
private function defaultCommandProcessor(\stdClass $object, array $commands, $type)
{
$object = $this->dropTypeAttributes($object, $type);
$commands = array_flip($commands);
if ($object->active_checks_enabled === '1') {
unset($commands[self::CMD_ENABLE_ACTIVE_CHECKS]);
} else {
unset($commands[self::CMD_DISABLE_ACTIVE_CHECKS]);
}
if ($object->passive_checks_enabled !== '1') {
unset($commands[self::CMD_SUBMIT_PASSIVE_CHECK_RESULT]);
}
if ($object->passive_checks_enabled === '1') {
unset($commands[self::CMD_STOP_ACCEPTING_PASSIVE_CHECKS]);
} else {
unset($commands[self::CMD_START_ACCEPTING_PASSIVE_CHECKS]);
}
if ($object->obsess_over_host === '1') {
unset($commands[self::CMD_START_OBSESSING]);
} else {
unset($commands[self::CMD_STOP_OBSESSING]);
}
if ($object->state !== '0') {
if ($object->acknowledged === '1') {
unset($commands[self::CMD_ACKNOWLEDGE_PROBLEM]);
} else {
unset($commands[self::CMD_REMOVE_ACKNOWLEDGEMENT]);
}
} else {
unset($commands[self::CMD_ACKNOWLEDGE_PROBLEM]);
unset($commands[self::CMD_REMOVE_ACKNOWLEDGEMENT]);
}
if ($object->notifications_enabled === '1') {
unset($commands[self::CMD_ENABLE_NOTIFICATIONS]);
} else {
unset($commands[self::CMD_DISABLE_NOTIFICATIONS]);
}
if ($object->event_handler_enabled === '1') {
unset($commands[self::CMD_ENABLE_EVENT_HANDLER]);
} else {
unset($commands[self::CMD_DISABLE_EVENT_HANDLER]);
}
if ($object->flap_detection_enabled === '1') {
unset($commands[self::CMD_ENABLE_FLAP_DETECTION]);
} else {
unset($commands[self::CMD_DISABLE_FLAP_DETECTION]);
}
return array_flip($commands);
}
/**
* Creates structure to work with in interfaces
*
* @param array $commands
* @param string $objectType
* @return array
*/
private function buildInterfaceConfiguration(array $commands, $objectType)
{
$out = array();
foreach ($commands as $index => $commandId) {
$command = new \stdClass();
$command->id = $commandId;
if (array_key_exists($commandId, self::$commandInformation)) {
$command->shortDescription = sprintf(self::$commandInformation[$commandId][1], $objectType);
$command->longDescription = sprintf(self::$commandInformation[$commandId][0], $objectType);
$command->iconCls =
(isset(self::$commandInformation[$commandId][2]))
? self::$commandInformation[$commandId][2]
: '';
$command->btnCls =
(isset(self::$commandInformation[$commandId][3]))
? self::$commandInformation[$commandId][3]
: '';
}
$out[] = $command;
}
return $out;
}
/**
* Drop commands
* For small interfaces or bypass when full interfaces are needed
* @param array $commands
* @param string $type
* @return array
*/
private function filterInterfaceType(array $commands, $type)
{
if ($type === self::TYPE_FULL) {
return $commands;
}
foreach ($commands as $arrayId => $commandId) {
if (in_array($commandId, self::$commandSmallFilter) === false) {
unset($commands[$arrayId]);
}
}
return $commands;
}
/**
* Get commands for an object
*
* Based on objects and interface type
*
* @param \stdClass $object
* @param $interfaceType
* @param User $user
* @return array
*/
public function getCommandForObject(\stdClass $object, $interfaceType, User $user = null)
{
$objectType = $this->getObjectType($object);
$commands = $this->getCommandsByType($objectType);
$method = $this->getCommandProcessorMethod($objectType);
$commands = $this->$method($object, $commands, $objectType);
$commands = $this->filterInterfaceType($commands, $interfaceType);
$commands = $this->buildInterfaceConfiguration($commands, $objectType);
return $commands;
}
}

View File

@ -0,0 +1,76 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
/**
* Icinga 2 Web - Head for multiple monitoring frontends
* Copyright (C) 2013 Icinga Development Team
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* @copyright 2013 Icinga Development Team <info@icinga.org>
* @author Icinga Development Team <info@icinga.org>
*/
// {{{ICINGA_LICENSE_HEADER}}}
namespace Monitoring\View;
/**
* Class DowntimeView
*/
class DowntimeView extends MonitoringView
{
/**
* Query object
* @var mixed
*/
protected $query;
/**
* Available columns
* @var string[]
*/
protected $availableColumns = array(
'downtime_type',
'downtime_author_name',
'downtime_comment_data',
'downtime_is_fixed',
'downtime_duration',
'downtime_scheduled_start_time',
'downtime_scheduled_end_time',
'downtime_was_started',
'downtime_actual_start_time',
'downtime_actual_start_time_usec',
'downtime_is_in_effect',
'downtime_trigger_time',
'downtime_internal_downtime_id'
);
/**
* Filters
* @var array
*/
protected $specialFilters = array();
/**
* Default sorting of data set
* @var array
*/
protected $sortDefaults = array(
'downtime_is_in_effect' => array(
'default_dir' => self::SORT_DESC
),
'downtime_actual_start_time' => array(
'default_dir' => self::SORT_DESC
)
);
}

View File

@ -135,6 +135,7 @@ class MonitoringView extends AbstractQuery
*/
protected function applyRequestSorting($request)
{
return $this->order(
// TODO: Use first sortDefaults entry if available, fall back to
// column if not
@ -238,12 +239,12 @@ class MonitoringView extends AbstractQuery
-4
) . 'Query';
$class = '\\' . get_class($this->ds) . '\\Query\\' . $class;
$query = new $class($this->ds, $this->columns);
foreach ($this->filters as $f) {
$query->where($f[0], $f[1]);
}
foreach ($this->order_columns as $col) {
if (isset($this->sortDefaults[$col[0]]['columns'])) {
foreach ($this->sortDefaults[$col[0]]['columns'] as $c) {
$query->order($c, $col[1]);
@ -252,11 +253,13 @@ class MonitoringView extends AbstractQuery
$query->order($col[0], $col[1]);
}
}
$this->query = $query;
}
if ($this->hasLimit()) {
$this->query->limit($this->getLimit(), $this->getOffset());
}
return $this->query;
}

View File

@ -37,6 +37,7 @@ class StatusView extends MonitoringView
'host_last_time_up',
'host_last_time_down',
'host_last_time_unreachable',
'host_unhandled_service_count',
// Services
'service',

View File

@ -0,0 +1,101 @@
<?php
namespace Test\Monitoring\Application\Controllers\ListController;
require_once(dirname(__FILE__).'/../../testlib/MonitoringControllerTest.php');
use Test\Monitoring\Testlib\MonitoringControllerTest;
use Test\Monitoring\Testlib\Datasource\TestFixture;
use Test\Monitoring\Testlib\Datasource\ObjectFlags;
class ListControllerHostMySQLTest extends MonitoringControllerTest
{
public function testHostListMySQL()
{
$this->executeHostListTestFor("mysql");
}
public function testHostListPgSQL()
{
$this->executeHostListTestFor("pgsql");
}
public function testHostListStatus()
{
$this->executeHostListTestFor("statusdat");
}
public function executeHostListTestFor($backend)
{
date_default_timezone_set('UTC');
$checkTime = time()-2000;
$fixture = new TestFixture();
$firstHostFlags = ObjectFlags::PASSIVE_ONLY();
$firstHostFlags->acknowledged = 1;
$firstHostFlags->in_downtime = 1;
$firstHostFlags->notifications = 0;
$firstHostFlags->flapping = 1;
$firstHostFlags->time = $checkTime;
$fixture->addHost('host1', 1, $firstHostFlags, array(
"address" => "10.92.1.5",
"icon_image" => "myIcon.png",
"notes_url" => "note1.html",
"action_url" => "action.html"))->
addToHostgroup('router')->
addComment('author', 'host comment text')->
addService('svc1', 2)->
addService('svc2', 2)->
addService('svc3', 2, ObjectFlags::ACKNOWLEDGED())->
addService('svc4', 0);
$fixture->addHost('host2', 1)->
addService('svc1', 2);
$fixture->addHost('host3', 0)->
addService('svc1', 0);
$fixture->addHost('host4', 0)->
addService('svc1', 0);
$fixture->addHost('host5', 2, ObjectFlags::ACKNOWLEDGED())->
addService('svc1', 3)->addComment('author','svc comment');
try {
$this->setupFixture($fixture, $backend);
} catch (\PDOException $e) {
echo $e->getMessage();
$this->markTestSkipped('Could not setup fixture for backends '.$backend.' :'.$e->getMessage());
return null;
}
$controller = $this->requireController('ListController', $backend);
$controller->hostsAction();
$result = $controller->view->hosts->fetchAll();
$this->assertCount(5, $result, 'Testing correct result count for '.$backend);
for($i=1;$i<=5;$i++) {
$this->assertEquals('host'.$i, $result[$i-1]->host_name, "Asserting correct host names for backend ".$backend);
}
$hostToTest = $result[0];
$persistedLastCheck = explode("+", $hostToTest->host_last_check);
$persistedLastCheck = $persistedLastCheck[0];
$this->assertEquals("10.92.1.5", $hostToTest->host_address, "Testing for correct host address field (backend ".$backend.")");
$this->assertEquals(1, $hostToTest->host_state, "Testing for status being DOWN (backend ".$backend.")");
$this->assertEquals(date("Y-m-d H:i:s", intval($checkTime)), $persistedLastCheck, "Testing for correct last check time format (backend ".$backend.")");
$this->assertEquals($checkTime, $hostToTest->host_last_state_change, "Testing for correct last state change (backend ".$backend.")");
$this->assertEquals("Plugin output for host host1", $hostToTest->host_output, "Testing correct output for host (backend ".$backend.")");
$this->assertEquals("Long plugin output for host host1", $hostToTest->host_long_output, "Testing correct long output for host (backend ".$backend.")");
$this->assertEquals(0, $hostToTest->host_notifications_enabled, "Testing for disabled notifications (backend ".$backend.')');
$this->assertEquals(1, $hostToTest->host_acknowledged, "Testing for host being acknowledged (backend ".$backend.')');
$this->assertEquals(1, $hostToTest->host_in_downtime, "Testing for host being in downtime (backend ".$backend.')');
$this->assertEquals(1, $hostToTest->host_is_flapping, "Testing for host being flapping (backend ".$backend.')');
$this->assertEquals(1, $hostToTest->host_last_comment, 'Testing correct comment count for first host (backend '.$backend.')');
$this->assertEquals(0, $hostToTest->host_state_type, 'Testing for soft state');
$this->assertEquals(1, $hostToTest->host_handled, 'Testing for handled host (backend '.$backend.')');
$this->assertEquals("myIcon.png", $hostToTest->host_icon_image, 'Testing for icon image (backend '.$backend.')');
$this->assertEquals("note1.html", $hostToTest->host_notes_url, 'Testing for notes url (backend '.$backend.')');
$this->assertEquals("action.html", $hostToTest->host_action_url, 'Testing for action url (backend '.$backend.')');
$this->assertEquals(2, $hostToTest->host_unhandled_service_count, 'Testing correct open problems count (backend '.$backend.')');
}
}

View File

@ -0,0 +1,69 @@
<?php
namespace Test\Monitoring\Application\Controllers\ListController;
require_once(dirname(__FILE__).'/../../testlib/MonitoringControllerTest.php');
use Test\Monitoring\Testlib\MonitoringControllerTest;
use Test\Monitoring\Testlib\Datasource\TestFixture;
use Test\Monitoring\Testlib\Datasource\ObjectFlags;
class ListControllerServiceMySQLTest extends MonitoringControllerTest
{
public function testServiceListMySQL()
{
$this->executeServiceListTestFor("mysql");
}
public function testServiceListPgSQL()
{
$this->executeServiceListTestFor("pgsql");
}
public function testServiceListStatusdat()
{
$this->executeServiceListTestFor("statusdat");
}
public function executeServiceListTestFor($backend)
{
date_default_timezone_set('UTC');
$checkTime = time()-2000;
$fixture = new TestFixture();
$fixture->addHost('host1', 0)->
addService("svc1", 0, new ObjectFlags(2000), array(
"notes_url" => "notes.url",
"action_url" => "action.url",
"icon_image" => "svcIcon.png"
))->
addService("svcDown", 2) -> addComment("author", "Comment text")->
addService("svcFlapping", 1, ObjectFlags::FLAPPING())->addToServicegroup("Warning")->
addService("svcNotifDisabled", 2, ObjectFlags::DISABLE_NOTIFICATIONS())->
addService("svcPending", 0, ObjectFlags::PENDING());
$fixture->addHost('host2', 1)->
addService("svcPassive", 1, ObjectFlags::PASSIVE_ONLY())->addToServicegroup("Warning")->
addService("svcDisabled", 1, ObjectFlags::DISABLED())->addToServicegroup("Warning")->
addService("svcDowntime", 2, ObjectFlags::IN_DOWNTIME())->
addService("svcAcknowledged", 1, ObjectFlags::ACKNOWLEDGED())->addToServicegroup("Warning");
try {
$this->setupFixture($fixture, $backend);
} catch (\PDOException $e) {
echo $e->getMessage();
$this->markTestSkipped('Could not setup fixture for backends '.$backend.' :'.$e->getMessage());
return null;
}
$controller = $this->requireController('ListController', $backend);
$controller->servicesAction();
$result = $controller->view->services->fetchAll();
$this->assertEquals(9, count($result), "Testing for correct service count");
$this->assertEquals("notes.url", $result[0]->service_notes_url, "Testing for correct notes_url");
$this->assertEquals("action.url", $result[0]->service_action_url, "Testing for correct action_url");
$this->assertEquals(0, $result[0]->service_state, "Testing for correct Service state");
}
}

View File

@ -0,0 +1,116 @@
<?php
namespace Test\Modules\Monitoring\Application\Views\Helpers;
use Monitoring\Command\Meta;
require_once 'Zend/View/Helper/Abstract.php';
require_once 'Zend/View.php';
require_once __DIR__. '/../../../../../application/views/helpers/MonitoringCommands.php';
require_once __DIR__. '/../../../../../library/Monitoring/Command/Meta.php';
require_once __DIR__. '/../../../../../../../library/Icinga/Exception/ProgrammingError.php';
class HostStruct extends \stdClass
{
public $host_name = 'localhost';
public $host_address = '127.0.0.1';
public $host_state = '1';
public $host_handled = '1';
public $host_in_downtime = '1';
public $host_acknowledged = '1';
public $host_check_command = 'check-host-alive';
public $host_last_state_change = '1372937083';
public $host_alias = 'localhost';
public $host_output = 'DDD';
public $host_long_output = '';
public $host_perfdata = '';
public $host_current_check_attempt = '1';
public $host_max_check_attempts = '10';
public $host_attempt = '1/10';
public $host_last_check = '2013-07-04 11:24:42';
public $host_next_check = '2013-07-04 11:29:43';
public $host_check_type = '1';
public $host_last_hard_state_change = '2013-07-04 11:24:43';
public $host_last_hard_state = '0';
public $host_last_time_up = '2013-07-04 11:20:23';
public $host_last_time_down = '2013-07-04 11:24:43';
public $host_last_time_unreachable = '0000-00-00 00:00:00';
public $host_state_type = '1';
public $host_last_notification = '0000-00-00 00:00:00';
public $host_next_notification = '0000-00-00 00:00:00';
public $host_no_more_notifications = '0';
public $host_notifications_enabled = '1';
public $host_problem_has_been_acknowledged = '1';
public $host_acknowledgement_type = '2';
public $host_current_notification_number = '0';
public $host_passive_checks_enabled = '1';
public $host_active_checks_enabled = '0';
public $host_event_handler_enabled = '0';
public $host_flap_detection_enabled = '1';
public $host_is_flapping = '0';
public $host_percent_state_change = '12.36842';
public $host_latency = '0.12041';
public $host_execution_time = '0';
public $host_scheduled_downtime_depth = '1';
public $host_failure_prediction_enabled = '1';
public $host_process_performance_data = '1';
public $host_obsess_over_host = '1';
public $host_modified_host_attributes = '14';
public $host_event_handler = '';
public $host_normal_check_interval = '5';
public $host_retry_check_interval = '1';
public $host_check_timeperiod_object_id = '27';
}
class MonitoringCommandsTest extends \PHPUnit_Framework_TestCase {
public function testOutput1()
{
$helper = new \Zend_View_Helper_MonitoringCommands();
$object = new HostStruct();
$html = $helper->monitoringCommands($object, Meta::TYPE_SMALL);
$this->assertContains('Remove acknowledgement', $html);
$this->assertContains('Recheck', $html);
$this->assertNotContains('Obsess', $html);
$this->assertNotContains('Enable', $html);
$this->assertNotContains('Disable', $html);
}
public function testOutput2()
{
$helper = new \Zend_View_Helper_MonitoringCommands();
$object = new HostStruct();
$html = $helper->monitoringCommands($object, Meta::TYPE_FULL);
$dom = new \DOMDocument('1.0', 'utf-8');
$dom->loadXML($html);
$xpath = new \DOMXPath($dom);
$nodes = $xpath->query('//div[@class=\'command-section pull-left\']');
$this->assertEquals(5, $nodes->length);
$nodes = $xpath->query('//button');
$this->assertEquals(21, $nodes->length);
}
public function testOutput3()
{
$helper = new \Zend_View_Helper_MonitoringCommands();
$object = new HostStruct();
$object->host_state = '0';
$html = $helper->monitoringCommands($object, Meta::TYPE_FULL);
$dom = new \DOMDocument('1.0', 'utf-8');
$dom->loadXML($html);
$xpath = new \DOMXPath($dom);
$nodes = $xpath->query('//button');
$this->assertEquals(20, $nodes->length);
}
}

View File

@ -0,0 +1,116 @@
<?php
namespace Test\Modules\Monitoring\Application\Views\Helpers;
require_once 'Zend/View/Helper/Abstract.php';
require_once 'Zend/View.php';
require_once __DIR__. '/../../../../../application/views/helpers/MonitoringFlags.php';
class MonitoringFlagsTest extends \PHPUnit_Framework_TestCase
{
public function testHosts1()
{
$testArray = array(
'host_passive_checks_enabled' => '0',
'host_active_checks_enabled' => '0',
'host_obsess_over_host' => '1',
'host_notifications_enabled' => '0',
'host_event_handler_enabled' => '1',
'host_flap_detection_enabled' => '1',
);
$monitoringFlags = new \Zend_View_Helper_MonitoringFlags();
$returnArray = $monitoringFlags->monitoringFlags((object)$testArray);
$this->assertCount(6, $returnArray);
$expected = array(
'Passive checks' => false,
'Active checks' => false,
'Obsessing' => true,
'Notifications' => false,
'Event handler' => true,
'Flap detection' => true
);
$this->assertEquals($expected, $returnArray);
}
public function testService1()
{
$testArray = array(
'service_passive_checks_enabled' => '0',
'service_active_checks_enabled' => '1',
'service_obsess_over_host' => '0',
'service_notifications_enabled' => '1',
'service_event_handler_enabled' => '1',
'service_flap_detection_enabled' => '0',
);
$monitoringFlags = new \Zend_View_Helper_MonitoringFlags();
$returnArray = $monitoringFlags->monitoringFlags((object)$testArray);
$this->assertCount(6, $returnArray);
$expected = array(
'Passive checks' => false,
'Active checks' => true,
'Obsessing' => false,
'Notifications' => true,
'Event handler' => true,
'Flap detection' => false
);
$this->assertEquals($expected, $returnArray);
}
public function testUglyConditions1()
{
$testArray = array(
'service_active_checks_enabled' => '1',
'service_obsess_over_host' => '1',
'DING DING' => '$$$',
'DONG DONG' => '###'
);
$monitoringFlags = new \Zend_View_Helper_MonitoringFlags();
$returnArray = $monitoringFlags->monitoringFlags((object)$testArray);
$this->assertCount(6, $returnArray);
$expected = array(
'Passive checks' => false,
'Active checks' => true,
'Obsessing' => true,
'Notifications' => false,
'Event handler' => false,
'Flap detection' => false
);
$this->assertEquals($expected, $returnArray);
}
public function testUglyConditions2()
{
$testArray = array(
'DING DING' => '$$$',
'DONG DONG' => '###'
);
$monitoringFlags = new \Zend_View_Helper_MonitoringFlags();
$returnArray = $monitoringFlags->monitoringFlags((object)$testArray);
$this->assertCount(6, $returnArray);
$expected = array(
'Passive checks' => false,
'Active checks' => false,
'Obsessing' => false,
'Notifications' => false,
'Event handler' => false,
'Flap detection' => false
);
$this->assertEquals($expected, $returnArray);
}
}

View File

@ -0,0 +1,107 @@
<?php
namespace Test\Modules\Monitoring\Application\Views\Helpers;
require_once 'Zend/View/Helper/Abstract.php';
require_once 'Zend/View.php';
require_once __DIR__. '/../../../../../application/views/helpers/MonitoringProperties.php';
class HostStruct4Properties extends \stdClass
{
public $host_name = 'localhost';
public $host_address = '127.0.0.1';
public $host_state = '1';
public $host_handled = '1';
public $host_in_downtime = '1';
public $host_acknowledged = '1';
public $host_check_command = 'check-host-alive';
public $host_last_state_change = '1372937083';
public $host_alias = 'localhost';
public $host_output = 'DDD';
public $host_long_output = '';
public $host_perfdata = '';
public $host_current_check_attempt = '1';
public $host_max_check_attempts = '10';
public $host_attempt = '1/10';
public $host_last_check = '2013-07-04 11:24:42';
public $host_next_check = '2013-07-04 11:29:43';
public $host_check_type = '1';
public $host_last_hard_state_change = '2013-07-04 11:24:43';
public $host_last_hard_state = '0';
public $host_last_time_up = '2013-07-04 11:20:23';
public $host_last_time_down = '2013-07-04 11:24:43';
public $host_last_time_unreachable = '0000-00-00 00:00:00';
public $host_state_type = '1';
public $host_last_notification = '0000-00-00 00:00:00';
public $host_next_notification = '0000-00-00 00:00:00';
public $host_no_more_notifications = '0';
public $host_notifications_enabled = '1';
public $host_problem_has_been_acknowledged = '1';
public $host_acknowledgement_type = '2';
public $host_current_notification_number = '0';
public $host_passive_checks_enabled = '1';
public $host_active_checks_enabled = '0';
public $host_event_handler_enabled = '0';
public $host_flap_detection_enabled = '1';
public $host_is_flapping = '0';
public $host_percent_state_change = '12.36842';
public $host_latency = '0.12041';
public $host_execution_time = '0';
public $host_scheduled_downtime_depth = '1';
public $host_failure_prediction_enabled = '1';
public $host_process_performance_data = '1';
public $host_obsess_over_host = '1';
public $host_modified_host_attributes = '14';
public $host_event_handler = '';
public $host_normal_check_interval = '5';
public $host_retry_check_interval = '1';
public $host_check_timeperiod_object_id = '27';
public $host_status_update_time = '2013-07-08 10:10:10';
}
class MonitoringPropertiesTest extends \PHPUnit_Framework_TestCase
{
public function testOutput1()
{
$host = new HostStruct4Properties();
$host->host_current_check_attempt = '5';
$propertyHelper = new \Zend_View_Helper_MonitoringProperties();
$items = $propertyHelper->monitoringProperties($host);
$this->assertCount(10, $items);
$this->assertEquals('5/10 (HARD state)', $items['Current attempt']);
$this->assertEquals('2013-07-08 10:10:10', $items['Last update']);
}
public function testOutput2()
{
date_default_timezone_set("UTC");
$host = new HostStruct4Properties();
$host->host_current_check_attempt = '5';
$host->host_active_checks_enabled = '1';
$host->host_passive_checks_enabled = '0';
$host->host_is_flapping = '1';
$propertyHelper = new \Zend_View_Helper_MonitoringProperties();
$items = $propertyHelper->monitoringProperties($host);
$this->assertCount(10, $items);
$test = array(
'Current attempt' => "5/10 (HARD state)",
'Last check time' => "2013-07-04 11:24:42",
'Check type' => "ACTIVE",
'Check latency / duration' => "0.1204 / 0.0000 seconds",
'Next scheduled active check' => "2013-07-04 11:29:43",
'Last state change' => "2013-07-04 11:24:43",
'Last notification' => "N/A (notification 0)",
'Is this host flapping?' => "YES (12.37% state change)",
'In scheduled downtime?' => "YES",
'Last update' => "2013-07-08 10:10:10",
);
$this->assertEquals($test, $items);
}
}

View File

@ -1,17 +1,19 @@
<?php
namespace Tests\Icinga\Backend\Statusdat;
namespace Tests\Monitoring\Backend\Statusdat;
use Tests\Icinga\Protocol\Statusdat\ReaderMock as ReaderMock;
require_once("Zend/Config.php");
require_once("./library/Icinga/Protocol/Statusdat/ReaderMock.php");
require_once("../../library/Icinga/Backend/Query.php");
require_once("../../library/Icinga/Backend/Criteria/Order.php");
require_once("../../library/Icinga/Backend/AbstractBackend.php");
require_once("../../library/Icinga/Backend/Statusdat/Query.php");
require_once("../../library/Icinga/Backend/Statusdat/GroupsummaryQuery.php");
require_once("../../library/Icinga/Backend/Statusdat/ServicegroupsummaryQuery.php");
use Monitoring\Backend\Statusdat\Query\ServicegroupsummaryQuery;
use Tests\Icinga\Protocol\Statusdat\StatusdatTestLoader;
class BackendMock extends \Icinga\Backend\AbstractBackend{
$base = dirname(__FILE__)."/../../../../..";
require_once($base."/../../test/php/library/Icinga/Protocol/Statusdat/StatusdatTestLoader.php");
StatusdatTestLoader::requireLibrary();
require_once(realpath($base."/library/Monitoring/Backend/Statusdat/Query/GroupsummaryQuery.php"));
require_once(realpath($base."/library/Monitoring/Backend/Statusdat/Query/ServicegroupsummaryQuery.php"));
class BackendMock extends \Monitoring\Backend\AbstractBackend
{
public $reader;
public function select() {
@ -27,12 +29,6 @@ class BackendMock extends \Icinga\Backend\AbstractBackend{
}
/**
*
* Test class for Servicegroupsummaryquery
* Created Mon, 18 Feb 2013 14:33:21 +0000
*
**/
class ServicegroupsummaryqueryTest extends \PHPUnit_Framework_TestCase
{
@ -40,7 +36,7 @@ class ServicegroupsummaryqueryTest extends \PHPUnit_Framework_TestCase
{
$backend = new BackendMock();
$backend->setReader($this->getTestDataset());
$q = new \Icinga\Backend\Statusdat\ServicegroupsummaryQuery($backend);
$q = new ServicegroupsummaryQuery($backend);
$indices = array(
"service" => array(
"hosta;service1", "hosta;service2", "hosta;service3",

View File

@ -0,0 +1,185 @@
<?php
namespace Test\Modules\Monitoring\Library\Command;
require_once __DIR__. '/../../../../library/Monitoring/Command/Meta.php';
require_once __DIR__. '/../../../../../../library/Icinga/Exception/ProgrammingError.php';
use Monitoring\Command\Meta;
class HostStruct extends \stdClass
{
public $host_name = 'localhost';
public $host_address = '127.0.0.1';
public $host_state = '1';
public $host_handled = '1';
public $host_in_downtime = '1';
public $host_acknowledged = '1';
public $host_check_command = 'check-host-alive';
public $host_last_state_change = '1372937083';
public $host_alias = 'localhost';
public $host_output = 'DDD';
public $host_long_output = '';
public $host_perfdata = '';
public $host_current_check_attempt = '1';
public $host_max_check_attempts = '10';
public $host_attempt = '1/10';
public $host_last_check = '2013-07-04 11:24:42';
public $host_next_check = '2013-07-04 11:29:43';
public $host_check_type = '1';
public $host_last_hard_state_change = '2013-07-04 11:24:43';
public $host_last_hard_state = '0';
public $host_last_time_up = '2013-07-04 11:20:23';
public $host_last_time_down = '2013-07-04 11:24:43';
public $host_last_time_unreachable = '0000-00-00 00:00:00';
public $host_state_type = '1';
public $host_last_notification = '0000-00-00 00:00:00';
public $host_next_notification = '0000-00-00 00:00:00';
public $host_no_more_notifications = '0';
public $host_notifications_enabled = '1';
public $host_problem_has_been_acknowledged = '1';
public $host_acknowledgement_type = '2';
public $host_current_notification_number = '0';
public $host_passive_checks_enabled = '1';
public $host_active_checks_enabled = '0';
public $host_event_handler_enabled = '0';
public $host_flap_detection_enabled = '1';
public $host_is_flapping = '0';
public $host_percent_state_change = '12.36842';
public $host_latency = '0.12041';
public $host_execution_time = '0';
public $host_scheduled_downtime_depth = '1';
public $host_failure_prediction_enabled = '1';
public $host_process_performance_data = '1';
public $host_obsess_over_host = '1';
public $host_modified_host_attributes = '14';
public $host_event_handler = '';
public $host_normal_check_interval = '5';
public $host_retry_check_interval = '1';
public $host_check_timeperiod_object_id = '27';
}
class MetaTest extends \PHPUnit_Framework_TestCase
{
public function testRawCommands1()
{
$meta = new Meta();
$commands = $meta->getRawCommands();
$this->assertCount(173, $commands);
$this->assertTrue(in_array('SCHEDULE_SERVICEGROUP_SVC_DOWNTIME', $commands));
$this->assertTrue(in_array('SCHEDULE_SVC_CHECK', $commands));
$this->assertTrue(in_array('ENABLE_HOSTGROUP_SVC_CHECKS', $commands));
$this->assertTrue(in_array('PROCESS_HOST_CHECK_RESULT', $commands));
$this->assertTrue(in_array('ACKNOWLEDGE_SVC_PROBLEM', $commands));
$this->assertTrue(in_array('ACKNOWLEDGE_HOST_PROBLEM', $commands));
$this->assertTrue(in_array('SCHEDULE_FORCED_SVC_CHECK', $commands));
$this->assertTrue(in_array('DISABLE_FLAP_DETECTION', $commands));
}
public function testRawCommands2()
{
$meta = new Meta();
$categories = $meta->getRawCategories();
$this->assertCount(7, $categories);
$this->assertEquals(
array(
'comment',
'contact',
'global',
'host',
'hostgroup',
'service',
'servicegroup'
),
$categories
);
}
public function testRawCommands3()
{
$meta = new Meta();
$this->assertCount(9, $meta->getRawCommandsForCategory('hostgroup'));
$this->assertCount(14, $meta->getRawCommandsForCategory('servicegroup'));
$test1 = $meta->getRawCommandsForCategory('global');
$this->count(26, $test1);
$this->assertTrue(in_array('DISABLE_NOTIFICATIONS', $test1));
$this->assertTrue(in_array('RESTART_PROCESS', $test1));
$this->assertTrue(in_array('ENABLE_FLAP_DETECTION', $test1));
$this->assertTrue(in_array('PROCESS_FILE', $test1));
}
/**
* @expectedException Icinga\Exception\ProgrammingError
* @expectedExceptionMessage Category does not exists: DOES_NOT_EXIST
*/
public function testRawCommands4()
{
$meta = new Meta();
$meta->getRawCommandsForCategory('DOES_NOT_EXIST');
}
public function testObjectForCommand1()
{
$meta = new Meta();
$object = new HostStruct();
$commands = $meta->getCommandForObject($object, Meta::TYPE_SMALL);
$this->assertEquals(3, $commands[0]->id);
$this->assertEquals(27, $commands[1]->id);
$object->host_state = '0';
$commands = $meta->getCommandForObject($object, Meta::TYPE_SMALL);
$this->assertEquals(3, $commands[0]->id);
$this->assertFalse(isset($commands[1])); // STATE IS OK AGAIN
$object->host_state = '1';
$object->host_acknowledged = '0';
$commands = $meta->getCommandForObject($object, Meta::TYPE_SMALL);
$this->assertEquals(3, $commands[0]->id);
$this->assertEquals(26, $commands[1]->id);
}
public function testObjectForCommand2()
{
$meta = new Meta();
$object = new HostStruct();
$object->host_obsess_over_host = '0';
$object->host_flap_detection_enabled = '0';
$object->host_active_checks_enabled = '0';
$commands = $meta->getCommandForObject($object, Meta::TYPE_FULL);
$this->assertEquals(2, $commands[0]->id);
$this->assertEquals(6, $commands[3]->id);
}
/**
* @expectedException Icinga\Exception\ProgrammingError
* @expectedExceptionMessage Type has no commands defined: UNKNOWN
*/
public function testObjectForCommand3()
{
$meta = new Meta();
$test = new \stdClass();
$test->UNKNOWN_state = '2';
$test->UNKNOWN_flap_detection_enabled = '1';
$commands = $meta->getCommandForObject($test, Meta::TYPE_FULL);
}
}

View File

@ -0,0 +1,274 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Web
{
/**
* Mocked controller base class to avoid the complete
* Bootstrap dependency of the normally used ModuleActionController
*/
class ModuleActionController
{
/**
* The view this controller would create
* @var stdClass
*/
public $view;
public $headers = array();
/**
* Parameters provided on call
* @var array
*/
public $params = array();
/**
* _getParam method that normally retrieves GET/POST parameters
*
* @param string $param The parameter name to retrieve
* @return mixed|bool The parameter $param or false if it doesn't exist
*/
public function _getParam($param, $default = null)
{
if (!isset($this->params[$param])) {
return $default;
}
return $this->params[$param];
}
public function getParam($param, $default = null)
{
return $this->_getParam($param, $default);
}
public function preserve()
{
return $this;
}
public function getParams()
{
return $this->params;
}
/**
* Sets the backend for this controller which will be used in the action
*
* @param $backend
*/
public function setBackend($backend)
{
$this->backend = $backend;
}
public function __get($param) {
return $this;
}
public function getHeader($header) {
if (isset($this->headers[$header])) {
return $this->headers[$header];
}
return null;
}
}
}
namespace Test\Monitoring\Testlib
{
use Icinga\Protocol\Statusdat\Reader;
use Test\Monitoring\Testlib\DataSource\TestFixture;
use Test\Monitoring\Testlib\DataSource\DataSourceTestSetup;
use Monitoring\Backend\Ido;
use Monitoring\Backend\Statusdat;
/**
* Base class for monitoring controllers that loads required dependencies
* and allows easier setup of tests
*
* Example:
* <code>
*
* class MyControllerTest extends MonitoringControllerTest
* {
* public function testSomething()
* {
* // Create a test fixture
* $fixture = new TestFixture()
* $fixture->addHost('host', 0)->addService(...)->..->;
*
* $this->setupFixture($fixture, "mysql"); // setup the fixture
* $controller = $this->requireController('MyController', 'mysql');
* // controller is now the Zend controller instance, perform an action
* $controller->myAction();
* $result = $controller->view->hosts->fetchAll();
* // assert stuff
* }
* }
*/
abstract class MonitoringControllerTest extends \PHPUnit_Framework_TestCase
{
/**
* The module directory for requiring modules (is relative to the source file)
* @var string
*/
private $moduleDir = "";
/**
* The application directory for requirying library files (is relative to the source file)
* @var string
*/
private $appDir = "";
/**
* Require necessary libraries on test creation
*
* This is called for every test and assures that all required libraries for the controllers
* are loaded. If you need additional dependencies you should overwrite this method, call the parent
* and then require your classes
*/
public function setUp()
{
$this->moduleDir = dirname(__FILE__) . '/../../../';
$this->appDir = $this->moduleDir.'../../library/Icinga/';
$module = $this->moduleDir;
$app = $this->appDir;
set_include_path(get_include_path().':'.$module);
set_include_path(get_include_path().':'.$app);
require_once('Zend/Config.php');
require_once('Zend/Db.php');
require_once(dirname(__FILE__) . '/datasource/DataSourceTestSetup.php');
$this->requireBase();
$this->requireViews();
}
/**
* Require base application and data retrieval classes from the Icinga Library
*
*/
private function requireBase()
{
require_once('Application/Benchmark.php');
require_once('Data/AbstractQuery.php');
require_once('Data/DatasourceInterface.php');
require_once('Data/Db/Connection.php');
require_once('Data/Db/Query.php');
require_once('Exception/ProgrammingError.php');
require_once('library/Monitoring/Backend/AbstractBackend.php');
}
/**
* Require all defined IDO queries in this module
*
*/
private function requireIDOQueries()
{
require_once('library/Monitoring/Backend/Ido.php');
$this->requireFolder('library/Monitoring/Backend/Ido/Query');
}
/**
* Require all php files in the folder $folder
*
* @param $folder The path to the folder containing PHP files
*/
private function requireFolder($folder)
{
$module = $this->moduleDir;
$views = scandir($module.$folder);
foreach ($views as $view) {
if (!preg_match('/php$/', $view)) {
continue;
}
require_once(realpath($module.$folder."/".$view));
}
}
/**
* Require all views and queries from the statusdat backen
*
*/
private function requireStatusDatQueries()
{
require_once(realpath($this->moduleDir.'/library/Monitoring/Backend/Statusdat.php'));
require_once(realpath($this->moduleDir.'/library/Monitoring/Backend/Statusdat/Query/Query.php'));
$this->requireFolder('library/Monitoring/Backend/Statusdat');
$this->requireFolder('library/Monitoring/Backend/Statusdat/Criteria');
$this->requireFolder('library/Monitoring/Backend/Statusdat/Query');
$this->requireFolder('library/Monitoring/Backend/Statusdat/DataView');
$this->requireFolder('library/Monitoring/Backend/Statusdat/DataView');
}
/**
* Require all (generic) view classes from the monitoring module
*/
private function requireViews()
{
$module = $this->moduleDir;
require_once($module.'library/Monitoring/View/MonitoringView.php');
$this->requireFolder('library/Monitoring/View/');
}
/**
* Require and set up a controller $controller using the backend type specified at $backend
*
* @param string $controller The name of the controller tu use (must be under monitoring/application/controllers)
* @param string $backend The backend to use ('mysql', 'pgsql' or 'statusdat')
* @return ModuleActionController The newly created controller
*/
public function requireController($controller, $backend)
{
require_once($this->moduleDir.'/application/controllers/'.$controller.'.php');
$controllerName = '\Monitoring_'.ucfirst($controller);
$controller = new $controllerName;
$controller->setBackend($this->getBackendFor($backend));
return $controller;
}
/**
* Create a new backend and insert the given fixture into it
*
* @param TestFixture $fixture The TestFixture to create
* @param string $type The type of the backend ('mysql', 'pgsql' or 'statusdat')
*/
public function setupFixture(TestFixture $fixture, $type)
{
$dbInstance = new DataSourceTestSetup($type);
$dbInstance->setup();
$dbInstance->insert($fixture);
}
/**
* Set up and configure a new testbackend for the given type
*
* @param string $type The type of the backend 'mysql', 'pgsql' or 'statusdat'
* @return Ido|Statusdat The newly created backend
*/
public function getBackendFor($type) {
if ($type == "mysql" || $type == "pgsql") {
$this->requireIDOQueries();
return new Ido(new \Zend_Config(array(
"dbtype"=> $type,
'host' => "localhost",
'user' => "icinga_unittest",
'pass' => "icinga_unittest",
'db' => "icinga_unittest"
)));
} else if ($type == "statusdat") {
$this->requireStatusDatQueries();
return new Statusdat(new \Zend_Config(array(
'status_file' => '/tmp/teststatus.dat',
'objects_file' => '/tmp/testobjects.cache',
'no_cache' => true
)));
}
}
}
}

View File

@ -0,0 +1,130 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Test\Monitoring\Testlib\DataSource;
require_once(dirname(__FILE__).'/strategies/InsertionStrategy.php');
require_once(dirname(__FILE__).'/strategies/SetupStrategy.php');
require_once(dirname(__FILE__).'/strategies/MySQLSetupStrategy.php');
require_once(dirname(__FILE__).'/strategies/PgSQLSetupStrategy.php');
require_once(dirname(__FILE__).'/strategies/PDOInsertionStrategy.php');
require_once(dirname(__FILE__).'/strategies/StatusdatInsertionStrategy.php');
require_once(dirname(__FILE__).'/strategies/StatusdatSetupStrategy.php');
require_once(dirname(__FILE__).'/TestFixture.php');
use \Test\Monitoring\Testlib\Datasource\Strategies\InsertionStrategy;
use \Test\Monitoring\Testlib\Datasource\Strategies\SetupStrategy;
use \Test\Monitoring\Testlib\Datasource\Strategies\MySQLSetupStrategy;
use \Test\Monitoring\Testlib\Datasource\Strategies\PgSQLSetupStrategy;
use \Test\Monitoring\Testlib\Datasource\Strategies\PDOInsertionStrategy;
use \Test\Monitoring\Testlib\Datasource\Strategies\StatusdatInsertionStrategy;
use \Test\Monitoring\Testlib\Datasource\Strategies\StatusdatSetupStrategy;
/**
* Fascade class that handles creation of test-fixture backends
*
* This class handles the creation and combination of SetupStrategies and InsertionStrategy
* when testing controllers/queries with different backends.
*
* Example:
* <code>
* // TestFixtures contain the objects that should be written for testing
* $fixture = new TestFixture();
* $fixture->addHost(..)->... // setup fixture
*
* $ds = new DataSourceTestSetup('mysql');
* $ds->setup(); // create a blank datasource
* $ds->insert($fixture);
* </code>
*
*
*/
class DataSourceTestSetup implements SetupStrategy, InsertionStrategy
{
/**
* The SetupStrategy that is used on 'setup'
* @var \Test\Monitoring\Testlib\Datasource\Strategies\StatusdatSetupStrategy
*/
private $setupStrategy;
/**
* The InsertionStrategy that is used on 'insert'
* @var \Test\Monitoring\Testlib\Datasource\Strategies\StatusdatInsertionStrategy
*/
private $insertionStrategy;
/**
* Create a DataSource for the backend $type.
*
* On creation, a suitable setup/insert combination will be used
* for the provided backend, so the caller needn't to care about which
* setup or insertion strategy he wants to use.
*
* @param String $type The type of the backend (currently 'mysql', 'pgsql' and 'statusdat')
*/
public function __construct($type)
{
if ($type == 'mysql') {
$this->setupStrategy = new MySQLSetupStrategy();
$this->insertionStrategy = new PDOInsertionStrategy();
$this->insertionStrategy->datetimeFormat = "Y-m-d H:i:s";
} elseif ($type == 'pgsql') {
$this->setupStrategy = new PgSQLSetupStrategy();
$this->insertionStrategy = new PDOInsertionStrategy();
$this->insertionStrategy->datetimeFormat = "Y-m-d H:i:s";
} elseif ($type == 'statusdat') {
$this->setupStrategy = new StatusdatSetupStrategy();
$this->insertionStrategy = new StatusdatInsertionStrategy();
} else {
throw new \Exception('Unsupported backend '.$type);
}
}
/**
* Insert a testfixture into this datasource
*
* @param TestFixture $fixture The fixture to insert into the datasource
*/
public function insert(TestFixture $fixture) {
$this->insertionStrategy->insert($fixture);
}
/**
* Create a blank datasource that can be filled with TestFixtures afterwards
*
* @param String $version An (optional) version to use for creation
* @param mixed $connection An (optional) connection to use for this datasource
*/
public function setup($version = null, $connection = null)
{
$c = $this->setupStrategy->setup($version, $connection);
$this->insertionStrategy->setConnection($c);
}
/**
* Remove all testdata created in this datasource
*
* @param mixed $connection An optional connection to use for clean up
*/
public function teardown($connection = null)
{
$this->setupStrategy->teardown($connection);
}
/**
* Sets the connection to use for writing to this datasource
*
* @param mixed $connection The connection to use. The actual type depends
* on the used backend
*/
public function setConnection($connection)
{
$this->insertionStrategy->setConnection($connection);
}
}

View File

@ -0,0 +1,561 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Test\Monitoring\Testlib\DataSource;
/**
* Status flags for objects
*
*/
class ObjectFlags {
/**
* 1 if the test host is flapping, otherwise 0
* @var int
*/
public $flapping = 0;
/**
* 1 if the test host has notifications enabled, otherwise 0
* @var int
*/
public $notifications = 1;
/**
* 1 if the test host is active, otherwise 0
* @var int
*/
public $active_checks = 1;
/**
* 1 if the test host allows passive checks, otherwise 0
* @var int
*/
public $passive_checks = 1;
/**
* 1 if the test host is acknowledged, otherwise 0
* @var int
*/
public $acknowledged = 0;
/**
* 1 if the test host is in a downtime, otherwise 0
* @var int
*/
public $in_downtime = 0;
/**
* 1 if the test host is pending, otherwise 0
* @var int
*/
public $is_pending = 0;
/**
* The last check and state change time as a UNIX timestamp
* @var int
*/
public $time = 0;
/**
* Create a new ObjectFlags instance with default values
*
* @param int $ageInSeconds How old this check should be in seconds
*/
public function __construct($ageInSeconds = null)
{
if(!is_int($ageInSeconds))
$ageInSeconds = 0;
$this->time = time()-$ageInSeconds;
}
/**
* Create a new ObjectFlags object that is in 'flapping' state
*
* @return ObjectFlags
*/
public static function FLAPPING()
{
$flags = new ObjectFlags();
$flags->flapping = 0;
return $flags;
}
/**
* Create a new ObjectFlags object that is in 'pending' state
*
* @return ObjectFlags
*/
public static function PENDING()
{
$flags = new ObjectFlags();
$flags->is_pending = 1;
return $flags;
}
/**
* Create a new ObjectFlags object that is in 'notifications_disabled' state
*
* @return ObjectFlags
*/
public static function DISABLE_NOTIFICATIONS()
{
$flags = new ObjectFlags();
$flags->notifications = 0;
return $flags;
}
/**
* Create a new ObjectFlags object that has active checks disabled but passive enabled
*
* @return ObjectFlags
*/
public static function PASSIVE_ONLY()
{
$flags = new ObjectFlags();
$flags->active_checks = 0;
return $flags;
}
/**
* Create a new ObjectFlags object that has passive checks disabled but active enabled
*
* @return ObjectFlags
*/
public static function ACTIVE_ONLY()
{
$flags = new ObjectFlags();
$flags->passive_checks = 0;
return $flags;
}
/**
* Create a new ObjectFlags object that is neither active nor passive
*
* @return ObjectFlags
*/
public static function DISABLED() {
$flags = new ObjectFlags();
$flags->passive_checks = 0;
$flags->active_checks = 0;
return $flags;
}
/**
* Create a new ObjectFlags object that is in 'acknowledged' state
*
* @return ObjectFlags
*/
public static function ACKNOWLEDGED()
{
$flags = new ObjectFlags();
$flags->acknowledged = 1;
return $flags;
}
/**
* Create a new ObjectFlags object that is in a downtime
*
* @return ObjectFlags
*/
public static function IN_DOWNTIME()
{
$flags = new ObjectFlags();
$flags->in_downtime = 1;
return $flags;
}
}
/**
* Internal class that adds an object scope on Fixture operations
*
* This class allows to use $fixture->addHost('host',0)->addService() instead('svc')
* of $fixture->addHost('host',0); $fixture->addService('host', 'svc') as it encapsulates
* the scope of the last called object and automatically adds it as the first parameter
* of the next call.
*
*/
class TestFixtureObjectClosure
{
/**
* The object (hostname or hostname/servicename pair) this scope represents
* @var String|array
*/
private $scope;
/**
* The Testfixture to operate on
* @var TestFixture
*/
private $environment;
/**
* Create a new scope using the TestFixture with the given host / service
* as the scope
*
* @param TestFixture $environment The testfixture to use for subsequent calls
* @param $scope The scope to prepend to all further calls
*/
public function __construct(TestFixture $environment, $scope)
{
$this->scope = $scope;
$this->environment = $environment;
}
/**
* Magic method that forwards all function calls to the environment
* but prepends the scope.
*
* A call func($arg1) to this class would be rewritten to $environment->func($scope, $arg1)
*
* @param string $string The method that should be called with this scope
* @param array $arguments The arguments the user passed to the function
* @return mixed The result of the function call
*/
public function __call($string, $arguments)
{
$callArg = array($this->scope);
$args = array_merge($callArg, $arguments);
return call_user_func_array(array($this->environment, $string), $args);
}
}
/**
* Create test-states that can be persisted to different backends
* using DataSourceTestSetup.
*
* This class provides not all fields used in monitoring, but the most
* important ones (and the ones that are missing should be added during
* developmen).
*
* Usage:
* <code>
* $fixture = new TestFixture();
* // adding a new critical, but acknowledged host
* $fixture->addHost("hostname", 1, ObjectFlags::ACKNOWLEDGED())
*
* // add a comment to the host (this has to be done before adding services)
* ->addComment("author", "comment text")
*
* // assign to hostgroup
* ->addToHostgroup("myHosts")
*
* // and add three services to this host
* ->addService("svc1", 0) // Service is ok
* ->addService("svc2", 1, ObjectFlags::PASSIVE) // service is warning and passive
* ->addService("svc3", 2, null, array("notes_url" => "test.html")) // critical with notes url
* ->addComment("author", "what a nice service comment") // add a comment to the service
* ->addToServicegroup("alwaysdown"); // add svc3 to servicegroup
*
* // Create the datasource from this fixture, here form MySQL
* $ds = new DataSourceTestSetup("mysql");
* $ds->setup();
* // insert fixture
* $ds->insert($fixture);
* </code>
*
*/
class TestFixture
{
/**
* Internal dataholder for all defined hosts
* @var array
*/
private $hosts = array();
/**
* Internal holder for all defined services
* @var array
*/
private $services = array();
/**
* Internal holder for all defined contacts
* @var array
*/
private $contacts = array();
/**
* Internal holder for all defined comments
* @var array
*/
private $comments = array();
/**
* Internal holder for all defined servicegroups
* @var array
*/
private $servicegroups = array();
/**
* Internal holder for all defined hostgroups
* @var array
*/
private $hostgroups = array();
/**
* Return array with all defined hostobjects
*
* @return array Returns an array of host-arrays, which have the following fields
* - 'name' : The name of the host
* - 'state' : The state of the host (0,1,2)
* - 'address' : The string representation of the address (127.0.0.1 as default)
* - 'flags' : An ObjectFlags object containing additional state information
* - 'icon_image' : The icon image of this host (default: 'icon.png')
* - 'notes_url' : The notes url of this host (default empty string)
* - 'action_url' : The action url of this host (default empty string)
* - 'contacts' : An array of contact objects (having 'name' as the most important field)
* - 'customvariables' : An associative "cv_name"=>"cv_value" array containing the customvariables
*/
public function getHosts()
{
return $this->hosts;
}
/**
* Return array with all defined service objects
*
* @return array Returns an array of service-arrays, which have the following fields
* - 'name' : The name of the service
* - 'host' : A reference to the hostobject
* - 'state' : The state of the service (0,1,2,3)
* - 'flags' : An ObjectFlags object containing additional state information
* - 'icon_image' : The icon image of this service (default: 'icon.png')
* - 'notes_url' : The notes url of this service (default empty string)
* - 'action_url' : The action url of this service (default empty string)
* - 'contacts' : An array of contact objects (having 'name' as the most important field)
* - 'customvariables' : An associative "cv_name"=>"cv_value" array containing the customvariables
*/
public function getServices()
{
return $this->services;
}
/**
* Return array with all defined contacts
*
* @return array Returns an array of contact-arrays, which have the following fields
* - 'alias' : The name of the contact
*/
public function getContacts()
{
return $this->contacts;
}
/**
* Return array with all defined servicegroups
*
* @return array Returns an array of group-arrays in the following format:
* - 'name' : The name of the group
* - 'members' : An array of service objects that belong to this group
*/
public function getServicegroups()
{
return $this->servicegroups;
}
/**
* Return an array with all defined hostgroups
*
* @return array Returns an array of group-arrays in the following format:
* - 'name' : The name of the group
* - 'members' : An array of host objects that belong to this group
*/
public function getHostgroups()
{
return $this->hostgroups;
}
/**
* Return an array of service and hostcomments
*
* @return array Returns an array of comment arrays in the following format:
* - 'service' (if servicecomment) : A reference to the service object this comment belongs to
* - 'host' (if hostcomment) : A reference to the host object this comment belongs to
* - 'author' : The author of this comment
* - 'text' : The comment text
*/
public function getComments()
{
return $this->comments;
}
/**
* Add a new host to this TestFixture
*
* @param string $name The name of the host to add
* @param int $state The state of the host to add (0,1,2)
* @param ObjectFlags $flags (optional) An @see ObjectFlags object defining additional state inforamtion
* @param array $additional (optional) An array with additional object fields
*
* @return TestFixtureObjectClosure The TestFixture with the newly added host as the scope
*/
public function addHost($name, $state, ObjectFlags $flags = null, array $additional = array()) {
if ($flags === null) {
$flags = new ObjectFlags();
}
if (isset($this->hosts[$name])) {
throw new Exception('Tried to create hosts twice');
}
$this->hosts[$name] = array(
'name' => $name,
'state' => $state,
'address' => '127.0.0.1',
'flags' => $flags,
'icon_image' => 'icon.png',
'notes_url' => '',
'action_url' => '',
'contacts' => array(),
'customvariables' => array()
);
$this->hosts[$name] = array_merge($this->hosts[$name], $additional);
return new TestFixtureObjectClosure($this, $name);
}
/**
* Add a new service to this TestFixture
*
* @param string $host The name of the host this service belongs to (must exist prior to service creation)
* @param string $name The name of the service to add
* @param int $state The state of the service to add (0,1,2,3)
* @param ObjectFlags $flags (optional) An @see ObjectFlags object defining additional state information
* @param array $additional (optional) An array with additional object fields
*
* @return TestFixtureObjectClosure The TestFixture with the newly added service as the scope
*/
public function addService($host, $name, $state, ObjectFlags $flags = null, array $additional = array()) {
// when called in service scope only use the host
if (is_array($host)) {
$host = $host[0];
}
if ($flags === null) {
$flags = new ObjectFlags();
}
if (!isset($this->hosts[$host])) {
throw new Exception('Tried to create service for non existing host '.$host);
}
if (isset($this->services[$name])) {
throw new Exception('Tried to create service twice '.$name);
}
$this->services[$host.';'.$name] = array(
'host' => &$this->hosts[$host],
'name' => $name,
'state' => $state,
'contacts' => array(),
'icon_image' => 'icon.png',
'notes_url' => '',
'action_url' => '',
'customvariables' => array(),
'flags' => $flags
);
$this->services[$host.';'.$name] = array_merge($this->services[$host.';'.$name], $additional);
return new TestFixtureObjectClosure($this, array($host, $name));
}
/**
* Add a new comment to the host or service provided in $hostOrServiceHostPair
*
* @param string|array $hostOrServiceHostPair Either a string with the hostname or an array with the hostname
* as the first and the servicename as the second element
* @param $author The author for the coment
* @param $text The content of the comment
* @return TestFixtureObjectClosure The TestFixture with the comment owner as the scope
*/
public function addComment($hostOrServiceHostPair, $author, $text) {
if (is_array($hostOrServiceHostPair)) {
if (!isset($this->services[$hostOrServiceHostPair[0].';'.$hostOrServiceHostPair[1]])) {
throw new Exception('Tried to add a comment for a nonexisting service '.$hostOrServiceHostPair[1]);
}
$this->comments[] = array(
'service' => &$this->services[$hostOrServiceHostPair[0].';'.$hostOrServiceHostPair[1]],
'author' => $author,
'text' => $text
);
} else {
if (!isset($this->hosts[$hostOrServiceHostPair])) {
throw new Exception('Tried to add a comment for a nonexisting host '.$hostOrServiceHostPair);
}
$this->comments[] = array(
'host' => &$this->hosts[$hostOrServiceHostPair],
'author' => $author,
'text' => $text
);
}
return new TestFixtureObjectClosure($this, $hostOrServiceHostPair);
}
/**
* Assign a new contact to a host or service
*
* @param $hostOrServiceHostPair Either a string with the hostname or an array with the hostname
* as the first and the servicename as the second element
* @param $contactname The contactname to assign (will be created)
* @return TestFixtureObjectClosure The TestFixture with the host or service as the scope
*/
public function assignContact($hostOrServiceHostPair, $contactname) {
$this->contacts[$contactname] = array('alias' => $contactname);
if (is_array($hostOrServiceHostPair)) {
if (!isset($this->services[$hostOrServiceHostPair[0].';'.$hostOrServiceHostPair[1]])) {
throw new Exception('Tried to add a comment for a nonexisting service '.$hostOrServiceHostPair[1]);
}
$service = $this->services[$hostOrServiceHostPair[0].';'.$hostOrServiceHostPair[1]];
$service['contacts'][] = &$this->contacts[$contactname];
} else {
if (!isset($this->hosts[$hostOrServiceHostPair])) {
throw new Exception('Tried to add a comment for a nonexisting host '.$hostOrServiceHostPair);
}
$host = $this->hosts[$hostOrServiceHostPair];
$host['contacts'][] = &$this->contacts[$contactname];
}
return new TestFixtureObjectClosure($this, $hostOrServiceHostPair);
}
/**
* Add a host to a hostgroup
*
* Create the new hostgroup if it not exists yet, otherwise just add the
* host to it
*
* @param string $host The name of the host to add to the hostgroup
* @param string $groupname The name of the hostgroup
* @return TestFixtureObjectClosure The TestFixture with the host as the scope
*/
public function addToHostgroup($host, $groupname) {
// check if in service scope
if (is_array($host)) {
$host = $host[0];
}
if (!isset($this->hosts[$host])) {
throw new Exception('Tried to add non-existing host '.$host.' to hostgroup ');
}
if (!isset($this->hostgroups[$groupname])) {
$this->hostgroups[$groupname] = array("name" => $groupname, "members" => array());
}
$this->hostgroups[$groupname]["members"][] = &$this->hosts[$host];
return new TestFixtureObjectClosure($this, $host);
}
/**
* Add service to a servicegroup
*
* Create the new service if it not exists yet, otherwise just add the service
*
* @param array $serviceHostPair An array containing the hostname as the first and the
* servicename as the second element
* @param string $groupname The name of the servicegroup
* @return TestFixtureObjectClosure The TestFixture with the service as the scope
*/
public function addToServicegroup(array $serviceHostPair, $groupname) {
if (!isset($this->services[$serviceHostPair[0].";".$serviceHostPair[1]])) {
throw new Exception('Tried to add non-existing service '.$serviceHostPair[1].' to servicegroup ');
}
$service = &$this->services[$serviceHostPair[0].";".$serviceHostPair[1]];
if (!isset($this->servicegroups[$groupname])) {
$this->servicegroups[$groupname] = array("name" => $groupname, "members" => array());
}
$this->servicegroups[$groupname]["members"][] = &$service;
return new TestFixtureObjectClosure($this, $serviceHostPair);
}
}

View File

@ -0,0 +1,100 @@
<?php
namespace Test\Monitoring\Testlib\DataSource\schemes;
/**
* Container class for Objectcache object snipptes
*
*/
class ObjectsCacheTemplates {
public static $HOST =<<<'EOF'
define host {
host_name\t{{HOST_NAME}}
alias\t{{HOST_NAME}} alias
address\t{{HOST_ADDRESS}}
check_period\t24x7
check_command\ttest-check-host-alive-parent!flap!$HOSTSTATE:router_00$
contact_groups\ttest_contact
notification_period\t24x7
initial_state\to
check_interval\t10.000000
retry_interval\t1.000000
max_check_attempts\t5
active_checks_enabled\t1
passive_checks_enabled\t1
obsess_over_host\t1
event_handler_enabled\t1
low_flap_threshold\t0.000000
high_flap_threshold\t0.000000
flap_detection_enabled\t1
flap_detection_options\to,d,u
freshness_threshold\t0
check_freshness\t0
notification_options\td,u,r
notifications_enabled\t1
notification_interval\t0.000000
first_notification_delay\t0.000000
stalking_options\tn
process_perf_data\t1
failure_prediction_enabled\t1
icon_image\t{{ICON_IMAGE}}
icon_image_alt\ticon alt string
notes\tjust a notes string
notes_url\t{{NOTES_URL}}
action_url\t{{ACTION_URL}}
retain_status_information\t1
retain_nonstatus_information\t1
}
EOF;
public static $SERVICE =<<<'EOF'
define service {
host_name\t{{HOST_NAME}}
service_description\t{{SERVICE_NAME}}
check_period\t24x7
check_command\tcheck_service!critical
contact_groups\ttest_contact
notification_period\t24x7
initial_state\to
check_interval\t5.000000
retry_interval\t2.000000
max_check_attempts\t3
is_volatile\t0
parallelize_check\t1
active_checks_enabled\t1
passive_checks_enabled\t1
obsess_over_service\t1
event_handler_enabled\t1
low_flap_threshold\t0.000000
high_flap_threshold\t0.000000
flap_detection_enabled\t1
flap_detection_options\to,w,u,c
freshness_threshold\t0
check_freshness\t0
notification_options\tu,w,c,r
notifications_enabled\t1
notification_interval\t0.000000
first_notification_delay\t0.000000
stalking_options\tn
process_perf_data\t1
failure_prediction_enabled\t1
icon_image\t{{ICON_IMAGE}}
icon_image_alt\ticon alt string
notes\tjust a notes string
notes_url\t{{NOTES_URL}}
action_url\t{{ACTION_URL}}
retain_status_information\t1
retain_nonstatus_information\t1
}
EOF;
public static $GROUP =<<<'EOF'
define {{TYPE}}group {
{{TYPE}}group_name\t{{NAME}}
alias\t{{NAME}}
members\t{{MEMBERS}}
}
EOF;
};

View File

@ -0,0 +1,174 @@
<?php
/**
* Created by JetBrains PhpStorm.
* User: moja
* Date: 7/17/13
* Time: 10:25 AM
* To change this template use File | Settings | File Templates.
*/
namespace Test\Monitoring\Testlib\DataSource\schemes;
/**
* Container class for Statusdat object snippets
*
*/
class StatusdatTemplates {
public static $HOST =<<<'EOF'
hoststatus {
host_name={{HOST_NAME}}
modified_attributes=0
check_command=test-check-host-alive-parent!pending!$HOSTSTATE:router_01$
check_period=24x7
notification_period=24x7
check_interval=10.000000
retry_interval=1.000000
event_handler=
has_been_checked=0
should_be_scheduled=0
check_execution_time=0.000
check_latency=0.000
check_type=0
current_state={{HOST_STATUS}}
last_hard_state=0
last_event_id=14750
current_event_id=14756
current_problem_id=6016
last_problem_id=6010
plugin_output=Plugin output for host {{HOST_NAME}}
long_plugin_output=Long plugin output for host {{HOST_NAME}}
performance_data=
last_check={{TIME}}
next_check=1374002661
check_options=0
current_attempt=2
max_attempts=5
state_type=0
last_state_change={{TIME}}
last_hard_state_change={{TIME}}
last_time_up=1373984768
last_time_down=1373984818
last_time_unreachable=1373984748
last_notification=0
next_notification=0
no_more_notifications=1
current_notification_number=0
current_down_notification_number=0
current_unreachable_notification_number=0
current_notification_id=0
notifications_enabled={{NOTIFICATIONS_ENABLED}}
problem_has_been_acknowledged={{ACKNOWLEDGED}}
acknowledgement_type=0
acknowledgement_end_time=0
active_checks_enabled={{ACTIVE_ENABLED}}
passive_checks_enabled={{PASSIVE_ENABLED}}
event_handler_enabled=1
flap_detection_enabled=1
failure_prediction_enabled=1
process_performance_data=1
obsess_over_host=1
last_update=1374002209
is_flapping={{FLAPPING}}
percent_state_change=0.00
scheduled_downtime_depth={{IN_DOWNTIME}}
{{CVS}}
}
EOF;
public static $SERIVCE =<<<'EOF'
servicestatus {
host_name={{HOST_NAME}}
service_description={{SERVICE_NAME}}
modified_attributes=0
check_command=check_service!critical
check_period=24x7
notification_period=24x7
check_interval=5.000000
retry_interval=2.000000
event_handler=
has_been_checked=1
should_be_scheduled=1
check_execution_time=0.250
check_latency=0.113
check_type=0
current_state={{SERVICE_STATUS}}
last_hard_state=2
last_event_id=0
current_event_id=6179
current_problem_id=2434
last_problem_id=0
current_attempt=3
max_attempts=3
state_type=1
last_state_change={{TIME}}
last_hard_state_change={{TIME}}
last_time_ok=0
last_time_warning=0
last_time_unknown=0
last_time_critical=1373024663
plugin_output=Plugin output for service {{SERVICE_NAME}}
long_plugin_output=Long plugin output for service {{SERVICE_NAME}}
performance_data=runtime=0.012226
last_check=1373087666
next_check=1374002401
check_options=0
current_notification_number=0
current_warning_notification_number=0
current_critical_notification_number=0
current_unknown_notification_number=0
current_notification_id=0
last_notification=0
next_notification=0
no_more_notifications=1
notifications_enabled={{NOTIFICATIONS_ENABLED}}
active_checks_enabled={{ACTIVE_ENABLED}}
passive_checks_enabled={{PASSIVE_ENABLED}}
event_handler_enabled=1
problem_has_been_acknowledged={{ACKNOWLEDGED}}
acknowledgement_type=1
acknowledgement_end_time=0
flap_detection_enabled=1
failure_prediction_enabled=1
process_performance_data=1
obsess_over_service=1
last_update=1374002209
is_flapping={{FLAPPING}}
percent_state_change=6.25
scheduled_downtime_depth={{IN_DOWNTIME}}
{{CVS}}
}
EOF;
public static $SERVICECOMMENT =<<<'EOF'
servicecomment {
host_name={{HOST_NAME}}
service_description={{SERVICE_NAME}}
entry_type=3
comment_id={{ID}}
source=0
persistent=0
entry_time={{TIME}}
expires=0
expire_time=0
author={{AUTHOR}}
comment_data={{TEXT}
}
EOF;
public static $HOSTCOMMENT =<<<'EOF'
hostcomment {
host_name={{HOST_NAME}}
entry_type=3
comment_id={{ID}}
source=0
persistent=0
entry_time={{TIME}}
expires=0
expire_time=0
author={{AUTHOR}}
comment_data={{TEXT}}
}
EOF;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,33 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Test\Monitoring\Testlib\Datasource\Strategies;
use \Test\Monitoring\Testlib\DataSource\TestFixture;
/**
* Generic interface for Fixture insertion implementations
*
* These implementations can create Icinga-compatible Datatsources
* from TestFixture classes and are therefore rather free in their
* implementation
*
*/
interface InsertionStrategy {
/**
* Tell the class to use the given ressource as the
* connection identifier
*
* @param $connection A generic connection identifier,
* the concrete class depends on the implementation
*/
public function setConnection($connection);
/**
* Insert the passed fixture into the datasource and allow
* the icinga backends to query it.
*
* @param TestFixture $fixture
*/
public function insert(TestFixture $fixture);
}

View File

@ -0,0 +1,82 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Test\Monitoring\Testlib\Datasource\Strategies;
/**
* SetupStrategy implementation for MySQL based IDO-Backends
*
* This strategy creates a new MySQL Database and removes old ones
* if necessary. Per default the database user is icinga_unittest:icinga_unittest
* and the database to be created is also icinga_unittest. The user must
* have all Privileges on the test database, so its best to create him
* with:
*
* mysql -u root
* # CREATE USER `icinga_unittest`@`localhost` IDENTIFIED BY 'icinga_unittest';
* # CREATE DATABASE icinga_unittest;
* # GRANT ALL PRIVILEGES ON icinga_unittest.* TO `icinga_unittest`@`localhost`
*
**/
class MySQLSetupStrategy implements SetupStrategy {
/**
* Tears down any existing databases and creates a new blank IDO scheme.
*
* The database is created according to the passed version (or using the newest version if no version is provided),
* using the idoMySQL-%VERSION%.sql underneath the schemes folder.
* A \PDO Connection can be provided, if not the icinga_unittest default
* connection will be established and used.
*
* @param String $version An optional version to use as the db scheme
* @param \PDO $connection An optional connection to use instead of icinga_unittest
* @return \PDO The connection that has been created
*
* @throws \PDOException In case connecting to or creating the database fails
* @throws \Exception In case of an invalid/non-existing DB scheme
*/
public function setup($version = null, $connection = null)
{
if ($connection === null) {
$connection = new \PDO("mysql:dbname=icinga_unittest", "icinga_unittest", "icinga_unittest");
}
$connection->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
$this->teardown($connection);
// the latest schema doesn't have a suffix, so if no version is given this one is used
$sqlFileName = 'idoMySQL'.($version !== null ? '-'.$version : '' ).'.sql';
$path = realpath(dirname(__FILE__).'/../schemes/'.$sqlFileName);
if (!file_exists($path)) {
throw new \Exception('File '.$path.' not found: Could not create scheme for IDO mysql backend '.($version ? '(version : '.$version.')' :''));
}
$connection->setAttribute(\PDO::ATTR_EMULATE_PREPARES, true);
if ($connection->query(file_get_contents($path)) === false) {
$error = $connection->errorInfo();;
throw new \PDOException($error[0].' : '.$error[2]);
}
return $connection;
}
/**
* Drops all tables from the connection via DROP TABLE
*
* @param \PDO $connection An optional connection to use, if none is
* given the icinga_unittest default will be used
*
*/
public function teardown($connection = null)
{
if ($connection === null) {
$connection = new \PDO("mysql:dbname=icinga_unittest", "icinga_unittest", "icinga_unittest");
}
$tables = $connection->query("SHOW TABLES")->fetchAll();
foreach($tables as $table) {
$connection->query("DROP TABLE ".$table[0]);
}
}
}

View File

@ -0,0 +1,303 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Test\Monitoring\Testlib\Datasource\Strategies;
use \Test\Monitoring\Testlib\DataSource\TestFixture;
/**
* TestFixture insertion implementation for PDO based backends
*
* This class allows to create the actual IDO databases from TestFixture
* classes using PDO.
*
*/
class PDOInsertionStrategy
{
/**
* Points to the (icinga) objectId of the next inserted object
* @var int
*/
private $objectId = 0;
/**
* The fixture that is being inserted by this object
* @var TestFixture
*/
private $fixture;
/**
* The database (PDO) connection to use for inserting
* @var \PDO
*/
private $connection;
/**
* The date format that will be used for inserting
* date values, see @link http://php.net/manual/en/function.date.php
* for possible values
*
* @var string
*/
public $datetimeFormat = "U";
/**
* @see InsertionStrategy::setConnection
*
* @param \PDO $connection The PDO connection to use
*/
public function setConnection($connection) {
$this->connection = $connection;
}
/**
* Insert the provided @see TestFixture into this database
*
* @param TestFixture $fixture The fixture to insert into the database
*/
public function insert(TestFixture $fixture)
{
$this->fixture = $fixture;
$this->insertContacts();
$this->insertHosts();
$this->insertServices();
$this->insertComments();
$this->insertHostgroups();
$this->insertServicegroups();
}
/**
* Insert all hosts from the current fixture into the IDO Database
*
* This method updates the icinga_objects, icinga_hosts, icinga_hoststatus
* and icinga_customvariablestatus tables with the host values provided
* by the internal fixture (@see PDOInsertStrategy::insert)
*
*/
private function insertHosts()
{
$hosts = &$this->fixture->getHosts();
$insertObjectQuery = $this->connection->prepare(
'INSERT INTO icinga_objects (object_id, objecttype_id, name1, is_active) VALUES (?, 1, ?, 1);'
);
$insertHostQuery = $this->connection->prepare(
'INSERT INTO icinga_hosts ('.
'host_id, alias, display_name, address, host_object_id, '.
'icon_image, notes_url, action_url'.
') VALUES (?, ?, ?, ?, ?, ?, ?, ?);'
);
$insertContactQuery = $this->connection->prepare(
'INSERT INTO icinga_host_contacts (host_id, contact_object_id) VALUES (?, ?);'
);
$insertHostStatusQuery = $this->connection->prepare(
'INSERT INTO icinga_hoststatus'.
'(host_object_id, current_state, last_check, last_state_change, notifications_enabled, '.
'active_checks_enabled, passive_checks_enabled, is_flapping, scheduled_downtime_depth,'.
'output, long_output, '.
'problem_has_been_acknowledged, has_been_checked) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'
);
$insertCVQuery = $this->connection->prepare(
'INSERT INTO icinga_customvariablestatus'.
'(object_id, varname, varvalue) VALUES (?, ?, ?)'
);
foreach($hosts as &$host) {
$flags = $host["flags"];
$insertObjectQuery->execute(array($this->objectId, $host["name"]));
$insertHostQuery->execute(array(
$this->objectId, $host["name"]." alias", $host["name"], $host["address"], $this->objectId,
$host["icon_image"], $host["notes_url"], $host["action_url"]
));
$insertHostStatusQuery->execute(array(
$this->objectId, $host["state"], date($this->datetimeFormat, $flags->time),
date($this->datetimeFormat, $flags->time), $flags->notifications, $flags->active_checks,
$flags->passive_checks, $flags->flapping, $flags->in_downtime, "Plugin output for host ".$host["name"],
"Long plugin output for host ".$host["name"], $flags->acknowledged, $flags->is_pending == 0
));
foreach($host["contacts"] as $contact) {
$insertContactQuery->execute(array($this->objectId, $contact["object_id"]));
}
foreach($host["customvariables"] as $cvName=>$cvValue) {
$insertCVQuery->execute(array($this->objectId, $cvName, $cvValue));
}
$host["object_id"] = $this->objectId;
$this->objectId++;
}
}
/**
* Insert all services from the provided fixture into the IDO database
*
* This method updates the icinga_objects, icinga_services, icinga_servicestatus,
* icinga_service_contacts, icinga_customvariablestatus
*/
private function insertServices()
{
$services = $this->fixture->getServices();
$insertObjectQuery = $this->connection->prepare(
'INSERT INTO icinga_objects (object_id, objecttype_id, name1, name2, is_active) VALUES (?, 2, ?, ?, 1);'
);
$insertServiceQuery = $this->connection->prepare(
'INSERT INTO icinga_services ('.
'service_id, host_object_id, service_object_id, display_name, '.
'icon_image, notes_url, action_url'.
') VALUES (?, ?, ?, ?, ?, ?, ?)'
);
$insertServiceStatusQuery = $this->connection->prepare(
'INSERT INTO icinga_servicestatus'.
'(service_object_id, current_state, last_check, last_state_change, notifications_enabled, '.
'active_checks_enabled, passive_checks_enabled, is_flapping, scheduled_downtime_depth,'.
'output, long_output, '.
'problem_has_been_acknowledged, has_been_checked) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) '
);
$insertContactQuery = $this->connection->prepare(
'INSERT INTO icinga_service_contacts (host_id, contact_object_id) VALUES (?, ?);'
);
$insertCVQuery = $this->connection->prepare(
'INSERT INTO icinga_customvariablestatus '.
'(object_id, varname, varvalue) VALUES (?, ?, ?)'
);
foreach($services as &$service) {
$flags = $service["flags"];
$insertObjectQuery->execute(array($this->objectId, $service["host"]["name"], $service["name"]));
$insertServiceQuery->execute(array(
$this->objectId, $service['host']['object_id'], $this->objectId, $service['name'],
$service["icon_image"], $service["notes_url"], $service["action_url"]
));
$insertServiceStatusQuery->execute(array(
$this->objectId, $service["state"], date($this->datetimeFormat, $flags->time),
date($this->datetimeFormat, $flags->time), $flags->notifications, $flags->active_checks,
$flags->passive_checks, $flags->flapping, $flags->in_downtime, "Plugin output for service ".$service["name"],
"Long plugin output for service ".$service["name"], $flags->acknowledged,
$flags->is_pending == 0 ? '1' : '0'
));
foreach($service["contacts"] as $contact) {
$insertContactQuery->execute(array($this->objectId, $contact["object_id"]));
}
foreach($service["customvariables"] as $cvName=>$cvValue) {
$insertCVQuery->execute(array($this->objectId, $cvName, $cvValue));
}
$service["object_id"] = $this->objectId;
$this->objectId++;
}
}
/**
* Insert the contacts provided by the fixture into the database
*
* This method updates the icinga_objects and icinga_contacts tables
* according to the provided fixture
*/
private function insertContacts()
{
$insertObjectQuery = $this->connection->prepare(
'INSERT INTO icinga_objects (object_id, objecttype_id, name1) VALUES (?, 10, ?);'
);
$insertContactQuery = $this->connection->prepare(
'INSERT INTO icinga_contacts (contact_object_id, alias) VALUES (?, ?);'
);
$contacts = &$this->fixture->getContacts();
foreach($contacts as &$contact) {
$insertObjectQuery->execute($this->objectId, $contact["alias"]);
$insertContactQuery->execute($this->objectId, $contact["alias"]);
$contact["object_id"] = $this->objectId;
$this->objectId++;
}
}
/**
* Insert comments provided by the fixture into the IDO database
*
* This method updates the icinga_comments table according to the provided
* fixture
*/
private function insertComments()
{ $comment_id=0;
$insertCommentsQuery = $this->connection->prepare(
'INSERT INTO icinga_comments (object_id, comment_type, internal_comment_id, author_name, comment_data)'.
' VALUES (?, ?, ?, ?, ?);'
);
$comments = &$this->fixture->getComments();
foreach ($comments as $comment) {
if (isset($comment["host"])) {
$type = 1;
$object_id = $comment["host"]["object_id"];
} elseif (isset($comment["service"])) {
$type = 2;
$object_id = $comment["service"]["object_id"];
}
$insertCommentsQuery->execute(array(
$object_id, $type, $comment_id++, $comment["author"], $comment["text"]
));
}
}
/**
* Insert hostgroups from the provided fixture into the IDO database
*
* This method updates the icinga_objects, icinga_hostgroups and icinga_hostgroup_members
* table with the values provide by the fixture
*/
private function insertHostgroups()
{
$insertObjectQuery = $this->connection->prepare(
'INSERT INTO icinga_objects (object_id, objecttype_id, name1) VALUES (?, 3, ?)'
);
$insertHostgroupQuery = $this->connection->prepare(
'INSERT INTO icinga_hostgroups (hostgroup_id, hostgroup_object_id, alias) VALUES (?, ?, ?)'
);
$insertHostgroupMemberQuery = $this->connection->prepare(
'INSERT INTO icinga_hostgroup_members (hostgroup_id, host_object_id) VALUES (?, ?)'
);
$hostgroups = &$this->fixture->getHostgroups();
foreach ($hostgroups as &$hostgroup) {
$insertObjectQuery->execute(array($this->objectId, $hostgroup["name"]));
$insertHostgroupQuery->execute(array($this->objectId, $this->objectId, $hostgroup["name"]));
foreach ($hostgroup["members"] as $member) {
$insertHostgroupMemberQuery->execute(array($this->objectId, $member["object_id"]));
}
$this->objectId++;
}
}
/**
* Insert servicegroups from the provided fixture into the IDO database
*
* This method updates the icinga_objects, icinga_servicegroups and icinga_servicegroup_members
* table with the values provide by the fixture
*/
private function insertServicegroups()
{
$insertObjectQuery = $this->connection->prepare(
'INSERT INTO icinga_objects (object_id, objecttype_id, name1) VALUES (?, 4, ?)'
);
$insertServicegroupQuery = $this->connection->prepare(
'INSERT INTO icinga_servicegroups (servicegroup_id, servicegroup_object_id, alias) VALUES (?, ?, ?)'
);
$insertServicegroupMemberQuery = $this->connection->prepare(
'INSERT INTO icinga_servicegroup_members (servicegroup_id, service_object_id) VALUES (?, ?)'
);
$servicegroups = &$this->fixture->getServicegroups();
foreach ($servicegroups as &$servicegroup) {
$insertObjectQuery->execute(array($this->objectId, $servicegroup["name"]));
$insertServicegroupQuery->execute(array($this->objectId, $this->objectId, $servicegroup["name"]));
foreach ($servicegroup["members"] as $member) {
$insertServicegroupMemberQuery->execute(array($this->objectId, $member["object_id"]));
}
$this->objectId++;
}
}
}

View File

@ -0,0 +1,77 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Test\Monitoring\Testlib\Datasource\Strategies;
/***
* SetupStrategy implementation for PostgreSQL based IDO-Backends
*
* This strategy creates a new PostgreSQL Database and removes old ones
* if necessary. Per default the database user is icinga_unittest:icinga_unittest
* and the database to be created is also icinga_unittest.
**/
class PgSQLSetupStrategy implements SetupStrategy {
/**
* Tears down any existing databases and creates a new blank IDO scheme.
*
* The database is created according to the passed version (or using the
* newest version if no version is provided), using the idoPgSQL-%VERSION%.sql
* underneath the schemes folder.
* A \PDO Connection can be provided, if not the icinga_unittest default
* connection will be established and used.
*
* @param String $version An optional version to use as the db scheme
* @param \PDO $connection An optional connection to use instead of icinga_unittest
* @return \PDO The connection that has been created
*
* @throws \PDOException In case connecting to or creating the database fails
* @throws \Exception In case of an invalid/non-existing DB scheme
*/
public function setup($version = null, $connection = null)
{
if ($connection === null) {
$connection = new \PDO('pgsql:dbname=icinga_unittest', 'icinga_unittest', 'icinga_unittest');
}
$connection->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
$this->teardown($connection);
// the latest schema doesn't have a suffix, so if no version is given this one is used
$sqlFileName = 'idoPgSQL'.($version !== null ? '-'.$version : '' ).'.sql';
$path = realpath(dirname(__FILE__).'/../schemes/'.$sqlFileName);
if (!file_exists($path)) {
throw new \Exception('File '.$path.' not found: Could not create scheme for IDO pgsql backend '.($version ? '(version : '.$version.')' :''));
}
$connection->setAttribute(\PDO::ATTR_EMULATE_PREPARES, true);
if ($connection->query(file_get_contents($path)) === false) {
$error = $connection->errorInfo();;
throw new \PDOException($error[0].' : '.$error[2]);
}
return $connection;
}
/**
* Drops all tables from the connection via DROP TABLE
*
* @param \PDO $connection An optional connection to use, if none is
* given the icinga_unittest default will be used
*
*/
public function teardown($connection = null)
{
if ($connection === null) {
$connection = new \PDO('pgsql:dbname=icinga_unittest', 'icinga_unittest', 'icinga_unittest');
}
$tables = $connection
->query('SELECT table_schema,table_name FROM information_schema.tables WHERE table_type = \'BASE TABLE\''.
'AND table_schema = \'public\' ORDER BY table_schema,table_name;')
->fetchAll();
foreach($tables as $table) {
$connection->query('DROP TABLE '.$table['table_name']);
}
}
}

View File

@ -0,0 +1,35 @@
<?php
namespace Test\Monitoring\Testlib\Datasource\Strategies;
/**
* Interface for setup classes that provide a clean starting point
* for @see InsertionStrategy classes to setup TestFixtures.
*
* As the backend for the setupstrategy can be anything from a database to
* a file to a socket, the resource is a mixed php type and the
* concrete requirement on the type is defined by the subclass implementing
* this interface.
*
*/
interface SetupStrategy {
/**
* Set up a new clean datastore icinga backends can use for querying data
*
* The resource parameter should be optional, as the setup class should provide
* a default setup method most testing setups can use
*
* @param String $version The optional version of the storage implementation to create
* @param mixed $resource The optional resource to use for setting up the storage
*
* @return mixed The connection or resource that has been created
*/
public function setup($version = null, $resource = null);
/**
* Remove all data from the given resource (or the default resource if none is given)
*
* @param mixed $resource
*/
public function teardown($resource = null);
}

View File

@ -0,0 +1,298 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Test\Monitoring\Testlib\Datasource\Strategies;
use Test\Monitoring\Testlib\DataSource\schemes\ObjectsCacheTemplates;
use \Test\Monitoring\Testlib\DataSource\TestFixture;
use \Test\Monitoring\Testlib\DataSource\schemes\StatusdatTemplates;
require_once(dirname(__FILE__).'/../schemes/ObjectsCacheTemplates.php');
require_once(dirname(__FILE__).'/../schemes/StatusdatTemplates.php');
/**
* An @see InsertionStrategy for creating status.dat and objects.cache
* files from a TestFixture
*
* This class helps testing status.dat backends by writing testfixtures
* to according objects.cache and status.dat files which then can be read
* by the Statusdat parser and used in tests.
*
* The templates for insertion can be found under schemes/objectsCacheTemplates.php
* and schemes/StatusdatTempaltes.php
*
*/
class StatusdatInsertionStrategy implements InsertionStrategy {
/**
* The status.dat filename to write the object-state to
* @var String
*/
private $statusDatFile;
/**
* The objects.cache filename to write the object structure to
* @var String
*/
private $objectsCacheFile;
/**
* The TestFixture that will be written to a status.dat compatible format
* @var TestFixture
*/
private $fixture;
/**
* The content of the status.dat file that will be written
* @var String
*/
private $statusDat;
/**
* The content of the objects.cache file that will be written
* @var String
*/
private $objectsCache;
/**
* Tell this object to use the status.dat/objects.cache file combination
* provided in $resource
*
* @param Array $ressource An associative array containing the following keys:
* - "status_file" : The location where to write the status.dat to
* - "objects_file" : The location to write the objects cache to
*/
public function setConnection($ressource)
{
$this->statusDatFile = $ressource['status_file'];
$this->objectsCacheFile = $ressource['objects_file'];
}
/**
* Insert the provided fixture into the status.dat and objects.cache files for testing
*
* @param TestFixture $fixture The fixture to create status.dat and objects.cache files from
*/
public function insert(TestFixture $fixture)
{
$this->fixture = $fixture;
$this->statusDat = '# Automatically created test statusdat from fixture\n';
$this->objectsCache = '';
$this->insertHoststatus();
$this->insertHosts();
$this->insertServicestatus();
$this->insertServices();
$this->insertHostgroups();
$this->insertServicegroups();
$this->insertComments();
file_put_contents($this->statusDatFile, $this->statusDat);
file_put_contents($this->objectsCacheFile, $this->objectsCache);
}
/**
* Insert the host monitoring state from the provided fixture to the internal
* statusdat string $statusDat
*
*/
private function insertHoststatus()
{
$hosts = $this->fixture->getHosts();
foreach ($hosts as $host) {
$cvs = '';
foreach ($host['customvariables'] as $name=>$var) {
$cvs .= '_'.$name.'='.$var."\n";
}
$flags = $host['flags'];
$hostStatus = str_replace(
array(
'{{HOST_NAME}}', '{{TIME}}', '{{NOTIFICATIONS_ENABLED}}',
'{{ACKNOWLEDGED}}', '{{ACTIVE_ENABLED}}', '{{PASSIVE_ENABLED}}',
'{{FLAPPING}}', '{{IN_DOWNTIME}}', '{{HOST_STATUS}}','{{CVS}}')
, array(
$host['name'], $flags->time, $flags->notifications, $flags->acknowledged,
$flags->active_checks, $flags->passive_checks, $flags->flapping,
$flags->in_downtime, $host['state'], $cvs
), StatusdatTemplates::$HOST);
$this->statusDat .= "\n".$hostStatus;
}
}
/**
* Insert the host object state into the internal objects.cache representation
* $objectsCache
*
*/
private function insertHosts()
{
$hosts = $this->fixture->getHosts();
foreach ($hosts as $host) {
if ($host['flags']->is_pending) {
continue; // Pending states are not written to status.dat yet
}
$hostDefinition = str_replace(
array('\t',
'{{HOST_NAME}}', '{{HOST_ADDRESS}}', '{{ICON_IMAGE}}',
'{{NOTES_URL}}', '{{ACTION_URL}}'
),
array("\t",
$host['name'], $host['address'], $host['icon_image'],
$host['notes_url'], $host['action_url']
),
ObjectsCacheTemplates::$HOST
);
$this->objectsCache .= "\n".$hostDefinition;
}
}
/**
* Insert the service monitoring state from the provided fixture to the internal
* statusdat string $statusDat
*
*/
private function insertServicestatus()
{
$services = $this->fixture->getServices();
foreach ($services as $service) {
if ($service['flags']->is_pending) {
continue; // Pending states are not written to status.dat yet
}
$cvs = '';
foreach ($service['customvariables'] as $name=>$var) {
$cvs .= '_'.$name.'='.$var;
}
$flags = $service['flags'];
$serviceStatus = str_replace(
array(
'{{HOST_NAME}}','{{SERVICE_NAME}}', '{{TIME}}', '{{NOTIFICATIONS_ENABLED}}',
'{{ACKNOWLEDGED}}', '{{ACTIVE_ENABLED}}', '{{PASSIVE_ENABLED}}',
'{{FLAPPING}}', '{{IN_DOWNTIME}}', '{{SERVICE_STATUS}}','{{CVS}}')
, array(
$service['host']['name'], $service['name'], $flags->time, $flags->notifications,
$flags->acknowledged, $flags->active_checks, $flags->passive_checks,
$flags->flapping, $flags->in_downtime, $service['state'], $cvs
), StatusdatTemplates::$SERIVCE);
$this->statusDat .= "\n".$serviceStatus;
}
}
/**
* Insert the service object state into the internal objects.cache representation
* $objectsCache
*
*/
private function insertServices()
{
$services = $this->fixture->getServices();
foreach ($services as $service) {
$serviceDefinition = str_replace(
array('\t',
'{{HOST_NAME}}', '{{SERVICE_NAME}}', '{{ICON_IMAGE}}',
'{{NOTES_URL}}', '{{ACTION_URL}}'
),
array("\t",
$service['host']['name'], $service['name'], $service['icon_image'],
$service['notes_url'], $service['action_url']
),
ObjectsCacheTemplates::$SERVICE
);
$this->objectsCache .= "\n".$serviceDefinition;
}
}
/**
* Inserts a group object into the object.cache file
*
* @param String $type The type of the group ('host' or 'service')
* @param String $name The name of the group to insert
* @param array $members A String array of the members names to use
*/
private function insertGroup($type, $name, array $members)
{
$groupDefinition = str_replace(
array('\t',
'{{TYPE}}', '{{NAME}}', '{{MEMBERS}}'
),
array("\t",
$type, $name, implode(",", $members)
),
ObjectsCacheTemplates::$GROUP
);
$this->objectsCache .= "\n".$groupDefinition;
}
/**
* Insert all hostgroups from the fixtures into the objects.cache
*
*/
private function insertHostgroups()
{
$hostgroups = $this->fixture->getHostgroups();
foreach ($hostgroups as $hostgroup) {
$memberNames = array();
foreach ($hostgroup["members"] as $member) {
$memberNames[] = $member["name"];
}
$this->insertGroup("host", $hostgroup["name"], $memberNames);
}
}
/**
* Inserts all servicegroups from the fixtures into the objects.cache
*
*/
private function insertServicegroups()
{
$servicegroups = $this->fixture->getServicegroups();
foreach ($servicegroups as $servicegroup) {
$memberNames = array();
foreach ($servicegroup["members"] as $member) {
$memberNames[] = $member["host"]["name"];
$memberNames[] = $member["name"];
}
$this->insertGroup("service", $servicegroup["name"], $memberNames);
}
}
/**
* Inserts all comments from the fixtures into the status.dat string
* $statusDat
*
*/
private function insertComments()
{
$comments = $this->fixture->getComments();
$commentId = 1;
foreach($comments as $comment) {
if (isset($comment["service"])) {
$service = $comment["service"];
$commentDefinition = str_replace(
array('{{HOST_NAME}}', '{{SERVICE_NAME}}', '{{TIME}}', '{{AUTHOR}}', '{{TEXT}}', '{{ID}}'),
array(
$service["host"]["name"], $service["name"], $service["flags"]->time,
$comment["author"], $comment["text"], $commentId++
),
StatusdatTemplates::$SERVICECOMMENT
);
} elseif (isset($comment["host"])) {
$host = $comment["host"];
$commentDefinition = str_replace(
array('{{HOST_NAME}}', '{{TIME}}', '{{AUTHOR}}', '{{TEXT}}', '{{ID}}'),
array(
$host["name"], $host["flags"]->time,
$comment["author"], $comment["text"], $commentId++
),
StatusdatTemplates::$HOSTCOMMENT
);
}
$this->statusDat .= "\n".$commentDefinition;
}
}
}

View File

@ -0,0 +1,102 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Test\Monitoring\Testlib\Datasource\Strategies;
use Tests\Icinga\Protocol\Statusdat\StatusdatTestLoader;
/**
* SetupStrategy for status dat.
*
* This class is used for setting up a test enviromnent for querying
* statusdat fixtures.
*
*/
class StatusdatSetupStrategy implements SetupStrategy {
/**
* Recursively require all php files underneath $folder
*
* @param String $folder The folder to require
*/
private function requireFolder($folder)
{
$files = scandir($folder);
foreach($files as $file) {
if ($file[0] == ".") {
continue;
}
if (is_dir($folder."/".$file)) {
$this->requireFolder($folder."/".$file);
} elseif (preg_match("/\.php/", $file)) {
require_once(realpath($folder."/".$file));
}
}
}
/**
* Require all classes needed to work with the status.dat Reader
*
* This includes the Status.dat Reader and Parser classes
* from Icinga/PRotocol as well as a few dependencies (Logging, Zend_Cache)
*
*/
private function requireStatusDat()
{
require_once 'library/Icinga/Protocol/Statusdat/StatusdatTestLoader.php';
StatusdatTestLoader::requireLibrary();
}
/**
* Create the status.dat and objects.cache files for using testfixtures
*
* Remove existing files for status.dat testfixtures and create new
* (empty) files at /tmp/ when no resource is given.
*
* @param String $version The version to use, will be ignored
* @param array $resource An optional associative array pointing to the
* objects_cache and status.dat files. The keys are as following:
* - "status_file" : Path to the status.dat to remove and recreate
* - "objects_file" : Path to the objects.cache file to remove and recreate
* @return array An path array (see $resource) that contains the used file paths
*/
public function setup($version = null, $resource = null)
{
if ($resource == null) {
$resource = array(
"status_file" => "/tmp/teststatus.dat",
"objects_file" => "/tmp/testobjects.cache"
);
}
$this->requireStatusDat();
$this->teardown($resource);
touch($resource["status_file"]);
touch($resource["objects_file"]);
return $resource;
}
/**
* Remove test status.dat and objects.cache files
*
* @param array $resource An optional associative array pointing to the
* objects_cache and status.dat files. The keys are as following:
* - "status_file" : Path to the status.dat to remove
* - "objects_file" : Path to the objects.cache file to remove
*/
public function teardown($resource = null)
{
if ($resource == null) {
$resource = array(
"status_file" => "/tmp/teststatus.dat",
"objects_file" => "/tmp/testobjects.cache"
);
}
if (file_exists($resource["status_file"])) {
unlink($resource["status_file"]);
}
if (file_exists($resource["objects_file"])) {
unlink($resource["objects_file"]);
}
}
}

View File

@ -10,7 +10,6 @@ $less = new lessc;
$cssdir = dirname(__FILE__) . '/css';
echo $less->compileFile($cssdir . '/base.less');
echo $less->compileFile($cssdir . '/icinga.less');
foreach ($app->moduleManager()->getLoadedModules() as $name => $module) {
if ($module->hasCss()) {
echo $less->compile(

23
public/css/base.less Executable file → Normal file
View File

@ -174,7 +174,30 @@ body {
}
}
/**
* Superscript badge
*
**/
.badge.sup {
font-size:0.7em;
border-radius:50%;
background-color:red;
padding-left:0.4em;
padding-right:0.5em;
padding-top:0.2em;
padding-bottom:0.2em;
vertical-align:super;
}
input.input-squeezed {
height: 14px;
font-size: 12px;
line-height: 12px;
}
@import 'components/toolbars';
@import 'dataviews';
@import 'components/layouts';
@import 'components/tables';
@import 'components/details';
@import 'components/icons';

68
public/css/components/details.less Executable file → Normal file
View File

@ -84,4 +84,70 @@ font-size: 12px;
clear:left;
font-weight:bold;
}
}
}
.information-container {
margin: 0 0 5px 0;
border: 1px #fa4600 solid;
padding: 5px;
.head {
top: -5px;
left: -5px;
position: relative;
display: table-cell;
background-color: yellow;
padding: 4px;
}
.container-spacer {
margin: 10px 0 0 0;
}
}
.flag-container {
.flag {
display: inline-block;
padding: 2px;
width: 80px;
text-align: center;
}
.flag-enabled {
background-color: #00ff00;
}
.flag-disabled {
background-color: #cc0000;
color: white;
}
th {
text-align: left;
}
table {
border-collapse: collapse;
}
td, th {
border: 1px #ff0000 solid;
}
}
.command-container {
div.command-section {
overflow: hidden;
margin: 0 0 0 10px;
}
div.command-section div {
margin: 4px 0 0 0;
}
div.command-section div button {
width: 100%;
}
}

View File

@ -0,0 +1,36 @@
/* {{ICINGA_LICENSE_HEADERS}}
{{ICINGA_LICENSE_HEADERS}} */
@keyframes shake {
0% { transform: translate(3px, 0); }
50% { transform: translate(-3px, 0); }
100% { transform: translate(0, 0); }
}
@-moz-keyframes shake{
0% { -moz-transform: translate(3px, 0); }
50% { -moz-transform: translate(-3px, 0); }
100% { -moz-transform: translate(0, 0); }
}
@-webkit-keyframes shake {
0% { -webkit-transform: translate(3px, 0); }
50% { -webkit-transform: translate(-3px, 0); }
100% { -webkit-transform: translate(0, 0); }
}
i.reactible {
&:hover {
animation-name: shake;
animation-duration: 150ms;
animation-timing-function: linear;
-moz-animation-name: shake;
-moz-animation-duration: 150ms;
-moz-animation-timing-function: linear;
-webkit-animation-name: shake;
-webkit-animation-duration: 150ms;
-webkit-animation-timing-function: linear;
}
}

View File

@ -81,6 +81,7 @@
min-width: 400px;
top: 0px;
bottom: 0px;
margin: 0 10px 0 10px;
-webkit-transition: right 0.5s ease;
-moz-transition: right 0.5s ease;
-o-transition: right 0.5s ease;

View File

@ -2,31 +2,66 @@
.statusTable(@color) {
font-size:10px;
&:hover {
background-color: @color;
background-color: darken(@color-white, 10%);
}
&.active {
background-color: lighten(@color-emphasis,20%);
text-shadow: 0px 1px 0px rgba(255,255,255,.5);
color:@color-black;
}
& td:first-child {
}
td.indicator {
background-color: @color;
text-shadow: 0px 1px 0px rgba(255,255,255,.5);
color:darken(@color,50%);
text-align:center;
a {
text-shadow: 0px 1px 0px rgba(255,255,255,.5);
color:darken(@color,40%);
}
}
td.icons {
padding-top:0.4em;
font-size: 12px;
color:black;
.icon-box {
display: inline-block;
width: 32px;
max-width:64px;
&:empty {
width: 0px;
}
}
.img-box {
display: inline-block;
width: 16px;
max-width:16px;
&:empty {
width: 0px;
}
}
}
border-collapse:collapse;
td.state {
padding-right:1em;
.statetext {
max-width:8em;
min-width:6em;
}
}
td.hostname {
width:12%;
padding-left: 0.5em;
padding-right: 0.5em;
}
td.expand-full {
width: 100%;
}
cursor:pointer;
}
.icinga-container.action-table-content {
.expanded_absolute;
top: 35px;
top: 1em;
}
.icinga-container {
@ -51,16 +86,12 @@
tr {
th {
//background-color: @color-black;
text-shadow: inset 0px 1px 0px rgba(0,0,0,.5);
//color:@color-emphasis;
border-bottom:1px solid @color-black;
text-align:center;
height:2em;
text-align:left;
height:1em;
font-size:1em;
}
cursor:pointer;
/*
&.ok, &.up{
.statusTable(@color-ok);
}
@ -85,11 +116,10 @@
&.pending, &.pending {
.statusTable(@color-pending);
}
*/
}
td {;
padding:0.1em;
padding-left:0.2em;
padding-left:0.3em;
padding-right:0.3em;
}
}
@ -123,4 +153,4 @@ table.subTable {
}
}
}
}
}

View File

@ -3,8 +3,8 @@
*/
ul.icinga-navigation.nav.nav-tabs {
height:100%;
overflow-y:auto;
// overflow-x:hidden;
overflow: hidden;
-webkit-overflow-scroll:touch;
li {
a {

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,399 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<svg xmlns="http://www.w3.org/2000/svg">
<metadata></metadata>
<defs>
<font id="fontawesomeregular" horiz-adv-x="1536" >
<font-face units-per-em="1792" ascent="1536" descent="-256" />
<missing-glyph horiz-adv-x="448" />
<glyph unicode=" " horiz-adv-x="448" />
<glyph unicode="&#x09;" horiz-adv-x="448" />
<glyph unicode="&#xa0;" horiz-adv-x="448" />
<glyph unicode="&#xa8;" horiz-adv-x="1792" />
<glyph unicode="&#xa9;" horiz-adv-x="1792" />
<glyph unicode="&#xae;" horiz-adv-x="1792" />
<glyph unicode="&#xb4;" horiz-adv-x="1792" />
<glyph unicode="&#xc6;" horiz-adv-x="1792" />
<glyph unicode="&#x2000;" horiz-adv-x="768" />
<glyph unicode="&#x2001;" />
<glyph unicode="&#x2002;" horiz-adv-x="768" />
<glyph unicode="&#x2003;" />
<glyph unicode="&#x2004;" horiz-adv-x="512" />
<glyph unicode="&#x2005;" horiz-adv-x="384" />
<glyph unicode="&#x2006;" horiz-adv-x="256" />
<glyph unicode="&#x2007;" horiz-adv-x="256" />
<glyph unicode="&#x2008;" horiz-adv-x="192" />
<glyph unicode="&#x2009;" horiz-adv-x="307" />
<glyph unicode="&#x200a;" horiz-adv-x="85" />
<glyph unicode="&#x202f;" horiz-adv-x="307" />
<glyph unicode="&#x205f;" horiz-adv-x="384" />
<glyph unicode="&#x2122;" horiz-adv-x="1792" />
<glyph unicode="&#x221e;" horiz-adv-x="1792" />
<glyph unicode="&#x2260;" horiz-adv-x="1792" />
<glyph unicode="&#xe000;" horiz-adv-x="500" d="M0 0z" />
<glyph unicode="&#xf000;" horiz-adv-x="1792" d="M1699 1350q0 -35 -43 -78l-632 -632v-768h320q26 0 45 -19t19 -45t-19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45t45 19h320v768l-632 632q-43 43 -43 78q0 23 18 36.5t38 17.5t43 4h1408q23 0 43 -4t38 -17.5t18 -36.5z" />
<glyph unicode="&#xf001;" d="M1536 1312v-1120q0 -50 -34 -89t-86 -60.5t-103.5 -32t-96.5 -10.5t-96.5 10.5t-103.5 32t-86 60.5t-34 89t34 89t86 60.5t103.5 32t96.5 10.5q105 0 192 -39v537l-768 -237v-709q0 -50 -34 -89t-86 -60.5t-103.5 -32t-96.5 -10.5t-96.5 10.5t-103.5 32t-86 60.5t-34 89 t34 89t86 60.5t103.5 32t96.5 10.5q105 0 192 -39v967q0 31 19 56.5t49 35.5l832 256q12 4 28 4q40 0 68 -28t28 -68z" />
<glyph unicode="&#xf002;" horiz-adv-x="1664" d="M1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5zM1664 -128q0 -52 -38 -90t-90 -38q-54 0 -90 38l-343 342q-179 -124 -399 -124q-143 0 -273.5 55.5t-225 150t-150 225t-55.5 273.5 t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -220 -124 -399l343 -343q37 -37 37 -90z" />
<glyph unicode="&#xf003;" horiz-adv-x="1792" d="M1664 32v768q-32 -36 -69 -66q-268 -206 -426 -338q-51 -43 -83 -67t-86.5 -48.5t-102.5 -24.5h-1h-1q-48 0 -102.5 24.5t-86.5 48.5t-83 67q-158 132 -426 338q-37 30 -69 66v-768q0 -13 9.5 -22.5t22.5 -9.5h1472q13 0 22.5 9.5t9.5 22.5zM1664 1083v11v13.5t-0.5 13 t-3 12.5t-5.5 9t-9 7.5t-14 2.5h-1472q-13 0 -22.5 -9.5t-9.5 -22.5q0 -168 147 -284q193 -152 401 -317q6 -5 35 -29.5t46 -37.5t44.5 -31.5t50.5 -27.5t43 -9h1h1q20 0 43 9t50.5 27.5t44.5 31.5t46 37.5t35 29.5q208 165 401 317q54 43 100.5 115.5t46.5 131.5z M1792 1120v-1088q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1472q66 0 113 -47t47 -113z" />
<glyph unicode="&#xf004;" horiz-adv-x="1792" d="M896 -128q-26 0 -44 18l-624 602q-10 8 -27.5 26t-55.5 65.5t-68 97.5t-53.5 121t-23.5 138q0 220 127 344t351 124q62 0 126.5 -21.5t120 -58t95.5 -68.5t76 -68q36 36 76 68t95.5 68.5t120 58t126.5 21.5q224 0 351 -124t127 -344q0 -221 -229 -450l-623 -600 q-18 -18 -44 -18z" />
<glyph unicode="&#xf005;" horiz-adv-x="1664" d="M1664 889q0 -22 -26 -48l-363 -354l86 -500q1 -7 1 -20q0 -21 -10.5 -35.5t-30.5 -14.5q-19 0 -40 12l-449 236l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41t49 -41l225 -455 l502 -73q56 -9 56 -46z" />
<glyph unicode="&#xf006;" horiz-adv-x="1664" d="M1137 532l306 297l-422 62l-189 382l-189 -382l-422 -62l306 -297l-73 -421l378 199l377 -199zM1664 889q0 -22 -26 -48l-363 -354l86 -500q1 -7 1 -20q0 -50 -41 -50q-19 0 -40 12l-449 236l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500 l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41t49 -41l225 -455l502 -73q56 -9 56 -46z" />
<glyph unicode="&#xf007;" horiz-adv-x="1408" d="M1408 131q0 -120 -73 -189.5t-194 -69.5h-874q-121 0 -194 69.5t-73 189.5q0 53 3.5 103.5t14 109t26.5 108.5t43 97.5t62 81t85.5 53.5t111.5 20q9 0 42 -21.5t74.5 -48t108 -48t133.5 -21.5t133.5 21.5t108 48t74.5 48t42 21.5q61 0 111.5 -20t85.5 -53.5t62 -81 t43 -97.5t26.5 -108.5t14 -109t3.5 -103.5zM1088 1024q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5z" />
<glyph unicode="&#xf008;" horiz-adv-x="1920" d="M384 -64v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM384 320v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM384 704v128q0 26 -19 45t-45 19h-128 q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1408 -64v512q0 26 -19 45t-45 19h-768q-26 0 -45 -19t-19 -45v-512q0 -26 19 -45t45 -19h768q26 0 45 19t19 45zM384 1088v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45 t45 -19h128q26 0 45 19t19 45zM1792 -64v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1408 704v512q0 26 -19 45t-45 19h-768q-26 0 -45 -19t-19 -45v-512q0 -26 19 -45t45 -19h768q26 0 45 19t19 45zM1792 320v128 q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1792 704v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1792 1088v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19 t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1920 1248v-1344q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1344q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" />
<glyph unicode="&#xf009;" horiz-adv-x="1664" d="M768 512v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM768 1280v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM1664 512v-384q0 -52 -38 -90t-90 -38 h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM1664 1280v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90z" />
<glyph unicode="&#xf00a;" horiz-adv-x="1792" d="M512 288v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 800v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1152 288v-192q0 -40 -28 -68t-68 -28h-320 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1152 800v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28 h320q40 0 68 -28t28 -68zM1792 288v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1152 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 800v-192 q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68z" />
<glyph unicode="&#xf00b;" horiz-adv-x="1792" d="M512 288v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 800v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 288v-192q0 -40 -28 -68t-68 -28h-960 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h960q40 0 68 -28t28 -68zM512 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 800v-192q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v192q0 40 28 68t68 28 h960q40 0 68 -28t28 -68zM1792 1312v-192q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h960q40 0 68 -28t28 -68z" />
<glyph unicode="&#xf00c;" horiz-adv-x="1792" d="M1671 970q0 -40 -28 -68l-724 -724l-136 -136q-28 -28 -68 -28t-68 28l-136 136l-362 362q-28 28 -28 68t28 68l136 136q28 28 68 28t68 -28l294 -295l656 657q28 28 68 28t68 -28l136 -136q28 -28 28 -68z" />
<glyph unicode="&#xf00d;" horiz-adv-x="1408" d="M1298 214q0 -40 -28 -68l-136 -136q-28 -28 -68 -28t-68 28l-294 294l-294 -294q-28 -28 -68 -28t-68 28l-136 136q-28 28 -28 68t28 68l294 294l-294 294q-28 28 -28 68t28 68l136 136q28 28 68 28t68 -28l294 -294l294 294q28 28 68 28t68 -28l136 -136q28 -28 28 -68 t-28 -68l-294 -294l294 -294q28 -28 28 -68z" />
<glyph unicode="&#xf00e;" horiz-adv-x="1664" d="M1024 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-224v-224q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v224h-224q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h224v224q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5v-224h224 q13 0 22.5 -9.5t9.5 -22.5zM1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5zM1664 -128q0 -53 -37.5 -90.5t-90.5 -37.5q-54 0 -90 38l-343 342q-179 -124 -399 -124q-143 0 -273.5 55.5 t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -220 -124 -399l343 -343q37 -37 37 -90z" />
<glyph unicode="&#xf010;" horiz-adv-x="1664" d="M1024 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-576q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h576q13 0 22.5 -9.5t9.5 -22.5zM1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5z M1664 -128q0 -53 -37.5 -90.5t-90.5 -37.5q-54 0 -90 38l-343 342q-179 -124 -399 -124q-143 0 -273.5 55.5t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -220 -124 -399l343 -343q37 -37 37 -90z " />
<glyph unicode="&#xf011;" d="M1536 640q0 -156 -61 -298t-164 -245t-245 -164t-298 -61t-298 61t-245 164t-164 245t-61 298q0 182 80.5 343t226.5 270q43 32 95.5 25t83.5 -50q32 -42 24.5 -94.5t-49.5 -84.5q-98 -74 -151.5 -181t-53.5 -228q0 -104 40.5 -198.5t109.5 -163.5t163.5 -109.5 t198.5 -40.5t198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5q0 121 -53.5 228t-151.5 181q-42 32 -49.5 84.5t24.5 94.5q31 43 84 50t95 -25q146 -109 226.5 -270t80.5 -343zM896 1408v-640q0 -52 -38 -90t-90 -38t-90 38t-38 90v640q0 52 38 90t90 38t90 -38t38 -90z" />
<glyph unicode="&#xf012;" horiz-adv-x="1792" d="M256 96v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM640 224v-320q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v320q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1024 480v-576q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23 v576q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1408 864v-960q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v960q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1792 1376v-1472q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v1472q0 14 9 23t23 9h192q14 0 23 -9t9 -23z" />
<glyph unicode="&#xf013;" d="M1024 640q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1536 749v-222q0 -12 -8 -23t-20 -13l-185 -28q-19 -54 -39 -91q35 -50 107 -138q10 -12 10 -25t-9 -23q-27 -37 -99 -108t-94 -71q-12 0 -26 9l-138 108q-44 -23 -91 -38 q-16 -136 -29 -186q-7 -28 -36 -28h-222q-14 0 -24.5 8.5t-11.5 21.5l-28 184q-49 16 -90 37l-141 -107q-10 -9 -25 -9q-14 0 -25 11q-126 114 -165 168q-7 10 -7 23q0 12 8 23q15 21 51 66.5t54 70.5q-27 50 -41 99l-183 27q-13 2 -21 12.5t-8 23.5v222q0 12 8 23t19 13 l186 28q14 46 39 92q-40 57 -107 138q-10 12 -10 24q0 10 9 23q26 36 98.5 107.5t94.5 71.5q13 0 26 -10l138 -107q44 23 91 38q16 136 29 186q7 28 36 28h222q14 0 24.5 -8.5t11.5 -21.5l28 -184q49 -16 90 -37l142 107q9 9 24 9q13 0 25 -10q129 -119 165 -170q7 -8 7 -22 q0 -12 -8 -23q-15 -21 -51 -66.5t-54 -70.5q26 -50 41 -98l183 -28q13 -2 21 -12.5t8 -23.5z" />
<glyph unicode="&#xf014;" horiz-adv-x="1408" d="M512 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM768 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1024 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576 q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1152 76v948h-896v-948q0 -22 7 -40.5t14.5 -27t10.5 -8.5h832q3 0 10.5 8.5t14.5 27t7 40.5zM480 1152h448l-48 117q-7 9 -17 11h-317q-10 -2 -17 -11zM1408 1120v-64q0 -14 -9 -23t-23 -9h-96v-948q0 -83 -47 -143.5t-113 -60.5h-832 q-66 0 -113 58.5t-47 141.5v952h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h309l70 167q15 37 54 63t79 26h320q40 0 79 -26t54 -63l70 -167h309q14 0 23 -9t9 -23z" />
<glyph unicode="&#xf015;" horiz-adv-x="1664" d="M1408 544v-480q0 -26 -19 -45t-45 -19h-384v384h-256v-384h-384q-26 0 -45 19t-19 45v480q0 1 0.5 3t0.5 3l575 474l575 -474q1 -2 1 -6zM1631 613l-62 -74q-8 -9 -21 -11h-3q-13 0 -21 7l-692 577l-692 -577q-12 -8 -24 -7q-13 2 -21 11l-62 74q-8 10 -7 23.5t11 21.5 l719 599q32 26 76 26t76 -26l244 -204v195q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-408l219 -182q10 -8 11 -21.5t-7 -23.5z" />
<glyph unicode="&#xf016;" horiz-adv-x="1280" d="M128 0h1024v768h-416q-40 0 -68 28t-28 68v416h-512v-1280zM768 896h376q-10 29 -22 41l-313 313q-12 12 -41 22v-376zM1280 864v-896q0 -40 -28 -68t-68 -28h-1088q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h640q40 0 88 -20t76 -48l312 -312q28 -28 48 -76t20 -88z " />
<glyph unicode="&#xf017;" d="M896 992v-448q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h224v352q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
<glyph unicode="&#xf018;" horiz-adv-x="1920" d="M1111 540v4l-24 320q-1 13 -11 22.5t-23 9.5h-186q-13 0 -23 -9.5t-11 -22.5l-24 -320v-4q-1 -12 8 -20t21 -8h244q12 0 21 8t8 20zM1870 73q0 -73 -46 -73h-704q13 0 22 9.5t8 22.5l-20 256q-1 13 -11 22.5t-23 9.5h-272q-13 0 -23 -9.5t-11 -22.5l-20 -256 q-1 -13 8 -22.5t22 -9.5h-704q-46 0 -46 73q0 54 26 116l417 1044q8 19 26 33t38 14h339q-13 0 -23 -9.5t-11 -22.5l-15 -192q-1 -14 8 -23t22 -9h166q13 0 22 9t8 23l-15 192q-1 13 -11 22.5t-23 9.5h339q20 0 38 -14t26 -33l417 -1044q26 -62 26 -116z" />
<glyph unicode="&#xf019;" horiz-adv-x="1664" d="M1280 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 416v-320q0 -40 -28 -68t-68 -28h-1472q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h465l135 -136 q58 -56 136 -56t136 56l136 136h464q40 0 68 -28t28 -68zM1339 985q17 -41 -14 -70l-448 -448q-18 -19 -45 -19t-45 19l-448 448q-31 29 -14 70q17 39 59 39h256v448q0 26 19 45t45 19h256q26 0 45 -19t19 -45v-448h256q42 0 59 -39z" />
<glyph unicode="&#xf01a;" d="M1120 608q0 -12 -10 -24l-319 -319q-11 -9 -23 -9t-23 9l-320 320q-15 16 -7 35q8 20 30 20h192v352q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-352h192q14 0 23 -9t9 -23zM768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273 t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
<glyph unicode="&#xf01b;" d="M1118 660q-8 -20 -30 -20h-192v-352q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v352h-192q-14 0 -23 9t-9 23q0 12 10 24l319 319q11 9 23 9t23 -9l320 -320q15 -16 7 -35zM768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198 t73 273t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
<glyph unicode="&#xf01c;" d="M1023 576h316q-1 3 -2.5 8t-2.5 8l-212 496h-708l-212 -496q-1 -2 -2.5 -8t-2.5 -8h316l95 -192h320zM1536 546v-482q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v482q0 62 25 123l238 552q10 25 36.5 42t52.5 17h832q26 0 52.5 -17t36.5 -42l238 -552 q25 -61 25 -123z" />
<glyph unicode="&#xf01d;" d="M1184 640q0 -37 -32 -55l-544 -320q-15 -9 -32 -9q-16 0 -32 8q-32 19 -32 56v640q0 37 32 56q33 18 64 -1l544 -320q32 -18 32 -55zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
<glyph unicode="&#xf01e;" d="M1536 1280v-448q0 -26 -19 -45t-45 -19h-448q-42 0 -59 40q-17 39 14 69l138 138q-148 137 -349 137q-104 0 -198.5 -40.5t-163.5 -109.5t-109.5 -163.5t-40.5 -198.5t40.5 -198.5t109.5 -163.5t163.5 -109.5t198.5 -40.5q119 0 225 52t179 147q7 10 23 12q14 0 25 -9 l137 -138q9 -8 9.5 -20.5t-7.5 -22.5q-109 -132 -264 -204.5t-327 -72.5q-156 0 -298 61t-245 164t-164 245t-61 298t61 298t164 245t245 164t298 61q147 0 284.5 -55.5t244.5 -156.5l130 129q29 31 70 14q39 -17 39 -59z" />
<glyph unicode="&#xf021;" d="M1511 480q0 -5 -1 -7q-64 -268 -268 -434.5t-478 -166.5q-146 0 -282.5 55t-243.5 157l-129 -129q-19 -19 -45 -19t-45 19t-19 45v448q0 26 19 45t45 19h448q26 0 45 -19t19 -45t-19 -45l-137 -137q71 -66 161 -102t187 -36q134 0 250 65t186 179q11 17 53 117 q8 23 30 23h192q13 0 22.5 -9.5t9.5 -22.5zM1536 1280v-448q0 -26 -19 -45t-45 -19h-448q-26 0 -45 19t-19 45t19 45l138 138q-148 137 -349 137q-134 0 -250 -65t-186 -179q-11 -17 -53 -117q-8 -23 -30 -23h-199q-13 0 -22.5 9.5t-9.5 22.5v7q65 268 270 434.5t480 166.5 q146 0 284 -55.5t245 -156.5l130 129q19 19 45 19t45 -19t19 -45z" />
<glyph unicode="&#xf022;" horiz-adv-x="1792" d="M384 352v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 608v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M384 864v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1536 352v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h960q13 0 22.5 -9.5t9.5 -22.5z M1536 608v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h960q13 0 22.5 -9.5t9.5 -22.5zM1536 864v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h960q13 0 22.5 -9.5 t9.5 -22.5zM1664 160v832q0 13 -9.5 22.5t-22.5 9.5h-1472q-13 0 -22.5 -9.5t-9.5 -22.5v-832q0 -13 9.5 -22.5t22.5 -9.5h1472q13 0 22.5 9.5t9.5 22.5zM1792 1248v-1088q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1472q66 0 113 -47 t47 -113z" />
<glyph unicode="&#xf023;" horiz-adv-x="1152" d="M320 768h512v192q0 106 -75 181t-181 75t-181 -75t-75 -181v-192zM1152 672v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h32v192q0 184 132 316t316 132t316 -132t132 -316v-192h32q40 0 68 -28t28 -68z" />
<glyph unicode="&#xf024;" horiz-adv-x="1792" d="M320 1280q0 -72 -64 -110v-1266q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v1266q-64 38 -64 110q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1792 1216v-763q0 -25 -12.5 -38.5t-39.5 -27.5q-215 -116 -369 -116q-61 0 -123.5 22t-108.5 48 t-115.5 48t-142.5 22q-192 0 -464 -146q-17 -9 -33 -9q-26 0 -45 19t-19 45v742q0 32 31 55q21 14 79 43q236 120 421 120q107 0 200 -29t219 -88q38 -19 88 -19q54 0 117.5 21t110 47t88 47t54.5 21q26 0 45 -19t19 -45z" />
<glyph unicode="&#xf025;" horiz-adv-x="1664" d="M1664 650q0 -166 -60 -314l-20 -49l-185 -33q-22 -83 -90.5 -136.5t-156.5 -53.5v-32q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-32q71 0 130 -35.5t93 -95.5l68 12q29 95 29 193q0 148 -88 279t-236.5 209t-315.5 78 t-315.5 -78t-236.5 -209t-88 -279q0 -98 29 -193l68 -12q34 60 93 95.5t130 35.5v32q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v32q-88 0 -156.5 53.5t-90.5 136.5l-185 33l-20 49q-60 148 -60 314q0 151 67 291t179 242.5 t266 163.5t320 61t320 -61t266 -163.5t179 -242.5t67 -291z" />
<glyph unicode="&#xf026;" horiz-adv-x="768" d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45z" />
<glyph unicode="&#xf027;" horiz-adv-x="1152" d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45zM1152 640q0 -76 -42.5 -141.5t-112.5 -93.5q-10 -5 -25 -5q-26 0 -45 18.5t-19 45.5q0 21 12 35.5t29 25t34 23t29 35.5 t12 57t-12 57t-29 35.5t-34 23t-29 25t-12 35.5q0 27 19 45.5t45 18.5q15 0 25 -5q70 -27 112.5 -93t42.5 -142z" />
<glyph unicode="&#xf028;" horiz-adv-x="1664" d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45zM1152 640q0 -76 -42.5 -141.5t-112.5 -93.5q-10 -5 -25 -5q-26 0 -45 18.5t-19 45.5q0 21 12 35.5t29 25t34 23t29 35.5 t12 57t-12 57t-29 35.5t-34 23t-29 25t-12 35.5q0 27 19 45.5t45 18.5q15 0 25 -5q70 -27 112.5 -93t42.5 -142zM1408 640q0 -153 -85 -282.5t-225 -188.5q-13 -5 -25 -5q-27 0 -46 19t-19 45q0 39 39 59q56 29 76 44q74 54 115.5 135.5t41.5 173.5t-41.5 173.5 t-115.5 135.5q-20 15 -76 44q-39 20 -39 59q0 26 19 45t45 19q13 0 26 -5q140 -59 225 -188.5t85 -282.5zM1664 640q0 -230 -127 -422.5t-338 -283.5q-13 -5 -26 -5q-26 0 -45 19t-19 45q0 36 39 59q7 4 22.5 10.5t22.5 10.5q46 25 82 51q123 91 192 227t69 289t-69 289 t-192 227q-36 26 -82 51q-7 4 -22.5 10.5t-22.5 10.5q-39 23 -39 59q0 26 19 45t45 19q13 0 26 -5q211 -91 338 -283.5t127 -422.5z" />
<glyph unicode="&#xf029;" horiz-adv-x="1408" d="M384 384v-128h-128v128h128zM384 1152v-128h-128v128h128zM1152 1152v-128h-128v128h128zM128 129h384v383h-384v-383zM128 896h384v384h-384v-384zM896 896h384v384h-384v-384zM640 640v-640h-640v640h640zM1152 128v-128h-128v128h128zM1408 128v-128h-128v128h128z M1408 640v-384h-384v128h-128v-384h-128v640h384v-128h128v128h128zM640 1408v-640h-640v640h640zM1408 1408v-640h-640v640h640z" />
<glyph unicode="&#xf02a;" horiz-adv-x="1792" d="M63 0h-63v1408h63v-1408zM126 1h-32v1407h32v-1407zM220 1h-31v1407h31v-1407zM377 1h-31v1407h31v-1407zM534 1h-62v1407h62v-1407zM660 1h-31v1407h31v-1407zM723 1h-31v1407h31v-1407zM786 1h-31v1407h31v-1407zM943 1h-63v1407h63v-1407zM1100 1h-63v1407h63v-1407z M1226 1h-63v1407h63v-1407zM1352 1h-63v1407h63v-1407zM1446 1h-63v1407h63v-1407zM1635 1h-94v1407h94v-1407zM1698 1h-32v1407h32v-1407zM1792 0h-63v1408h63v-1408z" />
<glyph unicode="&#xf02b;" d="M448 1088q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1515 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-53 0 -90 37l-715 716q-38 37 -64.5 101t-26.5 117v416q0 52 38 90t90 38h416q53 0 117 -26.5t102 -64.5 l715 -714q37 -39 37 -91z" />
<glyph unicode="&#xf02c;" horiz-adv-x="1920" d="M448 1088q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1515 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-53 0 -90 37l-715 716q-38 37 -64.5 101t-26.5 117v416q0 52 38 90t90 38h416q53 0 117 -26.5t102 -64.5 l715 -714q37 -39 37 -91zM1899 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-36 0 -59 14t-53 45l470 470q37 37 37 90q0 52 -37 91l-715 714q-38 38 -102 64.5t-117 26.5h224q53 0 117 -26.5t102 -64.5l715 -714q37 -39 37 -91z" />
<glyph unicode="&#xf02d;" horiz-adv-x="1664" d="M1639 1058q40 -57 18 -129l-275 -906q-19 -64 -76.5 -107.5t-122.5 -43.5h-923q-77 0 -148.5 53.5t-99.5 131.5q-24 67 -2 127q0 4 3 27t4 37q1 8 -3 21.5t-3 19.5q2 11 8 21t16.5 23.5t16.5 23.5q23 38 45 91.5t30 91.5q3 10 0.5 30t-0.5 28q3 11 17 28t17 23 q21 36 42 92t25 90q1 9 -2.5 32t0.5 28q4 13 22 30.5t22 22.5q19 26 42.5 84.5t27.5 96.5q1 8 -3 25.5t-2 26.5q2 8 9 18t18 23t17 21q8 12 16.5 30.5t15 35t16 36t19.5 32t26.5 23.5t36 11.5t47.5 -5.5l-1 -3q38 9 51 9h761q74 0 114 -56t18 -130l-274 -906 q-36 -119 -71.5 -153.5t-128.5 -34.5h-869q-27 0 -38 -15q-11 -16 -1 -43q24 -70 144 -70h923q29 0 56 15.5t35 41.5l300 987q7 22 5 57q38 -15 59 -43zM575 1056q-4 -13 2 -22.5t20 -9.5h608q13 0 25.5 9.5t16.5 22.5l21 64q4 13 -2 22.5t-20 9.5h-608q-13 0 -25.5 -9.5 t-16.5 -22.5zM492 800q-4 -13 2 -22.5t20 -9.5h608q13 0 25.5 9.5t16.5 22.5l21 64q4 13 -2 22.5t-20 9.5h-608q-13 0 -25.5 -9.5t-16.5 -22.5z" />
<glyph unicode="&#xf02e;" horiz-adv-x="1280" d="M1164 1408q23 0 44 -9q33 -13 52.5 -41t19.5 -62v-1289q0 -34 -19.5 -62t-52.5 -41q-19 -8 -44 -8q-48 0 -83 32l-441 424l-441 -424q-36 -33 -83 -33q-23 0 -44 9q-33 13 -52.5 41t-19.5 62v1289q0 34 19.5 62t52.5 41q21 9 44 9h1048z" />
<glyph unicode="&#xf02f;" horiz-adv-x="1664" d="M384 0h896v256h-896v-256zM384 640h896v384h-160q-40 0 -68 28t-28 68v160h-640v-640zM1536 576q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 576v-416q0 -13 -9.5 -22.5t-22.5 -9.5h-224v-160q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68 v160h-224q-13 0 -22.5 9.5t-9.5 22.5v416q0 79 56.5 135.5t135.5 56.5h64v544q0 40 28 68t68 28h672q40 0 88 -20t76 -48l152 -152q28 -28 48 -76t20 -88v-256h64q79 0 135.5 -56.5t56.5 -135.5z" />
<glyph unicode="&#xf030;" horiz-adv-x="1920" d="M960 864q119 0 203.5 -84.5t84.5 -203.5t-84.5 -203.5t-203.5 -84.5t-203.5 84.5t-84.5 203.5t84.5 203.5t203.5 84.5zM1664 1280q106 0 181 -75t75 -181v-896q0 -106 -75 -181t-181 -75h-1408q-106 0 -181 75t-75 181v896q0 106 75 181t181 75h224l51 136 q19 49 69.5 84.5t103.5 35.5h512q53 0 103.5 -35.5t69.5 -84.5l51 -136h224zM960 128q185 0 316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" />
<glyph unicode="&#xf031;" horiz-adv-x="1664" d="M725 977l-170 -450q73 -1 153.5 -2t119 -1.5t52.5 -0.5l29 2q-32 95 -92 241q-53 132 -92 211zM21 -128h-21l2 79q22 7 80 18q89 16 110 31q20 16 48 68l237 616l280 724h75h53l11 -21l205 -480q103 -242 124 -297q39 -102 96 -235q26 -58 65 -164q24 -67 65 -149 q22 -49 35 -57q22 -19 69 -23q47 -6 103 -27q6 -39 6 -57q0 -14 -1 -26q-80 0 -192 8q-93 8 -189 8q-79 0 -135 -2l-200 -11l-58 -2q0 45 4 78l131 28q56 13 68 23q12 12 12 27t-6 32l-47 114l-92 228l-450 2q-29 -65 -104 -274q-23 -64 -23 -84q0 -31 17 -43 q26 -21 103 -32q3 0 13.5 -2t30 -5t40.5 -6q1 -28 1 -58q0 -17 -2 -27q-66 0 -349 20l-48 -8q-81 -14 -167 -14z" />
<glyph unicode="&#xf032;" horiz-adv-x="1408" d="M555 15q76 -32 140 -32q131 0 216 41t122 113q38 70 38 181q0 114 -41 180q-58 94 -141 126q-80 32 -247 32q-74 0 -101 -10v-144l-1 -173l3 -270q0 -15 12 -44zM541 761q43 -7 109 -7q175 0 264 65t89 224q0 112 -85 187q-84 75 -255 75q-52 0 -130 -13q0 -44 2 -77 q7 -122 6 -279l-1 -98q0 -43 1 -77zM0 -128l2 94q45 9 68 12q77 12 123 31q17 27 21 51q9 66 9 194l-2 497q-5 256 -9 404q-1 87 -11 109q-1 4 -12 12q-18 12 -69 15q-30 2 -114 13l-4 83l260 6l380 13l45 1q5 0 14 0.5t14 0.5q1 0 21.5 -0.5t40.5 -0.5h74q88 0 191 -27 q43 -13 96 -39q57 -29 102 -76q44 -47 65 -104t21 -122q0 -70 -32 -128t-95 -105q-26 -20 -150 -77q177 -41 267 -146q92 -106 92 -236q0 -76 -29 -161q-21 -62 -71 -117q-66 -72 -140 -108q-73 -36 -203 -60q-82 -15 -198 -11l-197 4q-84 2 -298 -11q-33 -3 -272 -11z" />
<glyph unicode="&#xf033;" horiz-adv-x="1024" d="M0 -126l17 85q4 1 77 20q76 19 116 39q29 37 41 101l27 139l56 268l12 64q8 44 17 84.5t16 67t12.5 46.5t9 30.5t3.5 11.5l29 157l16 63l22 135l8 50v38q-41 22 -144 28q-28 2 -38 4l19 103l317 -14q39 -2 73 -2q66 0 214 9q33 2 68 4.5t36 2.5q-2 -19 -6 -38 q-7 -29 -13 -51q-55 -19 -109 -31q-64 -16 -101 -31q-12 -31 -24 -88q-9 -44 -13 -82q-44 -199 -66 -306l-61 -311l-38 -158l-43 -235l-12 -45q-2 -7 1 -27q64 -15 119 -21q36 -5 66 -10q-1 -29 -7 -58q-7 -31 -9 -41q-18 0 -23 -1q-24 -2 -42 -2q-9 0 -28 3q-19 4 -145 17 l-198 2q-41 1 -174 -11q-74 -7 -98 -9z" />
<glyph unicode="&#xf034;" horiz-adv-x="1792" d="M81 1407l54 -27q20 -5 211 -5h130l19 3l115 1l215 -1h293l34 -2q14 -1 28 7t21 16l7 8l42 1q15 0 28 -1v-104.5t1 -131.5l1 -100l-1 -58q0 -32 -4 -51q-39 -15 -68 -18q-25 43 -54 128q-8 24 -15.5 62.5t-11.5 65.5t-6 29q-13 15 -27 19q-7 2 -42.5 2t-103.5 -1t-111 -1 q-34 0 -67 -5q-10 -97 -8 -136l1 -152v-332l3 -359l-1 -147q-1 -46 11 -85q49 -25 89 -32q2 0 18 -5t44 -13t43 -12q30 -8 50 -18q5 -45 5 -50q0 -10 -3 -29q-14 -1 -34 -1q-110 0 -187 10q-72 8 -238 8q-88 0 -233 -14q-48 -4 -70 -4q-2 22 -2 26l-1 26v9q21 33 79 49 q139 38 159 50q9 21 12 56q8 192 6 433l-5 428q-1 62 -0.5 118.5t0.5 102.5t-2 57t-6 15q-6 5 -14 6q-38 6 -148 6q-43 0 -100 -13.5t-73 -24.5q-13 -9 -22 -33t-22 -75t-24 -84q-6 -19 -19.5 -32t-20.5 -13q-44 27 -56 44v297v86zM1744 128q33 0 42 -18.5t-11 -44.5 l-126 -162q-20 -26 -49 -26t-49 26l-126 162q-20 26 -11 44.5t42 18.5h80v1024h-80q-33 0 -42 18.5t11 44.5l126 162q20 26 49 26t49 -26l126 -162q20 -26 11 -44.5t-42 -18.5h-80v-1024h80z" />
<glyph unicode="&#xf035;" d="M81 1407l54 -27q20 -5 211 -5h130l19 3l115 1l446 -1h318l34 -2q14 -1 28 7t21 16l7 8l42 1q15 0 28 -1v-104.5t1 -131.5l1 -100l-1 -58q0 -32 -4 -51q-39 -15 -68 -18q-25 43 -54 128q-8 24 -15.5 62.5t-11.5 65.5t-6 29q-13 15 -27 19q-7 2 -58.5 2t-138.5 -1t-128 -1 q-94 0 -127 -5q-10 -97 -8 -136l1 -152v52l3 -359l-1 -147q-1 -46 11 -85q49 -25 89 -32q2 0 18 -5t44 -13t43 -12q30 -8 50 -18q5 -45 5 -50q0 -10 -3 -29q-14 -1 -34 -1q-110 0 -187 10q-72 8 -238 8q-82 0 -233 -13q-45 -5 -70 -5q-2 22 -2 26l-1 26v9q21 33 79 49 q139 38 159 50q9 21 12 56q6 137 6 433l-5 44q0 265 -2 278q-2 11 -6 15q-6 5 -14 6q-38 6 -148 6q-50 0 -168.5 -14t-132.5 -24q-13 -9 -22 -33t-22 -75t-24 -84q-6 -19 -19.5 -32t-20.5 -13q-44 27 -56 44v297v86zM1505 113q26 -20 26 -49t-26 -49l-162 -126 q-26 -20 -44.5 -11t-18.5 42v80h-1024v-80q0 -33 -18.5 -42t-44.5 11l-162 126q-26 20 -26 49t26 49l162 126q26 20 44.5 11t18.5 -42v-80h1024v80q0 33 18.5 42t44.5 -11z" />
<glyph unicode="&#xf036;" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1408 576v-128q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1280q26 0 45 -19t19 -45zM1664 960v-128q0 -26 -19 -45 t-45 -19h-1536q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1536q26 0 45 -19t19 -45zM1280 1344v-128q0 -26 -19 -45t-45 -19h-1152q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" />
<glyph unicode="&#xf037;" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1408 576v-128q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h896q26 0 45 -19t19 -45zM1664 960v-128q0 -26 -19 -45t-45 -19 h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1280 1344v-128q0 -26 -19 -45t-45 -19h-640q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h640q26 0 45 -19t19 -45z" />
<glyph unicode="&#xf038;" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 576v-128q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1280q26 0 45 -19t19 -45zM1792 960v-128q0 -26 -19 -45 t-45 -19h-1536q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1536q26 0 45 -19t19 -45zM1792 1344v-128q0 -26 -19 -45t-45 -19h-1152q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" />
<glyph unicode="&#xf039;" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 576v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 960v-128q0 -26 -19 -45 t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 1344v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45z" />
<glyph unicode="&#xf03a;" horiz-adv-x="1792" d="M256 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5zM256 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5 t9.5 -22.5zM256 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1344 q13 0 22.5 -9.5t9.5 -22.5zM256 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5zM1792 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5 t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5zM1792 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5zM1792 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192 q0 13 9.5 22.5t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5z" />
<glyph unicode="&#xf03b;" horiz-adv-x="1792" d="M384 992v-576q0 -13 -9.5 -22.5t-22.5 -9.5q-14 0 -23 9l-288 288q-9 9 -9 23t9 23l288 288q9 9 23 9q13 0 22.5 -9.5t9.5 -22.5zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5 t9.5 -22.5zM1792 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088q13 0 22.5 -9.5t9.5 -22.5zM1792 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088 q13 0 22.5 -9.5t9.5 -22.5zM1792 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5t9.5 -22.5z" />
<glyph unicode="&#xf03c;" horiz-adv-x="1792" d="M352 704q0 -14 -9 -23l-288 -288q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5v576q0 13 9.5 22.5t22.5 9.5q14 0 23 -9l288 -288q9 -9 9 -23zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5 t9.5 -22.5zM1792 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088q13 0 22.5 -9.5t9.5 -22.5zM1792 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088 q13 0 22.5 -9.5t9.5 -22.5zM1792 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5t9.5 -22.5z" />
<glyph unicode="&#xf03d;" horiz-adv-x="1792" d="M1792 1184v-1088q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-403 403v-166q0 -119 -84.5 -203.5t-203.5 -84.5h-704q-119 0 -203.5 84.5t-84.5 203.5v704q0 119 84.5 203.5t203.5 84.5h704q119 0 203.5 -84.5t84.5 -203.5v-165l403 402q18 19 45 19q12 0 25 -5 q39 -17 39 -59z" />
<glyph unicode="&#xf03e;" horiz-adv-x="1920" d="M640 960q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1664 576v-448h-1408v192l320 320l160 -160l512 512zM1760 1280h-1600q-13 0 -22.5 -9.5t-9.5 -22.5v-1216q0 -13 9.5 -22.5t22.5 -9.5h1600q13 0 22.5 9.5t9.5 22.5v1216 q0 13 -9.5 22.5t-22.5 9.5zM1920 1248v-1216q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" />
<glyph unicode="&#xf040;" d="M363 0l91 91l-235 235l-91 -91v-107h128v-128h107zM886 928q0 22 -22 22q-10 0 -17 -7l-542 -542q-7 -7 -7 -17q0 -22 22 -22q10 0 17 7l542 542q7 7 7 17zM832 1120l416 -416l-832 -832h-416v416zM1515 1024q0 -53 -37 -90l-166 -166l-416 416l166 165q36 38 90 38 q53 0 91 -38l235 -234q37 -39 37 -91z" />
<glyph unicode="&#xf041;" horiz-adv-x="1024" d="M768 896q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1024 896q0 -109 -33 -179l-364 -774q-16 -33 -47.5 -52t-67.5 -19t-67.5 19t-46.5 52l-365 774q-33 70 -33 179q0 212 150 362t362 150t362 -150t150 -362z" />
<glyph unicode="&#xf042;" d="M768 96v1088q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
<glyph unicode="&#xf043;" horiz-adv-x="1024" d="M512 384q0 36 -20 69q-1 1 -15.5 22.5t-25.5 38t-25 44t-21 50.5q-4 16 -21 16t-21 -16q-7 -23 -21 -50.5t-25 -44t-25.5 -38t-15.5 -22.5q-20 -33 -20 -69q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1024 512q0 -212 -150 -362t-362 -150t-362 150t-150 362 q0 145 81 275q6 9 62.5 90.5t101 151t99.5 178t83 201.5q9 30 34 47t51 17t51.5 -17t33.5 -47q28 -93 83 -201.5t99.5 -178t101 -151t62.5 -90.5q81 -127 81 -275z" />
<glyph unicode="&#xf044;" horiz-adv-x="1792" d="M888 352l116 116l-152 152l-116 -116v-56h96v-96h56zM1328 1072q-16 16 -33 -1l-350 -350q-17 -17 -1 -33t33 1l350 350q17 17 1 33zM1408 478v-190q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832 q63 0 117 -25q15 -7 18 -23q3 -17 -9 -29l-49 -49q-14 -14 -32 -8q-23 6 -45 6h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v126q0 13 9 22l64 64q15 15 35 7t20 -29zM1312 1216l288 -288l-672 -672h-288v288zM1756 1084l-92 -92 l-288 288l92 92q28 28 68 28t68 -28l152 -152q28 -28 28 -68t-28 -68z" />
<glyph unicode="&#xf045;" horiz-adv-x="1664" d="M1408 547v-259q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h255v0q13 0 22.5 -9.5t9.5 -22.5q0 -27 -26 -32q-77 -26 -133 -60q-10 -4 -16 -4h-112q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832 q66 0 113 47t47 113v214q0 19 18 29q28 13 54 37q16 16 35 8q21 -9 21 -29zM1645 1043l-384 -384q-18 -19 -45 -19q-12 0 -25 5q-39 17 -39 59v192h-160q-323 0 -438 -131q-119 -137 -74 -473q3 -23 -20 -34q-8 -2 -12 -2q-16 0 -26 13q-10 14 -21 31t-39.5 68.5t-49.5 99.5 t-38.5 114t-17.5 122q0 49 3.5 91t14 90t28 88t47 81.5t68.5 74t94.5 61.5t124.5 48.5t159.5 30.5t196.5 11h160v192q0 42 39 59q13 5 25 5q26 0 45 -19l384 -384q19 -19 19 -45t-19 -45z" />
<glyph unicode="&#xf046;" horiz-adv-x="1664" d="M1408 606v-318q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832q63 0 117 -25q15 -7 18 -23q3 -17 -9 -29l-49 -49q-10 -10 -23 -10q-3 0 -9 2q-23 6 -45 6h-832q-66 0 -113 -47t-47 -113v-832 q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v254q0 13 9 22l64 64q10 10 23 10q6 0 12 -3q20 -8 20 -29zM1639 1095l-814 -814q-24 -24 -57 -24t-57 24l-430 430q-24 24 -24 57t24 57l110 110q24 24 57 24t57 -24l263 -263l647 647q24 24 57 24t57 -24l110 -110 q24 -24 24 -57t-24 -57z" />
<glyph unicode="&#xf047;" horiz-adv-x="1792" d="M1792 640q0 -26 -19 -45l-256 -256q-19 -19 -45 -19t-45 19t-19 45v128h-384v-384h128q26 0 45 -19t19 -45t-19 -45l-256 -256q-19 -19 -45 -19t-45 19l-256 256q-19 19 -19 45t19 45t45 19h128v384h-384v-128q0 -26 -19 -45t-45 -19t-45 19l-256 256q-19 19 -19 45 t19 45l256 256q19 19 45 19t45 -19t19 -45v-128h384v384h-128q-26 0 -45 19t-19 45t19 45l256 256q19 19 45 19t45 -19l256 -256q19 -19 19 -45t-19 -45t-45 -19h-128v-384h384v128q0 26 19 45t45 19t45 -19l256 -256q19 -19 19 -45z" />
<glyph unicode="&#xf048;" horiz-adv-x="1024" d="M979 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-678q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-678q4 11 13 19z" />
<glyph unicode="&#xf049;" horiz-adv-x="1792" d="M1747 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-710q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-678q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-678q4 11 13 19l710 710 q19 19 32 13t13 -32v-710q4 11 13 19z" />
<glyph unicode="&#xf04a;" horiz-adv-x="1664" d="M1619 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-8 9 -13 19v-710q0 -26 -13 -32t-32 13l-710 710q-19 19 -19 45t19 45l710 710q19 19 32 13t13 -32v-710q5 11 13 19z" />
<glyph unicode="&#xf04b;" horiz-adv-x="1408" d="M1384 609l-1328 -738q-23 -13 -39.5 -3t-16.5 36v1472q0 26 16.5 36t39.5 -3l1328 -738q23 -13 23 -31t-23 -31z" />
<glyph unicode="&#xf04c;" d="M1536 1344v-1408q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h512q26 0 45 -19t19 -45zM640 1344v-1408q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h512q26 0 45 -19t19 -45z" />
<glyph unicode="&#xf04d;" d="M1536 1344v-1408q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" />
<glyph unicode="&#xf04e;" horiz-adv-x="1664" d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q8 -8 13 -19v710q0 26 13 32t32 -13l710 -710q19 -19 19 -45t-19 -45l-710 -710q-19 -19 -32 -13t-13 32v710q-5 -10 -13 -19z" />
<glyph unicode="&#xf050;" horiz-adv-x="1792" d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q8 -8 13 -19v710q0 26 13 32t32 -13l710 -710q8 -8 13 -19v678q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-1408q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v678q-5 -10 -13 -19l-710 -710 q-19 -19 -32 -13t-13 32v710q-5 -10 -13 -19z" />
<glyph unicode="&#xf051;" horiz-adv-x="1024" d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q8 -8 13 -19v678q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-1408q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v678q-5 -10 -13 -19z" />
<glyph unicode="&#xf052;" horiz-adv-x="1538" d="M14 557l710 710q19 19 45 19t45 -19l710 -710q19 -19 13 -32t-32 -13h-1472q-26 0 -32 13t13 32zM1473 0h-1408q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1408q26 0 45 -19t19 -45v-256q0 -26 -19 -45t-45 -19z" />
<glyph unicode="&#xf053;" horiz-adv-x="1152" d="M742 -37l-652 651q-37 37 -37 90.5t37 90.5l652 651q37 37 90.5 37t90.5 -37l75 -75q37 -37 37 -90.5t-37 -90.5l-486 -486l486 -485q37 -38 37 -91t-37 -90l-75 -75q-37 -37 -90.5 -37t-90.5 37z" />
<glyph unicode="&#xf054;" horiz-adv-x="1152" d="M1099 704q0 -52 -37 -91l-652 -651q-37 -37 -90 -37t-90 37l-76 75q-37 39 -37 91q0 53 37 90l486 486l-486 485q-37 39 -37 91q0 53 37 90l76 75q36 38 90 38t90 -38l652 -651q37 -37 37 -90z" />
<glyph unicode="&#xf055;" d="M1216 576v128q0 26 -19 45t-45 19h-256v256q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-256h-256q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h256v-256q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v256h256q26 0 45 19t19 45zM1536 640q0 -209 -103 -385.5 t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
<glyph unicode="&#xf056;" d="M1216 576v128q0 26 -19 45t-45 19h-768q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h768q26 0 45 19t19 45zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5 t103 -385.5z" />
<glyph unicode="&#xf057;" d="M1149 414q0 26 -19 45l-181 181l181 181q19 19 19 45q0 27 -19 46l-90 90q-19 19 -46 19q-26 0 -45 -19l-181 -181l-181 181q-19 19 -45 19q-27 0 -46 -19l-90 -90q-19 -19 -19 -46q0 -26 19 -45l181 -181l-181 -181q-19 -19 -19 -45q0 -27 19 -46l90 -90q19 -19 46 -19 q26 0 45 19l181 181l181 -181q19 -19 45 -19q27 0 46 19l90 90q19 19 19 46zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
<glyph unicode="&#xf058;" d="M1284 802q0 28 -18 46l-91 90q-19 19 -45 19t-45 -19l-408 -407l-226 226q-19 19 -45 19t-45 -19l-91 -90q-18 -18 -18 -46q0 -27 18 -45l362 -362q19 -19 45 -19q27 0 46 19l543 543q18 18 18 45zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
<glyph unicode="&#xf059;" d="M896 160v192q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h192q14 0 23 9t9 23zM1152 832q0 88 -55.5 163t-138.5 116t-170 41q-243 0 -371 -213q-15 -24 8 -42l132 -100q7 -6 19 -6q16 0 25 12q53 68 86 92q34 24 86 24q48 0 85.5 -26t37.5 -59 q0 -38 -20 -61t-68 -45q-63 -28 -115.5 -86.5t-52.5 -125.5v-36q0 -14 9 -23t23 -9h192q14 0 23 9t9 23q0 19 21.5 49.5t54.5 49.5q32 18 49 28.5t46 35t44.5 48t28 60.5t12.5 81zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
<glyph unicode="&#xf05a;" d="M1024 160v160q0 14 -9 23t-23 9h-96v512q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23t23 -9h96v-320h-96q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23t23 -9h448q14 0 23 9t9 23zM896 1056v160q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23 t23 -9h192q14 0 23 9t9 23zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
<glyph unicode="&#xf05b;" d="M1197 512h-109q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h109q-32 108 -112.5 188.5t-188.5 112.5v-109q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v109q-108 -32 -188.5 -112.5t-112.5 -188.5h109q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-109 q32 -108 112.5 -188.5t188.5 -112.5v109q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-109q108 32 188.5 112.5t112.5 188.5zM1536 704v-128q0 -26 -19 -45t-45 -19h-143q-37 -161 -154.5 -278.5t-278.5 -154.5v-143q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v143 q-161 37 -278.5 154.5t-154.5 278.5h-143q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h143q37 161 154.5 278.5t278.5 154.5v143q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-143q161 -37 278.5 -154.5t154.5 -278.5h143q26 0 45 -19t19 -45z" />
<glyph unicode="&#xf05c;" d="M1097 457l-146 -146q-10 -10 -23 -10t-23 10l-137 137l-137 -137q-10 -10 -23 -10t-23 10l-146 146q-10 10 -10 23t10 23l137 137l-137 137q-10 10 -10 23t10 23l146 146q10 10 23 10t23 -10l137 -137l137 137q10 10 23 10t23 -10l146 -146q10 -10 10 -23t-10 -23 l-137 -137l137 -137q10 -10 10 -23t-10 -23zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5 t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
<glyph unicode="&#xf05d;" d="M1171 723l-422 -422q-19 -19 -45 -19t-45 19l-294 294q-19 19 -19 45t19 45l102 102q19 19 45 19t45 -19l147 -147l275 275q19 19 45 19t45 -19l102 -102q19 -19 19 -45t-19 -45zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198 t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
<glyph unicode="&#xf05e;" d="M1312 643q0 161 -87 295l-754 -753q137 -89 297 -89q111 0 211.5 43.5t173.5 116.5t116 174.5t43 212.5zM313 344l755 754q-135 91 -300 91q-148 0 -273 -73t-198 -199t-73 -274q0 -162 89 -299zM1536 643q0 -157 -61 -300t-163.5 -246t-245 -164t-298.5 -61t-298.5 61 t-245 164t-163.5 246t-61 300t61 299.5t163.5 245.5t245 164t298.5 61t298.5 -61t245 -164t163.5 -245.5t61 -299.5z" />
<glyph unicode="&#xf060;" d="M1536 640v-128q0 -53 -32.5 -90.5t-84.5 -37.5h-704l293 -294q38 -36 38 -90t-38 -90l-75 -76q-37 -37 -90 -37q-52 0 -91 37l-651 652q-37 37 -37 90q0 52 37 91l651 650q38 38 91 38q52 0 90 -38l75 -74q38 -38 38 -91t-38 -91l-293 -293h704q52 0 84.5 -37.5 t32.5 -90.5z" />
<glyph unicode="&#xf061;" d="M1472 576q0 -54 -37 -91l-651 -651q-39 -37 -91 -37q-51 0 -90 37l-75 75q-38 38 -38 91t38 91l293 293h-704q-52 0 -84.5 37.5t-32.5 90.5v128q0 53 32.5 90.5t84.5 37.5h704l-293 294q-38 36 -38 90t38 90l75 75q38 38 90 38q53 0 91 -38l651 -651q37 -35 37 -90z" />
<glyph unicode="&#xf062;" horiz-adv-x="1664" d="M1611 565q0 -51 -37 -90l-75 -75q-38 -38 -91 -38q-54 0 -90 38l-294 293v-704q0 -52 -37.5 -84.5t-90.5 -32.5h-128q-53 0 -90.5 32.5t-37.5 84.5v704l-294 -293q-36 -38 -90 -38t-90 38l-75 75q-38 38 -38 90q0 53 38 91l651 651q35 37 90 37q54 0 91 -37l651 -651 q37 -39 37 -91z" />
<glyph unicode="&#xf063;" horiz-adv-x="1664" d="M1611 704q0 -53 -37 -90l-651 -652q-39 -37 -91 -37q-53 0 -90 37l-651 652q-38 36 -38 90q0 53 38 91l74 75q39 37 91 37q53 0 90 -37l294 -294v704q0 52 38 90t90 38h128q52 0 90 -38t38 -90v-704l294 294q37 37 90 37q52 0 91 -37l75 -75q37 -39 37 -91z" />
<glyph unicode="&#xf064;" horiz-adv-x="1792" d="M1792 896q0 -26 -19 -45l-512 -512q-19 -19 -45 -19t-45 19t-19 45v256h-224q-98 0 -175.5 -6t-154 -21.5t-133 -42.5t-105.5 -69.5t-80 -101t-48.5 -138.5t-17.5 -181q0 -55 5 -123q0 -6 2.5 -23.5t2.5 -26.5q0 -15 -8.5 -25t-23.5 -10q-16 0 -28 17q-7 9 -13 22 t-13.5 30t-10.5 24q-127 285 -127 451q0 199 53 333q162 403 875 403h224v256q0 26 19 45t45 19t45 -19l512 -512q19 -19 19 -45z" />
<glyph unicode="&#xf065;" d="M755 480q0 -13 -10 -23l-332 -332l144 -144q19 -19 19 -45t-19 -45t-45 -19h-448q-26 0 -45 19t-19 45v448q0 26 19 45t45 19t45 -19l144 -144l332 332q10 10 23 10t23 -10l114 -114q10 -10 10 -23zM1536 1344v-448q0 -26 -19 -45t-45 -19t-45 19l-144 144l-332 -332 q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l332 332l-144 144q-19 19 -19 45t19 45t45 19h448q26 0 45 -19t19 -45z" />
<glyph unicode="&#xf066;" d="M768 576v-448q0 -26 -19 -45t-45 -19t-45 19l-144 144l-332 -332q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l332 332l-144 144q-19 19 -19 45t19 45t45 19h448q26 0 45 -19t19 -45zM1523 1248q0 -13 -10 -23l-332 -332l144 -144q19 -19 19 -45t-19 -45 t-45 -19h-448q-26 0 -45 19t-19 45v448q0 26 19 45t45 19t45 -19l144 -144l332 332q10 10 23 10t23 -10l114 -114q10 -10 10 -23z" />
<glyph unicode="&#xf067;" horiz-adv-x="1408" d="M1408 800v-192q0 -40 -28 -68t-68 -28h-416v-416q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v416h-416q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h416v416q0 40 28 68t68 28h192q40 0 68 -28t28 -68v-416h416q40 0 68 -28t28 -68z" />
<glyph unicode="&#xf068;" horiz-adv-x="1408" d="M1408 800v-192q0 -40 -28 -68t-68 -28h-1216q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h1216q40 0 68 -28t28 -68z" />
<glyph unicode="&#xf069;" horiz-adv-x="1664" d="M1482 486q46 -26 59.5 -77.5t-12.5 -97.5l-64 -110q-26 -46 -77.5 -59.5t-97.5 12.5l-266 153v-307q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v307l-266 -153q-46 -26 -97.5 -12.5t-77.5 59.5l-64 110q-26 46 -12.5 97.5t59.5 77.5l266 154l-266 154 q-46 26 -59.5 77.5t12.5 97.5l64 110q26 46 77.5 59.5t97.5 -12.5l266 -153v307q0 52 38 90t90 38h128q52 0 90 -38t38 -90v-307l266 153q46 26 97.5 12.5t77.5 -59.5l64 -110q26 -46 12.5 -97.5t-59.5 -77.5l-266 -154z" />
<glyph unicode="&#xf06a;" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM896 161v190q0 14 -9 23.5t-22 9.5h-192q-13 0 -23 -10t-10 -23v-190q0 -13 10 -23t23 -10h192 q13 0 22 9.5t9 23.5zM894 505l18 621q0 12 -10 18q-10 8 -24 8h-220q-14 0 -24 -8q-10 -6 -10 -18l17 -621q0 -10 10 -17.5t24 -7.5h185q14 0 23.5 7.5t10.5 17.5z" />
<glyph unicode="&#xf06b;" d="M928 180v56v468v192h-320v-192v-468v-56q0 -25 18 -38.5t46 -13.5h192q28 0 46 13.5t18 38.5zM472 1024h195l-126 161q-26 31 -69 31q-40 0 -68 -28t-28 -68t28 -68t68 -28zM1160 1120q0 40 -28 68t-68 28q-43 0 -69 -31l-125 -161h194q40 0 68 28t28 68zM1536 864v-320 q0 -14 -9 -23t-23 -9h-96v-416q0 -40 -28 -68t-68 -28h-1088q-40 0 -68 28t-28 68v416h-96q-14 0 -23 9t-9 23v320q0 14 9 23t23 9h440q-93 0 -158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5q107 0 168 -77l128 -165l128 165q61 77 168 77q93 0 158.5 -65.5t65.5 -158.5 t-65.5 -158.5t-158.5 -65.5h440q14 0 23 -9t9 -23z" />
<glyph unicode="&#xf06c;" horiz-adv-x="1792" d="M1280 832q0 26 -19 45t-45 19q-172 0 -318 -49.5t-259.5 -134t-235.5 -219.5q-19 -21 -19 -45q0 -26 19 -45t45 -19q24 0 45 19q27 24 74 71t67 66q137 124 268.5 176t313.5 52q26 0 45 19t19 45zM1792 1030q0 -95 -20 -193q-46 -224 -184.5 -383t-357.5 -268 q-214 -108 -438 -108q-148 0 -286 47q-15 5 -88 42t-96 37q-16 0 -39.5 -32t-45 -70t-52.5 -70t-60 -32q-30 0 -51 11t-31 24t-27 42q-2 4 -6 11t-5.5 10t-3 9.5t-1.5 13.5q0 35 31 73.5t68 65.5t68 56t31 48q0 4 -14 38t-16 44q-9 51 -9 104q0 115 43.5 220t119 184.5 t170.5 139t204 95.5q55 18 145 25.5t179.5 9t178.5 6t163.5 24t113.5 56.5l29.5 29.5t29.5 28t27 20t36.5 16t43.5 4.5q39 0 70.5 -46t47.5 -112t24 -124t8 -96z" />
<glyph unicode="&#xf06d;" horiz-adv-x="1408" d="M1408 -160v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5zM1152 896q0 -78 -24.5 -144t-64 -112.5t-87.5 -88t-96 -77.5t-87.5 -72t-64 -81.5t-24.5 -96.5q0 -96 67 -224l-4 1l1 -1 q-90 41 -160 83t-138.5 100t-113.5 122.5t-72.5 150.5t-27.5 184q0 78 24.5 144t64 112.5t87.5 88t96 77.5t87.5 72t64 81.5t24.5 96.5q0 94 -66 224l3 -1l-1 1q90 -41 160 -83t138.5 -100t113.5 -122.5t72.5 -150.5t27.5 -184z" />
<glyph unicode="&#xf06e;" horiz-adv-x="1792" d="M1664 576q-152 236 -381 353q61 -104 61 -225q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5q0 121 61 225q-229 -117 -381 -353q133 -205 333.5 -326.5t434.5 -121.5t434.5 121.5t333.5 326.5zM944 960q0 20 -14 34t-34 14q-125 0 -214.5 -89.5 t-89.5 -214.5q0 -20 14 -34t34 -14t34 14t14 34q0 86 61 147t147 61q20 0 34 14t14 34zM1792 576q0 -34 -20 -69q-140 -230 -376.5 -368.5t-499.5 -138.5t-499.5 139t-376.5 368q-20 35 -20 69t20 69q140 229 376.5 368t499.5 139t499.5 -139t376.5 -368q20 -35 20 -69z" />
<glyph unicode="&#xf070;" horiz-adv-x="1792" d="M555 201l78 141q-87 63 -136 159t-49 203q0 121 61 225q-229 -117 -381 -353q167 -258 427 -375zM944 960q0 20 -14 34t-34 14q-125 0 -214.5 -89.5t-89.5 -214.5q0 -20 14 -34t34 -14t34 14t14 34q0 86 61 147t147 61q20 0 34 14t14 34zM1307 1151q0 -7 -1 -9 q-105 -188 -315 -566t-316 -567l-49 -89q-10 -16 -28 -16q-12 0 -134 70q-16 10 -16 28q0 12 44 87q-143 65 -263.5 173t-208.5 245q-20 31 -20 69t20 69q153 235 380 371t496 136q89 0 180 -17l54 97q10 16 28 16q5 0 18 -6t31 -15.5t33 -18.5t31.5 -18.5t19.5 -11.5 q16 -10 16 -27zM1344 704q0 -139 -79 -253.5t-209 -164.5l280 502q8 -45 8 -84zM1792 576q0 -35 -20 -69q-39 -64 -109 -145q-150 -172 -347.5 -267t-419.5 -95l74 132q212 18 392.5 137t301.5 307q-115 179 -282 294l63 112q95 -64 182.5 -153t144.5 -184q20 -34 20 -69z " />
<glyph unicode="&#xf071;" horiz-adv-x="1792" d="M1024 161v190q0 14 -9.5 23.5t-22.5 9.5h-192q-13 0 -22.5 -9.5t-9.5 -23.5v-190q0 -14 9.5 -23.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 23.5zM1022 535l18 459q0 12 -10 19q-13 11 -24 11h-220q-11 0 -24 -11q-10 -7 -10 -21l17 -457q0 -10 10 -16.5t24 -6.5h185 q14 0 23.5 6.5t10.5 16.5zM1008 1469l768 -1408q35 -63 -2 -126q-17 -29 -46.5 -46t-63.5 -17h-1536q-34 0 -63.5 17t-46.5 46q-37 63 -2 126l768 1408q17 31 47 49t65 18t65 -18t47 -49z" />
<glyph unicode="&#xf072;" horiz-adv-x="1408" d="M1376 1376q44 -52 12 -148t-108 -172l-161 -161l160 -696q5 -19 -12 -33l-128 -96q-7 -6 -19 -6q-4 0 -7 1q-15 3 -21 16l-279 508l-259 -259l53 -194q5 -17 -8 -31l-96 -96q-9 -9 -23 -9h-2q-15 2 -24 13l-189 252l-252 189q-11 7 -13 23q-1 13 9 25l96 97q9 9 23 9 q6 0 8 -1l194 -53l259 259l-508 279q-14 8 -17 24q-2 16 9 27l128 128q14 13 30 8l665 -159l160 160q76 76 172 108t148 -12z" />
<glyph unicode="&#xf073;" horiz-adv-x="1664" d="M128 -128h288v288h-288v-288zM480 -128h320v288h-320v-288zM128 224h288v320h-288v-320zM480 224h320v320h-320v-320zM128 608h288v288h-288v-288zM864 -128h320v288h-320v-288zM480 608h320v288h-320v-288zM1248 -128h288v288h-288v-288zM864 224h320v320h-320v-320z M512 1088v288q0 13 -9.5 22.5t-22.5 9.5h-64q-13 0 -22.5 -9.5t-9.5 -22.5v-288q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5zM1248 224h288v320h-288v-320zM864 608h320v288h-320v-288zM1248 608h288v288h-288v-288zM1280 1088v288q0 13 -9.5 22.5t-22.5 9.5h-64 q-13 0 -22.5 -9.5t-9.5 -22.5v-288q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5zM1664 1152v-1280q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47 h64q66 0 113 -47t47 -113v-96h128q52 0 90 -38t38 -90z" />
<glyph unicode="&#xf074;" horiz-adv-x="1792" d="M666 1055q-60 -92 -137 -273q-22 45 -37 72.5t-40.5 63.5t-51 56.5t-63 35t-81.5 14.5h-224q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h224q250 0 410 -225zM1792 256q0 -14 -9 -23l-320 -320q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5v192q-32 0 -85 -0.5t-81 -1t-73 1 t-71 5t-64 10.5t-63 18.5t-58 28.5t-59 40t-55 53.5t-56 69.5q59 93 136 273q22 -45 37 -72.5t40.5 -63.5t51 -56.5t63 -35t81.5 -14.5h256v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23zM1792 1152q0 -14 -9 -23l-320 -320q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5 v192h-256q-48 0 -87 -15t-69 -45t-51 -61.5t-45 -77.5q-32 -62 -78 -171q-29 -66 -49.5 -111t-54 -105t-64 -100t-74 -83t-90 -68.5t-106.5 -42t-128 -16.5h-224q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h224q48 0 87 15t69 45t51 61.5t45 77.5q32 62 78 171q29 66 49.5 111 t54 105t64 100t74 83t90 68.5t106.5 42t128 16.5h256v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23z" />
<glyph unicode="&#xf075;" horiz-adv-x="1792" d="M1792 640q0 -174 -120 -321.5t-326 -233t-450 -85.5q-70 0 -145 8q-198 -175 -460 -242q-49 -14 -114 -22q-17 -2 -30.5 9t-17.5 29v1q-3 4 -0.5 12t2 10t4.5 9.5l6 9t7 8.5t8 9q7 8 31 34.5t34.5 38t31 39.5t32.5 51t27 59t26 76q-157 89 -247.5 220t-90.5 281 q0 130 71 248.5t191 204.5t286 136.5t348 50.5q244 0 450 -85.5t326 -233t120 -321.5z" />
<glyph unicode="&#xf076;" d="M1536 704v-128q0 -201 -98.5 -362t-274 -251.5t-395.5 -90.5t-395.5 90.5t-274 251.5t-98.5 362v128q0 26 19 45t45 19h384q26 0 45 -19t19 -45v-128q0 -52 23.5 -90t53.5 -57t71 -30t64 -13t44 -2t44 2t64 13t71 30t53.5 57t23.5 90v128q0 26 19 45t45 19h384 q26 0 45 -19t19 -45zM512 1344v-384q0 -26 -19 -45t-45 -19h-384q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h384q26 0 45 -19t19 -45zM1536 1344v-384q0 -26 -19 -45t-45 -19h-384q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h384q26 0 45 -19t19 -45z" />
<glyph unicode="&#xf077;" horiz-adv-x="1664" d="M1611 320q0 -53 -37 -90l-75 -75q-38 -38 -91 -38q-54 0 -90 38l-486 485l-486 -485q-36 -38 -90 -38t-90 38l-75 75q-38 36 -38 90q0 53 38 91l651 651q37 37 90 37q52 0 91 -37l650 -651q38 -38 38 -91z" />
<glyph unicode="&#xf078;" horiz-adv-x="1664" d="M1611 832q0 -53 -37 -90l-651 -651q-38 -38 -91 -38q-54 0 -90 38l-651 651q-38 36 -38 90q0 53 38 91l74 75q39 37 91 37q53 0 90 -37l486 -486l486 486q37 37 90 37q52 0 91 -37l75 -75q37 -39 37 -91z" />
<glyph unicode="&#xf079;" horiz-adv-x="1920" d="M1280 32q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-8 0 -13.5 2t-9 7t-5.5 8t-3 11.5t-1 11.5v13v11v160v416h-192q-26 0 -45 19t-19 45q0 24 15 41l320 384q19 22 49 22t49 -22l320 -384q15 -17 15 -41q0 -26 -19 -45t-45 -19h-192v-384h576q16 0 25 -11l160 -192q7 -11 7 -21 zM1920 448q0 -24 -15 -41l-320 -384q-20 -23 -49 -23t-49 23l-320 384q-15 17 -15 41q0 26 19 45t45 19h192v384h-576q-16 0 -25 12l-160 192q-7 9 -7 20q0 13 9.5 22.5t22.5 9.5h960q8 0 13.5 -2t9 -7t5.5 -8t3 -11.5t1 -11.5v-13v-11v-160v-416h192q26 0 45 -19t19 -45z " />
<glyph unicode="&#xf07a;" horiz-adv-x="1664" d="M640 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1536 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1664 1088v-512q0 -24 -16 -42.5t-41 -21.5 l-1044 -122q1 -7 4.5 -21.5t6 -26.5t2.5 -22q0 -16 -24 -64h920q26 0 45 -19t19 -45t-19 -45t-45 -19h-1024q-26 0 -45 19t-19 45q0 14 11 39.5t29.5 59.5t20.5 38l-177 823h-204q-26 0 -45 19t-19 45t19 45t45 19h256q16 0 28.5 -6.5t20 -15.5t13 -24.5t7.5 -26.5 t5.5 -29.5t4.5 -25.5h1201q26 0 45 -19t19 -45z" />
<glyph unicode="&#xf07b;" horiz-adv-x="1664" d="M1664 928v-704q0 -92 -66 -158t-158 -66h-1216q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h672q92 0 158 -66t66 -158z" />
<glyph unicode="&#xf07c;" horiz-adv-x="1920" d="M1879 584q0 -31 -31 -66l-336 -396q-43 -51 -120.5 -86.5t-143.5 -35.5h-1088q-34 0 -60.5 13t-26.5 43q0 31 31 66l336 396q43 51 120.5 86.5t143.5 35.5h1088q34 0 60.5 -13t26.5 -43zM1536 928v-160h-832q-94 0 -197 -47.5t-164 -119.5l-337 -396l-5 -6q0 4 -0.5 12.5 t-0.5 12.5v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h544q92 0 158 -66t66 -158z" />
<glyph unicode="&#xf07d;" horiz-adv-x="768" d="M704 1216q0 -26 -19 -45t-45 -19h-128v-1024h128q26 0 45 -19t19 -45t-19 -45l-256 -256q-19 -19 -45 -19t-45 19l-256 256q-19 19 -19 45t19 45t45 19h128v1024h-128q-26 0 -45 19t-19 45t19 45l256 256q19 19 45 19t45 -19l256 -256q19 -19 19 -45z" />
<glyph unicode="&#xf07e;" horiz-adv-x="1792" d="M1792 640q0 -26 -19 -45l-256 -256q-19 -19 -45 -19t-45 19t-19 45v128h-1024v-128q0 -26 -19 -45t-45 -19t-45 19l-256 256q-19 19 -19 45t19 45l256 256q19 19 45 19t45 -19t19 -45v-128h1024v128q0 26 19 45t45 19t45 -19l256 -256q19 -19 19 -45z" />
<glyph unicode="&#xf080;" horiz-adv-x="1920" d="M512 512v-384h-256v384h256zM896 1024v-896h-256v896h256zM1280 768v-640h-256v640h256zM1664 1152v-1024h-256v1024h256zM1792 32v1216q0 13 -9.5 22.5t-22.5 9.5h-1600q-13 0 -22.5 -9.5t-9.5 -22.5v-1216q0 -13 9.5 -22.5t22.5 -9.5h1600q13 0 22.5 9.5t9.5 22.5z M1920 1248v-1216q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" />
<glyph unicode="&#xf081;" d="M1280 926q-56 -25 -121 -34q68 40 93 117q-65 -38 -134 -51q-61 66 -153 66q-87 0 -148.5 -61.5t-61.5 -148.5q0 -29 5 -48q-129 7 -242 65t-192 155q-29 -50 -29 -106q0 -114 91 -175q-47 1 -100 26v-2q0 -75 50 -133.5t123 -72.5q-29 -8 -51 -8q-13 0 -39 4 q21 -63 74.5 -104t121.5 -42q-116 -90 -261 -90q-26 0 -50 3q148 -94 322 -94q112 0 210 35.5t168 95t120.5 137t75 162t24.5 168.5q0 18 -1 27q63 45 105 109zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5 t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
<glyph unicode="&#xf082;" d="M1307 618l23 219h-198v109q0 49 15.5 68.5t71.5 19.5h110v219h-175q-152 0 -218 -72t-66 -213v-131h-131v-219h131v-635h262v635h175zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960 q119 0 203.5 -84.5t84.5 -203.5z" />
<glyph unicode="&#xf083;" horiz-adv-x="1792" d="M928 704q0 14 -9 23t-23 9q-66 0 -113 -47t-47 -113q0 -14 9 -23t23 -9t23 9t9 23q0 40 28 68t68 28q14 0 23 9t9 23zM1152 574q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181zM128 0h1536v128h-1536v-128zM1280 574q0 159 -112.5 271.5 t-271.5 112.5t-271.5 -112.5t-112.5 -271.5t112.5 -271.5t271.5 -112.5t271.5 112.5t112.5 271.5zM256 1216h384v128h-384v-128zM128 1024h1536v118v138h-828l-64 -128h-644v-128zM1792 1280v-1280q0 -53 -37.5 -90.5t-90.5 -37.5h-1536q-53 0 -90.5 37.5t-37.5 90.5v1280 q0 53 37.5 90.5t90.5 37.5h1536q53 0 90.5 -37.5t37.5 -90.5z" />
<glyph unicode="&#xf084;" horiz-adv-x="1792" d="M832 1024q0 80 -56 136t-136 56t-136 -56t-56 -136q0 -42 19 -83q-41 19 -83 19q-80 0 -136 -56t-56 -136t56 -136t136 -56t136 56t56 136q0 42 -19 83q41 -19 83 -19q80 0 136 56t56 136zM1683 320q0 -17 -49 -66t-66 -49q-9 0 -28.5 16t-36.5 33t-38.5 40t-24.5 26 l-96 -96l220 -220q28 -28 28 -68q0 -42 -39 -81t-81 -39q-40 0 -68 28l-671 671q-176 -131 -365 -131q-163 0 -265.5 102.5t-102.5 265.5q0 160 95 313t248 248t313 95q163 0 265.5 -102.5t102.5 -265.5q0 -189 -131 -365l355 -355l96 96q-3 3 -26 24.5t-40 38.5t-33 36.5 t-16 28.5q0 17 49 66t66 49q13 0 23 -10q6 -6 46 -44.5t82 -79.5t86.5 -86t73 -78t28.5 -41z" />
<glyph unicode="&#xf085;" horiz-adv-x="1920" d="M896 640q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1664 128q0 52 -38 90t-90 38t-90 -38t-38 -90q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1664 1152q0 52 -38 90t-90 38t-90 -38t-38 -90q0 -53 37.5 -90.5t90.5 -37.5 t90.5 37.5t37.5 90.5zM1280 731v-185q0 -10 -7 -19.5t-16 -10.5l-155 -24q-11 -35 -32 -76q34 -48 90 -115q7 -10 7 -20q0 -12 -7 -19q-23 -30 -82.5 -89.5t-78.5 -59.5q-11 0 -21 7l-115 90q-37 -19 -77 -31q-11 -108 -23 -155q-7 -24 -30 -24h-186q-11 0 -20 7.5t-10 17.5 l-23 153q-34 10 -75 31l-118 -89q-7 -7 -20 -7q-11 0 -21 8q-144 133 -144 160q0 9 7 19q10 14 41 53t47 61q-23 44 -35 82l-152 24q-10 1 -17 9.5t-7 19.5v185q0 10 7 19.5t16 10.5l155 24q11 35 32 76q-34 48 -90 115q-7 11 -7 20q0 12 7 20q22 30 82 89t79 59q11 0 21 -7 l115 -90q34 18 77 32q11 108 23 154q7 24 30 24h186q11 0 20 -7.5t10 -17.5l23 -153q34 -10 75 -31l118 89q8 7 20 7q11 0 21 -8q144 -133 144 -160q0 -9 -7 -19q-12 -16 -42 -54t-45 -60q23 -48 34 -82l152 -23q10 -2 17 -10.5t7 -19.5zM1920 198v-140q0 -16 -149 -31 q-12 -27 -30 -52q51 -113 51 -138q0 -4 -4 -7q-122 -71 -124 -71q-8 0 -46 47t-52 68q-20 -2 -30 -2t-30 2q-14 -21 -52 -68t-46 -47q-2 0 -124 71q-4 3 -4 7q0 25 51 138q-18 25 -30 52q-149 15 -149 31v140q0 16 149 31q13 29 30 52q-51 113 -51 138q0 4 4 7q4 2 35 20 t59 34t30 16q8 0 46 -46.5t52 -67.5q20 2 30 2t30 -2q51 71 92 112l6 2q4 0 124 -70q4 -3 4 -7q0 -25 -51 -138q17 -23 30 -52q149 -15 149 -31zM1920 1222v-140q0 -16 -149 -31q-12 -27 -30 -52q51 -113 51 -138q0 -4 -4 -7q-122 -71 -124 -71q-8 0 -46 47t-52 68 q-20 -2 -30 -2t-30 2q-14 -21 -52 -68t-46 -47q-2 0 -124 71q-4 3 -4 7q0 25 51 138q-18 25 -30 52q-149 15 -149 31v140q0 16 149 31q13 29 30 52q-51 113 -51 138q0 4 4 7q4 2 35 20t59 34t30 16q8 0 46 -46.5t52 -67.5q20 2 30 2t30 -2q51 71 92 112l6 2q4 0 124 -70 q4 -3 4 -7q0 -25 -51 -138q17 -23 30 -52q149 -15 149 -31z" />
<glyph unicode="&#xf086;" horiz-adv-x="1792" d="M1408 768q0 -139 -94 -257t-256.5 -186.5t-353.5 -68.5q-86 0 -176 16q-124 -88 -278 -128q-36 -9 -86 -16h-3q-11 0 -20.5 8t-11.5 21q-1 3 -1 6.5t0.5 6.5t2 6l2.5 5t3.5 5.5t4 5t4.5 5t4 4.5q5 6 23 25t26 29.5t22.5 29t25 38.5t20.5 44q-124 72 -195 177t-71 224 q0 139 94 257t256.5 186.5t353.5 68.5t353.5 -68.5t256.5 -186.5t94 -257zM1792 512q0 -120 -71 -224.5t-195 -176.5q10 -24 20.5 -44t25 -38.5t22.5 -29t26 -29.5t23 -25q1 -1 4 -4.5t4.5 -5t4 -5t3.5 -5.5l2.5 -5t2 -6t0.5 -6.5t-1 -6.5q-3 -14 -13 -22t-22 -7 q-50 7 -86 16q-154 40 -278 128q-90 -16 -176 -16q-271 0 -472 132q58 -4 88 -4q161 0 309 45t264 129q125 92 192 212t67 254q0 77 -23 152q129 -71 204 -178t75 -230z" />
<glyph unicode="&#xf087;" d="M256 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 768q0 51 -39 89.5t-89 38.5h-352q0 58 48 159.5t48 160.5q0 98 -32 145t-128 47q-26 -26 -38 -85t-30.5 -125.5t-59.5 -109.5q-22 -23 -77 -91q-4 -5 -23 -30t-31.5 -41t-34.5 -42.5 t-40 -44t-38.5 -35.5t-40 -27t-35.5 -9h-32v-640h32q13 0 31.5 -3t33 -6.5t38 -11t35 -11.5t35.5 -12.5t29 -10.5q211 -73 342 -73h121q192 0 192 167q0 26 -5 56q30 16 47.5 52.5t17.5 73.5t-18 69q53 50 53 119q0 25 -10 55.5t-25 47.5q32 1 53.5 47t21.5 81zM1536 769 q0 -89 -49 -163q9 -33 9 -69q0 -77 -38 -144q3 -21 3 -43q0 -101 -60 -178q1 -139 -85 -219.5t-227 -80.5h-36h-93q-96 0 -189.5 22.5t-216.5 65.5q-116 40 -138 40h-288q-53 0 -90.5 37.5t-37.5 90.5v640q0 53 37.5 90.5t90.5 37.5h274q36 24 137 155q58 75 107 128 q24 25 35.5 85.5t30.5 126.5t62 108q39 37 90 37q84 0 151 -32.5t102 -101.5t35 -186q0 -93 -48 -192h176q104 0 180 -76t76 -179z" />
<glyph unicode="&#xf088;" d="M256 1088q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 512q0 35 -21.5 81t-53.5 47q15 17 25 47.5t10 55.5q0 69 -53 119q18 32 18 69t-17.5 73.5t-47.5 52.5q5 30 5 56q0 85 -49 126t-136 41h-128q-131 0 -342 -73q-5 -2 -29 -10.5 t-35.5 -12.5t-35 -11.5t-38 -11t-33 -6.5t-31.5 -3h-32v-640h32q16 0 35.5 -9t40 -27t38.5 -35.5t40 -44t34.5 -42.5t31.5 -41t23 -30q55 -68 77 -91q41 -43 59.5 -109.5t30.5 -125.5t38 -85q96 0 128 47t32 145q0 59 -48 160.5t-48 159.5h352q50 0 89 38.5t39 89.5z M1536 511q0 -103 -76 -179t-180 -76h-176q48 -99 48 -192q0 -118 -35 -186q-35 -69 -102 -101.5t-151 -32.5q-51 0 -90 37q-34 33 -54 82t-25.5 90.5t-17.5 84.5t-31 64q-48 50 -107 127q-101 131 -137 155h-274q-53 0 -90.5 37.5t-37.5 90.5v640q0 53 37.5 90.5t90.5 37.5 h288q22 0 138 40q128 44 223 66t200 22h112q140 0 226.5 -79t85.5 -216v-5q60 -77 60 -178q0 -22 -3 -43q38 -67 38 -144q0 -36 -9 -69q49 -74 49 -163z" />
<glyph unicode="&#xf089;" horiz-adv-x="896" d="M832 1504v-1339l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41z" />
<glyph unicode="&#xf08a;" horiz-adv-x="1792" d="M1664 940q0 81 -21.5 143t-55 98.5t-81.5 59.5t-94 31t-98 8t-112 -25.5t-110.5 -64t-86.5 -72t-60 -61.5q-18 -22 -49 -22t-49 22q-24 28 -60 61.5t-86.5 72t-110.5 64t-112 25.5t-98 -8t-94 -31t-81.5 -59.5t-55 -98.5t-21.5 -143q0 -168 187 -355l581 -560l580 559 q188 188 188 356zM1792 940q0 -221 -229 -450l-623 -600q-18 -18 -44 -18t-44 18l-624 602q-10 8 -27.5 26t-55.5 65.5t-68 97.5t-53.5 121t-23.5 138q0 220 127 344t351 124q62 0 126.5 -21.5t120 -58t95.5 -68.5t76 -68q36 36 76 68t95.5 68.5t120 58t126.5 21.5 q224 0 351 -124t127 -344z" />
<glyph unicode="&#xf08b;" horiz-adv-x="1664" d="M640 96q0 -4 1 -20t0.5 -26.5t-3 -23.5t-10 -19.5t-20.5 -6.5h-320q-119 0 -203.5 84.5t-84.5 203.5v704q0 119 84.5 203.5t203.5 84.5h320q13 0 22.5 -9.5t9.5 -22.5q0 -4 1 -20t0.5 -26.5t-3 -23.5t-10 -19.5t-20.5 -6.5h-320q-66 0 -113 -47t-47 -113v-704 q0 -66 47 -113t113 -47h288h11h13t11.5 -1t11.5 -3t8 -5.5t7 -9t2 -13.5zM1568 640q0 -26 -19 -45l-544 -544q-19 -19 -45 -19t-45 19t-19 45v288h-448q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h448v288q0 26 19 45t45 19t45 -19l544 -544q19 -19 19 -45z" />
<glyph unicode="&#xf08c;" d="M237 122h231v694h-231v-694zM483 1030q-1 52 -36 86t-93 34t-94.5 -34t-36.5 -86q0 -51 35.5 -85.5t92.5 -34.5h1q59 0 95 34.5t36 85.5zM1068 122h231v398q0 154 -73 233t-193 79q-136 0 -209 -117h2v101h-231q3 -66 0 -694h231v388q0 38 7 56q15 35 45 59.5t74 24.5 q116 0 116 -157v-371zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
<glyph unicode="&#xf08d;" horiz-adv-x="1152" d="M480 672v448q0 14 -9 23t-23 9t-23 -9t-9 -23v-448q0 -14 9 -23t23 -9t23 9t9 23zM1152 320q0 -26 -19 -45t-45 -19h-429l-51 -483q-2 -12 -10.5 -20.5t-20.5 -8.5h-1q-27 0 -32 27l-76 485h-404q-26 0 -45 19t-19 45q0 123 78.5 221.5t177.5 98.5v512q-52 0 -90 38 t-38 90t38 90t90 38h640q52 0 90 -38t38 -90t-38 -90t-90 -38v-512q99 0 177.5 -98.5t78.5 -221.5z" />
<glyph unicode="&#xf08e;" horiz-adv-x="1792" d="M1408 608v-320q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h704q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v320 q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1792 1472v-512q0 -26 -19 -45t-45 -19t-45 19l-176 176l-652 -652q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l652 652l-176 176q-19 19 -19 45t19 45t45 19h512q26 0 45 -19t19 -45z" />
<glyph unicode="&#xf090;" d="M1184 640q0 -26 -19 -45l-544 -544q-19 -19 -45 -19t-45 19t-19 45v288h-448q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h448v288q0 26 19 45t45 19t45 -19l544 -544q19 -19 19 -45zM1536 992v-704q0 -119 -84.5 -203.5t-203.5 -84.5h-320q-13 0 -22.5 9.5t-9.5 22.5 q0 4 -1 20t-0.5 26.5t3 23.5t10 19.5t20.5 6.5h320q66 0 113 47t47 113v704q0 66 -47 113t-113 47h-288h-11h-13t-11.5 1t-11.5 3t-8 5.5t-7 9t-2 13.5q0 4 -1 20t-0.5 26.5t3 23.5t10 19.5t20.5 6.5h320q119 0 203.5 -84.5t84.5 -203.5z" />
<glyph unicode="&#xf091;" horiz-adv-x="1664" d="M458 653q-74 162 -74 371h-256v-96q0 -78 94.5 -162t235.5 -113zM1536 928v96h-256q0 -209 -74 -371q141 29 235.5 113t94.5 162zM1664 1056v-128q0 -71 -41.5 -143t-112 -130t-173 -97.5t-215.5 -44.5q-42 -54 -95 -95q-38 -34 -52.5 -72.5t-14.5 -89.5q0 -54 30.5 -91 t97.5 -37q75 0 133.5 -45.5t58.5 -114.5v-64q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v64q0 69 58.5 114.5t133.5 45.5q67 0 97.5 37t30.5 91q0 51 -14.5 89.5t-52.5 72.5q-53 41 -95 95q-113 5 -215.5 44.5t-173 97.5t-112 130t-41.5 143v128q0 40 28 68t68 28h288v96 q0 66 47 113t113 47h576q66 0 113 -47t47 -113v-96h288q40 0 68 -28t28 -68z" />
<glyph unicode="&#xf092;" d="M394 184q-8 -9 -20 3q-13 11 -4 19q8 9 20 -3q12 -11 4 -19zM352 245q9 -12 0 -19q-8 -6 -17 7t0 18q9 7 17 -6zM291 305q-5 -7 -13 -2q-10 5 -7 12q3 5 13 2q10 -5 7 -12zM322 271q-6 -7 -16 3q-9 11 -2 16q6 6 16 -3q9 -11 2 -16zM451 159q-4 -12 -19 -6q-17 4 -13 15 t19 7q16 -5 13 -16zM514 154q0 -11 -16 -11q-17 -2 -17 11q0 11 16 11q17 2 17 -11zM572 164q2 -10 -14 -14t-18 8t14 15q16 2 18 -9zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-224q-16 0 -24.5 1t-19.5 5t-16 14.5t-5 27.5v239q0 97 -52 142q57 6 102.5 18t94 39 t81 66.5t53 105t20.5 150.5q0 121 -79 206q37 91 -8 204q-28 9 -81 -11t-92 -44l-38 -24q-93 26 -192 26t-192 -26q-16 11 -42.5 27t-83.5 38.5t-86 13.5q-44 -113 -7 -204q-79 -85 -79 -206q0 -85 20.5 -150t52.5 -105t80.5 -67t94 -39t102.5 -18q-40 -36 -49 -103 q-21 -10 -45 -15t-57 -5t-65.5 21.5t-55.5 62.5q-19 32 -48.5 52t-49.5 24l-20 3q-21 0 -29 -4.5t-5 -11.5t9 -14t13 -12l7 -5q22 -10 43.5 -38t31.5 -51l10 -23q13 -38 44 -61.5t67 -30t69.5 -7t55.5 3.5l23 4q0 -38 0.5 -103t0.5 -68q0 -22 -11 -33.5t-22 -13t-33 -1.5 h-224q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
<glyph unicode="&#xf093;" horiz-adv-x="1664" d="M1280 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 288v-320q0 -40 -28 -68t-68 -28h-1472q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h427q21 -56 70.5 -92 t110.5 -36h256q61 0 110.5 36t70.5 92h427q40 0 68 -28t28 -68zM1339 936q-17 -40 -59 -40h-256v-448q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v448h-256q-42 0 -59 40q-17 39 14 69l448 448q18 19 45 19t45 -19l448 -448q31 -30 14 -69z" />
<glyph unicode="&#xf094;" d="M1407 710q0 44 -7 113.5t-18 96.5q-12 30 -17 44t-9 36.5t-4 48.5q0 23 5 68.5t5 67.5q0 37 -10 55q-4 1 -13 1q-19 0 -58 -4.5t-59 -4.5q-60 0 -176 24t-175 24q-43 0 -94.5 -11.5t-85 -23.5t-89.5 -34q-137 -54 -202 -103q-96 -73 -159.5 -189.5t-88 -236t-24.5 -248.5 q0 -40 12.5 -120t12.5 -121q0 -23 -11 -66.5t-11 -65.5t12 -36.5t34 -14.5q24 0 72.5 11t73.5 11q57 0 169.5 -15.5t169.5 -15.5q181 0 284 36q129 45 235.5 152.5t166 245.5t59.5 275zM1535 712q0 -165 -70 -327.5t-196 -288t-281 -180.5q-124 -44 -326 -44 q-57 0 -170 14.5t-169 14.5q-24 0 -72.5 -14.5t-73.5 -14.5q-73 0 -123.5 55.5t-50.5 128.5q0 24 11 68t11 67q0 40 -12.5 120.5t-12.5 121.5q0 111 18 217.5t54.5 209.5t100.5 194t150 156q78 59 232 120q194 78 316 78q60 0 175.5 -24t173.5 -24q19 0 57 5t58 5 q81 0 118 -50.5t37 -134.5q0 -23 -5 -68t-5 -68q0 -10 1 -18.5t3 -17t4 -13.5t6.5 -16t6.5 -17q16 -40 25 -118.5t9 -136.5z" />
<glyph unicode="&#xf095;" horiz-adv-x="1408" d="M1408 296q0 -27 -10 -70.5t-21 -68.5q-21 -50 -122 -106q-94 -51 -186 -51q-27 0 -52.5 3.5t-57.5 12.5t-47.5 14.5t-55.5 20.5t-49 18q-98 35 -175 83q-128 79 -264.5 215.5t-215.5 264.5q-48 77 -83 175q-3 9 -18 49t-20.5 55.5t-14.5 47.5t-12.5 57.5t-3.5 52.5 q0 92 51 186q56 101 106 122q25 11 68.5 21t70.5 10q14 0 21 -3q18 -6 53 -76q11 -19 30 -54t35 -63.5t31 -53.5q3 -4 17.5 -25t21.5 -35.5t7 -28.5q0 -20 -28.5 -50t-62 -55t-62 -53t-28.5 -46q0 -9 5 -22.5t8.5 -20.5t14 -24t11.5 -19q76 -137 174 -235t235 -174 q2 -1 19 -11.5t24 -14t20.5 -8.5t22.5 -5q18 0 46 28.5t53 62t55 62t50 28.5q14 0 28.5 -7t35.5 -21.5t25 -17.5q25 -15 53.5 -31t63.5 -35t54 -30q70 -35 76 -53q3 -7 3 -21z" />
<glyph unicode="&#xf096;" horiz-adv-x="1408" d="M1120 1280h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v832q0 66 -47 113t-113 47zM1408 1120v-832q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832 q119 0 203.5 -84.5t84.5 -203.5z" />
<glyph unicode="&#xf097;" horiz-adv-x="1280" d="M1152 1280h-1024v-1242l423 406l89 85l89 -85l423 -406v1242zM1164 1408q23 0 44 -9q33 -13 52.5 -41t19.5 -62v-1289q0 -34 -19.5 -62t-52.5 -41q-19 -8 -44 -8q-48 0 -83 32l-441 424l-441 -424q-36 -33 -83 -33q-23 0 -44 9q-33 13 -52.5 41t-19.5 62v1289 q0 34 19.5 62t52.5 41q21 9 44 9h1048z" />
<glyph unicode="&#xf098;" d="M1280 343q0 11 -2 16q-3 8 -38.5 29.5t-88.5 49.5l-53 29q-5 3 -19 13t-25 15t-21 5q-18 0 -47 -32.5t-57 -65.5t-44 -33q-7 0 -16.5 3.5t-15.5 6.5t-17 9.5t-14 8.5q-99 55 -170.5 126.5t-126.5 170.5q-2 3 -8.5 14t-9.5 17t-6.5 15.5t-3.5 16.5q0 13 20.5 33.5t45 38.5 t45 39.5t20.5 36.5q0 10 -5 21t-15 25t-13 19q-3 6 -15 28.5t-25 45.5t-26.5 47.5t-25 40.5t-16.5 18t-16 2q-48 0 -101 -22q-46 -21 -80 -94.5t-34 -130.5q0 -16 2.5 -34t5 -30.5t9 -33t10 -29.5t12.5 -33t11 -30q60 -164 216.5 -320.5t320.5 -216.5q6 -2 30 -11t33 -12.5 t29.5 -10t33 -9t30.5 -5t34 -2.5q57 0 130.5 34t94.5 80q22 53 22 101zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
<glyph unicode="&#xf099;" horiz-adv-x="1664" d="M1620 1128q-67 -98 -162 -167q1 -14 1 -42q0 -130 -38 -259.5t-115.5 -248.5t-184.5 -210.5t-258 -146t-323 -54.5q-271 0 -496 145q35 -4 78 -4q225 0 401 138q-105 2 -188 64.5t-114 159.5q33 -5 61 -5q43 0 85 11q-112 23 -185.5 111.5t-73.5 205.5v4q68 -38 146 -41 q-66 44 -105 115t-39 154q0 88 44 163q121 -149 294.5 -238.5t371.5 -99.5q-8 38 -8 74q0 134 94.5 228.5t228.5 94.5q140 0 236 -102q109 21 205 78q-37 -115 -142 -178q93 10 186 50z" />
<glyph unicode="&#xf09a;" horiz-adv-x="768" d="M511 980h257l-30 -284h-227v-824h-341v824h-170v284h170v171q0 182 86 275.5t283 93.5h227v-284h-142q-39 0 -62.5 -6.5t-34 -23.5t-13.5 -34.5t-3 -49.5v-142z" />
<glyph unicode="&#xf09b;" d="M1536 640q0 -251 -146.5 -451.5t-378.5 -277.5q-27 -5 -39.5 7t-12.5 30v211q0 97 -52 142q57 6 102.5 18t94 39t81 66.5t53 105t20.5 150.5q0 121 -79 206q37 91 -8 204q-28 9 -81 -11t-92 -44l-38 -24q-93 26 -192 26t-192 -26q-16 11 -42.5 27t-83.5 38.5t-86 13.5 q-44 -113 -7 -204q-79 -85 -79 -206q0 -85 20.5 -150t52.5 -105t80.5 -67t94 -39t102.5 -18q-40 -36 -49 -103q-21 -10 -45 -15t-57 -5t-65.5 21.5t-55.5 62.5q-19 32 -48.5 52t-49.5 24l-20 3q-21 0 -29 -4.5t-5 -11.5t9 -14t13 -12l7 -5q22 -10 43.5 -38t31.5 -51l10 -23 q13 -38 44 -61.5t67 -30t69.5 -7t55.5 3.5l23 4q0 -38 0.5 -89t0.5 -54q0 -18 -13 -30t-40 -7q-232 77 -378.5 277.5t-146.5 451.5q0 209 103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
<glyph unicode="&#xf09c;" horiz-adv-x="1664" d="M1664 960v-256q0 -26 -19 -45t-45 -19h-64q-26 0 -45 19t-19 45v256q0 106 -75 181t-181 75t-181 -75t-75 -181v-192h96q40 0 68 -28t28 -68v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h672v192q0 185 131.5 316.5t316.5 131.5 t316.5 -131.5t131.5 -316.5z" />
<glyph unicode="&#xf09d;" horiz-adv-x="1920" d="M1760 1408q66 0 113 -47t47 -113v-1216q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1600zM160 1280q-13 0 -22.5 -9.5t-9.5 -22.5v-224h1664v224q0 13 -9.5 22.5t-22.5 9.5h-1600zM1760 0q13 0 22.5 9.5t9.5 22.5v608h-1664v-608 q0 -13 9.5 -22.5t22.5 -9.5h1600zM256 128v128h256v-128h-256zM640 128v128h384v-128h-384z" />
<glyph unicode="&#xf09e;" horiz-adv-x="1408" d="M384 192q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM896 69q2 -28 -17 -48q-18 -21 -47 -21h-135q-25 0 -43 16.5t-20 41.5q-22 229 -184.5 391.5t-391.5 184.5q-25 2 -41.5 20t-16.5 43v135q0 29 21 47q17 17 43 17h5q160 -13 306 -80.5 t259 -181.5q114 -113 181.5 -259t80.5 -306zM1408 67q2 -27 -18 -47q-18 -20 -46 -20h-143q-26 0 -44.5 17.5t-19.5 42.5q-12 215 -101 408.5t-231.5 336t-336 231.5t-408.5 102q-25 1 -42.5 19.5t-17.5 43.5v143q0 28 20 46q18 18 44 18h3q262 -13 501.5 -120t425.5 -294 q187 -186 294 -425.5t120 -501.5z" />
<glyph unicode="&#xf0a0;" d="M1040 320q0 -33 -23.5 -56.5t-56.5 -23.5t-56.5 23.5t-23.5 56.5t23.5 56.5t56.5 23.5t56.5 -23.5t23.5 -56.5zM1296 320q0 -33 -23.5 -56.5t-56.5 -23.5t-56.5 23.5t-23.5 56.5t23.5 56.5t56.5 23.5t56.5 -23.5t23.5 -56.5zM1408 160v320q0 13 -9.5 22.5t-22.5 9.5 h-1216q-13 0 -22.5 -9.5t-9.5 -22.5v-320q0 -13 9.5 -22.5t22.5 -9.5h1216q13 0 22.5 9.5t9.5 22.5zM178 640h1180l-157 482q-4 13 -16 21.5t-26 8.5h-782q-14 0 -26 -8.5t-16 -21.5zM1536 480v-320q0 -66 -47 -113t-113 -47h-1216q-66 0 -113 47t-47 113v320q0 25 16 75 l197 606q17 53 63 86t101 33h782q55 0 101 -33t63 -86l197 -606q16 -50 16 -75z" />
<glyph unicode="&#xf0a1;" horiz-adv-x="1792" d="M1664 896q53 0 90.5 -37.5t37.5 -90.5t-37.5 -90.5t-90.5 -37.5v-384q0 -52 -38 -90t-90 -38q-417 347 -812 380q-58 -19 -91 -66t-31 -100.5t40 -92.5q-20 -33 -23 -65.5t6 -58t33.5 -55t48 -50t61.5 -50.5q-29 -58 -111.5 -83t-168.5 -11.5t-132 55.5q-7 23 -29.5 87.5 t-32 94.5t-23 89t-15 101t3.5 98.5t22 110.5h-122q-66 0 -113 47t-47 113v192q0 66 47 113t113 47h480q435 0 896 384q52 0 90 -38t38 -90v-384zM1536 292v954q-394 -302 -768 -343v-270q377 -42 768 -341z" />
<glyph unicode="&#xf0a2;" horiz-adv-x="1664" d="M848 -160q0 16 -16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5q16 0 16 16zM183 128h1298q-164 181 -246.5 411.5t-82.5 484.5q0 256 -320 256t-320 -256q0 -254 -82.5 -484.5t-246.5 -411.5zM1664 128q0 -52 -38 -90t-90 -38 h-448q0 -106 -75 -181t-181 -75t-181 75t-75 181h-448q-52 0 -90 38t-38 90q190 161 287 397.5t97 498.5q0 165 96 262t264 117q-8 18 -8 37q0 40 28 68t68 28t68 -28t28 -68q0 -19 -8 -37q168 -20 264 -117t96 -262q0 -262 97 -498.5t287 -397.5z" />
<glyph unicode="&#xf0a3;" d="M1376 640l138 -135q30 -28 20 -70q-12 -41 -52 -51l-188 -48l53 -186q12 -41 -19 -70q-29 -31 -70 -19l-186 53l-48 -188q-10 -40 -51 -52q-12 -2 -19 -2q-31 0 -51 22l-135 138l-135 -138q-28 -30 -70 -20q-41 11 -51 52l-48 188l-186 -53q-41 -12 -70 19q-31 29 -19 70 l53 186l-188 48q-40 10 -52 51q-10 42 20 70l138 135l-138 135q-30 28 -20 70q12 41 52 51l188 48l-53 186q-12 41 19 70q29 31 70 19l186 -53l48 188q10 41 51 51q41 12 70 -19l135 -139l135 139q29 30 70 19q41 -10 51 -51l48 -188l186 53q41 12 70 -19q31 -29 19 -70 l-53 -186l188 -48q40 -10 52 -51q10 -42 -20 -70z" />
<glyph unicode="&#xf0a4;" horiz-adv-x="1792" d="M256 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 768q0 51 -39 89.5t-89 38.5h-576q0 20 15 48.5t33 55t33 68t15 84.5q0 67 -44.5 97.5t-115.5 30.5q-24 0 -90 -139q-24 -44 -37 -65q-40 -64 -112 -145q-71 -81 -101 -106 q-69 -57 -140 -57h-32v-640h32q72 0 167 -32t193.5 -64t179.5 -32q189 0 189 167q0 26 -5 56q30 16 47.5 52.5t17.5 73.5t-18 69q53 50 53 119q0 25 -10 55.5t-25 47.5h331q52 0 90 38t38 90zM1792 769q0 -105 -75.5 -181t-180.5 -76h-169q-4 -62 -37 -119q3 -21 3 -43 q0 -101 -60 -178q1 -139 -85 -219.5t-227 -80.5q-133 0 -322 69q-164 59 -223 59h-288q-53 0 -90.5 37.5t-37.5 90.5v640q0 53 37.5 90.5t90.5 37.5h288q10 0 21.5 4.5t23.5 14t22.5 18t24 22.5t20.5 21.5t19 21.5t14 17q65 74 100 129q13 21 33 62t37 72t40.5 63t55 49.5 t69.5 17.5q125 0 206.5 -67t81.5 -189q0 -68 -22 -128h374q104 0 180 -76t76 -179z" />
<glyph unicode="&#xf0a5;" horiz-adv-x="1792" d="M1376 128h32v640h-32q-35 0 -67.5 12t-62.5 37t-50 46t-49 54q-2 3 -3.5 4.5t-4 4.5t-4.5 5q-72 81 -112 145q-14 22 -38 68q-1 3 -10.5 22.5t-18.5 36t-20 35.5t-21.5 30.5t-18.5 11.5q-71 0 -115.5 -30.5t-44.5 -97.5q0 -43 15 -84.5t33 -68t33 -55t15 -48.5h-576 q-50 0 -89 -38.5t-39 -89.5q0 -52 38 -90t90 -38h331q-15 -17 -25 -47.5t-10 -55.5q0 -69 53 -119q-18 -32 -18 -69t17.5 -73.5t47.5 -52.5q-4 -24 -4 -56q0 -85 48.5 -126t135.5 -41q84 0 183 32t194 64t167 32zM1664 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45 t45 -19t45 19t19 45zM1792 768v-640q0 -53 -37.5 -90.5t-90.5 -37.5h-288q-59 0 -223 -59q-190 -69 -317 -69q-142 0 -230 77.5t-87 217.5l1 5q-61 76 -61 178q0 22 3 43q-33 57 -37 119h-169q-105 0 -180.5 76t-75.5 181q0 103 76 179t180 76h374q-22 60 -22 128 q0 122 81.5 189t206.5 67q38 0 69.5 -17.5t55 -49.5t40.5 -63t37 -72t33 -62q35 -55 100 -129q2 -3 14 -17t19 -21.5t20.5 -21.5t24 -22.5t22.5 -18t23.5 -14t21.5 -4.5h288q53 0 90.5 -37.5t37.5 -90.5z" />
<glyph unicode="&#xf0a6;" d="M1280 -64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 700q0 189 -167 189q-26 0 -56 -5q-16 30 -52.5 47.5t-73.5 17.5t-69 -18q-50 53 -119 53q-25 0 -55.5 -10t-47.5 -25v331q0 52 -38 90t-90 38q-51 0 -89.5 -39t-38.5 -89v-576 q-20 0 -48.5 15t-55 33t-68 33t-84.5 15q-67 0 -97.5 -44.5t-30.5 -115.5q0 -24 139 -90q44 -24 65 -37q64 -40 145 -112q81 -71 106 -101q57 -69 57 -140v-32h640v32q0 72 32 167t64 193.5t32 179.5zM1536 705q0 -133 -69 -322q-59 -164 -59 -223v-288q0 -53 -37.5 -90.5 t-90.5 -37.5h-640q-53 0 -90.5 37.5t-37.5 90.5v288q0 10 -4.5 21.5t-14 23.5t-18 22.5t-22.5 24t-21.5 20.5t-21.5 19t-17 14q-74 65 -129 100q-21 13 -62 33t-72 37t-63 40.5t-49.5 55t-17.5 69.5q0 125 67 206.5t189 81.5q68 0 128 -22v374q0 104 76 180t179 76 q105 0 181 -75.5t76 -180.5v-169q62 -4 119 -37q21 3 43 3q101 0 178 -60q139 1 219.5 -85t80.5 -227z" />
<glyph unicode="&#xf0a7;" d="M1408 576q0 84 -32 183t-64 194t-32 167v32h-640v-32q0 -35 -12 -67.5t-37 -62.5t-46 -50t-54 -49q-9 -8 -14 -12q-81 -72 -145 -112q-22 -14 -68 -38q-3 -1 -22.5 -10.5t-36 -18.5t-35.5 -20t-30.5 -21.5t-11.5 -18.5q0 -71 30.5 -115.5t97.5 -44.5q43 0 84.5 15t68 33 t55 33t48.5 15v-576q0 -50 38.5 -89t89.5 -39q52 0 90 38t38 90v331q46 -35 103 -35q69 0 119 53q32 -18 69 -18t73.5 17.5t52.5 47.5q24 -4 56 -4q85 0 126 48.5t41 135.5zM1280 1344q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 580 q0 -142 -77.5 -230t-217.5 -87l-5 1q-76 -61 -178 -61q-22 0 -43 3q-54 -30 -119 -37v-169q0 -105 -76 -180.5t-181 -75.5q-103 0 -179 76t-76 180v374q-54 -22 -128 -22q-121 0 -188.5 81.5t-67.5 206.5q0 38 17.5 69.5t49.5 55t63 40.5t72 37t62 33q55 35 129 100 q3 2 17 14t21.5 19t21.5 20.5t22.5 24t18 22.5t14 23.5t4.5 21.5v288q0 53 37.5 90.5t90.5 37.5h640q53 0 90.5 -37.5t37.5 -90.5v-288q0 -59 59 -223q69 -190 69 -317z" />
<glyph unicode="&#xf0a8;" d="M1280 576v128q0 26 -19 45t-45 19h-502l189 189q19 19 19 45t-19 45l-91 91q-18 18 -45 18t-45 -18l-362 -362l-91 -91q-18 -18 -18 -45t18 -45l91 -91l362 -362q18 -18 45 -18t45 18l91 91q18 18 18 45t-18 45l-189 189h502q26 0 45 19t19 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
<glyph unicode="&#xf0a9;" d="M1285 640q0 27 -18 45l-91 91l-362 362q-18 18 -45 18t-45 -18l-91 -91q-18 -18 -18 -45t18 -45l189 -189h-502q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h502l-189 -189q-19 -19 -19 -45t19 -45l91 -91q18 -18 45 -18t45 18l362 362l91 91q18 18 18 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
<glyph unicode="&#xf0aa;" d="M1284 641q0 27 -18 45l-362 362l-91 91q-18 18 -45 18t-45 -18l-91 -91l-362 -362q-18 -18 -18 -45t18 -45l91 -91q18 -18 45 -18t45 18l189 189v-502q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v502l189 -189q19 -19 45 -19t45 19l91 91q18 18 18 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
<glyph unicode="&#xf0ab;" d="M1284 639q0 27 -18 45l-91 91q-18 18 -45 18t-45 -18l-189 -189v502q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-502l-189 189q-19 19 -45 19t-45 -19l-91 -91q-18 -18 -18 -45t18 -45l362 -362l91 -91q18 -18 45 -18t45 18l91 91l362 362q18 18 18 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
<glyph unicode="&#xf0ac;" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM1042 887q-2 -1 -9.5 -9.5t-13.5 -9.5q2 0 4.5 5t5 11t3.5 7q6 7 22 15q14 6 52 12q34 8 51 -11 q-2 2 9.5 13t14.5 12q3 2 15 4.5t15 7.5l2 22q-12 -1 -17.5 7t-6.5 21q0 -2 -6 -8q0 7 -4.5 8t-11.5 -1t-9 -1q-10 3 -15 7.5t-8 16.5t-4 15q-2 5 -9.5 10.5t-9.5 10.5q-1 2 -2.5 5.5t-3 6.5t-4 5.5t-5.5 2.5t-7 -5t-7.5 -10t-4.5 -5q-3 2 -6 1.5t-4.5 -1t-4.5 -3t-5 -3.5 q-3 -2 -8.5 -3t-8.5 -2q15 5 -1 11q-10 4 -16 3q9 4 7.5 12t-8.5 14h5q-1 4 -8.5 8.5t-17.5 8.5t-13 6q-8 5 -34 9.5t-33 0.5q-5 -6 -4.5 -10.5t4 -14t3.5 -12.5q1 -6 -5.5 -13t-6.5 -12q0 -7 14 -15.5t10 -21.5q-3 -8 -16 -16t-16 -12q-5 -8 -1.5 -18.5t10.5 -16.5 q2 -2 1.5 -4t-3.5 -4.5t-5.5 -4t-6.5 -3.5l-3 -2q-11 -5 -20.5 6t-13.5 26q-7 25 -16 30q-23 8 -29 -1q-5 13 -41 26q-25 9 -58 4q6 1 0 15q-7 15 -19 12q3 6 4 17.5t1 13.5q3 13 12 23q1 1 7 8.5t9.5 13.5t0.5 6q35 -4 50 11q5 5 11.5 17t10.5 17q9 6 14 5.5t14.5 -5.5 t14.5 -5q14 -1 15.5 11t-7.5 20q12 -1 3 17q-5 7 -8 9q-12 4 -27 -5q-8 -4 2 -8q-1 1 -9.5 -10.5t-16.5 -17.5t-16 5q-1 1 -5.5 13.5t-9.5 13.5q-8 0 -16 -15q3 8 -11 15t-24 8q19 12 -8 27q-7 4 -20.5 5t-19.5 -4q-5 -7 -5.5 -11.5t5 -8t10.5 -5.5t11.5 -4t8.5 -3 q14 -10 8 -14q-2 -1 -8.5 -3.5t-11.5 -4.5t-6 -4q-3 -4 0 -14t-2 -14q-5 5 -9 17.5t-7 16.5q7 -9 -25 -6l-10 1q-4 0 -16 -2t-20.5 -1t-13.5 8q-4 8 0 20q1 4 4 2q-4 3 -11 9.5t-10 8.5q-46 -15 -94 -41q6 -1 12 1q5 2 13 6.5t10 5.5q34 14 42 7l5 5q14 -16 20 -25 q-7 4 -30 1q-20 -6 -22 -12q7 -12 5 -18q-4 3 -11.5 10t-14.5 11t-15 5q-16 0 -22 -1q-146 -80 -235 -222q7 -7 12 -8q4 -1 5 -9t2.5 -11t11.5 3q9 -8 3 -19q1 1 44 -27q19 -17 21 -21q3 -11 -10 -18q-1 2 -9 9t-9 4q-3 -5 0.5 -18.5t10.5 -12.5q-7 0 -9.5 -16t-2.5 -35.5 t-1 -23.5l2 -1q-3 -12 5.5 -34.5t21.5 -19.5q-13 -3 20 -43q6 -8 8 -9q3 -2 12 -7.5t15 -10t10 -10.5q4 -5 10 -22.5t14 -23.5q-2 -6 9.5 -20t10.5 -23q-1 0 -2.5 -1t-2.5 -1q3 -7 15.5 -14t15.5 -13q1 -3 2 -10t3 -11t8 -2q2 20 -24 62q-15 25 -17 29q-3 5 -5.5 15.5 t-4.5 14.5q2 0 6 -1.5t8.5 -3.5t7.5 -4t2 -3q-3 -7 2 -17.5t12 -18.5t17 -19t12 -13q6 -6 14 -19.5t0 -13.5q9 0 20 -10t17 -20q5 -8 8 -26t5 -24q2 -7 8.5 -13.5t12.5 -9.5l16 -8t13 -7q5 -2 18.5 -10.5t21.5 -11.5q10 -4 16 -4t14.5 2.5t13.5 3.5q15 2 29 -15t21 -21 q36 -19 55 -11q-2 -1 0.5 -7.5t8 -15.5t9 -14.5t5.5 -8.5q5 -6 18 -15t18 -15q6 4 7 9q-3 -8 7 -20t18 -10q14 3 14 32q-31 -15 -49 18q0 1 -2.5 5.5t-4 8.5t-2.5 8.5t0 7.5t5 3q9 0 10 3.5t-2 12.5t-4 13q-1 8 -11 20t-12 15q-5 -9 -16 -8t-16 9q0 -1 -1.5 -5.5t-1.5 -6.5 q-13 0 -15 1q1 3 2.5 17.5t3.5 22.5q1 4 5.5 12t7.5 14.5t4 12.5t-4.5 9.5t-17.5 2.5q-19 -1 -26 -20q-1 -3 -3 -10.5t-5 -11.5t-9 -7q-7 -3 -24 -2t-24 5q-13 8 -22.5 29t-9.5 37q0 10 2.5 26.5t3 25t-5.5 24.5q3 2 9 9.5t10 10.5q2 1 4.5 1.5t4.5 0t4 1.5t3 6q-1 1 -4 3 q-3 3 -4 3q7 -3 28.5 1.5t27.5 -1.5q15 -11 22 2q0 1 -2.5 9.5t-0.5 13.5q5 -27 29 -9q3 -3 15.5 -5t17.5 -5q3 -2 7 -5.5t5.5 -4.5t5 0.5t8.5 6.5q10 -14 12 -24q11 -40 19 -44q7 -3 11 -2t4.5 9.5t0 14t-1.5 12.5l-1 8v18l-1 8q-15 3 -18.5 12t1.5 18.5t15 18.5q1 1 8 3.5 t15.5 6.5t12.5 8q21 19 15 35q7 0 11 9q-1 0 -5 3t-7.5 5t-4.5 2q9 5 2 16q5 3 7.5 11t7.5 10q9 -12 21 -2q7 8 1 16q5 7 20.5 10.5t18.5 9.5q7 -2 8 2t1 12t3 12q4 5 15 9t13 5l17 11q3 4 0 4q18 -2 31 11q10 11 -6 20q3 6 -3 9.5t-15 5.5q3 1 11.5 0.5t10.5 1.5 q15 10 -7 16q-17 5 -43 -12zM879 10q206 36 351 189q-3 3 -12.5 4.5t-12.5 3.5q-18 7 -24 8q1 7 -2.5 13t-8 9t-12.5 8t-11 7q-2 2 -7 6t-7 5.5t-7.5 4.5t-8.5 2t-10 -1l-3 -1q-3 -1 -5.5 -2.5t-5.5 -3t-4 -3t0 -2.5q-21 17 -36 22q-5 1 -11 5.5t-10.5 7t-10 1.5t-11.5 -7 q-5 -5 -6 -15t-2 -13q-7 5 0 17.5t2 18.5q-3 6 -10.5 4.5t-12 -4.5t-11.5 -8.5t-9 -6.5t-8.5 -5.5t-8.5 -7.5q-3 -4 -6 -12t-5 -11q-2 4 -11.5 6.5t-9.5 5.5q2 -10 4 -35t5 -38q7 -31 -12 -48q-27 -25 -29 -40q-4 -22 12 -26q0 -7 -8 -20.5t-7 -21.5q0 -6 2 -16z" />
<glyph unicode="&#xf0ad;" horiz-adv-x="1664" d="M384 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1028 484l-682 -682q-37 -37 -90 -37q-52 0 -91 37l-106 108q-38 36 -38 90q0 53 38 91l681 681q39 -98 114.5 -173.5t173.5 -114.5zM1662 919q0 -39 -23 -106q-47 -134 -164.5 -217.5 t-258.5 -83.5q-185 0 -316.5 131.5t-131.5 316.5t131.5 316.5t316.5 131.5q58 0 121.5 -16.5t107.5 -46.5q16 -11 16 -28t-16 -28l-293 -169v-224l193 -107q5 3 79 48.5t135.5 81t70.5 35.5q15 0 23.5 -10t8.5 -25z" />
<glyph unicode="&#xf0ae;" horiz-adv-x="1792" d="M1024 128h640v128h-640v-128zM640 640h1024v128h-1024v-128zM1280 1152h384v128h-384v-128zM1792 320v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 832v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19 t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 1344v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45z" />
<glyph unicode="&#xf0b0;" horiz-adv-x="1408" d="M1403 1241q17 -41 -14 -70l-493 -493v-742q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-256 256q-19 19 -19 45v486l-493 493q-31 29 -14 70q17 39 59 39h1280q42 0 59 -39z" />
<glyph unicode="&#xf0b1;" horiz-adv-x="1792" d="M640 1280h512v128h-512v-128zM1792 640v-480q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v480h672v-160q0 -26 19 -45t45 -19h320q26 0 45 19t19 45v160h672zM1024 640v-128h-256v128h256zM1792 1120v-384h-1792v384q0 66 47 113t113 47h352v160q0 40 28 68 t68 28h576q40 0 68 -28t28 -68v-160h352q66 0 113 -47t47 -113z" />
<glyph unicode="&#xf0b2;" d="M1283 995l-355 -355l355 -355l144 144q29 31 70 14q39 -17 39 -59v-448q0 -26 -19 -45t-45 -19h-448q-42 0 -59 40q-17 39 14 69l144 144l-355 355l-355 -355l144 -144q31 -30 14 -69q-17 -40 -59 -40h-448q-26 0 -45 19t-19 45v448q0 42 40 59q39 17 69 -14l144 -144 l355 355l-355 355l-144 -144q-19 -19 -45 -19q-12 0 -24 5q-40 17 -40 59v448q0 26 19 45t45 19h448q42 0 59 -40q17 -39 -14 -69l-144 -144l355 -355l355 355l-144 144q-31 30 -14 69q17 40 59 40h448q26 0 45 -19t19 -45v-448q0 -42 -39 -59q-13 -5 -25 -5q-26 0 -45 19z " />
<glyph unicode="&#xf0c0;" horiz-adv-x="1920" d="M593 640q-162 -5 -265 -128h-134q-82 0 -138 40.5t-56 118.5q0 353 124 353q6 0 43.5 -21t97.5 -42.5t119 -21.5q67 0 133 23q-5 -37 -5 -66q0 -139 81 -256zM1664 3q0 -120 -73 -189.5t-194 -69.5h-874q-121 0 -194 69.5t-73 189.5q0 53 3.5 103.5t14 109t26.5 108.5 t43 97.5t62 81t85.5 53.5t111.5 20q10 0 43 -21.5t73 -48t107 -48t135 -21.5t135 21.5t107 48t73 48t43 21.5q61 0 111.5 -20t85.5 -53.5t62 -81t43 -97.5t26.5 -108.5t14 -109t3.5 -103.5zM640 1280q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75 t75 -181zM1344 896q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5zM1920 671q0 -78 -56 -118.5t-138 -40.5h-134q-103 123 -265 128q81 117 81 256q0 29 -5 66q66 -23 133 -23q59 0 119 21.5t97.5 42.5 t43.5 21q124 0 124 -353zM1792 1280q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181z" />
<glyph unicode="&#xf0c1;" horiz-adv-x="1664" d="M1456 320q0 40 -28 68l-208 208q-28 28 -68 28q-42 0 -72 -32q3 -3 19 -18.5t21.5 -21.5t15 -19t13 -25.5t3.5 -27.5q0 -40 -28 -68t-68 -28q-15 0 -27.5 3.5t-25.5 13t-19 15t-21.5 21.5t-18.5 19q-33 -31 -33 -73q0 -40 28 -68l206 -207q27 -27 68 -27q40 0 68 26 l147 146q28 28 28 67zM753 1025q0 40 -28 68l-206 207q-28 28 -68 28q-39 0 -68 -27l-147 -146q-28 -28 -28 -67q0 -40 28 -68l208 -208q27 -27 68 -27q42 0 72 31q-3 3 -19 18.5t-21.5 21.5t-15 19t-13 25.5t-3.5 27.5q0 40 28 68t68 28q15 0 27.5 -3.5t25.5 -13t19 -15 t21.5 -21.5t18.5 -19q33 31 33 73zM1648 320q0 -120 -85 -203l-147 -146q-83 -83 -203 -83q-121 0 -204 85l-206 207q-83 83 -83 203q0 123 88 209l-88 88q-86 -88 -208 -88q-120 0 -204 84l-208 208q-84 84 -84 204t85 203l147 146q83 83 203 83q121 0 204 -85l206 -207 q83 -83 83 -203q0 -123 -88 -209l88 -88q86 88 208 88q120 0 204 -84l208 -208q84 -84 84 -204z" />
<glyph unicode="&#xf0c2;" horiz-adv-x="1920" d="M1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088q-185 0 -316.5 131.5t-131.5 316.5q0 132 71 241.5t187 163.5q-2 28 -2 43q0 212 150 362t362 150q158 0 286.5 -88t187.5 -230q70 62 166 62q106 0 181 -75t75 -181q0 -75 -41 -138q129 -30 213 -134.5t84 -239.5z " />
<glyph unicode="&#xf0c3;" horiz-adv-x="1664" d="M1527 88q56 -89 21.5 -152.5t-140.5 -63.5h-1152q-106 0 -140.5 63.5t21.5 152.5l503 793v399h-64q-26 0 -45 19t-19 45t19 45t45 19h512q26 0 45 -19t19 -45t-19 -45t-45 -19h-64v-399zM748 813l-272 -429h712l-272 429l-20 31v37v399h-128v-399v-37z" />
<glyph unicode="&#xf0c4;" horiz-adv-x="1792" d="M960 640q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1260 576l507 -398q28 -20 25 -56q-5 -35 -35 -51l-128 -64q-13 -7 -29 -7q-17 0 -31 8l-690 387l-110 -66q-8 -4 -12 -5q14 -49 10 -97q-7 -77 -56 -147.5t-132 -123.5q-132 -84 -277 -84 q-136 0 -222 78q-90 84 -79 207q7 76 56 147t131 124q132 84 278 84q83 0 151 -31q9 13 22 22l122 73l-122 73q-13 9 -22 22q-68 -31 -151 -31q-146 0 -278 84q-82 53 -131 124t-56 147q-5 59 15.5 113t63.5 93q85 79 222 79q145 0 277 -84q83 -52 132 -123t56 -148 q4 -48 -10 -97q4 -1 12 -5l110 -66l690 387q14 8 31 8q16 0 29 -7l128 -64q30 -16 35 -51q3 -36 -25 -56zM579 836q46 42 21 108t-106 117q-92 59 -192 59q-74 0 -113 -36q-46 -42 -21 -108t106 -117q92 -59 192 -59q74 0 113 36zM494 91q81 51 106 117t-21 108 q-39 36 -113 36q-100 0 -192 -59q-81 -51 -106 -117t21 -108q39 -36 113 -36q100 0 192 59zM672 704l96 -58v11q0 36 33 56l14 8l-79 47l-26 -26q-3 -3 -10 -11t-12 -12q-2 -2 -4 -3.5t-3 -2.5zM896 480l96 -32l736 576l-128 64l-768 -431v-113l-160 -96l9 -8q2 -2 7 -6 q4 -4 11 -12t11 -12l26 -26zM1600 64l128 64l-520 408l-177 -138q-2 -3 -13 -7z" />
<glyph unicode="&#xf0c5;" horiz-adv-x="1792" d="M1696 1152q40 0 68 -28t28 -68v-1216q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v288h-544q-40 0 -68 28t-28 68v672q0 40 20 88t48 76l408 408q28 28 76 48t88 20h416q40 0 68 -28t28 -68v-328q68 40 128 40h416zM1152 939l-299 -299h299v299zM512 1323l-299 -299 h299v299zM708 676l316 316v416h-384v-416q0 -40 -28 -68t-68 -28h-416v-640h512v256q0 40 20 88t48 76zM1664 -128v1152h-384v-416q0 -40 -28 -68t-68 -28h-416v-640h896z" />
<glyph unicode="&#xf0c6;" horiz-adv-x="1408" d="M1404 151q0 -117 -79 -196t-196 -79q-135 0 -235 100l-777 776q-113 115 -113 271q0 159 110 270t269 111q158 0 273 -113l605 -606q10 -10 10 -22q0 -16 -30.5 -46.5t-46.5 -30.5q-13 0 -23 10l-606 607q-79 77 -181 77q-106 0 -179 -75t-73 -181q0 -105 76 -181 l776 -777q63 -63 145 -63q64 0 106 42t42 106q0 82 -63 145l-581 581q-26 24 -60 24q-29 0 -48 -19t-19 -48q0 -32 25 -59l410 -410q10 -10 10 -22q0 -16 -31 -47t-47 -31q-12 0 -22 10l-410 410q-63 61 -63 149q0 82 57 139t139 57q88 0 149 -63l581 -581q100 -98 100 -235 z" />
<glyph unicode="&#xf0c7;" d="M384 0h768v384h-768v-384zM1280 0h128v896q0 14 -10 38.5t-20 34.5l-281 281q-10 10 -34 20t-39 10v-416q0 -40 -28 -68t-68 -28h-576q-40 0 -68 28t-28 68v416h-128v-1280h128v416q0 40 28 68t68 28h832q40 0 68 -28t28 -68v-416zM896 928v320q0 13 -9.5 22.5t-22.5 9.5 h-192q-13 0 -22.5 -9.5t-9.5 -22.5v-320q0 -13 9.5 -22.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 22.5zM1536 896v-928q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h928q40 0 88 -20t76 -48l280 -280q28 -28 48 -76t20 -88z" />
<glyph unicode="&#xf0c8;" d="M1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
<glyph unicode="&#xf0c9;" d="M1536 192v-128q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1536 704v-128q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1536 1216v-128q0 -26 -19 -45 t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" />
<glyph unicode="&#xf0ca;" horiz-adv-x="1792" d="M384 128q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM384 640q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5 t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5zM384 1152q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1792 736v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5z M1792 1248v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5z" />
<glyph unicode="&#xf0cb;" horiz-adv-x="1792" d="M381 -84q0 -80 -54.5 -126t-135.5 -46q-106 0 -172 66l57 88q49 -45 106 -45q29 0 50.5 14.5t21.5 42.5q0 64 -105 56l-26 56q8 10 32.5 43.5t42.5 54t37 38.5v1q-16 0 -48.5 -1t-48.5 -1v-53h-106v152h333v-88l-95 -115q51 -12 81 -49t30 -88zM383 543v-159h-362 q-6 36 -6 54q0 51 23.5 93t56.5 68t66 47.5t56.5 43.5t23.5 45q0 25 -14.5 38.5t-39.5 13.5q-46 0 -81 -58l-85 59q24 51 71.5 79.5t105.5 28.5q73 0 123 -41.5t50 -112.5q0 -50 -34 -91.5t-75 -64.5t-75.5 -50.5t-35.5 -52.5h127v60h105zM1792 224v-192q0 -13 -9.5 -22.5 t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 14 9 23t23 9h1216q13 0 22.5 -9.5t9.5 -22.5zM384 1123v-99h-335v99h107q0 41 0.5 122t0.5 121v12h-2q-8 -17 -50 -54l-71 76l136 127h106v-404h108zM1792 736v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5 t-9.5 22.5v192q0 14 9 23t23 9h1216q13 0 22.5 -9.5t9.5 -22.5zM1792 1248v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5z" />
<glyph unicode="&#xf0cc;" horiz-adv-x="1792" d="M1760 640q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-1728q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h1728zM483 704q-28 35 -51 80q-48 97 -48 188q0 181 134 309q133 127 393 127q50 0 167 -19q66 -12 177 -48q10 -38 21 -118q14 -123 14 -183q0 -18 -5 -45l-12 -3l-84 6 l-14 2q-50 149 -103 205q-88 91 -210 91q-114 0 -182 -59q-67 -58 -67 -146q0 -73 66 -140t279 -129q69 -20 173 -66q58 -28 95 -52h-743zM990 448h411q7 -39 7 -92q0 -111 -41 -212q-23 -55 -71 -104q-37 -35 -109 -81q-80 -48 -153 -66q-80 -21 -203 -21q-114 0 -195 23 l-140 40q-57 16 -72 28q-8 8 -8 22v13q0 108 -2 156q-1 30 0 68l2 37v44l102 2q15 -34 30 -71t22.5 -56t12.5 -27q35 -57 80 -94q43 -36 105 -57q59 -22 132 -22q64 0 139 27q77 26 122 86q47 61 47 129q0 84 -81 157q-34 29 -137 71z" />
<glyph unicode="&#xf0cd;" d="M48 1313q-37 2 -45 4l-3 88q13 1 40 1q60 0 112 -4q132 -7 166 -7q86 0 168 3q116 4 146 5q56 0 86 2l-1 -14l2 -64v-9q-60 -9 -124 -9q-60 0 -79 -25q-13 -14 -13 -132q0 -13 0.5 -32.5t0.5 -25.5l1 -229l14 -280q6 -124 51 -202q35 -59 96 -92q88 -47 177 -47 q104 0 191 28q56 18 99 51q48 36 65 64q36 56 53 114q21 73 21 229q0 79 -3.5 128t-11 122.5t-13.5 159.5l-4 59q-5 67 -24 88q-34 35 -77 34l-100 -2l-14 3l2 86h84l205 -10q76 -3 196 10l18 -2q6 -38 6 -51q0 -7 -4 -31q-45 -12 -84 -13q-73 -11 -79 -17q-15 -15 -15 -41 q0 -7 1.5 -27t1.5 -31q8 -19 22 -396q6 -195 -15 -304q-15 -76 -41 -122q-38 -65 -112 -123q-75 -57 -182 -89q-109 -33 -255 -33q-167 0 -284 46q-119 47 -179 122q-61 76 -83 195q-16 80 -16 237v333q0 188 -17 213q-25 36 -147 39zM1536 -96v64q0 14 -9 23t-23 9h-1472 q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h1472q14 0 23 9t9 23z" />
<glyph unicode="&#xf0ce;" horiz-adv-x="1664" d="M512 160v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM512 544v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1024 160v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23 v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM512 928v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1024 544v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1536 160v192 q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1024 928v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1536 544v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192 q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1536 928v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1664 1248v-1088q0 -66 -47 -113t-113 -47h-1344q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1344q66 0 113 -47t47 -113 z" />
<glyph unicode="&#xf0d0;" horiz-adv-x="1664" d="M1190 955l293 293l-107 107l-293 -293zM1637 1248q0 -27 -18 -45l-1286 -1286q-18 -18 -45 -18t-45 18l-198 198q-18 18 -18 45t18 45l1286 1286q18 18 45 18t45 -18l198 -198q18 -18 18 -45zM286 1438l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98zM636 1276 l196 -60l-196 -60l-60 -196l-60 196l-196 60l196 60l60 196zM1566 798l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98zM926 1438l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98z" />
<glyph unicode="&#xf0d1;" horiz-adv-x="1792" d="M640 128q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM256 640h384v256h-158q-13 0 -22 -9l-195 -195q-9 -9 -9 -22v-30zM1536 128q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM1792 1216v-1024q0 -15 -4 -26.5t-13.5 -18.5 t-16.5 -11.5t-23.5 -6t-22.5 -2t-25.5 0t-22.5 0.5q0 -106 -75 -181t-181 -75t-181 75t-75 181h-384q0 -106 -75 -181t-181 -75t-181 75t-75 181h-64q-3 0 -22.5 -0.5t-25.5 0t-22.5 2t-23.5 6t-16.5 11.5t-13.5 18.5t-4 26.5q0 26 19 45t45 19v320q0 8 -0.5 35t0 38 t2.5 34.5t6.5 37t14 30.5t22.5 30l198 198q19 19 50.5 32t58.5 13h160v192q0 26 19 45t45 19h1024q26 0 45 -19t19 -45z" />
<glyph unicode="&#xf0d2;" d="M1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103q-111 0 -218 32q59 93 78 164q9 34 54 211q20 -39 73 -67.5t114 -28.5q121 0 216 68.5t147 188.5t52 270q0 114 -59.5 214t-172.5 163t-255 63q-105 0 -196 -29t-154.5 -77t-109 -110.5t-67 -129.5t-21.5 -134 q0 -104 40 -183t117 -111q30 -12 38 20q2 7 8 31t8 30q6 23 -11 43q-51 61 -51 151q0 151 104.5 259.5t273.5 108.5q151 0 235.5 -82t84.5 -213q0 -170 -68.5 -289t-175.5 -119q-61 0 -98 43.5t-23 104.5q8 35 26.5 93.5t30 103t11.5 75.5q0 50 -27 83t-77 33 q-62 0 -105 -57t-43 -142q0 -73 25 -122l-99 -418q-17 -70 -13 -177q-206 91 -333 281t-127 423q0 209 103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
<glyph unicode="&#xf0d3;" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-725q85 122 108 210q9 34 53 209q21 -39 73.5 -67t112.5 -28q181 0 295.5 147.5t114.5 373.5q0 84 -35 162.5t-96.5 139t-152.5 97t-197 36.5q-104 0 -194.5 -28.5t-153 -76.5 t-107.5 -109.5t-66.5 -128t-21.5 -132.5q0 -102 39.5 -180t116.5 -110q13 -5 23.5 0t14.5 19q10 44 15 61q6 23 -11 42q-50 62 -50 150q0 150 103.5 256.5t270.5 106.5q149 0 232.5 -81t83.5 -210q0 -168 -67.5 -286t-173.5 -118q-60 0 -97 43.5t-23 103.5q8 34 26.5 92.5 t29.5 102t11 74.5q0 49 -26.5 81.5t-75.5 32.5q-61 0 -103.5 -56.5t-42.5 -139.5q0 -72 24 -121l-98 -414q-24 -100 -7 -254h-183q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960z" />
<glyph unicode="&#xf0d4;" d="M678 -57q0 -38 -10 -71h-380q-95 0 -171.5 56.5t-103.5 147.5q24 45 69 77.5t100 49.5t107 24t107 7q32 0 49 -2q6 -4 30.5 -21t33 -23t31 -23t32 -25.5t27.5 -25.5t26.5 -29.5t21 -30.5t17.5 -34.5t9.5 -36t4.5 -40.5zM385 294q-234 -7 -385 -85v433q103 -118 273 -118 q32 0 70 5q-21 -61 -21 -86q0 -67 63 -149zM558 805q0 -100 -43.5 -160.5t-140.5 -60.5q-51 0 -97 26t-78 67.5t-56 93.5t-35.5 104t-11.5 99q0 96 51.5 165t144.5 69q66 0 119 -41t84 -104t47 -130t16 -128zM1536 896v-736q0 -119 -84.5 -203.5t-203.5 -84.5h-468 q39 73 39 157q0 66 -22 122.5t-55.5 93t-72 71t-72 59.5t-55.5 54.5t-22 59.5q0 36 23 68t56 61.5t65.5 64.5t55.5 93t23 131t-26.5 145.5t-75.5 118.5q-6 6 -14 11t-12.5 7.5t-10 9.5t-10.5 17h135l135 64h-437q-138 0 -244.5 -38.5t-182.5 -133.5q0 126 81 213t207 87h960 q119 0 203.5 -84.5t84.5 -203.5v-96h-256v256h-128v-256h-256v-128h256v-256h128v256h256z" />
<glyph unicode="&#xf0d5;" horiz-adv-x="1664" d="M876 71q0 21 -4.5 40.5t-9.5 36t-17.5 34.5t-21 30.5t-26.5 29.5t-27.5 25.5t-32 25.5t-31 23t-33 23t-30.5 21q-17 2 -50 2q-54 0 -106 -7t-108 -25t-98 -46t-69 -75t-27 -107q0 -68 35.5 -121.5t93 -84t120.5 -45.5t127 -15q59 0 112.5 12.5t100.5 39t74.5 73.5 t27.5 110zM756 933q0 60 -16.5 127.5t-47 130.5t-84 104t-119.5 41q-93 0 -144 -69t-51 -165q0 -47 11.5 -99t35.5 -104t56 -93.5t78 -67.5t97 -26q97 0 140.5 60.5t43.5 160.5zM625 1408h437l-135 -79h-135q71 -45 110 -126t39 -169q0 -74 -23 -131.5t-56 -92.5t-66 -64.5 t-56 -61t-23 -67.5q0 -26 16.5 -51t43 -48t58.5 -48t64 -55.5t58.5 -66t43 -85t16.5 -106.5q0 -160 -140 -282q-152 -131 -420 -131q-59 0 -119.5 10t-122 33.5t-108.5 58t-77 89t-30 121.5q0 61 37 135q32 64 96 110.5t145 71t155 36t150 13.5q-64 83 -64 149q0 12 2 23.5 t5 19.5t8 21.5t7 21.5q-40 -5 -70 -5q-149 0 -255.5 98t-106.5 246q0 140 95 250.5t234 141.5q94 20 187 20zM1664 1152v-128h-256v-256h-128v256h-256v128h256v256h128v-256h256z" />
<glyph unicode="&#xf0d6;" horiz-adv-x="1920" d="M768 384h384v96h-128v448h-114l-148 -137l77 -80q42 37 55 57h2v-288h-128v-96zM1280 640q0 -70 -21 -142t-59.5 -134t-101.5 -101t-138 -39t-138 39t-101.5 101t-59.5 134t-21 142t21 142t59.5 134t101.5 101t138 39t138 -39t101.5 -101t59.5 -134t21 -142zM1792 384 v512q-106 0 -181 75t-75 181h-1152q0 -106 -75 -181t-181 -75v-512q106 0 181 -75t75 -181h1152q0 106 75 181t181 75zM1920 1216v-1152q0 -26 -19 -45t-45 -19h-1792q-26 0 -45 19t-19 45v1152q0 26 19 45t45 19h1792q26 0 45 -19t19 -45z" />
<glyph unicode="&#xf0d7;" horiz-adv-x="1024" d="M1024 832q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45z" />
<glyph unicode="&#xf0d8;" horiz-adv-x="1024" d="M1024 320q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" />
<glyph unicode="&#xf0d9;" horiz-adv-x="640" d="M640 1088v-896q0 -26 -19 -45t-45 -19t-45 19l-448 448q-19 19 -19 45t19 45l448 448q19 19 45 19t45 -19t19 -45z" />
<glyph unicode="&#xf0da;" horiz-adv-x="640" d="M576 640q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19t-19 45v896q0 26 19 45t45 19t45 -19l448 -448q19 -19 19 -45z" />
<glyph unicode="&#xf0db;" horiz-adv-x="1664" d="M160 0h608v1152h-640v-1120q0 -13 9.5 -22.5t22.5 -9.5zM1536 32v1120h-640v-1152h608q13 0 22.5 9.5t9.5 22.5zM1664 1248v-1216q0 -66 -47 -113t-113 -47h-1344q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1344q66 0 113 -47t47 -113z" />
<glyph unicode="&#xf0dc;" horiz-adv-x="1024" d="M1024 448q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45zM1024 832q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" />
<glyph unicode="&#xf0dd;" horiz-adv-x="1024" d="M1024 448q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45z" />
<glyph unicode="&#xf0de;" horiz-adv-x="1024" d="M1024 832q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" />
<glyph unicode="&#xf0e0;" horiz-adv-x="1792" d="M1792 826v-794q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v794q44 -49 101 -87q362 -246 497 -345q57 -42 92.5 -65.5t94.5 -48t110 -24.5h1h1q51 0 110 24.5t94.5 48t92.5 65.5q170 123 498 345q57 39 100 87zM1792 1120q0 -79 -49 -151t-122 -123 q-376 -261 -468 -325q-10 -7 -42.5 -30.5t-54 -38t-52 -32.5t-57.5 -27t-50 -9h-1h-1q-23 0 -50 9t-57.5 27t-52 32.5t-54 38t-42.5 30.5q-91 64 -262 182.5t-205 142.5q-62 42 -117 115.5t-55 136.5q0 78 41.5 130t118.5 52h1472q65 0 112.5 -47t47.5 -113z" />
<glyph unicode="&#xf0e1;" d="M349 911v-991h-330v991h330zM370 1217q1 -73 -50.5 -122t-135.5 -49h-2q-82 0 -132 49t-50 122q0 74 51.5 122.5t134.5 48.5t133 -48.5t51 -122.5zM1536 488v-568h-329v530q0 105 -40.5 164.5t-126.5 59.5q-63 0 -105.5 -34.5t-63.5 -85.5q-11 -30 -11 -81v-553h-329 q2 399 2 647t-1 296l-1 48h329v-144h-2q20 32 41 56t56.5 52t87 43.5t114.5 15.5q171 0 275 -113.5t104 -332.5z" />
<glyph unicode="&#xf0e2;" d="M1536 640q0 -156 -61 -298t-164 -245t-245 -164t-298 -61q-172 0 -327 72.5t-264 204.5q-7 10 -6.5 22.5t8.5 20.5l137 138q10 9 25 9q16 -2 23 -12q73 -95 179 -147t225 -52q104 0 198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5t-40.5 198.5t-109.5 163.5 t-163.5 109.5t-198.5 40.5q-98 0 -188 -35.5t-160 -101.5l137 -138q31 -30 14 -69q-17 -40 -59 -40h-448q-26 0 -45 19t-19 45v448q0 42 40 59q39 17 69 -14l130 -129q107 101 244.5 156.5t284.5 55.5q156 0 298 -61t245 -164t164 -245t61 -298z" />
<glyph unicode="&#xf0e3;" horiz-adv-x="1792" d="M1771 0q0 -53 -37 -90l-107 -108q-39 -37 -91 -37q-53 0 -90 37l-363 364q-38 36 -38 90q0 53 43 96l-256 256l-126 -126q-14 -14 -34 -14t-34 14q2 -2 12.5 -12t12.5 -13t10 -11.5t10 -13.5t6 -13.5t5.5 -16.5t1.5 -18q0 -38 -28 -68q-3 -3 -16.5 -18t-19 -20.5 t-18.5 -16.5t-22 -15.5t-22 -9t-26 -4.5q-40 0 -68 28l-408 408q-28 28 -28 68q0 13 4.5 26t9 22t15.5 22t16.5 18.5t20.5 19t18 16.5q30 28 68 28q10 0 18 -1.5t16.5 -5.5t13.5 -6t13.5 -10t11.5 -10t13 -12.5t12 -12.5q-14 14 -14 34t14 34l348 348q14 14 34 14t34 -14 q-2 2 -12.5 12t-12.5 13t-10 11.5t-10 13.5t-6 13.5t-5.5 16.5t-1.5 18q0 38 28 68q3 3 16.5 18t19 20.5t18.5 16.5t22 15.5t22 9t26 4.5q40 0 68 -28l408 -408q28 -28 28 -68q0 -13 -4.5 -26t-9 -22t-15.5 -22t-16.5 -18.5t-20.5 -19t-18 -16.5q-30 -28 -68 -28 q-10 0 -18 1.5t-16.5 5.5t-13.5 6t-13.5 10t-11.5 10t-13 12.5t-12 12.5q14 -14 14 -34t-14 -34l-126 -126l256 -256q43 43 96 43q52 0 91 -37l363 -363q37 -39 37 -91z" />
<glyph unicode="&#xf0e4;" horiz-adv-x="1792" d="M384 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM576 832q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1004 351l101 382q6 26 -7.5 48.5t-38.5 29.5 t-48 -6.5t-30 -39.5l-101 -382q-60 -5 -107 -43.5t-63 -98.5q-20 -77 20 -146t117 -89t146 20t89 117q16 60 -6 117t-72 91zM1664 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1024 1024q0 53 -37.5 90.5 t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1472 832q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1792 384q0 -261 -141 -483q-19 -29 -54 -29h-1402q-35 0 -54 29 q-141 221 -141 483q0 182 71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" />
<glyph unicode="&#xf0e5;" horiz-adv-x="1792" d="M896 1152q-204 0 -381.5 -69.5t-282 -187.5t-104.5 -255q0 -112 71.5 -213.5t201.5 -175.5l87 -50l-27 -96q-24 -91 -70 -172q152 63 275 171l43 38l57 -6q69 -8 130 -8q204 0 381.5 69.5t282 187.5t104.5 255t-104.5 255t-282 187.5t-381.5 69.5zM1792 640 q0 -174 -120 -321.5t-326 -233t-450 -85.5q-70 0 -145 8q-198 -175 -460 -242q-49 -14 -114 -22h-5q-15 0 -27 10.5t-16 27.5v1q-3 4 -0.5 12t2 10t4.5 9.5l6 9t7 8.5t8 9q7 8 31 34.5t34.5 38t31 39.5t32.5 51t27 59t26 76q-157 89 -247.5 220t-90.5 281q0 174 120 321.5 t326 233t450 85.5t450 -85.5t326 -233t120 -321.5z" />
<glyph unicode="&#xf0e6;" horiz-adv-x="1792" d="M704 1152q-153 0 -286 -52t-211.5 -141t-78.5 -191q0 -82 53 -158t149 -132l97 -56l-35 -84q34 20 62 39l44 31l53 -10q78 -14 153 -14q153 0 286 52t211.5 141t78.5 191t-78.5 191t-211.5 141t-286 52zM704 1280q191 0 353.5 -68.5t256.5 -186.5t94 -257t-94 -257 t-256.5 -186.5t-353.5 -68.5q-86 0 -176 16q-124 -88 -278 -128q-36 -9 -86 -16h-3q-11 0 -20.5 8t-11.5 21q-1 3 -1 6.5t0.5 6.5t2 6l2.5 5t3.5 5.5t4 5t4.5 5t4 4.5q5 6 23 25t26 29.5t22.5 29t25 38.5t20.5 44q-124 72 -195 177t-71 224q0 139 94 257t256.5 186.5 t353.5 68.5zM1526 111q10 -24 20.5 -44t25 -38.5t22.5 -29t26 -29.5t23 -25q1 -1 4 -4.5t4.5 -5t4 -5t3.5 -5.5l2.5 -5t2 -6t0.5 -6.5t-1 -6.5q-3 -14 -13 -22t-22 -7q-50 7 -86 16q-154 40 -278 128q-90 -16 -176 -16q-271 0 -472 132q58 -4 88 -4q161 0 309 45t264 129 q125 92 192 212t67 254q0 77 -23 152q129 -71 204 -178t75 -230q0 -120 -71 -224.5t-195 -176.5z" />
<glyph unicode="&#xf0e7;" horiz-adv-x="896" d="M885 970q18 -20 7 -44l-540 -1157q-13 -25 -42 -25q-4 0 -14 2q-17 5 -25.5 19t-4.5 30l197 808l-406 -101q-4 -1 -12 -1q-18 0 -31 11q-18 15 -13 39l201 825q4 14 16 23t28 9h328q19 0 32 -12.5t13 -29.5q0 -8 -5 -18l-171 -463l396 98q8 2 12 2q19 0 34 -15z" />
<glyph unicode="&#xf0e8;" horiz-adv-x="1792" d="M1792 288v-320q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192h-512v-192h96q40 0 68 -28t28 -68v-320q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192h-512v-192h96q40 0 68 -28t28 -68v-320 q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192q0 52 38 90t90 38h512v192h-96q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h320q40 0 68 -28t28 -68v-320q0 -40 -28 -68t-68 -28h-96v-192h512q52 0 90 -38t38 -90v-192h96q40 0 68 -28t28 -68 z" />
<glyph unicode="&#xf0e9;" horiz-adv-x="1664" d="M896 708v-580q0 -104 -76 -180t-180 -76t-180 76t-76 180q0 26 19 45t45 19t45 -19t19 -45q0 -50 39 -89t89 -39t89 39t39 89v580q33 11 64 11t64 -11zM1664 681q0 -13 -9.5 -22.5t-22.5 -9.5q-11 0 -23 10q-49 46 -93 69t-102 23q-68 0 -128 -37t-103 -97 q-7 -10 -17.5 -28t-14.5 -24q-11 -17 -28 -17q-18 0 -29 17q-4 6 -14.5 24t-17.5 28q-43 60 -102.5 97t-127.5 37t-127.5 -37t-102.5 -97q-7 -10 -17.5 -28t-14.5 -24q-11 -17 -29 -17q-17 0 -28 17q-4 6 -14.5 24t-17.5 28q-43 60 -103 97t-128 37q-58 0 -102 -23t-93 -69 q-12 -10 -23 -10q-13 0 -22.5 9.5t-9.5 22.5q0 5 1 7q45 183 172.5 319.5t298 204.5t360.5 68q140 0 274.5 -40t246.5 -113.5t194.5 -187t115.5 -251.5q1 -2 1 -7zM896 1408v-98q-42 2 -64 2t-64 -2v98q0 26 19 45t45 19t45 -19t19 -45z" />
<glyph unicode="&#xf0ea;" horiz-adv-x="1792" d="M768 -128h896v640h-416q-40 0 -68 28t-28 68v416h-384v-1152zM1024 1312v64q0 13 -9.5 22.5t-22.5 9.5h-704q-13 0 -22.5 -9.5t-9.5 -22.5v-64q0 -13 9.5 -22.5t22.5 -9.5h704q13 0 22.5 9.5t9.5 22.5zM1280 640h299l-299 299v-299zM1792 512v-672q0 -40 -28 -68t-68 -28 h-960q-40 0 -68 28t-28 68v160h-544q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h1088q40 0 68 -28t28 -68v-328q21 -13 36 -28l408 -408q28 -28 48 -76t20 -88z" />
<glyph unicode="&#xf0eb;" horiz-adv-x="1024" d="M736 960q0 -13 -9.5 -22.5t-22.5 -9.5t-22.5 9.5t-9.5 22.5q0 46 -54 71t-106 25q-13 0 -22.5 9.5t-9.5 22.5t9.5 22.5t22.5 9.5q50 0 99.5 -16t87 -54t37.5 -90zM896 960q0 72 -34.5 134t-90 101.5t-123 62t-136.5 22.5t-136.5 -22.5t-123 -62t-90 -101.5t-34.5 -134 q0 -101 68 -180q10 -11 30.5 -33t30.5 -33q128 -153 141 -298h228q13 145 141 298q10 11 30.5 33t30.5 33q68 79 68 180zM1024 960q0 -155 -103 -268q-45 -49 -74.5 -87t-59.5 -95.5t-34 -107.5q47 -28 47 -82q0 -37 -25 -64q25 -27 25 -64q0 -52 -45 -81q13 -23 13 -47 q0 -46 -31.5 -71t-77.5 -25q-20 -44 -60 -70t-87 -26t-87 26t-60 70q-46 0 -77.5 25t-31.5 71q0 24 13 47q-45 29 -45 81q0 37 25 64q-25 27 -25 64q0 54 47 82q-4 50 -34 107.5t-59.5 95.5t-74.5 87q-103 113 -103 268q0 99 44.5 184.5t117 142t164 89t186.5 32.5 t186.5 -32.5t164 -89t117 -142t44.5 -184.5z" />
<glyph unicode="&#xf0ec;" horiz-adv-x="1792" d="M1792 352v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5q-12 0 -24 10l-319 320q-9 9 -9 22q0 14 9 23l320 320q9 9 23 9q13 0 22.5 -9.5t9.5 -22.5v-192h1376q13 0 22.5 -9.5t9.5 -22.5zM1792 896q0 -14 -9 -23l-320 -320q-9 -9 -23 -9 q-13 0 -22.5 9.5t-9.5 22.5v192h-1376q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1376v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23z" />
<glyph unicode="&#xf0ed;" horiz-adv-x="1920" d="M1280 608q0 14 -9 23t-23 9h-224v352q0 13 -9.5 22.5t-22.5 9.5h-192q-13 0 -22.5 -9.5t-9.5 -22.5v-352h-224q-13 0 -22.5 -9.5t-9.5 -22.5q0 -14 9 -23l352 -352q9 -9 23 -9t23 9l351 351q10 12 10 24zM1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088 q-185 0 -316.5 131.5t-131.5 316.5q0 130 70 240t188 165q-2 30 -2 43q0 212 150 362t362 150q156 0 285.5 -87t188.5 -231q71 62 166 62q106 0 181 -75t75 -181q0 -76 -41 -138q130 -31 213.5 -135.5t83.5 -238.5z" />
<glyph unicode="&#xf0ee;" horiz-adv-x="1920" d="M1280 672q0 14 -9 23l-352 352q-9 9 -23 9t-23 -9l-351 -351q-10 -12 -10 -24q0 -14 9 -23t23 -9h224v-352q0 -13 9.5 -22.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 22.5v352h224q13 0 22.5 9.5t9.5 22.5zM1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088 q-185 0 -316.5 131.5t-131.5 316.5q0 130 70 240t188 165q-2 30 -2 43q0 212 150 362t362 150q156 0 285.5 -87t188.5 -231q71 62 166 62q106 0 181 -75t75 -181q0 -76 -41 -138q130 -31 213.5 -135.5t83.5 -238.5z" />
<glyph unicode="&#xf0f0;" horiz-adv-x="1408" d="M384 192q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45t45 19t45 -19t19 -45zM1408 131q0 -121 -73 -190t-194 -69h-874q-121 0 -194 69t-73 190q0 68 5.5 131t24 138t47.5 132.5t81 103t120 60.5q-22 -52 -22 -120v-203q-58 -20 -93 -70t-35 -111q0 -80 56 -136t136 -56 t136 56t56 136q0 61 -35.5 111t-92.5 70v203q0 62 25 93q132 -104 295 -104t295 104q25 -31 25 -93v-64q-106 0 -181 -75t-75 -181v-89q-32 -29 -32 -71q0 -40 28 -68t68 -28t68 28t28 68q0 42 -32 71v89q0 52 38 90t90 38t90 -38t38 -90v-89q-32 -29 -32 -71q0 -40 28 -68 t68 -28t68 28t28 68q0 42 -32 71v89q0 68 -34.5 127.5t-93.5 93.5q0 10 0.5 42.5t0 48t-2.5 41.5t-7 47t-13 40q68 -15 120 -60.5t81 -103t47.5 -132.5t24 -138t5.5 -131zM1088 1024q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5 t271.5 -112.5t112.5 -271.5z" />
<glyph unicode="&#xf0f1;" horiz-adv-x="1408" d="M1280 832q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 832q0 -62 -35.5 -111t-92.5 -70v-395q0 -159 -131.5 -271.5t-316.5 -112.5t-316.5 112.5t-131.5 271.5v132q-164 20 -274 128t-110 252v512q0 26 19 45t45 19q6 0 16 -2q17 30 47 48 t65 18q53 0 90.5 -37.5t37.5 -90.5t-37.5 -90.5t-90.5 -37.5q-33 0 -64 18v-402q0 -106 94 -181t226 -75t226 75t94 181v402q-31 -18 -64 -18q-53 0 -90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5q35 0 65 -18t47 -48q10 2 16 2q26 0 45 -19t19 -45v-512q0 -144 -110 -252 t-274 -128v-132q0 -106 94 -181t226 -75t226 75t94 181v395q-57 21 -92.5 70t-35.5 111q0 80 56 136t136 56t136 -56t56 -136z" />
<glyph unicode="&#xf0f2;" horiz-adv-x="1792" d="M640 1152h512v128h-512v-128zM288 1152v-1280h-64q-92 0 -158 66t-66 158v832q0 92 66 158t158 66h64zM1408 1152v-1280h-1024v1280h128v160q0 40 28 68t68 28h576q40 0 68 -28t28 -68v-160h128zM1792 928v-832q0 -92 -66 -158t-158 -66h-64v1280h64q92 0 158 -66 t66 -158z" />
<glyph unicode="&#xf0f3;" horiz-adv-x="1664" d="M848 -160q0 16 -16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5q16 0 16 16zM1664 128q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-181 75t-75 181h-448q-52 0 -90 38t-38 90q190 161 287 397.5t97 498.5 q0 165 96 262t264 117q-8 18 -8 37q0 40 28 68t68 28t68 -28t28 -68q0 -19 -8 -37q168 -20 264 -117t96 -262q0 -262 97 -498.5t287 -397.5z" />
<glyph unicode="&#xf0f4;" horiz-adv-x="1920" d="M1664 896q0 80 -56 136t-136 56h-64v-384h64q80 0 136 56t56 136zM0 128h1792q0 -106 -75 -181t-181 -75h-1280q-106 0 -181 75t-75 181zM1856 896q0 -159 -112.5 -271.5t-271.5 -112.5h-64v-32q0 -92 -66 -158t-158 -66h-704q-92 0 -158 66t-66 158v736q0 26 19 45 t45 19h1152q159 0 271.5 -112.5t112.5 -271.5z" />
<glyph unicode="&#xf0f5;" horiz-adv-x="1408" d="M640 1472v-640q0 -61 -35.5 -111t-92.5 -70v-779q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v779q-57 20 -92.5 70t-35.5 111v640q0 26 19 45t45 19t45 -19t19 -45v-416q0 -26 19 -45t45 -19t45 19t19 45v416q0 26 19 45t45 19t45 -19t19 -45v-416q0 -26 19 -45 t45 -19t45 19t19 45v416q0 26 19 45t45 19t45 -19t19 -45zM1408 1472v-1600q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v512h-224q-13 0 -22.5 9.5t-9.5 22.5v800q0 132 94 226t226 94h256q26 0 45 -19t19 -45z" />
<glyph unicode="&#xf0f6;" horiz-adv-x="1280" d="M1024 352v-64q0 -14 -9 -23t-23 -9h-704q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h704q14 0 23 -9t9 -23zM1024 608v-64q0 -14 -9 -23t-23 -9h-704q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h704q14 0 23 -9t9 -23zM128 0h1024v768h-416q-40 0 -68 28t-28 68v416h-512v-1280z M768 896h376q-10 29 -22 41l-313 313q-12 12 -41 22v-376zM1280 864v-896q0 -40 -28 -68t-68 -28h-1088q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h640q40 0 88 -20t76 -48l312 -312q28 -28 48 -76t20 -88z" />
<glyph unicode="&#xf0f7;" horiz-adv-x="1408" d="M384 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 -128h384v1536h-1152v-1536h384v224q0 13 9.5 22.5t22.5 9.5h320q13 0 22.5 -9.5t9.5 -22.5v-224zM1408 1472v-1664q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v1664q0 26 19 45t45 19h1280q26 0 45 -19t19 -45z" />
<glyph unicode="&#xf0f8;" horiz-adv-x="1408" d="M384 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M1152 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M896 -128h384v1152h-256v-32q0 -40 -28 -68t-68 -28h-448q-40 0 -68 28t-28 68v32h-256v-1152h384v224q0 13 9.5 22.5t22.5 9.5h320q13 0 22.5 -9.5t9.5 -22.5v-224zM896 1056v320q0 13 -9.5 22.5t-22.5 9.5h-64q-13 0 -22.5 -9.5t-9.5 -22.5v-96h-128v96q0 13 -9.5 22.5 t-22.5 9.5h-64q-13 0 -22.5 -9.5t-9.5 -22.5v-320q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5v96h128v-96q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5zM1408 1088v-1280q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v1280q0 26 19 45t45 19h320 v288q0 40 28 68t68 28h448q40 0 68 -28t28 -68v-288h320q26 0 45 -19t19 -45z" />
<glyph unicode="&#xf0f9;" horiz-adv-x="1920" d="M640 128q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM256 640h384v256h-158q-14 -2 -22 -9l-195 -195q-7 -12 -9 -22v-30zM1536 128q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5 t90.5 37.5t37.5 90.5zM1664 800v192q0 14 -9 23t-23 9h-224v224q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-224h-224q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h224v-224q0 -14 9 -23t23 -9h192q14 0 23 9t9 23v224h224q14 0 23 9t9 23zM1920 1344v-1152 q0 -26 -19 -45t-45 -19h-192q0 -106 -75 -181t-181 -75t-181 75t-75 181h-384q0 -106 -75 -181t-181 -75t-181 75t-75 181h-128q-26 0 -45 19t-19 45t19 45t45 19v416q0 26 13 58t32 51l198 198q19 19 51 32t58 13h160v320q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" />
<glyph unicode="&#xf0fa;" horiz-adv-x="1792" d="M1280 416v192q0 14 -9 23t-23 9h-224v224q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-224h-224q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h224v-224q0 -14 9 -23t23 -9h192q14 0 23 9t9 23v224h224q14 0 23 9t9 23zM640 1152h512v128h-512v-128zM256 1152v-1280h-32 q-92 0 -158 66t-66 158v832q0 92 66 158t158 66h32zM1440 1152v-1280h-1088v1280h160v160q0 40 28 68t68 28h576q40 0 68 -28t28 -68v-160h160zM1792 928v-832q0 -92 -66 -158t-158 -66h-32v1280h32q92 0 158 -66t66 -158z" />
<glyph unicode="&#xf0fb;" horiz-adv-x="1920" d="M1920 576q-1 -32 -288 -96l-352 -32l-224 -64h-64l-293 -352h69q26 0 45 -4.5t19 -11.5t-19 -11.5t-45 -4.5h-96h-160h-64v32h64v416h-160l-192 -224h-96l-32 32v192h32v32h128v8l-192 24v128l192 24v8h-128v32h-32v192l32 32h96l192 -224h160v416h-64v32h64h160h96 q26 0 45 -4.5t19 -11.5t-19 -11.5t-45 -4.5h-69l293 -352h64l224 -64l352 -32q261 -58 287 -93z" />
<glyph unicode="&#xf0fc;" horiz-adv-x="1664" d="M640 640v384h-256v-256q0 -53 37.5 -90.5t90.5 -37.5h128zM1664 192v-192h-1152v192l128 192h-128q-159 0 -271.5 112.5t-112.5 271.5v320l-64 64l32 128h480l32 128h960l32 -192l-64 -32v-800z" />
<glyph unicode="&#xf0fd;" d="M1280 192v896q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-320h-512v320q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-896q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v320h512v-320q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
<glyph unicode="&#xf0fe;" d="M1280 576v128q0 26 -19 45t-45 19h-320v320q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-320h-320q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h320v-320q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v320h320q26 0 45 19t19 45zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
<glyph unicode="&#xf100;" horiz-adv-x="1024" d="M627 160q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23zM1011 160q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23 t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23z" />
<glyph unicode="&#xf101;" horiz-adv-x="1024" d="M595 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23zM979 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23 l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
<glyph unicode="&#xf102;" horiz-adv-x="1152" d="M1075 224q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23zM1075 608q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393 q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
<glyph unicode="&#xf103;" horiz-adv-x="1152" d="M1075 672q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23zM1075 1056q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23 t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" />
<glyph unicode="&#xf104;" horiz-adv-x="640" d="M627 992q0 -13 -10 -23l-393 -393l393 -393q10 -10 10 -23t-10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" />
<glyph unicode="&#xf105;" horiz-adv-x="640" d="M595 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
<glyph unicode="&#xf106;" horiz-adv-x="1152" d="M1075 352q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
<glyph unicode="&#xf107;" horiz-adv-x="1152" d="M1075 800q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" />
<glyph unicode="&#xf108;" horiz-adv-x="1920" d="M1792 544v832q0 13 -9.5 22.5t-22.5 9.5h-1600q-13 0 -22.5 -9.5t-9.5 -22.5v-832q0 -13 9.5 -22.5t22.5 -9.5h1600q13 0 22.5 9.5t9.5 22.5zM1920 1376v-1088q0 -66 -47 -113t-113 -47h-544q0 -37 16 -77.5t32 -71t16 -43.5q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19 t-19 45q0 14 16 44t32 70t16 78h-544q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" />
<glyph unicode="&#xf109;" horiz-adv-x="1920" d="M416 256q-66 0 -113 47t-47 113v704q0 66 47 113t113 47h1088q66 0 113 -47t47 -113v-704q0 -66 -47 -113t-113 -47h-1088zM384 1120v-704q0 -13 9.5 -22.5t22.5 -9.5h1088q13 0 22.5 9.5t9.5 22.5v704q0 13 -9.5 22.5t-22.5 9.5h-1088q-13 0 -22.5 -9.5t-9.5 -22.5z M1760 192h160v-96q0 -40 -47 -68t-113 -28h-1600q-66 0 -113 28t-47 68v96h160h1600zM1040 96q16 0 16 16t-16 16h-160q-16 0 -16 -16t16 -16h160z" />
<glyph unicode="&#xf10a;" horiz-adv-x="1152" d="M640 128q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1024 288v960q0 13 -9.5 22.5t-22.5 9.5h-832q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h832q13 0 22.5 9.5t9.5 22.5zM1152 1248v-1088q0 -66 -47 -113t-113 -47h-832 q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h832q66 0 113 -47t47 -113z" />
<glyph unicode="&#xf10b;" horiz-adv-x="768" d="M464 128q0 33 -23.5 56.5t-56.5 23.5t-56.5 -23.5t-23.5 -56.5t23.5 -56.5t56.5 -23.5t56.5 23.5t23.5 56.5zM672 288v704q0 13 -9.5 22.5t-22.5 9.5h-512q-13 0 -22.5 -9.5t-9.5 -22.5v-704q0 -13 9.5 -22.5t22.5 -9.5h512q13 0 22.5 9.5t9.5 22.5zM480 1136 q0 16 -16 16h-160q-16 0 -16 -16t16 -16h160q16 0 16 16zM768 1152v-1024q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v1024q0 52 38 90t90 38h512q52 0 90 -38t38 -90z" />
<glyph unicode="&#xf10c;" d="M768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103 t279.5 -279.5t103 -385.5z" />
<glyph unicode="&#xf10d;" horiz-adv-x="1664" d="M768 576v-384q0 -80 -56 -136t-136 -56h-384q-80 0 -136 56t-56 136v704q0 104 40.5 198.5t109.5 163.5t163.5 109.5t198.5 40.5h64q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-64q-106 0 -181 -75t-75 -181v-32q0 -40 28 -68t68 -28h224q80 0 136 -56t56 -136z M1664 576v-384q0 -80 -56 -136t-136 -56h-384q-80 0 -136 56t-56 136v704q0 104 40.5 198.5t109.5 163.5t163.5 109.5t198.5 40.5h64q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-64q-106 0 -181 -75t-75 -181v-32q0 -40 28 -68t68 -28h224q80 0 136 -56t56 -136z" />
<glyph unicode="&#xf10e;" horiz-adv-x="1664" d="M768 1216v-704q0 -104 -40.5 -198.5t-109.5 -163.5t-163.5 -109.5t-198.5 -40.5h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64q106 0 181 75t75 181v32q0 40 -28 68t-68 28h-224q-80 0 -136 56t-56 136v384q0 80 56 136t136 56h384q80 0 136 -56t56 -136zM1664 1216 v-704q0 -104 -40.5 -198.5t-109.5 -163.5t-163.5 -109.5t-198.5 -40.5h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64q106 0 181 75t75 181v32q0 40 -28 68t-68 28h-224q-80 0 -136 56t-56 136v384q0 80 56 136t136 56h384q80 0 136 -56t56 -136z" />
<glyph unicode="&#xf110;" horiz-adv-x="1568" d="M496 192q0 -60 -42.5 -102t-101.5 -42q-60 0 -102 42t-42 102t42 102t102 42q59 0 101.5 -42t42.5 -102zM928 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM320 640q0 -66 -47 -113t-113 -47t-113 47t-47 113 t47 113t113 47t113 -47t47 -113zM1360 192q0 -46 -33 -79t-79 -33t-79 33t-33 79t33 79t79 33t79 -33t33 -79zM528 1088q0 -73 -51.5 -124.5t-124.5 -51.5t-124.5 51.5t-51.5 124.5t51.5 124.5t124.5 51.5t124.5 -51.5t51.5 -124.5zM992 1280q0 -80 -56 -136t-136 -56 t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1536 640q0 -40 -28 -68t-68 -28t-68 28t-28 68t28 68t68 28t68 -28t28 -68zM1328 1088q0 -33 -23.5 -56.5t-56.5 -23.5t-56.5 23.5t-23.5 56.5t23.5 56.5t56.5 23.5t56.5 -23.5t23.5 -56.5z" />
<glyph unicode="&#xf111;" d="M1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
<glyph unicode="&#xf112;" horiz-adv-x="1792" d="M1792 416q0 -166 -127 -451q-3 -7 -10.5 -24t-13.5 -30t-13 -22q-12 -17 -28 -17q-15 0 -23.5 10t-8.5 25q0 9 2.5 26.5t2.5 23.5q5 68 5 123q0 101 -17.5 181t-48.5 138.5t-80 101t-105.5 69.5t-133 42.5t-154 21.5t-175.5 6h-224v-256q0 -26 -19 -45t-45 -19t-45 19 l-512 512q-19 19 -19 45t19 45l512 512q19 19 45 19t45 -19t19 -45v-256h224q713 0 875 -403q53 -134 53 -333z" />
<glyph unicode="&#xf113;" horiz-adv-x="1664" d="M640 320q0 -40 -12.5 -82t-43 -76t-72.5 -34t-72.5 34t-43 76t-12.5 82t12.5 82t43 76t72.5 34t72.5 -34t43 -76t12.5 -82zM1280 320q0 -40 -12.5 -82t-43 -76t-72.5 -34t-72.5 34t-43 76t-12.5 82t12.5 82t43 76t72.5 34t72.5 -34t43 -76t12.5 -82zM1440 320 q0 120 -69 204t-187 84q-41 0 -195 -21q-71 -11 -157 -11t-157 11q-152 21 -195 21q-118 0 -187 -84t-69 -204q0 -88 32 -153.5t81 -103t122 -60t140 -29.5t149 -7h168q82 0 149 7t140 29.5t122 60t81 103t32 153.5zM1664 496q0 -207 -61 -331q-38 -77 -105.5 -133t-141 -86 t-170 -47.5t-171.5 -22t-167 -4.5q-78 0 -142 3t-147.5 12.5t-152.5 30t-137 51.5t-121 81t-86 115q-62 123 -62 331q0 237 136 396q-27 82 -27 170q0 116 51 218q108 0 190 -39.5t189 -123.5q147 35 309 35q148 0 280 -32q105 82 187 121t189 39q51 -102 51 -218 q0 -87 -27 -168q136 -160 136 -398z" />
<glyph unicode="&#xf114;" horiz-adv-x="1664" d="M1536 224v704q0 40 -28 68t-68 28h-704q-40 0 -68 28t-28 68v64q0 40 -28 68t-68 28h-320q-40 0 -68 -28t-28 -68v-960q0 -40 28 -68t68 -28h1216q40 0 68 28t28 68zM1664 928v-704q0 -92 -66 -158t-158 -66h-1216q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320 q92 0 158 -66t66 -158v-32h672q92 0 158 -66t66 -158z" />
<glyph unicode="&#xf115;" horiz-adv-x="1920" d="M1781 605q0 35 -53 35h-1088q-40 0 -85.5 -21.5t-71.5 -52.5l-294 -363q-18 -24 -18 -40q0 -35 53 -35h1088q40 0 86 22t71 53l294 363q18 22 18 39zM640 768h768v160q0 40 -28 68t-68 28h-576q-40 0 -68 28t-28 68v64q0 40 -28 68t-68 28h-320q-40 0 -68 -28t-28 -68 v-853l256 315q44 53 116 87.5t140 34.5zM1909 605q0 -62 -46 -120l-295 -363q-43 -53 -116 -87.5t-140 -34.5h-1088q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h544q92 0 158 -66t66 -158v-160h192q54 0 99 -24.5t67 -70.5q15 -32 15 -68z " />
<glyph unicode="&#xf116;" horiz-adv-x="1152" d="M896 608v-64q0 -14 -9 -23t-23 -9h-224v-224q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v224h-224q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h224v224q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-224h224q14 0 23 -9t9 -23zM1024 224v704q0 40 -28 68t-68 28h-704q-40 0 -68 -28 t-28 -68v-704q0 -40 28 -68t68 -28h704q40 0 68 28t28 68zM1152 928v-704q0 -92 -65.5 -158t-158.5 -66h-704q-93 0 -158.5 66t-65.5 158v704q0 93 65.5 158.5t158.5 65.5h704q93 0 158.5 -65.5t65.5 -158.5z" />
<glyph unicode="&#xf117;" horiz-adv-x="1152" d="M928 1152q93 0 158.5 -65.5t65.5 -158.5v-704q0 -92 -65.5 -158t-158.5 -66h-704q-93 0 -158.5 66t-65.5 158v704q0 93 65.5 158.5t158.5 65.5h704zM1024 224v704q0 40 -28 68t-68 28h-704q-40 0 -68 -28t-28 -68v-704q0 -40 28 -68t68 -28h704q40 0 68 28t28 68z M864 640q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-576q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h576z" />
<glyph unicode="&#xf118;" d="M1134 461q-37 -121 -138 -195t-228 -74t-228 74t-138 195q-8 25 4 48.5t38 31.5q25 8 48.5 -4t31.5 -38q25 -80 92.5 -129.5t151.5 -49.5t151.5 49.5t92.5 129.5q8 26 32 38t49 4t37 -31.5t4 -48.5zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5 t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5 t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
<glyph unicode="&#xf119;" d="M1134 307q8 -25 -4 -48.5t-37 -31.5t-49 4t-32 38q-25 80 -92.5 129.5t-151.5 49.5t-151.5 -49.5t-92.5 -129.5q-8 -26 -31.5 -38t-48.5 -4q-26 8 -38 31.5t-4 48.5q37 121 138 195t228 74t228 -74t138 -195zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5 t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204 t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
<glyph unicode="&#xf11a;" d="M1152 448q0 -26 -19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h640q26 0 45 -19t19 -45zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5 t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
<glyph unicode="&#xf11b;" horiz-adv-x="1920" d="M832 448v128q0 14 -9 23t-23 9h-192v192q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-192h-192q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h192v-192q0 -14 9 -23t23 -9h128q14 0 23 9t9 23v192h192q14 0 23 9t9 23zM1408 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5 t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1664 640q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1920 512q0 -212 -150 -362t-362 -150q-192 0 -338 128h-220q-146 -128 -338 -128q-212 0 -362 150 t-150 362t150 362t362 150h896q212 0 362 -150t150 -362z" />
<glyph unicode="&#xf11c;" horiz-adv-x="1920" d="M384 368v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM512 624v-96q0 -16 -16 -16h-224q-16 0 -16 16v96q0 16 16 16h224q16 0 16 -16zM384 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1408 368v-96q0 -16 -16 -16 h-864q-16 0 -16 16v96q0 16 16 16h864q16 0 16 -16zM768 624v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM640 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1024 624v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16 h96q16 0 16 -16zM896 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1280 624v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1664 368v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1152 880v-96 q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1408 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1664 880v-352q0 -16 -16 -16h-224q-16 0 -16 16v96q0 16 16 16h112v240q0 16 16 16h96q16 0 16 -16zM1792 128v896h-1664v-896 h1664zM1920 1024v-896q0 -53 -37.5 -90.5t-90.5 -37.5h-1664q-53 0 -90.5 37.5t-37.5 90.5v896q0 53 37.5 90.5t90.5 37.5h1664q53 0 90.5 -37.5t37.5 -90.5z" />
<glyph unicode="&#xf11d;" horiz-adv-x="1792" d="M1664 491v616q-169 -91 -306 -91q-82 0 -145 32q-100 49 -184 76.5t-178 27.5q-173 0 -403 -127v-599q245 113 433 113q55 0 103.5 -7.5t98 -26t77 -31t82.5 -39.5l28 -14q44 -22 101 -22q120 0 293 92zM320 1280q0 -35 -17.5 -64t-46.5 -46v-1266q0 -14 -9 -23t-23 -9 h-64q-14 0 -23 9t-9 23v1266q-29 17 -46.5 46t-17.5 64q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1792 1216v-763q0 -39 -35 -57q-10 -5 -17 -9q-218 -116 -369 -116q-88 0 -158 35l-28 14q-64 33 -99 48t-91 29t-114 14q-102 0 -235.5 -44t-228.5 -102 q-15 -9 -33 -9q-16 0 -32 8q-32 19 -32 56v742q0 35 31 55q35 21 78.5 42.5t114 52t152.5 49.5t155 19q112 0 209 -31t209 -86q38 -19 89 -19q122 0 310 112q22 12 31 17q31 16 62 -2q31 -20 31 -55z" />
<glyph unicode="&#xf11e;" horiz-adv-x="1792" d="M832 536v192q-181 -16 -384 -117v-185q205 96 384 110zM832 954v197q-172 -8 -384 -126v-189q215 111 384 118zM1664 491v184q-235 -116 -384 -71v224q-20 6 -39 15q-5 3 -33 17t-34.5 17t-31.5 15t-34.5 15.5t-32.5 13t-36 12.5t-35 8.5t-39.5 7.5t-39.5 4t-44 2 q-23 0 -49 -3v-222h19q102 0 192.5 -29t197.5 -82q19 -9 39 -15v-188q42 -17 91 -17q120 0 293 92zM1664 918v189q-169 -91 -306 -91q-45 0 -78 8v-196q148 -42 384 90zM320 1280q0 -35 -17.5 -64t-46.5 -46v-1266q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v1266 q-29 17 -46.5 46t-17.5 64q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1792 1216v-763q0 -39 -35 -57q-10 -5 -17 -9q-218 -116 -369 -116q-88 0 -158 35l-28 14q-64 33 -99 48t-91 29t-114 14q-102 0 -235.5 -44t-228.5 -102q-15 -9 -33 -9q-16 0 -32 8 q-32 19 -32 56v742q0 35 31 55q35 21 78.5 42.5t114 52t152.5 49.5t155 19q112 0 209 -31t209 -86q38 -19 89 -19q122 0 310 112q22 12 31 17q31 16 62 -2q31 -20 31 -55z" />
<glyph unicode="&#xf120;" horiz-adv-x="1664" d="M585 553l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23t-10 -23zM1664 96v-64q0 -14 -9 -23t-23 -9h-960q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h960q14 0 23 -9 t9 -23z" />
<glyph unicode="&#xf121;" horiz-adv-x="1920" d="M617 137l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23t-10 -23zM1208 1204l-373 -1291q-4 -13 -15.5 -19.5t-23.5 -2.5l-62 17q-13 4 -19.5 15.5t-2.5 24.5 l373 1291q4 13 15.5 19.5t23.5 2.5l62 -17q13 -4 19.5 -15.5t2.5 -24.5zM1865 553l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23t-10 -23z" />
<glyph unicode="&#xf122;" horiz-adv-x="1792" d="M640 454v-70q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-512 512q-19 19 -19 45t19 45l512 512q29 31 70 14q39 -17 39 -59v-69l-397 -398q-19 -19 -19 -45t19 -45zM1792 416q0 -58 -17 -133.5t-38.5 -138t-48 -125t-40.5 -90.5l-20 -40q-8 -17 -28 -17q-6 0 -9 1 q-25 8 -23 34q43 400 -106 565q-64 71 -170.5 110.5t-267.5 52.5v-251q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-512 512q-19 19 -19 45t19 45l512 512q29 31 70 14q39 -17 39 -59v-262q411 -28 599 -221q169 -173 169 -509z" />
<glyph unicode="&#xf123;" horiz-adv-x="1664" d="M1186 579l257 250l-356 52l-66 10l-30 60l-159 322v-963l59 -31l318 -168l-60 355l-12 66zM1638 841l-363 -354l86 -500q5 -33 -6 -51.5t-34 -18.5q-17 0 -40 12l-449 236l-449 -236q-23 -12 -40 -12q-23 0 -34 18.5t-6 51.5l86 500l-364 354q-32 32 -23 59.5t54 34.5 l502 73l225 455q20 41 49 41q28 0 49 -41l225 -455l502 -73q45 -7 54 -34.5t-24 -59.5z" />
<glyph unicode="&#xf124;" horiz-adv-x="1408" d="M1401 1187l-640 -1280q-17 -35 -57 -35q-5 0 -15 2q-22 5 -35.5 22.5t-13.5 39.5v576h-576q-22 0 -39.5 13.5t-22.5 35.5t4 42t29 30l1280 640q13 7 29 7q27 0 45 -19q15 -14 18.5 -34.5t-6.5 -39.5z" />
<glyph unicode="&#xf125;" horiz-adv-x="1664" d="M557 256h595v595zM512 301l595 595h-595v-595zM1664 224v-192q0 -14 -9 -23t-23 -9h-224v-224q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v224h-864q-14 0 -23 9t-9 23v864h-224q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h224v224q0 14 9 23t23 9h192q14 0 23 -9t9 -23 v-224h851l246 247q10 9 23 9t23 -9q9 -10 9 -23t-9 -23l-247 -246v-851h224q14 0 23 -9t9 -23z" />
<glyph unicode="&#xf126;" horiz-adv-x="1024" d="M288 64q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM288 1216q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM928 1088q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1024 1088q0 -52 -26 -96.5t-70 -69.5 q-2 -287 -226 -414q-68 -38 -203 -81q-128 -40 -169.5 -71t-41.5 -100v-26q44 -25 70 -69.5t26 -96.5q0 -80 -56 -136t-136 -56t-136 56t-56 136q0 52 26 96.5t70 69.5v820q-44 25 -70 69.5t-26 96.5q0 80 56 136t136 56t136 -56t56 -136q0 -52 -26 -96.5t-70 -69.5v-497 q54 26 154 57q55 17 87.5 29.5t70.5 31t59 39.5t40.5 51t28 69.5t8.5 91.5q-44 25 -70 69.5t-26 96.5q0 80 56 136t136 56t136 -56t56 -136z" />
<glyph unicode="&#xf127;" horiz-adv-x="1664" d="M439 265l-256 -256q-10 -9 -23 -9q-12 0 -23 9q-9 10 -9 23t9 23l256 256q10 9 23 9t23 -9q9 -10 9 -23t-9 -23zM608 224v-320q0 -14 -9 -23t-23 -9t-23 9t-9 23v320q0 14 9 23t23 9t23 -9t9 -23zM384 448q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9t-9 23t9 23t23 9h320 q14 0 23 -9t9 -23zM1648 320q0 -120 -85 -203l-147 -146q-83 -83 -203 -83q-121 0 -204 85l-334 335q-21 21 -42 56l239 18l273 -274q27 -27 68 -27.5t68 26.5l147 146q28 28 28 67q0 40 -28 68l-274 275l18 239q35 -21 56 -42l336 -336q84 -86 84 -204zM1031 1044l-239 -18 l-273 274q-28 28 -68 28q-39 0 -68 -27l-147 -146q-28 -28 -28 -67q0 -40 28 -68l274 -274l-18 -240q-35 21 -56 42l-336 336q-84 86 -84 204q0 120 85 203l147 146q83 83 203 83q121 0 204 -85l334 -335q21 -21 42 -56zM1664 960q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9 t-9 23t9 23t23 9h320q14 0 23 -9t9 -23zM1120 1504v-320q0 -14 -9 -23t-23 -9t-23 9t-9 23v320q0 14 9 23t23 9t23 -9t9 -23zM1527 1353l-256 -256q-11 -9 -23 -9t-23 9q-9 10 -9 23t9 23l256 256q10 9 23 9t23 -9q9 -10 9 -23t-9 -23z" />
<glyph unicode="&#xf128;" horiz-adv-x="1024" d="M704 280v-240q0 -16 -12 -28t-28 -12h-240q-16 0 -28 12t-12 28v240q0 16 12 28t28 12h240q16 0 28 -12t12 -28zM1020 880q0 -54 -15.5 -101t-35 -76.5t-55 -59.5t-57.5 -43.5t-61 -35.5q-41 -23 -68.5 -65t-27.5 -67q0 -17 -12 -32.5t-28 -15.5h-240q-15 0 -25.5 18.5 t-10.5 37.5v45q0 83 65 156.5t143 108.5q59 27 84 56t25 76q0 42 -46.5 74t-107.5 32q-65 0 -108 -29q-35 -25 -107 -115q-13 -16 -31 -16q-12 0 -25 8l-164 125q-13 10 -15.5 25t5.5 28q160 266 464 266q80 0 161 -31t146 -83t106 -127.5t41 -158.5z" />
<glyph unicode="&#xf129;" horiz-adv-x="640" d="M640 192v-128q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64v384h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h384q26 0 45 -19t19 -45v-576h64q26 0 45 -19t19 -45zM512 1344v-192q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v192 q0 26 19 45t45 19h256q26 0 45 -19t19 -45z" />
<glyph unicode="&#xf12a;" horiz-adv-x="640" d="M512 288v-224q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v224q0 26 19 45t45 19h256q26 0 45 -19t19 -45zM542 1344l-28 -768q-1 -26 -20.5 -45t-45.5 -19h-256q-26 0 -45.5 19t-20.5 45l-28 768q-1 26 17.5 45t44.5 19h320q26 0 44.5 -19t17.5 -45z" />
<glyph unicode="&#xf12b;" d="M897 167v-167h-248l-159 252l-24 42q-8 9 -11 21h-3l-9 -21q-10 -20 -25 -44l-155 -250h-258v167h128l197 291l-185 272h-137v168h276l139 -228q2 -4 23 -42q8 -9 11 -21h3q3 9 11 21l25 42l140 228h257v-168h-125l-184 -267l204 -296h109zM1534 846v-206h-514l-3 27 q-4 28 -4 46q0 64 26 117t65 86.5t84 65t84 54.5t65 54t26 64q0 38 -29.5 62.5t-70.5 24.5q-51 0 -97 -39q-14 -11 -36 -38l-105 92q26 37 63 66q83 65 188 65q110 0 178 -59.5t68 -158.5q0 -56 -24.5 -103t-62 -76.5t-81.5 -58.5t-82 -50.5t-65.5 -51.5t-30.5 -63h232v80 h126z" />
<glyph unicode="&#xf12c;" d="M897 167v-167h-248l-159 252l-24 42q-8 9 -11 21h-3l-9 -21q-10 -20 -25 -44l-155 -250h-258v167h128l197 291l-185 272h-137v168h276l139 -228q2 -4 23 -42q8 -9 11 -21h3q3 9 11 21l25 42l140 228h257v-168h-125l-184 -267l204 -296h109zM1536 -50v-206h-514l-4 27 q-3 45 -3 46q0 64 26 117t65 86.5t84 65t84 54.5t65 54t26 64q0 38 -29.5 62.5t-70.5 24.5q-51 0 -97 -39q-14 -11 -36 -38l-105 92q26 37 63 66q80 65 188 65q110 0 178 -59.5t68 -158.5q0 -66 -34.5 -118.5t-84 -86t-99.5 -62.5t-87 -63t-41 -73h232v80h126z" />
<glyph unicode="&#xf12d;" horiz-adv-x="1920" d="M896 128l336 384h-768l-336 -384h768zM1909 1205q15 -34 9.5 -71.5t-30.5 -65.5l-896 -1024q-38 -44 -96 -44h-768q-38 0 -69.5 20.5t-47.5 54.5q-15 34 -9.5 71.5t30.5 65.5l896 1024q38 44 96 44h768q38 0 69.5 -20.5t47.5 -54.5z" />
<glyph unicode="&#xf12e;" horiz-adv-x="1664" d="M1664 438q0 -81 -44.5 -135t-123.5 -54q-41 0 -77.5 17.5t-59 38t-56.5 38t-71 17.5q-110 0 -110 -124q0 -39 16 -115t15 -115v-5q-22 0 -33 -1q-34 -3 -97.5 -11.5t-115.5 -13.5t-98 -5q-61 0 -103 26.5t-42 83.5q0 37 17.5 71t38 56.5t38 59t17.5 77.5q0 79 -54 123.5 t-135 44.5q-84 0 -143 -45.5t-59 -127.5q0 -43 15 -83t33.5 -64.5t33.5 -53t15 -50.5q0 -45 -46 -89q-37 -35 -117 -35q-95 0 -245 24q-9 2 -27.5 4t-27.5 4l-13 2q-1 0 -3 1q-2 0 -2 1v1024q2 -1 17.5 -3.5t34 -5t21.5 -3.5q150 -24 245 -24q80 0 117 35q46 44 46 89 q0 22 -15 50.5t-33.5 53t-33.5 64.5t-15 83q0 82 59 127.5t144 45.5q80 0 134 -44.5t54 -123.5q0 -41 -17.5 -77.5t-38 -59t-38 -56.5t-17.5 -71q0 -57 42 -83.5t103 -26.5q64 0 180 15t163 17v-2q-1 -2 -3.5 -17.5t-5 -34t-3.5 -21.5q-24 -150 -24 -245q0 -80 35 -117 q44 -46 89 -46q22 0 50.5 15t53 33.5t64.5 33.5t83 15q82 0 127.5 -59t45.5 -143z" />
<glyph unicode="&#xf130;" horiz-adv-x="1152" d="M1152 832v-128q0 -221 -147.5 -384.5t-364.5 -187.5v-132h256q26 0 45 -19t19 -45t-19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h256v132q-217 24 -364.5 187.5t-147.5 384.5v128q0 26 19 45t45 19t45 -19t19 -45v-128q0 -185 131.5 -316.5t316.5 -131.5 t316.5 131.5t131.5 316.5v128q0 26 19 45t45 19t45 -19t19 -45zM896 1216v-512q0 -132 -94 -226t-226 -94t-226 94t-94 226v512q0 132 94 226t226 94t226 -94t94 -226z" />
<glyph unicode="&#xf131;" horiz-adv-x="1408" d="M271 591l-101 -101q-42 103 -42 214v128q0 26 19 45t45 19t45 -19t19 -45v-128q0 -53 15 -113zM1385 1193l-361 -361v-128q0 -132 -94 -226t-226 -94q-55 0 -109 19l-96 -96q97 -51 205 -51q185 0 316.5 131.5t131.5 316.5v128q0 26 19 45t45 19t45 -19t19 -45v-128 q0 -221 -147.5 -384.5t-364.5 -187.5v-132h256q26 0 45 -19t19 -45t-19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h256v132q-125 13 -235 81l-254 -254q-10 -10 -23 -10t-23 10l-82 82q-10 10 -10 23t10 23l1234 1234q10 10 23 10t23 -10l82 -82q10 -10 10 -23 t-10 -23zM1005 1325l-621 -621v512q0 132 94 226t226 94q102 0 184.5 -59t116.5 -152z" />
<glyph unicode="&#xf132;" horiz-adv-x="1280" d="M1088 576v640h-448v-1137q119 63 213 137q235 184 235 360zM1280 1344v-768q0 -86 -33.5 -170.5t-83 -150t-118 -127.5t-126.5 -103t-121 -77.5t-89.5 -49.5t-42.5 -20q-12 -6 -26 -6t-26 6q-16 7 -42.5 20t-89.5 49.5t-121 77.5t-126.5 103t-118 127.5t-83 150 t-33.5 170.5v768q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" />
<glyph unicode="&#xf133;" horiz-adv-x="1664" d="M128 -128h1408v1024h-1408v-1024zM512 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1280 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1664 1152v-1280 q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h128q52 0 90 -38t38 -90z" />
<glyph unicode="&#xf134;" horiz-adv-x="1408" d="M512 1344q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 1376v-320q0 -16 -12 -25q-8 -7 -20 -7q-4 0 -7 1l-448 96q-11 2 -18 11t-7 20h-256v-102q111 -23 183.5 -111t72.5 -203v-800q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v800 q0 106 62.5 190.5t161.5 114.5v111h-32q-59 0 -115 -23.5t-91.5 -53t-66 -66.5t-40.5 -53.5t-14 -24.5q-17 -35 -57 -35q-16 0 -29 7q-23 12 -31.5 37t3.5 49q5 10 14.5 26t37.5 53.5t60.5 70t85 67t108.5 52.5q-25 42 -25 86q0 66 47 113t113 47t113 -47t47 -113 q0 -33 -14 -64h302q0 11 7 20t18 11l448 96q3 1 7 1q12 0 20 -7q12 -9 12 -25z" />
<glyph unicode="&#xf135;" horiz-adv-x="1664" d="M1440 1088q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1664 1376q0 -249 -75.5 -430.5t-253.5 -360.5q-81 -80 -195 -176l-20 -379q-2 -16 -16 -26l-384 -224q-7 -4 -16 -4q-12 0 -23 9l-64 64q-13 14 -8 32l85 276l-281 281l-276 -85q-3 -1 -9 -1 q-14 0 -23 9l-64 64q-17 19 -5 39l224 384q10 14 26 16l379 20q96 114 176 195q188 187 358 258t431 71q14 0 24 -9.5t10 -22.5z" />
<glyph unicode="&#xf136;" horiz-adv-x="1792" d="M1708 881l-188 -881h-304l181 849q4 21 1 43q-4 20 -16 35q-10 14 -28 24q-18 9 -40 9h-197l-205 -960h-303l204 960h-304l-205 -960h-304l272 1280h1139q157 0 245 -118q86 -116 52 -281z" />
<glyph unicode="&#xf137;" d="M909 141l102 102q19 19 19 45t-19 45l-307 307l307 307q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-454 -454q-19 -19 -19 -45t19 -45l454 -454q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
<glyph unicode="&#xf138;" d="M717 141l454 454q19 19 19 45t-19 45l-454 454q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l307 -307l-307 -307q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
<glyph unicode="&#xf139;" d="M1165 397l102 102q19 19 19 45t-19 45l-454 454q-19 19 -45 19t-45 -19l-454 -454q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19l307 307l307 -307q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
<glyph unicode="&#xf13a;" d="M813 237l454 454q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-307 -307l-307 307q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l454 -454q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
<glyph unicode="&#xf13b;" horiz-adv-x="1408" d="M1130 939l16 175h-884l47 -534h612l-22 -228l-197 -53l-196 53l-13 140h-175l22 -278l362 -100h4v1l359 99l50 544h-644l-15 181h674zM0 1408h1408l-128 -1438l-578 -162l-574 162z" />
<glyph unicode="&#xf13c;" horiz-adv-x="1792" d="M275 1408h1505l-266 -1333l-804 -267l-698 267l71 356h297l-29 -147l422 -161l486 161l68 339h-1208l58 297h1209l38 191h-1208z" />
<glyph unicode="&#xf13d;" horiz-adv-x="1792" d="M960 1280q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1792 352v-352q0 -22 -20 -30q-8 -2 -12 -2q-13 0 -23 9l-93 93q-119 -143 -318.5 -226.5t-429.5 -83.5t-429.5 83.5t-318.5 226.5l-93 -93q-9 -9 -23 -9q-4 0 -12 2q-20 8 -20 30v352 q0 14 9 23t23 9h352q22 0 30 -20q8 -19 -7 -35l-100 -100q67 -91 189.5 -153.5t271.5 -82.5v647h-192q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h192v163q-58 34 -93 92.5t-35 128.5q0 106 75 181t181 75t181 -75t75 -181q0 -70 -35 -128.5t-93 -92.5v-163h192q26 0 45 -19 t19 -45v-128q0 -26 -19 -45t-45 -19h-192v-647q149 20 271.5 82.5t189.5 153.5l-100 100q-15 16 -7 35q8 20 30 20h352q14 0 23 -9t9 -23z" />
<glyph unicode="&#xf13e;" horiz-adv-x="1152" d="M1056 768q40 0 68 -28t28 -68v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h32v320q0 185 131.5 316.5t316.5 131.5t316.5 -131.5t131.5 -316.5q0 -26 -19 -45t-45 -19h-64q-26 0 -45 19t-19 45q0 106 -75 181t-181 75t-181 -75t-75 -181 v-320h736z" />
<glyph unicode="&#xf140;" d="M1024 640q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181zM1152 640q0 159 -112.5 271.5t-271.5 112.5t-271.5 -112.5t-112.5 -271.5t112.5 -271.5t271.5 -112.5t271.5 112.5t112.5 271.5zM1280 640q0 -212 -150 -362t-362 -150t-362 150 t-150 362t150 362t362 150t362 -150t150 -362zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
<glyph unicode="&#xf141;" horiz-adv-x="1408" d="M384 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM896 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM1408 800v-192q0 -40 -28 -68t-68 -28h-192 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68z" />
<glyph unicode="&#xf142;" horiz-adv-x="384" d="M384 288v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM384 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM384 1312v-192q0 -40 -28 -68t-68 -28h-192 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68z" />
<glyph unicode="&#xf143;" d="M512 256q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM863 162q-13 232 -177 396t-396 177q-14 1 -24 -9t-10 -23v-128q0 -13 8.5 -22t21.5 -10q154 -11 264 -121t121 -264q1 -13 10 -21.5t22 -8.5h128q13 0 23 10 t9 24zM1247 161q-5 154 -56 297.5t-139.5 260t-205 205t-260 139.5t-297.5 56q-14 1 -23 -9q-10 -10 -10 -23v-128q0 -13 9 -22t22 -10q204 -7 378 -111.5t278.5 -278.5t111.5 -378q1 -13 10 -22t22 -9h128q13 0 23 10q11 9 9 23zM1536 1120v-960q0 -119 -84.5 -203.5 t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
<glyph unicode="&#xf144;" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM1152 585q32 18 32 55t-32 55l-544 320q-31 19 -64 1q-32 -19 -32 -56v-640q0 -37 32 -56 q16 -8 32 -8q17 0 32 9z" />
<glyph unicode="&#xf145;" horiz-adv-x="1792" d="M1024 1084l316 -316l-572 -572l-316 316zM813 105l618 618q19 19 19 45t-19 45l-362 362q-18 18 -45 18t-45 -18l-618 -618q-19 -19 -19 -45t19 -45l362 -362q18 -18 45 -18t45 18zM1702 742l-907 -908q-37 -37 -90.5 -37t-90.5 37l-126 126q56 56 56 136t-56 136 t-136 56t-136 -56l-125 126q-37 37 -37 90.5t37 90.5l907 906q37 37 90.5 37t90.5 -37l125 -125q-56 -56 -56 -136t56 -136t136 -56t136 56l126 -125q37 -37 37 -90.5t-37 -90.5z" />
<glyph unicode="&#xf146;" d="M1280 576v128q0 26 -19 45t-45 19h-896q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h896q26 0 45 19t19 45zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5 t84.5 -203.5z" />
<glyph unicode="&#xf147;" horiz-adv-x="1408" d="M1152 736v-64q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h832q14 0 23 -9t9 -23zM1280 288v832q0 66 -47 113t-113 47h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113zM1408 1120v-832q0 -119 -84.5 -203.5 t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832q119 0 203.5 -84.5t84.5 -203.5z" />
<glyph unicode="&#xf148;" horiz-adv-x="1024" d="M1018 933q-18 -37 -58 -37h-192v-864q0 -14 -9 -23t-23 -9h-704q-21 0 -29 18q-8 20 4 35l160 192q9 11 25 11h320v640h-192q-40 0 -58 37q-17 37 9 68l320 384q18 22 49 22t49 -22l320 -384q27 -32 9 -68z" />
<glyph unicode="&#xf149;" horiz-adv-x="1024" d="M32 1280h704q13 0 22.5 -9.5t9.5 -23.5v-863h192q40 0 58 -37t-9 -69l-320 -384q-18 -22 -49 -22t-49 22l-320 384q-26 31 -9 69q18 37 58 37h192v640h-320q-14 0 -25 11l-160 192q-13 14 -4 34q9 19 29 19z" />
<glyph unicode="&#xf14a;" d="M685 237l614 614q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-467 -467l-211 211q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l358 -358q19 -19 45 -19t45 19zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5 t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
<glyph unicode="&#xf14b;" d="M404 428l152 -152l-52 -52h-56v96h-96v56zM818 818q14 -13 -3 -30l-291 -291q-17 -17 -30 -3q-14 13 3 30l291 291q17 17 30 3zM544 128l544 544l-288 288l-544 -544v-288h288zM1152 736l92 92q28 28 28 68t-28 68l-152 152q-28 28 -68 28t-68 -28l-92 -92zM1536 1120 v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
<glyph unicode="&#xf14c;" d="M1280 608v480q0 26 -19 45t-45 19h-480q-42 0 -59 -39q-17 -41 14 -70l144 -144l-534 -534q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19l534 534l144 -144q18 -19 45 -19q12 0 25 5q39 17 39 59zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960 q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
<glyph unicode="&#xf14d;" d="M1005 435l352 352q19 19 19 45t-19 45l-352 352q-30 31 -69 14q-40 -17 -40 -59v-160q-119 0 -216 -19.5t-162.5 -51t-114 -79t-76.5 -95.5t-44.5 -109t-21.5 -111.5t-5 -110.5q0 -181 167 -404q10 -12 25 -12q7 0 13 3q22 9 19 33q-44 354 62 473q46 52 130 75.5 t224 23.5v-160q0 -42 40 -59q12 -5 24 -5q26 0 45 19zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
<glyph unicode="&#xf14e;" d="M640 448l256 128l-256 128v-256zM1024 1039v-542l-512 -256v542zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
<glyph unicode="&#xf150;" d="M1145 861q18 -35 -5 -66l-320 -448q-19 -27 -52 -27t-52 27l-320 448q-23 31 -5 66q17 35 57 35h640q40 0 57 -35zM1280 160v960q0 13 -9.5 22.5t-22.5 9.5h-960q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5zM1536 1120 v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
<glyph unicode="&#xf151;" d="M1145 419q-17 -35 -57 -35h-640q-40 0 -57 35q-18 35 5 66l320 448q19 27 52 27t52 -27l320 -448q23 -31 5 -66zM1280 160v960q0 13 -9.5 22.5t-22.5 9.5h-960q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
<glyph unicode="&#xf152;" d="M1088 640q0 -33 -27 -52l-448 -320q-31 -23 -66 -5q-35 17 -35 57v640q0 40 35 57q35 18 66 -5l448 -320q27 -19 27 -52zM1280 160v960q0 14 -9 23t-23 9h-960q-14 0 -23 -9t-9 -23v-960q0 -14 9 -23t23 -9h960q14 0 23 9t9 23zM1536 1120v-960q0 -119 -84.5 -203.5 t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
<glyph unicode="&#xf153;" horiz-adv-x="1024" d="M976 229l35 -159q3 -12 -3 -22.5t-17 -14.5l-5 -1q-4 -2 -10.5 -3.5t-16 -4.5t-21.5 -5.5t-25.5 -5t-30 -5t-33.5 -4.5t-36.5 -3t-38.5 -1q-234 0 -409 130.5t-238 351.5h-95q-13 0 -22.5 9.5t-9.5 22.5v113q0 13 9.5 22.5t22.5 9.5h66q-2 57 1 105h-67q-14 0 -23 9 t-9 23v114q0 14 9 23t23 9h98q67 210 243.5 338t400.5 128q102 0 194 -23q11 -3 20 -15q6 -11 3 -24l-43 -159q-3 -13 -14 -19.5t-24 -2.5l-4 1q-4 1 -11.5 2.5l-17.5 3.5t-22.5 3.5t-26 3t-29 2.5t-29.5 1q-126 0 -226 -64t-150 -176h468q16 0 25 -12q10 -12 7 -26 l-24 -114q-5 -26 -32 -26h-488q-3 -37 0 -105h459q15 0 25 -12q9 -12 6 -27l-24 -112q-2 -11 -11 -18.5t-20 -7.5h-387q48 -117 149.5 -185.5t228.5 -68.5q18 0 36 1.5t33.5 3.5t29.5 4.5t24.5 5t18.5 4.5l12 3l5 2q13 5 26 -2q12 -7 15 -21z" />
<glyph unicode="&#xf154;" horiz-adv-x="1024" d="M1020 399v-367q0 -14 -9 -23t-23 -9h-956q-14 0 -23 9t-9 23v150q0 13 9.5 22.5t22.5 9.5h97v383h-95q-14 0 -23 9.5t-9 22.5v131q0 14 9 23t23 9h95v223q0 171 123.5 282t314.5 111q185 0 335 -125q9 -8 10 -20.5t-7 -22.5l-103 -127q-9 -11 -22 -12q-13 -2 -23 7 q-5 5 -26 19t-69 32t-93 18q-85 0 -137 -47t-52 -123v-215h305q13 0 22.5 -9t9.5 -23v-131q0 -13 -9.5 -22.5t-22.5 -9.5h-305v-379h414v181q0 13 9 22.5t23 9.5h162q14 0 23 -9.5t9 -22.5z" />
<glyph unicode="&#xf155;" horiz-adv-x="1024" d="M978 351q0 -153 -99.5 -263.5t-258.5 -136.5v-175q0 -14 -9 -23t-23 -9h-135q-13 0 -22.5 9.5t-9.5 22.5v175q-66 9 -127.5 31t-101.5 44.5t-74 48t-46.5 37.5t-17.5 18q-17 21 -2 41l103 135q7 10 23 12q15 2 24 -9l2 -2q113 -99 243 -125q37 -8 74 -8q81 0 142.5 43 t61.5 122q0 28 -15 53t-33.5 42t-58.5 37.5t-66 32t-80 32.5q-39 16 -61.5 25t-61.5 26.5t-62.5 31t-56.5 35.5t-53.5 42.5t-43.5 49t-35.5 58t-21 66.5t-8.5 78q0 138 98 242t255 134v180q0 13 9.5 22.5t22.5 9.5h135q14 0 23 -9t9 -23v-176q57 -6 110.5 -23t87 -33.5 t63.5 -37.5t39 -29t15 -14q17 -18 5 -38l-81 -146q-8 -15 -23 -16q-14 -3 -27 7q-3 3 -14.5 12t-39 26.5t-58.5 32t-74.5 26t-85.5 11.5q-95 0 -155 -43t-60 -111q0 -26 8.5 -48t29.5 -41.5t39.5 -33t56 -31t60.5 -27t70 -27.5q53 -20 81 -31.5t76 -35t75.5 -42.5t62 -50 t53 -63.5t31.5 -76.5t13 -94z" />
<glyph unicode="&#xf156;" horiz-adv-x="898" d="M898 1066v-102q0 -14 -9 -23t-23 -9h-168q-23 -144 -129 -234t-276 -110q167 -178 459 -536q14 -16 4 -34q-8 -18 -29 -18h-195q-16 0 -25 12q-306 367 -498 571q-9 9 -9 22v127q0 13 9.5 22.5t22.5 9.5h112q132 0 212.5 43t102.5 125h-427q-14 0 -23 9t-9 23v102 q0 14 9 23t23 9h413q-57 113 -268 113h-145q-13 0 -22.5 9.5t-9.5 22.5v133q0 14 9 23t23 9h832q14 0 23 -9t9 -23v-102q0 -14 -9 -23t-23 -9h-233q47 -61 64 -144h171q14 0 23 -9t9 -23z" />
<glyph unicode="&#xf157;" horiz-adv-x="1027" d="M603 0h-172q-13 0 -22.5 9t-9.5 23v330h-288q-13 0 -22.5 9t-9.5 23v103q0 13 9.5 22.5t22.5 9.5h288v85h-288q-13 0 -22.5 9t-9.5 23v104q0 13 9.5 22.5t22.5 9.5h214l-321 578q-8 16 0 32q10 16 28 16h194q19 0 29 -18l215 -425q19 -38 56 -125q10 24 30.5 68t27.5 61 l191 420q8 19 29 19h191q17 0 27 -16q9 -14 1 -31l-313 -579h215q13 0 22.5 -9.5t9.5 -22.5v-104q0 -14 -9.5 -23t-22.5 -9h-290v-85h290q13 0 22.5 -9.5t9.5 -22.5v-103q0 -14 -9.5 -23t-22.5 -9h-290v-330q0 -13 -9.5 -22.5t-22.5 -9.5z" />
<glyph unicode="&#xf158;" horiz-adv-x="1664" d="M1664 352v-32q0 -132 -94 -226t-226 -94h-128q-132 0 -226 94t-94 226v480h-224q-2 -102 -14.5 -190.5t-30.5 -156t-48.5 -126.5t-57 -99.5t-67.5 -77.5t-69.5 -58.5t-74 -44t-69 -32t-65.5 -25.5q-4 -2 -32 -13q-8 -2 -12 -2q-22 0 -30 20l-71 178q-5 13 0 25t17 17 q7 3 20 7.5t18 6.5q31 12 46.5 18.5t44.5 20t45.5 26t42 32.5t40.5 42.5t34.5 53.5t30.5 68.5t22.5 83.5t17 103t6.5 123h-256q-14 0 -23 9t-9 23v160q0 14 9 23t23 9h1216q14 0 23 -9t9 -23v-160q0 -14 -9 -23t-23 -9h-224v-512q0 -26 19 -45t45 -19h128q26 0 45 19t19 45 v64q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1280 1376v-160q0 -14 -9 -23t-23 -9h-960q-14 0 -23 9t-9 23v160q0 14 9 23t23 9h960q14 0 23 -9t9 -23z" />
<glyph unicode="&#xf159;" horiz-adv-x="1792" d="M514 341l81 299h-159l75 -300q1 -1 1 -3t1 -3q0 1 0.5 3.5t0.5 3.5zM630 768l35 128h-292l32 -128h225zM822 768h139l-35 128h-70zM1271 340l78 300h-162l81 -299q0 -1 0.5 -3.5t1.5 -3.5q0 1 0.5 3t0.5 3zM1382 768l33 128h-297l34 -128h230zM1792 736v-64q0 -14 -9 -23 t-23 -9h-213l-164 -616q-7 -24 -31 -24h-159q-24 0 -31 24l-166 616h-209l-167 -616q-7 -24 -31 -24h-159q-11 0 -19.5 7t-10.5 17l-160 616h-208q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h175l-33 128h-142q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h109l-89 344q-5 15 5 28 q10 12 26 12h137q26 0 31 -24l90 -360h359l97 360q7 24 31 24h126q24 0 31 -24l98 -360h365l93 360q5 24 31 24h137q16 0 26 -12q10 -13 5 -28l-91 -344h111q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-145l-34 -128h179q14 0 23 -9t9 -23z" />
<glyph unicode="&#xf15a;" horiz-adv-x="1280" d="M1167 896q18 -182 -131 -258q117 -28 175 -103t45 -214q-7 -71 -32.5 -125t-64.5 -89t-97 -58.5t-121.5 -34.5t-145.5 -15v-255h-154v251q-80 0 -122 1v-252h-154v255q-18 0 -54 0.5t-55 0.5h-200l31 183h111q50 0 58 51v402h16q-6 1 -16 1v287q-13 68 -89 68h-111v164 l212 -1q64 0 97 1v252h154v-247q82 2 122 2v245h154v-252q79 -7 140 -22.5t113 -45t82.5 -78t36.5 -114.5zM952 351q0 36 -15 64t-37 46t-57.5 30.5t-65.5 18.5t-74 9t-69 3t-64.5 -1t-47.5 -1v-338q8 0 37 -0.5t48 -0.5t53 1.5t58.5 4t57 8.5t55.5 14t47.5 21t39.5 30 t24.5 40t9.5 51zM881 827q0 33 -12.5 58.5t-30.5 42t-48 28t-55 16.5t-61.5 8t-58 2.5t-54 -1t-39.5 -0.5v-307q5 0 34.5 -0.5t46.5 0t50 2t55 5.5t51.5 11t48.5 18.5t37 27t27 38.5t9 51z" />
<glyph unicode="&#xf15b;" horiz-adv-x="1280" d="M1280 768v-800q0 -40 -28 -68t-68 -28h-1088q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h544v-544q0 -40 28 -68t68 -28h544zM1277 896h-509v509q82 -15 132 -65l312 -312q50 -50 65 -132z" />
<glyph unicode="&#xf15c;" horiz-adv-x="1280" d="M1024 160v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704q14 0 23 9t9 23zM1024 416v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704q14 0 23 9t9 23zM1280 768v-800q0 -40 -28 -68t-68 -28h-1088q-40 0 -68 28 t-28 68v1344q0 40 28 68t68 28h544v-544q0 -40 28 -68t68 -28h544zM1277 896h-509v509q82 -15 132 -65l312 -312q50 -50 65 -132z" />
<glyph unicode="&#xf15d;" horiz-adv-x="1664" d="M1191 1128h177l-72 218l-12 47q-2 16 -2 20h-4l-3 -20q0 -1 -3.5 -18t-7.5 -29zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1572 -23 v-233h-584v90l369 529q12 18 21 27l11 9v3q-2 0 -6.5 -0.5t-7.5 -0.5q-12 -3 -30 -3h-232v-115h-120v229h567v-89l-369 -530q-6 -8 -21 -26l-11 -11v-2l14 2q9 2 30 2h248v119h121zM1661 874v-106h-288v106h75l-47 144h-243l-47 -144h75v-106h-287v106h70l230 662h162 l230 -662h70z" />
<glyph unicode="&#xf15e;" horiz-adv-x="1664" d="M1191 104h177l-72 218l-12 47q-2 16 -2 20h-4l-3 -20q0 -1 -3.5 -18t-7.5 -29zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1661 -150 v-106h-288v106h75l-47 144h-243l-47 -144h75v-106h-287v106h70l230 662h162l230 -662h70zM1572 1001v-233h-584v90l369 529q12 18 21 27l11 9v3q-2 0 -6.5 -0.5t-7.5 -0.5q-12 -3 -30 -3h-232v-115h-120v229h567v-89l-369 -530q-6 -8 -21 -26l-11 -10v-3l14 3q9 1 30 1h248 v119h121z" />
<glyph unicode="&#xf160;" horiz-adv-x="1792" d="M736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1792 -32v-192q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h832 q14 0 23 -9t9 -23zM1600 480v-192q0 -14 -9 -23t-23 -9h-640q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h640q14 0 23 -9t9 -23zM1408 992v-192q0 -14 -9 -23t-23 -9h-448q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h448q14 0 23 -9t9 -23zM1216 1504v-192q0 -14 -9 -23t-23 -9h-256 q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h256q14 0 23 -9t9 -23z" />
<glyph unicode="&#xf161;" horiz-adv-x="1792" d="M1216 -32v-192q0 -14 -9 -23t-23 -9h-256q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h256q14 0 23 -9t9 -23zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192 q14 0 23 -9t9 -23zM1408 480v-192q0 -14 -9 -23t-23 -9h-448q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h448q14 0 23 -9t9 -23zM1600 992v-192q0 -14 -9 -23t-23 -9h-640q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h640q14 0 23 -9t9 -23zM1792 1504v-192q0 -14 -9 -23t-23 -9h-832 q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h832q14 0 23 -9t9 -23z" />
<glyph unicode="&#xf162;" d="M1346 223q0 63 -44 116t-103 53q-52 0 -83 -37t-31 -94t36.5 -95t104.5 -38q50 0 85 27t35 68zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23 zM1486 165q0 -62 -13 -121.5t-41 -114t-68 -95.5t-98.5 -65.5t-127.5 -24.5q-62 0 -108 16q-24 8 -42 15l39 113q15 -7 31 -11q37 -13 75 -13q84 0 134.5 58.5t66.5 145.5h-2q-21 -23 -61.5 -37t-84.5 -14q-106 0 -173 71.5t-67 172.5q0 105 72 178t181 73q123 0 205 -94.5 t82 -252.5zM1456 882v-114h-469v114h167v432q0 7 0.5 19t0.5 17v16h-2l-7 -12q-8 -13 -26 -31l-62 -58l-82 86l192 185h123v-654h165z" />
<glyph unicode="&#xf163;" d="M1346 1247q0 63 -44 116t-103 53q-52 0 -83 -37t-31 -94t36.5 -95t104.5 -38q50 0 85 27t35 68zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9 t9 -23zM1456 -142v-114h-469v114h167v432q0 7 0.5 19t0.5 17v16h-2l-7 -12q-8 -13 -26 -31l-62 -58l-82 86l192 185h123v-654h165zM1486 1189q0 -62 -13 -121.5t-41 -114t-68 -95.5t-98.5 -65.5t-127.5 -24.5q-62 0 -108 16q-24 8 -42 15l39 113q15 -7 31 -11q37 -13 75 -13 q84 0 134.5 58.5t66.5 145.5h-2q-21 -23 -61.5 -37t-84.5 -14q-106 0 -173 71.5t-67 172.5q0 105 72 178t181 73q123 0 205 -94.5t82 -252.5z" />
<glyph unicode="&#xf164;" horiz-adv-x="1664" d="M256 192q0 26 -19 45t-45 19q-27 0 -45.5 -19t-18.5 -45q0 -27 18.5 -45.5t45.5 -18.5q26 0 45 18.5t19 45.5zM416 704v-640q0 -26 -19 -45t-45 -19h-288q-26 0 -45 19t-19 45v640q0 26 19 45t45 19h288q26 0 45 -19t19 -45zM1600 704q0 -86 -55 -149q15 -44 15 -76 q3 -76 -43 -137q17 -56 0 -117q-15 -57 -54 -94q9 -112 -49 -181q-64 -76 -197 -78h-36h-76h-17q-66 0 -144 15.5t-121.5 29t-120.5 39.5q-123 43 -158 44q-26 1 -45 19.5t-19 44.5v641q0 25 18 43.5t43 20.5q24 2 76 59t101 121q68 87 101 120q18 18 31 48t17.5 48.5 t13.5 60.5q7 39 12.5 61t19.5 52t34 50q19 19 45 19q46 0 82.5 -10.5t60 -26t40 -40.5t24 -45t12 -50t5 -45t0.5 -39q0 -38 -9.5 -76t-19 -60t-27.5 -56q-3 -6 -10 -18t-11 -22t-8 -24h277q78 0 135 -57t57 -135z" />
<glyph unicode="&#xf165;" horiz-adv-x="1664" d="M256 960q0 -26 -19 -45t-45 -19q-27 0 -45.5 19t-18.5 45q0 27 18.5 45.5t45.5 18.5q26 0 45 -18.5t19 -45.5zM416 448v640q0 26 -19 45t-45 19h-288q-26 0 -45 -19t-19 -45v-640q0 -26 19 -45t45 -19h288q26 0 45 19t19 45zM1545 597q55 -61 55 -149q-1 -78 -57.5 -135 t-134.5 -57h-277q4 -14 8 -24t11 -22t10 -18q18 -37 27 -57t19 -58.5t10 -76.5q0 -24 -0.5 -39t-5 -45t-12 -50t-24 -45t-40 -40.5t-60 -26t-82.5 -10.5q-26 0 -45 19q-20 20 -34 50t-19.5 52t-12.5 61q-9 42 -13.5 60.5t-17.5 48.5t-31 48q-33 33 -101 120q-49 64 -101 121 t-76 59q-25 2 -43 20.5t-18 43.5v641q0 26 19 44.5t45 19.5q35 1 158 44q77 26 120.5 39.5t121.5 29t144 15.5h17h76h36q133 -2 197 -78q58 -69 49 -181q39 -37 54 -94q17 -61 0 -117q46 -61 43 -137q0 -32 -15 -76z" />
<glyph unicode="&#xf166;" d="M919 233v157q0 50 -29 50q-17 0 -33 -16v-224q16 -16 33 -16q29 0 29 49zM1103 355h66v34q0 51 -33 51t-33 -51v-34zM532 621v-70h-80v-423h-74v423h-78v70h232zM733 495v-367h-67v40q-39 -45 -76 -45q-33 0 -42 28q-6 16 -6 54v290h66v-270q0 -24 1 -26q1 -15 15 -15 q20 0 42 31v280h67zM985 384v-146q0 -52 -7 -73q-12 -42 -53 -42q-35 0 -68 41v-36h-67v493h67v-161q32 40 68 40q41 0 53 -42q7 -21 7 -74zM1236 255v-9q0 -29 -2 -43q-3 -22 -15 -40q-27 -40 -80 -40q-52 0 -81 38q-21 27 -21 86v129q0 59 20 86q29 38 80 38t78 -38 q21 -28 21 -86v-76h-133v-65q0 -51 34 -51q24 0 30 26q0 1 0.5 7t0.5 16.5v21.5h68zM785 1079v-156q0 -51 -32 -51t-32 51v156q0 52 32 52t32 -52zM1318 366q0 177 -19 260q-10 44 -43 73.5t-76 34.5q-136 15 -412 15q-275 0 -411 -15q-44 -5 -76.5 -34.5t-42.5 -73.5 q-20 -87 -20 -260q0 -176 20 -260q10 -43 42.5 -73t75.5 -35q137 -15 412 -15t412 15q43 5 75.5 35t42.5 73q20 84 20 260zM563 1017l90 296h-75l-51 -195l-53 195h-78l24 -69t23 -69q35 -103 46 -158v-201h74v201zM852 936v130q0 58 -21 87q-29 38 -78 38q-51 0 -78 -38 q-21 -29 -21 -87v-130q0 -58 21 -87q27 -38 78 -38q49 0 78 38q21 27 21 87zM1033 816h67v370h-67v-283q-22 -31 -42 -31q-15 0 -16 16q-1 2 -1 26v272h-67v-293q0 -37 6 -55q11 -27 43 -27q36 0 77 45v-40zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960 q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
<glyph unicode="&#xf167;" d="M971 292v-211q0 -67 -39 -67q-23 0 -45 22v301q22 22 45 22q39 0 39 -67zM1309 291v-46h-90v46q0 68 45 68t45 -68zM343 509h107v94h-312v-94h105v-569h100v569zM631 -60h89v494h-89v-378q-30 -42 -57 -42q-18 0 -21 21q-1 3 -1 35v364h-89v-391q0 -49 8 -73 q12 -37 58 -37q48 0 102 61v-54zM1060 88v197q0 73 -9 99q-17 56 -71 56q-50 0 -93 -54v217h-89v-663h89v48q45 -55 93 -55q54 0 71 55q9 27 9 100zM1398 98v13h-91q0 -51 -2 -61q-7 -36 -40 -36q-46 0 -46 69v87h179v103q0 79 -27 116q-39 51 -106 51q-68 0 -107 -51 q-28 -37 -28 -116v-173q0 -79 29 -116q39 -51 108 -51q72 0 108 53q18 27 21 54q2 9 2 58zM790 1011v210q0 69 -43 69t-43 -69v-210q0 -70 43 -70t43 70zM1509 260q0 -234 -26 -350q-14 -59 -58 -99t-102 -46q-184 -21 -555 -21t-555 21q-58 6 -102.5 46t-57.5 99 q-26 112 -26 350q0 234 26 350q14 59 58 99t103 47q183 20 554 20t555 -20q58 -7 102.5 -47t57.5 -99q26 -112 26 -350zM511 1536h102l-121 -399v-271h-100v271q-14 74 -61 212q-37 103 -65 187h106l71 -263zM881 1203v-175q0 -81 -28 -118q-37 -51 -106 -51q-67 0 -105 51 q-28 38 -28 118v175q0 80 28 117q38 51 105 51q69 0 106 -51q28 -37 28 -117zM1216 1365v-499h-91v55q-53 -62 -103 -62q-46 0 -59 37q-8 24 -8 75v394h91v-367q0 -33 1 -35q3 -22 21 -22q27 0 57 43v381h91z" />
<glyph unicode="&#xf168;" horiz-adv-x="1408" d="M597 869q-10 -18 -257 -456q-27 -46 -65 -46h-239q-21 0 -31 17t0 36l253 448q1 0 0 1l-161 279q-12 22 -1 37q9 15 32 15h239q40 0 66 -45zM1403 1511q11 -16 0 -37l-528 -934v-1l336 -615q11 -20 1 -37q-10 -15 -32 -15h-239q-42 0 -66 45l-339 622q18 32 531 942 q25 45 64 45h241q22 0 31 -15z" />
<glyph unicode="&#xf169;" d="M685 771q0 1 -126 222q-21 34 -52 34h-184q-18 0 -26 -11q-7 -12 1 -29l125 -216v-1l-196 -346q-9 -14 0 -28q8 -13 24 -13h185q31 0 50 36zM1309 1268q-7 12 -24 12h-187q-30 0 -49 -35l-411 -729q1 -2 262 -481q20 -35 52 -35h184q18 0 25 12q8 13 -1 28l-260 476v1 l409 723q8 16 0 28zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
<glyph unicode="&#xf16a;" horiz-adv-x="1792" d="M1280 640q0 37 -30 54l-512 320q-31 20 -65 2q-33 -18 -33 -56v-640q0 -38 33 -56q16 -8 31 -8q20 0 34 10l512 320q30 17 30 54zM1792 640q0 -96 -1 -150t-8.5 -136.5t-22.5 -147.5q-16 -73 -69 -123t-124 -58q-222 -25 -671 -25t-671 25q-71 8 -124.5 58t-69.5 123 q-14 65 -21.5 147.5t-8.5 136.5t-1 150t1 150t8.5 136.5t22.5 147.5q16 73 69 123t124 58q222 25 671 25t671 -25q71 -8 124.5 -58t69.5 -123q14 -65 21.5 -147.5t8.5 -136.5t1 -150z" />
<glyph unicode="&#xf16b;" horiz-adv-x="1792" d="M402 829l494 -305l-342 -285l-490 319zM1388 274v-108l-490 -293v-1l-1 1l-1 -1v1l-489 293v108l147 -96l342 284v2l1 -1l1 1v-2l343 -284zM554 1418l342 -285l-494 -304l-338 270zM1390 829l338 -271l-489 -319l-343 285zM1239 1418l489 -319l-338 -270l-494 304z" />
<glyph unicode="&#xf16c;" horiz-adv-x="1408" d="M928 135v-151l-707 -1v151zM1169 481v-701l-1 -35v-1h-1132l-35 1h-1v736h121v-618h928v618h120zM241 393l704 -65l-13 -150l-705 65zM309 709l683 -183l-39 -146l-683 183zM472 1058l609 -360l-77 -130l-609 360zM832 1389l398 -585l-124 -85l-399 584zM1285 1536 l121 -697l-149 -26l-121 697z" />
<glyph unicode="&#xf16d;" d="M1362 110v648h-135q20 -63 20 -131q0 -126 -64 -232.5t-174 -168.5t-240 -62q-197 0 -337 135.5t-140 327.5q0 68 20 131h-141v-648q0 -26 17.5 -43.5t43.5 -17.5h1069q25 0 43 17.5t18 43.5zM1078 643q0 124 -90.5 211.5t-218.5 87.5q-127 0 -217.5 -87.5t-90.5 -211.5 t90.5 -211.5t217.5 -87.5q128 0 218.5 87.5t90.5 211.5zM1362 1003v165q0 28 -20 48.5t-49 20.5h-174q-29 0 -49 -20.5t-20 -48.5v-165q0 -29 20 -49t49 -20h174q29 0 49 20t20 49zM1536 1211v-1142q0 -81 -58 -139t-139 -58h-1142q-81 0 -139 58t-58 139v1142q0 81 58 139 t139 58h1142q81 0 139 -58t58 -139z" />
<glyph unicode="&#xf16e;" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960zM698 640q0 88 -62 150t-150 62t-150 -62t-62 -150t62 -150t150 -62t150 62t62 150zM1262 640q0 88 -62 150 t-150 62t-150 -62t-62 -150t62 -150t150 -62t150 62t62 150z" />
<glyph unicode="&#xf170;" d="M768 914l201 -306h-402zM1133 384h94l-459 691l-459 -691h94l104 160h522zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
<glyph unicode="&#xf171;" horiz-adv-x="1408" d="M815 677q8 -63 -50.5 -101t-111.5 -6q-39 17 -53.5 58t-0.5 82t52 58q36 18 72.5 12t64 -35.5t27.5 -67.5zM926 698q-14 107 -113 164t-197 13q-63 -28 -100.5 -88.5t-34.5 -129.5q4 -91 77.5 -155t165.5 -56q91 8 152 84t50 168zM1165 1240q-20 27 -56 44.5t-58 22 t-71 12.5q-291 47 -566 -2q-43 -7 -66 -12t-55 -22t-50 -43q30 -28 76 -45.5t73.5 -22t87.5 -11.5q228 -29 448 -1q63 8 89.5 12t72.5 21.5t75 46.5zM1222 205q-8 -26 -15.5 -76.5t-14 -84t-28.5 -70t-58 -56.5q-86 -48 -189.5 -71.5t-202 -22t-201.5 18.5q-46 8 -81.5 18 t-76.5 27t-73 43.5t-52 61.5q-25 96 -57 292l6 16l18 9q223 -148 506.5 -148t507.5 148q21 -6 24 -23t-5 -45t-8 -37zM1403 1166q-26 -167 -111 -655q-5 -30 -27 -56t-43.5 -40t-54.5 -31q-252 -126 -610 -88q-248 27 -394 139q-15 12 -25.5 26.5t-17 35t-9 34t-6 39.5 t-5.5 35q-9 50 -26.5 150t-28 161.5t-23.5 147.5t-22 158q3 26 17.5 48.5t31.5 37.5t45 30t46 22.5t48 18.5q125 46 313 64q379 37 676 -50q155 -46 215 -122q16 -20 16.5 -51t-5.5 -54z" />
<glyph unicode="&#xf172;" d="M848 666q0 43 -41 66t-77 1q-43 -20 -42.5 -72.5t43.5 -70.5q39 -23 81 4t36 72zM928 682q8 -66 -36 -121t-110 -61t-119 40t-56 113q-2 49 25.5 93t72.5 64q70 31 141.5 -10t81.5 -118zM1100 1073q-20 -21 -53.5 -34t-53 -16t-63.5 -8q-155 -20 -324 0q-44 6 -63 9.5 t-52.5 16t-54.5 32.5q13 19 36 31t40 15.5t47 8.5q198 35 408 1q33 -5 51 -8.5t43 -16t39 -31.5zM1142 327q0 7 5.5 26.5t3 32t-17.5 16.5q-161 -106 -365 -106t-366 106l-12 -6l-5 -12q26 -154 41 -210q47 -81 204 -108q249 -46 428 53q34 19 49 51.5t22.5 85.5t12.5 71z M1272 1020q9 53 -8 75q-43 55 -155 88q-216 63 -487 36q-132 -12 -226 -46q-38 -15 -59.5 -25t-47 -34t-29.5 -54q8 -68 19 -138t29 -171t24 -137q1 -5 5 -31t7 -36t12 -27t22 -28q105 -80 284 -100q259 -28 440 63q24 13 39.5 23t31 29t19.5 40q48 267 80 473zM1536 1120 v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
<glyph unicode="&#xf173;" horiz-adv-x="1024" d="M390 1408h219v-388h364v-241h-364v-394q0 -136 14 -172q13 -37 52 -60q50 -31 117 -31q117 0 232 76v-242q-102 -48 -178 -65q-77 -19 -173 -19q-105 0 -186 27q-78 25 -138 75q-58 51 -79 105q-22 54 -22 161v539h-170v217q91 30 155 84q64 55 103 132q39 78 54 196z " />
<glyph unicode="&#xf174;" d="M1123 127v181q-88 -56 -174 -56q-51 0 -88 23q-29 17 -39 45q-11 30 -11 129v295h274v181h-274v291h-164q-11 -90 -40 -147t-78 -99q-48 -40 -116 -63v-163h127v-404q0 -78 17 -121q17 -42 59 -78q43 -37 104 -57q62 -20 140 -20q67 0 129 14q57 13 134 49zM1536 1120 v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
<glyph unicode="&#xf175;" horiz-adv-x="768" d="M765 237q8 -19 -5 -35l-350 -384q-10 -10 -23 -10q-14 0 -24 10l-355 384q-13 16 -5 35q9 19 29 19h224v1248q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1248h224q21 0 29 -19z" />
<glyph unicode="&#xf176;" horiz-adv-x="768" d="M765 1043q-9 -19 -29 -19h-224v-1248q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v1248h-224q-21 0 -29 19t5 35l350 384q10 10 23 10q14 0 24 -10l355 -384q13 -16 5 -35z" />
<glyph unicode="&#xf177;" horiz-adv-x="1792" d="M1792 736v-192q0 -14 -9 -23t-23 -9h-1248v-224q0 -21 -19 -29t-35 5l-384 350q-10 10 -10 23q0 14 10 24l384 354q16 14 35 6q19 -9 19 -29v-224h1248q14 0 23 -9t9 -23z" />
<glyph unicode="&#xf178;" horiz-adv-x="1792" d="M1728 643q0 -14 -10 -24l-384 -354q-16 -14 -35 -6q-19 9 -19 29v224h-1248q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h1248v224q0 21 19 29t35 -5l384 -350q10 -10 10 -23z" />
<glyph unicode="&#xf179;" horiz-adv-x="1408" d="M1393 321q-39 -125 -123 -250q-129 -196 -257 -196q-49 0 -140 32q-86 32 -151 32q-61 0 -142 -33q-81 -34 -132 -34q-152 0 -301 259q-147 261 -147 503q0 228 113 374q112 144 284 144q72 0 177 -30q104 -30 138 -30q45 0 143 34q102 34 173 34q119 0 213 -65 q52 -36 104 -100q-79 -67 -114 -118q-65 -94 -65 -207q0 -124 69 -223t158 -126zM1017 1494q0 -61 -29 -136q-30 -75 -93 -138q-54 -54 -108 -72q-37 -11 -104 -17q3 149 78 257q74 107 250 148q1 -3 2.5 -11t2.5 -11q0 -4 0.5 -10t0.5 -10z" />
<glyph unicode="&#xf17a;" horiz-adv-x="1664" d="M682 530v-651l-682 94v557h682zM682 1273v-659h-682v565zM1664 530v-786l-907 125v661h907zM1664 1408v-794h-907v669z" />
<glyph unicode="&#xf17b;" horiz-adv-x="1408" d="M493 1053q16 0 27.5 11.5t11.5 27.5t-11.5 27.5t-27.5 11.5t-27 -11.5t-11 -27.5t11 -27.5t27 -11.5zM915 1053q16 0 27 11.5t11 27.5t-11 27.5t-27 11.5t-27.5 -11.5t-11.5 -27.5t11.5 -27.5t27.5 -11.5zM103 869q42 0 72 -30t30 -72v-430q0 -43 -29.5 -73t-72.5 -30 t-73 30t-30 73v430q0 42 30 72t73 30zM1163 850v-666q0 -46 -32 -78t-77 -32h-75v-227q0 -43 -30 -73t-73 -30t-73 30t-30 73v227h-138v-227q0 -43 -30 -73t-73 -30q-42 0 -72 30t-30 73l-1 227h-74q-46 0 -78 32t-32 78v666h918zM931 1255q107 -55 171 -153.5t64 -215.5 h-925q0 117 64 215.5t172 153.5l-71 131q-7 13 5 20q13 6 20 -6l72 -132q95 42 201 42t201 -42l72 132q7 12 20 6q12 -7 5 -20zM1408 767v-430q0 -43 -30 -73t-73 -30q-42 0 -72 30t-30 73v430q0 43 30 72.5t72 29.5q43 0 73 -29.5t30 -72.5z" />
<glyph unicode="&#xf17c;" d="M663 1125q-11 -1 -15.5 -10.5t-8.5 -9.5q-5 -1 -5 5q0 12 19 15h10zM750 1111q-4 -1 -11.5 6.5t-17.5 4.5q24 11 32 -2q3 -6 -3 -9zM399 684q-4 1 -6 -3t-4.5 -12.5t-5.5 -13.5t-10 -13q-7 -10 -1 -12q4 -1 12.5 7t12.5 18q1 3 2 7t2 6t1.5 4.5t0.5 4v3t-1 2.5t-3 2z M1254 325q0 18 -55 42q4 15 7.5 27.5t5 26t3 21.5t0.5 22.5t-1 19.5t-3.5 22t-4 20.5t-5 25t-5.5 26.5q-10 48 -47 103t-72 75q24 -20 57 -83q87 -162 54 -278q-11 -40 -50 -42q-31 -4 -38.5 18.5t-8 83.5t-11.5 107q-9 39 -19.5 69t-19.5 45.5t-15.5 24.5t-13 15t-7.5 7 q-14 62 -31 103t-29.5 56t-23.5 33t-15 40q-4 21 6 53.5t4.5 49.5t-44.5 25q-15 3 -44.5 18t-35.5 16q-8 1 -11 26t8 51t36 27q37 3 51 -30t4 -58q-11 -19 -2 -26.5t30 -0.5q13 4 13 36v37q-5 30 -13.5 50t-21 30.5t-23.5 15t-27 7.5q-107 -8 -89 -134q0 -15 -1 -15 q-9 9 -29.5 10.5t-33 -0.5t-15.5 5q1 57 -16 90t-45 34q-27 1 -41.5 -27.5t-16.5 -59.5q-1 -15 3.5 -37t13 -37.5t15.5 -13.5q10 3 16 14q4 9 -7 8q-7 0 -15.5 14.5t-9.5 33.5q-1 22 9 37t34 14q17 0 27 -21t9.5 -39t-1.5 -22q-22 -15 -31 -29q-8 -12 -27.5 -23.5 t-20.5 -12.5q-13 -14 -15.5 -27t7.5 -18q14 -8 25 -19.5t16 -19t18.5 -13t35.5 -6.5q47 -2 102 15q2 1 23 7t34.5 10.5t29.5 13t21 17.5q9 14 20 8q5 -3 6.5 -8.5t-3 -12t-16.5 -9.5q-20 -6 -56.5 -21.5t-45.5 -19.5q-44 -19 -70 -23q-25 -5 -79 2q-10 2 -9 -2t17 -19 q25 -23 67 -22q17 1 36 7t36 14t33.5 17.5t30 17t24.5 12t17.5 2.5t8.5 -11q0 -2 -1 -4.5t-4 -5t-6 -4.5t-8.5 -5t-9 -4.5t-10 -5t-9.5 -4.5q-28 -14 -67.5 -44t-66.5 -43t-49 -1q-21 11 -63 73q-22 31 -25 22q-1 -3 -1 -10q0 -25 -15 -56.5t-29.5 -55.5t-21 -58t11.5 -63 q-23 -6 -62.5 -90t-47.5 -141q-2 -18 -1.5 -69t-5.5 -59q-8 -24 -29 -3q-32 31 -36 94q-2 28 4 56q4 19 -1 18l-4 -5q-36 -65 10 -166q5 -12 25 -28t24 -20q20 -23 104 -90.5t93 -76.5q16 -15 17.5 -38t-14 -43t-45.5 -23q8 -15 29 -44.5t28 -54t7 -70.5q46 24 7 92 q-4 8 -10.5 16t-9.5 12t-2 6q3 5 13 9.5t20 -2.5q46 -52 166 -36q133 15 177 87q23 38 34 30q12 -6 10 -52q-1 -25 -23 -92q-9 -23 -6 -37.5t24 -15.5q3 19 14.5 77t13.5 90q2 21 -6.5 73.5t-7.5 97t23 70.5q15 18 51 18q1 37 34.5 53t72.5 10.5t60 -22.5zM626 1152 q3 17 -2.5 30t-11.5 15q-9 2 -9 -7q2 -5 5 -6q10 0 7 -15q-3 -20 8 -20q3 0 3 3zM1045 955q-2 8 -6.5 11.5t-13 5t-14.5 5.5q-5 3 -9.5 8t-7 8t-5.5 6.5t-4 4t-4 -1.5q-14 -16 7 -43.5t39 -31.5q9 -1 14.5 8t3.5 20zM867 1168q0 11 -5 19.5t-11 12.5t-9 3q-14 -1 -7 -7l4 -2 q14 -4 18 -31q0 -3 8 2zM921 1401q0 2 -2.5 5t-9 7t-9.5 6q-15 15 -24 15q-9 -1 -11.5 -7.5t-1 -13t-0.5 -12.5q-1 -4 -6 -10.5t-6 -9t3 -8.5q4 -3 8 0t11 9t15 9q1 1 9 1t15 2t9 7zM1486 60q20 -12 31 -24.5t12 -24t-2.5 -22.5t-15.5 -22t-23.5 -19.5t-30 -18.5 t-31.5 -16.5t-32 -15.5t-27 -13q-38 -19 -85.5 -56t-75.5 -64q-17 -16 -68 -19.5t-89 14.5q-18 9 -29.5 23.5t-16.5 25.5t-22 19.5t-47 9.5q-44 1 -130 1q-19 0 -57 -1.5t-58 -2.5q-44 -1 -79.5 -15t-53.5 -30t-43.5 -28.5t-53.5 -11.5q-29 1 -111 31t-146 43q-19 4 -51 9.5 t-50 9t-39.5 9.5t-33.5 14.5t-17 19.5q-10 23 7 66.5t18 54.5q1 16 -4 40t-10 42.5t-4.5 36.5t10.5 27q14 12 57 14t60 12q30 18 42 35t12 51q21 -73 -32 -106q-32 -20 -83 -15q-34 3 -43 -10q-13 -15 5 -57q2 -6 8 -18t8.5 -18t4.5 -17t1 -22q0 -15 -17 -49t-14 -48 q3 -17 37 -26q20 -6 84.5 -18.5t99.5 -20.5q24 -6 74 -22t82.5 -23t55.5 -4q43 6 64.5 28t23 48t-7.5 58.5t-19 52t-20 36.5q-121 190 -169 242q-68 74 -113 40q-11 -9 -15 15q-3 16 -2 38q1 29 10 52t24 47t22 42q8 21 26.5 72t29.5 78t30 61t39 54q110 143 124 195 q-12 112 -16 310q-2 90 24 151.5t106 104.5q39 21 104 21q53 1 106 -13.5t89 -41.5q57 -42 91.5 -121.5t29.5 -147.5q-5 -95 30 -214q34 -113 133 -218q55 -59 99.5 -163t59.5 -191q8 -49 5 -84.5t-12 -55.5t-20 -22q-10 -2 -23.5 -19t-27 -35.5t-40.5 -33.5t-61 -14 q-18 1 -31.5 5t-22.5 13.5t-13.5 15.5t-11.5 20.5t-9 19.5q-22 37 -41 30t-28 -49t7 -97q20 -70 1 -195q-10 -65 18 -100.5t73 -33t85 35.5q59 49 89.5 66.5t103.5 42.5q53 18 77 36.5t18.5 34.5t-25 28.5t-51.5 23.5q-33 11 -49.5 48t-15 72.5t15.5 47.5q1 -31 8 -56.5 t14.5 -40.5t20.5 -28.5t21 -19t21.5 -13t16.5 -9.5z" />
<glyph unicode="&#xf17d;" d="M1024 36q-42 241 -140 498h-2l-2 -1q-16 -6 -43 -16.5t-101 -49t-137 -82t-131 -114.5t-103 -148l-15 11q184 -150 418 -150q132 0 256 52zM839 643q-21 49 -53 111q-311 -93 -673 -93q-1 -7 -1 -21q0 -124 44 -236.5t124 -201.5q50 89 123.5 166.5t142.5 124.5t130.5 81 t99.5 48l37 13q4 1 13 3.5t13 4.5zM732 855q-120 213 -244 378q-138 -65 -234 -186t-128 -272q302 0 606 80zM1416 536q-210 60 -409 29q87 -239 128 -469q111 75 185 189.5t96 250.5zM611 1277q-1 0 -2 -1q1 1 2 1zM1201 1132q-185 164 -433 164q-76 0 -155 -19 q131 -170 246 -382q69 26 130 60.5t96.5 61.5t65.5 57t37.5 40.5zM1424 647q-3 232 -149 410l-1 -1q-9 -12 -19 -24.5t-43.5 -44.5t-71 -60.5t-100 -65t-131.5 -64.5q25 -53 44 -95q2 -6 6.5 -17.5t7.5 -16.5q36 5 74.5 7t73.5 2t69 -1.5t64 -4t56.5 -5.5t48 -6.5t36.5 -6 t25 -4.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
<glyph unicode="&#xf17e;" d="M1173 473q0 50 -19.5 91.5t-48.5 68.5t-73 49t-82.5 34t-87.5 23l-104 24q-30 7 -44 10.5t-35 11.5t-30 16t-16.5 21t-7.5 30q0 77 144 77q43 0 77 -12t54 -28.5t38 -33.5t40 -29t48 -12q47 0 75.5 32t28.5 77q0 55 -56 99.5t-142 67.5t-182 23q-68 0 -132 -15.5 t-119.5 -47t-89 -87t-33.5 -128.5q0 -61 19 -106.5t56 -75.5t80 -48.5t103 -32.5l146 -36q90 -22 112 -36q32 -20 32 -60q0 -39 -40 -64.5t-105 -25.5q-51 0 -91.5 16t-65 38.5t-45.5 45t-46 38.5t-54 16q-50 0 -75.5 -30t-25.5 -75q0 -92 122 -157.5t291 -65.5 q73 0 140 18.5t122.5 53.5t88.5 93.5t33 131.5zM1536 256q0 -159 -112.5 -271.5t-271.5 -112.5q-130 0 -234 80q-77 -16 -150 -16q-143 0 -273.5 55.5t-225 150t-150 225t-55.5 273.5q0 73 16 150q-80 104 -80 234q0 159 112.5 271.5t271.5 112.5q130 0 234 -80 q77 16 150 16q143 0 273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -73 -16 -150q80 -104 80 -234z" />
<glyph unicode="&#xf180;" horiz-adv-x="1664" d="M1483 512l-587 -587q-52 -53 -127.5 -53t-128.5 53l-587 587q-53 53 -53 128t53 128l587 587q53 53 128 53t128 -53l265 -265l-398 -399l-188 188q-42 42 -99 42q-59 0 -100 -41l-120 -121q-42 -40 -42 -99q0 -58 42 -100l406 -408q30 -28 67 -37l6 -4h28q60 0 99 41 l619 619l2 -3q53 -53 53 -128t-53 -128zM1406 1138l120 -120q14 -15 14 -36t-14 -36l-730 -730q-17 -15 -37 -15v0q-4 0 -6 1q-18 2 -30 14l-407 408q-14 15 -14 36t14 35l121 120q13 15 35 15t36 -15l252 -252l574 575q15 15 36 15t36 -15z" />
<glyph unicode="&#xf181;" d="M704 192v1024q0 14 -9 23t-23 9h-480q-14 0 -23 -9t-9 -23v-1024q0 -14 9 -23t23 -9h480q14 0 23 9t9 23zM1376 576v640q0 14 -9 23t-23 9h-480q-14 0 -23 -9t-9 -23v-640q0 -14 9 -23t23 -9h480q14 0 23 9t9 23zM1536 1344v-1408q0 -26 -19 -45t-45 -19h-1408 q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" />
<glyph unicode="&#xf182;" horiz-adv-x="1280" d="M1280 480q0 -40 -28 -68t-68 -28q-51 0 -80 43l-227 341h-45v-132l247 -411q9 -15 9 -33q0 -26 -19 -45t-45 -19h-192v-272q0 -46 -33 -79t-79 -33h-160q-46 0 -79 33t-33 79v272h-192q-26 0 -45 19t-19 45q0 18 9 33l247 411v132h-45l-227 -341q-29 -43 -80 -43 q-40 0 -68 28t-28 68q0 29 16 53l256 384q73 107 176 107h384q103 0 176 -107l256 -384q16 -24 16 -53zM864 1280q0 -93 -65.5 -158.5t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5z" />
<glyph unicode="&#xf183;" horiz-adv-x="1024" d="M1024 832v-416q0 -40 -28 -68t-68 -28t-68 28t-28 68v352h-64v-912q0 -46 -33 -79t-79 -33t-79 33t-33 79v464h-64v-464q0 -46 -33 -79t-79 -33t-79 33t-33 79v912h-64v-352q0 -40 -28 -68t-68 -28t-68 28t-28 68v416q0 80 56 136t136 56h640q80 0 136 -56t56 -136z M736 1280q0 -93 -65.5 -158.5t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5z" />
<glyph unicode="&#xf184;" d="M773 234l350 473q16 22 24.5 59t-6 85t-61.5 79q-40 26 -83 25.5t-73.5 -17.5t-54.5 -45q-36 -40 -96 -40q-59 0 -95 40q-24 28 -54.5 45t-73.5 17.5t-84 -25.5q-46 -31 -60.5 -79t-6 -85t24.5 -59zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
<glyph unicode="&#xf185;" horiz-adv-x="1792" d="M1472 640q0 117 -45.5 223.5t-123 184t-184 123t-223.5 45.5t-223.5 -45.5t-184 -123t-123 -184t-45.5 -223.5t45.5 -223.5t123 -184t184 -123t223.5 -45.5t223.5 45.5t184 123t123 184t45.5 223.5zM1748 363q-4 -15 -20 -20l-292 -96v-306q0 -16 -13 -26q-15 -10 -29 -4 l-292 94l-180 -248q-10 -13 -26 -13t-26 13l-180 248l-292 -94q-14 -6 -29 4q-13 10 -13 26v306l-292 96q-16 5 -20 20q-5 17 4 29l180 248l-180 248q-9 13 -4 29q4 15 20 20l292 96v306q0 16 13 26q15 10 29 4l292 -94l180 248q9 12 26 12t26 -12l180 -248l292 94 q14 6 29 -4q13 -10 13 -26v-306l292 -96q16 -5 20 -20q5 -16 -4 -29l-180 -248l180 -248q9 -12 4 -29z" />
<glyph unicode="&#xf186;" d="M1262 233q-54 -9 -110 -9q-182 0 -337 90t-245 245t-90 337q0 192 104 357q-201 -60 -328.5 -229t-127.5 -384q0 -130 51 -248.5t136.5 -204t204 -136.5t248.5 -51q144 0 273.5 61.5t220.5 171.5zM1465 318q-94 -203 -283.5 -324.5t-413.5 -121.5q-156 0 -298 61 t-245 164t-164 245t-61 298q0 153 57.5 292.5t156 241.5t235.5 164.5t290 68.5q44 2 61 -39q18 -41 -15 -72q-86 -78 -131.5 -181.5t-45.5 -218.5q0 -148 73 -273t198 -198t273 -73q118 0 228 51q41 18 72 -13q14 -14 17.5 -34t-4.5 -38z" />
<glyph unicode="&#xf187;" horiz-adv-x="1792" d="M1088 704q0 26 -19 45t-45 19h-256q-26 0 -45 -19t-19 -45t19 -45t45 -19h256q26 0 45 19t19 45zM1664 896v-960q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v960q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1728 1344v-256q0 -26 -19 -45t-45 -19h-1536 q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1536q26 0 45 -19t19 -45z" />
<glyph unicode="&#xf188;" horiz-adv-x="1664" d="M1632 576q0 -26 -19 -45t-45 -19h-224q0 -171 -67 -290l208 -209q19 -19 19 -45t-19 -45q-18 -19 -45 -19t-45 19l-198 197q-5 -5 -15 -13t-42 -28.5t-65 -36.5t-82 -29t-97 -13v896h-128v-896q-51 0 -101.5 13.5t-87 33t-66 39t-43.5 32.5l-15 14l-183 -207 q-20 -21 -48 -21q-24 0 -43 16q-19 18 -20.5 44.5t15.5 46.5l202 227q-58 114 -58 274h-224q-26 0 -45 19t-19 45t19 45t45 19h224v294l-173 173q-19 19 -19 45t19 45t45 19t45 -19l173 -173h844l173 173q19 19 45 19t45 -19t19 -45t-19 -45l-173 -173v-294h224q26 0 45 -19 t19 -45zM1152 1152h-640q0 133 93.5 226.5t226.5 93.5t226.5 -93.5t93.5 -226.5z" />
<glyph unicode="&#xf189;" horiz-adv-x="1920" d="M1917 1016q23 -64 -150 -294q-24 -32 -65 -85q-78 -100 -90 -131q-17 -41 14 -81q17 -21 81 -82h1l1 -1l1 -1l2 -2q141 -131 191 -221q3 -5 6.5 -12.5t7 -26.5t-0.5 -34t-25 -27.5t-59 -12.5l-256 -4q-24 -5 -56 5t-52 22l-20 12q-30 21 -70 64t-68.5 77.5t-61 58 t-56.5 15.5q-3 -1 -8 -3.5t-17 -14.5t-21.5 -29.5t-17 -52t-6.5 -77.5q0 -15 -3.5 -27.5t-7.5 -18.5l-4 -5q-18 -19 -53 -22h-115q-71 -4 -146 16.5t-131.5 53t-103 66t-70.5 57.5l-25 24q-10 10 -27.5 30t-71.5 91t-106 151t-122.5 211t-130.5 272q-6 16 -6 27t3 16l4 6 q15 19 57 19l274 2q12 -2 23 -6.5t16 -8.5l5 -3q16 -11 24 -32q20 -50 46 -103.5t41 -81.5l16 -29q29 -60 56 -104t48.5 -68.5t41.5 -38.5t34 -14t27 5q2 1 5 5t12 22t13.5 47t9.5 81t0 125q-2 40 -9 73t-14 46l-6 12q-25 34 -85 43q-13 2 5 24q17 19 38 30q53 26 239 24 q82 -1 135 -13q20 -5 33.5 -13.5t20.5 -24t10.5 -32t3.5 -45.5t-1 -55t-2.5 -70.5t-1.5 -82.5q0 -11 -1 -42t-0.5 -48t3.5 -40.5t11.5 -39t22.5 -24.5q8 -2 17 -4t26 11t38 34.5t52 67t68 107.5q60 104 107 225q4 10 10 17.5t11 10.5l4 3l5 2.5t13 3t20 0.5l288 2 q39 5 64 -2.5t31 -16.5z" />
<glyph unicode="&#xf18a;" horiz-adv-x="1792" d="M675 252q21 34 11 69t-45 50q-34 14 -73 1t-60 -46q-22 -34 -13 -68.5t43 -50.5t74.5 -2.5t62.5 47.5zM769 373q8 13 3.5 26.5t-17.5 18.5q-14 5 -28.5 -0.5t-21.5 -18.5q-17 -31 13 -45q14 -5 29 0.5t22 18.5zM943 266q-45 -102 -158 -150t-224 -12 q-107 34 -147.5 126.5t6.5 187.5q47 93 151.5 139t210.5 19q111 -29 158.5 -119.5t2.5 -190.5zM1255 426q-9 96 -89 170t-208.5 109t-274.5 21q-223 -23 -369.5 -141.5t-132.5 -264.5q9 -96 89 -170t208.5 -109t274.5 -21q223 23 369.5 141.5t132.5 264.5zM1563 422 q0 -68 -37 -139.5t-109 -137t-168.5 -117.5t-226 -83t-270.5 -31t-275 33.5t-240.5 93t-171.5 151t-65 199.5q0 115 69.5 245t197.5 258q169 169 341.5 236t246.5 -7q65 -64 20 -209q-4 -14 -1 -20t10 -7t14.5 0.5t13.5 3.5l6 2q139 59 246 59t153 -61q45 -63 0 -178 q-2 -13 -4.5 -20t4.5 -12.5t12 -7.5t17 -6q57 -18 103 -47t80 -81.5t34 -116.5zM1489 1046q42 -47 54.5 -108.5t-6.5 -117.5q-8 -23 -29.5 -34t-44.5 -4q-23 8 -34 29.5t-4 44.5q20 63 -24 111t-107 35q-24 -5 -45 8t-25 37q-5 24 8 44.5t37 25.5q60 13 119 -5.5t101 -65.5z M1670 1209q87 -96 112.5 -222.5t-13.5 -241.5q-9 -27 -34 -40t-52 -4t-40 34t-5 52q28 82 10 172t-80 158q-62 69 -148 95.5t-173 8.5q-28 -6 -52 9.5t-30 43.5t9.5 51.5t43.5 29.5q123 26 244 -11.5t208 -134.5z" />
<glyph unicode="&#xf18b;" horiz-adv-x="1920" d="M805 163q-122 -67 -261 -67q-141 0 -261 67q98 61 167 149t94 191q25 -103 94 -191t167 -149zM453 1176v-344q0 -179 -89.5 -326t-234.5 -217q-129 152 -129 351q0 200 129.5 352t323.5 184zM958 991q-128 -152 -128 -351q0 -201 128 -351q-145 70 -234.5 218t-89.5 328 v341q196 -33 324 -185zM1638 163q-122 -67 -261 -67q-141 0 -261 67q98 61 167 149t94 191q25 -103 94 -191t167 -149zM1286 1176v-344q0 -179 -91 -326t-237 -217v0q133 154 133 351q0 195 -133 351q129 151 328 185zM1920 640q0 -201 -129 -351q-145 70 -234.5 218 t-89.5 328v341q194 -32 323.5 -184t129.5 -352z" />
<glyph unicode="&#xf18c;" horiz-adv-x="1792" />
<glyph unicode="&#xf18d;" horiz-adv-x="1792" />
<glyph unicode="&#xf18e;" horiz-adv-x="1792" />
<glyph unicode="&#xf500;" horiz-adv-x="1792" />
</font>
</defs></svg>

After

Width:  |  Height:  |  Size: 193 KiB

Some files were not shown because too many files have changed in this diff Show More