Initial Files Addition to Repository

All required files are added to the repository with the use of
development branch
This commit is contained in:
Siby P Varkey 2017-04-26 13:59:14 +05:30
parent 029b27702e
commit fd98e37a84
136 changed files with 24400 additions and 0 deletions

243
PEAR2/Autoload.php Normal file
View file

@ -0,0 +1,243 @@
<?php
namespace PEAR2;
if (!class_exists('\PEAR2\Autoload', false)) {
class Autoload
{
/**
* Whether the autoload class has been spl_autoload_register-ed
*
* @var bool
*/
protected static $registered = false;
/**
* Array of PEAR2 autoload paths registered
*
* @var array
*/
protected static $paths = array();
/**
* Array of classname-to-file mapping
*
* @var array
*/
protected static $map = array();
/**
* Array of class maps loaded
*
* @var array
*/
protected static $maps = array();
/**
* Last classmap specified
*
* @var array
*/
protected static $mapfile = null;
/**
* Array of classes loaded automatically not in the map
*
* @var array
*/
protected static $unmapped = array();
/**
* Initialize the PEAR2 autoloader
*
* @param string $path Directory path to register
*
* @return void
*/
static function initialize($path, $mapfile = null)
{
self::register();
self::addPath($path);
self::addMap($mapfile);
}
/**
* Register the PEAR2 autoload class with spl_autoload_register
*
* @return void
*/
protected static function register()
{
if (!self::$registered) {
// set up __autoload
$autoload = spl_autoload_functions();
spl_autoload_register('PEAR2\Autoload::load');
if (function_exists('__autoload') && ($autoload === false)) {
// __autoload() was being used, but now would be ignored, add
// it to the autoload stack
spl_autoload_register('__autoload');
}
}
self::$registered = true;
}
/**
* Add a path
*
* @param string $path The directory to add to the set of PEAR2 paths
*
* @return void
*/
protected static function addPath($path)
{
if (!in_array($path, self::$paths)) {
self::$paths[] = $path;
}
}
/**
* Add a classname-to-file map
*
* @param string $mapfile The filename of the classmap
*
* @return void
*/
protected static function addMap($mapfile)
{
if (! in_array($mapfile, self::$maps)) {
// keep track of specific map file loaded in this
// instance so we can update it if necessary
self::$mapfile = $mapfile;
if (file_exists($mapfile)) {
$map = include $mapfile;
if (is_array($map)) {
// mapfile contains a valid map, so we'll keep it
self::$maps[] = $mapfile;
self::$map = array_merge(self::$map, $map);
}
}
}
}
/**
* Check if the class is already defined in a classmap
*
* @param string $class The class to look for
*
* @return bool
*/
protected static function isMapped($class)
{
if (isset(self::$map[$class])) {
return true;
}
if (isset(self::$mapfile) && ! isset(self::$map[$class])) {
self::$unmapped[] = $class;
return false;
}
return false;
}
/**
* Load a PEAR2 class
*
* @param string $class The class to load
*
* @return bool
*/
static function load($class)
{
// need to check if there's a current map file specified ALSO.
// this could be the first time writing it.
$mapped = self::isMapped($class);
if ($mapped) {
require self::$map[$class];
if (!self::loadSuccessful($class)) {
// record this failure & keep going, we may still find it
self::$unmapped[] = $class;
} else {
return true;
}
}
$file = str_replace(array('_', '\\'), DIRECTORY_SEPARATOR, $class) . '.php';
foreach (self::$paths as $path) {
if (file_exists($path . DIRECTORY_SEPARATOR . $file)) {
require $path . DIRECTORY_SEPARATOR . $file;
if (!self::loadSuccessful($class)) {
throw new \Exception('Class ' . $class . ' was not present in ' .
$path . DIRECTORY_SEPARATOR . $file .
'") [PEAR2_Autoload-0.2.4]');
}
if (in_array($class, self::$unmapped)) {
self::updateMap($class, $path . DIRECTORY_SEPARATOR . $file);
}
return true;
}
}
$e = new \Exception('Class ' . $class . ' could not be loaded from ' .
$file . ', file does not exist (registered paths="' .
implode(PATH_SEPARATOR, self::$paths) .
'") [PEAR2_Autoload-0.2.4]');
$trace = $e->getTrace();
if (isset($trace[2]) && isset($trace[2]['function']) &&
in_array($trace[2]['function'], array('class_exists', 'interface_exists'))) {
return false;
}
if (isset($trace[1]) && isset($trace[1]['function']) &&
in_array($trace[1]['function'], array('class_exists', 'interface_exists'))) {
return false;
}
throw $e;
}
/**
* Check if the requested class was loaded from the specified path
*
* @return bool
*/
protected static function loadSuccessful($class)
{
if (!class_exists($class, false) && !interface_exists($class, false)) {
return false;
}
return true;
}
/**
* If possible, update the classmap file with newly-discovered
* mapping.
*
* @param string $class Class name discovered
*
* @param string $origin File where class was found
*
*/
protected static function updateMap($class, $origin)
{
if (is_writable(self::$mapfile) || is_writable(dirname(self::$mapfile))) {
self::$map[$class] = $origin;
file_put_contents(self::$mapfile,
'<'."?php\n"
. "// PEAR2\Autoload auto-generated classmap\n"
. "return " . var_export(self::$map, true) . ';',
LOCK_EX
);
}
}
/**
* return the array of paths PEAR2 autoload has registered
*
* @return array
*/
static function getPaths()
{
return self::$paths;
}
}
}
Autoload::initialize(dirname(__DIR__));

371
PEAR2/Cache/SHM.php Normal file
View file

@ -0,0 +1,371 @@
<?php
/**
* ~~summary~~
*
* ~~description~~
*
* PHP version 5
*
* @category Caching
* @package PEAR2_Cache_SHM
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 0.1.3
* @link http://pear2.php.net/PEAR2_Cache_SHM
*/
/**
* The namespace declaration.
*/
namespace PEAR2\Cache;
/**
* Used as a catch-all for adapter initialization.
*/
use Exception as E;
/**
* Implements this class.
*/
use IteratorAggregate;
/**
* Used on failures by this class.
*/
use PEAR2\Cache\SHM\InvalidArgumentException;
/**
* Main class for this package.
*
* Automatically chooses an adapter based on the available extensions.
*
* @category Caching
* @package PEAR2_Cache_SHM
* @author Vasil Rangelov <boen.robot@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear2.php.net/PEAR2_Cache_SHM
*/
abstract class SHM implements IteratorAggregate
{
/**
* @var array An array of adapter names that meet their requirements.
*/
private static $_adapters = array();
/**
* Creates a new shared memory storage.
*
* Estabilishes a separate persistent storage. Adapter is automatically
* chosen based on the available extensions.
*
* @param string $persistentId The ID for the storage.
*
* @return static|SHM A new instance of an SHM adapter (child of this
* class).
*/
final public static function factory($persistentId)
{
foreach (self::$_adapters as $adapter) {
try {
return new $adapter($persistentId);
} catch (E $e) {
//In case of a runtime error, try to fallback to other adapters.
}
}
throw new InvalidArgumentException(
'No appropriate adapter available',
1
);
}
/**
* Checks if the adapter meets its requirements.
*
* @return bool TRUE on success, FALSE on failure.
*/
public static function isMeetingRequirements()
{
return true;
}
/**
* Registers an adapter.
*
* Registers an SHM adapter, allowing you to call it with {@link factory()}.
*
* @param string $adapter FQCN of adapter. A valid adapter is one that
* extends this class. The class will be autoloaded if not already
* present.
* @param bool $prepend Whether to prepend this adapter into the list of
* possible adapters, instead of appending to it.
*
* @return bool TRUE on success, FALSE on failure.
*/
final public static function registerAdapter($adapter, $prepend = false)
{
if (class_exists($adapter, true)
&& is_subclass_of($adapter, '\\' . __CLASS__)
&& $adapter::isMeetingRequirements()
) {
if ($prepend) {
self::$_adapters = array_merge(
array($adapter),
self::$_adapters
);
} else {
self::$_adapters[] = $adapter;
}
return true;
}
return false;
}
/**
* Adds a value to the shared memory storage.
*
* Adds a value to the storage if it doesn't exist, or fails if it does.
*
* @param string $key Name of key to associate the value with.
* @param mixed $value Value for the specified key.
* @param int $ttl Seconds to store the value. If set to 0 indicates no
* time limit.
*
* @return bool TRUE on success, FALSE on failure.
*/
public function __invoke($key, $value, $ttl = 0)
{
return $this->add($key, $value, $ttl);
}
/**
* Gets a value from the shared memory storage.
*
* This is a magic method, thanks to which any property you attempt to get
* the value of will be fetched from the adapter, treating the property name
* as the key of the value to get.
*
* @param string $key Name of key to get.
*
* @return mixed The current value of the specified key.
*/
public function __get($key)
{
return $this->get($key);
}
/**
* Sets a value in the shared memory storage.
*
* This is a magic method, thanks to which any property you attempt to set
* the value of will be set by the adapter, treating the property name as
* the key of the value to set. The value is set without a TTL.
*
* @param string $key Name of key to associate the value with.
* @param mixed $value Value for the specified key.
*
* @return bool TRUE on success, FALSE on failure.
*/
public function __set($key, $value)
{
return $this->set($key, $value);
}
/**
* Checks if a specified key is in the storage.
*
* This is a magic method, thanks to which any property you call isset() on
* will be checked by the adapter, treating the property name as the key
* of the value to check.
*
* @param string $key Name of key to check.
*
* @return bool TRUE if the key is in the storage, FALSE otherwise.
*/
public function __isset($key)
{
return $this->exists($key);
}
/**
* Deletes a value from the shared memory storage.
*
* This is a magic method, thanks to which any property you attempt to unset
* the value of will be unset by the adapter, treating the property name as
* the key of the value to delete.
*
* @param string $key Name of key to delete.
*
* @return bool TRUE on success, FALSE on failure.
*/
public function __unset($key)
{
return $this->delete($key);
}
/**
* Creates a new shared memory storage.
*
* Estabilishes a separate persistent storage.
*
* @param string $persistentId The ID for the storage. The storage will be
* reused if it exists, or created if it doesn't exist. Data and locks
* are namespaced by this ID.
*/
abstract public function __construct($persistentId);
/**
* Obtains a named lock.
*
* @param string $key Name of the key to obtain. Note that $key may
* repeat for each distinct $persistentId.
* @param double $timeout If the lock can't be immediatly obtained, the
* script will block for at most the specified amount of seconds.
* Setting this to 0 makes lock obtaining non blocking, and setting it
* to NULL makes it block without a time limit.
*
* @return bool TRUE on success, FALSE on failure.
*/
abstract public function lock($key, $timeout = null);
/**
* Releases a named lock.
*
* @param string $key Name of the key to release. Note that $key may
* repeat for each distinct $persistentId.
*
* @return bool TRUE on success, FALSE on failure.
*/
abstract public function unlock($key);
/**
* Checks if a specified key is in the storage.
*
* @param string $key Name of key to check.
*
* @return bool TRUE if the key is in the storage, FALSE otherwise.
*/
abstract public function exists($key);
/**
* Adds a value to the shared memory storage.
*
* Adds a value to the storage if it doesn't exist, or fails if it does.
*
* @param string $key Name of key to associate the value with.
* @param mixed $value Value for the specified key.
* @param int $ttl Seconds to store the value. If set to 0 indicates no
* time limit.
*
* @return bool TRUE on success, FALSE on failure.
*/
abstract public function add($key, $value, $ttl = 0);
/**
* Sets a value in the shared memory storage.
*
* Adds a value to the storage if it doesn't exist, overwrites it otherwise.
*
* @param string $key Name of key to associate the value with.
* @param mixed $value Value for the specified key.
* @param int $ttl Seconds to store the value. If set to 0 indicates no
* time limit.
*
* @return bool TRUE on success, FALSE on failure.
*/
abstract public function set($key, $value, $ttl = 0);
/**
* Gets a value from the shared memory storage.
*
* Gets the current value, or throws an exception if it's not stored.
*
* @param string $key Name of key to get the value of.
*
* @return mixed The current value of the specified key.
*/
abstract public function get($key);
/**
* Deletes a value from the shared memory storage.
*
* @param string $key Name of key to delete.
*
* @return bool TRUE on success, FALSE on failure.
*/
abstract public function delete($key);
/**
* Increases a value from the shared memory storage.
*
* Increases a value from the shared memory storage. Unlike a plain
* set($key, get($key)+$step) combination, this function also implicitly
* performs locking.
*
* @param string $key Name of key to increase.
* @param int $step Value to increase the key by.
*
* @return int The new value.
*/
abstract public function inc($key, $step = 1);
/**
* Decreases a value from the shared memory storage.
*
* Decreases a value from the shared memory storage. Unlike a plain
* set($key, get($key)-$step) combination, this function also implicitly
* performs locking.
*
* @param string $key Name of key to decrease.
* @param int $step Value to decrease the key by.
*
* @return int The new value.
*/
abstract public function dec($key, $step = 1);
/**
* Sets a new value if a key has a certain value.
*
* Sets a new value if a key has a certain value. This function only works
* when $old and $new are longs.
*
* @param string $key Key of the value to compare and set.
* @param int $old The value to compare the key against.
* @param int $new The value to set the key to.
*
* @return bool TRUE on success, FALSE on failure.
*/
abstract public function cas($key, $old, $new);
/**
* Clears the persistent storage.
*
* Clears the persistent storage, i.e. removes all keys. Locks are left
* intact.
*
* @return void
*/
abstract public function clear();
/**
* Retrieve an external iterator
*
* Returns an external iterator.
*
* @param string|null $filter A PCRE regular expression.
* Only matching keys will be iterated over.
* Setting this to NULL matches all keys of this instance.
* @param bool $keysOnly Whether to return only the keys,
* or return both the keys and values.
*
* @return \Traversable An array with all matching keys as array keys,
* and values as array values. If $keysOnly is TRUE, the array keys are
* numeric, and the array values are key names.
*/
abstract public function getIterator($filter = null, $keysOnly = false);
}
SHM::registerAdapter('\\' . __NAMESPACE__ . '\SHM\Adapter\Placebo');
SHM::registerAdapter('\\' . __NAMESPACE__ . '\SHM\Adapter\Wincache');
SHM::registerAdapter('\\' . __NAMESPACE__ . '\SHM\Adapter\APC');

View file

@ -0,0 +1,406 @@
<?php
/**
* ~~summary~~
*
* ~~description~~
*
* PHP version 5
*
* @category Caching
* @package PEAR2_Cache_SHM
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 0.1.3
* @link http://pear2.php.net/PEAR2_Cache_SHM
*/
/**
* The namespace declaration.
*/
namespace PEAR2\Cache\SHM\Adapter;
/**
* Throws exceptions from this namespace, and extends from this class.
*/
use PEAR2\Cache\SHM;
/**
* {@link APC::getIterator()} returns this object.
*/
use ArrayObject;
/**
* Shared memory adapter for the APC extension.
*
* @category Caching
* @package PEAR2_Cache_SHM
* @author Vasil Rangelov <boen.robot@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear2.php.net/PEAR2_Cache_SHM
*/
class APC extends SHM
{
/**
* @var string ID of the current storage.
*/
protected $persistentId;
/**
* List of persistent IDs.
*
* A list of persistent IDs within the current request (as keys) with an int
* (as a value) specifying the number of instances in the current request.
* Used as an attempt to ensure implicit lock releases even on errors in the
* critical sections, since APC doesn't have an actual locking function.
* @var array
*/
protected static $requestInstances = array();
/**
* @var array Array of lock names (as values) for each persistent ID (as
* key) obtained during the current request.
*/
protected static $locksBackup = array();
/**
* Creates a new shared memory storage.
*
* Estabilishes a separate persistent storage.
*
* @param string $persistentId The ID for the storage. The storage will be
* reused if it exists, or created if it doesn't exist. Data and locks
* are namespaced by this ID.
*/
public function __construct($persistentId)
{
$this->persistentId = __CLASS__ . ' ' . $persistentId;
if (isset(static::$requestInstances[$this->persistentId])) {
static::$requestInstances[$this->persistentId]++;
} else {
static::$requestInstances[$this->persistentId] = 1;
static::$locksBackup[$this->persistentId] = array();
}
register_shutdown_function(
get_called_class() . '::releaseLocks',
$this->persistentId,
true
);
}
/**
* Checks if the adapter meets its requirements.
*
* @return bool TRUE on success, FALSE on failure.
*/
public static function isMeetingRequirements()
{
return extension_loaded('apc')
&& version_compare(phpversion('apc'), '3.0.13', '>=')
&& ini_get('apc.enabled')
&& ('cli' !== PHP_SAPI || ini_get('apc.enable_cli'));
}
/**
* Releases all locks in a storage.
*
* This function is not meant to be used directly. It is implicitly called
* by the the destructor and as a shutdown function when the request ends.
* One of these calls ends up releasing any unreleased locks obtained
* during the request. A lock is also implicitly released as soon as there
* are no objects left in the current request using the same persistent ID.
*
* @param string $internalPersistentId The internal persistent ID, the locks
* of which are being released.
* @param bool $isAtShutdown Whether the function was executed at
* shutdown.
*
* @return void
* @internal
*/
public static function releaseLocks($internalPersistentId, $isAtShutdown)
{
$hasInstances = 0 !== static::$requestInstances[$internalPersistentId];
if ($isAtShutdown === $hasInstances) {
foreach (static::$locksBackup[$internalPersistentId] as $key) {
apc_delete($internalPersistentId . 'l ' . $key);
}
}
}
/**
* Releases any locks obtained by this instance as soon as there are no more
* references to the object's persistent ID.
*/
public function __destruct()
{
static::$requestInstances[$this->persistentId]--;
static::releaseLocks($this->persistentId, false);
}
/**
* Obtains a named lock.
*
* @param string $key Name of the key to obtain. Note that $key may
* repeat for each distinct $persistentId.
* @param double $timeout If the lock can't be immediatly obtained, the
* script will block for at most the specified amount of seconds.
* Setting this to 0 makes lock obtaining non blocking, and setting it
* to NULL makes it block without a time limit.
*
* @return bool TRUE on success, FALSE on failure.
*/
public function lock($key, $timeout = null)
{
$lock = $this->persistentId . 'l ' . $key;
$hasTimeout = $timeout !== null;
$start = microtime(true);
while (!apc_add($lock, 1)) {
if ($hasTimeout && (microtime(true) - $start) > $timeout) {
return false;
}
}
static::$locksBackup[$this->persistentId] = $key;
return true;
}
/**
* Releases a named lock.
*
* @param string $key Name of the key to release. Note that $key may
* repeat for each distinct $persistentId.
*
* @return bool TRUE on success, FALSE on failure.
*/
public function unlock($key)
{
$lock = $this->persistentId . 'l ' . $key;
$success = apc_delete($lock);
if ($success) {
unset(static::$locksBackup[$this->persistentId][array_search(
$key,
static::$locksBackup[$this->persistentId],
true
)]);
return true;
}
return false;
}
/**
* Checks if a specified key is in the storage.
*
* @param string $key Name of key to check.
*
* @return bool TRUE if the key is in the storage, FALSE otherwise.
*/
public function exists($key)
{
return apc_exists($this->persistentId . 'd ' . $key);
}
/**
* Adds a value to the shared memory storage.
*
* Adds a value to the storage if it doesn't exist, or fails if it does.
*
* @param string $key Name of key to associate the value with.
* @param mixed $value Value for the specified key.
* @param int $ttl Seconds to store the value. If set to 0 indicates no
* time limit.
*
* @return bool TRUE on success, FALSE on failure.
*/
public function add($key, $value, $ttl = 0)
{
return apc_add($this->persistentId . 'd ' . $key, $value, $ttl);
}
/**
* Sets a value in the shared memory storage.
*
* Adds a value to the storage if it doesn't exist, overwrites it otherwise.
*
* @param string $key Name of key to associate the value with.
* @param mixed $value Value for the specified key.
* @param int $ttl Seconds to store the value. If set to 0 indicates no
* time limit.
*
* @return bool TRUE on success, FALSE on failure.
*/
public function set($key, $value, $ttl = 0)
{
return apc_store($this->persistentId . 'd ' . $key, $value, $ttl);
}
/**
* Gets a value from the shared memory storage.
*
* Gets the current value, or throws an exception if it's not stored.
*
* @param string $key Name of key to get the value of.
*
* @return mixed The current value of the specified key.
*/
public function get($key)
{
$fullKey = $this->persistentId . 'd ' . $key;
if (apc_exists($fullKey)) {
$value = apc_fetch($fullKey, $success);
if (!$success) {
throw new SHM\InvalidArgumentException(
'Unable to fetch key. ' .
'Key has either just now expired or (if no TTL was set) ' .
'is possibly in a race condition with another request.',
100
);
}
return $value;
}
throw new SHM\InvalidArgumentException('No such key in cache', 101);
}
/**
* Deletes a value from the shared memory storage.
*
* @param string $key Name of key to delete.
*
* @return bool TRUE on success, FALSE on failure.
*/
public function delete($key)
{
return apc_delete($this->persistentId . 'd ' . $key);
}
/**
* Increases a value from the shared memory storage.
*
* Increases a value from the shared memory storage. Unlike a plain
* set($key, get($key)+$step) combination, this function also implicitly
* performs locking.
*
* @param string $key Name of key to increase.
* @param int $step Value to increase the key by.
*
* @return int The new value.
*/
public function inc($key, $step = 1)
{
$newValue = apc_inc(
$this->persistentId . 'd ' . $key,
(int) $step,
$success
);
if (!$success) {
throw new SHM\InvalidArgumentException(
'Unable to increase the value. Are you sure the value is int?',
102
);
}
return $newValue;
}
/**
* Decreases a value from the shared memory storage.
*
* Decreases a value from the shared memory storage. Unlike a plain
* set($key, get($key)-$step) combination, this function also implicitly
* performs locking.
*
* @param string $key Name of key to decrease.
* @param int $step Value to decrease the key by.
*
* @return int The new value.
*/
public function dec($key, $step = 1)
{
$newValue = apc_dec(
$this->persistentId . 'd ' . $key,
(int) $step,
$success
);
if (!$success) {
throw new SHM\InvalidArgumentException(
'Unable to decrease the value. Are you sure the value is int?',
103
);
}
return $newValue;
}
/**
* Sets a new value if a key has a certain value.
*
* Sets a new value if a key has a certain value. This function only works
* when $old and $new are longs.
*
* @param string $key Key of the value to compare and set.
* @param int $old The value to compare the key against.
* @param int $new The value to set the key to.
*
* @return bool TRUE on success, FALSE on failure.
*/
public function cas($key, $old, $new)
{
return apc_cas($this->persistentId . 'd ' . $key, $old, $new);
}
/**
* Clears the persistent storage.
*
* Clears the persistent storage, i.e. removes all keys. Locks are left
* intact.
*
* @return void
*/
public function clear()
{
foreach (new APCIterator(
'user',
'/^' . preg_quote($this->persistentId, '/') . 'd /',
APC_ITER_KEY,
100,
APC_LIST_ACTIVE
) as $key) {
apc_delete($key);
}
}
/**
* Retrieve an external iterator
*
* Returns an external iterator.
*
* @param string|null $filter A PCRE regular expression.
* Only matching keys will be iterated over.
* Setting this to NULL matches all keys of this instance.
* @param bool $keysOnly Whether to return only the keys,
* or return both the keys and values.
*
* @return ArrayObject An array with all matching keys as array keys,
* and values as array values. If $keysOnly is TRUE, the array keys are
* numeric, and the array values are key names.
*/
public function getIterator($filter = null, $keysOnly = false)
{
$result = array();
foreach (new APCIterator(
'user',
'/^' . preg_quote($this->persistentId, '/') . 'd /',
APC_ITER_KEY,
100,
APC_LIST_ACTIVE
) as $key) {
$localKey = strstr($key, $this->persistentId . 'd ');
if (null === $filter || preg_match($filter, $localKey)) {
if ($keysOnly) {
$result[] = $localKey;
} else {
$result[$localKey] = apc_fetch($key);
}
}
}
return new ArrayObject($result);
}
}

View file

@ -0,0 +1,358 @@
<?php
/**
* ~~summary~~
*
* ~~description~~
*
* PHP version 5
*
* @category Caching
* @package PEAR2_Cache_SHM
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 0.1.3
* @link http://pear2.php.net/PEAR2_Cache_SHM
*/
/**
* The namespace declaration.
*/
namespace PEAR2\Cache\SHM\Adapter;
/**
* Throws exceptions from this namespace, and extends from this class.
*/
use PEAR2\Cache\SHM;
/**
* {@link Placebo::getIterator()} returns this object.
*/
use ArrayObject;
/**
* This adapter is not truly persistent. It is intended to emulate persistency
* in non persistent environments, so that upper level applications can use a
* single code path for persistent and non persistent code.
*
* @category Caching
* @package PEAR2_Cache_SHM
* @author Vasil Rangelov <boen.robot@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear2.php.net/PEAR2_Cache_SHM
*/
class Placebo extends SHM
{
/**
* @var string ID of the current storage.
*/
protected $persistentId;
/**
* List of persistent IDs.
*
* A list of persistent IDs within the current request (as keys) with an int
* (as a value) specifying the number of instances in the current request.
* Used as an attempt to ensure implicit lock releases on destruction.
* @var array
*/
protected static $requestInstances = array();
/**
* @var array Array of lock names (as values) for each persistent ID (as
* key) obtained during the current request.
*/
protected static $locksBackup = array();
/**
* The data storage.
*
* Each persistent ID is a key, and the value is an array.
* Each such array has data keys as its keys, and an array as a value.
* Each such array has as its elements the value, the timeout and the time
* the data was set.
* @var array
*/
protected static $data = array();
/**
* Creates a new shared memory storage.
*
* Estabilishes a separate persistent storage.
*
* @param string $persistentId The ID for the storage. The storage will be
* reused if it exists, or created if it doesn't exist. Data and locks
* are namespaced by this ID.
*/
public function __construct($persistentId)
{
if (isset(static::$requestInstances[$persistentId])) {
++static::$requestInstances[$persistentId];
} else {
static::$requestInstances[$persistentId] = 1;
static::$locksBackup[$persistentId] = array();
static::$data[$persistentId] = array();
}
$this->persistentId = $persistentId;
}
/**
* Releases any unreleased locks.
*/
public function __destruct()
{
if (0 === --static::$requestInstances[$this->persistentId]) {
static::$locksBackup[$this->persistentId] = array();
}
}
/**
* Checks if the adapter meets its requirements.
*
* @return bool TRUE on success, FALSE on failure.
*/
public static function isMeetingRequirements()
{
return 'cli' === PHP_SAPI;
}
/**
* Pretends to obtain a lock.
*
* @param string $key Ignored.
* @param double $timeout Ignored.
*
* @return bool TRUE on success, FALSE on failure.
*/
public function lock($key, $timeout = null)
{
$key = (string) $key;
if (in_array($key, static::$locksBackup[$this->persistentId], true)) {
return false;
}
static::$locksBackup[$this->persistentId][] = $key;
return true;
}
/**
* Pretends to release a lock.
*
* @param string $key Ignored
*
* @return bool TRUE on success, FALSE on failure.
*/
public function unlock($key)
{
$key = (string) $key;
if (!in_array($key, static::$locksBackup[$this->persistentId], true)) {
return false;
}
unset(static::$locksBackup[$this->persistentId][array_search(
$key,
static::$locksBackup[$this->persistentId],
true
)]);
return true;
}
/**
* Checks if a specified key is in the storage.
*
* @param string $key Name of key to check.
*
* @return bool TRUE if the key is in the storage, FALSE otherwise.
*/
public function exists($key)
{
return array_key_exists($key, static::$data[$this->persistentId]);
}
/**
* Adds a value to the shared memory storage.
*
* Adds a value to the storage if it doesn't exist, or fails if it does.
*
* @param string $key Name of key to associate the value with.
* @param mixed $value Value for the specified key.
* @param int $ttl Because "true" adapters purge the cache at the next
* request, this setting is ignored.
*
* @return bool TRUE on success, FALSE on failure.
*/
public function add($key, $value, $ttl = 0)
{
if ($this->exists($key)) {
return false;
}
return $this->set($key, $value, $ttl);
}
/**
* Sets a value in the shared memory storage.
*
* Adds a value to the storage if it doesn't exist, overwrites it otherwise.
*
* @param string $key Name of key to associate the value with.
* @param mixed $value Value for the specified key.
* @param int $ttl Because "true" adapters purge the cache at the next
* request, this setting is ignored.
*
* @return bool TRUE on success, FALSE on failure.
*/
public function set($key, $value, $ttl = 0)
{
static::$data[$this->persistentId][$key] = $value;
return true;
}
/**
* Gets a value from the shared memory storage.
*
* Gets the current value, or throws an exception if it's not stored.
*
* @param string $key Name of key to get the value of.
*
* @return mixed The current value of the specified key.
*/
public function get($key)
{
if ($this->exists($key)) {
return static::$data[$this->persistentId][$key];
}
throw new SHM\InvalidArgumentException(
'Unable to fetch key. No such key.',
200
);
}
/**
* Deletes a value from the shared memory storage.
*
* @param string $key Name of key to delete.
*
* @return bool TRUE on success, FALSE on failure.
*/
public function delete($key)
{
if ($this->exists($key)) {
unset(static::$data[$this->persistentId][$key]);
return true;
}
return false;
}
/**
* Increases a value from the shared memory storage.
*
* Increases a value from the shared memory storage. Unlike a plain
* set($key, get($key)+$step) combination, this function also implicitly
* performs locking.
*
* @param string $key Name of key to increase.
* @param int $step Value to increase the key by.
*
* @return int The new value.
*/
public function inc($key, $step = 1)
{
if (!$this->exists($key) || !is_int($value = $this->get($key))
|| !$this->set($key, $value + (int) $step)
) {
throw new SHM\InvalidArgumentException(
'Unable to increase the value. Are you sure the value is int?',
201
);
}
return $this->get($key);
}
/**
* Decreases a value from the shared memory storage.
*
* Decreases a value from the shared memory storage. Unlike a plain
* set($key, get($key)-$step) combination, this function also implicitly
* performs locking.
*
* @param string $key Name of key to decrease.
* @param int $step Value to decrease the key by.
*
* @return int The new value.
*/
public function dec($key, $step = 1)
{
if (!$this->exists($key) || !is_int($value = $this->get($key))
|| !$this->set($key, $value - (int) $step)
) {
throw new SHM\InvalidArgumentException(
'Unable to increase the value. Are you sure the value is int?',
202
);
}
return $this->get($key);
}
/**
* Sets a new value if a key has a certain value.
*
* Sets a new value if a key has a certain value. This function only works
* when $old and $new are longs.
*
* @param string $key Key of the value to compare and set.
* @param int $old The value to compare the key against.
* @param int $new The value to set the key to.
*
* @return bool TRUE on success, FALSE on failure.
*/
public function cas($key, $old, $new)
{
return $this->exists($key) && ($this->get($key) === $old)
&& is_int($new) && $this->set($key, $new);
}
/**
* Clears the persistent storage.
*
* Clears the persistent storage, i.e. removes all keys. Locks are left
* intact.
*
* @return void
*/
public function clear()
{
static::$data[$this->persistentId] = array();
}
/**
* Retrieve an external iterator
*
* Returns an external iterator.
*
* @param string|null $filter A PCRE regular expression.
* Only matching keys will be iterated over.
* Setting this to NULL matches all keys of this instance.
* @param bool $keysOnly Whether to return only the keys,
* or return both the keys and values.
*
* @return ArrayObject An array with all matching keys as array keys,
* and values as array values. If $keysOnly is TRUE, the array keys are
* numeric, and the array values are key names.
*/
public function getIterator($filter = null, $keysOnly = false)
{
if (null === $filter) {
return new ArrayObject(
$keysOnly
? array_keys(static::$data[$this->persistentId])
: static::$data[$this->persistentId]
);
}
$result = array();
foreach (static::$data[$this->persistentId] as $key => $value) {
if (preg_match($filter, $key)) {
$result[$key] = $value;
}
}
return new ArrayObject($keysOnly ? array_keys($result) : $result);
}
}

View file

@ -0,0 +1,383 @@
<?php
/**
* ~~summary~~
*
* ~~description~~
*
* PHP version 5
*
* @category Caching
* @package PEAR2_Cache_SHM
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 0.1.3
* @link http://pear2.php.net/PEAR2_Cache_SHM
*/
/**
* The namespace declaration.
*/
namespace PEAR2\Cache\SHM\Adapter;
/**
* Throws exceptions from this namespace, and extends from this class.
*/
use PEAR2\Cache\SHM;
/**
* {@link Wincache::getIterator()} returns this object.
*/
use ArrayObject;
/**
* Shared memory adapter for the WinCache extension.
*
* @category Caching
* @package PEAR2_Cache_SHM
* @author Vasil Rangelov <boen.robot@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear2.php.net/PEAR2_Cache_SHM
*/
class Wincache extends SHM
{
/**
* @var string ID of the current storage.
*/
protected $persistentId;
/**
* List of persistent IDs.
*
* A list of persistent IDs within the current request (as keys) with an int
* (as a value) specifying the number of instances in the current request.
* Used as an attempt to ensure implicit lock releases on destruction.
* @var array
*/
protected static $requestInstances = array();
/**
* @var array Array of lock names obtained during the current request.
*/
protected static $locksBackup = array();
/**
* Creates a new shared memory storage.
*
* Estabilishes a separate persistent storage.
*
* @param string $persistentId The ID for the storage. The storage will be
* reused if it exists, or created if it doesn't exist. Data and locks
* are namespaced by this ID.
*/
public function __construct($persistentId)
{
$this->persistentId
= static::encodeLockName(__CLASS__ . ' ' . $persistentId) . ' ';
if (isset(static::$requestInstances[$this->persistentId])) {
static::$requestInstances[$this->persistentId]++;
} else {
static::$requestInstances[$this->persistentId] = 1;
static::$locksBackup[$this->persistentId] = array();
}
}
/**
* Encodes a lock name
*
* Encodes a lock name, so that it can be properly obtained. The scheme used
* is a subset of URL encoding, with only the "%" and "\" characters being
* escaped. The encoding itself is necessary, since lock names can't contain
* the "\" character.
*
* @param string $name The lock name to encode.
*
* @return string The encoded name.
* @link http://msdn.microsoft.com/en-us/library/ms682411(VS.85).aspx
*/
protected static function encodeLockName($name)
{
return str_replace(array('%', '\\'), array('%25', '%5C'), $name);
}
/**
* Checks if the adapter meets its requirements.
*
* @return bool TRUE on success, FALSE on failure.
*/
public static function isMeetingRequirements()
{
return extension_loaded('wincache')
&& version_compare(phpversion('wincache'), '1.1.0', '>=')
&& ini_get('wincache.ucenabled')
&& ('cli' !== PHP_SAPI || ini_get('wincache.enablecli'));
}
/**
* Releases any locks obtained by this instance as soon as there are no more
* references to the object's persistent ID.
*/
public function __destruct()
{
if (0 === --static::$requestInstances[$this->persistentId]) {
foreach (static::$locksBackup[$this->persistentId] as $key) {
wincache_unlock(
$this->persistentId . static::encodeLockName($key)
);
}
}
}
/**
* Obtains a named lock.
*
* @param string $key Name of the key to obtain. Note that $key may
* repeat for each distinct $persistentId.
* @param double $timeout Ignored with WinCache. Script will always block if
* the lock can't be immediatly obtained.
*
* @return bool TRUE on success, FALSE on failure.
*/
public function lock($key, $timeout = null)
{
$result = wincache_lock(
$this->persistentId . static::encodeLockName($key)
);
if ($result) {
static::$locksBackup[$this->persistentId] = $key;
}
return $result;
}
/**
* Releases a named lock.
*
* @param string $key Name of the key to release. Note that $key may
* repeat for each distinct $persistentId.
*
* @return bool TRUE on success, FALSE on failure.
*/
public function unlock($key)
{
$result = wincache_unlock(
$this->persistentId . static::encodeLockName($key)
);
if ($result) {
unset(static::$locksBackup[$this->persistentId][array_search(
$key,
static::$locksBackup[$this->persistentId],
true
)]);
}
return $result;
}
/**
* Checks if a specified key is in the storage.
*
* @param string $key Name of key to check.
*
* @return bool TRUE if the key is in the storage, FALSE otherwise.
*/
public function exists($key)
{
return wincache_ucache_exists($this->persistentId . $key);
}
/**
* Adds a value to the shared memory storage.
*
* Sets a value to the storage if it doesn't exist, or fails if it does.
*
* @param string $key Name of key to associate the value with.
* @param mixed $value Value for the specified key.
* @param int $ttl Seconds to store the value. If set to 0 indicates no
* time limit.
*
* @return bool TRUE on success, FALSE on failure.
*/
public function add($key, $value, $ttl = 0)
{
return wincache_ucache_add($this->persistentId . $key, $value, $ttl);
}
/**
* Sets a value in the shared memory storage.
*
* Adds a value to the storage if it doesn't exist, overwrites it otherwise.
*
* @param string $key Name of key to associate the value with.
* @param mixed $value Value for the specified key.
* @param int $ttl Seconds to store the value. If set to 0 indicates no
* time limit.
*
* @return bool TRUE on success, FALSE on failure.
*/
public function set($key, $value, $ttl = 0)
{
return wincache_ucache_set($this->persistentId . $key, $value, $ttl);
}
/**
* Gets a value from the shared memory storage.
*
* Gets the current value, or throws an exception if it's not stored.
*
* @param string $key Name of key to get the value of.
*
* @return mixed The current value of the specified key.
*/
public function get($key)
{
$value = wincache_ucache_get($this->persistentId . $key, $success);
if (!$success) {
throw new SHM\InvalidArgumentException(
'Unable to fetch key. No such key, or key has expired.',
300
);
}
return $value;
}
/**
* Deletes a value from the shared memory storage.
*
* @param string $key Name of key to delete.
*
* @return bool TRUE on success, FALSE on failure.
*/
public function delete($key)
{
return wincache_ucache_delete($this->persistentId . $key);
}
/**
* Increases a value from the shared memory storage.
*
* Increases a value from the shared memory storage. Unlike a plain
* set($key, get($key)+$step) combination, this function also implicitly
* performs locking.
*
* @param string $key Name of key to increase.
* @param int $step Value to increase the key by.
*
* @return int The new value.
*/
public function inc($key, $step = 1)
{
$newValue = wincache_ucache_inc(
$this->persistentId . $key,
(int) $step,
$success
);
if (!$success) {
throw new SHM\InvalidArgumentException(
'Unable to increase the value. Are you sure the value is int?',
301
);
}
return $newValue;
}
/**
* Decreases a value from the shared memory storage.
*
* Decreases a value from the shared memory storage. Unlike a plain
* set($key, get($key)-$step) combination, this function also implicitly
* performs locking.
*
* @param string $key Name of key to decrease.
* @param int $step Value to decrease the key by.
*
* @return int The new value.
*/
public function dec($key, $step = 1)
{
$newValue = wincache_ucache_dec(
$this->persistentId . $key,
(int) $step,
$success
);
if (!$success) {
throw new SHM\InvalidArgumentException(
'Unable to decrease the value. Are you sure the value is int?',
302
);
}
return $newValue;
}
/**
* Sets a new value if a key has a certain value.
*
* Sets a new value if a key has a certain value. This function only works
* when $old and $new are longs.
*
* @param string $key Key of the value to compare and set.
* @param int $old The value to compare the key against.
* @param int $new The value to set the key to.
*
* @return bool TRUE on success, FALSE on failure.
*/
public function cas($key, $old, $new)
{
return wincache_ucache_cas($this->persistentId . $key, $old, $new);
}
/**
* Clears the persistent storage.
*
* Clears the persistent storage, i.e. removes all keys. Locks are left
* intact.
*
* @return void
*/
public function clear()
{
$info = wincache_ucache_info();
foreach ($info['ucache_entries'] as $entry) {
if (!$entry['is_session']
&& 0 === strpos($entry['key_name'], $this->persistentId)
) {
wincache_ucache_delete($entry['key_name']);
}
}
}
/**
* Retrieve an external iterator
*
* Returns an external iterator.
*
* @param string|null $filter A PCRE regular expression.
* Only matching keys will be iterated over.
* Setting this to NULL matches all keys of this instance.
* @param bool $keysOnly Whether to return only the keys,
* or return both the keys and values.
*
* @return ArrayObject An array with all matching keys as array keys,
* and values as array values. If $keysOnly is TRUE, the array keys are
* numeric, and the array values are key names.
*/
public function getIterator($filter = null, $keysOnly = false)
{
$info = wincache_ucache_info();
$result = array();
foreach ($info['ucache_entries'] as $entry) {
if (!$entry['is_session']
&& 0 === strpos($entry['key_name'], $this->persistentId)
) {
$localKey = strstr($entry['key_name'], $this->persistentId);
if (null === $filter || preg_match($filter, $localKey)) {
if ($keysOnly) {
$result[] = $localKey;
} else {
$result[$localKey] = apc_fetch($localKey);
}
}
}
}
return new ArrayObject($result);
}
}

View file

@ -0,0 +1,34 @@
<?php
/**
* ~~summary~~
*
* ~~description~~
*
* PHP version 5
*
* @category Caching
* @package PEAR2_Cache_SHM
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 0.1.3
* @link http://pear2.php.net/PEAR2_Cache_SHM
*/
/**
* The namespace declaration.
*/
namespace PEAR2\Cache\SHM;
/**
* Generic exception class of this package.
*
* @category Caching
* @package PEAR2_Cache_SHM
* @author Vasil Rangelov <boen.robot@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear2.php.net/PEAR2_Cache_SHM
*/
interface Exception
{
}

View file

@ -0,0 +1,35 @@
<?php
/**
* ~~summary~~
*
* ~~description~~
*
* PHP version 5
*
* @category Caching
* @package PEAR2_Cache_SHM
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 0.1.3
* @link http://pear2.php.net/PEAR2_Cache_SHM
*/
/**
* The namespace declaration.
*/
namespace PEAR2\Cache\SHM;
/**
* Exception thrown when there's something wrong with an argument.
*
* @category Caching
* @package PEAR2_Cache_SHM
* @author Vasil Rangelov <boen.robot@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear2.php.net/PEAR2_Cache_SHM
*/
class InvalidArgumentException extends \InvalidArgumentException
implements Exception
{
}

369
PEAR2/Console/Color.php Normal file
View file

@ -0,0 +1,369 @@
<?php
/**
* Main class for Console_Color
*
* PHP version 5.3
*
* @category Console
* @package Console_Color
* @author Vasil Rangelov <boen.robot@gmail.com>
* @author Ivo Nascimento <ivo@o8o.com.br>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0
* @link http://pear.php.net/package/Console_Color
*/
namespace PEAR2\Console;
use PEAR2\Console\Color\Backgrounds;
use PEAR2\Console\Color\Flags;
use PEAR2\Console\Color\Fonts;
use PEAR2\Console\Color\Styles;
use PEAR2\Console\Color\UnexpectedValueException;
use ReflectionClass;
/**
* Main class for Console_Color.
*
* @category Console
* @package Console_Color
* @author Ivo Nascimento <ivo@o8o.com.br>
* @author Vasil Rangelov <boen.robot@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear2.php.net/PEAR2_Console_Color
*/
class Color
{
/**
* @var array List of valid font colors.
* Filled by {@link fillValidators()}.
*/
protected static $validFonts = array();
/**
* @var array List of valid background colors.
* Filled by {@link fillValidators()}.
*/
protected static $validBackgorunds = array();
/**
* @var string Name of a class that is used to resolve flags to codes.
*/
protected static $flagsResolver = '';
/**
* @var string Name of a class that is used to resolve styles to codes.
*/
protected static $stylesResolver = '';
/**
* @var int Flags to set.
*/
protected $flags = 0;
/**
* @var int|null The code for the currently specified font color.
*/
protected $font = null;
/**
* @var int|null The code for the currently specified background color.
*/
protected $backgorund = null;
/**
* @var bool[] Array with the status of each style.
*/
protected $styles = array();
/**
* @var string|null The string to write to console to get the specified
* styling. NULL when the string needs to be regenerated.
*/
protected $sequence = null;
/**
* Fills the list of valid fonts and backgrounds.
*
* Classes extending this one that wish to add additional valid colors,
* flags or styles should call this method in their own constructor BEFORE
* calling the parent constructor.
*
* @param string $fonts Name of class, the constants of which are
* valid font colors.
* @param string $backgrounds Name of class, the constants of which are
* valid background colors.
* @param string $flags Name of class that resolves flags to codes.
* Must inheirt from {@link Flags}. Constants of this
* class are considered the valid flags, and the coresponding codes must
* be overriden at the static $flagCodes property.
* @param string $styles Name of class that resolves styles to codes.
* Must inherit from {@link Styles}. Constants of this class are
* considered the valid styles, and the corresponding off/on codes must
* be overriden at the static $styleCodes property.
*
* @return void
*/
protected static function fillVlidators(
$fonts,
$backgrounds,
$flags,
$styles
) {
if (empty(static::$validFonts)) {
$fonts = new ReflectionClass($fonts);
static::$validFonts = array_values(
array_unique($fonts->getConstants(), SORT_REGULAR)
);
}
if (empty(static::$validBackgorunds)) {
$bgs = new ReflectionClass($backgrounds);
static::$validBackgorunds = array_values(
array_unique($bgs->getConstants(), SORT_REGULAR)
);
}
if ('' === static::$flagsResolver) {
$base = __CLASS__ . '\Flags';
if ($base === $flags || is_subclass_of($flags, $base)) {
static::$flagsResolver = $flags;
}
}
if ('' === static::$stylesResolver) {
$base = __CLASS__ . '\Styles';
if ($base === $styles || is_subclass_of($styles, $base)) {
static::$stylesResolver = $styles;
}
}
}
/**
* Creates a new color.
*
* Note that leaving all arguments with their default values (and not
* applying styles) would result in a sequence that resets all settings to
* the console's defaults.
*
* @param int|null $font Initial font color.
* @param int|null $background Initial backgorund color.
* @param int $flags Initial flags.
*
* @see setFlags()
* @see setStyles()
* @see __toString()
*/
public function __construct(
$font = Fonts::KEEP,
$background = Backgrounds::KEEP,
$flags = Flags::NONE
) {
static::fillVlidators(
__CLASS__ . '\Fonts',
__CLASS__ . '\Backgrounds',
__CLASS__ . '\Flags',
__CLASS__ . '\Styles'
);
$this->setFont($font);
$this->setBackground($background);
$this->setFlags($flags);
}
/**
* Gets the font color.
*
* @return int|null $color The font color.
*/
public function getFont()
{
return $this->font;
}
/**
* Sets the font color.
*
* @param int|null $color The font color.
*
* @return $this
*/
public function setFont($color)
{
if (!in_array($color, static::$validFonts, true)) {
throw new UnexpectedValueException(
'Invalid font supplied.',
UnexpectedValueException::CODE_FONT
);
}
$this->font = $color;
$this->sequence = null;
return $this;
}
/**
* Gets the background color.
*
* @return int|null $color The background color.
*/
public function getBackground()
{
return $this->backgorund;
}
/**
* Sets the background color.
*
* @param int|null $color The background color.
*
* @return $this
*/
public function setBackground($color)
{
if (!in_array($color, static::$validBackgorunds, true)) {
throw new UnexpectedValueException(
'Invalid background supplied.',
UnexpectedValueException::CODE_BACKGROUND
);
}
$this->backgorund = $color;
$this->sequence = null;
return $this;
}
/**
* Gets the flags.
*
* @return int The currently set flags.
*/
public function getFlags()
{
return $this->flags;
}
/**
* Sets the flags.
*
* Sets the flags to apply in the sequence. Note that flags are applied
* before all other settings, in ascending order of the constant values.
*
* @param int $flags The new flags to set. Unknown flags will be ignored
* when forming the sequence, but will be visible with
* {@link getFlags()} non the less.
*
* @return $this
*/
public function setFlags($flags)
{
$this->flags = (int)$flags;
$this->sequence = null;
return $this;
}
/**
* Gets styles.
*
* @param int|null $style A single style to get the status of,
* or {@link Styles::ALL} to get all styles in an array.
*
* @return bool|null|bool[] A single style status, or
* an array of status if $style is {@link Styles::ALL}.
*/
public function getStyles($style = Styles::ALL)
{
if (Styles::ALL === $style) {
return $this->styles;
}
return isset($this->styles[$style]) ? $this->styles[$style] : null;
}
/**
* Sets styles.
*
* Sets styles matched to a specified state.
*
* @param int|null $styles Bitmask of styles to set. You can also use the
* constant {@link Styles::ALL} (only) to set all known styles.
* Unknown styles will be ignored.
* @param bool|null $state The state to set the matched styles in.
* TRUE to enable them,
* FLASE to disable them,
* NULL to remove the setting for them (in effect using whatever the
* console had before the sequence was applied).
*
* @return $this
*/
public function setStyles($styles, $state)
{
$matchingStyles = call_user_func(
array(static::$stylesResolver, 'match'),
$styles
);
if (null === $state) {
foreach ($matchingStyles as $style) {
unset($this->styles[$style]);
}
} else {
$state = (bool)$state;
foreach ($matchingStyles as $style) {
$this->styles[$style] = $state;
}
ksort($this->styles);
}
$this->sequence = null;
return $this;
}
/**
* Get the console escaping sequence.
*
* This is a magic PHP method that will be called when you use the object in
* a string context or otherwise explicitly cast it to a string.
*
* It generates the escape sequence and returns it.
* For the sake of performance, the escape sequence is cached, and is only
* regenerated when a setter has been previously called.
*
* @return string The string to write to console to get the specified
* styling.
*/
public function __toString()
{
if (null === $this->sequence) {
$seq = "\033[";
$flags = implode(
';',
call_user_func(
array(static::$flagsResolver, 'getCodes'),
$this->flags
)
);
if ('' !== $flags) {
$seq .= $flags . ';';
}
if (Fonts::KEEP !== $this->font) {
$seq .= "{$this->font};";
}
if (Backgrounds::KEEP !== $this->backgorund) {
$seq .= "{$this->backgorund};";
}
foreach ($this->styles as $style => $state) {
$seq .= call_user_func(
array(static::$stylesResolver, 'getCode'),
$style,
$state
) . ';';
}
$this->sequence = rtrim($seq, ';') . 'm';
}
return $this->sequence;
}
}

View file

@ -0,0 +1,136 @@
<?php
/**
* Backgrounds class for PEAR2_Console_Color.
*
* PHP version 5.3
*
* @category Console
* @package PEAR2_Console_Color
* @author Ivo Nascimento <ivo@o8o.com.br>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0
* @link http://pear2.php.net/PEAR2_Console_Color
*/
namespace PEAR2\Console\Color;
/**
* This class has the possibles values to a Background Color.
*
* @category Console
* @package PEAR2_Console_Color
* @author Ivo Nascimento <ivo@o8o.com.br>
* @copyright 2011 Ivo Nascimento
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear2.php.net/PEAR2_Console_Color
*/
abstract class Backgrounds
{
/**
* Used at {@link \PEAR2\Console\Color::setBackground()} to specify that
* the background color already in effect should be kept.
*/
const KEEP = null;
/**
* Used at {@link \PEAR2\Console\Color::setBackground()} to set the
* background color to black/grey (implmementation defined).
*/
const BLACK = 40;
/**
* Used at {@link \PEAR2\Console\Color::setBackground()} to set the
* background color to black/grey (implementation defined).
*/
const GREY = 40;
/**
* Used at {@link \PEAR2\Console\Color::setBackground()} to set the
* background color to maroon/red (implementation defined).
*/
const MAROON = 41;
/**
* Used at {@link \PEAR2\Console\Color::setBackground()} to set the
* background color to maroon/red (implementation defined).
*/
const RED = 41;
/**
* Used at {@link \PEAR2\Console\Color::setBackground()} to set the
* background color to green/lime (implementation defined).
*/
const GREEN = 42;
/**
* Used at {@link \PEAR2\Console\Color::setBackground()} to set the
* background color to green/lime (implementation defined).
*/
const LIME = 42;
/**
* Used at {@link \PEAR2\Console\Color::setBackground()} to set the
* background color to brown/yellow (implementation defined).
*/
const BROWN = 43;
/**
* Used at {@link \PEAR2\Console\Color::setBackground()} to set the
* background color to brown/yellow (implementation defined).
*/
const YELLOW = 43;
/**
* Used at {@link \PEAR2\Console\Color::setBackground()} to set the
* background color to navy/blue (implementation defined).
*/
const NAVY = 44;
/**
* Used at {@link \PEAR2\Console\Color::setBackground()} to set the
* background color to navy/blue (implementation defined).
*/
const BLUE = 44;
/**
* Used at {@link \PEAR2\Console\Color::setBackground()} to set the
* background color to purple/magenta (implementation defined).
*/
const PURPLE = 45;
/**
* Used at {@link \PEAR2\Console\Color::setBackground()} to set the
* background color to purple/magenta (implementation defined).
*/
const MAGENTA = 45;
/**
* Used at {@link \PEAR2\Console\Color::setBackground()} to set the
* background color to teal/cyan (implementation defined).
*/
const TEAL = 46;
/**
* Used at {@link \PEAR2\Console\Color::setBackground()} to set the
* background color to teal/cyan (implementation defined).
*/
const CYAN = 46;
/**
* Used at {@link \PEAR2\Console\Color::setBackground()} to set the
* background color to silver/white (implementation defined).
*/
const SILVER = 47;
/**
* Used at {@link \PEAR2\Console\Color::setBackground()} to set the
* background color to silver/white (implementation defined).
*/
const WHITE = 47;
/**
* Used at {@link \PEAR2\Console\Color::setBackground()} to set the
* background color to whatever the default one is.
*/
const RESET = 49;
}

View file

@ -0,0 +1,28 @@
<?php
/**
* Exception class for PEAR2_Console_Color.
*
* PHP version 5.3
*
* @category Console
* @package PEAR2_Console_Color
* @author Vasil Rangelov <boen.robot@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0
* @link http://pear2.php.net/PEAR2_Console_Color
*/
namespace PEAR2\Console\Color;
/**
* Exception class for PEAR2_Console_Color.
*
* @category Console
* @package PEAR2_Console_Color
* @author Vasil Rangelov <boen.robot@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear2.php.net/PEAR2_Console_Color
*/
interface Exception
{
}

View file

@ -0,0 +1,88 @@
<?php
/**
* Flags class for PEAR2_Console_Color
* Mappping the names of Font Style to your values.
*
* PHP version 5.3
*
* @category Console
* @package PEAR2_Console_Color
* @author Vasil Rangelov <boen.robot@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0
* @link http://pear2.php.net/PEAR2_Console_Color
*/
namespace PEAR2\Console\Color;
use ReflectionClass;
/**
* This class has the possibles flags to a color setting.
*
* @category Console
* @package PEAR2_Console_Color
* @author Vasil Rangelov <boen.robot@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear2.php.net/PEAR2_Console_Color
*/
abstract class Flags
{
/**
* Used at {@link \PEAR2\Console\Color::setFlags()} to specify that no
* flags should be applied.
*/
const NONE = 0;
/**
* Used at {@link \PEAR2\Console\Color::setFlags()} as part of a bitmask.
* If specified, resets all color and style information before applying
* everything else.
*/
const RESET = 1;
/**
* Used at {@link \PEAR2\Console\Color::setFlags()} as part of a bitmask.
* If specified, inverses the font and background colors, before letting
* the remaining settings further modify things.
* If specified together with {@link self::RESET}, takes effect AFTER the
* reset.
*/
const INVERSE = 2;
/**
* @var int[] Array with the flag as a key, and the corresponding code as a
* value.
*/
protected static $flagCodes = array(
self::RESET => 0,
self::INVERSE => 7
);
/**
* Gets the codes for a flag set.
*
* @param int $flags The flags to get the codes for.
*
* @return int[] The codes for the flags specified, in ascending order,
* based on the flag constants' values.
*/
final public static function getCodes($flags)
{
if (self::NONE === $flags) {
return array();
}
$result = array();
$flagsClass = new ReflectionClass(get_called_class());
$validFlags = array_values(
array_unique($flagsClass->getConstants(), SORT_NUMERIC)
);
foreach ($validFlags as $flag) {
if ($flags & $flag) {
$result[] = static::$flagCodes[$flag];
}
}
return $result;
}
}

View file

@ -0,0 +1,136 @@
<?php
/**
* Font class for PEAR2_Console_Color
*
* PHP version 5.3
*
* @category Console
* @package PEAR2_Console_Color
* @author Ivo Nascimento <ivo@o8o.com.br>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0
* @link http://pear2.php.net/PEAR2_Console_Color
*/
namespace PEAR2\Console\Color;
/**
* This class has the possibles values to a Font Color.
*
* @category Console
* @package PEAR2_Console_Color
* @author Ivo Nascimento <ivo@o8o.com.br>
* @copyright 2011 Ivo Nascimento
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear2.php.net/PEAR2_Console_Color
*/
abstract class Fonts
{
/**
* Used at {@link \PEAR2\Console\Color::setFont()} to specify that
* the font color already in effect should be kept.
*/
const KEEP = null;
/**
* Used at {@link \PEAR2\Console\Color::setFont()} to set the
* font color to black/grey (implementation defined).
*/
const BLACK = 30;
/**
* Used at {@link \PEAR2\Console\Color::setFont()} to set the
* font color to black/grey (implementation defined).
*/
const GREY = 30;
/**
* Used at {@link \PEAR2\Console\Color::setFont()} to set the
* font color to maroon/red (implementation defined).
*/
const MAROON = 31;
/**
* Used at {@link \PEAR2\Console\Color::setFont()} to set the
* font color to maroon/red (implementation defined).
*/
const RED = 31;
/**
* Used at {@link \PEAR2\Console\Color::setFont()} to set the
* font color to green/lime (implementation defined).
*/
const LIME = 32;
/**
* Used at {@link \PEAR2\Console\Color::setFont()} to set the
* font color to green/lime (implementation defined).
*/
const GREEN = 32;
/**
* Used at {@link \PEAR2\Console\Color::setFont()} to set the
* font color to brown/yellow (implementation defined).
*/
const BROWN = 33;
/**
* Used at {@link \PEAR2\Console\Color::setFont()} to set the
* font color to brown/yellow (implementation defined).
*/
const YELLOW = 33;
/**
* Used at {@link \PEAR2\Console\Color::setFont()} to set the
* font color to navy/blue (implementation defined).
*/
const NAVY = 34;
/**
* Used at {@link \PEAR2\Console\Color::setFont()} to set the
* font color to navy/blue (implementation defined).
*/
const BLUE = 34;
/**
* Used at {@link \PEAR2\Console\Color::setFont()} to set the
* font color to purple/magenta (implementation defined).
*/
const PURPLE = 35;
/**
* Used at {@link \PEAR2\Console\Color::setFont()} to set the
* font color to purple/magenta (implementation defined).
*/
const MAGENTA = 35;
/**
* Used at {@link \PEAR2\Console\Color::setFont()} to set the
* font color to teal/cyan (implementation defined).
*/
const TEAL = 36;
/**
* Used at {@link \PEAR2\Console\Color::setFont()} to set the
* font color to teal/cyan (implementation defined).
*/
const CYAN = 36;
/**
* Used at {@link \PEAR2\Console\Color::setFont()} to set the
* font color to silver/white (implementation defined).
*/
const SILVER = 37;
/**
* Used at {@link \PEAR2\Console\Color::setFont()} to set the
* font color to silver/white (implementation defined).
*/
const WHITE = 37;
/**
* Used at {@link \PEAR2\Console\Color::setFont()} to set the
* font color to whatever the default one is.
*/
const RESET = 39;
}

View file

@ -0,0 +1,130 @@
<?php
/**
* Styles class for PEAR2_Console_Color.
*
* PHP version 5.3
*
* @category Console
* @package PEAR2_Console_Color
* @author Vasil Rangelov <boen.robot@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0
* @link http://pear2.php.net/PEAR2_Console_Color
*/
namespace PEAR2\Console\Color;
use ReflectionClass;
/**
* This class has the possibles values to a Font Style.
*
* @category Console
* @package PEAR2_Console_Color
* @author Vasil Rangelov <boen.robot@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear2.php.net/PEAR2_Console_Color
*/
abstract class Styles
{
/**
* Used in {@link \PEAR2\Console\Color::setStyles()} to match all styles.
*/
const ALL = null;
/**
* Used in {@link \PEAR2\Console\Color::setStyles()} as part of a bitmask.
* If specified, matches the bold style.
* When this style is enabled, the font is bolder.
* With ANSICON, the font color becomes more intense (but not bolder).
*/
const BOLD = 1;
/**
* Used in {@link \PEAR2\Console\Color::setStyles()} as part of a bitmask.
* If specified, matches the underline style.
* When this style is enabled, the font is underlined.
* With ANSICON, the background color becomes more intense
* (and the font is not underlined), same as {@link self::BLINK}.
*/
const UNDERLINE = 2;
/**
* Used in {@link \PEAR2\Console\Color::setStyles()} as part of a bitmask.
* If specified, matches the blink style.
* When this style is enabled, the font color switches between its regular
* color and the background color at regular (implementation defined)
* intervals, creating the illusion of a blinking text.
* With ANSICON, the background color becomes more intense
* (and the font is not blinking), same as with {@link self::UNDERLINE}.
*/
const BLINK = 4;
/**
* Used in {@link \PEAR2\Console\Color::setStyles()} as part of a bitmask.
* If specified, matches the concealed style.
* When this style is enabled, the font color becomes the background color,
* rendering the text invisible. This style is particularly useful for
* implementations where simply setting the same color and background color
* would not necesarily provide a fully invisibile text (e.g. ANSICON).
*/
const CONCEALED = 8;
/**
* @var (int[])[] An array describing the codes for the styles.
* Each array key is the style's constant, and each value is an array
* where the first member is the disable code, and the second is the
* enable code.
*/
protected static $styleCodes = array(
self::BOLD => array(22, 1),
self::UNDERLINE => array(24, 4),
self::BLINK => array(25, 5),
self::CONCEALED => array(28, 8)
);
/**
* Get style constants.
*
* @param int|null $styles Bitmask of styles to match.
* You can also use {@link self::ALL} (only) to get all styles.
*
* @return int[] Matching style constants.
*/
final public static function match($styles)
{
$flagsClass = new ReflectionClass(get_called_class());
$validStyles = array_values(
array_unique($flagsClass->getConstants(), SORT_NUMERIC)
);
unset($validStyles[array_search(self::ALL, $validStyles, true)]);
if (self::ALL === $styles) {
return $validStyles;
}
$styles = (int)$styles;
$result = array();
foreach ($validStyles as $flag) {
if ($styles & $flag) {
$result[] = $flag;
}
}
return $result;
}
/**
* Gets the code for a style.
*
* @param int $style The style to get the code for.
* @param bool $state The state to get code for.
* TRUE for the enabled state codes,
* FALSE for the disabled state codes.
*
* @return int The code for the flag specified.
*/
final public static function getCode($style, $state)
{
return static::$styleCodes[$style][(int)(bool)$state];
}
}

View file

@ -0,0 +1,40 @@
<?php
/**
* Exception class for PEAR2_Console_Color.
*
* PHP version 5.3
*
* @category Console
* @package PEAR2_Console_Color
* @author Vasil Rangelov <boen.robot@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0
* @link http://pear2.php.net/PEAR2_Console_Color
*/
namespace PEAR2\Console\Color;
use UnexpectedValueException as U;
/**
* Exception class for PEAR2_Console_Color.
*
* @category Console
* @package PEAR2_Console_Color
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Ivo Nascimento
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear2.php.net/PEAR2_Console_Color
*/
class UnexpectedValueException extends U implements Exception
{
/**
* Used when an unexpected font value is supplied.
*/
const CODE_FONT = 1;
/**
* Used when an unexpected background value is supplied.
*/
const CODE_BACKGROUND = 2;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,142 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* This file is part of the PEAR2\Console\CommandLine package.
*
* PHP version 5
*
* LICENSE: This source file is subject to the MIT license that is available
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
* @filesource
*/
namespace PEAR2\Console\CommandLine;
/**
* Class that represent an option action.
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since Class available since release 0.1.0
*/
abstract class Action
{
// Properties {{{
/**
* A reference to the result instance.
*
* @var PEAR2\Console\CommandLine_Result $result The result instance
*/
protected $result;
/**
* A reference to the option instance.
*
* @var PEAR2\Console\CommandLine_Option $option The action option
*/
protected $option;
/**
* A reference to the parser instance.
*
* @var PEAR2\Console\CommandLine $parser The parser
*/
protected $parser;
// }}}
// __construct() {{{
/**
* Constructor
*
* @param PEAR2\Console\CommandLine_Result $result The result instance
* @param PEAR2\Console\CommandLine_Option $option The action option
* @param PEAR2\Console\CommandLine $parser The current parser
*
* @return void
*/
public function __construct($result, $option, $parser)
{
$this->result = $result;
$this->option = $option;
$this->parser = $parser;
}
// }}}
// getResult() {{{
/**
* Convenience method to retrieve the value of result->options[name].
*
* @return mixed The result value or null
*/
public function getResult()
{
if (isset($this->result->options[$this->option->name])) {
return $this->result->options[$this->option->name];
}
return null;
}
// }}}
// format() {{{
/**
* Allow a value to be pre-formatted prior to being used in a choices test.
* Setting $value to the new format will keep the formatting.
*
* @param mixed &$value The value to format
*
* @return mixed The formatted value
*/
public function format(&$value)
{
return $value;
}
// }}}
// setResult() {{{
/**
* Convenience method to assign the result->options[name] value.
*
* @param mixed $result The result value
*
* @return void
*/
public function setResult($result)
{
$this->result->options[$this->option->name] = $result;
}
// }}}
// execute() {{{
/**
* Executes the action with the value entered by the user.
* All children actions must implement this method.
*
* @param mixed $value The option value
* @param array $params An optional array of parameters
*
* @return string
*/
abstract public function execute($value = false, $params = array());
// }}}
}

View file

@ -0,0 +1,86 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* This file is part of the PEAR2\Console\CommandLine package.
*
* PHP version 5
*
* LICENSE: This source file is subject to the MIT license that is available
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
* @filesource
*/
namespace PEAR2\Console\CommandLine\Action;
use PEAR2\Console\CommandLine;
/**
* Class that represent the Callback action.
*
* The result option array entry value is set to the return value of the
* callback defined in the option.
*
* There are two steps to defining a callback option:
* - define the option itself using the callback action
* - write the callback; this is a function (or method) that takes five
* arguments, as described below.
*
* All callbacks are called as follows:
* <code>
* callable_func(
* $value, // the value of the option
* $option_instance, // the option instance
* $result_instance, // the result instance
* $parser_instance, // the parser instance
* $params // an array of params as specified in the option
* );
* </code>
* and *must* return the option value.
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since Class available since release 0.1.0
*/
class Callback extends CommandLine\Action
{
// execute() {{{
/**
* Executes the action with the value entered by the user.
*
* @param mixed $value The value of the option
* @param array $params An optional array of parameters
*
* @return string
*/
public function execute($value = false, $params = array())
{
$this->setResult(
call_user_func(
$this->option->callback,
$value,
$this->option,
$this->result,
$this->parser,
$params
)
);
}
// }}}
}

View file

@ -0,0 +1,84 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* This file is part of the PEAR2\Console\CommandLine package.
*
* PHP version 5
*
* LICENSE: This source file is subject to the MIT license that is available
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
* @filesource
*/
namespace PEAR2\Console\CommandLine\Action;
use PEAR2\Console\CommandLine;
/**
* Class that represent the Version action.
*
* The execute methode add 1 to the value of the result option array entry.
* The value is incremented each time the option is found, for example
* with an option defined like that:
*
* <code>
* $parser->addOption(
* 'verbose',
* array(
* 'short_name' => '-v',
* 'action' => 'Counter'
* )
* );
* </code>
* If the user type:
* <code>
* $ script.php -v -v -v
* </code>
* or:
* <code>
* $ script.php -vvv
* </code>
* the verbose variable will be set to to 3.
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since Class available since release 0.1.0
*/
class Counter extends CommandLine\Action
{
// execute() {{{
/**
* Executes the action with the value entered by the user.
*
* @param mixed $value The option value
* @param array $params An optional array of parameters
*
* @return string
*/
public function execute($value = false, $params = array())
{
$result = $this->getResult();
if ($result === null) {
$result = 0;
}
$this->setResult(++$result);
}
// }}}
}

View file

@ -0,0 +1,58 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* This file is part of the PEAR2\Console\CommandLine package.
*
* PHP version 5
*
* LICENSE: This source file is subject to the MIT license that is available
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
* @filesource
*/
namespace PEAR2\Console\CommandLine\Action;
use PEAR2\Console\CommandLine;
/**
* Class that represent the Help action, a special action that displays the
* help message, telling the user how to use the program.
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since Class available since release 0.1.0
*/
class Help extends CommandLine\Action
{
// execute() {{{
/**
* Executes the action with the value entered by the user.
*
* @param mixed $value The option value
* @param array $params An optional array of parameters
*
* @return string
*/
public function execute($value = false, $params = array())
{
return $this->parser->displayUsage();
}
// }}}
}

View file

@ -0,0 +1,69 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* This file is part of the PEAR2\Console\CommandLine package.
*
* PHP version 5
*
* LICENSE: This source file is subject to the MIT license that is available
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version CVS: $Id: List.php,v 1.2 2009/02/27 08:03:17 izi Exp $
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
* @filesource
*/
namespace PEAR2\Console\CommandLine;
/**
* Class that represent the List action, a special action that simply output an
* array as a list.
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since Class available since release 0.1.0
*/
class Action_List extends Action
{
// execute() {{{
/**
* Executes the action with the value entered by the user.
* Possible parameters are:
* - message: an alternative message to display instead of the default
* message,
* - delimiter: an alternative delimiter instead of the comma,
* - post: a string to append after the message (default is the new line
* char).
*
* @param mixed $value The option value
* @param array $params An optional array of parameters
*
* @return string
*/
public function execute($value = false, $params = array())
{
$list = isset($params['list']) ? $params['list'] : array();
$msg = isset($params['message'])
? $params['message']
: $this->parser->message_provider->get('LIST_DISPLAYED_MESSAGE');
$del = isset($params['delimiter']) ? $params['delimiter'] : ', ';
$post = isset($params['post']) ? $params['post'] : "\n";
$this->parser->outputter->stdout($msg . implode($del, $list) . $post);
exit(0);
}
// }}}
}

View file

@ -0,0 +1,90 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* This file is part of the PEAR2\Console\CommandLine package.
*
* PHP version 5
*
* LICENSE: This source file is subject to the MIT license that is available
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
* @filesource
*/
namespace PEAR2\Console\CommandLine\Action;
use PEAR2\Console\CommandLine;
/**
* Class that represent the Password action, a special action that allow the
* user to specify the password on the commandline or to be prompted for
* entering it.
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since Class available since release 0.1.0
*/
class Password extends CommandLine\Action
{
// execute() {{{
/**
* Executes the action with the value entered by the user.
*
* @param mixed $value The option value
* @param array $params An array of optional parameters
*
* @return string
*/
public function execute($value = false, $params = array())
{
$this->setResult(empty($value) ? $this->_promptPassword() : $value);
}
// }}}
// _promptPassword() {{{
/**
* Prompts the password to the user without echoing it.
*
* @return string
* @todo not echo-ing the password does not work on windows is there a way
* to make this work ?
*/
private function _promptPassword()
{
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
fwrite(
STDOUT,
$this->parser->message_provider->get('PASSWORD_PROMPT_ECHO')
);
@flock(STDIN, LOCK_EX);
$passwd = fgets(STDIN);
@flock(STDIN, LOCK_UN);
} else {
fwrite(STDOUT, $this->parser->message_provider->get('PASSWORD_PROMPT'));
// disable echoing
system('stty -echo');
@flock(STDIN, LOCK_EX);
$passwd = fgets(STDIN);
@flock(STDIN, LOCK_UN);
system('stty echo');
}
return trim($passwd);
}
// }}}
}

View file

@ -0,0 +1,76 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* This file is part of the PEAR2\Console\CommandLine package.
*
* PHP version 5
*
* LICENSE: This source file is subject to the MIT license that is available
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
* @filesource
*/
namespace PEAR2\Console\CommandLine\Action;
use PEAR2\Console\CommandLine;
/**
* Class that represent the StoreArray action.
*
* The execute method appends the value of the option entered by the user to
* the result option array entry.
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since Class available since release 0.1.0
*/
class StoreArray extends CommandLine\Action
{
// Protected properties {{{
/**
* Force a clean result when first called, overriding any defaults assigned.
*
* @var object $firstPass First time this action has been called.
*/
protected $firstPass = true;
// }}}
// execute() {{{
/**
* Executes the action with the value entered by the user.
*
* @param mixed $value The option value
* @param array $params An optional array of parameters
*
* @return string
*/
public function execute($value = false, $params = array())
{
$result = $this->getResult();
if (null === $result || $this->firstPass) {
$result = array();
$this->firstPass = false;
}
$result[] = $value;
$this->setResult($result);
}
// }}}
}

View file

@ -0,0 +1,62 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* This file is part of the PEAR2\Console\CommandLine package.
*
* PHP version 5
*
* LICENSE: This source file is subject to the MIT license that is available
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
* @filesource
*/
namespace PEAR2\Console\CommandLine\Action;
use PEAR2\Console\CommandLine;
/**
* Class that represent the StoreFalse action.
*
* The execute method store the boolean 'false' in the corrsponding result
* option array entry (the value is true if the option is not present in the
* command line entered by the user).
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since Class available since release 0.1.0
*/
class StoreFalse extends CommandLine\Action
{
// execute() {{{
/**
* Executes the action with the value entered by the user.
*
* @param mixed $value The option value
* @param array $params An array of optional parameters
*
* @return string
*/
public function execute($value = false, $params = array())
{
$this->setResult(false);
}
// }}}
}

View file

@ -0,0 +1,73 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* This file is part of the PEAR2\Console\CommandLine package.
*
* PHP version 5
*
* LICENSE: This source file is subject to the MIT license that is available
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
* @filesource
*/
namespace PEAR2\Console\CommandLine\Action;
use PEAR2\Console\CommandLine;
/**
* Class that represent the StoreFloat action.
*
* The execute method store the value of the option entered by the user as a
* float in the result option array entry, if the value passed is not a float
* an Exception is raised.
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since Class available since release 0.1.0
*/
class StoreFloat extends CommandLine\Action
{
// execute() {{{
/**
* Executes the action with the value entered by the user.
*
* @param mixed $value The option value
* @param array $params An array of optional parameters
*
* @return string
* @throws PEAR2\Console\CommandLine\Exception
*/
public function execute($value = false, $params = array())
{
if (!is_numeric($value)) {
throw CommandLine\Exception::factory(
'OPTION_VALUE_TYPE_ERROR',
array(
'name' => $this->option->name,
'type' => 'float',
'value' => $value
),
$this->parser
);
}
$this->setResult((float)$value);
}
// }}}
}

View file

@ -0,0 +1,73 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* This file is part of the PEAR2\Console\CommandLine package.
*
* PHP version 5
*
* LICENSE: This source file is subject to the MIT license that is available
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
* @filesource
*/
namespace PEAR2\Console\CommandLine\Action;
use PEAR2\Console\CommandLine;
/**
* Class that represent the StoreInt action.
*
* The execute method store the value of the option entered by the user as an
* integer in the result option array entry, if the value passed is not an
* integer an Exception is raised.
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since Class available since release 0.1.0
*/
class StoreInt extends CommandLine\Action
{
// execute() {{{
/**
* Executes the action with the value entered by the user.
*
* @param mixed $value The option value
* @param array $params An array of optional parameters
*
* @return string
* @throws PEAR2\Console\CommandLine\Exception
*/
public function execute($value = false, $params = array())
{
if (!is_numeric($value)) {
throw CommandLine\Exception::factory(
'OPTION_VALUE_TYPE_ERROR',
array(
'name' => $this->option->name,
'type' => 'int',
'value' => $value
),
$this->parser
);
}
$this->setResult((int)$value);
}
// }}}
}

View file

@ -0,0 +1,60 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* This file is part of the PEAR2\Console\CommandLine package.
*
* PHP version 5
*
* LICENSE: This source file is subject to the MIT license that is available
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
* @filesource
*/
namespace PEAR2\Console\CommandLine\Action;
use PEAR2\Console\CommandLine;
/**
* Class that represent the StoreString action.
*
* The execute method store the value of the option entered by the user as a
* string in the result option array entry.
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since Class available since release 0.1.0
*/
class StoreString extends CommandLine\Action
{
// execute() {{{
/**
* Executes the action with the value entered by the user.
*
* @param mixed $value The option value
* @param array $params An array of optional parameters
*
* @return string
*/
public function execute($value = false, $params = array())
{
$this->setResult((string)$value);
}
// }}}
}

View file

@ -0,0 +1,61 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* This file is part of the PEAR2\Console\CommandLine package.
*
* PHP version 5
*
* LICENSE: This source file is subject to the MIT license that is available
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
* @filesource
*/
namespace PEAR2\Console\CommandLine\Action;
use PEAR2\Console\CommandLine;
/**
* Class that represent the StoreTrue action.
*
* The execute method store the boolean 'true' in the corrsponding result
* option array entry (the value is false if the option is not present in the
* command line entered by the user).
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since Class available since release 0.1.0
*/
class StoreTrue extends CommandLine\Action
{
// execute() {{{
/**
* Executes the action with the value entered by the user.
*
* @param mixed $value The option value
* @param array $params An array of optional parameters
*
* @return string
*/
public function execute($value = false, $params = array())
{
$this->setResult(true);
}
// }}}
}

View file

@ -0,0 +1,58 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* This file is part of the PEAR2\Console\CommandLine package.
*
* PHP version 5
*
* LICENSE: This source file is subject to the MIT license that is available
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
* @filesource
*/
namespace PEAR2\Console\CommandLine\Action;
use PEAR2\Console\CommandLine;
/**
* Class that represent the Version action, a special action that displays the
* version string of the program.
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since Class available since release 0.1.0
*/
class Version extends CommandLine\Action
{
// execute() {{{
/**
* Executes the action with the value entered by the user.
*
* @param mixed $value The option value
* @param array $params An array of optional parameters
*
* @return string
*/
public function execute($value = false, $params = array())
{
return $this->parser->displayVersion();
}
// }}}
}

View file

@ -0,0 +1,94 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* This file is part of the PEAR2\Console\CommandLine package.
*
* PHP version 5
*
* LICENSE: This source file is subject to the MIT license that is available
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
* @filesource
*/
namespace PEAR2\Console\CommandLine;
/**
* Class that represent a command line argument.
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since Class available since release 0.1.0
*/
class Argument extends Element
{
// Public properties {{{
/**
* Setting this to true will tell the parser that the argument expects more
* than one argument and that argument values should be stored in an array.
*
* @var boolean $multiple Whether the argument expects multiple values
*/
public $multiple = false;
/**
* Setting this to true will tell the parser that the argument is optional
* and can be ommited.
* Note that it is not a good practice to make arguments optional, it is
* the role of the options to be optional, by essence.
*
* @var boolean $optional Whether the argument is optional or not.
*/
public $optional = false;
// }}}
// validate() {{{
/**
* Validates the argument instance.
*
* @return void
* @throws PEAR2\Console\CommandLine\Exception
* @todo use exceptions
*/
public function validate()
{
// check if the argument name is valid
if (!preg_match(
'/^[a-zA-Z_\x7f-\xff]+[a-zA-Z0-9_\x7f-\xff]*$/',
$this->name
)
) {
\PEAR2\Console\CommandLine::triggerError(
'argument_bad_name',
E_USER_ERROR,
array('{$name}' => $this->name)
);
}
if (!$this->optional && $this->default !== null) {
\PEAR2\Console\CommandLine::triggerError(
'argument_no_default',
E_USER_ERROR
);
}
parent::validate();
}
// }}}
}

View file

@ -0,0 +1,72 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* This file is part of the PEAR2\Console\CommandLine package.
*
* PHP version 5
*
* LICENSE: This source file is subject to the MIT license that is available
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
* @filesource
*/
namespace PEAR2\Console\CommandLine;
/**
* Class that represent a command with option and arguments.
*
* This class exist just to clarify the interface but at the moment it is
* strictly identical to PEAR2\Console\CommandLine class, it could change in the
* future though.
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since Class available since release 0.1.0
*/
class Command extends \PEAR2\Console\CommandLine
{
// Public properties {{{
/**
* An array of aliases for the subcommand.
*
* @var array $aliases Aliases for the subcommand.
*/
public $aliases = array();
// }}}
// __construct() {{{
/**
* Constructor.
*
* @param array $params An optional array of parameters
*
* @return void
*/
public function __construct($params = array())
{
if (isset($params['aliases'])) {
$this->aliases = $params['aliases'];
}
parent::__construct($params);
}
// }}}
}

View file

@ -0,0 +1,67 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* This file is part of the PEAR2\Console\CommandLine package.
*
* PHP version 5
*
* LICENSE: This source file is subject to the MIT license that is available
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @author Michael Gauthier <mike@silverorange.com>
* @copyright 2007 David JEAN LOUIS, 2009 silverorange
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version CVS: $Id: CustomMessageProvider.php 282427 2009-06-19 10:22:48Z izi $
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 1.1.0
* @filesource
*/
namespace PEAR2\Console\CommandLine;
/**
* Common interfacefor message providers that allow overriding with custom
* messages
*
* Message providers may optionally implement this interface.
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @author Michael Gauthier <mike@silverorange.com>
* @copyright 2007 David JEAN LOUIS, 2009 silverorange
* @license http://opensource.org/licenses/mit-license.php MIT License
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since Interface available since release 1.1.0
*/
interface CustomMessageProvider
{
// getWithCustomMesssages() {{{
/**
* Retrieves the given string identifier corresponding message.
*
* For a list of identifiers please see the provided default message
* provider.
*
* @param string $code The string identifier of the message
* @param array $vars An array of template variables
* @param array $messages An optional array of messages to use. Array
* indexes are message codes.
*
* @return string
* @see PEAR2\Console\CommandLine_MessageProvider
* @see PEAR2\Console\CommandLine_MessageProvider_Default
*/
public function getWithCustomMessages(
$code, $vars = array(), $messages = array()
);
// }}}
}

View file

@ -0,0 +1,151 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* This file is part of the PEAR2\Console\CommandLine package.
*
* PHP version 5
*
* LICENSE: This source file is subject to the MIT license that is available
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
* @filesource
*/
namespace PEAR2\Console\CommandLine;
/**
* Class that represent a command line element (an option, or an argument).
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since Class available since release 0.1.0
*/
abstract class Element
{
// Public properties {{{
/**
* The element name.
*
* @var string $name Element name
*/
public $name;
/**
* The name of variable displayed in the usage message, if no set it
* defaults to the "name" property.
*
* @var string $help_name Element "help" variable name
*/
public $help_name;
/**
* The element description.
*
* @var string $description Element description
*/
public $description;
/**
* The default value of the element if not provided on the command line.
*
* @var mixed $default Default value of the option.
*/
public $default;
/**
* Custom errors messages for this element
*
* This array is of the form:
* <code>
* <?php
* array(
* $messageName => $messageText,
* $messageName => $messageText,
* ...
* );
* ?>
* </code>
*
* If specified, these messages override the messages provided by the
* default message provider. For example:
* <code>
* <?php
* $messages = array(
* 'ARGUMENT_REQUIRED' => 'The argument foo is required.',
* );
* ?>
* </code>
*
* @var array
* @see PEAR2\Console\CommandLine_MessageProvider_Default
*/
public $messages = array();
// }}}
// __construct() {{{
/**
* Constructor.
*
* @param string $name The name of the element
* @param array $params An optional array of parameters
*
* @return void
*/
public function __construct($name = null, $params = array())
{
$this->name = $name;
foreach ($params as $attr => $value) {
if (property_exists($this, $attr)) {
$this->$attr = $value;
}
}
}
// }}}
// toString() {{{
/**
* Returns the string representation of the element.
*
* @return string The string representation of the element
* @todo use __toString() instead
*/
public function toString()
{
return $this->help_name;
}
// }}}
// validate() {{{
/**
* Validates the element instance and set it's default values.
*
* @return void
* @throws PEAR2\Console\CommandLine\Exception
*/
public function validate()
{
// if no help_name passed, default to name
if ($this->help_name == null) {
$this->help_name = $this->name;
}
}
// }}}
}

View file

@ -0,0 +1,90 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* This file is part of the PEAR2\Console\CommandLine package.
*
* PHP version 5
*
* LICENSE: This source file is subject to the MIT license that is available
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
* @filesource
*/
namespace PEAR2\Console\CommandLine;
use Exception as E;
/**
* Class for exceptions raised by the PEAR2\Console\CommandLine package.
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since Class available since release 0.1.0
*/
class Exception extends E
{
// Codes constants {{{
/**#@+
* Exception code constants.
*/
const OPTION_VALUE_REQUIRED = 1;
const OPTION_VALUE_UNEXPECTED = 2;
const OPTION_VALUE_TYPE_ERROR = 3;
const OPTION_UNKNOWN = 4;
const ARGUMENT_REQUIRED = 5;
const INVALID_SUBCOMMAND = 6;
/**#@-*/
// }}}
// factory() {{{
/**
* Convenience method that builds the exception with the array of params by
* calling the message provider class.
*
* @param string $code The string identifier of the
* exception.
* @param array $params Array of template vars/values
* @param PEAR2\Console\CommandLine $parser An instance of the parser
* @param array $messages An optional array of messages
* passed to the message provider.
*
* @return PEAR2\Console\CommandLine\Exception The exception instance
*/
public static function factory(
$code, $params, $parser, array $messages = array()
) {
$provider = $parser->message_provider;
if ($provider instanceof CommandLine\CustomMessageProvider) {
$msg = $provider->getWithCustomMessages(
$code,
$params,
$messages
);
} else {
$msg = $provider->get($code, $params);
}
$const = '\PEAR2\Console\CommandLine\Exception::' . $code;
$code = defined($const) ? constant($const) : 0;
return new static($msg, $code);
}
// }}}
}

View file

@ -0,0 +1,57 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* This file is part of the PEAR2\Console\CommandLine package.
*
* PHP version 5
*
* LICENSE: This source file is subject to the MIT license that is available
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
* @filesource
*/
namespace PEAR2\Console\CommandLine;
/**
* Message providers common interface, all message providers must implement
* this interface.
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since Class available since release 0.1.0
*/
interface MessageProvider
{
// get() {{{
/**
* Retrieves the given string identifier corresponding message.
* For a list of identifiers please see the provided default message
* provider.
*
* @param string $code The string identifier of the message
* @param array $vars An array of template variables
*
* @return string
* @see PEAR2\Console\CommandLine_MessageProvider_Default
*/
public function get($code, $vars=array());
// }}}
}

View file

@ -0,0 +1,143 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* This file is part of the PEAR2\Console\CommandLine package.
*
* PHP version 5
*
* LICENSE: This source file is subject to the MIT license that is available
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
* @filesource
*/
namespace PEAR2\Console\CommandLine;
/**
* Lightweight class that manages messages used by PEAR2\Console\CommandLine package,
* allowing the developper to customize these messages, for example to
* internationalize a command line frontend.
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since Class available since release 0.1.0
*/
class MessageProvider_Default
implements MessageProvider,
CustomMessageProvider
{
// Properties {{{
/**
* Associative array of messages
*
* @var array $messages
*/
protected $messages = array(
'OPTION_VALUE_REQUIRED' => 'Option "{$name}" requires a value.',
'OPTION_VALUE_UNEXPECTED' => 'Option "{$name}" does not expect a value (got "{$value}").',
'OPTION_VALUE_NOT_VALID' => 'Option "{$name}" must be one of the following: "{$choices}" (got "{$value}").',
'OPTION_VALUE_TYPE_ERROR' => 'Option "{$name}" requires a value of type {$type} (got "{$value}").',
'OPTION_AMBIGUOUS' => 'Ambiguous option "{$name}", can be one of the following: {$matches}.',
'OPTION_UNKNOWN' => 'Unknown option "{$name}".',
'ARGUMENT_REQUIRED' => 'You must provide at least {$argnum} argument{$plural}.',
'PROG_HELP_LINE' => 'Type "{$progname} --help" to get help.',
'PROG_VERSION_LINE' => '{$progname} version {$version}.',
'COMMAND_HELP_LINE' => 'Type "{$progname} <command> --help" to get help on specific command.',
'USAGE_WORD' => 'Usage',
'OPTION_WORD' => 'Options',
'ARGUMENT_WORD' => 'Arguments',
'COMMAND_WORD' => 'Commands',
'PASSWORD_PROMPT' => 'Password: ',
'PASSWORD_PROMPT_ECHO' => 'Password (warning: will echo): ',
'INVALID_CUSTOM_INSTANCE' => 'Instance does not implement the required interface',
'LIST_OPTION_MESSAGE' => 'lists valid choices for option {$name}',
'LIST_DISPLAYED_MESSAGE' => 'Valid choices are: ',
'INVALID_SUBCOMMAND' => 'Command "{$command}" is not valid.',
'SUBCOMMAND_REQUIRED' => 'Please enter one of the following command: {$commands}.',
);
// }}}
// get() {{{
/**
* Retrieve the given string identifier corresponding message.
*
* @param string $code The string identifier of the message
* @param array $vars An array of template variables
*
* @return string
*/
public function get($code, $vars = array())
{
if (!isset($this->messages[$code])) {
return 'UNKNOWN';
}
return $this->replaceTemplateVars($this->messages[$code], $vars);
}
// }}}
// getWithCustomMessages() {{{
/**
* Retrieve the given string identifier corresponding message.
*
* @param string $code The string identifier of the message
* @param array $vars An array of template variables
* @param array $messages An optional array of messages to use. Array
* indexes are message codes.
*
* @return string
*/
public function getWithCustomMessages(
$code, $vars = array(), $messages = array()
) {
// get message
if (isset($messages[$code])) {
$message = $messages[$code];
} elseif (isset($this->messages[$code])) {
$message = $this->messages[$code];
} else {
$message = 'UNKNOWN';
}
return $this->replaceTemplateVars($message, $vars);
}
// }}}
// replaceTemplateVars() {{{
/**
* Replaces template vars in a message
*
* @param string $message The message
* @param array $vars An array of template variables
*
* @return string
*/
protected function replaceTemplateVars($message, $vars = array())
{
$tmpkeys = array_keys($vars);
$keys = array();
foreach ($tmpkeys as $key) {
$keys[] = '{$' . $key . '}';
}
return str_replace($keys, array_values($vars), $message);
}
// }}}
}

View file

@ -0,0 +1,393 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* This file is part of the PEAR2\Console\CommandLine package.
*
* PHP version 5
*
* LICENSE: This source file is subject to the MIT license that is available
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
* @filesource
*/
namespace PEAR2\Console\CommandLine;
use PEAR2\Console;
/**
* Class that represent a commandline option.
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since Class available since release 0.1.0
*/
class Option extends Element
{
// Public properties {{{
/**
* The option short name (ex: -v).
*
* @var string $short_name Short name of the option
*/
public $short_name;
/**
* The option long name (ex: --verbose).
*
* @var string $long_name Long name of the option
*/
public $long_name;
/**
* The option action, defaults to "StoreString".
*
* @var string $action Option action
*/
public $action = 'StoreString';
/**
* An array of possible values for the option. If this array is not empty
* and the value passed is not in the array an exception is raised.
* This only make sense for actions that accept values of course.
*
* @var array $choices Valid choices for the option
*/
public $choices = array();
/**
* The callback function (or method) to call for an action of type
* Callback, this can be any callable supported by the php function
* call_user_func.
*
* Example:
*
* <code>
* $parser->addOption('myoption', array(
* 'short_name' => '-m',
* 'long_name' => '--myoption',
* 'action' => 'Callback',
* 'callback' => 'myCallbackFunction'
* ));
* </code>
*
* @var callable $callback The option callback
*/
public $callback;
/**
* An associative array of additional params to pass to the class
* corresponding to the action, this array will also be passed to the
* callback defined for an action of type Callback, Example:
*
* <code>
* // for a custom action
* $parser->addOption('myoption', array(
* 'short_name' => '-m',
* 'long_name' => '--myoption',
* 'action' => 'MyCustomAction',
* 'action_params' => array('foo'=>true, 'bar'=>false)
* ));
*
* // if the user type:
* // $ <yourprogram> -m spam
* // in your MyCustomAction class the execute() method will be called
* // with the value 'spam' as first parameter and
* // array('foo'=>true, 'bar'=>false) as second parameter
* </code>
*
* @var array $action_params Additional parameters to pass to the action
*/
public $action_params = array();
/**
* For options that expect an argument, this property tells the parser if
* the option argument is optional and can be ommited.
*
* @var bool $argumentOptional Whether the option arg is optional or not
*/
public $argument_optional = false;
/**
* For options that uses the "choice" property only.
* Adds a --list-<choice> option to the parser that displays the list of
* choices for the option.
*
* @var bool $add_list_option Whether to add a list option or not
*/
public $add_list_option = false;
// }}}
// Private properties {{{
/**
* When an action is called remember it to allow for multiple calls.
*
* @var object $action_instance Placeholder for action
*/
private $_action_instance = null;
// }}}
// __construct() {{{
/**
* Constructor.
*
* @param string $name The name of the option
* @param array $params An optional array of parameters
*
* @return void
*/
public function __construct($name = null, $params = array())
{
parent::__construct($name, $params);
if ($this->action == 'Password') {
// special case for Password action, password can be passed to the
// commandline or prompted by the parser
$this->argument_optional = true;
}
}
// }}}
// toString() {{{
/**
* Returns the string representation of the option.
*
* @param string $delim Delimiter to use between short and long option
*
* @return string The string representation of the option
* @todo use __toString() instead
*/
public function toString($delim = ", ")
{
$ret = '';
$padding = '';
if ($this->short_name != null) {
$ret .= $this->short_name;
if ($this->expectsArgument()) {
$ret .= ' ' . $this->help_name;
}
$padding = $delim;
}
if ($this->long_name != null) {
$ret .= $padding . $this->long_name;
if ($this->expectsArgument()) {
$ret .= '=' . $this->help_name;
}
}
return $ret;
}
// }}}
// expectsArgument() {{{
/**
* Returns true if the option requires one or more argument and false
* otherwise.
*
* @return bool Whether the option expects an argument or not
*/
public function expectsArgument()
{
if ($this->action == 'StoreTrue'
|| $this->action == 'StoreFalse'
|| $this->action == 'Help'
|| $this->action == 'Version'
|| $this->action == 'Counter'
|| $this->action == 'List'
) {
return false;
}
return true;
}
// }}}
// dispatchAction() {{{
/**
* Formats the value $value according to the action of the option and
* updates the passed PEAR2\Console\CommandLine_Result object.
*
* @param mixed $value The value to format
* @param PEAR2\Console\CommandLine_Result $result The result instance
* @param PEAR2\Console\CommandLine $parser The parser instance
*
* @return void
* @throws PEAR2\Console\CommandLine\Exception
*/
public function dispatchAction($value, $result, $parser)
{
$actionInfo = Console\CommandLine::$actions[$this->action];
$clsname = $actionInfo[0];
if ($this->_action_instance === null) {
$this->_action_instance = new $clsname($result, $this, $parser);
}
// check value is in option choices
if (!empty($this->choices)
&& !in_array(
$this->_action_instance->format($value),
$this->choices
)
) {
throw Console\CommandLine\Exception::factory(
'OPTION_VALUE_NOT_VALID',
array(
'name' => $this->name,
'choices' => implode('", "', $this->choices),
'value' => $value,
),
$parser,
$this->messages
);
}
$this->_action_instance->execute($value, $this->action_params);
}
// }}}
// validate() {{{
/**
* Validates the option instance.
*
* @return void
* @throws PEAR2\Console\CommandLine\Exception
* @todo use exceptions instead
*/
public function validate()
{
// check if the option name is valid
if (!preg_match(
'/^[a-zA-Z_\x7f-\xff]+[a-zA-Z0-9_\x7f-\xff]*$/',
$this->name
)
) {
Console\CommandLine::triggerError(
'option_bad_name',
E_USER_ERROR,
array('{$name}' => $this->name)
);
}
// call the parent validate method
parent::validate();
// a short_name or a long_name must be provided
if ($this->short_name == null && $this->long_name == null) {
Console\CommandLine::triggerError(
'option_long_and_short_name_missing',
E_USER_ERROR,
array('{$name}' => $this->name)
);
}
// check if the option short_name is valid
if ($this->short_name != null
&& !(preg_match('/^\-[a-zA-Z]{1}$/', $this->short_name))
) {
Console\CommandLine::triggerError(
'option_bad_short_name',
E_USER_ERROR,
array(
'{$name}' => $this->name,
'{$short_name}' => $this->short_name
)
);
}
// check if the option long_name is valid
if ($this->long_name != null
&& !preg_match('/^\-\-[a-zA-Z]+[a-zA-Z0-9_\-]*$/', $this->long_name)
) {
Console\CommandLine::triggerError(
'option_bad_long_name',
E_USER_ERROR,
array(
'{$name}' => $this->name,
'{$long_name}' => $this->long_name
)
);
}
// check if we have a valid action
if (!is_string($this->action)) {
Console\CommandLine::triggerError(
'option_bad_action',
E_USER_ERROR,
array('{$name}' => $this->name)
);
}
if (!isset(Console\CommandLine::$actions[$this->action])) {
Console\CommandLine::triggerError(
'option_unregistered_action',
E_USER_ERROR,
array(
'{$action}' => $this->action,
'{$name}' => $this->name
)
);
}
// if the action is a callback, check that we have a valid callback
if ($this->action == 'Callback' && !is_callable($this->callback)) {
Console\CommandLine::triggerError(
'option_invalid_callback',
E_USER_ERROR,
array('{$name}' => $this->name)
);
}
}
// }}}
// setDefaults() {{{
/**
* Set the default value according to the configured action.
*
* Note that for backward compatibility issues this method is only called
* when the 'force_options_defaults' is set to true, it will become the
* default behaviour in the next major release of PEAR2\Console\CommandLine.
*
* @return void
*/
public function setDefaults()
{
if ($this->default !== null) {
// already set
return;
}
switch ($this->action) {
case 'Counter':
case 'StoreInt':
$this->default = 0;
break;
case 'StoreFloat':
$this->default = 0.0;
break;
case 'StoreArray':
$this->default = array();
break;
case 'StoreTrue':
$this->default = false;
break;
case 'StoreFalse':
$this->default = true;
break;
default:
return;
}
}
// }}}
}

View file

@ -0,0 +1,64 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* This file is part of the PEAR2\Console\CommandLine package.
*
* PHP version 5
*
* LICENSE: This source file is subject to the MIT license that is available
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
* @filesource
*/
namespace PEAR2\Console\CommandLine;
/**
* Outputters common interface, all outputters must implement this interface.
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since Class available since release 0.1.0
*/
interface Outputter
{
// stdout() {{{
/**
* Processes the output for a message that should be displayed on STDOUT.
*
* @param string $msg The message to output
*
* @return void
*/
public function stdout($msg);
// }}}
// stderr() {{{
/**
* Processes the output for a message that should be displayed on STDERR.
*
* @param string $msg The message to output
*
* @return void
*/
public function stderr($msg);
// }}}
}

View file

@ -0,0 +1,78 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* This file is part of the PEAR2\Console\CommandLine package.
*
* PHP version 5
*
* LICENSE: This source file is subject to the MIT license that is available
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
* @filesource
*/
namespace PEAR2\Console\CommandLine;
/**
* PEAR2\Console\CommandLine default Outputter.
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since Class available since release 0.1.0
*/
class Outputter_Default implements Outputter
{
// stdout() {{{
/**
* Writes the message $msg to STDOUT.
*
* @param string $msg The message to output
*
* @return void
*/
public function stdout($msg)
{
if (defined('STDOUT')) {
fwrite(STDOUT, $msg);
} else {
echo $msg;
}
}
// }}}
// stderr() {{{
/**
* Writes the message $msg to STDERR.
*
* @param string $msg The message to output
*
* @return void
*/
public function stderr($msg)
{
if (defined('STDERR')) {
fwrite(STDERR, $msg);
} else {
echo $msg;
}
}
// }}}
}

View file

@ -0,0 +1,72 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* This file is part of the PEAR2\Console\CommandLine package.
*
* PHP version 5
*
* LICENSE: This source file is subject to the MIT license that is available
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
* @filesource
*/
namespace PEAR2\Console\CommandLine;
/**
* Renderers common interface, all renderers must implement this interface.
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since Class available since release 0.1.0
*/
interface Renderer
{
// usage() {{{
/**
* Returns the full usage message.
*
* @return string The usage message
*/
public function usage();
// }}}
// error() {{{
/**
* Returns a formatted error message.
*
* @param string $error The error message to format
*
* @return string The error string
*/
public function error($error);
// }}}
// version() {{{
/**
* Returns the program version string.
*
* @return string The version string
*/
public function version();
// }}}
}

View file

@ -0,0 +1,441 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* This file is part of the PEAR2\Console\CommandLine package.
*
* PHP version 5
*
* LICENSE: This source file is subject to the MIT license that is available
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
*/
namespace PEAR2\Console\CommandLine;
/**
* PEAR2\Console\CommandLine default renderer.
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since Class available since release 0.1.0
*/
class Renderer_Default implements Renderer
{
// Properties {{{
/**
* Integer that define the max width of the help text.
*
* @var integer $line_width Line width
*/
public $line_width = 75;
/**
* Integer that define the max width of the help text.
*
* @var integer $line_width Line width
*/
public $options_on_different_lines = false;
/**
* An instance of PEAR2\Console\CommandLine.
*
* @var PEAR2\Console\CommandLine $parser The parser
*/
public $parser = false;
// }}}
// __construct() {{{
/**
* Constructor.
*
* @param object $parser A PEAR2\Console\CommandLine instance
*
* @return void
*/
public function __construct($parser = false)
{
$this->parser = $parser;
}
// }}}
// usage() {{{
/**
* Returns the full usage message.
*
* @return string The usage message
*/
public function usage()
{
$ret = '';
if (!empty($this->parser->description)) {
$ret .= $this->description() . "\n\n";
}
$ret .= $this->usageLine() . "\n";
if (count($this->parser->commands) > 0) {
$ret .= $this->commandUsageLine() . "\n";
}
if (count($this->parser->options) > 0) {
$ret .= "\n" . $this->optionList() . "\n";
}
if (count($this->parser->args) > 0) {
$ret .= "\n" . $this->argumentList() . "\n";
}
if (count($this->parser->commands) > 0) {
$ret .= "\n" . $this->commandList() . "\n";
}
$ret .= "\n";
return $ret;
}
// }}}
// error() {{{
/**
* Returns a formatted error message.
*
* @param string $error The error message to format
*
* @return string The error string
*/
public function error($error)
{
$ret = 'Error: ' . $error . "\n";
if ($this->parser->add_help_option) {
$name = $this->name();
$ret .= $this->wrap(
$this->parser->message_provider->get(
'PROG_HELP_LINE',
array('progname' => $name)
)
) . "\n";
if (count($this->parser->commands) > 0) {
$ret .= $this->wrap(
$this->parser->message_provider->get(
'COMMAND_HELP_LINE',
array('progname' => $name)
)
) . "\n";
}
}
return $ret;
}
// }}}
// version() {{{
/**
* Returns the program version string.
*
* @return string The version string
*/
public function version()
{
return $this->parser->message_provider->get(
'PROG_VERSION_LINE',
array(
'progname' => $this->name(),
'version' => $this->parser->version
)
) . "\n";
}
// }}}
// name() {{{
/**
* Returns the full name of the program or the sub command
*
* @return string The name of the program
*/
protected function name()
{
$name = $this->parser->name;
$parent = $this->parser->parent;
while ($parent) {
if (count($parent->options) > 0) {
$name = '['
. strtolower(
$this->parser->message_provider->get(
'OPTION_WORD',
array('plural' => 's')
)
) . '] ' . $name;
}
$name = $parent->name . ' ' . $name;
$parent = $parent->parent;
}
return $this->wrap($name);
}
// }}}
// description() {{{
/**
* Returns the command line description message.
*
* @return string The description message
*/
protected function description()
{
return $this->wrap($this->parser->description);
}
// }}}
// usageLine() {{{
/**
* Returns the command line usage message
*
* @return string the usage message
*/
protected function usageLine()
{
$usage = $this->parser->message_provider->get('USAGE_WORD') . ":\n";
$ret = $usage . ' ' . $this->name();
if (count($this->parser->options) > 0) {
$ret .= ' ['
. strtolower($this->parser->message_provider->get('OPTION_WORD'))
. ']';
}
if (count($this->parser->args) > 0) {
foreach ($this->parser->args as $name=>$arg) {
$arg_str = $arg->help_name;
if ($arg->multiple) {
$arg_str .= '1 ' . $arg->help_name . '2 ...';
}
if ($arg->optional) {
$arg_str = '[' . $arg_str . ']';
}
$ret .= ' ' . $arg_str;
}
}
return $this->columnWrap($ret, 2);
}
// }}}
// commandUsageLine() {{{
/**
* Returns the command line usage message for subcommands.
*
* @return string The usage line
*/
protected function commandUsageLine()
{
if (count($this->parser->commands) == 0) {
return '';
}
$ret = ' ' . $this->name();
if (count($this->parser->options) > 0) {
$ret .= ' ['
. strtolower($this->parser->message_provider->get('OPTION_WORD'))
. ']';
}
$ret .= " <command>";
$hasArgs = false;
$hasOptions = false;
foreach ($this->parser->commands as $command) {
if (!$hasArgs && count($command->args) > 0) {
$hasArgs = true;
}
if (!$hasOptions && ($command->add_help_option
|| $command->add_version_option
|| count($command->options) > 0)
) {
$hasOptions = true;
}
}
if ($hasOptions) {
$ret .= ' [options]';
}
if ($hasArgs) {
$ret .= ' [args]';
}
return $this->columnWrap($ret, 2);
}
// }}}
// argumentList() {{{
/**
* Render the arguments list that will be displayed to the user, you can
* override this method if you want to change the look of the list.
*
* @return string The formatted argument list
*/
protected function argumentList()
{
$col = 0;
$args = array();
foreach ($this->parser->args as $arg) {
$argstr = ' ' . $arg->toString();
$args[] = array($argstr, $arg->description);
$ln = strlen($argstr);
if ($col < $ln) {
$col = $ln;
}
}
$ret = $this->parser->message_provider->get('ARGUMENT_WORD') . ":";
foreach ($args as $arg) {
$text = str_pad($arg[0], $col) . ' ' . $arg[1];
$ret .= "\n" . $this->columnWrap($text, $col+2);
}
return $ret;
}
// }}}
// optionList() {{{
/**
* Render the options list that will be displayed to the user, you can
* override this method if you want to change the look of the list.
*
* @return string The formatted option list
*/
protected function optionList()
{
$col = 0;
$options = array();
foreach ($this->parser->options as $option) {
$delim = $this->options_on_different_lines ? "\n" : ', ';
$optstr = $option->toString($delim);
$lines = explode("\n", $optstr);
$lines[0] = ' ' . $lines[0];
if (count($lines) > 1) {
$lines[1] = ' ' . $lines[1];
$ln = strlen($lines[1]);
} else {
$ln = strlen($lines[0]);
}
$options[] = array($lines, $option->description);
if ($col < $ln) {
$col = $ln;
}
}
$ret = $this->parser->message_provider->get('OPTION_WORD') . ":";
foreach ($options as $option) {
if (count($option[0]) > 1) {
$text = str_pad($option[0][1], $col) . ' ' . $option[1];
$pre = $option[0][0] . "\n";
} else {
$text = str_pad($option[0][0], $col) . ' ' . $option[1];
$pre = '';
}
$ret .= "\n" . $pre . $this->columnWrap($text, $col+2);
}
return $ret;
}
// }}}
// commandList() {{{
/**
* Render the command list that will be displayed to the user, you can
* override this method if you want to change the look of the list.
*
* @return string The formatted subcommand list
*/
protected function commandList()
{
$commands = array();
$col = 0;
foreach ($this->parser->commands as $cmdname=>$command) {
$cmdname = ' ' . $cmdname;
$commands[] = array($cmdname, $command->description, $command->aliases);
$ln = strlen($cmdname);
if ($col < $ln) {
$col = $ln;
}
}
$ret = $this->parser->message_provider->get('COMMAND_WORD') . ":";
foreach ($commands as $command) {
$text = str_pad($command[0], $col) . ' ' . $command[1];
if ($aliasesCount = count($command[2])) {
$pad = '';
$text .= ' (';
$text .= $aliasesCount > 1 ? 'aliases: ' : 'alias: ';
foreach ($command[2] as $alias) {
$text .= $pad . $alias;
$pad = ', ';
}
$text .= ')';
}
$ret .= "\n" . $this->columnWrap($text, $col+2);
}
return $ret;
}
// }}}
// wrap() {{{
/**
* Wraps the text passed to the method.
*
* @param string $text The text to wrap
* @param int $lw The column width (defaults to line_width property)
*
* @return string The wrapped text
*/
protected function wrap($text, $lw=null)
{
if ($this->line_width > 0) {
if ($lw === null) {
$lw = $this->line_width;
}
return wordwrap($text, $lw, "\n", false);
}
return $text;
}
// }}}
// columnWrap() {{{
/**
* Wraps the text passed to the method at the specified width.
*
* @param string $text The text to wrap
* @param int $cw The wrap width
*
* @return string The wrapped text
*/
protected function columnWrap($text, $cw)
{
$tokens = explode("\n", $this->wrap($text));
$ret = $tokens[0];
$text = trim(substr($text, strlen($ret)));
if (empty($text)) {
return $ret;
}
$chunks = $this->wrap($text, $this->line_width - $cw);
$tokens = explode("\n", $chunks);
foreach ($tokens as $token) {
if (!empty($token)) {
$ret .= "\n" . str_repeat(' ', $cw) . $token;
} else {
$ret .= "\n";
}
}
return $ret;
}
// }}}
}

View file

@ -0,0 +1,72 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* This file is part of the PEAR2\Console\CommandLine package.
*
* PHP version 5
*
* LICENSE: This source file is subject to the MIT license that is available
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
* @filesource
*/
namespace PEAR2\Console\CommandLine;
/**
* A lightweight class to store the result of the command line parsing.
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since Class available since release 0.1.0
*/
class Result
{
// Public properties {{{
/**
* The result options associative array.
* Key is the name of the option and value its value.
*
* @var array $options Result options array
*/
public $options = array();
/**
* The result arguments array.
*
* @var array $args Result arguments array
*/
public $args = array();
/**
* Name of the command invoked by the user, false if no command invoked.
*
* @var string $command_name Result command name
*/
public $command_name = false;
/**
* A result instance for the subcommand.
*
* @var static $command Result instance for the subcommand
*/
public $command = false;
// }}}
}

View file

@ -0,0 +1,303 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* This file is part of the PEAR2\Console\CommandLine package.
*
* PHP version 5
*
* LICENSE: This source file is subject to the MIT license that is available
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
* @filesource
*/
namespace PEAR2\Console\CommandLine;
use PEAR2\Console\CommandLine;
/**
* Parser for command line xml definitions.
*
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since Class available since release 0.1.0
*/
class XmlParser
{
// parse() {{{
/**
* Parses the given xml definition file and returns a
* PEAR2\Console\CommandLine instance constructed with the xml data.
*
* @param string $xmlfile The xml file to parse
*
* @return PEAR2\Console\CommandLine A parser instance
*/
public static function parse($xmlfile)
{
if (!is_readable($xmlfile)) {
CommandLine::triggerError(
'invalid_xml_file',
E_USER_ERROR,
array('{$file}' => $xmlfile)
);
}
$doc = new \DomDocument();
$doc->load($xmlfile);
self::validate($doc);
$nodes = $doc->getElementsByTagName('command');
$root = $nodes->item(0);
return self::_parseCommandNode($root, true);
}
// }}}
// parseString() {{{
/**
* Parses the given xml definition string and returns a
* PEAR2\Console\CommandLine instance constructed with the xml data.
*
* @param string $xmlstr The xml string to parse
*
* @return PEAR2\Console\CommandLine A parser instance
*/
public static function parseString($xmlstr)
{
$doc = new \DomDocument();
$doc->loadXml($xmlstr);
self::validate($doc);
$nodes = $doc->getElementsByTagName('command');
$root = $nodes->item(0);
return self::_parseCommandNode($root, true);
}
// }}}
// validate() {{{
/**
* Validates the xml definition using Relax NG.
*
* @param DomDocument $doc The document to validate
*
* @return boolean Whether the xml data is valid or not.
* @throws PEAR2\Console\CommandLine\Exception
* @todo use exceptions only
*/
public static function validate($doc)
{
$rngfile = __DIR__
. '/../../../../data/pear2.php.net/PEAR2_Console_CommandLine/xmlschema.rng';
if (!is_file($rngfile)) {
$rngfile = __DIR__ . '/../../../../data/xmlschema.rng';
}
if (!is_readable($rngfile)) {
CommandLine::triggerError(
'invalid_xml_file',
E_USER_ERROR,
array('{$file}' => $rngfile)
);
}
return $doc->relaxNGValidate($rngfile);
}
// }}}
// _parseCommandNode() {{{
/**
* Parses the root command node or a command node and returns the
* constructed PEAR2\Console\CommandLine or PEAR2\Console\CommandLine_Command
* instance.
*
* @param DomDocumentNode $node The node to parse
* @param bool $isRootNode Whether it is a root node or not
*
* @return mixed PEAR2\Console\CommandLine or PEAR2\Console\CommandLine_Command
*/
private static function _parseCommandNode($node, $isRootNode = false)
{
if ($isRootNode) {
$obj = new CommandLine();
} else {
$obj = new CommandLine\Command();
}
foreach ($node->childNodes as $cNode) {
$cNodeName = $cNode->nodeName;
switch ($cNodeName) {
case 'name':
case 'description':
case 'version':
$obj->$cNodeName = trim($cNode->nodeValue);
break;
case 'add_help_option':
case 'add_version_option':
case 'force_posix':
$obj->$cNodeName = self::_bool(trim($cNode->nodeValue));
break;
case 'option':
$obj->addOption(self::_parseOptionNode($cNode));
break;
case 'argument':
$obj->addArgument(self::_parseArgumentNode($cNode));
break;
case 'command':
$obj->addCommand(self::_parseCommandNode($cNode));
break;
case 'aliases':
if (!$isRootNode) {
foreach ($cNode->childNodes as $subChildNode) {
if ($subChildNode->nodeName == 'alias') {
$obj->aliases[] = trim($subChildNode->nodeValue);
}
}
}
break;
case 'messages':
$obj->messages = self::_messages($cNode);
break;
default:
break;
}
}
return $obj;
}
// }}}
// _parseOptionNode() {{{
/**
* Parses an option node and returns the constructed
* PEAR2\Console\CommandLine_Option instance.
*
* @param DomDocumentNode $node The node to parse
*
* @return PEAR2\Console\CommandLine\Option The built option
*/
private static function _parseOptionNode($node)
{
$obj = new CommandLine\Option($node->getAttribute('name'));
foreach ($node->childNodes as $cNode) {
$cNodeName = $cNode->nodeName;
switch ($cNodeName) {
case 'choices':
foreach ($cNode->childNodes as $subChildNode) {
if ($subChildNode->nodeName == 'choice') {
$obj->choices[] = trim($subChildNode->nodeValue);
}
}
break;
case 'messages':
$obj->messages = self::_messages($cNode);
break;
default:
if (property_exists($obj, $cNodeName)) {
$obj->$cNodeName = trim($cNode->nodeValue);
}
break;
}
}
if ($obj->action == 'Password') {
$obj->argument_optional = true;
}
return $obj;
}
// }}}
// _parseArgumentNode() {{{
/**
* Parses an argument node and returns the constructed
* PEAR2\Console\CommandLine_Argument instance.
*
* @param DomDocumentNode $node The node to parse
*
* @return PEAR2\Console\CommandLine\Argument The built argument
*/
private static function _parseArgumentNode($node)
{
$obj = new CommandLine\Argument($node->getAttribute('name'));
foreach ($node->childNodes as $cNode) {
$cNodeName = $cNode->nodeName;
switch ($cNodeName) {
case 'description':
case 'help_name':
case 'default':
$obj->$cNodeName = trim($cNode->nodeValue);
break;
case 'multiple':
$obj->multiple = self::_bool(trim($cNode->nodeValue));
break;
case 'optional':
$obj->optional = self::_bool(trim($cNode->nodeValue));
break;
case 'messages':
$obj->messages = self::_messages($cNode);
break;
default:
break;
}
}
return $obj;
}
// }}}
// _bool() {{{
/**
* Returns a boolean according to true/false possible strings.
*
* @param string $str The string to process
*
* @return boolean
*/
private static function _bool($str)
{
return in_array((string)$str, array('true', '1', 'on', 'yes'));
}
// }}}
// _messages() {{{
/**
* Returns an array of custom messages for the element
*
* @param DOMNode $node The messages node to process
*
* @return array an array of messages
*
* @see PEAR2\Console\CommandLine::$messages
* @see PEAR2\Console\CommandLine_Element::$messages
*/
private static function _messages(DOMNode $node)
{
$messages = array();
foreach ($node->childNodes as $cNode) {
if ($cNode->nodeType == XML_ELEMENT_NODE) {
$name = $cNode->getAttribute('name');
$value = trim($cNode->nodeValue);
$messages[$name] = $value;
}
}
return $messages;
}
// }}}
}

View file

@ -0,0 +1,819 @@
<?php
/**
* RouterOS API client implementation.
*
* RouterOS is the flag product of the company MikroTik and is a powerful router software. One of its many abilities is to allow control over it via an API. This package provides a client for that API, in turn allowing you to use PHP to control RouterOS hosts.
*
* PHP version 5
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0b5
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
/**
* The namespace declaration.
*/
namespace PEAR2\Net\RouterOS;
/**
* Refers to transmitter direction constants.
*/
use PEAR2\Net\Transmitter\Stream as S;
/**
* Refers to the cryptography constants.
*/
use PEAR2\Net\Transmitter\NetworkStream as N;
/**
* Catches arbitrary exceptions at some points.
*/
use Exception as E;
/**
* A RouterOS client.
*
* Provides functionality for easily communicating with a RouterOS host.
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
class Client
{
/**
* Used in {@link static::isRequestActive()} to limit search only to
* requests that have a callback.
*/
const FILTER_CALLBACK = 1;
/**
* Used in {@link static::isRequestActive()} to limit search only to
* requests that use the buffer.
*/
const FILTER_BUFFER = 2;
/**
* Used in {@link static::isRequestActive()} to indicate no limit in search.
*/
const FILTER_ALL = 3;
/**
* @var Communicator The communicator for this client.
*/
protected $com;
/**
* @var int The number of currently pending requests.
*/
protected $pendingRequestsCount = 0;
/**
* @var array An array of responses that have not yet been extracted or
* passed to a callback. Key is the tag of the request, and the value
* is an array of associated responses.
*/
protected $responseBuffer = array();
/**
* @var array An array of callbacks to be executed as responses come.
* Key is the tag of the request, and the value is the callback for it.
*/
protected $callbacks = array();
/**
* @var Registry A registry for the operations. Particularly helpful at
* persistent connections.
*/
protected $registry = null;
/**
* @var bool Whether to stream future responses.
*/
private $_streamingResponses = false;
/**
* Creates a new instance of a RouterOS API client.
*
* Creates a new instance of a RouterOS API client with the specified
* settings.
*
* @param string $host Hostname (IP or domain) of the RouterOS server.
* @param string $username The RouterOS username.
* @param string $password The RouterOS password.
* @param int|null $port The port on which the RouterOS server provides
* the API service. You can also specify NULL, in which case the port
* will automatically be chosen between 8728 and 8729, depending on the
* value of $crypto.
* @param bool $persist Whether or not the connection should be a
* persistent one.
* @param float $timeout The timeout for the connection.
* @param string $crypto The encryption for this connection. Must be one
* of the PEAR2\Net\Transmitter\NetworkStream::CRYPTO_* constants. Off
* by default. RouterOS currently supports only TLS, but the setting is
* provided in this fashion for forward compatibility's sake. And for
* the sake of simplicity, if you specify an encryption, don't specify a
* context and your default context uses the value "DEFAULT" for
* ciphers, "ADH" will be automatically added to the list of ciphers.
* @param resource $context A context for the socket.
*
* @see sendSync()
* @see sendAsync()
*/
public function __construct(
$host,
$username,
$password = '',
$port = 8728,
$persist = false,
$timeout = null,
$crypto = N::CRYPTO_OFF,
$context = null
) {
$this->com = new Communicator(
$host,
$port,
$persist,
$timeout,
$username . '/' . $password,
$crypto,
$context
);
$timeout = null == $timeout
? ini_get('default_socket_timeout')
: (int) $timeout;
//Login the user if necessary
if ((!$persist
|| !($old = $this->com->getTransmitter()->lock(S::DIRECTION_ALL)))
&& $this->com->getTransmitter()->isFresh()
) {
if (!static::login($this->com, $username, $password, $timeout)) {
$this->com->close();
throw new DataFlowException(
'Invalid username or password supplied.',
DataFlowException::CODE_INVALID_CREDENTIALS
);
}
}
if (isset($old)) {
$this->com->getTransmitter()->lock($old, true);
}
if ($persist) {
$this->registry = new Registry("{$host}:{$port}/{$username}");
}
}
/**
* A shorthand gateway.
*
* This is a magic PHP method that allows you to call the object as a
* function. Depending on the argument given, one of the other functions in
* the class is invoked and its returned value is returned by this function.
*
* @param mixed $arg Value can be either a {@link Request} to send, which
* would be sent asynchoniously if it has a tag, and synchroniously if
* not, a number to loop with or NULL to complete all pending requests.
* Any other value is converted to string and treated as the tag of a
* request to complete.
*
* @return mixed Whatever the long form function would have returned.
*/
public function __invoke($arg = null)
{
if (is_int($arg) || is_double($arg)) {
return $this->loop($arg);
} elseif ($arg instanceof Request) {
return '' == $arg->getTag() ? $this->sendSync($arg)
: $this->sendAsync($arg);
} elseif (null === $arg) {
return $this->completeRequest();
}
return $this->completeRequest((string) $arg);
}
/**
* Login to a RouterOS connection.
*
* @param Communicator $com The communicator to attempt to login to.
* @param string $username The RouterOS username.
* @param string $password The RouterOS password.
* @param int|null $timeout The time to wait for each response. NULL
* waits indefinetly.
*
* @return bool TRUE on success, FALSE on failure.
*/
public static function login(
Communicator $com,
$username,
$password = '',
$timeout = null
) {
if (null !== ($remoteCharset = $com->getCharset($com::CHARSET_REMOTE))
&& null !== ($localCharset = $com->getCharset($com::CHARSET_LOCAL))
) {
$password = iconv(
$localCharset,
$remoteCharset . '//IGNORE//TRANSLIT',
$password
);
}
$old = null;
try {
if ($com->getTransmitter()->isPersistent()) {
$old = $com->getTransmitter()->lock(S::DIRECTION_ALL);
$result = self::_login($com, $username, $password, $timeout);
$com->getTransmitter()->lock($old, true);
return $result;
}
return self::_login($com, $username, $password, $timeout);
} catch (E $e) {
if ($com->getTransmitter()->isPersistent() && null !== $old) {
$com->getTransmitter()->lock($old, true);
}
throw ($e instanceof NotSupportedException
|| $e instanceof UnexpectedValueException
|| !$com->getTransmitter()->isDataAwaiting()) ? new SocketException(
'This is not a compatible RouterOS service',
SocketException::CODE_SERVICE_INCOMPATIBLE,
$e
) : $e;
}
}
/**
* Login to a RouterOS connection.
*
* This is the actual login procedure, applied regardless of persistence and
* charset settings.
*
* @param Communicator $com The communicator to attempt to login to.
* @param string $username The RouterOS username.
* @param string $password The RouterOS password. Potentially parsed
* already by iconv.
* @param int|null $timeout The time to wait for each response. NULL
* waits indefinetly.
*
* @return bool TRUE on success, FALSE on failure.
*/
private static function _login(
Communicator $com,
$username,
$password = '',
$timeout = null
) {
$request = new Request('/login');
$request->send($com);
$response = new Response($com, false, $timeout);
$request->setArgument('name', $username);
$request->setArgument(
'response',
'00' . md5(
chr(0) . $password
. pack('H*', $response->getProperty('ret'))
)
);
$request->send($com);
$response = new Response($com, false, $timeout);
return $response->getType() === Response::TYPE_FINAL
&& null === $response->getProperty('ret');
}
/**
* Sets the charset(s) for this connection.
*
* Sets the charset(s) for this connection. The specified charset(s) will be
* used for all future requests and responses. When sending,
* {@link Communicator::CHARSET_LOCAL} is converted to
* {@link Communicator::CHARSET_REMOTE}, and when receiving,
* {@link Communicator::CHARSET_REMOTE} is converted to
* {@link Communicator::CHARSET_LOCAL}. Setting NULL to either charset will
* disable charset convertion, and data will be both sent and received "as
* is".
*
* @param mixed $charset The charset to set. If $charsetType is
* {@link Communicator::CHARSET_ALL}, you can supply either a string to
* use for all charsets, or an array with the charset types as keys, and
* the charsets as values.
* @param int $charsetType Which charset to set. Valid values are the
* Communicator::CHARSET_* constants. Any other value is treated as
* {@link Communicator::CHARSET_ALL}.
*
* @return string|array The old charset. If $charsetType is
* {@link Communicator::CHARSET_ALL}, the old values will be returned as
* an array with the types as keys, and charsets as values.
* @see Communicator::setDefaultCharset()
*/
public function setCharset(
$charset,
$charsetType = Communicator::CHARSET_ALL
) {
return $this->com->setCharset($charset, $charsetType);
}
/**
* Gets the charset(s) for this connection.
*
* @param int $charsetType Which charset to get. Valid values are the
* Communicator::CHARSET_* constants. Any other value is treated as
* {@link Communicator::CHARSET_ALL}.
*
* @return string|array The current charset. If $charsetType is
* {@link Communicator::CHARSET_ALL}, the current values will be
* returned as an array with the types as keys, and charsets as values.
* @see setCharset()
*/
public function getCharset($charsetType)
{
return $this->com->getCharset($charsetType);
}
/**
* Sends a request and waits for responses.
*
* @param Request $request The request to send.
* @param callback $callback Optional. A function that is to be executed
* when new responses for this request are available. The callback takes
* two parameters. The {@link Response} object as the first, and the
* {@link Client} object as the second one. If the function returns
* TRUE, the request is canceled. Note that the callback may be executed
* one last time after that with a response that notifies about the
* canceling.
*
* @return $this The client object.
* @see completeRequest()
* @see loop()
* @see cancelRequest()
*/
public function sendAsync(Request $request, $callback = null)
{
//Error checking
$tag = $request->getTag();
if ('' == $tag) {
throw new DataFlowException(
'Asynchonous commands must have a tag.',
DataFlowException::CODE_TAG_REQUIRED
);
}
if ($this->isRequestActive($tag)) {
throw new DataFlowException(
'There must not be multiple active requests sharing a tag.',
DataFlowException::CODE_TAG_UNIQUE
);
}
if (null !== $callback && !is_callable($callback, true)) {
throw new UnexpectedValueException(
'Invalid callback provided.',
UnexpectedValueException::CODE_CALLBACK_INVALID
);
}
$this->send($request);
if (null === $callback) {
//Register the request at the buffer
$this->responseBuffer[$tag] = array();
} else {
//Prepare the callback
$this->callbacks[$tag] = $callback;
}
return $this;
}
/**
* Checks if a request is active.
*
* Checks if a request is active. A request is considered active if it's a
* pending request and/or has responses that are not yet extracted.
*
* @param string $tag The tag of the request to look for.
* @param int $filter One of the FILTER_* consntants. Limits the search
* to the specified places.
*
* @return bool TRUE if the request is active, FALSE otherwise.
* @see getPendingRequestsCount()
* @see completeRequest()
*/
public function isRequestActive($tag, $filter = self::FILTER_ALL)
{
$result = 0;
if ($filter & self::FILTER_CALLBACK) {
$result |= (int) array_key_exists($tag, $this->callbacks);
}
if ($filter & self::FILTER_BUFFER) {
$result |= (int) array_key_exists($tag, $this->responseBuffer);
}
return 0 !== $result;
}
/**
* Sends a request and gets the full response.
*
* @param Request $request The request to send.
*
* @return ResponseCollection The received responses as a collection.
* @see sendAsync()
* @see close()
*/
public function sendSync(Request $request)
{
$tag = $request->getTag();
if ('' == $tag) {
$this->send($request);
} else {
$this->sendAsync($request);
}
return $this->completeRequest($tag);
}
/**
* Completes a specified request.
*
* Starts an event loop for the RouterOS callbacks and finishes when a
* specified request is completed.
*
* @param string $tag The tag of the request to complete. Setting NULL
* completes all requests.
*
* @return ResponseCollection A collection of {@link Response} objects that
* haven't been passed to a callback function or previously extracted
* with {@link static::extractNewResponses()}. Returns an empty
* collection when $tag is set to NULL (responses can still be
* extracted).
*/
public function completeRequest($tag = null)
{
$hasNoTag = '' == $tag;
$result = $hasNoTag ? array()
: $this->extractNewResponses($tag)->toArray();
while ((!$hasNoTag && $this->isRequestActive($tag))
|| ($hasNoTag && 0 !== $this->getPendingRequestsCount())
) {
$newReply = $this->dispatchNextResponse(null);
if ($newReply->getTag() === $tag) {
if ($hasNoTag) {
$result[] = $newReply;
}
if ($newReply->getType() === Response::TYPE_FINAL) {
if (!$hasNoTag) {
$result = array_merge(
$result,
$this->isRequestActive($tag)
? $this->extractNewResponses($tag)->toArray()
: array()
);
}
break;
}
}
}
return new ResponseCollection($result);
}
/**
* Extracts responses for a request.
*
* Gets all new responses for a request that haven't been passed to a
* callback and clears the buffer from them.
*
* @param string $tag The tag of the request to extract new responses for.
* Specifying NULL with extract new responses for all requests.
*
* @return ResponseCollection A collection of {@link Response} objects for
* the specified request.
* @see loop()
*/
public function extractNewResponses($tag = null)
{
if (null === $tag) {
$result = array();
foreach (array_keys($this->responseBuffer) as $tag) {
$result = array_merge(
$result,
$this->extractNewResponses($tag)->toArray()
);
}
return new ResponseCollection($result);
} elseif ($this->isRequestActive($tag, self::FILTER_CALLBACK)) {
return new ResponseCollection(array());
} elseif ($this->isRequestActive($tag, self::FILTER_BUFFER)) {
$result = $this->responseBuffer[$tag];
if (!empty($result)) {
if (end($result)->getType() === Response::TYPE_FINAL) {
unset($this->responseBuffer[$tag]);
} else {
$this->responseBuffer[$tag] = array();
}
}
return new ResponseCollection($result);
} else {
throw new DataFlowException(
'No such request, or the request has already finished.',
DataFlowException::CODE_UNKNOWN_REQUEST
);
}
}
/**
* Starts an event loop for the RouterOS callbacks.
*
* Starts an event loop for the RouterOS callbacks and finishes when there
* are no more pending requests or when a specified timeout has passed
* (whichever comes first).
*
* @param int $sTimeout Timeout for the loop. If NULL, there is no time
* limit.
* @param int $usTimeout Microseconds to add to the time limit.
*
* @return bool TRUE when there are any more pending requests, FALSE
* otherwise.
* @see extractNewResponses()
* @see getPendingRequestsCount()
*/
public function loop($sTimeout = null, $usTimeout = 0)
{
try {
if (null === $sTimeout) {
while ($this->getPendingRequestsCount() !== 0) {
$this->dispatchNextResponse(null);
}
} else {
list($usStart, $sStart) = explode(' ', microtime());
while ($this->getPendingRequestsCount() !== 0
&& ($sTimeout >= 0 || $usTimeout >= 0)
) {
$this->dispatchNextResponse($sTimeout, $usTimeout);
list($usEnd, $sEnd) = explode(' ', microtime());
$sTimeout -= $sEnd - $sStart;
$usTimeout -= $usEnd - $usStart;
if ($usTimeout <= 0) {
if ($sTimeout > 0) {
$usTimeout = 1000000 + $usTimeout;
$sTimeout--;
}
}
$sStart = $sEnd;
$usStart = $usEnd;
}
}
} catch (SocketException $e) {
if ($e->getCode() !== SocketException::CODE_NO_DATA) {
// @codeCoverageIgnoreStart
// It's impossible to reliably cause any other SocketException.
// This line is only here in case the unthinkable happens:
// The connection terminates just after it was supposedly
// about to send back some data.
throw $e;
// @codeCoverageIgnoreEnd
}
}
return $this->getPendingRequestsCount() !== 0;
}
/**
* Gets the number of pending requests.
*
* @return int The number of pending requests.
* @see isRequestActive()
*/
public function getPendingRequestsCount()
{
return $this->pendingRequestsCount;
}
/**
* Cancels a request.
*
* Cancels an active request. Using this function in favor of a plain call
* to the "/cancel" command is highly reccomended, as it also updates the
* counter of pending requests properly. Note that canceling a request also
* removes any responses for it that were not previously extracted with
* {@link static::extractNewResponses()}.
*
* @param string $tag Tag of the request to cancel. Setting NULL will cancel
* all requests.
*
* @return $this The client object.
* @see sendAsync()
* @see close()
*/
public function cancelRequest($tag = null)
{
$cancelRequest = new Request('/cancel');
$hasTag = !('' == $tag);
$hasReg = null !== $this->registry;
if ($hasReg && !$hasTag) {
$tags = array_merge(
array_keys($this->responseBuffer),
array_keys($this->callbacks)
);
$this->registry->setTaglessMode(true);
foreach ($tags as $t) {
$cancelRequest->setArgument(
'tag',
$this->registry->getOwnershipTag() . $t
);
$this->sendSync($cancelRequest);
}
$this->registry->setTaglessMode(false);
} else {
if ($hasTag) {
if ($this->isRequestActive($tag)) {
if ($hasReg) {
$this->registry->setTaglessMode(true);
$cancelRequest->setArgument(
'tag',
$this->registry->getOwnershipTag() . $tag
);
} else {
$cancelRequest->setArgument('tag', $tag);
}
} else {
throw new DataFlowException(
'No such request. Canceling aborted.',
DataFlowException::CODE_CANCEL_FAIL
);
}
}
$this->sendSync($cancelRequest);
if ($hasReg) {
$this->registry->setTaglessMode(false);
}
}
if ($hasTag) {
if ($this->isRequestActive($tag, self::FILTER_BUFFER)) {
$this->responseBuffer[$tag] = $this->completeRequest($tag);
} else {
$this->completeRequest($tag);
}
} else {
$this->loop();
}
return $this;
}
/**
* Sets response streaming setting.
*
* Sets whether future responses are streamed. If responses are streamed,
* the argument values are returned as streams instead of strings. This is
* particularly useful if you expect a response that may contain one or more
* very large words.
*
* @param bool $streamingResponses Whether to stream future responses.
*
* @return bool The previous value of the setting.
* @see isStreamingResponses()
*/
public function setStreamingResponses($streamingResponses)
{
$oldValue = $this->_streamingResponses;
$this->_streamingResponses = (bool) $streamingResponses;
return $oldValue;
}
/**
* Gets response streaming setting.
*
* Gets whether future responses are streamed.
*
* @return bool The value of the setting.
* @see setStreamingResponses()
*/
public function isStreamingResponses()
{
return $this->_streamingResponses;
}
/**
* Closes the opened connection, even if it is a persistent one.
*
* Closes the opened connection, even if it is a persistent one. Note that
* {@link static::extractNewResponses()} can still be used to extract
* responses collected prior to the closing.
*
* @return bool TRUE on success, FALSE on failure.
*/
public function close()
{
$result = true;
/*
* The check below is done because for some unknown reason
* (either a PHP or a RouterOS bug) calling "/quit" on an encrypted
* connection makes one end hang.
*
* Since encrypted connections only appeared in RouterOS 6.1, and
* the "/quit" call is needed for all <6.0 versions, problems due
* to its absence should be limited to some earlier 6.* versions
* on some RouterBOARD devices.
*/
if ($this->com->getTransmitter()->getCrypto() === N::CRYPTO_OFF) {
if (null !== $this->registry) {
$this->registry->setTaglessMode(true);
}
try {
$response = $this->sendSync(new Request('/quit'));
$result = $response[0]->getType() === Response::TYPE_FATAL;
} catch (SocketException $e) {
$result
= $e->getCode() === SocketException::CODE_REQUEST_SEND_FAIL;
} catch (E $e) {
//Ignore unknown errors.
}
if (null !== $this->registry) {
$this->registry->setTaglessMode(false);
}
}
$result = $result && $this->com->close();
$this->callbacks = array();
$this->pendingRequestsCount = 0;
return $result;
}
/**
* Closes the connection, unless it's a persistent one.
*/
public function __destruct()
{
if ($this->com->getTransmitter()->isPersistent()) {
if (0 !== $this->pendingRequestsCount) {
$this->cancelRequest();
}
} else {
$this->close();
}
}
/**
* Sends a request to RouterOS.
*
* @param Request $request The request to send.
*
* @return $this The client object.
* @see sendSync()
* @see sendAsync()
*/
protected function send(Request $request)
{
$request->send($this->com, $this->registry);
$this->pendingRequestsCount++;
return $this;
}
/**
* Dispatches the next response in queue.
*
* Dispatches the next response in queue, i.e. it executes the associated
* callback if there is one, or places the response in the response buffer.
*
* @param int $sTimeout If a response is not immediatly available, wait
* this many seconds. If NULL, wait indefinetly.
* @param int $usTimeout Microseconds to add to the waiting time.
*
* @throws SocketException When there's no response within the time limit.
* @return Response The dispatched response.
*/
protected function dispatchNextResponse($sTimeout = 0, $usTimeout = 0)
{
$response = new Response(
$this->com,
$this->_streamingResponses,
$sTimeout,
$usTimeout,
$this->registry
);
if ($response->getType() === Response::TYPE_FATAL) {
$this->pendingRequestsCount = 0;
$this->com->close();
return $response;
}
$tag = $response->getTag();
$isLastForRequest = $response->getType() === Response::TYPE_FINAL;
if ($isLastForRequest) {
$this->pendingRequestsCount--;
}
if ('' != $tag) {
if ($this->isRequestActive($tag, self::FILTER_CALLBACK)) {
if ($this->callbacks[$tag]($response, $this)) {
$this->cancelRequest($tag);
} elseif ($isLastForRequest) {
unset($this->callbacks[$tag]);
}
} else {
$this->responseBuffer[$tag][] = $response;
}
}
return $response;
}
}

View file

@ -0,0 +1,671 @@
<?php
/**
* RouterOS API client implementation.
*
* RouterOS is the flag product of the company MikroTik and is a powerful router software. One of its many abilities is to allow control over it via an API. This package provides a client for that API, in turn allowing you to use PHP to control RouterOS hosts.
*
* PHP version 5
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0b5
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
/**
* The namespace declaration.
*/
namespace PEAR2\Net\RouterOS;
/**
* Using transmitters.
*/
use PEAR2\Net\Transmitter as T;
/**
* A RouterOS communicator.
*
* Implementation of the RouterOS API protocol. Unlike the other classes in this
* package, this class doesn't provide any conviniences beyond the low level
* implementation details (automatic word length encoding/decoding, charset
* translation and data integrity), and because of that, its direct usage is
* strongly discouraged.
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear2.php.net/PEAR2_Net_RouterOS
* @see Client
*/
class Communicator
{
/**
* Used when getting/setting all (default) charsets.
*/
const CHARSET_ALL = -1;
/**
* Used when getting/setting the (default) remote charset.
*
* The remote charset is the charset in which RouterOS stores its data.
* If you want to keep compatibility with your Winbox, this charset should
* match the default charset from your Windows' regional settings.
*/
const CHARSET_REMOTE = 0;
/**
* Used when getting/setting the (default) local charset.
*
* The local charset is the charset in which the data from RouterOS will be
* returned as. This charset should match the charset of the place the data
* will eventually be written to.
*/
const CHARSET_LOCAL = 1;
/**
* @var array An array with the default charset types as keys, and the
* default charsets as values.
*/
protected static $defaultCharsets = array(
self::CHARSET_REMOTE => null,
self::CHARSET_LOCAL => null
);
/**
* @var array An array with the current charset types as keys, and the
* current charsets as values.
*/
protected $charsets = array();
/**
* @var T\TcpClient The transmitter for the connection.
*/
protected $trans;
/**
* Creates a new connection with the specified options.
*
* @param string $host Hostname (IP or domain) of the RouterOS server.
* @param int|null $port The port on which the RouterOS server provides
* the API service. You can also specify NULL, in which case the port
* will automatically be chosen between 8728 and 8729, depending on the
* value of $crypto.
* @param bool $persist Whether or not the connection should be a
* persistent one.
* @param float $timeout The timeout for the connection.
* @param string $key A string that uniquely identifies the
* connection.
* @param string $crypto The encryption for this connection. Must be one
* of the PEAR2\Net\Transmitter\NetworkStream::CRYPTO_* constants. Off
* by default. RouterOS currently supports only TLS, but the setting is
* provided in this fashion for forward compatibility's sake. And for
* the sake of simplicity, if you specify an encryption, don't specify a
* context and your default context uses the value "DEFAULT" for
* ciphers, "ADH" will be automatically added to the list of ciphers.
* @param resource $context A context for the socket.
*
* @see sendWord()
*/
public function __construct(
$host,
$port = 8728,
$persist = false,
$timeout = null,
$key = '',
$crypto = T\NetworkStream::CRYPTO_OFF,
$context = null
) {
$isUnencrypted = T\NetworkStream::CRYPTO_OFF === $crypto;
if (($context === null) && !$isUnencrypted) {
$context = stream_context_get_default();
$opts = stream_context_get_options($context);
if (!isset($opts['ssl']['ciphers'])
|| 'DEFAULT' === $opts['ssl']['ciphers']
) {
stream_context_set_option($context, 'ssl', 'ciphers', 'ADH');
}
}
// @codeCoverageIgnoreStart
// The $port is customizable in testing.
if (null === $port) {
$port = $isUnencrypted ? 8728 : 8729;
}
// @codeCoverageIgnoreEnd
try {
$this->trans = new T\TcpClient(
$host,
$port,
$persist,
$timeout,
$key,
$crypto,
$context
);
} catch (T\Exception $e) {
throw new SocketException(
'Error connecting to RouterOS',
SocketException::CODE_CONNECTION_FAIL,
$e
);
}
$this->setCharset(
self::getDefaultCharset(self::CHARSET_ALL),
self::CHARSET_ALL
);
}
/**
* A shorthand gateway.
*
* This is a magic PHP method that allows you to call the object as a
* function. Depending on the argument given, one of the other functions in
* the class is invoked and its returned value is returned by this function.
*
* @param string $string A string of the word to send, or NULL to get the
* next word as a string.
*
* @return int|string If a string is provided, returns the number of bytes
* sent, otherwise retuns the next word as a string.
*/
public function __invoke($string = null)
{
return null === $string ? $this->getNextWord()
: $this->sendWord($string);
}
/**
* Checks whether a variable is a seekable stream resource.
*
* @param mixed $var The value to check.
*
* @return bool TRUE if $var is a seekable stream, FALSE otherwise.
*/
public static function isSeekableStream($var)
{
if (T\Stream::isStream($var)) {
$meta = stream_get_meta_data($var);
return $meta['seekable'];
}
return false;
}
/**
* Uses iconv to convert a stream from one charset to another.
*
* @param string $inCharset The charset of the stream.
* @param string $outCharset The desired resulting charset.
* @param resource $stream The stream to convert. The stream is assumed
* to be seekable, and is read from its current position to its end,
* after which, it is seeked back to its starting position.
*
* @return resource A new stream that uses the $out_charset. The stream is a
* subset from the original stream, from its current position to its
* end, seeked at its start.
*/
public static function iconvStream($inCharset, $outCharset, $stream)
{
$bytes = 0;
$result = fopen('php://temp', 'r+b');
$iconvFilter = stream_filter_append(
$result,
'convert.iconv.' . $inCharset . '.' . $outCharset,
STREAM_FILTER_WRITE
);
flock($stream, LOCK_SH);
while (!feof($stream)) {
$bytes += stream_copy_to_stream($stream, $result, 0xFFFFF);
}
fseek($stream, -$bytes, SEEK_CUR);
flock($stream, LOCK_UN);
stream_filter_remove($iconvFilter);
rewind($result);
return $result;
}
/**
* Sets the default charset(s) for new connections.
*
* @param mixed $charset The charset to set. If $charsetType is
* {@link self::CHARSET_ALL}, you can supply either a string to use for
* all charsets, or an array with the charset types as keys, and the
* charsets as values.
* @param int $charsetType Which charset to set. Valid values are the
* CHARSET_* constants. Any other value is treated as
* {@link self::CHARSET_ALL}.
*
* @return string|array The old charset. If $charsetType is
* {@link self::CHARSET_ALL}, the old values will be returned as an
* array with the types as keys, and charsets as values.
* @see setCharset()
*/
public static function setDefaultCharset(
$charset,
$charsetType = self::CHARSET_ALL
) {
if (array_key_exists($charsetType, self::$defaultCharsets)) {
$oldCharset = self::$defaultCharsets[$charsetType];
self::$defaultCharsets[$charsetType] = $charset;
return $oldCharset;
} else {
$oldCharsets = self::$defaultCharsets;
self::$defaultCharsets = is_array($charset) ? $charset : array_fill(
0,
count(self::$defaultCharsets),
$charset
);
return $oldCharsets;
}
}
/**
* Gets the default charset(s).
*
* @param int $charsetType Which charset to get. Valid values are the
* CHARSET_* constants. Any other value is treated as
* {@link self::CHARSET_ALL}.
*
* @return string|array The current charset. If $charsetType is
* {@link self::CHARSET_ALL}, the current values will be returned as an
* array with the types as keys, and charsets as values.
* @see setDefaultCharset()
*/
public static function getDefaultCharset($charsetType)
{
return array_key_exists($charsetType, self::$defaultCharsets)
? self::$defaultCharsets[$charsetType] : self::$defaultCharsets;
}
/**
* Gets the length of a seekable stream.
*
* Gets the length of a seekable stream.
*
* @param resource $stream The stream to check. The stream is assumed to be
* seekable.
*
* @return double The number of bytes in the stream between its current
* position and its end.
*/
public static function seekableStreamLength($stream)
{
$streamPosition = (double) sprintf('%u', ftell($stream));
fseek($stream, 0, SEEK_END);
$streamLength = ((double) sprintf('%u', ftell($stream)))
- $streamPosition;
fseek($stream, $streamPosition, SEEK_SET);
return $streamLength;
}
/**
* Sets the charset(s) for this connection.
*
* Sets the charset(s) for this connection. The specified charset(s) will be
* used for all future words. When sending, {@link self::CHARSET_LOCAL} is
* converted to {@link self::CHARSET_REMOTE}, and when receiving,
* {@link self::CHARSET_REMOTE} is converted to {@link self::CHARSET_LOCAL}.
* Setting NULL to either charset will disable charset convertion, and data
* will be both sent and received "as is".
*
* @param mixed $charset The charset to set. If $charsetType is
* {@link self::CHARSET_ALL}, you can supply either a string to use for
* all charsets, or an array with the charset types as keys, and the
* charsets as values.
* @param int $charsetType Which charset to set. Valid values are the
* CHARSET_* constants. Any other value is treated as
* {@link self::CHARSET_ALL}.
*
* @return string|array The old charset. If $charsetType is
* {@link self::CHARSET_ALL}, the old values will be returned as an
* array with the types as keys, and charsets as values.
* @see setDefaultCharset()
*/
public function setCharset($charset, $charsetType = self::CHARSET_ALL)
{
if (array_key_exists($charsetType, $this->charsets)) {
$oldCharset = $this->charsets[$charsetType];
$this->charsets[$charsetType] = $charset;
return $oldCharset;
} else {
$oldCharsets = $this->charsets;
$this->charsets = is_array($charset) ? $charset : array_fill(
0,
count($this->charsets),
$charset
);
return $oldCharsets;
}
}
/**
* Gets the charset(s) for this connection.
*
* @param int $charsetType Which charset to get. Valid values are the
* CHARSET_* constants. Any other value is treated as
* {@link self::CHARSET_ALL}.
*
* @return string|array The current charset. If $charsetType is
* {@link self::CHARSET_ALL}, the current values will be returned as an
* array with the types as keys, and charsets as values.
* @see getDefaultCharset()
* @see setCharset()
*/
public function getCharset($charsetType)
{
return array_key_exists($charsetType, $this->charsets)
? $this->charsets[$charsetType] : $this->charsets;
}
/**
* Gets the transmitter for this connection.
*
* @return T\TcpClient The transmitter for this connection.
*/
public function getTransmitter()
{
return $this->trans;
}
/**
* Sends a word.
*
* Sends a word and automatically encodes its length when doing so.
*
* @param string $word The word to send.
*
* @return int The number of bytes sent.
* @see sendWordFromStream()
* @see getNextWord()
*/
public function sendWord($word)
{
if (null !== ($remoteCharset = $this->getCharset(self::CHARSET_REMOTE))
&& null !== ($localCharset = $this->getCharset(self::CHARSET_LOCAL))
) {
$word = iconv(
$localCharset,
$remoteCharset . '//IGNORE//TRANSLIT',
$word
);
}
$length = strlen($word);
static::verifyLengthSupport($length);
if ($this->trans->isPersistent()) {
$old = $this->trans->lock(T\Stream::DIRECTION_SEND);
$bytes = $this->trans->send(self::encodeLength($length) . $word);
$this->trans->lock($old, true);
return $bytes;
}
return $this->trans->send(self::encodeLength($length) . $word);
}
/**
* Sends a word based on a stream.
*
* Sends a word based on a stream and automatically encodes its length when
* doing so. The stream is read from its current position to its end, and
* then returned to its current position. Because of those operations, the
* supplied stream must be seekable.
*
* @param string $prefix A string to prepend before the stream contents.
* @param resource $stream The seekable stream to send.
*
* @return int The number of bytes sent.
* @see sendWord()
*/
public function sendWordFromStream($prefix, $stream)
{
if (!self::isSeekableStream($stream)) {
throw new InvalidArgumentException(
'The stream must be seekable.',
InvalidArgumentException::CODE_SEEKABLE_REQUIRED
);
}
if (null !== ($remoteCharset = $this->getCharset(self::CHARSET_REMOTE))
&& null !== ($localCharset = $this->getCharset(self::CHARSET_LOCAL))
) {
$prefix = iconv(
$localCharset,
$remoteCharset . '//IGNORE//TRANSLIT',
$prefix
);
$stream = self::iconvStream(
$localCharset,
$remoteCharset . '//IGNORE//TRANSLIT',
$stream
);
}
flock($stream, LOCK_SH);
$totalLength = strlen($prefix) + self::seekableStreamLength($stream);
static::verifyLengthSupport($totalLength);
$bytes = $this->trans->send(self::encodeLength($totalLength) . $prefix);
$bytes += $this->trans->send($stream);
flock($stream, LOCK_UN);
return $bytes;
}
/**
* Verifies that the length is supported.
*
* Verifies if the specified length is supported by the API. Throws a
* {@link LengthException} if that's not the case. Currently, RouterOS
* supports words up to 0xFFFFFFFF in length, so that's the only check
* performed.
*
* @param int $length The length to verify.
*
* @return void
*/
protected static function verifyLengthSupport($length)
{
if ($length > 0xFFFFFFFF) {
throw new LengthException(
'Words with length above 0xFFFFFFFF are not supported.',
LengthException::CODE_UNSUPPORTED,
null,
$length
);
}
}
/**
* Encodes the length as requred by the RouterOS API.
*
* @param int $length The length to encode.
*
* @return string The encoded length.
*/
public static function encodeLength($length)
{
if ($length < 0) {
throw new LengthException(
'Length must not be negative.',
LengthException::CODE_INVALID,
null,
$length
);
} elseif ($length < 0x80) {
return chr($length);
} elseif ($length < 0x4000) {
return pack('n', $length |= 0x8000);
} elseif ($length < 0x200000) {
$length |= 0xC00000;
return pack('n', $length >> 8) . chr($length & 0xFF);
} elseif ($length < 0x10000000) {
return pack('N', $length |= 0xE0000000);
} elseif ($length <= 0xFFFFFFFF) {
return chr(0xF0) . pack('N', $length);
} elseif ($length <= 0x7FFFFFFFF) {
$length = 'f' . base_convert($length, 10, 16);
return chr(hexdec(substr($length, 0, 2))) .
pack('N', hexdec(substr($length, 2)));
}
throw new LengthException(
'Length must not be above 0x7FFFFFFFF.',
LengthException::CODE_BEYOND_SHEME,
null,
$length
);
}
/**
* Get the next word in queue as a string.
*
* Get the next word in queue as a string, after automatically decoding its
* length.
*
* @return string The word.
* @see close()
*/
public function getNextWord()
{
if ($this->trans->isPersistent()) {
$old = $this->trans->lock(T\Stream::DIRECTION_RECEIVE);
$word = $this->trans->receive(
self::decodeLength($this->trans),
'word'
);
$this->trans->lock($old, true);
} else {
$word = $this->trans->receive(
self::decodeLength($this->trans),
'word'
);
}
if (null !== ($remoteCharset = $this->getCharset(self::CHARSET_REMOTE))
&& null !== ($localCharset = $this->getCharset(self::CHARSET_LOCAL))
) {
$word = iconv(
$remoteCharset,
$localCharset . '//IGNORE//TRANSLIT',
$word
);
}
return $word;
}
/**
* Get the next word in queue as a stream.
*
* Get the next word in queue as a stream, after automatically decoding its
* length.
*
* @return resource The word, as a stream.
* @see close()
*/
public function getNextWordAsStream()
{
$filters = new T\FilterCollection();
if (null !== ($remoteCharset = $this->getCharset(self::CHARSET_REMOTE))
&& null !== ($localCharset = $this->getCharset(self::CHARSET_LOCAL))
) {
$filters->append(
'convert.iconv.' .
$remoteCharset . '.' . $localCharset . '//IGNORE//TRANSLIT'
);
}
if ($this->trans->isPersistent()) {
$old = $this->trans->lock(T\Stream::DIRECTION_RECEIVE);
$stream = $this->trans->receiveStream(
self::decodeLength($this->trans),
$filters,
'stream word'
);
$this->trans->lock($old, true);
} else {
$stream = $this->trans->receiveStream(
self::decodeLength($this->trans),
$filters,
'stream word'
);
}
return $stream;
}
/**
* Decodes the lenght of the incoming message.
*
* Decodes the lenght of the incoming message, as specified by the RouterOS
* API.
*
* @param T\Stream $trans The transmitter from which to decode the length of
* the incoming message.
*
* @return int The decoded length.
*/
public static function decodeLength(T\Stream $trans)
{
if ($trans->isPersistent() && $trans instanceof T\TcpClient) {
$old = $trans->lock($trans::DIRECTION_RECEIVE);
$length = self::_decodeLength($trans);
$trans->lock($old, true);
return $length;
}
return self::_decodeLength($trans);
}
/**
* Decodes the lenght of the incoming message.
*
* Decodes the lenght of the incoming message, as specified by the RouterOS
* API.
*
* Difference with the non private function is that this one doesn't perform
* locking if the connection is a persistent one.
*
* @param T\Stream $trans The transmitter from which to decode the length of
* the incoming message.
*
* @return int The decoded length.
*/
private static function _decodeLength(T\Stream $trans)
{
$byte = ord($trans->receive(1, 'initial length byte'));
if ($byte & 0x80) {
if (($byte & 0xC0) === 0x80) {
return (($byte & 077) << 8 ) + ord($trans->receive(1));
} elseif (($byte & 0xE0) === 0xC0) {
$rem = unpack('n~', $trans->receive(2));
return (($byte & 037) << 16 ) + $rem['~'];
} elseif (($byte & 0xF0) === 0xE0) {
$rem = unpack('n~/C~~', $trans->receive(3));
return (($byte & 017) << 24 ) + ($rem['~'] << 8) + $rem['~~'];
} elseif (($byte & 0xF8) === 0xF0) {
$rem = unpack('N~', $trans->receive(4));
return (($byte & 007) * 0x100000000/* '<< 32' or '2^32' */)
+ (double) sprintf('%u', $rem['~']);
}
throw new NotSupportedException(
'Unknown control byte encountered.',
NotSupportedException::CODE_CONTROL_BYTE,
null,
$byte
);
} else {
return $byte;
}
}
/**
* Closes the opened connection, even if it is a persistent one.
*
* @return bool TRUE on success, FALSE on failure.
*/
public function close()
{
return $this->trans->close();
}
}

View file

@ -0,0 +1,44 @@
<?php
/**
* RouterOS API client implementation.
*
* RouterOS is the flag product of the company MikroTik and is a powerful router software. One of its many abilities is to allow control over it via an API. This package provides a client for that API, in turn allowing you to use PHP to control RouterOS hosts.
*
* PHP version 5
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0b5
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
/**
* The namespace declaration.
*/
namespace PEAR2\Net\RouterOS;
/**
* Base of this class.
*/
use RuntimeException;
/**
* Exception thrown when the request/response cycle goes an unexpected way.
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
class DataFlowException extends RuntimeException implements Exception
{
const CODE_INVALID_CREDENTIALS = 10000;
const CODE_TAG_REQUIRED = 10500;
const CODE_TAG_UNIQUE = 10501;
const CODE_UNKNOWN_REQUEST = 10900;
const CODE_CANCEL_FAIL = 11200;
}

View file

@ -0,0 +1,34 @@
<?php
/**
* RouterOS API client implementation.
*
* RouterOS is the flag product of the company MikroTik and is a powerful router software. One of its many abilities is to allow control over it via an API. This package provides a client for that API, in turn allowing you to use PHP to control RouterOS hosts.
*
* PHP version 5
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0b5
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
/**
* The namespace declaration.
*/
namespace PEAR2\Net\RouterOS;
/**
* Generic exception class of this package.
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
interface Exception
{
}

View file

@ -0,0 +1,43 @@
<?php
/**
* RouterOS API client implementation.
*
* RouterOS is the flag product of the company MikroTik and is a powerful router software. One of its many abilities is to allow control over it via an API. This package provides a client for that API, in turn allowing you to use PHP to control RouterOS hosts.
*
* PHP version 5
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0b5
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
/**
* The namespace declaration.
*/
namespace PEAR2\Net\RouterOS;
use InvalidArgumentException as I;
/**
* Exception thrown when there's something wrong with message arguments.
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
class InvalidArgumentException extends I implements Exception
{
const CODE_SEEKABLE_REQUIRED = 1100;
const CODE_NAME_INVALID = 20100;
const CODE_ABSOLUTE_REQUIRED = 40200;
const CODE_CMD_UNRESOLVABLE = 40201;
const CODE_CMD_INVALID = 40202;
const CODE_NAME_UNPARSABLE = 41000;
const CODE_VALUE_UNPARSABLE = 41001;
}

View file

@ -0,0 +1,93 @@
<?php
/**
* RouterOS API client implementation.
*
* RouterOS is the flag product of the company MikroTik and is a powerful router software. One of its many abilities is to allow control over it via an API. This package provides a client for that API, in turn allowing you to use PHP to control RouterOS hosts.
*
* PHP version 5
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0b5
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
/**
* The namespace declaration.
*/
namespace PEAR2\Net\RouterOS;
/**
* Base of this class.
*/
use LengthException as L;
/**
* Exception thrown when there is a problem with a word's length.
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
class LengthException extends L implements Exception
{
const CODE_UNSUPPORTED = 1200;
const CODE_INVALID = 1300;
const CODE_BEYOND_SHEME = 1301;
/**
*
* @var mixed The problematic length.
*/
private $_length;
/**
* Creates a new LengthException.
*
* @param string $message The Exception message to throw.
* @param int $code The Exception code.
* @param \Exception $previous The previous exception used for the exception
* chaining.
* @param number $length The length.
*/
public function __construct(
$message,
$code = 0,
$previous = null,
$length = null
) {
parent::__construct($message, $code, $previous);
$this->_length = $length;
}
/**
* Gets the length.
*
* @return number The length.
*/
public function getLength()
{
return $this->_length;
}
// @codeCoverageIgnoreStart
// String representation is not reliable in testing
/**
* Returns a string representation of the exception.
*
* @return string The exception as a string.
*/
public function __toString()
{
return parent::__toString() . "\nLength:{$this->_length}";
}
// @codeCoverageIgnoreEnd
}

View file

@ -0,0 +1,237 @@
<?php
/**
* RouterOS API client implementation.
*
* RouterOS is the flag product of the company MikroTik and is a powerful router software. One of its many abilities is to allow control over it via an API. This package provides a client for that API, in turn allowing you to use PHP to control RouterOS hosts.
*
* PHP version 5
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0b5
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
/**
* The namespace declaration.
*/
namespace PEAR2\Net\RouterOS;
/**
* Implements this interface.
*/
use Countable;
/**
* Implements this interface.
*/
use IteratorAggregate;
/**
* Requred for IteratorAggregate::getIterator() to work properly with foreach.
*/
use ArrayObject;
/**
* Represents a RouterOS message.
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
abstract class Message implements IteratorAggregate, Countable
{
/**
* @var array An array with message attributes. Each array key is the the
* name of an attribute, and the correspding array value is the value
* for that attribute.
*/
protected $attributes = array();
/**
* @var string An optional tag to associate the message with.
*/
private $_tag = null;
/**
* A shorthand gateway.
*
* This is a magic PHP method that allows you to call the object as a
* function. Depending on the argument given, one of the other functions in
* the class is invoked and its returned value is returned by this function.
*
* @param string $name The name of an attribute to get the value of, or NULL
* to get the tag.
*
* @return string|resource The value of the specified attribute,
* or the tag if NULL is provided.
*/
public function __invoke($name = null)
{
if (null === $name) {
return $this->getTag();
}
return $this->getAttribute($name);
}
/**
* Sanitizes a name of an attribute (message or query one).
*
* @param mixed $name The name to sanitize.
*
* @return string The sanitized name.
*/
public static function sanitizeAttributeName($name)
{
$name = (string) $name;
if ((empty($name) && $name !== '0')
|| preg_match('/[=\s]/s', $name)
) {
throw new InvalidArgumentException(
'Invalid name of argument supplied.',
InvalidArgumentException::CODE_NAME_INVALID
);
}
return $name;
}
/**
* Sanitizes a value of an attribute (message or query one).
*
* @param mixed $value The value to sanitize.
*
* @return string The sanitized value.
*/
public static function sanitizeAttributeValue($value)
{
if (Communicator::isSeekableStream($value)) {
return $value;
} else {
return (string) $value;
}
}
/**
* Gets the tag that the message is associated with.
*
* @return string The current tag or NULL if there isn't a tag.
* @see setTag()
*/
public function getTag()
{
return $this->_tag;
}
/**
* Sets the tag to associate the request with.
*
* Sets the tag to associate the message with. Setting NULL erases the
* currently set tag.
*
* @param string $tag The tag to set.
*
* @return $this The message object.
* @see getTag()
*/
protected function setTag($tag)
{
$this->_tag = (null === $tag) ? null : (string) $tag;
return $this;
}
/**
* Gets the value of an attribute.
*
* @param string $name The name of the attribute.
*
* @return string|resource|null The value of the specified attribute.
* Returns NULL if such an attribute is not set.
* @see setAttribute()
*/
protected function getAttribute($name)
{
$name = self::sanitizeAttributeName($name);
if (array_key_exists($name, $this->attributes)) {
return $this->attributes[$name];
}
return null;
}
/**
* Gets all arguments in an array.
*
* @return ArrayObject An ArrayObject with the keys being argument names,
* and the array values being argument values.
* @see getArgument()
* @see setArgument()
*/
public function getIterator()
{
return new ArrayObject($this->attributes);
}
/**
* Counts the number of arguments.
*
* @param int $mode The counter mode.
* Either COUNT_NORMAL or COUNT_RECURSIVE.
* When in normal mode, counts the number of arguments.
* When in recursive mode, counts the number of API words
* (including the empty word at the end).
*
* @return int The number of arguments/words.
*/
public function count($mode = COUNT_NORMAL)
{
$result = count($this->attributes);
if ($mode !== COUNT_NORMAL) {
$result += 2/*first+last word*/
+ (int)(null !== $this->getTag());
}
return $result;
}
/**
* Sets an attribute for the message.
*
* @param string $name Name of the attribute.
* @param string|resource|null $value Value of the attribute as a string or
* seekable stream.
* Setting the value to NULL removes an argument of this name.
* If a seekable stream is provided, it is sent from its current
* posistion to its end, and the pointer is seeked back to its current
* position after sending.
* Non seekable streams, as well as all other types, are casted to a
* string.
*
* @return $this The message object.
* @see getArgument()
*/
protected function setAttribute($name, $value = '')
{
if (null === $value) {
unset($this->attributes[self::sanitizeAttributeName($name)]);
} else {
$this->attributes[self::sanitizeAttributeName($name)]
= self::sanitizeAttributeValue($value);
}
return $this;
}
/**
* Removes all attributes from the message.
*
* @return $this The message object.
*/
protected function removeAllAttributes()
{
$this->attributes = array();
return $this;
}
}

View file

@ -0,0 +1,91 @@
<?php
/**
* RouterOS API client implementation.
*
* RouterOS is the flag product of the company MikroTik and is a powerful router software. One of its many abilities is to allow control over it via an API. This package provides a client for that API, in turn allowing you to use PHP to control RouterOS hosts.
*
* PHP version 5
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0b5
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
/**
* The namespace declaration.
*/
namespace PEAR2\Net\RouterOS;
/**
* Base of this class.
*/
use Exception as E;
/**
* Exception thrown when encountering something not supported by RouterOS or
* this package.
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
class NotSupportedException extends E implements Exception
{
const CODE_CONTROL_BYTE = 1601;
/**
* @var mixed The unsuppported value.
*/
private $_value;
/**
* Creates a new NotSupportedException.
*
* @param string $message The Exception message to throw.
* @param int $code The Exception code.
* @param \Exception $previous The previous exception used for the exception
* chaining.
* @param mixed $value The unsupported value.
*/
public function __construct(
$message,
$code = 0,
$previous = null,
$value = null
) {
parent::__construct($message, $code, $previous);
$this->_value = $value;
}
/**
* Gets the unsupported value.
*
* @return mixed The unsupported value.
*/
public function getValue()
{
return $this->_value;
}
// @codeCoverageIgnoreStart
// String representation is not reliable in testing
/**
* Returns a string representation of the exception.
*
* @return string The exception as a string.
*/
public function __toString()
{
return parent::__toString() . "\nValue:{$this->_value}";
}
// @codeCoverageIgnoreEnd
}

View file

@ -0,0 +1,267 @@
<?php
/**
* RouterOS API client implementation.
*
* RouterOS is the flag product of the company MikroTik and is a powerful router software. One of its many abilities is to allow control over it via an API. This package provides a client for that API, in turn allowing you to use PHP to control RouterOS hosts.
*
* PHP version 5
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0b5
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
/**
* The namespace declaration.
*/
namespace PEAR2\Net\RouterOS;
/**
* Refers to transmitter direction constants.
*/
use PEAR2\Net\Transmitter as T;
/**
* Represents a query for RouterOS requests.
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
class Query
{
/**
* Checks if the property exists.
*/
const OP_EX = '';
/**
* Checks if the property does not exist.
*/
const OP_NEX = '-';
/**
* Checks if the property equals a certain value.
*/
const OP_EQ = '=';
/**
* Checks if the property is less than a certain value.
*/
const OP_LT = '<';
/**
* Checks if the property is greather than a certain value.
*/
const OP_GT = '>';
/**
* @var array An array of the words forming the query. Each value is an
* array with the first member being the predicate (operator and name),
* and the second member being the value for the predicate.
*/
protected $words = array();
/**
* This class is not to be instantiated normally, but by static methods
* instead. Use {@link static::where()} to create an instance of it.
*/
private function __construct()
{
}
/**
* Sanitizes the operator of a condition.
*
* @param string $operator The operator to sanitize.
*
* @return string The sanitized operator.
*/
protected static function sanitizeOperator($operator)
{
$operator = (string) $operator;
switch ($operator) {
case Query::OP_EX:
case Query::OP_NEX:
case Query::OP_EQ:
case Query::OP_LT:
case Query::OP_GT:
return $operator;
default:
throw new UnexpectedValueException(
'Unknown operator specified',
UnexpectedValueException::CODE_ACTION_UNKNOWN,
null,
$operator
);
}
}
/**
* Creates a new query with an initial condition.
*
* @param string $name The name of the property to test.
* @param string|resource|null $value Value of the property as a string
* or seekable stream. Not required for existence tests.
* If a seekable stream is provided, it is sent from its current
* posistion to its end, and the pointer is seeked back to its current
* position after sending.
* Non seekable streams, as well as all other types, are casted to a
* string.
* @param string $operator One of the OP_* constants.
* Describes the operation to perform.
*
* @return static A new query object.
*/
public static function where(
$name,
$value = null,
$operator = self::OP_EX
) {
$query = new static;
return $query->addWhere($name, $value, $operator);
}
/**
* Negates the query.
*
* @return $this The query object.
*/
public function not()
{
$this->words[] = array('#!', null);
return $this;
}
/**
* Adds a condition as an alternative to the query.
*
* @param string $name The name of the property to test.
* @param string|resource|null $value Value of the property as a string
* or seekable stream. Not required for existence tests.
* If a seekable stream is provided, it is sent from its current
* posistion to its end, and the pointer is seeked back to its current
* position after sending.
* Non seekable streams, as well as all other types, are casted to a
* string.
* @param string $operator One of the OP_* constants.
* Describes the operation to perform.
*
* @return $this The query object.
*/
public function orWhere($name, $value = null, $operator = self::OP_EX)
{
$this->addWhere($name, $value, $operator)->words[] = array('#|', null);
return $this;
}
/**
* Adds a condition in addition to the query.
*
* @param string $name The name of the property to test.
* @param string|resource|null $value Value of the property as a string
* or seekable stream. Not required for existence tests.
* If a seekable stream is provided, it is sent from its current
* posistion to its end, and the pointer is seeked back to its current
* position after sending.
* Non seekable streams, as well as all other types, are casted to a
* string.
* @param string $operator One of the OP_* constants.
* Describes the operation to perform.
*
* @return $this The query object.
*/
public function andWhere($name, $value = null, $operator = self::OP_EX)
{
$this->addWhere($name, $value, $operator)->words[] = array('#&', null);
return $this;
}
/**
* Sends the query over a communicator.
*
* @param Communicator $com The communicator to send the query over.
*
* @return int The number of bytes sent.
*/
public function send(Communicator $com)
{
if ($com->getTransmitter()->isPersistent()) {
$old = $com->getTransmitter()->lock(T\Stream::DIRECTION_SEND);
$bytes = $this->_send($com);
$com->getTransmitter()->lock($old, true);
return $bytes;
}
return $this->_send($com);
}
/**
* Sends the query over a communicator.
*
* The only difference with the non private equivalent is that this one does
* not do locking.
*
* @param Communicator $com The communicator to send the query over.
*
* @return int The number of bytes sent.
*/
private function _send(Communicator $com)
{
if (!$com->getTransmitter()->isAcceptingData()) {
throw new SocketException(
'Transmitter is invalid. Sending aborted.',
SocketException::CODE_QUERY_SEND_FAIL
);
}
$bytes = 0;
foreach ($this->words as $queryWord) {
list($predicate, $value) = $queryWord;
$prefix = '?' . $predicate;
if (null === $value) {
$bytes += $com->sendWord($prefix);
} else {
$prefix .= '=';
if (is_string($value)) {
$bytes += $com->sendWord($prefix . $value);
} else {
$bytes += $com->sendWordFromStream($prefix, $value);
}
}
}
return $bytes;
}
/**
* Adds a condition.
*
* @param string $name The name of the property to test.
* @param string|resource|null $value Value of the property as a string
* or seekable stream. Not required for existence tests.
* If a seekable stream is provided, it is sent from its current
* posistion to its end, and the pointer is seeked back to its current
* position after sending.
* Non seekable streams, as well as all other types, are casted to a
* string.
* @param string $operator One of the ACTION_* constants.
* Describes the operation to perform.
*
* @return $this The query object.
*/
protected function addWhere($name, $value, $operator)
{
$this->words[] = array(
static::sanitizeOperator($operator)
. Message::sanitizeAttributeName($name),
(null === $value ? null : Message::sanitizeAttributeValue($value))
);
return $this;
}
}

View file

@ -0,0 +1,279 @@
<?php
/**
* RouterOS API client implementation.
*
* RouterOS is the flag product of the company MikroTik and is a powerful router software. One of its many abilities is to allow control over it via an API. This package provides a client for that API, in turn allowing you to use PHP to control RouterOS hosts.
*
* PHP version 5
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0b5
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
/**
* The namespace declaration.
*/
namespace PEAR2\Net\RouterOS;
/**
* Uses shared memory to keep responses in.
*/
use PEAR2\Cache\SHM;
/**
* A RouterOS registry.
*
* Provides functionality for managing the request/response flow. Particularly
* useful in persistent connections.
*
* Note that this class is not meant to be called directly.
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
class Registry
{
/**
* @var SHM The storage.
*/
protected $shm;
/**
* @var int ID of request. Populated at first instance in request.
*/
protected static $requestId = -1;
/**
* @var int ID to be given to next instance, after incrementing it.
*/
protected static $instanceIdSeed = -1;
/**
* @var int ID of instance within the request.
*/
protected $instanceId;
/**
* Creates a registry.
*
* @param string $uri An URI to bind the registry to.
*/
public function __construct($uri)
{
$this->shm = SHM::factory(__CLASS__ . ' ' . $uri);
if (-1 === self::$requestId) {
self::$requestId = $this->shm->add('requestId', 0)
? 0 : $this->shm->inc('requestId');
}
$this->instanceId = ++self::$instanceIdSeed;
$this->shm->add('responseBuffer_' . $this->getOwnershipTag(), array());
}
/**
* Parses a tag.
*
* Parses a tag to reveal the ownership part of it, and the original tag.
*
* @param string $tag The tag (as received) to parse.
*
* @return array An array with the first member being the ownership tag, and
* the second one being the original tag.
*/
public static function parseTag($tag)
{
if (null === $tag) {
return array(null, null);
}
$result = explode('__', $tag, 2);
$result[0] .= '__';
if ('' === $result[1]) {
$result[1] = null;
}
return $result;
}
/**
* Checks if this instance is the tagless mode owner.
*
* @return bool TRUE if this instance is the tagless mode owner, FALSE
* otherwise.
*/
public function isTaglessModeOwner()
{
$this->shm->lock('taglessModeOwner');
$result = $this->shm->exists('taglessModeOwner')
&& $this->getOwnershipTag() === $this->shm->get('taglessModeOwner');
$this->shm->unlock('taglessModeOwner');
return $result;
}
/**
* Sets the "tagless mode" setting.
*
* While in tagless mode, this instance will claim owhership of any
* responses without a tag. While not in this mode, any requests without a
* tag will be given to all instances.
*
* Regardless of mode, if the type of the response is
* {@link Response::TYPE_FATAL}, it will be given to all instances.
*
* @param bool $taglessMode TRUE to claim tagless ownership, FALSE to
* release such ownership, if taken.
*
* @return bool TRUE on success, FALSE on failure.
*/
public function setTaglessMode($taglessMode)
{
return $taglessMode
? ($this->shm->lock('taglessMode')
&& $this->shm->lock('taglessModeOwner')
&& $this->shm->add('taglessModeOwner', $this->getOwnershipTag())
&& $this->shm->unlock('taglessModeOwner'))
: ($this->isTaglessModeOwner()
&& $this->shm->lock('taglessModeOwner')
&& $this->shm->delete('taglessModeOwner')
&& $this->shm->unlock('taglessModeOwner')
&& $this->shm->unlock('taglessMode'));
}
/**
* Get the ownership tag for this instance.
*
* @return string The ownership tag for this registry instance.
*/
public function getOwnershipTag()
{
return self::$requestId . '_' . $this->instanceId . '__';
}
/**
* Add a response to the registry.
*
* @param Response $response The response to add. The caller of this
* function is responsible for ensuring that the ownership tag and the
* original tag are separated, so that only the original one remains in
* the response.
* @param string $ownershipTag The ownership tag that the response had.
*
* @return bool TRUE if the request was added to its buffer, FALSE if
* this instance owns the response, and therefore doesn't need to add
* the response to its buffer.
*/
public function add(Response $response, $ownershipTag)
{
if ($this->getOwnershipTag() === $ownershipTag
|| ($this->isTaglessModeOwner()
&& $response->getType() !== Response::TYPE_FATAL)
) {
return false;
}
if (null === $ownershipTag) {
$this->shm->lock('taglessModeOwner');
if ($this->shm->exists('taglessModeOwner')
&& $response->getType() !== Response::TYPE_FATAL
) {
$ownershipTag = $this->shm->get('taglessModeOwner');
$this->shm->unlock('taglessModeOwner');
} else {
$this->shm->unlock('taglessModeOwner');
foreach ($this->shm->getIterator(
'/^(responseBuffer\_)/',
true
) as $targetBufferName) {
$this->_add($response, $targetBufferName);
}
return true;
}
}
$this->_add($response, 'responseBuffer_' . $ownershipTag);
return true;
}
/**
* Adds a response to a buffer.
*
* @param Response $response The response to add.
* @param string $targetBufferName The name of the buffer to add the
* response to.
*
* @return void
*/
private function _add(Response $response, $targetBufferName)
{
if ($this->shm->lock($targetBufferName)) {
$targetBuffer = $this->shm->get($targetBufferName);
$targetBuffer[] = $response;
$this->shm->set($targetBufferName, $targetBuffer);
$this->shm->unlock($targetBufferName);
}
}
/**
* Gets the next response from this instance's buffer.
*
* @return Response|null The next response, or NULL if there isn't one.
*/
public function getNextResponse()
{
$response = null;
$targetBufferName = 'responseBuffer_' . $this->getOwnershipTag();
if ($this->shm->exists($targetBufferName)
&& $this->shm->lock($targetBufferName)
) {
$targetBuffer = $this->shm->get($targetBufferName);
if (!empty($targetBuffer)) {
$response = array_shift($targetBuffer);
$this->shm->set($targetBufferName, $targetBuffer);
}
$this->shm->unlock($targetBufferName);
}
return $response;
}
/**
* Closes the registry.
*
* Closes the registry, meaning that all buffers are cleared.
*
* @return void
*/
public function close()
{
self::$requestId = -1;
self::$instanceIdSeed = -1;
$this->shm->clear();
}
/**
* Removes a buffer.
*
* @param string $targetBufferName The buffer to remove.
*
* @return void
*/
private function _close($targetBufferName)
{
if ($this->shm->lock($targetBufferName)) {
$this->shm->delete($targetBufferName);
$this->shm->unlock($targetBufferName);
}
}
/**
* Removes this instance's buffer.
*/
public function __destruct()
{
$this->_close('responseBuffer_' . $this->getOwnershipTag());
}
}

View file

@ -0,0 +1,403 @@
<?php
/**
* RouterOS API client implementation.
*
* RouterOS is the flag product of the company MikroTik and is a powerful router software. One of its many abilities is to allow control over it via an API. This package provides a client for that API, in turn allowing you to use PHP to control RouterOS hosts.
*
* PHP version 5
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0b5
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
/**
* The namespace declaration.
*/
namespace PEAR2\Net\RouterOS;
/**
* Refers to transmitter direction constants.
*/
use PEAR2\Net\Transmitter as T;
/**
* Represents a RouterOS request.
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
class Request extends Message
{
/**
* @var string The command to be executed.
*/
private $_command;
/**
* @var Query A query for the command.
*/
private $_query;
/**
* Creates a request to send to RouterOS.
*
* @param string $command The command to send. Can also contain arguments
* expressed in a shell-like syntax.
* @param Query $query A query to associate with the request.
* @param string $tag The tag for the request.
*
* @see setCommand()
* @see setArgument()
* @see setTag()
* @see setQuery()
*/
public function __construct($command, Query $query = null, $tag = null)
{
if (false !== strpos($command, '=')
&& false !== ($spaceBeforeEquals = strrpos(
strstr($command, '=', true),
' '
))
) {
$this->parseArgumentString(substr($command, $spaceBeforeEquals));
$command = rtrim(substr($command, 0, $spaceBeforeEquals));
}
$this->setCommand($command);
$this->setQuery($query);
$this->setTag($tag);
}
/**
* A shorthand gateway.
*
* This is a magic PHP method that allows you to call the object as a
* function. Depending on the argument given, one of the other functions in
* the class is invoked and its returned value is returned by this function.
*
* @param Query|Communicator|string|null $arg A {@link Query} to associate
* the request with, a {@link Communicator} to send the request over,
* an argument to get the value of, or NULL to get the tag. If a
* second argument is provided, this becomes the name of the argument to
* set the value of, and the second argument is the value to set.
*
* @return string|resource|int|$this Whatever the long form
* function returns.
*/
public function __invoke($arg = null)
{
if (func_num_args() > 1) {
return $this->setArgument(func_get_arg(0), func_get_arg(1));
}
if ($arg instanceof Query) {
return $this->setQuery($arg);
}
if ($arg instanceof Communicator) {
return $this->send($arg);
}
return parent::__invoke($arg);
}
/**
* Sets the command to send to RouterOS.
*
* Sets the command to send to RouterOS. The command can use the API or CLI
* syntax of RouterOS, but either way, it must be absolute (begin with a
* "/") and without arguments.
*
* @param string $command The command to send.
*
* @return $this The request object.
* @see getCommand()
* @see setArgument()
*/
public function setCommand($command)
{
$command = (string) $command;
if (strpos($command, '/') !== 0) {
throw new InvalidArgumentException(
'Commands must be absolute.',
InvalidArgumentException::CODE_ABSOLUTE_REQUIRED
);
}
if (substr_count($command, '/') === 1) {
//Command line syntax convertion
$cmdParts = preg_split('#[\s/]+#sm', $command);
$cmdRes = array($cmdParts[0]);
for ($i = 1, $n = count($cmdParts); $i < $n; $i++) {
if ('..' === $cmdParts[$i]) {
$delIndex = count($cmdRes) - 1;
if ($delIndex < 1) {
throw new InvalidArgumentException(
'Unable to resolve command',
InvalidArgumentException::CODE_CMD_UNRESOLVABLE
);
}
unset($cmdRes[$delIndex]);
$cmdRes = array_values($cmdRes);
} else {
$cmdRes[] = $cmdParts[$i];
}
}
$command = implode('/', $cmdRes);
}
if (!preg_match('#^/\S+$#sm', $command)) {
throw new InvalidArgumentException(
'Invalid command supplied.',
InvalidArgumentException::CODE_CMD_INVALID
);
}
$this->_command = $command;
return $this;
}
/**
* Gets the command that will be send to RouterOS.
*
* Gets the command that will be send to RouterOS in its API syntax.
*
* @return string The command to send.
* @see setCommand()
*/
public function getCommand()
{
return $this->_command;
}
/**
* Sets the query to send with the command.
*
* @param Query $query The query to be set. Setting NULL will remove the
* currently associated query.
*
* @return $this The request object.
* @see getQuery()
*/
public function setQuery(Query $query = null)
{
$this->_query = $query;
return $this;
}
/**
* Gets the currently associated query
*
* @return Query The currently associated query.
* @see setQuery()
*/
public function getQuery()
{
return $this->_query;
}
/**
* Sets the tag to associate the request with.
*
* Sets the tag to associate the request with. Setting NULL erases the
* currently set tag.
*
* @param string $tag The tag to set.
*
* @return $this The request object.
* @see getTag()
*/
public function setTag($tag)
{
return parent::setTag($tag);
}
/**
* Sets an argument for the request.
*
* @param string $name Name of the argument.
* @param string|resource|null $value Value of the argument as a string or
* seekable stream.
* Setting the value to NULL removes an argument of this name.
* If a seekable stream is provided, it is sent from its current
* posistion to its end, and the pointer is seeked back to its current
* position after sending.
* Non seekable streams, as well as all other types, are casted to a
* string.
*
* @return $this The request object.
* @see getArgument()
*/
public function setArgument($name, $value = '')
{
return parent::setAttribute($name, $value);
}
/**
* Gets the value of an argument.
*
* @param string $name The name of the argument.
*
* @return string|resource|null The value of the specified argument.
* Returns NULL if such an argument is not set.
* @see setAttribute()
*/
public function getArgument($name)
{
return parent::getAttribute($name);
}
/**
* Removes all arguments from the request.
*
* @return $this The request object.
*/
public function removeAllArguments()
{
return parent::removeAllAttributes();
}
/**
* Sends a request over a communicator.
*
* @param Communicator $com The communicator to send the request over.
* @param Registry $reg An optional registry to sync the request with.
*
* @return int The number of bytes sent.
* @see Client::sendSync()
* @see Client::sendAsync()
*/
public function send(Communicator $com, Registry $reg = null)
{
if (null !== $reg
&& (null != $this->getTag() || !$reg->isTaglessModeOwner())
) {
$originalTag = $this->getTag();
$this->setTag($reg->getOwnershipTag() . $originalTag);
$bytes = $this->send($com);
$this->setTag($originalTag);
return $bytes;
}
if ($com->getTransmitter()->isPersistent()) {
$old = $com->getTransmitter()->lock(T\Stream::DIRECTION_SEND);
$bytes = $this->_send($com);
$com->getTransmitter()->lock($old, true);
return $bytes;
}
return $this->_send($com);
}
/**
* Sends a request over a communicator.
*
* The only difference with the non private equivalent is that this one does
* not do locking.
*
* @param Communicator $com The communicator to send the request over.
*
* @return int The number of bytes sent.
* @see Client::sendSync()
* @see Client::sendAsync()
*/
private function _send(Communicator $com)
{
if (!$com->getTransmitter()->isAcceptingData()) {
throw new SocketException(
'Transmitter is invalid. Sending aborted.',
SocketException::CODE_REQUEST_SEND_FAIL
);
}
$bytes = 0;
$bytes += $com->sendWord($this->getCommand());
if (null !== ($tag = $this->getTag())) {
$bytes += $com->sendWord('.tag=' . $tag);
}
foreach ($this->attributes as $name => $value) {
$prefix = '=' . $name . '=';
if (is_string($value)) {
$bytes += $com->sendWord($prefix . $value);
} else {
$bytes += $com->sendWordFromStream($prefix, $value);
}
}
$query = $this->getQuery();
if ($query instanceof Query) {
$bytes += $query->send($com);
}
$bytes += $com->sendWord('');
return $bytes;
}
/**
* Parses the arguments of a command.
*
* @param string $string The argument string to parse.
*
* @return void
*/
protected function parseArgumentString($string)
{
/*
* Grammar:
*
* <arguments> := (<<\s+>>, <argument>)*,
* <argument> := <name>, <value>?
* <name> := <<[^\=\s]+>>
* <value> := "=", (<quoted string> | <unquoted string>)
* <quotedString> := <<">>, <<([^"]|\\"|\\\\)*>>, <<">>
* <unquotedString> := <<\S+>>
*/
$token = '';
$name = null;
while ($string = substr($string, strlen($token))) {
if (null === $name) {
if (preg_match('/^\s+([^\s=]+)/sS', $string, $matches)) {
$token = $matches[0];
$name = $matches[1];
} else {
throw new InvalidArgumentException(
"Parsing of argument name failed near '{$string}'",
InvalidArgumentException::CODE_NAME_UNPARSABLE
);
}
} elseif (preg_match('/^\s/s', $string, $matches)) {
//Empty argument
$token = '';
$this->setArgument($name);
$name = null;
} elseif (preg_match(
'/^="(([^\\\"]|\\\"|\\\\)*)"/sS',
$string,
$matches
)) {
$token = $matches[0];
$this->setArgument(
$name,
str_replace(
array('\\"', '\\\\'),
array('"', '\\'),
$matches[1]
)
);
$name = null;
} elseif (preg_match('/^=(\S+)/sS', $string, $matches)) {
$token = $matches[0];
$this->setArgument($name, $matches[1]);
$name = null;
} else {
throw new InvalidArgumentException(
"Parsing of argument value failed near '{$string}'",
InvalidArgumentException::CODE_VALUE_UNPARSABLE
);
}
}
if (null !== $name && ('' !== ($name = trim($name)))) {
$this->setArgument($name, '');
}
}
}

View file

@ -0,0 +1,335 @@
<?php
/**
* RouterOS API client implementation.
*
* RouterOS is the flag product of the company MikroTik and is a powerful router software. One of its many abilities is to allow control over it via an API. This package provides a client for that API, in turn allowing you to use PHP to control RouterOS hosts.
*
* PHP version 5
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0b5
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
/**
* The namespace declaration.
*/
namespace PEAR2\Net\RouterOS;
/**
* Refers to transmitter direction constants.
*/
use PEAR2\Net\Transmitter as T;
/**
* Locks are released upon any exception from anywhere.
*/
use Exception as E;
/**
* Represents a RouterOS response.
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
class Response extends Message
{
/**
* The last response for a request.
*/
const TYPE_FINAL = '!done';
/**
* A response with data.
*/
const TYPE_DATA = '!re';
/**
* A response signifying error.
*/
const TYPE_ERROR = '!trap';
/**
* A response signifying a fatal error, due to which the connection would be
* terminated.
*/
const TYPE_FATAL = '!fatal';
/**
* @var array An array of unrecognized words in network order.
*/
protected $unrecognizedWords = array();
/**
* @var string The response type.
*/
private $_type;
/**
* Extracts a new response from a communicator.
*
* @param Communicator $com The communicator from which to extract
* the new response.
* @param bool $asStream Whether to populate the argument values
* with streams instead of strings.
* @param int $sTimeout If a response is not immediatly
* available, wait this many seconds. If NULL, wait indefinetly.
* @param int $usTimeout Microseconds to add to the waiting time.
* @param Registry $reg An optional registry to sync the
* response with.
*
* @see getType()
* @see getArgument()
*/
public function __construct(
Communicator $com,
$asStream = false,
$sTimeout = 0,
$usTimeout = null,
Registry $reg = null
) {
if (null === $reg) {
if ($com->getTransmitter()->isPersistent()) {
$old = $com->getTransmitter()
->lock(T\Stream::DIRECTION_RECEIVE);
try {
$this->_receive($com, $asStream, $sTimeout, $usTimeout);
} catch (E $e) {
$com->getTransmitter()->lock($old, true);
throw $e;
}
$com->getTransmitter()->lock($old, true);
} else {
$this->_receive($com, $asStream, $sTimeout, $usTimeout);
}
} else {
while (null === ($response = $reg->getNextResponse())) {
$newResponse = new self($com, true, $sTimeout, $usTimeout);
$tagInfo = $reg::parseTag($newResponse->getTag());
$newResponse->setTag($tagInfo[1]);
if (!$reg->add($newResponse, $tagInfo[0])) {
$response = $newResponse;
break;
}
}
$this->_type = $response->_type;
$this->attributes = $response->attributes;
$this->unrecognizedWords = $response->unrecognizedWords;
$this->setTag($response->getTag());
if (!$asStream) {
foreach ($this->attributes as $name => $value) {
$this->setAttribute(
$name,
stream_get_contents($value)
);
}
foreach ($response->unrecognizedWords as $i => $value) {
$this->unrecognizedWords[$i] = stream_get_contents($value);
}
}
}
}
/**
* Extracts a new response from a communicator.
*
* This is the function that performs the actual receiving, while the
* constructor is also involved in locks and registry sync.
*
* @param Communicator $com The communicator from which to extract
* the new response.
* @param bool $asStream Whether to populate the argument values
* with streams instead of strings.
* @param int $sTimeout If a response is not immediatly
* available, wait this many seconds. If NULL, wait indefinetly.
* Note that if an empty sentence is received, the timeout will be
* reset for another sentence receiving.
* @param int $usTimeout Microseconds to add to the waiting time.
*
* @return void
*/
private function _receive(
Communicator $com,
$asStream = false,
$sTimeout = 0,
$usTimeout = null
) {
do {
if (!$com->getTransmitter()->isDataAwaiting(
$sTimeout,
$usTimeout
)) {
throw new SocketException(
'No data within the time limit',
SocketException::CODE_NO_DATA
);
}
$type = $com->getNextWord();
} while ('' === $type);
$this->setType($type);
if ($asStream) {
for ($word = $com->getNextWordAsStream(), fseek($word, 0, SEEK_END);
ftell($word) !== 0;
$word = $com->getNextWordAsStream(), fseek(
$word,
0,
SEEK_END
)) {
rewind($word);
$ind = fread($word, 1);
if ('=' === $ind || '.' === $ind) {
$prefix = stream_get_line($word, null, '=');
}
if ('=' === $ind) {
$value = fopen('php://temp', 'r+b');
$bytesCopied = ftell($word);
while (!feof($word)) {
$bytesCopied += stream_copy_to_stream(
$word,
$value,
0xFFFFF,
$bytesCopied
);
}
rewind($value);
$this->setAttribute($prefix, $value);
continue;
}
if ('.' === $ind && 'tag' === $prefix) {
$this->setTag(stream_get_contents($word, -1, -1));
continue;
}
rewind($word);
$this->unrecognizedWords[] = $word;
}
} else {
for ($word = $com->getNextWord(); '' !== $word;
$word = $com->getNextWord()) {
if (preg_match('/^=([^=]+)=(.*)$/sS', $word, $matches)) {
$this->setAttribute($matches[1], $matches[2]);
} elseif (preg_match('/^\.tag=(.*)$/sS', $word, $matches)) {
$this->setTag($matches[1]);
} else {
$this->unrecognizedWords[] = $word;
}
}
}
}
/**
* Sets the response type.
*
* Sets the response type. Valid values are the TYPE_* constants.
*
* @param string $type The new response type.
*
* @return $this The response object.
* @see getType()
*/
protected function setType($type)
{
switch ($type) {
case self::TYPE_FINAL:
case self::TYPE_DATA:
case self::TYPE_ERROR:
case self::TYPE_FATAL:
$this->_type = $type;
return $this;
default:
throw new UnexpectedValueException(
'Unrecognized response type.',
UnexpectedValueException::CODE_RESPONSE_TYPE_UNKNOWN,
null,
$type
);
}
}
/**
* Gets the response type.
*
* @return string The response type.
* @see setType()
*/
public function getType()
{
return $this->_type;
}
/**
* Gets the value of an argument.
*
* @param string $name The name of the argument.
*
* @return string|resource|null The value of the specified argument.
* Returns NULL if such an argument is not set.
* @deprecated 1.0.0b5 Use {@link static::getProperty()} instead.
* This method will be removed upon final release, and is currently
* left standing merely because it can't be easily search&replaced in
* existing code, due to the fact the name "getArgument()" is shared
* with {@link Request::getArgument()}, which is still valid.
* @codeCoverageIgnore
*/
public function getArgument($name)
{
trigger_error(
'Response::getArgument() is deprecated in favor of ' .
'Response::getProperty() (but note that Request::getArgument() ' .
'is still valid)',
E_USER_DEPRECATED
);
return $this->getAttribute($name);
}
/**
* Gets the value of a property.
*
* @param string $name The name of the property.
*
* @return string|resource|null The value of the specified property.
* Returns NULL if such a property is not set.
*/
public function getProperty($name)
{
return parent::getAttribute($name);
}
/**
* Gets a list of unrecognized words.
*
* @return array The list of unrecognized words.
*/
public function getUnrecognizedWords()
{
return $this->unrecognizedWords;
}
/**
* Counts the number of arguments or words.
*
* @param int $mode The counter mode.
* Either COUNT_NORMAL or COUNT_RECURSIVE.
* When in normal mode, counts the number of arguments.
* When in recursive mode, counts the number of API words.
*
* @return int The number of arguments/words.
*/
public function count($mode = COUNT_NORMAL)
{
$result = parent::count($mode);
if ($mode !== COUNT_NORMAL) {
$result += count($this->unrecognizedWords);
}
return $result;
}
}

View file

@ -0,0 +1,569 @@
<?php
/**
* RouterOS API client implementation.
*
* RouterOS is the flag product of the company MikroTik and is a powerful router software. One of its many abilities is to allow control over it via an API. This package provides a client for that API, in turn allowing you to use PHP to control RouterOS hosts.
*
* PHP version 5
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0b5
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
/**
* The namespace declaration.
*/
namespace PEAR2\Net\RouterOS;
/**
* Implemented by this class.
*/
use ArrayAccess;
/**
* Implemented by this class.
*/
use Countable;
/**
* Implemented by this class.
*/
use SeekableIterator;
/**
* Represents a collection of RouterOS responses.
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*
* @method string getType()
* Calls {@link Response::getType()}
* on the response pointed by the pointer.
* @method string[] getUnrecognizedWords()
* Calls {@link Response::getUnrecognizedWords()}
* on the response pointed by the pointer.
* @method string|resource|null getProperty(string $name)
* Calls {@link Response::getProperty()}
* on the response pointed by the pointer.
* @method string getTag()
* Calls {@link Response::getTag()}
* on the response pointed by the pointer.
*/
class ResponseCollection implements ArrayAccess, SeekableIterator, Countable
{
/**
* @var array An array with all {@link Response} objects.
*/
protected $responses = array();
/**
* @var array An array with each {@link Response} object's type.
*/
protected $responseTypes = array();
/**
* @var array An array with each {@link Response} object's tag.
*/
protected $responseTags = array();
/**
* @var array An array with positions of responses, based on an property
* name. The name of each property is the array key, and the array value
* is another array where the key is the value for that property, and
* the value is the posistion of the response. For performance reasons,
* each key is built only when {@link static::setIndex()} is called with
* that property, and remains available for the lifetime of this
* collection.
*/
protected $responsesIndex = array();
/**
* @var array An array with all distinct properties across all
* {@link Response} objects. Created at the first call of
* {@link static::getPropertyMap()}.
*/
protected $propertyMap = null;
/**
* @var int A pointer, as required by SeekableIterator.
*/
protected $position = 0;
/**
* @var string|null Name of property to use as index. NULL when disabled.
*/
protected $index = null;
/**
* @var array Criterias used by {@link compare()} to determine the order
* between two respones. See {@link orderBy()} for a detailed
* description of this array's format.
*/
protected $compareBy = array();
/**
* Creates a new collection.
*
* @param array $responses An array of responses, in network order.
*/
public function __construct(array $responses)
{
$pos = 0;
foreach ($responses as $response) {
if ($response instanceof Response) {
$this->responseTypes[$pos] = $response->getType();
$this->responseTags[$pos] = $response->getTag();
$this->responses[$pos++] = $response;
}
}
}
/**
* A shorthand gateway.
*
* This is a magic PHP method that allows you to call the object as a
* function. Depending on the argument given, one of the other functions in
* the class is invoked and its returned value is returned by this function.
*
* @param int|string|null $offset The offset of the response to seek to.
* If the offset is negative, seek to that relative to the end.
* If the collection is indexed, you can also supply a value to seek to.
* Setting NULL will get the current response's interator.
*
* @return Response|ArrayObject The {@link Response} at the specified
* offset, the current response's iterator (which is an ArrayObject)
* when NULL is given, or FALSE if the offset is invalid
* or the collection is empty.
*/
public function __invoke($offset = null)
{
return null === $offset
? $this->current()->getIterator()
: $this->seek($offset);
}
/**
* Sets a property to be usable as a key in the collection.
*
* @param string|null $name The name of the property to use. Future calls
* that accept a position will then also be able to search values of
* that property for a matching value.
* Specifying NULL will disable such lookups (as is by default).
* Note that in case this value occures multiple times within the
* collection, only the last matching response will be accessible by
* that value.
*
* @return $this The object itself.
*/
public function setIndex($name)
{
if (null !== $name) {
$name = (string)$name;
if (!isset($this->responsesIndex[$name])) {
$this->responsesIndex[$name] = array();
foreach ($this->responses as $pos => $response) {
$val = $response->getProperty($name);
if (null !== $val) {
$this->responsesIndex[$name][$val] = $pos;
}
}
}
}
$this->index = $name;
return $this;
}
/**
* Gets the name of the property used as an index.
*
* @return string|null Name of property used as index. NULL when disabled.
*/
public function getIndex()
{
return $this->index;
}
/**
* Gets the whole collection as an array.
*
* @param bool $useIndex Whether to use the index values as keys for the
* resulting array.
*
* @return array An array with all responses, in network order.
*/
public function toArray($useIndex = false)
{
if ($useIndex) {
$positions = $this->responsesIndex[$this->index];
asort($positions, SORT_NUMERIC);
$positions = array_flip($positions);
return array_combine(
$positions,
array_intersect_key($this->responses, $positions)
);
}
return $this->responses;
}
/**
* Counts the responses/words in the collection.
*
* @param int $mode The counter mode.
* Either COUNT_NORMAL or COUNT_RECURSIVE.
* When in normal mode, counts the number of responses.
* When in recursive mode, counts the total number of API words.
*
* @return int The number of responses in the collection.
*/
public function count($mode = COUNT_NORMAL)
{
if ($mode !== COUNT_NORMAL) {
$result = 0;
foreach ($this->responses as $response) {
$result += $response->count($mode);
}
return $result;
} else {
return count($this->responses);
}
}
/**
* Checks if an offset exists.
*
* @param int|string $offset The offset to check. If the
* collection is indexed, you can also supply a value to check.
* Note that negative numeric offsets are NOT accepted.
*
* @return bool TRUE if the offset exists, FALSE otherwise.
*/
public function offsetExists($offset)
{
return is_int($offset)
? array_key_exists($offset, $this->responses)
: array_key_exists($offset, $this->responsesIndex[$this->index]);
}
/**
* Gets a {@link Response} from a specified offset.
*
* @param int|string $offset The offset of the desired response. If the
* collection is indexed, you can also supply the value to search for.
*
* @return Response The response at the specified offset.
*/
public function offsetGet($offset)
{
return is_int($offset)
? $this->responses[$offset >= 0
? $offset
: count($this->responses) + $offset]
: $this->responses[$this->responsesIndex[$this->index][$offset]];
}
/**
* N/A
*
* This method exists only because it is required for ArrayAccess. The
* collection is read only.
*
* @param int|string $offset N/A
* @param Response $value N/A
*
* @return void
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function offsetSet($offset, $value)
{
}
/**
* N/A
*
* This method exists only because it is required for ArrayAccess. The
* collection is read only.
*
* @param int|string $offset N/A
*
* @return void
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function offsetUnset($offset)
{
}
/**
* Resets the pointer to 0, and returns the first response.
*
* @return Response The first response in the collection, or FALSE if the
* collection is empty.
*/
public function rewind()
{
return $this->seek(0);
}
/**
* Moves the position pointer to a specified position.
*
* @param int|string $position The position to move to. If the collection is
* indexed, you can also supply a value to move the pointer to.
* A non-existent index will move the pointer to "-1".
*
* @return Response The {@link Response} at the specified position, or FALSE
* if the specified position is not valid.
*/
public function seek($position)
{
$this->position = is_int($position)
? ($position >= 0
? $position
: count($this->responses) + $position)
: ($this->offsetExists($position)
? $this->responsesIndex[$this->index][$position]
: -1);
return $this->current();
}
/**
* Moves the pointer forward by 1, and gets the next response.
*
* @return Response The next {@link Response} object, or FALSE if the
* position is not valid.
*/
public function next()
{
++$this->position;
return $this->current();
}
/**
* Gets the response at the current pointer position.
*
* @return Response The response at the current pointer position, or FALSE
* if the position is not valid.
*/
public function current()
{
return $this->valid() ? $this->responses[$this->position] : false;
}
/**
* Moves the pointer backwards by 1, and gets the previous response.
*
* @return Response The next {@link Response} object, or FALSE if the
* position is not valid.
*/
public function prev()
{
--$this->position;
return $this->current();
}
/**
* Moves the pointer to the last valid position, and returns the last
* response.
*
* @return Response The last response in the collection, or FALSE if the
* collection is empty.
*/
public function end()
{
$this->position = count($this->responses) - 1;
return $this->current();
}
/**
* Gets the key at the current pointer position.
*
* @return int The key at the current pointer position, i.e. the pointer
* position itself, or FALSE if the position is not valid.
*/
public function key()
{
return $this->valid() ? $this->position : false;
}
/**
* Checks if the pointer is still pointing to an existing offset.
*
* @return bool TRUE if the pointer is valid, FALSE otherwise.
*/
public function valid()
{
return $this->offsetExists($this->position);
}
/**
* Gets all distinct property names.
*
* Gets all distinct property names across all responses.
*
* @return array An array with all distinct property names as keys, and the
* indexes at which they occur as values.
*/
public function getPropertyMap()
{
if (null === $this->propertyMap) {
$properties = array();
foreach ($this->responses as $index => $response) {
$names = array_keys($response->getIterator()->getArrayCopy());
foreach ($names as $name) {
if (!isset($properties[$name])) {
$properties[$name] = array();
}
$properties[$name][] = $index;
}
}
$this->propertyMap = $properties;
}
return $this->propertyMap;
}
/**
* Gets all responses of a specified type.
*
* @param string $type The response type to filter by. Valid values are the
* Response::TYPE_* constants.
*
* @return static A new collection with responses of the
* specified type.
*/
public function getAllOfType($type)
{
$result = array();
foreach (array_keys($this->responseTypes, $type, true) as $index) {
$result[] = $this->responses[$index];
}
return new static($result);
}
/**
* Gets all responses with a specified tag.
*
* @param string $tag The tag to filter by.
*
* @return static A new collection with responses having the
* specified tag.
*/
public function getAllTagged($tag)
{
$result = array();
foreach (array_keys($this->responseTags, $tag, true) as $index) {
$result[] = $this->responses[$index];
}
return new static($result);
}
/**
* Order resones by criteria.
*
* @param mixed[] $criteria The criteria to order respones by. It takes the
* form of an array where each key is the name of the property to use
* as (N+1)th sorting key. The value of each member can be either NULL
* (for that property, sort normally in ascending order), a single sort
* order constant (SORT_ASC or SORT_DESC) to sort normally in the
* specified order, an array where the first member is an order
* constant, and the second one is sorting flags (same as built in PHP
* array functions) or a callback.
* If a callback is provided, it must accept two arguments
* (the two values to be compared), and return -1, 0 or 1 if the first
* value is respectively less than, equal to or greather than the second
* one.
* Each key of $criteria can also be numeric, in which case the
* value is the name of the property, and sorting is done normally in
* ascending order.
*
* @return static A new collection with the responses sorted in the
* specified order.
*/
public function orderBy(array $criteria)
{
$this->compareBy = $criteria;
$sortedResponses = $this->responses;
usort($sortedResponses, array($this, 'compare'));
return new static($sortedResponses);
}
/**
* Calls a method of the response pointed by the pointer.
*
* Calls a method of the response pointed by the pointer. This is a magic
* PHP method, thanks to which any function you call on the collection that
* is not defined will be redirected to the response.
*
* @param string $method The name of the method to call.
* @param array $args The arguments to pass to the method.
*
* @return mixed Whatever the called function returns.
*/
public function __call($method, array $args)
{
return call_user_func_array(
array($this->current(), $method),
$args
);
}
/**
* Compares two respones.
*
* Compares two respones, based on criteria defined in
* {@link static::$compareBy}.
*
* @param Response $itemA The response to compare.
* @param Response $itemB The response to compare $a against.
*
* @return int Returns 0 if the two respones are equal according to every
* criteria specified, -1 if $a should be placed before $b, and 1 if $b
* should be placed before $a.
*/
protected function compare(Response $itemA, Response $itemB)
{
foreach ($this->compareBy as $name => $spec) {
if (!is_string($name)) {
$name = $spec;
$spec = null;
}
$members = array(
0 => $itemA->getProperty($name),
1 => $itemB->getProperty($name)
);
if (is_callable($spec)) {
uasort($members, $spec);
} elseif ($members[0] === $members[1]) {
continue;
} else {
$flags = SORT_REGULAR;
$order = SORT_ASC;
if (is_array($spec)) {
list($order, $flags) = $spec;
} elseif (null !== $spec) {
$order = $spec;
}
if (SORT_ASC === $order) {
asort($members, $flags);
} else {
arsort($members, $flags);
}
}
return (key($members) === 0) ? -1 : 1;
}
return 0;
}
}

View file

@ -0,0 +1,44 @@
<?php
/**
* RouterOS API client implementation.
*
* RouterOS is the flag product of the company MikroTik and is a powerful router software. One of its many abilities is to allow control over it via an API. This package provides a client for that API, in turn allowing you to use PHP to control RouterOS hosts.
*
* PHP version 5
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0b5
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
/**
* The namespace declaration.
*/
namespace PEAR2\Net\RouterOS;
/**
* Base of this class.
*/
use RuntimeException;
/**
* Exception thrown when something goes wrong with the connection.
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
class SocketException extends RuntimeException implements Exception
{
const CODE_SERVICE_INCOMPATIBLE = 10200;
const CODE_CONNECTION_FAIL = 100;
const CODE_QUERY_SEND_FAIL = 30600;
const CODE_REQUEST_SEND_FAIL = 40900;
const CODE_NO_DATA = 50000;
}

View file

@ -0,0 +1,88 @@
<?php
/**
* RouterOS API client implementation.
*
* RouterOS is the flag product of the company MikroTik and is a powerful router software. One of its many abilities is to allow control over it via an API. This package provides a client for that API, in turn allowing you to use PHP to control RouterOS hosts.
*
* PHP version 5
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0b5
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
/**
* The namespace declaration.
*/
namespace PEAR2\Net\RouterOS;
use UnexpectedValueException as U;
/**
* Exception thrown when encountering an invalid value in a function argument.
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
class UnexpectedValueException extends U implements Exception
{
const CODE_CALLBACK_INVALID = 10502;
const CODE_ACTION_UNKNOWN = 30100;
const CODE_RESPONSE_TYPE_UNKNOWN = 50100;
/**
* @var mixed The unexpected value.
*/
private $_value;
/**
* Creates a new UnexpectedValueException.
*
* @param string $message The Exception message to throw.
* @param int $code The Exception code.
* @param \Exception $previous The previous exception used for the exception
* chaining.
* @param mixed $value The unexpected value.
*/
public function __construct(
$message,
$code = 0,
$previous = null,
$value = null
) {
parent::__construct($message, $code, $previous);
$this->_value = $value;
}
/**
* Gets the unexpected value.
*
* @return mixed The unexpected value.
*/
public function getValue()
{
return $this->_value;
}
// @codeCoverageIgnoreStart
// String representation is not reliable in testing
/**
* Returns a string representation of the exception.
*
* @return string The exception as a string.
*/
public function __toString()
{
return parent::__toString() . "\nValue:{$this->_value}";
}
// @codeCoverageIgnoreEnd
}

1177
PEAR2/Net/RouterOS/Util.php Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,36 @@
<?php
/**
* Wrapper for network stream functionality.
*
* PHP has built in support for various types of network streams, such as HTTP and TCP sockets. One problem that arises with them is the fact that a single fread/fwrite call might not read/write all the data you intended, regardless of whether you're in blocking mode or not. While the PHP manual offers a workaround in the form of a loop with a few variables, using it every single time you want to read/write can be tedious.
This package abstracts this away, so that when you want to get exactly N amount of bytes, you can be sure the upper levels of your app will be dealing with N bytes. Oh, and the functionality is nicely wrapped in an object (but that's just the icing on the cake).
*
* PHP version 5
*
* @category Net
* @package PEAR2_Net_Transmitter
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0a5
* @link http://pear2.php.net/PEAR2_Net_Transmitter
*/
/**
* The namespace declaration.
*/
namespace PEAR2\Net\Transmitter;
/**
* Generic exception class of this package.
*
* @category Net
* @package PEAR2_Net_Transmitter
* @author Vasil Rangelov <boen.robot@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear2.php.net/PEAR2_Net_Transmitter
*/
interface Exception
{
}

View file

@ -0,0 +1,229 @@
<?php
/**
* Wrapper for network stream functionality.
*
* PHP has built in support for various types of network streams, such as HTTP and TCP sockets. One problem that arises with them is the fact that a single fread/fwrite call might not read/write all the data you intended, regardless of whether you're in blocking mode or not. While the PHP manual offers a workaround in the form of a loop with a few variables, using it every single time you want to read/write can be tedious.
This package abstracts this away, so that when you want to get exactly N amount of bytes, you can be sure the upper levels of your app will be dealing with N bytes. Oh, and the functionality is nicely wrapped in an object (but that's just the icing on the cake).
*
* PHP version 5
*
* @category Net
* @package PEAR2_Net_Transmitter
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0a5
* @link http://pear2.php.net/PEAR2_Net_Transmitter
*/
/**
* The namespace declaration.
*/
namespace PEAR2\Net\Transmitter;
/**
* A filter collection.
*
* Represents a collection of stream filters.
*
* @category Net
* @package PEAR2_Net_Transmitter
* @author Vasil Rangelov <boen.robot@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear2.php.net/PEAR2_Net_Transmitter
* @see Client
*/
class FilterCollection implements \SeekableIterator, \Countable
{
/**
* @var array The filter collection itself.
*/
protected $filters = array();
/**
* @var int A pointer, as required by SeekableIterator.
*/
protected $position = 0;
/**
* Appends a filter to the collection
*
* @param string $name The name of the filter.
* @param array $params An array of parameters for the filter.
*
* @return $this The collection itself.
*/
public function append($name, array $params = array())
{
$this->filters[] = array((string) $name, $params);
return $this;
}
/**
* Inserts the filter before a position.
*
* Inserts the specified filter before a filter at a specified position. The
* new filter takes the specified position, while previous filters are moved
* forward by one.
*
* @param int $position The position before which the filter will be
* inserted.
* @param string $name The name of the filter.
* @param array $params An array of parameters for the filter.
*
* @return $this The collection itself.
*/
public function insertBefore($position, $name, array $params = array())
{
$position = (int) $position;
if ($position <= 0) {
$this->filters = array_merge(
array(0 => array((string) $name, $params)),
$this->filters
);
return $this;
}
if ($position > count($this->filters)) {
return $this->append($name, $params);
}
$this->filters = array_merge(
array_slice($this->filters, 0, $position),
array(0 => array((string) $name, $params)),
array_slice($this->filters, $position)
);
return $this;
}
/**
* Removes a filter at a specified position.
*
* @param int $position The position from which to remove a filter.
*
* @return $this The collection itself.
*/
public function removeAt($position)
{
unset($this->filters[$position]);
$this->filters = array_values($this->filters);
return $this;
}
/**
* Clears the collection
*
* @return $this The collection itself.
*/
public function clear()
{
$this->filters = array();
return $this;
}
/**
* Gets the number of filters in the collection.
*
* @return int The number of filters in the collection.
*/
public function count()
{
return count($this->filters);
}
/**
* Resets the pointer to 0.
*
* @return bool TRUE if the collection is not empty, FALSE otherwise.
*/
public function rewind()
{
return $this->seek(0);
}
/**
* Moves the pointer to a specified position.
*
* @param int $position The position to move to.
*
* @return bool TRUE if the specified position is valid, FALSE otherwise.
*/
public function seek($position)
{
$this->position = $position;
return $this->valid();
}
/**
* Gets the current position.
*
* @return int The current position.
*/
public function getCurrentPosition()
{
return $this->position;
}
/**
* Moves the pointer forward by 1.
*
* @return bool TRUE if the new position is valid, FALSE otherwise.
*/
public function next()
{
++$this->position;
return $this->valid();
}
/**
* Gets the filter name at the current pointer position.
*
* @return string The name of the filter at the current position.
*/
public function key()
{
return $this->valid() ? $this->filters[$this->position][0] : false;
}
/**
* Gets the filter parameters at the current pointer position.
*
* @return array An array of parameters for the filter at the current
* position.
*/
public function current()
{
return $this->valid() ? $this->filters[$this->position][1] : false;
}
/**
* Moves the pointer backwards by 1.
*
* @return bool TRUE if the new position is valid, FALSE otherwise.
*/
public function prev()
{
--$this->position;
return $this->valid();
}
/**
* Moves the pointer to the last valid position.
*
* @return bool TRUE if the collection is not empty, FALSE otherwise.
*/
public function end()
{
$this->position = count($this->filters) - 1;
return $this->valid();
}
/**
* Checks if the pointer is still pointing to an existing offset.
*
* @return bool TRUE if the pointer is valid, FALSE otherwise.
*/
public function valid()
{
return array_key_exists($this->position, $this->filters);
}
}

View file

@ -0,0 +1,36 @@
<?php
/**
* Wrapper for network stream functionality.
*
* PHP has built in support for various types of network streams, such as HTTP and TCP sockets. One problem that arises with them is the fact that a single fread/fwrite call might not read/write all the data you intended, regardless of whether you're in blocking mode or not. While the PHP manual offers a workaround in the form of a loop with a few variables, using it every single time you want to read/write can be tedious.
This package abstracts this away, so that when you want to get exactly N amount of bytes, you can be sure the upper levels of your app will be dealing with N bytes. Oh, and the functionality is nicely wrapped in an object (but that's just the icing on the cake).
*
* PHP version 5
*
* @category Net
* @package PEAR2_Net_Transmitter
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0a5
* @link http://pear2.php.net/PEAR2_Net_Transmitter
*/
/**
* The namespace declaration.
*/
namespace PEAR2\Net\Transmitter;
/**
* Exception thrown when something goes wrong when dealing with locks.
*
* @category Net
* @package PEAR2_Net_Transmitter
* @author Vasil Rangelov <boen.robot@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear2.php.net/PEAR2_Net_Transmitter
*/
class LockException extends \RuntimeException implements Exception
{
}

View file

@ -0,0 +1,181 @@
<?php
/**
* Wrapper for network stream functionality.
*
* PHP has built in support for various types of network streams, such as HTTP and TCP sockets. One problem that arises with them is the fact that a single fread/fwrite call might not read/write all the data you intended, regardless of whether you're in blocking mode or not. While the PHP manual offers a workaround in the form of a loop with a few variables, using it every single time you want to read/write can be tedious.
This package abstracts this away, so that when you want to get exactly N amount of bytes, you can be sure the upper levels of your app will be dealing with N bytes. Oh, and the functionality is nicely wrapped in an object (but that's just the icing on the cake).
*
* PHP version 5
*
* @category Net
* @package PEAR2_Net_Transmitter
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0a5
* @link http://pear2.php.net/PEAR2_Net_Transmitter
*/
/**
* The namespace declaration.
*/
namespace PEAR2\Net\Transmitter;
/**
* A network transmitter.
*
* This is a convinience wrapper for network streams. Used to ensure data
* integrity.
*
* @category Net
* @package PEAR2_Net_Transmitter
* @author Vasil Rangelov <boen.robot@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear2.php.net/PEAR2_Net_Transmitter
*/
abstract class NetworkStream extends Stream
{
/**
* Used in {@link setCrypto()} to disable encryption.
*/
const CRYPTO_OFF = '';
/**
* Used in {@link setCrypto()} to set encryption to either SSLv2 or SSLv3,
* depending on what the other end supports.
*/
const CRYPTO_SSL = 'SSLv23';
/**
* Used in {@link setCrypto()} to set encryption to SSLv2.
*/
const CRYPTO_SSL2 = 'SSLv2';
/**
* Used in {@link setCrypto()} to set encryption to SSLv3.
*/
const CRYPTO_SSL3 = 'SSLv3';
/**
* Used in {@link setCrypto()} to set encryption to TLS (exact version
* negotiated between 1.0 and 1.2).
*/
const CRYPTO_TLS = 'TLS';
/**
* @var string The type of stream. Can be either "_CLIENT" or "_SERVER".
* Used to complement the encryption type. Must be set by child classes
* for {@link setCrypto()} to work properly.
*/
protected $streamType = '';
/**
* @var string The current cryptography setting.
*/
protected $crypto = '';
/**
* Wraps around the specified stream.
*
* @param resource $stream The stream to wrap around.
*/
public function __construct($stream)
{
parent::__construct($stream, true);
}
/**
* Gets the current cryptography setting.
*
* @return string One of this class' CRYPTO_* constants.
*/
public function getCrypto()
{
return $this->crypto;
}
/**
* Sets the current connection's cryptography setting.
*
* @param string $type The encryption type to set. Must be one of this
* class' CRYPTO_* constants.
*
* @return boolean TRUE on success, FALSE on failure.
*/
public function setCrypto($type)
{
if (self::CRYPTO_OFF === $type) {
$result = stream_socket_enable_crypto($this->stream, false);
} else {
$result = stream_socket_enable_crypto(
$this->stream,
true,
constant("STREAM_CRYPTO_METHOD_{$type}{$this->streamType}")
);
}
if ($result) {
$this->crypto = $type;
}
return $result;
}
/**
* Checks whether the stream is available for operations.
*
* @return bool TRUE if the stream is available, FALSE otherwise.
*/
public function isAvailable()
{
if (parent::isStream($this->stream)) {
if ($this->isBlocking && feof($this->stream)) {
return false;
}
$meta = stream_get_meta_data($this->stream);
return !$meta['eof'];
}
return false;
}
/**
* Sets the size of a stream's buffer.
*
* @param int $size The desired size of the buffer, in bytes.
* @param string $direction The buffer of which direction to set. Valid
* values are the DIRECTION_* constants.
*
* @return bool TRUE on success, FALSE on failure.
*/
public function setBuffer($size, $direction = self::DIRECTION_ALL)
{
$result = parent::setBuffer($size, $direction);
if (self::DIRECTION_SEND === $direction
&& function_exists('stream_set_chunk_size') && !$result
) {
return false !== @stream_set_chunk_size($this->stream, $size);
}
return $result;
}
/**
* Shutdown a full-duplex connection
*
* Shutdowns (partially or not) a full-duplex connection.
*
* @param string $direction The direction for which to disable further
* communications.
*
* @return bool TRUE on success, FALSE on failure.
*/
public function shutdown($direction = self::DIRECTION_ALL)
{
$directionMap = array(
self::DIRECTION_ALL => STREAM_SHUT_RDWR,
self::DIRECTION_SEND => STREAM_SHUT_WR,
self::DIRECTION_RECEIVE => STREAM_SHUT_RD
);
return array_key_exists($direction, $directionMap)
&& stream_socket_shutdown($this->stream, $directionMap[$direction]);
}
}

View file

@ -0,0 +1,124 @@
<?php
/**
* Wrapper for network stream functionality.
*
* PHP has built in support for various types of network streams, such as HTTP and TCP sockets. One problem that arises with them is the fact that a single fread/fwrite call might not read/write all the data you intended, regardless of whether you're in blocking mode or not. While the PHP manual offers a workaround in the form of a loop with a few variables, using it every single time you want to read/write can be tedious.
This package abstracts this away, so that when you want to get exactly N amount of bytes, you can be sure the upper levels of your app will be dealing with N bytes. Oh, and the functionality is nicely wrapped in an object (but that's just the icing on the cake).
*
* PHP version 5
*
* @category Net
* @package PEAR2_Net_Transmitter
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0a5
* @link http://pear2.php.net/PEAR2_Net_Transmitter
*/
/**
* The namespace declaration.
*/
namespace PEAR2\Net\Transmitter;
/**
* Used to enable any exception in chaining.
*/
use Exception as E;
/**
* Exception thrown when something goes wrong with the connection.
*
* @category Net
* @package PEAR2_Net_Transmitter
* @author Vasil Rangelov <boen.robot@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear2.php.net/PEAR2_Net_Transmitter
*/
class SocketException extends StreamException
{
/**
* @var int The system level error code.
*/
protected $errorNo;
/**
* @var string The system level error message.
*/
protected $errorStr;
/**
* Creates a new socket exception.
*
* @param string $message The Exception message to throw.
* @param int $code The Exception code.
* @param E|null $previous Previous exception thrown,
* or NULL if there is none.
* @param int|string|resource|null $fragment The fragment up until the
* point of failure.
* On failure with sending, this is the number of bytes sent
* successfully before the failure.
* On failure when receiving, this is a string/stream holding
* the contents received successfully before the failure.
* NULL if the failure occured before the operation started.
* @param int $errorNo The system level error number.
* @param string $errorStr The system level
* error message.
*/
public function __construct(
$message = '',
$code = 0,
E $previous = null,
$fragment = null,
$errorNo = null,
$errorStr = null
) {
parent::__construct($message, $code, $previous, $fragment);
$this->errorNo = $errorNo;
$this->errorStr = $errorStr;
}
/**
* Gets the system level error code on the socket.
*
* @return int The system level error number.
*/
public function getSocketErrorNumber()
{
return $this->errorNo;
}
// @codeCoverageIgnoreStart
// Unreliable in testing.
/**
* Gets the system level error message on the socket.
*
* @return string The system level error message.
*/
public function getSocketErrorMessage()
{
return $this->errorStr;
}
/**
* Returns a string representation of the exception.
*
* @return string The exception as a string.
*/
public function __toString()
{
$result = parent::__toString();
if (null !== $this->getSocketErrorNumber()) {
$result .= "\nSocket error number:" . $this->getSocketErrorNumber();
}
if (null !== $this->getSocketErrorMessage()) {
$result .= "\nSocket error message:"
. $this->getSocketErrorMessage();
}
return $result;
}
// @codeCoverageIgnoreEnd
}

View file

@ -0,0 +1,605 @@
<?php
/**
* Wrapper for network stream functionality.
*
* PHP has built in support for various types of network streams, such as HTTP and TCP sockets. One problem that arises with them is the fact that a single fread/fwrite call might not read/write all the data you intended, regardless of whether you're in blocking mode or not. While the PHP manual offers a workaround in the form of a loop with a few variables, using it every single time you want to read/write can be tedious.
This package abstracts this away, so that when you want to get exactly N amount of bytes, you can be sure the upper levels of your app will be dealing with N bytes. Oh, and the functionality is nicely wrapped in an object (but that's just the icing on the cake).
*
* PHP version 5
*
* @category Net
* @package PEAR2_Net_Transmitter
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0a5
* @link http://pear2.php.net/PEAR2_Net_Transmitter
*/
/**
* The namespace declaration.
*/
namespace PEAR2\Net\Transmitter;
use Exception as E;
/**
* A stream transmitter.
*
* This is a convinience wrapper for stream functionality. Used to ensure data
* integrity. Designed for TCP sockets, but it has intentionally been made to
* accept any stream.
*
* @category Net
* @package PEAR2_Net_Transmitter
* @author Vasil Rangelov <boen.robot@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear2.php.net/PEAR2_Net_Transmitter
*/
class Stream
{
/**
* Used to stop settings in either direction being applied.
*/
const DIRECTION_NONE = 0;
/**
* Used to apply settings only to receiving.
*/
const DIRECTION_RECEIVE = 1;
/**
* Used to apply settings only to sending.
*/
const DIRECTION_SEND = 2;
/**
* Used to apply settings to both sending and receiving.
*/
const DIRECTION_ALL = 3;
/**
* @var resource The stream to wrap around.
*/
protected $stream;
/**
* @var bool Whether to automaticaly close the stream on
* object destruction if it's not a persistent one. Setting this to
* FALSE may be useful if you're only using this class "part time",
* while setting it to TRUE might be useful if you're doing some
* "on offs".
*/
protected $autoClose = false;
/**
* @var bool A flag that tells whether or not the stream is persistent.
*/
protected $persist;
/**
* @var bool Whether the wrapped stream is in blocking mode or not.
*/
protected $isBlocking = true;
/**
* @var array An associative array with the chunk size of each direction.
* Key is the direction, value is the size in bytes as integer.
*/
protected $chunkSize = array(
self::DIRECTION_SEND => 0xFFFFF, self::DIRECTION_RECEIVE => 0xFFFFF
);
/**
* Wraps around the specified stream.
*
* @param resource $stream The stream to wrap around.
* @param bool $autoClose Whether to automaticaly close the stream on
* object destruction if it's not a persistent one. Setting this to
* FALSE may be useful if you're only using this class "part time",
* while setting it to TRUE might be useful if you're doing some
* "on offs".
*
* @see static::isFresh()
*/
public function __construct($stream, $autoClose = false)
{
if (!self::isStream($stream)) {
throw $this->createException('Invalid stream supplied.', 1);
}
$this->stream = $stream;
$this->autoClose = (bool) $autoClose;
$this->persist = (bool) preg_match(
'#\s?persistent\s?#sm',
get_resource_type($stream)
);
$meta = stream_get_meta_data($stream);
$this->isBlocking = isset($meta['blocked']) ? $meta['blocked'] : true;
}
/**
* PHP error handler for connection errors.
*
* @param string $level Level of PHP error raised. Ignored.
* @param string $message Message raised by PHP.
*
* @return void
* @throws SocketException That's how the error is handled.
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
protected function handleError($level, $message)
{
throw $this->createException($message, 0);
}
/**
* Checks if a given variable is a stream resource.
*
* @param mixed $var The variable to check.
*
* @return bool TRUE on success, FALSE on failure.
*/
public static function isStream($var)
{
return is_resource($var)
&& (bool) preg_match('#\s?stream$#sm', get_resource_type($var));
}
/**
* Checks whether the wrapped stream is fresh.
*
* Checks whether the wrapped stream is fresh. A stream is considered fresh
* if there hasn't been any activity on it. Particularly useful for
* detecting reused persistent connections.
*
* @return bool TRUE if the socket is fresh, FALSE otherwise.
*/
public function isFresh()
{
return ftell($this->stream) === 0;
}
/**
* Checks whether the wrapped stream is a persistent one.
*
* @return bool TRUE if the stream is a persistent one, FALSE otherwise.
*/
public function isPersistent()
{
return $this->persist;
}
/**
* Checks whether the wrapped stream is a blocking one.
*
* @return bool TRUE if the stream is a blocking one, FALSE otherwise.
*/
public function isBlocking()
{
return $this->isBlocking;
}
/**
* Sets blocking mode.
*
* @param bool $block Sets whether the stream is in blocking mode.
*
* @return bool TRUE on success, FALSE on failure.
*/
public function setIsBlocking($block)
{
$block = (bool)$block;
if (stream_set_blocking($this->stream, (int)$block)) {
$this->isBlocking = $block;
return true;
}
return false;
}
/**
* Sets the timeout for the stream.
*
* @param int $seconds Timeout in seconds.
* @param int $microseconds Timeout in microseconds to be added to the
* seconds.
*
* @return bool TRUE on success, FALSE on failure.
*/
public function setTimeout($seconds, $microseconds = 0)
{
return stream_set_timeout($this->stream, $seconds, $microseconds);
}
/**
* Sets the size of a stream's buffer.
*
* @param int $size The desired size of the buffer, in bytes.
* @param string $direction The buffer of which direction to set. Valid
* values are the DIRECTION_* constants.
*
* @return bool TRUE on success, FALSE on failure.
*/
public function setBuffer($size, $direction = self::DIRECTION_ALL)
{
switch($direction) {
case self::DIRECTION_SEND:
return stream_set_write_buffer($this->stream, $size) === 0;
case self::DIRECTION_RECEIVE:
return stream_set_read_buffer($this->stream, $size) === 0;
case self::DIRECTION_ALL:
return $this->setBuffer($size, self::DIRECTION_RECEIVE)
&& $this->setBuffer($size, self::DIRECTION_SEND);
}
return false;
}
/**
* Sets the size of the chunk.
*
* To ensure data integrity, as well as to allow for lower memory
* consumption, data is sent/received in chunks. This function
* allows you to set the size of each chunk. The default is 0xFFFFF.
*
* @param int $size The desired size of the chunk, in bytes.
* @param string $direction The chunk of which direction to set. Valid
* values are the DIRECTION_* constants.
*
* @return bool TRUE on success, FALSE on failure.
*/
public function setChunk($size, $direction = self::DIRECTION_ALL)
{
$size = (int) $size;
if ($size <= 0) {
return false;
}
switch($direction) {
case self::DIRECTION_SEND:
case self::DIRECTION_RECEIVE:
$this->chunkSize[$direction] = $size;
return true;
case self::DIRECTION_ALL:
$this->chunkSize[self::DIRECTION_SEND]
= $this->chunkSize[self::DIRECTION_RECEIVE] = $size;
return true;
}
return false;
}
/**
* Gets the size of the chunk.
*
* @param string $direction The chunk of which direction to get. Valid
* values are the DIRECTION_* constants.
*
* @return int|array|false The chunk size in bytes,
* or an array of chunk sizes with the directions as keys.
* FALSE on invalid direction.
*/
public function getChunk($direction = self::DIRECTION_ALL)
{
switch($direction) {
case self::DIRECTION_SEND:
case self::DIRECTION_RECEIVE:
return $this->chunkSize[$direction];
case self::DIRECTION_ALL:
return $this->chunkSize;
}
return false;
}
/**
* Sends a string or stream over the wrapped stream.
*
* Sends a string or stream over the wrapped stream. If a seekable stream is
* provided, it will be seeked back to the same position it was passed as,
* regardless of the $offset parameter.
*
* @param string|resource $contents The string or stream to send.
* @param int $offset The offset from which to start sending.
* If a stream is provided, and this is set to NULL, sending will start
* from the current stream position.
* @param int $length The maximum length to send. If omitted,
* the string/stream will be sent to its end.
*
* @return int The number of bytes sent.
*/
public function send($contents, $offset = null, $length = null)
{
$bytes = 0;
$chunkSize = $this->chunkSize[self::DIRECTION_SEND];
$lengthIsNotNull = null !== $length;
$offsetIsNotNull = null !== $offset;
if (self::isStream($contents)) {
if ($offsetIsNotNull) {
$oldPos = ftell($contents);
fseek($contents, $offset, SEEK_SET);
}
while (!feof($contents)) {
if ($lengthIsNotNull
&& 0 === $chunkSize = min($chunkSize, $length - $bytes)
) {
break;
}
$bytesNow = @fwrite(
$this->stream,
fread($contents, $chunkSize)
);
if (0 != $bytesNow) {
$bytes += $bytesNow;
} elseif ($this->isBlocking || false === $bytesNow) {
throw $this->createException(
'Failed while sending stream.',
2,
null,
$bytes
);
} else {
usleep(300000);
}
$this->isAcceptingData(null);
}
if ($offsetIsNotNull) {
fseek($contents, $oldPos, SEEK_SET);
} else {
fseek($contents, -$bytes, SEEK_CUR);
}
} else {
$contents = (string) $contents;
if ($offsetIsNotNull) {
$contents = substr($contents, $offset);
}
if ($lengthIsNotNull) {
$contents = substr($contents, 0, $length);
}
$bytesToSend = (double) sprintf('%u', strlen($contents));
while ($bytes < $bytesToSend) {
$bytesNow = @fwrite(
$this->stream,
substr($contents, $bytes, $chunkSize)
);
if (0 != $bytesNow) {
$bytes += $bytesNow;
} elseif ($this->isBlocking || false === $bytesNow) {
throw $this->createException(
'Failed while sending string.',
3,
null,
$bytes
);
} else {
usleep(300000);
}
$this->isAcceptingData(null);
}
}
return $bytes;
}
/**
* Reads from the wrapped stream to receive.
*
* Reads from the wrapped stream to receive content as a string.
*
* @param int $length The number of bytes to receive.
* @param string $what Descriptive string about what is being received
* (used in exception messages).
*
* @return string The received content.
*/
public function receive($length, $what = 'data')
{
$result = '';
$chunkSize = $this->chunkSize[self::DIRECTION_RECEIVE];
while ($length > 0) {
while ($this->isAvailable()) {
$fragment = fread($this->stream, min($length, $chunkSize));
if ('' != $fragment) {
$length -= strlen($fragment);
$result .= $fragment;
continue 2;
} elseif (!$this->isBlocking && !(false === $fragment)) {
usleep(3000);
continue 2;
}
}
throw $this->createException(
"Failed while receiving {$what}",
4,
null,
$result
);
}
return $result;
}
/**
* Reads from the wrapped stream to receive.
*
* Reads from the wrapped stream to receive content as a stream.
*
* @param int $length The number of bytes to receive.
* @param FilterCollection $filters A collection of filters to apply to the
* stream while receiving. Note that the filters will not be present on
* the stream after receiving is done.
* @param string $what Descriptive string about what is being
* received (used in exception messages).
*
* @return resource The received content.
*/
public function receiveStream(
$length,
FilterCollection $filters = null,
$what = 'stream data'
) {
$result = fopen('php://temp', 'r+b');
$appliedFilters = array();
if (null !== $filters) {
foreach ($filters as $filtername => $params) {
$appliedFilters[] = stream_filter_append(
$result,
$filtername,
STREAM_FILTER_WRITE,
$params
);
}
}
$chunkSize = $this->chunkSize[self::DIRECTION_RECEIVE];
while ($length > 0) {
while ($this->isAvailable()) {
$fragment = fread($this->stream, min($length, $chunkSize));
if ('' != $fragment) {
$length -= strlen($fragment);
fwrite($result, $fragment);
continue 2;
} elseif (!$this->isBlocking && !(false === $fragment)) {
usleep(3000);
continue 2;
}
}
foreach ($appliedFilters as $filter) {
stream_filter_remove($filter);
}
rewind($result);
throw $this->createException(
"Failed while receiving {$what}",
5,
null,
$result
);
}
foreach ($appliedFilters as $filter) {
stream_filter_remove($filter);
}
rewind($result);
return $result;
}
/**
* Checks whether the stream is available for operations.
*
* For network streams, this means whether the other end has closed the
* connection.
*
* @return bool TRUE if the stream is available, FALSE otherwise.
*/
public function isAvailable()
{
return self::isStream($this->stream) && !feof($this->stream);
}
/**
* Checks whether there is data to be read from the wrapped stream.
*
* @param int|null $sTimeout If theere isn't data awaiting currently,
* wait for it this many seconds for data to arrive. If NULL is
* specified, wait indefinetly for that.
* @param int $usTimeout Microseconds to add to the waiting time.
*
* @return bool TRUE if there is data to be read, FALSE otherwise.
* @SuppressWarnings(PHPMD.ShortVariable)
*/
public function isDataAwaiting($sTimeout = 0, $usTimeout = 0)
{
if (self::isStream($this->stream)) {
if (null === $sTimeout && !$this->isBlocking) {
$meta = stream_get_meta_data($this->stream);
return !$meta['eof'];
}
$w = $e = null;
$r = array($this->stream);
return 1 === @/* due to PHP bug #54563 */stream_select(
$r,
$w,
$e,
$sTimeout,
$usTimeout
);
}
return false;
}
/**
* Checks whether the wrapped stream can be written to without a block.
*
* @param int|null $sTimeout If the stream isn't currently accepting data,
* wait for it this many seconds to start accepting data. If NULL is
* specified, wait indefinetly for that.
* @param int $usTimeout Microseconds to add to the waiting time.
*
* @return bool TRUE if the wrapped stream would not block on a write, FALSE
* otherwise.
* @SuppressWarnings(PHPMD.ShortVariable)
*/
public function isAcceptingData($sTimeout = 0, $usTimeout = 0)
{
if (self::isStream($this->stream)) {
if (!$this->isBlocking) {
$meta = stream_get_meta_data($this->stream);
return !$meta['eof'];
} elseif (feof($this->stream)) {
return false;
}
$r = $e = null;
$w = array($this->stream);
return 1 === @/* due to PHP bug #54563 */stream_select(
$r,
$w,
$e,
$sTimeout,
$usTimeout
);
}
return false;
}
/**
* Closes the opened stream, unless it's a persistent one.
*/
public function __destruct()
{
if ((!$this->persist) && $this->autoClose) {
$this->close();
}
}
/**
* Closes the opened stream, even if it is a persistent one.
*
* @return bool TRUE on success, FALSE on failure.
*/
public function close()
{
return self::isStream($this->stream) && fclose($this->stream);
}
/**
* Creates a new exception.
*
* Creates a new exception. Used by the rest of the functions in this class.
* Override in derived classes for custom exception handling.
*
* @param string $message The exception message.
* @param int $code The exception code.
* @param E|null $previous Previous exception thrown,
* or NULL if there is none.
* @param int|string|resource|null $fragment The fragment up until the
* point of failure.
* On failure with sending, this is the number of bytes sent
* successfully before the failure.
* On failure when receiving, this is a string/stream holding
* the contents received successfully before the failure.
*
* @return StreamException The exception to then be thrown.
*/
protected function createException(
$message,
$code = 0,
E $previous = null,
$fragment = null
) {
return new StreamException($message, $code, $previous, $fragment);
}
}

View file

@ -0,0 +1,119 @@
<?php
/**
* Wrapper for network stream functionality.
*
* PHP has built in support for various types of network streams, such as HTTP and TCP sockets. One problem that arises with them is the fact that a single fread/fwrite call might not read/write all the data you intended, regardless of whether you're in blocking mode or not. While the PHP manual offers a workaround in the form of a loop with a few variables, using it every single time you want to read/write can be tedious.
This package abstracts this away, so that when you want to get exactly N amount of bytes, you can be sure the upper levels of your app will be dealing with N bytes. Oh, and the functionality is nicely wrapped in an object (but that's just the icing on the cake).
*
* PHP version 5
*
* @category Net
* @package PEAR2_Net_Transmitter
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0a5
* @link http://pear2.php.net/PEAR2_Net_Transmitter
*/
/**
* The namespace declaration.
*/
namespace PEAR2\Net\Transmitter;
/**
* Base for this exception.
*/
use RuntimeException;
/**
* Used to enable any exception in chaining.
*/
use Exception as E;
/**
* Exception thrown when something goes wrong with the connection.
*
* @category Net
* @package PEAR2_Net_Transmitter
* @author Vasil Rangelov <boen.robot@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear2.php.net/PEAR2_Net_Transmitter
*/
class StreamException extends RuntimeException implements Exception
{
/**
* @var int|string|resource|null The fragment up until the point of failure.
* On failure with sending, this is the number of bytes sent
* successfully before the failure.
* On failure when receiving, this is a string/stream holding
* the contents received successfully before the failure.
* NULL if the failure occured before the operation started.
*/
protected $fragment = null;
/**
* Creates a new stream exception.
*
* @param string $message The Exception message to throw.
* @param int $code The Exception code.
* @param E|null $previous Previous exception thrown,
* or NULL if there is none.
* @param int|string|resource|null $fragment The fragment up until the
* point of failure.
* On failure with sending, this is the number of bytes sent
* successfully before the failure.
* On failure when receiving, this is a string/stream holding
* the contents received successfully before the failure.
* NULL if the failure occured before the operation started.
*/
public function __construct(
$message,
$code,
E $previous = null,
$fragment = null
) {
parent::__construct($message, $code, $previous);
$this->fragment = $fragment;
}
/**
* Gets the stream fragment.
*
* @return int|string|resource|null The fragment up until the
* point of failure.
* On failure with sending, this is the number of bytes sent
* successfully before the failure.
* On failure when receiving, this is a string/stream holding
* the contents received successfully before the failure.
* NULL if the failure occured before the operation started.
*/
public function getFragment()
{
return $this->fragment;
}
// @codeCoverageIgnoreStart
// Unreliable in testing.
/**
* Returns a string representation of the exception.
*
* @return string The exception as a string.
*/
public function __toString()
{
$result = parent::__toString();
if (null !== $this->fragment) {
$result .= "\nFragment: ";
if (is_scalar($this->fragment)) {
$result .= (string)$this->fragment;
} else {
$result .= stream_get_contents($this->fragment);
}
}
return $result;
}
// @codeCoverageIgnoreEnd
}

View file

@ -0,0 +1,400 @@
<?php
/**
* Wrapper for network stream functionality.
*
* PHP has built in support for various types of network streams, such as HTTP and TCP sockets. One problem that arises with them is the fact that a single fread/fwrite call might not read/write all the data you intended, regardless of whether you're in blocking mode or not. While the PHP manual offers a workaround in the form of a loop with a few variables, using it every single time you want to read/write can be tedious.
This package abstracts this away, so that when you want to get exactly N amount of bytes, you can be sure the upper levels of your app will be dealing with N bytes. Oh, and the functionality is nicely wrapped in an object (but that's just the icing on the cake).
*
* PHP version 5
*
* @category Net
* @package PEAR2_Net_Transmitter
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0a5
* @link http://pear2.php.net/PEAR2_Net_Transmitter
*/
/**
* The namespace declaration.
*/
namespace PEAR2\Net\Transmitter;
/**
* Used for managing persistent connections.
*/
use PEAR2\Cache\SHM;
/**
* Used for matching arbitrary exceptions in
* {@link TcpClient::createException()} and releasing locks properly.
*/
use Exception as E;
/**
* A socket transmitter.
*
* This is a convinience wrapper for socket functionality. Used to ensure data
* integrity.
*
* @category Net
* @package PEAR2_Net_Transmitter
* @author Vasil Rangelov <boen.robot@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear2.php.net/PEAR2_Net_Transmitter
*/
class TcpClient extends NetworkStream
{
/**
* @var int The error code of the last error on the socket.
*/
protected $errorNo = 0;
/**
* @var string The error message of the last error on the socket.
*/
protected $errorStr = null;
/**
* @var SHM Persistent connection handler. Remains NULL for non-persistent
* connections.
*/
protected $shmHandler = null;
/**
* @var array An array with all connections from this PHP request (as keys)
* and their lock state (as a value).
*/
protected static $lockState = array();
protected static $cryptoScheme = array(
parent::CRYPTO_OFF => 'tcp',
parent::CRYPTO_SSL2 => 'sslv2',
parent::CRYPTO_SSL3 => 'sslv3',
parent::CRYPTO_SSL => 'ssl',
parent::CRYPTO_TLS => 'tls'
);
/**
* @var string The URI of this connection.
*/
protected $uri;
/**
* Creates a new connection with the specified options.
*
* @param string $host Hostname (IP or domain) of the server.
* @param int $port The port on the server.
* @param bool $persist Whether or not the connection should be a
* persistent one.
* @param float $timeout The timeout for the connection.
* @param string $key A string that uniquely identifies the
* connection.
* @param string $crypto Encryption setting. Must be one of the
* NetworkStream::CRYPTO_* constants. By default, encryption is
* disabled. If the setting has an associated scheme for it, it will be
* used, and if not, the setting will be adjusted right after the
* connection is estabilished.
* @param resource $context A context for the socket.
*/
public function __construct(
$host,
$port,
$persist = false,
$timeout = null,
$key = '',
$crypto = parent::CRYPTO_OFF,
$context = null
) {
$this->streamType = '_CLIENT';
if (strpos($host, ':') !== false) {
$host = "[{$host}]";
}
$flags = STREAM_CLIENT_CONNECT;
if ($persist) {
$flags |= STREAM_CLIENT_PERSISTENT;
}
$timeout
= null == $timeout ? ini_get('default_socket_timeout') : $timeout;
$key = rawurlencode($key);
if (null === $context) {
$context = stream_context_get_default();
} elseif ((!is_resource($context))
|| ('stream-context' !== get_resource_type($context))
) {
throw $this->createException('Invalid context supplied.', 6);
}
$hasCryptoScheme = array_key_exists($crypto, static::$cryptoScheme);
$scheme = $hasCryptoScheme ? static::$cryptoScheme[$crypto] : 'tcp';
$this->uri = "{$scheme}://{$host}:{$port}/{$key}";
set_error_handler(array($this, 'handleError'));
try {
parent::__construct(
stream_socket_client(
$this->uri,
$this->errorNo,
$this->errorStr,
$timeout,
$flags,
$context
)
);
restore_error_handler();
} catch (E $e) {
restore_error_handler();
if (0 === $this->errorNo) {
throw $this->createException(
'Failed to initialize socket.',
7,
$e
);
}
throw $this->createException(
'Failed to connect with socket.',
8,
$e
);
}
if ($hasCryptoScheme) {
$this->crypto = $crypto;
} elseif (parent::CRYPTO_OFF !== $crypto) {
$this->setCrypto($crypto);
}
$this->setIsBlocking(parent::CRYPTO_OFF === $crypto);
if ($persist) {
$this->shmHandler = SHM::factory(
__CLASS__ . ' ' . $this->uri . ' '
);
self::$lockState[$this->uri] = self::DIRECTION_NONE;
}
}
/**
* Creates a new exception.
*
* Creates a new exception. Used by the rest of the functions in this class.
*
* @param string $message The exception message.
* @param int $code The exception code.
* @param E|null $previous Previous exception thrown,
* or NULL if there is none.
* @param int|string|resource|null $fragment The fragment up until the
* point of failure.
* On failure with sending, this is the number of bytes sent
* successfully before the failure.
* On failure when receiving, this is a string/stream holding
* the contents received successfully before the failure.
*
* @return SocketException The exception to then be thrown.
*/
protected function createException(
$message,
$code = 0,
E $previous = null,
$fragment = null
) {
return new SocketException(
$message,
$code,
$previous,
$fragment,
$this->errorNo,
$this->errorStr
);
}
/**
* Locks transmission.
*
* Locks transmission in one or more directions. Useful when dealing with
* persistent connections. Note that every send/receive call implicitly
* calls this function and then restores it to the previous state. You only
* need to call this function if you need to do an uninterrputed sequence of
* such calls.
*
* @param int $direction The direction(s) to have locked. Acceptable values
* are the DIRECTION_* constants. If a lock for a direction can't be
* obtained immediatly, the function will block until one is aquired.
* Note that if you specify {@link DIRECTION_ALL}, the sending lock will
* be obtained before the receiving one, and if obtaining the receiving
* lock afterwards fails, the sending lock will be released too.
* @param bool $replace Whether to replace all locks with the specified
* ones. Setting this to FALSE will make the function only obtain the
* locks which are not already obtained.
*
* @return int|false The previous state or FALSE if the connection is not
* persistent or arguments are invalid.
*/
public function lock($direction = self::DIRECTION_ALL, $replace = false)
{
if ($this->persist && is_int($direction)) {
$old = self::$lockState[$this->uri];
if ($direction & self::DIRECTION_SEND) {
if (($old & self::DIRECTION_SEND)
|| $this->shmHandler->lock(self::DIRECTION_SEND)
) {
self::$lockState[$this->uri] |= self::DIRECTION_SEND;
} else {
throw new LockException('Unable to obtain sending lock.');
}
} elseif ($replace) {
if (!($old & self::DIRECTION_SEND)
|| $this->shmHandler->unlock(self::DIRECTION_SEND)
) {
self::$lockState[$this->uri] &= ~self::DIRECTION_SEND;
} else {
throw new LockException('Unable to release sending lock.');
}
}
try {
if ($direction & self::DIRECTION_RECEIVE) {
if (($old & self::DIRECTION_RECEIVE)
|| $this->shmHandler->lock(self::DIRECTION_RECEIVE)
) {
self::$lockState[$this->uri] |= self::DIRECTION_RECEIVE;
} else {
throw new LockException(
'Unable to obtain receiving lock.'
);
}
} elseif ($replace) {
if (!($old & self::DIRECTION_RECEIVE)
|| $this->shmHandler->unlock(self::DIRECTION_RECEIVE)
) {
self::$lockState[$this->uri]
&= ~self::DIRECTION_RECEIVE;
} else {
throw new LockException(
'Unable to release receiving lock.'
);
}
}
} catch (LockException $e) {
if ($direction & self::DIRECTION_SEND
&& !($old & self::DIRECTION_SEND)
) {
$this->shmHandler->unlock(self::DIRECTION_SEND);
}
throw $e;
}
return $old;
}
return false;
}
/**
* Sends a string or stream to the server.
*
* Sends a string or stream to the server. If a seekable stream is
* provided, it will be seeked back to the same position it was passed as,
* regardless of the $offset parameter.
*
* @param string|resource $contents The string or stream to send.
* @param int $offset The offset from which to start sending.
* If a stream is provided, and this is set to NULL, sending will start
* from the current stream position.
* @param int $length The maximum length to send. If omitted,
* the string/stream will be sent to its end.
*
* @return int The number of bytes sent.
*/
public function send($contents, $offset = null, $length = null)
{
if (false === ($previousState = $this->lock(self::DIRECTION_SEND))
&& $this->persist
) {
throw $this->createException(
'Unable to obtain sending lock',
10
);
}
try {
$result = parent::send($contents, $offset, $length);
} catch (E $e) {
$this->lock($previousState, true);
throw $e;
}
$this->lock($previousState, true);
return $result;
}
/**
* Receives data from the server.
*
* Receives data from the server as a string.
*
* @param int $length The number of bytes to receive.
* @param string $what Descriptive string about what is being received
* (used in exception messages).
*
* @return string The received content.
*/
public function receive($length, $what = 'data')
{
if (false === ($previousState = $this->lock(self::DIRECTION_RECEIVE))
&& $this->persist
) {
throw $this->createException(
'Unable to obtain receiving lock',
9
);
}
try {
$result = parent::receive($length, $what);
} catch (E $e) {
$this->lock($previousState, true);
throw $e;
}
$this->lock($previousState, true);
return $result;
}
/**
* Receives data from the server.
*
* Receives data from the server as a stream.
*
* @param int $length The number of bytes to receive.
* @param FilterCollection $filters A collection of filters to apply to the
* stream while receiving. Note that the filters will not be present on
* the stream after receiving is done.
* @param string $what Descriptive string about what is being
* received (used in exception messages).
*
* @return resource The received content.
*/
public function receiveStream(
$length,
FilterCollection $filters = null,
$what = 'stream data'
) {
if (false === ($previousState = $this->lock(self::DIRECTION_RECEIVE))
&& $this->persist
) {
throw $this->createException(
'Unable to obtain receiving lock',
9
);
}
try {
$result = parent::receiveStream($length, $filters, $what);
} catch (E $e) {
$this->lock($previousState, true);
throw $e;
}
$this->lock($previousState, true);
return $result;
}
}

View file

@ -0,0 +1,147 @@
<?php
/**
* Wrapper for network stream functionality.
*
* PHP has built in support for various types of network streams, such as HTTP and TCP sockets. One problem that arises with them is the fact that a single fread/fwrite call might not read/write all the data you intended, regardless of whether you're in blocking mode or not. While the PHP manual offers a workaround in the form of a loop with a few variables, using it every single time you want to read/write can be tedious.
This package abstracts this away, so that when you want to get exactly N amount of bytes, you can be sure the upper levels of your app will be dealing with N bytes. Oh, and the functionality is nicely wrapped in an object (but that's just the icing on the cake).
*
* PHP version 5
*
* @category Net
* @package PEAR2_Net_Transmitter
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0a5
* @link http://pear2.php.net/PEAR2_Net_Transmitter
*/
/**
* The namespace declaration.
*/
namespace PEAR2\Net\Transmitter;
use Exception as E;
/**
* A transmitter for connections to a socket server.
*
* This is a convinience wrapper for functionality of socket server connections.
* Used to ensure data integrity. Server handling is not part of the class in
* order to allow its usage as part of various server implementations (e.g. fork
* and/or sequential).
*
* @category Net
* @package PEAR2_Net_Transmitter
* @author Vasil Rangelov <boen.robot@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear2.php.net/PEAR2_Net_Transmitter
*/
class TcpServerConnection extends NetworkStream
{
/**
* @var string The IP address of the connected client.
*/
protected $peerIP;
/**
* @var int The port of the connected client.
*/
protected $peerPort;
/**
* Creates a new connection with the specified options.
*
* @param resource $server A socket server, created with
* {@link stream_socket_server()}.
* @param float $timeout The timeout for the connection.
*/
public function __construct($server, $timeout = null)
{
$this->streamType = '_SERVER';
if (!self::isStream($server)) {
throw $this->createException('Invalid server supplied.', 9);
}
$timeout
= null == $timeout ? ini_get('default_socket_timeout') : $timeout;
set_error_handler(array($this, 'handleError'));
try {
parent::__construct(
stream_socket_accept($server, $timeout, $peername)
);
restore_error_handler();
$portString = strrchr($peername, ':');
$this->peerPort = (int) substr($portString, 1);
$ipString = substr(
$peername,
0,
strlen($peername) - strlen($portString)
);
if (strpos($ipString, '[') === 0
&& strpos(strrev($ipString), ']') === 0
) {
$ipString = substr($ipString, 1, strlen($ipString) - 2);
}
$this->peerIP = $ipString;
} catch (E $e) {
restore_error_handler();
throw $this->createException(
'Failed to initialize connection.',
10,
$e
);
}
}
/**
* Gets the IP address of the connected client.
*
* @return string The IP address of the connected client.
*/
public function getPeerIP()
{
return $this->peerIP;
}
/**
* Gets the port of the connected client.
*
* @return int The port of the connected client.
*/
public function getPeerPort()
{
return $this->peerPort;
}
/**
* Creates a new exception.
*
* Creates a new exception. Used by the rest of the functions in this class.
*
* @param string $message The exception message.
* @param int $code The exception code.
* @param E|null $previous Previous exception thrown, or NULL if there
* is none.
* @param string|null $fragment The fragment up until the point of failure.
* NULL if the failure occured before the operation started.
*
* @return SocketException The exception to then be thrown.
*/
protected function createException(
$message,
$code = 0,
E $previous = null,
$fragment = null
) {
return new SocketException(
$message,
$code,
$previous,
$fragment
);
}
}

55
ajax_add_profile.php Normal file
View file

@ -0,0 +1,55 @@
<?php
header('Content-Type: application/json');
use PEAR2\Net\RouterOS;
require_once 'PEAR2/Autoload.php';
require_once 'config.php';
if ( !isset($_SESSION) ) session_start();
$util = new RouterOS\Util($client = new RouterOS\Client("$host", "$user", "$pass"));
$profile_name=strtolower($_GET['profile_name']);
$session_timeout=$_GET['session_timeout'];
$shared_users=$_GET['shared_users'];
$mac_cookie_timeout=$_GET['mac_cookie_timeout'];
$keepalive_timeout=$_GET['keepalive_timeout'];
$rx_rate_limit=$_GET['rx_rate_limit'];
$tx_rate_limit=$_GET['tx_rate_limit'];
$rate_limit = $rx_rate_limit.'/'.$tx_rate_limit;
if (empty($session_timeout)) $session_timeout = '3d 00:00:00';
if (empty($mac_cookie_timeout)) $mac_cookie_timeout = '3d 00:00:00';
if (empty($keepalive_timeout)) $keepalive_timeout = '00:02:00';
if ($_SESSION['user_level'] == 1) {
if (!empty($profile_name)) {
$util->setMenu('/ip hotspot user profile');
if(strtolower($session_timeout) == 'none') $session_timeout = '00:00:00';
$util->add(
array(
'name' => "$profile_name",
'rate-limit' => "$rate_limit",
'session-timeout' => "$session_timeout",
'shared-users' => "$shared_users",
'mac-cookie-timeout' => "$mac_cookie_timeout",
'keepalive-timeout' => "$keepalive_timeout"
)
);
/*
if(strtolower($session_timeout) == 'none') {
$id = $client->sendSync(new Request('/ip/hotspot/user/profile/print .proplist=.id', null, Query::where('name', $profile_name)))->getArgument('.id');
$util->setMenu('/ip hotspot user profile');
$util->unsetValue($id, 'session-timeout');
} */
echo 2; //Success
}
else
{
echo 1; //Profile name/Session Timeout Empty
}
}
else
{
echo 0; //Not Authorised
}
?>

34
ajax_add_sysuser.php Normal file
View file

@ -0,0 +1,34 @@
<?php
if ( !isset($_SESSION) ) session_start();
if (($_SESSION['user_level'] == 1) and (!empty($_GET['username']))) {
include('dbconfig.php');
$password='password';
$password=sha1($password);
$username=strtolower($_GET['username']);
$firstname=$_GET['firstname'];
$lastname=$_GET['lastname'];
$user_level=$_GET['user_level'];
$status=$_GET['status'];
$stmt = $DB_con->prepare("SELECT * FROM hotspot_users WHERE username =:username");
$stmt->execute(array(':username' => $username));
$count = $stmt->rowCount();
if ($count != 0) {
echo 1;
}
else
{
$stmt = $DB_con->prepare("insert into hotspot_users (username, password, firstname, lastname, date_added, user_level, status)
values(:username, :password, :firstname, :lastname, CURDATE(), :user_level, :status)");
$stmt->execute(array(':username' => $username, ':password' => $password, ':firstname' => $firstname,
':lastname' => $lastname, ':user_level' => $user_level, ':status' => $status));
echo 2;
}
}
else {
echo 0;
}
// End Adding a new System User Details, Returned from modal_add_user.php
?>

116
ajax_adduser.php Normal file
View file

@ -0,0 +1,116 @@
<?php
require_once 'settings.php';
if (isset($_GET['name'])) $username = $_GET['name'];
if (isset($_GET['psd'])) $password = $_GET['psd'];
if (isset($_GET['limit_uptime'])) $limit_uptime = $_GET['limit_uptime'];
if (isset($_GET['limit_bytes'])) $limit_bytes = $_GET['limit_bytes'];
if (isset($_GET['profile'])) $profile = $_GET['profile'];
if ( !isset($_SESSION) ) session_start();
$util->setMenu('/ip hotspot user');
$iv = count($util);
if ((!empty($username)) and (!empty($password)) and (!empty($profile))) {
if (intval($limit_bytes) != 0) {
$limit_bytes_total = (intval($limit_bytes) * 1024 * 1024 * 1024 );
$util->add(
array(
'name' => "$username",
'password' => "$password",
'limit-uptime' => "$limit_uptime",
'limit-bytes-total' => "$limit_bytes_total",
'profile' => "$profile"
)
);
}
else
{
$util->add(
array(
'name' => "$username",
'password' => "$password",
'limit-uptime' => "$limit_uptime",
'profile' => "$profile"
)
);
$limit_bytes = 0; // For Adding it to Local database
}
if ($iv != count($util)) {
include('dbconfig.php');
$stmt = $DB_con->prepare("SELECT booking_id from hotspot_vouchers ORDER BY booking_id DESC LIMIT 1");
$stmt->execute(array());
$row = $stmt->fetch(PDO::FETCH_ASSOC);
$booking_id = $row['booking_id'];
$booking_id++;
$uid = $booking_id.'-1-'.date('dmY');
//$creator = $_SESSION['username'].'['.$_SESSION['id'].']';
$stmt = $DB_con->prepare("UPDATE hotspot_vouchers set status=:status WHERE 1");
$stmt->execute(array(':status' => 'Over'));
$stmt = $DB_con->prepare("insert into hotspot_vouchers (created_on, created_by, creator, user_name, password, printed_times,
printed_last, status, group_of, booking_id, limit_uptime, limit_bytes, profile, uid)
values(NOW(), :created_by, :creator, :user_name, :password, :printed_times, :printed_last, :status, :group_of,
:booking_id, :limit_uptime, :limit_bytes, :profile, :uid)");
$stmt->execute(array(':created_by' => $_SESSION['username'], ':creator' => $_SESSION['id'], ':user_name' => $username, ':password' => $password,
':printed_times' => 0, ':printed_last' => '', ':status' => 'Active', ':group_of' => 1,
':booking_id' => $booking_id, ':limit_uptime' => $limit_uptime, ':limit_bytes' => $limit_bytes,
':profile' => $profile, ':uid' => $uid));
// here starts Echo String
$echo_text ='
<div class="container">
<div class="row" style="padding-top:20px;">
<div class="col-sm-12 col-md-12">
<div class="panel panel-primary">
<div class="panel-heading"><h3 class="text-center">Hotspot User Voucher</h3></div>
<div class="panel-body">
<form id="userForm" class="form-horizontal" method="GET" action="" enctype="multipart/form-data">
<div class="col-sm-12 col-md-12">
<table cellpadding="0" cellspacing="0" border="0" class="table table-bordered" id="example">
<thead>
<tr>
<th width="10%"></th>
<th colspan="2">Username</th>
<th colspan="2">Password</th>
</tr>
</thead>
<tbody>';
$echo_text .= '<tr>
<td width="10%" style="margin:0px; border: 0px; padding: 2px;"><img src="images/logo.png" width="250" height="50"></td>
<td colspan="2"><input type="text" name="username" class="form-control" value="Username : '.$username.'" placeholder="User Name" readonly></td>
<td colspan="2"><input type="text" name="password" class="form-control" value="Password : '.$password.'" placeholder="Password" readonly></td>
</tr>
<tr>';
if (intval($limit_bytes) != 0) {
$echo_text .= '<td colspan="5">Validity : '.$limit_uptime.'ays; Counts from First login; Data usage Maximum : '.$limit_bytes_total.' Bytes; Bandwidth : '.$profile.'; HAPPY BROWSING...</td>';
}
else
{
$echo_text .= '<td colspan="5">Validity : '.$limit_uptime.'ays; Counts from First login; Bandwidth/Profile : '.$profile.'; HAPPY BROWSING...</td>';
}
$echo_text .= '
</tr>
</tbody>
</table>
</div>
</form>
</div>
</div>
</div>
<div class="col-sm-3 col-sm-offset-5">
<button onclick="window.print();" class="btn btn-primary" ><i class="icon-save icon-large"></i></a>&nbsp;PRINT</button>&nbsp;&nbsp;
<button onclick="document.getElementById("single").style.display="none !important;" type="reset" class="btn btn-danger"><i class="icon-save icon-large"></i></a>&nbsp;Reset</button>&nbsp;&nbsp;
<button data-dismiss="modal" class="btn btn-info" ><i class="icon-save icon-large"></i></a>&nbsp;BACK</button>&nbsp;&nbsp;
</div>
</div>
</div>';
echo $echo_text;
}
else
{
echo '<script>cmodalOkCancel("ERROR/DUPLICATE", " Username '.$username.' is not added, Found as Duplicate. Try some other name", "error");</script>';
}
}
//End Adding a Guest User
?>

90
ajax_addusers.php Normal file
View file

@ -0,0 +1,90 @@
<?php error_reporting(E_ALL);
ini_set('display_errors', 1);
require_once 'settings.php';
if (isset($_GET['no_of_users'])) $no_of_users = $_GET['no_of_users'];
if (isset($_GET['pass_length'])) $passLength = $_GET['pass_length'];
if (isset($_GET['user_prefix'])) $user_prefix = $_GET['user_prefix'];
if (isset($_GET['limit_uptime'])) $limit_uptime = $_GET['limit_uptime'];
if (isset($_GET['limit_bytes'])) $limit_bytes = $_GET['limit_bytes'];
if (isset($_GET['profile'])) $profile = $_GET['profile'];
if (isset($_GET['same_pass'])) $same_pass = $_GET['same_pass'];
if ( !isset($_SESSION) ) session_start();
if($_SESSION['user_level'] >= 1 and $_SESSION['user_level'] <= 3) {
include('dbconfig.php');
$stmt = $DB_con->prepare("SELECT booking_id from hotspot_vouchers ORDER BY booking_id DESC LIMIT 1");
$stmt->execute(array());
$row = $stmt->fetch(PDO::FETCH_ASSOC);
$booking_id = $row['booking_id'];
$booking_id++;
$stmt = $DB_con->prepare("UPDATE hotspot_vouchers set status=:status WHERE 1");
$stmt->execute(array(':status' => 'Over'));
$stmt = $DB_con->prepare("insert into hotspot_vouchers (created_on, created_by, creator, user_name, password, printed_times,
printed_last, status, group_of, booking_id, limit_uptime, limit_bytes, profile, uid)
values(NOW(), :created_by, :creator, :user_name, :password, :printed_times, :printed_last, :status, :group_of,
:booking_id, :limit_uptime, :limit_bytes, :profile, :uid)");
$k = 1;
for($i=0; $i < $no_of_users; $i++){
$passAlphabet = 'abcdefghikmnpqrstuvxyz23456789';
$passAlphabetLimit = strlen($passAlphabet)-1;
$pass = '';
$uid = '';
for ($j = 0; $j < $passLength; ++$j) {
$pass .= $passAlphabet[mt_rand(0, $passAlphabetLimit)];
}
for ($j = 0; $j < $passLength; ++$j) {
$uid .= $passAlphabet[mt_rand(0, $passAlphabetLimit)];
}
$user_name = $user_prefix.$uid;
if ($same_pass == 2) { $pass_word = $pass; } else { $pass_word = $user_name; }
$util->setMenu('/ip hotspot user');
$iv = count($util);
if (intval($limit_bytes) != 0) {
$limit_bytes_total = (intval($limit_bytes) * 1024 * 1024 * 1024 );
$util->add(
array(
'name' => "$user_name",
'password' => "$pass_word",
'limit-uptime' => "$limit_uptime",
'limit-bytes-total' => "$limit_bytes_total",
'profile' => "$profile"
)
);
}
else
{
$util->add(
array(
'name' => "$user_name",
'password' => "$pass_word",
'limit-uptime' => "$limit_uptime",
'profile' => "$profile"
)
);
$limit_bytes = 0; // For Adding it to Local database
}
if ($iv != count($util)) {
$uid = $booking_id.'-'.$k.'-'.$no_of_users.date('dmY');
//$creator = $_SESSION['username'].'['.$_SESSION['id'].']';
$stmt->execute(array(':created_by' => $_SESSION['username'], ':creator' => $_SESSION['id'], ':user_name' => $user_name, ':password' => $pass_word,
':printed_times' => 0, ':printed_last' => '', ':status' => 'Active', ':group_of' => $no_of_users,
':booking_id' => $booking_id, ':limit_uptime' => $limit_uptime, ':limit_bytes' => $limit_bytes,
':profile' => $profile, ':uid' => $uid));
$k++;
}
}
echo $k - 1; //Successful
}
else
{
echo 0; // Not an Authorised User
}
?>

16
ajax_change_syspass.php Normal file
View file

@ -0,0 +1,16 @@
<?php
if ( !isset($_SESSION) ) session_start();
include('dbconfig.php');
$np = $_GET['np'];
If ($_SESSION['user_level'] <= 3) {
$np = sha1($np);
$stmt = $DB_con->prepare("update hotspot_users set password = :np where user_id = :session_id");
$stmt->execute(array(':np' => $np, ':session_id' => $_SESSION['id']));
echo 1;
}
else
{
echo 0;
}
?>

40
ajax_del_profile.php Normal file
View file

@ -0,0 +1,40 @@
<?php
header('Content-Type: application/json');
use PEAR2\Net\RouterOS;
require_once 'PEAR2/Autoload.php';
require_once 'config.php';
if ( !isset($_SESSION) ) session_start();
$util = new RouterOS\Util($client = new RouterOS\Client("$host", "$user", "$pass"));
$profile_name=strtolower($_GET['profile_name']);
if ($_SESSION['user_level'] == 1) {
if (!empty($profile_name)) {
$printRequest = new RouterOS\Request('/ip hotspot user profile print');
$printRequest->setArgument('.proplist', '.id,name');
$printRequest->setQuery(RouterOS\Query::where('name', $profile_name));
$idList = '';
foreach ($client->sendSync($printRequest)->getAllOfType(RouterOS\Response::TYPE_DATA) as $item) {
$idList .= ',' . $item->getProperty('.id');
}
$idList = substr($idList, 1);
//$idList now contains a comma separated list of all IDs.
$removeRequest = new RouterOS\Request('/ip hotspot user profile remove');
$removeRequest->setArgument('numbers', $idList);
$client->sendSync($removeRequest);
echo 2; //Success
}
else
{
echo 1; //Profile name Empty
}
}
else
{
echo 0; //Not Authorised
}
?>

16
ajax_del_sysuser.php Normal file
View file

@ -0,0 +1,16 @@
<?php
if ( !isset($_SESSION) ) session_start();
if (($_SESSION['user_level'] == 1) and (!empty($_GET['user_id']))) {
include('dbconfig.php');
$id=$_GET['user_id'];
$myself = $_SESSION['id'];
$stmt = $DB_con->prepare("delete from hotspot_users where user_id=:id and user_id != :myself");
$stmt->execute(array(':id' => $id, ':myself' => $myself));
echo 1;
}
else
{
echo 0;
}
// End Adding a new System User Details, Returned from modal_add_user.php
?>

65
ajax_edit_profile.php Normal file
View file

@ -0,0 +1,65 @@
<?php
use PEAR2\Net\RouterOS;
require_once 'PEAR2/Autoload.php';
require_once 'config.php';
//$client = new RouterOS\Client("$host", "$user", "$pass");
$util = new RouterOS\Util($client = new RouterOS\Client("$host", "$user", "$pass"));
if ( !isset($_SESSION) ) session_start();
$profile_name=strtolower($_GET['profile_name']);
$rx_rate_limit=$_GET['rx_rate_limit'];
$tx_rate_limit=$_GET['tx_rate_limit'];
$session_timeout=$_GET['session_timeout'];
$shared_users=$_GET['shared_users'];
$mac_cookie_timeout=$_GET['mac_cookie_timeout'];
$keepalive_timeout=$_GET['keepalive_timeout'];
if (empty($rx_rate_limit)) $rx_rate_limit = "256k";
if (empty($tx_rate_limit)) $tx_rate_limit = "128k";
$rate_limit = $rx_rate_limit.'/'.$tx_rate_limit;
if (empty($session_timeout)) $session_timeout = "1d 00:00:00";
if (empty($shared_users)) $shared_users = 1;
if (empty($mac_cookie_timeout)) $mac_cookie_timeout = "1d 00:00:00";
if (empty($keepalive_timeout)) $keepalive_timeout = "00:02:00";
if ($_SESSION['user_level'] == 1) {
if (!empty($profile_name)) {
$printRequest = new RouterOS\Request('/ip/hotspot/user/profile/print');
$printRequest->setArgument('.proplist', '.id');
$printRequest->setQuery(RouterOS\Query::where('name', $profile_name));
$id = $client->sendSync($printRequest)->getProperty('.id');
$setRequest = new RouterOS\Request('/ip/hotspot/user/profile/set');
$setRequest->setArgument('numbers', $id);
$setRequest->setArgument('rate-limit', $rate_limit);
if(strtolower($session_timeout) != 'none') {
$setRequest->setArgument('session-timeout', $session_timeout);
}
else
{
$setRequest->setArgument('session-timeout', '00:00:00');
}
$setRequest->setArgument('shared-users', $shared_users);
$setRequest->setArgument('mac-cookie-timeout', $mac_cookie_timeout);
$setRequest->setArgument('keepalive-timeout', $keepalive_timeout);
$client->sendSync($setRequest);
/*
if(strtolower($session_timeout) == 'none') {
$id = $client->sendSync(new Request('/ip/hotspot/user/profile/print .proplist=.id', null, Query::where('name', $profile_name)))->getArgument('.id');
$util->setMenu('/ip hotspot user profile');
$util->unsetValue($id, 'session-timeout');
} */
echo 2; //Success
}
else
{
echo 1; //Profile name Improper
}
}
else
{
echo 0; //Not Authorised
}
?>

35
ajax_edit_sysuser.php Normal file
View file

@ -0,0 +1,35 @@
<?php
if ( !isset($_SESSION) ) session_start();
if (($_SESSION['user_level'] == 1) and (!empty($_GET['user_id']))) {
include('dbconfig.php');
$user_id=$_GET['user_id'];
$username=strtolower($_GET['username']);
$stmt = $DB_con->prepare("SELECT * FROM hotspot_users WHERE username = :username AND user_id != :user_id");
$stmt->execute(array(':username' => $username, ':user_id' => $user_id));
$count = $stmt->rowCount();
if ($count != 0) {
echo 1;
}
else
{
$firstname=$_GET['firstname'];
$lastname=$_GET['lastname'];
$user_level=$_GET['user_level'];
$status=$_GET['status'];
$stmt = $DB_con->prepare("update hotspot_users set username=:username, firstname = :firstname , lastname = :lastname,
user_level = :user_level, status = :status where user_id= :user_id");
$stmt->execute(array(':username' => $username, ':firstname' => $firstname, ':lastname' => $lastname,
':user_level' => $user_level, ':user_id' => $user_id, ':status' => $status));
echo 2;
}
}
else
{
echo 0;
}
// End Adding a new System User Details, Returned from modal_add_user.php
?>

31
ajax_expired.php Normal file
View file

@ -0,0 +1,31 @@
<?php
//Start Removing All Validity Expired Guest User Accounts
use PEAR2\Net\RouterOS;
require_once 'PEAR2/Autoload.php';
require_once 'config.php';
$util = new RouterOS\Util($client = new RouterOS\Client("$host", "$user", "$pass"));
if ( !isset($_SESSION) ) session_start();
if ($_SESSION['user_level'] <= 3) {
$printRequest = new RouterOS\Request('/ip hotspot user print');
$printRequest->setArgument('.proplist', '.id,limit-uptime,uptime,name');
//$printRequest->setQuery(RouterOS\Query::where('name', 'admin', RouterOS\Query::OP_EQ) ->not());
$printRequest->setQuery(RouterOS\Query::where('.id', '*0', RouterOS\Query::OP_EQ) ->not());
$idList = '';
foreach ($client->sendSync($printRequest)->getAllOfType(RouterOS\Response::TYPE_DATA) as $item) {
if (!empty($item->getProperty('limit-uptime'))) {
if (!($item->getProperty('uptime') < $item->getProperty('limit-uptime'))) {
$idList .= ',' . $item->getProperty('.id');
}
}
}
$idList = substr($idList, 1);
//$idList now contains a comma separated list of all IDs.
$removeRequest = new RouterOS\Request('/ip hotspot user remove');
$removeRequest->setArgument('numbers', $idList);
$client->sendSync($removeRequest);
}
//End Removing All Validity Expired Guest User Accounts
?>

35
ajax_get_profiles.php Normal file
View file

@ -0,0 +1,35 @@
<?php
header('Content-Type: application/json');
use PEAR2\Net\RouterOS;
require_once 'PEAR2/Autoload.php';
require_once 'config.php';
$util = new RouterOS\Util($client = new RouterOS\Client("$host", "$user", "$pass"));
if ( !isset($_SESSION) ) session_start();
if ($_SESSION['user_level'] == 1) {
$util->setMenu('/ip hotspot user profile print');
$profile_name=$_GET['profile_name'];
$printRequest = new RouterOS\Request('/ip hotspot user profile print');
$printRequest->setArgument('.proplist', '.id,name,address-pool,rate-limit,session-timeout,shared-users,mac-cookie-timeout,keepalive-timeout');
$printRequest->setQuery(RouterOS\Query::where('name', $profile_name));
foreach ($client->sendSync($printRequest)->getAllOfType(RouterOS\Response::TYPE_DATA) as $item) {
$tname = $item->getProperty("name");
$taddress_pool = $item->getProperty("address-pool");
$tshared_users = $item->getProperty("shared-users");
$trate_limit = $item->getProperty("rate-limit");
$tsession_timeout = $item->getProperty("session-timeout");
$tshared_users = $item->getProperty("shared-users");
$tmac_cookie_timeout = $item->getProperty("mac-cookie-timeout");
$tkeepalive_timeout = $item->getProperty("keepalive-timeout");
$arr = array('name' => $tname, 'address_pool' => $taddress_pool, 'rate_limit' => $trate_limit, 'session_timeout' => $tsession_timeout,
'shared_users' => $tshared_users, 'mac_cookie_timeout' => $tmac_cookie_timeout,
'keepalive_timeout' => $tkeepalive_timeout );
echo json_encode($arr);
}
}
?>

15
ajax_get_sysuser.php Normal file
View file

@ -0,0 +1,15 @@
<?php
header('Content-Type: application/json');
if ( !isset($_SESSION) ) session_start();
if (($_SESSION['user_level'] == 1) and (!empty($_GET['user_id']))) {
include('dbconfig.php');
$user_id=$_GET['user_id'];
$stmt = $DB_con->prepare("SELECT * FROM hotspot_users WHERE user_id =:user_id");
$stmt->execute(array(':user_id' => $user_id));
$row=$stmt->fetch(PDO::FETCH_ASSOC);
echo json_encode($row);
}
// End Getting Sysuser details
?>

38
ajax_rem_selected.php Normal file
View file

@ -0,0 +1,38 @@
<?php
use PEAR2\Net\RouterOS;
require_once 'PEAR2/Autoload.php';
require_once 'config.php';
$util = new RouterOS\Util($client = new RouterOS\Client("$host", "$user", "$pass"));
if ( !isset($_SESSION) ) session_start();
$i = 0;
if ($_SESSION['user_level'] <= 3) {
$guest_list=$_GET['removal_list'];
if (count($guest_list) != 0) {
$printRequest = new RouterOS\Request('/ip/hotspot/user/print');
$printRequest->setArgument('.proplist', '.id,name');
$removeRequest = new RouterOS\Request('/ip/hotspot/user/remove');
foreach ($guest_list as $guest) {
$i++;
//$printRequest->setArgument('.proplist', '.id,name');
$printRequest->setQuery(RouterOS\Query::where('name', $guest));
$id = $client->sendSync($printRequest)->getProperty('.id');
//$removeRequest = new RouterOS\Request('/ip/hotspot/user/remove');
$removeRequest->setArgument('numbers', $id);
$client->sendSync($removeRequest);
}
echo $i;
}
else
{
echo -1;
}
}
else
{
echo 0;
}
//$id = $client->sendSync(new Request('/ip/hotspot/user/profile/print .proplist=.id', null, Query::where('name', $profile_name)))->getArgument('.id');
?>

18
ajax_rem_user.php Normal file
View file

@ -0,0 +1,18 @@
<?php
use PEAR2\Net\RouterOS;
require_once 'PEAR2/Autoload.php';
require_once 'config.php';
$util = new RouterOS\Util($client = new RouterOS\Client("$host", "$user", "$pass"));
if ( !isset($_SESSION) ) session_start();
$guest_name=trim($_GET['username']);
$printRequest = new RouterOS\Request('/ip/hotspot/user/print');
$printRequest->setArgument('.proplist', '.id,name');
$printRequest->setQuery(RouterOS\Query::where('name', $guest_name));
$id = $client->sendSync($printRequest)->getProperty('.id');
$removeRequest = new RouterOS\Request('/ip/hotspot/user/remove');
$removeRequest->setArgument('numbers', $id);
$client->sendSync($removeRequest);
?>

26
ajax_reset_pass.php Normal file
View file

@ -0,0 +1,26 @@
<?php
if ( !isset($_SESSION) ) session_start();
if ($_SESSION['user_level'] == 1) {
include('dbconfig.php');
$user_id= $_GET['user_id'];
$password='password';
$password=sha1($password);
$stmt = $DB_con->prepare("SELECT * FROM hotspot_users WHERE user_id = :user_id");
$stmt->execute(array(':user_id' => $user_id));
$count = $stmt->rowCount();
if ($count == 0){
echo 1;
}
else
{
$stmt = $DB_con->prepare("update hotspot_users set password=:password where user_id= :user_id");
$stmt->execute(array(':password' => $password, ':user_id' => $user_id));
echo 2;
}
}
else
{
echo 0;
}
//End Resetting a System User Password, called from modal_reset_psd.php Modal
?>

28
ajax_uninitiated.php Normal file
View file

@ -0,0 +1,28 @@
<?php
//Start Removing All Un-initiated Guest User Accounts
use PEAR2\Net\RouterOS;
require_once 'PEAR2/Autoload.php';
require_once 'config.php';
$util = new RouterOS\Util($client = new RouterOS\Client("$host", "$user", "$pass"));
if ( !isset($_SESSION) ) session_start();
if ($_SESSION['user_level'] <= 2) {
$printRequest = new RouterOS\Request('/ip hotspot user print');
$printRequest->setArgument('.proplist', '.id,limit-uptime,uptime,name');
//$printRequest->setQuery(RouterOS\Query::where('name', 'default-trial', RouterOS\Query::OP_EQ) ->not());
$printRequest->setQuery(RouterOS\Query::where('.id', '*0', RouterOS\Query::OP_EQ) ->not());
$idList = '';
foreach ($client->sendSync($printRequest)->getAllOfType(RouterOS\Response::TYPE_DATA) as $item) {
if ($item->getProperty('uptime') == 0) {
$idList .= ',' . $item->getProperty('.id');
}
}
$idList = substr($idList, 1);
//$idList now contains a comma separated list of all IDs.
$removeRequest = new RouterOS\Request('/ip hotspot user remove');
$removeRequest->setArgument('numbers', $idList);
$client->sendSync($removeRequest);
}
//End Removing All Un-initiated Guest User Accounts
?>

66
backup.php Normal file
View file

@ -0,0 +1,66 @@
<?php include('session.php'); ?>
<?php header( 'Content-Type: text/plain' ); ?>
<?php include('header.php'); ?>
<?php include('navbar.php'); ?>
<?php
$progress_val = 100; ?>
<div class="progress">
<div class="progress-bar progress-bar-striped active" role="progressbar"
aria-valuenow="<?php echo $progress_val; ?>" aria-valuemin="0" aria-valuemax="100" style="width:<?php echo $progress_val; ?>%">
<?php echo $progress_val.'%'; ?>
</div>
</div>
<?php
$folder = $_SESSION['backup_folder'];
if (!is_dir($folder)) { mkdir($folder, 0777, true); }
chmod($folder, 0777);
$date = date('d-m-Y-H-i-s', time());
$filename = $folder."db-backup-".$date;
include('dbconfig.php');
define( 'DUMPFILE', $filename . '.sql' );
try {
//$DB_con = new PDO( 'mysql:host=' . DBHOST . ';dbname=' . DBNAME, DBUSER, DBPASS );
$f = fopen( DUMPFILE, 'wt' );
$tables = $DB_con->query( 'SHOW TABLES' );
foreach ( $tables as $table ) {
//echo $table[0] . ' ... ';
flush();
$sql = '-- TABLE: ' . $table[0] . PHP_EOL;
$create = $DB_con->query( 'SHOW CREATE TABLE `' . $table[0] . '`' )->fetch();
$sql .= $create['Create Table'] . ';' . PHP_EOL;
fwrite( $f, $sql );
$rows = $DB_con->query( 'SELECT * FROM `' . $table[0] . '`' );
$rows->setFetchMode( PDO::FETCH_ASSOC );
foreach ( $rows as $row ) {
$row = array_map( array( $DB_con, 'quote' ), $row );
$sql = 'INSERT INTO `' . $table[0] . '` (`' . implode( '`, `', array_keys( $row ) ) . '`) VALUES (' . implode( ', ', $row ) . ');' . PHP_EOL;
fwrite( $f, $sql );
}
$sql = PHP_EOL;
$result = fwrite( $f, $sql );
if ( $result !== FALSE ) {
echo '';
} else {
// echo 'ERROR!!' . PHP_EOL;
}
flush();
}
fclose( $f );
} catch (Exception $e) {
echo 'Damn it! ' . $e->getMessage() . PHP_EOL;
}
?>
<a id="dlink" href=<?php echo '"'.$filename.'.sql"'?> download>
<script>
var btnDownload = function() {
document.getElementById("dlink").click();
window.location = "admin.php";
}
btns = [{text:"No",action:"admin.php",style:"cmodal-cancel"}, {text:"Yes",action:btnDownload,style:"cmodal-ok"}];
cmodalOkCancel("Backup Complete", "Backing-up of Database Tables to the Selected Path Completed Successfully. Do you want to download the backup ?", "information", btns);
</script>

5
config.php Normal file
View file

@ -0,0 +1,5 @@
<?php
$host = '192.168.0.200';
$user = 'admin';
$pass = 'admin';
?>

3591
css/animate.css vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,317 @@
.checkbox {
padding-left: 20px;
}
.checkbox label {
display: inline-block;
vertical-align: middle;
position: relative;
padding-left: 5px;
}
.checkbox label::before {
content: "";
display: inline-block;
position: absolute;
width: 17px;
height: 17px;
left: 0;
margin-left: -20px;
border: 1px solid #cccccc;
border-radius: 3px;
background-color: #fff;
-webkit-transition: border 0.15s ease-in-out, color 0.15s ease-in-out;
-o-transition: border 0.15s ease-in-out, color 0.15s ease-in-out;
transition: border 0.15s ease-in-out, color 0.15s ease-in-out;
}
.checkbox label::after {
display: inline-block;
position: absolute;
width: 16px;
height: 16px;
left: 0;
top: 0;
margin-left: -20px;
padding-left: 3px;
padding-top: 1px;
font-size: 11px;
color: #555555;
}
.checkbox input[type="checkbox"],
.checkbox input[type="radio"] {
opacity: 0;
z-index: 1;
}
.checkbox input[type="checkbox"]:focus + label::before,
.checkbox input[type="radio"]:focus + label::before {
outline: thin dotted;
outline: 5px auto -webkit-focus-ring-color;
outline-offset: -2px;
}
.checkbox input[type="checkbox"]:checked + label::after,
.checkbox input[type="radio"]:checked + label::after {
font-family: "FontAwesome";
content: "\f00c";
}
.checkbox input[type="checkbox"]:indeterminate + label::after,
.checkbox input[type="radio"]:indeterminate + label::after {
display: block;
content: "";
width: 10px;
height: 3px;
background-color: #555555;
border-radius: 2px;
margin-left: -16.5px;
margin-top: 7px;
}
.checkbox input[type="checkbox"]:disabled + label,
.checkbox input[type="radio"]:disabled + label {
opacity: 0.65;
}
.checkbox input[type="checkbox"]:disabled + label::before,
.checkbox input[type="radio"]:disabled + label::before {
background-color: #eeeeee;
cursor: not-allowed;
}
.checkbox.checkbox-circle label::before {
border-radius: 50%;
}
.checkbox.checkbox-inline {
margin-top: 0;
}
.checkbox-primary input[type="checkbox"]:checked + label::before,
.checkbox-primary input[type="radio"]:checked + label::before {
background-color: #337ab7;
border-color: #337ab7;
}
.checkbox-primary input[type="checkbox"]:checked + label::after,
.checkbox-primary input[type="radio"]:checked + label::after {
color: #fff;
}
.checkbox-danger input[type="checkbox"]:checked + label::before,
.checkbox-danger input[type="radio"]:checked + label::before {
background-color: #d9534f;
border-color: #d9534f;
}
.checkbox-danger input[type="checkbox"]:checked + label::after,
.checkbox-danger input[type="radio"]:checked + label::after {
color: #fff;
}
.checkbox-info input[type="checkbox"]:checked + label::before,
.checkbox-info input[type="radio"]:checked + label::before {
background-color: #5bc0de;
border-color: #5bc0de;
}
.checkbox-info input[type="checkbox"]:checked + label::after,
.checkbox-info input[type="radio"]:checked + label::after {
color: #fff;
}
.checkbox-warning input[type="checkbox"]:checked + label::before,
.checkbox-warning input[type="radio"]:checked + label::before {
background-color: #f0ad4e;
border-color: #f0ad4e;
}
.checkbox-warning input[type="checkbox"]:checked + label::after,
.checkbox-warning input[type="radio"]:checked + label::after {
color: #fff;
}
.checkbox-success input[type="checkbox"]:checked + label::before,
.checkbox-success input[type="radio"]:checked + label::before {
background-color: #5cb85c;
border-color: #5cb85c;
}
.checkbox-success input[type="checkbox"]:checked + label::after,
.checkbox-success input[type="radio"]:checked + label::after {
color: #fff;
}
.checkbox-primary input[type="checkbox"]:indeterminate + label::before,
.checkbox-primary input[type="radio"]:indeterminate + label::before {
background-color: #337ab7;
border-color: #337ab7;
}
.checkbox-primary input[type="checkbox"]:indeterminate + label::after,
.checkbox-primary input[type="radio"]:indeterminate + label::after {
background-color: #fff;
}
.checkbox-danger input[type="checkbox"]:indeterminate + label::before,
.checkbox-danger input[type="radio"]:indeterminate + label::before {
background-color: #d9534f;
border-color: #d9534f;
}
.checkbox-danger input[type="checkbox"]:indeterminate + label::after,
.checkbox-danger input[type="radio"]:indeterminate + label::after {
background-color: #fff;
}
.checkbox-info input[type="checkbox"]:indeterminate + label::before,
.checkbox-info input[type="radio"]:indeterminate + label::before {
background-color: #5bc0de;
border-color: #5bc0de;
}
.checkbox-info input[type="checkbox"]:indeterminate + label::after,
.checkbox-info input[type="radio"]:indeterminate + label::after {
background-color: #fff;
}
.checkbox-warning input[type="checkbox"]:indeterminate + label::before,
.checkbox-warning input[type="radio"]:indeterminate + label::before {
background-color: #f0ad4e;
border-color: #f0ad4e;
}
.checkbox-warning input[type="checkbox"]:indeterminate + label::after,
.checkbox-warning input[type="radio"]:indeterminate + label::after {
background-color: #fff;
}
.checkbox-success input[type="checkbox"]:indeterminate + label::before,
.checkbox-success input[type="radio"]:indeterminate + label::before {
background-color: #5cb85c;
border-color: #5cb85c;
}
.checkbox-success input[type="checkbox"]:indeterminate + label::after,
.checkbox-success input[type="radio"]:indeterminate + label::after {
background-color: #fff;
}
.radio {
padding-left: 20px;
}
.radio label {
display: inline-block;
vertical-align: middle;
position: relative;
padding-left: 5px;
}
.radio label::before {
content: "";
display: inline-block;
position: absolute;
width: 17px;
height: 17px;
left: 0;
margin-left: -20px;
border: 1px solid #cccccc;
border-radius: 50%;
background-color: #fff;
-webkit-transition: border 0.15s ease-in-out;
-o-transition: border 0.15s ease-in-out;
transition: border 0.15s ease-in-out;
}
.radio label::after {
display: inline-block;
position: absolute;
content: " ";
width: 11px;
height: 11px;
left: 3px;
top: 3px;
margin-left: -20px;
border-radius: 50%;
background-color: #555555;
-webkit-transform: scale(0, 0);
-ms-transform: scale(0, 0);
-o-transform: scale(0, 0);
transform: scale(0, 0);
-webkit-transition: -webkit-transform 0.1s cubic-bezier(0.8, -0.33, 0.2, 1.33);
-moz-transition: -moz-transform 0.1s cubic-bezier(0.8, -0.33, 0.2, 1.33);
-o-transition: -o-transform 0.1s cubic-bezier(0.8, -0.33, 0.2, 1.33);
transition: transform 0.1s cubic-bezier(0.8, -0.33, 0.2, 1.33);
}
.radio input[type="radio"] {
opacity: 0;
z-index: 1;
}
.radio input[type="radio"]:focus + label::before {
outline: thin dotted;
outline: 5px auto -webkit-focus-ring-color;
outline-offset: -2px;
}
.radio input[type="radio"]:checked + label::after {
-webkit-transform: scale(1, 1);
-ms-transform: scale(1, 1);
-o-transform: scale(1, 1);
transform: scale(1, 1);
}
.radio input[type="radio"]:disabled + label {
opacity: 0.65;
}
.radio input[type="radio"]:disabled + label::before {
cursor: not-allowed;
}
.radio.radio-inline {
margin-top: 0;
}
.radio-primary input[type="radio"] + label::after {
background-color: #337ab7;
}
.radio-primary input[type="radio"]:checked + label::before {
border-color: #337ab7;
}
.radio-primary input[type="radio"]:checked + label::after {
background-color: #337ab7;
}
.radio-danger input[type="radio"] + label::after {
background-color: #d9534f;
}
.radio-danger input[type="radio"]:checked + label::before {
border-color: #d9534f;
}
.radio-danger input[type="radio"]:checked + label::after {
background-color: #d9534f;
}
.radio-info input[type="radio"] + label::after {
background-color: #5bc0de;
}
.radio-info input[type="radio"]:checked + label::before {
border-color: #5bc0de;
}
.radio-info input[type="radio"]:checked + label::after {
background-color: #5bc0de;
}
.radio-warning input[type="radio"] + label::after {
background-color: #f0ad4e;
}
.radio-warning input[type="radio"]:checked + label::before {
border-color: #f0ad4e;
}
.radio-warning input[type="radio"]:checked + label::after {
background-color: #f0ad4e;
}
.radio-success input[type="radio"] + label::after {
background-color: #5cb85c;
}
.radio-success input[type="radio"]:checked + label::before {
border-color: #5cb85c;
}
.radio-success input[type="radio"]:checked + label::after {
background-color: #5cb85c;
}
input[type="checkbox"].styled:checked + label:after,
input[type="radio"].styled:checked + label:after {
font-family: 'FontAwesome';
content: "\f00c";
}
input[type="checkbox"] .styled:checked + label::before,
input[type="radio"] .styled:checked + label::before {
color: #fff;
}
input[type="checkbox"] .styled:checked + label::after,
input[type="radio"] .styled:checked + label::after {
color: #fff;
}

5
css/bootstrap.min.css vendored Normal file

File diff suppressed because one or more lines are too long

168
css/customModal.css Normal file
View file

@ -0,0 +1,168 @@
.custom-modal {
display: none;
position: fixed;
z-index: 1053;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgb(0,0,0);
background-color: rgba(0,0,0,0.5);
}
.cmodal-content {
position: relative;
margin: 10% auto;
border: 1px solid #888;
border-radius: 10px;
width: 40%;
box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19);
-webkit-animation: cmodalmove .4s ;
-o-animation: cmodalmove .4s;
-moz-animation: cmodalmove .4s;
animation: cmodalmove .4s;
}
@-webkit-keyframes cmodalmove {
0% {top:-400px;}
100% {top:0px;}
}
@keyframes cmodalmove {
0% {top:-400px;}
100% {top:0px;}
}
.cmodal-header {
display: block;
height: fit-content;
width: 100%;
border-radius: 10px 10px 0px 0px;
background-color: rgb(0,0,0);
background-color: rgba(0,0,0,0.25);
color: white;
padding: -30px;
}
.cmodal-title {
font-size: 1.08em;
display: inline;
padding: 10px;
font-weight: 500;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
.cmodal-close:hover {
background-color: orangered;
}
.cmodal-close {
float: right;
height: 100%;
border-color: rgba(0,0,0,0);
border-radius: 5px 5px 0px 5px;
text-align: center;
font-weight: bold;
box-shadow: none;
background: lightgrey;
cursor: pointer;
}
.cmodal-body {
display: inline;
}
.cmodal-message {
display: block;
padding: 20px 10px;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
.cmodal-icon {
float: right;
}
.cmodal-footer {
display: block;
z-index: -1;
border-radius: 0px 0px 10px 10px;
background-color: rgb(255,255,255);
background-color: rgba(255,255,255,.4);
text-align: right;
}
.cmodal-button {
display: inline;
margin: 3px 3px;
padding: 3px;
color: white;
min-width: 70px;
cursor: pointer;
border-radius: 6px;
border-color: black;
border-color: rgba(0,0,0,0);
-webkit-transition: all .2s;
-moz-transition: all .2s;
transition: all .2s;
text-decoration: none;
text-align: center;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
.cmodal-button:hover {
opacity: .95;
box-shadow: 2px 2px 1px black;
}
.cmodal-ok {
background: green;
background: linear-gradient( green, mediumseagreen);
}
.cmodal-cancel {
background: red;
background: linear-gradient( red, indianred);
}
.cmodal-generic {
background: purple;
background: linear-gradient( purple, mediumpurple);
}
.cmodal-blue {
background-color: skyblue;
background: linear-gradient( dodgerblue, deepskyblue);
}
.error {
background: red;
background: -moz-linear-gradient(red, indianred);
background: -webkit-linear-gradient(red, indianred);
background: -o-linear-gradient(red, indianred);
background: linear-gradient(red, indianred);
}
.information {
background: dodgerblue;
background: -moz-linear-gradient(dodgerblue, lightblue);
background: -webkit-linear-gradient(dodgerblue, lightblue);
background: -o-linear-gradient(dodgerblue, lightblue);
background: linear-gradient(dodgerblue, lightblue);
}
.success {
background: green;
background: -moz-linear-gradient(green, mediumseagreen);
background: -webkit-linear-gradient(green, mediumseagreen);
background: -o-linear-gradient(green, mediumseagreen);
background: linear-gradient(green, mediumseagreen);
}
.warning {
background: darkorange;
background: -moz-linear-gradient(orangered, darkorange);
background: -webkit-linear-gradient(orangered, darkorange);
background: -o-linear-gradient(orangered, darkorange);
background: linear-gradient(orangered, darkorange);
}

4
css/font-awesome.min.css vendored Normal file

File diff suppressed because one or more lines are too long

77
css/print.css Normal file
View file

@ -0,0 +1,77 @@
.navbar{
display:none;
}
.modal{
display:none;
}
.action{
display:none;
}
h1{
text-transform:uppercase;
}
.title, img {
display:visible;
}
th{
text-align:left;
}
td{
text-align:left;
border-top:1px solid;
padding:2px;
}
.btn{
display:none;
}
.alert{
display:none;
}
body{
font-family:arial;
font-size:13px;
}
.no_print{
display:none;
}
.printable{
display:visible;
}
span{
text-transform:uppercase;
}
/*
.name span{
display:block;
}
.name span strong{
margin-left:10px;
}
.add_grade{
display:none;
}
.act{
display:none;
}
.logout{
display:none;
}
#add{
display:none;
}
.dataTables_filter{
display:none;
}
.nav{
display:none;
}
.dataTables_paginate {
display:none;
}
#example_length{
display:none;
}
.dataTables_info{
display:none;
}
*/

341
css/style.css Normal file
View file

@ -0,0 +1,341 @@
@import url(http://fonts.googleapis.com/css?family=Open+Sans:400,300,700,600);
@import url(http://fonts.googleapis.com/css?family=Oswald:400,300);
body {
background: url(../images/bg.jpg);
background-attachment: fixed;
background-size: cover;
background-position: 50% 50%;
font-family: 'Open Sans', sans-serif;
}
a,
a:hover,
a:focus,
a:active,
a.active {
outline: 0;
}
ul,ol {
margin: 0;
padding: 0;
}
li {
list-style: none;
}
a {
color: #FF432E;
text-decoration: none;
}
a:hover {
text-decoration: none;
}
p {
font-family: 'Open Sans', sans-serif;
font-size: 13px;
line-height: 21px;
}
/**** Start Logo Section ****/
#logo-section {
}
.logo h1 {
font-family: 'Lobster', cursive;
color: #fff;
font-size: 60px;
}
.logo span {
color: #999;
}
/**** Start Background Color ****/
.blue {
background: #28ABE3;
}
.green {
background: #72bf48;
}
.red {
background: #FF432E;
}
.olive {
background: #808000;
}
.purple {
background: #800080;
}
.fuchsia {
background: #FF00FF;
}
.navy {
background: #000080;
}
.bisque {
background: #FFE4C4;
}
.gold {
background: #FFD700;
}
.skyblue {
background: #87CEEB;
}
.lavender {
background: #E6E6FA;
}
.coral {
background: #FB7F50; /* wrong code for color */
}
/**** Start Main Body Section ****/
.mainbody-section {
padding-top: 50px;
padding-bottom: 30px;
}
.menu-item {
color: #fff;
padding-top: 20px;
padding-bottom: 20px;
margin-bottom: 30px;
-webkit-transition: all 0.3s;
transition: all 0.3s;
}
.menu-item a {
color: #fff;
display: block;
-webkit-transition: all 0.3s;
transition: all 0.3s;
}
.menu-item a p {
font-family: 'Oswald', sans-serif;
font-weight: 300;
font-size: 20px;
}
.menu-item a i {
font-size: 50px;
padding-bottom: 20px;
}
.menu-item:hover a {
text-decoration: none;
//color: #333;
animation: wobble;
-webkit-animation: wobble;
animation-duration: 1000ms;
-webkit-animation-duration: 1000ms;
}
@media only screen
and (min-width : 600px)
and (max-width : 991px) {
.menu-item {
display: inline-block;
width: 32.8%;
}
.menu-item.responsive {
width: 49.5%;
float: left;
margin-right: 3px;
}
.menu-item.responsive-2 {
width: 49.5%;
float: right;
}
}
@media only screen
and (min-width : 992px)
and (max-width : 1199px) {
.menu-item {
padding-top: 15px;
padding-bottom: 15px;
}
.menu-item a i {
font-size: 32px;
}
.menu-item a p {
font-size: 16px;
}
}
/**** Start Modal Section ****/
.modal-content {
overflow:visible !important;
}
.child-modal .modal-content {
padding: 50px 0 !important;
margin-top: 120px !important;
margin-right: 20px !important;
margin-left: 20px !important;
margin-bottom: 80px !important;
min-height: auto !important;
border: 2 !important;
border-radius: 6 !important;
background-clip: border-box;
-webkit-box-shadow: none !important;
-moz-box-shadow: none !important;
box-shadow: 10px 10px 5px 3px #888888 !important;
font-weight: 200;
color: #666 !important;
font-family: 'Oswald', sans-serif;
text-transform: none;
}
.modal-footer {
padding: 1px !important;
}
table#table-01 {
width:100%;
border-radius: 10 !important;
border-spacing: 5px !important;
}
table, th, td {
border: 1px solid black;
border-collapse: collapse;
border-spacing: 5px !important;
}
th, td {
padding: 5px;
text-align: left;
}
table#table-01 tr:nth-child(even) {
background-color: #eee;
}
table#table-01 tr:nth-child(odd) {
background-color:#fff;
}
table#table-01 th {
background-color: black;
color: white;
}
.card-columns {
@include media-breakpoint-only(lg) {
column-count: 4;
}
@include media-breakpoint-only(xl) {
column-count: 5;
}
@include media-breakpoint-only(sm) {
column-count: 3;
}
@include media-breakpoint-only(xs) {
column-count: 3;
}
}
img.center {
display: block;
margin: 0 auto;
}
.center-element {
width: 100%;
margin: 0px auto 0px auto;
}
/*
@media print {
*,
*:before,enter code here
*:after {
color: #000 !important;
text-shadow: none !important;
background: transparent !important;
-webkit-box-shadow: none !important;
box-shadow: none !important;
}
a,
a:visited {
text-decoration: underline;
}
a[href]:after {
content: " (" attr(href) ")";
}
abbr[title]:after {
content: " (" attr(title) ")";
}
a[href^="#"]:after,
a[href^="javascript:"]:after {
content: "";
}
pre,
blockquote {
border: 1px solid #999;
page-break-inside: avoid;
}
thead {
display: table-header-group;
}
tr,
img {
page-break-inside: avoid;
}
img {
max-width: 100% !important;
}
p,
h2,
h3 {
orphans: 3;
widows: 3;
}
h2,
h3 {
page-break-after: avoid;
}
select {
background: #fff !important;
}
.navbar {
display: none;
}
.btn > .caret,
.dropup > .btn > .caret {
border-top-color: #000 !important;
}
.label {
border: 1px solid #000;
}
.table {
border-collapse: collapse !important;
}
.table td,
.table th {
background-color: #fff !important;
}
.table-bordered th,
.table-bordered td {
border: 1px solid #ddd !important;
}
}
*/

60
database.php Normal file
View file

@ -0,0 +1,60 @@
<?php
$stmt = $DB_con->prepare("SET SQL_MODE = 'NO_AUTO_VALUE_ON_ZERO'");
$stmt->execute(array());
$stmt = $DB_con->prepare("SET time_zone = '+05:30'");
$stmt->execute(array());
$stmt = $DB_con->prepare("CREATE TABLE IF NOT EXISTS `hotspot_users` (
`user_id` int(11) NOT NULL,
`email` varchar(200) NOT NULL,
`date_added` date NOT NULL,
`firstname` varchar(30) NOT NULL,
`lastname` varchar(30) NOT NULL,
`password` varchar(60) NOT NULL,
`created_at` datetime NOT NULL,
`username` varchar(30) NOT NULL,
`user_level` int(11) NOT NULL DEFAULT '3',
`user_group` int(1) NOT NULL,
`image_path` varchar(50) NOT NULL,
`thumb_path` varchar(50) NOT NULL,
`status` varchar(20) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8");
$stmt->execute(array());
$stmt = $DB_con->prepare("ALTER TABLE `hotspot_users`
ADD PRIMARY KEY (`user_id`),
ADD KEY `username` (`username`)");
$stmt->execute(array());
$stmt = $DB_con->prepare("ALTER TABLE `hotspot_users`
MODIFY `user_id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=1");
$stmt->execute(array());
$stmt = $DB_con->prepare("CREATE TABLE IF NOT EXISTS `hotspot_vouchers` (
`id` int(11) NOT NULL,
`created_on` datetime DEFAULT NULL,
`created_by` varchar(30) DEFAULT NULL,
`creator` int(3) DEFAULT NULL,
`user_name` varchar(30) DEFAULT NULL,
`password` varchar(30) DEFAULT NULL,
`printed_times` int(3) DEFAULT NULL,
`printed_last` varchar(30) DEFAULT NULL,
`status` varchar(10) DEFAULT NULL,
`group_of` int(4) DEFAULT NULL,
`booking_id` int(11) DEFAULT NULL,
`limit_uptime` varchar(30) DEFAULT NULL,
`limit_bytes` varchar(30) DEFAULT NULL,
`profile` varchar(30) DEFAULT NULL,
`uid` VARCHAR(30) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8");
$stmt->execute(array());
$stmt = $DB_con->prepare("ALTER TABLE `hotspot_vouchers`
ADD PRIMARY KEY (`id`)");
$stmt->execute(array());
$stmt = $DB_con->prepare("ALTER TABLE `hotspot_vouchers`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT");
$stmt->execute(array());
?>

File diff suppressed because one or more lines are too long

24
dbconfig.php Normal file
View file

@ -0,0 +1,24 @@
<?php
$DB_host = "localhost";
$DB_user = "root";
$DB_pass = "root123";
$DB_name = "mikrotik";
try
{
$DB_con = new PDO("mysql:host={$DB_host}",$DB_user,$DB_pass);
$DB_con->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$dbname = "`".str_replace("`","``",$DB_name)."`";
$DB_con->query("CREATE DATABASE IF NOT EXISTS $dbname");
$DB_con->query("use $dbname");
}
catch(PDOException $e) {
echo "Error Creating/Locating Database $dbname: " . $e->getMessage();
}
/* Old Version, NOT creating DB if NOT Exist
$DB_con = new PDO("mysql:host={$DB_host};dbname={$DB_name}",$DB_user,$DB_pass);
$DB_con->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
*/
?>

BIN
favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
fonts/FontAwesome.otf Normal file

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,520 @@
<?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="&#xd8;" horiz-adv-x="1792" />
<glyph unicode="&#x2000;" horiz-adv-x="768" />
<glyph unicode="&#x2001;" horiz-adv-x="1537" />
<glyph unicode="&#x2002;" horiz-adv-x="768" />
<glyph unicode="&#x2003;" horiz-adv-x="1537" />
<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="&#x25fc;" 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;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z " />
<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 -450q33 0 136.5 -2t160.5 -2q19 0 57 2q-87 253 -184 452zM0 -128l2 79q23 7 56 12.5t57 10.5t49.5 14.5t44.5 29t31 50.5l237 616l280 724h75h53q8 -14 11 -21l205 -480q33 -78 106 -257.5t114 -274.5q15 -34 58 -144.5t72 -168.5q20 -45 35 -57 q19 -15 88 -29.5t84 -20.5q6 -38 6 -57q0 -4 -0.5 -13t-0.5 -13q-63 0 -190 8t-191 8q-76 0 -215 -7t-178 -8q0 43 4 78l131 28q1 0 12.5 2.5t15.5 3.5t14.5 4.5t15 6.5t11 8t9 11t2.5 14q0 16 -31 96.5t-72 177.5t-42 100l-450 2q-26 -58 -76.5 -195.5t-50.5 -162.5 q0 -22 14 -37.5t43.5 -24.5t48.5 -13.5t57 -8.5t41 -4q1 -19 1 -58q0 -9 -2 -27q-58 0 -174.5 10t-174.5 10q-8 0 -26.5 -4t-21.5 -4q-80 -14 -188 -14z" />
<glyph unicode="&#xf032;" horiz-adv-x="1408" d="M555 15q74 -32 140 -32q376 0 376 335q0 114 -41 180q-27 44 -61.5 74t-67.5 46.5t-80.5 25t-84 10.5t-94.5 2q-73 0 -101 -10q0 -53 -0.5 -159t-0.5 -158q0 -8 -1 -67.5t-0.5 -96.5t4.5 -83.5t12 -66.5zM541 761q42 -7 109 -7q82 0 143 13t110 44.5t74.5 89.5t25.5 142 q0 70 -29 122.5t-79 82t-108 43.5t-124 14q-50 0 -130 -13q0 -50 4 -151t4 -152q0 -27 -0.5 -80t-0.5 -79q0 -46 1 -69zM0 -128l2 94q15 4 85 16t106 27q7 12 12.5 27t8.5 33.5t5.5 32.5t3 37.5t0.5 34v35.5v30q0 982 -22 1025q-4 8 -22 14.5t-44.5 11t-49.5 7t-48.5 4.5 t-30.5 3l-4 83q98 2 340 11.5t373 9.5q23 0 68.5 -0.5t67.5 -0.5q70 0 136.5 -13t128.5 -42t108 -71t74 -104.5t28 -137.5q0 -52 -16.5 -95.5t-39 -72t-64.5 -57.5t-73 -45t-84 -40q154 -35 256.5 -134t102.5 -248q0 -100 -35 -179.5t-93.5 -130.5t-138 -85.5t-163.5 -48.5 t-176 -14q-44 0 -132 3t-132 3q-106 0 -307 -11t-231 -12z" />
<glyph unicode="&#xf033;" horiz-adv-x="1024" d="M0 -126l17 85q6 2 81.5 21.5t111.5 37.5q28 35 41 101q1 7 62 289t114 543.5t52 296.5v25q-24 13 -54.5 18.5t-69.5 8t-58 5.5l19 103q33 -2 120 -6.5t149.5 -7t120.5 -2.5q48 0 98.5 2.5t121 7t98.5 6.5q-5 -39 -19 -89q-30 -10 -101.5 -28.5t-108.5 -33.5 q-8 -19 -14 -42.5t-9 -40t-7.5 -45.5t-6.5 -42q-27 -148 -87.5 -419.5t-77.5 -355.5q-2 -9 -13 -58t-20 -90t-16 -83.5t-6 -57.5l1 -18q17 -4 185 -31q-3 -44 -16 -99q-11 0 -32.5 -1.5t-32.5 -1.5q-29 0 -87 10t-86 10q-138 2 -206 2q-51 0 -143 -9t-121 -11z" />
<glyph unicode="&#xf034;" horiz-adv-x="1792" d="M1744 128q33 0 42 -18.5t-11 -44.5l-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-1024h80zM81 1407l54 -27q12 -5 211 -5q44 0 132 2 t132 2q36 0 107.5 -0.5t107.5 -0.5h293q6 0 21 -0.5t20.5 0t16 3t17.5 9t15 17.5l42 1q4 0 14 -0.5t14 -0.5q2 -112 2 -336q0 -80 -5 -109q-39 -14 -68 -18q-25 44 -54 128q-3 9 -11 48t-14.5 73.5t-7.5 35.5q-6 8 -12 12.5t-15.5 6t-13 2.5t-18 0.5t-16.5 -0.5 q-17 0 -66.5 0.5t-74.5 0.5t-64 -2t-71 -6q-9 -81 -8 -136q0 -94 2 -388t2 -455q0 -16 -2.5 -71.5t0 -91.5t12.5 -69q40 -21 124 -42.5t120 -37.5q5 -40 5 -50q0 -14 -3 -29l-34 -1q-76 -2 -218 8t-207 10q-50 0 -151 -9t-152 -9q-3 51 -3 52v9q17 27 61.5 43t98.5 29t78 27 q19 42 19 383q0 101 -3 303t-3 303v117q0 2 0.5 15.5t0.5 25t-1 25.5t-3 24t-5 14q-11 12 -162 12q-33 0 -93 -12t-80 -26q-19 -13 -34 -72.5t-31.5 -111t-42.5 -53.5q-42 26 -56 44v383z" />
<glyph unicode="&#xf035;" d="M81 1407l54 -27q12 -5 211 -5q44 0 132 2t132 2q70 0 246.5 1t304.5 0.5t247 -4.5q33 -1 56 31l42 1q4 0 14 -0.5t14 -0.5q2 -112 2 -336q0 -80 -5 -109q-39 -14 -68 -18q-25 44 -54 128q-3 9 -11 47.5t-15 73.5t-7 36q-10 13 -27 19q-5 2 -66 2q-30 0 -93 1t-103 1 t-94 -2t-96 -7q-9 -81 -8 -136l1 -152v52q0 -55 1 -154t1.5 -180t0.5 -153q0 -16 -2.5 -71.5t0 -91.5t12.5 -69q40 -21 124 -42.5t120 -37.5q5 -40 5 -50q0 -14 -3 -29l-34 -1q-76 -2 -218 8t-207 10q-50 0 -151 -9t-152 -9q-3 51 -3 52v9q17 27 61.5 43t98.5 29t78 27 q7 16 11.5 74t6 145.5t1.5 155t-0.5 153.5t-0.5 89q0 7 -2.5 21.5t-2.5 22.5q0 7 0.5 44t1 73t0 76.5t-3 67.5t-6.5 32q-11 12 -162 12q-41 0 -163 -13.5t-138 -24.5q-19 -12 -34 -71.5t-31.5 -111.5t-42.5 -54q-42 26 -56 44v383zM1310 125q12 0 42 -19.5t57.5 -41.5 t59.5 -49t36 -30q26 -21 26 -49t-26 -49q-4 -3 -36 -30t-59.5 -49t-57.5 -41.5t-42 -19.5q-13 0 -20.5 10.5t-10 28.5t-2.5 33.5t1.5 33t1.5 19.5h-1024q0 -2 1.5 -19.5t1.5 -33t-2.5 -33.5t-10 -28.5t-20.5 -10.5q-12 0 -42 19.5t-57.5 41.5t-59.5 49t-36 30q-26 21 -26 49 t26 49q4 3 36 30t59.5 49t57.5 41.5t42 19.5q13 0 20.5 -10.5t10 -28.5t2.5 -33.5t-1.5 -33t-1.5 -19.5h1024q0 2 -1.5 19.5t-1.5 33t2.5 33.5t10 28.5t20.5 10.5z" />
<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="1280" d="M1171 1235l-531 -531l531 -531q19 -19 19 -45t-19 -45l-166 -166q-19 -19 -45 -19t-45 19l-742 742q-19 19 -19 45t19 45l742 742q19 19 45 19t45 -19l166 -166q19 -19 19 -45t-19 -45z" />
<glyph unicode="&#xf054;" horiz-adv-x="1280" d="M1107 659l-742 -742q-19 -19 -45 -19t-45 19l-166 166q-19 19 -19 45t19 45l531 531l-531 531q-19 19 -19 45t19 45l166 166q19 19 45 19t45 -19l742 -742q19 -19 19 -45t-19 -45z" />
<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="1792" d="M1683 205l-166 -165q-19 -19 -45 -19t-45 19l-531 531l-531 -531q-19 -19 -45 -19t-45 19l-166 165q-19 19 -19 45.5t19 45.5l742 741q19 19 45 19t45 -19l742 -741q19 -19 19 -45.5t-19 -45.5z" />
<glyph unicode="&#xf078;" horiz-adv-x="1792" d="M1683 728l-742 -741q-19 -19 -45 -19t-45 19l-742 741q-19 19 -19 45.5t19 45.5l166 165q19 19 45 19t45 -19l531 -531l531 531q19 19 45 19t45 -19l166 -165q19 -19 19 -45.5t-19 -45.5z" />
<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="2048" d="M640 640v-512h-256v512h256zM1024 1152v-1024h-256v1024h256zM2048 0v-128h-2048v1536h128v-1408h1920zM1408 896v-768h-256v768h256zM1792 1280v-1152h-256v1152h256z" />
<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="M1536 160q0 -119 -84.5 -203.5t-203.5 -84.5h-192v608h203l30 224h-233v143q0 54 28 83t96 29l132 1v207q-96 9 -180 9q-136 0 -218 -80.5t-82 -225.5v-166h-224v-224h224v-608h-544q-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.5v-960z" />
<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="1024" d="M959 1524v-264h-157q-86 0 -116 -36t-30 -108v-189h293l-39 -296h-254v-759h-306v759h-255v296h255v218q0 186 104 288.5t277 102.5q147 0 228 -12z" />
<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="1792" d="M912 -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 16zM246 128h1300q-266 300 -266 832q0 51 -24 105t-69 103t-121.5 80.5t-169.5 31.5t-169.5 -31.5t-121.5 -80.5t-69 -103t-24 -105q0 -532 -266 -832z M1728 128q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-181 75t-75 181h-448q-52 0 -90 38t-38 90q50 42 91 88t85 119.5t74.5 158.5t50 206t19.5 260q0 152 117 282.5t307 158.5q-8 19 -8 39q0 40 28 68t68 28t68 -28t28 -68q0 -20 -8 -39q190 -28 307 -158.5 t117 -282.5q0 -139 19.5 -260t50 -206t74.5 -158.5t85 -119.5t91 -88z" />
<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="M829 318q0 -76 -58.5 -112.5t-139.5 -36.5q-41 0 -80.5 9.5t-75.5 28.5t-58 53t-22 78q0 46 25 80t65.5 51.5t82 25t84.5 7.5q20 0 31 -2q2 -1 23 -16.5t26 -19t23 -18t24.5 -22t19 -22.5t17 -26t9 -26.5t4.5 -31.5zM755 863q0 -60 -33 -99.5t-92 -39.5q-53 0 -93 42.5 t-57.5 96.5t-17.5 106q0 61 32 104t92 43q53 0 93.5 -45t58 -101t17.5 -107zM861 1120l88 64h-265q-85 0 -161 -32t-127.5 -98t-51.5 -153q0 -93 64.5 -154.5t158.5 -61.5q22 0 43 3q-13 -29 -13 -54q0 -44 40 -94q-175 -12 -257 -63q-47 -29 -75.5 -73t-28.5 -95 q0 -43 18.5 -77.5t48.5 -56.5t69 -37t77.5 -21t76.5 -6q60 0 120.5 15.5t113.5 46t86 82.5t33 117q0 49 -20 89.5t-49 66.5t-58 47.5t-49 44t-20 44.5t15.5 42.5t37.5 39.5t44 42t37.5 59.5t15.5 82.5q0 60 -22.5 99.5t-72.5 90.5h83zM1152 672h128v64h-128v128h-64v-128 h-128v-64h128v-160h64v160zM1536 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="&#xf0d5;" horiz-adv-x="1664" d="M735 740q0 -36 32 -70.5t77.5 -68t90.5 -73.5t77 -104t32 -142q0 -90 -48 -173q-72 -122 -211 -179.5t-298 -57.5q-132 0 -246.5 41.5t-171.5 137.5q-37 60 -37 131q0 81 44.5 150t118.5 115q131 82 404 100q-32 42 -47.5 74t-15.5 73q0 36 21 85q-46 -4 -68 -4 q-148 0 -249.5 96.5t-101.5 244.5q0 82 36 159t99 131q77 66 182.5 98t217.5 32h418l-138 -88h-131q74 -63 112 -133t38 -160q0 -72 -24.5 -129.5t-59 -93t-69.5 -65t-59.5 -61.5t-24.5 -66zM589 836q38 0 78 16.5t66 43.5q53 57 53 159q0 58 -17 125t-48.5 129.5 t-84.5 103.5t-117 41q-42 0 -82.5 -19.5t-65.5 -52.5q-47 -59 -47 -160q0 -46 10 -97.5t31.5 -103t52 -92.5t75 -67t96.5 -26zM591 -37q58 0 111.5 13t99 39t73 73t27.5 109q0 25 -7 49t-14.5 42t-27 41.5t-29.5 35t-38.5 34.5t-36.5 29t-41.5 30t-36.5 26q-16 2 -48 2 q-53 0 -105 -7t-107.5 -25t-97 -46t-68.5 -74.5t-27 -105.5q0 -70 35 -123.5t91.5 -83t119 -44t127.5 -14.5zM1401 839h213v-108h-213v-219h-105v219h-212v108h212v217h105v-217z" />
<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="1792" d="M912 -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 16zM1728 128q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-181 75t-75 181h-448q-52 0 -90 38t-38 90q50 42 91 88t85 119.5t74.5 158.5 t50 206t19.5 260q0 152 117 282.5t307 158.5q-8 19 -8 39q0 40 28 68t68 28t68 -28t28 -68q0 -20 -8 -39q190 -28 307 -158.5t117 -282.5q0 -139 19.5 -260t50 -206t74.5 -158.5t85 -119.5t91 -88z" />
<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;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M384 736q0 14 9 23t23 9h704q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704q-14 0 -23 9t-9 23v64zM1120 512q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h704zM1120 256q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704 q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h704z" />
<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="1792" />
<glyph unicode="&#xf117;" horiz-adv-x="1792" />
<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="M1745 763l-164 -763h-334l178 832q13 56 -15 88q-27 33 -83 33h-169l-204 -953h-334l204 953h-286l-204 -953h-334l204 953l-153 327h1276q101 0 189.5 -40.5t147.5 -113.5q60 -73 81 -168.5t0 -194.5z" />
<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="1280" d="M1043 971q0 100 -65 162t-171 62h-320v-448h320q106 0 171 62t65 162zM1280 971q0 -193 -126.5 -315t-326.5 -122h-340v-118h505q14 0 23 -9t9 -23v-128q0 -14 -9 -23t-23 -9h-505v-192q0 -14 -9.5 -23t-22.5 -9h-167q-14 0 -23 9t-9 23v192h-224q-14 0 -23 9t-9 23v128 q0 14 9 23t23 9h224v118h-224q-14 0 -23 9t-9 23v149q0 13 9 22.5t23 9.5h224v629q0 14 9 23t23 9h539q200 0 326.5 -122t126.5 -315z" />
<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;" d="M1024 1024v472q22 -14 36 -28l408 -408q14 -14 28 -36h-472zM896 992q0 -40 28 -68t68 -28h544v-1056q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h800v-544z" />
<glyph unicode="&#xf15c;" d="M1468 1060q14 -14 28 -36h-472v472q22 -14 36 -28zM992 896h544v-1056q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h800v-544q0 -40 28 -68t68 -28zM1152 160v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704 q14 0 23 9t9 23zM1152 416v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704q14 0 23 9t9 23zM1152 672v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704q14 0 23 9t9 23z" />
<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="M944 207l80 -237q-23 -35 -111 -66t-177 -32q-104 -2 -190.5 26t-142.5 74t-95 106t-55.5 120t-16.5 118v544h-168v215q72 26 129 69.5t91 90t58 102t34 99t15 88.5q1 5 4.5 8.5t7.5 3.5h244v-424h333v-252h-334v-518q0 -30 6.5 -56t22.5 -52.5t49.5 -41.5t81.5 -14 q78 2 134 29z" />
<glyph unicode="&#xf174;" d="M1136 75l-62 183q-44 -22 -103 -22q-36 -1 -62 10.5t-38.5 31.5t-17.5 40.5t-5 43.5v398h257v194h-256v326h-188q-8 0 -9 -10q-5 -44 -17.5 -87t-39 -95t-77 -95t-118.5 -68v-165h130v-418q0 -57 21.5 -115t65 -111t121 -85.5t176.5 -30.5q69 1 136.5 25t85.5 50z 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="&#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="1280" d="M1000 1102l37 194q5 23 -9 40t-35 17h-712q-23 0 -38.5 -17t-15.5 -37v-1101q0 -7 6 -1l291 352q23 26 38 33.5t48 7.5h239q22 0 37 14.5t18 29.5q24 130 37 191q4 21 -11.5 40t-36.5 19h-294q-29 0 -48 19t-19 48v42q0 29 19 47.5t48 18.5h346q18 0 35 13.5t20 29.5z M1227 1324q-15 -73 -53.5 -266.5t-69.5 -350t-35 -173.5q-6 -22 -9 -32.5t-14 -32.5t-24.5 -33t-38.5 -21t-58 -10h-271q-13 0 -22 -10q-8 -9 -426 -494q-22 -25 -58.5 -28.5t-48.5 5.5q-55 22 -55 98v1410q0 55 38 102.5t120 47.5h888q95 0 127 -53t10 -159zM1227 1324 l-158 -790q4 17 35 173.5t69.5 350t53.5 266.5z" />
<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;" d="M1133 -34q-171 -94 -368 -94q-196 0 -367 94q138 87 235.5 211t131.5 268q35 -144 132.5 -268t235.5 -211zM638 1394v-485q0 -252 -126.5 -459.5t-330.5 -306.5q-181 215 -181 495q0 187 83.5 349.5t229.5 269.5t325 137zM1536 638q0 -280 -181 -495 q-204 99 -330.5 306.5t-126.5 459.5v485q179 -30 325 -137t229.5 -269.5t83.5 -349.5z" />
<glyph unicode="&#xf18c;" horiz-adv-x="1408" d="M1402 433q-32 -80 -76 -138t-91 -88.5t-99 -46.5t-101.5 -14.5t-96.5 8.5t-86.5 22t-69.5 27.5t-46 22.5l-17 10q-113 -228 -289.5 -359.5t-384.5 -132.5q-19 0 -32 13t-13 32t13 31.5t32 12.5q173 1 322.5 107.5t251.5 294.5q-36 -14 -72 -23t-83 -13t-91 2.5t-93 28.5 t-92 59t-84.5 100t-74.5 146q114 47 214 57t167.5 -7.5t124.5 -56.5t88.5 -77t56.5 -82q53 131 79 291q-7 -1 -18 -2.5t-46.5 -2.5t-69.5 0.5t-81.5 10t-88.5 23t-84 42.5t-75 65t-54.5 94.5t-28.5 127.5q70 28 133.5 36.5t112.5 -1t92 -30t73.5 -50t56 -61t42 -63t27.5 -56 t16 -39.5l4 -16q12 122 12 195q-8 6 -21.5 16t-49 44.5t-63.5 71.5t-54 93t-33 112.5t12 127t70 138.5q73 -25 127.5 -61.5t84.5 -76.5t48 -85t20.5 -89t-0.5 -85.5t-13 -76.5t-19 -62t-17 -42l-7 -15q1 -5 1 -50.5t-1 -71.5q3 7 10 18.5t30.5 43t50.5 58t71 55.5t91.5 44.5 t112 14.5t132.5 -24q-2 -78 -21.5 -141.5t-50 -104.5t-69.5 -71.5t-81.5 -45.5t-84.5 -24t-80 -9.5t-67.5 1t-46.5 4.5l-17 3q-23 -147 -73 -283q6 7 18 18.5t49.5 41t77.5 52.5t99.5 42t117.5 20t129 -23.5t137 -77.5z" />
<glyph unicode="&#xf18d;" horiz-adv-x="1280" d="M1259 283v-66q0 -85 -57.5 -144.5t-138.5 -59.5h-57l-260 -269v269h-529q-81 0 -138.5 59.5t-57.5 144.5v66h1238zM1259 609v-255h-1238v255h1238zM1259 937v-255h-1238v255h1238zM1259 1077v-67h-1238v67q0 84 57.5 143.5t138.5 59.5h846q81 0 138.5 -59.5t57.5 -143.5z " />
<glyph unicode="&#xf18e;" d="M1152 640q0 -14 -9 -23l-320 -320q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5v192h-352q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h352v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198 t-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.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
<glyph unicode="&#xf190;" d="M1152 736v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-352v-192q0 -14 -9 -23t-23 -9q-12 0 -24 10l-319 319q-9 9 -9 23t9 23l320 320q9 9 23 9q13 0 22.5 -9.5t9.5 -22.5v-192h352q13 0 22.5 -9.5t9.5 -22.5zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198 t-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.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
<glyph unicode="&#xf191;" d="M1024 960v-640q0 -26 -19 -45t-45 -19q-20 0 -37 12l-448 320q-27 19 -27 52t27 52l448 320q17 12 37 12q26 0 45 -19t19 -45zM1280 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.5z 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="&#xf192;" d="M1024 640q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181zM768 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.5 t-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="&#xf193;" horiz-adv-x="1664" d="M1023 349l102 -204q-58 -179 -210 -290t-339 -111q-156 0 -288.5 77.5t-210 210t-77.5 288.5q0 181 104.5 330t274.5 211l17 -131q-122 -54 -195 -165.5t-73 -244.5q0 -185 131.5 -316.5t316.5 -131.5q126 0 232.5 65t165 175.5t49.5 236.5zM1571 249l58 -114l-256 -128 q-13 -7 -29 -7q-40 0 -57 35l-239 477h-472q-24 0 -42.5 16.5t-21.5 40.5l-96 779q-2 16 6 42q14 51 57 82.5t97 31.5q66 0 113 -47t47 -113q0 -69 -52 -117.5t-120 -41.5l37 -289h423v-128h-407l16 -128h455q40 0 57 -35l228 -455z" />
<glyph unicode="&#xf194;" d="M1254 899q16 85 -21 132q-52 65 -187 45q-17 -3 -41 -12.5t-57.5 -30.5t-64.5 -48.5t-59.5 -70t-44.5 -91.5q80 7 113.5 -16t26.5 -99q-5 -52 -52 -143q-43 -78 -71 -99q-44 -32 -87 14q-23 24 -37.5 64.5t-19 73t-10 84t-8.5 71.5q-23 129 -34 164q-12 37 -35.5 69 t-50.5 40q-57 16 -127 -25q-54 -32 -136.5 -106t-122.5 -102v-7q16 -8 25.5 -26t21.5 -20q21 -3 54.5 8.5t58 10.5t41.5 -30q11 -18 18.5 -38.5t15 -48t12.5 -40.5q17 -46 53 -187q36 -146 57 -197q42 -99 103 -125q43 -12 85 -1.5t76 31.5q131 77 250 237 q104 139 172.5 292.5t82.5 226.5zM1536 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="&#xf195;" horiz-adv-x="1152" d="M1152 704q0 -191 -94.5 -353t-256.5 -256.5t-353 -94.5h-160q-14 0 -23 9t-9 23v611l-215 -66q-3 -1 -9 -1q-10 0 -19 6q-13 10 -13 26v128q0 23 23 31l233 71v93l-215 -66q-3 -1 -9 -1q-10 0 -19 6q-13 10 -13 26v128q0 23 23 31l233 71v250q0 14 9 23t23 9h160 q14 0 23 -9t9 -23v-181l375 116q15 5 28 -5t13 -26v-128q0 -23 -23 -31l-393 -121v-93l375 116q15 5 28 -5t13 -26v-128q0 -23 -23 -31l-393 -121v-487q188 13 318 151t130 328q0 14 9 23t23 9h160q14 0 23 -9t9 -23z" />
<glyph unicode="&#xf196;" horiz-adv-x="1408" d="M1152 736v-64q0 -14 -9 -23t-23 -9h-352v-352q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v352h-352q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h352v352q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-352h352q14 0 23 -9t9 -23zM1280 288v832q0 66 -47 113t-113 47h-832 q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113zM1408 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.5h832q119 0 203.5 -84.5t84.5 -203.5z" />
<glyph unicode="&#xf197;" horiz-adv-x="2176" d="M620 416q-110 -64 -268 -64h-128v64h-64q-13 0 -22.5 23.5t-9.5 56.5q0 24 7 49q-58 2 -96.5 10.5t-38.5 20.5t38.5 20.5t96.5 10.5q-7 25 -7 49q0 33 9.5 56.5t22.5 23.5h64v64h128q158 0 268 -64h1113q42 -7 106.5 -18t80.5 -14q89 -15 150 -40.5t83.5 -47.5t22.5 -40 t-22.5 -40t-83.5 -47.5t-150 -40.5q-16 -3 -80.5 -14t-106.5 -18h-1113zM1739 668q53 -36 53 -92t-53 -92l81 -30q68 48 68 122t-68 122zM625 400h1015q-217 -38 -456 -80q-57 0 -113 -24t-83 -48l-28 -24l-288 -288q-26 -26 -70.5 -45t-89.5 -19h-96l-93 464h29 q157 0 273 64zM352 816h-29l93 464h96q46 0 90 -19t70 -45l288 -288q4 -4 11 -10.5t30.5 -23t48.5 -29t61.5 -23t72.5 -10.5l456 -80h-1015q-116 64 -273 64z" />
<glyph unicode="&#xf198;" horiz-adv-x="1664" d="M1519 760q62 0 103.5 -40.5t41.5 -101.5q0 -97 -93 -130l-172 -59l56 -167q7 -21 7 -47q0 -59 -42 -102t-101 -43q-47 0 -85.5 27t-53.5 72l-55 165l-310 -106l55 -164q8 -24 8 -47q0 -59 -42 -102t-102 -43q-47 0 -85 27t-53 72l-55 163l-153 -53q-29 -9 -50 -9 q-61 0 -101.5 40t-40.5 101q0 47 27.5 85t71.5 53l156 53l-105 313l-156 -54q-26 -8 -48 -8q-60 0 -101 40.5t-41 100.5q0 47 27.5 85t71.5 53l157 53l-53 159q-8 24 -8 47q0 60 42 102.5t102 42.5q47 0 85 -27t53 -72l54 -160l310 105l-54 160q-8 24 -8 47q0 59 42.5 102 t101.5 43q47 0 85.5 -27.5t53.5 -71.5l53 -161l162 55q21 6 43 6q60 0 102.5 -39.5t42.5 -98.5q0 -45 -30 -81.5t-74 -51.5l-157 -54l105 -316l164 56q24 8 46 8zM725 498l310 105l-105 315l-310 -107z" />
<glyph unicode="&#xf199;" 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.5h960zM1280 352v436q-31 -35 -64 -55q-34 -22 -132.5 -85t-151.5 -99q-98 -69 -164 -69v0v0q-66 0 -164 69 q-46 32 -141.5 92.5t-142.5 92.5q-12 8 -33 27t-31 27v-436q0 -40 28 -68t68 -28h832q40 0 68 28t28 68zM1280 925q0 41 -27.5 70t-68.5 29h-832q-40 0 -68 -28t-28 -68q0 -37 30.5 -76.5t67.5 -64.5q47 -32 137.5 -89t129.5 -83q3 -2 17 -11.5t21 -14t21 -13t23.5 -13 t21.5 -9.5t22.5 -7.5t20.5 -2.5t20.5 2.5t22.5 7.5t21.5 9.5t23.5 13t21 13t21 14t17 11.5l267 174q35 23 66.5 62.5t31.5 73.5z" />
<glyph unicode="&#xf19a;" horiz-adv-x="1792" d="M127 640q0 163 67 313l367 -1005q-196 95 -315 281t-119 411zM1415 679q0 -19 -2.5 -38.5t-10 -49.5t-11.5 -44t-17.5 -59t-17.5 -58l-76 -256l-278 826q46 3 88 8q19 2 26 18.5t-2.5 31t-28.5 13.5l-205 -10q-75 1 -202 10q-12 1 -20.5 -5t-11.5 -15t-1.5 -18.5t9 -16.5 t19.5 -8l80 -8l120 -328l-168 -504l-280 832q46 3 88 8q19 2 26 18.5t-2.5 31t-28.5 13.5l-205 -10q-7 0 -23 0.5t-26 0.5q105 160 274.5 253.5t367.5 93.5q147 0 280.5 -53t238.5 -149h-10q-55 0 -92 -40.5t-37 -95.5q0 -12 2 -24t4 -21.5t8 -23t9 -21t12 -22.5t12.5 -21 t14.5 -24t14 -23q63 -107 63 -212zM909 573l237 -647q1 -6 5 -11q-126 -44 -255 -44q-112 0 -217 32zM1570 1009q95 -174 95 -369q0 -209 -104 -385.5t-279 -278.5l235 678q59 169 59 276q0 42 -6 79zM896 1536q182 0 348 -71t286 -191t191 -286t71 -348t-71 -348t-191 -286 t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71zM896 -215q173 0 331.5 68t273 182.5t182.5 273t68 331.5t-68 331.5t-182.5 273t-273 182.5t-331.5 68t-331.5 -68t-273 -182.5t-182.5 -273t-68 -331.5t68 -331.5t182.5 -273 t273 -182.5t331.5 -68z" />
<glyph unicode="&#xf19b;" horiz-adv-x="1792" d="M1086 1536v-1536l-272 -128q-228 20 -414 102t-293 208.5t-107 272.5q0 140 100.5 263.5t275 205.5t391.5 108v-172q-217 -38 -356.5 -150t-139.5 -255q0 -152 154.5 -267t388.5 -145v1360zM1755 954l37 -390l-525 114l147 83q-119 70 -280 99v172q277 -33 481 -157z" />
<glyph unicode="&#xf19c;" horiz-adv-x="2048" d="M960 1536l960 -384v-128h-128q0 -26 -20.5 -45t-48.5 -19h-1526q-28 0 -48.5 19t-20.5 45h-128v128zM256 896h256v-768h128v768h256v-768h128v768h256v-768h128v768h256v-768h59q28 0 48.5 -19t20.5 -45v-64h-1664v64q0 26 20.5 45t48.5 19h59v768zM1851 -64 q28 0 48.5 -19t20.5 -45v-128h-1920v128q0 26 20.5 45t48.5 19h1782z" />
<glyph unicode="&#xf19d;" horiz-adv-x="2304" d="M1774 700l18 -316q4 -69 -82 -128t-235 -93.5t-323 -34.5t-323 34.5t-235 93.5t-82 128l18 316l574 -181q22 -7 48 -7t48 7zM2304 1024q0 -23 -22 -31l-1120 -352q-4 -1 -10 -1t-10 1l-652 206q-43 -34 -71 -111.5t-34 -178.5q63 -36 63 -109q0 -69 -58 -107l58 -433 q2 -14 -8 -25q-9 -11 -24 -11h-192q-15 0 -24 11q-10 11 -8 25l58 433q-58 38 -58 107q0 73 65 111q11 207 98 330l-333 104q-22 8 -22 31t22 31l1120 352q4 1 10 1t10 -1l1120 -352q22 -8 22 -31z" />
<glyph unicode="&#xf19e;" d="M859 579l13 -707q-62 11 -105 11q-41 0 -105 -11l13 707q-40 69 -168.5 295.5t-216.5 374.5t-181 287q58 -15 108 -15q43 0 111 15q63 -111 133.5 -229.5t167 -276.5t138.5 -227q37 61 109.5 177.5t117.5 190t105 176t107 189.5q54 -14 107 -14q56 0 114 14v0 q-28 -39 -60 -88.5t-49.5 -78.5t-56.5 -96t-49 -84q-146 -248 -353 -610z" />
<glyph unicode="&#xf1a0;" horiz-adv-x="1280" d="M981 197q0 25 -7 49t-14.5 42t-27 41.5t-29.5 35t-38.5 34.5t-36.5 29t-41.5 30t-36.5 26q-16 2 -49 2q-53 0 -104.5 -7t-107 -25t-97 -46t-68.5 -74.5t-27 -105.5q0 -56 23.5 -102t61 -75.5t87 -50t100 -29t101.5 -8.5q58 0 111.5 13t99 39t73 73t27.5 109zM864 1055 q0 59 -17 125.5t-48 129t-84 103.5t-117 41q-42 0 -82.5 -19.5t-66.5 -52.5q-46 -59 -46 -160q0 -46 10 -97.5t31.5 -103t52 -92.5t75 -67t96.5 -26q37 0 77.5 16.5t65.5 43.5q53 56 53 159zM752 1536h417l-137 -88h-132q75 -63 113 -133t38 -160q0 -72 -24.5 -129.5 t-59.5 -93t-69.5 -65t-59 -61.5t-24.5 -66q0 -36 32 -70.5t77 -68t90.5 -73.5t77.5 -104t32 -142q0 -91 -49 -173q-71 -122 -209.5 -179.5t-298.5 -57.5q-132 0 -246.5 41.5t-172.5 137.5q-36 59 -36 131q0 81 44.5 150t118.5 115q131 82 404 100q-32 41 -47.5 73.5 t-15.5 73.5q0 40 21 85q-46 -4 -68 -4q-148 0 -249.5 96.5t-101.5 244.5q0 82 36 159t99 131q76 66 182 98t218 32z" />
<glyph unicode="&#xf1a1;" horiz-adv-x="1984" d="M831 572q0 -56 -40.5 -96t-96.5 -40q-57 0 -98 40t-41 96q0 57 41.5 98t97.5 41t96.5 -41t40.5 -98zM1292 711q56 0 96.5 -41t40.5 -98q0 -56 -40.5 -96t-96.5 -40q-57 0 -98 40t-41 96q0 57 41.5 98t97.5 41zM1984 722q0 -62 -31 -114t-83 -82q5 -33 5 -61 q0 -121 -68.5 -230.5t-197.5 -193.5q-125 -82 -285.5 -125.5t-335.5 -43.5q-176 0 -336.5 43.5t-284.5 125.5q-129 84 -197.5 193t-68.5 231q0 29 5 66q-48 31 -77 81.5t-29 109.5q0 94 66 160t160 66q83 0 148 -55q248 158 592 164l134 423q4 14 17.5 21.5t28.5 4.5 l347 -82q22 50 68.5 81t102.5 31q77 0 131.5 -54.5t54.5 -131.5t-54.5 -132t-131.5 -55q-76 0 -130.5 54t-55.5 131l-315 74l-116 -366q327 -14 560 -166q64 58 151 58q94 0 160 -66t66 -160zM1664 1459q-45 0 -77 -32t-32 -77t32 -77t77 -32t77 32t32 77t-32 77t-77 32z M77 722q0 -67 51 -111q49 131 180 235q-36 25 -82 25q-62 0 -105.5 -43.5t-43.5 -105.5zM1567 105q112 73 171.5 166t59.5 194t-59.5 193.5t-171.5 165.5q-116 75 -265.5 115.5t-313.5 40.5t-313.5 -40.5t-265.5 -115.5q-112 -73 -171.5 -165.5t-59.5 -193.5t59.5 -194 t171.5 -166q116 -75 265.5 -115.5t313.5 -40.5t313.5 40.5t265.5 115.5zM1850 605q57 46 57 117q0 62 -43.5 105.5t-105.5 43.5q-49 0 -86 -28q131 -105 178 -238zM1258 237q11 11 27 11t27 -11t11 -27.5t-11 -27.5q-99 -99 -319 -99h-2q-220 0 -319 99q-11 11 -11 27.5 t11 27.5t27 11t27 -11q77 -77 265 -77h2q188 0 265 77z" />
<glyph unicode="&#xf1a2;" d="M950 393q7 7 17.5 7t17.5 -7t7 -18t-7 -18q-65 -64 -208 -64h-1h-1q-143 0 -207 64q-8 7 -8 18t8 18q7 7 17.5 7t17.5 -7q49 -51 172 -51h1h1q122 0 173 51zM671 613q0 -37 -26 -64t-63 -27t-63 27t-26 64t26 63t63 26t63 -26t26 -63zM1214 1049q-29 0 -50 21t-21 50 q0 30 21 51t50 21q30 0 51 -21t21 -51q0 -29 -21 -50t-51 -21zM1216 1408q132 0 226 -94t94 -227v-894q0 -133 -94 -227t-226 -94h-896q-132 0 -226 94t-94 227v894q0 133 94 227t226 94h896zM1321 596q35 14 57 45.5t22 70.5q0 51 -36 87.5t-87 36.5q-60 0 -98 -48 q-151 107 -375 115l83 265l206 -49q1 -50 36.5 -85t84.5 -35q50 0 86 35.5t36 85.5t-36 86t-86 36q-36 0 -66 -20.5t-45 -53.5l-227 54q-9 2 -17.5 -2.5t-11.5 -14.5l-95 -302q-224 -4 -381 -113q-36 43 -93 43q-51 0 -87 -36.5t-36 -87.5q0 -37 19.5 -67.5t52.5 -45.5 q-7 -25 -7 -54q0 -98 74 -181.5t201.5 -132t278.5 -48.5q150 0 277.5 48.5t201.5 132t74 181.5q0 27 -6 54zM971 702q37 0 63 -26t26 -63t-26 -64t-63 -27t-63 27t-26 64t26 63t63 26z" />
<glyph unicode="&#xf1a3;" d="M866 697l90 27v62q0 79 -58 135t-138 56t-138 -55.5t-58 -134.5v-283q0 -20 -14 -33.5t-33 -13.5t-32.5 13.5t-13.5 33.5v120h-151v-122q0 -82 57.5 -139t139.5 -57q81 0 138.5 56.5t57.5 136.5v280q0 19 13.5 33t33.5 14q19 0 32.5 -14t13.5 -33v-54zM1199 502v122h-150 v-126q0 -20 -13.5 -33.5t-33.5 -13.5q-19 0 -32.5 14t-13.5 33v123l-90 -26l-60 28v-123q0 -80 58 -137t139 -57t138.5 57t57.5 139zM1536 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 103 t385.5 -103t279.5 -279.5t103 -385.5z" />
<glyph unicode="&#xf1a4;" horiz-adv-x="1920" d="M1062 824v118q0 42 -30 72t-72 30t-72 -30t-30 -72v-612q0 -175 -126 -299t-303 -124q-178 0 -303.5 125.5t-125.5 303.5v266h328v-262q0 -43 30 -72.5t72 -29.5t72 29.5t30 72.5v620q0 171 126.5 292t301.5 121q176 0 302 -122t126 -294v-136l-195 -58zM1592 602h328 v-266q0 -178 -125.5 -303.5t-303.5 -125.5q-177 0 -303 124.5t-126 300.5v268l131 -61l195 58v-270q0 -42 30 -71.5t72 -29.5t72 29.5t30 71.5v275z" />
<glyph unicode="&#xf1a5;" d="M1472 160v480h-704v704h-480q-93 0 -158.5 -65.5t-65.5 -158.5v-480h704v-704h480q93 0 158.5 65.5t65.5 158.5zM1536 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="&#xf1a6;" horiz-adv-x="2048" d="M328 1254h204v-983h-532v697h328v286zM328 435v369h-123v-369h123zM614 968v-697h205v697h-205zM614 1254v-204h205v204h-205zM901 968h533v-942h-533v163h328v82h-328v697zM1229 435v369h-123v-369h123zM1516 968h532v-942h-532v163h327v82h-327v697zM1843 435v369h-123 v-369h123z" />
<glyph unicode="&#xf1a7;" d="M1046 516q0 -64 -38 -109t-91 -45q-43 0 -70 15v277q28 17 70 17q53 0 91 -45.5t38 -109.5zM703 944q0 -64 -38 -109.5t-91 -45.5q-43 0 -70 15v277q28 17 70 17q53 0 91 -45t38 -109zM1265 513q0 134 -88 229t-213 95q-20 0 -39 -3q-23 -78 -78 -136q-87 -95 -211 -101 v-636l211 41v206q51 -19 117 -19q125 0 213 95t88 229zM922 940q0 134 -88.5 229t-213.5 95q-74 0 -141 -36h-186v-840l211 41v206q55 -19 116 -19q125 0 213.5 95t88.5 229zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960 q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
<glyph unicode="&#xf1a8;" horiz-adv-x="2038" d="M1222 607q75 3 143.5 -20.5t118 -58.5t101 -94.5t84 -108t75.5 -120.5q33 -56 78.5 -109t75.5 -80.5t99 -88.5q-48 -30 -108.5 -57.5t-138.5 -59t-114 -47.5q-44 37 -74 115t-43.5 164.5t-33 180.5t-42.5 168.5t-72.5 123t-122.5 48.5l-10 -2l-6 -4q4 -5 13 -14 q6 -5 28 -23.5t25.5 -22t19 -18t18 -20.5t11.5 -21t10.5 -27.5t4.5 -31t4 -40.5l1 -33q1 -26 -2.5 -57.5t-7.5 -52t-12.5 -58.5t-11.5 -53q-35 1 -101 -9.5t-98 -10.5q-39 0 -72 10q-2 16 -2 47q0 74 3 96q2 13 31.5 41.5t57 59t26.5 51.5q-24 2 -43 -24 q-36 -53 -111.5 -99.5t-136.5 -46.5q-25 0 -75.5 63t-106.5 139.5t-84 96.5q-6 4 -27 30q-482 -112 -513 -112q-16 0 -28 11t-12 27q0 15 8.5 26.5t22.5 14.5l486 106q-8 14 -8 25t5.5 17.5t16 11.5t20 7t23 4.5t18.5 4.5q4 1 15.5 7.5t17.5 6.5q15 0 28 -16t20 -33 q163 37 172 37q17 0 29.5 -11t12.5 -28q0 -15 -8.5 -26t-23.5 -14l-182 -40l-1 -16q-1 -26 81.5 -117.5t104.5 -91.5q47 0 119 80t72 129q0 36 -23.5 53t-51 18.5t-51 11.5t-23.5 34q0 16 10 34l-68 19q43 44 43 117q0 26 -5 58q82 16 144 16q44 0 71.5 -1.5t48.5 -8.5 t31 -13.5t20.5 -24.5t15.5 -33.5t17 -47.5t24 -60l50 25q-3 -40 -23 -60t-42.5 -21t-40 -6.5t-16.5 -20.5zM1282 842q-5 5 -13.5 15.5t-12 14.5t-10.5 11.5t-10 10.5l-8 8t-8.5 7.5t-8 5t-8.5 4.5q-7 3 -14.5 5t-20.5 2.5t-22 0.5h-32.5h-37.5q-126 0 -217 -43 q16 30 36 46.5t54 29.5t65.5 36t46 36.5t50 55t43.5 50.5q12 -9 28 -31.5t32 -36.5t38 -13l12 1v-76l22 -1q247 95 371 190q28 21 50 39t42.5 37.5t33 31t29.5 34t24 31t24.5 37t23 38t27 47.5t29.5 53l7 9q-2 -53 -43 -139q-79 -165 -205 -264t-306 -142q-14 -3 -42 -7.5 t-50 -9.5t-39 -14q3 -19 24.5 -46t21.5 -34q0 -11 -26 -30zM1061 -79q39 26 131.5 47.5t146.5 21.5q9 0 22.5 -15.5t28 -42.5t26 -50t24 -51t14.5 -33q-121 -45 -244 -45q-61 0 -125 11zM822 568l48 12l109 -177l-73 -48zM1323 51q3 -15 3 -16q0 -7 -17.5 -14.5t-46 -13 t-54 -9.5t-53.5 -7.5t-32 -4.5l-7 43q21 2 60.5 8.5t72 10t60.5 3.5h14zM866 679l-96 -20l-6 17q10 1 32.5 7t34.5 6q19 0 35 -10zM1061 45h31l10 -83l-41 -12v95zM1950 1535v1v-1zM1950 1535l-1 -5l-2 -2l1 3zM1950 1535l1 1z" />
<glyph unicode="&#xf1a9;" d="M1167 -50q-5 19 -24 5q-30 -22 -87 -39t-131 -17q-129 0 -193 49q-5 4 -13 4q-11 0 -26 -12q-7 -6 -7.5 -16t7.5 -20q34 -32 87.5 -46t102.5 -12.5t99 4.5q41 4 84.5 20.5t65 30t28.5 20.5q12 12 7 29zM1128 65q-19 47 -39 61q-23 15 -76 15q-47 0 -71 -10 q-29 -12 -78 -56q-26 -24 -12 -44q9 -8 17.5 -4.5t31.5 23.5q3 2 10.5 8.5t10.5 8.5t10 7t11.5 7t12.5 5t15 4.5t16.5 2.5t20.5 1q27 0 44.5 -7.5t23 -14.5t13.5 -22q10 -17 12.5 -20t12.5 1q23 12 14 34zM1483 346q0 22 -5 44.5t-16.5 45t-34 36.5t-52.5 14 q-33 0 -97 -41.5t-129 -83.5t-101 -42q-27 -1 -63.5 19t-76 49t-83.5 58t-100 49t-111 19q-115 -1 -197 -78.5t-84 -178.5q-2 -112 74 -164q29 -20 62.5 -28.5t103.5 -8.5q57 0 132 32.5t134 71t120 70.5t93 31q26 -1 65 -31.5t71.5 -67t68 -67.5t55.5 -32q35 -3 58.5 14 t55.5 63q28 41 42.5 101t14.5 106zM1536 506q0 -164 -62 -304.5t-166 -236t-242.5 -149.5t-290.5 -54t-293 57.5t-247.5 157t-170.5 241.5t-64 302q0 89 19.5 172.5t49 145.5t70.5 118.5t78.5 94t78.5 69.5t64.5 46.5t42.5 24.5q14 8 51 26.5t54.5 28.5t48 30t60.5 44 q36 28 58 72.5t30 125.5q129 -155 186 -193q44 -29 130 -68t129 -66q21 -13 39 -25t60.5 -46.5t76 -70.5t75 -95t69 -122t47 -148.5t19.5 -177.5z" />
<glyph unicode="&#xf1aa;" d="M1070 463l-160 -160l-151 -152l-30 -30q-65 -64 -151.5 -87t-171.5 -2q-16 -70 -72 -115t-129 -45q-85 0 -145 60.5t-60 145.5q0 72 44.5 128t113.5 72q-22 86 1 173t88 152l12 12l151 -152l-11 -11q-37 -37 -37 -89t37 -90q37 -37 89 -37t89 37l30 30l151 152l161 160z M729 1145l12 -12l-152 -152l-12 12q-37 37 -89 37t-89 -37t-37 -89.5t37 -89.5l29 -29l152 -152l160 -160l-151 -152l-161 160l-151 152l-30 30q-68 67 -90 159.5t5 179.5q-70 15 -115 71t-45 129q0 85 60 145.5t145 60.5q76 0 133.5 -49t69.5 -123q84 20 169.5 -3.5 t149.5 -87.5zM1536 78q0 -85 -60 -145.5t-145 -60.5q-74 0 -131 47t-71 118q-86 -28 -179.5 -6t-161.5 90l-11 12l151 152l12 -12q37 -37 89 -37t89 37t37 89t-37 89l-30 30l-152 152l-160 160l152 152l160 -160l152 -152l29 -30q64 -64 87.5 -150.5t2.5 -171.5 q76 -11 126.5 -68.5t50.5 -134.5zM1534 1202q0 -77 -51 -135t-127 -69q26 -85 3 -176.5t-90 -158.5l-12 -12l-151 152l12 12q37 37 37 89t-37 89t-89 37t-89 -37l-30 -30l-152 -152l-160 -160l-152 152l161 160l152 152l29 30q67 67 159 89.5t178 -3.5q11 75 68.5 126 t135.5 51q85 0 145 -60.5t60 -145.5z" />
<glyph unicode="&#xf1ab;" d="M654 458q-1 -3 -12.5 0.5t-31.5 11.5l-20 9q-44 20 -87 49q-7 5 -41 31.5t-38 28.5q-67 -103 -134 -181q-81 -95 -105 -110q-4 -2 -19.5 -4t-18.5 0q6 4 82 92q21 24 85.5 115t78.5 118q17 30 51 98.5t36 77.5q-8 1 -110 -33q-8 -2 -27.5 -7.5t-34.5 -9.5t-17 -5 q-2 -2 -2 -10.5t-1 -9.5q-5 -10 -31 -15q-23 -7 -47 0q-18 4 -28 21q-4 6 -5 23q6 2 24.5 5t29.5 6q58 16 105 32q100 35 102 35q10 2 43 19.5t44 21.5q9 3 21.5 8t14.5 5.5t6 -0.5q2 -12 -1 -33q0 -2 -12.5 -27t-26.5 -53.5t-17 -33.5q-25 -50 -77 -131l64 -28 q12 -6 74.5 -32t67.5 -28q4 -1 10.5 -25.5t4.5 -30.5zM449 944q3 -15 -4 -28q-12 -23 -50 -38q-30 -12 -60 -12q-26 3 -49 26q-14 15 -18 41l1 3q3 -3 19.5 -5t26.5 0t58 16q36 12 55 14q17 0 21 -17zM1147 815l63 -227l-139 42zM39 15l694 232v1032l-694 -233v-1031z M1280 332l102 -31l-181 657l-100 31l-216 -536l102 -31l45 110l211 -65zM777 1294l573 -184v380zM1088 -29l158 -13l-54 -160l-40 66q-130 -83 -276 -108q-58 -12 -91 -12h-84q-79 0 -199.5 39t-183.5 85q-8 7 -8 16q0 8 5 13.5t13 5.5q4 0 18 -7.5t30.5 -16.5t20.5 -11 q73 -37 159.5 -61.5t157.5 -24.5q95 0 167 14.5t157 50.5q15 7 30.5 15.5t34 19t28.5 16.5zM1536 1050v-1079l-774 246q-14 -6 -375 -127.5t-368 -121.5q-13 0 -18 13q0 1 -1 3v1078q3 9 4 10q5 6 20 11q106 35 149 50v384l558 -198q2 0 160.5 55t316 108.5t161.5 53.5 q20 0 20 -21v-418z" />
<glyph unicode="&#xf1ac;" horiz-adv-x="1792" d="M288 1152q66 0 113 -47t47 -113v-1088q0 -66 -47 -113t-113 -47h-128q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h128zM1664 989q58 -34 93 -93t35 -128v-768q0 -106 -75 -181t-181 -75h-864q-66 0 -113 47t-47 113v1536q0 40 28 68t68 28h672q40 0 88 -20t76 -48 l152 -152q28 -28 48 -76t20 -88v-163zM928 0v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM928 256v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM928 512v128q0 14 -9 23 t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1184 0v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1184 256v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128 q14 0 23 9t9 23zM1184 512v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1440 0v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1440 256v128q0 14 -9 23t-23 9h-128 q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1440 512v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1536 896v256h-160q-40 0 -68 28t-28 68v160h-640v-512h896z" />
<glyph unicode="&#xf1ad;" d="M1344 1536q26 0 45 -19t19 -45v-1664q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v1664q0 26 19 45t45 19h1280zM512 1248v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM512 992v-64q0 -14 9 -23t23 -9h64q14 0 23 9 t9 23v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM512 736v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM512 480v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM384 160v64 q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM384 416v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM384 672v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64 q14 0 23 9t9 23zM384 928v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM384 1184v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM896 -96v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9 t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM896 416v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM896 672v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM896 928v64 q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM896 1184v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1152 160v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64 q14 0 23 9t9 23zM1152 416v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1152 672v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1152 928v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9 t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1152 1184v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23z" />
<glyph unicode="&#xf1ae;" horiz-adv-x="1280" d="M1188 988l-292 -292v-824q0 -46 -33 -79t-79 -33t-79 33t-33 79v384h-64v-384q0 -46 -33 -79t-79 -33t-79 33t-33 79v824l-292 292q-28 28 -28 68t28 68t68 28t68 -28l228 -228h368l228 228q28 28 68 28t68 -28t28 -68t-28 -68zM864 1152q0 -93 -65.5 -158.5 t-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="&#xf1b0;" horiz-adv-x="1664" d="M780 1064q0 -60 -19 -113.5t-63 -92.5t-105 -39q-76 0 -138 57.5t-92 135.5t-30 151q0 60 19 113.5t63 92.5t105 39q77 0 138.5 -57.5t91.5 -135t30 -151.5zM438 581q0 -80 -42 -139t-119 -59q-76 0 -141.5 55.5t-100.5 133.5t-35 152q0 80 42 139.5t119 59.5 q76 0 141.5 -55.5t100.5 -134t35 -152.5zM832 608q118 0 255 -97.5t229 -237t92 -254.5q0 -46 -17 -76.5t-48.5 -45t-64.5 -20t-76 -5.5q-68 0 -187.5 45t-182.5 45q-66 0 -192.5 -44.5t-200.5 -44.5q-183 0 -183 146q0 86 56 191.5t139.5 192.5t187.5 146t193 59zM1071 819 q-61 0 -105 39t-63 92.5t-19 113.5q0 74 30 151.5t91.5 135t138.5 57.5q61 0 105 -39t63 -92.5t19 -113.5q0 -73 -30 -151t-92 -135.5t-138 -57.5zM1503 923q77 0 119 -59.5t42 -139.5q0 -74 -35 -152t-100.5 -133.5t-141.5 -55.5q-77 0 -119 59t-42 139q0 74 35 152.5 t100.5 134t141.5 55.5z" />
<glyph unicode="&#xf1b1;" horiz-adv-x="768" d="M704 1008q0 -145 -57 -243.5t-152 -135.5l45 -821q2 -26 -16 -45t-44 -19h-192q-26 0 -44 19t-16 45l45 821q-95 37 -152 135.5t-57 243.5q0 128 42.5 249.5t117.5 200t160 78.5t160 -78.5t117.5 -200t42.5 -249.5z" />
<glyph unicode="&#xf1b2;" horiz-adv-x="1792" d="M896 -93l640 349v636l-640 -233v-752zM832 772l698 254l-698 254l-698 -254zM1664 1024v-768q0 -35 -18 -65t-49 -47l-704 -384q-28 -16 -61 -16t-61 16l-704 384q-31 17 -49 47t-18 65v768q0 40 23 73t61 47l704 256q22 8 44 8t44 -8l704 -256q38 -14 61 -47t23 -73z " />
<glyph unicode="&#xf1b3;" horiz-adv-x="2304" d="M640 -96l384 192v314l-384 -164v-342zM576 358l404 173l-404 173l-404 -173zM1664 -96l384 192v314l-384 -164v-342zM1600 358l404 173l-404 173l-404 -173zM1152 651l384 165v266l-384 -164v-267zM1088 1030l441 189l-441 189l-441 -189zM2176 512v-416q0 -36 -19 -67 t-52 -47l-448 -224q-25 -14 -57 -14t-57 14l-448 224q-5 2 -7 4q-2 -2 -7 -4l-448 -224q-25 -14 -57 -14t-57 14l-448 224q-33 16 -52 47t-19 67v416q0 38 21.5 70t56.5 48l434 186v400q0 38 21.5 70t56.5 48l448 192q23 10 50 10t50 -10l448 -192q35 -16 56.5 -48t21.5 -70 v-400l434 -186q36 -16 57 -48t21 -70z" />
<glyph unicode="&#xf1b4;" horiz-adv-x="2048" d="M1848 1197h-511v-124h511v124zM1596 771q-90 0 -146 -52.5t-62 -142.5h408q-18 195 -200 195zM1612 186q63 0 122 32t76 87h221q-100 -307 -427 -307q-214 0 -340.5 132t-126.5 347q0 208 130.5 345.5t336.5 137.5q138 0 240.5 -68t153 -179t50.5 -248q0 -17 -2 -47h-658 q0 -111 57.5 -171.5t166.5 -60.5zM277 236h296q205 0 205 167q0 180 -199 180h-302v-347zM277 773h281q78 0 123.5 36.5t45.5 113.5q0 144 -190 144h-260v-294zM0 1282h594q87 0 155 -14t126.5 -47.5t90 -96.5t31.5 -154q0 -181 -172 -263q114 -32 172 -115t58 -204 q0 -75 -24.5 -136.5t-66 -103.5t-98.5 -71t-121 -42t-134 -13h-611v1260z" />
<glyph unicode="&#xf1b5;" 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.5h960zM499 1041h-371v-787h382q117 0 197 57.5t80 170.5q0 158 -143 200q107 52 107 164q0 57 -19.5 96.5 t-56.5 60.5t-79 29.5t-97 8.5zM477 723h-176v184h163q119 0 119 -90q0 -94 -106 -94zM486 388h-185v217h189q124 0 124 -113q0 -104 -128 -104zM1136 356q-68 0 -104 38t-36 107h411q1 10 1 30q0 132 -74.5 220.5t-203.5 88.5q-128 0 -210 -86t-82 -216q0 -135 79 -217 t213 -82q205 0 267 191h-138q-11 -34 -47.5 -54t-75.5 -20zM1126 722q113 0 124 -122h-254q4 56 39 89t91 33zM964 988h319v-77h-319v77z" />
<glyph unicode="&#xf1b6;" horiz-adv-x="1792" d="M1582 954q0 -101 -71.5 -172.5t-172.5 -71.5t-172.5 71.5t-71.5 172.5t71.5 172.5t172.5 71.5t172.5 -71.5t71.5 -172.5zM812 212q0 104 -73 177t-177 73q-27 0 -54 -6l104 -42q77 -31 109.5 -106.5t1.5 -151.5q-31 -77 -107 -109t-152 -1q-21 8 -62 24.5t-61 24.5 q32 -60 91 -96.5t130 -36.5q104 0 177 73t73 177zM1642 953q0 126 -89.5 215.5t-215.5 89.5q-127 0 -216.5 -89.5t-89.5 -215.5q0 -127 89.5 -216t216.5 -89q126 0 215.5 89t89.5 216zM1792 953q0 -189 -133.5 -322t-321.5 -133l-437 -319q-12 -129 -109 -218t-229 -89 q-121 0 -214 76t-118 192l-230 92v429l389 -157q79 48 173 48q13 0 35 -2l284 407q2 187 135.5 319t320.5 132q188 0 321.5 -133.5t133.5 -321.5z" />
<glyph unicode="&#xf1b7;" d="M1242 889q0 80 -57 136.5t-137 56.5t-136.5 -57t-56.5 -136q0 -80 56.5 -136.5t136.5 -56.5t137 56.5t57 136.5zM632 301q0 -83 -58 -140.5t-140 -57.5q-56 0 -103 29t-72 77q52 -20 98 -40q60 -24 120 1.5t85 86.5q24 60 -1.5 120t-86.5 84l-82 33q22 5 42 5 q82 0 140 -57.5t58 -140.5zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v153l172 -69q20 -92 93.5 -152t168.5 -60q104 0 181 70t87 173l345 252q150 0 255.5 105.5t105.5 254.5q0 150 -105.5 255.5t-255.5 105.5 q-148 0 -253 -104.5t-107 -252.5l-225 -322q-9 1 -28 1q-75 0 -137 -37l-297 119v468q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5zM1289 887q0 -100 -71 -170.5t-171 -70.5t-170.5 70.5t-70.5 170.5t70.5 171t170.5 71q101 0 171.5 -70.5t70.5 -171.5z " />
<glyph unicode="&#xf1b8;" horiz-adv-x="1792" d="M836 367l-15 -368l-2 -22l-420 29q-36 3 -67 31.5t-47 65.5q-11 27 -14.5 55t4 65t12 55t21.5 64t19 53q78 -12 509 -28zM449 953l180 -379l-147 92q-63 -72 -111.5 -144.5t-72.5 -125t-39.5 -94.5t-18.5 -63l-4 -21l-190 357q-17 26 -18 56t6 47l8 18q35 63 114 188 l-140 86zM1680 436l-188 -359q-12 -29 -36.5 -46.5t-43.5 -20.5l-18 -4q-71 -7 -219 -12l8 -164l-230 367l211 362l7 -173q170 -16 283 -5t170 33zM895 1360q-47 -63 -265 -435l-317 187l-19 12l225 356q20 31 60 45t80 10q24 -2 48.5 -12t42 -21t41.5 -33t36 -34.5 t36 -39.5t32 -35zM1550 1053l212 -363q18 -37 12.5 -76t-27.5 -74q-13 -20 -33 -37t-38 -28t-48.5 -22t-47 -16t-51.5 -14t-46 -12q-34 72 -265 436l313 195zM1407 1279l142 83l-220 -373l-419 20l151 86q-34 89 -75 166t-75.5 123.5t-64.5 80t-47 46.5l-17 13l405 -1 q31 3 58 -10.5t39 -28.5l11 -15q39 -61 112 -190z" />
<glyph unicode="&#xf1b9;" horiz-adv-x="2048" d="M480 448q0 66 -47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47t113 47t47 113zM516 768h1016l-89 357q-2 8 -14 17.5t-21 9.5h-768q-9 0 -21 -9.5t-14 -17.5zM1888 448q0 66 -47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47t113 47t47 113zM2048 544v-384 q0 -14 -9 -23t-23 -9h-96v-128q0 -80 -56 -136t-136 -56t-136 56t-56 136v128h-1024v-128q0 -80 -56 -136t-136 -56t-136 56t-56 136v128h-96q-14 0 -23 9t-9 23v384q0 93 65.5 158.5t158.5 65.5h28l105 419q23 94 104 157.5t179 63.5h768q98 0 179 -63.5t104 -157.5 l105 -419h28q93 0 158.5 -65.5t65.5 -158.5z" />
<glyph unicode="&#xf1ba;" horiz-adv-x="2048" d="M1824 640q93 0 158.5 -65.5t65.5 -158.5v-384q0 -14 -9 -23t-23 -9h-96v-64q0 -80 -56 -136t-136 -56t-136 56t-56 136v64h-1024v-64q0 -80 -56 -136t-136 -56t-136 56t-56 136v64h-96q-14 0 -23 9t-9 23v384q0 93 65.5 158.5t158.5 65.5h28l105 419q23 94 104 157.5 t179 63.5h128v224q0 14 9 23t23 9h448q14 0 23 -9t9 -23v-224h128q98 0 179 -63.5t104 -157.5l105 -419h28zM320 160q66 0 113 47t47 113t-47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47zM516 640h1016l-89 357q-2 8 -14 17.5t-21 9.5h-768q-9 0 -21 -9.5t-14 -17.5z M1728 160q66 0 113 47t47 113t-47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47z" />
<glyph unicode="&#xf1bb;" d="M1504 64q0 -26 -19 -45t-45 -19h-462q1 -17 6 -87.5t5 -108.5q0 -25 -18 -42.5t-43 -17.5h-320q-25 0 -43 17.5t-18 42.5q0 38 5 108.5t6 87.5h-462q-26 0 -45 19t-19 45t19 45l402 403h-229q-26 0 -45 19t-19 45t19 45l402 403h-197q-26 0 -45 19t-19 45t19 45l384 384 q19 19 45 19t45 -19l384 -384q19 -19 19 -45t-19 -45t-45 -19h-197l402 -403q19 -19 19 -45t-19 -45t-45 -19h-229l402 -403q19 -19 19 -45z" />
<glyph unicode="&#xf1bc;" d="M1127 326q0 32 -30 51q-193 115 -447 115q-133 0 -287 -34q-42 -9 -42 -52q0 -20 13.5 -34.5t35.5 -14.5q5 0 37 8q132 27 243 27q226 0 397 -103q19 -11 33 -11q19 0 33 13.5t14 34.5zM1223 541q0 40 -35 61q-237 141 -548 141q-153 0 -303 -42q-48 -13 -48 -64 q0 -25 17.5 -42.5t42.5 -17.5q7 0 37 8q122 33 251 33q279 0 488 -124q24 -13 38 -13q25 0 42.5 17.5t17.5 42.5zM1331 789q0 47 -40 70q-126 73 -293 110.5t-343 37.5q-204 0 -364 -47q-23 -7 -38.5 -25.5t-15.5 -48.5q0 -31 20.5 -52t51.5 -21q11 0 40 8q133 37 307 37 q159 0 309.5 -34t253.5 -95q21 -12 40 -12q29 0 50.5 20.5t21.5 51.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="&#xf1bd;" d="M1397 1408q58 0 98.5 -40.5t40.5 -98.5v-1258q0 -58 -40.5 -98.5t-98.5 -40.5h-1258q-58 0 -98.5 40.5t-40.5 98.5v1258q0 58 40.5 98.5t98.5 40.5h1258zM1465 11v1258q0 28 -20 48t-48 20h-1258q-28 0 -48 -20t-20 -48v-1258q0 -28 20 -48t48 -20h1258q28 0 48 20t20 48 zM694 749l188 -387l533 145v-496q0 -7 -5.5 -12.5t-12.5 -5.5h-1258q-7 0 -12.5 5.5t-5.5 12.5v141l711 195l-212 439q4 1 12 2.5t12 1.5q170 32 303.5 21.5t221 -46t143.5 -94.5q27 -28 -25 -42q-64 -16 -256 -62l-97 198q-111 7 -240 -16zM1397 1287q7 0 12.5 -5.5 t5.5 -12.5v-428q-85 30 -188 52q-294 64 -645 12l-18 -3l-65 134h-233l85 -190q-132 -51 -230 -137v560q0 7 5.5 12.5t12.5 5.5h1258zM286 387q-14 -3 -26 4.5t-14 21.5q-24 203 166 305l129 -270z" />
<glyph unicode="&#xf1be;" horiz-adv-x="2304" d="M784 164l16 241l-16 523q-1 10 -7.5 17t-16.5 7q-9 0 -16 -7t-7 -17l-14 -523l14 -241q1 -10 7.5 -16.5t15.5 -6.5q22 0 24 23zM1080 193l11 211l-12 586q0 16 -13 24q-8 5 -16 5t-16 -5q-13 -8 -13 -24l-1 -6l-10 -579q0 -1 11 -236v-1q0 -10 6 -17q9 -11 23 -11 q11 0 20 9q9 7 9 20zM35 533l20 -128l-20 -126q-2 -9 -9 -9t-9 9l-17 126l17 128q2 9 9 9t9 -9zM121 612l26 -207l-26 -203q-2 -9 -10 -9q-9 0 -9 10l-23 202l23 207q0 9 9 9q8 0 10 -9zM401 159zM213 650l25 -245l-25 -237q0 -11 -11 -11q-10 0 -12 11l-21 237l21 245 q2 12 12 12q11 0 11 -12zM307 657l23 -252l-23 -244q-2 -13 -14 -13q-13 0 -13 13l-21 244l21 252q0 13 13 13q12 0 14 -13zM401 639l21 -234l-21 -246q-2 -16 -16 -16q-6 0 -10.5 4.5t-4.5 11.5l-20 246l20 234q0 6 4.5 10.5t10.5 4.5q14 0 16 -15zM784 164zM495 785 l21 -380l-21 -246q0 -7 -5 -12.5t-12 -5.5q-16 0 -18 18l-18 246l18 380q2 18 18 18q7 0 12 -5.5t5 -12.5zM589 871l19 -468l-19 -244q0 -8 -5.5 -13.5t-13.5 -5.5q-18 0 -20 19l-16 244l16 468q2 19 20 19q8 0 13.5 -5.5t5.5 -13.5zM687 911l18 -506l-18 -242 q-2 -21 -22 -21q-19 0 -21 21l-16 242l16 506q0 9 6.5 15.5t14.5 6.5q9 0 15 -6.5t7 -15.5zM1079 169v0v0zM881 915l15 -510l-15 -239q0 -10 -7.5 -17.5t-17.5 -7.5t-17 7t-8 18l-14 239l14 510q0 11 7.5 18t17.5 7t17.5 -7t7.5 -18zM980 896l14 -492l-14 -236q0 -11 -8 -19 t-19 -8t-19 8t-9 19l-12 236l12 492q1 12 9 20t19 8t18.5 -8t8.5 -20zM1192 404l-14 -231v0q0 -13 -9 -22t-22 -9t-22 9t-10 22l-6 114l-6 117l12 636v3q2 15 12 24q9 7 20 7q8 0 15 -5q14 -8 16 -26zM2304 423q0 -117 -83 -199.5t-200 -82.5h-786q-13 2 -22 11t-9 22v899 q0 23 28 33q85 34 181 34q195 0 338 -131.5t160 -323.5q53 22 110 22q117 0 200 -83t83 -201z" />
<glyph unicode="&#xf1c0;" d="M768 768q237 0 443 43t325 127v-170q0 -69 -103 -128t-280 -93.5t-385 -34.5t-385 34.5t-280 93.5t-103 128v170q119 -84 325 -127t443 -43zM768 0q237 0 443 43t325 127v-170q0 -69 -103 -128t-280 -93.5t-385 -34.5t-385 34.5t-280 93.5t-103 128v170q119 -84 325 -127 t443 -43zM768 384q237 0 443 43t325 127v-170q0 -69 -103 -128t-280 -93.5t-385 -34.5t-385 34.5t-280 93.5t-103 128v170q119 -84 325 -127t443 -43zM768 1536q208 0 385 -34.5t280 -93.5t103 -128v-128q0 -69 -103 -128t-280 -93.5t-385 -34.5t-385 34.5t-280 93.5 t-103 128v128q0 69 103 128t280 93.5t385 34.5z" />
<glyph unicode="&#xf1c1;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M894 465q33 -26 84 -56q59 7 117 7q147 0 177 -49q16 -22 2 -52q0 -1 -1 -2l-2 -2v-1q-6 -38 -71 -38q-48 0 -115 20t-130 53q-221 -24 -392 -83q-153 -262 -242 -262q-15 0 -28 7l-24 12q-1 1 -6 5q-10 10 -6 36q9 40 56 91.5t132 96.5q14 9 23 -6q2 -2 2 -4q52 85 107 197 q68 136 104 262q-24 82 -30.5 159.5t6.5 127.5q11 40 42 40h21h1q23 0 35 -15q18 -21 9 -68q-2 -6 -4 -8q1 -3 1 -8v-30q-2 -123 -14 -192q55 -164 146 -238zM318 54q52 24 137 158q-51 -40 -87.5 -84t-49.5 -74zM716 974q-15 -42 -2 -132q1 7 7 44q0 3 7 43q1 4 4 8 q-1 1 -1 2t-0.5 1.5t-0.5 1.5q-1 22 -13 36q0 -1 -1 -2v-2zM592 313q135 54 284 81q-2 1 -13 9.5t-16 13.5q-76 67 -127 176q-27 -86 -83 -197q-30 -56 -45 -83zM1238 329q-24 24 -140 24q76 -28 124 -28q14 0 18 1q0 1 -2 3z" />
<glyph unicode="&#xf1c2;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M233 768v-107h70l164 -661h159l128 485q7 20 10 46q2 16 2 24h4l3 -24q1 -3 3.5 -20t5.5 -26l128 -485h159l164 661h70v107h-300v-107h90l-99 -438q-5 -20 -7 -46l-2 -21h-4l-3 21q-1 5 -4 21t-5 25l-144 545h-114l-144 -545q-2 -9 -4.5 -24.5t-3.5 -21.5l-4 -21h-4l-2 21 q-2 26 -7 46l-99 438h90v107h-300z" />
<glyph unicode="&#xf1c3;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M429 106v-106h281v106h-75l103 161q5 7 10 16.5t7.5 13.5t3.5 4h2q1 -4 5 -10q2 -4 4.5 -7.5t6 -8t6.5 -8.5l107 -161h-76v-106h291v106h-68l-192 273l195 282h67v107h-279v-107h74l-103 -159q-4 -7 -10 -16.5t-9 -13.5l-2 -3h-2q-1 4 -5 10q-6 11 -17 23l-106 159h76v107 h-290v-107h68l189 -272l-194 -283h-68z" />
<glyph unicode="&#xf1c4;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M416 106v-106h327v106h-93v167h137q76 0 118 15q67 23 106.5 87t39.5 146q0 81 -37 141t-100 87q-48 19 -130 19h-368v-107h92v-555h-92zM769 386h-119v268h120q52 0 83 -18q56 -33 56 -115q0 -89 -62 -120q-31 -15 -78 -15z" />
<glyph unicode="&#xf1c5;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M1280 320v-320h-1024v192l192 192l128 -128l384 384zM448 512q-80 0 -136 56t-56 136t56 136t136 56t136 -56t56 -136t-56 -136t-136 -56z" />
<glyph unicode="&#xf1c6;" d="M640 1152v128h-128v-128h128zM768 1024v128h-128v-128h128zM640 896v128h-128v-128h128zM768 768v128h-128v-128h128zM1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400 v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-128v-128h-128v128h-512v-1536h1280zM781 593l107 -349q8 -27 8 -52q0 -83 -72.5 -137.5t-183.5 -54.5t-183.5 54.5t-72.5 137.5q0 25 8 52q21 63 120 396v128h128v-128h79 q22 0 39 -13t23 -34zM640 128q53 0 90.5 19t37.5 45t-37.5 45t-90.5 19t-90.5 -19t-37.5 -45t37.5 -45t90.5 -19z" />
<glyph unicode="&#xf1c7;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M620 686q20 -8 20 -30v-544q0 -22 -20 -30q-8 -2 -12 -2q-12 0 -23 9l-166 167h-131q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h131l166 167q16 15 35 7zM1037 -3q31 0 50 24q129 159 129 363t-129 363q-16 21 -43 24t-47 -14q-21 -17 -23.5 -43.5t14.5 -47.5 q100 -123 100 -282t-100 -282q-17 -21 -14.5 -47.5t23.5 -42.5q18 -15 40 -15zM826 145q27 0 47 20q87 93 87 219t-87 219q-18 19 -45 20t-46 -17t-20 -44.5t18 -46.5q52 -57 52 -131t-52 -131q-19 -20 -18 -46.5t20 -44.5q20 -17 44 -17z" />
<glyph unicode="&#xf1c8;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M768 768q52 0 90 -38t38 -90v-384q0 -52 -38 -90t-90 -38h-384q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h384zM1260 766q20 -8 20 -30v-576q0 -22 -20 -30q-8 -2 -12 -2q-14 0 -23 9l-265 266v90l265 266q9 9 23 9q4 0 12 -2z" />
<glyph unicode="&#xf1c9;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M480 768q8 11 21 12.5t24 -6.5l51 -38q11 -8 12.5 -21t-6.5 -24l-182 -243l182 -243q8 -11 6.5 -24t-12.5 -21l-51 -38q-11 -8 -24 -6.5t-21 12.5l-226 301q-14 19 0 38zM1282 467q14 -19 0 -38l-226 -301q-8 -11 -21 -12.5t-24 6.5l-51 38q-11 8 -12.5 21t6.5 24l182 243 l-182 243q-8 11 -6.5 24t12.5 21l51 38q11 8 24 6.5t21 -12.5zM662 6q-13 2 -20.5 13t-5.5 24l138 831q2 13 13 20.5t24 5.5l63 -10q13 -2 20.5 -13t5.5 -24l-138 -831q-2 -13 -13 -20.5t-24 -5.5z" />
<glyph unicode="&#xf1ca;" d="M1497 709v-198q-101 -23 -198 -23q-65 -136 -165.5 -271t-181.5 -215.5t-128 -106.5q-80 -45 -162 3q-28 17 -60.5 43.5t-85 83.5t-102.5 128.5t-107.5 184t-105.5 244t-91.5 314.5t-70.5 390h283q26 -218 70 -398.5t104.5 -317t121.5 -235.5t140 -195q169 169 287 406 q-142 72 -223 220t-81 333q0 192 104 314.5t284 122.5q178 0 273 -105.5t95 -297.5q0 -159 -58 -286q-7 -1 -19.5 -3t-46 -2t-63 6t-62 25.5t-50.5 51.5q31 103 31 184q0 87 -29 132t-79 45q-53 0 -85 -49.5t-32 -140.5q0 -186 105 -293.5t267 -107.5q62 0 121 14z" />
<glyph unicode="&#xf1cb;" horiz-adv-x="1792" d="M216 367l603 -402v359l-334 223zM154 511l193 129l-193 129v-258zM973 -35l603 402l-269 180l-334 -223v-359zM896 458l272 182l-272 182l-272 -182zM485 733l334 223v359l-603 -402zM1445 640l193 -129v258zM1307 733l269 180l-603 402v-359zM1792 913v-546 q0 -41 -34 -64l-819 -546q-21 -13 -43 -13t-43 13l-819 546q-34 23 -34 64v546q0 41 34 64l819 546q21 13 43 13t43 -13l819 -546q34 -23 34 -64z" />
<glyph unicode="&#xf1cc;" horiz-adv-x="2048" d="M1800 764q111 -46 179.5 -145.5t68.5 -221.5q0 -164 -118 -280.5t-285 -116.5q-4 0 -11.5 0.5t-10.5 0.5h-1209h-1h-2h-5q-170 10 -288 125.5t-118 280.5q0 110 55 203t147 147q-12 39 -12 82q0 115 82 196t199 81q95 0 172 -58q75 154 222.5 248t326.5 94 q166 0 306 -80.5t221.5 -218.5t81.5 -301q0 -6 -0.5 -18t-0.5 -18zM468 498q0 -122 84 -193t208 -71q137 0 240 99q-16 20 -47.5 56.5t-43.5 50.5q-67 -65 -144 -65q-55 0 -93.5 33.5t-38.5 87.5q0 53 38.5 87t91.5 34q44 0 84.5 -21t73 -55t65 -75t69 -82t77 -75t97 -55 t121.5 -21q121 0 204.5 71.5t83.5 190.5q0 121 -84 192t-207 71q-143 0 -241 -97q14 -16 29.5 -34t34.5 -40t29 -34q66 64 142 64q52 0 92 -33t40 -84q0 -57 -37 -91.5t-94 -34.5q-43 0 -82.5 21t-72 55t-65.5 75t-69.5 82t-77.5 75t-96.5 55t-118.5 21q-122 0 -207 -70.5 t-85 -189.5z" />
<glyph unicode="&#xf1cd;" horiz-adv-x="1792" d="M896 1536q182 0 348 -71t286 -191t191 -286t71 -348t-71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71zM896 1408q-190 0 -361 -90l194 -194q82 28 167 28t167 -28l194 194q-171 90 -361 90zM218 279l194 194 q-28 82 -28 167t28 167l-194 194q-90 -171 -90 -361t90 -361zM896 -128q190 0 361 90l-194 194q-82 -28 -167 -28t-167 28l-194 -194q171 -90 361 -90zM896 256q159 0 271.5 112.5t112.5 271.5t-112.5 271.5t-271.5 112.5t-271.5 -112.5t-112.5 -271.5t112.5 -271.5 t271.5 -112.5zM1380 473l194 -194q90 171 90 361t-90 361l-194 -194q28 -82 28 -167t-28 -167z" />
<glyph unicode="&#xf1ce;" horiz-adv-x="1792" d="M1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348q0 222 101 414.5t276.5 317t390.5 155.5v-260q-221 -45 -366.5 -221t-145.5 -406q0 -130 51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5 q0 230 -145.5 406t-366.5 221v260q215 -31 390.5 -155.5t276.5 -317t101 -414.5z" />
<glyph unicode="&#xf1d0;" horiz-adv-x="1792" d="M19 662q8 217 116 406t305 318h5q0 -1 -1 -3q-8 -8 -28 -33.5t-52 -76.5t-60 -110.5t-44.5 -135.5t-14 -150.5t39 -157.5t108.5 -154q50 -50 102 -69.5t90.5 -11.5t69.5 23.5t47 32.5l16 16q39 51 53 116.5t6.5 122.5t-21 107t-26.5 80l-14 29q-10 25 -30.5 49.5t-43 41 t-43.5 29.5t-35 19l-13 6l104 115q39 -17 78 -52t59 -61l19 -27q1 48 -18.5 103.5t-40.5 87.5l-20 31l161 183l160 -181q-33 -46 -52.5 -102.5t-22.5 -90.5l-4 -33q22 37 61.5 72.5t67.5 52.5l28 17l103 -115q-44 -14 -85 -50t-60 -65l-19 -29q-31 -56 -48 -133.5t-7 -170 t57 -156.5q33 -45 77.5 -60.5t85 -5.5t76 26.5t57.5 33.5l21 16q60 53 96.5 115t48.5 121.5t10 121.5t-18 118t-37 107.5t-45.5 93t-45 72t-34.5 47.5l-13 17q-14 13 -7 13l10 -3q40 -29 62.5 -46t62 -50t64 -58t58.5 -65t55.5 -77t45.5 -88t38 -103t23.5 -117t10.5 -136 q3 -259 -108 -465t-312 -321t-456 -115q-185 0 -351 74t-283.5 198t-184 293t-60.5 353z" />
<glyph unicode="&#xf1d1;" horiz-adv-x="1792" d="M874 -102v-66q-208 6 -385 109.5t-283 275.5l58 34q29 -49 73 -99l65 57q148 -168 368 -212l-17 -86q65 -12 121 -13zM276 428l-83 -28q22 -60 49 -112l-57 -33q-98 180 -98 385t98 385l57 -33q-30 -56 -49 -112l82 -28q-35 -100 -35 -212q0 -109 36 -212zM1528 251 l58 -34q-106 -172 -283 -275.5t-385 -109.5v66q56 1 121 13l-17 86q220 44 368 212l65 -57q44 50 73 99zM1377 805l-233 -80q14 -42 14 -85t-14 -85l232 -80q-31 -92 -98 -169l-185 162q-57 -67 -147 -85l48 -241q-52 -10 -98 -10t-98 10l48 241q-90 18 -147 85l-185 -162 q-67 77 -98 169l232 80q-14 42 -14 85t14 85l-233 80q33 93 99 169l185 -162q59 68 147 86l-48 240q44 10 98 10t98 -10l-48 -240q88 -18 147 -86l185 162q66 -76 99 -169zM874 1448v-66q-65 -2 -121 -13l17 -86q-220 -42 -368 -211l-65 56q-38 -42 -73 -98l-57 33 q106 172 282 275.5t385 109.5zM1705 640q0 -205 -98 -385l-57 33q27 52 49 112l-83 28q36 103 36 212q0 112 -35 212l82 28q-19 56 -49 112l57 33q98 -180 98 -385zM1585 1063l-57 -33q-35 56 -73 98l-65 -56q-148 169 -368 211l17 86q-56 11 -121 13v66q209 -6 385 -109.5 t282 -275.5zM1748 640q0 173 -67.5 331t-181.5 272t-272 181.5t-331 67.5t-331 -67.5t-272 -181.5t-181.5 -272t-67.5 -331t67.5 -331t181.5 -272t272 -181.5t331 -67.5t331 67.5t272 181.5t181.5 272t67.5 331zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71 t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" />
<glyph unicode="&#xf1d2;" d="M582 228q0 -66 -93 -66q-107 0 -107 63q0 64 98 64q102 0 102 -61zM546 694q0 -85 -74 -85q-77 0 -77 84q0 90 77 90q36 0 55 -25.5t19 -63.5zM712 769v125q-78 -29 -135 -29q-50 29 -110 29q-86 0 -145 -57t-59 -143q0 -50 29.5 -102t73.5 -67v-3q-38 -17 -38 -85 q0 -53 41 -77v-3q-113 -37 -113 -139q0 -45 20 -78.5t54 -51t72 -25.5t81 -8q224 0 224 188q0 67 -48 99t-126 46q-27 5 -51.5 20.5t-24.5 39.5q0 44 49 52q77 15 122 70t45 134q0 24 -10 52q37 9 49 13zM771 350h137q-2 27 -2 82v387q0 46 2 69h-137q3 -23 3 -71v-392 q0 -50 -3 -75zM1280 366v121q-30 -21 -68 -21q-53 0 -53 82v225h52q9 0 26.5 -1t26.5 -1v117h-105q0 82 3 102h-140q4 -24 4 -55v-47h-60v-117q36 3 37 3q3 0 11 -0.5t12 -0.5v-2h-2v-217q0 -37 2.5 -64t11.5 -56.5t24.5 -48.5t43.5 -31t66 -12q64 0 108 24zM924 1072 q0 36 -24 63.5t-60 27.5t-60.5 -27t-24.5 -64q0 -36 25 -62.5t60 -26.5t59.5 27t24.5 62zM1536 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="&#xf1d3;" horiz-adv-x="1792" d="M595 22q0 100 -165 100q-158 0 -158 -104q0 -101 172 -101q151 0 151 105zM536 777q0 61 -30 102t-89 41q-124 0 -124 -145q0 -135 124 -135q119 0 119 137zM805 1101v-202q-36 -12 -79 -22q16 -43 16 -84q0 -127 -73 -216.5t-197 -112.5q-40 -8 -59.5 -27t-19.5 -58 q0 -31 22.5 -51.5t58 -32t78.5 -22t86 -25.5t78.5 -37.5t58 -64t22.5 -98.5q0 -304 -363 -304q-69 0 -130 12.5t-116 41t-87.5 82t-32.5 127.5q0 165 182 225v4q-67 41 -67 126q0 109 63 137v4q-72 24 -119.5 108.5t-47.5 165.5q0 139 95 231.5t235 92.5q96 0 178 -47 q98 0 218 47zM1123 220h-222q4 45 4 134v609q0 94 -4 128h222q-4 -33 -4 -124v-613q0 -89 4 -134zM1724 442v-196q-71 -39 -174 -39q-62 0 -107 20t-70 50t-39.5 78t-18.5 92t-4 103v351h2v4q-7 0 -19 1t-18 1q-21 0 -59 -6v190h96v76q0 54 -6 89h227q-6 -41 -6 -165h171 v-190q-15 0 -43.5 2t-42.5 2h-85v-365q0 -131 87 -131q61 0 109 33zM1148 1389q0 -58 -39 -101.5t-96 -43.5q-58 0 -98 43.5t-40 101.5q0 59 39.5 103t98.5 44q58 0 96.5 -44.5t38.5 -102.5z" />
<glyph unicode="&#xf1d4;" d="M825 547l343 588h-150q-21 -39 -63.5 -118.5t-68 -128.5t-59.5 -118.5t-60 -128.5h-3q-21 48 -44.5 97t-52 105.5t-46.5 92t-54 104.5t-49 95h-150l323 -589v-435h134v436zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960 q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
<glyph unicode="&#xf1d5;" horiz-adv-x="1280" d="M842 964q0 -80 -57 -136.5t-136 -56.5q-60 0 -111 35q-62 -67 -115 -146q-247 -371 -202 -859q1 -22 -12.5 -38.5t-34.5 -18.5h-5q-20 0 -35 13.5t-17 33.5q-14 126 -3.5 247.5t29.5 217t54 186t69 155.5t74 125q61 90 132 165q-16 35 -16 77q0 80 56.5 136.5t136.5 56.5 t136.5 -56.5t56.5 -136.5zM1223 953q0 -158 -78 -292t-212.5 -212t-292.5 -78q-64 0 -131 14q-21 5 -32.5 23.5t-6.5 39.5q5 20 23 31.5t39 7.5q51 -13 108 -13q97 0 186 38t153 102t102 153t38 186t-38 186t-102 153t-153 102t-186 38t-186 -38t-153 -102t-102 -153 t-38 -186q0 -114 52 -218q10 -20 3.5 -40t-25.5 -30t-39.5 -3t-30.5 26q-64 123 -64 265q0 119 46.5 227t124.5 186t186 124t226 46q158 0 292.5 -78t212.5 -212.5t78 -292.5z" />
<glyph unicode="&#xf1d6;" horiz-adv-x="1792" d="M270 730q-8 19 -8 52q0 20 11 49t24 45q-1 22 7.5 53t22.5 43q0 139 92.5 288.5t217.5 209.5q139 66 324 66q133 0 266 -55q49 -21 90 -48t71 -56t55 -68t42 -74t32.5 -84.5t25.5 -89.5t22 -98l1 -5q55 -83 55 -150q0 -14 -9 -40t-9 -38q0 -1 1.5 -3.5t3.5 -5t2 -3.5 q77 -114 120.5 -214.5t43.5 -208.5q0 -43 -19.5 -100t-55.5 -57q-9 0 -19.5 7.5t-19 17.5t-19 26t-16 26.5t-13.5 26t-9 17.5q-1 1 -3 1l-5 -4q-59 -154 -132 -223q20 -20 61.5 -38.5t69 -41.5t35.5 -65q-2 -4 -4 -16t-7 -18q-64 -97 -302 -97q-53 0 -110.5 9t-98 20 t-104.5 30q-15 5 -23 7q-14 4 -46 4.5t-40 1.5q-41 -45 -127.5 -65t-168.5 -20q-35 0 -69 1.5t-93 9t-101 20.5t-74.5 40t-32.5 64q0 40 10 59.5t41 48.5q11 2 40.5 13t49.5 12q4 0 14 2q2 2 2 4l-2 3q-48 11 -108 105.5t-73 156.5l-5 3q-4 0 -12 -20q-18 -41 -54.5 -74.5 t-77.5 -37.5h-1q-4 0 -6 4.5t-5 5.5q-23 54 -23 100q0 275 252 466z" />
<glyph unicode="&#xf1d7;" horiz-adv-x="2048" d="M580 1075q0 41 -25 66t-66 25q-43 0 -76 -25.5t-33 -65.5q0 -39 33 -64.5t76 -25.5q41 0 66 24.5t25 65.5zM1323 568q0 28 -25.5 50t-65.5 22q-27 0 -49.5 -22.5t-22.5 -49.5q0 -28 22.5 -50.5t49.5 -22.5q40 0 65.5 22t25.5 51zM1087 1075q0 41 -24.5 66t-65.5 25 q-43 0 -76 -25.5t-33 -65.5q0 -39 33 -64.5t76 -25.5q41 0 65.5 24.5t24.5 65.5zM1722 568q0 28 -26 50t-65 22q-27 0 -49.5 -22.5t-22.5 -49.5q0 -28 22.5 -50.5t49.5 -22.5q39 0 65 22t26 51zM1456 965q-31 4 -70 4q-169 0 -311 -77t-223.5 -208.5t-81.5 -287.5 q0 -78 23 -152q-35 -3 -68 -3q-26 0 -50 1.5t-55 6.5t-44.5 7t-54.5 10.5t-50 10.5l-253 -127l72 218q-290 203 -290 490q0 169 97.5 311t264 223.5t363.5 81.5q176 0 332.5 -66t262 -182.5t136.5 -260.5zM2048 404q0 -117 -68.5 -223.5t-185.5 -193.5l55 -181l-199 109 q-150 -37 -218 -37q-169 0 -311 70.5t-223.5 191.5t-81.5 264t81.5 264t223.5 191.5t311 70.5q161 0 303 -70.5t227.5 -192t85.5 -263.5z" />
<glyph unicode="&#xf1d8;" horiz-adv-x="1792" d="M1764 1525q33 -24 27 -64l-256 -1536q-5 -29 -32 -45q-14 -8 -31 -8q-11 0 -24 5l-453 185l-242 -295q-18 -23 -49 -23q-13 0 -22 4q-19 7 -30.5 23.5t-11.5 36.5v349l864 1059l-1069 -925l-395 162q-37 14 -40 55q-2 40 32 59l1664 960q15 9 32 9q20 0 36 -11z" />
<glyph unicode="&#xf1d9;" horiz-adv-x="1792" d="M1764 1525q33 -24 27 -64l-256 -1536q-5 -29 -32 -45q-14 -8 -31 -8q-11 0 -24 5l-527 215l-298 -327q-18 -21 -47 -21q-14 0 -23 4q-19 7 -30 23.5t-11 36.5v452l-472 193q-37 14 -40 55q-3 39 32 59l1664 960q35 21 68 -2zM1422 26l221 1323l-1434 -827l336 -137 l863 639l-478 -797z" />
<glyph unicode="&#xf1da;" 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 -298zM896 928v-448q0 -14 -9 -23 t-23 -9h-320q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h224v352q0 14 9 23t23 9h64q14 0 23 -9t9 -23z" />
<glyph unicode="&#xf1db;" d="M768 1280q-130 0 -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.5t-51 248.5t-136.5 204t-204 136.5t-248.5 51zM1536 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="&#xf1dc;" horiz-adv-x="1792" d="M1682 -128q-44 0 -132.5 3.5t-133.5 3.5q-44 0 -132 -3.5t-132 -3.5q-24 0 -37 20.5t-13 45.5q0 31 17 46t39 17t51 7t45 15q33 21 33 140l-1 391q0 21 -1 31q-13 4 -50 4h-675q-38 0 -51 -4q-1 -10 -1 -31l-1 -371q0 -142 37 -164q16 -10 48 -13t57 -3.5t45 -15 t20 -45.5q0 -26 -12.5 -48t-36.5 -22q-47 0 -139.5 3.5t-138.5 3.5q-43 0 -128 -3.5t-127 -3.5q-23 0 -35.5 21t-12.5 45q0 30 15.5 45t36 17.5t47.5 7.5t42 15q33 23 33 143l-1 57v813q0 3 0.5 26t0 36.5t-1.5 38.5t-3.5 42t-6.5 36.5t-11 31.5t-16 18q-15 10 -45 12t-53 2 t-41 14t-18 45q0 26 12 48t36 22q46 0 138.5 -3.5t138.5 -3.5q42 0 126.5 3.5t126.5 3.5q25 0 37.5 -22t12.5 -48q0 -30 -17 -43.5t-38.5 -14.5t-49.5 -4t-43 -13q-35 -21 -35 -160l1 -320q0 -21 1 -32q13 -3 39 -3h699q25 0 38 3q1 11 1 32l1 320q0 139 -35 160 q-18 11 -58.5 12.5t-66 13t-25.5 49.5q0 26 12.5 48t37.5 22q44 0 132 -3.5t132 -3.5q43 0 129 3.5t129 3.5q25 0 37.5 -22t12.5 -48q0 -30 -17.5 -44t-40 -14.5t-51.5 -3t-44 -12.5q-35 -23 -35 -161l1 -943q0 -119 34 -140q16 -10 46 -13.5t53.5 -4.5t41.5 -15.5t18 -44.5 q0 -26 -12 -48t-36 -22z" />
<glyph unicode="&#xf1dd;" horiz-adv-x="1280" d="M1278 1347v-73q0 -29 -18.5 -61t-42.5 -32q-50 0 -54 -1q-26 -6 -32 -31q-3 -11 -3 -64v-1152q0 -25 -18 -43t-43 -18h-108q-25 0 -43 18t-18 43v1218h-143v-1218q0 -25 -17.5 -43t-43.5 -18h-108q-26 0 -43.5 18t-17.5 43v496q-147 12 -245 59q-126 58 -192 179 q-64 117 -64 259q0 166 88 286q88 118 209 159q111 37 417 37h479q25 0 43 -18t18 -43z" />
<glyph unicode="&#xf1de;" d="M352 128v-128h-352v128h352zM704 256q26 0 45 -19t19 -45v-256q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h256zM864 640v-128h-864v128h864zM224 1152v-128h-224v128h224zM1536 128v-128h-736v128h736zM576 1280q26 0 45 -19t19 -45v-256 q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h256zM1216 768q26 0 45 -19t19 -45v-256q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h256zM1536 640v-128h-224v128h224zM1536 1152v-128h-864v128h864z" />
<glyph unicode="&#xf1e0;" d="M1216 512q133 0 226.5 -93.5t93.5 -226.5t-93.5 -226.5t-226.5 -93.5t-226.5 93.5t-93.5 226.5q0 12 2 34l-360 180q-92 -86 -218 -86q-133 0 -226.5 93.5t-93.5 226.5t93.5 226.5t226.5 93.5q126 0 218 -86l360 180q-2 22 -2 34q0 133 93.5 226.5t226.5 93.5 t226.5 -93.5t93.5 -226.5t-93.5 -226.5t-226.5 -93.5q-126 0 -218 86l-360 -180q2 -22 2 -34t-2 -34l360 -180q92 86 218 86z" />
<glyph unicode="&#xf1e1;" d="M1280 341q0 88 -62.5 151t-150.5 63q-84 0 -145 -58l-241 120q2 16 2 23t-2 23l241 120q61 -58 145 -58q88 0 150.5 63t62.5 151t-62.5 150.5t-150.5 62.5t-151 -62.5t-63 -150.5q0 -7 2 -23l-241 -120q-62 57 -145 57q-88 0 -150.5 -62.5t-62.5 -150.5t62.5 -150.5 t150.5 -62.5q83 0 145 57l241 -120q-2 -16 -2 -23q0 -88 63 -150.5t151 -62.5t150.5 62.5t62.5 150.5zM1536 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="&#xf1e2;" horiz-adv-x="1792" d="M571 947q-10 25 -34 35t-49 0q-108 -44 -191 -127t-127 -191q-10 -25 0 -49t35 -34q13 -5 24 -5q42 0 60 40q34 84 98.5 148.5t148.5 98.5q25 11 35 35t0 49zM1513 1303l46 -46l-244 -243l68 -68q19 -19 19 -45.5t-19 -45.5l-64 -64q89 -161 89 -343q0 -143 -55.5 -273.5 t-150 -225t-225 -150t-273.5 -55.5t-273.5 55.5t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5q182 0 343 -89l64 64q19 19 45.5 19t45.5 -19l68 -68zM1521 1359q-10 -10 -22 -10q-13 0 -23 10l-91 90q-9 10 -9 23t9 23q10 9 23 9t23 -9l90 -91 q10 -9 10 -22.5t-10 -22.5zM1751 1129q-11 -9 -23 -9t-23 9l-90 91q-10 9 -10 22.5t10 22.5q9 10 22.5 10t22.5 -10l91 -90q9 -10 9 -23t-9 -23zM1792 1312q0 -14 -9 -23t-23 -9h-96q-14 0 -23 9t-9 23t9 23t23 9h96q14 0 23 -9t9 -23zM1600 1504v-96q0 -14 -9 -23t-23 -9 t-23 9t-9 23v96q0 14 9 23t23 9t23 -9t9 -23zM1751 1449l-91 -90q-10 -10 -22 -10q-13 0 -23 10q-10 9 -10 22.5t10 22.5l90 91q10 9 23 9t23 -9q9 -10 9 -23t-9 -23z" />
<glyph unicode="&#xf1e3;" horiz-adv-x="1792" d="M609 720l287 208l287 -208l-109 -336h-355zM896 1536q182 0 348 -71t286 -191t191 -286t71 -348t-71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71zM1515 186q149 203 149 454v3l-102 -89l-240 224l63 323 l134 -12q-150 206 -389 282l53 -124l-287 -159l-287 159l53 124q-239 -76 -389 -282l135 12l62 -323l-240 -224l-102 89v-3q0 -251 149 -454l30 132l326 -40l139 -298l-116 -69q117 -39 240 -39t240 39l-116 69l139 298l326 40z" />
<glyph unicode="&#xf1e4;" horiz-adv-x="1792" d="M448 224v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM256 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM832 224v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23 v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM640 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM66 768q-28 0 -47 19t-19 46v129h514v-129q0 -27 -19 -46t-46 -19h-383zM1216 224v-192q0 -14 -9 -23t-23 -9h-192 q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1024 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1600 224v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23 zM1408 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1792 1016v-13h-514v10q0 104 -382 102q-382 -1 -382 -102v-10h-514v13q0 17 8.5 43t34 64t65.5 75.5t110.5 76t160 67.5t224 47.5t293.5 18.5t293 -18.5t224 -47.5 t160.5 -67.5t110.5 -76t65.5 -75.5t34 -64t8.5 -43zM1792 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1792 962v-129q0 -27 -19 -46t-46 -19h-384q-27 0 -46 19t-19 46v129h514z" />
<glyph unicode="&#xf1e5;" horiz-adv-x="1792" d="M704 1216v-768q0 -26 -19 -45t-45 -19v-576q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v512l249 873q7 23 31 23h424zM1024 1216v-704h-256v704h256zM1792 320v-512q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v576q-26 0 -45 19t-19 45v768h424q24 0 31 -23z M736 1504v-224h-352v224q0 14 9 23t23 9h288q14 0 23 -9t9 -23zM1408 1504v-224h-352v224q0 14 9 23t23 9h288q14 0 23 -9t9 -23z" />
<glyph unicode="&#xf1e6;" horiz-adv-x="1792" d="M1755 1083q37 -37 37 -90t-37 -91l-401 -400l150 -150l-160 -160q-163 -163 -389.5 -186.5t-411.5 100.5l-362 -362h-181v181l362 362q-124 185 -100.5 411.5t186.5 389.5l160 160l150 -150l400 401q38 37 91 37t90 -37t37 -90.5t-37 -90.5l-400 -401l234 -234l401 400 q38 37 91 37t90 -37z" />
<glyph unicode="&#xf1e7;" horiz-adv-x="1792" d="M873 796q0 -83 -63.5 -142.5t-152.5 -59.5t-152.5 59.5t-63.5 142.5q0 84 63.5 143t152.5 59t152.5 -59t63.5 -143zM1375 796q0 -83 -63 -142.5t-153 -59.5q-89 0 -152.5 59.5t-63.5 142.5q0 84 63.5 143t152.5 59q90 0 153 -59t63 -143zM1600 616v667q0 87 -32 123.5 t-111 36.5h-1112q-83 0 -112.5 -34t-29.5 -126v-673q43 -23 88.5 -40t81 -28t81 -18.5t71 -11t70 -4t58.5 -0.5t56.5 2t44.5 2q68 1 95 -27q6 -6 10 -9q26 -25 61 -51q7 91 118 87q5 0 36.5 -1.5t43 -2t45.5 -1t53 1t54.5 4.5t61 8.5t62 13.5t67 19.5t67.5 27t72 34.5z M1763 621q-121 -149 -372 -252q84 -285 -23 -465q-66 -113 -183 -148q-104 -32 -182 15q-86 51 -82 164l-1 326v1q-8 2 -24.5 6t-23.5 5l-1 -338q4 -114 -83 -164q-79 -47 -183 -15q-117 36 -182 150q-105 180 -22 463q-251 103 -372 252q-25 37 -4 63t60 -1q3 -2 11 -7 t11 -8v694q0 72 47 123t114 51h1257q67 0 114 -51t47 -123v-694l21 15q39 27 60 1t-4 -63z" />
<glyph unicode="&#xf1e8;" horiz-adv-x="1792" d="M896 1102v-434h-145v434h145zM1294 1102v-434h-145v434h145zM1294 342l253 254v795h-1194v-1049h326v-217l217 217h398zM1692 1536v-1013l-434 -434h-326l-217 -217h-217v217h-398v1158l109 289h1483z" />
<glyph unicode="&#xf1e9;" d="M773 217v-127q-1 -292 -6 -305q-12 -32 -51 -40q-54 -9 -181.5 38t-162.5 89q-13 15 -17 36q-1 12 4 26q4 10 34 47t181 216q1 0 60 70q15 19 39.5 24.5t49.5 -3.5q24 -10 37.5 -29t12.5 -42zM624 468q-3 -55 -52 -70l-120 -39q-275 -88 -292 -88q-35 2 -54 36 q-12 25 -17 75q-8 76 1 166.5t30 124.5t56 32q13 0 202 -77q70 -29 115 -47l84 -34q23 -9 35.5 -30.5t11.5 -48.5zM1450 171q-7 -54 -91.5 -161t-135.5 -127q-37 -14 -63 7q-14 10 -184 287l-47 77q-14 21 -11.5 46t19.5 46q35 43 83 26q1 -1 119 -40q203 -66 242 -79.5 t47 -20.5q28 -22 22 -61zM778 803q5 -102 -54 -122q-58 -17 -114 71l-378 598q-8 35 19 62q41 43 207.5 89.5t224.5 31.5q40 -10 49 -45q3 -18 22 -305.5t24 -379.5zM1440 695q3 -39 -26 -59q-15 -10 -329 -86q-67 -15 -91 -23l1 2q-23 -6 -46 4t-37 32q-30 47 0 87 q1 1 75 102q125 171 150 204t34 39q28 19 65 2q48 -23 123 -133.5t81 -167.5v-3z" />
<glyph unicode="&#xf1ea;" horiz-adv-x="2048" d="M1024 1024h-384v-384h384v384zM1152 384v-128h-640v128h640zM1152 1152v-640h-640v640h640zM1792 384v-128h-512v128h512zM1792 640v-128h-512v128h512zM1792 896v-128h-512v128h512zM1792 1152v-128h-512v128h512zM256 192v960h-128v-960q0 -26 19 -45t45 -19t45 19 t19 45zM1920 192v1088h-1536v-1088q0 -33 -11 -64h1483q26 0 45 19t19 45zM2048 1408v-1216q0 -80 -56 -136t-136 -56h-1664q-80 0 -136 56t-56 136v1088h256v128h1792z" />
<glyph unicode="&#xf1eb;" horiz-adv-x="2048" d="M1024 13q-20 0 -93 73.5t-73 93.5q0 32 62.5 54t103.5 22t103.5 -22t62.5 -54q0 -20 -73 -93.5t-93 -73.5zM1294 284q-2 0 -40 25t-101.5 50t-128.5 25t-128.5 -25t-101 -50t-40.5 -25q-18 0 -93.5 75t-75.5 93q0 13 10 23q78 77 196 121t233 44t233 -44t196 -121 q10 -10 10 -23q0 -18 -75.5 -93t-93.5 -75zM1567 556q-11 0 -23 8q-136 105 -252 154.5t-268 49.5q-85 0 -170.5 -22t-149 -53t-113.5 -62t-79 -53t-31 -22q-17 0 -92 75t-75 93q0 12 10 22q132 132 320 205t380 73t380 -73t320 -205q10 -10 10 -22q0 -18 -75 -93t-92 -75z M1838 827q-11 0 -22 9q-179 157 -371.5 236.5t-420.5 79.5t-420.5 -79.5t-371.5 -236.5q-11 -9 -22 -9q-17 0 -92.5 75t-75.5 93q0 13 10 23q187 186 445 288t527 102t527 -102t445 -288q10 -10 10 -23q0 -18 -75.5 -93t-92.5 -75z" />
<glyph unicode="&#xf1ec;" horiz-adv-x="1792" d="M384 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.5zM768 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.5zM384 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.5zM1152 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.5zM768 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.5 t37.5 90.5zM384 768q0 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 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.5zM768 768q0 53 -37.5 90.5t-90.5 37.5 t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1536 0v384q0 52 -38 90t-90 38t-90 -38t-38 -90v-384q0 -52 38 -90t90 -38t90 38t38 90zM1152 768q0 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.5z M1536 1088v256q0 26 -19 45t-45 19h-1280q-26 0 -45 -19t-19 -45v-256q0 -26 19 -45t45 -19h1280q26 0 45 19t19 45zM1536 768q0 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 1408v-1536q0 -52 -38 -90t-90 -38 h-1408q-52 0 -90 38t-38 90v1536q0 52 38 90t90 38h1408q52 0 90 -38t38 -90z" />
<glyph unicode="&#xf1ed;" horiz-adv-x="1792" d="M1112 1090q0 159 -237 159h-70q-32 0 -59.5 -21.5t-34.5 -52.5l-63 -276q-2 -5 -2 -16q0 -24 17 -39.5t41 -15.5h53q69 0 128.5 13t112.5 41t83.5 81.5t30.5 126.5zM1716 938q0 -265 -220 -428q-219 -161 -612 -161h-61q-32 0 -59 -21.5t-34 -52.5l-73 -316 q-8 -36 -40.5 -61.5t-69.5 -25.5h-213q-31 0 -53 20t-22 51q0 10 13 65h151q34 0 64 23.5t38 56.5l73 316q8 33 37.5 57t63.5 24h61q390 0 607 160t217 421q0 129 -51 207q183 -92 183 -335zM1533 1123q0 -264 -221 -428q-218 -161 -612 -161h-60q-32 0 -59.5 -22t-34.5 -53 l-73 -315q-8 -36 -40 -61.5t-69 -25.5h-214q-31 0 -52.5 19.5t-21.5 51.5q0 8 2 20l300 1301q8 36 40.5 61.5t69.5 25.5h444q68 0 125 -4t120.5 -15t113.5 -30t96.5 -50.5t77.5 -74t49.5 -103.5t18.5 -136z" />
<glyph unicode="&#xf1ee;" horiz-adv-x="1792" d="M602 949q19 -61 31 -123.5t17 -141.5t-14 -159t-62 -145q-21 81 -67 157t-95.5 127t-99 90.5t-78.5 57.5t-33 19q-62 34 -81.5 100t14.5 128t101 81.5t129 -14.5q138 -83 238 -177zM927 1236q11 -25 20.5 -46t36.5 -100.5t42.5 -150.5t25.5 -179.5t0 -205.5t-47.5 -209.5 t-105.5 -208.5q-51 -72 -138 -72q-54 0 -98 31q-57 40 -69 109t28 127q60 85 81 195t13 199.5t-32 180.5t-39 128t-22 52q-31 63 -8.5 129.5t85.5 97.5q34 17 75 17q47 0 88.5 -25t63.5 -69zM1248 567q-17 -160 -72 -311q-17 131 -63 246q25 174 -5 361q-27 178 -94 342 q114 -90 212 -211q9 -37 15 -80q26 -179 7 -347zM1520 1440q9 -17 23.5 -49.5t43.5 -117.5t50.5 -178t34 -227.5t5 -269t-47 -300t-112.5 -323.5q-22 -48 -66 -75.5t-95 -27.5q-39 0 -74 16q-67 31 -92.5 100t4.5 136q58 126 90 257.5t37.5 239.5t-3.5 213.5t-26.5 180.5 t-38.5 138.5t-32.5 90t-15.5 32.5q-34 65 -11.5 135.5t87.5 104.5q37 20 81 20q49 0 91.5 -25.5t66.5 -70.5z" />
<glyph unicode="&#xf1f0;" horiz-adv-x="2304" d="M1975 546h-138q14 37 66 179l3 9q4 10 10 26t9 26l12 -55zM531 611l-58 295q-11 54 -75 54h-268l-2 -13q311 -79 403 -336zM710 960l-162 -438l-17 89q-26 70 -85 129.5t-131 88.5l135 -510h175l261 641h-176zM849 318h166l104 642h-166zM1617 944q-69 27 -149 27 q-123 0 -201 -59t-79 -153q-1 -102 145 -174q48 -23 67 -41t19 -39q0 -30 -30 -46t-69 -16q-86 0 -156 33l-22 11l-23 -144q74 -34 185 -34q130 -1 208.5 59t80.5 160q0 106 -140 174q-49 25 -71 42t-22 38q0 22 24.5 38.5t70.5 16.5q70 1 124 -24l15 -8zM2042 960h-128 q-65 0 -87 -54l-246 -588h174l35 96h212q5 -22 20 -96h154zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" />
<glyph unicode="&#xf1f1;" horiz-adv-x="2304" d="M671 603h-13q-47 0 -47 -32q0 -22 20 -22q17 0 28 15t12 39zM1066 639h62v3q1 4 0.5 6.5t-1 7t-2 8t-4.5 6.5t-7.5 5t-11.5 2q-28 0 -36 -38zM1606 603h-12q-48 0 -48 -32q0 -22 20 -22q17 0 28 15t12 39zM1925 629q0 41 -30 41q-19 0 -31 -20t-12 -51q0 -42 28 -42 q20 0 32.5 20t12.5 52zM480 770h87l-44 -262h-56l32 201l-71 -201h-39l-4 200l-34 -200h-53l44 262h81l2 -163zM733 663q0 -6 -4 -42q-16 -101 -17 -113h-47l1 22q-20 -26 -58 -26q-23 0 -37.5 16t-14.5 42q0 39 26 60.5t73 21.5q14 0 23 -1q0 3 0.5 5.5t1 4.5t0.5 3 q0 20 -36 20q-29 0 -59 -10q0 4 7 48q38 11 67 11q74 0 74 -62zM889 721l-8 -49q-22 3 -41 3q-27 0 -27 -17q0 -8 4.5 -12t21.5 -11q40 -19 40 -60q0 -72 -87 -71q-34 0 -58 6q0 2 7 49q29 -8 51 -8q32 0 32 19q0 7 -4.5 11.5t-21.5 12.5q-43 20 -43 59q0 72 84 72 q30 0 50 -4zM977 721h28l-7 -52h-29q-2 -17 -6.5 -40.5t-7 -38.5t-2.5 -18q0 -16 19 -16q8 0 16 2l-8 -47q-21 -7 -40 -7q-43 0 -45 47q0 12 8 56q3 20 25 146h55zM1180 648q0 -23 -7 -52h-111q-3 -22 10 -33t38 -11q30 0 58 14l-9 -54q-30 -8 -57 -8q-95 0 -95 95 q0 55 27.5 90.5t69.5 35.5q35 0 55.5 -21t20.5 -56zM1319 722q-13 -23 -22 -62q-22 2 -31 -24t-25 -128h-56l3 14q22 130 29 199h51l-3 -33q14 21 25.5 29.5t28.5 4.5zM1506 763l-9 -57q-28 14 -50 14q-31 0 -51 -27.5t-20 -70.5q0 -30 13.5 -47t38.5 -17q21 0 48 13 l-10 -59q-28 -8 -50 -8q-45 0 -71.5 30.5t-26.5 82.5q0 70 35.5 114.5t91.5 44.5q26 0 61 -13zM1668 663q0 -18 -4 -42q-13 -79 -17 -113h-46l1 22q-20 -26 -59 -26q-23 0 -37 16t-14 42q0 39 25.5 60.5t72.5 21.5q15 0 23 -1q2 7 2 13q0 20 -36 20q-29 0 -59 -10q0 4 8 48 q38 11 67 11q73 0 73 -62zM1809 722q-14 -24 -21 -62q-23 2 -31.5 -23t-25.5 -129h-56l3 14q19 104 29 199h52q0 -11 -4 -33q15 21 26.5 29.5t27.5 4.5zM1950 770h56l-43 -262h-53l3 19q-23 -23 -52 -23q-31 0 -49.5 24t-18.5 64q0 53 27.5 92t64.5 39q31 0 53 -29z M2061 640q0 148 -72.5 273t-198 198t-273.5 73q-181 0 -328 -110q127 -116 171 -284h-50q-44 150 -158 253q-114 -103 -158 -253h-50q44 168 171 284q-147 110 -328 110q-148 0 -273.5 -73t-198 -198t-72.5 -273t72.5 -273t198 -198t273.5 -73q181 0 328 110 q-120 111 -165 264h50q46 -138 152 -233q106 95 152 233h50q-45 -153 -165 -264q147 -110 328 -110q148 0 273.5 73t198 198t72.5 273zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" />
<glyph unicode="&#xf1f2;" horiz-adv-x="2304" d="M313 759q0 -51 -36 -84q-29 -26 -89 -26h-17v220h17q61 0 89 -27q36 -31 36 -83zM2089 824q0 -52 -64 -52h-19v101h20q63 0 63 -49zM380 759q0 74 -50 120.5t-129 46.5h-95v-333h95q74 0 119 38q60 51 60 128zM410 593h65v333h-65v-333zM730 694q0 40 -20.5 62t-75.5 42 q-29 10 -39.5 19t-10.5 23q0 16 13.5 26.5t34.5 10.5q29 0 53 -27l34 44q-41 37 -98 37q-44 0 -74 -27.5t-30 -67.5q0 -35 18 -55.5t64 -36.5q37 -13 45 -19q19 -12 19 -34q0 -20 -14 -33.5t-36 -13.5q-48 0 -71 44l-42 -40q44 -64 115 -64q51 0 83 30.5t32 79.5zM1008 604 v77q-37 -37 -78 -37q-49 0 -80.5 32.5t-31.5 82.5q0 48 31.5 81.5t77.5 33.5q43 0 81 -38v77q-40 20 -80 20q-74 0 -125.5 -50.5t-51.5 -123.5t51 -123.5t125 -50.5q42 0 81 19zM2240 0v527q-65 -40 -144.5 -84t-237.5 -117t-329.5 -137.5t-417.5 -134.5t-504 -118h1569 q26 0 45 19t19 45zM1389 757q0 75 -53 128t-128 53t-128 -53t-53 -128t53 -128t128 -53t128 53t53 128zM1541 584l144 342h-71l-90 -224l-89 224h-71l142 -342h35zM1714 593h184v56h-119v90h115v56h-115v74h119v57h-184v-333zM2105 593h80l-105 140q76 16 76 94q0 47 -31 73 t-87 26h-97v-333h65v133h9zM2304 1274v-1268q0 -56 -38.5 -95t-93.5 -39h-2040q-55 0 -93.5 39t-38.5 95v1268q0 56 38.5 95t93.5 39h2040q55 0 93.5 -39t38.5 -95z" />
<glyph unicode="&#xf1f3;" horiz-adv-x="2304" d="M119 854h89l-45 108zM740 328l74 79l-70 79h-163v-49h142v-55h-142v-54h159zM898 406l99 -110v217zM1186 453q0 33 -40 33h-84v-69h83q41 0 41 36zM1475 457q0 29 -42 29h-82v-61h81q43 0 43 32zM1197 923q0 29 -42 29h-82v-60h81q43 0 43 31zM1656 854h89l-44 108z M699 1009v-271h-66v212l-94 -212h-57l-94 212v-212h-132l-25 60h-135l-25 -60h-70l116 271h96l110 -257v257h106l85 -184l77 184h108zM1255 453q0 -20 -5.5 -35t-14 -25t-22.5 -16.5t-26 -10t-31.5 -4.5t-31.5 -1t-32.5 0.5t-29.5 0.5v-91h-126l-80 90l-83 -90h-256v271h260 l80 -89l82 89h207q109 0 109 -89zM964 794v-56h-217v271h217v-57h-152v-49h148v-55h-148v-54h152zM2304 235v-229q0 -55 -38.5 -94.5t-93.5 -39.5h-2040q-55 0 -93.5 39.5t-38.5 94.5v678h111l25 61h55l25 -61h218v46l19 -46h113l20 47v-47h541v99l10 1q10 0 10 -14v-86h279 v23q23 -12 55 -18t52.5 -6.5t63 0.5t51.5 1l25 61h56l25 -61h227v58l34 -58h182v378h-180v-44l-25 44h-185v-44l-23 44h-249q-69 0 -109 -22v22h-172v-22q-24 22 -73 22h-628l-43 -97l-43 97h-198v-44l-22 44h-169l-78 -179v391q0 55 38.5 94.5t93.5 39.5h2040 q55 0 93.5 -39.5t38.5 -94.5v-678h-120q-51 0 -81 -22v22h-177q-55 0 -78 -22v22h-316v-22q-31 22 -87 22h-209v-22q-23 22 -91 22h-234l-54 -58l-50 58h-349v-378h343l55 59l52 -59h211v89h21q59 0 90 13v-102h174v99h8q8 0 10 -2t2 -10v-87h529q57 0 88 24v-24h168 q60 0 95 17zM1546 469q0 -23 -12 -43t-34 -29q25 -9 34 -26t9 -46v-54h-65v45q0 33 -12 43.5t-46 10.5h-69v-99h-65v271h154q48 0 77 -15t29 -58zM1269 936q0 -24 -12.5 -44t-33.5 -29q26 -9 34.5 -25.5t8.5 -46.5v-53h-65q0 9 0.5 26.5t0 25t-3 18.5t-8.5 16t-17.5 8.5 t-29.5 3.5h-70v-98h-64v271l153 -1q49 0 78 -14.5t29 -57.5zM1798 327v-56h-216v271h216v-56h-151v-49h148v-55h-148v-54zM1372 1009v-271h-66v271h66zM2065 357q0 -86 -102 -86h-126v58h126q34 0 34 25q0 16 -17 21t-41.5 5t-49.5 3.5t-42 22.5t-17 55q0 39 26 60t66 21 h130v-57h-119q-36 0 -36 -25q0 -16 17.5 -20.5t42 -4t49 -2.5t42 -21.5t17.5 -54.5zM2304 407v-101q-24 -35 -88 -35h-125v58h125q33 0 33 25q0 13 -12.5 19t-31 5.5t-40 2t-40 8t-31 24t-12.5 48.5q0 39 26.5 60t66.5 21h129v-57h-118q-36 0 -36 -25q0 -20 29 -22t68.5 -5 t56.5 -26zM2139 1008v-270h-92l-122 203v-203h-132l-26 60h-134l-25 -60h-75q-129 0 -129 133q0 138 133 138h63v-59q-7 0 -28 1t-28.5 0.5t-23 -2t-21.5 -6.5t-14.5 -13.5t-11.5 -23t-3 -33.5q0 -38 13.5 -58t49.5 -20h29l92 213h97l109 -256v256h99l114 -188v188h66z" />
<glyph unicode="&#xf1f4;" horiz-adv-x="2304" d="M322 689h-15q-19 0 -19 18q0 28 19 85q5 15 15 19.5t28 4.5q77 0 77 -49q0 -41 -30.5 -59.5t-74.5 -18.5zM664 528q-47 0 -47 29q0 62 123 62l3 -3q-5 -88 -79 -88zM1438 687h-15q-19 0 -19 19q0 28 19 85q5 15 14.5 19t28.5 4q77 0 77 -49q0 -41 -30.5 -59.5 t-74.5 -18.5zM1780 527q-47 0 -47 30q0 62 123 62l3 -3q-5 -89 -79 -89zM373 894h-128q-8 0 -14.5 -4t-8.5 -7.5t-7 -12.5q-3 -7 -45 -190t-42 -192q0 -7 5.5 -12.5t13.5 -5.5h62q25 0 32.5 34.5l15 69t32.5 34.5q47 0 87.5 7.5t80.5 24.5t63.5 52.5t23.5 84.5 q0 36 -14.5 61t-41 36.5t-53.5 15.5t-62 4zM719 798q-38 0 -74 -6q-2 0 -8.5 -1t-9 -1.5l-7.5 -1.5t-7.5 -2t-6.5 -3t-6.5 -4t-5 -5t-4.5 -7t-4 -9q-9 -29 -9 -39t9 -10q5 0 21.5 5t19.5 6q30 8 58 8q74 0 74 -36q0 -11 -10 -14q-8 -2 -18 -3t-21.5 -1.5t-17.5 -1.5 q-38 -4 -64.5 -10t-56.5 -19.5t-45.5 -39t-15.5 -62.5q0 -38 26 -59.5t64 -21.5q24 0 45.5 6.5t33 13t38.5 23.5q-3 -7 -3 -15t5.5 -13.5t12.5 -5.5h56q1 1 7 3.5t7.5 3.5t5 3.5t5 5.5t2.5 8l45 194q4 13 4 30q0 81 -145 81zM1247 793h-74q-22 0 -39 -23q-5 -7 -29.5 -51 t-46.5 -81.5t-26 -38.5l-5 4q0 77 -27 166q-1 5 -3.5 8.5t-6 6.5t-6.5 5t-8.5 3t-8.5 1.5t-9.5 1t-9 0.5h-10h-8.5q-38 0 -38 -21l1 -5q5 -53 25 -151t25 -143q2 -16 2 -24q0 -19 -30.5 -61.5t-30.5 -58.5q0 -13 40 -13q61 0 76 25l245 415q10 20 10 26q0 9 -8 9zM1489 892 h-129q-18 0 -29 -23q-6 -13 -46.5 -191.5t-40.5 -190.5q0 -20 43 -20h7.5h9h9t9.5 1t8.5 2t8.5 3t6.5 4.5t5.5 6t3 8.5l21 91q2 10 10.5 17t19.5 7q47 0 87.5 7t80.5 24.5t63.5 52.5t23.5 84q0 36 -14.5 61t-41 36.5t-53.5 15.5t-62 4zM1835 798q-26 0 -74 -6 q-38 -6 -48 -16q-7 -8 -11 -19q-8 -24 -8 -39q0 -10 8 -10q1 0 41 12q30 8 58 8q74 0 74 -36q0 -12 -10 -14q-4 -1 -57 -7q-38 -4 -64.5 -10t-56.5 -19.5t-45.5 -39t-15.5 -62.5t26 -58.5t64 -21.5q24 0 45 6t34 13t38 24q-3 -15 -3 -16q0 -5 2 -8.5t6.5 -5.5t8 -3.5 t10.5 -2t9.5 -0.5h9.5h8q42 0 48 25l45 194q3 15 3 31q0 81 -145 81zM2157 889h-55q-25 0 -33 -40q-10 -44 -36.5 -167t-42.5 -190v-5q0 -16 16 -18h1h57q10 0 18.5 6.5t10.5 16.5l83 374h-1l1 5q0 7 -5.5 12.5t-13.5 5.5zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048 q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" />
<glyph unicode="&#xf1f5;" horiz-adv-x="2304" d="M1597 633q0 -69 -21 -106q-19 -35 -52 -35q-23 0 -41 9v224q29 30 57 30q57 0 57 -122zM2035 669h-110q6 98 56 98q51 0 54 -98zM476 534q0 59 -33 91.5t-101 57.5q-36 13 -52 24t-16 25q0 26 38 26q58 0 124 -33l18 112q-67 32 -149 32q-77 0 -123 -38q-48 -39 -48 -109 q0 -58 32.5 -90.5t99.5 -56.5q39 -14 54.5 -25.5t15.5 -27.5q0 -31 -48 -31q-29 0 -70 12.5t-72 30.5l-18 -113q72 -41 168 -41q81 0 129 37q51 41 51 117zM771 749l19 111h-96v135l-129 -21l-18 -114l-46 -8l-17 -103h62v-219q0 -84 44 -120q38 -30 111 -30q32 0 79 11v118 q-32 -7 -44 -7q-42 0 -42 50v197h77zM1087 724v139q-15 3 -28 3q-32 0 -55.5 -16t-33.5 -46l-10 56h-131v-471h150v306q26 31 82 31q16 0 26 -2zM1124 389h150v471h-150v-471zM1746 638q0 122 -45 179q-40 52 -111 52q-64 0 -117 -56l-8 47h-132v-645l150 25v151 q36 -11 68 -11q83 0 134 56q61 65 61 202zM1278 986q0 33 -23 56t-56 23t-56 -23t-23 -56t23 -56.5t56 -23.5t56 23.5t23 56.5zM2176 629q0 113 -48 176q-50 64 -144 64q-96 0 -151.5 -66t-55.5 -180q0 -128 63 -188q55 -55 161 -55q101 0 160 40l-16 103q-57 -31 -128 -31 q-43 0 -63 19q-23 19 -28 66h248q2 14 2 52zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" />
<glyph unicode="&#xf1f6;" horiz-adv-x="2048" d="M1558 684q61 -356 298 -556q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-180.5 74.5t-75.5 180.5zM1024 -176q16 0 16 16t-16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5zM2026 1424q8 -10 7.5 -23.5t-10.5 -22.5 l-1872 -1622q-10 -8 -23.5 -7t-21.5 11l-84 96q-8 10 -7.5 23.5t10.5 21.5l186 161q-19 32 -19 66q50 42 91 88t85 119.5t74.5 158.5t50 206t19.5 260q0 152 117 282.5t307 158.5q-8 19 -8 39q0 40 28 68t68 28t68 -28t28 -68q0 -20 -8 -39q124 -18 219 -82.5t148 -157.5 l418 363q10 8 23.5 7t21.5 -11z" />
<glyph unicode="&#xf1f7;" horiz-adv-x="2048" d="M1040 -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 16zM503 315l877 760q-42 88 -132.5 146.5t-223.5 58.5q-93 0 -169.5 -31.5t-121.5 -80.5t-69 -103t-24 -105q0 -384 -137 -645zM1856 128 q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-180.5 74.5t-75.5 180.5l149 129h757q-166 187 -227 459l111 97q61 -356 298 -556zM1942 1520l84 -96q8 -10 7.5 -23.5t-10.5 -22.5l-1872 -1622q-10 -8 -23.5 -7t-21.5 11l-84 96q-8 10 -7.5 23.5t10.5 21.5l186 161 q-19 32 -19 66q50 42 91 88t85 119.5t74.5 158.5t50 206t19.5 260q0 152 117 282.5t307 158.5q-8 19 -8 39q0 40 28 68t68 28t68 -28t28 -68q0 -20 -8 -39q124 -18 219 -82.5t148 -157.5l418 363q10 8 23.5 7t21.5 -11z" />
<glyph unicode="&#xf1f8;" horiz-adv-x="1408" d="M512 160v704q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-704q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM768 160v704q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-704q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1024 160v704q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-704 q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM480 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-832q-66 0 -113 58.5t-47 141.5v952h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h309l70 167 q15 37 54 63t79 26h320q40 0 79 -26t54 -63l70 -167h309q14 0 23 -9t9 -23z" />
<glyph unicode="&#xf1f9;" d="M1150 462v-109q0 -50 -36.5 -89t-94 -60.5t-118 -32.5t-117.5 -11q-205 0 -342.5 139t-137.5 346q0 203 136 339t339 136q34 0 75.5 -4.5t93 -18t92.5 -34t69 -56.5t28 -81v-109q0 -16 -16 -16h-118q-16 0 -16 16v70q0 43 -65.5 67.5t-137.5 24.5q-140 0 -228.5 -91.5 t-88.5 -237.5q0 -151 91.5 -249.5t233.5 -98.5q68 0 138 24t70 66v70q0 7 4.5 11.5t10.5 4.5h119q6 0 11 -4.5t5 -11.5zM768 1280q-130 0 -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.5 t-51 248.5t-136.5 204t-204 136.5t-248.5 51zM1536 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="&#xf1fa;" d="M972 761q0 108 -53.5 169t-147.5 61q-63 0 -124 -30.5t-110 -84.5t-79.5 -137t-30.5 -180q0 -112 53.5 -173t150.5 -61q96 0 176 66.5t122.5 166t42.5 203.5zM1536 640q0 -111 -37 -197t-98.5 -135t-131.5 -74.5t-145 -27.5q-6 0 -15.5 -0.5t-16.5 -0.5q-95 0 -142 53 q-28 33 -33 83q-52 -66 -131.5 -110t-173.5 -44q-161 0 -249.5 95.5t-88.5 269.5q0 157 66 290t179 210.5t246 77.5q87 0 155 -35.5t106 -99.5l2 19l11 56q1 6 5.5 12t9.5 6h118q5 0 13 -11q5 -5 3 -16l-120 -614q-5 -24 -5 -48q0 -39 12.5 -52t44.5 -13q28 1 57 5.5t73 24 t77 50t57 89.5t24 137q0 292 -174 466t-466 174q-130 0 -248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51q228 0 405 144q11 9 24 8t21 -12l41 -49q8 -12 7 -24q-2 -13 -12 -22q-102 -83 -227.5 -128t-258.5 -45q-156 0 -298 61 t-245 164t-164 245t-61 298t61 298t164 245t245 164t298 61q344 0 556 -212t212 -556z" />
<glyph unicode="&#xf1fb;" horiz-adv-x="1792" d="M1698 1442q94 -94 94 -226.5t-94 -225.5l-225 -223l104 -104q10 -10 10 -23t-10 -23l-210 -210q-10 -10 -23 -10t-23 10l-105 105l-603 -603q-37 -37 -90 -37h-203l-256 -128l-64 64l128 256v203q0 53 37 90l603 603l-105 105q-10 10 -10 23t10 23l210 210q10 10 23 10 t23 -10l104 -104l223 225q93 94 225.5 94t226.5 -94zM512 64l576 576l-192 192l-576 -576v-192h192z" />
<glyph unicode="&#xf1fc;" horiz-adv-x="1792" d="M1615 1536q70 0 122.5 -46.5t52.5 -116.5q0 -63 -45 -151q-332 -629 -465 -752q-97 -91 -218 -91q-126 0 -216.5 92.5t-90.5 219.5q0 128 92 212l638 579q59 54 130 54zM706 502q39 -76 106.5 -130t150.5 -76l1 -71q4 -213 -129.5 -347t-348.5 -134q-123 0 -218 46.5 t-152.5 127.5t-86.5 183t-29 220q7 -5 41 -30t62 -44.5t59 -36.5t46 -17q41 0 55 37q25 66 57.5 112.5t69.5 76t88 47.5t103 25.5t125 10.5z" />
<glyph unicode="&#xf1fd;" horiz-adv-x="1792" d="M1792 128v-384h-1792v384q45 0 85 14t59 27.5t47 37.5q30 27 51.5 38t56.5 11t55.5 -11t52.5 -38q29 -25 47 -38t58 -27t86 -14q45 0 85 14.5t58 27t48 37.5q21 19 32.5 27t31 15t43.5 7q35 0 56.5 -11t51.5 -38q28 -24 47 -37.5t59 -27.5t85 -14t85 14t59 27.5t47 37.5 q30 27 51.5 38t56.5 11q34 0 55.5 -11t51.5 -38q28 -24 47 -37.5t59 -27.5t85 -14zM1792 448v-192q-35 0 -55.5 11t-52.5 38q-29 25 -47 38t-58 27t-85 14q-46 0 -86 -14t-58 -27t-47 -38q-22 -19 -33 -27t-31 -15t-44 -7q-35 0 -56.5 11t-51.5 38q-29 25 -47 38t-58 27 t-86 14q-45 0 -85 -14.5t-58 -27t-48 -37.5q-21 -19 -32.5 -27t-31 -15t-43.5 -7q-35 0 -56.5 11t-51.5 38q-28 24 -47 37.5t-59 27.5t-85 14q-46 0 -86 -14t-58 -27t-47 -38q-30 -27 -51.5 -38t-56.5 -11v192q0 80 56 136t136 56h64v448h256v-448h256v448h256v-448h256v448 h256v-448h64q80 0 136 -56t56 -136zM512 1312q0 -77 -36 -118.5t-92 -41.5q-53 0 -90.5 37.5t-37.5 90.5q0 29 9.5 51t23.5 34t31 28t31 31.5t23.5 44.5t9.5 67q38 0 83 -74t45 -150zM1024 1312q0 -77 -36 -118.5t-92 -41.5q-53 0 -90.5 37.5t-37.5 90.5q0 29 9.5 51 t23.5 34t31 28t31 31.5t23.5 44.5t9.5 67q38 0 83 -74t45 -150zM1536 1312q0 -77 -36 -118.5t-92 -41.5q-53 0 -90.5 37.5t-37.5 90.5q0 29 9.5 51t23.5 34t31 28t31 31.5t23.5 44.5t9.5 67q38 0 83 -74t45 -150z" />
<glyph unicode="&#xf1fe;" horiz-adv-x="2048" d="M2048 0v-128h-2048v1536h128v-1408h1920zM1664 1024l256 -896h-1664v576l448 576l576 -576z" />
<glyph unicode="&#xf200;" horiz-adv-x="1792" d="M768 646l546 -546q-106 -108 -247.5 -168t-298.5 -60q-209 0 -385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103v-762zM955 640h773q0 -157 -60 -298.5t-168 -247.5zM1664 768h-768v768q209 0 385.5 -103t279.5 -279.5t103 -385.5z" />
<glyph unicode="&#xf201;" horiz-adv-x="2048" d="M2048 0v-128h-2048v1536h128v-1408h1920zM1920 1248v-435q0 -21 -19.5 -29.5t-35.5 7.5l-121 121l-633 -633q-10 -10 -23 -10t-23 10l-233 233l-416 -416l-192 192l585 585q10 10 23 10t23 -10l233 -233l464 464l-121 121q-16 16 -7.5 35.5t29.5 19.5h435q14 0 23 -9 t9 -23z" />
<glyph unicode="&#xf202;" horiz-adv-x="1792" d="M1292 832q0 -6 10 -41q10 -29 25 -49.5t41 -34t44 -20t55 -16.5q325 -91 325 -332q0 -146 -105.5 -242.5t-254.5 -96.5q-59 0 -111.5 18.5t-91.5 45.5t-77 74.5t-63 87.5t-53.5 103.5t-43.5 103t-39.5 106.5t-35.5 95q-32 81 -61.5 133.5t-73.5 96.5t-104 64t-142 20 q-96 0 -183 -55.5t-138 -144.5t-51 -185q0 -160 106.5 -279.5t263.5 -119.5q177 0 258 95q56 63 83 116l84 -152q-15 -34 -44 -70l1 -1q-131 -152 -388 -152q-147 0 -269.5 79t-190.5 207.5t-68 274.5q0 105 43.5 206t116 176.5t172 121.5t204.5 46q87 0 159 -19t123.5 -50 t95 -80t72.5 -99t58.5 -117t50.5 -124.5t50 -130.5t55 -127q96 -200 233 -200q81 0 138.5 48.5t57.5 128.5q0 42 -19 72t-50.5 46t-72.5 31.5t-84.5 27t-87.5 34t-81 52t-65 82t-39 122.5q-3 16 -3 33q0 110 87.5 192t198.5 78q78 -3 120.5 -14.5t90.5 -53.5h-1 q12 -11 23 -24.5t26 -36t19 -27.5l-129 -99q-26 49 -54 70v1q-23 21 -97 21q-49 0 -84 -33t-35 -83z" />
<glyph unicode="&#xf203;" d="M1432 484q0 173 -234 239q-35 10 -53 16.5t-38 25t-29 46.5q0 2 -2 8.5t-3 12t-1 7.5q0 36 24.5 59.5t60.5 23.5q54 0 71 -15h-1q20 -15 39 -51l93 71q-39 54 -49 64q-33 29 -67.5 39t-85.5 10q-80 0 -142 -57.5t-62 -137.5q0 -7 2 -23q16 -96 64.5 -140t148.5 -73 q29 -8 49 -15.5t45 -21.5t38.5 -34.5t13.5 -46.5v-5q1 -58 -40.5 -93t-100.5 -35q-97 0 -167 144q-23 47 -51.5 121.5t-48 125.5t-54 110.5t-74 95.5t-103.5 60.5t-147 24.5q-101 0 -192 -56t-144 -148t-50 -192v-1q4 -108 50.5 -199t133.5 -147.5t196 -56.5q186 0 279 110 q20 27 31 51l-60 109q-42 -80 -99 -116t-146 -36q-115 0 -191 87t-76 204q0 105 82 189t186 84q112 0 170 -53.5t104 -172.5q8 -21 25.5 -68.5t28.5 -76.5t31.5 -74.5t38.5 -74t45.5 -62.5t55.5 -53.5t66 -33t80 -13.5q107 0 183 69.5t76 174.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="&#xf204;" horiz-adv-x="2048" d="M1152 640q0 104 -40.5 198.5t-109.5 163.5t-163.5 109.5t-198.5 40.5t-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.5t198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5zM1920 640q0 104 -40.5 198.5 t-109.5 163.5t-163.5 109.5t-198.5 40.5h-386q119 -90 188.5 -224t69.5 -288t-69.5 -288t-188.5 -224h386q104 0 198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5zM2048 640q0 -130 -51 -248.5t-136.5 -204t-204 -136.5t-248.5 -51h-768q-130 0 -248.5 51t-204 136.5 t-136.5 204t-51 248.5t51 248.5t136.5 204t204 136.5t248.5 51h768q130 0 248.5 -51t204 -136.5t136.5 -204t51 -248.5z" />
<glyph unicode="&#xf205;" horiz-adv-x="2048" d="M0 640q0 130 51 248.5t136.5 204t204 136.5t248.5 51h768q130 0 248.5 -51t204 -136.5t136.5 -204t51 -248.5t-51 -248.5t-136.5 -204t-204 -136.5t-248.5 -51h-768q-130 0 -248.5 51t-204 136.5t-136.5 204t-51 248.5zM1408 128q104 0 198.5 40.5t163.5 109.5 t109.5 163.5t40.5 198.5t-40.5 198.5t-109.5 163.5t-163.5 109.5t-198.5 40.5t-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.5z" />
<glyph unicode="&#xf206;" horiz-adv-x="2304" d="M762 384h-314q-40 0 -57.5 35t6.5 67l188 251q-65 31 -137 31q-132 0 -226 -94t-94 -226t94 -226t226 -94q115 0 203 72.5t111 183.5zM576 512h186q-18 85 -75 148zM1056 512l288 384h-480l-99 -132q105 -103 126 -252h165zM2176 448q0 132 -94 226t-226 94 q-60 0 -121 -24l174 -260q15 -23 10 -49t-27 -40q-15 -11 -36 -11q-35 0 -53 29l-174 260q-93 -95 -93 -225q0 -132 94 -226t226 -94t226 94t94 226zM2304 448q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5q0 97 39.5 183.5t109.5 149.5l-65 98l-353 -469 q-18 -26 -51 -26h-197q-23 -164 -149 -274t-294 -110q-185 0 -316.5 131.5t-131.5 316.5t131.5 316.5t316.5 131.5q114 0 215 -55l137 183h-224q-26 0 -45 19t-19 45t19 45t45 19h384v-128h435l-85 128h-222q-26 0 -45 19t-19 45t19 45t45 19h256q33 0 53 -28l267 -400 q91 44 192 44q185 0 316.5 -131.5t131.5 -316.5z" />
<glyph unicode="&#xf207;" d="M384 320q0 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 320q0 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.5zM1362 716l-72 384q-5 23 -22.5 37.5t-40.5 14.5 h-918q-23 0 -40.5 -14.5t-22.5 -37.5l-72 -384q-5 -30 14 -53t49 -23h1062q30 0 49 23t14 53zM1136 1328q0 20 -14 34t-34 14h-640q-20 0 -34 -14t-14 -34t14 -34t34 -14h640q20 0 34 14t14 34zM1536 603v-603h-128v-128q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5 t-37.5 90.5v128h-768v-128q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5v128h-128v603q0 112 25 223l103 454q9 78 97.5 137t230 89t312.5 30t312.5 -30t230 -89t97.5 -137l105 -454q23 -102 23 -223z" />
<glyph unicode="&#xf208;" horiz-adv-x="2048" d="M1463 704q0 -35 -25 -60.5t-61 -25.5h-702q-36 0 -61 25.5t-25 60.5t25 60.5t61 25.5h702q36 0 61 -25.5t25 -60.5zM1677 704q0 86 -23 170h-982q-36 0 -61 25t-25 60q0 36 25 61t61 25h908q-88 143 -235 227t-320 84q-177 0 -327.5 -87.5t-238 -237.5t-87.5 -327 q0 -86 23 -170h982q36 0 61 -25t25 -60q0 -36 -25 -61t-61 -25h-908q88 -143 235.5 -227t320.5 -84q132 0 253 51.5t208 139t139 208t52 253.5zM2048 959q0 -35 -25 -60t-61 -25h-131q17 -85 17 -170q0 -167 -65.5 -319.5t-175.5 -263t-262.5 -176t-319.5 -65.5 q-246 0 -448.5 133t-301.5 350h-189q-36 0 -61 25t-25 61q0 35 25 60t61 25h132q-17 85 -17 170q0 167 65.5 319.5t175.5 263t262.5 176t320.5 65.5q245 0 447.5 -133t301.5 -350h188q36 0 61 -25t25 -61z" />
<glyph unicode="&#xf209;" horiz-adv-x="1280" d="M953 1158l-114 -328l117 -21q165 451 165 518q0 56 -38 56q-57 0 -130 -225zM654 471l33 -88q37 42 71 67l-33 5.5t-38.5 7t-32.5 8.5zM362 1367q0 -98 159 -521q18 10 49 10q15 0 75 -5l-121 351q-75 220 -123 220q-19 0 -29 -17.5t-10 -37.5zM283 608q0 -36 51.5 -119 t117.5 -153t100 -70q14 0 25.5 13t11.5 27q0 24 -32 102q-13 32 -32 72t-47.5 89t-61.5 81t-62 32q-20 0 -45.5 -27t-25.5 -47zM125 273q0 -41 25 -104q59 -145 183.5 -227t281.5 -82q227 0 382 170q152 169 152 427q0 43 -1 67t-11.5 62t-30.5 56q-56 49 -211.5 75.5 t-270.5 26.5q-37 0 -49 -11q-12 -5 -12 -35q0 -34 21.5 -60t55.5 -40t77.5 -23.5t87.5 -11.5t85 -4t70 0h23q24 0 40 -19q15 -19 19 -55q-28 -28 -96 -54q-61 -22 -93 -46q-64 -46 -108.5 -114t-44.5 -137q0 -31 18.5 -88.5t18.5 -87.5l-3 -12q-4 -12 -4 -14 q-137 10 -146 216q-8 -2 -41 -2q2 -7 2 -21q0 -53 -40.5 -89.5t-94.5 -36.5q-82 0 -166.5 78t-84.5 159q0 34 33 67q52 -64 60 -76q77 -104 133 -104q12 0 26.5 8.5t14.5 20.5q0 34 -87.5 145t-116.5 111q-43 0 -70 -44.5t-27 -90.5zM11 264q0 101 42.5 163t136.5 88 q-28 74 -28 104q0 62 61 123t122 61q29 0 70 -15q-163 462 -163 567q0 80 41 130.5t119 50.5q131 0 325 -581q6 -17 8 -23q6 16 29 79.5t43.5 118.5t54 127.5t64.5 123t70.5 86.5t76.5 36q71 0 112 -49t41 -122q0 -108 -159 -550q61 -15 100.5 -46t58.5 -78t26 -93.5 t7 -110.5q0 -150 -47 -280t-132 -225t-211 -150t-278 -55q-111 0 -223 42q-149 57 -258 191.5t-109 286.5z" />
<glyph unicode="&#xf20a;" horiz-adv-x="2048" d="M785 528h207q-14 -158 -98.5 -248.5t-214.5 -90.5q-162 0 -254.5 116t-92.5 316q0 194 93 311.5t233 117.5q148 0 232 -87t97 -247h-203q-5 64 -35.5 99t-81.5 35q-57 0 -88.5 -60.5t-31.5 -177.5q0 -48 5 -84t18 -69.5t40 -51.5t66 -18q95 0 109 139zM1497 528h206 q-14 -158 -98 -248.5t-214 -90.5q-162 0 -254.5 116t-92.5 316q0 194 93 311.5t233 117.5q148 0 232 -87t97 -247h-204q-4 64 -35 99t-81 35q-57 0 -88.5 -60.5t-31.5 -177.5q0 -48 5 -84t18 -69.5t39.5 -51.5t65.5 -18q49 0 76.5 38t33.5 101zM1856 647q0 207 -15.5 307 t-60.5 161q-6 8 -13.5 14t-21.5 15t-16 11q-86 63 -697 63q-625 0 -710 -63q-5 -4 -17.5 -11.5t-21 -14t-14.5 -14.5q-45 -60 -60 -159.5t-15 -308.5q0 -208 15 -307.5t60 -160.5q6 -8 15 -15t20.5 -14t17.5 -12q44 -33 239.5 -49t470.5 -16q610 0 697 65q5 4 17 11t20.5 14 t13.5 16q46 60 61 159t15 309zM2048 1408v-1536h-2048v1536h2048z" />
<glyph unicode="&#xf20b;" d="M992 912v-496q0 -14 -9 -23t-23 -9h-160q-14 0 -23 9t-9 23v496q0 112 -80 192t-192 80h-272v-1152q0 -14 -9 -23t-23 -9h-160q-14 0 -23 9t-9 23v1344q0 14 9 23t23 9h464q135 0 249 -66.5t180.5 -180.5t66.5 -249zM1376 1376v-880q0 -135 -66.5 -249t-180.5 -180.5 t-249 -66.5h-464q-14 0 -23 9t-9 23v960q0 14 9 23t23 9h160q14 0 23 -9t9 -23v-768h272q112 0 192 80t80 192v880q0 14 9 23t23 9h160q14 0 23 -9t9 -23z" />
<glyph unicode="&#xf20c;" d="M1311 694v-114q0 -24 -13.5 -38t-37.5 -14h-202q-24 0 -38 14t-14 38v114q0 24 14 38t38 14h202q24 0 37.5 -14t13.5 -38zM821 464v250q0 53 -32.5 85.5t-85.5 32.5h-133q-68 0 -96 -52q-28 52 -96 52h-130q-53 0 -85.5 -32.5t-32.5 -85.5v-250q0 -22 21 -22h55 q22 0 22 22v230q0 24 13.5 38t38.5 14h94q24 0 38 -14t14 -38v-230q0 -22 21 -22h54q22 0 22 22v230q0 24 14 38t38 14h97q24 0 37.5 -14t13.5 -38v-230q0 -22 22 -22h55q21 0 21 22zM1410 560v154q0 53 -33 85.5t-86 32.5h-264q-53 0 -86 -32.5t-33 -85.5v-410 q0 -21 22 -21h55q21 0 21 21v180q31 -42 94 -42h191q53 0 86 32.5t33 85.5zM1536 1176v-1072q0 -96 -68 -164t-164 -68h-1072q-96 0 -164 68t-68 164v1072q0 96 68 164t164 68h1072q96 0 164 -68t68 -164z" />
<glyph unicode="&#xf20d;" horiz-adv-x="1792" />
<glyph unicode="&#xf20e;" horiz-adv-x="1792" />
<glyph unicode="&#xf500;" horiz-adv-x="1792" />
</font>
</defs></svg>

After

Width:  |  Height:  |  Size: 280 KiB

Binary file not shown.

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