From 67bbf15ed31e3d4dded763e738598dc6c59be913 Mon Sep 17 00:00:00 2001 From: Vitali Kari Date: Tue, 18 Aug 2015 18:52:57 +0200 Subject: [PATCH 001/598] Update syslog.inc.php --- html/includes/common/syslog.inc.php | 51 ++++++++++++++--------------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/html/includes/common/syslog.inc.php b/html/includes/common/syslog.inc.php index d77936133..e610ebfc7 100644 --- a/html/includes/common/syslog.inc.php +++ b/html/includes/common/syslog.inc.php @@ -1,28 +1,27 @@ -
-
-
-
- Syslog entries -
- '; - -foreach (dbFetchRows($sql) as $entry) { - $entry = array_merge($entry, device_by_id_cache($entry['device_id'])); - include 'includes/print-syslog.inc.php'; -} - -$syslog_output .= ' -
-
-
-
- +$common_output[] = ' + + + + + + + + + +
DatetimeHostnameProgramMessage
+ '; - -$common_output[] = $syslog_output; From 2a08827ebb43176c1bc1cc261c1563800e9634bb Mon Sep 17 00:00:00 2001 From: Vitali Kari Date: Tue, 18 Aug 2015 19:03:59 +0200 Subject: [PATCH 002/598] Update syslog.inc.php --- html/includes/common/syslog.inc.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/html/includes/common/syslog.inc.php b/html/includes/common/syslog.inc.php index e610ebfc7..7d3121e06 100644 --- a/html/includes/common/syslog.inc.php +++ b/html/includes/common/syslog.inc.php @@ -3,10 +3,10 @@ $common_output[] = ' - - + + - +
DatetimeHostnameDatetimeHostname ProgramMessageMessage
From e51576078804fadb1cd2b2ce13ba482048c9a985 Mon Sep 17 00:00:00 2001 From: laf Date: Tue, 18 Aug 2015 18:40:57 +0000 Subject: [PATCH 003/598] Make new dashboard the default --- includes/defaults.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/defaults.inc.php b/includes/defaults.inc.php index 7807ba179..66ca1fcea 100644 --- a/includes/defaults.inc.php +++ b/includes/defaults.inc.php @@ -110,7 +110,7 @@ $config['mono_font'] = 'DejaVuSansMono'; $config['favicon'] = ''; $config['page_refresh'] = '300'; // Refresh the page every xx seconds, 0 to disable -$config['front_page'] = 'pages/front/default.php'; +$config['front_page'] = 'pages/front/tiles.php'; $config['front_page_settings']['top']['ports'] = 10; $config['front_page_settings']['top']['devices'] = 10; $config['front_page_down_box_limit'] = 10; From 24d88ea7a46c78b76c6ed3c4374f29aa45925f78 Mon Sep 17 00:00:00 2001 From: Vitali Kari Date: Wed, 19 Aug 2015 17:04:11 +0200 Subject: [PATCH 004/598] Update syslog.inc.php --- html/includes/common/syslog.inc.php | 87 +++++++++++++++++++++++++++-- 1 file changed, 81 insertions(+), 6 deletions(-) diff --git a/html/includes/common/syslog.inc.php b/html/includes/common/syslog.inc.php index 7d3121e06..4e75fd38c 100644 --- a/html/includes/common/syslog.inc.php +++ b/html/includes/common/syslog.inc.php @@ -1,6 +1,15 @@ +$no_refresh = true; +$param = array(); +if ($vars['action'] == 'expunge' && $_SESSION['userlevel'] >= '10') { + dbQuery('TRUNCATE TABLE `syslog`'); + print_message('syslog truncated'); +} +$pagetitle[] = 'Syslog'; +?> + +
+ @@ -10,18 +19,84 @@ $common_output[] = '
Datetime
+
+ -'; From 178024e61fdeffb11ba9f35593720260132e2598 Mon Sep 17 00:00:00 2001 From: vitalisator Date: Wed, 19 Aug 2015 18:03:43 +0200 Subject: [PATCH 005/598] - --- html/includes/common/syslog.inc.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/html/includes/common/syslog.inc.php b/html/includes/common/syslog.inc.php index 4e75fd38c..bd708c175 100644 --- a/html/includes/common/syslog.inc.php +++ b/html/includes/common/syslog.inc.php @@ -1,10 +1,14 @@ = '10') { dbQuery('TRUNCATE TABLE `syslog`'); print_message('syslog truncated'); } + $pagetitle[] = 'Syslog'; ?> @@ -22,6 +26,7 @@ $pagetitle[] = 'Syslog'; +'; +$common_output[] = $syslog_output; From e2f5a1fdf0ece32422f35251f67b23772659e12f Mon Sep 17 00:00:00 2001 From: Mark Schouten Date: Thu, 20 Aug 2015 12:25:47 +0200 Subject: [PATCH 010/598] Make app-recognition more efficient --- includes/polling/unix-agent.inc.php | 33 ++++++++--------------------- 1 file changed, 9 insertions(+), 24 deletions(-) diff --git a/includes/polling/unix-agent.inc.php b/includes/polling/unix-agent.inc.php index a759313a4..cc0ac1fd2 100644 --- a/includes/polling/unix-agent.inc.php +++ b/includes/polling/unix-agent.inc.php @@ -47,32 +47,17 @@ if ($device['os_group'] == 'unix') { list($section, $data) = explode('>>>', $section); list($sa, $sb) = explode('-', $section, 2); - if ($section == 'apache') { - $sa = 'app'; - $sb = 'apache'; + $agentapps = array( + "apache", + "mysql", + "nginx", + "bind", + "tinydns"); + + if (in_array($section, $agentapps)) { + $agent_data['app'][$section] = trim($data); } - if ($section == 'mysql') { - $sa = 'app'; - $sb = 'mysql'; - } - - if ($section == 'nginx') { - $sa = 'app'; - $sb = 'nginx'; - } - - if ($section == 'bind') { - $sa = 'app'; - $sb = 'bind'; - } - - if ($section == 'tinydns') { - $sa = 'app'; - $sb = 'tinydns'; - } - - // if ($section == "drbd") { $sa = "app"; $sb = "drbd"; } if (!empty($sa) && !empty($sb)) { $agent_data[$sa][$sb] = trim($data); } From 30e47b382c4fc41bc637580b3d747870cffa8471 Mon Sep 17 00:00:00 2001 From: Mark Schouten Date: Thu, 20 Aug 2015 12:36:37 +0200 Subject: [PATCH 011/598] Do not include the applications, but enable them in the database. The application poller will run them. Also, reduce code-duplication. --- includes/polling/unix-agent.inc.php | 37 ++++++++++------------------- 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/includes/polling/unix-agent.inc.php b/includes/polling/unix-agent.inc.php index cc0ac1fd2..c5f5d4bc4 100644 --- a/includes/polling/unix-agent.inc.php +++ b/includes/polling/unix-agent.inc.php @@ -83,16 +83,6 @@ if ($device['os_group'] == 'unix') { } } - foreach (array_keys($agent_data['app']) as $key) { - if (file_exists("includes/polling/applications/$key.inc.php")) { - if ($debug) { - echo "Including: applications/$key.inc.php"; - } - - include "applications/$key.inc.php"; - } - } - // Processes if (!empty($agent_data['ps'])) { echo 'Processes: '; @@ -111,12 +101,18 @@ if ($device['os_group'] == 'unix') { echo "\n"; } - // Apache - if (!empty($agent_data['app']['apache'])) { - $app_found['apache'] = true; - if (dbFetchCell('SELECT COUNT(*) FROM `applications` WHERE `device_id` = ? AND `app_type` = ?', array($device['device_id'], 'apache')) == '0') { - echo "Found new application 'Apache'\n"; - dbInsert(array('device_id' => $device['device_id'], 'app_type' => 'apache'), 'applications'); + foreach (array_keys($agent_data['app']) as $key) { + if (file_exists("includes/polling/applications/$key.inc.php")) { + if ($debug) { + echo "Enabling $key for $device['hostname'] if not yet enabled\n"; + } + + if (in_array($key, array('apache', 'mysql', 'nginx')) { + if (dbFetchCell('SELECT COUNT(*) FROM `applications` WHERE `device_id` = ? AND `app_type` = ?', array($device['device_id'], $key)) == '0') { + echo "Found new application '$key'\n"; + dbInsert(array('device_id' => $device['device_id'], 'app_type' => $key), 'applications'); + } + } } } @@ -131,15 +127,6 @@ if ($device['os_group'] == 'unix') { } } - // MySQL - if (!empty($agent_data['app']['mysql'])) { - $app_found['mysql'] = true; - if (dbFetchCell('SELECT COUNT(*) FROM `applications` WHERE `device_id` = ? AND `app_type` = ?', array($device['device_id'], 'mysql')) == '0') { - echo "Found new application 'MySQL'\n"; - dbInsert(array('device_id' => $device['device_id'], 'app_type' => 'mysql'), 'applications'); - } - } - // DRBD if (!empty($agent_data['drbd'])) { $agent_data['app']['drbd'] = array(); From 47c87cb7c6d82a05a8e2ab684a0850f5a6c99f12 Mon Sep 17 00:00:00 2001 From: Mark Schouten Date: Thu, 20 Aug 2015 13:26:18 +0200 Subject: [PATCH 012/598] Fix typos (Sorry about that) Replace if($debug){..} with d_echo --- includes/polling/unix-agent.inc.php | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/includes/polling/unix-agent.inc.php b/includes/polling/unix-agent.inc.php index c5f5d4bc4..d68daa816 100644 --- a/includes/polling/unix-agent.inc.php +++ b/includes/polling/unix-agent.inc.php @@ -66,18 +66,14 @@ if ($device['os_group'] == 'unix') { } }//end foreach - if ($debug) { - print_r($agent_data); - } + d_echo($agent_data); include 'unix-agent/packages.inc.php'; include 'unix-agent/munin-plugins.inc.php'; foreach (array_keys($agent_data) as $key) { if (file_exists("includes/polling/unix-agent/$key.inc.php")) { - if ($debug) { - echo "Including: unix-agent/$key.inc.php"; - } + d_echo("Including: unix-agent/$key.inc.php"); include "unix-agent/$key.inc.php"; } @@ -103,11 +99,9 @@ if ($device['os_group'] == 'unix') { foreach (array_keys($agent_data['app']) as $key) { if (file_exists("includes/polling/applications/$key.inc.php")) { - if ($debug) { - echo "Enabling $key for $device['hostname'] if not yet enabled\n"; - } + d_echo("Enabling $key for ".$device['hostname']." if not yet enabled\n"); - if (in_array($key, array('apache', 'mysql', 'nginx')) { + if (in_array($key, array('apache', 'mysql', 'nginx'))) { if (dbFetchCell('SELECT COUNT(*) FROM `applications` WHERE `device_id` = ? AND `app_type` = ?', array($device['device_id'], $key)) == '0') { echo "Found new application '$key'\n"; dbInsert(array('device_id' => $device['device_id'], 'app_type' => $key), 'applications'); From f0bb0ecc953f647f37e691a1c8e4827e816e2537 Mon Sep 17 00:00:00 2001 From: laf Date: Thu, 20 Aug 2015 17:06:11 +0000 Subject: [PATCH 013/598] Checks for v3 use lowercase first letter so changed drop down menu to reflext --- html/pages/device/edit/snmp.inc.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/html/pages/device/edit/snmp.inc.php b/html/pages/device/edit/snmp.inc.php index 59c6bf4cd..eeae2c056 100644 --- a/html/pages/device/edit/snmp.inc.php +++ b/html/pages/device/edit/snmp.inc.php @@ -140,9 +140,9 @@ echo "
From 4724c6bc30623751a1a4e9f1b762867e5732a143 Mon Sep 17 00:00:00 2001 From: laf Date: Thu, 20 Aug 2015 17:06:43 +0000 Subject: [PATCH 014/598] Checks for v3 use lowercase first letter so changed drop down menu to reflext --- html/pages/addhost.inc.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/html/pages/addhost.inc.php b/html/pages/addhost.inc.php index 9fed6ba32..27bca2a57 100644 --- a/html/pages/addhost.inc.php +++ b/html/pages/addhost.inc.php @@ -147,9 +147,9 @@ foreach ($config['snmp']['transports'] as $transport) {
From 5e858b63e5464e23872c3a5a1be1863dbd908f80 Mon Sep 17 00:00:00 2001 From: f0o Date: Thu, 20 Aug 2015 19:19:15 +0000 Subject: [PATCH 015/598] Pass snmp-auth parameters enclosed by single-quotes --- includes/snmp.inc.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/includes/snmp.inc.php b/includes/snmp.inc.php index ebf143a13..45fbc702e 100644 --- a/includes/snmp.inc.php +++ b/includes/snmp.inc.php @@ -748,7 +748,7 @@ function snmp_gen_auth(&$device) { $cmd = ''; if ($device['snmpver'] === 'v3') { - $cmd = ' -v3 -n "" -l '.$device['authlevel']; + $cmd = " -v3 -n '' -l '".$device['authlevel']."'"; if ($device['authlevel'] === 'noAuthNoPriv') { // We have to provide a username anyway (see Net-SNMP doc) @@ -756,16 +756,16 @@ function snmp_gen_auth(&$device) { $cmd .= ' -u root'; } else if ($device['authlevel'] === 'authNoPriv') { - $cmd .= ' -a '.$device['authalgo']; - $cmd .= ' -A "'.$device['authpass'].'"'; - $cmd .= ' -u '.$device['authname']; + $cmd .= " -a '".$device['authalgo']."'"; + $cmd .= " -A '".$device['authpass']."'"; + $cmd .= " -u '".$device['authname']."'"; } else if ($device['authlevel'] === 'authPriv') { - $cmd .= ' -a '.$device['authalgo']; - $cmd .= ' -A "'.$device['authpass'].'"'; - $cmd .= ' -u '.$device['authname']; - $cmd .= ' -x '.$device['cryptoalgo']; - $cmd .= ' -X "'.$device['cryptopass'].'"'; + $cmd .= " -a '".$device['authalgo']."'"; + $cmd .= " -A '".$device['authpass']."'"; + $cmd .= " -u '".$device['authname']."'"; + $cmd .= " -x '".$device['cryptoalgo']."'"; + $cmd .= " -X '".$device['cryptopass']."'"; } else { if ($debug) { From 701c7931986b32d7a8fdfa28d1193f49ceb4d5bb Mon Sep 17 00:00:00 2001 From: Wes Mason Date: Fri, 21 Aug 2015 10:42:39 +0100 Subject: [PATCH 016/598] Correct small grammatical typo in README This replaces the sentence fragment "mutual respect the basis of our behaviour towards others.", which doesn't make sense grammatically as a piece of English text, with the more correct "mutual respect is the basis of our behaviour towards others." --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d4e46e41d..ebea5a646 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ We intend LibreNMS to be a viable project and community that: - offers a welcoming, friendly environment for everyone. The [Debian Social Contract][10] will be the basis of our priority system, -and mutual respect the basis of our behaviour towards others. For more +and mutual respect is the basis of our behaviour towards others. For more about the culture we're trying to build, please read the [Freenode philosophy][13], including [guidelines for running an IRC channel][6] and [being a community catalyst][7]. From b79d2906aed8cd183b0c313d659f67aba41b6af9 Mon Sep 17 00:00:00 2001 From: Mark Schouten Date: Fri, 21 Aug 2015 16:02:59 +0200 Subject: [PATCH 017/598] Rewrite sender-ip if ::ffff: is prepended because the syslogserver uses IPv6 --- includes/syslog.php | 1 + 1 file changed, 1 insertion(+) diff --git a/includes/syslog.php b/includes/syslog.php index 4c24270c7..7111a6be6 100644 --- a/includes/syslog.php +++ b/includes/syslog.php @@ -46,6 +46,7 @@ function process_syslog($entry, $update) { } } + $entry['host'] = preg_replace("/^::ffff:/", "", $entry['host']); $entry['device_id'] = get_cache($entry['host'], 'device_id'); if ($entry['device_id']) { $os = get_cache($entry['host'], 'os'); From 55a2e0423d5e5d3eee2fca0a6e00270eb80c1f4f Mon Sep 17 00:00:00 2001 From: Mark Schouten Date: Thu, 20 Aug 2015 15:02:40 +0200 Subject: [PATCH 018/598] Remove all unneeded if($debug)-statements and replace them with d_echo --- includes/polling/applications.inc.php | 4 +-- includes/polling/bgp-peers.inc.php | 27 +++++-------------- includes/polling/cisco-cef.inc.php | 4 +-- includes/polling/cisco-mac-accounting.inc.php | 8 ++---- includes/polling/entity-physical.inc.php | 4 +-- includes/polling/functions.inc.php | 8 ++---- includes/polling/junose-atm-vp.inc.php | 8 ++---- includes/polling/mempools.inc.php | 4 +-- includes/polling/mempools/cemp.inc.php | 4 +-- includes/polling/mempools/cmp.inc.php | 4 +-- includes/polling/mempools/hpGlobal.inc.php | 8 ++---- includes/polling/mempools/hpLocal.inc.php | 8 ++---- includes/polling/mempools/hrstorage.inc.php | 8 ++---- includes/polling/mempools/junos.inc.php | 12 +++------ includes/polling/mempools/vrp.inc.php | 12 +++------ includes/polling/netscaler-vsvr.inc.php | 8 ++---- includes/polling/ospf.inc.php | 4 +-- includes/polling/ports.inc.php | 24 +++++------------ includes/polling/storage.inc.php | 4 +-- includes/polling/storage/hrstorage.inc.php | 4 +-- .../polling/storage/netapp-storage.inc.php | 4 +-- includes/polling/ucd-diskio.inc.php | 8 ++---- includes/polling/unix-agent.inc.php | 2 -- .../polling/unix-agent/munin-plugins.inc.php | 8 ++---- 24 files changed, 47 insertions(+), 142 deletions(-) diff --git a/includes/polling/applications.inc.php b/includes/polling/applications.inc.php index f0291ac67..4258129a6 100644 --- a/includes/polling/applications.inc.php +++ b/includes/polling/applications.inc.php @@ -1,9 +1,7 @@ $b_in:$b_out:$p_in:$p_out "; - } + d_echo("\n".$acc['hostname'].' '.$acc['ifDescr']." $mac -> $b_in:$b_out:$p_in:$p_out "); $rrdfile = $config['rrd_dir'].'/'.$device['hostname'].'/'.safename('cip-'.$acc['ifIndex'].'-'.$acc['mac'].'.rrd'); diff --git a/includes/polling/entity-physical.inc.php b/includes/polling/entity-physical.inc.php index c12f2d9cb..06eb5f65a 100644 --- a/includes/polling/entity-physical.inc.php +++ b/includes/polling/entity-physical.inc.php @@ -32,9 +32,7 @@ if ($device['os'] == 'ios') { $rrd = $config['rrd_dir'].'/'.$device['hostname'].'/'.safename('c6kxbar-'.$index.'-'.$subindex.'.rrd'); - if ($debug) { - echo "$rrd "; - } + d_echo("$rrd "); if (!is_file($rrd)) { rrdtool_create( diff --git a/includes/polling/functions.inc.php b/includes/polling/functions.inc.php index d148fa021..27bf8053f 100644 --- a/includes/polling/functions.inc.php +++ b/includes/polling/functions.inc.php @@ -23,9 +23,7 @@ function poll_sensor($device, $class, $unit) { else { // Try 5 times to get a valid temp reading for ($i = 0; $i < 5; $i++) { - if ($debug) { - echo "Attempt $i "; - } + d_echo("Attempt $i "); $sensor_value = trim(str_replace('"', '', snmp_get($device, $sensor['sensor_oid'], '-OUqnv', "SNMPv2-MIB$mib"))); preg_match('/[\d\.]+/', $sensor_value, $temp_response); @@ -280,9 +278,7 @@ function poll_device($device, $options) { // echo("$device_end - $device_start; $device_time $device_run"); echo "Polled in $device_time seconds\n"; - if ($debug) { - echo 'Updating '.$device['hostname'].' - '.print_r($update_array)." \n"; - } + d_echo('Updating '.$device['hostname'].' - '.print_r($update_array)." \n"); $updated = dbUpdate($update_array, 'devices', '`device_id` = ?', array($device['device_id'])); if ($updated) { diff --git a/includes/polling/junose-atm-vp.inc.php b/includes/polling/junose-atm-vp.inc.php index 3ee6d2a7b..6d7dba82c 100644 --- a/includes/polling/junose-atm-vp.inc.php +++ b/includes/polling/junose-atm-vp.inc.php @@ -20,9 +20,7 @@ if (count($vp_rows)) { $oid = $vp['ifIndex'].'.'.$vp['vp_id']; - if ($debug) { - echo "$oid "; - } + d_echo("$oid "); $t_vp = $vp_cache[$oid]; @@ -33,9 +31,7 @@ if (count($vp_rows)) { $rrd = $config['rrd_dir'].'/'.$device['hostname'].'/'.safename('vp-'.$vp['ifIndex'].'-'.$vp['vp_id'].'.rrd'); - if ($debug) { - echo "$rrd "; - } + d_echo("$rrd "); if (!is_file($rrd)) { rrdtool_create( diff --git a/includes/polling/mempools.inc.php b/includes/polling/mempools.inc.php index 4e4b6ce7a..99f055c5b 100644 --- a/includes/polling/mempools.inc.php +++ b/includes/polling/mempools.inc.php @@ -44,9 +44,7 @@ foreach (dbFetchRows('SELECT * FROM mempools WHERE device_id = ?', array($device } if ($config['memcached']['enable'] === true) { - if ($debug) { - print_r($mempool['state']); - } + d_echo($mempool['state']); $memcache->set('mempool-'.$mempool['mempool_id'].'-value', $mempool['state']); } diff --git a/includes/polling/mempools/cemp.inc.php b/includes/polling/mempools/cemp.inc.php index 1cc757d37..748c226cb 100644 --- a/includes/polling/mempools/cemp.inc.php +++ b/includes/polling/mempools/cemp.inc.php @@ -7,9 +7,7 @@ $pool_cmd = $config['snmpget'].' -M '.$config['mibdir'].' -m CISCO-ENHANCED-MEM $pool_cmd .= " cempMemPoolUsed.$oid cempMemPoolFree.$oid cempMemPoolLargestFree.$oid"; $pool_cmd .= " | cut -f 1 -d ' '"; -if ($debug) { - echo "SNMP [ $pool_cmd ]\n"; -} +d_echo("SNMP [ $pool_cmd ]\n"); $pool = shell_exec($pool_cmd); diff --git a/includes/polling/mempools/cmp.inc.php b/includes/polling/mempools/cmp.inc.php index f06be53d7..b60ad06da 100644 --- a/includes/polling/mempools/cmp.inc.php +++ b/includes/polling/mempools/cmp.inc.php @@ -7,9 +7,7 @@ $pool_cmd = $config['snmpget'].' -M '.$config['mibdir'].' -m CISCO-MEMORY-POOL- $pool_cmd .= " ciscoMemoryPoolUsed.$oid ciscoMemoryPoolFree.$oid ciscoMemoryPoolLargestFree.$oid"; $pool_cmd .= " | cut -f 1 -d ' '"; -if ($debug) { - echo "$pool_cmd"; -} +d_echo("$pool_cmd"); $pool = shell_exec($pool_cmd); diff --git a/includes/polling/mempools/hpGlobal.inc.php b/includes/polling/mempools/hpGlobal.inc.php index 98ed70149..1e3ebd2ef 100644 --- a/includes/polling/mempools/hpGlobal.inc.php +++ b/includes/polling/mempools/hpGlobal.inc.php @@ -9,14 +9,10 @@ // NETSWITCH-MIB::hpGlobalMemAllocBytes.1 = INTEGER: 1668728 if (!is_array($mempool_cache['hpGlobal'])) { $mempool_cache['hpGlobal'] = snmpwalk_cache_oid($device, 'hpGlobal', null, 'NETSWITCH-MIB', $config['mibdir'].':'.$config['mibdir'].'/hp'); - if ($debug) { - print_r($mempool_cache); - } + d_echo($mempool_cache); } else { - if ($debug) { - echo 'Cached!'; - } + d_echo('Cached!'); } $entry = $mempool_cache['hpGlobal'][$mempool[mempool_index]]; diff --git a/includes/polling/mempools/hpLocal.inc.php b/includes/polling/mempools/hpLocal.inc.php index c503cbe11..0688c00aa 100644 --- a/includes/polling/mempools/hpLocal.inc.php +++ b/includes/polling/mempools/hpLocal.inc.php @@ -9,14 +9,10 @@ // NETSWITCH-MIB::hpLocalMemAllocBytes.1 = INTEGER: 1668728 if (!is_array($mempool_cache['hpLocal'])) { $mempool_cache['hpLocal'] = snmpwalk_cache_oid($device, 'hpLocal', null, 'NETSWITCH-MIB', $config['mibdir'].':'.$config['mibdir'].'/hp'); - if ($debug) { - print_r($mempool_cache); - } + d_echo($mempool_cache); } else { - if ($debug) { - echo 'Cached!'; - } + d_echo('Cached!'); } $entry = $mempool_cache['hpLocal'][$mempool[mempool_index]]; diff --git a/includes/polling/mempools/hrstorage.inc.php b/includes/polling/mempools/hrstorage.inc.php index 29a8bd675..6039687ff 100644 --- a/includes/polling/mempools/hrstorage.inc.php +++ b/includes/polling/mempools/hrstorage.inc.php @@ -3,14 +3,10 @@ // HOST-RESOURCES-MIB - Memory Objects if (!is_array($storage_cache['hrstorage'])) { $storage_cache['hrstorage'] = snmpwalk_cache_oid($device, 'hrStorageEntry', null, 'HOST-RESOURCES-MIB:HOST-RESOURCES-TYPES'); - if ($debug) { - print_r($storage_cache); - } + d_echo($storage_cache); } else { - if ($debug) { - echo 'Cached!'; - } + d_echo('Cached!'); } $entry = $storage_cache['hrstorage'][$mempool[mempool_index]]; diff --git a/includes/polling/mempools/junos.inc.php b/includes/polling/mempools/junos.inc.php index 5f28d30d4..813f05304 100644 --- a/includes/polling/mempools/junos.inc.php +++ b/includes/polling/mempools/junos.inc.php @@ -2,22 +2,16 @@ $oid = $mempool['mempool_index']; -if ($debug) { - echo 'JunOS Mempool'; -} +d_echo('JunOS Mempool'); if (!is_array($mempool_cache['junos'])) { - if ($debug) { - echo 'caching'; - } + d_echo('caching'); $mempool_cache['junos'] = array(); $mempool_cache['junos'] = snmpwalk_cache_multi_oid($device, 'jnxOperatingBuffer', $mempool_cache['junos'], 'JUNIPER-MIB', $config['install_dir'].'/mibs/junos'); $mempool_cache['junos'] = snmpwalk_cache_multi_oid($device, 'jnxOperatingDRAMSize', $mempool_cache['junos'], 'JUNIPER-MIB', $config['install_dir'].'/mibs/junos'); $mempool_cache['junos'] = snmpwalk_cache_multi_oid($device, 'jnxOperatingMemory', $mempool_cache['junos'], 'JUNIPER-MIB', $config['install_dir'].'/mibs/junos'); - if ($debug) { - print_r($mempool_cache); - } + d_echo($mempool_cache); } $entry = $mempool_cache['junos'][$mempool[mempool_index]]; diff --git a/includes/polling/mempools/vrp.inc.php b/includes/polling/mempools/vrp.inc.php index 5345e3a73..5693a0e9a 100644 --- a/includes/polling/mempools/vrp.inc.php +++ b/includes/polling/mempools/vrp.inc.php @@ -2,21 +2,15 @@ $oid = $mempool['mempool_index']; -if ($debug) { - echo 'Huawei VRP Mempool'; -} +d_echo('Huawei VRP Mempool'); if (!is_array($mempool_cache['vrp'])) { - if ($debug) { - echo 'caching'; - } + d_echo('caching'); $mempool_cache['vrp'] = array(); $mempool_cache['vrp'] = snmpwalk_cache_multi_oid($device, 'hwEntityMemSize', $mempool_cache['vrp'], 'HUAWEI-ENTITY-EXTENT-MIB', $config['install_dir'].'/mibs'); $mempool_cache['vrp'] = snmpwalk_cache_multi_oid($device, 'hwEntityMemUsage', $mempool_cache['vrp'], 'HUAWEI-ENTITY-EXTENT-MIB', $config['install_dir'].'/mibs'); - if ($debug) { - print_r($mempool_cache); - } + d_echo($mempool_cache); } $entry = $mempool_cache['vrp'][$mempool[mempool_index]]; diff --git a/includes/polling/netscaler-vsvr.inc.php b/includes/polling/netscaler-vsvr.inc.php index f6a462f21..613d4d058 100644 --- a/includes/polling/netscaler-vsvr.inc.php +++ b/includes/polling/netscaler-vsvr.inc.php @@ -77,9 +77,7 @@ if ($device['os'] == 'netscaler') { print_r($vsvr); } - if ($debug) { - print_r($vsvrs); - } + d_echo($vsvrs); foreach ($vsvr_array as $index => $vsvr) { if (isset($vsvr['vsvrName'])) { @@ -129,9 +127,7 @@ if ($device['os'] == 'netscaler') { }//end if }//end foreach - if ($debug) { - print_r($vsvr_exist); - } + d_echo($vsvr_exist); foreach ($vsvrs as $db_name => $db_id) { if (!$vsvr_exist[$db_name]) { diff --git a/includes/polling/ospf.inc.php b/includes/polling/ospf.inc.php index 9f2e0c3e0..ef6ebeafd 100644 --- a/includes/polling/ospf.inc.php +++ b/includes/polling/ospf.inc.php @@ -327,9 +327,7 @@ if (is_array($ospf_nbrs_db)) { foreach ($ospf_nbr_oids as $oid) { // Loop the OIDs - if ($debug) { - echo $ospf_nbr_db[$oid].'|'.$ospf_nbr_poll[$oid]."\n"; - } + d_echo($ospf_nbr_db[$oid].'|'.$ospf_nbr_poll[$oid]."\n"); if ($ospf_nbr_db[$oid] != $ospf_nbr_poll[$oid]) { // If data has changed, build a query diff --git a/includes/polling/ports.inc.php b/includes/polling/ports.inc.php index f374f5f62..f98c62d09 100644 --- a/includes/polling/ports.inc.php +++ b/includes/polling/ports.inc.php @@ -192,9 +192,7 @@ else { $polled = time(); // End Building SNMP Cache Array -if ($debug) { - print_r($port_stats); -} +d_echo($port_stats); // Build array of ports in the database // FIXME -- this stuff is a little messy, looping the array to make an array just seems wrong. :> @@ -243,9 +241,7 @@ foreach ($ports as $port) { if ($config['memcached']['enable'] === true) { $state = $memcache->get('port-'.$port['port_id'].'-state'); - if ($debug) { - print_r($state); - } + d_echo($state); if (is_array($state)) { $port = array_merge($port, $state); @@ -336,7 +332,7 @@ foreach ($ports as $port) { $port['update'][$oid] = array('NULL'); log_event($oid.': '.$port[$oid].' -> NULL', $device, 'interface', $port['port_id']); if ($debug) { - echo $oid.': '.$port[$oid].' -> NULL '; + d_echo($oid.': '.$port[$oid].' -> NULL '); } else { echo $oid.' '; @@ -346,7 +342,7 @@ foreach ($ports as $port) { $port['update'][$oid] = $this_port[$oid]; log_event($oid.': '.$port[$oid].' -> '.$this_port[$oid], $device, 'interface', $port['port_id']); if ($debug) { - echo $oid.': '.$port[$oid].' -> '.$this_port[$oid].' '; + d_echo($oid.': '.$port[$oid].' -> '.$this_port[$oid].' '); } else { echo $oid.' '; @@ -423,9 +419,7 @@ foreach ($ports as $port) { $port['state'][$oid.'_delta'] = $oid_diff; } - if ($debug) { - echo "\n $oid ($oid_diff B) $oid_rate Bps $polled_period secs\n"; - } + d_echo("\n $oid ($oid_diff B) $oid_rate Bps $polled_period secs\n"); }//end if }//end foreach @@ -547,9 +541,7 @@ foreach ($ports as $port) { // Update Memcached if ($config['memcached']['enable'] === true) { - if ($debug) { - print_r($port['state']); - } + d_echo($port['state']); $memcache->set('port-'.$port['port_id'].'-state', $port['state']); } @@ -563,9 +555,7 @@ foreach ($ports as $port) { // Update Database if (count($port['update'])) { $updated = dbUpdate($port['update'], 'ports', '`port_id` = ?', array($port['port_id'])); - if ($debug) { - echo "$updated updated"; - } + d_echo("$updated updated"); } // End Update Database diff --git a/includes/polling/storage.inc.php b/includes/polling/storage.inc.php index f15330d30..b57fc526c 100644 --- a/includes/polling/storage.inc.php +++ b/includes/polling/storage.inc.php @@ -19,9 +19,7 @@ foreach (dbFetchRows('SELECT * FROM storage WHERE device_id = ?', array($device[ // FIXME Generic poller goes here if we ever have a discovery module which uses it. } - if ($debug) { - print_r($storage); - } + d_echo($storage); if ($storage['size']) { $percent = round(($storage['used'] / $storage['size'] * 100)); diff --git a/includes/polling/storage/hrstorage.inc.php b/includes/polling/storage/hrstorage.inc.php index 2f8149a4b..50dade55f 100644 --- a/includes/polling/storage/hrstorage.inc.php +++ b/includes/polling/storage/hrstorage.inc.php @@ -3,9 +3,7 @@ // HOST-RESOURCES-MIB - Storage Objects if (!is_array($storage_cache['hrstorage'])) { $storage_cache['hrstorage'] = snmpwalk_cache_oid($device, 'hrStorageEntry', null, 'HOST-RESOURCES-MIB:HOST-RESOURCES-TYPES'); - if ($debug) { - print_r($storage_cache); - } + d_echo($storage_cache); } $entry = $storage_cache['hrstorage'][$storage[storage_index]]; diff --git a/includes/polling/storage/netapp-storage.inc.php b/includes/polling/storage/netapp-storage.inc.php index 1738b1470..dbeffda0e 100644 --- a/includes/polling/storage/netapp-storage.inc.php +++ b/includes/polling/storage/netapp-storage.inc.php @@ -2,9 +2,7 @@ if (!is_array($storage_cache['netapp-storage'])) { $storage_cache['netapp-storage'] = snmpwalk_cache_oid($device, 'dfEntry', null, 'NETAPP-MIB'); - if ($debug) { - print_r($storage_cache); - } + d_echo($storage_cache); } $entry = $storage_cache['netapp-storage'][$storage[storage_index]]; diff --git a/includes/polling/ucd-diskio.inc.php b/includes/polling/ucd-diskio.inc.php index 6b653f99e..6ad6526cd 100644 --- a/includes/polling/ucd-diskio.inc.php +++ b/includes/polling/ucd-diskio.inc.php @@ -15,15 +15,11 @@ if (count($diskio_data)) { echo $diskio['diskio_descr'].' '; - if ($debug) { - print_r($entry); - } + d_echo($entry); $rrd = $config['rrd_dir'].'/'.$device['hostname'].'/'.safename('ucd_diskio-'.$diskio['diskio_descr'].'.rrd'); - if ($debug) { - echo "$rrd "; - } + d_echo("$rrd "); if (!is_file($rrd)) { rrdtool_create( diff --git a/includes/polling/unix-agent.inc.php b/includes/polling/unix-agent.inc.php index d68daa816..3d1754498 100644 --- a/includes/polling/unix-agent.inc.php +++ b/includes/polling/unix-agent.inc.php @@ -1,7 +1,5 @@ Date: Thu, 20 Aug 2015 15:07:28 +0200 Subject: [PATCH 019/598] Remove all unneeded if($debug)-statements and replace them with d_echo . html dir.. --- html/graph.php | 7 ++----- html/includes/graphs/graph.inc.php | 8 ++------ html/includes/graphs/macaccounting/auth.inc.php | 8 ++------ html/pages/device/health/mempool.inc.php | 4 +--- html/pages/device/overview/mempools.inc.php | 4 +--- html/pages/device/port.inc.php | 4 +--- html/pages/device/ports.inc.php | 4 +--- html/pages/health/sensors.inc.php | 4 +--- 8 files changed, 11 insertions(+), 32 deletions(-) diff --git a/html/graph.php b/html/graph.php index f3cf51fd9..537c5e999 100644 --- a/html/graph.php +++ b/html/graph.php @@ -58,8 +58,5 @@ $end = utime(); $run = ($end - $start); -if ($debug) { - echo '
Runtime '.$run.' secs'; - - echo ('
MySQL: Cell '.($db_stats['fetchcell'] + 0).'/'.round(($db_stats['fetchcell_sec'] + 0), 3).'s'.' Row '.($db_stats['fetchrow'] + 0).'/'.round(($db_stats['fetchrow_sec'] + 0), 3).'s'.' Rows '.($db_stats['fetchrows'] + 0).'/'.round(($db_stats['fetchrows_sec'] + 0), 3).'s'.' Column '.($db_stats['fetchcol'] + 0).'/'.round(($db_stats['fetchcol_sec'] + 0), 3).'s'); -} +d_echo('
Runtime '.$run.' secs'); +d_echo('
MySQL: Cell '.($db_stats['fetchcell'] + 0).'/'.round(($db_stats['fetchcell_sec'] + 0), 3).'s'.' Row '.($db_stats['fetchrow'] + 0).'/'.round(($db_stats['fetchrow_sec'] + 0), 3).'s'.' Rows '.($db_stats['fetchrows'] + 0).'/'.round(($db_stats['fetchrows_sec'] + 0), 3).'s'.' Column '.($db_stats['fetchcol'] + 0).'/'.round(($db_stats['fetchcol_sec'] + 0), 3).'s'); diff --git a/html/includes/graphs/graph.inc.php b/html/includes/graphs/graph.inc.php index 19e99c9b6..d7ed4cbc8 100644 --- a/html/includes/graphs/graph.inc.php +++ b/html/includes/graphs/graph.inc.php @@ -69,9 +69,7 @@ function graph_error($string) { if ($height > '99') { shell_exec($rrd_cmd); - if ($debug) { - echo '
'.$rrd_cmd.'
'; - } + d_echo('
'.$rrd_cmd.'
'); if (is_file($graphfile) && !$debug) { header('Content-type: image/png'); @@ -135,9 +133,7 @@ else { else { if ($rrd_options) { rrdtool_graph($graphfile, $rrd_options); - if ($debug) { - echo $rrd_cmd; - } + d_echo($rrd_cmd); if (is_file($graphfile)) { if (!$debug) { diff --git a/html/includes/graphs/macaccounting/auth.inc.php b/html/includes/graphs/macaccounting/auth.inc.php index 971874116..d6a2ccb5f 100644 --- a/html/includes/graphs/macaccounting/auth.inc.php +++ b/html/includes/graphs/macaccounting/auth.inc.php @@ -11,14 +11,10 @@ if (is_numeric($vars['id'])) { if (is_array($acc)) { if ($auth || port_permitted($acc['port_id'])) { - if ($debug) { - echo $config['rrd_dir'].'/'.$acc['hostname'].'/'.safename('cip-'.$acc['ifIndex'].'-'.$acc['mac'].'.rrd'); - } + d_echo($config['rrd_dir'].'/'.$acc['hostname'].'/'.safename('cip-'.$acc['ifIndex'].'-'.$acc['mac'].'.rrd')); if (is_file($config['rrd_dir'].'/'.$acc['hostname'].'/'.safename('cip-'.$acc['ifIndex'].'-'.$acc['mac'].'.rrd'))) { - if ($debug) { - echo 'exists'; - } + d_echo('exists'); $rrd_filename = $config['rrd_dir'].'/'.$acc['hostname'].'/'.safename('cip-'.$acc['ifIndex'].'-'.$acc['mac'].'.rrd'); $port = get_port_by_id($acc['port_id']); diff --git a/html/pages/device/health/mempool.inc.php b/html/pages/device/health/mempool.inc.php index 613aa1250..e2a6eaa51 100644 --- a/html/pages/device/health/mempool.inc.php +++ b/html/pages/device/health/mempool.inc.php @@ -18,9 +18,7 @@ foreach (dbFetchRows('SELECT * FROM `mempools` WHERE device_id = ?', array($devi if ($config['memcached']['enable'] === true) { $state = $memcache->get('mempool-'.$mempool['mempool_id'].'-state'); - if ($debug) { - print_r($state); - } + d_echo($state); if (is_array($state)) { $mempool = array_merge($mempool, $state); diff --git a/html/pages/device/overview/mempools.inc.php b/html/pages/device/overview/mempools.inc.php index 49884331d..01895ee7d 100644 --- a/html/pages/device/overview/mempools.inc.php +++ b/html/pages/device/overview/mempools.inc.php @@ -21,9 +21,7 @@ if (count($mempools)) { foreach ($mempools as $mempool) { if ($config['memcached']['enable'] === true) { $state = $memcache->get('mempool-'.$mempool['mempool_id'].'-state'); - if ($debug) { - print_r($state); - } + d_echo($state); if (is_array($state)) { $mempool = array_merge($mempool, $state); diff --git a/html/pages/device/port.inc.php b/html/pages/device/port.inc.php index 80bdbff91..bd9c38acd 100644 --- a/html/pages/device/port.inc.php +++ b/html/pages/device/port.inc.php @@ -8,9 +8,7 @@ $port = dbFetchRow('SELECT * FROM `ports` WHERE `port_id` = ?', array($vars['por if ($config['memcached']['enable'] === true) { $state = $memcache->get('port-'.$port['port_id'].'-state'); - if ($debug) { - print_r($state); - } + d_echo($state); if (is_array($state)) { $port = array_merge($port, $state); diff --git a/html/pages/device/ports.inc.php b/html/pages/device/ports.inc.php index dc941e246..11a5978ff 100644 --- a/html/pages/device/ports.inc.php +++ b/html/pages/device/ports.inc.php @@ -138,9 +138,7 @@ else { foreach ($ports as $port) { if ($config['memcached']['enable'] === true) { $state = $memcache->get('port-'.$port['port_id'].'-state'); - if ($debug) { - print_r($state); - } + d_echo($state); if (is_array($state)) { $port = array_merge($port, $state); diff --git a/html/pages/health/sensors.inc.php b/html/pages/health/sensors.inc.php index a51ba6e71..7ed65f926 100644 --- a/html/pages/health/sensors.inc.php +++ b/html/pages/health/sensors.inc.php @@ -24,9 +24,7 @@ echo ' foreach (dbFetchRows($sql, $param) as $sensor) { if ($config['memcached']['enable'] === true) { $sensor['sensor_current'] = $memcache->get('sensor-'.$sensor['sensor_id'].'-value'); - if ($debug) { - echo 'Memcached['.'sensor-'.$sensor['sensor_id'].'-value'.'='.$sensor['sensor_current'].']'; - } + d_echo('Memcached['.'sensor-'.$sensor['sensor_id'].'-value'.'='.$sensor['sensor_current'].']'); } if (empty($sensor['sensor_current'])) { From 677a4f3f5f89f0b72b5b13c41c8b854c4d7a6282 Mon Sep 17 00:00:00 2001 From: Mark Schouten Date: Thu, 20 Aug 2015 15:59:43 +0200 Subject: [PATCH 020/598] Remove all unneeded if($debug)-statements and replace them with d_echo . discovery dir.. --- includes/discovery/arp-table.inc.php | 8 +- includes/discovery/bgp-peers.inc.php | 32 ++---- includes/discovery/charge.inc.php | 4 +- includes/discovery/charge/apc.inc.php | 8 +- includes/discovery/charge/rfc1628.inc.php | 4 +- includes/discovery/cisco-cef.inc.php | 4 +- .../discovery/cisco-entity-sensor.inc.php | 4 +- includes/discovery/cisco-vrf.inc.php | 6 +- includes/discovery/current.inc.php | 4 +- includes/discovery/current/apc.inc.php | 20 +--- includes/discovery/current/mgeups.inc.php | 8 +- includes/discovery/current/rfc1628.inc.php | 16 +-- includes/discovery/current/sentry3.inc.php | 4 +- includes/discovery/current/xups.inc.php | 12 +- .../discovery/discovery-protocols.inc.php | 12 +- includes/discovery/fanspeeds.inc.php | 4 +- includes/discovery/fanspeeds/areca.inc.php | 4 +- includes/discovery/fanspeeds/dell.inc.php | 4 +- includes/discovery/fanspeeds/drac.inc.php | 4 +- .../discovery/fanspeeds/lmsensors.inc.php | 4 +- includes/discovery/fanspeeds/mikrotik.inc.php | 4 +- .../discovery/fanspeeds/supermicro.inc.php | 4 +- includes/discovery/frequencies.inc.php | 4 +- includes/discovery/frequencies/apc.inc.php | 16 +-- includes/discovery/frequencies/mgeups.inc.php | 8 +- .../discovery/frequencies/rfc1628.inc.php | 4 +- includes/discovery/functions.inc.php | 104 +++++------------- includes/discovery/hr-device.inc.php | 18 +-- includes/discovery/humidity.inc.php | 4 +- includes/discovery/humidity/akcp.inc.php | 4 +- includes/discovery/humidity/mgeups.inc.php | 6 +- includes/discovery/humidity/netbotz.inc.php | 4 +- includes/discovery/humidity/sentry3.inc.php | 4 +- includes/discovery/junose-atm-vp.inc.php | 12 +- includes/discovery/libvirt-vminfo.inc.php | 4 +- includes/discovery/load.inc.php | 4 +- includes/discovery/load/apc.inc.php | 4 +- includes/discovery/load/rfc1628.inc.php | 4 +- includes/discovery/mempools.inc.php | 8 +- includes/discovery/mempools/junos.inc.php | 8 +- includes/discovery/mempools/vrp.inc.php | 8 +- includes/discovery/ports.inc.php | 4 +- includes/discovery/power.inc.php | 4 +- includes/discovery/power/rfc1628.inc.php | 12 +- includes/discovery/processors.inc.php | 8 +- .../discovery/processors/hrdevice.inc.php | 4 +- includes/discovery/processors/ios.inc.php | 8 +- .../discovery/processors/ironware.inc.php | 4 +- includes/discovery/processors/junos.inc.php | 12 +- includes/discovery/processors/junose.inc.php | 4 +- includes/discovery/processors/vrp.inc.php | 8 +- includes/discovery/states.inc.php | 4 +- includes/discovery/states/dell.inc.php | 4 +- includes/discovery/states/drac.inc.php | 4 +- includes/discovery/states/rfc1628.inc.php | 8 +- includes/discovery/storage.inc.php | 8 +- includes/discovery/storage/hrstorage.inc.php | 24 +--- .../discovery/storage/netapp-storage.inc.php | 12 +- includes/discovery/temperatures.inc.php | 4 +- includes/discovery/temperatures/akcp.inc.php | 4 +- includes/discovery/temperatures/apc.inc.php | 19 +--- includes/discovery/temperatures/areca.inc.php | 8 +- .../temperatures/cometsystem-p85xx.inc.php | 1 - includes/discovery/temperatures/dell.inc.php | 8 +- includes/discovery/temperatures/drac.inc.php | 8 +- .../discovery/temperatures/lm-sensors.inc.php | 4 +- .../discovery/temperatures/mgeups.inc.php | 6 +- .../discovery/temperatures/mikrotik.inc.php | 4 +- .../discovery/temperatures/netapp.inc.php | 4 +- .../discovery/temperatures/netbotz.inc.php | 4 +- .../temperatures/observernms-custom.inc.php | 4 +- .../discovery/temperatures/rfc1628.inc.php | 4 +- .../discovery/temperatures/sentry3.inc.php | 4 +- includes/discovery/temperatures/siklu.inc.php | 4 +- includes/discovery/temperatures/xups.inc.php | 4 +- includes/discovery/toner.inc.php | 12 +- includes/discovery/ucd-diskio.inc.php | 17 +-- includes/discovery/voltages.inc.php | 4 +- includes/discovery/voltages/apc.inc.php | 24 +--- includes/discovery/voltages/areca.inc.php | 4 +- includes/discovery/voltages/drac.inc.php | 4 +- includes/discovery/voltages/linux.inc.php | 4 +- includes/discovery/voltages/mgeups.inc.php | 8 +- includes/discovery/voltages/mikrotik.inc.php | 4 +- includes/discovery/voltages/rfc1628.inc.php | 16 +-- includes/discovery/voltages/sentry3.inc.php | 4 +- includes/discovery/voltages/siklu.inc.php | 4 +- .../discovery/voltages/supermicro.inc.php | 4 +- includes/discovery/voltages/xups.inc.php | 16 +-- 89 files changed, 192 insertions(+), 561 deletions(-) diff --git a/includes/discovery/arp-table.inc.php b/includes/discovery/arp-table.inc.php index a292bf25b..69b0d9b75 100644 --- a/includes/discovery/arp-table.inc.php +++ b/includes/discovery/arp-table.inc.php @@ -43,9 +43,7 @@ foreach (explode("\n", $ipNetToMedia_data) as $data) { $old_mac = dbFetchCell('SELECT mac_address from ipv4_mac WHERE ipv4_address=? AND port_id=?', array($ip, $interface['port_id'])); if ($clean_mac != $old_mac && $clean_mac != '' && $old_mac != '') { - if ($debug) { - echo "Changed mac address for $ip from $old_mac to $clean_mac\n"; - } + d_echo("Changed mac address for $ip from $old_mac to $clean_mac\n"); log_event("MAC change: $ip : ".mac_clean_to_readable($old_mac).' -> '.mac_clean_to_readable($clean_mac), $device, 'interface', $interface['port_id']); } @@ -73,9 +71,7 @@ foreach (dbFetchRows($sql) as $entry) { $entry_if = $entry['port_id']; if (!$mac_table[$entry_if][$entry_mac]) { dbDelete('ipv4_mac', '`port_id` = ? AND `mac_address` = ?', array($entry_if, $entry_mac)); - if ($debug) { - echo "Removing MAC $entry_mac from interface ".$interface['ifName']; - } + d_echo("Removing MAC $entry_mac from interface ".$interface['ifName']); echo '-'; } diff --git a/includes/discovery/bgp-peers.inc.php b/includes/discovery/bgp-peers.inc.php index 304bbc6b1..b9f3c16a0 100644 --- a/includes/discovery/bgp-peers.inc.php +++ b/includes/discovery/bgp-peers.inc.php @@ -1,7 +1,5 @@ $peer_ip, @@ -70,9 +64,7 @@ if ($config['enable_bgp']) { $peer_ip = Net_IPv6::compress(snmp2ipv6(implode('.', array_slice(explode('.', $peer_ip_snmp), (count(explode('.', $peer_ip_snmp)) - 16))))); if ($peer) { - if ($debug) { - echo "Found peer $peer_ip (AS$peer_as)\n"; - } + d_echo("Found peer $peer_ip (AS$peer_as)\n"); $peerlist[] = array( 'ip' => $peer_ip, @@ -121,19 +113,15 @@ if ($config['enable_bgp']) { $af_data = snmpwalk_cache_oid($device, 'cbgpPeerAddrFamilyEntry', $cbgp, 'CISCO-BGP4-MIB', $config['mibdir']); } - if ($debug) { - echo 'afi data :: '; - print_r($af_data); - } + d_echo('afi data :: '; + d_echo($af_data); foreach ($af_data as $k => $v) { if ($peer2 === true) { list(,$k) = explode('.', $k, 2); } - if ($debug) { - echo "AFISAFI = $k\n"; - } + d_echo("AFISAFI = $k\n"); $afisafi_tmp = explode('.', $k); $safi = array_pop($afisafi_tmp); @@ -162,9 +150,7 @@ if ($config['enable_bgp']) { switch ($entry['jnxBgpM2PeerRemoteAddrType']) { case 'ipv4': $ip = long2ip(hexdec($entry['jnxBgpM2PeerRemoteAddr'])); - if ($debug) { - echo "peerindex for ipv4 $ip is ".$entry['jnxBgpM2PeerIndex']."\n"; - } + d_echo("peerindex for ipv4 $ip is ".$entry['jnxBgpM2PeerIndex']."\n"); $j_peerIndexes[$ip] = $entry['jnxBgpM2PeerIndex']; break; @@ -173,9 +159,7 @@ if ($config['enable_bgp']) { $ip6 = trim(str_replace(' ', '', $entry['jnxBgpM2PeerRemoteAddr']), '"'); $ip6 = substr($ip6, 0, 4).':'.substr($ip6, 4, 4).':'.substr($ip6, 8, 4).':'.substr($ip6, 12, 4).':'.substr($ip6, 16, 4).':'.substr($ip6, 20, 4).':'.substr($ip6, 24, 4).':'.substr($ip6, 28, 4); $ip6 = Net_IPv6::compress($ip6); - if ($debug) { - echo "peerindex for ipv6 $ip6 is ".$entry['jnxBgpM2PeerIndex']."\n"; - } + d_echo("peerindex for ipv6 $ip6 is ".$entry['jnxBgpM2PeerIndex']."\n"); $j_peerIndexes[$ip6] = $entry['jnxBgpM2PeerIndex']; break; diff --git a/includes/discovery/charge.inc.php b/includes/discovery/charge.inc.php index c82863d0f..eeea0961f 100644 --- a/includes/discovery/charge.inc.php +++ b/includes/discovery/charge.inc.php @@ -6,9 +6,7 @@ echo 'Battery Charge: '; $include_dir = 'includes/discovery/charge'; require 'includes/include-dir.inc.php'; -if ($debug) { - print_r($valid['sensor']['charge']); -} +d_echo($valid['sensor']['charge']); check_valid_sensors($device, 'charge', $valid['sensor']); diff --git a/includes/discovery/charge/apc.inc.php b/includes/discovery/charge/apc.inc.php index b9858b958..ce98b4b9d 100644 --- a/includes/discovery/charge/apc.inc.php +++ b/includes/discovery/charge/apc.inc.php @@ -2,9 +2,7 @@ if ($device['os'] == 'apc') { $oids = snmp_get($device, '1.3.6.1.4.1.318.1.1.1.2.3.1.0', '-OsqnU', ''); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); // Try High-Precision First if (!empty($oids)) { @@ -27,9 +25,7 @@ if ($device['os'] == 'apc') { else { // Try to just get capacity $oids = snmp_get($device, '1.3.6.1.4.1.318.1.1.1.2.2.1.0', '-OsqnU', ''); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); if (!empty($oids)) { echo 'APC UPS Battery Charge'; diff --git a/includes/discovery/charge/rfc1628.inc.php b/includes/discovery/charge/rfc1628.inc.php index c7d5742c7..02b85e03f 100644 --- a/includes/discovery/charge/rfc1628.inc.php +++ b/includes/discovery/charge/rfc1628.inc.php @@ -5,9 +5,7 @@ if (isset($config['modules_compat']['rfc1628'][$device['os']]) && $config['modul echo 'RFC1628 '; $oids = snmp_walk($device, '1.3.6.1.2.1.33.1.2.4', '-Osqn', 'UPS-MIB'); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); $oids = trim($oids); foreach (explode("\n", $oids) as $data) { diff --git a/includes/discovery/cisco-cef.inc.php b/includes/discovery/cisco-cef.inc.php index 7b8ef3a80..5f9ef1ca6 100644 --- a/includes/discovery/cisco-cef.inc.php +++ b/includes/discovery/cisco-cef.inc.php @@ -4,9 +4,7 @@ echo 'Cisco CEF Switching Path: '; $cefs = array(); $cefs = snmpwalk_cache_threepart_oid($device, 'CISCO-CEF-MIB::cefSwitchingPath', $cefs); -if ($debug) { - print_r($cefs); -} +d_echo($cefs); if (is_array($cefs)) { if (!is_array($entity_array)) { diff --git a/includes/discovery/cisco-entity-sensor.inc.php b/includes/discovery/cisco-entity-sensor.inc.php index e7053a20d..66340dedb 100644 --- a/includes/discovery/cisco-entity-sensor.inc.php +++ b/includes/discovery/cisco-entity-sensor.inc.php @@ -33,9 +33,7 @@ if ($device['os_group'] == 'cisco') { echo ' entSensorThresholdValue'; $t_oids = snmpwalk_cache_twopart_oid($device, 'entSensorThresholdValue', $t_oids, 'CISCO-ENTITY-SENSOR-MIB'); - if ($debug) { - print_r($oids); - } + d_echo($oids); $entitysensor['voltsDC'] = 'voltage'; $entitysensor['voltsAC'] = 'voltage'; diff --git a/includes/discovery/cisco-vrf.inc.php b/includes/discovery/cisco-vrf.inc.php index 39928b734..aceef192f 100644 --- a/includes/discovery/cisco-vrf.inc.php +++ b/includes/discovery/cisco-vrf.inc.php @@ -34,10 +34,8 @@ if ($config['enable_vrfs']) { $ports_oid = '.1.3.6.1.2.1.10.166.11.1.2.1.1.2'; } - if ($debug) { - echo "\n[DEBUG]\nUsing $vpnmib\n[/DEBUG]\n"; - echo "\n[DEBUG OIDS]\n$rds\n[/DEBUG]\n"; - } + d_echo("\n[DEBUG]\nUsing $vpnmib\n[/DEBUG]\n"); + d_echo("\n[DEBUG OIDS]\n$rds\n[/DEBUG]\n"); $rds = trim($rds); diff --git a/includes/discovery/current.inc.php b/includes/discovery/current.inc.php index c28644184..143d6068c 100644 --- a/includes/discovery/current.inc.php +++ b/includes/discovery/current.inc.php @@ -5,9 +5,7 @@ echo 'Current: '; $include_dir = 'includes/discovery/current'; require 'includes/include-dir.inc.php'; -if ($debug) { - print_r($valid['sensor']['current']); -} +d_echo($valid['sensor']['current']); check_valid_sensors($device, 'current', $valid['sensor']); diff --git a/includes/discovery/current/apc.inc.php b/includes/discovery/current/apc.inc.php index e57f26640..8e35df882 100644 --- a/includes/discovery/current/apc.inc.php +++ b/includes/discovery/current/apc.inc.php @@ -9,9 +9,7 @@ if ($device['os'] == 'apc') { } if ($oids) { - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); $oids = trim($oids); if ($oids) { @@ -64,9 +62,7 @@ if ($device['os'] == 'apc') { // should work with firmware v2 and v3 if ($oids) { echo 'APC PowerNet-MIB Banks '; - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); $oids = trim($oids); $type = 'apc'; @@ -132,9 +128,7 @@ if ($device['os'] == 'apc') { $oids = snmp_walk($device, '1.3.6.1.4.1.318.1.1.26.9.4.3.1.1', '-t 30 -OsqnU', 'PowerNet-MIB'); if ($oids) { echo 'APC PowerNet-MIB Outlets '; - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); $oids = trim($oids); $type = 'apc'; @@ -179,9 +173,7 @@ if ($device['os'] == 'apc') { $oids = snmp_walk($device, 'atsConfigPhaseTableIndex', '-OsqnU', 'PowerNet-MIB'); if ($oids) { $type = 'apc'; - if ($debug) { - print_r($oids); - } + d_echo($oids."\n"); $oids = trim($oids); if ($oids) { @@ -239,9 +231,7 @@ if ($device['os'] == 'apc') { } if (!empty($oids)) { - if ($debug) { - print_r($oids); - } + d_echo($oids."\n"); $oids = trim($oids); if ($oids) { diff --git a/includes/discovery/current/mgeups.inc.php b/includes/discovery/current/mgeups.inc.php index c2a7b77a7..bc80a0b16 100644 --- a/includes/discovery/current/mgeups.inc.php +++ b/includes/discovery/current/mgeups.inc.php @@ -4,9 +4,7 @@ if ($device['os'] == 'mgeups') { echo 'MGE '; $oids = trim(snmp_walk($device, '1.3.6.1.4.1.705.1.7.1', '-OsqnU')); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); $numPhase = count(explode("\n", $oids)); for ($i = 1; $i <= $numPhase; $i++) { @@ -36,9 +34,7 @@ if ($device['os'] == 'mgeups') { }//end for $oids = trim(snmp_walk($device, '1.3.6.1.4.1.705.1.6.1', '-OsqnU')); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); $numPhase = count(explode("\n", $oids)); for ($i = 1; $i <= $numPhase; $i++) { diff --git a/includes/discovery/current/rfc1628.inc.php b/includes/discovery/current/rfc1628.inc.php index d86b70808..73811ae10 100644 --- a/includes/discovery/current/rfc1628.inc.php +++ b/includes/discovery/current/rfc1628.inc.php @@ -5,9 +5,7 @@ if (isset($config['modules_compat']['rfc1628'][$device['os']]) && $config['modul echo 'RFC1628 '; $oids = snmp_walk($device, '1.3.6.1.2.1.33.1.2.6', '-Osqn', 'UPS-MIB'); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); $oids = trim($oids); foreach (explode("\n", $oids) as $data) { @@ -28,9 +26,7 @@ if (isset($config['modules_compat']['rfc1628'][$device['os']]) && $config['modul } $oids = trim(snmp_walk($device, '1.3.6.1.2.1.33.1.4.3.0', '-OsqnU')); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); list($unused,$numPhase) = explode(' ', $oids); for ($i = 1; $i <= $numPhase; $i++) { @@ -49,9 +45,7 @@ if (isset($config['modules_compat']['rfc1628'][$device['os']]) && $config['modul } $oids = trim(snmp_walk($device, '1.3.6.1.2.1.33.1.3.2.0', '-OsqnU')); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); list($unused,$numPhase) = explode(' ', $oids); for ($i = 1; $i <= $numPhase; $i++) { @@ -70,9 +64,7 @@ if (isset($config['modules_compat']['rfc1628'][$device['os']]) && $config['modul } $oids = trim(snmp_walk($device, '1.3.6.1.2.1.33.1.5.2.0', '-OsqnU')); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); list($unused,$numPhase) = explode(' ', $oids); for ($i = 1; $i <= $numPhase; $i++) { diff --git a/includes/discovery/current/sentry3.inc.php b/includes/discovery/current/sentry3.inc.php index 6946d3770..45bcc6d9f 100644 --- a/includes/discovery/current/sentry3.inc.php +++ b/includes/discovery/current/sentry3.inc.php @@ -12,9 +12,7 @@ if ($device['os'] == 'sentry3') { // // Check for Infeeds $infeed_oids = snmp_walk($device, "infeedID.$towers.1", '-Osqn', 'Sentry3-MIB'); - if ($debug) { - echo $infeed_oids."\n"; - } + d_echo($infeed_oids."\n"); $infeed_oids = trim($infeed_oids); diff --git a/includes/discovery/current/xups.inc.php b/includes/discovery/current/xups.inc.php index 328ed9801..d6dff4d3f 100644 --- a/includes/discovery/current/xups.inc.php +++ b/includes/discovery/current/xups.inc.php @@ -5,9 +5,7 @@ if ($device['os'] == 'powerware') { echo 'XUPS-MIB '; $oids = snmp_walk($device, 'xupsBatCurrent', '-Osqn', 'XUPS-MIB'); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); $oids = trim($oids); foreach (explode("\n", $oids) as $data) { @@ -28,9 +26,7 @@ if ($device['os'] == 'powerware') { } $oids = trim(snmp_walk($device, 'xupsOutputCurrent', '-OsqnU', 'XUPS-MIB')); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); list($unused,$numPhase) = explode(' ', $oids); for ($i = 1; $i <= $numPhase; $i++) { @@ -49,9 +45,7 @@ if ($device['os'] == 'powerware') { } $oids = trim(snmp_walk($device, 'xupsInputCurrent', '-OsqnU', 'XUPS-MIB')); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); list($unused,$numPhase) = explode(' ', $oids); for ($i = 1; $i <= $numPhase; $i++) { diff --git a/includes/discovery/discovery-protocols.inc.php b/includes/discovery/discovery-protocols.inc.php index 0e5d540f1..0afe43311 100644 --- a/includes/discovery/discovery-protocols.inc.php +++ b/includes/discovery/discovery-protocols.inc.php @@ -186,25 +186,19 @@ else { echo "disabled\n"; } -if ($debug) { - print_r($link_exists); -} +d_echo($link_exists); $sql = "SELECT * FROM `links` AS L, `ports` AS I WHERE L.local_port_id = I.port_id AND I.device_id = '".$device['device_id']."'"; foreach (dbFetchRows($sql) as $test) { $local_port_id = $test['local_port_id']; $remote_hostname = $test['remote_hostname']; $remote_port = $test['remote_port']; - if ($debug) { - echo "$local_port_id -> $remote_hostname -> $remote_port \n"; - } + d_echo("$local_port_id -> $remote_hostname -> $remote_port \n"); if (!$link_exists[$local_port_id][$remote_hostname][$remote_port]) { echo '-'; $rows = dbDelete('links', '`id` = ?', array($test['id'])); - if ($debug) { - echo "$rows deleted "; - } + d_echo("$rows deleted "); } } diff --git a/includes/discovery/fanspeeds.inc.php b/includes/discovery/fanspeeds.inc.php index 6ad629549..536232149 100644 --- a/includes/discovery/fanspeeds.inc.php +++ b/includes/discovery/fanspeeds.inc.php @@ -6,9 +6,7 @@ echo 'Fanspeeds : '; $include_dir = 'includes/discovery/fanspeeds'; require 'includes/include-dir.inc.php'; -if ($debug) { - print_r($valid['sensor']['fanspeed']); -} +d_echo($valid['sensor']['fanspeed']); check_valid_sensors($device, 'fanspeed', $valid['sensor']); diff --git a/includes/discovery/fanspeeds/areca.inc.php b/includes/discovery/fanspeeds/areca.inc.php index 831cd78a5..cdb0fb791 100644 --- a/includes/discovery/fanspeeds/areca.inc.php +++ b/includes/discovery/fanspeeds/areca.inc.php @@ -3,9 +3,7 @@ // Areca Fanspeeds if ($device['os'] == 'areca') { $oids = snmp_walk($device, '1.3.6.1.4.1.18928.1.2.2.1.9.1.2', '-OsqnU', ''); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); if ($oids) { echo 'Areca '; diff --git a/includes/discovery/fanspeeds/dell.inc.php b/includes/discovery/fanspeeds/dell.inc.php index f1ee40d94..d1522a656 100644 --- a/includes/discovery/fanspeeds/dell.inc.php +++ b/includes/discovery/fanspeeds/dell.inc.php @@ -2,9 +2,7 @@ if ($device['os'] == 'linux') { $oids = snmp_walk($device, 'coolingDevicechassisIndex.1', '-OsqnU', 'MIB-Dell-10892'); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); $oids = trim($oids); if ($oids) { diff --git a/includes/discovery/fanspeeds/drac.inc.php b/includes/discovery/fanspeeds/drac.inc.php index 38b80c340..3d9e0bf41 100644 --- a/includes/discovery/fanspeeds/drac.inc.php +++ b/includes/discovery/fanspeeds/drac.inc.php @@ -2,9 +2,7 @@ if ($device['os'] == 'drac') { $oids = snmp_walk($device, 'coolingDevicechassisIndex.1', '-OsqnU', 'IDRAC-MIB-SMIv2'); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); $oids = trim($oids); if ($oids) { diff --git a/includes/discovery/fanspeeds/lmsensors.inc.php b/includes/discovery/fanspeeds/lmsensors.inc.php index a4aa7c6ca..8e288e73d 100644 --- a/includes/discovery/fanspeeds/lmsensors.inc.php +++ b/includes/discovery/fanspeeds/lmsensors.inc.php @@ -3,9 +3,7 @@ // LMSensors Fanspeeds if ($device['os'] == 'linux') { $oids = snmp_walk($device, 'lmFanSensorsDevice', '-OsqnU', 'LM-SENSORS-MIB'); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); $oids = trim($oids); if ($oids) { diff --git a/includes/discovery/fanspeeds/mikrotik.inc.php b/includes/discovery/fanspeeds/mikrotik.inc.php index 9908fdbf0..789769f7d 100644 --- a/includes/discovery/fanspeeds/mikrotik.inc.php +++ b/includes/discovery/fanspeeds/mikrotik.inc.php @@ -2,9 +2,7 @@ if ($device['os'] == 'routeros') { $oids = snmp_walk($device, 'mtxrHlActiveFan', '-OsqnU', 'MIKROTIK-MIB'); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); if ($oids !== false) { echo 'MIKROTIK-MIB '; diff --git a/includes/discovery/fanspeeds/supermicro.inc.php b/includes/discovery/fanspeeds/supermicro.inc.php index be56aec02..c16eb1b09 100644 --- a/includes/discovery/fanspeeds/supermicro.inc.php +++ b/includes/discovery/fanspeeds/supermicro.inc.php @@ -3,9 +3,7 @@ // Supermicro Fanspeeds if ($device['os'] == 'linux') { $oids = snmp_walk($device, '1.3.6.1.4.1.10876.2.1.1.1.1.3', '-OsqnU', 'SUPERMICRO-HEALTH-MIB'); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); $oids = trim($oids); if ($oids) { diff --git a/includes/discovery/frequencies.inc.php b/includes/discovery/frequencies.inc.php index 23b30b092..93fa17117 100644 --- a/includes/discovery/frequencies.inc.php +++ b/includes/discovery/frequencies.inc.php @@ -6,9 +6,7 @@ echo 'Frequencies: '; $include_dir = 'includes/discovery/frequencies'; require 'includes/include-dir.inc.php'; -if ($debug) { - print_r($valid['sensor']['frequency']); -} +d_echo($valid['sensor']['frequency']); check_valid_sensors($device, 'frequency', $valid['sensor']); diff --git a/includes/discovery/frequencies/apc.inc.php b/includes/discovery/frequencies/apc.inc.php index cfb4d08ef..794fe5fc5 100644 --- a/includes/discovery/frequencies/apc.inc.php +++ b/includes/discovery/frequencies/apc.inc.php @@ -3,9 +3,7 @@ // APC if ($device['os'] == 'apc') { $oids = snmp_walk($device, '1.3.6.1.4.1.318.1.1.8.5.3.2.1.4', '-OsqnU', ''); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); if ($oids) { echo 'APC In '; @@ -26,9 +24,7 @@ if ($device['os'] == 'apc') { } $oids = snmp_walk($device, '1.3.6.1.4.1.318.1.1.8.5.4.2.1.4', '-OsqnU', ''); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); if ($oids) { echo ' APC Out '; @@ -53,9 +49,7 @@ if ($device['os'] == 'apc') { } $oids = snmp_get($device, '1.3.6.1.4.1.318.1.1.1.3.2.4.0', '-OsqnU', ''); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); if ($oids) { echo ' APC In '; @@ -68,9 +62,7 @@ if ($device['os'] == 'apc') { } $oids = snmp_get($device, '1.3.6.1.4.1.318.1.1.1.4.2.2.0', '-OsqnU', ''); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); if ($oids) { echo ' APC Out '; diff --git a/includes/discovery/frequencies/mgeups.inc.php b/includes/discovery/frequencies/mgeups.inc.php index 67a31218c..1815a30c6 100644 --- a/includes/discovery/frequencies/mgeups.inc.php +++ b/includes/discovery/frequencies/mgeups.inc.php @@ -4,9 +4,7 @@ if ($device['os'] == 'mgeups') { echo 'MGE '; $oids = trim(snmp_walk($device, '1.3.6.1.4.1.705.1.7.1', '-OsqnU')); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); $numPhase = count(explode("\n", $oids)); for ($i = 1; $i <= $numPhase; $i++) { @@ -30,9 +28,7 @@ if ($device['os'] == 'mgeups') { } $oids = trim(snmp_walk($device, '1.3.6.1.4.1.705.1.6.1', '-OsqnU')); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); $numPhase = count(explode("\n", $oids)); for ($i = 1; $i <= $numPhase; $i++) { diff --git a/includes/discovery/frequencies/rfc1628.inc.php b/includes/discovery/frequencies/rfc1628.inc.php index aeadbf3e6..707318154 100644 --- a/includes/discovery/frequencies/rfc1628.inc.php +++ b/includes/discovery/frequencies/rfc1628.inc.php @@ -5,9 +5,7 @@ if (isset($config['modules_compat']['rfc1628'][$device['os']]) && $config['modul echo 'RFC1628 '; $oids = trim(snmp_walk($device, '1.3.6.1.2.1.33.1.3.2.0', '-OsqnU')); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); list($unused,$numPhase) = explode(' ', $oids); for ($i = 1; $i <= $numPhase; $i++) { diff --git a/includes/discovery/functions.inc.php b/includes/discovery/functions.inc.php index 512f39cff..dbe5d08dd 100644 --- a/includes/discovery/functions.inc.php +++ b/includes/discovery/functions.inc.php @@ -14,7 +14,7 @@ function discover_new_device($hostname, $device='', $method='', $interface='') { - global $config, $debug; + global $config; if (!empty($config['mydomain']) && isDomainResolves($hostname.'.'.$config['mydomain'])) { $dst_host = $hostname.'.'.$config['mydomain']; @@ -23,32 +23,24 @@ function discover_new_device($hostname, $device='', $method='', $interface='') { $dst_host = $hostname; } - if ($debug) { - echo "discovering $dst_host\n"; - } + d_echo("discovering $dst_host\n"); $ip = gethostbyname($dst_host); if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) === false && filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false) { // $ip isn't a valid IP so it must be a name. if ($ip == $dst_host) { - if ($debug) { - echo "name lookup of $dst_host failed\n"; - } + d_echo("name lookup of $dst_host failed\n"); return false; } } - if ($debug) { - echo "ip lookup result: $ip\n"; - } + d_echo("ip lookup result: $ip\n"); $dst_host = rtrim($dst_host, '.'); // remove trailing dot if (match_network($config['autodiscovery']['nets-exclude'], $ip)) { - if ($debug) { - echo "$ip in an excluded network - skipping\n"; - } + d_echo("$ip in an excluded network - skipping\n"); return false; } @@ -77,9 +69,7 @@ function discover_new_device($hostname, $device='', $method='', $interface='') { } } else { - if ($debug) { - echo "$ip not in a matched network - skipping\n"; - } + d_echo("$ip not in a matched network - skipping\n"); }//end if }//end discover_new_device() @@ -161,11 +151,9 @@ function discover_device($device, $options=null) { function discover_sensor(&$valid, $class, $device, $oid, $index, $type, $descr, $divisor='1', $multiplier='1', $low_limit=null, $low_warn_limit=null, $warn_limit=null, $high_limit=null, $current=null, $poller_type='snmp', $entPhysicalIndex=null, $entPhysicalIndex_measured=null) { - global $config, $debug; + global $config; - if ($debug) { - echo "Discover sensor: $oid, $index, $type, $descr, $poller_type, $precision, $entPhysicalIndex\n"; - } + d_echo("Discover sensor: $oid, $index, $type, $descr, $poller_type, $precision, $entPhysicalIndex\n"); if (is_null($low_warn_limit) && !is_null($warn_limit)) { // Warn limits only make sense when we have both a high and a low limit @@ -218,9 +206,7 @@ function discover_sensor(&$valid, $class, $device, $oid, $index, $type, $descr, $inserted = dbInsert($insert, 'sensors'); - if ($debug) { - echo "( $inserted inserted )\n"; - } + d_echo("( $inserted inserted )\n"); echo '+'; log_event('Sensor Added: '.mres($class).' '.mres($type).' '.mres($index).' '.mres($descr), $device, 'sensor', $inserted); @@ -258,9 +244,7 @@ function discover_sensor(&$valid, $class, $device, $oid, $index, $type, $descr, if ($high_limit != $sensor_entry['sensor_limit'] && $sensor_entry['sensor_custom'] == 'No') { $update = array('sensor_limit' => ($high_limit == null ? array('NULL') : $high_limit)); $updated = dbUpdate($update, 'sensors', '`sensor_id` = ?', array($sensor_entry['sensor_id'])); - if ($debug) { - echo "( $updated updated )\n"; - } + d_echo("( $updated updated )\n"); echo 'H'; log_event('Sensor High Limit Updated: '.mres($class).' '.mres($type).' '.mres($index).' '.mres($descr).' ('.$high_limit.')', $device, 'sensor', $sensor_id); @@ -269,9 +253,7 @@ function discover_sensor(&$valid, $class, $device, $oid, $index, $type, $descr, if ($sensor_entry['sensor_limit_low'] != $low_limit && $sensor_entry['sensor_custom'] == 'No') { $update = array('sensor_limit_low' => ($low_limit == null ? array('NULL') : $low_limit)); $updated = dbUpdate($update, 'sensors', '`sensor_id` = ?', array($sensor_entry['sensor_id'])); - if ($debug) { - echo "( $updated updated )\n"; - } + d_echo("( $updated updated )\n"); echo 'L'; log_event('Sensor Low Limit Updated: '.mres($class).' '.mres($type).' '.mres($index).' '.mres($descr).' ('.$low_limit.')', $device, 'sensor', $sensor_id); @@ -280,9 +262,7 @@ function discover_sensor(&$valid, $class, $device, $oid, $index, $type, $descr, if ($warn_limit != $sensor_entry['sensor_limit_warn'] && $sensor_entry['sensor_custom'] == 'No') { $update = array('sensor_limit_warn' => ($warn_limit == null ? array('NULL') : $warn_limit)); $updated = dbUpdate($update, 'sensors', '`sensor_id` = ?', array($sensor_entry['sensor_id'])); - if ($debug) { - echo "( $updated updated )\n"; - } + d_echo("( $updated updated )\n"); echo 'WH'; log_event('Sensor Warn High Limit Updated: '.mres($class).' '.mres($type).' '.mres($index).' '.mres($descr).' ('.$warn_limit.')', $device, 'sensor', $sensor_id); @@ -291,9 +271,7 @@ function discover_sensor(&$valid, $class, $device, $oid, $index, $type, $descr, if ($sensor_entry['sensor_limit_low_warn'] != $low_warn_limit && $sensor_entry['sensor_custom'] == 'No') { $update = array('sensor_limit_low_warn' => ($low_warn_limit == null ? array('NULL') : $low_warn_limit)); $updated = dbUpdate($update, 'sensors', '`sensor_id` = ?', array($sensor_entry['sensor_id'])); - if ($debug) { - echo "( $updated updated )\n"; - } + d_echo("( $updated updated )\n"); echo 'WL'; log_event('Sensor Warn Low Limit Updated: '.mres($class).' '.mres($type).' '.mres($index).' '.mres($descr).' ('.$low_warn_limit.')', $device, 'sensor', $sensor_id); @@ -314,9 +292,7 @@ function discover_sensor(&$valid, $class, $device, $oid, $index, $type, $descr, $updated = dbUpdate($update, 'sensors', '`sensor_id` = ?', array($sensor_entry['sensor_id'])); echo 'U'; log_event('Sensor Updated: '.mres($class).' '.mres($type).' '.mres($index).' '.mres($descr), $device, 'sensor', $sensor_id); - if ($debug) { - echo "( $updated updated )\n"; - } + d_echo("( $updated updated )\n"); } }//end if $valid[$class][$type][$index] = 1; @@ -417,9 +393,7 @@ function check_valid_sensors($device, $class, $valid, $poller_type='snmp') { foreach ($entries as $entry) { $index = $entry['sensor_index']; $type = $entry['sensor_type']; - if ($debug) { - echo $index.' -> '.$type."\n"; - } + d_echo($index.' -> '.$type."\n"); if (!$valid[$class][$type][$index]) { echo '-'; @@ -436,13 +410,11 @@ function check_valid_sensors($device, $class, $valid, $poller_type='snmp') { function discover_juniAtmVp(&$valid, $port_id, $vp_id, $vp_descr) { - global $config, $debug; + global $config; if (dbFetchCell('SELECT COUNT(*) FROM `juniAtmVp` WHERE `port_id` = ? AND `vp_id` = ?', array($port_id, $vp_id)) == '0') { $inserted = dbInsert(array('port_id' => $port_id, 'vp_id' => $vp_id, 'vp_descr' => $vp_descr), 'juniAtmVp'); - if ($debug) { - echo "( $inserted inserted )\n"; - } + d_echo("( $inserted inserted )\n"); // FIXME vv no $device! log_event('Juniper ATM VP Added: port '.mres($port_id).' vp '.mres($vp_id).' descr'.mres($vp_descr), 'juniAtmVp', $inserted); @@ -457,7 +429,7 @@ function discover_juniAtmVp(&$valid, $port_id, $vp_id, $vp_descr) { function discover_link($local_port_id, $protocol, $remote_port_id, $remote_hostname, $remote_port, $remote_platform, $remote_version, $local_device_id, $remote_device_id) { - global $config, $debug, $link_exists; + global $config, $link_exists; d_echo("$local_port_id, $protocol, $remote_port_id, $remote_hostname, $remote_port, $remote_platform, $remote_version"); @@ -488,9 +460,7 @@ function discover_link($local_port_id, $protocol, $remote_port_id, $remote_hostn $inserted = dbInsert($insert_data, 'links'); echo '+'; - if ($debug) { - echo "( $inserted inserted )"; - } + d_echo("( $inserted inserted )"); } else { $data = dbFetchRow('SELECT * FROM `links` WHERE `remote_hostname` = ? AND `local_port_id` = ? AND `protocol` = ? AND `remote_port` = ?', array($remote_hostname, $local_port_id, $protocol, $remote_port)); @@ -512,9 +482,7 @@ function discover_link($local_port_id, $protocol, $remote_port_id, $remote_hostn $updated = dbUpdate($update_data, 'links', '`id` = ?', array($data['id'])); echo 'U'; - if ($debug) { - echo "( $updated updated )"; - } + d_echo("( $updated updated )"); }//end if }//end if $link_exists[$local_port_id][$remote_hostname][$remote_port] = 1; @@ -523,11 +491,9 @@ function discover_link($local_port_id, $protocol, $remote_port_id, $remote_hostn function discover_storage(&$valid, $device, $index, $type, $mib, $descr, $size, $units, $used=null) { - global $config, $debug; + global $config; - if ($debug) { - echo "$device, $index, $type, $mib, $descr, $units, $used, $size\n"; - } + d_echo("$device, $index, $type, $mib, $descr, $units, $used, $size\n"); if ($descr && $size > '0') { $storage = dbFetchRow('SELECT * FROM `storage` WHERE `storage_index` = ? AND `device_id` = ? AND `storage_mib` = ?', array($index, $device['device_id'], $mib)); @@ -565,11 +531,9 @@ function discover_storage(&$valid, $device, $index, $type, $mib, $descr, $size, function discover_processor(&$valid, $device, $oid, $index, $type, $descr, $precision='1', $current=null, $entPhysicalIndex=null, $hrDeviceIndex=null) { - global $config, $debug; + global $config; - if ($debug) { - echo "$device, $oid, $index, $type, $descr, $precision, $current, $entPhysicalIndex, $hrDeviceIndex\n"; - } + d_echo("$device, $oid, $index, $type, $descr, $precision, $current, $entPhysicalIndex, $hrDeviceIndex\n"); if ($descr) { $descr = trim(str_replace('"', '', $descr)); @@ -604,9 +568,7 @@ function discover_processor(&$valid, $device, $oid, $index, $type, $descr, $prec 'processor_precision' => $precision, ); dbUpdate($update_data, 'processors', '`device_id`=? AND `processor_index`=? AND `processor_type`=?', array($device['device_id'], $index, $type)); - if ($debug) { - print $query."\n"; - } + d_echo($query."\n"); }//end if $valid[$type][$index] = 1; }//end if @@ -615,11 +577,9 @@ function discover_processor(&$valid, $device, $oid, $index, $type, $descr, $prec function discover_mempool(&$valid, $device, $index, $type, $descr, $precision='1', $entPhysicalIndex=null, $hrDeviceIndex=null) { - global $config, $debug; + global $config; - if ($debug) { - echo "$device, $oid, $index, $type, $descr, $precision, $current, $entPhysicalIndex, $hrDeviceIndex\n"; - } + d_echo("$device, $oid, $index, $type, $descr, $precision, $current, $entPhysicalIndex, $hrDeviceIndex\n"); // FIXME implement the mempool_perc, mempool_used, etc. if ($descr) { @@ -663,9 +623,7 @@ function discover_mempool(&$valid, $device, $index, $type, $descr, $precision='1 } dbUpdate($update_data, 'mempools', 'device_id=? AND mempool_index=? AND mempool_type=?', array($device['device_id'], $index, $type)); - if ($debug) { - print $query."\n"; - } + d_echo($query."\n"); }//end if $valid[$type][$index] = 1; }//end if @@ -674,11 +632,9 @@ function discover_mempool(&$valid, $device, $index, $type, $descr, $precision='1 function discover_toner(&$valid, $device, $oid, $index, $type, $descr, $capacity_oid=null, $capacity=null, $current=null) { - global $config, $debug; + global $config; - if ($debug) { - echo "$oid, $index, $type, $descr, $capacity, $capacity_oid\n"; - } + d_echo("$oid, $index, $type, $descr, $capacity, $capacity_oid\n"); if (dbFetchCell('SELECT COUNT(toner_id) FROM `toner` WHERE device_id = ? AND toner_type = ? AND `toner_index` = ? AND `toner_capacity_oid` =?', array($device['device_id'], $type, $index, $capacity_oid)) == '0') { $inserted = dbInsert(array('device_id' => $device['device_id'], 'toner_oid' => $oid, 'toner_capacity_oid' => $capacity_oid, 'toner_index' => $index, 'toner_type' => $type, 'toner_descr' => $descr, 'toner_capacity' => $capacity, 'toner_current' => $current), 'toner'); diff --git a/includes/discovery/hr-device.inc.php b/includes/discovery/hr-device.inc.php index aa168da8c..a00ddc887 100644 --- a/includes/discovery/hr-device.inc.php +++ b/includes/discovery/hr-device.inc.php @@ -6,18 +6,14 @@ $hrDevice_oids = array( 'hrDeviceEntry', 'hrProcessorEntry', ); -if ($debug) { - print_r($hrDevices); -} +d_echo($hrDevices); $hrDevices = array(); foreach ($hrDevice_oids as $oid) { $hrDevices = snmpwalk_cache_oid($device, $oid, $hrDevices, 'HOST-RESOURCES-MIB:HOST-RESOURCES-TYPES'); } -if ($debug) { - print_r($hrDevices); -} +d_echo($hrDevices); if (is_array($hrDevices)) { $hrDevices = $hrDevices; @@ -40,10 +36,8 @@ if (is_array($hrDevices)) { else { $inserted_rows = dbInsert(array('hrDeviceIndex' => mres($hrDevice['hrDeviceIndex']), 'device_id' => mres($device['device_id']), 'hrDeviceType' => mres($hrDevice['hrDeviceType']), 'hrDeviceDescr' => mres($hrDevice['hrDeviceDescr']), 'hrDeviceStatus' => mres($hrDevice['hrDeviceStatus']), 'hrDeviceErrors' => (int) mres($hrDevice['hrDeviceErrors'])), 'hrDevice'); echo '+'; - if ($debug) { - print_r($hrDevice); - echo "$inserted_rows row inserted"; - } + d_echo($hrDevice); + d_echo("$inserted_rows row inserted"); }//end if $valid_hrDevice[$hrDevice['hrDeviceIndex']] = 1; @@ -57,9 +51,7 @@ foreach (dbFetchRows($sql) as $test_hrDevice) { if (!$valid_hrDevice[$test_hrDevice['hrDeviceIndex']]) { echo '-'; dbDelete('hrDevice', '`hrDevice_id` = ?', array($test_hrDevice['hrDevice_id'])); - if ($debug) { - print_r($test_hrDevice); - } + d_echo($test_hrDevice); } } diff --git a/includes/discovery/humidity.inc.php b/includes/discovery/humidity.inc.php index 69b3d9d97..d32be07e4 100644 --- a/includes/discovery/humidity.inc.php +++ b/includes/discovery/humidity.inc.php @@ -6,9 +6,7 @@ echo 'Humidity : '; $include_dir = 'includes/discovery/humidity'; require 'includes/include-dir.inc.php'; -if ($debug) { - print_r($valid['sensor']['humidity']); -} +d_echo($valid['sensor']['humidity']); check_valid_sensors($device, 'humidity', $valid['sensor']); diff --git a/includes/discovery/humidity/akcp.inc.php b/includes/discovery/humidity/akcp.inc.php index 07dc0864c..d32406ba2 100644 --- a/includes/discovery/humidity/akcp.inc.php +++ b/includes/discovery/humidity/akcp.inc.php @@ -2,9 +2,7 @@ if ($device['os'] == 'akcp' || $device['os'] == 'minkelsrms') { $oids = snmp_walk($device, '.1.3.6.1.4.1.3854.1.2.2.1.16.1.4', '-Osqn', ''); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); $oids = trim($oids); if ($oids) { diff --git a/includes/discovery/humidity/mgeups.inc.php b/includes/discovery/humidity/mgeups.inc.php index 3d524d259..0f15b3c24 100644 --- a/includes/discovery/humidity/mgeups.inc.php +++ b/includes/discovery/humidity/mgeups.inc.php @@ -1,7 +1,5 @@ Sensor not available diff --git a/includes/discovery/humidity/netbotz.inc.php b/includes/discovery/humidity/netbotz.inc.php index e4dd44dab..e3f686fd9 100644 --- a/includes/discovery/humidity/netbotz.inc.php +++ b/includes/discovery/humidity/netbotz.inc.php @@ -2,9 +2,7 @@ if ($device['os'] == 'netbotz') { $oids = snmp_walk($device, '.1.3.6.1.4.1.5528.100.4.1.2.1.4', '-Osqn', ''); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); $oids = trim($oids); if ($oids) { diff --git a/includes/discovery/humidity/sentry3.inc.php b/includes/discovery/humidity/sentry3.inc.php index c3e4ff440..e1417993c 100644 --- a/includes/discovery/humidity/sentry3.inc.php +++ b/includes/discovery/humidity/sentry3.inc.php @@ -4,9 +4,7 @@ if ($device['os'] == 'sentry3') { $oids = snmp_walk($device, 'tempHumidSensorHumidValue', '-Osqn', 'Sentry3-MIB'); $divisor = '1'; $multiplier = '1'; - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); $oids = trim($oids); if ($oids) { diff --git a/includes/discovery/junose-atm-vp.inc.php b/includes/discovery/junose-atm-vp.inc.php index 53916e8dc..f65320fcc 100644 --- a/includes/discovery/junose-atm-vp.inc.php +++ b/includes/discovery/junose-atm-vp.inc.php @@ -7,9 +7,7 @@ if ($device['os'] == 'junose' && $config['enable_ports_junoseatmvp']) { echo 'JunOSe ATM vps : '; $vp_array = snmpwalk_cache_multi_oid($device, 'juniAtmVpStatsInCells', $vp_array, 'Juniper-UNI-ATM-MIB', $config['install_dir'].'/mibs/junose'); $valid_vp = array(); - if ($debug) { - print_r($vp_array); - } + d_echo($vp_array); if (is_array($vp_array)) { foreach ($vp_array as $index => $entry) { @@ -28,16 +26,12 @@ if ($device['os'] == 'junose' && $config['enable_ports_junoseatmvp']) { // Remove ATM vps which weren't redetected here $sql = "SELECT * FROM `ports` AS P, `juniAtmVp` AS J WHERE P.`device_id` = '".$device['device_id']."' AND J.port_id = P.port_id"; - if ($debug) { - print_r($valid_vp); - } + d_echo($valid_vp); foreach (dbFetchRows($sql) as $test) { $port_id = $test['port_id']; $vp_id = $test['vp_id']; - if ($debug) { - echo $port_id.' -> '.$vp_id."\n"; - } + d_echo($port_id.' -> '.$vp_id."\n"); if (!$valid_vp[$port_id][$vp_id]) { echo '-'; diff --git a/includes/discovery/libvirt-vminfo.inc.php b/includes/discovery/libvirt-vminfo.inc.php index 38777b902..8825bf7b4 100644 --- a/includes/discovery/libvirt-vminfo.inc.php +++ b/includes/discovery/libvirt-vminfo.inc.php @@ -59,9 +59,7 @@ if ($config['enable_libvirt'] == '1' && $device['os'] == 'linux') { } $xml = simplexml_load_string(' '.$vm_info_xml); - if ($debug) { - print_r($xml); - } + d_echo($xml); $vmwVmDisplayName = $xml->name; $vmwVmGuestOS = ''; diff --git a/includes/discovery/load.inc.php b/includes/discovery/load.inc.php index aa28fe866..f09ae86e3 100644 --- a/includes/discovery/load.inc.php +++ b/includes/discovery/load.inc.php @@ -5,9 +5,7 @@ echo 'Load: '; $include_dir = 'includes/discovery/load'; require 'includes/include-dir.inc.php'; -if ($debug) { - print_r($valid['sensor']['load']); -} +d_echo($valid['sensor']['load']); check_valid_sensors($device, 'load', $valid['sensor']); diff --git a/includes/discovery/load/apc.inc.php b/includes/discovery/load/apc.inc.php index 39927b59f..1d0c7ce5e 100644 --- a/includes/discovery/load/apc.inc.php +++ b/includes/discovery/load/apc.inc.php @@ -30,9 +30,7 @@ if ($device['os'] == 'apc') { } if (!empty($oids)) { - if ($debug) { - print_r($oids); - } + d_echo($oids); $oids = trim($oids); if ($oids) { diff --git a/includes/discovery/load/rfc1628.inc.php b/includes/discovery/load/rfc1628.inc.php index c11522f45..01f006782 100644 --- a/includes/discovery/load/rfc1628.inc.php +++ b/includes/discovery/load/rfc1628.inc.php @@ -5,9 +5,7 @@ if (isset($config['modules_compat']['rfc1628'][$device['os']]) && $config['modul echo 'RFC1628 '; $oids = snmp_walk($device, '1.3.6.1.2.1.33.1.4.4.1.5', '-Osqn', 'UPS-MIB'); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); $oids = trim($oids); foreach (explode("\n", $oids) as $data) { diff --git a/includes/discovery/mempools.inc.php b/includes/discovery/mempools.inc.php index 9435b0207..b865b9f43 100644 --- a/includes/discovery/mempools.inc.php +++ b/includes/discovery/mempools.inc.php @@ -9,16 +9,12 @@ require 'includes/include-dir.inc.php'; // Remove memory pools which weren't redetected here $sql = "SELECT * FROM `mempools` WHERE `device_id` = '".$device['device_id']."'"; -if ($debug) { - print_r($valid_mempool); -} +d_echo($valid_mempool); foreach (dbFetchRows($sql) as $test_mempool) { $mempool_index = $test_mempool['mempool_index']; $mempool_type = $test_mempool['mempool_type']; - if ($debug) { - echo $mempool_index.' -> '.$mempool_type."\n"; - } + d_echo($mempool_index.' -> '.$mempool_type."\n"); if (!$valid_mempool[$mempool_type][$mempool_index]) { echo '-'; diff --git a/includes/discovery/mempools/junos.inc.php b/includes/discovery/mempools/junos.inc.php index f3a30c139..2a9ed6bd2 100644 --- a/includes/discovery/mempools/junos.inc.php +++ b/includes/discovery/mempools/junos.inc.php @@ -7,9 +7,7 @@ if ($device['os'] == 'junos') { $mempools_array = snmpwalk_cache_multi_oid($device, 'jnxOperatingDRAMSize', $mempools_array, 'JUNIPER-MIB', $config['install_dir'].'/mibs/junos'); $mempools_array = snmpwalk_cache_multi_oid($device, 'jnxOperatingMemory', $mempools_array, 'JUNIPER-MIB', $config['install_dir'].'/mibs/junos'); $mempools_array = snmpwalk_cache_multi_oid($device, 'jnxOperatingDescr', $mempools_array, 'JUNIPER-MIB', $config['install_dir'].'/mibs/junos'); - if ($debug) { - print_r($mempools_array); - } + d_echo($mempools_array); if (is_array($mempools_array)) { foreach ($mempools_array as $index => $entry) { @@ -18,9 +16,7 @@ if ($device['os'] == 'junos') { continue; } - if ($debug) { - echo $index.' '.$entry['jnxOperatingDescr'].' -> '.$entry['jnxOperatingBuffer'].' -> '.$entry['jnxOperatingDRAMSize']."\n"; - } + d_echo($index.' '.$entry['jnxOperatingDescr'].' -> '.$entry['jnxOperatingBuffer'].' -> '.$entry['jnxOperatingDRAMSize']."\n"); $usage_oid = '.1.3.6.1.4.1.2636.3.1.13.1.8.'.$index; $descr = $entry['jnxOperatingDescr']; diff --git a/includes/discovery/mempools/vrp.inc.php b/includes/discovery/mempools/vrp.inc.php index 180514368..ca06a851e 100644 --- a/includes/discovery/mempools/vrp.inc.php +++ b/includes/discovery/mempools/vrp.inc.php @@ -6,16 +6,12 @@ if ($device['os'] == 'vrp') { $mempools_array = snmpwalk_cache_multi_oid($device, 'hwEntityMemUsage', $mempools_array, 'HUAWEI-ENTITY-EXTENT-MIB', $config['install_dir'].'/mibs'); $mempools_array = snmpwalk_cache_multi_oid($device, 'hwEntityMemSize', $mempools_array, 'HUAWEI-ENTITY-EXTENT-MIB', $config['install_dir'].'/mibs'); $mempools_array = snmpwalk_cache_multi_oid($device, 'hwEntityBomEnDesc', $mempools_array, 'HUAWEI-ENTITY-EXTENT-MIB', $config['install_dir'].'/mibs'); - if ($debug) { - print_r($mempools_array); - } + d_echo($mempools_array); if (is_array($mempools_array)) { foreach ($mempools_array as $index => $entry) { if ($entry['hwEntityMemSize'] != 0) { - if ($debug) { - echo $index.' '.$entry['hwEntityBomEnDesc'].' -> '.$entry['hwEntityMemUsage'].' -> '.$entry['hwEntityMemSize']."\n"; - } + d_echo($index.' '.$entry['hwEntityBomEnDesc'].' -> '.$entry['hwEntityMemUsage'].' -> '.$entry['hwEntityMemSize']."\n"); $usage_oid = '.1.3.6.1.4.1.2011.5.25.31.1.1.1.1.7.'.$index; $descr = $entry['hwEntityBomEnDesc']; diff --git a/includes/discovery/ports.inc.php b/includes/discovery/ports.inc.php index 3a8a2eb60..32067fa05 100644 --- a/includes/discovery/ports.inc.php +++ b/includes/discovery/ports.inc.php @@ -7,9 +7,7 @@ $port_stats = snmpwalk_cache_oid($device, 'ifName', $port_stats, 'IF-MIB'); $port_stats = snmpwalk_cache_oid($device, 'ifType', $port_stats, 'IF-MIB'); // End Building SNMP Cache Array -if ($debug) { - print_r($port_stats); -} +d_echo($port_stats); // Build array of ports in the database // FIXME -- this stuff is a little messy, looping the array to make an array just seems wrong. :> diff --git a/includes/discovery/power.inc.php b/includes/discovery/power.inc.php index 2161e5ec2..d204c4b5c 100644 --- a/includes/discovery/power.inc.php +++ b/includes/discovery/power.inc.php @@ -6,9 +6,7 @@ echo 'Power: '; $include_dir = 'includes/discovery/power'; require 'includes/include-dir.inc.php'; -if ($debug) { - print_r($valid['sensor']['power']); -} +d_echo($valid['sensor']['power']); check_valid_sensors($device, 'power', $valid['sensor']); diff --git a/includes/discovery/power/rfc1628.inc.php b/includes/discovery/power/rfc1628.inc.php index 8816ff9b4..adaa5c918 100644 --- a/includes/discovery/power/rfc1628.inc.php +++ b/includes/discovery/power/rfc1628.inc.php @@ -5,9 +5,7 @@ if (isset($config['modules_compat']['rfc1628'][$device['os']]) && $config['modul echo("RFC1628 "); $oids = trim(snmp_walk($device, "1.3.6.1.2.1.33.1.4.3.0", "-OsqnU")); - if ($debug) { - echo($oids."\n"); - } + d_echo($oids."\n"); list($unused,$numPhase) = explode(' ',$oids); for($i = 1; $i <= $numPhase;$i++) { $current_oid = ".1.3.6.1.2.1.33.1.4.4.1.4.$i"; @@ -22,9 +20,7 @@ if (isset($config['modules_compat']['rfc1628'][$device['os']]) && $config['modul } $oids = trim(snmp_walk($device, "1.3.6.1.2.1.33.1.3.2.0", "-OsqnU")); - if ($debug) { - echo($oids."\n"); - } + d_echo($oids."\n"); list($unused,$numPhase) = explode(' ',$oids); for($i = 1; $i <= $numPhase;$i++) { $current_oid = "1.3.6.1.2.1.33.1.3.3.1.5.$i"; @@ -39,9 +35,7 @@ if (isset($config['modules_compat']['rfc1628'][$device['os']]) && $config['modul } $oids = trim(snmp_walk($device, "1.3.6.1.2.1.33.1.5.2.0", "-OsqnU")); - if ($debug) { - echo($oids."\n"); - } + d_echo($oids."\n"); list($unused,$numPhase) = explode(' ',$oids); for($i = 1; $i <= $numPhase;$i++) { $current_oid = ".1.3.6.1.2.1.33.1.5.3.1.4.$i"; diff --git a/includes/discovery/processors.inc.php b/includes/discovery/processors.inc.php index 3d0eb0cb4..c09501598 100644 --- a/includes/discovery/processors.inc.php +++ b/includes/discovery/processors.inc.php @@ -12,16 +12,12 @@ require 'processors-ucd-old.inc.php'; // Remove processors which weren't redetected here $sql = "SELECT * FROM `processors` WHERE `device_id` = '".$device['device_id']."'"; -if ($debug) { - print_r($valid['processor']); -} +d_echo($valid['processor']); foreach (dbFetchRows($sql) as $test_processor) { $processor_index = $test_processor['processor_index']; $processor_type = $test_processor['processor_type']; - if ($debug) { - echo $processor_index.' -> '.$processor_type."\n"; - } + d_echo($processor_index.' -> '.$processor_type."\n"); if (!$valid['processor'][$processor_type][$processor_index]) { echo '-'; diff --git a/includes/discovery/processors/hrdevice.inc.php b/includes/discovery/processors/hrdevice.inc.php index 2f6c152b7..97d021745 100644 --- a/includes/discovery/processors/hrdevice.inc.php +++ b/includes/discovery/processors/hrdevice.inc.php @@ -60,9 +60,7 @@ if (is_array($hrDevice_array)) { $old_rrd = $config['rrd_dir'].'/'.$device['hostname'].'/'.safename('hrProcessor-'.$index.'.rrd'); $new_rrd = $config['rrd_dir'].'/'.$device['hostname'].'/'.safename('processor-hr-'.$index.'.rrd'); - if ($debug) { - echo "$old_rrd $new_rrd"; - } + d_echo("$old_rrd $new_rrd"); if (is_file($old_rrd)) { rename($old_rrd, $new_rrd); diff --git a/includes/discovery/processors/ios.inc.php b/includes/discovery/processors/ios.inc.php index 36a18493f..4bcaa0ffa 100644 --- a/includes/discovery/processors/ios.inc.php +++ b/includes/discovery/processors/ios.inc.php @@ -3,9 +3,7 @@ if ($device['os_group'] == 'cisco' || $device['os'] == 'acsw') { echo 'CISCO-PROCESS-MIB: '; $processors_array = snmpwalk_cache_oid($device, 'cpmCPU', null, 'CISCO-PROCESS-MIB'); - if ($debug) { - print_r($processors_array); - } + d_echo($processors_array); foreach ($processors_array as $index => $entry) { if (is_numeric($entry['cpmCPUTotal5minRev']) || is_numeric($entry['cpmCPUTotal5min'])) { @@ -34,9 +32,7 @@ if ($device['os_group'] == 'cisco' || $device['os'] == 'acsw') { if (is_file($old_rrd)) { rename($old_rrd, $new_rrd); - if ($debug) { - echo "$old_rrd $new_rrd"; - } + d_echo("$old_rrd $new_rrd"); echo 'Moved RRD '; } diff --git a/includes/discovery/processors/ironware.inc.php b/includes/discovery/processors/ironware.inc.php index b3f995c87..7acb763d7 100644 --- a/includes/discovery/processors/ironware.inc.php +++ b/includes/discovery/processors/ironware.inc.php @@ -3,9 +3,7 @@ if ($device['os'] == 'ironware' || $device['os_group'] == 'ironware') { echo 'IronWare : '; $processors_array = snmpwalk_cache_triple_oid($device, 'snAgentCpuUtilEntry', $processors_array, 'FOUNDRY-SN-AGENT-MIB'); - if ($debug) { - print_r($processors_array); - } + d_echo($processors_array); foreach ($processors_array as $index => $entry) { if (($entry['snAgentCpuUtilValue'] || $entry['snAgentCpuUtil100thPercent']) && $entry['snAgentCpuUtilInterval'] == '300') { diff --git a/includes/discovery/processors/junos.inc.php b/includes/discovery/processors/junos.inc.php index d15c898f6..c66785ddc 100644 --- a/includes/discovery/processors/junos.inc.php +++ b/includes/discovery/processors/junos.inc.php @@ -7,9 +7,7 @@ if ($device['os'] == 'junos') { $processors_array = snmpwalk_cache_multi_oid($device, 'jnxOperatingDRAMSize', $processors_array, 'JUNIPER-MIB', '+'.$config['install_dir'].'/mibs/junos'); $processors_array = snmpwalk_cache_multi_oid($device, 'jnxOperatingMemory', $processors_array, 'JUNIPER-MIB', '+'.$config['install_dir'].'/mibs/junos'); $processors_array = snmpwalk_cache_multi_oid($device, 'jnxOperatingDescr', $processors_array, 'JUNIPER-MIB', '+'.$config['install_dir'].'/mibs/junos'); - if ($debug) { - print_r($processors_array); - } + d_echo($processors_array); if (is_array($processors_array)) { foreach ($processors_array as $index => $entry) { @@ -18,9 +16,7 @@ if ($device['os'] == 'junos') { continue; } - if ($debug) { - echo $index.' '.$entry['jnxOperatingDescr'].' -> '.$entry['jnxOperatingCPU'].' -> '.$entry['jnxOperatingDRAMSize']."\n"; - } + d_echo($index.' '.$entry['jnxOperatingDescr'].' -> '.$entry['jnxOperatingCPU'].' -> '.$entry['jnxOperatingDRAMSize']."\n"); $usage_oid = '.1.3.6.1.4.1.2636.3.1.13.1.8.'.$index; $descr = $entry['jnxOperatingDescr']; @@ -33,9 +29,7 @@ if ($device['os'] == 'junos') { } $srx_processors_array = snmpwalk_cache_multi_oid($device, 'jnxJsSPUMonitoringCPUUsage', $srx_processors_array, 'JUNIPER-SRX5000-SPU-MONITORING-MIB', '+'.$config['install_dir'].'/mibs/junos'); - if ($debug) { - print_r($processors_array); - } + d_echo($processors_array); if (is_array($srx_processors_array)) { foreach ($srx_processors_array as $index => $entry) { diff --git a/includes/discovery/processors/junose.inc.php b/includes/discovery/processors/junose.inc.php index 81fd03247..a0c997607 100644 --- a/includes/discovery/processors/junose.inc.php +++ b/includes/discovery/processors/junose.inc.php @@ -4,9 +4,7 @@ if ($device['os'] == 'junose') { echo 'JUNOSe : '; $processors_array = snmpwalk_cache_double_oid($device, 'juniSystemModule', $processors_array, 'Juniper-System-MIB', $config['install_dir'].'/mibs/junose'); - if ($debug) { - print_r($processors_array); - } + d_echo($processors_array); foreach ($processors_array as $index => $entry) { if ($entry['juniSystemModuleCpuUtilPct'] && $entry['juniSystemModuleCpuUtilPct'] != '-1') { diff --git a/includes/discovery/processors/vrp.inc.php b/includes/discovery/processors/vrp.inc.php index c8a17126b..3cdbcdf2e 100644 --- a/includes/discovery/processors/vrp.inc.php +++ b/includes/discovery/processors/vrp.inc.php @@ -6,16 +6,12 @@ if ($device['os'] == 'vrp') { $processors_array = snmpwalk_cache_multi_oid($device, 'hwEntityCpuUsage', $processors_array, 'HUAWEI-ENTITY-EXTENT-MIB', '+'.$config['install_dir'].'/mibs'); $processors_array = snmpwalk_cache_multi_oid($device, 'hwEntityMemSize', $processors_array, 'HUAWEI-ENTITY-EXTENT-MIB', '+'.$config['install_dir'].'/mibs'); $processors_array = snmpwalk_cache_multi_oid($device, 'hwEntityBomEnDesc', $processors_array, 'HUAWEI-ENTITY-EXTENT-MIB', '+'.$config['install_dir'].'/mibs'); - if ($debug) { - print_r($processors_array); - } + d_echo($processors_array); if (is_array($processors_array)) { foreach ($processors_array as $index => $entry) { if ($entry['hwEntityMemSize'] != 0) { - if ($debug) { - echo $index.' '.$entry['hwEntityBomEnDesc'].' -> '.$entry['hwEntityCpuUsage'].' -> '.$entry['hwEntityMemSize']."\n"; - } + d_echo($index.' '.$entry['hwEntityBomEnDesc'].' -> '.$entry['hwEntityCpuUsage'].' -> '.$entry['hwEntityMemSize']."\n"); $usage_oid = '.1.3.6.1.4.1.2011.5.25.31.1.1.1.1.5.'.$index; $descr = $entry['hwEntityBomEnDesc']; diff --git a/includes/discovery/states.inc.php b/includes/discovery/states.inc.php index 12a07296b..2eb1c740e 100644 --- a/includes/discovery/states.inc.php +++ b/includes/discovery/states.inc.php @@ -17,9 +17,7 @@ echo 'States: '; $include_dir = 'includes/discovery/states'; require 'includes/include-dir.inc.php'; -if ($debug) { - print_r($valid['sensor']['states']); -} +d_echo($valid['sensor']['states']); check_valid_sensors($device, 'states', $valid['sensor']); diff --git a/includes/discovery/states/dell.inc.php b/includes/discovery/states/dell.inc.php index c5c070a74..b8dca50df 100644 --- a/includes/discovery/states/dell.inc.php +++ b/includes/discovery/states/dell.inc.php @@ -15,9 +15,7 @@ if ($device['os'] == 'linux') { $oids = snmp_walk($device, 'virtualDiskNumber', '-Oesqn', 'StorageManagement-MIB'); $main_oid = '.1.3.6.1.4.1.674.10893.1.20.140.1.1.'; - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); $oids = trim($oids); if ($oids) { diff --git a/includes/discovery/states/drac.inc.php b/includes/discovery/states/drac.inc.php index 099599108..5e4c5eba8 100644 --- a/includes/discovery/states/drac.inc.php +++ b/includes/discovery/states/drac.inc.php @@ -15,9 +15,7 @@ if ($device['os'] == "drac") { $oids = snmp_walk($device, "virtualDiskNumber", "-Oesqn", "IDRAC-MIB-SMIv2"); $main_oid = ".1.3.6.1.4.1.674.10892.5.5.1.20.140.1.1."; - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); $oids = trim($oids); if ($oids) { echo "Dell iDRAC"; diff --git a/includes/discovery/states/rfc1628.inc.php b/includes/discovery/states/rfc1628.inc.php index 0a8a482fd..0dd8e6a14 100644 --- a/includes/discovery/states/rfc1628.inc.php +++ b/includes/discovery/states/rfc1628.inc.php @@ -5,9 +5,7 @@ if (isset($config['modules_compat']['rfc1628'][$device['os']]) && $config['modul echo 'RFC1628 '; $oids = snmp_walk($device, '1.3.6.1.2.1.33.1.2.2', '-Osqn', 'UPS-MIB'); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); $oids = trim($oids); foreach (explode("\n", $oids) as $data) { @@ -27,9 +25,7 @@ if (isset($config['modules_compat']['rfc1628'][$device['os']]) && $config['modul } $oids = snmp_walk($device, '1.3.6.1.2.1.33.1.2.3', '-Osqn', 'UPS-MIB'); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); $oids = trim($oids); foreach (explode("\n", $oids) as $data) { diff --git a/includes/discovery/storage.inc.php b/includes/discovery/storage.inc.php index b8b8fd7e3..d04817c9b 100644 --- a/includes/discovery/storage.inc.php +++ b/includes/discovery/storage.inc.php @@ -9,16 +9,12 @@ require 'includes/include-dir.inc.php'; // Remove storage which weren't redetected here $sql = "SELECT * FROM `storage` WHERE `device_id` = '".$device['device_id']."'"; -if ($debug) { - print_r($valid_storage); -} +d_echo($valid_storage); foreach (dbFetchRows($sql) as $test_storage) { $storage_index = $test_storage['storage_index']; $storage_mib = $test_storage['storage_mib']; - if ($debug) { - echo $storage_index.' -> '.$storage_mib."\n"; - } + d_echo($storage_index.' -> '.$storage_mib."\n"); if (!$valid_storage[$storage_mib][$storage_index]) { echo '-'; diff --git a/includes/discovery/storage/hrstorage.inc.php b/includes/discovery/storage/hrstorage.inc.php index f32a48faa..46907e10a 100644 --- a/includes/discovery/storage/hrstorage.inc.php +++ b/includes/discovery/storage/hrstorage.inc.php @@ -36,49 +36,37 @@ if (is_array($hrstorage_array)) { foreach ($config['ignore_mount'] as $bi) { if ($bi == $descr) { $deny = 1; - if ($debug) { - echo "$bi == $descr \n"; - } + d_echo("$bi == $descr \n"); } } foreach ($config['ignore_mount_string'] as $bi) { if (strpos($descr, $bi) !== false) { $deny = 1; - if ($debug) { - echo "strpos: $descr, $bi \n"; - } + d_echo("strpos: $descr, $bi \n"); } } foreach ($config['ignore_mount_regexp'] as $bi) { if (preg_match($bi, $descr) > '0') { $deny = 1; - if ($debug) { - echo "preg_match $bi, $descr \n"; - } + d_echo("preg_match $bi, $descr \n"); } } if (isset($config['ignore_mount_removable']) && $config['ignore_mount_removable'] && $fstype == 'hrStorageRemovableDisk') { $deny = 1; - if ($debug) { - echo "skip(removable)\n"; - } + d_echo("skip(removable)\n"); } if (isset($config['ignore_mount_network']) && $config['ignore_mount_network'] && $fstype == 'hrStorageNetworkDisk') { $deny = 1; - if ($debug) { - echo "skip(network)\n"; - } + d_echo("skip(network)\n"); } if (isset($config['ignore_mount_optical']) && $config['ignore_mount_optical'] && $fstype == 'hrStorageCompactDisc') { $deny = 1; - if ($debug) { - echo "skip(cd)\n"; - } + d_echo("skip(cd)\n"); } if (!$deny && is_numeric($index)) { diff --git a/includes/discovery/storage/netapp-storage.inc.php b/includes/discovery/storage/netapp-storage.inc.php index 83709c07f..49cd0d803 100644 --- a/includes/discovery/storage/netapp-storage.inc.php +++ b/includes/discovery/storage/netapp-storage.inc.php @@ -20,27 +20,21 @@ if (is_array($netapp_storage)) { foreach ($config['ignore_mount'] as $bi) { if ($bi == $descr) { $deny = 1; - if ($debug) { - echo "$bi == $descr \n"; - } + d_echo("$bi == $descr \n"); } } foreach ($config['ignore_mount_string'] as $bi) { if (strpos($descr, $bi) !== false) { $deny = 1; - if ($debug) { - echo "strpos: $descr, $bi \n"; - } + d_echo("strpos: $descr, $bi \n"); } } foreach ($config['ignore_mount_regexp'] as $bi) { if (preg_match($bi, $descr) > '0') { $deny = 1; - if ($debug) { - echo "preg_match $bi, $descr \n"; - } + d_echo("preg_match $bi, $descr \n"); } } diff --git a/includes/discovery/temperatures.inc.php b/includes/discovery/temperatures.inc.php index 25f385500..60e01b0ba 100644 --- a/includes/discovery/temperatures.inc.php +++ b/includes/discovery/temperatures.inc.php @@ -6,9 +6,7 @@ echo 'Temperatures: '; $include_dir = 'includes/discovery/temperatures'; require 'includes/include-dir.inc.php'; -if ($debug) { - print_r($valid['sensor']['temperature']); -} +d_echo($valid['sensor']['temperature']); check_valid_sensors($device, 'temperature', $valid['sensor']); diff --git a/includes/discovery/temperatures/akcp.inc.php b/includes/discovery/temperatures/akcp.inc.php index 76602e418..b60e9ab87 100644 --- a/includes/discovery/temperatures/akcp.inc.php +++ b/includes/discovery/temperatures/akcp.inc.php @@ -2,9 +2,7 @@ if ($device['os'] == 'akcp' || $device['os'] == 'minkelsrms') { $oids = snmp_walk($device, '.1.3.6.1.4.1.3854.1.2.2.1.16.1.4', '-Osqn', ''); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); $oids = trim($oids); if ($oids) { diff --git a/includes/discovery/temperatures/apc.inc.php b/includes/discovery/temperatures/apc.inc.php index 93aa89dd9..4c7d53cc9 100644 --- a/includes/discovery/temperatures/apc.inc.php +++ b/includes/discovery/temperatures/apc.inc.php @@ -2,9 +2,7 @@ if ($device['os'] == 'apc') { $oids = snmp_get($device, '1.3.6.1.4.1.318.1.1.1.2.2.2.0', '-OsqnU', ''); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); if ($oids) { echo 'APC UPS Internal '; @@ -77,10 +75,8 @@ if ($device['os'] == 'apc') { $set_oids = snmp_get($device, '1.3.6.1.4.1.318.1.1.13.2.2.4.0', '-OsqnU', ''); $oids = snmp_get($device, '1.3.6.1.4.1.318.1.1.13.2.2.10.0', '-OsqnU', ''); - if ($debug) { - echo $set_oids."\n"; - echo $oids."\n"; - } + d_echo($oids."\n"); + d_echo($set_oids."\n"); if ($oids !== false) { echo 'APC Portable Supply Temp '; @@ -103,9 +99,7 @@ if ($device['os'] == 'apc') { unset($oids); $oids = snmp_get($device, '1.3.6.1.4.1.318.1.1.13.2.2.12.0', '-OsqnU', ''); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); if ($oids !== false) { echo 'APC Portable Return Temp '; @@ -128,10 +122,7 @@ if ($device['os'] == 'apc') { unset($oids); $oids = snmp_get($device, '1.3.6.1.4.1.318.1.1.13.2.2.14.0', '-OsqnU', ''); - if ($debug) { - echo $oids."\n"; - } - + d_echo($oids."\n"); if ($oids !== false) { echo 'APC Portable Remote Temp '; list($oid,$current_raw) = explode(' ', $oids); diff --git a/includes/discovery/temperatures/areca.inc.php b/includes/discovery/temperatures/areca.inc.php index beffb9dd4..a286ad62f 100644 --- a/includes/discovery/temperatures/areca.inc.php +++ b/includes/discovery/temperatures/areca.inc.php @@ -2,9 +2,7 @@ if ($device['os'] == 'areca') { $oids = snmp_walk($device, '1.3.6.1.4.1.18928.1.1.2.14.1.2', '-Osqn', ''); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); $oids = trim($oids); if ($oids) { @@ -29,9 +27,7 @@ if ($device['os'] == 'areca') { } $oids = snmp_walk($device, '1.3.6.1.4.1.18928.1.2.2.1.10.1.2', '-OsqnU', ''); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); if ($oids) { echo 'Areca Controller '; diff --git a/includes/discovery/temperatures/cometsystem-p85xx.inc.php b/includes/discovery/temperatures/cometsystem-p85xx.inc.php index 4049e00fb..28e8f0908 100644 --- a/includes/discovery/temperatures/cometsystem-p85xx.inc.php +++ b/includes/discovery/temperatures/cometsystem-p85xx.inc.php @@ -14,7 +14,6 @@ if ($device['os'] == 'cometsystem-p85xx') { /x'; $oids = snmp_walk($device, '.1.3.6.1.4.1.22626.1.5.2', '-OsqnU', ''); - // if ($debug) { echo($oids."\n"); } if ($oids) { $out = array(); foreach (explode("\n", $oids) as $line) { diff --git a/includes/discovery/temperatures/dell.inc.php b/includes/discovery/temperatures/dell.inc.php index acddb2cbc..dcf6a3b9c 100644 --- a/includes/discovery/temperatures/dell.inc.php +++ b/includes/discovery/temperatures/dell.inc.php @@ -27,9 +27,7 @@ if (strstr($device['hardware'], 'Dell')) { // stuff partially copied from akcp sensor $oids = snmp_walk($device, 'temperatureProbeStatus', '-Osqn', 'MIB-Dell-10892'); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); $oids = trim($oids); if ($oids) { @@ -40,9 +38,7 @@ if (strstr($device['hardware'], 'Dell')) { $data = trim($data); if ($data) { list($oid,$status) = explode(' ', $data, 2); - if ($debug) { - echo 'status : '.$status."\n"; - } + d_echo('status : '.$status."\n"); if ($status == 'ok') { // 2 = normal, 0 = not connected diff --git a/includes/discovery/temperatures/drac.inc.php b/includes/discovery/temperatures/drac.inc.php index 1edc63b53..3687db6c9 100644 --- a/includes/discovery/temperatures/drac.inc.php +++ b/includes/discovery/temperatures/drac.inc.php @@ -13,9 +13,7 @@ if (strstr($device['os'], 'drac')) { $oids = snmp_walk($device, 'temperatureProbeStatus', '-Osqn', 'IDRAC-MIB-SMIv2'); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); $oids = trim($oids); if ($oids) { @@ -26,9 +24,7 @@ if (strstr($device['os'], 'drac')) { $data = trim($data); if ($data) { list($oid,$status) = explode(' ', $data, 2); - if ($debug) { - echo 'status : '.$status."\n"; - } + d_echo('status : '.$status."\n"); if ($status == 'ok') { $split_oid = explode('.', $oid); diff --git a/includes/discovery/temperatures/lm-sensors.inc.php b/includes/discovery/temperatures/lm-sensors.inc.php index 1df73f023..1482b356c 100644 --- a/includes/discovery/temperatures/lm-sensors.inc.php +++ b/includes/discovery/temperatures/lm-sensors.inc.php @@ -2,9 +2,7 @@ if ($device['os'] == 'linux') { $oids = snmp_walk($device, 'lmTempSensorsDevice', '-Osqn', 'LM-SENSORS-MIB'); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); $oids = trim($oids); if ($oids) { diff --git a/includes/discovery/temperatures/mgeups.inc.php b/includes/discovery/temperatures/mgeups.inc.php index 269664697..4c6e7a478 100644 --- a/includes/discovery/temperatures/mgeups.inc.php +++ b/includes/discovery/temperatures/mgeups.inc.php @@ -1,7 +1,5 @@ $entry) { if ($entry['diskIONRead'] > '0' || $entry['diskIONWritten'] > '0') { - if ($debug) { - echo "$index ".$entry['diskIODevice']."\n"; - } + d_echo("$index ".$entry['diskIODevice']."\n"); if (dbFetchCell('SELECT COUNT(*) FROM `ucd_diskio` WHERE `device_id` = ? AND `diskio_index` = ?', array($device['device_id'], $index)) == '0') { $inserted = dbInsert(array('device_id' => $device['device_id'], 'diskio_index' => $index, 'diskio_descr' => $entry['diskIODevice']), 'ucd_diskio'); echo '+'; - if ($debug) { - echo $sql." - $inserted inserted "; - } + d_echo($sql." - $inserted inserted "); } else { echo '.'; @@ -31,14 +26,10 @@ if (is_array($diskio_array)) { // Remove diskio entries which weren't redetected here $sql = "SELECT * FROM `ucd_diskio` where `device_id` = '".$device['device_id']."'"; -if ($debug) { - print_r($valid_diskio); -} +d_echo($valid_diskio); foreach (dbFetchRows($sql) as $test) { - if ($debug) { - echo $test['diskio_index'].' -> '.$test['diskio_descr']."\n"; - } + d_echo($test['diskio_index'].' -> '.$test['diskio_descr']."\n"); if (!$valid_diskio[$test['diskio_index']]) { echo '-'; diff --git a/includes/discovery/voltages.inc.php b/includes/discovery/voltages.inc.php index d91fe5d4e..5ce7b438d 100644 --- a/includes/discovery/voltages.inc.php +++ b/includes/discovery/voltages.inc.php @@ -6,9 +6,7 @@ echo 'Voltages: '; $include_dir = 'includes/discovery/voltages'; require 'includes/include-dir.inc.php'; -if ($debug) { - print_r($valid['sensor']['voltage']); -} +d_echo($valid['sensor']['voltage']); check_valid_sensors($device, 'voltage', $valid['sensor']); diff --git a/includes/discovery/voltages/apc.inc.php b/includes/discovery/voltages/apc.inc.php index b309d21fb..a45b7027a 100644 --- a/includes/discovery/voltages/apc.inc.php +++ b/includes/discovery/voltages/apc.inc.php @@ -3,9 +3,7 @@ // APC Voltages if ($device['os'] == 'apc') { $oids = snmp_walk($device, '1.3.6.1.4.1.318.1.1.8.5.3.3.1.3', '-OsqnU', ''); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); if ($oids) { echo 'APC In '; @@ -27,9 +25,7 @@ if ($device['os'] == 'apc') { } $oids = snmp_walk($device, '1.3.6.1.4.1.318.1.1.8.5.4.3.1.3', '-OsqnU', ''); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); if ($oids) { echo ' APC Out '; @@ -54,9 +50,7 @@ if ($device['os'] == 'apc') { } $oids = snmp_get($device, '1.3.6.1.4.1.318.1.1.1.3.2.1.0', '-OsqnU', ''); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); if ($oids) { echo ' APC In '; @@ -70,9 +64,7 @@ if ($device['os'] == 'apc') { } $oids = snmp_get($device, '1.3.6.1.4.1.318.1.1.1.4.2.1.0', '-OsqnU', ''); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); if ($oids) { echo ' APC Out '; @@ -88,9 +80,7 @@ if ($device['os'] == 'apc') { // PDU // $oids = snmp_get($device, "1.3.6.1.4.1.318.1.1.12.1.15.0", "-OsqnU", ""); $oids = snmp_walk($device, 'rPDUIdentDeviceLinetoLineVoltage.0', '-OsqnU', 'PowerNet-MIB'); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); if ($oids) { echo ' Voltage In '; @@ -104,9 +94,7 @@ if ($device['os'] == 'apc') { } $oids = snmp_walk($device, '1.3.6.1.4.1.318.1.1.26.6.3.1.6', '-OsqnU', 'PowerNet-MIB'); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); if ($oids) { echo ' Voltage In '; diff --git a/includes/discovery/voltages/areca.inc.php b/includes/discovery/voltages/areca.inc.php index 258203a80..0958f3b50 100644 --- a/includes/discovery/voltages/areca.inc.php +++ b/includes/discovery/voltages/areca.inc.php @@ -3,9 +3,7 @@ // Areca Voltages if ($device['os'] == 'areca') { $oids = snmp_walk($device, '1.3.6.1.4.1.18928.1.2.2.1.8.1.2', '-OsqnU', ''); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); if ($oids) { echo 'Areca '; diff --git a/includes/discovery/voltages/drac.inc.php b/includes/discovery/voltages/drac.inc.php index e94ce8f02..f009a74cb 100644 --- a/includes/discovery/voltages/drac.inc.php +++ b/includes/discovery/voltages/drac.inc.php @@ -2,9 +2,7 @@ if ($device['os'] == "drac") { $oids = snmp_walk($device, "powerSupplyIndex.1", "-OsqnU", "IDRAC-MIB-SMIv2"); - if ($debug) { - echo($oids."\n"); - } + d_echo($oids."\n"); $oids = trim($oids); if ($oids) { echo("Dell iDRAC"); diff --git a/includes/discovery/voltages/linux.inc.php b/includes/discovery/voltages/linux.inc.php index f599f02ee..061594ede 100644 --- a/includes/discovery/voltages/linux.inc.php +++ b/includes/discovery/voltages/linux.inc.php @@ -3,9 +3,7 @@ // LMSensors Voltages if ($device['os'] == 'linux') { $oids = snmp_walk($device, 'lmVoltSensorsDevice', '-OsqnU', 'LM-SENSORS-MIB'); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); if ($oids) { echo 'LM-SENSORS '; diff --git a/includes/discovery/voltages/mgeups.inc.php b/includes/discovery/voltages/mgeups.inc.php index 6e715b995..b31cba73c 100644 --- a/includes/discovery/voltages/mgeups.inc.php +++ b/includes/discovery/voltages/mgeups.inc.php @@ -4,9 +4,7 @@ if ($device['os'] == 'mgeups') { echo 'MGE '; $oids = trim(snmp_walk($device, 'mgoutputVoltage', '-OsqnU', 'MG-SNMP-UPS-MIB')); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); $numPhase = count(explode("\n", $oids)); for ($i = 1; $i <= $numPhase; $i++) { @@ -31,9 +29,7 @@ if ($device['os'] == 'mgeups') { } $oids = trim(snmp_walk($device, 'mgeinputVoltage', '-OsqnU', 'MG-SNMP-UPS-MIB')); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); $numPhase = count(explode("\n", $oids)); for ($i = 1; $i <= $numPhase; $i++) { diff --git a/includes/discovery/voltages/mikrotik.inc.php b/includes/discovery/voltages/mikrotik.inc.php index 23bff12ad..0127469e0 100644 --- a/includes/discovery/voltages/mikrotik.inc.php +++ b/includes/discovery/voltages/mikrotik.inc.php @@ -2,9 +2,7 @@ if ($device['os'] == "routeros") { $oids = snmp_walk($device, "mtxrHlVoltage", "-OsqnU", "MIKROTIK-MIB"); - if ($debug) { - echo($oids."\n"); - } + d_echo($oids."\n"); if ($oids !== false) echo("MIKROTIK-MIB "); $divisor = 10.0; $type = "mikrotik"; diff --git a/includes/discovery/voltages/rfc1628.inc.php b/includes/discovery/voltages/rfc1628.inc.php index 4c1f654d6..a89efbbd1 100644 --- a/includes/discovery/voltages/rfc1628.inc.php +++ b/includes/discovery/voltages/rfc1628.inc.php @@ -5,9 +5,7 @@ if (isset($config['modules_compat']['rfc1628'][$device['os']]) && $config['modul echo 'RFC1628 '; $oids = snmp_walk($device, '1.3.6.1.2.1.33.1.2.5', '-Osqn', 'UPS-MIB'); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); $oids = trim($oids); foreach (explode("\n", $oids) as $data) { @@ -31,9 +29,7 @@ if (isset($config['modules_compat']['rfc1628'][$device['os']]) && $config['modul } $oids = trim(snmp_walk($device, '1.3.6.1.2.1.33.1.4.3.0', '-OsqnU')); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); list($unused,$numPhase) = explode(' ', $oids); for ($i = 1; $i <= $numPhase; $i++) { @@ -55,9 +51,7 @@ if (isset($config['modules_compat']['rfc1628'][$device['os']]) && $config['modul } $oids = trim(snmp_walk($device, '1.3.6.1.2.1.33.1.3.2.0', '-OsqnU')); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); list($unused,$numPhase) = explode(' ', $oids); for ($i = 1; $i <= $numPhase; $i++) { @@ -79,9 +73,7 @@ if (isset($config['modules_compat']['rfc1628'][$device['os']]) && $config['modul } $oids = trim(snmp_walk($device, '1.3.6.1.2.1.33.1.5.2.0', '-OsqnU')); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); list($unused,$numPhase) = explode(' ', $oids); for ($i = 1; $i <= $numPhase; $i++) { diff --git a/includes/discovery/voltages/sentry3.inc.php b/includes/discovery/voltages/sentry3.inc.php index e2d704322..7ccebb3e7 100644 --- a/includes/discovery/voltages/sentry3.inc.php +++ b/includes/discovery/voltages/sentry3.inc.php @@ -2,9 +2,7 @@ if ($device['os'] == 'sentry3') { $oids = snmp_walk($device, 'infeedVoltage', '-OsqnU', 'Sentry3-MIB'); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); if ($oids) { echo 'Sentry3-MIB '; diff --git a/includes/discovery/voltages/siklu.inc.php b/includes/discovery/voltages/siklu.inc.php index 867d0bd30..c80b2e75d 100644 --- a/includes/discovery/voltages/siklu.inc.php +++ b/includes/discovery/voltages/siklu.inc.php @@ -3,9 +3,7 @@ if ($device['os'] == 'siklu') { $oid = 'rbSysVoltage.0'; $oids = snmp_walk($device, "$oid", '-OsqnU', 'RADIO-BRIDGE-MIB'); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); if (!empty($oids)) { echo 'Siklu Voltage '; diff --git a/includes/discovery/voltages/supermicro.inc.php b/includes/discovery/voltages/supermicro.inc.php index 690d34747..21fc75f8a 100644 --- a/includes/discovery/voltages/supermicro.inc.php +++ b/includes/discovery/voltages/supermicro.inc.php @@ -3,9 +3,7 @@ // Supermicro Voltages if ($device['os'] == 'linux') { $oids = snmp_walk($device, '1.3.6.1.4.1.10876.2.1.1.1.1.3', '-OsqnU', 'SUPERMICRO-HEALTH-MIB'); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); $oids = trim($oids); if ($oids) { diff --git a/includes/discovery/voltages/xups.inc.php b/includes/discovery/voltages/xups.inc.php index b01a94341..8b26b3c08 100644 --- a/includes/discovery/voltages/xups.inc.php +++ b/includes/discovery/voltages/xups.inc.php @@ -6,9 +6,7 @@ if ($device['os'] == 'powerware') { // XUPS-MIB::xupsBatVoltage.0 = INTEGER: 51 $oids = snmp_walk($device, 'xupsBatVoltage', '-Osqn', 'XUPS-MIB'); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); $oids = trim($oids); foreach (explode("\n", $oids) as $data) { @@ -30,9 +28,7 @@ if ($device['os'] == 'powerware') { // XUPS-MIB::xupsInputNumPhases.0 = INTEGER: 1 $oids = trim(snmp_walk($device, 'xupsInputNumPhases', '-OsqnU', 'XUPS-MIB')); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); list($unused,$numPhase) = explode(' ', $oids); for ($i = 1; $i <= $numPhase; $i++) { @@ -53,9 +49,7 @@ if ($device['os'] == 'powerware') { // XUPS-MIB::xupsOutputNumPhases.0 = INTEGER: 1 $oids = trim(snmp_walk($device, 'xupsOutputNumPhases', '-OsqnU')); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); list($unused,$numPhase) = explode(' ', $oids); for ($i = 1; $i <= $numPhase; $i++) { @@ -76,9 +70,7 @@ if ($device['os'] == 'powerware') { // XUPS-MIB::xupsBypassNumPhases.0 = INTEGER: 1 $oids = trim(snmp_walk($device, 'xupsBypassNumPhases', '-OsqnU')); - if ($debug) { - echo $oids."\n"; - } + d_echo($oids."\n"); list($unused,$numPhase) = explode(' ', $oids); for ($i = 1; $i <= $numPhase; $i++) { From 4792879ce5d93f5b0b6faf324bb8af91cc1a2a82 Mon Sep 17 00:00:00 2001 From: Mark Schouten Date: Thu, 20 Aug 2015 16:06:44 +0200 Subject: [PATCH 021/598] Remove all unneeded if($debug)-statements and replace them with d_echo in the rest of the directories... --- discovery.php | 4 +--- includes/alerts.inc.php | 1 - includes/common.php | 10 ++-------- includes/definitions.inc.php | 4 +--- includes/functions.php | 30 +++++++++--------------------- includes/include-dir.inc.php | 4 +--- includes/port-descr-parser.inc.php | 4 +--- includes/rrdtool.inc.php | 16 +++++----------- includes/sql-schema/update.php | 4 +--- poller.php | 4 +--- 10 files changed, 22 insertions(+), 59 deletions(-) diff --git a/discovery.php b/discovery.php index 336f91ad0..c70878054 100755 --- a/discovery.php +++ b/discovery.php @@ -118,9 +118,7 @@ if ($discovered_devices) { } $string = $argv[0]." $doing ".date($config['dateformat']['compact'])." - $discovered_devices devices discovered in $proctime secs"; -if ($debug) { - echo "$string\n"; -} +d_echo("$string\n"); if ($options['h'] != 'new' && $config['version_check']) { include 'includes/versioncheck.inc.php'; diff --git a/includes/alerts.inc.php b/includes/alerts.inc.php index 1d5c5c91c..f57c102b3 100644 --- a/includes/alerts.inc.php +++ b/includes/alerts.inc.php @@ -220,7 +220,6 @@ function IsMaintenance( $device ) { * @return void */ function RunRules($device) { - global $debug; if( IsMaintenance($device) > 0 ) { echo "Under Maintenance, Skipping alerts.\r\n"; return false; diff --git a/includes/common.php b/includes/common.php index 03b239e85..32e6e65af 100644 --- a/includes/common.php +++ b/includes/common.php @@ -33,15 +33,9 @@ function format_number_short($number, $sf) { } function external_exec($command) { - global $debug; - - if ($debug) { - echo($command."\n"); - } + d_echo($command."\n"); $output = shell_exec($command); - if ($debug) { - echo($output."\n"); - } + d_echo($output."\n"); return $output; } diff --git a/includes/definitions.inc.php b/includes/definitions.inc.php index 0fc20c740..11151148c 100644 --- a/includes/definitions.inc.php +++ b/includes/definitions.inc.php @@ -1664,9 +1664,7 @@ if ($config['memcached']['enable'] === true) { if (class_exists('Memcached')) { $memcache = new Memcached(); $memcache->addServer($config['memcached']['host'], $config['memcached']['port']); - if ($debug) { - print_r($memcache->getStats()); - } + d_echo($memcache->getStats()); } else { echo "WARNING: You have enabled memcached but have not installed the PHP bindings. Disabling memcached support.\n"; diff --git a/includes/functions.php b/includes/functions.php index 10499c086..0027748ee 100644 --- a/includes/functions.php +++ b/includes/functions.php @@ -95,14 +95,12 @@ function logfile($string) { } function getHostOS($device){ - global $config, $debug; + global $config; $sysDescr = snmp_get ($device, "SNMPv2-MIB::sysDescr.0", "-Ovq"); $sysObjectId = snmp_get ($device, "SNMPv2-MIB::sysObjectID.0", "-Ovqn"); - if ($debug) { - echo("| $sysDescr | $sysObjectId | "); - } + d_echo("| $sysDescr | $sysObjectId | "); $path = $config['install_dir'] . "/includes/discovery/os"; $dir_handle = @opendir($path) or die("Unable to open $path"); @@ -698,8 +696,6 @@ function get_astext($asn) { # Use this function to write to the eventlog table function log_event($text, $device = NULL, $type = NULL, $reference = NULL) { - global $debug; - if (!is_array($device)) { $device = device_by_id_cache($device); } @@ -830,7 +826,7 @@ function isHexString($str) { # Include all .inc.php files in $dir function include_dir($dir, $regex = "") { - global $device, $config, $debug, $valid; + global $device, $config, $valid; if ($regex == "") { $regex = "/\.inc\.php$/"; @@ -839,9 +835,7 @@ function include_dir($dir, $regex = "") { if ($handle = opendir($config['install_dir'] . '/' . $dir)) { while (false !== ($file = readdir($handle))) { if (filetype($config['install_dir'] . '/' . $dir . '/' . $file) == 'file' && preg_match($regex, $file)) { - if ($debug) { - echo("Including: " . $config['install_dir'] . '/' . $dir . '/' . $file . "\n"); - } + d_echo("Including: " . $config['install_dir'] . '/' . $dir . '/' . $file . "\n"); include($config['install_dir'] . '/' . $dir . '/' . $file); } @@ -853,7 +847,7 @@ function include_dir($dir, $regex = "") { function is_port_valid($port, $device) { - global $config, $debug; + global $config; if (strstr($port['ifDescr'], "irtual")) { $valid = 0; @@ -868,9 +862,7 @@ function is_port_valid($port, $device) { foreach ($fringe as $bi) { if (strstr($if, $bi)) { $valid = 0; - if ($debug) { - echo("ignored : $bi : $if"); - } + d_echo("ignored : $bi : $if"); } } if (is_array($config['bad_if_regexp'])) { @@ -881,9 +873,7 @@ function is_port_valid($port, $device) { foreach ($fringe as $bi) { if (preg_match($bi ."i", $if)) { $valid = 0; - if ($debug) { - echo("ignored : $bi : ".$if); - } + d_echo("ignored : $bi : ".$if); } } } @@ -895,9 +885,7 @@ function is_port_valid($port, $device) { foreach ($fringe as $bi) { if (strstr($port['ifType'], $bi)) { $valid = 0; - if ($debug) { - echo("ignored ifType : ".$port['ifType']." (matched: ".$bi." )"); - } + d_echo("ignored ifType : ".$port['ifType']." (matched: ".$bi." )"); } } } @@ -917,7 +905,7 @@ function is_port_valid($port, $device) { function scan_new_plugins() { - global $config, $debug; + global $config; $installed = 0; // Track how many plugins we install. diff --git a/includes/include-dir.inc.php b/includes/include-dir.inc.php index d5c0a7eab..2d6c1456d 100644 --- a/includes/include-dir.inc.php +++ b/includes/include-dir.inc.php @@ -8,9 +8,7 @@ if ($include_dir_regexp == '' || !isset($include_dir_regexp)) { if ($handle = opendir($config['install_dir'].'/'.$include_dir)) { while (false !== ($file = readdir($handle))) { if (filetype($config['install_dir'].'/'.$include_dir.'/'.$file) == 'file' && preg_match($include_dir_regexp, $file)) { - if ($debug) { - echo 'Including: '.$config['install_dir'].'/'.$include_dir.'/'.$file."\n"; - } + d_echo('Including: '.$config['install_dir'].'/'.$include_dir.'/'.$file."\n"); include $config['install_dir'].'/'.$include_dir.'/'.$file; } diff --git a/includes/port-descr-parser.inc.php b/includes/port-descr-parser.inc.php index 2b0f475aa..144790c12 100644 --- a/includes/port-descr-parser.inc.php +++ b/includes/port-descr-parser.inc.php @@ -20,9 +20,7 @@ if ($type && $descr) { $port_ifAlias['speed'] = $speed; $port_ifAlias['notes'] = $notes; - if ($debug) { - print_r($port_ifAlias); - } + d_echo($port_ifAlias); } unset($port_type, $port_descr, $port_circuit, $port_notes, $port_speed); diff --git a/includes/rrdtool.inc.php b/includes/rrdtool.inc.php index afbd2f7ad..a8a7e9936 100644 --- a/includes/rrdtool.inc.php +++ b/includes/rrdtool.inc.php @@ -23,7 +23,7 @@ function rrdtool_pipe_open(&$rrd_process, &$rrd_pipes) { - global $config, $debug; + global $config; $command = $config['rrdtool'].' -'; @@ -74,12 +74,8 @@ function rrdtool_pipe_open(&$rrd_process, &$rrd_pipes) { function rrdtool_pipe_close($rrd_process, &$rrd_pipes) { - global $debug; - - if ($debug) { - echo stream_get_contents($rrd_pipes[1]); - echo stream_get_contents($rrd_pipes[2]); - } + d_echo(stream_get_contents($rrd_pipes[1])); + d_echo(stream_get_contents($rrd_pipes[2])); fclose($rrd_pipes[0]); fclose($rrd_pipes[1]); @@ -210,7 +206,7 @@ function rrdtool($command, $filename, $options) { function rrdtool_create($filename, $options) { - global $config, $debug, $console_color; + global $config, $console_color; if ($config['norrd']) { print $console_color->convert('[%gRRD Disabled%n] ', false); @@ -219,9 +215,7 @@ function rrdtool_create($filename, $options) { $command = $config['rrdtool']." create $filename $options"; } - if ($debug) { - print $console_color->convert('RRD[%g'.$command.'%n] '); - } + d_echo($console_color->convert('RRD[%g'.$command.'%n] ')); return shell_exec($command); diff --git a/includes/sql-schema/update.php b/includes/sql-schema/update.php index 6497d1ca5..4bb7df721 100644 --- a/includes/sql-schema/update.php +++ b/includes/sql-schema/update.php @@ -103,9 +103,7 @@ foreach ($filelist as $file) { foreach (explode("\n", $data) as $line) { if (trim($line)) { - if ($debug) { - echo "$line \n"; - } + d_echo("$line \n"); if ($line[0] != '#') { if ($config['db']['extension'] == 'mysqli') { diff --git a/poller.php b/poller.php index 623c00044..62bb94cd7 100755 --- a/poller.php +++ b/poller.php @@ -124,9 +124,7 @@ if ($polled_devices) { } $string = $argv[0]." $doing ".date($config['dateformat']['compact'])." - $polled_devices devices polled in $poller_time secs"; -if ($debug) { - echo "$string\n"; -} +d_echo("$string\n"); echo ("\n".'MySQL: Cell['.($db_stats['fetchcell'] + 0).'/'.round(($db_stats['fetchcell_sec'] + 0), 2).'s]'.' Row['.($db_stats['fetchrow'] + 0).'/'.round(($db_stats['fetchrow_sec'] + 0), 2).'s]'.' Rows['.($db_stats['fetchrows'] + 0).'/'.round(($db_stats['fetchrows_sec'] + 0), 2).'s]'.' Column['.($db_stats['fetchcol'] + 0).'/'.round(($db_stats['fetchcol_sec'] + 0), 2).'s]'.' Update['.($db_stats['update'] + 0).'/'.round(($db_stats['update_sec'] + 0), 2).'s]'.' Insert['.($db_stats['insert'] + 0).'/'.round(($db_stats['insert_sec'] + 0), 2).'s]'.' Delete['.($db_stats['delete'] + 0).'/'.round(($db_stats['delete_sec'] + 0), 2).'s]'); From 4260c6697cd7c2e1088bdf6a232f274a5d29a409 Mon Sep 17 00:00:00 2001 From: Mark Schouten Date: Fri, 21 Aug 2015 16:13:54 +0200 Subject: [PATCH 022/598] Sign AUTHORS.md --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 2421c7ce3..ad5e41629 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -48,6 +48,7 @@ Contributors to LibreNMS: - Michael Newton (miken32) - Tom Ferguson (Tawmu) - Jimmy Cleuren (jimmycleuren) +- Mark Schouten (tuxis-ie) [1]: http://observium.org/ "Observium web site" From bfe47128d39cb20c7b7f98ba02441fe70498a4db Mon Sep 17 00:00:00 2001 From: Mark Schouten Date: Fri, 21 Aug 2015 16:47:29 +0200 Subject: [PATCH 023/598] I agree to the conditions of the Contributor Agreement contained in doc/General/Contributing.md. --- AUTHORS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AUTHORS.md b/AUTHORS.md index ad5e41629..823ffedec 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -48,7 +48,7 @@ Contributors to LibreNMS: - Michael Newton (miken32) - Tom Ferguson (Tawmu) - Jimmy Cleuren (jimmycleuren) -- Mark Schouten (tuxis-ie) +- Mark Schouten (tuxis-ie) [1]: http://observium.org/ "Observium web site" From 0e12f695a372288429208bdaadda0c9dc5350171 Mon Sep 17 00:00:00 2001 From: Job Snijders Date: Fri, 21 Aug 2015 17:50:24 +0200 Subject: [PATCH 024/598] Improve about page Alfabetical sort for acknowledgements section, chronological sort for Copyright statements as is common in other OSS projects. --- html/pages/about.inc.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/html/pages/about.inc.php b/html/pages/about.inc.php index 4487d5431..53eee1e3e 100644 --- a/html/pages/about.inc.php +++ b/html/pages/about.inc.php @@ -21,8 +21,8 @@ $git_log = `git log -10`;

License

-Copyright (C) 2006-2012 Adam Armstrong
 Copyright (C) 2013- Contributors
+Copyright (C) 2006-2012 Adam Armstrong
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -192,12 +192,12 @@ echo "
 
     

Acknowledgements

- Observium Codebase for fork.
- Mark James Silk Iconset.
- Erik Bosrup Overlib Library.
- Jonathan De Graeve SNMP code improvements.
Bruno Pramont Collectd code.
Dennis de Houx Application monitors for PowerDNS, Shoutcast, NTPD (Client, Server).
+ Erik Bosrup Overlib Library.
+ Jonathan De Graeve SNMP code improvements.
+ Mark James Silk Iconset.
+ Observium Codebase for fork.
From ff565608d23b1b0eb7ec2109141b0dd190308da4 Mon Sep 17 00:00:00 2001 From: vitalisator Date: Fri, 21 Aug 2015 18:04:12 +0200 Subject: [PATCH 025/598] working one --- html/includes/common/syslog.inc.php | 85 +---------------------------- 1 file changed, 2 insertions(+), 83 deletions(-) diff --git a/html/includes/common/syslog.inc.php b/html/includes/common/syslog.inc.php index e5e492edc..eb61936a5 100644 --- a/html/includes/common/syslog.inc.php +++ b/html/includes/common/syslog.inc.php @@ -1,16 +1,6 @@ = '10') { - dbQuery('TRUNCATE TABLE `syslog`'); - print_message('syslog truncated'); -} - -$pagetitle[] = 'Syslog'; -$syslog_output = ' -
+$common_output[] = ' @@ -21,91 +11,20 @@ $syslog_output = '
-
'; -$common_output[] = $syslog_output; From dadbcb454a8214716aab01e7fec91c5826ed1471 Mon Sep 17 00:00:00 2001 From: Mark Schouten Date: Fri, 21 Aug 2015 23:42:18 +0200 Subject: [PATCH 026/598] Fix two typos --- includes/discovery/bgp-peers.inc.php | 2 +- includes/discovery/temperatures/mgeups.inc.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/includes/discovery/bgp-peers.inc.php b/includes/discovery/bgp-peers.inc.php index b9f3c16a0..1b87eaecf 100644 --- a/includes/discovery/bgp-peers.inc.php +++ b/includes/discovery/bgp-peers.inc.php @@ -113,7 +113,7 @@ if ($config['enable_bgp']) { $af_data = snmpwalk_cache_oid($device, 'cbgpPeerAddrFamilyEntry', $cbgp, 'CISCO-BGP4-MIB', $config['mibdir']); } - d_echo('afi data :: '; + d_echo('afi data :: '); d_echo($af_data); foreach ($af_data as $k => $v) { diff --git a/includes/discovery/temperatures/mgeups.inc.php b/includes/discovery/temperatures/mgeups.inc.php index 4c6e7a478..f60170a5a 100644 --- a/includes/discovery/temperatures/mgeups.inc.php +++ b/includes/discovery/temperatures/mgeups.inc.php @@ -50,7 +50,7 @@ if ($device['os'] == 'mgeups') { $low_warn_limit = ($low_limit + $hysteresis); $high_warn_limit = ($high_limit - $hysteresis); - d_echo("low_limit : $low_limit\nlow_warn_limit : $low_warn_limit\nhigh_warn_limit : $high_warn_limit\nhigh_limit : $high_limit\n"): + d_echo("low_limit : $low_limit\nlow_warn_limit : $low_warn_limit\nhigh_warn_limit : $high_warn_limit\nhigh_limit : $high_limit\n"); discover_sensor($valid['sensor'], 'temperature', $device, $oid, $index, $sensorType, $descr, '10', '1', $low_limit, $low_warn_limit, $high_warn_limit, $high_limit, ($current / 10)); } From f5ad4665cd2c097cafa2b3d5cdd82ed681d0338a Mon Sep 17 00:00:00 2001 From: Arjit Chaudhary Date: Sat, 22 Aug 2015 17:58:10 +0530 Subject: [PATCH 027/598] Center the graph displayed. --- html/pages/graphs.inc.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/html/pages/graphs.inc.php b/html/pages/graphs.inc.php index 6b431c40f..868265600 100644 --- a/html/pages/graphs.inc.php +++ b/html/pages/graphs.inc.php @@ -201,9 +201,9 @@ else { echo generate_graph_js_state($graph_array); - echo('
'); + echo('
'); echo generate_lazy_graph_tag($graph_array); - echo("
"); + echo("
"); if (isset($config['graph_descr'][$vars['type']])) { From fde6d20999d9239d2ad3b9c17e108d431f28ff74 Mon Sep 17 00:00:00 2001 From: laf Date: Sat, 22 Aug 2015 15:13:06 +0000 Subject: [PATCH 028/598] Removed d_echo from memcache --- includes/definitions.inc.php | 1 - 1 file changed, 1 deletion(-) diff --git a/includes/definitions.inc.php b/includes/definitions.inc.php index 11151148c..a639de8d9 100644 --- a/includes/definitions.inc.php +++ b/includes/definitions.inc.php @@ -1664,7 +1664,6 @@ if ($config['memcached']['enable'] === true) { if (class_exists('Memcached')) { $memcache = new Memcached(); $memcache->addServer($config['memcached']['host'], $config['memcached']['port']); - d_echo($memcache->getStats()); } else { echo "WARNING: You have enabled memcached but have not installed the PHP bindings. Disabling memcached support.\n"; From 3ae9637ac4b36e0870fbddc8dbf63e0ce3870d2f Mon Sep 17 00:00:00 2001 From: laf Date: Sat, 22 Aug 2015 15:15:01 +0000 Subject: [PATCH 029/598] Added $memcache->getStats() back in --- includes/definitions.inc.php | 1 + 1 file changed, 1 insertion(+) diff --git a/includes/definitions.inc.php b/includes/definitions.inc.php index a639de8d9..e98c7b07e 100644 --- a/includes/definitions.inc.php +++ b/includes/definitions.inc.php @@ -1664,6 +1664,7 @@ if ($config['memcached']['enable'] === true) { if (class_exists('Memcached')) { $memcache = new Memcached(); $memcache->addServer($config['memcached']['host'], $config['memcached']['port']); + $memcache->getStats(); } else { echo "WARNING: You have enabled memcached but have not installed the PHP bindings. Disabling memcached support.\n"; From eb4d3867318d0298360d576e97e52a9dbef3c157 Mon Sep 17 00:00:00 2001 From: Arjit Chaudhary Date: Sun, 23 Aug 2015 00:09:12 +0530 Subject: [PATCH 030/598] Highlight table on hover, added column names for status and brand Probably could re-name brand to manufacturer ? --- html/pages/devices.inc.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/html/pages/devices.inc.php b/html/pages/devices.inc.php index f7a1f3723..c34d09c83 100644 --- a/html/pages/devices.inc.php +++ b/html/pages/devices.inc.php @@ -220,11 +220,11 @@ else {
- +
- - + + From abb70d9d4d520d312c0f1858af147ca000c8bd4f Mon Sep 17 00:00:00 2001 From: Todd Eddy Date: Sat, 22 Aug 2015 21:56:11 -0400 Subject: [PATCH 031/598] I agree to the conditions of the Contributor Agreement contained in doc/General/Contributing.md. --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 823ffedec..ab2b2b713 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -49,6 +49,7 @@ Contributors to LibreNMS: - Tom Ferguson (Tawmu) - Jimmy Cleuren (jimmycleuren) - Mark Schouten (tuxis-ie) +- Todd Eddy (vrillusions) [1]: http://observium.org/ "Observium web site" From 1d9fc71c7119db9a246928e8d1bcda4e3a62c83e Mon Sep 17 00:00:00 2001 From: laf Date: Sun, 23 Aug 2015 09:40:55 +0000 Subject: [PATCH 032/598] Revert change which skips over ports that are down / admin down --- includes/polling/ports.inc.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/includes/polling/ports.inc.php b/includes/polling/ports.inc.php index f98c62d09..ec4aa092f 100644 --- a/includes/polling/ports.inc.php +++ b/includes/polling/ports.inc.php @@ -348,10 +348,6 @@ foreach ($ports as $port) { echo $oid.' '; } } - - if (( $oid == 'ifOperStatus' || $oid == 'ifAdminStatus' ) && $this_port[$oid] == 'down') { - break; - } }//end foreach // Parse description (usually ifAlias) if config option set From efa475d3e8899d141789ce5ac3b4db54d25854ad Mon Sep 17 00:00:00 2001 From: Arjit Chaudhary Date: Sun, 23 Aug 2015 15:20:18 +0530 Subject: [PATCH 033/598] renamed brand to vendor --- html/pages/devices.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/html/pages/devices.inc.php b/html/pages/devices.inc.php index c34d09c83..663215f9c 100644 --- a/html/pages/devices.inc.php +++ b/html/pages/devices.inc.php @@ -224,7 +224,7 @@ else { - + From 0c6044cf730719857f6030f816c64cfe7ff75b1c Mon Sep 17 00:00:00 2001 From: Arjit Chaudhary Date: Sun, 23 Aug 2015 15:21:12 +0530 Subject: [PATCH 034/598] Added back table-condensed to table-hover --- html/pages/devices.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/html/pages/devices.inc.php b/html/pages/devices.inc.php index 663215f9c..fed2307a9 100644 --- a/html/pages/devices.inc.php +++ b/html/pages/devices.inc.php @@ -220,7 +220,7 @@ else {
-
StatusBrand Device Platform
StatusBrandVendor Device Platform
+
From 72b9ee266979d27a625f096913fdd9d8aa2f655e Mon Sep 17 00:00:00 2001 From: Arjit Chaudhary Date: Sun, 23 Aug 2015 16:37:21 +0530 Subject: [PATCH 035/598] Cleanup/Change UI a bit. --- html/pages/graphs.inc.php | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/html/pages/graphs.inc.php b/html/pages/graphs.inc.php index 868265600..9ca22603a 100644 --- a/html/pages/graphs.inc.php +++ b/html/pages/graphs.inc.php @@ -128,7 +128,7 @@ else { }
"); echo(' @@ -161,12 +161,11 @@ else { $("#dtpickerfrom").datetimepicker({useCurrent: true, sideBySide: true, useStrict: false}); $("#dtpickerto").datetimepicker({useCurrent: true, sideBySide: true, useStrict: false}); }); - + '); - - echo("
"); - + echo ('
'); + echo('
'); if ($vars['legend'] == "no") { echo(generate_link("Show Legend",$vars, array('page' => "graphs", 'legend' => NULL))); } @@ -186,16 +185,14 @@ else { } # } - echo('
'); - + echo(' | '); if ($vars['showcommand'] == "yes") { echo(generate_link("Hide RRD Command",$vars, array('page' => "graphs", 'showcommand' => NULL))); } else { echo(generate_link("Show RRD Command",$vars, array('page' => "graphs", 'showcommand' => "yes"))); } - - echo('
'); + echo('
'); print_optionbar_end(); From 3ac8ffc70fd4f67d93b48c2936092e9ab7414fac Mon Sep 17 00:00:00 2001 From: laf Date: Sun, 23 Aug 2015 11:57:56 +0000 Subject: [PATCH 036/598] Extended support for list devices to support mac/ipv4 and ipv6 filtering --- doc/API/API-Docs.md | 36 ++++++++++++++++++++++++-- html/includes/api_functions.inc.php | 39 ++++++++++++++++++++++------- 2 files changed, 64 insertions(+), 11 deletions(-) diff --git a/doc/API/API-Docs.md b/doc/API/API-Docs.md index 3a7db5085..82f57b9f7 100644 --- a/doc/API/API-Docs.md +++ b/doc/API/API-Docs.md @@ -333,8 +333,16 @@ Route: /api/v0/devices Input: - order: How to order the output, default is by hostname. Can be prepended by DESC or ASC to change the order. - - type: can be one of the following, all, ignored, up, down, disabled to filter by that device status. - + - type: can be one of the following to filter or search by: + - all: All devices + - ignored: Only ignored devices + - up: Only devices that are up + - down: Only devices that are down + - disabled: Disabled devices + - mac: search by mac address + - ipv4: search by IPv4 address + - ipv6: search by IPv6 address (compressed or uncompressed) + - query: If searching by, then this will be used as the input. Example: ```curl curl -H 'X-Auth-Token: YOURAPITOKENHERE' https://librenms.org/api/v0/devices?order=hostname%20DESC&type=down @@ -345,6 +353,30 @@ Output: ```text { "status": "ok", + "count": 1, + "devices": [ + { + "device_id": "1", + "hostname": "localhost", + ... + "serial": null, + "icon": null + } + ] +} +``` + +Example: +```curl +curl -H 'X-Auth-Token: YOURAPITOKENHERE' https://librenms.org/api/v0/devices?type=mac&query=00000c9ff013 +``` + +Output: + +```text +{ + "status": "ok", + "count": 1, "devices": [ { "device_id": "1", diff --git a/html/includes/api_functions.inc.php b/html/includes/api_functions.inc.php index 3c2c7fab1..637e7f219 100644 --- a/html/includes/api_functions.inc.php +++ b/html/includes/api_functions.inc.php @@ -155,6 +155,9 @@ function list_devices() { $app = \Slim\Slim::getInstance(); $order = $_GET['order']; $type = $_GET['type']; + $query = mres($_GET['query']); + $param = array(); + $join = ''; if (empty($order)) { $order = 'hostname'; } @@ -166,28 +169,46 @@ function list_devices() { if ($type == 'all' || empty($type)) { $sql = '1'; } - else if ($type == 'ignored') { + elseif ($type == 'ignored') { $sql = "ignore='1' AND disabled='0'"; } - else if ($type == 'up') { + elseif ($type == 'up') { $sql = "status='1' AND ignore='0' AND disabled='0'"; } - else if ($type == 'down') { + elseif ($type == 'down') { $sql = "status='0' AND ignore='0' AND disabled='0'"; } - else if ($type == 'disabled') { + elseif ($type == 'disabled') { $sql = "disabled='1'"; } + elseif ($type == 'mac') { + $join = " LEFT JOIN `ports` ON `devices`.`device_id`=`ports`.`device_id` LEFT JOIN `ipv4_mac` ON `ports`.`port_id`=`ipv4_mac`.`port_id` "; + $sql = "`ipv4_mac`.`mac_address`=?"; + $param[] = $query; + } + elseif ($type == 'ipv4') { + $join = " LEFT JOIN `ports` ON `devices`.`device_id`=`ports`.`device_id` LEFT JOIN `ipv4_addresses` ON `ports`.`port_id`=`ipv4_addresses`.`port_id` "; + $sql = "`ipv4_addresses`.`ipv4_address`=?"; + $param[] = $query; + } + elseif ($type == 'ipv6') { + $join = " LEFT JOIN `ports` ON `devices`.`device_id`=`ports`.`device_id` LEFT JOIN `ipv6_addresses` ON `ports`.`port_id`=`ipv6_addresses`.`port_id` "; + $sql = "`ipv6_addresses`.`ipv6_address`=? OR `ipv6_addresses`.`ipv6_compressed`=?"; + $param = array($query,$query); + } else { $sql = '1'; } $devices = array(); - foreach (dbFetchRows("SELECT * FROM `devices` WHERE $sql ORDER by $order") as $device) { + foreach (dbFetchRows("SELECT * FROM `devices` $join WHERE $sql ORDER by $order", $param) as $device) { $devices[] = $device; } + $count = count($devices); + $output = array( 'status' => 'ok', + 'count' => $count, 'devices' => $devices, ); $app->response->headers->set('Content-Type', 'application/json'); @@ -211,7 +232,7 @@ function add_device() { $message = 'No information has been provided to add this new device'; } - else if (empty($data['hostname'])) { + elseif (empty($data['hostname'])) { $message = 'Missing the device hostname'; } @@ -227,7 +248,7 @@ function add_device() { $snmpver = mres($data['version']); } - else if ($data['version'] == 'v3') { + elseif ($data['version'] == 'v3') { $v3 = array( 'authlevel' => mres($data['authlevel']), 'authname' => mres($data['authname']), @@ -625,7 +646,7 @@ function add_edit_rule() { if (empty($device_id) && !isset($rule_id)) { $message = 'Missing the device id or global device id (-1)'; } - else if ($device_id == 0) { + elseif ($device_id == 0) { $device_id = '-1'; } @@ -687,7 +708,7 @@ function add_edit_rule() { $message = 'Failed to update existing alert rule'; } } - else if (dbInsert(array('name' => $name, 'device_id' => $device_id, 'rule' => $rule, 'severity' => $severity, 'disabled' => $disabled, 'extra' => $extra_json), 'alert_rules')) { + elseif (dbInsert(array('name' => $name, 'device_id' => $device_id, 'rule' => $rule, 'severity' => $severity, 'disabled' => $disabled, 'extra' => $extra_json), 'alert_rules')) { $status = 'ok'; $code = 200; } From c4d9e5404ecb1d149a17005c12e9431abdc64d15 Mon Sep 17 00:00:00 2001 From: Arjit Chaudhary Date: Sun, 23 Aug 2015 18:48:21 +0530 Subject: [PATCH 037/598] I agree to the conditions of the Contributor Agreement contained in doc/General/Contributing.md. --- AUTHORS.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/AUTHORS.md b/AUTHORS.md index ab2b2b713..95833993b 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -26,7 +26,6 @@ Contributors to LibreNMS: - Mickael Marchand (mmarchand) - Mohammad Al-Shami (mohshami) - Rudy Hardeman (zarya) -- Arjit Chaudhary (arjit.c@gmail.com) (arjitc) - Freddie Cash (fjwcash@gmail.com) (fjwcash) - Thom Seddon (thomseddon) - Vitali Kari (vitalisator) @@ -50,7 +49,7 @@ Contributors to LibreNMS: - Jimmy Cleuren (jimmycleuren) - Mark Schouten (tuxis-ie) - Todd Eddy (vrillusions) +- Arjit Chaudhary (arjit.c@gmail.com) (arjitc) [1]: http://observium.org/ "Observium web site" - From 8d929bc43cebc512e6e02231da81838f6dda134e Mon Sep 17 00:00:00 2001 From: laf Date: Sun, 23 Aug 2015 17:04:20 +0000 Subject: [PATCH 038/598] Moved the snmp query for poe outside of the loop --- includes/polling/port-poe.inc.php | 4 ++-- includes/polling/ports.inc.php | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/includes/polling/port-poe.inc.php b/includes/polling/port-poe.inc.php index 3e48e9336..1537deafc 100644 --- a/includes/polling/port-poe.inc.php +++ b/includes/polling/port-poe.inc.php @@ -35,8 +35,8 @@ $peth_oids = array( 'pethMainPseConsumptionPower', ); -$port_stats = snmpwalk_cache_oid($device, 'pethPsePortEntry', $port_stats, 'POWER-ETHERNET-MIB'); -$port_stats = snmpwalk_cache_oid($device, 'cpeExtPsePortEntry', $port_stats, 'CISCO-POWER-ETHERNET-EXT-MIB'); +//$port_stats = snmpwalk_cache_oid($device, 'pethPsePortEntry', $port_stats, 'POWER-ETHERNET-MIB'); +//$port_stats = snmpwalk_cache_oid($device, 'cpeExtPsePortEntry', $port_stats, 'CISCO-POWER-ETHERNET-EXT-MIB'); if ($port_stats[$port['ifIndex']] && $port['ifType'] == 'ethernetCsmacd' diff --git a/includes/polling/ports.inc.php b/includes/polling/ports.inc.php index ec4aa092f..e1df712ba 100644 --- a/includes/polling/ports.inc.php +++ b/includes/polling/ports.inc.php @@ -145,6 +145,11 @@ if ($device['adsl_count'] > '0') { $port_stats = snmpwalk_cache_oid($device, '.1.3.6.1.2.1.10.94.1.1.7.1.7', $port_stats, 'ADSL-LINE-MIB'); }//end if +if ($config['enable_ports_poe']) { + $port_stats = snmpwalk_cache_oid($device, 'pethPsePortEntry', $port_stats, 'POWER-ETHERNET-MIB'); + $port_stats = snmpwalk_cache_oid($device, 'cpeExtPsePortEntry', $port_stats, 'CISCO-POWER-ETHERNET-EXT-MIB'); +} + // FIXME This probably needs re-enabled. We need to clear these things when they get unset, too. // foreach ($etherlike_oids as $oid) { $port_stats = snmpwalk_cache_oid($device, $oid, $port_stats, "EtherLike-MIB"); } // foreach ($cisco_oids as $oid) { $port_stats = snmpwalk_cache_oid($device, $oid, $port_stats, "OLD-CISCO-INTERFACES-MIB"); } From 8bf254182b0b36837451b2d42045d91b775663b0 Mon Sep 17 00:00:00 2001 From: laf Date: Sun, 23 Aug 2015 17:54:55 +0000 Subject: [PATCH 039/598] Removed commented out code --- includes/polling/port-poe.inc.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/includes/polling/port-poe.inc.php b/includes/polling/port-poe.inc.php index 1537deafc..2263a1a5e 100644 --- a/includes/polling/port-poe.inc.php +++ b/includes/polling/port-poe.inc.php @@ -35,9 +35,6 @@ $peth_oids = array( 'pethMainPseConsumptionPower', ); -//$port_stats = snmpwalk_cache_oid($device, 'pethPsePortEntry', $port_stats, 'POWER-ETHERNET-MIB'); -//$port_stats = snmpwalk_cache_oid($device, 'cpeExtPsePortEntry', $port_stats, 'CISCO-POWER-ETHERNET-EXT-MIB'); - if ($port_stats[$port['ifIndex']] && $port['ifType'] == 'ethernetCsmacd' && isset($port_stats[$port['ifIndex']]['dot3StatsIndex'])) { From c0125f28e408d3410b48205258c8aa0ba70da5d6 Mon Sep 17 00:00:00 2001 From: laf Date: Sun, 23 Aug 2015 19:36:22 +0000 Subject: [PATCH 040/598] Added support for rrdtool 1.5 --- doc/Extensions/Distributed-Poller.md | 21 +++++++++++++++++++-- doc/Extensions/RRDCached.md | 15 +++++++++++---- includes/defaults.inc.php | 1 + includes/rrdtool.inc.php | 16 ++-------------- 4 files changed, 33 insertions(+), 20 deletions(-) diff --git a/doc/Extensions/Distributed-Poller.md b/doc/Extensions/Distributed-Poller.md index 86163b644..e6c3e2c9d 100644 --- a/doc/Extensions/Distributed-Poller.md +++ b/doc/Extensions/Distributed-Poller.md @@ -5,7 +5,11 @@ These machines can be in a different physical location and therefore minimize ne Devices can also be groupped together into a `poller_group` to pin these devices to a single or a group of designated pollers. -All pollers need to share their RRD-folder, for example via NFS or a combination of NFS and rrdcached. +~~All pollers need to share their RRD-folder, for example via NFS or a combination of NFS and rrdcached.~~ + +> This is no longer a strict requirement with the use of rrdtool 1.5 and above. If you are NOT running 1.5 then you will still +need to share the RRD-folder. + It is also required that all pollers can access the central memcached to communicate with eachother. In order to enable distributed polling, set `$config['distributed_poller'] = true` and your memcached details into `$config['distributed_poller_memcached_host']` and `$config['distributed_poller_memcached_port']`. @@ -49,7 +53,14 @@ The pollers, web and API layers should all be able to access the database server ####RRD Storage Central storage should be provided so all RRD files can be read from and written to in one location. As suggested above, it's recommended that RRD Cached is configured and used. -For this example, we are running RRDCached to allow all pollers and web/api servers to read/write to the rrd iles with the rrd directory also exported by NFS for simple access and maintenance. +For this example, we are running RRDCached to allow all pollers and web/api servers to read/write to the rrd iles ~~with the rrd directory also exported by NFS for simple access and maintenance.~~ + +Sharing rrd files via something like NFS is no longer required if you run rrdtool 1.5 or greater. If you don't - please share your rrd folder as before. If you run rrdtool +1.5 or greater then add this config to your pollers: + +```php +$config['rrdtool_version'] = 1.5; +``` ####Memcache Memcache is required for the distributed pollers to be able to register to a central location and record what devices are polled. Memcache can run from any of the kit so long as it is accessable by all pollers. @@ -88,4 +99,10 @@ $config['rrd_dir'] = "/opt/librenms/rrd"; $config['rrdcached_dir'] = ""; ``` +For rrdtool 1.5 or greater then you can enable support for rrdcached to create the rrd files: + +```php +$config['rrdtool_version'] = 1.5; +``` + $config['rrdcached_dir'] Is only needed if you are using tcp connections for rrd cached and needs only to be set if you want to store rrd files within a sub directory of your rrdcached base directory. diff --git a/doc/Extensions/RRDCached.md b/doc/Extensions/RRDCached.md index 27a157c5d..1459235c6 100644 --- a/doc/Extensions/RRDCached.md +++ b/doc/Extensions/RRDCached.md @@ -6,19 +6,19 @@ This document will explain how to setup RRDCached for LibreNMS. This example is based on a fresh LibreNMS install, on a minimimal CentOS installation. In this example, we'll use the Repoforge repository. -```ssh +```php rpm -ivh http://pkgs.repoforge.org/rpmforge-release/rpmforge-release-0.5.3-1.el6.rf.x86_64.rpm vi /etc/yum.repos.d/rpmforge.repo ``` - Enable the Extra repo -```ssh +```php yum update rrdtool vi /etc/yum.repos.d/rpmforge.repo ``` - Disable the [rpmforge] and [rpmforge-extras] repos again -```ssh +```php vi /etc/sysconfig/rrdcached # Settings for rrdcached @@ -34,6 +34,13 @@ service rrdcached start ``` Edit config.php to include: -```ssh +```php $config['rrdcached'] = "unix:/var/run/rrdcached/rrdcached.sock"; ``` + +> If you are using rrdtool / rrdcached version 1.5 or above then this now supports creating rrd files over rrdcached. To +enable this set the following config: + +```php +$config['rrdtool_version'] = 1.5; +``` diff --git a/includes/defaults.inc.php b/includes/defaults.inc.php index 66ca1fcea..9f370381a 100644 --- a/includes/defaults.inc.php +++ b/includes/defaults.inc.php @@ -51,6 +51,7 @@ $config['own_hostname'] = 'localhost'; // Location of executables $config['rrdtool'] = '/usr/bin/rrdtool'; +$config['rrdtool_version'] = 1.4; // Doesn't need to contain minor numbers. $config['fping'] = '/usr/bin/fping'; $config['fping_options']['retries'] = 3; $config['fping_options']['timeout'] = 500; diff --git a/includes/rrdtool.inc.php b/includes/rrdtool.inc.php index a8a7e9936..3e09d523b 100644 --- a/includes/rrdtool.inc.php +++ b/includes/rrdtool.inc.php @@ -166,7 +166,7 @@ function rrdtool_graph($graph_file, $options) { function rrdtool($command, $filename, $options) { global $config, $debug, $rrd_pipes, $console_color; - if ($command != 'create' && $config['rrdcached']) { + if ($config['rrdtool_version'] >= 1.5 && $config['rrdcached']) { if (isset($config['rrdcached_dir']) && $config['rrdcached_dir'] !== false) { $filename = str_replace($config['rrd_dir'].'/', './'.$config['rrdcached_dir'].'/', $filename); $filename = str_replace($config['rrd_dir'], './'.$config['rrdcached_dir'].'/', $filename); @@ -206,19 +206,7 @@ function rrdtool($command, $filename, $options) { function rrdtool_create($filename, $options) { - global $config, $console_color; - - if ($config['norrd']) { - print $console_color->convert('[%gRRD Disabled%n] ', false); - } - else { - $command = $config['rrdtool']." create $filename $options"; - } - - d_echo($console_color->convert('RRD[%g'.$command.'%n] ')); - - return shell_exec($command); - + return rrdtool('create', $filename, $options); } From d825903c4efea290d312942b012a5b61d48b5a43 Mon Sep 17 00:00:00 2001 From: laf Date: Sun, 23 Aug 2015 20:01:09 +0000 Subject: [PATCH 041/598] Checks if port is permitted for user before doing neighbour lookup --- html/includes/print-interface.inc.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/html/includes/print-interface.inc.php b/html/includes/print-interface.inc.php index bfb5d1bd7..223c169fc 100644 --- a/html/includes/print-interface.inc.php +++ b/html/includes/print-interface.inc.php @@ -233,7 +233,7 @@ if (strpos($port['label'], 'oopback') === false && !$graph_type) { }//end foreach }//end if - if ($port_details && $config['enable_port_relationship'] === true) { + if ($port_details && $config['enable_port_relationship'] === true && port_permitted($int_link,$device['device_id'])) { foreach ($int_links as $int_link) { $link_if = dbFetchRow('SELECT * from ports AS I, devices AS D WHERE I.device_id = D.device_id and I.port_id = ?', array($int_link)); @@ -263,7 +263,7 @@ if (strpos($port['label'], 'oopback') === false && !$graph_type) { // unset($int_links, $int_links_v6, $int_links_v4, $int_links_phys, $br); }//end if -if ($port_details && $config['enable_port_relationship'] === true) { +if ($port_details && $config['enable_port_relationship'] === true && port_permitted($port['port_id'], $device['device_id'])) { foreach (dbFetchRows('SELECT * FROM `pseudowires` WHERE `port_id` = ?', array($port['port_id'])) as $pseudowire) { // `port_id`,`peer_device_id`,`peer_ldp_id`,`cpwVcID`,`cpwOid` $pw_peer_dev = dbFetchRow('SELECT * FROM `devices` WHERE `device_id` = ?', array($pseudowire['peer_device_id'])); From a413968eb8c2f908ea4e5ece77efb388964f1bcf Mon Sep 17 00:00:00 2001 From: laf Date: Sun, 23 Aug 2015 20:06:28 +0000 Subject: [PATCH 042/598] Also use ifHighSpeed if ifSpeed is 0 and ifHighSpeed exists --- includes/polling/ports.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/polling/ports.inc.php b/includes/polling/ports.inc.php index ec4aa092f..b05003679 100644 --- a/includes/polling/ports.inc.php +++ b/includes/polling/ports.inc.php @@ -289,7 +289,7 @@ foreach ($ports as $port) { } // Overwrite ifSpeed with ifHighSpeed if it's over 1G - if (is_numeric($this_port['ifHighSpeed']) && $this_port['ifSpeed'] > '1000000000') { + if ((is_numeric($this_port['ifHighSpeed']) && $this_port['ifSpeed'] > '1000000000') || (is_numeric($this_port['ifHighSpeed']) && $this_port['ifSpeed'] == 0)) { echo 'HighSpeed '; $this_port['ifSpeed'] = ($this_port['ifHighSpeed'] * 1000000); } From 0baa0d81e22db22206035291615c4cd174a61f5c Mon Sep 17 00:00:00 2001 From: laf Date: Sun, 23 Aug 2015 21:39:37 +0000 Subject: [PATCH 043/598] Reworked if check --- includes/polling/ports.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/polling/ports.inc.php b/includes/polling/ports.inc.php index b05003679..c102a664b 100644 --- a/includes/polling/ports.inc.php +++ b/includes/polling/ports.inc.php @@ -289,7 +289,7 @@ foreach ($ports as $port) { } // Overwrite ifSpeed with ifHighSpeed if it's over 1G - if ((is_numeric($this_port['ifHighSpeed']) && $this_port['ifSpeed'] > '1000000000') || (is_numeric($this_port['ifHighSpeed']) && $this_port['ifSpeed'] == 0)) { + if (is_numeric($this_port['ifHighSpeed']) && ($this_port['ifSpeed'] > '1000000000' || $this_port['ifSpeed'] == 0)) { echo 'HighSpeed '; $this_port['ifSpeed'] = ($this_port['ifHighSpeed'] * 1000000); } From 4e084c9632949898a559ca1480ad0c16886a173c Mon Sep 17 00:00:00 2001 From: Todd Eddy Date: Sun, 23 Aug 2015 19:01:39 -0400 Subject: [PATCH 044/598] Add netgear OID to os discovery --- includes/discovery/os/netgear.inc.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/includes/discovery/os/netgear.inc.php b/includes/discovery/os/netgear.inc.php index 4c8e8246c..21068df05 100644 --- a/includes/discovery/os/netgear.inc.php +++ b/includes/discovery/os/netgear.inc.php @@ -4,4 +4,7 @@ if (!$os) { if (stristr($sysDescr, 'ProSafe')) { $os = 'netgear'; } + elseif (strpos($sysObjectId, '1.3.6.1.4.1.4526') !== FALSE) { + $os = 'netgear'; + } } From 103221f76515640cf5dd4af60309c2dec36cc76f Mon Sep 17 00:00:00 2001 From: f0o Date: Mon, 24 Aug 2015 14:59:43 +0100 Subject: [PATCH 045/598] Added Config-SQL --- sql-schema/064.sql | 1 + 1 file changed, 1 insertion(+) create mode 100644 sql-schema/064.sql diff --git a/sql-schema/064.sql b/sql-schema/064.sql new file mode 100644 index 000000000..13ebbb243 --- /dev/null +++ b/sql-schema/064.sql @@ -0,0 +1 @@ +insert into config (config_name,config_value,config_default,config_descr,config_group,config_group_order,config_sub_group,config_sub_group_order,config_hidden,config_disabled) values ('alert.transports.pushbullet','','','Pushbullet access token','alerting',0,'transports',0,'0','0'); From 35614cea232f1e3204f3708ca3b4cfb6955bf8fb Mon Sep 17 00:00:00 2001 From: laf Date: Mon, 24 Aug 2015 18:39:49 +0000 Subject: [PATCH 046/598] fixed scrut issue, declare array --- includes/polling/functions.inc.php | 1 + 1 file changed, 1 insertion(+) diff --git a/includes/polling/functions.inc.php b/includes/polling/functions.inc.php index 14a4984de..f73589460 100644 --- a/includes/polling/functions.inc.php +++ b/includes/polling/functions.inc.php @@ -367,6 +367,7 @@ function poll_mib_def($device, $mib_name_table, $mib_subdir, $mib_oids, $mib_gra } $oid_count = 0; + $fields = array(); foreach ($oidglist as $fulloid) { list($splitoid, $splitindex) = explode('.', $fulloid, 2); if (is_numeric($snmpdata[$splitindex][$splitoid])) { From 4d9163c9ecc964d1a8536ab44f931b4de0a2c052 Mon Sep 17 00:00:00 2001 From: laf Date: Mon, 24 Aug 2015 19:14:30 +0000 Subject: [PATCH 047/598] Make network graphs compatible with 1.4.x and 1.5.x rrdtool --- html/includes/graphs/generic_multi_seperated.inc.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/html/includes/graphs/generic_multi_seperated.inc.php b/html/includes/graphs/generic_multi_seperated.inc.php index ce0a9472b..9b37f3751 100644 --- a/html/includes/graphs/generic_multi_seperated.inc.php +++ b/html/includes/graphs/generic_multi_seperated.inc.php @@ -74,7 +74,7 @@ foreach ($rrd_list as $rrd) { $stack = 'STACK'; } - $rrd_options .= ' AREA:inbits'.$i.'#'.$colour_in.":'".rrdtool_escape($rrd['descr'], 9)."In ':$stack"; + $rrd_options .= ' AREA:inbits'.$i.'#'.$colour_in.":'".rrdtool_escape($rrd['descr'], 9)."In '$stack"; $rrd_options .= ' GPRINT:inbits'.$i.':LAST:%6.2lf%s'; $rrd_options .= ' GPRINT:inbits'.$i.':AVERAGE:%6.2lf%s'; $rrd_options .= ' GPRINT:inbits'.$i.':MAX:%6.2lf%s'; @@ -84,8 +84,8 @@ foreach ($rrd_list as $rrd) { } $rrd_options .= " COMMENT:'\\n'"; - $rrd_optionsb .= ' AREA:outbits'.$i.'_neg#'.$colour_out."::$stack"; - $rrd_options .= ' HRULE:999999999999999#'.$colour_out.":'".str_pad('', 10)."Out':"; + $rrd_optionsb .= ' AREA:outbits'.$i.'_neg#'.$colour_out.":$stack"; + $rrd_options .= ' HRULE:999999999999999#'.$colour_out.":'".str_pad('', 10)."Out'"; $rrd_options .= ' GPRINT:outbits'.$i.':LAST:%6.2lf%s'; $rrd_options .= ' GPRINT:outbits'.$i.':AVERAGE:%6.2lf%s'; $rrd_options .= ' GPRINT:outbits'.$i.':MAX:%6.2lf%s'; @@ -141,21 +141,21 @@ if (!$args['nototal']) { $rrd_options .= " COMMENT:' \\n'"; - $rrd_options .= " HRULE:999999999999999#FFFFFF:'".str_pad('Total', 10)."In ':"; + $rrd_options .= " HRULE:999999999999999#FFFFFF:'".str_pad('Total', 10)."In '"; $rrd_options .= ' GPRINT:inbits:LAST:%6.2lf%s'; $rrd_options .= ' GPRINT:inbits:AVERAGE:%6.2lf%s'; $rrd_options .= ' GPRINT:inbits:MAX:%6.2lf%s'; $rrd_options .= " GPRINT:totin:%6.2lf%s$total_units"; $rrd_options .= " COMMENT:'\\n'"; - $rrd_options .= " HRULE:999999999999990#FFFFFF:'".str_pad('', 10)."Out':"; + $rrd_options .= " HRULE:999999999999990#FFFFFF:'".str_pad('', 10)."Out'"; $rrd_options .= ' GPRINT:outbits:LAST:%6.2lf%s'; $rrd_options .= ' GPRINT:outbits:AVERAGE:%6.2lf%s'; $rrd_options .= ' GPRINT:outbits:MAX:%6.2lf%s'; $rrd_options .= " GPRINT:totout:%6.2lf%s$total_units"; $rrd_options .= " COMMENT:'\\n'"; - $rrd_options .= " HRULE:999999999999990#FFFFFF:'".str_pad('', 10)."Agg':"; + $rrd_options .= " HRULE:999999999999990#FFFFFF:'".str_pad('', 10)."Agg'"; $rrd_options .= ' GPRINT:bits:LAST:%6.2lf%s'; $rrd_options .= ' GPRINT:bits:AVERAGE:%6.2lf%s'; $rrd_options .= ' GPRINT:bits:MAX:%6.2lf%s'; From 59de0d1478903c0917c3f1a9ea474f33f06212d4 Mon Sep 17 00:00:00 2001 From: laf Date: Mon, 24 Aug 2015 20:54:19 +0000 Subject: [PATCH 048/598] Clean up some poller debug + added updated version and last git commit --- discovery.php | 4 ++-- includes/definitions.inc.php | 2 +- includes/polling/functions.inc.php | 3 ++- poller.php | 3 ++- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/discovery.php b/discovery.php index c70878054..9dc39f4fe 100755 --- a/discovery.php +++ b/discovery.php @@ -23,11 +23,11 @@ require 'includes/discovery/functions.inc.php'; $start = utime(); $runtime_stats = array(); -// Observium Device Discovery $options = getopt('h:m:i:n:d::a::q'); if (!isset($options['q'])) { - echo $config['project_name_version']." Discovery\n\n"; + echo $config['project_name_version']." Discovery\n"; + echo `git log -n 1|grep 'commit '`."\n"; } if (isset($options['h'])) { diff --git a/includes/definitions.inc.php b/includes/definitions.inc.php index e98c7b07e..0744d79c8 100644 --- a/includes/definitions.inc.php +++ b/includes/definitions.inc.php @@ -1633,7 +1633,7 @@ if (isset($config['enable_printers']) && $config['enable_printers']) { // // No changes below this line # // -$config['version'] = '2014.master'; +$config['version'] = '2015.master'; $config['project_name_version'] = $config['project_name'].' '.$config['version']; if (isset($config['rrdgraph_def_text'])) { diff --git a/includes/polling/functions.inc.php b/includes/polling/functions.inc.php index 27bf8053f..d97555d46 100644 --- a/includes/polling/functions.inc.php +++ b/includes/polling/functions.inc.php @@ -278,7 +278,8 @@ function poll_device($device, $options) { // echo("$device_end - $device_start; $device_time $device_run"); echo "Polled in $device_time seconds\n"; - d_echo('Updating '.$device['hostname'].' - '.print_r($update_array)." \n"); + d_echo('Updating '.$device['hostname']."\n"); + d_echo($update_array); $updated = dbUpdate($update_array, 'devices', '`device_id` = ?', array($device['device_id'])); if ($updated) { diff --git a/poller.php b/poller.php index 62bb94cd7..26f90c505 100755 --- a/poller.php +++ b/poller.php @@ -22,7 +22,8 @@ require 'includes/polling/functions.inc.php'; require 'includes/alerts.inc.php'; $poller_start = utime(); -echo $config['project_name_version']." Poller\n\n"; +echo $config['project_name_version']." Poller\n"; +echo `git log -n 1|grep 'commit '`."\n"; $options = getopt('h:m:i:n:r::d::a::'); From 86059f67c126f4d552e8750ea25bb04178aa93a3 Mon Sep 17 00:00:00 2001 From: laf Date: Tue, 25 Aug 2015 08:40:20 +0000 Subject: [PATCH 049/598] updated to use function for last commit --- discovery.php | 2 +- includes/functions.php | 4 ++++ poller.php | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/discovery.php b/discovery.php index 9dc39f4fe..3006399ff 100755 --- a/discovery.php +++ b/discovery.php @@ -27,7 +27,7 @@ $options = getopt('h:m:i:n:d::a::q'); if (!isset($options['q'])) { echo $config['project_name_version']." Discovery\n"; - echo `git log -n 1|grep 'commit '`."\n"; + echo get_last_commit()."\n"; } if (isset($options['h'])) { diff --git a/includes/functions.php b/includes/functions.php index 0027748ee..84e95af1d 100644 --- a/includes/functions.php +++ b/includes/functions.php @@ -1227,3 +1227,7 @@ function fping($host,$params) { function function_check($function) { return function_exists($function); } + +function get_last_commit() { + return `git log -n 1|head -n1`; +}//end get_last_commit diff --git a/poller.php b/poller.php index 26f90c505..6412c37be 100755 --- a/poller.php +++ b/poller.php @@ -23,7 +23,7 @@ require 'includes/alerts.inc.php'; $poller_start = utime(); echo $config['project_name_version']." Poller\n"; -echo `git log -n 1|grep 'commit '`."\n"; +echo get_last_commit()."\n"; $options = getopt('h:m:i:n:r::d::a::'); From e7c51f2a80814b214ff8dccbd380b6227ec88fdb Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Mon, 6 Jul 2015 09:25:23 -0400 Subject: [PATCH 050/598] add mysql lock for polling --- includes/dbFacile.mysql.php | 28 ++++++++++++++++++++++++++++ includes/dbFacile.mysqli.php | 27 +++++++++++++++++++++++++++ poller.php | 8 +++++--- 3 files changed, 60 insertions(+), 3 deletions(-) diff --git a/includes/dbFacile.mysql.php b/includes/dbFacile.mysql.php index 0d1d7150c..44dc5d494 100644 --- a/includes/dbFacile.mysql.php +++ b/includes/dbFacile.mysql.php @@ -59,6 +59,34 @@ function dbQuery($sql, $parameters=array()) { }//end dbQuery() +/* + * Aquire a lock on a string + * */ +function dbGetLock($data, $timeout = 0) { + $sql = 'SELECT GET_LOCK(\'' . $data . '\',' . $timeout . ')'; + echo "printing sql: "; + echo "$sql\n"; + $result = dbFetchCell($sql); + echo "printing result: "; + echo "$result\n"; + return $result; +} + + +/* + * Release a lock on a string + * */ +function dbReleaseLock($data, $timeout = 0) { + $sql = 'SELECT RELEASE_LOCK(\'' . $data . '\')'; + echo "printing sql: "; + echo "$sql\n"; + $result = dbFetchCell($sql); + echo "printing result: "; + echo "$result\n"; + return $result; +} + + /* * Passed an array and a table name, it attempts to insert the data into the table. * Check for boolean false to determine whether insert failed diff --git a/includes/dbFacile.mysqli.php b/includes/dbFacile.mysqli.php index 2408ca990..7b48ad6b9 100644 --- a/includes/dbFacile.mysqli.php +++ b/includes/dbFacile.mysqli.php @@ -59,6 +59,33 @@ function dbQuery($sql, $parameters=array()) { }//end dbQuery() +/* + * Aquire a lock on a string + * */ +function dbGetLock($data, $timeout = 0) { + $sql = 'SELECT GET_LOCK(\'' . $data . '\',' . $timeout . ')'; + echo "printing sql: "; + echo "$sql\n"; + $result = dbFetchCell($sql); + echo "printing result: "; + echo "$result\n"; + return $result; +} + + +/* + * Release a lock on a string + * */ +function dbReleaseLock($data, $timeout = 0) { + $sql = 'SELECT RELEASE_LOCK(\'' . $data . '\')'; + echo "printing sql: "; + echo "$sql\n"; + $result = dbFetchCell($sql); + echo "printing result: "; + echo "$result\n"; + return $result; +} + /* * Passed an array and a table name, it attempts to insert the data into the table. * Check for boolean false to determine whether insert failed diff --git a/poller.php b/poller.php index 6412c37be..8c2b32881 100755 --- a/poller.php +++ b/poller.php @@ -110,9 +110,11 @@ if (!isset($query)) { foreach (dbFetch($query) as $device) { $device = dbFetchRow("SELECT * FROM `devices` WHERE `device_id` = '".$device['device_id']."'"); - poll_device($device, $options); - RunRules($device['device_id']); - echo "\r\n"; + if (dbGetLock('polling.' . $device['device_id'])) { + poll_device($device, $options); + RunRules($device['device_id']); + echo "\r\n"; + } $polled_devices++; } From 8e34e83d9740bea782775077ff130c5e5960e758 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Mon, 6 Jul 2015 09:59:24 -0400 Subject: [PATCH 051/598] add swp to gitignore for vim --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index d56e86250..5c73ae6be 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ nbproject .alerts.lock .ircbot.alert .metadata_never_index +*.swp From b34fcf872851e0ee530aeea929dc298364d5445a Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Mon, 6 Jul 2015 10:19:05 -0400 Subject: [PATCH 052/598] remove debug echos --- includes/dbFacile.mysql.php | 11 +---------- includes/dbFacile.mysqli.php | 10 +--------- 2 files changed, 2 insertions(+), 19 deletions(-) diff --git a/includes/dbFacile.mysql.php b/includes/dbFacile.mysql.php index 44dc5d494..9fd82c698 100644 --- a/includes/dbFacile.mysql.php +++ b/includes/dbFacile.mysql.php @@ -64,11 +64,7 @@ function dbQuery($sql, $parameters=array()) { * */ function dbGetLock($data, $timeout = 0) { $sql = 'SELECT GET_LOCK(\'' . $data . '\',' . $timeout . ')'; - echo "printing sql: "; - echo "$sql\n"; $result = dbFetchCell($sql); - echo "printing result: "; - echo "$result\n"; return $result; } @@ -78,15 +74,10 @@ function dbGetLock($data, $timeout = 0) { * */ function dbReleaseLock($data, $timeout = 0) { $sql = 'SELECT RELEASE_LOCK(\'' . $data . '\')'; - echo "printing sql: "; - echo "$sql\n"; $result = dbFetchCell($sql); - echo "printing result: "; - echo "$result\n"; return $result; -} - + /* * Passed an array and a table name, it attempts to insert the data into the table. * Check for boolean false to determine whether insert failed diff --git a/includes/dbFacile.mysqli.php b/includes/dbFacile.mysqli.php index 7b48ad6b9..36b2208cb 100644 --- a/includes/dbFacile.mysqli.php +++ b/includes/dbFacile.mysqli.php @@ -64,11 +64,7 @@ function dbQuery($sql, $parameters=array()) { * */ function dbGetLock($data, $timeout = 0) { $sql = 'SELECT GET_LOCK(\'' . $data . '\',' . $timeout . ')'; - echo "printing sql: "; - echo "$sql\n"; $result = dbFetchCell($sql); - echo "printing result: "; - echo "$result\n"; return $result; } @@ -78,13 +74,9 @@ function dbGetLock($data, $timeout = 0) { * */ function dbReleaseLock($data, $timeout = 0) { $sql = 'SELECT RELEASE_LOCK(\'' . $data . '\')'; - echo "printing sql: "; - echo "$sql\n"; $result = dbFetchCell($sql); - echo "printing result: "; - echo "$result\n"; return $result; -} + /* * Passed an array and a table name, it attempts to insert the data into the table. From 7f262fd2cc3fcbd1b8daca8440d19fef493bab35 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Mon, 6 Jul 2015 10:47:18 -0400 Subject: [PATCH 053/598] limit sql query to amount_of_workers --- poller-service.py | 202 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 202 insertions(+) create mode 100644 poller-service.py diff --git a/poller-service.py b/poller-service.py new file mode 100644 index 000000000..291e95534 --- /dev/null +++ b/poller-service.py @@ -0,0 +1,202 @@ +""" + poller-service A service to wrap SNMP polling. It will poll up to $threads devices at a time, and will not re-poll + devices that have been polled within the last $frequency seconds. It will prioritize devices based on + the last time polled. If resources are sufficient, this service should poll every device every + $frequency seconds, but should gracefully degrade if resources are inefficient, polling devices as + frequently as possible. This service is based on poller-wrapper.py. + + Author: Clint Armstrong + Date: July 2015 + + Usage: poller-service [threads] [frequency] + Default is 16 threads and 300 seconds. +""" + +import json +import os +import Queue +import subprocess +import sys +import threading +import time +import MySQLdb + +install_dir = os.path.dirname(os.path.realpath(__file__)) +config_file = ob_install_dir + '/config.php' + +def get_config_data(): + config_cmd = ['/usr/bin/env', 'php', '%s/config_to_json.php' % ob_install_dir] + try: + proc = subprocess.Popen(config_cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE) + except: + print "ERROR: Could not execute: %s" % config_cmd + sys.exit(2) + return proc.communicate()[0] + +try: + with open(config_file) as f: + pass +except IOError as e: + print "ERROR: Oh dear... %s does not seem readable" % config_file + sys.exit(2) + +try: + config = json.loads(get_config_data()) +except: + print "ERROR: Could not load or parse configuration, are PATHs correct?" + sys.exit(2) + +poller_path = config['install_dir'] + '/poller.php' +db_username = config['db_user'] +db_password = config['db_pass'] + +if config['db_host'][:5].lower() == 'unix:': + db_server = config['db_host'] + db_port = 0 +elif ':' in config['db_host']: + db_server = config['db_host'].rsplit(':')[0] + db_port = int(config['db_host'].rsplit(':')[1]) +else: + db_server = config['db_host'] + db_port =0 + +db_dbname = config['db_name'] + +# (c) 2015, GPLv3, Daniel Preussker << 300: + print "WARNING: the process took more than 5 minutes to finish, you need faster hardware or more threads" + print "INFO: in sequential style polling the elapsed time would have been: %s seconds" % real_duration + for device in per_device_duration: + if per_device_duration[device] > 300: + print "WARNING: device %s is taking too long: %s seconds" % (device, per_device_duration[device]) + show_stopper = True + if show_stopper: + print "ERROR: Some devices are taking more than 300 seconds, the script cannot recommend you what to do." + else: + recommend = int(total_time / 300.0 * amount_of_workers + 1) + print "WARNING: Consider setting a minimum of %d threads. (This does not constitute professional advice!)" % recommend + + sys.exit(2) From 72844d112ea00975c29ec5efb2b98dd43ec21f8c Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Mon, 6 Jul 2015 10:50:08 -0400 Subject: [PATCH 054/598] make poller-service executable --- poller-service.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 poller-service.py diff --git a/poller-service.py b/poller-service.py old mode 100644 new mode 100755 From 2ba1d9e0ece2a9c7a1446b179878cf61ddfa3e4e Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Mon, 6 Jul 2015 10:52:32 -0400 Subject: [PATCH 055/598] add shebang --- poller-service.py | 1 + 1 file changed, 1 insertion(+) diff --git a/poller-service.py b/poller-service.py index 291e95534..0bdf2a08c 100755 --- a/poller-service.py +++ b/poller-service.py @@ -1,3 +1,4 @@ +#! /usr/bin/env python """ poller-service A service to wrap SNMP polling. It will poll up to $threads devices at a time, and will not re-poll devices that have been polled within the last $frequency seconds. It will prioritize devices based on From e479d8cf69fbacc48a70c1885ebea1059ceac7e3 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Mon, 6 Jul 2015 10:52:59 -0400 Subject: [PATCH 056/598] change variables --- poller-service.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/poller-service.py b/poller-service.py index 0bdf2a08c..08d1a7754 100755 --- a/poller-service.py +++ b/poller-service.py @@ -23,10 +23,10 @@ import time import MySQLdb install_dir = os.path.dirname(os.path.realpath(__file__)) -config_file = ob_install_dir + '/config.php' +config_file = install_dir + '/config.php' def get_config_data(): - config_cmd = ['/usr/bin/env', 'php', '%s/config_to_json.php' % ob_install_dir] + config_cmd = ['/usr/bin/env', 'php', '%s/config_to_json.php' % install_dir] try: proc = subprocess.Popen(config_cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE) except: From bd054d7a81856796576ec406c0e921dc23700919 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Mon, 6 Jul 2015 12:00:21 -0400 Subject: [PATCH 057/598] first attempt at looping logic --- poller-service.py | 86 ++++++++++++++++++++++++++++++----------------- 1 file changed, 55 insertions(+), 31 deletions(-) diff --git a/poller-service.py b/poller-service.py index 08d1a7754..82fc7ed4c 100755 --- a/poller-service.py +++ b/poller-service.py @@ -21,6 +21,7 @@ import sys import threading import time import MySQLdb +from datetime import datetime, timedelta install_dir = os.path.dirname(os.path.realpath(__file__)) config_file = install_dir + '/config.php' @@ -70,6 +71,11 @@ else: poller_group = False # EOC1 +s_time = time.time() +real_duration = 0 +per_device_duration = {} +polled_devices = 0 + # Take the amount of threads we want to run in parallel from the commandline # if None are given or the argument was garbage, fall back to default of 16 try: @@ -100,15 +106,6 @@ except: print "ERROR: Could not connect to MySQL database!" sys.exit(2) -# Query ordering based on last polled date, so that the device with the oldest data is polled first. -query = 'select device_id from devices {} disabled = 0 order by last_polled asc limit {}'.format( - 'where poller_group IN({}) and'.format(poller_group) if poller_group else '', - amount_of_workers) - -cursor.execute(query) -devices_list = cursor.fetchall() - - # A seperate queue and a single worker for printing information to the screen prevents # the good old joke: # @@ -118,6 +115,7 @@ devices_list = cursor.fetchall() def printworker(): nodeso = 0 while True: + worker_id, device_id, elapsed_time = print_queue.get() global real_duration global per_device_duration global polled_devices @@ -130,41 +128,67 @@ def printworker(): print "WARNING: worker %s finished device %s in %s seconds" % (worker_id, device_id, elapsed_time) print_queue.task_done() -def poll_worker(): - while True: - device_id = poll_queue.get() - try: - start_time = time.time() - command = "/usr/bin/env php %s -h %s >> /dev/null 2>&1" % (poller_path, device_id) - subprocess.check_call(command, shell=True) - elapsed_time = int(time.time() - start_time) - print_queue.put([threading.current_thread().name, device_id, elapsed_time]) - except (KeyboardInterrupt, SystemExit): - raise - except: - pass - poll_queue.task_done() +def poll_worker(device_id): + try: + start_time = time.time() + command = "/usr/bin/env php %s -h %s >> /dev/null 2>&1" % (poller_path, device_id) + subprocess.check_call(command, shell=True) + elapsed_time = int(time.time() - start_time) + print_queue.put([threading.current_thread().name, device_id, elapsed_time]) + except (KeyboardInterrupt, SystemExit): + raise + except: + pass -poll_queue = Queue.Queue() print_queue = Queue.Queue() print "INFO: starting the poller at %s with %s threads, slowest devices first" % (time.strftime("%Y-%m-%d %H:%M:%S"), amount_of_workers) -for device_id in devices_list: - poll_queue.put(device_id) -for i in range(amount_of_workers): - t = threading.Thread(target=poll_worker) - t.setDaemon(True) - t.start() +def queue_feeder(): + while True: + if threading.active_count() > amount_of_workers + 1: + time.sleep(1) + continue + + query = 'select device_id,last_polled from devices {} disabled = 0 order by last_polled asc'.format( + 'where poller_group IN({}) and'.format(poller_group) if poller_group else '') + cursor.execute(query) + for device_id, last_polled in cursor.fetchall(): + cursor.execute("SELECT IS_FREE_LOCK('polling.{}')".format(device_id)) + if cursor.fetchone()[0] != 1: + continue + cursor.execute("SELECT IS_FREE_LOCK('queued.{}')".format(device_id)) + if cursor.fetchone()[0] != 1: + continue + last_polled_date = strptime(last_polled, '%Y-%m-%d %H:%M:%S') + if last_polled_date < datetime.now() - timedelta(seconds=frequency): + t = threading.Thread(target=poll_worker(device_id)) + t.setDaemon(True) + t.start() + break + else: + cursor.execute("SELECT GET_LOCK('queued.{}')".format(device_id)) + if cursor.fetchone()[0] != 1: + break + sleeptime = ((last_polled_date + timedelta(seconds=300)) - datetime.now()).seconds + datetime.sleep(sleeptime) + t = threading.Thread(target=poll_worker(device_id)) + t.setDaemon(True) + t.start() + cursor.execute("SELECT RELEASE_LOCK('queued.{}')".format(device_id)) + break p = threading.Thread(target=printworker) p.setDaemon(True) p.start() +f = threading.Thread(target=queue_feeder) +f.setDaemon(True) +f.start() + try: - poll_queue.join() print_queue.join() except (KeyboardInterrupt, SystemExit): raise From 4d3b7a3c0fe75ff31af5569714506b635bd3c748 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Mon, 6 Jul 2015 14:51:03 -0400 Subject: [PATCH 058/598] working --- poller-service.py | 140 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 98 insertions(+), 42 deletions(-) diff --git a/poller-service.py b/poller-service.py index 82fc7ed4c..60588dde6 100755 --- a/poller-service.py +++ b/poller-service.py @@ -90,17 +90,28 @@ except: # if None are given or the argument was garbage, fall back to default of 300 try: frequency = int(sys.argv[2]) - if amount_of_workers == 0: + if frequency == 0: print "ERROR: 0 seconds is not a valid value" sys.exit(2) except: frequency = 300 +# Take the down_retry value from the commandline +# if None are given or the argument was garbage, fall back to default of 15 +try: + down_retry = int(sys.argv[3]) + if down_retry == 0: + print "ERROR: 0 seconds is not a valid value" + sys.exit(2) +except: + down_retry = 15 + try: if db_port == 0: db = MySQLdb.connect(host=db_server, user=db_username, passwd=db_password, db=db_dbname) else: db = MySQLdb.connect(host=db_server, port=db_port, user=db_username, passwd=db_password, db=db_dbname) + db.autocommit(True) cursor = db.cursor() except: print "ERROR: Could not connect to MySQL database!" @@ -137,56 +148,101 @@ def poll_worker(device_id): print_queue.put([threading.current_thread().name, device_id, elapsed_time]) except (KeyboardInterrupt, SystemExit): raise - except: - pass + #except: + # pass print_queue = Queue.Queue() -print "INFO: starting the poller at %s with %s threads, slowest devices first" % (time.strftime("%Y-%m-%d %H:%M:%S"), +print "INFO: starting the poller at %s with %s threads" % (time.strftime("%Y-%m-%d %H:%M:%S"), amount_of_workers) - -def queue_feeder(): - while True: - if threading.active_count() > amount_of_workers + 1: - time.sleep(1) - continue - - query = 'select device_id,last_polled from devices {} disabled = 0 order by last_polled asc'.format( - 'where poller_group IN({}) and'.format(poller_group) if poller_group else '') - cursor.execute(query) - for device_id, last_polled in cursor.fetchall(): - cursor.execute("SELECT IS_FREE_LOCK('polling.{}')".format(device_id)) - if cursor.fetchone()[0] != 1: - continue - cursor.execute("SELECT IS_FREE_LOCK('queued.{}')".format(device_id)) - if cursor.fetchone()[0] != 1: - continue - last_polled_date = strptime(last_polled, '%Y-%m-%d %H:%M:%S') - if last_polled_date < datetime.now() - timedelta(seconds=frequency): - t = threading.Thread(target=poll_worker(device_id)) - t.setDaemon(True) - t.start() - break - else: - cursor.execute("SELECT GET_LOCK('queued.{}')".format(device_id)) - if cursor.fetchone()[0] != 1: - break - sleeptime = ((last_polled_date + timedelta(seconds=300)) - datetime.now()).seconds - datetime.sleep(sleeptime) - t = threading.Thread(target=poll_worker(device_id)) - t.setDaemon(True) - t.start() - cursor.execute("SELECT RELEASE_LOCK('queued.{}')".format(device_id)) - break - p = threading.Thread(target=printworker) p.setDaemon(True) p.start() -f = threading.Thread(target=queue_feeder) -f.setDaemon(True) -f.start() +def lockFree(lock): + global cursor + query = "SELECT IS_FREE_LOCK('{}')".format(lock) + #print 'checking lock: {}'.format(query) + cursor.execute(query) + return cursor.fetchall()[0][0] == 1 + +def getLock(lock): + global cursor + query = "SELECT GET_LOCK('{}', 0)".format(lock) + #print 'getting lock: {}'.format(query) + cursor.execute(query) + return cursor.fetchall()[0][0] == 1 + +def releaseLock(lock): + global cursor + query = "SELECT RELEASE_LOCK('{}')".format(lock) + #print 'releasing lock: {}'.format(query) + cursor.execute(query) + return cursor.fetchall()[0][0] == 1 + +recently_scanned = {} + +while True: + print '{} threads currently active'.format(threading.active_count()) + while threading.active_count() >= amount_of_workers: + time.sleep(.5) + + #print 'querying for devices' + query = 'select device_id,last_polled from devices {} disabled = 0 order by last_polled asc'.format( + 'where poller_group IN({}) and'.format(poller_group) if poller_group else '') + cursor.execute(query) + devices = cursor.fetchall() + dead_retry_in = frequency + #print "first 5 devices: {}".format(devices[:5]) + for device_id, last_polled in devices: +# print 'trying device {}'.format(device_id) +# time.sleep(1) + if not lockFree('polling.{}'.format(device_id)): +# print 'polling lock is not free on {} continuing'.format(device_id) +# time.sleep(1) + continue + if not lockFree('queued.{}'.format(device_id)): +# print 'queued lock is not free on {} continuing'.format(device_id) +# time.sleep(1) + continue + try: + if ((recently_scanned[device_id] + timedelta(seconds=down_retry)) - datetime.now()).seconds > 1: + dead_retry_in = ((recently_scanned[device_id] + timedelta(seconds=down_retry)) - datetime.now()).seconds +# print 'device {} recently scanned already'.format(device_id) +# time.sleep(1) + continue + except KeyError: + pass + + # add queue lock, so if we sleep, we lock the next device against any other pollers, break + # if aquiring lock fails + if not getLock('queued.{}'.format(device_id)): +# print 'getting queue lock on {} failed'.format(device_id) +# time.sleep(1) + break + + if last_polled > datetime.now() - timedelta(seconds=frequency): + sleeptime = ((last_polled + timedelta(seconds=300)) - datetime.now()).seconds + if sleeptime > dead_retry_in: + print 'Sleeping {} seconds before retrying failed device'.format(dead_retry_in, device_id, last_polled) + time.sleep(dead_retry_in) + break + + print 'Sleeping {} seconds before polling {}, last polled {}'.format(sleeptime, device_id, last_polled) + time.sleep(sleeptime) + + print 'Starting poll of device {}, last polled {}'.format(device_id, last_polled) + recently_scanned[device_id] = datetime.now() + t = threading.Thread(target=poll_worker, args=[device_id]) + #t.setDaemon(True) + t.start() + #print 'thread launched' + + releaseLock('queued.{}'.format(device_id)) + + # If we made it this far, break out of the loop and query again. + break try: print_queue.join() From 99cf049645fc28ee5c14b200cad6f79e3aa0ebfc Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Mon, 6 Jul 2015 15:10:48 -0400 Subject: [PATCH 059/598] cleaned up --- poller-service.py | 85 ++++++++++------------------------------------- 1 file changed, 17 insertions(+), 68 deletions(-) diff --git a/poller-service.py b/poller-service.py index 60588dde6..7150e313b 100755 --- a/poller-service.py +++ b/poller-service.py @@ -26,6 +26,7 @@ from datetime import datetime, timedelta install_dir = os.path.dirname(os.path.realpath(__file__)) config_file = install_dir + '/config.php' + def get_config_data(): config_cmd = ['/usr/bin/env', 'php', '%s/config_to_json.php' % install_dir] try: @@ -53,24 +54,17 @@ db_username = config['db_user'] db_password = config['db_pass'] if config['db_host'][:5].lower() == 'unix:': - db_server = config['db_host'] - db_port = 0 + db_server = config['db_host'] + db_port = 0 elif ':' in config['db_host']: - db_server = config['db_host'].rsplit(':')[0] - db_port = int(config['db_host'].rsplit(':')[1]) + db_server = config['db_host'].rsplit(':')[0] + db_port = int(config['db_host'].rsplit(':')[1]) else: - db_server = config['db_host'] - db_port =0 + db_server = config['db_host'] + db_port = 0 db_dbname = config['db_name'] -# (c) 2015, GPLv3, Daniel Preussker <<= amount_of_workers: time.sleep(.5) - #print 'querying for devices' query = 'select device_id,last_polled from devices {} disabled = 0 order by last_polled asc'.format( - 'where poller_group IN({}) and'.format(poller_group) if poller_group else '') + 'where poller_group IN({}) and'.format(str(config['distributed_poller_group'])) + if 'distributed_poller_group' in config else '') cursor.execute(query) devices = cursor.fetchall() dead_retry_in = frequency - #print "first 5 devices: {}".format(devices[:5]) for device_id, last_polled in devices: -# print 'trying device {}'.format(device_id) -# time.sleep(1) if not lockFree('polling.{}'.format(device_id)): -# print 'polling lock is not free on {} continuing'.format(device_id) -# time.sleep(1) continue if not lockFree('queued.{}'.format(device_id)): -# print 'queued lock is not free on {} continuing'.format(device_id) -# time.sleep(1) continue try: if ((recently_scanned[device_id] + timedelta(seconds=down_retry)) - datetime.now()).seconds > 1: dead_retry_in = ((recently_scanned[device_id] + timedelta(seconds=down_retry)) - datetime.now()).seconds -# print 'device {} recently scanned already'.format(device_id) -# time.sleep(1) continue except KeyError: pass @@ -218,8 +204,6 @@ while True: # add queue lock, so if we sleep, we lock the next device against any other pollers, break # if aquiring lock fails if not getLock('queued.{}'.format(device_id)): -# print 'getting queue lock on {} failed'.format(device_id) -# time.sleep(1) break if last_polled > datetime.now() - timedelta(seconds=frequency): @@ -235,9 +219,7 @@ while True: print 'Starting poll of device {}, last polled {}'.format(device_id, last_polled) recently_scanned[device_id] = datetime.now() t = threading.Thread(target=poll_worker, args=[device_id]) - #t.setDaemon(True) t.start() - #print 'thread launched' releaseLock('queued.{}'.format(device_id)) @@ -248,36 +230,3 @@ try: print_queue.join() except (KeyboardInterrupt, SystemExit): raise - -total_time = int(time.time() - s_time) - -print "INFO: poller-wrapper polled %s devices in %s seconds with %s workers" % (polled_devices, total_time, amount_of_workers) - -show_stopper = False - -query = "update pollers set last_polled=NOW(), devices='%d', time_taken='%d' where poller_name='%s'" % (polled_devices, - total_time, config['distributed_poller_name']) -response = cursor.execute(query) -if response == 1: - db.commit() -else: - query = "insert into pollers set poller_name='%s', last_polled=NOW(), devices='%d', time_taken='%d'" % ( - config['distributed_poller_name'], polled_devices, total_time) - cursor.execute(query) - db.commit() -db.close() - -if total_time > 300: - print "WARNING: the process took more than 5 minutes to finish, you need faster hardware or more threads" - print "INFO: in sequential style polling the elapsed time would have been: %s seconds" % real_duration - for device in per_device_duration: - if per_device_duration[device] > 300: - print "WARNING: device %s is taking too long: %s seconds" % (device, per_device_duration[device]) - show_stopper = True - if show_stopper: - print "ERROR: Some devices are taking more than 300 seconds, the script cannot recommend you what to do." - else: - recommend = int(total_time / 300.0 * amount_of_workers + 1) - print "WARNING: Consider setting a minimum of %d threads. (This does not constitute professional advice!)" % recommend - - sys.exit(2) From 1dcaa51011acb7f5d3c434746bc87d116704b009 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Tue, 7 Jul 2015 10:09:55 -0400 Subject: [PATCH 060/598] more efficient sql queries, working well all night --- poller-service.py | 96 ++++++++++++++++++++++++++++++----------------- 1 file changed, 61 insertions(+), 35 deletions(-) diff --git a/poller-service.py b/poller-service.py index 7150e313b..13c3af851 100755 --- a/poller-service.py +++ b/poller-service.py @@ -176,53 +176,79 @@ def releaseLock(lock): cursor.execute(query) return cursor.fetchall()[0][0] == 1 -recently_scanned = {} +def sleep_until(timestamp): + now = datetime.now() + if timestamp > now: + sleeptime = (timestamp - now).seconds + else: + sleeptime = 0 + time.sleep(sleeptime) + +poller_group = ('and poller_group IN({}) ' + .format(str(config['distributed_poller_group'])) if 'distributed_poller_group' in config else '') + +# Add last_polled and last_polled_timetaken so we can sort by the time the last poll started, with the goal +# of having each device complete a poll within the given time range. +dev_query = ( 'SELECT device_id, ' + 'DATE_ADD( ' + ' DATE_SUB( ' + ' last_polled, ' + ' INTERVAL last_polled_timetaken SECOND ' + ' ), ' + ' INTERVAL {0} SECOND) AS next_poll ' + 'FROM devices WHERE ' + 'disabled = 0 ' + 'AND IS_FREE_LOCK(CONCAT("polling.", device_id)) ' + 'AND IS_FREE_LOCK(CONCAT("queued.", device_id)) ' + '{1} ' + 'ORDER BY next_poll asc ').format(frequency, poller_group) + +dont_retry = {} +threads = 0 while True: - print '{} threads currently active'.format(threading.active_count()) + cur_threads = threading.active_count() + if cur_threads != threads: + threads = cur_threads + print 'INFO: {} threads currently active'.format(threads) + + dont_retry = dict((dev, time) for dev, time in dont_retry.iteritems() if time > datetime.now()) + while threading.active_count() >= amount_of_workers: time.sleep(.5) - query = 'select device_id,last_polled from devices {} disabled = 0 order by last_polled asc'.format( - 'where poller_group IN({}) and'.format(str(config['distributed_poller_group'])) - if 'distributed_poller_group' in config else '') - cursor.execute(query) + cursor.execute(dev_query) devices = cursor.fetchall() - dead_retry_in = frequency - for device_id, last_polled in devices: - if not lockFree('polling.{}'.format(device_id)): - continue - if not lockFree('queued.{}'.format(device_id)): - continue - try: - if ((recently_scanned[device_id] + timedelta(seconds=down_retry)) - datetime.now()).seconds > 1: - dead_retry_in = ((recently_scanned[device_id] + timedelta(seconds=down_retry)) - datetime.now()).seconds - continue - except KeyError: - pass - - # add queue lock, so if we sleep, we lock the next device against any other pollers, break - # if aquiring lock fails + for device_id, next_poll in devices: + # add queue lock, so we lock the next device against any other pollers + # if this fails, the device is locked by another poller already if not getLock('queued.{}'.format(device_id)): - break + continue + if not lockFree('polling.{}'.format(device_id)): + releaseLock('queued.{}'.format(device_id)) + continue + if device_id in dont_retry: + releaseLock('queued.{}'.format(device_id)) + continue - if last_polled > datetime.now() - timedelta(seconds=frequency): - sleeptime = ((last_polled + timedelta(seconds=300)) - datetime.now()).seconds - if sleeptime > dead_retry_in: - print 'Sleeping {} seconds before retrying failed device'.format(dead_retry_in, device_id, last_polled) - time.sleep(dead_retry_in) - break + if next_poll > datetime.now(): + next_retry_device = min(dont_retry, key=dont_retry.get) + next_retry_time = dont_retry[next_retry_device] + if next_retry_time < next_poll: + device_id = next_retry_device + if not getLock('queued.{}'.format(device_id)): + continue + print 'INFO: Sleeping until {} before retrying failed device {}'.format(next_retry_time, device_id) + sleep_until(next_retry_time) + else: + print 'INFO: Sleeping until {} before polling {}'.format(next_poll, device_id) + sleep_until(next_poll) - print 'Sleeping {} seconds before polling {}, last polled {}'.format(sleeptime, device_id, last_polled) - time.sleep(sleeptime) - - print 'Starting poll of device {}, last polled {}'.format(device_id, last_polled) - recently_scanned[device_id] = datetime.now() + print 'INFO: Starting poll of device {}'.format(device_id) + dont_retry[device_id] = datetime.now() + timedelta(seconds=down_retry) t = threading.Thread(target=poll_worker, args=[device_id]) t.start() - releaseLock('queued.{}'.format(device_id)) - # If we made it this far, break out of the loop and query again. break From 4736544e7e691e125265bc6194a60ed496afb8e4 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Tue, 7 Jul 2015 10:27:40 -0400 Subject: [PATCH 061/598] fix bug on retrying failed devices --- poller-service.py | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/poller-service.py b/poller-service.py index 13c3af851..b07424d83 100755 --- a/poller-service.py +++ b/poller-service.py @@ -219,6 +219,7 @@ while True: cursor.execute(dev_query) devices = cursor.fetchall() + retry_devs_found = {} for device_id, next_poll in devices: # add queue lock, so we lock the next device against any other pollers # if this fails, the device is locked by another poller already @@ -228,21 +229,27 @@ while True: releaseLock('queued.{}'.format(device_id)) continue if device_id in dont_retry: + retry_devs_found[device_id] = dont_retry[device_id] releaseLock('queued.{}'.format(device_id)) continue if next_poll > datetime.now(): - next_retry_device = min(dont_retry, key=dont_retry.get) - next_retry_time = dont_retry[next_retry_device] - if next_retry_time < next_poll: - device_id = next_retry_device - if not getLock('queued.{}'.format(device_id)): - continue - print 'INFO: Sleeping until {} before retrying failed device {}'.format(next_retry_time, device_id) - sleep_until(next_retry_time) - else: - print 'INFO: Sleeping until {} before polling {}'.format(next_poll, device_id) - sleep_until(next_poll) + poll_action = 'polling' + sleep_until_time = next_poll + try: + next_retry_device = min(retry_devs_found, key=retry_devs_found.get) + next_retry_time = retry_devs_found[next_retry_device] + if next_retry_time < next_poll: + device_id = next_retry_device + if not getLock('queued.{}'.format(device_id)): + continue + poll_action = 'retrying failed device' + sleep_until_time = next_retry_time + except ValueError: + pass + + print 'INFO: Sleeping until {0} before {1} {2}'.format(next_poll, poll_action, device_id) + sleep_until(sleep_until_time) print 'INFO: Starting poll of device {}'.format(device_id) dont_retry[device_id] = datetime.now() + timedelta(seconds=down_retry) From e9ffc7a374398134cbc435863146b6a802a921ac Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Tue, 7 Jul 2015 10:35:36 -0400 Subject: [PATCH 062/598] thread numbers are meaningless --- poller-service.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/poller-service.py b/poller-service.py index b07424d83..bdf9a3aea 100755 --- a/poller-service.py +++ b/poller-service.py @@ -129,9 +129,9 @@ def printworker(): per_device_duration[device_id] = elapsed_time polled_devices += 1 if elapsed_time < 300: - print "INFO: worker %s finished device %s in %s seconds" % (worker_id, device_id, elapsed_time) + print "INFO: worker finished device %s in %s seconds" % (device_id, elapsed_time) else: - print "WARNING: worker %s finished device %s in %s seconds" % (worker_id, device_id, elapsed_time) + print "WARNING: worker finished device %s in %s seconds" % (device_id, elapsed_time) print_queue.task_done() From 2b3d70e928a35c7bd2e4f80fa191ad97818db897 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Tue, 7 Jul 2015 11:20:09 -0400 Subject: [PATCH 063/598] add proper logging --- poller-service.py | 78 +++++++++++++++++++---------------------------- 1 file changed, 32 insertions(+), 46 deletions(-) diff --git a/poller-service.py b/poller-service.py index bdf9a3aea..e3172e285 100755 --- a/poller-service.py +++ b/poller-service.py @@ -21,18 +21,29 @@ import sys import threading import time import MySQLdb +import logging +import logging.handlers from datetime import datetime, timedelta +log = logging.getLogger('poller-service') +log.setLevel(logging.DEBUG) + +formatter = logging.Formatter('poller-service: %(message)s') +handler = logging.handlers.SysLogHandler(address= '/dev/log') +handler.setFormatter(formatter) +log.addHandler(handler) + install_dir = os.path.dirname(os.path.realpath(__file__)) config_file = install_dir + '/config.php' +log.info('Starting poller-service') def get_config_data(): config_cmd = ['/usr/bin/env', 'php', '%s/config_to_json.php' % install_dir] try: proc = subprocess.Popen(config_cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE) except: - print "ERROR: Could not execute: %s" % config_cmd + log.critical("ERROR: Could not execute: %s" % config_cmd) sys.exit(2) return proc.communicate()[0] @@ -40,13 +51,13 @@ try: with open(config_file) as f: pass except IOError as e: - print "ERROR: Oh dear... %s does not seem readable" % config_file + log.critical("ERROR: Oh dear... %s does not seem readable" % config_file) sys.exit(2) try: config = json.loads(get_config_data()) except: - print "ERROR: Could not load or parse configuration, are PATHs correct?" + log.critical("ERROR: Could not load or parse configuration, are PATHs correct?") sys.exit(2) poller_path = config['install_dir'] + '/poller.php' @@ -65,17 +76,13 @@ else: db_dbname = config['db_name'] -s_time = time.time() -real_duration = 0 -per_device_duration = {} -polled_devices = 0 # Take the amount of threads we want to run in parallel from the commandline # if None are given or the argument was garbage, fall back to default of 16 try: amount_of_workers = int(sys.argv[1]) if amount_of_workers == 0: - print "ERROR: 0 threads is not a valid value" + log.critical("ERROR: 0 threads is not a valid value") sys.exit(2) except: amount_of_workers = 16 @@ -85,7 +92,7 @@ except: try: frequency = int(sys.argv[2]) if frequency == 0: - print "ERROR: 0 seconds is not a valid value" + log.critical("ERROR: 0 seconds is not a valid value") sys.exit(2) except: frequency = 300 @@ -95,7 +102,7 @@ except: try: down_retry = int(sys.argv[3]) if down_retry == 0: - print "ERROR: 0 seconds is not a valid value" + log.critical("ERROR: 0 seconds is not a valid value") sys.exit(2) except: down_retry = 15 @@ -108,32 +115,9 @@ try: db.autocommit(True) cursor = db.cursor() except: - print "ERROR: Could not connect to MySQL database!" + log.critical("ERROR: Could not connect to MySQL database!") sys.exit(2) -# A seperate queue and a single worker for printing information to the screen prevents -# the good old joke: -# -# Some people, when confronted with a problem, think, -# "I know, I'll use threads," and then two they hav erpoblesms. - - -def printworker(): - nodeso = 0 - while True: - worker_id, device_id, elapsed_time = print_queue.get() - global real_duration - global per_device_duration - global polled_devices - real_duration += elapsed_time - per_device_duration[device_id] = elapsed_time - polled_devices += 1 - if elapsed_time < 300: - print "INFO: worker finished device %s in %s seconds" % (device_id, elapsed_time) - else: - print "WARNING: worker finished device %s in %s seconds" % (device_id, elapsed_time) - print_queue.task_done() - def poll_worker(device_id): try: @@ -141,20 +125,15 @@ def poll_worker(device_id): command = "/usr/bin/env php %s -h %s >> /dev/null 2>&1" % (poller_path, device_id) subprocess.check_call(command, shell=True) elapsed_time = int(time.time() - start_time) - print_queue.put([threading.current_thread().name, device_id, elapsed_time]) + if elapsed_time < 300: + log.debug("DEBUG: worker finished device %s in %s seconds" % (device_id, elapsed_time)) + else: + log.warning("WARNING: worker finished device %s in %s seconds" % (device_id, elapsed_time)) except (KeyboardInterrupt, SystemExit): raise except: pass -print_queue = Queue.Queue() - -print "INFO: starting the poller at %s with %s threads" % (time.strftime("%Y-%m-%d %H:%M:%S"), amount_of_workers) - -p = threading.Thread(target=printworker) -p.setDaemon(True) -p.start() - def lockFree(lock): global cursor @@ -205,12 +184,18 @@ dev_query = ( 'SELECT device_id, ' dont_retry = {} threads = 0 +next_update = datetime.now() + timedelta(minutes=5) while True: cur_threads = threading.active_count() if cur_threads != threads: threads = cur_threads - print 'INFO: {} threads currently active'.format(threads) + log.debug('DEBUG: {} threads currently active'.format(threads)) + + if next_update < datetime.now(): + log.info('INFO: {} devices scanned in the last 5 minutes'.format(devices_scanned)) + devices_scanned = 0 + next_update = datetime.now() + timedelta(minutes=5) dont_retry = dict((dev, time) for dev, time in dont_retry.iteritems() if time > datetime.now()) @@ -248,10 +233,11 @@ while True: except ValueError: pass - print 'INFO: Sleeping until {0} before {1} {2}'.format(next_poll, poll_action, device_id) + log.debug('DEBUG: Sleeping until {0} before {1} {2}'.format(next_poll, poll_action, device_id)) sleep_until(sleep_until_time) - print 'INFO: Starting poll of device {}'.format(device_id) + log.debug('INFO: Starting poll of device {}'.format(device_id)) + devices_scanned += 1 dont_retry[device_id] = datetime.now() + timedelta(seconds=down_retry) t = threading.Thread(target=poll_worker, args=[device_id]) t.start() From f7993a204c2f1113217ddefd97bccf1fa9465c5b Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Tue, 7 Jul 2015 11:29:04 -0400 Subject: [PATCH 064/598] log level from config --- poller-service.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/poller-service.py b/poller-service.py index e3172e285..1b84e69e0 100755 --- a/poller-service.py +++ b/poller-service.py @@ -60,6 +60,13 @@ except: log.critical("ERROR: Could not load or parse configuration, are PATHs correct?") sys.exit(2) +try: + loglevel = config['poller_service_loglevel'] +except KeyError: + loglevel = 'INFO' +numeric_level = getattr(logging, loglevel.upper(), None) +log.basicConfig(level=numeric_level) + poller_path = config['install_dir'] + '/poller.php' db_username = config['db_user'] db_password = config['db_pass'] @@ -185,6 +192,7 @@ dev_query = ( 'SELECT device_id, ' dont_retry = {} threads = 0 next_update = datetime.now() + timedelta(minutes=5) +devices_scanned = 0 while True: cur_threads = threading.active_count() @@ -236,7 +244,7 @@ while True: log.debug('DEBUG: Sleeping until {0} before {1} {2}'.format(next_poll, poll_action, device_id)) sleep_until(sleep_until_time) - log.debug('INFO: Starting poll of device {}'.format(device_id)) + log.debug('DEBUG: Starting poll of device {}'.format(device_id)) devices_scanned += 1 dont_retry[device_id] = datetime.now() + timedelta(seconds=down_retry) t = threading.Thread(target=poll_worker, args=[device_id]) From e30aea0168e02c521dacd3def5de9b32bdb88722 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Tue, 7 Jul 2015 11:40:29 -0400 Subject: [PATCH 065/598] get all config from config.php --- poller-service.py | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/poller-service.py b/poller-service.py index 1b84e69e0..6492ab0bc 100755 --- a/poller-service.py +++ b/poller-service.py @@ -36,7 +36,7 @@ log.addHandler(handler) install_dir = os.path.dirname(os.path.realpath(__file__)) config_file = install_dir + '/config.php' -log.info('Starting poller-service') +log.info('INFO: Starting poller-service') def get_config_data(): config_cmd = ['/usr/bin/env', 'php', '%s/config_to_json.php' % install_dir] @@ -61,11 +61,13 @@ except: sys.exit(2) try: - loglevel = config['poller_service_loglevel'] + loglevel = logging.getLevelName(config['poller_service_loglevel'].upper()) except KeyError: - loglevel = 'INFO' -numeric_level = getattr(logging, loglevel.upper(), None) -log.basicConfig(level=numeric_level) + loglevel = logging.getLevelName('INFO') +if not isinstance(loglevel, int): + log.warning('ERROR: {} is not a valid log level'.format(str(loglevel))) + loglevel = logging.getLevelName('INFO') +log.setLevel(loglevel) poller_path = config['install_dir'] + '/poller.php' db_username = config['db_user'] @@ -84,34 +86,28 @@ else: db_dbname = config['db_name'] -# Take the amount of threads we want to run in parallel from the commandline -# if None are given or the argument was garbage, fall back to default of 16 try: - amount_of_workers = int(sys.argv[1]) + amount_of_workers = int(config['poller_service_workers']) if amount_of_workers == 0: log.critical("ERROR: 0 threads is not a valid value") sys.exit(2) -except: +except KeyError: amount_of_workers = 16 -# Take the frequency of scans we want from the commandline -# if None are given or the argument was garbage, fall back to default of 300 try: - frequency = int(sys.argv[2]) + frequency = int(config['poller_service_frequency']) if frequency == 0: log.critical("ERROR: 0 seconds is not a valid value") sys.exit(2) -except: +except KeyError: frequency = 300 -# Take the down_retry value from the commandline -# if None are given or the argument was garbage, fall back to default of 15 try: - down_retry = int(sys.argv[3]) + down_retry = int(config['poller_service_down_retry']) if down_retry == 0: log.critical("ERROR: 0 seconds is not a valid value") sys.exit(2) -except: +except KeyError: down_retry = 15 try: From 57bf214df3c5ce02127bb672fd3e08d24fb14c9d Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Tue, 7 Jul 2015 11:41:42 -0400 Subject: [PATCH 066/598] first attempt at upstart conf --- poller-service.conf | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 poller-service.conf diff --git a/poller-service.conf b/poller-service.conf new file mode 100644 index 000000000..c5a9f26d2 --- /dev/null +++ b/poller-service.conf @@ -0,0 +1,28 @@ +# poller-service - SNMP polling service for LibreNMS + +description "SNMP polling service for LibreNMS" +author "Clint Armstrong " + +# When to start the service +start on runlevel [2345] + +# When to stop the service +stop on runlevel [016] + +# Automatically restart process if crashed +respawn + +# Essentially lets upstart know the process will detach itself to the background +expect fork + +# # Run before process +# pre-start script +# [ -d /var/run/myservice ] || mkdir -p /var/run/myservice +# echo "Put bash code here" +# end script + +# Set working directory +chdir /opt/librenms + +# Start the process +exec su -u librenms poller-service.py From cf8844742ef8b5088faba17abd12b4e1f4f45b36 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Tue, 7 Jul 2015 12:04:36 -0400 Subject: [PATCH 067/598] poller service upstart conf working --- poller-service.conf | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/poller-service.conf b/poller-service.conf index c5a9f26d2..36677e7d2 100644 --- a/poller-service.conf +++ b/poller-service.conf @@ -13,7 +13,7 @@ stop on runlevel [016] respawn # Essentially lets upstart know the process will detach itself to the background -expect fork +#expect fork # # Run before process # pre-start script @@ -21,8 +21,9 @@ expect fork # echo "Put bash code here" # end script -# Set working directory chdir /opt/librenms +setuid librenms +setgid librenms # Start the process -exec su -u librenms poller-service.py +exec /opt/librenms/poller-service.py From c7423d2c4e1b1ad81a9dafd4cbc87a82587666ce Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Tue, 7 Jul 2015 12:48:36 -0400 Subject: [PATCH 068/598] start docs --- doc/Extensions/Poller-Service.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 doc/Extensions/Poller-Service.md diff --git a/doc/Extensions/Poller-Service.md b/doc/Extensions/Poller-Service.md new file mode 100644 index 000000000..9c515c378 --- /dev/null +++ b/doc/Extensions/Poller-Service.md @@ -0,0 +1,2 @@ +# Poller Service +The Poller service is an alternative to polling cron jobs. From f293e3d9679b4b93965f4156f3a777ccd8886636 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Tue, 7 Jul 2015 13:02:13 -0400 Subject: [PATCH 069/598] add discovery support to service --- poller-service.py | 50 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/poller-service.py b/poller-service.py index 6492ab0bc..f1530f1b5 100755 --- a/poller-service.py +++ b/poller-service.py @@ -1,15 +1,15 @@ #! /usr/bin/env python """ poller-service A service to wrap SNMP polling. It will poll up to $threads devices at a time, and will not re-poll - devices that have been polled within the last $frequency seconds. It will prioritize devices based on + devices that have been polled within the last $poll_frequency seconds. It will prioritize devices based on the last time polled. If resources are sufficient, this service should poll every device every - $frequency seconds, but should gracefully degrade if resources are inefficient, polling devices as + $poll_frequency seconds, but should gracefully degrade if resources are inefficient, polling devices as frequently as possible. This service is based on poller-wrapper.py. Author: Clint Armstrong Date: July 2015 - Usage: poller-service [threads] [frequency] + Usage: poller-service [threads] [poll_frequency] Default is 16 threads and 300 seconds. """ @@ -70,6 +70,7 @@ if not isinstance(loglevel, int): log.setLevel(loglevel) poller_path = config['install_dir'] + '/poller.php' +discover_path = config['install_dir'] + '/discovery.php' db_username = config['db_user'] db_password = config['db_pass'] @@ -95,12 +96,20 @@ except KeyError: amount_of_workers = 16 try: - frequency = int(config['poller_service_frequency']) - if frequency == 0: + poll_frequency = int(config['poller_service_poll_frequency']) + if poll_frequency == 0: log.critical("ERROR: 0 seconds is not a valid value") sys.exit(2) except KeyError: - frequency = 300 + poll_frequency = 300 + +try: + discover_frequency = int(config['poller_service_discover_frequency']) + if poll_frequency == 0: + log.critical("ERROR: 0 seconds is not a valid value") + sys.exit(2) +except KeyError: + poll_frequency = 21600 try: down_retry = int(config['poller_service_down_retry']) @@ -122,10 +131,13 @@ except: sys.exit(2) -def poll_worker(device_id): +def poll_worker(device_id, action): try: start_time = time.time() - command = "/usr/bin/env php %s -h %s >> /dev/null 2>&1" % (poller_path, device_id) + path = poller_path + if action = 'discovery' + path = discovery_path + command = "/usr/bin/env php %s -h %s >> /dev/null 2>&1" % (path, device_id) subprocess.check_call(command, shell=True) elapsed_time = int(time.time() - start_time) if elapsed_time < 300: @@ -178,12 +190,20 @@ dev_query = ( 'SELECT device_id, ' ' INTERVAL last_polled_timetaken SECOND ' ' ), ' ' INTERVAL {0} SECOND) AS next_poll ' + 'DATE_ADD( ' + ' DATE_SUB( ' + ' last_discovered, ' + ' INTERVAL last_discovered_timetaken SECOND ' + ' ), ' + ' INTERVAL {1} SECOND) AS next_discovery ' 'FROM devices WHERE ' 'disabled = 0 ' 'AND IS_FREE_LOCK(CONCAT("polling.", device_id)) ' 'AND IS_FREE_LOCK(CONCAT("queued.", device_id)) ' - '{1} ' - 'ORDER BY next_poll asc ').format(frequency, poller_group) + '{2} ' + 'ORDER BY next_poll asc ').format( poll_frequency, + discover_frequency, + poller_group ) dont_retry = {} threads = 0 @@ -209,7 +229,7 @@ while True: cursor.execute(dev_query) devices = cursor.fetchall() retry_devs_found = {} - for device_id, next_poll in devices: + for device_id, next_poll, next_discovery in devices: # add queue lock, so we lock the next device against any other pollers # if this fails, the device is locked by another poller already if not getLock('queued.{}'.format(device_id)): @@ -240,10 +260,14 @@ while True: log.debug('DEBUG: Sleeping until {0} before {1} {2}'.format(next_poll, poll_action, device_id)) sleep_until(sleep_until_time) - log.debug('DEBUG: Starting poll of device {}'.format(device_id)) + action = 'poll' + if not next_discovery or next_discovery < datetime.now(): + action = 'discovery' + + log.debug('DEBUG: Starting {} of device {}'.format(action, device_id)) devices_scanned += 1 dont_retry[device_id] = datetime.now() + timedelta(seconds=down_retry) - t = threading.Thread(target=poll_worker, args=[device_id]) + t = threading.Thread(target=poll_worker, args=[device_id, action]) t.start() # If we made it this far, break out of the loop and query again. From 18d8914548af4d2a438ca63cd762c8a334d430fe Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Tue, 7 Jul 2015 13:10:36 -0400 Subject: [PATCH 070/598] discover integration working --- poller-service.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/poller-service.py b/poller-service.py index f1530f1b5..e6656036a 100755 --- a/poller-service.py +++ b/poller-service.py @@ -105,11 +105,11 @@ except KeyError: try: discover_frequency = int(config['poller_service_discover_frequency']) - if poll_frequency == 0: + if discover_frequency == 0: log.critical("ERROR: 0 seconds is not a valid value") sys.exit(2) except KeyError: - poll_frequency = 21600 + discover_frequency = 21600 try: down_retry = int(config['poller_service_down_retry']) @@ -135,8 +135,8 @@ def poll_worker(device_id, action): try: start_time = time.time() path = poller_path - if action = 'discovery' - path = discovery_path + if action == 'discovery': + path = discover_path command = "/usr/bin/env php %s -h %s >> /dev/null 2>&1" % (path, device_id) subprocess.check_call(command, shell=True) elapsed_time = int(time.time() - start_time) @@ -189,7 +189,7 @@ dev_query = ( 'SELECT device_id, ' ' last_polled, ' ' INTERVAL last_polled_timetaken SECOND ' ' ), ' - ' INTERVAL {0} SECOND) AS next_poll ' + ' INTERVAL {0} SECOND) AS next_poll, ' 'DATE_ADD( ' ' DATE_SUB( ' ' last_discovered, ' @@ -242,7 +242,7 @@ while True: releaseLock('queued.{}'.format(device_id)) continue - if next_poll > datetime.now(): + if next_poll and next_poll > datetime.now(): poll_action = 'polling' sleep_until_time = next_poll try: From 9ae0bc3f8319cafa1387f7c7284c12c1b172569c Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Tue, 7 Jul 2015 13:33:16 -0400 Subject: [PATCH 071/598] documentation written --- doc/Extensions/Poller-Service.md | 21 ++++++++++++++++++++- poller-service.py | 2 +- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/doc/Extensions/Poller-Service.md b/doc/Extensions/Poller-Service.md index 9c515c378..8406067c6 100644 --- a/doc/Extensions/Poller-Service.md +++ b/doc/Extensions/Poller-Service.md @@ -1,2 +1,21 @@ # Poller Service -The Poller service is an alternative to polling cron jobs. +The Poller service is an alternative to polling and discovery cron jobs and provides support for distributed polling without memcache. It is multi-threaded and runs continuously discovering and polling devices with the oldest data attempting to honor the polling frequency configured in `config.php`. + +Configure the maximum number of threads for the service in `$config['poller_service_workers']`. Configure the minimum desired polling frequency in `$config['poller_service_poll_frequency']` and the minimum desired discovery frequency in `$config['poller_service_discover_frequency']`. The service will not poll or discover devices which have data newer than this this configured age in seconds. Configure how frequently the service will attempt to poll devices which are down in `$config['poller_service_down_retry']`. + +The poller service is designed to gracefully degrade. If not all devices can be polled within the configured frequency, the service will continuously poll devices refreshing as frequently as possible using the configured number of threads. + +## Configuration +```php +// Poller-Service settings +$config['poller_service_workers'] = 16; +$config['poller_service_poll_frequency'] = 300; +$config['poller_service_discover_frequency'] = 21600; +$config['poller_service_down_retry'] = 60; +``` + +## Distributed Polling +Distributed polling is possible. The database must be acessable from the distributed pollers, and properly configured. Remote access to the RRD directory must also be configured as described in the Distributed Poller documentation. Memcache is not required. Concurrency is managed using mysql GET_LOCK to ensure that devices are only being polled by one device at at time. The poller service is compatible with poller groups. + +## Service Installation +The service is tested on Ubuntu 14.04. An upstart configuration `poller-service.conf` is provided. To install copy this file to `/etc/init/poller-service.conf`. The service will start on boot and can be started manually by running `start poller-service`. The service is configured to run as the user `librenms` and will fail if that user does not exist. diff --git a/poller-service.py b/poller-service.py index e6656036a..c65c99a40 100755 --- a/poller-service.py +++ b/poller-service.py @@ -117,7 +117,7 @@ try: log.critical("ERROR: 0 seconds is not a valid value") sys.exit(2) except KeyError: - down_retry = 15 + down_retry = 60 try: if db_port == 0: From 1f0799fc03b2088a57107e26f6f7673af3892918 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Tue, 7 Jul 2015 13:34:41 -0400 Subject: [PATCH 072/598] more details about which cronjobs this replaces --- doc/Extensions/Poller-Service.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/Extensions/Poller-Service.md b/doc/Extensions/Poller-Service.md index 8406067c6..5248a1019 100644 --- a/doc/Extensions/Poller-Service.md +++ b/doc/Extensions/Poller-Service.md @@ -1,5 +1,5 @@ # Poller Service -The Poller service is an alternative to polling and discovery cron jobs and provides support for distributed polling without memcache. It is multi-threaded and runs continuously discovering and polling devices with the oldest data attempting to honor the polling frequency configured in `config.php`. +The Poller service is an alternative to polling and discovery cron jobs and provides support for distributed polling without memcache. It is multi-threaded and runs continuously discovering and polling devices with the oldest data attempting to honor the polling frequency configured in `config.php`. This service replaces all the required cron jobs except for `/opt/librenms/daily.sh` and `/opt/librenms/alerts.php`. Configure the maximum number of threads for the service in `$config['poller_service_workers']`. Configure the minimum desired polling frequency in `$config['poller_service_poll_frequency']` and the minimum desired discovery frequency in `$config['poller_service_discover_frequency']`. The service will not poll or discover devices which have data newer than this this configured age in seconds. Configure how frequently the service will attempt to poll devices which are down in `$config['poller_service_down_retry']`. From f8756dc956c43590929208f1acb20fbe8a187a51 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Tue, 7 Jul 2015 13:58:56 -0400 Subject: [PATCH 073/598] more details indocs --- doc/Extensions/Poller-Service.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/Extensions/Poller-Service.md b/doc/Extensions/Poller-Service.md index 5248a1019..0b552d6c3 100644 --- a/doc/Extensions/Poller-Service.md +++ b/doc/Extensions/Poller-Service.md @@ -15,7 +15,7 @@ $config['poller_service_down_retry'] = 60; ``` ## Distributed Polling -Distributed polling is possible. The database must be acessable from the distributed pollers, and properly configured. Remote access to the RRD directory must also be configured as described in the Distributed Poller documentation. Memcache is not required. Concurrency is managed using mysql GET_LOCK to ensure that devices are only being polled by one device at at time. The poller service is compatible with poller groups. +Distributed polling is possible, and uses the same configuration options as are described for traditional distributed polling, except that the memcached options are not necessary. The database must be acessable from the distributed pollers, and properly configured. Remote access to the RRD directory must also be configured as described in the Distributed Poller documentation. Memcache is not required. Concurrency is managed using mysql GET_LOCK to ensure that devices are only being polled by one device at at time. The poller service is compatible with poller groups. ## Service Installation The service is tested on Ubuntu 14.04. An upstart configuration `poller-service.conf` is provided. To install copy this file to `/etc/init/poller-service.conf`. The service will start on boot and can be started manually by running `start poller-service`. The service is configured to run as the user `librenms` and will fail if that user does not exist. From 4fed175935d7723f065ef5fff85cea8e07d75142 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Tue, 7 Jul 2015 14:08:30 -0400 Subject: [PATCH 074/598] document loglevel --- doc/Extensions/Poller-Service.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/Extensions/Poller-Service.md b/doc/Extensions/Poller-Service.md index 0b552d6c3..354d58c39 100644 --- a/doc/Extensions/Poller-Service.md +++ b/doc/Extensions/Poller-Service.md @@ -5,9 +5,12 @@ Configure the maximum number of threads for the service in `$config['poller_serv The poller service is designed to gracefully degrade. If not all devices can be polled within the configured frequency, the service will continuously poll devices refreshing as frequently as possible using the configured number of threads. +The service logs to syslog. A loglevel of INFO will print status updates every 5 minutes. Loglevel of DEBUG will print updates on every device as it is scanned. + ## Configuration ```php // Poller-Service settings +$config['poller_service_loglevel'] = "INFO"; $config['poller_service_workers'] = 16; $config['poller_service_poll_frequency'] = 300; $config['poller_service_discover_frequency'] = 21600; From b0c02a167ef18b7f8341b06150eba2e57b832b57 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Tue, 7 Jul 2015 14:16:55 -0400 Subject: [PATCH 075/598] add license to docstring --- poller-service.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/poller-service.py b/poller-service.py index c65c99a40..6ef51d5ae 100755 --- a/poller-service.py +++ b/poller-service.py @@ -9,8 +9,7 @@ Author: Clint Armstrong Date: July 2015 - Usage: poller-service [threads] [poll_frequency] - Default is 16 threads and 300 seconds. + License: BSD """ import json From 67b8f9f4733785b98498199b95e802ef55b2f490 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Tue, 7 Jul 2015 14:33:33 -0400 Subject: [PATCH 076/598] pep8 --- poller-service.py | 58 ++++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/poller-service.py b/poller-service.py index 6ef51d5ae..07e1ea3f2 100755 --- a/poller-service.py +++ b/poller-service.py @@ -1,8 +1,8 @@ #! /usr/bin/env python """ poller-service A service to wrap SNMP polling. It will poll up to $threads devices at a time, and will not re-poll - devices that have been polled within the last $poll_frequency seconds. It will prioritize devices based on - the last time polled. If resources are sufficient, this service should poll every device every + devices that have been polled within the last $poll_frequency seconds. It will prioritize devices based + on the last time polled. If resources are sufficient, this service should poll every device every $poll_frequency seconds, but should gracefully degrade if resources are inefficient, polling devices as frequently as possible. This service is based on poller-wrapper.py. @@ -14,7 +14,6 @@ import json import os -import Queue import subprocess import sys import threading @@ -28,7 +27,7 @@ log = logging.getLogger('poller-service') log.setLevel(logging.DEBUG) formatter = logging.Formatter('poller-service: %(message)s') -handler = logging.handlers.SysLogHandler(address= '/dev/log') +handler = logging.handlers.SysLogHandler(address='/dev/log') handler.setFormatter(formatter) log.addHandler(handler) @@ -37,6 +36,7 @@ config_file = install_dir + '/config.php' log.info('INFO: Starting poller-service') + def get_config_data(): config_cmd = ['/usr/bin/env', 'php', '%s/config_to_json.php' % install_dir] try: @@ -169,6 +169,7 @@ def releaseLock(lock): cursor.execute(query) return cursor.fetchall()[0][0] == 1 + def sleep_until(timestamp): now = datetime.now() if timestamp > now: @@ -178,31 +179,31 @@ def sleep_until(timestamp): time.sleep(sleeptime) poller_group = ('and poller_group IN({}) ' - .format(str(config['distributed_poller_group'])) if 'distributed_poller_group' in config else '') + .format(str(config['distributed_poller_group'])) if 'distributed_poller_group' in config else '') # Add last_polled and last_polled_timetaken so we can sort by the time the last poll started, with the goal # of having each device complete a poll within the given time range. -dev_query = ( 'SELECT device_id, ' - 'DATE_ADD( ' - ' DATE_SUB( ' - ' last_polled, ' - ' INTERVAL last_polled_timetaken SECOND ' - ' ), ' - ' INTERVAL {0} SECOND) AS next_poll, ' - 'DATE_ADD( ' - ' DATE_SUB( ' - ' last_discovered, ' - ' INTERVAL last_discovered_timetaken SECOND ' - ' ), ' - ' INTERVAL {1} SECOND) AS next_discovery ' - 'FROM devices WHERE ' - 'disabled = 0 ' - 'AND IS_FREE_LOCK(CONCAT("polling.", device_id)) ' - 'AND IS_FREE_LOCK(CONCAT("queued.", device_id)) ' - '{2} ' - 'ORDER BY next_poll asc ').format( poll_frequency, - discover_frequency, - poller_group ) +dev_query = ('SELECT device_id, ' + 'DATE_ADD( ' + ' DATE_SUB( ' + ' last_polled, ' + ' INTERVAL last_polled_timetaken SECOND ' + ' ), ' + ' INTERVAL {0} SECOND) AS next_poll, ' + 'DATE_ADD( ' + ' DATE_SUB( ' + ' last_discovered, ' + ' INTERVAL last_discovered_timetaken SECOND ' + ' ), ' + ' INTERVAL {1} SECOND) AS next_discovery ' + 'FROM devices WHERE ' + 'disabled = 0 ' + 'AND IS_FREE_LOCK(CONCAT("polling.", device_id)) ' + 'AND IS_FREE_LOCK(CONCAT("queued.", device_id)) ' + '{2} ' + 'ORDER BY next_poll asc ').format(poll_frequency, + discover_frequency, + poller_group) dont_retry = {} threads = 0 @@ -271,8 +272,3 @@ while True: # If we made it this far, break out of the loop and query again. break - -try: - print_queue.join() -except (KeyboardInterrupt, SystemExit): - raise From 0588ff41c301a792150e3bba40a1c691e2da3606 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Tue, 7 Jul 2015 15:53:04 -0400 Subject: [PATCH 077/598] get a lock when doing discovery --- discovery.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/discovery.php b/discovery.php index 3006399ff..93ca69a09 100755 --- a/discovery.php +++ b/discovery.php @@ -106,7 +106,9 @@ if ($config['distributed_poller'] === true) { } foreach (dbFetch("SELECT * FROM `devices` WHERE status = 1 AND disabled = 0 $where ORDER BY device_id DESC") as $device) { + if (dbGetLock('polling.' . $device['device_id'])) { discover_device($device, $options); + } } $end = utime(); From c65a160c18a424058edc146f330bb8a23e4ce189 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Fri, 10 Jul 2015 16:59:16 -0400 Subject: [PATCH 078/598] log progress to db every 5 minutes --- poller-service.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/poller-service.py b/poller-service.py index 07e1ea3f2..6477ee93c 100755 --- a/poller-service.py +++ b/poller-service.py @@ -217,6 +217,15 @@ while True: log.debug('DEBUG: {} threads currently active'.format(threads)) if next_update < datetime.now(): + seconds_taken = (datetime.now() - (next_update - timedelta(minutes=5))).seconds + update_query = ("insert into pollers set " + "poller_name='%s', " + "last_polled=NOW(), " + "devices='%d', " + "time_taken='%d' ").format(config['distributed_poller_name'], + devices_scanned, + seconds_taken) + cursor.execute(update_query) log.info('INFO: {} devices scanned in the last 5 minutes'.format(devices_scanned)) devices_scanned = 0 next_update = datetime.now() + timedelta(minutes=5) From 4529ba2e7da25bb2bbe5ca4c90ddc333ff10f7e2 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Fri, 10 Jul 2015 17:19:51 -0400 Subject: [PATCH 079/598] fix stupid query --- poller-service.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/poller-service.py b/poller-service.py index 6477ee93c..e2649586e 100755 --- a/poller-service.py +++ b/poller-service.py @@ -218,13 +218,18 @@ while True: if next_update < datetime.now(): seconds_taken = (datetime.now() - (next_update - timedelta(minutes=5))).seconds - update_query = ("insert into pollers set " - "poller_name='%s', " - "last_polled=NOW(), " - "devices='%d', " - "time_taken='%d' ").format(config['distributed_poller_name'], - devices_scanned, - seconds_taken) + update_query = ("INSERT INTO pollers(poller_name, " + " last_polled, " + " devices, " + " time_taken) " + " values({0}, NOW(), {1}, {2}) " + "ON DUPLICATE KEY UPDATE " + " poller_name=values(poller_name), " + " last_polled=values(last_polled), " + " devices=values(devices) " + " time_taken=values(time_taken) ").format(config['distributed_poller_name'], + devices_scanned, + seconds_taken) cursor.execute(update_query) log.info('INFO: {} devices scanned in the last 5 minutes'.format(devices_scanned)) devices_scanned = 0 From b9c3b3cec8a7de50fa59904a70cc3071ca7d2ea7 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Fri, 10 Jul 2015 17:34:34 -0400 Subject: [PATCH 080/598] sql stuff --- poller-service.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/poller-service.py b/poller-service.py index e2649586e..c794704f1 100755 --- a/poller-service.py +++ b/poller-service.py @@ -218,16 +218,15 @@ while True: if next_update < datetime.now(): seconds_taken = (datetime.now() - (next_update - timedelta(minutes=5))).seconds - update_query = ("INSERT INTO pollers(poller_name, " - " last_polled, " - " devices, " - " time_taken) " - " values({0}, NOW(), {1}, {2}) " - "ON DUPLICATE KEY UPDATE " - " poller_name=values(poller_name), " - " last_polled=values(last_polled), " - " devices=values(devices) " - " time_taken=values(time_taken) ").format(config['distributed_poller_name'], + update_query = ('INSERT INTO pollers(poller_name, ' + ' last_polled, ' + ' devices, ' + ' time_taken) ' + ' values("{0}", NOW(), "{1}", "{2}") ' + 'ON DUPLICATE KEY UPDATE ' + ' last_polled=values(last_polled), ' + ' devices=values(devices) ' + ' time_taken=values(time_taken) ').format(config['distributed_poller_name'], devices_scanned, seconds_taken) cursor.execute(update_query) From b4c5f0a5ec38beea1711f444b28e64f3db319a74 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Fri, 10 Jul 2015 17:34:45 -0400 Subject: [PATCH 081/598] notes --- notes.txt | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 notes.txt diff --git a/notes.txt b/notes.txt new file mode 100644 index 000000000..e3a826237 --- /dev/null +++ b/notes.txt @@ -0,0 +1,6 @@ +Need to set poller_name as primary key for this to work: + +ALTER TABLE pollers + ADD PRIMARY KEY (poller_name) + +Check in beginning? From bedf425c1cabf3c0c6326ad221fd97b3893778d7 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Mon, 13 Jul 2015 08:43:18 -0400 Subject: [PATCH 082/598] update sql schema to add primary key for pollers --- notes.txt | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 notes.txt diff --git a/notes.txt b/notes.txt deleted file mode 100644 index e3a826237..000000000 --- a/notes.txt +++ /dev/null @@ -1,6 +0,0 @@ -Need to set poller_name as primary key for this to work: - -ALTER TABLE pollers - ADD PRIMARY KEY (poller_name) - -Check in beginning? From 55ad58b4e98a2d94f1c5e413d9631e04735b7e7c Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Mon, 13 Jul 2015 08:43:23 -0400 Subject: [PATCH 083/598] update sql schema to add primary key for pollers --- sql-schema/065.sql | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 sql-schema/065.sql diff --git a/sql-schema/065.sql b/sql-schema/065.sql new file mode 100644 index 000000000..b201eab9a --- /dev/null +++ b/sql-schema/065.sql @@ -0,0 +1,3 @@ +ALTER TABLE `device_perf` DROP INDEX `id` , ADD INDEX `id` ( `id` ), ADD INDEX ( `device_id` ); +DELETE n1 FROM pollers n1, pollers n2 WHERE n1.last_polled < n2.last_polled and n1.poller_name = n2.poller_name; +ALTER TABLE pollers ADD PRIMARY KEY (poller_name); From 01b7648136cd692cfccfbf798a99cce683a5b9d4 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Mon, 13 Jul 2015 09:22:53 -0400 Subject: [PATCH 084/598] add last_poll_attempted column to devices table --- sql-schema/065.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql-schema/065.sql b/sql-schema/065.sql index b201eab9a..ab64beca9 100644 --- a/sql-schema/065.sql +++ b/sql-schema/065.sql @@ -1,3 +1,3 @@ -ALTER TABLE `device_perf` DROP INDEX `id` , ADD INDEX `id` ( `id` ), ADD INDEX ( `device_id` ); DELETE n1 FROM pollers n1, pollers n2 WHERE n1.last_polled < n2.last_polled and n1.poller_name = n2.poller_name; ALTER TABLE pollers ADD PRIMARY KEY (poller_name); +ALTER TABLE `devices` ADD `last_poll_attempted` timestamp NULL DEFAULT NULL AFTER `last_polled`; From f12725fc814371868ad0a7e164fce7bf4cef215d Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Mon, 13 Jul 2015 09:38:03 -0400 Subject: [PATCH 085/598] store last attempted in sql for simpler down_retry --- poller-service.py | 43 ++++++++++++++++--------------------------- 1 file changed, 16 insertions(+), 27 deletions(-) diff --git a/poller-service.py b/poller-service.py index c794704f1..43ee9875c 100755 --- a/poller-service.py +++ b/poller-service.py @@ -140,9 +140,9 @@ def poll_worker(device_id, action): subprocess.check_call(command, shell=True) elapsed_time = int(time.time() - start_time) if elapsed_time < 300: - log.debug("DEBUG: worker finished device %s in %s seconds" % (device_id, elapsed_time)) + log.debug("DEBUG: worker finished %s of device %s in %s seconds" % (action, device_id, elapsed_time)) else: - log.warning("WARNING: worker finished device %s in %s seconds" % (device_id, elapsed_time)) + log.warning("WARNING: worker finished %s of device %s in %s seconds" % (action, device_id, elapsed_time)) except (KeyboardInterrupt, SystemExit): raise except: @@ -200,12 +200,14 @@ dev_query = ('SELECT device_id, ' 'disabled = 0 ' 'AND IS_FREE_LOCK(CONCAT("polling.", device_id)) ' 'AND IS_FREE_LOCK(CONCAT("queued.", device_id)) ' - '{2} ' + 'AND last_poll_attempted < DATE_SUB( ' + ' NOW(), INTERVAL {2} SECOND ) ' + '{3} ' 'ORDER BY next_poll asc ').format(poll_frequency, discover_frequency, + down_retry, poller_group) -dont_retry = {} threads = 0 next_update = datetime.now() + timedelta(minutes=5) devices_scanned = 0 @@ -220,28 +222,26 @@ while True: seconds_taken = (datetime.now() - (next_update - timedelta(minutes=5))).seconds update_query = ('INSERT INTO pollers(poller_name, ' ' last_polled, ' - ' devices, ' + ' devices, ' ' time_taken) ' ' values("{0}", NOW(), "{1}", "{2}") ' 'ON DUPLICATE KEY UPDATE ' ' last_polled=values(last_polled), ' ' devices=values(devices) ' ' time_taken=values(time_taken) ').format(config['distributed_poller_name'], - devices_scanned, - seconds_taken) + devices_scanned, + seconds_taken) cursor.execute(update_query) + cursor.fetchall() log.info('INFO: {} devices scanned in the last 5 minutes'.format(devices_scanned)) devices_scanned = 0 next_update = datetime.now() + timedelta(minutes=5) - dont_retry = dict((dev, time) for dev, time in dont_retry.iteritems() if time > datetime.now()) - while threading.active_count() >= amount_of_workers: time.sleep(.5) cursor.execute(dev_query) devices = cursor.fetchall() - retry_devs_found = {} for device_id, next_poll, next_discovery in devices: # add queue lock, so we lock the next device against any other pollers # if this fails, the device is locked by another poller already @@ -256,22 +256,8 @@ while True: continue if next_poll and next_poll > datetime.now(): - poll_action = 'polling' - sleep_until_time = next_poll - try: - next_retry_device = min(retry_devs_found, key=retry_devs_found.get) - next_retry_time = retry_devs_found[next_retry_device] - if next_retry_time < next_poll: - device_id = next_retry_device - if not getLock('queued.{}'.format(device_id)): - continue - poll_action = 'retrying failed device' - sleep_until_time = next_retry_time - except ValueError: - pass - - log.debug('DEBUG: Sleeping until {0} before {1} {2}'.format(next_poll, poll_action, device_id)) - sleep_until(sleep_until_time) + log.debug('DEBUG: Sleeping until {0} before polling {2}'.format(next_poll, device_id)) + sleep_until(next_poll) action = 'poll' if not next_discovery or next_discovery < datetime.now(): @@ -279,7 +265,10 @@ while True: log.debug('DEBUG: Starting {} of device {}'.format(action, device_id)) devices_scanned += 1 - dont_retry[device_id] = datetime.now() + timedelta(seconds=down_retry) + + cursor.execute('UPDATE devices SET last_poll_attempted = NOW() WHERE device_id = {}'.format(device_id)) + cursor.fetchall() + t = threading.Thread(target=poll_worker, args=[device_id, action]) t.start() From d23bed0af7686b08fa4a28b85bd4f2a7e1a551e6 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Mon, 13 Jul 2015 09:40:54 -0400 Subject: [PATCH 086/598] don't check dont-retry' --- poller-service.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/poller-service.py b/poller-service.py index 43ee9875c..8852a1a65 100755 --- a/poller-service.py +++ b/poller-service.py @@ -250,10 +250,6 @@ while True: if not lockFree('polling.{}'.format(device_id)): releaseLock('queued.{}'.format(device_id)) continue - if device_id in dont_retry: - retry_devs_found[device_id] = dont_retry[device_id] - releaseLock('queued.{}'.format(device_id)) - continue if next_poll and next_poll > datetime.now(): log.debug('DEBUG: Sleeping until {0} before polling {2}'.format(next_poll, device_id)) From c35a1ea750ca2dd456b285a956e109304fd4635e Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Mon, 13 Jul 2015 09:48:18 -0400 Subject: [PATCH 087/598] don't loop too fast --- poller-service.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/poller-service.py b/poller-service.py index 8852a1a65..e57f8f7ae 100755 --- a/poller-service.py +++ b/poller-service.py @@ -270,3 +270,7 @@ while True: # If we made it this far, break out of the loop and query again. break + + # Looping with no break causes the service to be killed by init. + # This point is only reached if the query is empty, so sleep half a second before querying again. + time.sleep(.5) From 4a66720969596805a7cf39207c1032c98bd2dbf2 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Mon, 13 Jul 2015 09:59:08 -0400 Subject: [PATCH 088/598] release lock for 1 device --- poller-service.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/poller-service.py b/poller-service.py index e57f8f7ae..e64c9800b 100755 --- a/poller-service.py +++ b/poller-service.py @@ -201,7 +201,7 @@ dev_query = ('SELECT device_id, ' 'AND IS_FREE_LOCK(CONCAT("polling.", device_id)) ' 'AND IS_FREE_LOCK(CONCAT("queued.", device_id)) ' 'AND last_poll_attempted < DATE_SUB( ' - ' NOW(), INTERVAL {2} SECOND ) ' + ' NOW(), INTERVAL {2} SECOND ) ' '{3} ' 'ORDER BY next_poll asc ').format(poll_frequency, discover_frequency, @@ -268,6 +268,10 @@ while True: t = threading.Thread(target=poll_worker, args=[device_id, action]) t.start() + # If there is only one device, release the queue lock, because it won't release automatically. + if len(devices) == 1: + releaseLock('queued.{}'.format(device_id)) + # If we made it this far, break out of the loop and query again. break From 6c5f71bbb583990f753b6bc3a34ee479214caf71 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Mon, 13 Jul 2015 10:06:57 -0400 Subject: [PATCH 089/598] remove queue locks on empty query --- poller-service.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/poller-service.py b/poller-service.py index e64c9800b..db20994f0 100755 --- a/poller-service.py +++ b/poller-service.py @@ -268,13 +268,12 @@ while True: t = threading.Thread(target=poll_worker, args=[device_id, action]) t.start() - # If there is only one device, release the queue lock, because it won't release automatically. - if len(devices) == 1: - releaseLock('queued.{}'.format(device_id)) - # If we made it this far, break out of the loop and query again. break # Looping with no break causes the service to be killed by init. # This point is only reached if the query is empty, so sleep half a second before querying again. time.sleep(.5) + + # Make sure we're not holding any device queue locks in this connection before querying again. + getLock('unlock.{}'.format(config['distributed_poller_name'])) From e68bebbc625fdd765d98e82934a0d2d9f089d1d4 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Mon, 13 Jul 2015 10:10:49 -0400 Subject: [PATCH 090/598] bad index --- poller-service.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/poller-service.py b/poller-service.py index db20994f0..f92eae490 100755 --- a/poller-service.py +++ b/poller-service.py @@ -246,13 +246,15 @@ while True: # add queue lock, so we lock the next device against any other pollers # if this fails, the device is locked by another poller already if not getLock('queued.{}'.format(device_id)): + time.sleep(.5) continue if not lockFree('polling.{}'.format(device_id)): releaseLock('queued.{}'.format(device_id)) + time.sleep(.5) continue if next_poll and next_poll > datetime.now(): - log.debug('DEBUG: Sleeping until {0} before polling {2}'.format(next_poll, device_id)) + log.debug('DEBUG: Sleeping until {0} before polling {1}'.format(next_poll, device_id)) sleep_until(next_poll) action = 'poll' From 5672afd0a8acf6659dc1117444235a85ee7eadbb Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Mon, 13 Jul 2015 10:15:06 -0400 Subject: [PATCH 091/598] test for null last_attempted --- poller-service.py | 48 +++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/poller-service.py b/poller-service.py index f92eae490..32d4deb32 100755 --- a/poller-service.py +++ b/poller-service.py @@ -183,30 +183,30 @@ poller_group = ('and poller_group IN({}) ' # Add last_polled and last_polled_timetaken so we can sort by the time the last poll started, with the goal # of having each device complete a poll within the given time range. -dev_query = ('SELECT device_id, ' - 'DATE_ADD( ' - ' DATE_SUB( ' - ' last_polled, ' - ' INTERVAL last_polled_timetaken SECOND ' - ' ), ' - ' INTERVAL {0} SECOND) AS next_poll, ' - 'DATE_ADD( ' - ' DATE_SUB( ' - ' last_discovered, ' - ' INTERVAL last_discovered_timetaken SECOND ' - ' ), ' - ' INTERVAL {1} SECOND) AS next_discovery ' - 'FROM devices WHERE ' - 'disabled = 0 ' - 'AND IS_FREE_LOCK(CONCAT("polling.", device_id)) ' - 'AND IS_FREE_LOCK(CONCAT("queued.", device_id)) ' - 'AND last_poll_attempted < DATE_SUB( ' - ' NOW(), INTERVAL {2} SECOND ) ' - '{3} ' - 'ORDER BY next_poll asc ').format(poll_frequency, - discover_frequency, - down_retry, - poller_group) +dev_query = ('SELECT device_id, ' + 'DATE_ADD( ' + ' DATE_SUB( ' + ' last_polled, ' + ' INTERVAL last_polled_timetaken SECOND ' + ' ), ' + ' INTERVAL {0} SECOND) AS next_poll, ' + 'DATE_ADD( ' + ' DATE_SUB( ' + ' last_discovered, ' + ' INTERVAL last_discovered_timetaken SECOND ' + ' ), ' + ' INTERVAL {1} SECOND) AS next_discovery ' + 'FROM devices WHERE ' + 'disabled = 0 ' + 'AND IS_FREE_LOCK(CONCAT("polling.", device_id)) ' + 'AND IS_FREE_LOCK(CONCAT("queued.", device_id)) ' + 'AND ( last_poll_attempted < DATE_SUB(NOW(), INTERVAL {2} SECOND ) ' + ' OR last_poll_attempted IS NULL ) ' + '{3} ' + 'ORDER BY next_poll asc ').format(poll_frequency, + discover_frequency, + down_retry, + poller_group) threads = 0 next_update = datetime.now() + timedelta(minutes=5) From c3b6fee0eb2705ef1f0fac64c590b175159904c3 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Mon, 13 Jul 2015 10:51:56 -0400 Subject: [PATCH 092/598] bad sql --- poller-service.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/poller-service.py b/poller-service.py index 32d4deb32..13841df20 100755 --- a/poller-service.py +++ b/poller-service.py @@ -227,8 +227,8 @@ while True: ' values("{0}", NOW(), "{1}", "{2}") ' 'ON DUPLICATE KEY UPDATE ' ' last_polled=values(last_polled), ' - ' devices=values(devices) ' - ' time_taken=values(time_taken) ').format(config['distributed_poller_name'], + ' devices=values(devices), ' + ' time_taken=values(time_taken) ').format(config['distributed_poller_name'].strip(), devices_scanned, seconds_taken) cursor.execute(update_query) From 4d832067a9ace2e921b43f1be3c600ec88e9d138 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Mon, 13 Jul 2015 10:57:49 -0400 Subject: [PATCH 093/598] change to 2 minute updates --- poller-service.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/poller-service.py b/poller-service.py index 13841df20..3f9f96082 100755 --- a/poller-service.py +++ b/poller-service.py @@ -209,7 +209,7 @@ dev_query = ('SELECT device_id, poller_group) threads = 0 -next_update = datetime.now() + timedelta(minutes=5) +next_update = datetime.now() + timedelta(minutes=2) devices_scanned = 0 while True: @@ -219,7 +219,7 @@ while True: log.debug('DEBUG: {} threads currently active'.format(threads)) if next_update < datetime.now(): - seconds_taken = (datetime.now() - (next_update - timedelta(minutes=5))).seconds + seconds_taken = (datetime.now() - (next_update - timedelta(minutes=2))).seconds update_query = ('INSERT INTO pollers(poller_name, ' ' last_polled, ' ' devices, ' @@ -235,7 +235,7 @@ while True: cursor.fetchall() log.info('INFO: {} devices scanned in the last 5 minutes'.format(devices_scanned)) devices_scanned = 0 - next_update = datetime.now() + timedelta(minutes=5) + next_update = datetime.now() + timedelta(minutes=2) while threading.active_count() >= amount_of_workers: time.sleep(.5) From 9f1c2232f02812cdcc380f9f253c13d3136e1dc0 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Mon, 13 Jul 2015 10:59:26 -0400 Subject: [PATCH 094/598] update every minute --- poller-service.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/poller-service.py b/poller-service.py index 3f9f96082..8591cdfe0 100755 --- a/poller-service.py +++ b/poller-service.py @@ -209,7 +209,7 @@ dev_query = ('SELECT device_id, poller_group) threads = 0 -next_update = datetime.now() + timedelta(minutes=2) +next_update = datetime.now() + timedelta(minutes=1) devices_scanned = 0 while True: @@ -219,7 +219,7 @@ while True: log.debug('DEBUG: {} threads currently active'.format(threads)) if next_update < datetime.now(): - seconds_taken = (datetime.now() - (next_update - timedelta(minutes=2))).seconds + seconds_taken = (datetime.now() - (next_update - timedelta(minutes=1))).seconds update_query = ('INSERT INTO pollers(poller_name, ' ' last_polled, ' ' devices, ' @@ -235,7 +235,7 @@ while True: cursor.fetchall() log.info('INFO: {} devices scanned in the last 5 minutes'.format(devices_scanned)) devices_scanned = 0 - next_update = datetime.now() + timedelta(minutes=2) + next_update = datetime.now() + timedelta(minutes=1) while threading.active_count() >= amount_of_workers: time.sleep(.5) From 3ff7a4808903a9d0ba2d0563e9d7719c0a816461 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Mon, 13 Jul 2015 11:10:14 -0400 Subject: [PATCH 095/598] catch sql errors --- poller-service.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/poller-service.py b/poller-service.py index 8591cdfe0..b1170ed58 100755 --- a/poller-service.py +++ b/poller-service.py @@ -231,7 +231,10 @@ while True: ' time_taken=values(time_taken) ').format(config['distributed_poller_name'].strip(), devices_scanned, seconds_taken) - cursor.execute(update_query) + try: + cursor.execute(update_query) + except: + log.critical('ERROR: MySQL query error. Is your schema up to date?') cursor.fetchall() log.info('INFO: {} devices scanned in the last 5 minutes'.format(devices_scanned)) devices_scanned = 0 @@ -240,7 +243,11 @@ while True: while threading.active_count() >= amount_of_workers: time.sleep(.5) - cursor.execute(dev_query) + try: + cursor.execute(dev_query) + except: + log.critical('ERROR: MySQL query error. Is your schema up to date?') + devices = cursor.fetchall() for device_id, next_poll, next_discovery in devices: # add queue lock, so we lock the next device against any other pollers From 21e9dac646da714a213ce0ec7bbbe98140b0185c Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Mon, 13 Jul 2015 11:16:51 -0400 Subject: [PATCH 096/598] exit on mysql error --- poller-service.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/poller-service.py b/poller-service.py index b1170ed58..7f94f1423 100755 --- a/poller-service.py +++ b/poller-service.py @@ -235,6 +235,7 @@ while True: cursor.execute(update_query) except: log.critical('ERROR: MySQL query error. Is your schema up to date?') + sys.exit(2) cursor.fetchall() log.info('INFO: {} devices scanned in the last 5 minutes'.format(devices_scanned)) devices_scanned = 0 @@ -247,6 +248,7 @@ while True: cursor.execute(dev_query) except: log.critical('ERROR: MySQL query error. Is your schema up to date?') + sys.exit(2) devices = cursor.fetchall() for device_id, next_poll, next_discovery in devices: From 9931d9dc442d0f3d4a1f2a2a29504f40ceec0a0b Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Mon, 13 Jul 2015 14:32:00 -0400 Subject: [PATCH 097/598] don't try to discover down devices --- poller-service.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/poller-service.py b/poller-service.py index 7f94f1423..e9aa123bc 100755 --- a/poller-service.py +++ b/poller-service.py @@ -183,7 +183,7 @@ poller_group = ('and poller_group IN({}) ' # Add last_polled and last_polled_timetaken so we can sort by the time the last poll started, with the goal # of having each device complete a poll within the given time range. -dev_query = ('SELECT device_id, ' +dev_query = ('SELECT device_id, status, ' 'DATE_ADD( ' ' DATE_SUB( ' ' last_polled, ' @@ -251,7 +251,7 @@ while True: sys.exit(2) devices = cursor.fetchall() - for device_id, next_poll, next_discovery in devices: + for device_id, status, next_poll, next_discovery in devices: # add queue lock, so we lock the next device against any other pollers # if this fails, the device is locked by another poller already if not getLock('queued.{}'.format(device_id)): @@ -267,7 +267,7 @@ while True: sleep_until(next_poll) action = 'poll' - if not next_discovery or next_discovery < datetime.now(): + if (not next_discovery or next_discovery < datetime.now()) and status == 1: action = 'discovery' log.debug('DEBUG: Starting {} of device {}'.format(action, device_id)) From b73b49bfcb36c39676fa4fd1799402918d880648 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Thu, 16 Jul 2015 11:55:04 -0400 Subject: [PATCH 098/598] remove unnecessary exit conditions --- poller-service.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/poller-service.py b/poller-service.py index e9aa123bc..c9d39b8b5 100755 --- a/poller-service.py +++ b/poller-service.py @@ -89,32 +89,28 @@ db_dbname = config['db_name'] try: amount_of_workers = int(config['poller_service_workers']) if amount_of_workers == 0: - log.critical("ERROR: 0 threads is not a valid value") - sys.exit(2) + amount_of_workers = 16 except KeyError: amount_of_workers = 16 try: poll_frequency = int(config['poller_service_poll_frequency']) if poll_frequency == 0: - log.critical("ERROR: 0 seconds is not a valid value") - sys.exit(2) + poll_frequency = 300 except KeyError: poll_frequency = 300 try: discover_frequency = int(config['poller_service_discover_frequency']) if discover_frequency == 0: - log.critical("ERROR: 0 seconds is not a valid value") - sys.exit(2) + discover_frequency = 21600 except KeyError: discover_frequency = 21600 try: down_retry = int(config['poller_service_down_retry']) if down_retry == 0: - log.critical("ERROR: 0 seconds is not a valid value") - sys.exit(2) + down_retry = 60 except KeyError: down_retry = 60 From bb697a35bd81bd71428edd6593ac49bc7332e035 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Thu, 16 Jul 2015 12:11:45 -0400 Subject: [PATCH 099/598] attribution --- poller-service.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/poller-service.py b/poller-service.py index c9d39b8b5..0ca3b5cd9 100755 --- a/poller-service.py +++ b/poller-service.py @@ -4,12 +4,12 @@ devices that have been polled within the last $poll_frequency seconds. It will prioritize devices based on the last time polled. If resources are sufficient, this service should poll every device every $poll_frequency seconds, but should gracefully degrade if resources are inefficient, polling devices as - frequently as possible. This service is based on poller-wrapper.py. + frequently as possible. This service is based on Job Snijders' poller-wrapper.py. Author: Clint Armstrong Date: July 2015 - License: BSD + License: BSD 2-Clause """ import json From c9a56e248d0312568318fee0b758e8d59e0db215 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Fri, 17 Jul 2015 13:33:24 -0400 Subject: [PATCH 100/598] index and limit --- poller-service.py | 9 ++++----- sql-schema/065.sql | 2 ++ 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/poller-service.py b/poller-service.py index 0ca3b5cd9..bbcfa7617 100755 --- a/poller-service.py +++ b/poller-service.py @@ -199,7 +199,8 @@ dev_query = ('SELECT device_id, status, 'AND ( last_poll_attempted < DATE_SUB(NOW(), INTERVAL {2} SECOND ) ' ' OR last_poll_attempted IS NULL ) ' '{3} ' - 'ORDER BY next_poll asc ').format(poll_frequency, + 'ORDER BY next_poll asc ' + 'LIMIT 5 ').format(poll_frequency, discover_frequency, down_retry, poller_group) @@ -251,11 +252,9 @@ while True: # add queue lock, so we lock the next device against any other pollers # if this fails, the device is locked by another poller already if not getLock('queued.{}'.format(device_id)): - time.sleep(.5) continue if not lockFree('polling.{}'.format(device_id)): releaseLock('queued.{}'.format(device_id)) - time.sleep(.5) continue if next_poll and next_poll > datetime.now(): @@ -278,9 +277,9 @@ while True: # If we made it this far, break out of the loop and query again. break - # Looping with no break causes the service to be killed by init. # This point is only reached if the query is empty, so sleep half a second before querying again. time.sleep(.5) - # Make sure we're not holding any device queue locks in this connection before querying again. + # Make sure we're not holding any device queue locks in this connection before querying again + # by locking a different string. getLock('unlock.{}'.format(config['distributed_poller_name'])) diff --git a/sql-schema/065.sql b/sql-schema/065.sql index ab64beca9..4fb76d358 100644 --- a/sql-schema/065.sql +++ b/sql-schema/065.sql @@ -1,3 +1,5 @@ DELETE n1 FROM pollers n1, pollers n2 WHERE n1.last_polled < n2.last_polled and n1.poller_name = n2.poller_name; ALTER TABLE pollers ADD PRIMARY KEY (poller_name); ALTER TABLE `devices` ADD `last_poll_attempted` timestamp NULL DEFAULT NULL AFTER `last_polled`; +ALTER TABLE `devices` ADD INDEX `last_polled` (`last_polled`); +ALTER TABLE `devices` ADD INDEX `last_poll_attempted` (`last_poll_attempted`); From 71c1771d8492e6ea57f710c5d9e3bb28fdd47a7d Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Sat, 18 Jul 2015 20:04:44 -0400 Subject: [PATCH 101/598] zero length field in format --- poller-service.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/poller-service.py b/poller-service.py index bbcfa7617..82b486316 100755 --- a/poller-service.py +++ b/poller-service.py @@ -64,7 +64,7 @@ try: except KeyError: loglevel = logging.getLevelName('INFO') if not isinstance(loglevel, int): - log.warning('ERROR: {} is not a valid log level'.format(str(loglevel))) + log.warning('ERROR: {0} is not a valid log level'.format(str(loglevel))) loglevel = logging.getLevelName('INFO') log.setLevel(loglevel) @@ -147,21 +147,21 @@ def poll_worker(device_id, action): def lockFree(lock): global cursor - query = "SELECT IS_FREE_LOCK('{}')".format(lock) + query = "SELECT IS_FREE_LOCK('{0}')".format(lock) cursor.execute(query) return cursor.fetchall()[0][0] == 1 def getLock(lock): global cursor - query = "SELECT GET_LOCK('{}', 0)".format(lock) + query = "SELECT GET_LOCK('{0}', 0)".format(lock) cursor.execute(query) return cursor.fetchall()[0][0] == 1 def releaseLock(lock): global cursor - query = "SELECT RELEASE_LOCK('{}')".format(lock) + query = "SELECT RELEASE_LOCK('{0}')".format(lock) cursor.execute(query) return cursor.fetchall()[0][0] == 1 @@ -174,7 +174,7 @@ def sleep_until(timestamp): sleeptime = 0 time.sleep(sleeptime) -poller_group = ('and poller_group IN({}) ' +poller_group = ('and poller_group IN({0}) ' .format(str(config['distributed_poller_group'])) if 'distributed_poller_group' in config else '') # Add last_polled and last_polled_timetaken so we can sort by the time the last poll started, with the goal @@ -213,7 +213,7 @@ while True: cur_threads = threading.active_count() if cur_threads != threads: threads = cur_threads - log.debug('DEBUG: {} threads currently active'.format(threads)) + log.debug('DEBUG: {0} threads currently active'.format(threads)) if next_update < datetime.now(): seconds_taken = (datetime.now() - (next_update - timedelta(minutes=1))).seconds @@ -234,7 +234,7 @@ while True: log.critical('ERROR: MySQL query error. Is your schema up to date?') sys.exit(2) cursor.fetchall() - log.info('INFO: {} devices scanned in the last 5 minutes'.format(devices_scanned)) + log.info('INFO: {0} devices scanned in the last 5 minutes'.format(devices_scanned)) devices_scanned = 0 next_update = datetime.now() + timedelta(minutes=1) @@ -251,10 +251,10 @@ while True: for device_id, status, next_poll, next_discovery in devices: # add queue lock, so we lock the next device against any other pollers # if this fails, the device is locked by another poller already - if not getLock('queued.{}'.format(device_id)): + if not getLock('queued.{0}'.format(device_id)): continue - if not lockFree('polling.{}'.format(device_id)): - releaseLock('queued.{}'.format(device_id)) + if not lockFree('polling.{0}'.format(device_id)): + releaseLock('queued.{0}'.format(device_id)) continue if next_poll and next_poll > datetime.now(): @@ -265,10 +265,10 @@ while True: if (not next_discovery or next_discovery < datetime.now()) and status == 1: action = 'discovery' - log.debug('DEBUG: Starting {} of device {}'.format(action, device_id)) + log.debug('DEBUG: Starting {0} of device {1}'.format(action, device_id)) devices_scanned += 1 - cursor.execute('UPDATE devices SET last_poll_attempted = NOW() WHERE device_id = {}'.format(device_id)) + cursor.execute('UPDATE devices SET last_poll_attempted = NOW() WHERE device_id = {0}'.format(device_id)) cursor.fetchall() t = threading.Thread(target=poll_worker, args=[device_id, action]) @@ -282,4 +282,4 @@ while True: # Make sure we're not holding any device queue locks in this connection before querying again # by locking a different string. - getLock('unlock.{}'.format(config['distributed_poller_name'])) + getLock('unlock.{0}'.format(config['distributed_poller_name'])) From 73ada34f306b3c8608ae544b8f19730401a4873e Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Sat, 18 Jul 2015 20:37:34 -0400 Subject: [PATCH 102/598] make logging python3 compatible --- poller-service.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/poller-service.py b/poller-service.py index 82b486316..c0c861413 100755 --- a/poller-service.py +++ b/poller-service.py @@ -44,7 +44,7 @@ def get_config_data(): except: log.critical("ERROR: Could not execute: %s" % config_cmd) sys.exit(2) - return proc.communicate()[0] + return proc.communicate()[0].decode() try: with open(config_file) as f: @@ -60,13 +60,12 @@ except: sys.exit(2) try: - loglevel = logging.getLevelName(config['poller_service_loglevel'].upper()) + log.setLevel(config['poller_service_loglevel'].upper()) except KeyError: - loglevel = logging.getLevelName('INFO') -if not isinstance(loglevel, int): - log.warning('ERROR: {0} is not a valid log level'.format(str(loglevel))) - loglevel = logging.getLevelName('INFO') -log.setLevel(loglevel) + log.setLevel('INFO') +except ValueError: + log.warning('ERROR: {0} is not a valid log level'.format(config['poller_service_loglevel'])) + log.setLevel('INFO') poller_path = config['install_dir'] + '/poller.php' discover_path = config['install_dir'] + '/discovery.php' From 9022c168367732d300b9f4552dc032e0839e71d1 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Sat, 18 Jul 2015 20:57:25 -0400 Subject: [PATCH 103/598] upper case warning --- poller-service.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poller-service.py b/poller-service.py index c0c861413..fd97860e2 100755 --- a/poller-service.py +++ b/poller-service.py @@ -64,7 +64,7 @@ try: except KeyError: log.setLevel('INFO') except ValueError: - log.warning('ERROR: {0} is not a valid log level'.format(config['poller_service_loglevel'])) + log.warning('ERROR: {0} is not a valid log level'.format(config['poller_service_loglevel'].upper())) log.setLevel('INFO') poller_path = config['install_dir'] + '/poller.php' From 0f34042b84aaff7c4a5f732f027d25dc738944e4 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Sat, 18 Jul 2015 21:09:10 -0400 Subject: [PATCH 104/598] Revert "upper case warning" This reverts commit c87d626105ad80d7856e2c15f98219c43ebe0c2e. --- poller-service.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poller-service.py b/poller-service.py index fd97860e2..c0c861413 100755 --- a/poller-service.py +++ b/poller-service.py @@ -64,7 +64,7 @@ try: except KeyError: log.setLevel('INFO') except ValueError: - log.warning('ERROR: {0} is not a valid log level'.format(config['poller_service_loglevel'].upper())) + log.warning('ERROR: {0} is not a valid log level'.format(config['poller_service_loglevel'])) log.setLevel('INFO') poller_path = config['install_dir'] + '/poller.php' From 85aa9ccdb8b530aac72221bcc62260b5edd31f66 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Sat, 18 Jul 2015 21:09:20 -0400 Subject: [PATCH 105/598] Revert "make logging python3 compatible" This reverts commit 74531c6e69c31c252a48d2bab90bc98e4f566111. --- poller-service.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/poller-service.py b/poller-service.py index c0c861413..82b486316 100755 --- a/poller-service.py +++ b/poller-service.py @@ -44,7 +44,7 @@ def get_config_data(): except: log.critical("ERROR: Could not execute: %s" % config_cmd) sys.exit(2) - return proc.communicate()[0].decode() + return proc.communicate()[0] try: with open(config_file) as f: @@ -60,12 +60,13 @@ except: sys.exit(2) try: - log.setLevel(config['poller_service_loglevel'].upper()) + loglevel = logging.getLevelName(config['poller_service_loglevel'].upper()) except KeyError: - log.setLevel('INFO') -except ValueError: - log.warning('ERROR: {0} is not a valid log level'.format(config['poller_service_loglevel'])) - log.setLevel('INFO') + loglevel = logging.getLevelName('INFO') +if not isinstance(loglevel, int): + log.warning('ERROR: {0} is not a valid log level'.format(str(loglevel))) + loglevel = logging.getLevelName('INFO') +log.setLevel(loglevel) poller_path = config['install_dir'] + '/poller.php' discover_path = config['install_dir'] + '/discovery.php' From 403d4c53646c11825d85cb4ac0acfb89bdf599a8 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Sat, 18 Jul 2015 21:09:49 -0400 Subject: [PATCH 106/598] decode proc --- poller-service.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poller-service.py b/poller-service.py index 82b486316..3a98a6ac2 100755 --- a/poller-service.py +++ b/poller-service.py @@ -44,7 +44,7 @@ def get_config_data(): except: log.critical("ERROR: Could not execute: %s" % config_cmd) sys.exit(2) - return proc.communicate()[0] + return proc.communicate()[0].decode() try: with open(config_file) as f: From 779862601762680a120c9370fc4b17dd1c614646 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Sat, 18 Jul 2015 21:31:01 -0400 Subject: [PATCH 107/598] fix logging options --- poller-service.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/poller-service.py b/poller-service.py index 3a98a6ac2..4fcf37818 100755 --- a/poller-service.py +++ b/poller-service.py @@ -60,12 +60,14 @@ except: sys.exit(2) try: - loglevel = logging.getLevelName(config['poller_service_loglevel'].upper()) + loglevel = config['poller_service_loglevel'] except KeyError: - loglevel = logging.getLevelName('INFO') + loglevel = 20 if not isinstance(loglevel, int): - log.warning('ERROR: {0} is not a valid log level'.format(str(loglevel))) - loglevel = logging.getLevelName('INFO') + loglevel = logging.getLevelName(loglevel) +if not isinstance(loglevel, int): + log.warning('ERROR: {0} is not a valid log level. If using python 3.4.0-3.4.1 you must specify loglevel by number'.format(str(loglevel))) + loglevel = 20 log.setLevel(loglevel) poller_path = config['install_dir'] + '/poller.php' From 617e695b2012fb94303d555376b151fc83b64ff4 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Sat, 18 Jul 2015 21:38:27 -0400 Subject: [PATCH 108/598] better logging error checking --- poller-service.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/poller-service.py b/poller-service.py index 4fcf37818..0989b27a2 100755 --- a/poller-service.py +++ b/poller-service.py @@ -60,15 +60,17 @@ except: sys.exit(2) try: - loglevel = config['poller_service_loglevel'] + loglevel = int(config['poller_service_loglevel']) except KeyError: loglevel = 20 -if not isinstance(loglevel, int): - loglevel = logging.getLevelName(loglevel) -if not isinstance(loglevel, int): +except ValueError: + loglevel = logging.getLevelName(config['poller_service_loglevel']) + +try: + log.setLevel(loglevel) +except ValueError: log.warning('ERROR: {0} is not a valid log level. If using python 3.4.0-3.4.1 you must specify loglevel by number'.format(str(loglevel))) - loglevel = 20 -log.setLevel(loglevel) + log.setLevel(20) poller_path = config['install_dir'] + '/poller.php' discover_path = config['install_dir'] + '/discovery.php' From 9039dbb425555c48d9ce4ac5927e65f97ae7c803 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 22 Jul 2015 07:37:02 -0400 Subject: [PATCH 109/598] give discovery it's own lock --- discovery.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/discovery.php b/discovery.php index 93ca69a09..a8e48c649 100755 --- a/discovery.php +++ b/discovery.php @@ -106,8 +106,8 @@ if ($config['distributed_poller'] === true) { } foreach (dbFetch("SELECT * FROM `devices` WHERE status = 1 AND disabled = 0 $where ORDER BY device_id DESC") as $device) { - if (dbGetLock('polling.' . $device['device_id'])) { - discover_device($device, $options); + if (dbGetLock('discovering.' . $device['device_id'])) { + discover_device($device, $options); } } From a47ae33cfd0e096bbc980e4370eca7e79f571983 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 22 Jul 2015 07:39:37 -0400 Subject: [PATCH 110/598] check for schema_update lock when poller-service runs --- poller-service.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poller-service.py b/poller-service.py index 0989b27a2..178282026 100755 --- a/poller-service.py +++ b/poller-service.py @@ -242,7 +242,7 @@ while True: devices_scanned = 0 next_update = datetime.now() + timedelta(minutes=1) - while threading.active_count() >= amount_of_workers: + while threading.active_count() >= amount_of_workers or not lockFree('schema_update'): time.sleep(.5) try: From 86e0f42dc75a678d1a78b0f20a179b47c0215928 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 22 Jul 2015 07:52:58 -0400 Subject: [PATCH 111/598] bail out if we can't get a lock on schema_update --- includes/sql-schema/update.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/includes/sql-schema/update.php b/includes/sql-schema/update.php index 4bb7df721..19b043ada 100644 --- a/includes/sql-schema/update.php +++ b/includes/sql-schema/update.php @@ -31,6 +31,11 @@ if (!isset($debug)) { } } +if (!dbGetLock('schema_update')) { + echo "Schema update already in progress. Exiting"; + exit(1); +} + $insert = 0; if ($db_rev = @dbFetchCell('SELECT version FROM `dbSchema` ORDER BY version DESC LIMIT 1')) { From 777d5d6c6f586dedaeadc2c607b172ed9c36e4a4 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 22 Jul 2015 07:58:36 -0400 Subject: [PATCH 112/598] add function to check for a lock --- includes/dbFacile.mysql.php | 13 +++++++------ includes/dbFacile.mysqli.php | 11 ++++++----- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/includes/dbFacile.mysql.php b/includes/dbFacile.mysql.php index 9fd82c698..bac21b008 100644 --- a/includes/dbFacile.mysql.php +++ b/includes/dbFacile.mysql.php @@ -60,12 +60,12 @@ function dbQuery($sql, $parameters=array()) { /* - * Aquire a lock on a string + * Check a lock on a string * */ -function dbGetLock($data, $timeout = 0) { - $sql = 'SELECT GET_LOCK(\'' . $data . '\',' . $timeout . ')'; - $result = dbFetchCell($sql); - return $result; +function dbCheckLock($data, $timeout = 0) { + $sql = 'SELECT IS_FREE_LOCK(\'' . $data . '\')'; + $result = dbFetchCell($sql); + return $result; } @@ -76,8 +76,9 @@ function dbReleaseLock($data, $timeout = 0) { $sql = 'SELECT RELEASE_LOCK(\'' . $data . '\')'; $result = dbFetchCell($sql); return $result; - +} + /* * Passed an array and a table name, it attempts to insert the data into the table. * Check for boolean false to determine whether insert failed diff --git a/includes/dbFacile.mysqli.php b/includes/dbFacile.mysqli.php index 36b2208cb..158a1dae5 100644 --- a/includes/dbFacile.mysqli.php +++ b/includes/dbFacile.mysqli.php @@ -60,12 +60,12 @@ function dbQuery($sql, $parameters=array()) { /* - * Aquire a lock on a string + * Check a lock on a string * */ -function dbGetLock($data, $timeout = 0) { - $sql = 'SELECT GET_LOCK(\'' . $data . '\',' . $timeout . ')'; - $result = dbFetchCell($sql); - return $result; +function dbCheckLock($data, $timeout = 0) { + $sql = 'SELECT IS_FREE_LOCK(\'' . $data . '\')'; + $result = dbFetchCell($sql); + return $result; } @@ -76,6 +76,7 @@ function dbReleaseLock($data, $timeout = 0) { $sql = 'SELECT RELEASE_LOCK(\'' . $data . '\')'; $result = dbFetchCell($sql); return $result; +} /* From 1379a13c7686cfef66f52aa85625d609cf8b7400 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 22 Jul 2015 08:09:19 -0400 Subject: [PATCH 113/598] wait for all locks to be free when updating schema --- includes/sql-schema/update.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/includes/sql-schema/update.php b/includes/sql-schema/update.php index 19b043ada..46233e8dd 100644 --- a/includes/sql-schema/update.php +++ b/includes/sql-schema/update.php @@ -34,7 +34,11 @@ if (!isset($debug)) { if (!dbGetLock('schema_update')) { echo "Schema update already in progress. Exiting"; exit(1); -} +} //end if + +do { + sleep(1); +} while (@dbFetchCell('SELECT COUNT(*) FROM `devices` WHERE NOT IS_FREE_LOCK(CONCAT("polling.", device_id)) OR NOT IS_FREE_LOCK(CONCAT("queued.", device_id)) OR NOT IS_FREE_LOCK(CONCAT("discovering.", device_id))') > 0); $insert = 0; From c5fcb87b51b7590195e3e5b27570ace0fc8d8da6 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 22 Jul 2015 08:31:51 -0400 Subject: [PATCH 114/598] bail if schema is already up to date --- includes/sql-schema/update.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/includes/sql-schema/update.php b/includes/sql-schema/update.php index 46233e8dd..23038e5fc 100644 --- a/includes/sql-schema/update.php +++ b/includes/sql-schema/update.php @@ -32,7 +32,7 @@ if (!isset($debug)) { } if (!dbGetLock('schema_update')) { - echo "Schema update already in progress. Exiting"; + echo "Schema update already in progress. Exiting\n"; exit(1); } //end if @@ -93,6 +93,13 @@ if ($handle = opendir($config['install_dir'].'/sql-schema')) { asort($filelist); +if (explode('.', max($filelist), 2) <= $db_rev) { + if ($debug) { + echo "DB Schema already up to date.\n"; + } + exit(0); +} + foreach ($filelist as $file) { list($filename,$extension) = explode('.', $file, 2); if ($filename > $db_rev) { From e74a6db21650f1e3b08d4f190450ea0a712a1f2f Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 22 Jul 2015 08:32:30 -0400 Subject: [PATCH 115/598] move lock checks after bail out --- includes/sql-schema/update.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/includes/sql-schema/update.php b/includes/sql-schema/update.php index 23038e5fc..c07909845 100644 --- a/includes/sql-schema/update.php +++ b/includes/sql-schema/update.php @@ -31,15 +31,6 @@ if (!isset($debug)) { } } -if (!dbGetLock('schema_update')) { - echo "Schema update already in progress. Exiting\n"; - exit(1); -} //end if - -do { - sleep(1); -} while (@dbFetchCell('SELECT COUNT(*) FROM `devices` WHERE NOT IS_FREE_LOCK(CONCAT("polling.", device_id)) OR NOT IS_FREE_LOCK(CONCAT("queued.", device_id)) OR NOT IS_FREE_LOCK(CONCAT("discovering.", device_id))') > 0); - $insert = 0; if ($db_rev = @dbFetchCell('SELECT version FROM `dbSchema` ORDER BY version DESC LIMIT 1')) { @@ -100,6 +91,15 @@ if (explode('.', max($filelist), 2) <= $db_rev) { exit(0); } +if (!dbGetLock('schema_update')) { + echo "Schema update already in progress. Exiting\n"; + exit(1); +} //end if + +do { + sleep(1); +} while (@dbFetchCell('SELECT COUNT(*) FROM `devices` WHERE NOT IS_FREE_LOCK(CONCAT("polling.", device_id)) OR NOT IS_FREE_LOCK(CONCAT("queued.", device_id)) OR NOT IS_FREE_LOCK(CONCAT("discovering.", device_id))') > 0); + foreach ($filelist as $file) { list($filename,$extension) = explode('.', $file, 2); if ($filename > $db_rev) { From d9efadb441c243fb39a1dfe9eb26850ce1061013 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 22 Jul 2015 08:44:55 -0400 Subject: [PATCH 116/598] fix bailout comparison --- includes/sql-schema/update.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/sql-schema/update.php b/includes/sql-schema/update.php index c07909845..141139a35 100644 --- a/includes/sql-schema/update.php +++ b/includes/sql-schema/update.php @@ -84,7 +84,7 @@ if ($handle = opendir($config['install_dir'].'/sql-schema')) { asort($filelist); -if (explode('.', max($filelist), 2) <= $db_rev) { +if (explode('.', max($filelist), 2)[0] <= $db_rev) { if ($debug) { echo "DB Schema already up to date.\n"; } From 38af8b4c4c6cf568487342b3469811091466b32b Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 22 Jul 2015 08:48:33 -0400 Subject: [PATCH 117/598] return instead of exit --- includes/sql-schema/update.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/sql-schema/update.php b/includes/sql-schema/update.php index 141139a35..1d0c70804 100644 --- a/includes/sql-schema/update.php +++ b/includes/sql-schema/update.php @@ -88,7 +88,7 @@ if (explode('.', max($filelist), 2)[0] <= $db_rev) { if ($debug) { echo "DB Schema already up to date.\n"; } - exit(0); + return; } if (!dbGetLock('schema_update')) { From 33baea6d6a9edcec35f1e01690aca86405feff46 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 22 Jul 2015 08:50:35 -0400 Subject: [PATCH 118/598] release schema lock --- includes/sql-schema/update.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/includes/sql-schema/update.php b/includes/sql-schema/update.php index 1d0c70804..154ac007c 100644 --- a/includes/sql-schema/update.php +++ b/includes/sql-schema/update.php @@ -169,3 +169,5 @@ if ($updating) { echo "-- Done\n"; } + +dbReleaseLock('schema_update'); From 6f0969c1516b15c246606d3b16e12bbd5f6ccbf0 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 22 Jul 2015 09:04:12 -0400 Subject: [PATCH 119/598] typo --- poller-service.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poller-service.py b/poller-service.py index 178282026..74e584e64 100755 --- a/poller-service.py +++ b/poller-service.py @@ -238,7 +238,7 @@ while True: log.critical('ERROR: MySQL query error. Is your schema up to date?') sys.exit(2) cursor.fetchall() - log.info('INFO: {0} devices scanned in the last 5 minutes'.format(devices_scanned)) + log.info('INFO: {0} devices scanned in the last minute'.format(devices_scanned)) devices_scanned = 0 next_update = datetime.now() + timedelta(minutes=1) From 507e4baa95daacec409e31077cbea65f5175ccba Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Thu, 23 Jul 2015 14:48:08 -0400 Subject: [PATCH 120/598] simplify poller-service.conf --- poller-service.conf | 9 --------- 1 file changed, 9 deletions(-) diff --git a/poller-service.conf b/poller-service.conf index 36677e7d2..b41af1830 100644 --- a/poller-service.conf +++ b/poller-service.conf @@ -12,15 +12,6 @@ stop on runlevel [016] # Automatically restart process if crashed respawn -# Essentially lets upstart know the process will detach itself to the background -#expect fork - -# # Run before process -# pre-start script -# [ -d /var/run/myservice ] || mkdir -p /var/run/myservice -# echo "Put bash code here" -# end script - chdir /opt/librenms setuid librenms setgid librenms From bba88039338fdd7a22508a9b149164a0d226bc67 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Thu, 23 Jul 2015 14:49:34 -0400 Subject: [PATCH 121/598] symlink instead of copy --- doc/Extensions/Poller-Service.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/Extensions/Poller-Service.md b/doc/Extensions/Poller-Service.md index 354d58c39..d6efd97a2 100644 --- a/doc/Extensions/Poller-Service.md +++ b/doc/Extensions/Poller-Service.md @@ -21,4 +21,4 @@ $config['poller_service_down_retry'] = 60; Distributed polling is possible, and uses the same configuration options as are described for traditional distributed polling, except that the memcached options are not necessary. The database must be acessable from the distributed pollers, and properly configured. Remote access to the RRD directory must also be configured as described in the Distributed Poller documentation. Memcache is not required. Concurrency is managed using mysql GET_LOCK to ensure that devices are only being polled by one device at at time. The poller service is compatible with poller groups. ## Service Installation -The service is tested on Ubuntu 14.04. An upstart configuration `poller-service.conf` is provided. To install copy this file to `/etc/init/poller-service.conf`. The service will start on boot and can be started manually by running `start poller-service`. The service is configured to run as the user `librenms` and will fail if that user does not exist. +The service is tested on Ubuntu 14.04. An upstart configuration `poller-service.conf` is provided. To install symlink this file to `/etc/init/poller-service.conf`. The service will start on boot and can be started manually by running `start poller-service`. The service is configured to run as the user `librenms` and will fail if that user does not exist. From ef91005f6c9b6a84a425f6612bf3efa33409e269 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Thu, 23 Jul 2015 14:53:37 -0400 Subject: [PATCH 122/598] add LSB script --- poller-service.init | 88 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100755 poller-service.init diff --git a/poller-service.init b/poller-service.init new file mode 100755 index 000000000..ff5b4766c --- /dev/null +++ b/poller-service.init @@ -0,0 +1,88 @@ +### BEGIN INIT INFO +# Provides: poller-service +# Required-Start: networking +# Required-Stop: networking +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: The LibreNMS poller-service daemon +# Description: The LibreNMS poller-service daemon +# This polls devices monitored by LibreNMS +### END INIT INFO + +./lib/lsb/init-functions + +NAME=poller-service + +DAEMON=/opt/librenms/poller-service.py + +PIDFILE=/var/run/poller-service.pid + +test -x $DAEMON || exit 5 + +case $1 in + + start) + # Checked the PID file exists and check the actual status of process + if [ -e $PIDFILE ]; then + status_of_proc -p $PIDFILE $DAEMON "$NAME process" && status="0" || status="$?" + # If the status is SUCCESS then don't need to start again. + if [ $status = "0" ]; then + exit # Exit + fi + fi + # Start the daemon. + log_daemon_msg "Starting the process" "$NAME" + # Start the daemon with the help of start-stop-daemon + # Log the message appropriately + if start-stop-daemon --start --quiet --oknodo --pidfile $PIDFILE --exec $DAEMON ; then + log_end_msg 0 + else + log_end_msg 1 + fi + ;; + + stop) + # Stop the daemon. + if [ -e $PIDFILE ]; then + status_of_proc -p $PIDFILE $DAEMON "Stoppping the $NAME process" && status="0" || status="$?" + if [ "$status" = 0 ]; then + start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE + /bin/rm -rf $PIDFILE + fi + else + log_daemon_msg "$NAME process is not running" + log_end_msg 0 + fi + ;; + restart) + # Restart the daemon. + $0 stop && sleep 2 && $0 start + ;; + + status) + # Check the status of the process. + if [ -e $PIDFILE ]; then + status_of_proc -p $PIDFILE $DAEMON "$NAME process" && exit 0 || exit $? + else + log_daemon_msg "$NAME Process is not running" + log_end_msg 0 + fi + ;; + + reload) + # Reload the process. Basically sending some signal to a daemon to reload + # it configurations. + if [ -e $PIDFILE ]; then + start-stop-daemon --stop --signal USR1 --quiet --pidfile $PIDFILE --name $NAME + log_success_msg "$NAME process reloaded successfully" + else + log_failure_msg "$PIDFILE does not exists" + fi + ;; + + *) + # For invalid arguments, print the usage message. + echo "Usage: $0 {start|stop|restart|reload|status}" + exit 2 + ;; +esac From 4c5f7f9dd1ce34ac23849fda751fa976b5719367 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Thu, 23 Jul 2015 14:56:42 -0400 Subject: [PATCH 123/598] add lsb docs --- doc/Extensions/Poller-Service.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/Extensions/Poller-Service.md b/doc/Extensions/Poller-Service.md index d6efd97a2..4d709ccd6 100644 --- a/doc/Extensions/Poller-Service.md +++ b/doc/Extensions/Poller-Service.md @@ -21,4 +21,6 @@ $config['poller_service_down_retry'] = 60; Distributed polling is possible, and uses the same configuration options as are described for traditional distributed polling, except that the memcached options are not necessary. The database must be acessable from the distributed pollers, and properly configured. Remote access to the RRD directory must also be configured as described in the Distributed Poller documentation. Memcache is not required. Concurrency is managed using mysql GET_LOCK to ensure that devices are only being polled by one device at at time. The poller service is compatible with poller groups. ## Service Installation -The service is tested on Ubuntu 14.04. An upstart configuration `poller-service.conf` is provided. To install symlink this file to `/etc/init/poller-service.conf`. The service will start on boot and can be started manually by running `start poller-service`. The service is configured to run as the user `librenms` and will fail if that user does not exist. +An upstart configuration `poller-service.conf` is provided. To install run `ln -s /opt/librenms/poller-service.conf /etc/init/poller-service.conf`. The service will start on boot and can be started manually by running `start poller-service`. The service is configured to run as the user `librenms` and will fail if that user does not exist. + +An LSB init script `poller-service.init` is also provided. To install run `ln -s /opt/librenms/poller-service.init /etc/init.d/poller-service && update-rc.d poller-service defaults`. From 92177414ad0bb477b4470e73fa54f4dbb2c35cea Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Thu, 23 Jul 2015 14:59:17 -0400 Subject: [PATCH 124/598] space --- poller-service.init | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poller-service.init b/poller-service.init index ff5b4766c..7e1e5620f 100755 --- a/poller-service.init +++ b/poller-service.init @@ -9,7 +9,7 @@ # This polls devices monitored by LibreNMS ### END INIT INFO -./lib/lsb/init-functions +. /lib/lsb/init-functions NAME=poller-service From 29a6f1b0579555d4badee0a16330bb9891ebfe29 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Thu, 23 Jul 2015 15:03:01 -0400 Subject: [PATCH 125/598] run as librenms and background --- poller-service.init | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/poller-service.init b/poller-service.init index 7e1e5620f..25c4bd253 100755 --- a/poller-service.init +++ b/poller-service.init @@ -15,6 +15,8 @@ NAME=poller-service DAEMON=/opt/librenms/poller-service.py +USER=librenms + PIDFILE=/var/run/poller-service.pid test -x $DAEMON || exit 5 @@ -34,7 +36,7 @@ case $1 in log_daemon_msg "Starting the process" "$NAME" # Start the daemon with the help of start-stop-daemon # Log the message appropriately - if start-stop-daemon --start --quiet --oknodo --pidfile $PIDFILE --exec $DAEMON ; then + if start-stop-daemon --start --quiet --oknodo --pidfile $PIDFILE --exec $DAEMON --chuid $USER --background; then log_end_msg 0 else log_end_msg 1 @@ -69,17 +71,6 @@ case $1 in fi ;; - reload) - # Reload the process. Basically sending some signal to a daemon to reload - # it configurations. - if [ -e $PIDFILE ]; then - start-stop-daemon --stop --signal USR1 --quiet --pidfile $PIDFILE --name $NAME - log_success_msg "$NAME process reloaded successfully" - else - log_failure_msg "$PIDFILE does not exists" - fi - ;; - *) # For invalid arguments, print the usage message. echo "Usage: $0 {start|stop|restart|reload|status}" From 985ea21f6e2321d68626bfb8a842529f26b25807 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Thu, 23 Jul 2015 15:09:06 -0400 Subject: [PATCH 126/598] make and remove pidfile --- poller-service.init | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/poller-service.init b/poller-service.init index 25c4bd253..15f2509d5 100755 --- a/poller-service.init +++ b/poller-service.init @@ -36,7 +36,7 @@ case $1 in log_daemon_msg "Starting the process" "$NAME" # Start the daemon with the help of start-stop-daemon # Log the message appropriately - if start-stop-daemon --start --quiet --oknodo --pidfile $PIDFILE --exec $DAEMON --chuid $USER --background; then + if start-stop-daemon --start --quiet --oknodo --make-pidfile --pidfile $PIDFILE --exec $DAEMON --chuid $USER --background; then log_end_msg 0 else log_end_msg 1 @@ -48,7 +48,7 @@ case $1 in if [ -e $PIDFILE ]; then status_of_proc -p $PIDFILE $DAEMON "Stoppping the $NAME process" && status="0" || status="$?" if [ "$status" = 0 ]; then - start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE + start-stop-daemon --stop --quiet --oknodo --remove-pidfile --pidfile $PIDFILE /bin/rm -rf $PIDFILE fi else From 2fdea68e493e82ca5e77480a9d526115451d9286 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Thu, 23 Jul 2015 15:10:59 -0400 Subject: [PATCH 127/598] no removepidfile --- poller-service.init | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poller-service.init b/poller-service.init index 15f2509d5..6e870a6db 100755 --- a/poller-service.init +++ b/poller-service.init @@ -48,7 +48,7 @@ case $1 in if [ -e $PIDFILE ]; then status_of_proc -p $PIDFILE $DAEMON "Stoppping the $NAME process" && status="0" || status="$?" if [ "$status" = 0 ]; then - start-stop-daemon --stop --quiet --oknodo --remove-pidfile --pidfile $PIDFILE + start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE /bin/rm -rf $PIDFILE fi else From 2caba3ee589c6d5480c2bbc6781c96e9440aca93 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Thu, 23 Jul 2015 15:35:32 -0400 Subject: [PATCH 128/598] add note to reload initctl after linking upstart job --- doc/Extensions/Poller-Service.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/Extensions/Poller-Service.md b/doc/Extensions/Poller-Service.md index 4d709ccd6..26bf898c1 100644 --- a/doc/Extensions/Poller-Service.md +++ b/doc/Extensions/Poller-Service.md @@ -21,6 +21,6 @@ $config['poller_service_down_retry'] = 60; Distributed polling is possible, and uses the same configuration options as are described for traditional distributed polling, except that the memcached options are not necessary. The database must be acessable from the distributed pollers, and properly configured. Remote access to the RRD directory must also be configured as described in the Distributed Poller documentation. Memcache is not required. Concurrency is managed using mysql GET_LOCK to ensure that devices are only being polled by one device at at time. The poller service is compatible with poller groups. ## Service Installation -An upstart configuration `poller-service.conf` is provided. To install run `ln -s /opt/librenms/poller-service.conf /etc/init/poller-service.conf`. The service will start on boot and can be started manually by running `start poller-service`. The service is configured to run as the user `librenms` and will fail if that user does not exist. +An upstart configuration `poller-service.conf` is provided. To install run `ln -s /opt/librenms/poller-service.conf /etc/init/poller-service.conf`. The service will start on boot and can be started manually by running `start poller-service`. If you recieve an error that the service does not exist, run `initctl reload-configuration`. The service is configured to run as the user `librenms` and will fail if that user does not exist. An LSB init script `poller-service.init` is also provided. To install run `ln -s /opt/librenms/poller-service.init /etc/init.d/poller-service && update-rc.d poller-service defaults`. From a71172969f88ed4d2898e5a5e38722a051fb5003 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Tue, 28 Jul 2015 07:31:46 -0400 Subject: [PATCH 129/598] fix unused code --- includes/dbFacile.mysql.php | 22 ++++++++++++++++------ includes/dbFacile.mysqli.php | 21 +++++++++++++++------ 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/includes/dbFacile.mysql.php b/includes/dbFacile.mysql.php index bac21b008..7b75aa9fb 100644 --- a/includes/dbFacile.mysql.php +++ b/includes/dbFacile.mysql.php @@ -59,10 +59,20 @@ function dbQuery($sql, $parameters=array()) { }//end dbQuery() +/* + * Aquire a lock on a string + * */ +function dbGetLock($data, $timeout = 0) { + $sql = 'SELECT GET_LOCK(\'' . $data . '\',' . $timeout . ')'; + $result = dbFetchCell($sql); + return $result; +} + + /* * Check a lock on a string * */ -function dbCheckLock($data, $timeout = 0) { +function dbCheckLock($data) { $sql = 'SELECT IS_FREE_LOCK(\'' . $data . '\')'; $result = dbFetchCell($sql); return $result; @@ -72,12 +82,12 @@ function dbCheckLock($data, $timeout = 0) { /* * Release a lock on a string * */ -function dbReleaseLock($data, $timeout = 0) { - $sql = 'SELECT RELEASE_LOCK(\'' . $data . '\')'; - $result = dbFetchCell($sql); - return $result; +function dbReleaseLock($data) { + $sql = 'SELECT RELEASE_LOCK(\'' . $data . '\')'; + $result = dbFetchCell($sql); + return $result; } - + /* * Passed an array and a table name, it attempts to insert the data into the table. diff --git a/includes/dbFacile.mysqli.php b/includes/dbFacile.mysqli.php index 158a1dae5..d7016368d 100644 --- a/includes/dbFacile.mysqli.php +++ b/includes/dbFacile.mysqli.php @@ -59,10 +59,20 @@ function dbQuery($sql, $parameters=array()) { }//end dbQuery() +/* + * Aquire a lock on a string + * */ +function dbGetLock($data, $timeout = 0) { + $sql = 'SELECT GET_LOCK(\'' . $data . '\',' . $timeout . ')'; + $result = dbFetchCell($sql); + return $result; +} + + /* * Check a lock on a string * */ -function dbCheckLock($data, $timeout = 0) { +function dbCheckLock($data) { $sql = 'SELECT IS_FREE_LOCK(\'' . $data . '\')'; $result = dbFetchCell($sql); return $result; @@ -72,13 +82,12 @@ function dbCheckLock($data, $timeout = 0) { /* * Release a lock on a string * */ -function dbReleaseLock($data, $timeout = 0) { - $sql = 'SELECT RELEASE_LOCK(\'' . $data . '\')'; - $result = dbFetchCell($sql); - return $result; +function dbReleaseLock($data) { + $sql = 'SELECT RELEASE_LOCK(\'' . $data . '\')'; + $result = dbFetchCell($sql); + return $result; } - /* * Passed an array and a table name, it attempts to insert the data into the table. * Check for boolean false to determine whether insert failed From f28c0cceca229b17fc1177aa8cef5e6618af3513 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Thu, 30 Jul 2015 09:39:08 -0400 Subject: [PATCH 130/598] multi-master mysql docs --- doc/Extensions/Poller-Service.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/Extensions/Poller-Service.md b/doc/Extensions/Poller-Service.md index 26bf898c1..ab5461ca6 100644 --- a/doc/Extensions/Poller-Service.md +++ b/doc/Extensions/Poller-Service.md @@ -20,6 +20,9 @@ $config['poller_service_down_retry'] = 60; ## Distributed Polling Distributed polling is possible, and uses the same configuration options as are described for traditional distributed polling, except that the memcached options are not necessary. The database must be acessable from the distributed pollers, and properly configured. Remote access to the RRD directory must also be configured as described in the Distributed Poller documentation. Memcache is not required. Concurrency is managed using mysql GET_LOCK to ensure that devices are only being polled by one device at at time. The poller service is compatible with poller groups. +## Multi-Master MySQL considerations +Because locks are not replicated in Multi-Master MySQL configurations, if you are using such a configuration, you will need to make sure that all pollers are using the same MySQL server. + ## Service Installation An upstart configuration `poller-service.conf` is provided. To install run `ln -s /opt/librenms/poller-service.conf /etc/init/poller-service.conf`. The service will start on boot and can be started manually by running `start poller-service`. If you recieve an error that the service does not exist, run `initctl reload-configuration`. The service is configured to run as the user `librenms` and will fail if that user does not exist. From 588ea4083eee6d3dbf9f93f4416347f8204ffad2 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Fri, 21 Aug 2015 07:44:05 -0400 Subject: [PATCH 131/598] add license text --- poller-service.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/poller-service.py b/poller-service.py index 74e584e64..d8b48f455 100755 --- a/poller-service.py +++ b/poller-service.py @@ -10,6 +10,17 @@ Date: July 2015 License: BSD 2-Clause + +Copyright (c) 2015, Clint Armstrong +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """ import json From 29887af3766e1f2133b6c8d5fb9253b77de0b3a7 Mon Sep 17 00:00:00 2001 From: f0o Date: Wed, 26 Aug 2015 08:44:15 +0100 Subject: [PATCH 132/598] Remain PHP Backwards compatibility --- includes/sql-schema/update.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/includes/sql-schema/update.php b/includes/sql-schema/update.php index 154ac007c..00add08f9 100644 --- a/includes/sql-schema/update.php +++ b/includes/sql-schema/update.php @@ -83,8 +83,8 @@ if ($handle = opendir($config['install_dir'].'/sql-schema')) { } asort($filelist); - -if (explode('.', max($filelist), 2)[0] <= $db_rev) { +$tmp = explode('.', max($filelist), 2); +if ($tmp[0] <= $db_rev) { if ($debug) { echo "DB Schema already up to date.\n"; } From f28103173bf2a2885711c5686c4f6f985d98a31d Mon Sep 17 00:00:00 2001 From: f0o Date: Thu, 27 Aug 2015 14:05:47 +0100 Subject: [PATCH 133/598] Only process followups if there are any results --- alerts.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alerts.php b/alerts.php index fafc909ac..7a0f7afd4 100755 --- a/alerts.php +++ b/alerts.php @@ -193,7 +193,7 @@ function RunFollowUp() { $state = 4; } - if ($state > 0) { + if ($state > 0 && $n > 0) { $alert['details']['rule'] = $chk; if (dbInsert(array('state' => $state, 'device_id' => $alert['device_id'], 'rule_id' => $alert['rule_id'], 'details' => gzcompress(json_encode($alert['details']), 9)), 'alert_log')) { dbUpdate(array('state' => $state, 'open' => 1, 'alerted' => 1), 'alerts', 'rule_id = ? && device_id = ?', array($alert['rule_id'], $alert['device_id'])); From 867c83e9acdc13b758ed6c97b1ce29898f74cddc Mon Sep 17 00:00:00 2001 From: f0o Date: Thu, 27 Aug 2015 14:28:46 +0100 Subject: [PATCH 134/598] Fix Alert-Test Object. --- alerts.php | 2 +- html/includes/forms/test-transport.inc.php | 37 +++++++++++----------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/alerts.php b/alerts.php index fafc909ac..8cbeae55d 100755 --- a/alerts.php +++ b/alerts.php @@ -326,7 +326,7 @@ function ExtTransports($obj) { foreach ($config['alert']['transports'] as $transport => $opts) { if (($opts === true || !empty($opts)) && $opts != false && file_exists($config['install_dir'].'/includes/alerts/transport.'.$transport.'.php')) { echo $transport.' => '; - eval('$tmp = function($obj,$opts) { global $config; '.file_get_contents($config['install_dir'].'/includes/alerts/transport.'.$transport.'.php').' };'); + eval('$tmp = function($obj,$opts) { global $config; '.file_get_contents($config['install_dir'].'/includes/alerts/transport.'.$transport.'.php').' return false; };'); $tmp = $tmp($obj,$opts); $prefix = array( 0=>"recovery", 1=>$obj['severity']." alert", 2=>"acknowledgment" ); $prefix[3] = &$prefix[0]; diff --git a/html/includes/forms/test-transport.inc.php b/html/includes/forms/test-transport.inc.php index 121961ee0..4919a7ebc 100644 --- a/html/includes/forms/test-transport.inc.php +++ b/html/includes/forms/test-transport.inc.php @@ -18,31 +18,32 @@ if (is_admin() === false) { $transport = mres($_POST['transport']); +require_once $config['install_dir'].'/includes/alerts.inc.php'; +$tmp = array(dbFetchRow('select device_id,hostname from devices order by device_id asc limit 1')); +$tmp['contacts'] = GetContacts($tmp); $obj = array( - 'contacts' => $config['alert']['default_mail'], - 'title' => 'Testing transport from ' . $config['project_name'], - 'msg' => 'This is a test alert', - 'severity' => 'critical', - 'state' => 'critical', - 'hostname' => 'testing', - 'name' => 'Testing rule', + "hostname" => $tmp[0]['hostname'], + "device_id" => $tmp[0]['device_id'], + "title" => "Testing transport from ".$config['project_name'], + "elapsed" => "11s", + "id" => "000", + "faults" => false, + "uid" => "000", + "severity" => "critical", + "rule" => "%macros.device = 1", + "name" => "Test-Rule", + "timestamp" => date("Y-m-d H:i:s"), + "contacts" => $tmp['contacts'], + "state" => "0", + "msg" => "This is a test alert", ); -unset($obj); -$obj['contacts'] = 'test'; -$obj['title'] = 'test'; -$obj['msg'] = 'test'; -$obj['severity'] = 'test'; -$obj['state'] = 'test'; -$obj['hostname'] = 'test'; -$obj['name'] = 'test'; - $status = 'error'; -if (file_exists($config['install_dir']."/includes/alerts/transport.$transport.php")) { +if (file_exists($config['install_dir']."/includes/alerts/transport.".$transport.".php")) { $opts = $config['alert']['transports'][$transport]; if ($opts) { - eval('$tmp = function($obj,$opts) { global $config; '.file_get_contents($config['install_dir'].'/includes/alerts/transport.'.$transport.'.php').' };'); + eval('$tmp = function($obj,$opts) { global $config; '.file_get_contents($config['install_dir'].'/includes/alerts/transport.'.$transport.'.php').' return false; };'); $tmp = $tmp($obj,$opts); if ($tmp) { $status = 'ok'; From d58cdc0bb78ef0bb68cf2d8dde67b0c6203f9331 Mon Sep 17 00:00:00 2001 From: Rosiak Date: Thu, 27 Aug 2015 19:04:01 +0200 Subject: [PATCH 135/598] Basic MacOSX Discovery --- includes/definitions.inc.php | 8 ++++++++ includes/discovery/os/macosx.inc.php | 16 ++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 includes/discovery/os/macosx.inc.php diff --git a/includes/definitions.inc.php b/includes/definitions.inc.php index 0fc20c740..b818cf266 100644 --- a/includes/definitions.inc.php +++ b/includes/definitions.inc.php @@ -1276,6 +1276,14 @@ $config['os'][$os]['icon'] = 'perle'; $config['os'][$os]['over'][0]['graph'] = 'device_bits'; $config['os'][$os]['over'][0]['text'] = 'Traffic'; +// MACOSX +$os = 'macosx'; +$config['os'][$os]['text'] = 'Apple OSX'; +$config['os'][$os]['type'] = 'server'; +$config['os'][$os]['icon'] = 'generic'; +$config['os'][$os]['over'][0]['graph'] = 'device_bits'; +$config['os'][$os]['over'][0]['text'] = 'Traffic'; + // Graph Types require_once $config['install_dir'].'/includes/load_db_graph_types.inc.php'; diff --git a/includes/discovery/os/macosx.inc.php b/includes/discovery/os/macosx.inc.php new file mode 100644 index 000000000..e2cf9a534 --- /dev/null +++ b/includes/discovery/os/macosx.inc.php @@ -0,0 +1,16 @@ + + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. Please see LICENSE.txt at the top level of + * the source code distribution for details. + */ +if (!$os) { + if (strpos($sysObjectId, '1.3.6.1.4.1.8072.3.2.16') !== false) { + $os = 'macosx'; + } +} From 976dbfd1006dc2ebbbe7cdf0efeee763e473109e Mon Sep 17 00:00:00 2001 From: f0o Date: Thu, 27 Aug 2015 19:00:17 +0100 Subject: [PATCH 136/598] Temporally fixes #1771 A nicer fix would be knowing a full sysDescr.0 from a Zyxel IES DSLAM to be more specific with the matching. --- includes/discovery/os/ies.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/discovery/os/ies.inc.php b/includes/discovery/os/ies.inc.php index 62b2e49a6..1079ba8d8 100644 --- a/includes/discovery/os/ies.inc.php +++ b/includes/discovery/os/ies.inc.php @@ -1,7 +1,7 @@ Date: Thu, 27 Aug 2015 18:19:06 +0000 Subject: [PATCH 137/598] Added response to test transport button --- html/pages/settings/alerting.inc.php | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/html/pages/settings/alerting.inc.php b/html/pages/settings/alerting.inc.php index ef58465db..f6c1bda0a 100644 --- a/html/pages/settings/alerting.inc.php +++ b/html/pages/settings/alerting.inc.php @@ -834,12 +834,33 @@ echo '
$(".toolTip").tooltip(); $("button#test-alert").click(function() { - var transport = $(this).data("transport"); + var $this = $(this); + var transport = $this.data("transport"); $.ajax({ type: 'POST', url: '/ajax_form.php', data: { type: "test-transport", transport: transport }, - dataType: "json" + dataType: "json", + success: function(data){ + if (data.status == 'ok') { + $this.removeClass('btn-primary').addClass('btn-success'); + setTimeout(function(){ + $this.removeClass('btn-success').addClass('btn-primary'); + }, 2000); + } + else { + $this.removeClass('btn-primary').addClass('btn-danger'); + setTimeout(function(){ + $this.removeClass('btn-danger').addClass('btn-primary'); + }, 2000); + } + }, + error: function(){ + $this.removeClass('btn-primary').addClass('btn-danger'); + setTimeout(function(){ + $this.removeClass('btn-danger').addClass('btn-primary'); + }, 2000); + } }); }); From ddf800fb16a5ef1e7c30c02e690d028eae49f0a6 Mon Sep 17 00:00:00 2001 From: laf Date: Thu, 27 Aug 2015 20:29:16 +0000 Subject: [PATCH 138/598] Added docs for device groups and tried to make sure old alerting docs are clear --- doc/Extensions/Device-Groups.md | 30 ++++++++++++++++++++++++++++++ doc/Extensions/Email-Alerting.md | 10 +++++++--- 2 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 doc/Extensions/Device-Groups.md diff --git a/doc/Extensions/Device-Groups.md b/doc/Extensions/Device-Groups.md new file mode 100644 index 000000000..cc48cdaad --- /dev/null +++ b/doc/Extensions/Device-Groups.md @@ -0,0 +1,30 @@ +# Device Groups + +LibreNMS supports grouping your devices together in much the same way as you can configure alerts. This document will hopefully help you get started. + +### Pattern + +Patterns work in the same was as Entities within the alerting system, the format of the pattern is based on the MySQL structure your data is in such +as __tablename.columnname__. If you are ensure of what the entity is you want then have a browse around inside MySQL using `show tables` and `desc `. + +As a working example and a common question, let's assume you want to group devices by hostname. If you hostname format is dcX.[devicetype].example.com. You would use the pattern +devices.hostname. Select the condition which in this case would Like and then enter dc1.@.example.com. This would then match dc1.sw01.example.com, dc1.rtr01.example.com but not + dc2.sw01.example.com. + +#### Wildcards + +As used in the example above, wildcards are represented by the @ symbol. I.e @.example.com would match any hostnames under example.com. + +A list of common entities is maintained in our [Alerting docs](http://docs.librenms.org/Extensions/Alerting/#entities). + +### Conditions + +Please see our [Alerting docs](http://docs.librenms.org/Extensions/Alerting/#syntax) for explanations. + +### Connection + +If you only want to group based on one pattern then select And. If however you want to build a group based on multiple patterns then you can build a SQL like +query using And / Or. As an example, we want to base our group on the devices hostname AND it's type. Use the pattern as before, devices.hostname, select the condition which in this case would Like and then enter dc1.@.example.com then click And. Now enter devices.type in the pattern, select Equals and enter firewall. This would then match dc1.fw01.example.com but not dc1.sw01.example.com as that is a network type. + +You can now select this group from the Devices -> All Devices link in the navigation at the top. You can also use the group to map alert rules to by creating an alert mapping +Overview -> Alerts -> Rule Mapping. diff --git a/doc/Extensions/Email-Alerting.md b/doc/Extensions/Email-Alerting.md index 67b51a6ba..0cb61dc9d 100644 --- a/doc/Extensions/Email-Alerting.md +++ b/doc/Extensions/Email-Alerting.md @@ -2,11 +2,15 @@ #### Please see [The new alerting docs](http://docs.librenms.org/Extensions/Alerting/#transports-email) -Currently, the email alerts needs to be set up in the config. If you want to enable it, paste this in your config and change it: +> None of these configuration options will work on builds older than the 1st of August 2015. + + +~~Currently, the email alerts needs to be set up in the config. If you want to enable it, paste this in your config and change it:~~ + ```php // Mailer backend Settings -$config['email_backend'] = 'mail'; // Mail backend. Allowed: "mail" (PHP's built-in), "sendmail", "smtp". +~~$config['email_backend'] = 'mail'; // Mail backend. Allowed: "mail" (PHP's built-in), "sendmail", "smtp". $config['email_from'] = NULL; // Mail from. Default: "ProjectName" $config['email_user'] = $config['project_id']; $config['email_sendmail_path'] = '/usr/sbin/sendmail'; // The location of the sendmail program. @@ -23,5 +27,5 @@ $config['alerts']['email']['default'] = 'sendto@somewhere.com'; // Defau $config['alerts']['email']['default_only'] = FALSE; // Only use default recipient $config['alerts']['email']['enable'] = TRUE; // Enable email alerts $config['alerts']['bgp']['whitelist'] = NULL; // Populate as an array() with ASNs to alert on. -$config['alerts']['port']['ifdown'] = FALSE; // Generate alerts for ports that go down +$config['alerts']['port']['ifdown'] = FALSE; // Generate alerts for ports that go down~~ ``` From e7df1285477547307b1b1c96bfdb234c760063b8 Mon Sep 17 00:00:00 2001 From: laf Date: Thu, 27 Aug 2015 20:43:30 +0000 Subject: [PATCH 139/598] Added dnos to this, does not seem worth duplicating the code for another os --- includes/discovery/temperatures/ftos-s-series.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/discovery/temperatures/ftos-s-series.inc.php b/includes/discovery/temperatures/ftos-s-series.inc.php index f1628240f..fc18b4a6a 100644 --- a/includes/discovery/temperatures/ftos-s-series.inc.php +++ b/includes/discovery/temperatures/ftos-s-series.inc.php @@ -3,7 +3,7 @@ // Force10 S-Series // F10-S-SERIES-CHASSIS-MIB::chStackUnitTemp.1 = Gauge32: 47 // F10-S-SERIES-CHASSIS-MIB::chStackUnitModelID.1 = STRING: S25-01-GE-24V -if ($device['os'] == 'ftos' || $device['os_group'] == 'ftos') { +if ($device['os'] == 'ftos' || $device['os_group'] == 'ftos' || $device['os'] == 'dnos') { echo 'FTOS C-Series '; $oids = snmpwalk_cache_oid($device, 'chStackUnitTemp', array(), 'F10-S-SERIES-CHASSIS-MIB', $config['mib_dir'].':'.$config['mib_dir'].'/ftos'); From 2dc98ce2f7aafe59ea4290e905bfdc11830802c5 Mon Sep 17 00:00:00 2001 From: laf Date: Thu, 27 Aug 2015 21:01:31 +0000 Subject: [PATCH 140/598] Added check for zywall using OID --- includes/discovery/os/zywall.inc.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/includes/discovery/os/zywall.inc.php b/includes/discovery/os/zywall.inc.php index 0b3b25056..0a6fc008e 100644 --- a/includes/discovery/os/zywall.inc.php +++ b/includes/discovery/os/zywall.inc.php @@ -4,4 +4,7 @@ if (!$os) { if (strstr($sysDescr, 'ZyWALL')) { $os = 'zywall'; } + if (strstr($sysObjectId, '.1.3.6.1.4.1.890.1.15')) { + $os = 'zywall'; + } } From 5fe78afec6190465a7870af15fa33c658d9f432a Mon Sep 17 00:00:00 2001 From: vitalisator Date: Fri, 28 Aug 2015 08:54:35 +0200 Subject: [PATCH 141/598] add arrows to edges --- includes/defaults.inc.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/includes/defaults.inc.php b/includes/defaults.inc.php index 66ca1fcea..ca9da0bc2 100644 --- a/includes/defaults.inc.php +++ b/includes/defaults.inc.php @@ -339,6 +339,9 @@ $config['network_map_vis_options'] = '{ randomSeed:2 }, "edges": { + arrows: { + to: {enabled: true, scaleFactor:0.5}, + }, "smooth": { enabled: false }, From a1f9fe19faf38b395cdb9116fd299bd70a715993 Mon Sep 17 00:00:00 2001 From: f0o Date: Fri, 28 Aug 2015 09:24:08 +0100 Subject: [PATCH 142/598] Added option to display errored ports in device summary --- doc/Support/Configuration.md | 1 + html/includes/common/device-summary-horiz.inc.php | 4 ++++ html/includes/common/device-summary-vert.inc.php | 15 +++++++++++++++ includes/defaults.inc.php | 3 +++ 4 files changed, 23 insertions(+) diff --git a/doc/Support/Configuration.md b/doc/Support/Configuration.md index dfc2fd143..e804239e6 100644 --- a/doc/Support/Configuration.md +++ b/doc/Support/Configuration.md @@ -143,6 +143,7 @@ $config['show_locations'] = 1; # Enable Locations on menu $config['show_locations_dropdown'] = 1; # Enable Locations dropdown on menu $config['show_services'] = 0; # Enable Services on menu $config['int_customers'] = 1; # Enable Customer Port Parsing +$config['summary_errors'] = 0; # Show Errored ports in summary boxes on the dashboard $config['customers_descr'] = 'cust'; // The description to look for in ifDescr. Can be an array as well array('cust','cid'); $config['transit_descr'] = ""; // Add custom transit descriptions (can be an array) $config['peering_descr'] = ""; // Add custom peering descriptions (can be an array) diff --git a/html/includes/common/device-summary-horiz.inc.php b/html/includes/common/device-summary-horiz.inc.php index 439234af4..f8b6b56bd 100644 --- a/html/includes/common/device-summary-horiz.inc.php +++ b/html/includes/common/device-summary-horiz.inc.php @@ -12,6 +12,7 @@ $temp_output = '
+ '.($config['summary_errors'] ? '' : '').' @@ -22,6 +23,7 @@ $temp_output = ' + '.($config['summary_errors'] ? '' : '').' @@ -30,6 +32,7 @@ $temp_output = ' + '.($config['summary_errors'] ? '' : '').' '; if ($config['show_services']) { @@ -41,6 +44,7 @@ $temp_output .= ' + '.($config['summary_errors'] ? '' : '').' '; } $temp_output .= ' diff --git a/html/includes/common/device-summary-vert.inc.php b/html/includes/common/device-summary-vert.inc.php index e5d5706fe..067677504 100644 --- a/html/includes/common/device-summary-vert.inc.php +++ b/html/includes/common/device-summary-vert.inc.php @@ -83,6 +83,21 @@ if ($config['show_services']) { } +if ($config['summary_errors']) { + $temp_output .= ' + + + + + +'; + if ($config['show_services']) { + $temp_output .= ' + +'; + } +} + $temp_output .= ' diff --git a/includes/defaults.inc.php b/includes/defaults.inc.php index 66ca1fcea..27d715d93 100644 --- a/includes/defaults.inc.php +++ b/includes/defaults.inc.php @@ -783,3 +783,6 @@ $config['gui']['network-map']['style'] = 'new';//old is also va // Navbar variables $config['navbar']['manage_groups']['hide'] = 0; + +// Show errored ports in the summary table on the dashboard +$config['summary_errors'] = 0; From 08368f92f2fdb22256de0d418c9ca59e154babca Mon Sep 17 00:00:00 2001 From: laf Date: Fri, 28 Aug 2015 08:55:46 +0000 Subject: [PATCH 143/598] Moved strikeout to outside code block --- doc/Extensions/Email-Alerting.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/Extensions/Email-Alerting.md b/doc/Extensions/Email-Alerting.md index 0cb61dc9d..fc20362e9 100644 --- a/doc/Extensions/Email-Alerting.md +++ b/doc/Extensions/Email-Alerting.md @@ -8,9 +8,9 @@ ~~Currently, the email alerts needs to be set up in the config. If you want to enable it, paste this in your config and change it:~~ -```php +~~```php // Mailer backend Settings -~~$config['email_backend'] = 'mail'; // Mail backend. Allowed: "mail" (PHP's built-in), "sendmail", "smtp". +$config['email_backend'] = 'mail'; // Mail backend. Allowed: "mail" (PHP's built-in), "sendmail", "smtp". $config['email_from'] = NULL; // Mail from. Default: "ProjectName" $config['email_user'] = $config['project_id']; $config['email_sendmail_path'] = '/usr/sbin/sendmail'; // The location of the sendmail program. @@ -27,5 +27,5 @@ $config['alerts']['email']['default'] = 'sendto@somewhere.com'; // Defau $config['alerts']['email']['default_only'] = FALSE; // Only use default recipient $config['alerts']['email']['enable'] = TRUE; // Enable email alerts $config['alerts']['bgp']['whitelist'] = NULL; // Populate as an array() with ASNs to alert on. -$config['alerts']['port']['ifdown'] = FALSE; // Generate alerts for ports that go down~~ -``` +$config['alerts']['port']['ifdown'] = FALSE; // Generate alerts for ports that go down +```~~ From 813b518abf4ba217524a09b4b5558f1196bc0b96 Mon Sep 17 00:00:00 2001 From: laf Date: Fri, 28 Aug 2015 08:58:06 +0000 Subject: [PATCH 144/598] Renamed file --- .../{ftos-s-series.inc.php => dnos-ftos-s-series.inc.php} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename includes/discovery/temperatures/{ftos-s-series.inc.php => dnos-ftos-s-series.inc.php} (100%) diff --git a/includes/discovery/temperatures/ftos-s-series.inc.php b/includes/discovery/temperatures/dnos-ftos-s-series.inc.php similarity index 100% rename from includes/discovery/temperatures/ftos-s-series.inc.php rename to includes/discovery/temperatures/dnos-ftos-s-series.inc.php From 950b58ba657f71149720e1051d7ca97efc1259f5 Mon Sep 17 00:00:00 2001 From: laf Date: Fri, 28 Aug 2015 09:02:36 +0000 Subject: [PATCH 145/598] Removed strikethrough --- doc/Extensions/Email-Alerting.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/doc/Extensions/Email-Alerting.md b/doc/Extensions/Email-Alerting.md index fc20362e9..55a2f0a5f 100644 --- a/doc/Extensions/Email-Alerting.md +++ b/doc/Extensions/Email-Alerting.md @@ -7,8 +7,7 @@ ~~Currently, the email alerts needs to be set up in the config. If you want to enable it, paste this in your config and change it:~~ - -~~```php +```php // Mailer backend Settings $config['email_backend'] = 'mail'; // Mail backend. Allowed: "mail" (PHP's built-in), "sendmail", "smtp". $config['email_from'] = NULL; // Mail from. Default: "ProjectName" @@ -28,4 +27,4 @@ $config['alerts']['email']['default_only'] = FALSE; // Only use default recipi $config['alerts']['email']['enable'] = TRUE; // Enable email alerts $config['alerts']['bgp']['whitelist'] = NULL; // Populate as an array() with ASNs to alert on. $config['alerts']['port']['ifdown'] = FALSE; // Generate alerts for ports that go down -```~~ +``` From 1384505d1c51d9abaca3736aa0f5fd0adc592608 Mon Sep 17 00:00:00 2001 From: Richard Lawley Date: Fri, 28 Aug 2015 14:38:57 +0100 Subject: [PATCH 146/598] Fix broken repeated RRA config Since d8693f0 the RRA config section repeats in the file - the second contains MAX instead of the first MIN definition. --- includes/defaults.inc.php | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/includes/defaults.inc.php b/includes/defaults.inc.php index 9776c5991..db087244b 100644 --- a/includes/defaults.inc.php +++ b/includes/defaults.inc.php @@ -191,14 +191,7 @@ $config['snmp']['v3'][0]['cryptopass'] = ''; // Privacy (Encryption) Passphrase $config['snmp']['v3'][0]['cryptoalgo'] = 'AES'; // AES | DES -// RRD Format Settings -// These should not normally be changed -// Though one could conceivably increase or decrease the size of each RRA if one had performance problems -// Or if one had a very fast I/O subsystem with no performance worries. -$config['rrd_rra'] = ' RRA:AVERAGE:0.5:1:2016 RRA:AVERAGE:0.5:6:1440 RRA:AVERAGE:0.5:24:1440 RRA:AVERAGE:0.5:288:1440 '; -$config['rrd_rra'] .= ' RRA:MAX:0.5:1:720 RRA:MIN:0.5:6:1440 RRA:MIN:0.5:24:775 RRA:MIN:0.5:288:797 '; -$config['rrd_rra'] .= ' RRA:MAX:0.5:1:720 RRA:MAX:0.5:6:1440 RRA:MAX:0.5:24:775 RRA:MAX:0.5:288:797 '; -$config['rrd_rra'] .= ' RRA:LAST:0.5:1:1440 '; + // Autodiscovery Settings $config['autodiscovery']['xdp'] = true; From 408b8dd8551120468e3924d5db5fc7ee4775dc1d Mon Sep 17 00:00:00 2001 From: Louis Rossouw Date: Sat, 29 Aug 2015 02:41:47 +0200 Subject: [PATCH 147/598] Fix to avoid triggering this bug: http://sourceforge.net/p/mysql-python/bugs/325/ We remove miliseconds from datetime. --- poller-service.py | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/poller-service.py b/poller-service.py index d8b48f455..099bf7213 100755 --- a/poller-service.py +++ b/poller-service.py @@ -195,18 +195,24 @@ poller_group = ('and poller_group IN({0}) ' # Add last_polled and last_polled_timetaken so we can sort by the time the last poll started, with the goal # of having each device complete a poll within the given time range. dev_query = ('SELECT device_id, status, ' - 'DATE_ADD( ' - ' DATE_SUB( ' - ' last_polled, ' - ' INTERVAL last_polled_timetaken SECOND ' - ' ), ' - ' INTERVAL {0} SECOND) AS next_poll, ' - 'DATE_ADD( ' - ' DATE_SUB( ' - ' last_discovered, ' - ' INTERVAL last_discovered_timetaken SECOND ' - ' ), ' - ' INTERVAL {1} SECOND) AS next_discovery ' + 'CAST( ' + ' DATE_ADD( ' + ' DATE_SUB( ' + ' last_polled, ' + ' INTERVAL last_polled_timetaken SECOND ' + ' ), ' + ' INTERVAL {0} SECOND) ' + ' AS DATETIME(0) ' + ') AS next_poll, ' + 'CAST( ' + ' DATE_ADD( ' + ' DATE_SUB( ' + ' last_discovered, ' + ' INTERVAL last_discovered_timetaken SECOND ' + ' ), ' + ' INTERVAL {1} SECOND) ' + ' AS DATETIME(0) ' + ') as next_discovery ' 'FROM devices WHERE ' 'disabled = 0 ' 'AND IS_FREE_LOCK(CONCAT("polling.", device_id)) ' From 35c7c6ab1bea037156038eebc77f5ab5b41e62e8 Mon Sep 17 00:00:00 2001 From: Arjit Chaudhary Date: Sat, 29 Aug 2015 18:46:14 +0530 Subject: [PATCH 148/598] Display a message if no Group is found Screenshot: http://i.imgur.com/ac9okNO.png --- html/pages/device-groups.inc.php | 36 +++++++++++++++++++------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/html/pages/device-groups.inc.php b/html/pages/device-groups.inc.php index 891b42c20..e5e6c9918 100644 --- a/html/pages/device-groups.inc.php +++ b/html/pages/device-groups.inc.php @@ -3,23 +3,31 @@ require_once 'includes/modal/new_device_group.inc.php'; require_once 'includes/modal/delete_device_group.inc.php'; $no_refresh = true; - +$group_count_check = array_filter(GetDeviceGroups()); +if(!empty($group_count_check)) { echo '
'; echo '
'; echo '
StatusDown Ignored DisabledErrored
'.$devices['down'].' '.$devices['ignored'].' '.$devices['disabled'].'-
Ports '.$ports['down'].' '.$ports['ignored'].' '.$ports['shutdown'].' '.$ports['errored'].'
'.$services['down'].' '.$services['ignored'].' '.$services['disabled'].'-
Errored- '.$ports['errored'].'-
'; echo ''; echo ''; -foreach (GetDeviceGroups() as $group) { - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; -} - + foreach (GetDeviceGroups() as $group) { + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + } +} else { //if $group_count_check is empty, aka no group found, then display a message to the user. + echo "
Looks like no groups have been created, let's create one now. Click on Create New Group to create one.

"; + echo "
"; +} echo '
NameDescriptionPatternActions
'.$group['name'].''.$group['desc'].''.$group['pattern'].''; - echo " "; - echo ""; - echo '
'.$group['name'].''.$group['desc'].''.$group['pattern'].''; + echo " "; + echo ""; + echo '
'; -echo " "; + +if(!empty($group_count_check)) { //display create new node group when $group_count_check has a value so that the user can define more groups in the future. +echo "
"; +echo "
"; +} From 55e94573091f039a63854094e4ff749f73122adf Mon Sep 17 00:00:00 2001 From: Arjit Chaudhary Date: Sat, 29 Aug 2015 18:50:57 +0530 Subject: [PATCH 149/598] Minor UI changes Screenshot: http://i.imgur.com/PwmyNNG.png --- html/pages/addhost.inc.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/html/pages/addhost.inc.php b/html/pages/addhost.inc.php index 27bca2a57..2844982d7 100644 --- a/html/pages/addhost.inc.php +++ b/html/pages/addhost.inc.php @@ -221,7 +221,8 @@ if ($config['distributed_poller'] === true) { }//end if ?> - +
+
From 7efbb076957995e7c50399e4b62cbc4eb2c239cd Mon Sep 17 00:00:00 2001 From: Arjit Chaudhary Date: Sat, 29 Aug 2015 19:00:50 +0530 Subject: [PATCH 150/598] Unify UI as in add device.. Screenshot: http://i.imgur.com/TgpwIXR.png --- html/pages/delhost.inc.php | 55 +++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/html/pages/delhost.inc.php b/html/pages/delhost.inc.php index 165ee99e4..79a2e3f05 100644 --- a/html/pages/delhost.inc.php +++ b/html/pages/delhost.inc.php @@ -1,5 +1,3 @@ -

Delete Host

-
+
@@ -46,37 +45,39 @@ else { else { ?> - -
-
- -

It will also remove historical data about this device such as Syslog, Eventlog and Alert log data.

");?> -
-
-
- -
- + ".$data['hostname'].""); + } -".$data['hostname'].""); -} - -?> - -
-
+ ?> + +
+ +
+
+
+
-
- - -
Date: Sat, 29 Aug 2015 21:27:11 +0530 Subject: [PATCH 151/598] Fixed indents and coding style. --- html/pages/device-groups.inc.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/html/pages/device-groups.inc.php b/html/pages/device-groups.inc.php index e5e6c9918..8cc08e020 100644 --- a/html/pages/device-groups.inc.php +++ b/html/pages/device-groups.inc.php @@ -21,13 +21,14 @@ echo ''; echo ''; echo ''; } -} else { //if $group_count_check is empty, aka no group found, then display a message to the user. +} +else { //if $group_count_check is empty, aka no group found, then display a message to the user. echo "
Looks like no groups have been created, let's create one now. Click on Create New Group to create one.

"; echo "
"; } echo '
'; if(!empty($group_count_check)) { //display create new node group when $group_count_check has a value so that the user can define more groups in the future. -echo "
"; -echo "
"; + echo "
"; + echo "
"; } From 419336a7a29d6f89b570c2d07a54f46c6ac9449c Mon Sep 17 00:00:00 2001 From: Arjit Chaudhary Date: Sat, 29 Aug 2015 21:36:19 +0530 Subject: [PATCH 152/598] Add page title for poll-log.inc.php --- html/pages/poll-log.inc.php | 1 + 1 file changed, 1 insertion(+) diff --git a/html/pages/poll-log.inc.php b/html/pages/poll-log.inc.php index ac912a6f8..ddeca02c8 100644 --- a/html/pages/poll-log.inc.php +++ b/html/pages/poll-log.inc.php @@ -1,5 +1,6 @@ From 9488ef63a904a119aa41ea5051c06d46a5ad590c Mon Sep 17 00:00:00 2001 From: Arjit Chaudhary Date: Sat, 29 Aug 2015 21:44:29 +0530 Subject: [PATCH 153/598] UI changes to preferences.inc.php Screenshot: http://i.imgur.com/QaobUQv.png --- html/pages/preferences.inc.php | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/html/pages/preferences.inc.php b/html/pages/preferences.inc.php index 91a02e1ce..661a7a8f5 100644 --- a/html/pages/preferences.inc.php +++ b/html/pages/preferences.inc.php @@ -4,7 +4,8 @@ $no_refresh = true; $pagetitle[] = 'Preferences'; -echo '

User Preferences

'; +echo '

User Preferences

'; +echo '
'; if ($_SESSION['userlevel'] == 11) { demo_account(); @@ -30,10 +31,12 @@ else { include 'includes/update-preferences-password.inc.php'; - echo "
"; + if (passwordscanchange($_SESSION['username'])) { echo '

Change Password

'; + echo '
'; + echo "
"; echo $changepass_message; echo "
@@ -57,11 +60,13 @@ else {
+
+
- + "; echo '
'; }//end if @@ -183,9 +188,10 @@ else { }//end if }//end if -echo "
"; -echo "
Device Permissions
"; +echo "

Device Permissions

"; +echo "
"; +echo "
"; if ($_SESSION['userlevel'] == '10') { echo "Global Administrative Access"; } From c69596314aa832eb9c8d5f94687a6a3282f14737 Mon Sep 17 00:00:00 2001 From: Arjit Chaudhary Date: Sat, 29 Aug 2015 22:10:19 +0530 Subject: [PATCH 154/598] Added header to authlog page --- html/pages/authlog.inc.php | 236 ++++++++++++++++++++++++++++++++----- 1 file changed, 207 insertions(+), 29 deletions(-) diff --git a/html/pages/authlog.inc.php b/html/pages/authlog.inc.php index 3cffbbea9..661a7a8f5 100644 --- a/html/pages/authlog.inc.php +++ b/html/pages/authlog.inc.php @@ -1,37 +1,215 @@ = '10') { - echo '
'; +$no_refresh = true; - foreach (dbFetchRows("SELECT *,DATE_FORMAT(datetime, '".$config['dateformat']['mysql']['compact']."') as humandate FROM `authlog` ORDER BY `datetime` DESC LIMIT 0,250") as $entry) { - if ($bg == $list_colour_a) { - $bg = $list_colour_b; - } - else { - $bg = $list_colour_a; - } +$pagetitle[] = 'Preferences'; - echo " - - - - - - '; - }//end foreach +echo '

User Preferences

'; +echo '
'; - $pagetitle[] = 'Authlog'; - - echo '
- ".$entry['datetime'].' - - '.$entry['user'].' - - '.$entry['address'].' - - '.$entry['result'].' -
'; +if ($_SESSION['userlevel'] == 11) { + demo_account(); } else { - include 'includes/error-no-perm.inc.php'; + if ($_POST['action'] == 'changepass') { + if (authenticate($_SESSION['username'], $_POST['old_pass'])) { + if ($_POST['new_pass'] == '' || $_POST['new_pass2'] == '') { + $changepass_message = 'Password must not be blank.'; + } + else if ($_POST['new_pass'] == $_POST['new_pass2']) { + changepassword($_SESSION['username'], $_POST['new_pass']); + $changepass_message = 'Password Changed.'; + } + else { + $changepass_message = "Passwords don't match."; + } + } + else { + $changepass_message = 'Incorrect password'; + } + } + + include 'includes/update-preferences-password.inc.php'; + + + + if (passwordscanchange($_SESSION['username'])) { + echo '

Change Password

'; + echo '
'; + echo "
"; + echo $changepass_message; + echo "
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+
+
+
+
+ +
+ +
+
+
+
+
+
+ +
"; + echo '
'; + }//end if + + if ($config['twofactor'] === true) { + if ($_POST['twofactorremove'] == 1) { + include_once $config['install_dir'].'/html/includes/authentication/twofactor.lib.php'; + if (!isset($_POST['twofactor'])) { + echo '
'; + echo ''; + echo twofactor_form(false); + echo '
'; + } + else { + $twofactor = dbFetchRow('SELECT twofactor FROM users WHERE username = ?', array($_SESSION['username'])); + if (empty($twofactor['twofactor'])) { + echo '
Error: How did you even get here?!
'; + } + else { + $twofactor = json_decode($twofactor['twofactor'], true); + } + + if (verify_hotp($twofactor['key'], $_POST['twofactor'], $twofactor['counter'])) { + if (!dbUpdate(array('twofactor' => ''), 'users', 'username = ?', array($_SESSION['username']))) { + echo '
Error while disabling TwoFactor.
'; + } + else { + echo '
TwoFactor Disabled.
'; + } + } + else { + session_destroy(); + echo '
Error: Supplied TwoFactor Token is wrong, you\'ve been logged out.
'; + } + }//end if + } + else { + $twofactor = dbFetchRow('SELECT twofactor FROM users WHERE username = ?', array($_SESSION['username'])); + echo ''; + echo '

Two-Factor Authentication

'; + if (!empty($twofactor['twofactor'])) { + $twofactor = json_decode($twofactor['twofactor'], true); + $twofactor['text'] = "
+ +
+ +
+
"; + if ($twofactor['counter'] !== false) { + $twofactor['uri'] = 'otpauth://hotp/'.$_SESSION['username'].'?issuer=LibreNMS&counter='.$twofactor['counter'].'&secret='.$twofactor['key']; + $twofactor['text'] .= "
+ +
+ +
+
"; + } + else { + $twofactor['uri'] = 'otpauth://totp/'.$_SESSION['username'].'?issuer=LibreNMS&secret='.$twofactor['key']; + } + + echo '
+
+ +
'; + echo '
+
'.$twofactor['text'].'
+ +
'; + echo ''; + echo '
+ + +
'; + } + else { + if (isset($_POST['gentwofactorkey']) && isset($_POST['twofactortype'])) { + include_once $config['install_dir'].'/html/includes/authentication/twofactor.lib.php'; + $chk = dbFetchRow('SELECT twofactor FROM users WHERE username = ?', array($_SESSION['username'])); + if (empty($chk['twofactor'])) { + $twofactor = array('key' => twofactor_genkey()); + if ($_POST['twofactortype'] == 'counter') { + $twofactor['counter'] = 1; + } + else { + $twofactor['counter'] = false; + } + + if (!dbUpdate(array('twofactor' => json_encode($twofactor)), 'users', 'username = ?', array($_SESSION['username']))) { + echo '
Error inserting TwoFactor details. Please try again later and contact Administrator if error persists.
'; + } + else { + echo '
Added TwoFactor credentials. Please reload page.
'; + } + } + else { + echo '
TwoFactor credentials already exists.
'; + } + } + else { + echo '
+ +
+ +
+ +
+
+ +
'; + }//end if + }//end if + echo '
'; + }//end if + }//end if }//end if + + +echo "

Device Permissions

"; +echo "
"; +echo "
"; +if ($_SESSION['userlevel'] == '10') { + echo "Global Administrative Access"; +} + +if ($_SESSION['userlevel'] == '5') { + echo "Global Viewing Access"; +} + +if ($_SESSION['userlevel'] == '1') { + foreach (dbFetchRows('SELECT * FROM `devices_perms` AS P, `devices` AS D WHERE `user_id` = ? AND P.device_id = D.device_id', array($_SESSION['user_id'])) as $perm) { + // FIXME generatedevicelink? + echo "".$perm['hostname'].'
'; + $dev_access = 1; + } + + if (!$dev_access) { + echo 'No access!'; + } +} + +echo '
'; From 1f8c48ac66568a4f5b90d2997a84acd756b8facc Mon Sep 17 00:00:00 2001 From: Arjit Chaudhary Date: Sat, 29 Aug 2015 22:35:13 +0530 Subject: [PATCH 155/598] Fixed :) --- html/pages/authlog.inc.php | 237 +++++-------------------------------- 1 file changed, 30 insertions(+), 207 deletions(-) diff --git a/html/pages/authlog.inc.php b/html/pages/authlog.inc.php index 661a7a8f5..a882e83fd 100644 --- a/html/pages/authlog.inc.php +++ b/html/pages/authlog.inc.php @@ -1,215 +1,38 @@ Authlog"; +echo "
"; +if ($_SESSION['userlevel'] >= '10') { + echo ''; -$no_refresh = true; + foreach (dbFetchRows("SELECT *,DATE_FORMAT(datetime, '".$config['dateformat']['mysql']['compact']."') as humandate FROM `authlog` ORDER BY `datetime` DESC LIMIT 0,250") as $entry) { + if ($bg == $list_colour_a) { + $bg = $list_colour_b; + } + else { + $bg = $list_colour_a; + } -$pagetitle[] = 'Preferences'; + echo " + + + + + + '; + }//end foreach -echo '

User Preferences

'; -echo '
'; + $pagetitle[] = 'Authlog'; -if ($_SESSION['userlevel'] == 11) { - demo_account(); + echo '
+ ".$entry['datetime'].' + + '.$entry['user'].' + + '.$entry['address'].' + + '.$entry['result'].' +
'; } else { - if ($_POST['action'] == 'changepass') { - if (authenticate($_SESSION['username'], $_POST['old_pass'])) { - if ($_POST['new_pass'] == '' || $_POST['new_pass2'] == '') { - $changepass_message = 'Password must not be blank.'; - } - else if ($_POST['new_pass'] == $_POST['new_pass2']) { - changepassword($_SESSION['username'], $_POST['new_pass']); - $changepass_message = 'Password Changed.'; - } - else { - $changepass_message = "Passwords don't match."; - } - } - else { - $changepass_message = 'Incorrect password'; - } - } - - include 'includes/update-preferences-password.inc.php'; - - - - if (passwordscanchange($_SESSION['username'])) { - echo '

Change Password

'; - echo '
'; - echo "
"; - echo $changepass_message; - echo "
- -
- -
- -
-
-
-
-
- -
- -
-
-
-
-
- -
- -
-
-
-
-
-
- -
"; - echo '
'; - }//end if - - if ($config['twofactor'] === true) { - if ($_POST['twofactorremove'] == 1) { - include_once $config['install_dir'].'/html/includes/authentication/twofactor.lib.php'; - if (!isset($_POST['twofactor'])) { - echo '
'; - echo ''; - echo twofactor_form(false); - echo '
'; - } - else { - $twofactor = dbFetchRow('SELECT twofactor FROM users WHERE username = ?', array($_SESSION['username'])); - if (empty($twofactor['twofactor'])) { - echo '
Error: How did you even get here?!
'; - } - else { - $twofactor = json_decode($twofactor['twofactor'], true); - } - - if (verify_hotp($twofactor['key'], $_POST['twofactor'], $twofactor['counter'])) { - if (!dbUpdate(array('twofactor' => ''), 'users', 'username = ?', array($_SESSION['username']))) { - echo '
Error while disabling TwoFactor.
'; - } - else { - echo '
TwoFactor Disabled.
'; - } - } - else { - session_destroy(); - echo '
Error: Supplied TwoFactor Token is wrong, you\'ve been logged out.
'; - } - }//end if - } - else { - $twofactor = dbFetchRow('SELECT twofactor FROM users WHERE username = ?', array($_SESSION['username'])); - echo ''; - echo '

Two-Factor Authentication

'; - if (!empty($twofactor['twofactor'])) { - $twofactor = json_decode($twofactor['twofactor'], true); - $twofactor['text'] = "
- -
- -
-
"; - if ($twofactor['counter'] !== false) { - $twofactor['uri'] = 'otpauth://hotp/'.$_SESSION['username'].'?issuer=LibreNMS&counter='.$twofactor['counter'].'&secret='.$twofactor['key']; - $twofactor['text'] .= "
- -
- -
-
"; - } - else { - $twofactor['uri'] = 'otpauth://totp/'.$_SESSION['username'].'?issuer=LibreNMS&secret='.$twofactor['key']; - } - - echo '
-
- -
'; - echo '
-
'.$twofactor['text'].'
- -
'; - echo ''; - echo '
- - -
'; - } - else { - if (isset($_POST['gentwofactorkey']) && isset($_POST['twofactortype'])) { - include_once $config['install_dir'].'/html/includes/authentication/twofactor.lib.php'; - $chk = dbFetchRow('SELECT twofactor FROM users WHERE username = ?', array($_SESSION['username'])); - if (empty($chk['twofactor'])) { - $twofactor = array('key' => twofactor_genkey()); - if ($_POST['twofactortype'] == 'counter') { - $twofactor['counter'] = 1; - } - else { - $twofactor['counter'] = false; - } - - if (!dbUpdate(array('twofactor' => json_encode($twofactor)), 'users', 'username = ?', array($_SESSION['username']))) { - echo '
Error inserting TwoFactor details. Please try again later and contact Administrator if error persists.
'; - } - else { - echo '
Added TwoFactor credentials. Please reload page.
'; - } - } - else { - echo '
TwoFactor credentials already exists.
'; - } - } - else { - echo '
- -
- -
- -
-
- -
'; - }//end if - }//end if - echo '
'; - }//end if - }//end if + include 'includes/error-no-perm.inc.php'; }//end if - - -echo "

Device Permissions

"; -echo "
"; -echo "
"; -if ($_SESSION['userlevel'] == '10') { - echo "Global Administrative Access"; -} - -if ($_SESSION['userlevel'] == '5') { - echo "Global Viewing Access"; -} - -if ($_SESSION['userlevel'] == '1') { - foreach (dbFetchRows('SELECT * FROM `devices_perms` AS P, `devices` AS D WHERE `user_id` = ? AND P.device_id = D.device_id', array($_SESSION['user_id'])) as $perm) { - // FIXME generatedevicelink? - echo "".$perm['hostname'].'
'; - $dev_access = 1; - } - - if (!$dev_access) { - echo 'No access!'; - } -} - -echo '
'; From eb70f3e089455eda8c78b6ba7fade90b0af78f21 Mon Sep 17 00:00:00 2001 From: Arjit Chaudhary Date: Sat, 29 Aug 2015 22:37:27 +0530 Subject: [PATCH 156/598] Added page title --- html/pages/about.inc.php | 1 + 1 file changed, 1 insertion(+) diff --git a/html/pages/about.inc.php b/html/pages/about.inc.php index 53eee1e3e..8d131d5b5 100644 --- a/html/pages/about.inc.php +++ b/html/pages/about.inc.php @@ -1,4 +1,5 @@ '; if(!empty($group_count_check)) { //display create new node group when $group_count_check has a value so that the user can define more groups in the future. echo "
"; From cba5e03817821f55e21def2db4902b1fdcd2d016 Mon Sep 17 00:00:00 2001 From: Arjit Chaudhary Date: Sat, 29 Aug 2015 22:44:44 +0530 Subject: [PATCH 158/598] Added title and page header --- html/pages/availability-map.inc.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/html/pages/availability-map.inc.php b/html/pages/availability-map.inc.php index d41153b65..b5ede4e14 100644 --- a/html/pages/availability-map.inc.php +++ b/html/pages/availability-map.inc.php @@ -1,4 +1,6 @@ +

Availability Map

+
Date: Sat, 29 Aug 2015 22:52:09 +0530 Subject: [PATCH 159/598] UI changes Screenshot http://i.imgur.com/tObHk8F.png --- html/pages/adduser.inc.php | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/html/pages/adduser.inc.php b/html/pages/adduser.inc.php index 1ba262150..7f5c21c09 100644 --- a/html/pages/adduser.inc.php +++ b/html/pages/adduser.inc.php @@ -10,6 +10,7 @@ else if ($_SESSION['userlevel'] == 11) { } else { echo '

Add User

'; + echo '
'; $pagetitle[] = 'Add user'; @@ -37,7 +38,6 @@ else { echo '
Please enter a username!
'; }//end if }//end if - echo "
"; echo "
@@ -89,22 +89,25 @@ else { +
+ +
+
+
"; echo "
-
- -
+
"; - echo ""; + echo '
'; } else { From e9ca3d4d702b867a3afab95844f9e3c18fcd903d Mon Sep 17 00:00:00 2001 From: Rosiak Date: Sun, 30 Aug 2015 16:16:18 +0100 Subject: [PATCH 160/598] Docs Correction --- doc/Installation/Installation-(RHEL-CentOS).md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/Installation/Installation-(RHEL-CentOS).md b/doc/Installation/Installation-(RHEL-CentOS).md index 124fbe9f8..101a0d766 100644 --- a/doc/Installation/Installation-(RHEL-CentOS).md +++ b/doc/Installation/Installation-(RHEL-CentOS).md @@ -27,14 +27,13 @@ service mariadb start Now continue with the installation: ```bash -yum install net-snmp mysql-server service snmpd start chkconfig snmpd on mysql_secure_installation mysql -uroot -p ``` -Enter the MySQL root password to enter the MySQL command-line interface. +Enter the MySQL/MariaDB root password to enter the command-line interface. Create database. From ac7d0c9420680c864a434b404d117092dbae963c Mon Sep 17 00:00:00 2001 From: f0o Date: Sun, 30 Aug 2015 16:53:34 +0100 Subject: [PATCH 161/598] Added user defined titles for alert templates --- alerts.php | 36 ++++++++++++--------- html/includes/forms/alert-templates.inc.php | 4 +-- html/includes/modal/alert_template.inc.php | 2 ++ sql-schema/066.sql | 2 ++ 4 files changed, 26 insertions(+), 18 deletions(-) create mode 100644 sql-schema/066.sql diff --git a/alerts.php b/alerts.php index 8cbeae55d..b23f96fa0 100755 --- a/alerts.php +++ b/alerts.php @@ -96,24 +96,14 @@ function IssueAlert($alert) { return true; } - $default_tpl = "%title\r\nSeverity: %severity\r\n{if %state == 0}Time elapsed: %elapsed\r\n{/if}Timestamp: %timestamp\r\nUnique-ID: %uid\r\nRule: {if %name}%name{else}%rule{/if}\r\n{if %faults}Faults:\r\n{foreach %faults} #%key: %value.string\r\n{/foreach}{/if}Alert sent to: {foreach %contacts}%value <%key> {/foreach}"; - // FIXME: Put somewhere else? if ($config['alert']['fixed-contacts'] == false) { $alert['details']['contacts'] = GetContacts($alert['details']['rule']); } $obj = DescribeAlert($alert); if (is_array($obj)) { - $tpl = dbFetchRow('SELECT `template` FROM `alert_templates` JOIN `alert_template_map` ON `alert_template_map`.`alert_templates_id`=`alert_templates`.`id` WHERE `alert_template_map`.`alert_rule_id`=?', array($alert['rule_id'])); - if (isset($tpl['template'])) { - $tpl = $tpl['template']; - } - else { - $tpl = $default_tpl; - } - echo 'Issuing Alert-UID #'.$alert['id'].'/'.$alert['state'].': '; - $msg = FormatAlertTpl($tpl, $obj); + $msg = FormatAlertTpl($obj); $obj['msg'] = $msg; if (!empty($config['alert']['transports'])) { ExtTransports($obj); @@ -349,12 +339,11 @@ function ExtTransports($obj) { /** * Format Alert - * @param string $tpl Template * @param array $obj Alert-Array * @return string */ -function FormatAlertTpl($tpl, $obj) { - $msg = '$ret .= "'.str_replace(array('{else}', '{/if}', '{/foreach}'), array('"; } else { $ret .= "', '"; } $ret .= "', '"; } $ret .= "'), addslashes($tpl)).'";'; +function FormatAlertTpl($obj) { + $msg = '$ret .= "'.str_replace(array('{else}', '{/if}', '{/foreach}'), array('"; } else { $ret .= "', '"; } $ret .= "', '"; } $ret .= "'), addslashes($obj["template"])).'";'; $parsed = $msg; $s = strlen($msg); $x = $pos = -1; @@ -426,11 +415,21 @@ function DescribeAlert($alert) { $obj = array(); $i = 0; $device = dbFetchRow('SELECT hostname FROM devices WHERE device_id = ?', array($alert['device_id'])); + $tpl = dbFetchRow('SELECT `template`,`title`,`title_rec` FROM `alert_templates` JOIN `alert_template_map` ON `alert_template_map`.`alert_templates_id`=`alert_templates`.`id` WHERE `alert_template_map`.`alert_rule_id`=?', array($alert['rule_id'])); + $default_tpl = "%title\r\nSeverity: %severity\r\n{if %state == 0}Time elapsed: %elapsed\r\n{/if}Timestamp: %timestamp\r\nUnique-ID: %uid\r\nRule: {if %name}%name{else}%rule{/if}\r\n{if %faults}Faults:\r\n{foreach %faults} #%key: %value.string\r\n{/foreach}{/if}Alert sent to: {foreach %contacts}%value <%key> {/foreach}"; $obj['hostname'] = $device['hostname']; $obj['device_id'] = $alert['device_id']; $extra = $alert['details']; + if (!isset($tpl['template'])) { + $tpl['template'] = $default_tpl; + } if ($alert['state'] >= 1) { - $obj['title'] = 'Alert for device '.$device['hostname'].' - '.($alert['name'] ? $alert['name'] : $alert['rule']); + if (!empty($tpl['title'])) { + $obj['title'] = $tpl['title']; + } + else { + $obj['title'] = 'Alert for device '.$device['hostname'].' - '.($alert['name'] ? $alert['name'] : $alert['rule']); + } if ($alert['state'] == 2) { $obj['title'] .= ' got acknowledged'; } @@ -458,7 +457,12 @@ function DescribeAlert($alert) { } $extra = json_decode(gzuncompress($id['details']), true); - $obj['title'] = 'Device '.$device['hostname'].' recovered from '.($alert['name'] ? $alert['name'] : $alert['rule']); + if (!empty($tpl['title_rec'])) { + $obj['title'] = $tpl['title_rec']; + } + else { + $obj['title'] = 'Device '.$device['hostname'].' recovered from '.($alert['name'] ? $alert['name'] : $alert['rule']); + } $obj['elapsed'] = TimeFormat(strtotime($alert['time_logged']) - strtotime($id['time_logged'])); $obj['id'] = $id['id']; $obj['faults'] = false; diff --git a/html/includes/forms/alert-templates.inc.php b/html/includes/forms/alert-templates.inc.php index 67182b1f2..74fda1b8c 100644 --- a/html/includes/forms/alert-templates.inc.php +++ b/html/includes/forms/alert-templates.inc.php @@ -52,7 +52,7 @@ if(!empty($name)) { elseif( $_REQUEST['template'] && is_numeric($_REQUEST['template_id']) ) { //Update template-text - if($ret = dbUpdate(array('template' => $_REQUEST['template'], 'name' => $name), "alert_templates", "id = ?", array($_REQUEST['template_id']))) { + if($ret = dbUpdate(array('template' => $_REQUEST['template'], 'name' => $name, 'title' => $_REQUEST['title'], 'title_rec' => $_REQUEST['title_rec']), "alert_templates", "id = ?", array($_REQUEST['template_id']))) { $ok = "Updated template"; } else { @@ -62,7 +62,7 @@ if(!empty($name)) { elseif( $_REQUEST['template'] ) { //Create new template - if(dbInsert(array('template' => $_REQUEST['template'], 'name' => $name), "alert_templates")) { + if(dbInsert(array('template' => $_REQUEST['template'], 'name' => $name, 'title' => $_REQUEST['title'], 'title_rec' => $_REQUEST['title_rec']), "alert_templates")) { $ok = "Alert template has been created."; } else { diff --git a/html/includes/modal/alert_template.inc.php b/html/includes/modal/alert_template.inc.php index 71574ba6f..dceab82cf 100644 --- a/html/includes/modal/alert_template.inc.php +++ b/html/includes/modal/alert_template.inc.php @@ -51,6 +51,8 @@ if(is_admin() === false) {

Give your template a name:

+ Optionally, add custom titles:
+

diff --git a/sql-schema/066.sql b/sql-schema/066.sql new file mode 100644 index 000000000..37b4dc6ed --- /dev/null +++ b/sql-schema/066.sql @@ -0,0 +1,2 @@ +ALTER TABLE `alert_templates` ADD `title` VARCHAR(255) NULL DEFAULT NULL; +ALTER TABLE `alert_templates` ADD `title_rec` VARCHAR(255) NULL DEFAULT NULL; From 9057d48273778159d45cb7fabc5054361886204e Mon Sep 17 00:00:00 2001 From: f0o Date: Sun, 30 Aug 2015 17:07:02 +0100 Subject: [PATCH 162/598] Fix default template assignment --- alerts.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/alerts.php b/alerts.php index b23f96fa0..eb63a8ad5 100755 --- a/alerts.php +++ b/alerts.php @@ -343,7 +343,8 @@ function ExtTransports($obj) { * @return string */ function FormatAlertTpl($obj) { - $msg = '$ret .= "'.str_replace(array('{else}', '{/if}', '{/foreach}'), array('"; } else { $ret .= "', '"; } $ret .= "', '"; } $ret .= "'), addslashes($obj["template"])).'";'; + $tpl = $obj["template"]; + $msg = '$ret .= "'.str_replace(array('{else}', '{/if}', '{/foreach}'), array('"; } else { $ret .= "', '"; } $ret .= "', '"; } $ret .= "'), addslashes($tpl)).'";'; $parsed = $msg; $s = strlen($msg); $x = $pos = -1; @@ -421,7 +422,9 @@ function DescribeAlert($alert) { $obj['device_id'] = $alert['device_id']; $extra = $alert['details']; if (!isset($tpl['template'])) { - $tpl['template'] = $default_tpl; + $obj['template'] = $default_tpl; + } else { + $obj['template'] = $tpl['template']; } if ($alert['state'] >= 1) { if (!empty($tpl['title'])) { From 65e38c69b18087d03231a2897d416791889ef37e Mon Sep 17 00:00:00 2001 From: Rosiak Date: Sun, 30 Aug 2015 17:14:30 +0100 Subject: [PATCH 163/598] Add Varnish Docs - Fix #1808 --- doc/Extensions/Varnish.md | 53 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 doc/Extensions/Varnish.md diff --git a/doc/Extensions/Varnish.md b/doc/Extensions/Varnish.md new file mode 100644 index 000000000..001332007 --- /dev/null +++ b/doc/Extensions/Varnish.md @@ -0,0 +1,53 @@ +# Setting up Varnish + +This document will explain how to setup Varnish for LibreNMS. + +### Varnish installation +This example is based on a fresh LibreNMS install, on a minimimal CentOS installation. +In this example, we'll use the default package available through yum. + +- Install Varnish + +```ssh +yum install varnish +chkconfig varnish on +``` +- Confirm that Varnish has been installed + +```ssh +varnishd -V +varnishd (varnish-2.1.5 SVN ) +``` +- Change the webservers port to 8080, since we'll put Varnish in front(Or whatever you prefer) + +- Point Varnish towards the webserver by editing the default.vcl + +```ssh +vi /etc/varnish/default.vcl + +backend default { + .host = "127.0.0.1"; + .port = "8080"; +} + +``` +- Change the default port Varnish listens on + +```ssh +vi /etc/sysconfig/varnish + +VARNISH_LISTEN_PORT=80 +``` + +- Restart webserver(Apache in this case) and start Varnish afterwards + +```ssh +service httpd restart +service varnish start +``` + +- Browse around the webui to build up the cache, verify that the cache is working afterwards + +```ssh +varnishstat +``` From 68f9812b9d18c63a236f58a50b9d436daa85deb5 Mon Sep 17 00:00:00 2001 From: f0o Date: Sun, 30 Aug 2015 17:27:31 +0100 Subject: [PATCH 164/598] Added JavaScript to modal --- html/includes/modal/alert_template.inc.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/html/includes/modal/alert_template.inc.php b/html/includes/modal/alert_template.inc.php index dceab82cf..bef4957a2 100644 --- a/html/includes/modal/alert_template.inc.php +++ b/html/includes/modal/alert_template.inc.php @@ -125,10 +125,12 @@ $('#create-template').click('', function(e) { var template = $("#template").val(); var template_id = $("#template_id").val(); var name = $("#name").val(); + var title = $("#title").val(); + var title_rec = $("#title_rec").val(); $.ajax({ type: "POST", url: "ajax_form.php", - data: { type: "alert-templates", template: template , name: name, template_id: template_id}, + data: { type: "alert-templates", template: template , name: name, template_id: template_id, title: title, title_rec: title_rec}, dataType: "html", success: function(msg){ if(msg.indexOf("ERROR:") <= -1) { From 937d598564e7a577e328b5b4ed6ab0d9c288329d Mon Sep 17 00:00:00 2001 From: Paul Gear Date: Sun, 30 Aug 2015 17:48:45 +0100 Subject: [PATCH 165/598] Move packages into overview menu --- html/includes/print-menubar.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/html/includes/print-menubar.php b/html/includes/print-menubar.php index 06b4ffb04..927cba8fe 100644 --- a/html/includes/print-menubar.php +++ b/html/includes/print-menubar.php @@ -65,6 +65,14 @@ if ($_SESSION['userlevel'] >= '10') {
  • Templates
  • +
  • + Packages +
  • + @@ -427,14 +435,6 @@ if ($_SESSION['userlevel'] >= '5' && ($routing_count['bgp']+$routing_count['ospf -
  • - Packages -
  • -
  • Templates
  • -
  • - Packages -
  • - @@ -97,6 +89,15 @@ if (isset($config['graylog']['server']) && isset($config['graylog']['port'])) { ?>
  • Inventory
  • + +
  • + Packages +
  • +
  • IPv4 Search
  • From a833d46d4d5aae6cd1dda89055ff4b91501540d1 Mon Sep 17 00:00:00 2001 From: f0o Date: Sun, 30 Aug 2015 18:02:29 +0100 Subject: [PATCH 167/598] Add placehoders to custom titles --- alerts.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/alerts.php b/alerts.php index eb63a8ad5..3e8bdead8 100755 --- a/alerts.php +++ b/alerts.php @@ -480,6 +480,9 @@ function DescribeAlert($alert) { $obj['timestamp'] = $alert['time_logged']; $obj['contacts'] = $extra['contacts']; $obj['state'] = $alert['state']; + if (strstr($obj['title'],'%')) { + $obj['title'] = RunJail('$ret = "'.populate(addslashes($obj['title'])).'";', $obj); + } return $obj; }//end DescribeAlert() From bea05876344ba4f2e2f632637bfdd9f39581dcfa Mon Sep 17 00:00:00 2001 From: f0o Date: Sun, 30 Aug 2015 18:05:57 +0100 Subject: [PATCH 168/598] Fixed edit-javascript --- html/includes/forms/parse-alert-template.inc.php | 6 ++++-- html/includes/modal/alert_template.inc.php | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/html/includes/forms/parse-alert-template.inc.php b/html/includes/forms/parse-alert-template.inc.php index 31dc3c714..2b8bb2e56 100644 --- a/html/includes/forms/parse-alert-template.inc.php +++ b/html/includes/forms/parse-alert-template.inc.php @@ -21,8 +21,10 @@ $template_id = ($_POST['template_id']); if (is_numeric($template_id) && $template_id > 0) { $template = dbFetchRow('SELECT * FROM `alert_templates` WHERE `id` = ? LIMIT 1', array($template_id)); $output = array( - 'template' => $template['template'], - 'name' => $template['name'], + 'template' => $template['template'], + 'name' => $template['name'], + 'title' => $template['title'], + 'title_rec' => $template['title_rec'], ); echo _json_encode($output); } diff --git a/html/includes/modal/alert_template.inc.php b/html/includes/modal/alert_template.inc.php index bef4957a2..8e96f3032 100644 --- a/html/includes/modal/alert_template.inc.php +++ b/html/includes/modal/alert_template.inc.php @@ -115,6 +115,8 @@ $('#alert-template').on('show.bs.modal', function (event) { success: function(output) { $('#template').val(output['template']); $('#name').val(output['name']); + $('#title').val(output['title']); + $('#title_rec').val(output['title_rec']); } }); } From 3ae4372e6821284a2da25be61741feccdec11eb2 Mon Sep 17 00:00:00 2001 From: laf Date: Sun, 30 Aug 2015 17:33:54 +0000 Subject: [PATCH 169/598] Initial work on port override --- html/includes/table/edit-ports.inc.php | 4 +-- html/pages/device/edit/ports.inc.php | 38 ++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/html/includes/table/edit-ports.inc.php b/html/includes/table/edit-ports.inc.php index d53a436d8..0c73c88b5 100644 --- a/html/includes/table/edit-ports.inc.php +++ b/html/includes/table/edit-ports.inc.php @@ -64,7 +64,7 @@ foreach (dbFetchRows($sql, $param) as $port) { ', 'ignore' => ' ', - 'ifAlias' => $port['ifAlias'] + 'ifAlias' => '' ); }//end foreach @@ -75,4 +75,4 @@ $output = array( 'rows' => $response, 'total' => $total, ); -echo _json_encode($output); \ No newline at end of file +echo _json_encode($output); diff --git a/html/pages/device/edit/ports.inc.php b/html/pages/device/edit/ports.inc.php index 865439595..368747a76 100644 --- a/html/pages/device/edit/ports.inc.php +++ b/html/pages/device/edit/ports.inc.php @@ -1,3 +1,4 @@ +
    n.b For the first time, please click any button twice.
    @@ -20,6 +21,42 @@
    '; } else { From e67f91c48ebdc67a6beb11be80e14fd5e27abe6e Mon Sep 17 00:00:00 2001 From: laf Date: Mon, 31 Aug 2015 21:17:34 +0000 Subject: [PATCH 190/598] Added FortiOS definitions + appliance type --- includes/definitions.inc.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/includes/definitions.inc.php b/includes/definitions.inc.php index 24326b104..5fcdce7b6 100644 --- a/includes/definitions.inc.php +++ b/includes/definitions.inc.php @@ -1284,6 +1284,18 @@ $config['os'][$os]['icon'] = 'generic'; $config['os'][$os]['over'][0]['graph'] = 'device_bits'; $config['os'][$os]['over'][0]['text'] = 'Traffic'; +// Appliances +$os = 'fortios'; +$config['os'][$os]['text'] = 'FortiOS'; +$config['os'][$os]['type'] = 'appliance'; +$config['os'][$os]['icon'] = 'fortios'; +$config['os'][$os]['over'][0]['graph'] = 'device_bits'; +$config['os'][$os]['over'][0]['text'] = 'Traffic'; +$config['os'][$os]['over'][1]['graph'] = 'device_processor'; +$config['os'][$os]['over'][1]['text'] = 'CPU Usage'; +$config['os'][$os]['over'][2]['graph'] = 'device_mempool'; +$config['os'][$os]['over'][2]['text'] = 'Memory Usage'; + // Graph Types require_once $config['install_dir'].'/includes/load_db_graph_types.inc.php'; @@ -1638,6 +1650,11 @@ if (isset($config['enable_printers']) && $config['enable_printers']) { $config['device_types'][$i]['icon'] = 'printer.png'; } +$i++; +$config['device_types'][$i]['text'] = 'Appliance'; +$config['device_types'][$i]['type'] = 'appliance'; +$config['device_types'][$i]['icon'] = 'appliance.png'; + // // No changes below this line # // From 6d39bb4f81c2818fabd28d449bd1bd93e40ad697 Mon Sep 17 00:00:00 2001 From: laf Date: Mon, 31 Aug 2015 21:17:56 +0000 Subject: [PATCH 191/598] Added appliance logo - this is a copy of apps.png --- html/images/icons/appliance.png | Bin 0 -> 555 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 html/images/icons/appliance.png diff --git a/html/images/icons/appliance.png b/html/images/icons/appliance.png new file mode 100644 index 0000000000000000000000000000000000000000..851950db7c285f586d7ee74bcc417f225bdf18c1 GIT binary patch literal 555 zcmV+`0@VG9P)CjNr zUW1fN1d-Gd7r2N>l%796-}n2KALIT2^YO?eu@~9M*vzf-7i;%d+Nwx^J95X|kPDY1 zGh9Mum^%l$6{Q6;tonHam& z&u-m)+9C;(lg!W0^P=Y{J$aeIu9KK&6b^;p+My?$?QijWYk;}0r)e}Am>WqzqNC`2 z&bQ6)?2D%u>Kdo4V?>9yzpnCg;~hszOJrF_;)Rg}bEBg#TjxYM(AWKi=r@UR2yLC= z^Xf3~moMO(#>D=QByLU;NZgGixEo2m zUZ+l-#NFwTM29LuhehJSZEZZ_k>_v$^`U`{uGrzP*mgoQg002ovPDHLkV1oRO19t!b literal 0 HcmV?d00001 From 3c577a271576fcedf81fcb2016062a5c8458d4d5 Mon Sep 17 00:00:00 2001 From: laf Date: Mon, 31 Aug 2015 21:18:19 +0000 Subject: [PATCH 192/598] www.fortinet.com/sites/all/themes/fortinet/images/fortinet_logo.png --- html/images/os/fortios.png | Bin 0 -> 22231 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 html/images/os/fortios.png diff --git a/html/images/os/fortios.png b/html/images/os/fortios.png new file mode 100644 index 0000000000000000000000000000000000000000..3c4252d05423f5bd5be6c13d98d24712d3f1ef87 GIT binary patch literal 22231 zcmeI4cT`hZ)VD89nji=YDoF2y&;y}LkuG4PgCPWnbP~E0k=_)P-Yg(Zx^$@`NN>`+ zG!+4*D&U3jnkik@E6dT9$TbJCvoJJ)?@eJfpp% zojKAP0RXNexo$|YYx{%WMqZwwi*QRpu&*VxuSwp`qN6L8Z>H9WV&!hR_n7z;S3;Jb zma1U%1Jw|@EMZ2beVR90TRYPGkS-^wRGOX2t?HGMf$D*h{ObH_8GzaMd3m|z11iRV z$U1bHK8ou#ZbWbJ;>kpZ{7$XIMdmxs#Gmnv6pS-J0A5-nW(Io(^r_~KyfGGl5 z?kA@7V>mu!0P+UDcohIZ07n^S{2K%(0ysw8bKh~?nE~zM_%Hze6bb2gKoIW3-C%8F za~|FMP58P4PdX`yol|(kg3c_~L@{VQZZ>e+t)E6qG)E`tg;_4hY`a?emCytBxDR!% zyp-~c@qBEfLOIb1)RFsaHY&M^J$n~;`6Vc6-!d+E*%)BN^Z7=E(60hp@z=*~%Xq@F z>xFqv02KIj>QoI5{i+)PmIbT}*;I!a|*mdf?6P zdqkJpP)&SI9B#Y8OKLaV^V;b=&Z!i;7;WC|Xk;sQ=ks{!V2@8)fUlyAuR`Rj8{`+1 z*HWo+&#=OjO!$TzZTAI){}-xhJmDL-c$QN*S)Yh$WdpZs9p+{6*t?mCX$!Vvjij?> zIlFy`Rb&HQgM7E@{AdknAx&fsN@KK;SK$sCh76ExDvp-V8QeV~mMYKL^r=qme9$@PHr1)g7t2vjxz5jR^(r z�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 UaVA>_H;St$UQ)=DyW#u)01aSCO#lD@ literal 0 HcmV?d00001 From 703bdf37174af124e0bbdc66257b390a0dbe7d1d Mon Sep 17 00:00:00 2001 From: laf Date: Mon, 31 Aug 2015 21:18:49 +0000 Subject: [PATCH 193/598] http://en.community.dell.com/techcenter/networking/nms/f/4877/t/19583922 --- mibs/FORTINET-FORTIANALYZER-MIB.mib | 538 ++++++++++++++++++++++++++++ 1 file changed, 538 insertions(+) create mode 100755 mibs/FORTINET-FORTIANALYZER-MIB.mib diff --git a/mibs/FORTINET-FORTIANALYZER-MIB.mib b/mibs/FORTINET-FORTIANALYZER-MIB.mib new file mode 100755 index 000000000..e4681cd51 --- /dev/null +++ b/mibs/FORTINET-FORTIANALYZER-MIB.mib @@ -0,0 +1,538 @@ + +FORTINET-FORTIANALYZER-MIB DEFINITIONS ::= BEGIN + +IMPORTS + FnIndex, fnGenTrapMsg, fnSysSerial, fortinet, fnTrapsPrefix + FROM FORTINET-CORE-MIB + InetPortNumber + FROM INET-ADDRESS-MIB + sysName + FROM SNMPv2-MIB + MODULE-COMPLIANCE, NOTIFICATION-GROUP, OBJECT-GROUP + FROM SNMPv2-CONF + Counter32, Gauge32, Integer32, IpAddress, MODULE-IDENTITY, + NOTIFICATION-TYPE, OBJECT-TYPE + FROM SNMPv2-SMI + DisplayString, TEXTUAL-CONVENTION + FROM SNMPv2-TC; + +fnFortiAnalyzerMib MODULE-IDENTITY + LAST-UPDATED "200909210000Z" + ORGANIZATION + "Fortinet Technologies, Inc." + CONTACT-INFO + " + Technical Support + email: support@fortinet.com + http://www.fortinet.com" + DESCRIPTION + "MIB module for Fortinet FortiAnalyzer devices." + REVISION "200909210000Z" + DESCRIPTION + "Fix syntax errors." + REVISION "200902050000Z" + DESCRIPTION + "Initial version of FORTINET-FORTIANALYZER-MIB." + ::= { fortinet 102 } + +FaSessProto ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "data type for session protocols" + SYNTAX INTEGER { ip(0), icmp(1), igmp(2), ipip(4), tcp(6), + egp(8), pup(12), udp(17), idp(22), ipv6(41), + rsvp(46), gre(47), esp(50), ah(51), ospf(89), + pim(103), comp(108), raw(255) } + +FaRAIDStatusCode ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "Enumerated list of RAID status codes." + SYNTAX INTEGER { arrayOK(1), arrayDegraded(2), arrayInoperable(3), + arrayRebuilding(4), arrayRebuildingStarted(5), + arrayRebuildingFinished(6), arrayInitializing(7), + arrayInitializingStarted(8), arrayInitializingFinished(9), + diskOK(10), diskDegraded(11), diskFailEvent(12) } + +FaSysEventCode ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "Enumerated list of system events." + SYNTAX INTEGER { systemHalt(1), systemReboot(2), + upgradeConfig(3), systemUpgrade(4), logdiskFormat(5) } + +faTraps OBJECT IDENTIFIER + ::= { fnFortiAnalyzerMib 0 } + +faTrapPrefix OBJECT IDENTIFIER + ::= { faTraps 0 } + +faTrapObject OBJECT IDENTIFIER + ::= { faTraps 1 } + +faSystemEvent OBJECT-TYPE + SYNTAX FaSysEventCode + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "Type of system event that triggered notification." + ::= { faTrapObject 1 } + +faRAIDStatus OBJECT-TYPE + SYNTAX FaRAIDStatusCode + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "New RAID state associated with a RAID status change event." + ::= { faTrapObject 2 } + +faRAIDDevIndex OBJECT-TYPE + SYNTAX DisplayString (SIZE(0..32)) + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "Name/index of a RAID device relating to the event." + ::= { faTrapObject 3 } + +faGenAlert OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Detail of defined event alert sent from FortiAnalyzer" + ::= { faTrapObject 4 } + +faModel OBJECT IDENTIFIER + ::= { fnFortiAnalyzerMib 1 } + +faz100 OBJECT IDENTIFIER + ::= { faModel 1000 } + +faz100A OBJECT IDENTIFIER + ::= { faModel 1001 } + +faz100B OBJECT IDENTIFIER + ::= { faModel 1002 } + +faz100C OBJECT IDENTIFIER + ::= { faModel 1003 } + +faz400 OBJECT IDENTIFIER + ::= { faModel 4000 } + +faz400B OBJECT IDENTIFIER + ::= { faModel 4002 } + +faz800 OBJECT IDENTIFIER + ::= { faModel 8000 } + +faz800B OBJECT IDENTIFIER + ::= { faModel 8002 } + +faz1000B OBJECT IDENTIFIER + ::= { faModel 10002 } + +faz2000 OBJECT IDENTIFIER + ::= { faModel 20000 } + +faz2000A OBJECT IDENTIFIER + ::= { faModel 20001 } + +faz4000 OBJECT IDENTIFIER + ::= { faModel 40000 } + +faz4000A OBJECT IDENTIFIER + ::= { faModel 40001 } + + +faInetProto OBJECT IDENTIFIER + ::= { fnFortiAnalyzerMib 2 } + +faInetProtoInfo OBJECT IDENTIFIER + ::= { faInetProto 1 } + +faInetProtoTables OBJECT IDENTIFIER + ::= { faInetProto 2 } + +faIpSessTable OBJECT-TYPE + SYNTAX SEQUENCE OF FaIpSessEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Information on the IP sessions active on the device" + ::= { faInetProtoTables 1 } + +faIpSessEntry OBJECT-TYPE + SYNTAX FaIpSessEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Information on a specific session, including source and destination" + INDEX { faIpSessIndex } + ::= { faIpSessTable 1 } + +FaIpSessEntry ::= SEQUENCE { + faIpSessIndex FnIndex, + faIpSessProto FaSessProto, + faIpSessFromAddr IpAddress, + faIpSessFromPort InetPortNumber, + faIpSessToAddr IpAddress, + faIpSessToPort InetPortNumber, + faIpSessExp Counter32 +} + +faIpSessIndex OBJECT-TYPE + SYNTAX FnIndex + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "An index value that uniquely identifies + an IP session within the faIpSessTable" + ::= { faIpSessEntry 1 } + +faIpSessProto OBJECT-TYPE + SYNTAX FaSessProto + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The protocol the session is using (IP, TCP, UDP, etc.)" + ::= { faIpSessEntry 2 } + +faIpSessFromAddr OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Source IP address (IPv4 only) of the session" + ::= { faIpSessEntry 3 } + +faIpSessFromPort OBJECT-TYPE + SYNTAX InetPortNumber + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Source port number (UDP and TCP only) of the session" + ::= { faIpSessEntry 4 } + +faIpSessToAddr OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Destination IP address (IPv4 only) of the session" + ::= { faIpSessEntry 5 } + +faIpSessToPort OBJECT-TYPE + SYNTAX InetPortNumber + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Destination Port number (UDP and TCP only) of the session" + ::= { faIpSessEntry 6 } + +faIpSessExp OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of seconds remaining before the session expires (if idle)" + ::= { faIpSessEntry 7 } + +fa300Compat OBJECT IDENTIFIER + ::= { fnFortiAnalyzerMib 99 } + +faHwSensors OBJECT IDENTIFIER + ::= { fa300Compat 1 } + +faHwSensorCount OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "The number of entries in faHwSensorTable" + ::= { faHwSensors 1 } + +faHwSensorTable OBJECT-TYPE + SYNTAX SEQUENCE OF FaHwSensorEntry + MAX-ACCESS not-accessible + STATUS deprecated + DESCRIPTION + "A list of device specific hardware sensors and values. Because different devices have different hardware sensor capabilities, this table may or may not contain any values." + ::= { faHwSensors 2 } + +faHwSensorEntry OBJECT-TYPE + SYNTAX FaHwSensorEntry + MAX-ACCESS not-accessible + STATUS deprecated + DESCRIPTION + "An entry containing the name, value, and alarm status of a given hardware sensor" + INDEX { faHwSensorEntIndex } + ::= { faHwSensorTable 1 } + +FaHwSensorEntry ::= SEQUENCE { + faHwSensorEntIndex FnIndex, + faHwSensorEntName DisplayString, + faHwSensorEntValue DisplayString, + faHwSensorEntAlarmStatus INTEGER +} + +faHwSensorEntIndex OBJECT-TYPE + SYNTAX FnIndex + MAX-ACCESS not-accessible + STATUS deprecated + DESCRIPTION + "A unique identifier within the faHwSensorTable" + ::= { faHwSensorEntry 1 } + +faHwSensorEntName OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "A string identifying the sensor by name" + ::= { faHwSensorEntry 2 } + +faHwSensorEntValue OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "A string representation of the value of the sensor. Because sensors can present data in different formats, string representation is most general format. Interpretation of the value (units of measure, for example) is dependent on the individual sensor." + ::= { faHwSensorEntry 3 } + +faHwSensorEntAlarmStatus OBJECT-TYPE + SYNTAX INTEGER { false(0), true(1) } + MAX-ACCESS read-only + STATUS deprecated + DESCRIPTION + "If the sensor has an alarm threshold and has exceeded it, this will indicate its status. Not all sensors have alarms." + ::= { faHwSensorEntry 4 } + + + +fa300System OBJECT IDENTIFIER + ::= { fa300Compat 2 } + +fa300SysSerial OBJECT-TYPE + SYNTAX DisplayString (SIZE(0..32)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Serial number of the device" + ::= { fa300System 1 } + +fa300SysVersion OBJECT-TYPE + SYNTAX DisplayString (SIZE(0..128)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Firmware version of the device" + ::= { fa300System 2 } + +fa300SysCpuUsage OBJECT-TYPE + SYNTAX Gauge32 (0..100) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Current CPU usage (percentage)" + ::= { fa300System 3 } + +fa300SysMemUsage OBJECT-TYPE + SYNTAX Gauge32 (0..100) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Current memory utilization (percentage)" + ::= { fa300System 4 } + +fa300SysSesCount OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of active sessions on the device" + ::= { fa300System 5 } + +fa300SysDiskCapacity OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Total hard disk capacity (MB), if disk is present" + ::= { fa300System 6 } + +fa300SysDiskUsage OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Current hard disk usage (MB), if disk is present" + ::= { fa300System 7 } + +fa300SysMemCapacity OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Total physical memory (RAM) installed (KB)" + ::= { fa300System 8 } + + + + +faMIBConformance OBJECT IDENTIFIER + ::= { fnFortiAnalyzerMib 100 } + +faTrapSystemEvent NOTIFICATION-TYPE + OBJECTS { fnSysSerial, faSystemEvent } + STATUS current + DESCRIPTION + "A system event occured. The specific type of event is indecated by the faSystemEvent parameter." + ::= { faTrapPrefix 1001 } + +faTrapRAIDStatusChange NOTIFICATION-TYPE + OBJECTS { fnSysSerial, faRAIDStatus, faRAIDDevIndex } + STATUS current + DESCRIPTION + "Trap is sent when there is a change in the status of the RAID array, if present." + ::= { faTrapPrefix 1002 } + +faTrapGenAlert NOTIFICATION-TYPE + OBJECTS { fnSysSerial, fnGenTrapMsg } + STATUS current + DESCRIPTION + "Trap sent when FortiAnalyzer event parameter + exceeds configured limit. Event description + included in trap." + ::= { faTrapPrefix 1003 } + + +faTrapLogRateThreshold NOTIFICATION-TYPE + OBJECTS { fnSysSerial, sysName } + STATUS current + DESCRIPTION + "Indicates that the incoming log rate has exceeded the configured threshold." + ::= { fnTrapsPrefix 1005 } + +faTrapDataRateThreshold NOTIFICATION-TYPE + OBJECTS { fnSysSerial, sysName } + STATUS current + DESCRIPTION + "Indicates that the incoming data rate has exceeded the configured threshold." + ::= { fnTrapsPrefix 1006 } + + + +faSystemComplianceGroup OBJECT-GROUP + OBJECTS { + fa300SysSerial, + fa300SysVersion, + fa300SysCpuUsage, + fa300SysMemUsage, + fa300SysDiskCapacity, + fa300SysDiskUsage, + fa300SysMemCapacity, + fa300SysSesCount, + faSystemEvent + } + STATUS current + DESCRIPTION "System related instrumentation" + ::= { faMIBConformance 1 } + + +faTrapsComplianceGroup NOTIFICATION-GROUP + NOTIFICATIONS { faTrapSystemEvent, faTrapRAIDStatusChange, + faTrapGenAlert, faTrapLogRateThreshold, faTrapDataRateThreshold } + STATUS current + DESCRIPTION + "Event notifications" + ::= { faMIBConformance 2 } + + +faSessionComplianceGroup OBJECT-GROUP + OBJECTS { + faIpSessProto, + faIpSessFromAddr, + faIpSessFromPort, + faIpSessToAddr, + faIpSessToPort, + faIpSessExp + } + STATUS current + DESCRIPTION "Session related instrumentation" + ::= { faMIBConformance 3 } + +faMiscComplianceGroup OBJECT-GROUP + OBJECTS { + faGenAlert + + } + STATUS current + DESCRIPTION "Miscellanious instrumentation" + ::= { faMIBConformance 4 } + +faHwSensorComplianceGroup OBJECT-GROUP + OBJECTS { + faHwSensorCount, + faHwSensorEntName, + faHwSensorEntValue, + faHwSensorEntAlarmStatus + } + STATUS deprecated + DESCRIPTION "Hardware sensor related information" + ::= { faMIBConformance 5 } + +faNotificationObjectsComplianceGroup OBJECT-GROUP + OBJECTS { faSystemEvent, faRAIDStatus, faRAIDDevIndex } + STATUS current + DESCRIPTION + "Object identifiers used in notifications" + ::= { faMIBConformance 6 } + + + + +faMIBCompliance MODULE-COMPLIANCE + STATUS current + DESCRIPTION + "The compliance statement for the application MIB." + + MODULE -- this module + + GROUP faSystemComplianceGroup + DESCRIPTION "System related instrumentation" + + GROUP faSessionComplianceGroup + DESCRIPTION + "Session related instrumentation" + + GROUP faMiscComplianceGroup + DESCRIPTION "Miscellanious instrumentation" + + GROUP faTrapsComplianceGroup + DESCRIPTION + "Traps are optional. Not all models support all traps. Consult product literature to see which traps are supported." + + GROUP faNotificationObjectsComplianceGroup + DESCRIPTION + "Object identifiers used in notifications. Objects are required if their containing trap is implemented." + + ::= { faMIBConformance 100 } + + + +faObsoleteMIBCompliance MODULE-COMPLIANCE + STATUS deprecated + DESCRIPTION + "The compliance statement of deprecated objects for the application MIB, they may still be used by older models." + + MODULE -- this module + + GROUP faHwSensorComplianceGroup + DESCRIPTION + "Traps are optional. Not all models support all traps. Consult product literature to see which traps are supported." + + ::= { faMIBConformance 101 } + + +END -- end of module FORTINET-FORTIANALYZER-MIB. From c708610c9672bf0f8b8e2f0ec605c9ae4e1ccf7f Mon Sep 17 00:00:00 2001 From: laf Date: Mon, 31 Aug 2015 21:19:39 +0000 Subject: [PATCH 194/598] Added basic detection for FortiOS --- includes/discovery/os/fortios.inc.php | 7 +++++++ includes/polling/os/fortios.inc.php | 3 +++ 2 files changed, 10 insertions(+) create mode 100644 includes/discovery/os/fortios.inc.php create mode 100644 includes/polling/os/fortios.inc.php diff --git a/includes/discovery/os/fortios.inc.php b/includes/discovery/os/fortios.inc.php new file mode 100644 index 000000000..bf432ddd7 --- /dev/null +++ b/includes/discovery/os/fortios.inc.php @@ -0,0 +1,7 @@ + Date: Mon, 31 Aug 2015 21:21:36 +0000 Subject: [PATCH 195/598] Updated sysObjectId --- includes/discovery/os/fortios.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/discovery/os/fortios.inc.php b/includes/discovery/os/fortios.inc.php index bf432ddd7..62584f2cb 100644 --- a/includes/discovery/os/fortios.inc.php +++ b/includes/discovery/os/fortios.inc.php @@ -1,7 +1,7 @@ Date: Mon, 31 Aug 2015 21:33:57 +0000 Subject: [PATCH 196/598] Fixed syslog and eventlog tables to be responsive --- html/includes/common/eventlog.inc.php | 23 ++++++++++++----------- html/includes/common/syslog.inc.php | 23 ++++++++++++----------- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/html/includes/common/eventlog.inc.php b/html/includes/common/eventlog.inc.php index 7ce1590c0..fcf5e955e 100644 --- a/html/includes/common/eventlog.inc.php +++ b/html/includes/common/eventlog.inc.php @@ -1,17 +1,18 @@ - - - Datetime - Hostname - Type - Message - - - - +
    + + + + + + + + + +
    DatetimeHostnameTypeMessage
    +
    '; + return; + } else { + echo 'Step #'.$limit.' ...'.PHP_EOL; + } + } + if (!empty($line)) { $creation = mysqli_query($database_link, $line); - if (!$creation) { + if (!$creation && ($limit <= 100 || $limit > 391) ) { echo 'WARNING: Cannot execute query ('.$line.'): '.mysqli_error($database_link)."\n"; } } @@ -41,4 +53,9 @@ while (!feof($sql_fh)) { fclose($sql_fh); -require 'includes/sql-schema/update.php'; +if( !isset($_SESSION['stage']) ) { + require 'includes/sql-schema/update.php'; +} else { + $_SESSION['build-ok'] = true; + dbInsert(array('version' => 67), 'dbSchema'); +} diff --git a/build.sql b/build.sql index 9f4526069..39d87c8cf 100644 --- a/build.sql +++ b/build.sql @@ -70,12 +70,9 @@ CREATE TABLE IF NOT EXISTS `frequency` ( `freq_id` int(11) NOT NULL auto_increme CREATE TABLE IF NOT EXISTS `current` ( `current_id` int(11) NOT NULL auto_increment, `device_id` int(11) NOT NULL default '0', `current_oid` varchar(64) NOT NULL, `current_index` varchar(8) NOT NULL, `current_type` varchar(32) NOT NULL, `current_descr` varchar(32) NOT NULL default '', `current_precision` int(11) NOT NULL default '1', `current_current` float default NULL, `current_limit` float default NULL, `current_limit_warn` float default NULL, `current_limit_low` float default NULL, PRIMARY KEY (`current_id`), KEY `current_host` (`device_id`)) ENGINE=MyISAM AUTO_INCREMENT=189 DEFAULT CHARSET=latin1; CREATE TABLE IF NOT EXISTS `ucd_diskio` ( `diskio_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `diskio_index` int(11) NOT NULL, `diskio_descr` varchar(32) NOT NULL, PRIMARY KEY (`diskio_id`)) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=11 ; CREATE TABLE IF NOT EXISTS `applications` ( `app_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `app_type` varchar(64) NOT NULL, PRIMARY KEY (`app_id`)) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ; -## 0.10.6 CREATE TABLE IF NOT EXISTS `sensors` ( `sensor_id` int(11) NOT NULL auto_increment, `sensor_class` varchar(64) NOT NULL, `device_id` int(11) NOT NULL default '0', `sensor_oid` varchar(64) NOT NULL, `sensor_index` varchar(8) NOT NULL, `sensor_type` varchar(32) NOT NULL, `sensor_descr` varchar(32) NOT NULL default '', `sensor_precision` int(11) NOT NULL default '1', `sensor_current` float default NULL, `sensor_limit` float default NULL, `sensor_limit_warn` float default NULL, `sensor_limit_low` float default NULL, `sensor_limit_low_warn` float default NULL, PRIMARY KEY (`sensor_id`), KEY `sensor_host` (`device_id`)) ENGINE=MyISAM AUTO_INCREMENT=189 DEFAULT CHARSET=latin1; CREATE TABLE IF NOT EXISTS `ports_adsl` ( `interface_id` int(11) NOT NULL, `port_adsl_updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `adslLineCoding` varchar(8) COLLATE utf8_bin NOT NULL, `adslLineType` varchar(16) COLLATE utf8_bin NOT NULL, `adslAtucInvVendorID` varchar(8) COLLATE utf8_bin NOT NULL, `adslAtucInvVersionNumber` varchar(8) COLLATE utf8_bin NOT NULL, `adslAtucCurrSnrMgn` decimal(5,1) NOT NULL, `adslAtucCurrAtn` decimal(5,1) NOT NULL, `adslAtucCurrOutputPwr` decimal(5,1) NOT NULL, `adslAtucCurrAttainableRate` int(11) NOT NULL, `adslAtucChanCurrTxRate` int(11) NOT NULL, `adslAturInvSerialNumber` varchar(8) COLLATE utf8_bin NOT NULL, `adslAturInvVendorID` varchar(8) COLLATE utf8_bin NOT NULL, `adslAturInvVersionNumber` varchar(8) COLLATE utf8_bin NOT NULL, `adslAturChanCurrTxRate` int(11) NOT NULL, `adslAturCurrSnrMgn` decimal(5,1) NOT NULL, `adslAturCurrAtn` decimal(5,1) NOT NULL, `adslAturCurrOutputPwr` decimal(5,1) NOT NULL, `adslAturCurrAttainableRate` int(11) NOT NULL, UNIQUE KEY `interface_id` (`interface_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; -## 0.10.7 CREATE TABLE IF NOT EXISTS `perf_times` ( `type` varchar(8) NOT NULL, `doing` varchar(64) NOT NULL, `start` int(11) NOT NULL, `duration` double(5,2) NOT NULL, `devices` int(11) NOT NULL, KEY `type` (`type`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; -## 0.10.7.1 CREATE TABLE IF NOT EXISTS `device_graphs` ( `device_id` int(11) NOT NULL, `graph` varchar(32) COLLATE utf8_unicode_ci NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; CREATE TABLE IF NOT EXISTS `graph_types` ( `graph_type` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `graph_subtype` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `graph_section` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `graph_descr` varchar(64) COLLATE utf8_unicode_ci NOT NULL, `graph_order` int(11) NOT NULL, KEY `graph_type` (`graph_type`), KEY `graph_subtype` (`graph_subtype`), KEY `graph_section` (`graph_section`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; INSERT INTO `graph_types` (`graph_type`, `graph_subtype`, `graph_section`, `graph_descr`, `graph_order`) VALUES('device', 'bits', 'netstats', 'Total Traffic', 0),('device', 'hr_users', 'system', 'Users Logged In', 0),('device', 'ucd_load', 'system', 'Load Averages', 0),('device', 'ucd_cpu', 'system', 'Detailed Processor Usage', 0),('device', 'ucd_memory', 'system', 'Detailed Memory Usage', 0),('device', 'netstat_tcp', 'netstats', 'TCP Statistics', 0),('device', 'netstat_icmp_info', 'netstats', 'ICMP Informational Statistics', 0),('device', 'netstat_icmp_stat', 'netstats', 'ICMP Statistics', 0),('device', 'netstat_ip', 'netstats', 'IP Statistics', 0),('device', 'netstat_ip_frag', 'netstats', 'IP Fragmentation Statistics', 0),('device', 'netstat_udp', 'netstats', 'UDP Statistics', 0),('device', 'netstat_snmp', 'netstats', 'SNMP Statistics', 0),('device', 'temperatures', 'system', 'Temperatures', 0),('device', 'mempools', 'system', 'Memory Pool Usage', 0),('device', 'processors', 'system', 'Processor Usage', 0),('device', 'storage', 'system', 'Filesystem Usage', 0),('device', 'hr_processes', 'system', 'Running Processes', 0),('device', 'uptime', 'system', 'System Uptime', 0),('device', 'ipsystemstats_ipv4', 'netstats', 'IPv4 Packet Statistics', 0),('device', 'ipsystemstats_ipv6_frag', 'netstats', 'IPv6 Fragmentation Statistics', 0),('device', 'ipsystemstats_ipv6', 'netstats', 'IPv6 Packet Statistics', 0),('device', 'ipsystemstats_ipv4_frag', 'netstats', 'IPv4 Fragmentation Statistics', 0),('device', 'fortigate_sessions', 'firewall', 'Active Sessions', 0), ('device', 'screenos_sessions', 'firewall', 'Active Sessions', 0), ('device', 'fdb_count', 'system', 'MAC Addresses Learnt', 0),('device', 'cras_sessions', 'firewall', 'Remote Access Sessions', 0); @@ -98,3 +95,448 @@ CREATE TABLE IF NOT EXISTS `slas` ( `sla_id` int(11) NOT NULL auto_increment, CREATE TABLE IF NOT EXISTS `munin_plugins` ( `mplug_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `mplug_type` varchar(256) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, `mplug_instance` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL, `mplug_category` varchar(32) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL, `mplug_title` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL, `mplug_info` text CHARACTER SET utf8 COLLATE utf8_bin, `mplug_vlabel` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL, `mplug_args` varchar(512) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL, `mplug_total` binary(1) NOT NULL DEFAULT '0', `mplug_graph` binary(1) NOT NULL DEFAULT '1', PRIMARY KEY (`mplug_id`), UNIQUE KEY `UNIQUE` (`device_id`,`mplug_type`), KEY `device_id` (`device_id`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin ; CREATE TABLE IF NOT EXISTS `munin_plugins_ds` ( `mplug_id` int(11) NOT NULL, `ds_name` varchar(32) COLLATE utf8_bin NOT NULL, `ds_type` enum('COUNTER','ABSOLUTE','DERIVE','GAUGE') COLLATE utf8_bin NOT NULL DEFAULT 'GAUGE', `ds_label` varchar(64) COLLATE utf8_bin NOT NULL, `ds_cdef` text COLLATE utf8_bin NOT NULL, `ds_draw` varchar(64) COLLATE utf8_bin NOT NULL, `ds_graph` enum('no','yes') COLLATE utf8_bin NOT NULL DEFAULT 'yes', `ds_info` varchar(255) COLLATE utf8_bin NOT NULL, `ds_extinfo` text COLLATE utf8_bin NOT NULL, `ds_max` varchar(32) COLLATE utf8_bin NOT NULL, `ds_min` varchar(32) COLLATE utf8_bin NOT NULL, `ds_negative` varchar(32) COLLATE utf8_bin NOT NULL, `ds_warning` varchar(32) COLLATE utf8_bin NOT NULL, `ds_critical` varchar(32) COLLATE utf8_bin NOT NULL, `ds_colour` varchar(32) COLLATE utf8_bin NOT NULL, `ds_sum` text CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, `ds_stack` text COLLATE utf8_bin NOT NULL, `ds_line` varchar(64) COLLATE utf8_bin NOT NULL, UNIQUE KEY `splug_id` (`mplug_id`,`ds_name`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin; CREATE TABLE IF NOT EXISTS `access_points` ( `accesspoint_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `name` varchar(255) NOT NULL, `radio_number` tinyint(4) DEFAULT NULL, `type` varchar(16) NOT NULL, `mac_addr` varchar(24) NOT NULL, `deleted` tinyint(1) NOT NULL DEFAULT '0', `channel` tinyint(4) unsigned NOT NULL DEFAULT '0', `txpow` tinyint(4) NOT NULL DEFAULT '0', `radioutil` tinyint(4) NOT NULL DEFAULT '0', `numasoclients` smallint(6) NOT NULL DEFAULT '0', `nummonclients` smallint(6) NOT NULL DEFAULT '0', `numactbssid` tinyint(4) NOT NULL DEFAULT '0', `nummonbssid` tinyint(4) NOT NULL DEFAULT '0', `interference` tinyint(3) unsigned NOT NULL, PRIMARY KEY (`accesspoint_id`), KEY `deleted` (`deleted`), KEY `name` (`name`,`radio_number`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Access Points'; +CREATE TABLE IF NOT EXISTS `alerts` ( `id` int(11) NOT NULL AUTO_INCREMENT, `importance` int(11) NOT NULL DEFAULT '0', `device_id` int(11) NOT NULL, `message` text NOT NULL, `time_logged` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `alerted` smallint(6) NOT NULL DEFAULT '0', KEY `id` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE IF NOT EXISTS `applications` ( `app_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `app_type` varchar(64) NOT NULL, PRIMARY KEY (`app_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE IF NOT EXISTS `authlog` ( `id` int(11) NOT NULL AUTO_INCREMENT, `datetime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `user` text NOT NULL, `address` text NOT NULL, `result` text NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE IF NOT EXISTS `bgpPeers` ( `bgpPeer_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `astext` varchar(64) NOT NULL, `bgpPeerIdentifier` text NOT NULL, `bgpPeerRemoteAs` int(11) NOT NULL, `bgpPeerState` text NOT NULL, `bgpPeerAdminStatus` text NOT NULL, `bgpLocalAddr` text NOT NULL, `bgpPeerRemoteAddr` text NOT NULL, `bgpPeerInUpdates` int(11) NOT NULL, `bgpPeerOutUpdates` int(11) NOT NULL, `bgpPeerInTotalMessages` int(11) NOT NULL, `bgpPeerOutTotalMessages` int(11) NOT NULL, `bgpPeerFsmEstablishedTime` int(11) NOT NULL, `bgpPeerInUpdateElapsedTime` int(11) NOT NULL, PRIMARY KEY (`bgpPeer_id`), KEY `device_id` (`device_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE IF NOT EXISTS `bgpPeers_cbgp` ( `device_id` int(11) NOT NULL, `bgpPeerIdentifier` varchar(64) NOT NULL, `afi` varchar(16) NOT NULL, `safi` varchar(16) NOT NULL, KEY `device_id` (`device_id`,`bgpPeerIdentifier`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE IF NOT EXISTS `bills` ( `bill_id` int(11) NOT NULL AUTO_INCREMENT, `bill_name` text NOT NULL, `bill_type` text NOT NULL, `bill_cdr` int(11) DEFAULT NULL, `bill_day` int(11) NOT NULL DEFAULT '1', `bill_gb` int(11) DEFAULT NULL, `rate_95th_in` int(11) NOT NULL, `rate_95th_out` int(11) NOT NULL, `rate_95th` int(11) NOT NULL, `dir_95th` varchar(3) NOT NULL, `total_data` int(11) NOT NULL, `total_data_in` int(11) NOT NULL, `total_data_out` int(11) NOT NULL, `rate_average_in` int(11) NOT NULL, `rate_average_out` int(11) NOT NULL, `rate_average` int(11) NOT NULL, `bill_last_calc` datetime NOT NULL, `bill_custid` varchar(64) NOT NULL, `bill_ref` varchar(64) NOT NULL, `bill_notes` varchar(256) NOT NULL, `bill_autoadded` tinyint(1) NOT NULL, UNIQUE KEY `bill_id` (`bill_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 ; +CREATE TABLE IF NOT EXISTS `bill_data` ( `bill_id` int(11) NOT NULL, `timestamp` datetime NOT NULL, `period` int(11) NOT NULL, `delta` bigint(11) NOT NULL, `in_delta` bigint(11) NOT NULL, `out_delta` bigint(11) NOT NULL, KEY `bill_id` (`bill_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE IF NOT EXISTS `bill_perms` ( `user_id` int(11) NOT NULL, `bill_id` int(11) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE IF NOT EXISTS `bill_ports` ( `bill_id` int(11) NOT NULL, `port_id` int(11) NOT NULL, `bill_port_autoadded` tinyint(1) NOT NULL DEFAULT '0' ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE IF NOT EXISTS `cef_switching` ( `cef_switching_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `entPhysicalIndex` int(11) NOT NULL, `afi` varchar(4) COLLATE utf8_unicode_ci NOT NULL, `cef_index` int(11) NOT NULL, `cef_path` varchar(16) COLLATE utf8_unicode_ci NOT NULL, `drop` int(11) NOT NULL, `punt` int(11) NOT NULL, `punt2host` int(11) NOT NULL, `drop_prev` int(11) NOT NULL, `punt_prev` int(11) NOT NULL, `punt2host_prev` int(11) NOT NULL, `updated` int(11) NOT NULL, `updated_prev` int(11) NOT NULL, PRIMARY KEY (`cef_switching_id`), UNIQUE KEY `device_id` (`device_id`,`entPhysicalIndex`,`afi`,`cef_index`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +CREATE TABLE IF NOT EXISTS `customers` ( `customer_id` int(11) NOT NULL AUTO_INCREMENT, `username` char(64) NOT NULL, `password` char(32) NOT NULL, `string` char(64) NOT NULL, `level` tinyint(4) NOT NULL DEFAULT '0', PRIMARY KEY (`customer_id`), UNIQUE KEY `username` (`username`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE IF NOT EXISTS `dbSchema` ( `revision` int(11) NOT NULL DEFAULT '0', PRIMARY KEY (`revision`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE IF NOT EXISTS `devices` ( `device_id` int(11) NOT NULL AUTO_INCREMENT, `hostname` varchar(128) CHARACTER SET latin1 NOT NULL, `sysName` varchar(128) CHARACTER SET latin1 DEFAULT NULL, `community` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, `snmpver` varchar(4) CHARACTER SET latin1 NOT NULL DEFAULT 'v2c', `port` smallint(5) unsigned NOT NULL DEFAULT '161', `transport` varchar(16) COLLATE utf8_unicode_ci NOT NULL DEFAULT 'udp', `timeout` int(11) DEFAULT NULL, `retries` int(11) DEFAULT NULL, `bgpLocalAs` varchar(16) CHARACTER SET latin1 DEFAULT NULL, `sysDescr` text CHARACTER SET latin1, `sysContact` text CHARACTER SET latin1, `version` text CHARACTER SET latin1, `hardware` text CHARACTER SET latin1, `features` text CHARACTER SET latin1, `location` text COLLATE utf8_unicode_ci, `os` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL, `status` tinyint(4) NOT NULL DEFAULT '0', `ignore` tinyint(4) NOT NULL DEFAULT '0', `disabled` tinyint(1) NOT NULL DEFAULT '0', `uptime` bigint(20) DEFAULT NULL, `agent_uptime` int(11) NOT NULL, `last_polled` timestamp NULL DEFAULT NULL, `last_polled_timetaken` double(5,2) DEFAULT NULL, `last_discovered_timetaken` double(5,2) DEFAULT NULL, `last_discovered` timestamp NULL DEFAULT NULL, `purpose` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL, `type` varchar(20) COLLATE utf8_unicode_ci NOT NULL, `serial` text COLLATE utf8_unicode_ci, PRIMARY KEY (`device_id`), KEY `status` (`status`), KEY `hostname` (`hostname`), KEY `sysName` (`sysName`), KEY `os` (`os`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +CREATE TABLE IF NOT EXISTS `devices_attribs` ( `attrib_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `attrib_type` varchar(32) NOT NULL, `attrib_value` text NOT NULL, `updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`attrib_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE IF NOT EXISTS `devices_perms` ( `user_id` int(11) NOT NULL, `device_id` int(11) NOT NULL, `access_level` int(4) NOT NULL DEFAULT '0', KEY `user_id` (`user_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE IF NOT EXISTS `device_graphs` ( `device_id` int(11) NOT NULL, `graph` varchar(32) COLLATE utf8_unicode_ci NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +CREATE TABLE IF NOT EXISTS `entPhysical` ( `entPhysical_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `entPhysicalIndex` int(11) NOT NULL, `entPhysicalDescr` text NOT NULL, `entPhysicalClass` text NOT NULL, `entPhysicalName` text NOT NULL, `entPhysicalHardwareRev` varchar(64) DEFAULT NULL, `entPhysicalFirmwareRev` varchar(64) DEFAULT NULL, `entPhysicalSoftwareRev` varchar(64) DEFAULT NULL, `entPhysicalAlias` varchar(32) DEFAULT NULL, `entPhysicalAssetID` varchar(32) DEFAULT NULL, `entPhysicalIsFRU` varchar(8) DEFAULT NULL, `entPhysicalModelName` text NOT NULL, `entPhysicalVendorType` text, `entPhysicalSerialNum` text NOT NULL, `entPhysicalContainedIn` int(11) NOT NULL, `entPhysicalParentRelPos` int(11) NOT NULL, `entPhysicalMfgName` text NOT NULL, `ifIndex` int(11) DEFAULT NULL, PRIMARY KEY (`entPhysical_id`), KEY `device_id` (`device_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE IF NOT EXISTS `eventlog` ( `event_id` int(11) NOT NULL AUTO_INCREMENT, `host` int(11) NOT NULL DEFAULT '0', `datetime` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', `message` text CHARACTER SET latin1, `type` varchar(64) CHARACTER SET latin1 DEFAULT NULL, `reference` varchar(64) CHARACTER SET latin1 NOT NULL, PRIMARY KEY (`event_id`), KEY `host` (`host`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +CREATE TABLE IF NOT EXISTS `graph_types` ( `graph_type` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `graph_subtype` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `graph_section` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `graph_descr` varchar(64) COLLATE utf8_unicode_ci NOT NULL, `graph_order` int(11) NOT NULL, KEY `graph_type` (`graph_type`), KEY `graph_subtype` (`graph_subtype`), KEY `graph_section` (`graph_section`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +CREATE TABLE IF NOT EXISTS `graph_types_dead` ( `graph_type` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `graph_subtype` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `graph_section` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `graph_descr` varchar(64) COLLATE utf8_unicode_ci NOT NULL, `graph_order` int(11) NOT NULL, KEY `graph_type` (`graph_type`), KEY `graph_subtype` (`graph_subtype`), KEY `graph_section` (`graph_section`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +CREATE TABLE IF NOT EXISTS `hrDevice` ( `hrDevice_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `hrDeviceIndex` int(11) NOT NULL, `hrDeviceDescr` text CHARACTER SET latin1 NOT NULL, `hrDeviceType` text CHARACTER SET latin1 NOT NULL, `hrDeviceErrors` int(11) NOT NULL, `hrDeviceStatus` text CHARACTER SET latin1 NOT NULL, `hrProcessorLoad` tinyint(4) DEFAULT NULL, PRIMARY KEY (`hrDevice_id`), KEY `device_id` (`device_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +CREATE TABLE IF NOT EXISTS `ipv4_addresses` ( `ipv4_address_id` int(11) NOT NULL AUTO_INCREMENT,`ipv4_address` varchar(32) CHARACTER SET latin1 NOT NULL, `ipv4_prefixlen` int(11) NOT NULL,`ipv4_network_id` varchar(32) CHARACTER SET latin1 NOT NULL, `interface_id` int(11) NOT NULL,PRIMARY KEY (`ipv4_address_id`), KEY `interface_id` (`interface_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +CREATE TABLE IF NOT EXISTS `ipv4_mac` ( `interface_id` int(11) NOT NULL, `mac_address` varchar(32) CHARACTER SET latin1 NOT NULL, `ipv4_address` varchar(32) CHARACTER SET latin1 NOT NULL, KEY `interface_id` (`interface_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +CREATE TABLE IF NOT EXISTS `ipv4_networks` ( `ipv4_network_id` int(11) NOT NULL AUTO_INCREMENT, `ipv4_network` varchar(64) CHARACTER SET latin1 NOT NULL, PRIMARY KEY (`ipv4_network_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +CREATE TABLE IF NOT EXISTS `ipv6_addresses` ( `ipv6_address_id` int(11) NOT NULL AUTO_INCREMENT, `ipv6_address` varchar(128) CHARACTER SET latin1 NOT NULL, `ipv6_compressed` varchar(128) CHARACTER SET latin1 NOT NULL, `ipv6_prefixlen` int(11) NOT NULL, `ipv6_origin` varchar(16) CHARACTER SET latin1 NOT NULL, `ipv6_network_id` varchar(128) CHARACTER SET latin1 NOT NULL, `interface_id` int(11) NOT NULL, PRIMARY KEY (`ipv6_address_id`), KEY `interface_id` (`interface_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +CREATE TABLE IF NOT EXISTS `ipv6_networks` ( `ipv6_network_id` int(11) NOT NULL AUTO_INCREMENT, `ipv6_network` varchar(64) CHARACTER SET latin1 NOT NULL, PRIMARY KEY (`ipv6_network_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +CREATE TABLE IF NOT EXISTS `juniAtmVp` ( `juniAtmVp_id` int(11) NOT NULL, `interface_id` int(11) NOT NULL, `vp_id` int(11) NOT NULL, `vp_descr` varchar(32) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE IF NOT EXISTS `links` ( `id` int(11) NOT NULL AUTO_INCREMENT, `local_interface_id` int(11) DEFAULT NULL, `remote_interface_id` int(11) DEFAULT NULL, `active` tinyint(4) NOT NULL DEFAULT '1', `protocol` varchar(11) DEFAULT NULL, `remote_hostname` varchar(128) NOT NULL, `remote_port` varchar(128) NOT NULL, `remote_platform` varchar(128) NOT NULL, `remote_version` varchar(256) NOT NULL, PRIMARY KEY (`id`), KEY `src_if` (`local_interface_id`), KEY `dst_if` (`remote_interface_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE IF NOT EXISTS `mac_accounting` ( `ma_id` int(11) NOT NULL AUTO_INCREMENT, `interface_id` int(11) NOT NULL, `mac` varchar(32) NOT NULL, `in_oid` varchar(128) NOT NULL, `out_oid` varchar(128) NOT NULL, `bps_out` int(11) NOT NULL, `bps_in` int(11) NOT NULL, `cipMacHCSwitchedBytes_input` bigint(20) DEFAULT NULL, `cipMacHCSwitchedBytes_input_prev` bigint(20) DEFAULT NULL, `cipMacHCSwitchedBytes_input_delta` bigint(20) DEFAULT NULL, `cipMacHCSwitchedBytes_input_rate` int(11) DEFAULT NULL, `cipMacHCSwitchedBytes_output` bigint(20) DEFAULT NULL, `cipMacHCSwitchedBytes_output_prev` bigint(20) DEFAULT NULL, `cipMacHCSwitchedBytes_output_delta` bigint(20) DEFAULT NULL, `cipMacHCSwitchedBytes_output_rate` int(11) DEFAULT NULL, `cipMacHCSwitchedPkts_input` bigint(20) DEFAULT NULL, `cipMacHCSwitchedPkts_input_prev` bigint(20) DEFAULT NULL, `cipMacHCSwitchedPkts_input_delta` bigint(20) DEFAULT NULL, `cipMacHCSwitchedPkts_input_rate` int(11) DEFAULT NULL, `cipMacHCSwitchedPkts_output` bigint(20) DEFAULT NULL, `cipMacHCSwitchedPkts_output_prev` bigint(20) DEFAULT NULL, `cipMacHCSwitchedPkts_output_delta` bigint(20) DEFAULT NULL, `cipMacHCSwitchedPkts_output_rate` int(11) DEFAULT NULL, `poll_time` int(11) DEFAULT NULL, `poll_prev` int(11) DEFAULT NULL, `poll_period` int(11) DEFAULT NULL, PRIMARY KEY (`ma_id`), KEY `interface_id` (`interface_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE IF NOT EXISTS `mempools` ( `mempool_id` int(11) NOT NULL AUTO_INCREMENT, `mempool_index` varchar(16) CHARACTER SET latin1 NOT NULL, `entPhysicalIndex` int(11) DEFAULT NULL, `hrDeviceIndex` int(11) DEFAULT NULL, `mempool_type` varchar(32) CHARACTER SET latin1 NOT NULL, `mempool_precision` int(11) NOT NULL DEFAULT '1', `mempool_descr` varchar(64) CHARACTER SET latin1 NOT NULL, `device_id` int(11) NOT NULL, `mempool_perc` int(11) NOT NULL, `mempool_used` bigint(16) NOT NULL, `mempool_free` bigint(16) NOT NULL, `mempool_total` bigint(16) NOT NULL, `mempool_largestfree` bigint(16) DEFAULT NULL, `mempool_lowestfree` bigint(16) DEFAULT NULL, PRIMARY KEY (`mempool_id`), KEY `device_id` (`device_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +CREATE TABLE IF NOT EXISTS `ospf_areas` ( `device_id` int(11) NOT NULL, `ospfAreaId` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfAuthType` varchar(64) COLLATE utf8_unicode_ci NOT NULL, `ospfImportAsExtern` varchar(128) COLLATE utf8_unicode_ci NOT NULL, `ospfSpfRuns` int(11) NOT NULL, `ospfAreaBdrRtrCount` int(11) NOT NULL, `ospfAsBdrRtrCount` int(11) NOT NULL, `ospfAreaLsaCount` int(11) NOT NULL, `ospfAreaLsaCksumSum` int(11) NOT NULL, `ospfAreaSummary` varchar(64) COLLATE utf8_unicode_ci NOT NULL, `ospfAreaStatus` varchar(64) COLLATE utf8_unicode_ci NOT NULL, UNIQUE KEY `device_area` (`device_id`,`ospfAreaId`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +CREATE TABLE IF NOT EXISTS `ospf_instances` ( `device_id` int(11) NOT NULL, `ospf_instance_id` int(11) NOT NULL, `ospfRouterId` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfAdminStat` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfVersionNumber` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfAreaBdrRtrStatus` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfASBdrRtrStatus` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfExternLsaCount` int(11) NOT NULL, `ospfExternLsaCksumSum` int(11) NOT NULL, `ospfTOSSupport` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfOriginateNewLsas` int(11) NOT NULL, `ospfRxNewLsas` int(11) NOT NULL, `ospfExtLsdbLimit` int(11) DEFAULT NULL, `ospfMulticastExtensions` int(11) DEFAULT NULL, `ospfExitOverflowInterval` int(11) DEFAULT NULL, `ospfDemandExtensions` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL, UNIQUE KEY `device_id` (`device_id`,`ospf_instance_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +CREATE TABLE IF NOT EXISTS `ospf_nbrs` ( `device_id` int(11) NOT NULL, `interface_id` int(11) NOT NULL, `ospf_nbr_id` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfNbrIpAddr` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfNbrAddressLessIndex` int(11) NOT NULL, `ospfNbrRtrId` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfNbrOptions` int(11) NOT NULL, `ospfNbrPriority` int(11) NOT NULL, `ospfNbrState` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfNbrEvents` int(11) NOT NULL, `ospfNbrLsRetransQLen` int(11) NOT NULL, `ospfNbmaNbrStatus` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfNbmaNbrPermanence` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfNbrHelloSuppressed` varchar(32) COLLATE utf8_unicode_ci NOT NULL, UNIQUE KEY `device_id` (`device_id`,`ospf_nbr_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +CREATE TABLE IF NOT EXISTS `ospf_ports` ( `device_id` int(11) NOT NULL, `interface_id` int(11) NOT NULL, `ospf_port_id` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfIfIpAddress` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfAddressLessIf` int(11) NOT NULL, `ospfIfAreaId` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfIfType` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL, `ospfIfAdminStat` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL, `ospfIfRtrPriority` int(11) DEFAULT NULL, `ospfIfTransitDelay` int(11) DEFAULT NULL, `ospfIfRetransInterval` int(11) DEFAULT NULL, `ospfIfHelloInterval` int(11) DEFAULT NULL, `ospfIfRtrDeadInterval` int(11) DEFAULT NULL, `ospfIfPollInterval` int(11) DEFAULT NULL, `ospfIfState` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL, `ospfIfDesignatedRouter` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL, `ospfIfBackupDesignatedRouter` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL, `ospfIfEvents` int(11) DEFAULT NULL, `ospfIfAuthKey` varchar(128) COLLATE utf8_unicode_ci DEFAULT NULL, `ospfIfStatus` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL, `ospfIfMulticastForwarding` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL, `ospfIfDemand` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL, `ospfIfAuthType` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL, UNIQUE KEY `device_id` (`device_id`,`ospf_port_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +CREATE TABLE IF NOT EXISTS `perf_times` ( `type` varchar(8) CHARACTER SET latin1 NOT NULL, `doing` varchar(64) CHARACTER SET latin1 NOT NULL, `start` int(11) NOT NULL, `duration` double(8,2) NOT NULL, `devices` int(11) NOT NULL, KEY `type` (`type`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +CREATE TABLE IF NOT EXISTS `ports` ( `interface_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL DEFAULT '0', `port_descr_type` varchar(255) DEFAULT NULL, `port_descr_descr` varchar(255) DEFAULT NULL, `port_descr_circuit` varchar(255) DEFAULT NULL, `port_descr_speed` varchar(32) DEFAULT NULL, `port_descr_notes` varchar(255) DEFAULT NULL, `ifDescr` varchar(255) DEFAULT NULL, `ifName` varchar(64) DEFAULT NULL, `portName` varchar(128) DEFAULT NULL, `ifIndex` int(11) DEFAULT '0', `ifSpeed` bigint(20) DEFAULT NULL, `ifConnectorPresent` varchar(12) DEFAULT NULL, `ifPromiscuousMode` varchar(12) DEFAULT NULL, `ifHighSpeed` int(11) DEFAULT NULL, `ifOperStatus` varchar(16) DEFAULT NULL, `ifAdminStatus` varchar(16) DEFAULT NULL, `ifDuplex` varchar(12) DEFAULT NULL, `ifMtu` int(11) DEFAULT NULL, `ifType` text, `ifAlias` text, `ifPhysAddress` text, `ifHardType` varchar(64) DEFAULT NULL, `ifLastChange` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `ifVlan` varchar(8) NOT NULL DEFAULT '', `ifTrunk` varchar(8) DEFAULT '', `ifVrf` int(11) NOT NULL, `counter_in` int(11) DEFAULT NULL, `counter_out` int(11) DEFAULT NULL, `ignore` tinyint(1) NOT NULL DEFAULT '0', `disabled` tinyint(1) NOT NULL DEFAULT '0', `detailed` tinyint(1) NOT NULL DEFAULT '0', `deleted` tinyint(1) NOT NULL DEFAULT '0', `pagpOperationMode` varchar(32) DEFAULT NULL, `pagpPortState` varchar(16) DEFAULT NULL, `pagpPartnerDeviceId` varchar(48) DEFAULT NULL, `pagpPartnerLearnMethod` varchar(16) DEFAULT NULL, `pagpPartnerIfIndex` int(11) DEFAULT NULL, `pagpPartnerGroupIfIndex` int(11) DEFAULT NULL, `pagpPartnerDeviceName` varchar(128) DEFAULT NULL, `pagpEthcOperationMode` varchar(16) DEFAULT NULL, `pagpDeviceId` varchar(48) DEFAULT NULL, `pagpGroupIfIndex` int(11) DEFAULT NULL, `ifInUcastPkts` bigint(20) DEFAULT NULL, `ifInUcastPkts_prev` bigint(20) DEFAULT NULL, `ifInUcastPkts_delta` bigint(20) DEFAULT NULL, `ifInUcastPkts_rate` int(11) DEFAULT NULL, `ifOutUcastPkts` bigint(20) DEFAULT NULL, `ifOutUcastPkts_prev` bigint(20) DEFAULT NULL, `ifOutUcastPkts_delta` bigint(20) DEFAULT NULL, `ifOutUcastPkts_rate` int(11) DEFAULT NULL, `ifInErrors` bigint(20) DEFAULT NULL, `ifInErrors_prev` bigint(20) DEFAULT NULL, `ifInErrors_delta` bigint(20) DEFAULT NULL, `ifInErrors_rate` int(11) DEFAULT NULL, `ifOutErrors` bigint(20) DEFAULT NULL, `ifOutErrors_prev` bigint(20) DEFAULT NULL, `ifOutErrors_delta` bigint(20) DEFAULT NULL, `ifOutErrors_rate` int(11) DEFAULT NULL, `ifInOctets` bigint(20) DEFAULT NULL, `ifInOctets_prev` bigint(20) DEFAULT NULL, `ifInOctets_delta` bigint(20) DEFAULT NULL, `ifInOctets_rate` int(11) DEFAULT NULL, `ifOutOctets` bigint(20) DEFAULT NULL, `ifOutOctets_prev` bigint(20) DEFAULT NULL, `ifOutOctets_delta` bigint(20) DEFAULT NULL, `ifOutOctets_rate` int(11) DEFAULT NULL, `poll_time` int(11) DEFAULT NULL, `poll_prev` int(11) DEFAULT NULL, `poll_period` int(11) DEFAULT NULL, PRIMARY KEY (`interface_id`), UNIQUE KEY `device_ifIndex` (`device_id`,`ifIndex`), KEY `if_2` (`ifDescr`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE IF NOT EXISTS `ports_adsl` ( `interface_id` int(11) NOT NULL, `port_adsl_updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `adslLineCoding` varchar(8) COLLATE utf8_bin NOT NULL, `adslLineType` varchar(16) COLLATE utf8_bin NOT NULL, `adslAtucInvVendorID` varchar(8) COLLATE utf8_bin NOT NULL, `adslAtucInvVersionNumber` varchar(8) COLLATE utf8_bin NOT NULL, `adslAtucCurrSnrMgn` decimal(5,1) NOT NULL, `adslAtucCurrAtn` decimal(5,1) NOT NULL, `adslAtucCurrOutputPwr` decimal(5,1) NOT NULL, `adslAtucCurrAttainableRate` int(11) NOT NULL, `adslAtucChanCurrTxRate` int(11) NOT NULL, `adslAturInvSerialNumber` varchar(8) COLLATE utf8_bin NOT NULL, `adslAturInvVendorID` varchar(8) COLLATE utf8_bin NOT NULL, `adslAturInvVersionNumber` varchar(8) COLLATE utf8_bin NOT NULL, `adslAturChanCurrTxRate` int(11) NOT NULL, `adslAturCurrSnrMgn` decimal(5,1) NOT NULL, `adslAturCurrAtn` decimal(5,1) NOT NULL, `adslAturCurrOutputPwr` decimal(5,1) NOT NULL, `adslAturCurrAttainableRate` int(11) NOT NULL, UNIQUE KEY `interface_id` (`interface_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; +CREATE TABLE IF NOT EXISTS `ports_perms` ( `user_id` int(11) NOT NULL, `interface_id` int(11) NOT NULL, `access_level` int(11) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE IF NOT EXISTS `ports_stack` ( `device_id` int(11) NOT NULL, `interface_id_high` int(11) NOT NULL, `interface_id_low` int(11) NOT NULL, `ifStackStatus` varchar(32) COLLATE utf8_unicode_ci NOT NULL, UNIQUE KEY `device_id` (`device_id`,`interface_id_high`,`interface_id_low`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +CREATE TABLE IF NOT EXISTS `port_in_measurements` ( `port_id` int(11) NOT NULL, `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `counter` bigint(11) NOT NULL, `delta` bigint(11) NOT NULL, KEY `port_id` (`port_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE IF NOT EXISTS `port_out_measurements` ( `port_id` int(11) NOT NULL, `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `counter` bigint(11) NOT NULL, `delta` bigint(11) NOT NULL, KEY `port_id` (`port_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE IF NOT EXISTS `processors` ( `processor_id` int(11) NOT NULL AUTO_INCREMENT, `entPhysicalIndex` int(11) NOT NULL, `hrDeviceIndex` int(11) DEFAULT NULL, `device_id` int(11) NOT NULL, `processor_oid` varchar(128) CHARACTER SET latin1 NOT NULL, `processor_index` varchar(32) CHARACTER SET latin1 NOT NULL, `processor_type` varchar(16) CHARACTER SET latin1 NOT NULL, `processor_usage` int(11) NOT NULL, `processor_descr` varchar(64) CHARACTER SET latin1 NOT NULL, `processor_precision` int(11) NOT NULL DEFAULT '1', PRIMARY KEY (`processor_id`), KEY `device_id` (`device_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +CREATE TABLE IF NOT EXISTS `pseudowires` ( `pseudowire_id` int(11) NOT NULL AUTO_INCREMENT, `interface_id` int(11) NOT NULL, `peer_device_id` int(11) NOT NULL, `peer_ldp_id` int(11) NOT NULL, `cpwVcID` int(11) NOT NULL, `cpwOid` int(11) NOT NULL, PRIMARY KEY (`pseudowire_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE IF NOT EXISTS `sensors` ( `sensor_id` int(11) NOT NULL AUTO_INCREMENT, `sensor_class` varchar(64) CHARACTER SET latin1 NOT NULL, `device_id` int(11) NOT NULL DEFAULT '0', `poller_type` varchar(16) COLLATE utf8_unicode_ci NOT NULL DEFAULT 'snmp', `sensor_oid` varchar(64) CHARACTER SET latin1 NOT NULL, `sensor_index` varchar(10) COLLATE utf8_unicode_ci NOT NULL, `sensor_type` varchar(255) CHARACTER SET latin1 NOT NULL, `sensor_descr` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, `sensor_divisor` int(11) NOT NULL DEFAULT '1', `sensor_multiplier` int(11) NOT NULL DEFAULT '1', `sensor_current` float DEFAULT NULL, `sensor_limit` float DEFAULT NULL, `sensor_limit_warn` float DEFAULT NULL, `sensor_limit_low` float DEFAULT NULL, `sensor_limit_low_warn` float DEFAULT NULL, `entPhysicalIndex` varchar(16) CHARACTER SET latin1 DEFAULT NULL, `entPhysicalIndex_measured` varchar(16) CHARACTER SET latin1 DEFAULT NULL, PRIMARY KEY (`sensor_id`), KEY `sensor_host` (`device_id`), KEY `sensor_class` (`sensor_class`), KEY `sensor_type` (`sensor_type`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +CREATE TABLE IF NOT EXISTS `services` ( `service_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `service_ip` text NOT NULL, `service_type` varchar(16) NOT NULL, `service_desc` text NOT NULL, `service_param` text NOT NULL, `service_ignore` tinyint(1) NOT NULL, `service_status` tinyint(4) NOT NULL DEFAULT '0', `service_checked` int(11) NOT NULL DEFAULT '0', `service_changed` int(11) NOT NULL DEFAULT '0', `service_message` text NOT NULL, `service_disabled` tinyint(1) NOT NULL DEFAULT '0', PRIMARY KEY (`service_id`), KEY `service_host` (`device_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE IF NOT EXISTS `storage` ( `storage_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `storage_mib` varchar(16) NOT NULL, `storage_index` int(11) NOT NULL, `storage_type` varchar(32) DEFAULT NULL, `storage_descr` text NOT NULL, `storage_size` bigint(20) NOT NULL, `storage_units` int(11) NOT NULL, `storage_used` bigint(20) NOT NULL, `storage_free` bigint(20) NOT NULL, `storage_perc` text NOT NULL, `storage_perc_warn` int(11) DEFAULT '60', PRIMARY KEY (`storage_id`), KEY `device_id` (`device_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE IF NOT EXISTS `syslog` ( `device_id` int(11) DEFAULT NULL, `facility` varchar(10) DEFAULT NULL, `priority` varchar(10) DEFAULT NULL, `level` varchar(10) DEFAULT NULL, `tag` varchar(10) DEFAULT NULL, `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `program` varchar(32) DEFAULT NULL, `msg` text, `seq` bigint(20) unsigned NOT NULL AUTO_INCREMENT, PRIMARY KEY (`seq`), KEY `datetime` (`timestamp`), KEY `device_id` (`device_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE IF NOT EXISTS `toner` ( `toner_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL DEFAULT '0', `toner_index` int(11) NOT NULL, `toner_type` varchar(64) NOT NULL, `toner_oid` varchar(64) NOT NULL, `toner_descr` varchar(32) NOT NULL DEFAULT '', `toner_capacity` int(11) NOT NULL DEFAULT '0', `toner_current` int(11) NOT NULL DEFAULT '0', PRIMARY KEY (`toner_id`), KEY `device_id` (`device_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE IF NOT EXISTS `ucd_diskio` ( `diskio_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `diskio_index` int(11) NOT NULL, `diskio_descr` varchar(32) CHARACTER SET latin1 NOT NULL, PRIMARY KEY (`diskio_id`), KEY `device_id` (`device_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +CREATE TABLE IF NOT EXISTS `users` ( `user_id` int(11) NOT NULL AUTO_INCREMENT, `username` char(30) NOT NULL, `password` varchar(34) DEFAULT NULL, `realname` varchar(64) NOT NULL, `email` varchar(64) NOT NULL, `descr` char(30) NOT NULL, `level` tinyint(4) NOT NULL DEFAULT '0', `can_modify_passwd` tinyint(4) NOT NULL DEFAULT '1', PRIMARY KEY (`user_id`), UNIQUE KEY `username` (`username`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE IF NOT EXISTS `users_prefs` ( `user_id` int(16) NOT NULL, `pref` varchar(32) NOT NULL, `value` varchar(128) NOT NULL, PRIMARY KEY (`user_id`), UNIQUE KEY `user_id.pref` (`user_id`,`pref`), KEY `pref` (`pref`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE IF NOT EXISTS `vlans` ( `vlan_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) DEFAULT NULL, `vlan_vlan` int(11) DEFAULT NULL, `vlan_domain` text, `vlan_descr` text, PRIMARY KEY (`vlan_id`), KEY `device_id` (`device_id`,`vlan_vlan`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE IF NOT EXISTS `vminfo` ( `id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `vm_type` varchar(16) NOT NULL DEFAULT 'vmware', `vmwVmVMID` int(11) NOT NULL, `vmwVmDisplayName` varchar(128) NOT NULL, `vmwVmGuestOS` varchar(128) NOT NULL, `vmwVmMemSize` int(11) NOT NULL, `vmwVmCpus` int(11) NOT NULL, `vmwVmState` varchar(128) NOT NULL, PRIMARY KEY (`id`), KEY `device_id` (`device_id`), KEY `vmwVmVMID` (`vmwVmVMID`)) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE IF NOT EXISTS `vmware_vminfo` ( `id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `vmwVmVMID` int(11) NOT NULL, `vmwVmDisplayName` varchar(128) NOT NULL, `vmwVmGuestOS` varchar(128) NOT NULL, `vmwVmMemSize` int(11) NOT NULL, `vmwVmCpus` int(11) NOT NULL, `vmwVmState` varchar(128) NOT NULL, PRIMARY KEY (`id`), KEY `device_id` (`device_id`), KEY `vmwVmVMID` (`vmwVmVMID`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE IF NOT EXISTS `vrfs` ( `vrf_id` int(11) NOT NULL AUTO_INCREMENT, `vrf_oid` varchar(256) NOT NULL, `vrf_name` varchar(128) DEFAULT NULL, `mplsVpnVrfRouteDistinguisher` varchar(128) DEFAULT NULL, `mplsVpnVrfDescription` text NOT NULL, `device_id` int(11) NOT NULL, PRIMARY KEY (`vrf_id`), KEY `device_id` (`device_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE IF NOT EXISTS `bill_history` ( `bill_hist_id` int(11) NOT NULL AUTO_INCREMENT, `bill_id` int(11) NOT NULL, `updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `bill_datefrom` datetime NOT NULL, `bill_dateto` datetime NOT NULL, `bill_type` text NOT NULL, `bill_allowed` bigint(20) NOT NULL, `bill_used` bigint(20) NOT NULL, `bill_overuse` bigint(20) NOT NULL, `bill_percent` decimal(10,2) NOT NULL, `rate_95th_in` bigint(20) NOT NULL, `rate_95th_out` bigint(20) NOT NULL, `rate_95th` bigint(20) NOT NULL, `dir_95th` varchar(3) NOT NULL, `rate_average` bigint(20) NOT NULL, `rate_average_in` bigint(20) NOT NULL, `rate_average_out` bigint(20) NOT NULL, `traf_in` bigint(20) NOT NULL, `traf_out` bigint(20) NOT NULL, `traf_total` bigint(20) NOT NULL, `pdf` longblob, PRIMARY KEY (`bill_hist_id`), UNIQUE KEY `unique_index` (`bill_id`,`bill_datefrom`,`bill_dateto`), KEY `bill_id` (`bill_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ; +CREATE TABLE IF NOT EXISTS `entPhysical_state` ( `device_id` int(11) NOT NULL, `entPhysicalIndex` varchar(64) NOT NULL, `subindex` varchar(64) DEFAULT NULL, `group` varchar(64) NOT NULL, `key` varchar(64) NOT NULL, `value` varchar(255) NOT NULL, KEY `device_id_index` (`device_id`,`entPhysicalIndex`)) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE IF NOT EXISTS `ports_vlans` ( `port_vlan_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `interface_id` int(11) NOT NULL, `vlan` int(11) NOT NULL, `baseport` int(11) NOT NULL, `priority` bigint(32) NOT NULL, `state` varchar(16) NOT NULL, `cost` int(11) NOT NULL, PRIMARY KEY (`port_vlan_id`), UNIQUE KEY `unique` (`device_id`,`interface_id`,`vlan`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ; +CREATE TABLE IF NOT EXISTS `netscaler_vservers` ( `vsvr_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `vsvr_name` varchar(128) COLLATE utf8_unicode_ci NOT NULL, `vsvr_ip` varchar(128) COLLATE utf8_unicode_ci NOT NULL, `vsvr_port` int(8) NOT NULL, `vsvr_type` varchar(64) COLLATE utf8_unicode_ci NOT NULL, `vsvr_state` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `vsvr_clients` int(11) NOT NULL, `vsvr_server` int(11) NOT NULL, `vsvr_req_rate` int(11) NOT NULL, `vsvr_bps_in` int(11) NOT NULL, `vsvr_bps_out` int(11) NOT NULL, PRIMARY KEY (`vsvr_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +ALTER TABLE `mac_accounting` ADD `cipMacHCSwitchedBytes_input` bigint(20) default NULL; +ALTER TABLE `mac_accounting` ADD `cipMacHCSwitchedBytes_input_prev` bigint(20) default NULL; +ALTER TABLE `mac_accounting` ADD `cipMacHCSwitchedBytes_input_delta` bigint(20) default NULL; +ALTER TABLE `mac_accounting` ADD `cipMacHCSwitchedBytes_input_rate` int(11) default NULL; +ALTER TABLE `mac_accounting` ADD `cipMacHCSwitchedBytes_output` bigint(20) default NULL; +ALTER TABLE `mac_accounting` ADD `cipMacHCSwitchedBytes_output_prev` bigint(20) default NULL; +ALTER TABLE `mac_accounting` ADD `cipMacHCSwitchedBytes_output_delta` bigint(20) default NULL; +ALTER TABLE `mac_accounting` ADD `cipMacHCSwitchedBytes_output_rate` int(11) default NULL; +ALTER TABLE `mac_accounting` ADD `cipMacHCSwitchedPkts_input` bigint(20) default NULL; +ALTER TABLE `mac_accounting` ADD `cipMacHCSwitchedPkts_input_prev` bigint(20) default NULL; +ALTER TABLE `mac_accounting` ADD `cipMacHCSwitchedPkts_input_delta` bigint(20) default NULL; +ALTER TABLE `mac_accounting` ADD `cipMacHCSwitchedPkts_input_rate` int(11) default NULL; +ALTER TABLE `mac_accounting` ADD `cipMacHCSwitchedPkts_output` bigint(20) default NULL; +ALTER TABLE `mac_accounting` ADD `cipMacHCSwitchedPkts_output_prev` bigint(20) default NULL; +ALTER TABLE `mac_accounting` ADD `cipMacHCSwitchedPkts_output_delta` bigint(20) default NULL; +ALTER TABLE `mac_accounting` ADD `cipMacHCSwitchedPkts_output_rate` int(11) default NULL; +ALTER TABLE `mac_accounting` ADD `poll_time` int(11) default NULL; +ALTER TABLE `mac_accounting` ADD `poll_prev` int(11) default NULL; +ALTER TABLE `mac_accounting` ADD `poll_period` int(11) default NULL; +ALTER TABLE `interfaces` ADD `ifInUcastPkts` bigint(20) default NULL; +ALTER TABLE `interfaces` ADD `ifInUcastPkts_prev` bigint(20) default NULL; +ALTER TABLE `interfaces` ADD `ifInUcastPkts_delta` bigint(20) default NULL; +ALTER TABLE `interfaces` ADD `ifInUcastPkts_rate` int(11) default NULL; +ALTER TABLE `interfaces` ADD `ifOutUcastPkts` bigint(20) default NULL; +ALTER TABLE `interfaces` ADD `ifOutUcastPkts_prev` bigint(20) default NULL; +ALTER TABLE `interfaces` ADD `ifOutUcastPkts_delta` bigint(20) default NULL; +ALTER TABLE `interfaces` ADD `ifOutUcastPkts_rate` int(11) default NULL; +ALTER TABLE `interfaces` ADD `ifInErrors` bigint(20) default NULL; +ALTER TABLE `interfaces` ADD `ifInErrors_prev` bigint(20) default NULL; +ALTER TABLE `interfaces` ADD `ifInErrors_delta` bigint(20) default NULL; +ALTER TABLE `interfaces` ADD `ifInErrors_rate` int(11) default NULL; +ALTER TABLE `interfaces` ADD `ifOutErrors` bigint(20) default NULL; +ALTER TABLE `interfaces` ADD `ifOutErrors_prev` bigint(20) default NULL; +ALTER TABLE `interfaces` ADD `ifOutErrors_delta` bigint(20) default NULL; +ALTER TABLE `interfaces` ADD `ifOutErrors_rate` int(11) default NULL; +ALTER TABLE `interfaces` ADD `ifInOctets` bigint(20) default NULL; +ALTER TABLE `interfaces` ADD `ifInOctets_prev` bigint(20) default NULL; +ALTER TABLE `interfaces` ADD `ifInOctets_delta` bigint(20) default NULL; +ALTER TABLE `interfaces` ADD `ifInOctets_rate` int(11) default NULL; +ALTER TABLE `interfaces` ADD `ifOutOctets` bigint(20) default NULL; +ALTER TABLE `interfaces` ADD `ifOutOctets_prev` bigint(20) default NULL; +ALTER TABLE `interfaces` ADD `ifOutOctets_delta` bigint(20) default NULL; +ALTER TABLE `interfaces` ADD `ifOutOctets_rate` int(11) default NULL; +ALTER TABLE `interfaces` ADD `poll_time` int(11) default NULL; +ALTER TABLE `interfaces` ADD `poll_prev` int(11) default NULL; +ALTER TABLE `interfaces` ADD `poll_period` int(11) default NULL; +ALTER TABLE `interfaces` ADD `pagpOperationMode` VARCHAR( 32 ) NULL ; +ALTER TABLE `interfaces` ADD `pagpPortState` VARCHAR( 16 ) NULL ; +ALTER TABLE `interfaces` ADD `pagpPartnerDeviceId` VARCHAR( 48 ) NULL ; +ALTER TABLE `interfaces` ADD `pagpPartnerLearnMethod` VARCHAR( 16 ) NULL ; +ALTER TABLE `interfaces` ADD `pagpPartnerIfIndex` INT NULL ; +ALTER TABLE `interfaces` ADD `pagpPartnerGroupIfIndex` INT NULL ; +ALTER TABLE `interfaces` ADD `pagpPartnerDeviceName` VARCHAR( 128 ) NULL ; +ALTER TABLE `interfaces` ADD `pagpEthcOperationMode` VARCHAR( 16 ) NULL ; +ALTER TABLE `interfaces` ADD `pagpDeviceId` VARCHAR( 48 ) NULL ; +ALTER TABLE `interfaces` ADD `pagpGroupIfIndex` INT NULL ; +ALTER TABLE `interfaces` ADD `ifPromiscuousMode` VARCHAR( 12 ) NULL DEFAULT NULL AFTER `ifSpeed`; +ALTER TABLE `interfaces` ADD `ifConnectorPresent` VARCHAR( 12 ) NULL DEFAULT NULL AFTER `ifSpeed`; +ALTER TABLE `interfaces` ADD `ifName` VARCHAR( 64 ) NULL DEFAULT NULL AFTER `ifDescr`; +ALTER TABLE `interfaces` ADD `portName` VARCHAR( 128 ) NULL DEFAULT NULL AFTER `ifName`; +ALTER TABLE `interfaces` ADD `ifHighSpeed` BIGINT ( 20 ) NULL DEFAULT NULL AFTER `ifSpeed`; +ALTER TABLE `interfaces` DROP `in_rate`; +ALTER TABLE `interfaces` DROP `out_rate`; +ALTER TABLE `interfaces` DROP `in_errors`; +ALTER TABLE `interfaces` DROP `out_errors`; +CREATE TABLE IF NOT EXISTS `cmpMemPool` ( `cmp_id` int(11) NOT NULL auto_increment, `Index` varchar(8) NOT NULL, `cmpName` varchar(32) NOT NULL, `cmpValid` varchar(8) NOT NULL, `device_id` int(11) NOT NULL, `cmpUsed` int(11) NOT NULL, `cmpFree` int(11) NOT NULL, `cmpLargestFree` int(11) NOT NULL, `cmpAlternate` tinyint(4) default NULL, PRIMARY KEY (`cmp_id`), KEY `device_id` (`device_id`)) ENGINE=MyISAM DEFAULT CHARSET=latin1; +CREATE TABLE IF NOT EXISTS `hrDevice` ( `hrDevice_id` int(11) NOT NULL auto_increment, `device_id` int(11) NOT NULL, `hrDeviceIndex` int(11) NOT NULL, `hrDeviceDescr` text NOT NULL, `hrDeviceType` text NOT NULL, `hrDeviceErrors` int(11) NOT NULL, `hrDeviceStatus` text NOT NULL, `hrProcessorLoad` tinyint(4) default NULL, PRIMARY KEY (`hrDevice_id`), KEY `device_id` (`device_id`)) ENGINE=MyISAM DEFAULT CHARSET=latin1; +ALTER TABLE `entPhysical` ADD `entPhysicalHardwareRev` VARCHAR( 16 ) NULL AFTER `entPhysicalName` ,ADD `entPhysicalFirmwareRev` VARCHAR( 16 ) NULL AFTER `entPhysicalHardwareRev` ,ADD `entPhysicalSoftwareRev` VARCHAR( 16 ) NULL AFTER `entPhysicalFirmwareRev` ,ADD `entPhysicalAlias` VARCHAR( 32 ) NULL AFTER `entPhysicalSoftwareRev` ,ADD `entPhysicalAssetID` VARCHAR( 32 ) NULL AFTER `entPhysicalAlias` ,ADD `entPhysicalIsFRU` VARCHAR( 8 ) NULL AFTER `entPhysicalAssetID`; +ALTER TABLE `devices` ADD `last_discovered` timestamp NULL DEFAULT NULL AFTER `last_polled`; +ALTER TABLE `devices` CHANGE `lastchange` `uptime` BIGINT NULL DEFAULT NULL; +ALTER TABLE `storage` ADD `hrStorageType` VARCHAR( 32 ) NULL DEFAULT NULL AFTER `hrStorageIndex`; +ALTER TABLE `devices` MODIFY `type` varchar(8) DEFAULT 'unknown'; +ALTER TABLE `devices` CHANGE `os` `os` VARCHAR( 32 ) NULL DEFAULT NULL; +ALTER TABLE `temperature` ADD `temp_precision` INT(11) NULL DEFAULT '1'; +UPDATE temperature SET temp_precision=10 WHERE temp_tenths=1; +ALTER TABLE `temperature` ADD `temp_index` INT NOT NULL AFTER `temp_host` , ADD `temp_mibtype` VARCHAR( 32 ) NOT NULL AFTER `temp_index`; +ALTER TABLE `temperature` DROP `temp_tenths`; +CREATE TABLE IF NOT EXISTS `dbSchema` ( `revision` int(11) NOT NULL default '0', PRIMARY KEY (`revision`)) ENGINE=MyISAM DEFAULT CHARSET=latin1; +ALTER TABLE `storage` ADD `storage_perc_warn` INT(11) NULL DEFAULT '60'; +CREATE TABLE IF NOT EXISTS `voltage` ( `volt_id` int(11) NOT NULL auto_increment, `volt_host` int(11) NOT NULL default '0', `volt_oid` varchar(64) NOT NULL, `volt_descr` varchar(32) NOT NULL default '', `volt_precision` int(11) NOT NULL default '1', `volt_current` int(11) NOT NULL default '0', `volt_limit` int(11) NOT NULL default '60', PRIMARY KEY (`volt_id`), KEY `volt_host` (`volt_host`)) ENGINE=InnoDB DEFAULT CHARSET=latin1; +CREATE TABLE IF NOT EXISTS `fanspeed` ( `fan_id` int(11) NOT NULL auto_increment, `fan_host` int(11) NOT NULL default '0', `fan_oid` varchar(64) NOT NULL, `fan_descr` varchar(32) NOT NULL default '', `fan_precision` int(11) NOT NULL default '1', `fan_current` int(11) NOT NULL default '0', `fan_limit` int(11) NOT NULL default '60', PRIMARY KEY (`fan_id`), KEY `fan_host` (`fan_host`)) ENGINE=InnoDB DEFAULT CHARSET=latin1; +ALTER TABLE `voltage` ADD `volt_limit_low` int(11) NULL DEFAULT NULL AFTER `volt_limit`; +ALTER TABLE `voltage` CHANGE `volt_current` `volt_current` FLOAT(3) NULL DEFAULT NULL; +ALTER TABLE `voltage` CHANGE `volt_limit` `volt_limit` FLOAT(3) NULL DEFAULT NULL; +ALTER TABLE `voltage` CHANGE `volt_limit_low` `volt_limit_low` FLOAT(3) NULL DEFAULT NULL; +ALTER TABLE `fanspeed` ADD `fan_index` INT NOT NULL AFTER `fan_host` , ADD `fan_mibtype` VARCHAR( 32 ) NOT NULL AFTER `fan_index`; +ALTER TABLE `temperature` CHANGE `temp_host` `device_id` INT( 11 ) NOT NULL DEFAULT '0'; +ALTER TABLE `fanspeed` CHANGE `fan_host` `device_id` INT( 11 ) NOT NULL DEFAULT '0'; +ALTER TABLE `voltage` CHANGE `volt_host` `device_id` INT( 11 ) NOT NULL DEFAULT '0'; +CREATE TABLE IF NOT EXISTS `processors` ( `processor_id` int(11) NOT NULL AUTO_INCREMENT, `entPhysicalIndex` int(11) NOT NULL, `device_id` int(11) NOT NULL, `processor_oid` int(11) NOT NULL, `processor_type` int(11) NOT NULL, `processor_usage` int(11) NOT NULL, `processor_description` varchar(64) NOT NULL, PRIMARY KEY (`processor_id`), KEY `cpuCPU_id` (`processor_id`,`device_id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ; +ALTER TABLE `processors` ADD `hrDeviceIndex` int(11) NULL AFTER `entPhysicalIndex`; +ALTER TABLE `temperature` CHANGE `temp_current` `temp_current` FLOAT( 4 ) NOT NULL DEFAULT '0'; +ALTER TABLE `processors` ADD `processor_index` varchar(32) NOT NULL AFTER `processor_oid`; +ALTER TABLE `processors` CHANGE `processor_description` `processor_descr` varchar(64) NOT NULL; +ALTER TABLE `fanspeed` CHANGE `fan_mibtype` `fan_type` varchar(64) NOT NULL ; +ALTER TABLE `voltage` ADD `volt_index` VARCHAR( 8 ) NOT NULL AFTER `volt_oid`,ADD `volt_type` VARCHAR( 32 ) NOT NULL AFTER `volt_index` ; +ALTER TABLE `processors` ADD `processor_precision` INT( 11 ) NOT NULL DEFAULT '1'; +ALTER TABLE `links` CHANGE `cdp` `vendor` VARCHAR( 11 ) NULL DEFAULT NULL; +ALTER TABLE `links` ADD `remote_hostname` VARCHAR( 128 ) NOT NULL ,ADD `remote_port` VARCHAR( 128 ) NOT NULL ,ADD `remote_platform` VARCHAR( 128 ) NOT NULL ,ADD `remote_version` VARCHAR( 256 ) NOT NULL ; +ALTER TABLE `links` CHANGE `src_if` `local_interface_id` INT( 11 ) NULL DEFAULT NULL ,CHANGE `dst_if` `remote_interface_id` INT( 11 ) NULL DEFAULT NULL ; +ALTER TABLE `links` CHANGE `vendor` `protocol` VARCHAR( 11 ) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL; +ALTER TABLE `processors` CHANGE `processor_type` `processor_type` varchar(16) NOT NULL; +ALTER TABLE `bgpPeers_cbgp` CHANGE `afi` `afi` VARCHAR( 16 ) NOT NULL , CHANGE `safi` `safi` VARCHAR( 16 ) NOT NULL; +ALTER TABLE `eventlog` ADD `reference` VARCHAR( 64 ) NOT NULL AFTER `type`; +ALTER TABLE `syslog` CHANGE `datetime` `timestamp` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP; +ALTER TABLE `syslog` DROP `host`, DROP `processed`; +RENAME TABLE `interfaces` TO `ports` ; +RENAME TABLE `interfaces_perms` TO `ports_perms` ; +ALTER TABLE `temperature` CHANGE `temp_index` `temp_index` VARCHAR( 32 ) NOT NULL AFTER `device_id` , ADD `temp_type` VARCHAR( 16 ) NOT NULL AFTER `temp_index`; +ALTER TABLE `processors` CHANGE `processor_oid` `processor_oid` VARCHAR( 128 ) NOT NULL; +ALTER TABLE eventlog CHANGE `type` `type` VARCHAR( 64 ) NOT NULL; +ALTER TABLE `services` CHANGE `service_host` `device_id` INT( 11 ) NOT NULL; +CREATE TABLE IF NOT EXISTS `mempools` ( `mempool_id` int(11) NOT NULL AUTO_INCREMENT, `mempool_index` varchar(8) CHARACTER SET latin1 NOT NULL, `entPhysicalIndex` int(11) DEFAULT NULL, `hrDeviceIndex` int(11) DEFAULT NULL, `mempool_type` varchar(32) CHARACTER SET latin1 NOT NULL, `mempool_precision` int(11) NOT NULL DEFAULT '1', `mempool_descr` varchar(32) CHARACTER SET latin1 NOT NULL, `device_id` int(11) NOT NULL, `mempool_used` int(11) NOT NULL, `mempool_free` int(11) NOT NULL, `mempool_total` int(11) NOT NULL, `mempool_largestfree` int(11) DEFAULT NULL, `mempool_lowestfree` int(11) DEFAULT NULL, PRIMARY KEY (`mempool_id`), KEY `device_id` (`device_id`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin ; +ALTER TABLE `storage` CHANGE `storage_id` `storage_id` INT( 11 ) NOT NULL AUTO_INCREMENT , CHANGE `host_id` `device_id` INT( 11 ) NOT NULL , CHANGE `hrStorageIndex` `storage_index` INT( 11 ) NOT NULL , CHANGE `hrStorageType` `storage_type` VARCHAR( 32 ) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL , CHANGE `hrStorageDescr` `storage_descr` TEXT CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL , CHANGE `hrStorageSize` `storage_size` INT( 11 ) NOT NULL , CHANGE `hrStorageAllocationUnits` `storage_units` INT( 11 ) NOT NULL , CHANGE `hrStorageUsed` `storage_used` INT( 11 ) NOT NULL , CHANGE `storage_perc` `storage_perc` TEXT CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL; +ALTER TABLE `storage` ADD `storage_mib` VARCHAR( 16 ) NOT NULL AFTER `device_id`; +ALTER TABLE `storage` ADD `storage_free` INT NOT NULL AFTER `storage_used`; +ALTER TABLE `storage` CHANGE `storage_size` `storage_size` BIGINT NOT NULL ,CHANGE `storage_used` `storage_used` BIGINT NOT NULL ,CHANGE `storage_free` `storage_free` BIGINT NOT NULL; +ALTER TABLE `mempools` CHANGE `mempool_used` `mempool_used` BIGINT( 20 ) NOT NULL , +CHANGE `mempool_free` `mempool_free` BIGINT( 20 ) NOT NULL ,CHANGE `mempool_total` `mempool_total` BIGINT( 20 ) NOT NULL ,CHANGE `mempool_largestfree` `mempool_largestfree` BIGINT( 20 ) NULL DEFAULT NULL ,CHANGE `mempool_lowestfree` `mempool_lowestfree` BIGINT( 20 ) NULL DEFAULT NULL; +CREATE TABLE IF NOT EXISTS `juniAtmVp` ( `juniAtmVp_id` int(11) NOT NULL AUTO_INCREMENT, `interface_id` int(11) NOT NULL, `vp_id` int(11) NOT NULL, `vp_descr` varchar(32) NOT NULL, PRIMARY KEY (`juniAtmVp_id`)) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ; +CREATE TABLE IF NOT EXISTS `toner` ( `toner_id` int(11) NOT NULL auto_increment, `device_id` int(11) NOT NULL default '0', `toner_index` int(11) NOT NULL, `toner_type` varchar(64) NOT NULL, `toner_oid` varchar(64) NOT NULL, `toner_descr` varchar(32) NOT NULL default '', `toner_capacity` int(11) NOT NULL default '0', `toner_current` int(11) NOT NULL default '0', PRIMARY KEY (`toner_id`), KEY `device_id` (`device_id`)) ENGINE=InnoDB DEFAULT CHARSET=latin1; +ALTER TABLE `mempools` CHANGE `mempool_descr` `mempool_descr` VARCHAR( 64 ) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL; +ALTER TABLE `processors` CHANGE `processor_descr` `processor_descr` VARCHAR( 64 ) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL; +DROP TABLE `cempMemPool`; +DROP TABLE `cpmCPU`; +DROP TABLE `cmpMemPool`; +ALTER TABLE `mempools` CHANGE `mempool_used` `mempool_used` BIGINT( 16 ) NOT NULL ,CHANGE `mempool_free` `mempool_free` BIGINT( 16 ) NOT NULL ,CHANGE `mempool_total` `mempool_total` BIGINT( 16 ) NOT NULL ,CHANGE `mempool_largestfree` `mempool_largestfree` BIGINT( 16 ) NULL DEFAULT NULL ,CHANGE `mempool_lowestfree` `mempool_lowestfree` BIGINT( 16 ) NULL DEFAULT NULL ; +ALTER TABLE `ports` ADD `port_descr_type` VARCHAR( 32 ) NULL DEFAULT NULL AFTER `device_id` ,ADD `port_descr_descr` VARCHAR( 64 ) NULL DEFAULT NULL AFTER `port_descr_type` ,ADD `port_descr_circuit` VARCHAR( 64 ) NULL DEFAULT NULL AFTER `port_descr_descr` ,ADD `port_descr_speed` VARCHAR( 32 ) NULL DEFAULT NULL AFTER `port_descr_circuit` ,ADD `port_descr_notes` VARCHAR( 128 ) NULL DEFAULT NULL AFTER `port_descr_speed`; +CREATE TABLE IF NOT EXISTS `frequency` ( `freq_id` int(11) NOT NULL auto_increment, `device_id` int(11) NOT NULL default '0', `freq_oid` varchar(64) NOT NULL, `freq_index` varchar(8) NOT NULL, `freq_type` varchar(32) NOT NULL, `freq_descr` varchar(32) NOT NULL default '', `freq_precision` int(11) NOT NULL default '1', `freq_current` float default NULL, `freq_limit` float default NULL, `freq_limit_low` float default NULL, PRIMARY KEY (`freq_id`), KEY `freq_host` (`device_id`)) ENGINE=MyISAM AUTO_INCREMENT=189 DEFAULT CHARSET=latin1; +ALTER TABLE `temperature` CHANGE `temp_index` `temp_index` int(11) NOT NULL; +CREATE TABLE IF NOT EXISTS `current` ( `current_id` int(11) NOT NULL auto_increment, `device_id` int(11) NOT NULL default '0', `current_oid` varchar(64) NOT NULL, `current_index` varchar(8) NOT NULL, `current_type` varchar(32) NOT NULL, `current_descr` varchar(32) NOT NULL default '', `current_precision` int(11) NOT NULL default '1', `current_current` float default NULL, `current_limit` float default NULL, `current_limit_warn` float default NULL, `current_limit_low` float default NULL, PRIMARY KEY (`current_id`), KEY `current_host` (`device_id`)) ENGINE=MyISAM AUTO_INCREMENT=189 DEFAULT CHARSET=latin1; +ALTER TABLE `devices` ADD `serial` text default NULL; +ALTER TABLE `temperature` CHANGE `temp_index` `temp_index` VARCHAR(32) NOT NULL; +ALTER TABLE `ports` CHANGE `ifDescr` `ifDescr` VARCHAR(255) NOT NULL; +CREATE TABLE IF NOT EXISTS `ucd_diskio` ( `diskio_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `diskio_index` int(11) NOT NULL, `diskio_descr` varchar(32) NOT NULL, PRIMARY KEY (`diskio_id`)) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=11 ; +ALTER TABLE `eventlog` CHANGE `type` `type` VARCHAR( 64 ) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL; +ALTER TABLE `bills` ADD `bill_custid` VARCHAR( 64 ) NOT NULL ,ADD `bill_ref` VARCHAR( 64 ) NOT NULL ,ADD `bill_notes` VARCHAR( 256 ) NOT NULL; +CREATE TABLE IF NOT EXISTS `applications` ( `app_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `app_type` varchar(64) NOT NULL, PRIMARY KEY (`app_id`)) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ; +CREATE TABLE IF NOT EXISTS `sensors` ( `sensor_id` int(11) NOT NULL auto_increment, `sensor_class` varchar(64) NOT NULL, `device_id` int(11) NOT NULL default '0', `sensor_oid` varchar(64) NOT NULL, `sensor_index` varchar(8) NOT NULL, `sensor_type` varchar(32) NOT NULL, `sensor_descr` varchar(32) NOT NULL default '', `sensor_precision` int(11) NOT NULL default '1', `sensor_current` float default NULL, `sensor_limit` float default NULL, `sensor_limit_warn` float default NULL, `sensor_limit_low` float default NULL, `sensor_limit_low_warn` float default NULL, PRIMARY KEY (`sensor_id`), KEY `sensor_host` (`device_id`)) ENGINE=MyISAM AUTO_INCREMENT=189 DEFAULT CHARSET=latin1; +ALTER TABLE `devices` CHANGE `type` `type` VARCHAR(20) NOT NULL; +ALTER TABLE `voltage` CHANGE `volt_index` `volt_index` VARCHAR(10) NOT NULL; +ALTER TABLE `frequency` CHANGE `freq_index` `freq_index` VARCHAR(10) NOT NULL; +ALTER TABLE `sensors` CHANGE `sensor_index` `sensor_index` VARCHAR(10) NOT NULL; +DROP TABLE `fanspeed`; +DROP TABLE `temperature`; +DROP TABLE `voltage`; +DROP TABLE `current`; +ALTER TABLE `sensors` ADD `entPhysicalIndex` VARCHAR( 16 ) NULL; +ALTER TABLE `sensors` ADD `entPhysicalIndex_measured` VARCHAR(16) NULL; +ALTER TABLE `processors` DROP INDEX `cpuCPU_id`; +ALTER TABLE `processors` ADD INDEX ( `device_id` ); +ALTER TABLE `ucd_diskio` ADD INDEX ( `device_id` ); +ALTER TABLE `storage` ADD INDEX ( `device_id` ); +ALTER TABLE `mac_accounting` ADD INDEX ( `interface_id` ); +ALTER TABLE `ipv4_addresses` ADD INDEX ( `interface_id` ); +ALTER TABLE `ipv6_addresses` ADD INDEX ( `interface_id` ); +ALTER TABLE `ipv4_mac` ADD INDEX ( `interface_id` ); +CREATE TABLE IF NOT EXISTS `ports_adsl` ( `interface_id` int(11) NOT NULL, `port_adsl_updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `adslLineCoding` varchar(8) COLLATE utf8_bin NOT NULL, `adslLineType` varchar(16) COLLATE utf8_bin NOT NULL, `adslAtucInvVendorID` varchar(8) COLLATE utf8_bin NOT NULL, `adslAtucInvVersionNumber` varchar(8) COLLATE utf8_bin NOT NULL, `adslAtucCurrSnrMgn` decimal(5,1) NOT NULL, `adslAtucCurrAtn` decimal(5,1) NOT NULL, `adslAtucCurrOutputPwr` decimal(5,1) NOT NULL, `adslAtucCurrAttainableRate` int(11) NOT NULL, `adslAtucChanCurrTxRate` int(11) NOT NULL, `adslAturInvSerialNumber` varchar(8) COLLATE utf8_bin NOT NULL, `adslAturInvVendorID` varchar(8) COLLATE utf8_bin NOT NULL, `adslAturInvVersionNumber` varchar(8) COLLATE utf8_bin NOT NULL, `adslAturChanCurrTxRate` int(11) NOT NULL, `adslAturCurrSnrMgn` decimal(5,1) NOT NULL, `adslAturCurrAtn` decimal(5,1) NOT NULL, `adslAturCurrOutputPwr` decimal(5,1) NOT NULL, `adslAturCurrAttainableRate` int(11) NOT NULL, UNIQUE KEY `interface_id` (`interface_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; +ALTER TABLE `devices` ADD `last_polled_timetaken` DOUBLE( 5, 2 ) NOT NULL AFTER `last_polled` , ADD `last_discovered_timetaken` DOUBLE( 5, 2 ) NOT NULL AFTER `last_polled_timetaken`; +CREATE TABLE IF NOT EXISTS `perf_times` ( `type` varchar(8) NOT NULL, `doing` varchar(64) NOT NULL, `start` int(11) NOT NULL, `duration` double(5,2) NOT NULL, `devices` int(11) NOT NULL, KEY `type` (`type`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; +ALTER TABLE `bills` ADD `bill_autoadded` BOOLEAN NOT NULL DEFAULT '0'; +ALTER TABLE `bill_ports` ADD `bill_port_autoadded` BOOLEAN NOT NULL DEFAULT '0'; +ALTER TABLE `sensors` CHANGE `sensor_precision` `sensor_divisor` INT( 11 ) NOT NULL DEFAULT '1' +ALTER TABLE `sensors` ADD `sensor_multiplier` INT( 11 ) NOT NULL AFTER `sensor_divisor`; +CREATE TABLE IF NOT EXISTS `device_graphs` ( `device_id` int(11) NOT NULL, `graph` varchar(32) COLLATE utf8_unicode_ci NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +DROP TABLE IF EXISTS `graph_types`; +CREATE TABLE IF NOT EXISTS `graph_types` ( `graph_type` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `graph_subtype` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `graph_section` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `graph_descr` varchar(64) COLLATE utf8_unicode_ci NOT NULL, `graph_order` int(11) NOT NULL, KEY `graph_type` (`graph_type`), KEY `graph_subtype` (`graph_subtype`), KEY `graph_section` (`graph_section`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +INSERT INTO `graph_types` (`graph_type`, `graph_subtype`, `graph_section`, `graph_descr`, `graph_order`) VALUES('device', 'bits', 'netstats', 'Total Traffic', 0),('device', 'hr_users', 'system', 'Users Logged In', 0),('device', 'ucd_load', 'system', 'Load Averages', 0),('device', 'ucd_cpu', 'system', 'Detailed Processor Usage', 0),('device', 'ucd_memory', 'system', 'Detailed Memory Usage', 0),('device', 'netstat_tcp', 'netstats', 'TCP Statistics', 0),('device', 'netstat_icmp_info', 'netstats', 'ICMP Informational Statistics', 0),('device', 'netstat_icmp_stat', 'netstats', 'ICMP Statistics', 0),('device', 'netstat_ip', 'netstats', 'IP Statistics', 0),('device', 'netstat_ip_frag', 'netstats', 'IP Fragmentation Statistics', 0),('device', 'netstat_udp', 'netstats', 'UDP Statistics', 0),('device', 'netstat_snmp', 'netstats', 'SNMP Statistics', 0),('device', 'temperatures', 'system', 'Temperatures', 0),('device', 'mempools', 'system', 'Memory Pool Usage', 0),('device', 'processors', 'system', 'Processor Usage', 0),('device', 'storage', 'system', 'Filesystem Usage', 0),('device', 'hr_processes', 'system', 'Running Processes', 0),('device', 'uptime', 'system', 'System Uptime', ''),('device', 'ipsystemstats_ipv4', 'netstats', 'IPv4 Packet Statistics', 0),('device', 'ipsystemstats_ipv6_frag', 'netstats', 'IPv6 Fragmentation Statistics', 0),('device', 'ipsystemstats_ipv6', 'netstats', 'IPv6 Packet Statistics', 0),('device', 'ipsystemstats_ipv4_frag', 'netstats', 'IPv4 Fragmentation Statistics', 0),('device', 'fortigate_sessions', 'firewall', 'Active Sessions', ''), ('device', 'screenos_sessions', 'firewall', 'Active Sessions', ''), ('device', 'fdb_count', 'system', 'MAC Addresses Learnt', '0'),('device', 'cras_sessions', 'firewall', 'Remote Access Sessions', 0); +DROP TABLE `frequency`; +ALTER TABLE `mempools` CHANGE `mempool_index` `mempool_index` VARCHAR( 16 ) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL; +ALTER TABLE `vrfs` CHANGE `mplsVpnVrfRouteDistinguisher` `mplsVpnVrfRouteDistinguisher` varchar(26) default NOT NULL; +ALTER TABLE `devices` ADD `timeout` INT NULL DEFAULT NULL AFTER `port`; +ALTER TABLE `devices` ADD `retries` INT NULL DEFAULT NULL AFTER `timeout`; +ALTER TABLE `ports` ADD `disabled` tinyint(1) NOT NULL DEFAULT '0' AFTER `ignore`; +ALTER TABLE `perf_times` CHANGE `duration` `duration` DOUBLE( 8, 2 ) NOT NULL +ALTER TABLE `sensors` ADD `poller_type` VARCHAR(16) NOT NULL DEFAULT 'snmp' AFTER `device_id`; +ALTER TABLE `devices` ADD `transport` VARCHAR(16) NOT NULL DEFAULT 'udp' AFTER `port`; +ALTER TABLE ports MODIFY port_descr_circuit VARCHAR(255); +ALTER TABLE ports MODIFY port_descr_descr VARCHAR(255); +ALTER TABLE ports MODIFY port_descr_notes VARCHAR(255); +ALTER TABLE devices MODIFY community VARCHAR(255); +ALTER TABLE users MODIFY password VARCHAR(34); +ALTER TABLE sensors MODIFY sensor_descr VARCHAR(255); +ALTER TABLE `vrfs` MODIFY `mplsVpnVrfRouteDistinguisher` VARCHAR(128); +ALTER TABLE `vrfs` MODIFY `vrf_name` VARCHAR(128); +ALTER TABLE `ports` MODIFY `ifDescr` VARCHAR(255); +CREATE TABLE IF NOT EXISTS `vminfo` (`id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `vmwVmVMID` int(11) NOT NULL, `vmwVmDisplayName` varchar(128) NOT NULL, `vmwVmGuestOS` varchar(128) NOT NULL, `vmwVmMemSize` int(11) NOT NULL, `vmwVmCpus` int(11) NOT NULL, `vmwVmState` varchar(128) NOT NULL, PRIMARY KEY (`id`), KEY `device_id` (`device_id`), KEY `vmwVmVMID` (`vmwVmVMID`)) ENGINE=InnoDB DEFAULT CHARSET=utf8; +ALTER TABLE `ports` MODIFY `port_descr_type` VARCHAR(255); +RENAME TABLE `vmware_vminfo` TO `vminfo` ; +ALTER TABLE `vminfo` ADD `vm_type` VARCHAR(16) NOT NULL DEFAULT 'vmware' AFTER `device_id`; +CREATE TABLE IF NOT EXISTS `cef_switching` ( `device_id` int(11) NOT NULL, `entPhysicalIndex` int(11) NOT NULL, `afi` varchar(4) COLLATE utf8_unicode_ci NOT NULL, `cef_index` int(11) NOT NULL, `cef_path` varchar(16) COLLATE utf8_unicode_ci NOT NULL, `drop` int(11) NOT NULL, `punt` int(11) NOT NULL, `punt2host` int(11) NOT NULL, `drop_prev` int(11) NOT NULL, `punt_prev` int(11) NOT NULL, `punt2host_prev` int(11) NOT NULL,`updated` INT NOT NULL , `updated_prev` INT NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +ALTER TABLE `mac_accounting` CHANGE `peer_mac` `mac` VARCHAR( 32 ) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL; +ALTER TABLE `mac_accounting` DROP `peer_ip`, DROP `peer_desc`, DROP `peer_asn`; +UPDATE sensors SET sensor_class='frequency' WHERE sensor_class='freq'; +ALTER TABLE `cef_switching` ADD `cef_switching_id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY FIRST; +ALTER TABLE `mempools` ADD `mempool_perc` INT NOT NULL AFTER `device_id`; +ALTER TABLE `ports` ADD UNIQUE `device_ifIndex` ( `device_id` , `ifIndex` ); +ALTER TABLE `ports` DROP INDEX `host`; +ALTER TABLE `ports` DROP INDEX `snmpid`; +CREATE TABLE IF NOT EXISTS `ospf_areas` ( `device_id` int(11) NOT NULL, `ospfAreaId` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfAuthType` varchar(64) COLLATE utf8_unicode_ci NOT NULL, `ospfImportAsExtern` varchar(128) COLLATE utf8_unicode_ci NOT NULL, `ospfSpfRuns` int(11) NOT NULL, `ospfAreaBdrRtrCount` int(11) NOT NULL, `ospfAsBdrRtrCount` int(11) NOT NULL, `ospfAreaLsaCount` int(11) NOT NULL, `ospfAreaLsaCksumSum` int(11) NOT NULL, `ospfAreaSummary` varchar(64) COLLATE utf8_unicode_ci NOT NULL, `ospfAreaStatus` varchar(64) COLLATE utf8_unicode_ci NOT NULL, UNIQUE KEY `device_area` (`device_id`,`ospfAreaId`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +CREATE TABLE IF NOT EXISTS `ospf_instances` ( `device_id` int(11) NOT NULL, `ospf_instance_id` int(11) NOT NULL, `ospfRouterId` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfAdminStat` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfVersionNumber` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfAreaBdrRtrStatus` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfASBdrRtrStatus` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfExternLsaCount` int(11) NOT NULL, `ospfExternLsaCksumSum` int(11) NOT NULL, `ospfTOSSupport` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfOriginateNewLsas` int(11) NOT NULL, `ospfRxNewLsas` int(11) NOT NULL, `ospfExtLsdbLimit` int(11) DEFAULT NULL, `ospfMulticastExtensions` int(11) DEFAULT NULL, `ospfExitOverflowInterval` int(11) DEFAULT NULL, `ospfDemandExtensions` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL, UNIQUE KEY `device_id` (`device_id`,`ospf_instance_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +CREATE TABLE IF NOT EXISTS `ospf_ports` ( `device_id` int(11) NOT NULL, `interface_id` int(11) NOT NULL, `ospf_port_id` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfIfIpAddress` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfAddressLessIf` int(11) NOT NULL, `ospfIfAreaId` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfIfType` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL, `ospfIfAdminStat` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL, `ospfIfRtrPriority` int(11) DEFAULT NULL, `ospfIfTransitDelay` int(11) DEFAULT NULL, `ospfIfRetransInterval` int(11) DEFAULT NULL, `ospfIfHelloInterval` int(11) DEFAULT NULL, `ospfIfRtrDeadInterval` int(11) DEFAULT NULL, `ospfIfPollInterval` int(11) DEFAULT NULL, `ospfIfState` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL, `ospfIfDesignatedRouter` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL, `ospfIfBackupDesignatedRouter` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL, `ospfIfEvents` int(11) DEFAULT NULL, `ospfIfAuthKey` varchar(128) COLLATE utf8_unicode_ci DEFAULT NULL, `ospfIfStatus` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL, `ospfIfMulticastForwarding` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL, `ospfIfDemand` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL, `ospfIfAuthType` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL, UNIQUE KEY `device_id` (`device_id`,`interface_id`,`ospf_port_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +CREATE TABLE IF NOT EXISTS `ospf_nbrs` ( `device_id` int(11) NOT NULL, `interface_id` int(11) NOT NULL, `ospf_nbr_id` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfNbrIpAddr` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfNbrAddressLessIndex` int(11) NOT NULL, `ospfNbrRtrId` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfNbrOptions` int(11) NOT NULL, `ospfNbrPriority` int(11) NOT NULL, `ospfNbrState` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfNbrEvents` int(11) NOT NULL, `ospfNbrLsRetransQLen` int(11) NOT NULL, `ospfNbmaNbrStatus` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfNbmaNbrPermanence` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfNbrHelloSuppressed` varchar(32) COLLATE utf8_unicode_ci NOT NULL, UNIQUE KEY `device_id` (`device_id`,`ospf_nbr_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +CREATE TABLE IF NOT EXISTS `ports_stack` (`interface_id_high` INT NOT NULL ,`interface_id_low` INT NOT NULL) ENGINE = INNODB; +ALTER TABLE `ports_stack` ADD `device_id` INT NOT NULL; +ALTER TABLE `ports_stack` ADD `ifStackStatus` VARCHAR(32); +ALTER TABLE users ADD can_modify_passwd TINYINT NOT NULL DEFAULT 1; +ALTER TABLE `storage` ADD UNIQUE `index_unique` ( `device_id` , `storage_mib` , `storage_index` ); +ALTER TABLE `bgpPeers_cbgp` ADD `AcceptedPrefixes` INT NOT NULL ,ADD `DeniedPrefixes` INT NOT NULL ,ADD `PrefixAdminLimit` INT NOT NULL ,ADD `PrefixThreshold` INT NOT NULL ,ADD `PrefixClearThreshold` INT NOT NULL ,ADD `AdvertisedPrefixes` INT NOT NULL ,ADD `SuppressedPrefixes` INT NOT NULL ,ADD `WithdrawnPrefixes` INT NOT NULL; +ALTER TABLE `bgpPeers_cbgp` ADD UNIQUE `unique_index` ( `device_id` , `bgpPeerIdentifier` , `afi` , `safi` ); +ALTER TABLE `ports` ADD UNIQUE `device_ifIndex` ( `device_id` , `ifIndex` ); +ALTER TABLE `devices` CHANGE `port` `port` SMALLINT( 5 ) UNSIGNED NOT NULL DEFAULT '161'; +CREATE TABLE IF NOT EXISTS `ipsec_tunnels` ( `tunnel_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `peer_port` int(11) NOT NULL, `peer_addr` varchar(64) COLLATE utf8_unicode_ci NOT NULL, `local_addr` varchar(64) COLLATE utf8_unicode_ci NOT NULL, `local_port` int(11) NOT NULL, `tunnel_name` varchar(96) COLLATE utf8_unicode_ci NOT NULL, `tunnel_status` varchar(11) COLLATE utf8_unicode_ci NOT NULL, PRIMARY KEY (`tunnel_id`), UNIQUE KEY `unique_index` (`device_id`,`peer_addr`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +ALTER TABLE `syslog` ADD INDEX ( `program` ); +ALTER TABLE `devices` ADD `sysObjectID` VARCHAR( 64 ) NULL DEFAULT NULL AFTER `bgpLocalAs`; +ALTER TABLE `ports` CHANGE `ifSpeed` `ifSpeed` BIGINT NULL DEFAULT NULL; +ALTER TABLE `sensors` CHANGE `sensor_oid` `sensor_oid` VARCHAR( 255 ) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL; +CREATE TABLE IF NOT EXISTS `entPhysical_state` ( `device_id` int(11) NOT NULL, `entPhysicalIndex` varchar(64) NOT NULL, `subindex` varchar(64) DEFAULT NULL, `group` varchar(64) NOT NULL, `key` varchar(64) NOT NULL, `value` varchar(255) NOT NULL, KEY `device_id_index` (`device_id`,`entPhysicalIndex`)) ENGINE=MyISAM DEFAULT CHARSET=latin1; +CREATE TABLE IF NOT EXISTS `ports_vlans` ( `port_vlan_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `interface_id` int(11) NOT NULL, `vlan` int(11) NOT NULL, `baseport` int(11) NOT NULL, `priority` bigint(32) NOT NULL, `state` varchar(16) NOT NULL, `cost` int(11) NOT NULL, PRIMARY KEY (`port_vlan_id`), UNIQUE KEY `unique` (`device_id`,`interface_id`,`vlan`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 ; +ALTER TABLE `bills` CHANGE `bill_cdr` `bill_cdr` BIGINT( 20 ) NULL DEFAULT NULL; +CREATE TABLE IF NOT EXISTS `loadbalancer_rservers` ( `rserver_id` int(11) NOT NULL AUTO_INCREMENT, `farm_id` varchar(128) CHARACTER SET utf8 NOT NULL, `device_id` int(11) NOT NULL, `StateDescr` varchar(64) CHARACTER SET utf8 NOT NULL, PRIMARY KEY (`rserver_id`)) ENGINE=MyISAM AUTO_INCREMENT=514 DEFAULT CHARSET=utf8; +CREATE TABLE IF NOT EXISTS `loadbalancer_vservers` ( `classmap_id` int(11) NOT NULL, `classmap` varchar(128) NOT NULL, `serverstate` varchar(64) NOT NULL, `device_id` int(11) NOT NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8; +ALTER TABLE `sensors` CHANGE `sensor_index` `sensor_index` VARCHAR( 64 ); +CREATE TABLE IF NOT EXISTS `netscaler_vservers` ( `vsvr_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `vsvr_name` varchar(128) COLLATE utf8_unicode_ci NOT NULL, `vsvr_ip` varchar(128) COLLATE utf8_unicode_ci NOT NULL, `vsvr_port` int(8) NOT NULL, `vsvr_type` varchar(64) COLLATE utf8_unicode_ci NOT NULL, `vsvr_state` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `vsvr_clients` int(11) NOT NULL, `vsvr_server` int(11) NOT NULL, `vsvr_req_rate` int(11) NOT NULL, `vsvr_bps_in` int(11) NOT NULL, `vsvr_bps_out` int(11) NOT NULL, PRIMARY KEY (`vsvr_id`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci ; +ALTER TABLE `dbSchema` ADD `version` INT NOT NULL; +ALTER TABLE `dbSchema` DROP `revision`; +ALTER TABLE `bills` CHANGE `bill_gb` `bill_quota` BIGINT( 20 ) NULL DEFAULT NULL; +ALTER TABLE `bills` CHANGE `rate_95th_in` `rate_95th_in` BIGINT( 20 ) NOT NULL; +ALTER TABLE `bills` CHANGE `rate_95th_out` `rate_95th_out` BIGINT( 20 ) NOT NULL; +ALTER TABLE `bills` CHANGE `rate_95th` `rate_95th` BIGINT( 20 ) NOT NULL; +ALTER TABLE `bills` CHANGE `total_data` `total_data` BIGINT( 20 ) NOT NULL; +ALTER TABLE `bills` CHANGE `total_data_in` `total_data_in` BIGINT( 20 ) NOT NULL ; +ALTER TABLE `bills` CHANGE `total_data_out` `total_data_out` BIGINT( 20 ) NOT NULL; +ALTER TABLE `bills` CHANGE `rate_average_in` `rate_average_in` BIGINT( 20 ) NOT NULL; +ALTER TABLE `bills` CHANGE `rate_average_out` `rate_average_out` BIGINT( 20 ) NOT NULL; +ALTER TABLE `bills` CHANGE `rate_average` `rate_average` BIGINT( 20 ) NOT NULL; +ALTER TABLE `eventlog` ADD INDEX `datetime` ( `datetime` ); +CREATE TABLE IF NOT EXISTS `packages` ( `pkg_id` int(11) NOT NULL auto_increment, `device_id` int(11) NOT NULL, `name` varchar(64) NOT NULL, `manager` varchar(16) NOT NULL default '1', `status` tinyint(1) NOT NULL, `version` varchar(64) NOT NULL, `build` varchar(64) NOT NULL, `arch` varchar(16) NOT NULL, `size` bigint(20) default NULL, PRIMARY KEY (`pkg_id`), UNIQUE KEY `unique_key` (`device_id`,`name`,`manager`,`arch`,`version`,`build`), KEY `device_id` (`device_id`)) ENGINE=MyISAM CHARSET=utf8 COLLATE=utf8_bin; +CREATE TABLE IF NOT EXISTS `slas` ( `sla_id` int(11) NOT NULL auto_increment, `device_id` int(11) NOT NULL, `sla_nr` int(11) NOT NULL, `owner` varchar(255) NOT NULL, `tag` varchar(255) NOT NULL, `rtt_type` varchar(16) NOT NULL, `status` tinyint(1) NOT NULL, `deleted` tinyint(1) NOT NULL DEFAULT '0', PRIMARY KEY (`sla_id`), UNIQUE KEY `unique_key` (`device_id`,`sla_nr`), KEY `device_id` (`device_id`)) ENGINE=MyISAM CHARSET=utf8 COLLATE=utf8_bin; +ALTER TABLE `devices` ADD COLUMN `icon` VARCHAR(255) DEFAULT NULL +CREATE TABLE IF NOT EXISTS `munin_plugins` ( `mplug_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `mplug_type` varchar(256) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, `mplug_instance` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL, `mplug_category` varchar(32) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL, `mplug_title` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL, `mplug_info` text CHARACTER SET utf8 COLLATE utf8_bin, `mplug_vlabel` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL, `mplug_args` varchar(512) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL, `mplug_total` binary(1) NOT NULL DEFAULT '0', `mplug_graph` binary(1) NOT NULL DEFAULT '1', PRIMARY KEY (`mplug_id`), UNIQUE KEY `UNIQUE` (`device_id`,`mplug_type`), KEY `device_id` (`device_id`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin ; +CREATE TABLE IF NOT EXISTS `munin_plugins_ds` ( `mplug_id` int(11) NOT NULL, `ds_name` varchar(32) COLLATE utf8_bin NOT NULL, `ds_type` enum('COUNTER','ABSOLUTE','DERIVE','GAUGE') COLLATE utf8_bin NOT NULL DEFAULT 'GAUGE', `ds_label` varchar(64) COLLATE utf8_bin NOT NULL, `ds_cdef` text COLLATE utf8_bin NOT NULL, `ds_draw` varchar(64) COLLATE utf8_bin NOT NULL, `ds_graph` enum('no','yes') COLLATE utf8_bin NOT NULL DEFAULT 'yes', `ds_info` varchar(255) COLLATE utf8_bin NOT NULL, `ds_extinfo` text COLLATE utf8_bin NOT NULL, `ds_max` varchar(32) COLLATE utf8_bin NOT NULL, `ds_min` varchar(32) COLLATE utf8_bin NOT NULL, `ds_negative` varchar(32) COLLATE utf8_bin NOT NULL, `ds_warning` varchar(32) COLLATE utf8_bin NOT NULL, `ds_critical` varchar(32) COLLATE utf8_bin NOT NULL, `ds_colour` varchar(32) COLLATE utf8_bin NOT NULL, `ds_sum` text CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, `ds_stack` text COLLATE utf8_bin NOT NULL, `ds_line` varchar(64) COLLATE utf8_bin NOT NULL, UNIQUE KEY `splug_id` (`mplug_id`,`ds_name`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin; +ALTER TABLE `munin_plugins_ds` CHANGE `ds_cdef` `ds_cdef` VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL; +ALTER TABLE `applications` ADD `app_state` TEXT CHARACTER SET utf8 COLLATE utf8_bin NOT NULL; +ALTER TABLE `vlans` ADD `vlan_type` VARCHAR( 16 ) NULL; +ALTER TABLE `vlans` CHANGE `vlan_domain` `vlan_domain` INT NULL DEFAULT NULL; +ALTER TABLE `vlans` CHANGE `vlan_descr` `vlan_name` VARCHAR( 32 ) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL; +ALTER TABLE `vlans` ADD `vlan_mtu` INT NULL; +ALTER TABLE `applications` ADD `app_status` VARCHAR( 8 ) NOT NULL ; +UPDATE `sensors` SET sensor_limit=sensor_limit/1.3*1.8 WHERE sensor_class="fanspeed" +ALTER TABLE `pseudowires` ADD `device_id` INT NOT NULL AFTER `pseudowire_id`; +TRUNCATE TABLE `pseudowires`; +ALTER TABLE `pseudowires` ADD `pw_type` VARCHAR( 32 ) NOT NULL ,ADD `pw_psntype` VARCHAR( 32 ) NOT NULL ,ADD `pw_local_mtu` INT NOT NULL ,ADD `pw_peer_mtu` INT NOT NULL ,ADD `pw_descr` VARCHAR( 128 ) NOT NULL; +ALTER TABLE `toner` ADD `toner_capacity_oid` VARCHAR( 64 ); +ALTER TABLE `devices` ADD `authlevel` ENUM("noAuthNoPriv", "authNoPriv", "authPriv") NULL DEFAULT NULL AFTER `community`; +ALTER TABLE `devices` ADD `authname` VARCHAR(64) NULL DEFAULT NULL AFTER `authlevel`; +ALTER TABLE `devices` ADD `authpass` VARCHAR(64) NULL DEFAULT NULL AFTER `authname`; +ALTER TABLE `devices` ADD `authalgo` ENUM("MD5", "SHA1") NULL DEFAULT NULL AFTER `authpass`; +ALTER TABLE `devices` ADD `cryptopass` VARCHAR(64) NULL DEFAULT NULL AFTER `authalgo`; +ALTER TABLE `devices` ADD `cryptoalgo` ENUM("AES", "DES") NULL DEFAULT NULL AFTER `cryptopass`; +ALTER TABLE `applications` CHANGE `app_state` `app_state` VARCHAR( 32 ) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT 'UNKNOWN'; +ALTER TABLE `applications` CHANGE `app_type` `app_type` VARCHAR( 64 ) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL; +ALTER TABLE `devices` CHANGE `authalgo` `authalgo` ENUM( 'MD5', 'SHA' ) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL; +ALTER TABLE `ports` CHANGE `interface_id` `port_id` INT( 11 ) NOT NULL AUTO_INCREMENT; +ALTER TABLE `storage` ADD `storage_deleted` BOOL NOT NULL DEFAULT '0'; +ALTER TABLE `links` CHANGE `local_interface_id` `local_port_id` INT( 11 ) NULL DEFAULT NULL; +ALTER TABLE `links` CHANGE `remote_interface_id` `remote_port_id` INT( 11 ) NULL DEFAULT NULL; +ALTER TABLE `sensors` ADD `sensor_deleted` BOOL NOT NULL DEFAULT '0' AFTER `sensor_id`; +ALTER TABLE `mempools` ADD `mempool_deleted` BOOL NOT NULL DEFAULT '0'; +ALTER TABLE `ipv4_addresses` CHANGE `interface_id` `port_id` INT( 11 ) NOT NULL; +ALTER TABLE `ipv6_addresses` CHANGE `interface_id` `port_id` INT( 11 ) NOT NULL; +ALTER TABLE `ipv4_mac` CHANGE `interface_id` `port_id` INT( 11 ) NOT NULL; +ALTER TABLE `juniAtmVp` CHANGE `interface_id` `port_id` INT( 11 ) NOT NULL; +ALTER TABLE `ospf_nbrs` CHANGE `interface_id` `port_id` INT( 11 ) NOT NULL; +ALTER TABLE `mac_accounting` CHANGE `interface_id` `port_id` INT( 11 ) NOT NULL; +ALTER TABLE `ospf_ports` CHANGE `interface_id` `port_id` INT( 11 ) NOT NULL; +ALTER TABLE `ports_adsl` CHANGE `interface_id` `port_id` INT( 11 ) NOT NULL; +ALTER TABLE `ports_perms` CHANGE `interface_id` `port_id` INT( 11 ) NOT NULL; +ALTER TABLE `ports_stack` CHANGE `interface_id_high` `port_id_high` INT( 11 ) NOT NULL; +ALTER TABLE `ports_stack` CHANGE `interface_id_low` `port_id_low` INT( 11 ) NOT NULL; +ALTER TABLE `ports_vlans` CHANGE `interface_id` `port_id` INT( 11 ) NOT NULL; +ALTER TABLE `pseudowires` CHANGE `interface_id` `port_id` INT( 11 ) NOT NULL; +CREATE TABLE IF NOT EXISTS `access_points` ( `accesspoint_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `name` varchar(255) NOT NULL, `radio_number` tinyint(4) DEFAULT NULL, `type` varchar(16) NOT NULL, `mac_addr` varchar(24) NOT NULL, `deleted` tinyint(1) NOT NULL DEFAULT '0', `channel` tinyint(4) unsigned NOT NULL DEFAULT '0', `txpow` tinyint(4) NOT NULL DEFAULT '0', `radioutil` tinyint(4) NOT NULL DEFAULT '0', `numasoclients` smallint(6) NOT NULL DEFAULT '0', `nummonclients` smallint(6) NOT NULL DEFAULT '0', `numactbssid` tinyint(4) NOT NULL DEFAULT '0', `nummonbssid` tinyint(4) NOT NULL DEFAULT '0', `interference` tinyint(3) unsigned NOT NULL, PRIMARY KEY (`accesspoint_id`), KEY `deleted` (`deleted`), KEY `name` (`name`,`radio_number`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Access Points';ALTER TABLE `juniAtmVp` ADD INDEX ( `port_id` ); +ALTER TABLE `loadbalancer_vservers` ADD INDEX ( `device_id` ); +ALTER TABLE `users` CHANGE `password` `password` VARCHAR( 60 ); +CREATE TABLE IF NOT EXISTS `session` ( `session_id` int(11) NOT NULL AUTO_INCREMENT, `session_username` varchar(30) NOT NULL, `session_value` varchar(60) NOT NULL, `session_token` varchar(60) NOT NULL, `session_auth` varchar(16) NOT NULL, `session_expiry` int(11) NOT NULL, PRIMARY KEY (`session_id`)) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ; +CREATE TABLE IF NOT EXISTS `plugins` ( `plugin_id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY , `plugin_name` VARCHAR( 60 ) NOT NULL , `plugin_active` INT NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1; +ALTER TABLE `sensors` ADD `sensor_alert` TINYINT( 1 ) NOT NULL DEFAULT '1' AFTER `sensor_limit_low_warn` ; +CREATE TABLE IF NOT EXISTS `ciscoASA` ( `ciscoASA_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `oid` varchar(255) NOT NULL, `data` bigint(20) NOT NULL, `high_alert` bigint(20) NOT NULL, `low_alert` bigint(20) NOT NULL, `disabled` tinyint(4) NOT NULL DEFAULT '0', PRIMARY KEY (`ciscoASA_id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ; +INSERT INTO `graph_types` SET `graph_type`='device', `graph_subtype`='asa_conns',`graph_section`='firewall',`graph_descr`='Current connections',`graph_order`='0'; +CREATE TABLE `api_tokens` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user_id` int(11) NOT NULL, `token_hash` varchar(32) NOT NULL, `description` varchar(100) NOT NULL, `disabled` tinyint(1) NOT NULL DEFAULT '0', PRIMARY KEY (`id`), UNIQUE KEY `token_hash` (`token_hash`)) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=latin1; +ALTER TABLE `api_tokens` MODIFY `token_hash` VARCHAR(256); +ALTER TABLE `devices` ADD `last_ping` TIMESTAMP NULL AFTER `last_discovered` , ADD `last_ping_timetaken` DOUBLE( 5, 2 ) NULL AFTER `last_ping` ; +DROP TABLE IF EXISTS `alerts`; +CREATE TABLE IF NOT EXISTS `alerts` ( `id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `rule_id` int(11) NOT NULL, `state` int(11) NOT NULL, `alerted` int(11) NOT NULL, `open` int(11) NOT NULL, `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8; +DROP TABLE IF EXISTS `alert_log`; +CREATE TABLE IF NOT EXISTS `alert_log` ( `id` int(11) NOT NULL AUTO_INCREMENT, `rule_id` int(11) NOT NULL, `device_id` int(11) NOT NULL, `state` int(11) NOT NULL, `details` longblob NOT NULL, `time_logged` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY `id` (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8; +DROP TABLE IF EXISTS `alert_rules`; +CREATE TABLE IF NOT EXISTS `alert_rules` ( `id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `rule` text CHARACTER SET utf8 NOT NULL, `severity` enum('ok','warning','critical') CHARACTER SET utf8 NOT NULL, `extra` varchar(255) CHARACTER SET utf8 NOT NULL, `disabled` tinyint(1) NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8; +DROP TABLE IF EXISTS `alert_schedule`; +CREATE TABLE IF NOT EXISTS `alert_schedule` ( `id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `start` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', `end` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8; +DROP TABLE IF EXISTS `alert_templates`; +CREATE TABLE IF NOT EXISTS `alert_templates` ( `id` int(11) NOT NULL AUTO_INCREMENT, `rule_id` varchar(255) NOT NULL DEFAULT ',',`name` varchar(255) NOT NULL, `template` longtext NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8; +ALTER TABLE `alert_rules` ADD `name` VARCHAR( 255 ) NOT NULL ; +ALTER TABLE `users` ADD `twofactor` VARCHAR( 255 ) NOT NULL; +CREATE TABLE IF NOT EXISTS `processes` ( `device_id` int(11) NOT NULL, `pid` int(255) NOT NULL, `vsz` int(255) NOT NULL, `rss` int(255) NOT NULL, `cputime` varchar(12) NOT NULL, `user` varchar(50) NOT NULL, `command` varchar(255) NOT NULL, KEY `device_id` (`device_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; +ALTER TABLE `devices` CHANGE `agent_uptime` `agent_uptime` INT( 11 ) NOT NULL DEFAULT '0'; +ALTER TABLE `devices` CHANGE `type` `type` VARCHAR( 20 ) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT ''; +ALTER TABLE `ports` CHANGE `ifVrf` `ifVrf` INT( 11 ) NOT NULL DEFAULT '0'; +ALTER TABLE `storage` CHANGE `storage_free` `storage_free` BIGINT( 20 ) NOT NULL DEFAULT '0'; +ALTER TABLE `storage` CHANGE `storage_used` `storage_used` BIGINT( 20 ) NOT NULL DEFAULT '0'; +ALTER TABLE `storage` CHANGE `storage_perc` `storage_perc` INT NOT NULL DEFAULT '0'; +ALTER TABLE `processors` CHANGE `entPhysicalIndex` `entPhysicalIndex` INT( 11 ) NOT NULL DEFAULT '0'; +ALTER TABLE `hrDevice` CHANGE `hrDeviceErrors` `hrDeviceErrors` INT( 11 ) NOT NULL DEFAULT '0'; +ALTER TABLE `devices_attribs` ADD INDEX ( `device_id` ); +ALTER TABLE `device_graphs` ADD INDEX ( `device_id` ); +ALTER TABLE `alert_log` ADD INDEX ( `rule_id` ); +ALTER TABLE `alert_log` ADD INDEX ( `device_id` ); +ALTER TABLE `alerts` ADD INDEX ( `rule_id` ); +ALTER TABLE `alerts` ADD INDEX ( `device_id` ); +ALTER TABLE `ciscoASA` ADD INDEX ( `device_id` ); +ALTER TABLE `alert_schedule` ADD INDEX ( `device_id` ); +ALTER TABLE `alert_rules` ADD INDEX ( `device_id` ); +CREATE TABLE `pollers` (`id` int(11) NOT NULL AUTO_INCREMENT, `poller_name` varchar(255) NOT NULL, `last_polled` datetime NOT NULL, `devices` int(11) NOT NULL, `time_taken` double NOT NULL, KEY `id` (`id`)) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8 COLLATE=utf8_bin; +ALTER TABLE `devices` ADD `poller_group` INT(11) NOT NULL DEFAULT '0'; +CREATE TABLE `poller_groups` (`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,`group_name` VARCHAR( 255 ) NOT NULL ,`descr` VARCHAR( 255 ) NOT NULL) ENGINE = INNODB; +ALTER TABLE `links` ADD `local_device_id` INT NOT NULL AFTER `local_port_id` , ADD `remote_device_id` INT NOT NULL AFTER `remote_hostname` ; +ALTER TABLE `links` ADD INDEX ( `local_device_id` , `remote_device_id` ) ; +CREATE TABLE IF NOT EXISTS `device_groups` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL DEFAULT '', `desc` varchar(255) NOT NULL DEFAULT '', `pattern` varchar(255) NOT NULL DEFAULT '', PRIMARY KEY (`id`), UNIQUE KEY `name` (`name`)) ENGINE=InnoDB; +CREATE TABLE IF NOT EXISTS `alert_map` ( `id` int(11) NOT NULL AUTO_INCREMENT, `rule` int(11) NOT NULL DEFAULT '0', `target` varchar(255) CHARACTER SET utf8 NOT NULL DEFAULT '', PRIMARY KEY (`id`)) ENGINE=InnoDB; +ALTER TABLE `alert_rules` ADD UNIQUE (`name`); +ALTER TABLE `alert_rules` CHANGE `device_id` `device_id` VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT ''; +CREATE TABLE `callback` ( `callback_id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY , `name` CHAR( 64 ) NOT NULL , `value` CHAR( 64 ) NOT NULL ) ENGINE = INNODB; +ALTER TABLE `alert_log` ADD INDEX ( `time_logged` ); +ALTER TABLE `alert_schedule` DROP `device_id`; +ALTER TABLE `alert_schedule` CHANGE `id` `schedule_id` INT( 11 ) NOT NULL AUTO_INCREMENT; +ALTER TABLE `alert_schedule` ADD `title` VARCHAR( 255 ) NOT NULL ,ADD `notes` TEXT NOT NULL ; +CREATE TABLE `librenms`.`alert_schedule_items` (`item_id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,`schedule_id` INT NOT NULL ,`target` VARCHAR( 255 ) NOT NULL ,INDEX ( `schedule_id` )) ENGINE = INNODB; +ALTER TABLE device_groups MODIFY COLUMN pattern TEXT; +ALTER TABLE `sensors` ADD `sensor_custom` ENUM( 'No', 'Yes' ) NOT NULL DEFAULT 'No' AFTER `sensor_alert` ; +DROP TABLE IF EXISTS `config`; +CREATE TABLE `config` ( `config_id` int(11) NOT NULL AUTO_INCREMENT, `config_name` varchar(255) NOT NULL, `config_value` varchar(512) NOT NULL, `config_default` varchar(512) NOT NULL, `config_descr` varchar(100) NOT NULL, `config_group` varchar(50) NOT NULL, `config_group_order` int(11) NOT NULL, `config_sub_group` varchar(50) NOT NULL, `config_sub_group_order` int(11) NOT NULL, `config_hidden` enum('0','1') NOT NULL DEFAULT '0', `config_disabled` enum('0','1') NOT NULL DEFAULT '0', PRIMARY KEY (`config_id`)) ENGINE=InnoDB AUTO_INCREMENT=720 DEFAULT CHARSET=latin1; +INSERT INTO `config` VALUES (441,'alert.macros.rule.now','NOW()','NOW()','Macro currenttime','alerting',0,'macros',0,'1','0'),(442,'alert.macros.rule.past_5m','DATE_SUB(NOW(),INTERVAL 5 MINUTE)','DATE_SUB(NOW(),INTERVAL 5 MINUTE)','Macro past 5 minutes','alerting',0,'macros',0,'1','0'),(443,'alert.macros.rule.past_10m','DATE_SUB(NOW(),INTERVAL 10 MINUTE)','DATE_SUB(NOW(),INTERVAL 10 MINUTE)','Macro past 10 minutes','alerting',0,'macros',0,'1','0'),(444,'alert.macros.rule.past_15m','DATE_SUB(NOW(),INTERVAL 15 MINUTE)','DATE_SUB(NOW(),INTERVAL 15 MINUTE)','Macro past 15 minutes','alerting',0,'macros',0,'1','0'),(445,'alert.macros.rule.past_30m','DATE_SUB(NOW(),INTERVAL 30 MINUTE)','DATE_SUB(NOW(),INTERVAL 30 MINUTE)','Macro past 30 minutes','alerting',0,'macros',0,'1','0'),(446,'alert.macros.rule.device','(%devices.disabled = 0 && %devices.ignore = 0)','(%devices.disabled = 0 && %devices.ignore = 0)','Devices that aren\'t disabled or ignored','alerting',0,'macros',0,'1','0'),(447,'alert.macros.rule.device_up','(%devices.status = 1 && %macros.device)','(%devices.status = 1 && %macros.device)','Devices that are up','alerting',0,'macros',0,'1','0'),(448,'alert.macros.rule.device_down','(%devices.status = 0 && %macros.device)','(%devices.status = 0 && %macros.device)','Devices that are down','alerting',0,'macros',0,'1','0'),(449,'alert.macros.rule.port','(%ports.deleted = 0 && %ports.ignore = 0 && %ports.disabled = 0)','(%ports.deleted = 0 && %ports.ignore = 0 && %ports.disabled = 0)','Ports that aren\'t disabled, ignored or delete','alerting',0,'macros',0,'1','0'),(450,'alert.macros.rule.port_up','(%ports.ifOperStatus = \"up\" && %ports.ifAdminStatus = \"up\" && %macros.port)','(%ports.ifOperStatus = \"up\" && %ports.ifAdminStatus = \"up\" && %macros.port)','Ports that are up','alerting',0,'macros',0,'1','0'),(451,'alert.admins','true','true','Alert administrators','alerting',0,'general',0,'0','0'),(452,'alert.default_only','true','true','Only alert default mail contact','alerting',0,'general',0,'0','0'),(453,'alert.default_mail','','','The default mail contact','alerting',0,'general',0,'0','0'),(454,'alert.transports.pagerduty','','','Pagerduty transport - put your API key here','alerting',0,'transports',0,'0','0'),(455,'alert.pagerduty.account','','','Pagerduty account name','alerting',0,'transports',0,'0','0'),(456,'alert.pagerduty.service','','','Pagerduty service name','alerting',0,'transports',0,'0','0'),(457,'alert.tolerance_window','5','5','Tolerance window in seconds','alerting',0,'general',0,'0','0'),(458,'email_backend','mail','mail','The backend to use for sending email, can be mail, sendmail or smtp','alerting',0,'general',0,'0','0'),(459,'alert.macros.rule.past_60m','DATE_SUB(NOW(),INTERVAL 60 MINUTE)','DATE_SUB(NOW(),INTERVAL 60 MINUTE)','Macro past 60 minutes','alerting',0,'macros',0,'1','0'),(460,'alert.macros.rule.port_usage_perc','((%ports.ifInOctets_rate*8)/%ports.ifSpeed)*100','((%ports.ifInOctets_rate*8)/%ports.ifSpeed)*100','Ports using more than X perc','alerting',0,'macros',0,'1','0'),(461,'alert.transports.dummy','false','false','Dummy transport','alerting',0,'transports',0,'0','0'),(462,'alert.transports.mail','true','true','Mail alerting transport','alerting',0,'transports',0,'0','0'),(463,'alert.transports.irc','FALSE','false','IRC alerting transport','alerting',0,'transports',0,'0','0'),(464,'alert.globals','true','TRUE','Alert read only administrators','alerting',0,'general',0,'0','0'),(465,'email_from','NULL','NULL','Email address used for sending emails (from)','alerting',0,'general',0,'0','0'),(466,'email_user','LibreNMS','LibreNMS','Name used as part of the from address','alerting',0,'general',0,'0','0'),(467,'email_sendmail_path','/usr/sbin/sendmail','/usr/sbin/sendmail','Location of sendmail if using this option','alerting',0,'general',0,'0','0'),(468,'email_smtp_host','localhost','localhost','SMTP Host for sending email if using this option','alerting',0,'general',0,'0','0'),(469,'email_smtp_port','25','25','SMTP port setting','alerting',0,'general',0,'0','0'),(470,'email_smtp_timeout','10','10','SMTP timeout setting','alerting',0,'general',0,'0','0'),(471,'email_smtp_secure','','','Enable / disable encryption (use tls or ssl)','alerting',0,'general',0,'0','0'),(472,'email_smtp_auth','false','FALSE','Enable / disable smtp authentication','alerting',0,'general',0,'0','0'),(473,'email_smtp_username','NULL','NULL','SMTP Auth username','alerting',0,'general',0,'0','0'),(474,'email_smtp_password','NULL','NULL','SMTP Auth password','alerting',0,'general',0,'0','0'),(475,'alert.macros.rule.port_down','(%ports.ifOperStatus = \"down\" && %ports.ifAdminStatus != \"down\" && %macros.port)','(%ports.ifOperStatus = \"down\" && %ports.ifAdminStatus != \"down\" && %macros.port)','Ports that are down','alerting',0,'macros',0,'1','0'),(486,'alert.syscontact','true','TRUE','Issue alerts to sysContact','alerting',0,'general',0,'0','0'),(487,'alert.fixed-contacts','true','TRUE','If TRUE any changes to sysContact or users emails will not be honoured whilst alert is active','alerting',0,'general',0,'0','0'),(488,'alert.transports.nagios','','','Nagios compatible via FIFO','alerting',0,'transports',0,'0','0'); +ALTER TABLE `munin_plugins` CHANGE `mplug_type` `mplug_type` VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL; +ALTER TABLE slas ENGINE=InnoDB; +ALTER TABLE packages ENGINE=InnoDB; +ALTER TABLE munin_plugins_ds ENGINE=InnoDB; +ALTER TABLE munin_plugins ENGINE=InnoDB; +ALTER TABLE loadbalancer_vservers ENGINE=InnoDB; +ALTER TABLE loadbalancer_rservers ENGINE=InnoDB; +ALTER TABLE ipsec_tunnels ENGINE=InnoDB; +CREATE TABLE `alert_template_map` (`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,`alert_templates_id` INT NOT NULL ,`alert_rule_id` INT NOT NULL ,INDEX ( `alert_templates_id` , `alert_rule_id` )) ENGINE = INNODB +ALTER TABLE `graph_types` CHANGE `graph_subtype` `graph_subtype` varchar(64); +ALTER TABLE `device_graphs` CHANGE `graph` `graph` varchar(64); +ALTER TABLE `graph_types` CHANGE `graph_descr` `graph_descr` varchar(255); +ALTER TABLE `graph_types` ADD PRIMARY KEY (`graph_type`, `graph_subtype`, `graph_section`); +insert into config (config_name,config_value,config_default,config_descr,config_group,config_group_order,config_sub_group,config_sub_group_order,config_hidden,config_disabled) values ('alert.macros.rule.sensor','(%sensors.sensor_alert = 1)','(%sensors.sensor_alert = 1)','Sensors of interest','alerting',0,'macros',0,1,0); +CREATE TABLE IF NOT EXISTS `device_perf` ( `id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `timestamp` datetime NOT NULL, `xmt` float NOT NULL, `rcv` float NOT NULL, `loss` float NOT NULL, `min` float NOT NULL, `max` float NOT NULL, `avg` float NOT NULL, KEY `id` (`id`,`device_id`)) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ; +insert into config (config_name,config_value,config_default,config_descr,config_group,config_group_order,config_sub_group,config_sub_group_order,config_hidden,config_disabled) values ('alert.macros.rule.packet_loss_15m','(%macros.past_15m && %device_perf.loss)','(%macros.past_15m && %device_perf.loss)','Packet loss over the last 15 minutes','alerting',0,'macros',0,1,0); +insert into config (config_name,config_value,config_default,config_descr,config_group,config_group_order,config_sub_group,config_sub_group_order,config_hidden,config_disabled) values ('alert.macros.rule.packet_loss_5m','(%macros.past_5m && %device_perf.loss)','(%macros.past_5m && %device_perf.loss)','Packet loss over the last 5 minutes','alerting',0,'macros',0,1,0); +ALTER TABLE `devices` ADD `status_reason` VARCHAR( 50 ) NOT NULL AFTER `status` ; +UPDATE `devices` SET `status_reason`='down' WHERE `status`=0; +ALTER TABLE `ipv4_mac` CHANGE `mac_address` `mac_address` VARCHAR( 32 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL , CHANGE `ipv4_address` `ipv4_address` VARCHAR( 32 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL +ALTER TABLE `ipv4_mac` ADD INDEX ( `port_id`), ADD INDEX (`mac_address` ) +ALTER TABLE `ipv4_mac` DROP INDEX `interface_id`, DROP INDEX `interface_id_2` +CREATE TABLE `locations` ( `id` INT NOT NULL AUTO_INCREMENT ,`location` TEXT NOT NULL ,`lat` FLOAT( 10, 6 ) NOT NULL ,`lng` FLOAT( 10, 6 ) NOT NULL ,`timestamp` DATETIME NOT NULL ,INDEX ( `id` )) ENGINE = INNODB; +ALTER TABLE `devices` ADD `override_sysLocation` bool DEFAULT false; +UPDATE `devices` LEFT JOIN devices_attribs AS sysloc_bool ON(devices.device_id=sysloc_bool.device_id and sysloc_bool.attrib_type = 'override_sysLocation_bool') LEFT JOIN devices_attribs AS sysloc_string ON(devices.device_id=sysloc_string.device_id and sysloc_string.attrib_type = 'override_sysLocation_string') SET `override_sysLocation` = true, `location` = sysloc_string.attrib_value WHERE sysloc_bool.attrib_value = 1; +CREATE TABLE `users_widgets` ( `user_widget_id` int(11) NOT NULL AUTO_INCREMENT, `user_id` int(11) NOT NULL, `widget_id` int(11) NOT NULL, `col` tinyint(4) NOT NULL, `row` tinyint(4) NOT NULL, `size_x` tinyint(4) NOT NULL, `size_y` tinyint(4) NOT NULL, `title` varchar(255) NOT NULL, `refresh` tinyint(4) NOT NULL DEFAULT '60', PRIMARY KEY (`user_widget_id`), KEY `user_id` (`user_id`,`widget_id`) ) ENGINE=InnoDB AUTO_INCREMENT=46 DEFAULT CHARSET=latin1; +CREATE TABLE `widgets` ( `widget_id` int(11) NOT NULL AUTO_INCREMENT, `widget_title` varchar(255) NOT NULL, `widget` varchar(255) NOT NULL, `base_dimensions` varchar(10) NOT NULL, PRIMARY KEY (`widget_id`), UNIQUE KEY `widget` (`widget`)) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1; +INSERT INTO `widgets` (`widget_id`, `widget_title`, `widget`, `base_dimensions`) VALUES (1, 'Availability map', 'availability-map', '4,3'), (2, 'Device summary horizontal', 'device-summary-horiz', '4,2'), (3, 'Alerts', 'alerts', '8,4'), (4, 'Device summary vertical', 'device-summary-vert', '4,3'), (5, 'World map', 'globe', '3,3'); +INSERT INTO `widgets` (`widget_title`, `widget`, `base_dimensions`) VALUES ('Syslog', 'syslog', '9,3'), ('Eventlog', 'eventlog', '9,5'), ('Global Map', 'worldmap', '8,6'); +ALTER TABLE `device_perf` DROP INDEX `id` , ADD INDEX `id` ( `id` ), ADD INDEX ( `device_id` ); +ALTER TABLE `bgpPeers` MODIFY `bgpPeerRemoteAs` bigint(20) NOT NULL; +INSERT INTO `widgets` (`widget_title`, `widget`, `base_dimensions`) VALUES ('Graylog', 'graylog', '9,7'); +insert into config (config_name,config_value,config_default,config_descr,config_group,config_group_order,config_sub_group,config_sub_group_order,config_hidden,config_disabled) values ('alert.transports.pushbullet','','','Pushbullet access token','alerting',0,'transports',0,'0','0'); +DELETE n1 FROM pollers n1, pollers n2 WHERE n1.last_polled < n2.last_polled and n1.poller_name = n2.poller_name; +ALTER TABLE pollers ADD PRIMARY KEY (poller_name); +ALTER TABLE `devices` ADD `last_poll_attempted` timestamp NULL DEFAULT NULL AFTER `last_polled`; +ALTER TABLE `devices` ADD INDEX `last_polled` (`last_polled`); +ALTER TABLE `devices` ADD INDEX `last_poll_attempted` (`last_poll_attempted`); +ALTER TABLE `alert_templates` ADD `title` VARCHAR(255) NULL DEFAULT NULL; +ALTER TABLE `alert_templates` ADD `title_rec` VARCHAR(255) NULL DEFAULT NULL; +CREATE TABLE `proxmox` ( `id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL DEFAULT '0', `vmid` int(11) NOT NULL, `cluster` varchar(255) NOT NULL, `description` varchar(255) DEFAULT NULL, `last_seen` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `cluster_vm` (`cluster`,`vmid`)) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE `proxmox_ports` ( `id` int(11) NOT NULL AUTO_INCREMENT, `vm_id` int(11) NOT NULL, `port` varchar(10) NOT NULL, `last_seen` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `vm_port` (`vm_id`,`port`)) ENGINE=InnoDB DEFAULT CHARSET=utf8; +ALTER TABLE `applications` ADD COLUMN `app_instance` varchar(255) NOT NULL; diff --git a/html/install.php b/html/install.php index 73ee6e8ce..127af0b17 100644 --- a/html/install.php +++ b/html/install.php @@ -1,9 +1,16 @@ " . mysqli_connect_error(); } - else { - $sql = "SELECT * FROM users LIMIT 1"; - if(mysqli_query($test_db,$sql)) { - $stage = 3; - $msg = "It appears that the database is already setup so have moved onto stage $stage"; + elseif ($stage != 3) { + if($_SESSION['build-ok'] == true) { + $stage = 3; + $msg = "It appears that the database is already setup so have moved onto stage $stage"; } } + $_SESSION['stage'] = $stage; } elseif($stage == "4") { // Now check we have a username, password and email before adding new user if(empty($add_user) || empty($add_pass) || empty($add_email)) { - $stage = 4; + $stage = 3; $msg = "You haven't entered enough information to add the user account, please check below and re-try"; } } @@ -302,6 +309,7 @@ elseif($stage == "2") {
    Importing MySQL DB - Do not close this page or interrupt the import
    +
     
    +
    diff --git a/includes/sql-schema/update.php b/includes/sql-schema/update.php index 505082615..264f1601b 100644 --- a/includes/sql-schema/update.php +++ b/includes/sql-schema/update.php @@ -147,17 +147,16 @@ foreach ($filelist as $file) { $updating++; $db_rev = $filename; + if ($insert) { + dbInsert(array('version' => $db_rev), 'dbSchema'); + } + else { + dbUpdate(array('version' => $db_rev), 'dbSchema'); + } }//end if }//end foreach if ($updating) { - if ($insert) { - dbInsert(array('version' => $db_rev), 'dbSchema'); - } - else { - dbUpdate(array('version' => $db_rev), 'dbSchema'); - } - echo "-- Done\n"; } From 3f7c37a523f86300066aca2c7982e4bac2a2b446 Mon Sep 17 00:00:00 2001 From: f0o Date: Tue, 1 Sep 2015 22:53:07 +0100 Subject: [PATCH 216/598] revision fix --- build-base.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/build-base.php b/build-base.php index dbfe8e3da..c496850d2 100644 --- a/build-base.php +++ b/build-base.php @@ -52,10 +52,8 @@ while (!feof($sql_fh)) { } fclose($sql_fh); +dbInsert(array('version' => 67), 'dbSchema'); -if( !isset($_SESSION['stage']) ) { - require 'includes/sql-schema/update.php'; -} else { +if( isset($_SESSION['stage']) ) { $_SESSION['build-ok'] = true; - dbInsert(array('version' => 67), 'dbSchema'); } From 2fd423f9fc20ac15ef55387f0669736f4587967c Mon Sep 17 00:00:00 2001 From: f0o Date: Tue, 1 Sep 2015 23:31:41 +0100 Subject: [PATCH 217/598] Revert build.sql Make update.php responsive --- build-base.php | 3 +- build.sql | 448 +-------------------------------- html/install.php | 2 +- includes/sql-schema/update.php | 10 + 4 files changed, 16 insertions(+), 447 deletions(-) diff --git a/build-base.php b/build-base.php index c496850d2..507abb266 100644 --- a/build-base.php +++ b/build-base.php @@ -52,7 +52,8 @@ while (!feof($sql_fh)) { } fclose($sql_fh); -dbInsert(array('version' => 67), 'dbSchema'); + +require 'includes/sql-schema/update.php'; if( isset($_SESSION['stage']) ) { $_SESSION['build-ok'] = true; diff --git a/build.sql b/build.sql index 39d87c8cf..9f4526069 100644 --- a/build.sql +++ b/build.sql @@ -70,9 +70,12 @@ CREATE TABLE IF NOT EXISTS `frequency` ( `freq_id` int(11) NOT NULL auto_increme CREATE TABLE IF NOT EXISTS `current` ( `current_id` int(11) NOT NULL auto_increment, `device_id` int(11) NOT NULL default '0', `current_oid` varchar(64) NOT NULL, `current_index` varchar(8) NOT NULL, `current_type` varchar(32) NOT NULL, `current_descr` varchar(32) NOT NULL default '', `current_precision` int(11) NOT NULL default '1', `current_current` float default NULL, `current_limit` float default NULL, `current_limit_warn` float default NULL, `current_limit_low` float default NULL, PRIMARY KEY (`current_id`), KEY `current_host` (`device_id`)) ENGINE=MyISAM AUTO_INCREMENT=189 DEFAULT CHARSET=latin1; CREATE TABLE IF NOT EXISTS `ucd_diskio` ( `diskio_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `diskio_index` int(11) NOT NULL, `diskio_descr` varchar(32) NOT NULL, PRIMARY KEY (`diskio_id`)) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=11 ; CREATE TABLE IF NOT EXISTS `applications` ( `app_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `app_type` varchar(64) NOT NULL, PRIMARY KEY (`app_id`)) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ; +## 0.10.6 CREATE TABLE IF NOT EXISTS `sensors` ( `sensor_id` int(11) NOT NULL auto_increment, `sensor_class` varchar(64) NOT NULL, `device_id` int(11) NOT NULL default '0', `sensor_oid` varchar(64) NOT NULL, `sensor_index` varchar(8) NOT NULL, `sensor_type` varchar(32) NOT NULL, `sensor_descr` varchar(32) NOT NULL default '', `sensor_precision` int(11) NOT NULL default '1', `sensor_current` float default NULL, `sensor_limit` float default NULL, `sensor_limit_warn` float default NULL, `sensor_limit_low` float default NULL, `sensor_limit_low_warn` float default NULL, PRIMARY KEY (`sensor_id`), KEY `sensor_host` (`device_id`)) ENGINE=MyISAM AUTO_INCREMENT=189 DEFAULT CHARSET=latin1; CREATE TABLE IF NOT EXISTS `ports_adsl` ( `interface_id` int(11) NOT NULL, `port_adsl_updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `adslLineCoding` varchar(8) COLLATE utf8_bin NOT NULL, `adslLineType` varchar(16) COLLATE utf8_bin NOT NULL, `adslAtucInvVendorID` varchar(8) COLLATE utf8_bin NOT NULL, `adslAtucInvVersionNumber` varchar(8) COLLATE utf8_bin NOT NULL, `adslAtucCurrSnrMgn` decimal(5,1) NOT NULL, `adslAtucCurrAtn` decimal(5,1) NOT NULL, `adslAtucCurrOutputPwr` decimal(5,1) NOT NULL, `adslAtucCurrAttainableRate` int(11) NOT NULL, `adslAtucChanCurrTxRate` int(11) NOT NULL, `adslAturInvSerialNumber` varchar(8) COLLATE utf8_bin NOT NULL, `adslAturInvVendorID` varchar(8) COLLATE utf8_bin NOT NULL, `adslAturInvVersionNumber` varchar(8) COLLATE utf8_bin NOT NULL, `adslAturChanCurrTxRate` int(11) NOT NULL, `adslAturCurrSnrMgn` decimal(5,1) NOT NULL, `adslAturCurrAtn` decimal(5,1) NOT NULL, `adslAturCurrOutputPwr` decimal(5,1) NOT NULL, `adslAturCurrAttainableRate` int(11) NOT NULL, UNIQUE KEY `interface_id` (`interface_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; +## 0.10.7 CREATE TABLE IF NOT EXISTS `perf_times` ( `type` varchar(8) NOT NULL, `doing` varchar(64) NOT NULL, `start` int(11) NOT NULL, `duration` double(5,2) NOT NULL, `devices` int(11) NOT NULL, KEY `type` (`type`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; +## 0.10.7.1 CREATE TABLE IF NOT EXISTS `device_graphs` ( `device_id` int(11) NOT NULL, `graph` varchar(32) COLLATE utf8_unicode_ci NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; CREATE TABLE IF NOT EXISTS `graph_types` ( `graph_type` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `graph_subtype` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `graph_section` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `graph_descr` varchar(64) COLLATE utf8_unicode_ci NOT NULL, `graph_order` int(11) NOT NULL, KEY `graph_type` (`graph_type`), KEY `graph_subtype` (`graph_subtype`), KEY `graph_section` (`graph_section`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; INSERT INTO `graph_types` (`graph_type`, `graph_subtype`, `graph_section`, `graph_descr`, `graph_order`) VALUES('device', 'bits', 'netstats', 'Total Traffic', 0),('device', 'hr_users', 'system', 'Users Logged In', 0),('device', 'ucd_load', 'system', 'Load Averages', 0),('device', 'ucd_cpu', 'system', 'Detailed Processor Usage', 0),('device', 'ucd_memory', 'system', 'Detailed Memory Usage', 0),('device', 'netstat_tcp', 'netstats', 'TCP Statistics', 0),('device', 'netstat_icmp_info', 'netstats', 'ICMP Informational Statistics', 0),('device', 'netstat_icmp_stat', 'netstats', 'ICMP Statistics', 0),('device', 'netstat_ip', 'netstats', 'IP Statistics', 0),('device', 'netstat_ip_frag', 'netstats', 'IP Fragmentation Statistics', 0),('device', 'netstat_udp', 'netstats', 'UDP Statistics', 0),('device', 'netstat_snmp', 'netstats', 'SNMP Statistics', 0),('device', 'temperatures', 'system', 'Temperatures', 0),('device', 'mempools', 'system', 'Memory Pool Usage', 0),('device', 'processors', 'system', 'Processor Usage', 0),('device', 'storage', 'system', 'Filesystem Usage', 0),('device', 'hr_processes', 'system', 'Running Processes', 0),('device', 'uptime', 'system', 'System Uptime', 0),('device', 'ipsystemstats_ipv4', 'netstats', 'IPv4 Packet Statistics', 0),('device', 'ipsystemstats_ipv6_frag', 'netstats', 'IPv6 Fragmentation Statistics', 0),('device', 'ipsystemstats_ipv6', 'netstats', 'IPv6 Packet Statistics', 0),('device', 'ipsystemstats_ipv4_frag', 'netstats', 'IPv4 Fragmentation Statistics', 0),('device', 'fortigate_sessions', 'firewall', 'Active Sessions', 0), ('device', 'screenos_sessions', 'firewall', 'Active Sessions', 0), ('device', 'fdb_count', 'system', 'MAC Addresses Learnt', 0),('device', 'cras_sessions', 'firewall', 'Remote Access Sessions', 0); @@ -95,448 +98,3 @@ CREATE TABLE IF NOT EXISTS `slas` ( `sla_id` int(11) NOT NULL auto_increment, CREATE TABLE IF NOT EXISTS `munin_plugins` ( `mplug_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `mplug_type` varchar(256) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, `mplug_instance` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL, `mplug_category` varchar(32) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL, `mplug_title` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL, `mplug_info` text CHARACTER SET utf8 COLLATE utf8_bin, `mplug_vlabel` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL, `mplug_args` varchar(512) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL, `mplug_total` binary(1) NOT NULL DEFAULT '0', `mplug_graph` binary(1) NOT NULL DEFAULT '1', PRIMARY KEY (`mplug_id`), UNIQUE KEY `UNIQUE` (`device_id`,`mplug_type`), KEY `device_id` (`device_id`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin ; CREATE TABLE IF NOT EXISTS `munin_plugins_ds` ( `mplug_id` int(11) NOT NULL, `ds_name` varchar(32) COLLATE utf8_bin NOT NULL, `ds_type` enum('COUNTER','ABSOLUTE','DERIVE','GAUGE') COLLATE utf8_bin NOT NULL DEFAULT 'GAUGE', `ds_label` varchar(64) COLLATE utf8_bin NOT NULL, `ds_cdef` text COLLATE utf8_bin NOT NULL, `ds_draw` varchar(64) COLLATE utf8_bin NOT NULL, `ds_graph` enum('no','yes') COLLATE utf8_bin NOT NULL DEFAULT 'yes', `ds_info` varchar(255) COLLATE utf8_bin NOT NULL, `ds_extinfo` text COLLATE utf8_bin NOT NULL, `ds_max` varchar(32) COLLATE utf8_bin NOT NULL, `ds_min` varchar(32) COLLATE utf8_bin NOT NULL, `ds_negative` varchar(32) COLLATE utf8_bin NOT NULL, `ds_warning` varchar(32) COLLATE utf8_bin NOT NULL, `ds_critical` varchar(32) COLLATE utf8_bin NOT NULL, `ds_colour` varchar(32) COLLATE utf8_bin NOT NULL, `ds_sum` text CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, `ds_stack` text COLLATE utf8_bin NOT NULL, `ds_line` varchar(64) COLLATE utf8_bin NOT NULL, UNIQUE KEY `splug_id` (`mplug_id`,`ds_name`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin; CREATE TABLE IF NOT EXISTS `access_points` ( `accesspoint_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `name` varchar(255) NOT NULL, `radio_number` tinyint(4) DEFAULT NULL, `type` varchar(16) NOT NULL, `mac_addr` varchar(24) NOT NULL, `deleted` tinyint(1) NOT NULL DEFAULT '0', `channel` tinyint(4) unsigned NOT NULL DEFAULT '0', `txpow` tinyint(4) NOT NULL DEFAULT '0', `radioutil` tinyint(4) NOT NULL DEFAULT '0', `numasoclients` smallint(6) NOT NULL DEFAULT '0', `nummonclients` smallint(6) NOT NULL DEFAULT '0', `numactbssid` tinyint(4) NOT NULL DEFAULT '0', `nummonbssid` tinyint(4) NOT NULL DEFAULT '0', `interference` tinyint(3) unsigned NOT NULL, PRIMARY KEY (`accesspoint_id`), KEY `deleted` (`deleted`), KEY `name` (`name`,`radio_number`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Access Points'; -CREATE TABLE IF NOT EXISTS `alerts` ( `id` int(11) NOT NULL AUTO_INCREMENT, `importance` int(11) NOT NULL DEFAULT '0', `device_id` int(11) NOT NULL, `message` text NOT NULL, `time_logged` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `alerted` smallint(6) NOT NULL DEFAULT '0', KEY `id` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE TABLE IF NOT EXISTS `applications` ( `app_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `app_type` varchar(64) NOT NULL, PRIMARY KEY (`app_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE TABLE IF NOT EXISTS `authlog` ( `id` int(11) NOT NULL AUTO_INCREMENT, `datetime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `user` text NOT NULL, `address` text NOT NULL, `result` text NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE TABLE IF NOT EXISTS `bgpPeers` ( `bgpPeer_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `astext` varchar(64) NOT NULL, `bgpPeerIdentifier` text NOT NULL, `bgpPeerRemoteAs` int(11) NOT NULL, `bgpPeerState` text NOT NULL, `bgpPeerAdminStatus` text NOT NULL, `bgpLocalAddr` text NOT NULL, `bgpPeerRemoteAddr` text NOT NULL, `bgpPeerInUpdates` int(11) NOT NULL, `bgpPeerOutUpdates` int(11) NOT NULL, `bgpPeerInTotalMessages` int(11) NOT NULL, `bgpPeerOutTotalMessages` int(11) NOT NULL, `bgpPeerFsmEstablishedTime` int(11) NOT NULL, `bgpPeerInUpdateElapsedTime` int(11) NOT NULL, PRIMARY KEY (`bgpPeer_id`), KEY `device_id` (`device_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE TABLE IF NOT EXISTS `bgpPeers_cbgp` ( `device_id` int(11) NOT NULL, `bgpPeerIdentifier` varchar(64) NOT NULL, `afi` varchar(16) NOT NULL, `safi` varchar(16) NOT NULL, KEY `device_id` (`device_id`,`bgpPeerIdentifier`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE TABLE IF NOT EXISTS `bills` ( `bill_id` int(11) NOT NULL AUTO_INCREMENT, `bill_name` text NOT NULL, `bill_type` text NOT NULL, `bill_cdr` int(11) DEFAULT NULL, `bill_day` int(11) NOT NULL DEFAULT '1', `bill_gb` int(11) DEFAULT NULL, `rate_95th_in` int(11) NOT NULL, `rate_95th_out` int(11) NOT NULL, `rate_95th` int(11) NOT NULL, `dir_95th` varchar(3) NOT NULL, `total_data` int(11) NOT NULL, `total_data_in` int(11) NOT NULL, `total_data_out` int(11) NOT NULL, `rate_average_in` int(11) NOT NULL, `rate_average_out` int(11) NOT NULL, `rate_average` int(11) NOT NULL, `bill_last_calc` datetime NOT NULL, `bill_custid` varchar(64) NOT NULL, `bill_ref` varchar(64) NOT NULL, `bill_notes` varchar(256) NOT NULL, `bill_autoadded` tinyint(1) NOT NULL, UNIQUE KEY `bill_id` (`bill_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 ; -CREATE TABLE IF NOT EXISTS `bill_data` ( `bill_id` int(11) NOT NULL, `timestamp` datetime NOT NULL, `period` int(11) NOT NULL, `delta` bigint(11) NOT NULL, `in_delta` bigint(11) NOT NULL, `out_delta` bigint(11) NOT NULL, KEY `bill_id` (`bill_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE TABLE IF NOT EXISTS `bill_perms` ( `user_id` int(11) NOT NULL, `bill_id` int(11) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE TABLE IF NOT EXISTS `bill_ports` ( `bill_id` int(11) NOT NULL, `port_id` int(11) NOT NULL, `bill_port_autoadded` tinyint(1) NOT NULL DEFAULT '0' ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE TABLE IF NOT EXISTS `cef_switching` ( `cef_switching_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `entPhysicalIndex` int(11) NOT NULL, `afi` varchar(4) COLLATE utf8_unicode_ci NOT NULL, `cef_index` int(11) NOT NULL, `cef_path` varchar(16) COLLATE utf8_unicode_ci NOT NULL, `drop` int(11) NOT NULL, `punt` int(11) NOT NULL, `punt2host` int(11) NOT NULL, `drop_prev` int(11) NOT NULL, `punt_prev` int(11) NOT NULL, `punt2host_prev` int(11) NOT NULL, `updated` int(11) NOT NULL, `updated_prev` int(11) NOT NULL, PRIMARY KEY (`cef_switching_id`), UNIQUE KEY `device_id` (`device_id`,`entPhysicalIndex`,`afi`,`cef_index`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; -CREATE TABLE IF NOT EXISTS `customers` ( `customer_id` int(11) NOT NULL AUTO_INCREMENT, `username` char(64) NOT NULL, `password` char(32) NOT NULL, `string` char(64) NOT NULL, `level` tinyint(4) NOT NULL DEFAULT '0', PRIMARY KEY (`customer_id`), UNIQUE KEY `username` (`username`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE TABLE IF NOT EXISTS `dbSchema` ( `revision` int(11) NOT NULL DEFAULT '0', PRIMARY KEY (`revision`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE TABLE IF NOT EXISTS `devices` ( `device_id` int(11) NOT NULL AUTO_INCREMENT, `hostname` varchar(128) CHARACTER SET latin1 NOT NULL, `sysName` varchar(128) CHARACTER SET latin1 DEFAULT NULL, `community` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, `snmpver` varchar(4) CHARACTER SET latin1 NOT NULL DEFAULT 'v2c', `port` smallint(5) unsigned NOT NULL DEFAULT '161', `transport` varchar(16) COLLATE utf8_unicode_ci NOT NULL DEFAULT 'udp', `timeout` int(11) DEFAULT NULL, `retries` int(11) DEFAULT NULL, `bgpLocalAs` varchar(16) CHARACTER SET latin1 DEFAULT NULL, `sysDescr` text CHARACTER SET latin1, `sysContact` text CHARACTER SET latin1, `version` text CHARACTER SET latin1, `hardware` text CHARACTER SET latin1, `features` text CHARACTER SET latin1, `location` text COLLATE utf8_unicode_ci, `os` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL, `status` tinyint(4) NOT NULL DEFAULT '0', `ignore` tinyint(4) NOT NULL DEFAULT '0', `disabled` tinyint(1) NOT NULL DEFAULT '0', `uptime` bigint(20) DEFAULT NULL, `agent_uptime` int(11) NOT NULL, `last_polled` timestamp NULL DEFAULT NULL, `last_polled_timetaken` double(5,2) DEFAULT NULL, `last_discovered_timetaken` double(5,2) DEFAULT NULL, `last_discovered` timestamp NULL DEFAULT NULL, `purpose` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL, `type` varchar(20) COLLATE utf8_unicode_ci NOT NULL, `serial` text COLLATE utf8_unicode_ci, PRIMARY KEY (`device_id`), KEY `status` (`status`), KEY `hostname` (`hostname`), KEY `sysName` (`sysName`), KEY `os` (`os`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; -CREATE TABLE IF NOT EXISTS `devices_attribs` ( `attrib_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `attrib_type` varchar(32) NOT NULL, `attrib_value` text NOT NULL, `updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`attrib_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE TABLE IF NOT EXISTS `devices_perms` ( `user_id` int(11) NOT NULL, `device_id` int(11) NOT NULL, `access_level` int(4) NOT NULL DEFAULT '0', KEY `user_id` (`user_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE TABLE IF NOT EXISTS `device_graphs` ( `device_id` int(11) NOT NULL, `graph` varchar(32) COLLATE utf8_unicode_ci NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; -CREATE TABLE IF NOT EXISTS `entPhysical` ( `entPhysical_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `entPhysicalIndex` int(11) NOT NULL, `entPhysicalDescr` text NOT NULL, `entPhysicalClass` text NOT NULL, `entPhysicalName` text NOT NULL, `entPhysicalHardwareRev` varchar(64) DEFAULT NULL, `entPhysicalFirmwareRev` varchar(64) DEFAULT NULL, `entPhysicalSoftwareRev` varchar(64) DEFAULT NULL, `entPhysicalAlias` varchar(32) DEFAULT NULL, `entPhysicalAssetID` varchar(32) DEFAULT NULL, `entPhysicalIsFRU` varchar(8) DEFAULT NULL, `entPhysicalModelName` text NOT NULL, `entPhysicalVendorType` text, `entPhysicalSerialNum` text NOT NULL, `entPhysicalContainedIn` int(11) NOT NULL, `entPhysicalParentRelPos` int(11) NOT NULL, `entPhysicalMfgName` text NOT NULL, `ifIndex` int(11) DEFAULT NULL, PRIMARY KEY (`entPhysical_id`), KEY `device_id` (`device_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE TABLE IF NOT EXISTS `eventlog` ( `event_id` int(11) NOT NULL AUTO_INCREMENT, `host` int(11) NOT NULL DEFAULT '0', `datetime` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', `message` text CHARACTER SET latin1, `type` varchar(64) CHARACTER SET latin1 DEFAULT NULL, `reference` varchar(64) CHARACTER SET latin1 NOT NULL, PRIMARY KEY (`event_id`), KEY `host` (`host`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; -CREATE TABLE IF NOT EXISTS `graph_types` ( `graph_type` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `graph_subtype` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `graph_section` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `graph_descr` varchar(64) COLLATE utf8_unicode_ci NOT NULL, `graph_order` int(11) NOT NULL, KEY `graph_type` (`graph_type`), KEY `graph_subtype` (`graph_subtype`), KEY `graph_section` (`graph_section`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; -CREATE TABLE IF NOT EXISTS `graph_types_dead` ( `graph_type` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `graph_subtype` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `graph_section` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `graph_descr` varchar(64) COLLATE utf8_unicode_ci NOT NULL, `graph_order` int(11) NOT NULL, KEY `graph_type` (`graph_type`), KEY `graph_subtype` (`graph_subtype`), KEY `graph_section` (`graph_section`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; -CREATE TABLE IF NOT EXISTS `hrDevice` ( `hrDevice_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `hrDeviceIndex` int(11) NOT NULL, `hrDeviceDescr` text CHARACTER SET latin1 NOT NULL, `hrDeviceType` text CHARACTER SET latin1 NOT NULL, `hrDeviceErrors` int(11) NOT NULL, `hrDeviceStatus` text CHARACTER SET latin1 NOT NULL, `hrProcessorLoad` tinyint(4) DEFAULT NULL, PRIMARY KEY (`hrDevice_id`), KEY `device_id` (`device_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; -CREATE TABLE IF NOT EXISTS `ipv4_addresses` ( `ipv4_address_id` int(11) NOT NULL AUTO_INCREMENT,`ipv4_address` varchar(32) CHARACTER SET latin1 NOT NULL, `ipv4_prefixlen` int(11) NOT NULL,`ipv4_network_id` varchar(32) CHARACTER SET latin1 NOT NULL, `interface_id` int(11) NOT NULL,PRIMARY KEY (`ipv4_address_id`), KEY `interface_id` (`interface_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; -CREATE TABLE IF NOT EXISTS `ipv4_mac` ( `interface_id` int(11) NOT NULL, `mac_address` varchar(32) CHARACTER SET latin1 NOT NULL, `ipv4_address` varchar(32) CHARACTER SET latin1 NOT NULL, KEY `interface_id` (`interface_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; -CREATE TABLE IF NOT EXISTS `ipv4_networks` ( `ipv4_network_id` int(11) NOT NULL AUTO_INCREMENT, `ipv4_network` varchar(64) CHARACTER SET latin1 NOT NULL, PRIMARY KEY (`ipv4_network_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; -CREATE TABLE IF NOT EXISTS `ipv6_addresses` ( `ipv6_address_id` int(11) NOT NULL AUTO_INCREMENT, `ipv6_address` varchar(128) CHARACTER SET latin1 NOT NULL, `ipv6_compressed` varchar(128) CHARACTER SET latin1 NOT NULL, `ipv6_prefixlen` int(11) NOT NULL, `ipv6_origin` varchar(16) CHARACTER SET latin1 NOT NULL, `ipv6_network_id` varchar(128) CHARACTER SET latin1 NOT NULL, `interface_id` int(11) NOT NULL, PRIMARY KEY (`ipv6_address_id`), KEY `interface_id` (`interface_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; -CREATE TABLE IF NOT EXISTS `ipv6_networks` ( `ipv6_network_id` int(11) NOT NULL AUTO_INCREMENT, `ipv6_network` varchar(64) CHARACTER SET latin1 NOT NULL, PRIMARY KEY (`ipv6_network_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; -CREATE TABLE IF NOT EXISTS `juniAtmVp` ( `juniAtmVp_id` int(11) NOT NULL, `interface_id` int(11) NOT NULL, `vp_id` int(11) NOT NULL, `vp_descr` varchar(32) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE TABLE IF NOT EXISTS `links` ( `id` int(11) NOT NULL AUTO_INCREMENT, `local_interface_id` int(11) DEFAULT NULL, `remote_interface_id` int(11) DEFAULT NULL, `active` tinyint(4) NOT NULL DEFAULT '1', `protocol` varchar(11) DEFAULT NULL, `remote_hostname` varchar(128) NOT NULL, `remote_port` varchar(128) NOT NULL, `remote_platform` varchar(128) NOT NULL, `remote_version` varchar(256) NOT NULL, PRIMARY KEY (`id`), KEY `src_if` (`local_interface_id`), KEY `dst_if` (`remote_interface_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE TABLE IF NOT EXISTS `mac_accounting` ( `ma_id` int(11) NOT NULL AUTO_INCREMENT, `interface_id` int(11) NOT NULL, `mac` varchar(32) NOT NULL, `in_oid` varchar(128) NOT NULL, `out_oid` varchar(128) NOT NULL, `bps_out` int(11) NOT NULL, `bps_in` int(11) NOT NULL, `cipMacHCSwitchedBytes_input` bigint(20) DEFAULT NULL, `cipMacHCSwitchedBytes_input_prev` bigint(20) DEFAULT NULL, `cipMacHCSwitchedBytes_input_delta` bigint(20) DEFAULT NULL, `cipMacHCSwitchedBytes_input_rate` int(11) DEFAULT NULL, `cipMacHCSwitchedBytes_output` bigint(20) DEFAULT NULL, `cipMacHCSwitchedBytes_output_prev` bigint(20) DEFAULT NULL, `cipMacHCSwitchedBytes_output_delta` bigint(20) DEFAULT NULL, `cipMacHCSwitchedBytes_output_rate` int(11) DEFAULT NULL, `cipMacHCSwitchedPkts_input` bigint(20) DEFAULT NULL, `cipMacHCSwitchedPkts_input_prev` bigint(20) DEFAULT NULL, `cipMacHCSwitchedPkts_input_delta` bigint(20) DEFAULT NULL, `cipMacHCSwitchedPkts_input_rate` int(11) DEFAULT NULL, `cipMacHCSwitchedPkts_output` bigint(20) DEFAULT NULL, `cipMacHCSwitchedPkts_output_prev` bigint(20) DEFAULT NULL, `cipMacHCSwitchedPkts_output_delta` bigint(20) DEFAULT NULL, `cipMacHCSwitchedPkts_output_rate` int(11) DEFAULT NULL, `poll_time` int(11) DEFAULT NULL, `poll_prev` int(11) DEFAULT NULL, `poll_period` int(11) DEFAULT NULL, PRIMARY KEY (`ma_id`), KEY `interface_id` (`interface_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE TABLE IF NOT EXISTS `mempools` ( `mempool_id` int(11) NOT NULL AUTO_INCREMENT, `mempool_index` varchar(16) CHARACTER SET latin1 NOT NULL, `entPhysicalIndex` int(11) DEFAULT NULL, `hrDeviceIndex` int(11) DEFAULT NULL, `mempool_type` varchar(32) CHARACTER SET latin1 NOT NULL, `mempool_precision` int(11) NOT NULL DEFAULT '1', `mempool_descr` varchar(64) CHARACTER SET latin1 NOT NULL, `device_id` int(11) NOT NULL, `mempool_perc` int(11) NOT NULL, `mempool_used` bigint(16) NOT NULL, `mempool_free` bigint(16) NOT NULL, `mempool_total` bigint(16) NOT NULL, `mempool_largestfree` bigint(16) DEFAULT NULL, `mempool_lowestfree` bigint(16) DEFAULT NULL, PRIMARY KEY (`mempool_id`), KEY `device_id` (`device_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; -CREATE TABLE IF NOT EXISTS `ospf_areas` ( `device_id` int(11) NOT NULL, `ospfAreaId` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfAuthType` varchar(64) COLLATE utf8_unicode_ci NOT NULL, `ospfImportAsExtern` varchar(128) COLLATE utf8_unicode_ci NOT NULL, `ospfSpfRuns` int(11) NOT NULL, `ospfAreaBdrRtrCount` int(11) NOT NULL, `ospfAsBdrRtrCount` int(11) NOT NULL, `ospfAreaLsaCount` int(11) NOT NULL, `ospfAreaLsaCksumSum` int(11) NOT NULL, `ospfAreaSummary` varchar(64) COLLATE utf8_unicode_ci NOT NULL, `ospfAreaStatus` varchar(64) COLLATE utf8_unicode_ci NOT NULL, UNIQUE KEY `device_area` (`device_id`,`ospfAreaId`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; -CREATE TABLE IF NOT EXISTS `ospf_instances` ( `device_id` int(11) NOT NULL, `ospf_instance_id` int(11) NOT NULL, `ospfRouterId` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfAdminStat` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfVersionNumber` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfAreaBdrRtrStatus` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfASBdrRtrStatus` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfExternLsaCount` int(11) NOT NULL, `ospfExternLsaCksumSum` int(11) NOT NULL, `ospfTOSSupport` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfOriginateNewLsas` int(11) NOT NULL, `ospfRxNewLsas` int(11) NOT NULL, `ospfExtLsdbLimit` int(11) DEFAULT NULL, `ospfMulticastExtensions` int(11) DEFAULT NULL, `ospfExitOverflowInterval` int(11) DEFAULT NULL, `ospfDemandExtensions` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL, UNIQUE KEY `device_id` (`device_id`,`ospf_instance_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; -CREATE TABLE IF NOT EXISTS `ospf_nbrs` ( `device_id` int(11) NOT NULL, `interface_id` int(11) NOT NULL, `ospf_nbr_id` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfNbrIpAddr` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfNbrAddressLessIndex` int(11) NOT NULL, `ospfNbrRtrId` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfNbrOptions` int(11) NOT NULL, `ospfNbrPriority` int(11) NOT NULL, `ospfNbrState` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfNbrEvents` int(11) NOT NULL, `ospfNbrLsRetransQLen` int(11) NOT NULL, `ospfNbmaNbrStatus` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfNbmaNbrPermanence` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfNbrHelloSuppressed` varchar(32) COLLATE utf8_unicode_ci NOT NULL, UNIQUE KEY `device_id` (`device_id`,`ospf_nbr_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; -CREATE TABLE IF NOT EXISTS `ospf_ports` ( `device_id` int(11) NOT NULL, `interface_id` int(11) NOT NULL, `ospf_port_id` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfIfIpAddress` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfAddressLessIf` int(11) NOT NULL, `ospfIfAreaId` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfIfType` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL, `ospfIfAdminStat` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL, `ospfIfRtrPriority` int(11) DEFAULT NULL, `ospfIfTransitDelay` int(11) DEFAULT NULL, `ospfIfRetransInterval` int(11) DEFAULT NULL, `ospfIfHelloInterval` int(11) DEFAULT NULL, `ospfIfRtrDeadInterval` int(11) DEFAULT NULL, `ospfIfPollInterval` int(11) DEFAULT NULL, `ospfIfState` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL, `ospfIfDesignatedRouter` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL, `ospfIfBackupDesignatedRouter` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL, `ospfIfEvents` int(11) DEFAULT NULL, `ospfIfAuthKey` varchar(128) COLLATE utf8_unicode_ci DEFAULT NULL, `ospfIfStatus` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL, `ospfIfMulticastForwarding` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL, `ospfIfDemand` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL, `ospfIfAuthType` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL, UNIQUE KEY `device_id` (`device_id`,`ospf_port_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; -CREATE TABLE IF NOT EXISTS `perf_times` ( `type` varchar(8) CHARACTER SET latin1 NOT NULL, `doing` varchar(64) CHARACTER SET latin1 NOT NULL, `start` int(11) NOT NULL, `duration` double(8,2) NOT NULL, `devices` int(11) NOT NULL, KEY `type` (`type`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; -CREATE TABLE IF NOT EXISTS `ports` ( `interface_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL DEFAULT '0', `port_descr_type` varchar(255) DEFAULT NULL, `port_descr_descr` varchar(255) DEFAULT NULL, `port_descr_circuit` varchar(255) DEFAULT NULL, `port_descr_speed` varchar(32) DEFAULT NULL, `port_descr_notes` varchar(255) DEFAULT NULL, `ifDescr` varchar(255) DEFAULT NULL, `ifName` varchar(64) DEFAULT NULL, `portName` varchar(128) DEFAULT NULL, `ifIndex` int(11) DEFAULT '0', `ifSpeed` bigint(20) DEFAULT NULL, `ifConnectorPresent` varchar(12) DEFAULT NULL, `ifPromiscuousMode` varchar(12) DEFAULT NULL, `ifHighSpeed` int(11) DEFAULT NULL, `ifOperStatus` varchar(16) DEFAULT NULL, `ifAdminStatus` varchar(16) DEFAULT NULL, `ifDuplex` varchar(12) DEFAULT NULL, `ifMtu` int(11) DEFAULT NULL, `ifType` text, `ifAlias` text, `ifPhysAddress` text, `ifHardType` varchar(64) DEFAULT NULL, `ifLastChange` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `ifVlan` varchar(8) NOT NULL DEFAULT '', `ifTrunk` varchar(8) DEFAULT '', `ifVrf` int(11) NOT NULL, `counter_in` int(11) DEFAULT NULL, `counter_out` int(11) DEFAULT NULL, `ignore` tinyint(1) NOT NULL DEFAULT '0', `disabled` tinyint(1) NOT NULL DEFAULT '0', `detailed` tinyint(1) NOT NULL DEFAULT '0', `deleted` tinyint(1) NOT NULL DEFAULT '0', `pagpOperationMode` varchar(32) DEFAULT NULL, `pagpPortState` varchar(16) DEFAULT NULL, `pagpPartnerDeviceId` varchar(48) DEFAULT NULL, `pagpPartnerLearnMethod` varchar(16) DEFAULT NULL, `pagpPartnerIfIndex` int(11) DEFAULT NULL, `pagpPartnerGroupIfIndex` int(11) DEFAULT NULL, `pagpPartnerDeviceName` varchar(128) DEFAULT NULL, `pagpEthcOperationMode` varchar(16) DEFAULT NULL, `pagpDeviceId` varchar(48) DEFAULT NULL, `pagpGroupIfIndex` int(11) DEFAULT NULL, `ifInUcastPkts` bigint(20) DEFAULT NULL, `ifInUcastPkts_prev` bigint(20) DEFAULT NULL, `ifInUcastPkts_delta` bigint(20) DEFAULT NULL, `ifInUcastPkts_rate` int(11) DEFAULT NULL, `ifOutUcastPkts` bigint(20) DEFAULT NULL, `ifOutUcastPkts_prev` bigint(20) DEFAULT NULL, `ifOutUcastPkts_delta` bigint(20) DEFAULT NULL, `ifOutUcastPkts_rate` int(11) DEFAULT NULL, `ifInErrors` bigint(20) DEFAULT NULL, `ifInErrors_prev` bigint(20) DEFAULT NULL, `ifInErrors_delta` bigint(20) DEFAULT NULL, `ifInErrors_rate` int(11) DEFAULT NULL, `ifOutErrors` bigint(20) DEFAULT NULL, `ifOutErrors_prev` bigint(20) DEFAULT NULL, `ifOutErrors_delta` bigint(20) DEFAULT NULL, `ifOutErrors_rate` int(11) DEFAULT NULL, `ifInOctets` bigint(20) DEFAULT NULL, `ifInOctets_prev` bigint(20) DEFAULT NULL, `ifInOctets_delta` bigint(20) DEFAULT NULL, `ifInOctets_rate` int(11) DEFAULT NULL, `ifOutOctets` bigint(20) DEFAULT NULL, `ifOutOctets_prev` bigint(20) DEFAULT NULL, `ifOutOctets_delta` bigint(20) DEFAULT NULL, `ifOutOctets_rate` int(11) DEFAULT NULL, `poll_time` int(11) DEFAULT NULL, `poll_prev` int(11) DEFAULT NULL, `poll_period` int(11) DEFAULT NULL, PRIMARY KEY (`interface_id`), UNIQUE KEY `device_ifIndex` (`device_id`,`ifIndex`), KEY `if_2` (`ifDescr`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE TABLE IF NOT EXISTS `ports_adsl` ( `interface_id` int(11) NOT NULL, `port_adsl_updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `adslLineCoding` varchar(8) COLLATE utf8_bin NOT NULL, `adslLineType` varchar(16) COLLATE utf8_bin NOT NULL, `adslAtucInvVendorID` varchar(8) COLLATE utf8_bin NOT NULL, `adslAtucInvVersionNumber` varchar(8) COLLATE utf8_bin NOT NULL, `adslAtucCurrSnrMgn` decimal(5,1) NOT NULL, `adslAtucCurrAtn` decimal(5,1) NOT NULL, `adslAtucCurrOutputPwr` decimal(5,1) NOT NULL, `adslAtucCurrAttainableRate` int(11) NOT NULL, `adslAtucChanCurrTxRate` int(11) NOT NULL, `adslAturInvSerialNumber` varchar(8) COLLATE utf8_bin NOT NULL, `adslAturInvVendorID` varchar(8) COLLATE utf8_bin NOT NULL, `adslAturInvVersionNumber` varchar(8) COLLATE utf8_bin NOT NULL, `adslAturChanCurrTxRate` int(11) NOT NULL, `adslAturCurrSnrMgn` decimal(5,1) NOT NULL, `adslAturCurrAtn` decimal(5,1) NOT NULL, `adslAturCurrOutputPwr` decimal(5,1) NOT NULL, `adslAturCurrAttainableRate` int(11) NOT NULL, UNIQUE KEY `interface_id` (`interface_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; -CREATE TABLE IF NOT EXISTS `ports_perms` ( `user_id` int(11) NOT NULL, `interface_id` int(11) NOT NULL, `access_level` int(11) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE TABLE IF NOT EXISTS `ports_stack` ( `device_id` int(11) NOT NULL, `interface_id_high` int(11) NOT NULL, `interface_id_low` int(11) NOT NULL, `ifStackStatus` varchar(32) COLLATE utf8_unicode_ci NOT NULL, UNIQUE KEY `device_id` (`device_id`,`interface_id_high`,`interface_id_low`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; -CREATE TABLE IF NOT EXISTS `port_in_measurements` ( `port_id` int(11) NOT NULL, `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `counter` bigint(11) NOT NULL, `delta` bigint(11) NOT NULL, KEY `port_id` (`port_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE TABLE IF NOT EXISTS `port_out_measurements` ( `port_id` int(11) NOT NULL, `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `counter` bigint(11) NOT NULL, `delta` bigint(11) NOT NULL, KEY `port_id` (`port_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE TABLE IF NOT EXISTS `processors` ( `processor_id` int(11) NOT NULL AUTO_INCREMENT, `entPhysicalIndex` int(11) NOT NULL, `hrDeviceIndex` int(11) DEFAULT NULL, `device_id` int(11) NOT NULL, `processor_oid` varchar(128) CHARACTER SET latin1 NOT NULL, `processor_index` varchar(32) CHARACTER SET latin1 NOT NULL, `processor_type` varchar(16) CHARACTER SET latin1 NOT NULL, `processor_usage` int(11) NOT NULL, `processor_descr` varchar(64) CHARACTER SET latin1 NOT NULL, `processor_precision` int(11) NOT NULL DEFAULT '1', PRIMARY KEY (`processor_id`), KEY `device_id` (`device_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; -CREATE TABLE IF NOT EXISTS `pseudowires` ( `pseudowire_id` int(11) NOT NULL AUTO_INCREMENT, `interface_id` int(11) NOT NULL, `peer_device_id` int(11) NOT NULL, `peer_ldp_id` int(11) NOT NULL, `cpwVcID` int(11) NOT NULL, `cpwOid` int(11) NOT NULL, PRIMARY KEY (`pseudowire_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE TABLE IF NOT EXISTS `sensors` ( `sensor_id` int(11) NOT NULL AUTO_INCREMENT, `sensor_class` varchar(64) CHARACTER SET latin1 NOT NULL, `device_id` int(11) NOT NULL DEFAULT '0', `poller_type` varchar(16) COLLATE utf8_unicode_ci NOT NULL DEFAULT 'snmp', `sensor_oid` varchar(64) CHARACTER SET latin1 NOT NULL, `sensor_index` varchar(10) COLLATE utf8_unicode_ci NOT NULL, `sensor_type` varchar(255) CHARACTER SET latin1 NOT NULL, `sensor_descr` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, `sensor_divisor` int(11) NOT NULL DEFAULT '1', `sensor_multiplier` int(11) NOT NULL DEFAULT '1', `sensor_current` float DEFAULT NULL, `sensor_limit` float DEFAULT NULL, `sensor_limit_warn` float DEFAULT NULL, `sensor_limit_low` float DEFAULT NULL, `sensor_limit_low_warn` float DEFAULT NULL, `entPhysicalIndex` varchar(16) CHARACTER SET latin1 DEFAULT NULL, `entPhysicalIndex_measured` varchar(16) CHARACTER SET latin1 DEFAULT NULL, PRIMARY KEY (`sensor_id`), KEY `sensor_host` (`device_id`), KEY `sensor_class` (`sensor_class`), KEY `sensor_type` (`sensor_type`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; -CREATE TABLE IF NOT EXISTS `services` ( `service_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `service_ip` text NOT NULL, `service_type` varchar(16) NOT NULL, `service_desc` text NOT NULL, `service_param` text NOT NULL, `service_ignore` tinyint(1) NOT NULL, `service_status` tinyint(4) NOT NULL DEFAULT '0', `service_checked` int(11) NOT NULL DEFAULT '0', `service_changed` int(11) NOT NULL DEFAULT '0', `service_message` text NOT NULL, `service_disabled` tinyint(1) NOT NULL DEFAULT '0', PRIMARY KEY (`service_id`), KEY `service_host` (`device_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE TABLE IF NOT EXISTS `storage` ( `storage_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `storage_mib` varchar(16) NOT NULL, `storage_index` int(11) NOT NULL, `storage_type` varchar(32) DEFAULT NULL, `storage_descr` text NOT NULL, `storage_size` bigint(20) NOT NULL, `storage_units` int(11) NOT NULL, `storage_used` bigint(20) NOT NULL, `storage_free` bigint(20) NOT NULL, `storage_perc` text NOT NULL, `storage_perc_warn` int(11) DEFAULT '60', PRIMARY KEY (`storage_id`), KEY `device_id` (`device_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE TABLE IF NOT EXISTS `syslog` ( `device_id` int(11) DEFAULT NULL, `facility` varchar(10) DEFAULT NULL, `priority` varchar(10) DEFAULT NULL, `level` varchar(10) DEFAULT NULL, `tag` varchar(10) DEFAULT NULL, `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `program` varchar(32) DEFAULT NULL, `msg` text, `seq` bigint(20) unsigned NOT NULL AUTO_INCREMENT, PRIMARY KEY (`seq`), KEY `datetime` (`timestamp`), KEY `device_id` (`device_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE TABLE IF NOT EXISTS `toner` ( `toner_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL DEFAULT '0', `toner_index` int(11) NOT NULL, `toner_type` varchar(64) NOT NULL, `toner_oid` varchar(64) NOT NULL, `toner_descr` varchar(32) NOT NULL DEFAULT '', `toner_capacity` int(11) NOT NULL DEFAULT '0', `toner_current` int(11) NOT NULL DEFAULT '0', PRIMARY KEY (`toner_id`), KEY `device_id` (`device_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE TABLE IF NOT EXISTS `ucd_diskio` ( `diskio_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `diskio_index` int(11) NOT NULL, `diskio_descr` varchar(32) CHARACTER SET latin1 NOT NULL, PRIMARY KEY (`diskio_id`), KEY `device_id` (`device_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; -CREATE TABLE IF NOT EXISTS `users` ( `user_id` int(11) NOT NULL AUTO_INCREMENT, `username` char(30) NOT NULL, `password` varchar(34) DEFAULT NULL, `realname` varchar(64) NOT NULL, `email` varchar(64) NOT NULL, `descr` char(30) NOT NULL, `level` tinyint(4) NOT NULL DEFAULT '0', `can_modify_passwd` tinyint(4) NOT NULL DEFAULT '1', PRIMARY KEY (`user_id`), UNIQUE KEY `username` (`username`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE TABLE IF NOT EXISTS `users_prefs` ( `user_id` int(16) NOT NULL, `pref` varchar(32) NOT NULL, `value` varchar(128) NOT NULL, PRIMARY KEY (`user_id`), UNIQUE KEY `user_id.pref` (`user_id`,`pref`), KEY `pref` (`pref`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE TABLE IF NOT EXISTS `vlans` ( `vlan_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) DEFAULT NULL, `vlan_vlan` int(11) DEFAULT NULL, `vlan_domain` text, `vlan_descr` text, PRIMARY KEY (`vlan_id`), KEY `device_id` (`device_id`,`vlan_vlan`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE TABLE IF NOT EXISTS `vminfo` ( `id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `vm_type` varchar(16) NOT NULL DEFAULT 'vmware', `vmwVmVMID` int(11) NOT NULL, `vmwVmDisplayName` varchar(128) NOT NULL, `vmwVmGuestOS` varchar(128) NOT NULL, `vmwVmMemSize` int(11) NOT NULL, `vmwVmCpus` int(11) NOT NULL, `vmwVmState` varchar(128) NOT NULL, PRIMARY KEY (`id`), KEY `device_id` (`device_id`), KEY `vmwVmVMID` (`vmwVmVMID`)) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE TABLE IF NOT EXISTS `vmware_vminfo` ( `id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `vmwVmVMID` int(11) NOT NULL, `vmwVmDisplayName` varchar(128) NOT NULL, `vmwVmGuestOS` varchar(128) NOT NULL, `vmwVmMemSize` int(11) NOT NULL, `vmwVmCpus` int(11) NOT NULL, `vmwVmState` varchar(128) NOT NULL, PRIMARY KEY (`id`), KEY `device_id` (`device_id`), KEY `vmwVmVMID` (`vmwVmVMID`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE TABLE IF NOT EXISTS `vrfs` ( `vrf_id` int(11) NOT NULL AUTO_INCREMENT, `vrf_oid` varchar(256) NOT NULL, `vrf_name` varchar(128) DEFAULT NULL, `mplsVpnVrfRouteDistinguisher` varchar(128) DEFAULT NULL, `mplsVpnVrfDescription` text NOT NULL, `device_id` int(11) NOT NULL, PRIMARY KEY (`vrf_id`), KEY `device_id` (`device_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE TABLE IF NOT EXISTS `bill_history` ( `bill_hist_id` int(11) NOT NULL AUTO_INCREMENT, `bill_id` int(11) NOT NULL, `updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `bill_datefrom` datetime NOT NULL, `bill_dateto` datetime NOT NULL, `bill_type` text NOT NULL, `bill_allowed` bigint(20) NOT NULL, `bill_used` bigint(20) NOT NULL, `bill_overuse` bigint(20) NOT NULL, `bill_percent` decimal(10,2) NOT NULL, `rate_95th_in` bigint(20) NOT NULL, `rate_95th_out` bigint(20) NOT NULL, `rate_95th` bigint(20) NOT NULL, `dir_95th` varchar(3) NOT NULL, `rate_average` bigint(20) NOT NULL, `rate_average_in` bigint(20) NOT NULL, `rate_average_out` bigint(20) NOT NULL, `traf_in` bigint(20) NOT NULL, `traf_out` bigint(20) NOT NULL, `traf_total` bigint(20) NOT NULL, `pdf` longblob, PRIMARY KEY (`bill_hist_id`), UNIQUE KEY `unique_index` (`bill_id`,`bill_datefrom`,`bill_dateto`), KEY `bill_id` (`bill_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ; -CREATE TABLE IF NOT EXISTS `entPhysical_state` ( `device_id` int(11) NOT NULL, `entPhysicalIndex` varchar(64) NOT NULL, `subindex` varchar(64) DEFAULT NULL, `group` varchar(64) NOT NULL, `key` varchar(64) NOT NULL, `value` varchar(255) NOT NULL, KEY `device_id_index` (`device_id`,`entPhysicalIndex`)) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE TABLE IF NOT EXISTS `ports_vlans` ( `port_vlan_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `interface_id` int(11) NOT NULL, `vlan` int(11) NOT NULL, `baseport` int(11) NOT NULL, `priority` bigint(32) NOT NULL, `state` varchar(16) NOT NULL, `cost` int(11) NOT NULL, PRIMARY KEY (`port_vlan_id`), UNIQUE KEY `unique` (`device_id`,`interface_id`,`vlan`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ; -CREATE TABLE IF NOT EXISTS `netscaler_vservers` ( `vsvr_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `vsvr_name` varchar(128) COLLATE utf8_unicode_ci NOT NULL, `vsvr_ip` varchar(128) COLLATE utf8_unicode_ci NOT NULL, `vsvr_port` int(8) NOT NULL, `vsvr_type` varchar(64) COLLATE utf8_unicode_ci NOT NULL, `vsvr_state` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `vsvr_clients` int(11) NOT NULL, `vsvr_server` int(11) NOT NULL, `vsvr_req_rate` int(11) NOT NULL, `vsvr_bps_in` int(11) NOT NULL, `vsvr_bps_out` int(11) NOT NULL, PRIMARY KEY (`vsvr_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -ALTER TABLE `mac_accounting` ADD `cipMacHCSwitchedBytes_input` bigint(20) default NULL; -ALTER TABLE `mac_accounting` ADD `cipMacHCSwitchedBytes_input_prev` bigint(20) default NULL; -ALTER TABLE `mac_accounting` ADD `cipMacHCSwitchedBytes_input_delta` bigint(20) default NULL; -ALTER TABLE `mac_accounting` ADD `cipMacHCSwitchedBytes_input_rate` int(11) default NULL; -ALTER TABLE `mac_accounting` ADD `cipMacHCSwitchedBytes_output` bigint(20) default NULL; -ALTER TABLE `mac_accounting` ADD `cipMacHCSwitchedBytes_output_prev` bigint(20) default NULL; -ALTER TABLE `mac_accounting` ADD `cipMacHCSwitchedBytes_output_delta` bigint(20) default NULL; -ALTER TABLE `mac_accounting` ADD `cipMacHCSwitchedBytes_output_rate` int(11) default NULL; -ALTER TABLE `mac_accounting` ADD `cipMacHCSwitchedPkts_input` bigint(20) default NULL; -ALTER TABLE `mac_accounting` ADD `cipMacHCSwitchedPkts_input_prev` bigint(20) default NULL; -ALTER TABLE `mac_accounting` ADD `cipMacHCSwitchedPkts_input_delta` bigint(20) default NULL; -ALTER TABLE `mac_accounting` ADD `cipMacHCSwitchedPkts_input_rate` int(11) default NULL; -ALTER TABLE `mac_accounting` ADD `cipMacHCSwitchedPkts_output` bigint(20) default NULL; -ALTER TABLE `mac_accounting` ADD `cipMacHCSwitchedPkts_output_prev` bigint(20) default NULL; -ALTER TABLE `mac_accounting` ADD `cipMacHCSwitchedPkts_output_delta` bigint(20) default NULL; -ALTER TABLE `mac_accounting` ADD `cipMacHCSwitchedPkts_output_rate` int(11) default NULL; -ALTER TABLE `mac_accounting` ADD `poll_time` int(11) default NULL; -ALTER TABLE `mac_accounting` ADD `poll_prev` int(11) default NULL; -ALTER TABLE `mac_accounting` ADD `poll_period` int(11) default NULL; -ALTER TABLE `interfaces` ADD `ifInUcastPkts` bigint(20) default NULL; -ALTER TABLE `interfaces` ADD `ifInUcastPkts_prev` bigint(20) default NULL; -ALTER TABLE `interfaces` ADD `ifInUcastPkts_delta` bigint(20) default NULL; -ALTER TABLE `interfaces` ADD `ifInUcastPkts_rate` int(11) default NULL; -ALTER TABLE `interfaces` ADD `ifOutUcastPkts` bigint(20) default NULL; -ALTER TABLE `interfaces` ADD `ifOutUcastPkts_prev` bigint(20) default NULL; -ALTER TABLE `interfaces` ADD `ifOutUcastPkts_delta` bigint(20) default NULL; -ALTER TABLE `interfaces` ADD `ifOutUcastPkts_rate` int(11) default NULL; -ALTER TABLE `interfaces` ADD `ifInErrors` bigint(20) default NULL; -ALTER TABLE `interfaces` ADD `ifInErrors_prev` bigint(20) default NULL; -ALTER TABLE `interfaces` ADD `ifInErrors_delta` bigint(20) default NULL; -ALTER TABLE `interfaces` ADD `ifInErrors_rate` int(11) default NULL; -ALTER TABLE `interfaces` ADD `ifOutErrors` bigint(20) default NULL; -ALTER TABLE `interfaces` ADD `ifOutErrors_prev` bigint(20) default NULL; -ALTER TABLE `interfaces` ADD `ifOutErrors_delta` bigint(20) default NULL; -ALTER TABLE `interfaces` ADD `ifOutErrors_rate` int(11) default NULL; -ALTER TABLE `interfaces` ADD `ifInOctets` bigint(20) default NULL; -ALTER TABLE `interfaces` ADD `ifInOctets_prev` bigint(20) default NULL; -ALTER TABLE `interfaces` ADD `ifInOctets_delta` bigint(20) default NULL; -ALTER TABLE `interfaces` ADD `ifInOctets_rate` int(11) default NULL; -ALTER TABLE `interfaces` ADD `ifOutOctets` bigint(20) default NULL; -ALTER TABLE `interfaces` ADD `ifOutOctets_prev` bigint(20) default NULL; -ALTER TABLE `interfaces` ADD `ifOutOctets_delta` bigint(20) default NULL; -ALTER TABLE `interfaces` ADD `ifOutOctets_rate` int(11) default NULL; -ALTER TABLE `interfaces` ADD `poll_time` int(11) default NULL; -ALTER TABLE `interfaces` ADD `poll_prev` int(11) default NULL; -ALTER TABLE `interfaces` ADD `poll_period` int(11) default NULL; -ALTER TABLE `interfaces` ADD `pagpOperationMode` VARCHAR( 32 ) NULL ; -ALTER TABLE `interfaces` ADD `pagpPortState` VARCHAR( 16 ) NULL ; -ALTER TABLE `interfaces` ADD `pagpPartnerDeviceId` VARCHAR( 48 ) NULL ; -ALTER TABLE `interfaces` ADD `pagpPartnerLearnMethod` VARCHAR( 16 ) NULL ; -ALTER TABLE `interfaces` ADD `pagpPartnerIfIndex` INT NULL ; -ALTER TABLE `interfaces` ADD `pagpPartnerGroupIfIndex` INT NULL ; -ALTER TABLE `interfaces` ADD `pagpPartnerDeviceName` VARCHAR( 128 ) NULL ; -ALTER TABLE `interfaces` ADD `pagpEthcOperationMode` VARCHAR( 16 ) NULL ; -ALTER TABLE `interfaces` ADD `pagpDeviceId` VARCHAR( 48 ) NULL ; -ALTER TABLE `interfaces` ADD `pagpGroupIfIndex` INT NULL ; -ALTER TABLE `interfaces` ADD `ifPromiscuousMode` VARCHAR( 12 ) NULL DEFAULT NULL AFTER `ifSpeed`; -ALTER TABLE `interfaces` ADD `ifConnectorPresent` VARCHAR( 12 ) NULL DEFAULT NULL AFTER `ifSpeed`; -ALTER TABLE `interfaces` ADD `ifName` VARCHAR( 64 ) NULL DEFAULT NULL AFTER `ifDescr`; -ALTER TABLE `interfaces` ADD `portName` VARCHAR( 128 ) NULL DEFAULT NULL AFTER `ifName`; -ALTER TABLE `interfaces` ADD `ifHighSpeed` BIGINT ( 20 ) NULL DEFAULT NULL AFTER `ifSpeed`; -ALTER TABLE `interfaces` DROP `in_rate`; -ALTER TABLE `interfaces` DROP `out_rate`; -ALTER TABLE `interfaces` DROP `in_errors`; -ALTER TABLE `interfaces` DROP `out_errors`; -CREATE TABLE IF NOT EXISTS `cmpMemPool` ( `cmp_id` int(11) NOT NULL auto_increment, `Index` varchar(8) NOT NULL, `cmpName` varchar(32) NOT NULL, `cmpValid` varchar(8) NOT NULL, `device_id` int(11) NOT NULL, `cmpUsed` int(11) NOT NULL, `cmpFree` int(11) NOT NULL, `cmpLargestFree` int(11) NOT NULL, `cmpAlternate` tinyint(4) default NULL, PRIMARY KEY (`cmp_id`), KEY `device_id` (`device_id`)) ENGINE=MyISAM DEFAULT CHARSET=latin1; -CREATE TABLE IF NOT EXISTS `hrDevice` ( `hrDevice_id` int(11) NOT NULL auto_increment, `device_id` int(11) NOT NULL, `hrDeviceIndex` int(11) NOT NULL, `hrDeviceDescr` text NOT NULL, `hrDeviceType` text NOT NULL, `hrDeviceErrors` int(11) NOT NULL, `hrDeviceStatus` text NOT NULL, `hrProcessorLoad` tinyint(4) default NULL, PRIMARY KEY (`hrDevice_id`), KEY `device_id` (`device_id`)) ENGINE=MyISAM DEFAULT CHARSET=latin1; -ALTER TABLE `entPhysical` ADD `entPhysicalHardwareRev` VARCHAR( 16 ) NULL AFTER `entPhysicalName` ,ADD `entPhysicalFirmwareRev` VARCHAR( 16 ) NULL AFTER `entPhysicalHardwareRev` ,ADD `entPhysicalSoftwareRev` VARCHAR( 16 ) NULL AFTER `entPhysicalFirmwareRev` ,ADD `entPhysicalAlias` VARCHAR( 32 ) NULL AFTER `entPhysicalSoftwareRev` ,ADD `entPhysicalAssetID` VARCHAR( 32 ) NULL AFTER `entPhysicalAlias` ,ADD `entPhysicalIsFRU` VARCHAR( 8 ) NULL AFTER `entPhysicalAssetID`; -ALTER TABLE `devices` ADD `last_discovered` timestamp NULL DEFAULT NULL AFTER `last_polled`; -ALTER TABLE `devices` CHANGE `lastchange` `uptime` BIGINT NULL DEFAULT NULL; -ALTER TABLE `storage` ADD `hrStorageType` VARCHAR( 32 ) NULL DEFAULT NULL AFTER `hrStorageIndex`; -ALTER TABLE `devices` MODIFY `type` varchar(8) DEFAULT 'unknown'; -ALTER TABLE `devices` CHANGE `os` `os` VARCHAR( 32 ) NULL DEFAULT NULL; -ALTER TABLE `temperature` ADD `temp_precision` INT(11) NULL DEFAULT '1'; -UPDATE temperature SET temp_precision=10 WHERE temp_tenths=1; -ALTER TABLE `temperature` ADD `temp_index` INT NOT NULL AFTER `temp_host` , ADD `temp_mibtype` VARCHAR( 32 ) NOT NULL AFTER `temp_index`; -ALTER TABLE `temperature` DROP `temp_tenths`; -CREATE TABLE IF NOT EXISTS `dbSchema` ( `revision` int(11) NOT NULL default '0', PRIMARY KEY (`revision`)) ENGINE=MyISAM DEFAULT CHARSET=latin1; -ALTER TABLE `storage` ADD `storage_perc_warn` INT(11) NULL DEFAULT '60'; -CREATE TABLE IF NOT EXISTS `voltage` ( `volt_id` int(11) NOT NULL auto_increment, `volt_host` int(11) NOT NULL default '0', `volt_oid` varchar(64) NOT NULL, `volt_descr` varchar(32) NOT NULL default '', `volt_precision` int(11) NOT NULL default '1', `volt_current` int(11) NOT NULL default '0', `volt_limit` int(11) NOT NULL default '60', PRIMARY KEY (`volt_id`), KEY `volt_host` (`volt_host`)) ENGINE=InnoDB DEFAULT CHARSET=latin1; -CREATE TABLE IF NOT EXISTS `fanspeed` ( `fan_id` int(11) NOT NULL auto_increment, `fan_host` int(11) NOT NULL default '0', `fan_oid` varchar(64) NOT NULL, `fan_descr` varchar(32) NOT NULL default '', `fan_precision` int(11) NOT NULL default '1', `fan_current` int(11) NOT NULL default '0', `fan_limit` int(11) NOT NULL default '60', PRIMARY KEY (`fan_id`), KEY `fan_host` (`fan_host`)) ENGINE=InnoDB DEFAULT CHARSET=latin1; -ALTER TABLE `voltage` ADD `volt_limit_low` int(11) NULL DEFAULT NULL AFTER `volt_limit`; -ALTER TABLE `voltage` CHANGE `volt_current` `volt_current` FLOAT(3) NULL DEFAULT NULL; -ALTER TABLE `voltage` CHANGE `volt_limit` `volt_limit` FLOAT(3) NULL DEFAULT NULL; -ALTER TABLE `voltage` CHANGE `volt_limit_low` `volt_limit_low` FLOAT(3) NULL DEFAULT NULL; -ALTER TABLE `fanspeed` ADD `fan_index` INT NOT NULL AFTER `fan_host` , ADD `fan_mibtype` VARCHAR( 32 ) NOT NULL AFTER `fan_index`; -ALTER TABLE `temperature` CHANGE `temp_host` `device_id` INT( 11 ) NOT NULL DEFAULT '0'; -ALTER TABLE `fanspeed` CHANGE `fan_host` `device_id` INT( 11 ) NOT NULL DEFAULT '0'; -ALTER TABLE `voltage` CHANGE `volt_host` `device_id` INT( 11 ) NOT NULL DEFAULT '0'; -CREATE TABLE IF NOT EXISTS `processors` ( `processor_id` int(11) NOT NULL AUTO_INCREMENT, `entPhysicalIndex` int(11) NOT NULL, `device_id` int(11) NOT NULL, `processor_oid` int(11) NOT NULL, `processor_type` int(11) NOT NULL, `processor_usage` int(11) NOT NULL, `processor_description` varchar(64) NOT NULL, PRIMARY KEY (`processor_id`), KEY `cpuCPU_id` (`processor_id`,`device_id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ; -ALTER TABLE `processors` ADD `hrDeviceIndex` int(11) NULL AFTER `entPhysicalIndex`; -ALTER TABLE `temperature` CHANGE `temp_current` `temp_current` FLOAT( 4 ) NOT NULL DEFAULT '0'; -ALTER TABLE `processors` ADD `processor_index` varchar(32) NOT NULL AFTER `processor_oid`; -ALTER TABLE `processors` CHANGE `processor_description` `processor_descr` varchar(64) NOT NULL; -ALTER TABLE `fanspeed` CHANGE `fan_mibtype` `fan_type` varchar(64) NOT NULL ; -ALTER TABLE `voltage` ADD `volt_index` VARCHAR( 8 ) NOT NULL AFTER `volt_oid`,ADD `volt_type` VARCHAR( 32 ) NOT NULL AFTER `volt_index` ; -ALTER TABLE `processors` ADD `processor_precision` INT( 11 ) NOT NULL DEFAULT '1'; -ALTER TABLE `links` CHANGE `cdp` `vendor` VARCHAR( 11 ) NULL DEFAULT NULL; -ALTER TABLE `links` ADD `remote_hostname` VARCHAR( 128 ) NOT NULL ,ADD `remote_port` VARCHAR( 128 ) NOT NULL ,ADD `remote_platform` VARCHAR( 128 ) NOT NULL ,ADD `remote_version` VARCHAR( 256 ) NOT NULL ; -ALTER TABLE `links` CHANGE `src_if` `local_interface_id` INT( 11 ) NULL DEFAULT NULL ,CHANGE `dst_if` `remote_interface_id` INT( 11 ) NULL DEFAULT NULL ; -ALTER TABLE `links` CHANGE `vendor` `protocol` VARCHAR( 11 ) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL; -ALTER TABLE `processors` CHANGE `processor_type` `processor_type` varchar(16) NOT NULL; -ALTER TABLE `bgpPeers_cbgp` CHANGE `afi` `afi` VARCHAR( 16 ) NOT NULL , CHANGE `safi` `safi` VARCHAR( 16 ) NOT NULL; -ALTER TABLE `eventlog` ADD `reference` VARCHAR( 64 ) NOT NULL AFTER `type`; -ALTER TABLE `syslog` CHANGE `datetime` `timestamp` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP; -ALTER TABLE `syslog` DROP `host`, DROP `processed`; -RENAME TABLE `interfaces` TO `ports` ; -RENAME TABLE `interfaces_perms` TO `ports_perms` ; -ALTER TABLE `temperature` CHANGE `temp_index` `temp_index` VARCHAR( 32 ) NOT NULL AFTER `device_id` , ADD `temp_type` VARCHAR( 16 ) NOT NULL AFTER `temp_index`; -ALTER TABLE `processors` CHANGE `processor_oid` `processor_oid` VARCHAR( 128 ) NOT NULL; -ALTER TABLE eventlog CHANGE `type` `type` VARCHAR( 64 ) NOT NULL; -ALTER TABLE `services` CHANGE `service_host` `device_id` INT( 11 ) NOT NULL; -CREATE TABLE IF NOT EXISTS `mempools` ( `mempool_id` int(11) NOT NULL AUTO_INCREMENT, `mempool_index` varchar(8) CHARACTER SET latin1 NOT NULL, `entPhysicalIndex` int(11) DEFAULT NULL, `hrDeviceIndex` int(11) DEFAULT NULL, `mempool_type` varchar(32) CHARACTER SET latin1 NOT NULL, `mempool_precision` int(11) NOT NULL DEFAULT '1', `mempool_descr` varchar(32) CHARACTER SET latin1 NOT NULL, `device_id` int(11) NOT NULL, `mempool_used` int(11) NOT NULL, `mempool_free` int(11) NOT NULL, `mempool_total` int(11) NOT NULL, `mempool_largestfree` int(11) DEFAULT NULL, `mempool_lowestfree` int(11) DEFAULT NULL, PRIMARY KEY (`mempool_id`), KEY `device_id` (`device_id`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin ; -ALTER TABLE `storage` CHANGE `storage_id` `storage_id` INT( 11 ) NOT NULL AUTO_INCREMENT , CHANGE `host_id` `device_id` INT( 11 ) NOT NULL , CHANGE `hrStorageIndex` `storage_index` INT( 11 ) NOT NULL , CHANGE `hrStorageType` `storage_type` VARCHAR( 32 ) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL , CHANGE `hrStorageDescr` `storage_descr` TEXT CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL , CHANGE `hrStorageSize` `storage_size` INT( 11 ) NOT NULL , CHANGE `hrStorageAllocationUnits` `storage_units` INT( 11 ) NOT NULL , CHANGE `hrStorageUsed` `storage_used` INT( 11 ) NOT NULL , CHANGE `storage_perc` `storage_perc` TEXT CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL; -ALTER TABLE `storage` ADD `storage_mib` VARCHAR( 16 ) NOT NULL AFTER `device_id`; -ALTER TABLE `storage` ADD `storage_free` INT NOT NULL AFTER `storage_used`; -ALTER TABLE `storage` CHANGE `storage_size` `storage_size` BIGINT NOT NULL ,CHANGE `storage_used` `storage_used` BIGINT NOT NULL ,CHANGE `storage_free` `storage_free` BIGINT NOT NULL; -ALTER TABLE `mempools` CHANGE `mempool_used` `mempool_used` BIGINT( 20 ) NOT NULL , -CHANGE `mempool_free` `mempool_free` BIGINT( 20 ) NOT NULL ,CHANGE `mempool_total` `mempool_total` BIGINT( 20 ) NOT NULL ,CHANGE `mempool_largestfree` `mempool_largestfree` BIGINT( 20 ) NULL DEFAULT NULL ,CHANGE `mempool_lowestfree` `mempool_lowestfree` BIGINT( 20 ) NULL DEFAULT NULL; -CREATE TABLE IF NOT EXISTS `juniAtmVp` ( `juniAtmVp_id` int(11) NOT NULL AUTO_INCREMENT, `interface_id` int(11) NOT NULL, `vp_id` int(11) NOT NULL, `vp_descr` varchar(32) NOT NULL, PRIMARY KEY (`juniAtmVp_id`)) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ; -CREATE TABLE IF NOT EXISTS `toner` ( `toner_id` int(11) NOT NULL auto_increment, `device_id` int(11) NOT NULL default '0', `toner_index` int(11) NOT NULL, `toner_type` varchar(64) NOT NULL, `toner_oid` varchar(64) NOT NULL, `toner_descr` varchar(32) NOT NULL default '', `toner_capacity` int(11) NOT NULL default '0', `toner_current` int(11) NOT NULL default '0', PRIMARY KEY (`toner_id`), KEY `device_id` (`device_id`)) ENGINE=InnoDB DEFAULT CHARSET=latin1; -ALTER TABLE `mempools` CHANGE `mempool_descr` `mempool_descr` VARCHAR( 64 ) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL; -ALTER TABLE `processors` CHANGE `processor_descr` `processor_descr` VARCHAR( 64 ) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL; -DROP TABLE `cempMemPool`; -DROP TABLE `cpmCPU`; -DROP TABLE `cmpMemPool`; -ALTER TABLE `mempools` CHANGE `mempool_used` `mempool_used` BIGINT( 16 ) NOT NULL ,CHANGE `mempool_free` `mempool_free` BIGINT( 16 ) NOT NULL ,CHANGE `mempool_total` `mempool_total` BIGINT( 16 ) NOT NULL ,CHANGE `mempool_largestfree` `mempool_largestfree` BIGINT( 16 ) NULL DEFAULT NULL ,CHANGE `mempool_lowestfree` `mempool_lowestfree` BIGINT( 16 ) NULL DEFAULT NULL ; -ALTER TABLE `ports` ADD `port_descr_type` VARCHAR( 32 ) NULL DEFAULT NULL AFTER `device_id` ,ADD `port_descr_descr` VARCHAR( 64 ) NULL DEFAULT NULL AFTER `port_descr_type` ,ADD `port_descr_circuit` VARCHAR( 64 ) NULL DEFAULT NULL AFTER `port_descr_descr` ,ADD `port_descr_speed` VARCHAR( 32 ) NULL DEFAULT NULL AFTER `port_descr_circuit` ,ADD `port_descr_notes` VARCHAR( 128 ) NULL DEFAULT NULL AFTER `port_descr_speed`; -CREATE TABLE IF NOT EXISTS `frequency` ( `freq_id` int(11) NOT NULL auto_increment, `device_id` int(11) NOT NULL default '0', `freq_oid` varchar(64) NOT NULL, `freq_index` varchar(8) NOT NULL, `freq_type` varchar(32) NOT NULL, `freq_descr` varchar(32) NOT NULL default '', `freq_precision` int(11) NOT NULL default '1', `freq_current` float default NULL, `freq_limit` float default NULL, `freq_limit_low` float default NULL, PRIMARY KEY (`freq_id`), KEY `freq_host` (`device_id`)) ENGINE=MyISAM AUTO_INCREMENT=189 DEFAULT CHARSET=latin1; -ALTER TABLE `temperature` CHANGE `temp_index` `temp_index` int(11) NOT NULL; -CREATE TABLE IF NOT EXISTS `current` ( `current_id` int(11) NOT NULL auto_increment, `device_id` int(11) NOT NULL default '0', `current_oid` varchar(64) NOT NULL, `current_index` varchar(8) NOT NULL, `current_type` varchar(32) NOT NULL, `current_descr` varchar(32) NOT NULL default '', `current_precision` int(11) NOT NULL default '1', `current_current` float default NULL, `current_limit` float default NULL, `current_limit_warn` float default NULL, `current_limit_low` float default NULL, PRIMARY KEY (`current_id`), KEY `current_host` (`device_id`)) ENGINE=MyISAM AUTO_INCREMENT=189 DEFAULT CHARSET=latin1; -ALTER TABLE `devices` ADD `serial` text default NULL; -ALTER TABLE `temperature` CHANGE `temp_index` `temp_index` VARCHAR(32) NOT NULL; -ALTER TABLE `ports` CHANGE `ifDescr` `ifDescr` VARCHAR(255) NOT NULL; -CREATE TABLE IF NOT EXISTS `ucd_diskio` ( `diskio_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `diskio_index` int(11) NOT NULL, `diskio_descr` varchar(32) NOT NULL, PRIMARY KEY (`diskio_id`)) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=11 ; -ALTER TABLE `eventlog` CHANGE `type` `type` VARCHAR( 64 ) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL; -ALTER TABLE `bills` ADD `bill_custid` VARCHAR( 64 ) NOT NULL ,ADD `bill_ref` VARCHAR( 64 ) NOT NULL ,ADD `bill_notes` VARCHAR( 256 ) NOT NULL; -CREATE TABLE IF NOT EXISTS `applications` ( `app_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `app_type` varchar(64) NOT NULL, PRIMARY KEY (`app_id`)) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ; -CREATE TABLE IF NOT EXISTS `sensors` ( `sensor_id` int(11) NOT NULL auto_increment, `sensor_class` varchar(64) NOT NULL, `device_id` int(11) NOT NULL default '0', `sensor_oid` varchar(64) NOT NULL, `sensor_index` varchar(8) NOT NULL, `sensor_type` varchar(32) NOT NULL, `sensor_descr` varchar(32) NOT NULL default '', `sensor_precision` int(11) NOT NULL default '1', `sensor_current` float default NULL, `sensor_limit` float default NULL, `sensor_limit_warn` float default NULL, `sensor_limit_low` float default NULL, `sensor_limit_low_warn` float default NULL, PRIMARY KEY (`sensor_id`), KEY `sensor_host` (`device_id`)) ENGINE=MyISAM AUTO_INCREMENT=189 DEFAULT CHARSET=latin1; -ALTER TABLE `devices` CHANGE `type` `type` VARCHAR(20) NOT NULL; -ALTER TABLE `voltage` CHANGE `volt_index` `volt_index` VARCHAR(10) NOT NULL; -ALTER TABLE `frequency` CHANGE `freq_index` `freq_index` VARCHAR(10) NOT NULL; -ALTER TABLE `sensors` CHANGE `sensor_index` `sensor_index` VARCHAR(10) NOT NULL; -DROP TABLE `fanspeed`; -DROP TABLE `temperature`; -DROP TABLE `voltage`; -DROP TABLE `current`; -ALTER TABLE `sensors` ADD `entPhysicalIndex` VARCHAR( 16 ) NULL; -ALTER TABLE `sensors` ADD `entPhysicalIndex_measured` VARCHAR(16) NULL; -ALTER TABLE `processors` DROP INDEX `cpuCPU_id`; -ALTER TABLE `processors` ADD INDEX ( `device_id` ); -ALTER TABLE `ucd_diskio` ADD INDEX ( `device_id` ); -ALTER TABLE `storage` ADD INDEX ( `device_id` ); -ALTER TABLE `mac_accounting` ADD INDEX ( `interface_id` ); -ALTER TABLE `ipv4_addresses` ADD INDEX ( `interface_id` ); -ALTER TABLE `ipv6_addresses` ADD INDEX ( `interface_id` ); -ALTER TABLE `ipv4_mac` ADD INDEX ( `interface_id` ); -CREATE TABLE IF NOT EXISTS `ports_adsl` ( `interface_id` int(11) NOT NULL, `port_adsl_updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `adslLineCoding` varchar(8) COLLATE utf8_bin NOT NULL, `adslLineType` varchar(16) COLLATE utf8_bin NOT NULL, `adslAtucInvVendorID` varchar(8) COLLATE utf8_bin NOT NULL, `adslAtucInvVersionNumber` varchar(8) COLLATE utf8_bin NOT NULL, `adslAtucCurrSnrMgn` decimal(5,1) NOT NULL, `adslAtucCurrAtn` decimal(5,1) NOT NULL, `adslAtucCurrOutputPwr` decimal(5,1) NOT NULL, `adslAtucCurrAttainableRate` int(11) NOT NULL, `adslAtucChanCurrTxRate` int(11) NOT NULL, `adslAturInvSerialNumber` varchar(8) COLLATE utf8_bin NOT NULL, `adslAturInvVendorID` varchar(8) COLLATE utf8_bin NOT NULL, `adslAturInvVersionNumber` varchar(8) COLLATE utf8_bin NOT NULL, `adslAturChanCurrTxRate` int(11) NOT NULL, `adslAturCurrSnrMgn` decimal(5,1) NOT NULL, `adslAturCurrAtn` decimal(5,1) NOT NULL, `adslAturCurrOutputPwr` decimal(5,1) NOT NULL, `adslAturCurrAttainableRate` int(11) NOT NULL, UNIQUE KEY `interface_id` (`interface_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; -ALTER TABLE `devices` ADD `last_polled_timetaken` DOUBLE( 5, 2 ) NOT NULL AFTER `last_polled` , ADD `last_discovered_timetaken` DOUBLE( 5, 2 ) NOT NULL AFTER `last_polled_timetaken`; -CREATE TABLE IF NOT EXISTS `perf_times` ( `type` varchar(8) NOT NULL, `doing` varchar(64) NOT NULL, `start` int(11) NOT NULL, `duration` double(5,2) NOT NULL, `devices` int(11) NOT NULL, KEY `type` (`type`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; -ALTER TABLE `bills` ADD `bill_autoadded` BOOLEAN NOT NULL DEFAULT '0'; -ALTER TABLE `bill_ports` ADD `bill_port_autoadded` BOOLEAN NOT NULL DEFAULT '0'; -ALTER TABLE `sensors` CHANGE `sensor_precision` `sensor_divisor` INT( 11 ) NOT NULL DEFAULT '1' -ALTER TABLE `sensors` ADD `sensor_multiplier` INT( 11 ) NOT NULL AFTER `sensor_divisor`; -CREATE TABLE IF NOT EXISTS `device_graphs` ( `device_id` int(11) NOT NULL, `graph` varchar(32) COLLATE utf8_unicode_ci NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; -DROP TABLE IF EXISTS `graph_types`; -CREATE TABLE IF NOT EXISTS `graph_types` ( `graph_type` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `graph_subtype` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `graph_section` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `graph_descr` varchar(64) COLLATE utf8_unicode_ci NOT NULL, `graph_order` int(11) NOT NULL, KEY `graph_type` (`graph_type`), KEY `graph_subtype` (`graph_subtype`), KEY `graph_section` (`graph_section`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; -INSERT INTO `graph_types` (`graph_type`, `graph_subtype`, `graph_section`, `graph_descr`, `graph_order`) VALUES('device', 'bits', 'netstats', 'Total Traffic', 0),('device', 'hr_users', 'system', 'Users Logged In', 0),('device', 'ucd_load', 'system', 'Load Averages', 0),('device', 'ucd_cpu', 'system', 'Detailed Processor Usage', 0),('device', 'ucd_memory', 'system', 'Detailed Memory Usage', 0),('device', 'netstat_tcp', 'netstats', 'TCP Statistics', 0),('device', 'netstat_icmp_info', 'netstats', 'ICMP Informational Statistics', 0),('device', 'netstat_icmp_stat', 'netstats', 'ICMP Statistics', 0),('device', 'netstat_ip', 'netstats', 'IP Statistics', 0),('device', 'netstat_ip_frag', 'netstats', 'IP Fragmentation Statistics', 0),('device', 'netstat_udp', 'netstats', 'UDP Statistics', 0),('device', 'netstat_snmp', 'netstats', 'SNMP Statistics', 0),('device', 'temperatures', 'system', 'Temperatures', 0),('device', 'mempools', 'system', 'Memory Pool Usage', 0),('device', 'processors', 'system', 'Processor Usage', 0),('device', 'storage', 'system', 'Filesystem Usage', 0),('device', 'hr_processes', 'system', 'Running Processes', 0),('device', 'uptime', 'system', 'System Uptime', ''),('device', 'ipsystemstats_ipv4', 'netstats', 'IPv4 Packet Statistics', 0),('device', 'ipsystemstats_ipv6_frag', 'netstats', 'IPv6 Fragmentation Statistics', 0),('device', 'ipsystemstats_ipv6', 'netstats', 'IPv6 Packet Statistics', 0),('device', 'ipsystemstats_ipv4_frag', 'netstats', 'IPv4 Fragmentation Statistics', 0),('device', 'fortigate_sessions', 'firewall', 'Active Sessions', ''), ('device', 'screenos_sessions', 'firewall', 'Active Sessions', ''), ('device', 'fdb_count', 'system', 'MAC Addresses Learnt', '0'),('device', 'cras_sessions', 'firewall', 'Remote Access Sessions', 0); -DROP TABLE `frequency`; -ALTER TABLE `mempools` CHANGE `mempool_index` `mempool_index` VARCHAR( 16 ) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL; -ALTER TABLE `vrfs` CHANGE `mplsVpnVrfRouteDistinguisher` `mplsVpnVrfRouteDistinguisher` varchar(26) default NOT NULL; -ALTER TABLE `devices` ADD `timeout` INT NULL DEFAULT NULL AFTER `port`; -ALTER TABLE `devices` ADD `retries` INT NULL DEFAULT NULL AFTER `timeout`; -ALTER TABLE `ports` ADD `disabled` tinyint(1) NOT NULL DEFAULT '0' AFTER `ignore`; -ALTER TABLE `perf_times` CHANGE `duration` `duration` DOUBLE( 8, 2 ) NOT NULL -ALTER TABLE `sensors` ADD `poller_type` VARCHAR(16) NOT NULL DEFAULT 'snmp' AFTER `device_id`; -ALTER TABLE `devices` ADD `transport` VARCHAR(16) NOT NULL DEFAULT 'udp' AFTER `port`; -ALTER TABLE ports MODIFY port_descr_circuit VARCHAR(255); -ALTER TABLE ports MODIFY port_descr_descr VARCHAR(255); -ALTER TABLE ports MODIFY port_descr_notes VARCHAR(255); -ALTER TABLE devices MODIFY community VARCHAR(255); -ALTER TABLE users MODIFY password VARCHAR(34); -ALTER TABLE sensors MODIFY sensor_descr VARCHAR(255); -ALTER TABLE `vrfs` MODIFY `mplsVpnVrfRouteDistinguisher` VARCHAR(128); -ALTER TABLE `vrfs` MODIFY `vrf_name` VARCHAR(128); -ALTER TABLE `ports` MODIFY `ifDescr` VARCHAR(255); -CREATE TABLE IF NOT EXISTS `vminfo` (`id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `vmwVmVMID` int(11) NOT NULL, `vmwVmDisplayName` varchar(128) NOT NULL, `vmwVmGuestOS` varchar(128) NOT NULL, `vmwVmMemSize` int(11) NOT NULL, `vmwVmCpus` int(11) NOT NULL, `vmwVmState` varchar(128) NOT NULL, PRIMARY KEY (`id`), KEY `device_id` (`device_id`), KEY `vmwVmVMID` (`vmwVmVMID`)) ENGINE=InnoDB DEFAULT CHARSET=utf8; -ALTER TABLE `ports` MODIFY `port_descr_type` VARCHAR(255); -RENAME TABLE `vmware_vminfo` TO `vminfo` ; -ALTER TABLE `vminfo` ADD `vm_type` VARCHAR(16) NOT NULL DEFAULT 'vmware' AFTER `device_id`; -CREATE TABLE IF NOT EXISTS `cef_switching` ( `device_id` int(11) NOT NULL, `entPhysicalIndex` int(11) NOT NULL, `afi` varchar(4) COLLATE utf8_unicode_ci NOT NULL, `cef_index` int(11) NOT NULL, `cef_path` varchar(16) COLLATE utf8_unicode_ci NOT NULL, `drop` int(11) NOT NULL, `punt` int(11) NOT NULL, `punt2host` int(11) NOT NULL, `drop_prev` int(11) NOT NULL, `punt_prev` int(11) NOT NULL, `punt2host_prev` int(11) NOT NULL,`updated` INT NOT NULL , `updated_prev` INT NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -ALTER TABLE `mac_accounting` CHANGE `peer_mac` `mac` VARCHAR( 32 ) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL; -ALTER TABLE `mac_accounting` DROP `peer_ip`, DROP `peer_desc`, DROP `peer_asn`; -UPDATE sensors SET sensor_class='frequency' WHERE sensor_class='freq'; -ALTER TABLE `cef_switching` ADD `cef_switching_id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY FIRST; -ALTER TABLE `mempools` ADD `mempool_perc` INT NOT NULL AFTER `device_id`; -ALTER TABLE `ports` ADD UNIQUE `device_ifIndex` ( `device_id` , `ifIndex` ); -ALTER TABLE `ports` DROP INDEX `host`; -ALTER TABLE `ports` DROP INDEX `snmpid`; -CREATE TABLE IF NOT EXISTS `ospf_areas` ( `device_id` int(11) NOT NULL, `ospfAreaId` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfAuthType` varchar(64) COLLATE utf8_unicode_ci NOT NULL, `ospfImportAsExtern` varchar(128) COLLATE utf8_unicode_ci NOT NULL, `ospfSpfRuns` int(11) NOT NULL, `ospfAreaBdrRtrCount` int(11) NOT NULL, `ospfAsBdrRtrCount` int(11) NOT NULL, `ospfAreaLsaCount` int(11) NOT NULL, `ospfAreaLsaCksumSum` int(11) NOT NULL, `ospfAreaSummary` varchar(64) COLLATE utf8_unicode_ci NOT NULL, `ospfAreaStatus` varchar(64) COLLATE utf8_unicode_ci NOT NULL, UNIQUE KEY `device_area` (`device_id`,`ospfAreaId`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; -CREATE TABLE IF NOT EXISTS `ospf_instances` ( `device_id` int(11) NOT NULL, `ospf_instance_id` int(11) NOT NULL, `ospfRouterId` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfAdminStat` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfVersionNumber` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfAreaBdrRtrStatus` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfASBdrRtrStatus` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfExternLsaCount` int(11) NOT NULL, `ospfExternLsaCksumSum` int(11) NOT NULL, `ospfTOSSupport` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfOriginateNewLsas` int(11) NOT NULL, `ospfRxNewLsas` int(11) NOT NULL, `ospfExtLsdbLimit` int(11) DEFAULT NULL, `ospfMulticastExtensions` int(11) DEFAULT NULL, `ospfExitOverflowInterval` int(11) DEFAULT NULL, `ospfDemandExtensions` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL, UNIQUE KEY `device_id` (`device_id`,`ospf_instance_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; -CREATE TABLE IF NOT EXISTS `ospf_ports` ( `device_id` int(11) NOT NULL, `interface_id` int(11) NOT NULL, `ospf_port_id` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfIfIpAddress` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfAddressLessIf` int(11) NOT NULL, `ospfIfAreaId` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfIfType` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL, `ospfIfAdminStat` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL, `ospfIfRtrPriority` int(11) DEFAULT NULL, `ospfIfTransitDelay` int(11) DEFAULT NULL, `ospfIfRetransInterval` int(11) DEFAULT NULL, `ospfIfHelloInterval` int(11) DEFAULT NULL, `ospfIfRtrDeadInterval` int(11) DEFAULT NULL, `ospfIfPollInterval` int(11) DEFAULT NULL, `ospfIfState` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL, `ospfIfDesignatedRouter` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL, `ospfIfBackupDesignatedRouter` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL, `ospfIfEvents` int(11) DEFAULT NULL, `ospfIfAuthKey` varchar(128) COLLATE utf8_unicode_ci DEFAULT NULL, `ospfIfStatus` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL, `ospfIfMulticastForwarding` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL, `ospfIfDemand` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL, `ospfIfAuthType` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL, UNIQUE KEY `device_id` (`device_id`,`interface_id`,`ospf_port_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; -CREATE TABLE IF NOT EXISTS `ospf_nbrs` ( `device_id` int(11) NOT NULL, `interface_id` int(11) NOT NULL, `ospf_nbr_id` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfNbrIpAddr` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfNbrAddressLessIndex` int(11) NOT NULL, `ospfNbrRtrId` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfNbrOptions` int(11) NOT NULL, `ospfNbrPriority` int(11) NOT NULL, `ospfNbrState` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfNbrEvents` int(11) NOT NULL, `ospfNbrLsRetransQLen` int(11) NOT NULL, `ospfNbmaNbrStatus` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfNbmaNbrPermanence` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `ospfNbrHelloSuppressed` varchar(32) COLLATE utf8_unicode_ci NOT NULL, UNIQUE KEY `device_id` (`device_id`,`ospf_nbr_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; -CREATE TABLE IF NOT EXISTS `ports_stack` (`interface_id_high` INT NOT NULL ,`interface_id_low` INT NOT NULL) ENGINE = INNODB; -ALTER TABLE `ports_stack` ADD `device_id` INT NOT NULL; -ALTER TABLE `ports_stack` ADD `ifStackStatus` VARCHAR(32); -ALTER TABLE users ADD can_modify_passwd TINYINT NOT NULL DEFAULT 1; -ALTER TABLE `storage` ADD UNIQUE `index_unique` ( `device_id` , `storage_mib` , `storage_index` ); -ALTER TABLE `bgpPeers_cbgp` ADD `AcceptedPrefixes` INT NOT NULL ,ADD `DeniedPrefixes` INT NOT NULL ,ADD `PrefixAdminLimit` INT NOT NULL ,ADD `PrefixThreshold` INT NOT NULL ,ADD `PrefixClearThreshold` INT NOT NULL ,ADD `AdvertisedPrefixes` INT NOT NULL ,ADD `SuppressedPrefixes` INT NOT NULL ,ADD `WithdrawnPrefixes` INT NOT NULL; -ALTER TABLE `bgpPeers_cbgp` ADD UNIQUE `unique_index` ( `device_id` , `bgpPeerIdentifier` , `afi` , `safi` ); -ALTER TABLE `ports` ADD UNIQUE `device_ifIndex` ( `device_id` , `ifIndex` ); -ALTER TABLE `devices` CHANGE `port` `port` SMALLINT( 5 ) UNSIGNED NOT NULL DEFAULT '161'; -CREATE TABLE IF NOT EXISTS `ipsec_tunnels` ( `tunnel_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `peer_port` int(11) NOT NULL, `peer_addr` varchar(64) COLLATE utf8_unicode_ci NOT NULL, `local_addr` varchar(64) COLLATE utf8_unicode_ci NOT NULL, `local_port` int(11) NOT NULL, `tunnel_name` varchar(96) COLLATE utf8_unicode_ci NOT NULL, `tunnel_status` varchar(11) COLLATE utf8_unicode_ci NOT NULL, PRIMARY KEY (`tunnel_id`), UNIQUE KEY `unique_index` (`device_id`,`peer_addr`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; -ALTER TABLE `syslog` ADD INDEX ( `program` ); -ALTER TABLE `devices` ADD `sysObjectID` VARCHAR( 64 ) NULL DEFAULT NULL AFTER `bgpLocalAs`; -ALTER TABLE `ports` CHANGE `ifSpeed` `ifSpeed` BIGINT NULL DEFAULT NULL; -ALTER TABLE `sensors` CHANGE `sensor_oid` `sensor_oid` VARCHAR( 255 ) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL; -CREATE TABLE IF NOT EXISTS `entPhysical_state` ( `device_id` int(11) NOT NULL, `entPhysicalIndex` varchar(64) NOT NULL, `subindex` varchar(64) DEFAULT NULL, `group` varchar(64) NOT NULL, `key` varchar(64) NOT NULL, `value` varchar(255) NOT NULL, KEY `device_id_index` (`device_id`,`entPhysicalIndex`)) ENGINE=MyISAM DEFAULT CHARSET=latin1; -CREATE TABLE IF NOT EXISTS `ports_vlans` ( `port_vlan_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `interface_id` int(11) NOT NULL, `vlan` int(11) NOT NULL, `baseport` int(11) NOT NULL, `priority` bigint(32) NOT NULL, `state` varchar(16) NOT NULL, `cost` int(11) NOT NULL, PRIMARY KEY (`port_vlan_id`), UNIQUE KEY `unique` (`device_id`,`interface_id`,`vlan`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 ; -ALTER TABLE `bills` CHANGE `bill_cdr` `bill_cdr` BIGINT( 20 ) NULL DEFAULT NULL; -CREATE TABLE IF NOT EXISTS `loadbalancer_rservers` ( `rserver_id` int(11) NOT NULL AUTO_INCREMENT, `farm_id` varchar(128) CHARACTER SET utf8 NOT NULL, `device_id` int(11) NOT NULL, `StateDescr` varchar(64) CHARACTER SET utf8 NOT NULL, PRIMARY KEY (`rserver_id`)) ENGINE=MyISAM AUTO_INCREMENT=514 DEFAULT CHARSET=utf8; -CREATE TABLE IF NOT EXISTS `loadbalancer_vservers` ( `classmap_id` int(11) NOT NULL, `classmap` varchar(128) NOT NULL, `serverstate` varchar(64) NOT NULL, `device_id` int(11) NOT NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8; -ALTER TABLE `sensors` CHANGE `sensor_index` `sensor_index` VARCHAR( 64 ); -CREATE TABLE IF NOT EXISTS `netscaler_vservers` ( `vsvr_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `vsvr_name` varchar(128) COLLATE utf8_unicode_ci NOT NULL, `vsvr_ip` varchar(128) COLLATE utf8_unicode_ci NOT NULL, `vsvr_port` int(8) NOT NULL, `vsvr_type` varchar(64) COLLATE utf8_unicode_ci NOT NULL, `vsvr_state` varchar(32) COLLATE utf8_unicode_ci NOT NULL, `vsvr_clients` int(11) NOT NULL, `vsvr_server` int(11) NOT NULL, `vsvr_req_rate` int(11) NOT NULL, `vsvr_bps_in` int(11) NOT NULL, `vsvr_bps_out` int(11) NOT NULL, PRIMARY KEY (`vsvr_id`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci ; -ALTER TABLE `dbSchema` ADD `version` INT NOT NULL; -ALTER TABLE `dbSchema` DROP `revision`; -ALTER TABLE `bills` CHANGE `bill_gb` `bill_quota` BIGINT( 20 ) NULL DEFAULT NULL; -ALTER TABLE `bills` CHANGE `rate_95th_in` `rate_95th_in` BIGINT( 20 ) NOT NULL; -ALTER TABLE `bills` CHANGE `rate_95th_out` `rate_95th_out` BIGINT( 20 ) NOT NULL; -ALTER TABLE `bills` CHANGE `rate_95th` `rate_95th` BIGINT( 20 ) NOT NULL; -ALTER TABLE `bills` CHANGE `total_data` `total_data` BIGINT( 20 ) NOT NULL; -ALTER TABLE `bills` CHANGE `total_data_in` `total_data_in` BIGINT( 20 ) NOT NULL ; -ALTER TABLE `bills` CHANGE `total_data_out` `total_data_out` BIGINT( 20 ) NOT NULL; -ALTER TABLE `bills` CHANGE `rate_average_in` `rate_average_in` BIGINT( 20 ) NOT NULL; -ALTER TABLE `bills` CHANGE `rate_average_out` `rate_average_out` BIGINT( 20 ) NOT NULL; -ALTER TABLE `bills` CHANGE `rate_average` `rate_average` BIGINT( 20 ) NOT NULL; -ALTER TABLE `eventlog` ADD INDEX `datetime` ( `datetime` ); -CREATE TABLE IF NOT EXISTS `packages` ( `pkg_id` int(11) NOT NULL auto_increment, `device_id` int(11) NOT NULL, `name` varchar(64) NOT NULL, `manager` varchar(16) NOT NULL default '1', `status` tinyint(1) NOT NULL, `version` varchar(64) NOT NULL, `build` varchar(64) NOT NULL, `arch` varchar(16) NOT NULL, `size` bigint(20) default NULL, PRIMARY KEY (`pkg_id`), UNIQUE KEY `unique_key` (`device_id`,`name`,`manager`,`arch`,`version`,`build`), KEY `device_id` (`device_id`)) ENGINE=MyISAM CHARSET=utf8 COLLATE=utf8_bin; -CREATE TABLE IF NOT EXISTS `slas` ( `sla_id` int(11) NOT NULL auto_increment, `device_id` int(11) NOT NULL, `sla_nr` int(11) NOT NULL, `owner` varchar(255) NOT NULL, `tag` varchar(255) NOT NULL, `rtt_type` varchar(16) NOT NULL, `status` tinyint(1) NOT NULL, `deleted` tinyint(1) NOT NULL DEFAULT '0', PRIMARY KEY (`sla_id`), UNIQUE KEY `unique_key` (`device_id`,`sla_nr`), KEY `device_id` (`device_id`)) ENGINE=MyISAM CHARSET=utf8 COLLATE=utf8_bin; -ALTER TABLE `devices` ADD COLUMN `icon` VARCHAR(255) DEFAULT NULL -CREATE TABLE IF NOT EXISTS `munin_plugins` ( `mplug_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `mplug_type` varchar(256) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, `mplug_instance` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL, `mplug_category` varchar(32) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL, `mplug_title` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL, `mplug_info` text CHARACTER SET utf8 COLLATE utf8_bin, `mplug_vlabel` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL, `mplug_args` varchar(512) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL, `mplug_total` binary(1) NOT NULL DEFAULT '0', `mplug_graph` binary(1) NOT NULL DEFAULT '1', PRIMARY KEY (`mplug_id`), UNIQUE KEY `UNIQUE` (`device_id`,`mplug_type`), KEY `device_id` (`device_id`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin ; -CREATE TABLE IF NOT EXISTS `munin_plugins_ds` ( `mplug_id` int(11) NOT NULL, `ds_name` varchar(32) COLLATE utf8_bin NOT NULL, `ds_type` enum('COUNTER','ABSOLUTE','DERIVE','GAUGE') COLLATE utf8_bin NOT NULL DEFAULT 'GAUGE', `ds_label` varchar(64) COLLATE utf8_bin NOT NULL, `ds_cdef` text COLLATE utf8_bin NOT NULL, `ds_draw` varchar(64) COLLATE utf8_bin NOT NULL, `ds_graph` enum('no','yes') COLLATE utf8_bin NOT NULL DEFAULT 'yes', `ds_info` varchar(255) COLLATE utf8_bin NOT NULL, `ds_extinfo` text COLLATE utf8_bin NOT NULL, `ds_max` varchar(32) COLLATE utf8_bin NOT NULL, `ds_min` varchar(32) COLLATE utf8_bin NOT NULL, `ds_negative` varchar(32) COLLATE utf8_bin NOT NULL, `ds_warning` varchar(32) COLLATE utf8_bin NOT NULL, `ds_critical` varchar(32) COLLATE utf8_bin NOT NULL, `ds_colour` varchar(32) COLLATE utf8_bin NOT NULL, `ds_sum` text CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, `ds_stack` text COLLATE utf8_bin NOT NULL, `ds_line` varchar(64) COLLATE utf8_bin NOT NULL, UNIQUE KEY `splug_id` (`mplug_id`,`ds_name`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin; -ALTER TABLE `munin_plugins_ds` CHANGE `ds_cdef` `ds_cdef` VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL; -ALTER TABLE `applications` ADD `app_state` TEXT CHARACTER SET utf8 COLLATE utf8_bin NOT NULL; -ALTER TABLE `vlans` ADD `vlan_type` VARCHAR( 16 ) NULL; -ALTER TABLE `vlans` CHANGE `vlan_domain` `vlan_domain` INT NULL DEFAULT NULL; -ALTER TABLE `vlans` CHANGE `vlan_descr` `vlan_name` VARCHAR( 32 ) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL; -ALTER TABLE `vlans` ADD `vlan_mtu` INT NULL; -ALTER TABLE `applications` ADD `app_status` VARCHAR( 8 ) NOT NULL ; -UPDATE `sensors` SET sensor_limit=sensor_limit/1.3*1.8 WHERE sensor_class="fanspeed" -ALTER TABLE `pseudowires` ADD `device_id` INT NOT NULL AFTER `pseudowire_id`; -TRUNCATE TABLE `pseudowires`; -ALTER TABLE `pseudowires` ADD `pw_type` VARCHAR( 32 ) NOT NULL ,ADD `pw_psntype` VARCHAR( 32 ) NOT NULL ,ADD `pw_local_mtu` INT NOT NULL ,ADD `pw_peer_mtu` INT NOT NULL ,ADD `pw_descr` VARCHAR( 128 ) NOT NULL; -ALTER TABLE `toner` ADD `toner_capacity_oid` VARCHAR( 64 ); -ALTER TABLE `devices` ADD `authlevel` ENUM("noAuthNoPriv", "authNoPriv", "authPriv") NULL DEFAULT NULL AFTER `community`; -ALTER TABLE `devices` ADD `authname` VARCHAR(64) NULL DEFAULT NULL AFTER `authlevel`; -ALTER TABLE `devices` ADD `authpass` VARCHAR(64) NULL DEFAULT NULL AFTER `authname`; -ALTER TABLE `devices` ADD `authalgo` ENUM("MD5", "SHA1") NULL DEFAULT NULL AFTER `authpass`; -ALTER TABLE `devices` ADD `cryptopass` VARCHAR(64) NULL DEFAULT NULL AFTER `authalgo`; -ALTER TABLE `devices` ADD `cryptoalgo` ENUM("AES", "DES") NULL DEFAULT NULL AFTER `cryptopass`; -ALTER TABLE `applications` CHANGE `app_state` `app_state` VARCHAR( 32 ) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT 'UNKNOWN'; -ALTER TABLE `applications` CHANGE `app_type` `app_type` VARCHAR( 64 ) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL; -ALTER TABLE `devices` CHANGE `authalgo` `authalgo` ENUM( 'MD5', 'SHA' ) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL; -ALTER TABLE `ports` CHANGE `interface_id` `port_id` INT( 11 ) NOT NULL AUTO_INCREMENT; -ALTER TABLE `storage` ADD `storage_deleted` BOOL NOT NULL DEFAULT '0'; -ALTER TABLE `links` CHANGE `local_interface_id` `local_port_id` INT( 11 ) NULL DEFAULT NULL; -ALTER TABLE `links` CHANGE `remote_interface_id` `remote_port_id` INT( 11 ) NULL DEFAULT NULL; -ALTER TABLE `sensors` ADD `sensor_deleted` BOOL NOT NULL DEFAULT '0' AFTER `sensor_id`; -ALTER TABLE `mempools` ADD `mempool_deleted` BOOL NOT NULL DEFAULT '0'; -ALTER TABLE `ipv4_addresses` CHANGE `interface_id` `port_id` INT( 11 ) NOT NULL; -ALTER TABLE `ipv6_addresses` CHANGE `interface_id` `port_id` INT( 11 ) NOT NULL; -ALTER TABLE `ipv4_mac` CHANGE `interface_id` `port_id` INT( 11 ) NOT NULL; -ALTER TABLE `juniAtmVp` CHANGE `interface_id` `port_id` INT( 11 ) NOT NULL; -ALTER TABLE `ospf_nbrs` CHANGE `interface_id` `port_id` INT( 11 ) NOT NULL; -ALTER TABLE `mac_accounting` CHANGE `interface_id` `port_id` INT( 11 ) NOT NULL; -ALTER TABLE `ospf_ports` CHANGE `interface_id` `port_id` INT( 11 ) NOT NULL; -ALTER TABLE `ports_adsl` CHANGE `interface_id` `port_id` INT( 11 ) NOT NULL; -ALTER TABLE `ports_perms` CHANGE `interface_id` `port_id` INT( 11 ) NOT NULL; -ALTER TABLE `ports_stack` CHANGE `interface_id_high` `port_id_high` INT( 11 ) NOT NULL; -ALTER TABLE `ports_stack` CHANGE `interface_id_low` `port_id_low` INT( 11 ) NOT NULL; -ALTER TABLE `ports_vlans` CHANGE `interface_id` `port_id` INT( 11 ) NOT NULL; -ALTER TABLE `pseudowires` CHANGE `interface_id` `port_id` INT( 11 ) NOT NULL; -CREATE TABLE IF NOT EXISTS `access_points` ( `accesspoint_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `name` varchar(255) NOT NULL, `radio_number` tinyint(4) DEFAULT NULL, `type` varchar(16) NOT NULL, `mac_addr` varchar(24) NOT NULL, `deleted` tinyint(1) NOT NULL DEFAULT '0', `channel` tinyint(4) unsigned NOT NULL DEFAULT '0', `txpow` tinyint(4) NOT NULL DEFAULT '0', `radioutil` tinyint(4) NOT NULL DEFAULT '0', `numasoclients` smallint(6) NOT NULL DEFAULT '0', `nummonclients` smallint(6) NOT NULL DEFAULT '0', `numactbssid` tinyint(4) NOT NULL DEFAULT '0', `nummonbssid` tinyint(4) NOT NULL DEFAULT '0', `interference` tinyint(3) unsigned NOT NULL, PRIMARY KEY (`accesspoint_id`), KEY `deleted` (`deleted`), KEY `name` (`name`,`radio_number`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Access Points';ALTER TABLE `juniAtmVp` ADD INDEX ( `port_id` ); -ALTER TABLE `loadbalancer_vservers` ADD INDEX ( `device_id` ); -ALTER TABLE `users` CHANGE `password` `password` VARCHAR( 60 ); -CREATE TABLE IF NOT EXISTS `session` ( `session_id` int(11) NOT NULL AUTO_INCREMENT, `session_username` varchar(30) NOT NULL, `session_value` varchar(60) NOT NULL, `session_token` varchar(60) NOT NULL, `session_auth` varchar(16) NOT NULL, `session_expiry` int(11) NOT NULL, PRIMARY KEY (`session_id`)) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ; -CREATE TABLE IF NOT EXISTS `plugins` ( `plugin_id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY , `plugin_name` VARCHAR( 60 ) NOT NULL , `plugin_active` INT NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1; -ALTER TABLE `sensors` ADD `sensor_alert` TINYINT( 1 ) NOT NULL DEFAULT '1' AFTER `sensor_limit_low_warn` ; -CREATE TABLE IF NOT EXISTS `ciscoASA` ( `ciscoASA_id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `oid` varchar(255) NOT NULL, `data` bigint(20) NOT NULL, `high_alert` bigint(20) NOT NULL, `low_alert` bigint(20) NOT NULL, `disabled` tinyint(4) NOT NULL DEFAULT '0', PRIMARY KEY (`ciscoASA_id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ; -INSERT INTO `graph_types` SET `graph_type`='device', `graph_subtype`='asa_conns',`graph_section`='firewall',`graph_descr`='Current connections',`graph_order`='0'; -CREATE TABLE `api_tokens` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user_id` int(11) NOT NULL, `token_hash` varchar(32) NOT NULL, `description` varchar(100) NOT NULL, `disabled` tinyint(1) NOT NULL DEFAULT '0', PRIMARY KEY (`id`), UNIQUE KEY `token_hash` (`token_hash`)) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=latin1; -ALTER TABLE `api_tokens` MODIFY `token_hash` VARCHAR(256); -ALTER TABLE `devices` ADD `last_ping` TIMESTAMP NULL AFTER `last_discovered` , ADD `last_ping_timetaken` DOUBLE( 5, 2 ) NULL AFTER `last_ping` ; -DROP TABLE IF EXISTS `alerts`; -CREATE TABLE IF NOT EXISTS `alerts` ( `id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `rule_id` int(11) NOT NULL, `state` int(11) NOT NULL, `alerted` int(11) NOT NULL, `open` int(11) NOT NULL, `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8; -DROP TABLE IF EXISTS `alert_log`; -CREATE TABLE IF NOT EXISTS `alert_log` ( `id` int(11) NOT NULL AUTO_INCREMENT, `rule_id` int(11) NOT NULL, `device_id` int(11) NOT NULL, `state` int(11) NOT NULL, `details` longblob NOT NULL, `time_logged` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY `id` (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8; -DROP TABLE IF EXISTS `alert_rules`; -CREATE TABLE IF NOT EXISTS `alert_rules` ( `id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `rule` text CHARACTER SET utf8 NOT NULL, `severity` enum('ok','warning','critical') CHARACTER SET utf8 NOT NULL, `extra` varchar(255) CHARACTER SET utf8 NOT NULL, `disabled` tinyint(1) NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8; -DROP TABLE IF EXISTS `alert_schedule`; -CREATE TABLE IF NOT EXISTS `alert_schedule` ( `id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `start` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', `end` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8; -DROP TABLE IF EXISTS `alert_templates`; -CREATE TABLE IF NOT EXISTS `alert_templates` ( `id` int(11) NOT NULL AUTO_INCREMENT, `rule_id` varchar(255) NOT NULL DEFAULT ',',`name` varchar(255) NOT NULL, `template` longtext NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8; -ALTER TABLE `alert_rules` ADD `name` VARCHAR( 255 ) NOT NULL ; -ALTER TABLE `users` ADD `twofactor` VARCHAR( 255 ) NOT NULL; -CREATE TABLE IF NOT EXISTS `processes` ( `device_id` int(11) NOT NULL, `pid` int(255) NOT NULL, `vsz` int(255) NOT NULL, `rss` int(255) NOT NULL, `cputime` varchar(12) NOT NULL, `user` varchar(50) NOT NULL, `command` varchar(255) NOT NULL, KEY `device_id` (`device_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; -ALTER TABLE `devices` CHANGE `agent_uptime` `agent_uptime` INT( 11 ) NOT NULL DEFAULT '0'; -ALTER TABLE `devices` CHANGE `type` `type` VARCHAR( 20 ) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT ''; -ALTER TABLE `ports` CHANGE `ifVrf` `ifVrf` INT( 11 ) NOT NULL DEFAULT '0'; -ALTER TABLE `storage` CHANGE `storage_free` `storage_free` BIGINT( 20 ) NOT NULL DEFAULT '0'; -ALTER TABLE `storage` CHANGE `storage_used` `storage_used` BIGINT( 20 ) NOT NULL DEFAULT '0'; -ALTER TABLE `storage` CHANGE `storage_perc` `storage_perc` INT NOT NULL DEFAULT '0'; -ALTER TABLE `processors` CHANGE `entPhysicalIndex` `entPhysicalIndex` INT( 11 ) NOT NULL DEFAULT '0'; -ALTER TABLE `hrDevice` CHANGE `hrDeviceErrors` `hrDeviceErrors` INT( 11 ) NOT NULL DEFAULT '0'; -ALTER TABLE `devices_attribs` ADD INDEX ( `device_id` ); -ALTER TABLE `device_graphs` ADD INDEX ( `device_id` ); -ALTER TABLE `alert_log` ADD INDEX ( `rule_id` ); -ALTER TABLE `alert_log` ADD INDEX ( `device_id` ); -ALTER TABLE `alerts` ADD INDEX ( `rule_id` ); -ALTER TABLE `alerts` ADD INDEX ( `device_id` ); -ALTER TABLE `ciscoASA` ADD INDEX ( `device_id` ); -ALTER TABLE `alert_schedule` ADD INDEX ( `device_id` ); -ALTER TABLE `alert_rules` ADD INDEX ( `device_id` ); -CREATE TABLE `pollers` (`id` int(11) NOT NULL AUTO_INCREMENT, `poller_name` varchar(255) NOT NULL, `last_polled` datetime NOT NULL, `devices` int(11) NOT NULL, `time_taken` double NOT NULL, KEY `id` (`id`)) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8 COLLATE=utf8_bin; -ALTER TABLE `devices` ADD `poller_group` INT(11) NOT NULL DEFAULT '0'; -CREATE TABLE `poller_groups` (`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,`group_name` VARCHAR( 255 ) NOT NULL ,`descr` VARCHAR( 255 ) NOT NULL) ENGINE = INNODB; -ALTER TABLE `links` ADD `local_device_id` INT NOT NULL AFTER `local_port_id` , ADD `remote_device_id` INT NOT NULL AFTER `remote_hostname` ; -ALTER TABLE `links` ADD INDEX ( `local_device_id` , `remote_device_id` ) ; -CREATE TABLE IF NOT EXISTS `device_groups` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL DEFAULT '', `desc` varchar(255) NOT NULL DEFAULT '', `pattern` varchar(255) NOT NULL DEFAULT '', PRIMARY KEY (`id`), UNIQUE KEY `name` (`name`)) ENGINE=InnoDB; -CREATE TABLE IF NOT EXISTS `alert_map` ( `id` int(11) NOT NULL AUTO_INCREMENT, `rule` int(11) NOT NULL DEFAULT '0', `target` varchar(255) CHARACTER SET utf8 NOT NULL DEFAULT '', PRIMARY KEY (`id`)) ENGINE=InnoDB; -ALTER TABLE `alert_rules` ADD UNIQUE (`name`); -ALTER TABLE `alert_rules` CHANGE `device_id` `device_id` VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT ''; -CREATE TABLE `callback` ( `callback_id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY , `name` CHAR( 64 ) NOT NULL , `value` CHAR( 64 ) NOT NULL ) ENGINE = INNODB; -ALTER TABLE `alert_log` ADD INDEX ( `time_logged` ); -ALTER TABLE `alert_schedule` DROP `device_id`; -ALTER TABLE `alert_schedule` CHANGE `id` `schedule_id` INT( 11 ) NOT NULL AUTO_INCREMENT; -ALTER TABLE `alert_schedule` ADD `title` VARCHAR( 255 ) NOT NULL ,ADD `notes` TEXT NOT NULL ; -CREATE TABLE `librenms`.`alert_schedule_items` (`item_id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,`schedule_id` INT NOT NULL ,`target` VARCHAR( 255 ) NOT NULL ,INDEX ( `schedule_id` )) ENGINE = INNODB; -ALTER TABLE device_groups MODIFY COLUMN pattern TEXT; -ALTER TABLE `sensors` ADD `sensor_custom` ENUM( 'No', 'Yes' ) NOT NULL DEFAULT 'No' AFTER `sensor_alert` ; -DROP TABLE IF EXISTS `config`; -CREATE TABLE `config` ( `config_id` int(11) NOT NULL AUTO_INCREMENT, `config_name` varchar(255) NOT NULL, `config_value` varchar(512) NOT NULL, `config_default` varchar(512) NOT NULL, `config_descr` varchar(100) NOT NULL, `config_group` varchar(50) NOT NULL, `config_group_order` int(11) NOT NULL, `config_sub_group` varchar(50) NOT NULL, `config_sub_group_order` int(11) NOT NULL, `config_hidden` enum('0','1') NOT NULL DEFAULT '0', `config_disabled` enum('0','1') NOT NULL DEFAULT '0', PRIMARY KEY (`config_id`)) ENGINE=InnoDB AUTO_INCREMENT=720 DEFAULT CHARSET=latin1; -INSERT INTO `config` VALUES (441,'alert.macros.rule.now','NOW()','NOW()','Macro currenttime','alerting',0,'macros',0,'1','0'),(442,'alert.macros.rule.past_5m','DATE_SUB(NOW(),INTERVAL 5 MINUTE)','DATE_SUB(NOW(),INTERVAL 5 MINUTE)','Macro past 5 minutes','alerting',0,'macros',0,'1','0'),(443,'alert.macros.rule.past_10m','DATE_SUB(NOW(),INTERVAL 10 MINUTE)','DATE_SUB(NOW(),INTERVAL 10 MINUTE)','Macro past 10 minutes','alerting',0,'macros',0,'1','0'),(444,'alert.macros.rule.past_15m','DATE_SUB(NOW(),INTERVAL 15 MINUTE)','DATE_SUB(NOW(),INTERVAL 15 MINUTE)','Macro past 15 minutes','alerting',0,'macros',0,'1','0'),(445,'alert.macros.rule.past_30m','DATE_SUB(NOW(),INTERVAL 30 MINUTE)','DATE_SUB(NOW(),INTERVAL 30 MINUTE)','Macro past 30 minutes','alerting',0,'macros',0,'1','0'),(446,'alert.macros.rule.device','(%devices.disabled = 0 && %devices.ignore = 0)','(%devices.disabled = 0 && %devices.ignore = 0)','Devices that aren\'t disabled or ignored','alerting',0,'macros',0,'1','0'),(447,'alert.macros.rule.device_up','(%devices.status = 1 && %macros.device)','(%devices.status = 1 && %macros.device)','Devices that are up','alerting',0,'macros',0,'1','0'),(448,'alert.macros.rule.device_down','(%devices.status = 0 && %macros.device)','(%devices.status = 0 && %macros.device)','Devices that are down','alerting',0,'macros',0,'1','0'),(449,'alert.macros.rule.port','(%ports.deleted = 0 && %ports.ignore = 0 && %ports.disabled = 0)','(%ports.deleted = 0 && %ports.ignore = 0 && %ports.disabled = 0)','Ports that aren\'t disabled, ignored or delete','alerting',0,'macros',0,'1','0'),(450,'alert.macros.rule.port_up','(%ports.ifOperStatus = \"up\" && %ports.ifAdminStatus = \"up\" && %macros.port)','(%ports.ifOperStatus = \"up\" && %ports.ifAdminStatus = \"up\" && %macros.port)','Ports that are up','alerting',0,'macros',0,'1','0'),(451,'alert.admins','true','true','Alert administrators','alerting',0,'general',0,'0','0'),(452,'alert.default_only','true','true','Only alert default mail contact','alerting',0,'general',0,'0','0'),(453,'alert.default_mail','','','The default mail contact','alerting',0,'general',0,'0','0'),(454,'alert.transports.pagerduty','','','Pagerduty transport - put your API key here','alerting',0,'transports',0,'0','0'),(455,'alert.pagerduty.account','','','Pagerduty account name','alerting',0,'transports',0,'0','0'),(456,'alert.pagerduty.service','','','Pagerduty service name','alerting',0,'transports',0,'0','0'),(457,'alert.tolerance_window','5','5','Tolerance window in seconds','alerting',0,'general',0,'0','0'),(458,'email_backend','mail','mail','The backend to use for sending email, can be mail, sendmail or smtp','alerting',0,'general',0,'0','0'),(459,'alert.macros.rule.past_60m','DATE_SUB(NOW(),INTERVAL 60 MINUTE)','DATE_SUB(NOW(),INTERVAL 60 MINUTE)','Macro past 60 minutes','alerting',0,'macros',0,'1','0'),(460,'alert.macros.rule.port_usage_perc','((%ports.ifInOctets_rate*8)/%ports.ifSpeed)*100','((%ports.ifInOctets_rate*8)/%ports.ifSpeed)*100','Ports using more than X perc','alerting',0,'macros',0,'1','0'),(461,'alert.transports.dummy','false','false','Dummy transport','alerting',0,'transports',0,'0','0'),(462,'alert.transports.mail','true','true','Mail alerting transport','alerting',0,'transports',0,'0','0'),(463,'alert.transports.irc','FALSE','false','IRC alerting transport','alerting',0,'transports',0,'0','0'),(464,'alert.globals','true','TRUE','Alert read only administrators','alerting',0,'general',0,'0','0'),(465,'email_from','NULL','NULL','Email address used for sending emails (from)','alerting',0,'general',0,'0','0'),(466,'email_user','LibreNMS','LibreNMS','Name used as part of the from address','alerting',0,'general',0,'0','0'),(467,'email_sendmail_path','/usr/sbin/sendmail','/usr/sbin/sendmail','Location of sendmail if using this option','alerting',0,'general',0,'0','0'),(468,'email_smtp_host','localhost','localhost','SMTP Host for sending email if using this option','alerting',0,'general',0,'0','0'),(469,'email_smtp_port','25','25','SMTP port setting','alerting',0,'general',0,'0','0'),(470,'email_smtp_timeout','10','10','SMTP timeout setting','alerting',0,'general',0,'0','0'),(471,'email_smtp_secure','','','Enable / disable encryption (use tls or ssl)','alerting',0,'general',0,'0','0'),(472,'email_smtp_auth','false','FALSE','Enable / disable smtp authentication','alerting',0,'general',0,'0','0'),(473,'email_smtp_username','NULL','NULL','SMTP Auth username','alerting',0,'general',0,'0','0'),(474,'email_smtp_password','NULL','NULL','SMTP Auth password','alerting',0,'general',0,'0','0'),(475,'alert.macros.rule.port_down','(%ports.ifOperStatus = \"down\" && %ports.ifAdminStatus != \"down\" && %macros.port)','(%ports.ifOperStatus = \"down\" && %ports.ifAdminStatus != \"down\" && %macros.port)','Ports that are down','alerting',0,'macros',0,'1','0'),(486,'alert.syscontact','true','TRUE','Issue alerts to sysContact','alerting',0,'general',0,'0','0'),(487,'alert.fixed-contacts','true','TRUE','If TRUE any changes to sysContact or users emails will not be honoured whilst alert is active','alerting',0,'general',0,'0','0'),(488,'alert.transports.nagios','','','Nagios compatible via FIFO','alerting',0,'transports',0,'0','0'); -ALTER TABLE `munin_plugins` CHANGE `mplug_type` `mplug_type` VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL; -ALTER TABLE slas ENGINE=InnoDB; -ALTER TABLE packages ENGINE=InnoDB; -ALTER TABLE munin_plugins_ds ENGINE=InnoDB; -ALTER TABLE munin_plugins ENGINE=InnoDB; -ALTER TABLE loadbalancer_vservers ENGINE=InnoDB; -ALTER TABLE loadbalancer_rservers ENGINE=InnoDB; -ALTER TABLE ipsec_tunnels ENGINE=InnoDB; -CREATE TABLE `alert_template_map` (`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,`alert_templates_id` INT NOT NULL ,`alert_rule_id` INT NOT NULL ,INDEX ( `alert_templates_id` , `alert_rule_id` )) ENGINE = INNODB -ALTER TABLE `graph_types` CHANGE `graph_subtype` `graph_subtype` varchar(64); -ALTER TABLE `device_graphs` CHANGE `graph` `graph` varchar(64); -ALTER TABLE `graph_types` CHANGE `graph_descr` `graph_descr` varchar(255); -ALTER TABLE `graph_types` ADD PRIMARY KEY (`graph_type`, `graph_subtype`, `graph_section`); -insert into config (config_name,config_value,config_default,config_descr,config_group,config_group_order,config_sub_group,config_sub_group_order,config_hidden,config_disabled) values ('alert.macros.rule.sensor','(%sensors.sensor_alert = 1)','(%sensors.sensor_alert = 1)','Sensors of interest','alerting',0,'macros',0,1,0); -CREATE TABLE IF NOT EXISTS `device_perf` ( `id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL, `timestamp` datetime NOT NULL, `xmt` float NOT NULL, `rcv` float NOT NULL, `loss` float NOT NULL, `min` float NOT NULL, `max` float NOT NULL, `avg` float NOT NULL, KEY `id` (`id`,`device_id`)) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ; -insert into config (config_name,config_value,config_default,config_descr,config_group,config_group_order,config_sub_group,config_sub_group_order,config_hidden,config_disabled) values ('alert.macros.rule.packet_loss_15m','(%macros.past_15m && %device_perf.loss)','(%macros.past_15m && %device_perf.loss)','Packet loss over the last 15 minutes','alerting',0,'macros',0,1,0); -insert into config (config_name,config_value,config_default,config_descr,config_group,config_group_order,config_sub_group,config_sub_group_order,config_hidden,config_disabled) values ('alert.macros.rule.packet_loss_5m','(%macros.past_5m && %device_perf.loss)','(%macros.past_5m && %device_perf.loss)','Packet loss over the last 5 minutes','alerting',0,'macros',0,1,0); -ALTER TABLE `devices` ADD `status_reason` VARCHAR( 50 ) NOT NULL AFTER `status` ; -UPDATE `devices` SET `status_reason`='down' WHERE `status`=0; -ALTER TABLE `ipv4_mac` CHANGE `mac_address` `mac_address` VARCHAR( 32 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL , CHANGE `ipv4_address` `ipv4_address` VARCHAR( 32 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL -ALTER TABLE `ipv4_mac` ADD INDEX ( `port_id`), ADD INDEX (`mac_address` ) -ALTER TABLE `ipv4_mac` DROP INDEX `interface_id`, DROP INDEX `interface_id_2` -CREATE TABLE `locations` ( `id` INT NOT NULL AUTO_INCREMENT ,`location` TEXT NOT NULL ,`lat` FLOAT( 10, 6 ) NOT NULL ,`lng` FLOAT( 10, 6 ) NOT NULL ,`timestamp` DATETIME NOT NULL ,INDEX ( `id` )) ENGINE = INNODB; -ALTER TABLE `devices` ADD `override_sysLocation` bool DEFAULT false; -UPDATE `devices` LEFT JOIN devices_attribs AS sysloc_bool ON(devices.device_id=sysloc_bool.device_id and sysloc_bool.attrib_type = 'override_sysLocation_bool') LEFT JOIN devices_attribs AS sysloc_string ON(devices.device_id=sysloc_string.device_id and sysloc_string.attrib_type = 'override_sysLocation_string') SET `override_sysLocation` = true, `location` = sysloc_string.attrib_value WHERE sysloc_bool.attrib_value = 1; -CREATE TABLE `users_widgets` ( `user_widget_id` int(11) NOT NULL AUTO_INCREMENT, `user_id` int(11) NOT NULL, `widget_id` int(11) NOT NULL, `col` tinyint(4) NOT NULL, `row` tinyint(4) NOT NULL, `size_x` tinyint(4) NOT NULL, `size_y` tinyint(4) NOT NULL, `title` varchar(255) NOT NULL, `refresh` tinyint(4) NOT NULL DEFAULT '60', PRIMARY KEY (`user_widget_id`), KEY `user_id` (`user_id`,`widget_id`) ) ENGINE=InnoDB AUTO_INCREMENT=46 DEFAULT CHARSET=latin1; -CREATE TABLE `widgets` ( `widget_id` int(11) NOT NULL AUTO_INCREMENT, `widget_title` varchar(255) NOT NULL, `widget` varchar(255) NOT NULL, `base_dimensions` varchar(10) NOT NULL, PRIMARY KEY (`widget_id`), UNIQUE KEY `widget` (`widget`)) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1; -INSERT INTO `widgets` (`widget_id`, `widget_title`, `widget`, `base_dimensions`) VALUES (1, 'Availability map', 'availability-map', '4,3'), (2, 'Device summary horizontal', 'device-summary-horiz', '4,2'), (3, 'Alerts', 'alerts', '8,4'), (4, 'Device summary vertical', 'device-summary-vert', '4,3'), (5, 'World map', 'globe', '3,3'); -INSERT INTO `widgets` (`widget_title`, `widget`, `base_dimensions`) VALUES ('Syslog', 'syslog', '9,3'), ('Eventlog', 'eventlog', '9,5'), ('Global Map', 'worldmap', '8,6'); -ALTER TABLE `device_perf` DROP INDEX `id` , ADD INDEX `id` ( `id` ), ADD INDEX ( `device_id` ); -ALTER TABLE `bgpPeers` MODIFY `bgpPeerRemoteAs` bigint(20) NOT NULL; -INSERT INTO `widgets` (`widget_title`, `widget`, `base_dimensions`) VALUES ('Graylog', 'graylog', '9,7'); -insert into config (config_name,config_value,config_default,config_descr,config_group,config_group_order,config_sub_group,config_sub_group_order,config_hidden,config_disabled) values ('alert.transports.pushbullet','','','Pushbullet access token','alerting',0,'transports',0,'0','0'); -DELETE n1 FROM pollers n1, pollers n2 WHERE n1.last_polled < n2.last_polled and n1.poller_name = n2.poller_name; -ALTER TABLE pollers ADD PRIMARY KEY (poller_name); -ALTER TABLE `devices` ADD `last_poll_attempted` timestamp NULL DEFAULT NULL AFTER `last_polled`; -ALTER TABLE `devices` ADD INDEX `last_polled` (`last_polled`); -ALTER TABLE `devices` ADD INDEX `last_poll_attempted` (`last_poll_attempted`); -ALTER TABLE `alert_templates` ADD `title` VARCHAR(255) NULL DEFAULT NULL; -ALTER TABLE `alert_templates` ADD `title_rec` VARCHAR(255) NULL DEFAULT NULL; -CREATE TABLE `proxmox` ( `id` int(11) NOT NULL AUTO_INCREMENT, `device_id` int(11) NOT NULL DEFAULT '0', `vmid` int(11) NOT NULL, `cluster` varchar(255) NOT NULL, `description` varchar(255) DEFAULT NULL, `last_seen` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `cluster_vm` (`cluster`,`vmid`)) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE TABLE `proxmox_ports` ( `id` int(11) NOT NULL AUTO_INCREMENT, `vm_id` int(11) NOT NULL, `port` varchar(10) NOT NULL, `last_seen` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `vm_port` (`vm_id`,`port`)) ENGINE=InnoDB DEFAULT CHARSET=utf8; -ALTER TABLE `applications` ADD COLUMN `app_instance` varchar(255) NOT NULL; diff --git a/html/install.php b/html/install.php index 127af0b17..663c4cf44 100644 --- a/html/install.php +++ b/html/install.php @@ -10,7 +10,6 @@ $stage = $_POST['stage']; // Before we do anything, if we see config.php, redirect back to the homepage. if(file_exists('../config.php') && $stage != "6") { - session_destroy(); header("Location: /"); exit; } @@ -76,6 +75,7 @@ elseif($stage == "4") { } } elseif($stage == "6") { + session_destroy(); // If we get here then let's do some final checks. if(!file_exists("../config.php")) { // config.php file doesn't exist. go back to that stage diff --git a/includes/sql-schema/update.php b/includes/sql-schema/update.php index 264f1601b..841faafcd 100644 --- a/includes/sql-schema/update.php +++ b/includes/sql-schema/update.php @@ -94,6 +94,16 @@ if ($tmp[0] <= $db_rev) { foreach ($filelist as $file) { list($filename,$extension) = explode('.', $file, 2); if ($filename > $db_rev) { + + if (isset($_SESSION['stage']) ) { + $limit++; + if ( abs($limit-$_REQUEST['offset']) > 6) { + $_SESSION['offset'] = $limit; + echo 'Updating, please wait..'.date('r').''; + die(); + } + } + if (!$updating) { echo "-- Updating database schema\n"; } From ca0f9ea2f927adf2fe750e6a3ed05d5303c4ab68 Mon Sep 17 00:00:00 2001 From: f0o Date: Tue, 1 Sep 2015 23:38:10 +0100 Subject: [PATCH 218/598] Avoid useless I/O --- build-base.php | 4 ---- html/install.php | 7 ++++++- includes/sql-schema/update.php | 3 +++ 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/build-base.php b/build-base.php index 507abb266..29700db22 100644 --- a/build-base.php +++ b/build-base.php @@ -54,7 +54,3 @@ while (!feof($sql_fh)) { fclose($sql_fh); require 'includes/sql-schema/update.php'; - -if( isset($_SESSION['stage']) ) { - $_SESSION['build-ok'] = true; -} diff --git a/html/install.php b/html/install.php index 663c4cf44..8619e7b4a 100644 --- a/html/install.php +++ b/html/install.php @@ -318,7 +318,12 @@ elseif($stage == "2") { $config['db_name']=$dbname; $config['db']['extension']='mysqli'; $sql_file = '../build.sql'; - require '../build-base.php'; + if ($_REQUEST['offset'] =< 100) { + require '../build-base.php'; + } + else { + require '../includes/sql-schema/update.php'; + } ?> diff --git a/includes/sql-schema/update.php b/includes/sql-schema/update.php index 841faafcd..45bf671b2 100644 --- a/includes/sql-schema/update.php +++ b/includes/sql-schema/update.php @@ -168,5 +168,8 @@ foreach ($filelist as $file) { if ($updating) { echo "-- Done\n"; + if( isset($_SESSION['stage']) ) { + $_SESSION['build-ok'] = true; + } } From a2096dad51fa5ef080fdd88349a2fc20f7bcc4b6 Mon Sep 17 00:00:00 2001 From: f0o Date: Tue, 1 Sep 2015 23:38:48 +0100 Subject: [PATCH 219/598] Remove dupe-warning suppressor --- build-base.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-base.php b/build-base.php index 29700db22..56860774e 100644 --- a/build-base.php +++ b/build-base.php @@ -45,7 +45,7 @@ while (!feof($sql_fh)) { if (!empty($line)) { $creation = mysqli_query($database_link, $line); - if (!$creation && ($limit <= 100 || $limit > 391) ) { + if (!$creation) { echo 'WARNING: Cannot execute query ('.$line.'): '.mysqli_error($database_link)."\n"; } } From e64d145bf1dfe0cc1bff9bcdef5c28ff9fd932c2 Mon Sep 17 00:00:00 2001 From: f0o Date: Tue, 1 Sep 2015 23:39:48 +0100 Subject: [PATCH 220/598] Gracefully break update --- includes/sql-schema/update.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/sql-schema/update.php b/includes/sql-schema/update.php index 45bf671b2..7bbe7fc3b 100644 --- a/includes/sql-schema/update.php +++ b/includes/sql-schema/update.php @@ -100,7 +100,7 @@ foreach ($filelist as $file) { if ( abs($limit-$_REQUEST['offset']) > 6) { $_SESSION['offset'] = $limit; echo 'Updating, please wait..'.date('r').''; - die(); + return; } } From 574e4c52908bb6df66d152c330a545f6cd2f3351 Mon Sep 17 00:00:00 2001 From: f0o Date: Tue, 1 Sep 2015 23:40:43 +0100 Subject: [PATCH 221/598] Typo --- html/install.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/html/install.php b/html/install.php index 8619e7b4a..b3775d2a8 100644 --- a/html/install.php +++ b/html/install.php @@ -318,7 +318,7 @@ elseif($stage == "2") { $config['db_name']=$dbname; $config['db']['extension']='mysqli'; $sql_file = '../build.sql'; - if ($_REQUEST['offset'] =< 100) { + if ($_REQUEST['offset'] <= 100) { require '../build-base.php'; } else { From 501cf5a6ef15ad92745f47c512744b199cda263c Mon Sep 17 00:00:00 2001 From: f0o Date: Wed, 2 Sep 2015 00:13:14 +0100 Subject: [PATCH 222/598] Present all output+errors at the end --- build-base.php | 2 +- html/install.php | 11 ++++++++--- includes/sql-schema/update.php | 3 ++- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/build-base.php b/build-base.php index 56860774e..1abbe7642 100644 --- a/build-base.php +++ b/build-base.php @@ -36,7 +36,7 @@ while (!feof($sql_fh)) { } elseif ( abs($limit-$_REQUEST['offset']) > 6) { $_SESSION['offset'] = $limit; - echo 'Installing, please wait..'.date('r').''; + $GLOBALS['refresh'] = 'Installing, please wait..'.date('r').''; return; } else { echo 'Step #'.$limit.' ...'.PHP_EOL; diff --git a/html/install.php b/html/install.php index b3775d2a8..bec581e35 100644 --- a/html/install.php +++ b/html/install.php @@ -309,7 +309,6 @@ elseif($stage == "2") {
    Importing MySQL DB - Do not close this page or interrupt the import
    -
     ".$_SESSION['out']."
    "; ?> -
    diff --git a/includes/sql-schema/update.php b/includes/sql-schema/update.php index 7bbe7fc3b..837794abf 100644 --- a/includes/sql-schema/update.php +++ b/includes/sql-schema/update.php @@ -91,6 +91,7 @@ if ($tmp[0] <= $db_rev) { return; } +$limit = @$limit?: $_REQUEST['offset']; foreach ($filelist as $file) { list($filename,$extension) = explode('.', $file, 2); if ($filename > $db_rev) { @@ -99,7 +100,7 @@ foreach ($filelist as $file) { $limit++; if ( abs($limit-$_REQUEST['offset']) > 6) { $_SESSION['offset'] = $limit; - echo 'Updating, please wait..'.date('r').''; + $GLOBALS['refresh'] = 'Updating, please wait..'.date('r').''; return; } } From 9ca926b9c6bd2b6a9d85be1ca0270461f2b79c56 Mon Sep 17 00:00:00 2001 From: f0o Date: Wed, 2 Sep 2015 14:30:15 +0100 Subject: [PATCH 223/598] SQLs are performed up to an execution time of 45s, then a page reload is induced to avoid fcgi/cgi/modphp timeouts. --- build-base.php | 2 +- html/install.php | 5 +++-- includes/sql-schema/update.php | 16 ++++++++-------- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/build-base.php b/build-base.php index 1abbe7642..c6135a12c 100644 --- a/build-base.php +++ b/build-base.php @@ -34,7 +34,7 @@ while (!feof($sql_fh)) { if (isset($_SESSION['offset']) && $limit < $_REQUEST['offset']) { continue; } - elseif ( abs($limit-$_REQUEST['offset']) > 6) { + elseif ( time()-$_SESSION['last'] > 45 ) { $_SESSION['offset'] = $limit; $GLOBALS['refresh'] = 'Installing, please wait..'.date('r').''; return; diff --git a/html/install.php b/html/install.php index bec581e35..232a44c12 100644 --- a/html/install.php +++ b/html/install.php @@ -317,6 +317,7 @@ elseif($stage == "2") { $config['db_name']=$dbname; $config['db']['extension']='mysqli'; $sql_file = '../build.sql'; + $_SESSION['last'] = time(); ob_end_flush(); ob_start(); if ($_SESSION['offset'] < 100 && $_REQUEST['offset'] < 94) { @@ -325,11 +326,11 @@ elseif($stage == "2") { else { require '../includes/sql-schema/update.php'; } - $_SESSION['out'] .= ob_get_clean().PHP_EOL; + $_SESSION['out'] .= ob_get_clean(); ob_end_clean(); ob_start(); echo $GLOBALS['refresh']; - echo "
    ".$_SESSION['out']."
    "; + echo "
    ".trim($_SESSION['out'])."
    "; ?>
    diff --git a/includes/sql-schema/update.php b/includes/sql-schema/update.php index 837794abf..3f3cab661 100644 --- a/includes/sql-schema/update.php +++ b/includes/sql-schema/update.php @@ -91,19 +91,19 @@ if ($tmp[0] <= $db_rev) { return; } -$limit = @$limit?: $_REQUEST['offset']; +$limit = 150; //magic marker far enough in the future foreach ($filelist as $file) { list($filename,$extension) = explode('.', $file, 2); if ($filename > $db_rev) { - if (isset($_SESSION['stage']) ) { - $limit++; - if ( abs($limit-$_REQUEST['offset']) > 6) { - $_SESSION['offset'] = $limit; - $GLOBALS['refresh'] = 'Updating, please wait..'.date('r').''; - return; + if (isset($_SESSION['stage']) ) { + $limit++; + if ( time()-$_SESSION['last'] > 45 ) { + $_SESSION['offset'] = $limit; + $GLOBALS['refresh'] = 'Updating, please wait..'.date('r').''; + return; + } } - } if (!$updating) { echo "-- Updating database schema\n"; From 38bd3cf763f48c63eeae94c881a7cac09b0a8ba6 Mon Sep 17 00:00:00 2001 From: f0o Date: Thu, 3 Sep 2015 15:15:17 +0100 Subject: [PATCH 224/598] fix a typo --- alerts.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/alerts.php b/alerts.php index 23b282a23..dc8e9949a 100755 --- a/alerts.php +++ b/alerts.php @@ -228,7 +228,7 @@ function RunAlerts() { if (!empty($rextra['count']) && empty($rextra['interval'])) { // This check below is for compat-reasons if (!empty($rextra['delay'])) { - if ((time() - strtotime($alert['time_logged']) + $config['alert']['tolerance-window']) < $rextra['delay'] || (!empty($alert['details']['delay']) && (time() - $alert['details']['delay'] + $config['alert']['tolerance-window']) < $rextra['delay'])) { + if ((time() - strtotime($alert['time_logged']) + $config['alert']['tolerance_window']) < $rextra['delay'] || (!empty($alert['details']['delay']) && (time() - $alert['details']['delay'] + $config['alert']['tolerance_window']) < $rextra['delay'])) { continue; } else { @@ -248,12 +248,12 @@ function RunAlerts() { } else { // This is the new way - if (!empty($rextra['delay']) && (time() - strtotime($alert['time_logged']) + $config['alert']['tolerance-window']) < $rextra['delay']) { + if (!empty($rextra['delay']) && (time() - strtotime($alert['time_logged']) + $config['alert']['tolerance_window']) < $rextra['delay']) { continue; } if (!empty($rextra['interval'])) { - if (!empty($alert['details']['interval']) && (time() - $alert['details']['interval'] + $config['alert']['tolerance-window']) < $rextra['interval']) { + if (!empty($alert['details']['interval']) && (time() - $alert['details']['interval'] + $config['alert']['tolerance_window']) < $rextra['interval']) { continue; } else { From 0a478e7ef9079829d4b86f13fe01b60e9f1ac1eb Mon Sep 17 00:00:00 2001 From: laf Date: Fri, 4 Sep 2015 01:06:16 +0000 Subject: [PATCH 225/598] Added support for Oxidized versioning --- doc/Extensions/Oxidized.md | 40 ++++++++++++++ html/pages/device/showconfig.inc.php | 82 ++++++++++++++++++++++------ 2 files changed, 106 insertions(+), 16 deletions(-) create mode 100644 doc/Extensions/Oxidized.md diff --git a/doc/Extensions/Oxidized.md b/doc/Extensions/Oxidized.md new file mode 100644 index 000000000..5d82dcdf5 --- /dev/null +++ b/doc/Extensions/Oxidized.md @@ -0,0 +1,40 @@ +# Oxidized integration + +You can integrate LibreNMS with [Oxidized](https://github.com/ytti/oxidized-web) in two ways: + +### Config viewing + +This is a straight forward use of Oxidized, it relies on you having a working Oxidized setup which is already taking config snapshots for your devices. +When you have that, you only need the following config to enable the display of device configs within the device page itself: + +```php +$config['oxidized']['enabled'] = TRUE; +$config['oxidized']['url'] = 'http://127.0.0.1:8888'; +``` + +We also support config versioning within Oxidized, this will allow you to see the old configs stored. At present this is waiting on a [PR](https://github.com/ytti/oxidized-web/pull/25) to be merged upstream into Oxidized but you could simply patch your local install in the meantime. + +```php +$config['oxidized']['features']['versioning'] = true; +``` + +### Feeding Oxidized + +Oxidized has support for feeding devices into it via an API call, support for Oxidized has been added to the LibreNMS API. A sample config for Oxidized is provided below. + +You will need to configure default credentials for your devices, LibreNMS doesn't provide login credentials at this time. + +```bash + source: + default: http + debug: false + http: + url: https://librenms/api/v0/oxidized + scheme: https + delimiter: !ruby/regexp /:/ + map: + name: hostname + model: os + headers: + X-Auth-Token: '01582bf94c03104ecb7953dsadsadwed' +``` diff --git a/html/pages/device/showconfig.inc.php b/html/pages/device/showconfig.inc.php index 9efc95d63..ac5672d82 100644 --- a/html/pages/device/showconfig.inc.php +++ b/html/pages/device/showconfig.inc.php @@ -94,26 +94,76 @@ if ($_SESSION['userlevel'] >= '7') { } else if ($config['oxidized']['enabled'] === true && isset($config['oxidized']['url'])) { $node_info = json_decode(file_get_contents($config['oxidized']['url'].'/node/show/'.$device['hostname'].'?format=json'), true); - $text = file_get_contents($config['oxidized']['url'].'/node/fetch/'.$device['hostname']); - if ($text == 'node not found') { - $text = file_get_contents($config['oxidized']['url'].'/node/fetch/'.$device['os'].'/'.$device['hostname']); + if ($config['oxidized']['features']['versioning'] === true && isset($_POST['config'])) { + list($oid,$date,$version) = explode('|',mres($_POST['config'])); + $text = file_get_contents($config['oxidized']['url'].'/node/version/view?node='.$device['hostname'].'&group=&oid='.$oid.'&date='.urlencode($date).'&num='.$version.'&format=text'); + if ($text == 'node not found') { + $text = file_get_contents($config['oxidized']['url'].'/node/version/view?node='.$device['hostname'].'&group='.$device['os'].'&oid='.$oid.'&date='.urlencode($date).'&num='.$version.'&format=text'); + } + } + else { + $text = file_get_contents($config['oxidized']['url'].'/node/fetch/'.$device['hostname']); + if ($text == 'node not found') { + $text = file_get_contents($config['oxidized']['url'].'/node/fetch/'.$device['os'].'/'.$device['hostname']); + } + } + if ($config['oxidized']['features']['versioning'] === true) { + $config_versions = json_decode(file_get_contents($config['oxidized']['url'].'/node/version?node_full='.$device['hostname'].'&format=json'), true); } - if (is_array($node_info)) { + if (is_array($node_info) || is_array($config_versions)) { echo '
    -
    -
    -
    Sync status: '.$node_info['last']['status'].'
    -
      -
    • Node: '.$node_info['name'].'
    • -
    • IP: '.$node_info['ip'].'
    • -
    • Model: '.$node_info['model'].'
    • -
    • Last Sync: '.$node_info['last']['end'].'
    • -
    -
    -
    -
    '; + '; + + if (is_array($node_info)) { + echo ' +
    +
    +
    Sync status: '.$node_info['last']['status'].'
    +
      +
    • Node: '.$node_info['name'].'
    • +
    • IP: '.$node_info['ip'].'
    • +
    • Model: '.$node_info['model'].'
    • +
    • Last Sync: '.$node_info['last']['end'].'
    • +
    +
    +
    + '; + } + + if (is_array($config_versions)) { + echo ' +
    +
    +
    + +
    + +
    +
    +
    +
    + +
    +
    +
    +
    + '; + } + + echo '
    '; } else { echo '
    '; From 91a61e285c295a461d882f1214e94a3b996ebeb3 Mon Sep 17 00:00:00 2001 From: laf Date: Fri, 4 Sep 2015 09:07:30 +0000 Subject: [PATCH 226/598] Removed notice that upstream PR is waiting to be merged --- doc/Extensions/Oxidized.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/Extensions/Oxidized.md b/doc/Extensions/Oxidized.md index 5d82dcdf5..7fb605571 100644 --- a/doc/Extensions/Oxidized.md +++ b/doc/Extensions/Oxidized.md @@ -12,7 +12,7 @@ $config['oxidized']['enabled'] = TRUE; $config['oxidized']['url'] = 'http://127.0.0.1:8888'; ``` -We also support config versioning within Oxidized, this will allow you to see the old configs stored. At present this is waiting on a [PR](https://github.com/ytti/oxidized-web/pull/25) to be merged upstream into Oxidized but you could simply patch your local install in the meantime. +We also support config versioning within Oxidized, this will allow you to see the old configs stored. ```php $config['oxidized']['features']['versioning'] = true; From 5e213990e01255feb57b72f6c74d50ab71baf593 Mon Sep 17 00:00:00 2001 From: f0o Date: Fri, 4 Sep 2015 21:49:31 +0100 Subject: [PATCH 227/598] Make test-alert an 'alert' instead of 'recovery' --- html/includes/forms/test-transport.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/html/includes/forms/test-transport.inc.php b/html/includes/forms/test-transport.inc.php index 4919a7ebc..05b4dcfdd 100644 --- a/html/includes/forms/test-transport.inc.php +++ b/html/includes/forms/test-transport.inc.php @@ -34,7 +34,7 @@ $obj = array( "name" => "Test-Rule", "timestamp" => date("Y-m-d H:i:s"), "contacts" => $tmp['contacts'], - "state" => "0", + "state" => "1", "msg" => "This is a test alert", ); From 31bf0b4dbf935e3002a75549f085ddb0f27f021a Mon Sep 17 00:00:00 2001 From: Daniel Preussker Date: Sat, 5 Sep 2015 15:51:20 +0100 Subject: [PATCH 228/598] remove debug statement --- includes/common.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/includes/common.php b/includes/common.php index 1fc1e648c..bcef46da0 100644 --- a/includes/common.php +++ b/includes/common.php @@ -693,9 +693,7 @@ function get_graph_subtypes($type) { // find the MIB subtypes foreach ($config['graph_types'] as $type => $unused1) { - print_r($type); foreach ($config['graph_types'][$type] as $subtype => $unused2) { - print_r($subtype); if (is_mib_graph($type, $subtype)) { $types[] = $subtype; } From 41cff319410e44db99aa653bb8db2929933de7cd Mon Sep 17 00:00:00 2001 From: Daniel Preussker Date: Sat, 5 Sep 2015 15:53:43 +0100 Subject: [PATCH 229/598] Allow multiple instances of the same widget --- .../forms/update-dashboard-config.inc.php | 24 +++++++------------ 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/html/includes/forms/update-dashboard-config.inc.php b/html/includes/forms/update-dashboard-config.inc.php index c2760adb5..fd6dc18a4 100644 --- a/html/includes/forms/update-dashboard-config.inc.php +++ b/html/includes/forms/update-dashboard-config.inc.php @@ -20,22 +20,14 @@ elseif ($sub_type == 'remove-all') { } } elseif ($sub_type == 'add' && is_numeric($widget_id)) { - $dupe_check = dbFetchCEll('SELECT `user_widget_id` FROM `users_widgets` WHERE `user_id`=? AND `widget_id`=?',array($_SESSION['user_id'],$widget_id)); - - if (is_numeric($dupe_check)) { - $message = 'This widget has already been added'; - } - else { - - $widget = dbFetchRow('SELECT * FROM `widgets` WHERE `widget_id`=?', array($widget_id)); - if (is_array($widget)) { - list($x,$y) = explode(',',$widget['base_dimensions']); - $item_id = dbInsert(array('user_id'=>$_SESSION['user_id'],'widget_id'=>$widget_id, 'col'=>1,'row'=>1,'refresh'=>60,'title'=>$widget['widget_title'],'size_x'=>$x,'size_y'=>$y),'users_widgets'); - if (is_numeric($item_id)) { - $extra = array('widget_id'=>$item_id,'title'=>$widget['widget_title'],'widget'=>$widget['widget'],'size_x'=>$x,'size_y'=>$y); - $status = 'ok'; - $message = ''; - } + $widget = dbFetchRow('SELECT * FROM `widgets` WHERE `widget_id`=?', array($widget_id)); + if (is_array($widget)) { + list($x,$y) = explode(',',$widget['base_dimensions']); + $item_id = dbInsert(array('user_id'=>$_SESSION['user_id'],'widget_id'=>$widget_id, 'col'=>1,'row'=>1,'refresh'=>60,'title'=>$widget['widget_title'],'size_x'=>$x,'size_y'=>$y),'users_widgets'); + if (is_numeric($item_id)) { + $extra = array('widget_id'=>$item_id,'title'=>$widget['widget_title'],'widget'=>$widget['widget'],'size_x'=>$x,'size_y'=>$y); + $status = 'ok'; + $message = ''; } } } From 7acc1d266a6e5fc013fad4cea085338d8bafaf25 Mon Sep 17 00:00:00 2001 From: Daniel Preussker Date: Sat, 5 Sep 2015 16:15:11 +0100 Subject: [PATCH 230/598] Added per-widget settings --- html/ajax_dash.php | 7 ++- html/includes/forms/widget-settings.inc.php | 52 +++++++++++++++++++++ html/pages/front/tiles.php | 46 +++++++++++++++--- sql-schema/068.sql | 1 + 4 files changed, 97 insertions(+), 9 deletions(-) create mode 100644 html/includes/forms/widget-settings.inc.php create mode 100644 sql-schema/068.sql diff --git a/html/ajax_dash.php b/html/ajax_dash.php index 3b4c56e46..a26e46e5a 100644 --- a/html/ajax_dash.php +++ b/html/ajax_dash.php @@ -33,8 +33,11 @@ if ($type == 'placeholder') { } elseif (is_file('includes/common/'.$type.'.inc.php')) { - $results_limit = 10; - $no_form = true; + $results_limit = 10; + $no_form = true; + $widget_id = mres($_POST['id']); + $widget_settings = json_decode(dbFetchCell('select settings from users_widgets where user_widget_id = ?',array($widget_id)),true); + $widget_dimensions = dbfetchRow('select size_x,size_y from users_widgets where user_widget_id = ?',array($widget_id)); include 'includes/common/'.$type.'.inc.php'; $output = implode('', $common_output); $status = 'ok'; diff --git a/html/includes/forms/widget-settings.inc.php b/html/includes/forms/widget-settings.inc.php new file mode 100644 index 000000000..2ce0cde63 --- /dev/null +++ b/html/includes/forms/widget-settings.inc.php @@ -0,0 +1,52 @@ + + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + +/** + * Store per-widget settings + * @author Daniel Preussker + * @copyright 2015 Daniel Preussker, QuxLabs UG + * @license GPL + * @package LibreNMS + * @subpackage Widgets + */ + +$status = 'error'; +$message = 'unknown error'; +$widget_id = (int) $_REQUEST['id']; + +if ($widget_id < 1) { + $status = 'error'; + $message = 'ERROR: malformed widget ID.'; +} +else { + $widget_settings = $_REQUEST['settings']; + if (!is_array($widget_settings)) { + $widget_settings = array(); + } + if (dbUpdate(array('settings'=>json_encode($widget_settings)),'users_widgets','user_widget_id=?',array($widget_id))) { + $status = 'ok'; + $message = 'Updated'; + } + else { + $status = 'error'; + $message = 'ERROR: Could not update'; + } +} + +die(json_encode(array( + 'status' => $status, + 'message' => $message +))); +?> diff --git a/html/pages/front/tiles.php b/html/pages/front/tiles.php index ddaf61af4..063b4bba6 100644 --- a/html/pages/front/tiles.php +++ b/html/pages/front/tiles.php @@ -18,7 +18,7 @@ $no_refresh = true; -foreach (dbFetchRows('SELECT * FROM `users_widgets` LEFT JOIN `widgets` ON `widgets`.`widget_id`=`users_widgets`.`widget_id` WHERE `user_id`=?',array($_SESSION['user_id'])) as $items) { +foreach (dbFetchRows('SELECT user_widget_id,users_widgets.widget_id,title,widget,col,row,size_x,size_y,refresh FROM `users_widgets` LEFT JOIN `widgets` ON `widgets`.`widget_id`=`users_widgets`.`widget_id` WHERE `user_id`=?',array($_SESSION['user_id'])) as $items) { $data[] = $items; } @@ -121,7 +121,7 @@ foreach (dbFetchRows("SELECT * FROM `widgets` ORDER BY `widget_title`") as $widg gridster.remove_all_widgets(); $.each(serialization, function() { gridster.add_widget( - '
  • '+ + '
  • '+ '\var timeout'+this.user_widget_id+' = grab_data('+this.user_widget_id+','+this.refresh+',\''+this.widget+'\');\<\/script\>'+ '
    '+this.title+'
    '+ '
    '+this.widget+'
    '+ @@ -166,7 +166,7 @@ foreach (dbFetchRows("SELECT * FROM `widgets` ORDER BY `widget_title`") as $widg var size_x = data.extra.size_x; var size_y = data.extra.size_y; gridster.add_widget( - '
  • '+ + '
  • '+ '\var timeout'+widget_id+' = grab_data('+widget_id+',60,\''+widget+'\');\<\/script\>'+ '
    '+title+'
    '+ '
    '+widget+'
    '+ @@ -209,12 +209,40 @@ foreach (dbFetchRows("SELECT * FROM `widgets` ORDER BY `widget_title`") as $widg }); - function grab_data(id,refresh,data_type) { - new_refresh = refresh * 1000; + function widget_settings(data) { + var widget_settings = {}; + var widget_id = 0; + datas = $(data).serializeArray(); + for( var field in datas ) { + widget_settings[datas[field].name] = datas[field].value; + } +console.log(widget_settings); + $('.gridster').find('div[id^=widget_body_]').each(function() { + if(this.contains(data)) { + widget_id = $(this).parent().attr('id'); + widget_type = $(this).parent().data('type'); + } + }); + if( widget_id > 0 && widget_settings != {} ) { + $.ajax({ + type: 'POST', + url: 'ajax_form.php', + data: {type: 'widget-settings', id: widget_id, settings: widget_settings}, + dataType: "json", + success: function (data) { + if( data.status == "ok" ) { + widget_reload(widget_id,widget_type); + } + } + }); + } + } + + function widget_reload(id,data_type) { $.ajax({ type: 'POST', url: 'ajax_dash.php', - data: {type: data_type}, + data: {type: data_type, id: id}, dataType: "json", success: function (data) { if (data.status == 'ok') { @@ -228,7 +256,11 @@ foreach (dbFetchRows("SELECT * FROM `widgets` ORDER BY `widget_title`") as $widg $("#widget_body_"+id).html('
    Problem with backend
    '); } }); - + } + + function grab_data(id,refresh,data_type) { + new_refresh = refresh * 1000; + widget_reload(id,data_type); setTimeout(function() { grab_data(id,refresh,data_type); }, diff --git a/sql-schema/068.sql b/sql-schema/068.sql new file mode 100644 index 000000000..39784b418 --- /dev/null +++ b/sql-schema/068.sql @@ -0,0 +1 @@ +alter table users_widgets add column `settings` text not null; From 63ed6e25aab2176ff1602355401fefe129ee49b9 Mon Sep 17 00:00:00 2001 From: Daniel Preussker Date: Sat, 5 Sep 2015 16:15:56 +0100 Subject: [PATCH 231/598] Added generic graph widget (non-responsive sizing) --- html/includes/common/generic-graph.inc.php | 114 +++++++++++++++++++++ sql-schema/068.sql | 1 + 2 files changed, 115 insertions(+) create mode 100644 html/includes/common/generic-graph.inc.php diff --git a/html/includes/common/generic-graph.inc.php b/html/includes/common/generic-graph.inc.php new file mode 100644 index 000000000..b6e5773ee --- /dev/null +++ b/html/includes/common/generic-graph.inc.php @@ -0,0 +1,114 @@ + + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + +/** + * Generic Graph Widget + * @author Daniel Preussker + * @copyright 2015 Daniel Preussker, QuxLabs UG + * @license GPL + * @package LibreNMS + * @subpackage Widgets + */ + +if( empty($widget_settings) ) { + $common_output[] = ' +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    + +
    +'; +} +else { + $widget_settings['device_id'] = dbFetchCell('select device_id from devices where hostname = ?',array($widget_settings['graph_device'])); + $common_output[] = "
    ".$widget_settings['graph_device']." / ".$widget_settings['graph_type']."
    "; + $common_output[] = generate_minigraph_image(array('device_id'=>(int) $widget_settings['device_id']), $config['time']['day'], $config['time']['now'], $widget_settings['graph_type'], $widget_settings['graph_legend'] == 1 ? 'yes' : 'no', $widget_settings['graph_width'], $widget_settings['graph_height'], '&', $widget_settings['graph_type']); +} +?> + diff --git a/sql-schema/068.sql b/sql-schema/068.sql index 39784b418..d0bbda576 100644 --- a/sql-schema/068.sql +++ b/sql-schema/068.sql @@ -1 +1,2 @@ alter table users_widgets add column `settings` text not null; +insert into widgets values(null,'Graph','generic-graph','6,2'); From f081706ab1258e5df068fcd75001064ce128b91c Mon Sep 17 00:00:00 2001 From: Daniel Preussker Date: Sun, 6 Sep 2015 10:59:44 +0100 Subject: [PATCH 232/598] Added option to allow absolute dimensions on graphs --- html/includes/functions.inc.php | 4 ++-- html/includes/graphs/common.inc.php | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/html/includes/functions.inc.php b/html/includes/functions.inc.php index 7b7ea62ca..b4ab63c70 100644 --- a/html/includes/functions.inc.php +++ b/html/includes/functions.inc.php @@ -181,8 +181,8 @@ function get_percentage_colours($percentage) { }//end get_percentage_colours() -function generate_minigraph_image($device, $start, $end, $type, $legend='no', $width=275, $height=100, $sep='&', $class='minigraph-image') { - return ''; +function generate_minigraph_image($device, $start, $end, $type, $legend='no', $width=275, $height=100, $sep='&', $class='minigraph-image',$absolute_size=0) { + return ''; }//end generate_minigraph_image() diff --git a/html/includes/graphs/common.inc.php b/html/includes/graphs/common.inc.php index 9dbc97b80..ba77fb3f6 100644 --- a/html/includes/graphs/common.inc.php +++ b/html/includes/graphs/common.inc.php @@ -103,3 +103,7 @@ else { } $rrd_options .= ' --font-render-mode normal'; + +if (isset($_GET['absolute']) && $_GET['absolute'] == "1") { + $rrd_options .= ' --full-size-mode'; +} From 9951c98e70bbb8c394864cbcce4169482fe00e48 Mon Sep 17 00:00:00 2001 From: Daniel Preussker Date: Sun, 6 Sep 2015 13:18:54 +0100 Subject: [PATCH 233/598] Added edit-page Added responsive resizing support for graph widget --- html/ajax_dash.php | 11 +- html/includes/common/generic-graph.inc.php | 81 ++++---- .../forms/update-dashboard-config.inc.php | 2 +- html/pages/front/tiles.php | 183 ++++++++++-------- 4 files changed, 153 insertions(+), 124 deletions(-) diff --git a/html/ajax_dash.php b/html/ajax_dash.php index a26e46e5a..ec88e68ec 100644 --- a/html/ajax_dash.php +++ b/html/ajax_dash.php @@ -30,23 +30,30 @@ $type = mres($_POST['type']); if ($type == 'placeholder') { $output = 'Please add a Widget to get started'; $status = 'ok'; + $title = 'Placeholder'; } elseif (is_file('includes/common/'.$type.'.inc.php')) { $results_limit = 10; $no_form = true; + $title = ucfirst($type); + $unique_id = str_replace(array("-","."),"_",uniqid($type,true)); $widget_id = mres($_POST['id']); $widget_settings = json_decode(dbFetchCell('select settings from users_widgets where user_widget_id = ?',array($widget_id)),true); - $widget_dimensions = dbfetchRow('select size_x,size_y from users_widgets where user_widget_id = ?',array($widget_id)); + $widget_dimensions = $_POST['dimensions']; + if( !empty($_POST['settings']) ) { + define('show_settings',true); + } include 'includes/common/'.$type.'.inc.php'; $output = implode('', $common_output); $status = 'ok'; - + $title = $widget_settings['title'] ?: $title; } $response = array( 'status' => $status, 'html' => $output, + 'title' => $title, ); echo _json_encode($response); diff --git a/html/includes/common/generic-graph.inc.php b/html/includes/common/generic-graph.inc.php index b6e5773ee..9d79fff22 100644 --- a/html/includes/common/generic-graph.inc.php +++ b/html/includes/common/generic-graph.inc.php @@ -22,13 +22,13 @@ * @subpackage Widgets */ -if( empty($widget_settings) ) { +if( defined('show_settings') || empty($widget_settings) ) { $common_output[] = '
    - +
    @@ -37,10 +37,10 @@ if( empty($widget_settings) ) { Legend + Legend
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    + +'; } else { $widget_settings['device_id'] = dbFetchCell('select device_id from devices where hostname = ?',array($widget_settings['graph_device'])); - $common_output[] = "
    ".$widget_settings['graph_device']." / ".$widget_settings['graph_type']."
    "; - $common_output[] = generate_minigraph_image(array('device_id'=>(int) $widget_settings['device_id']), $config['time']['day'], $config['time']['now'], $widget_settings['graph_type'], $widget_settings['graph_legend'] == 1 ? 'yes' : 'no', $widget_settings['graph_width'], $widget_settings['graph_height'], '&', $widget_settings['graph_type']); + $widget_settings['title'] = $widget_settings['graph_device']." / ".$widget_settings['graph_type']; + $common_output[] = generate_minigraph_image( + array('device_id'=>(int) $widget_settings['device_id']), + $config['time']['day'], + $config['time']['now'], + $widget_settings['graph_type'], + $widget_settings['graph_legend'] == 1 ? 'yes' : 'no', + $widget_dimensions['x'], + $widget_dimensions['y'], + '&', + 'minigraph-image', + 1 + ); } ?> diff --git a/html/includes/forms/update-dashboard-config.inc.php b/html/includes/forms/update-dashboard-config.inc.php index fd6dc18a4..de278fd91 100644 --- a/html/includes/forms/update-dashboard-config.inc.php +++ b/html/includes/forms/update-dashboard-config.inc.php @@ -25,7 +25,7 @@ elseif ($sub_type == 'add' && is_numeric($widget_id)) { list($x,$y) = explode(',',$widget['base_dimensions']); $item_id = dbInsert(array('user_id'=>$_SESSION['user_id'],'widget_id'=>$widget_id, 'col'=>1,'row'=>1,'refresh'=>60,'title'=>$widget['widget_title'],'size_x'=>$x,'size_y'=>$y),'users_widgets'); if (is_numeric($item_id)) { - $extra = array('widget_id'=>$item_id,'title'=>$widget['widget_title'],'widget'=>$widget['widget'],'size_x'=>$x,'size_y'=>$y); + $extra = array('user_widget_id'=>$item_id,'widget_id'=>$item_id,'title'=>$widget['widget_title'],'widget'=>$widget['widget'],'refresh'=>60,'size_x'=>$x,'size_y'=>$y); $status = 'ok'; $message = ''; } diff --git a/html/pages/front/tiles.php b/html/pages/front/tiles.php index 063b4bba6..5c6effb1e 100644 --- a/html/pages/front/tiles.php +++ b/html/pages/front/tiles.php @@ -103,31 +103,25 @@ foreach (dbFetchRows("SELECT * FROM `widgets` ORDER BY `widget_title`") as $widg }, resize: { enabled: true, - stop: function(e, ui, $widget) { + stop: function(e, ui, widget) { updatePos(gridster); + widget_reload(widget.attr('id'),widget.data('type')); } }, - serialize_params: function($w, wgd) { - return { - id: $($w).attr('id'), - col: wgd.col, - row: wgd.row, - size_x: wgd.size_x, - size_y: wgd.size_y + serialize_params: function(w, wgd) { + return { + id: $(w).attr('id'), + col: wgd.col, + row: wgd.row, + size_x: wgd.size_x, + size_y: wgd.size_y }; } }).data('gridster'); gridster.remove_all_widgets(); $.each(serialization, function() { - gridster.add_widget( - '
  • '+ - '\var timeout'+this.user_widget_id+' = grab_data('+this.user_widget_id+','+this.refresh+',\''+this.widget+'\');\<\/script\>'+ - '
    '+this.title+'
    '+ - '
    '+this.widget+'
    '+ - '
  • ', - parseInt(this.size_x), parseInt(this.size_y), parseInt(this.col), parseInt(this.row) - ); + widget_dom(this); }); $(document).on('click','#clear_widgets', function() { @@ -160,19 +154,7 @@ foreach (dbFetchRows("SELECT * FROM `widgets` ORDER BY `widget_title`") as $widg dataType: "json", success: function (data) { if (data.status == 'ok') { - var widget_id = data.extra.widget_id; - var title = data.extra.title; - var widget = data.extra.widget; - var size_x = data.extra.size_x; - var size_y = data.extra.size_y; - gridster.add_widget( - '
  • '+ - '\var timeout'+widget_id+' = grab_data('+widget_id+',60,\''+widget+'\');\<\/script\>'+ - '
    '+title+'
    '+ - '
    '+widget+'
    '+ - '
  • ', - parseInt(size_x), parseInt(size_y) - ); + widget_dom(data.extra); updatePos(gridster); } else { @@ -207,65 +189,96 @@ foreach (dbFetchRows("SELECT * FROM `widgets` ORDER BY `widget_title`") as $widg }); }); + $(document).on("click",".edit-widget",function() { + obj = $(this).parent().parent(); + if( obj.data('settings') == 1 ) { + obj.data('settings','0'); + } else { + obj.data('settings','1'); + } + widget_reload(obj.attr('id'),obj.data('type')); + }); + }); - function widget_settings(data) { - var widget_settings = {}; - var widget_id = 0; - datas = $(data).serializeArray(); - for( var field in datas ) { - widget_settings[datas[field].name] = datas[field].value; - } -console.log(widget_settings); - $('.gridster').find('div[id^=widget_body_]').each(function() { - if(this.contains(data)) { - widget_id = $(this).parent().attr('id'); - widget_type = $(this).parent().data('type'); - } - }); - if( widget_id > 0 && widget_settings != {} ) { - $.ajax({ - type: 'POST', - url: 'ajax_form.php', - data: {type: 'widget-settings', id: widget_id, settings: widget_settings}, - dataType: "json", - success: function (data) { - if( data.status == "ok" ) { - widget_reload(widget_id,widget_type); - } - } - }); - } - } + function widget_dom(data) { + dom = '
  • '+ + '
    '+data.title+''+ + ''+ + ''+ + '
    '+ + '
    '+data.widget+'
    '+ + '\var timeout'+data.user_widget_id+' = grab_data('+data.user_widget_id+','+data.refresh+',\''+data.widget+'\');\<\/script\>'+ + '
  • '; + if (data.hasOwnProperty('col') && data.hasOwnProperty('row')) { + gridster.add_widget(dom, parseInt(data.size_x), parseInt(data.size_y), parseInt(data.col), parseInt(data.row)); + } else { + gridster.add_widget(dom, parseInt(data.size_x), parseInt(data.size_y)); + } + } - function widget_reload(id,data_type) { - $.ajax({ - type: 'POST', - url: 'ajax_dash.php', - data: {type: data_type, id: id}, - dataType: "json", - success: function (data) { - if (data.status == 'ok') { - $("#widget_body_"+id).html(data.html); - } - else { - $("#widget_body_"+id).html('
    ' + data.message + '
    '); - } - }, - error: function () { - $("#widget_body_"+id).html('
    Problem with backend
    '); - } - }); - } + function widget_settings(data) { + var widget_settings = {}; + var widget_id = 0; + datas = $(data).serializeArray(); + for( var field in datas ) { + widget_settings[datas[field].name] = datas[field].value; + } + $('.gridster').find('div[id^=widget_body_]').each(function() { + if(this.contains(data)) { + widget_id = $(this).parent().attr('id'); + widget_type = $(this).parent().data('type'); + $(this).parent().data('settings','0'); + } + }); + if( widget_id > 0 && widget_settings != {} ) { + $.ajax({ + type: 'POST', + url: 'ajax_form.php', + data: {type: 'widget-settings', id: widget_id, settings: widget_settings}, + dataType: "json", + success: function (data) { + if( data.status == "ok" ) { + widget_reload(widget_id,widget_type); + } + } + }); + } + } - function grab_data(id,refresh,data_type) { - new_refresh = refresh * 1000; - widget_reload(id,data_type); - setTimeout(function() { - grab_data(id,refresh,data_type); - }, - new_refresh); - } -$('#new-widget').popover(); + function widget_reload(id,data_type) { + if( $("#widget_body_"+id).parent().data('settings') == 1 ) { + settings = 1; + } else { + settings = 0; + } + $.ajax({ + type: 'POST', + url: 'ajax_dash.php', + data: {type: data_type, id: id, dimensions: {x:$("#widget_body_"+id).innerWidth()-50, y:$("#widget_body_"+id).innerHeight()-50}, settings:settings}, + dataType: "json", + success: function (data) { + if (data.status == 'ok') { + $("#widget_title_"+id).html(data.title); + $("#widget_body_"+id).html(data.html); + } + else { + $("#widget_body_"+id).html('
    ' + data.message + '
    '); + } + }, + error: function () { + $("#widget_body_"+id).html('
    Problem with backend
    '); + } + }); + } + function grab_data(id,refresh,data_type) { + new_refresh = refresh * 1000; + widget_reload(id,data_type); + setTimeout(function() { + grab_data(id,refresh,data_type); + }, + new_refresh); + } + $('#new-widget').popover(); From b741e479a446258d02dcf258e55fe369bfa616da Mon Sep 17 00:00:00 2001 From: Daniel Preussker Date: Sun, 6 Sep 2015 13:37:48 +0100 Subject: [PATCH 234/598] Allow drag on title-text --- html/pages/front/tiles.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/html/pages/front/tiles.php b/html/pages/front/tiles.php index 5c6effb1e..e679f5079 100644 --- a/html/pages/front/tiles.php +++ b/html/pages/front/tiles.php @@ -96,7 +96,7 @@ foreach (dbFetchRows("SELECT * FROM `widgets` ORDER BY `widget_title`") as $widg widget_margins: [5, 5], avoid_overlapped_widgets: true, draggable: { - handle: 'header', + handle: 'header, span', stop: function(e, ui, $widget) { updatePos(gridster); }, From 64f1f3a6365eb2930a91aee19e826a5b68d6d5ed Mon Sep 17 00:00:00 2001 From: Daniel Preussker Date: Sun, 6 Sep 2015 14:28:55 +0100 Subject: [PATCH 235/598] scrut fixes --- html/includes/common/generic-graph.inc.php | 1 - html/includes/forms/widget-settings.inc.php | 1 - 2 files changed, 2 deletions(-) diff --git a/html/includes/common/generic-graph.inc.php b/html/includes/common/generic-graph.inc.php index 9d79fff22..3ac02ab69 100644 --- a/html/includes/common/generic-graph.inc.php +++ b/html/includes/common/generic-graph.inc.php @@ -119,5 +119,4 @@ else { 1 ); } -?> diff --git a/html/includes/forms/widget-settings.inc.php b/html/includes/forms/widget-settings.inc.php index 2ce0cde63..1926d3491 100644 --- a/html/includes/forms/widget-settings.inc.php +++ b/html/includes/forms/widget-settings.inc.php @@ -49,4 +49,3 @@ die(json_encode(array( 'status' => $status, 'message' => $message ))); -?> From 8182abe5f1ba96cc8984dea8af70c78033346b53 Mon Sep 17 00:00:00 2001 From: Daniel Preussker Date: Sat, 5 Sep 2015 20:06:29 +0200 Subject: [PATCH 236/598] Update Changelog --- doc/General/Changelog.md | 67 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/doc/General/Changelog.md b/doc/General/Changelog.md index 25eb1421a..f6fe9ab3c 100644 --- a/doc/General/Changelog.md +++ b/doc/General/Changelog.md @@ -1,3 +1,34 @@ +### September + +#### Bug fixes + - Alerting: + - Process followups if there are changes (PR1817) + - Typo in alert_window setting (PR1841) + - Issue alert-trigger as test object (PR1850) + - General: + - Remove 'sh' from cronjob (PR1818) + - Remove MySQL Locks (PR1822,PR1826,PR1829,PR1836) + +#### Improvements + - WebUI: + - Ability to edit ifAlias (PR1811) + - Honour Mouseout/Mouseleave on map widget (PR1814) + - Make syslog/eventlog responsive (PR1816) + - Reformat Proxmox UI (PR1825,PR1827) + - Misc Changes (PR1828,PR1830) + - Added support for Oxidized versioning (PR1842) + - Added graph widget + settings for widgets (PR1835) + - Added detection for: + - FortiOS (PR1815) + - Discovery / Poller: + - Added Proxmox support (PR1789) + - Documentation: + - Add varnish docs (PR1809) + - General: + - Make installer more responsive (PR1832) + - Update fping millisec option to 200 default (PR1833) + - Reduced cleanup of device_perf (PR1837) + ### August 2015 #### Bug fixes @@ -8,6 +39,9 @@ - Fixed Web installer due to code tidying update (PR1644) - Updated gridster variable names to make unique (PR1646) - Fixed issues with displaying devices with ' in location (PR1655) + - Fixes updating snmpv3 details in webui (PR1727) + - Check for user perms before listing neighbour ports (PR1749) + - Fixed Test-Transport button (PR1772) - DB: - Added proper indexes on device_perf table (PR1621) - Fixed multiple mysql strict issues (PR1638, PR1659) @@ -17,8 +51,18 @@ - Fixed discovery-arp not running since code formatting update (PR1671) - Correct the DSM upgrade OID (PR1696) - Fix MySQL agent host variable usage (PR1710) + - Pass snmp-auth parameters enclosed by single-quotes (PR1730) + - Revert change which skips over down ports (PR1742) + - Stop PoE polling for each port (PR1747) + - Use ifHighSpeed if ifSpeed equals 0 (PR1750) + - Keep PHP Backwards compatibility (PR1766) + - False identification of Zyxel as Cisco (PR1776) + - Fix MySQL statement in poller-service.py (PR1794) + - Fix upstart script for poller-service.py (PR1812) - General: - Fixed path to defaults.inc.php in config.php.default (PR1673) + - Strip '::ffff:' from syslog input (PR1734) + - Fix RRA (PR1791) #### Improvements - WebUI Updates: @@ -32,29 +76,50 @@ - Added support for running under sub-directory (PR1667) - Updated vis.js to latest version (PR1708) - Added border on availability map (PR1713) + - Make new dashboard the default (PR1719) + - Rearrange about page (PR1735,PR1743) + - Center/Cleanup graphs (PR1736) + - Added Hover-Effect on devices table (PR1738) + - Show Test-Transport result (PR1777) + - Add arrows to the network map (PR1787) + - Add errored ports to summary widget (PR1788) + - Show message if no Device-Groups exist (PR1796) + - Misc UI fixes (Titles, Headers, ...) (PR1797,PR1798,PR1800,PR1801,PR1802,PR1803,PR1804,PR1805) + - Move packages to overview dropdown (PR1810) - API Updates: - Improvided billing support in API (PR1599) + - Extended support for list devices to support mac/ipv4 and ipv6 filtering (PR1744) - Added detection for: - Perle Media convertors (PR1607) + - Mac OSX 10 (PR1774) - Improved detection for: - Windows devices (PR1639) - - Zywall CPU, Version and Memory (PR1660) + - Zywall CPU, Version and Memory (PR1660,PR1784) - Added LLDP support for PBN devices (PR1705) + - Netgear GS110TP (PR1751) - Additional Sensors: - Added Compressor state for PCOWEB (PR1600) - Added dbm support for IOS-XR (PR1661) + - Added temperature support for DNOS (PR1782) - Discovery / Poller: - Updated autodiscovery function to log new type (PR1623) + - Improve application polling (PR1724) + - Improve debug output (PR1756) - DB: - Added MySQLi support (PR1647) - Documentation: - Added docs on MySQL strict mode (PR1635) - Updated billing docs to use librenms user in cron (PR1676) - Updated LDAP docs to indicate php-ldap module needs installing (PR1716) + - Typo/Spellchecks (PR1731,PR1806) + - Improved Alerting and Device-Groups (PR1781) - Alerting: - Reformatted eventlog message to show state for alerts (PR1685) + - Add basic Pushbullet transport (PR1721) + - Allow custom titles (PR1807) - General: - Added more debugging and checks to discovery-protocols (PR1590) + - Cleanup debug statements (PR1725,PR1737) ### July 2015 From e0e4f97747729ec0b533efb683121894944fab6e Mon Sep 17 00:00:00 2001 From: Daniel Preussker Date: Sun, 6 Sep 2015 16:13:08 +0000 Subject: [PATCH 237/598] Fixed typo in changelog --- doc/General/Changelog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/General/Changelog.md b/doc/General/Changelog.md index f6fe9ab3c..86c04213e 100644 --- a/doc/General/Changelog.md +++ b/doc/General/Changelog.md @@ -1,4 +1,4 @@ -### September +### September 2015 #### Bug fixes - Alerting: From e8188c6143f9ee2689be59a302d2043b39419a84 Mon Sep 17 00:00:00 2001 From: Sergiusz Paprzycki Date: Sun, 6 Sep 2015 23:08:14 +0100 Subject: [PATCH 238/598] I agree to the conditions of the Contributor Agreement contained in doc/General/Contributing.md. --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 95833993b..610f95b21 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -50,6 +50,7 @@ Contributors to LibreNMS: - Mark Schouten (tuxis-ie) - Todd Eddy (vrillusions) - Arjit Chaudhary (arjit.c@gmail.com) (arjitc) +- Sergiusz Paprzycki (spaprzycki) [1]: http://observium.org/ "Observium web site" From 130d1c452a2bd36b31560a5e74e6ed1646daa866 Mon Sep 17 00:00:00 2001 From: Daniel Preussker Date: Mon, 7 Sep 2015 19:29:30 +0100 Subject: [PATCH 239/598] Added application and munin search operations --- html/ajax_search.php | 108 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 99 insertions(+), 9 deletions(-) diff --git a/html/ajax_search.php b/html/ajax_search.php index 791513972..e42655ee9 100644 --- a/html/ajax_search.php +++ b/html/ajax_search.php @@ -96,23 +96,22 @@ if (isset($_REQUEST['search'])) { }//end if $json = json_encode($device); - print_r($json); - exit; + die($json); } else if ($_REQUEST['type'] == 'ports') { // Search ports if (is_admin() === true || is_read() === true) { - $results = dbFetchRows("SELECT `ports`.*,`devices`.* FROM `ports` LEFT JOIN `devices` ON `ports`.`device_id` = `devices`.`device_id` WHERE `ifAlias` LIKE '%".$search."%' OR `ifDescr` LIKE '%".$search."%' ORDER BY ifDescr LIMIT 8"); + $results = dbFetchRows("SELECT `ports`.*,`devices`.* FROM `ports` LEFT JOIN `devices` ON `ports`.`device_id` = `devices`.`device_id` WHERE `ifAlias` LIKE '%".$search."%' OR `ifDescr` LIKE '%".$search."%' OR `ifName` LIKE '%".$search."%' ORDER BY ifDescr LIMIT 8"); } else { - $results = dbFetchRows("SELECT DISTINCT(`I`.`port_id`), `I`.*, `D`.`hostname` FROM `ports` AS `I`, `devices` AS `D`, `devices_perms` AS `P`, `ports_perms` AS `PP` WHERE ((`P`.`user_id` = ? AND `P`.`device_id` = `D`.`device_id`) OR (`PP`.`user_id` = ? AND `PP`.`port_id` = `I`.`port_id` AND `I`.`device_id` = `D`.`device_id`)) AND `D`.`device_id` = `I`.`device_id` AND (`ifAlias` LIKE '%".$search."%' OR `ifDescr` LIKE '%".$search."%') ORDER BY ifDescr LIMIT 8", array($_SESSION['user_id'], $_SESSION['user_id'])); + $results = dbFetchRows("SELECT DISTINCT(`I`.`port_id`), `I`.*, `D`.`hostname` FROM `ports` AS `I`, `devices` AS `D`, `devices_perms` AS `P`, `ports_perms` AS `PP` WHERE ((`P`.`user_id` = ? AND `P`.`device_id` = `D`.`device_id`) OR (`PP`.`user_id` = ? AND `PP`.`port_id` = `I`.`port_id` AND `I`.`device_id` = `D`.`device_id`)) AND `D`.`device_id` = `I`.`device_id` AND (`ifAlias` LIKE '%".$search."%' OR `ifDescr` LIKE '%".$search."%' OR `ifName` LIKE '%".$search."%') ORDER BY ifDescr LIMIT 8", array($_SESSION['user_id'], $_SESSION['user_id'])); } if (count($results)) { $found = 1; foreach ($results as $result) { - $name = $result['ifDescr']; + $name = $result['ifDescr'] == $result['ifAlias'] ? $result['ifName'] : $result['ifDescr']; $description = $result['ifAlias']; if ($result['deleted'] == 0 && ($result['ignore'] == 0 || $result['ignore'] == 0) && ($result['ifInErrors_delta'] > 0 || $result['ifOutErrors_delta'] > 0)) { @@ -143,13 +142,13 @@ if (isset($_REQUEST['search'])) { 'description' => $description, 'colours' => $highlight_colour, 'hostname' => $result['hostname'], + 'port_id' => $result['port_id'], ); }//end foreach }//end if $json = json_encode($ports); - print_r($json); - exit; + die($json); } else if ($_REQUEST['type'] == 'bgp') { // Search bgp peers @@ -204,8 +203,99 @@ if (isset($_REQUEST['search'])) { }//end if $json = json_encode($bgp); - print_r($json); - exit; + die($json); + } + else if ($_REQUEST['type'] == 'applications') { + // Device search + if (is_admin() === true || is_read() === true) { + $results = dbFetchRows("SELECT * FROM `applications` INNER JOIN `devices` ON devices.device_id = applications.device_id WHERE `app_type` LIKE '%".$search."%' OR `hostname` LIKE '%".$search."%' ORDER BY hostname LIMIT 8"); + } + else { + $results = dbFetchRows("SELECT * FROM `applications` INNER JOIN `devices` AS `D` ON `D`.`device_id` = `applications`.`device_id` INNER JOIN `devices_perms` AS `P` ON `P`.`device_id` = `D`.`device_id` WHERE `P`.`user_id` = ? AND (`app_type` LIKE '%".$search."%' OR `hostname` LIKE '%".$search."%') ORDER BY hostname LIMIT 8", array($_SESSION['user_id'])); + } + + if (count($results)) { + $found = 1; + $devices = count($results); + + foreach ($results as $result) { + $name = $result['app_type']; + if ($result['disabled'] == 1) { + $highlight_colour = '#808080'; + } + else if ($result['ignored'] == 1 && $result['disabled'] == 0) { + $highlight_colour = '#000000'; + } + else if ($result['status'] == 0 && $result['ignore'] == 0 && $result['disabled'] == 0) { + $highlight_colour = '#ff0000'; + } + else if ($result['status'] == 1 && $result['ignore'] == 0 && $result['disabled'] == 0) { + $highlight_colour = '#008000'; + } + + $device[] = array( + 'name' => $name, + 'hostname' => $result['hostname'], + 'app_id' => $result['app_id'], + 'device_id' => $result['device_id'], + 'colours' => $highlight_colour, + 'device_image' => getImageSrc($result), + 'device_hardware' => $result['hardware'], + 'device_os' => $config['os'][$result['os']]['text'], + 'version' => $result['version'], + 'location' => $result['location'], + ); + }//end foreach + }//end if + + $json = json_encode($device); + die($json); + } + else if ($_REQUEST['type'] == 'munin') { + // Device search + if (is_admin() === true || is_read() === true) { + $results = dbFetchRows("SELECT * FROM `munin_plugins` INNER JOIN `devices` ON devices.device_id = munin_plugins.device_id WHERE `mplug_type` LIKE '%".$search."%' OR `mplug_title` LIKE '%".$search."%' OR `hostname` LIKE '%".$search."%' ORDER BY hostname LIMIT 8"); + } + else { + $results = dbFetchRows("SELECT * FROM `munin_plugins` INNER JOIN `devices` AS `D` ON `D`.`device_id` = `munin_plugins`.`device_id` INNER JOIN `devices_perms` AS `P` ON `P`.`device_id` = `D`.`device_id` WHERE `P`.`user_id` = ? AND (`mplug_type` LIKE '%".$search."%' OR `mplug_title` LIKE '%".$search."%' OR `hostname` LIKE '%".$search."%') ORDER BY hostname LIMIT 8", array($_SESSION['user_id'])); + } + + if (count($results)) { + $found = 1; + $devices = count($results); + + foreach ($results as $result) { + $name = $result['mplug_title']; + if ($result['disabled'] == 1) { + $highlight_colour = '#808080'; + } + else if ($result['ignored'] == 1 && $result['disabled'] == 0) { + $highlight_colour = '#000000'; + } + else if ($result['status'] == 0 && $result['ignore'] == 0 && $result['disabled'] == 0) { + $highlight_colour = '#ff0000'; + } + else if ($result['status'] == 1 && $result['ignore'] == 0 && $result['disabled'] == 0) { + $highlight_colour = '#008000'; + } + + $device[] = array( + 'name' => $name, + 'hostname' => $result['hostname'], + 'device_id' => $result['device_id'], + 'colours' => $highlight_colour, + 'device_image' => getImageSrc($result), + 'device_hardware' => $result['hardware'], + 'device_os' => $config['os'][$result['os']]['text'], + 'version' => $result['version'], + 'location' => $result['location'], + 'plugin' => $result['mplug_type'], + ); + }//end foreach + }//end if + + $json = json_encode($device); + die($json); }//end if }//end if }//end if From e8f7f3b6f83918060672402189de50000e6eb098 Mon Sep 17 00:00:00 2001 From: Daniel Preussker Date: Mon, 7 Sep 2015 19:30:22 +0100 Subject: [PATCH 240/598] Add reload lock if widget is in settings mode --- html/pages/front/tiles.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/html/pages/front/tiles.php b/html/pages/front/tiles.php index e679f5079..9c7c5c933 100644 --- a/html/pages/front/tiles.php +++ b/html/pages/front/tiles.php @@ -202,7 +202,7 @@ foreach (dbFetchRows("SELECT * FROM `widgets` ORDER BY `widget_title`") as $widg }); function widget_dom(data) { - dom = '
  • '+ + dom = '
  • '+ '
    '+data.title+''+ ''+ ''+ @@ -273,8 +273,10 @@ foreach (dbFetchRows("SELECT * FROM `widgets` ORDER BY `widget_title`") as $widg } function grab_data(id,refresh,data_type) { + if( $("#widget_body_"+id).parent().data('settings') == 0 ) { + widget_reload(id,data_type); + } new_refresh = refresh * 1000; - widget_reload(id,data_type); setTimeout(function() { grab_data(id,refresh,data_type); }, From e67ccd9463f08394f41678c8d70b448edd41ccdd Mon Sep 17 00:00:00 2001 From: Daniel Preussker Date: Mon, 7 Sep 2015 19:30:37 +0100 Subject: [PATCH 241/598] Added multiple graph type support for the graph widget --- html/includes/common/generic-graph.inc.php | 288 ++++++++++++++++++--- 1 file changed, 246 insertions(+), 42 deletions(-) diff --git a/html/includes/common/generic-graph.inc.php b/html/includes/common/generic-graph.inc.php index 3ac02ab69..4e75b16ca 100644 --- a/html/includes/common/generic-graph.inc.php +++ b/html/includes/common/generic-graph.inc.php @@ -26,35 +26,107 @@ if( defined('show_settings') || empty($widget_settings) ) { $common_output[] = '
    - -
    - +
    +
    -
    -
    -
    -
    -
    - +
    +
    +
    + +
    +
    + +
    +
    +
    +
    + +
    +
    + +
    +
    +
    +
    + +
    +
    + +
    +
    +
    +
    + +
    +
    + +
    +
    +
    +
    + +
    +
    + +
    +
    +
    +
    + +
    +
    -'; } else { - $widget_settings['device_id'] = dbFetchCell('select device_id from devices where hostname = ?',array($widget_settings['graph_device'])); - $widget_settings['title'] = $widget_settings['graph_device']." / ".$widget_settings['graph_type']; - $common_output[] = generate_minigraph_image( - array('device_id'=>(int) $widget_settings['device_id']), - $config['time']['day'], - $config['time']['now'], - $widget_settings['graph_type'], - $widget_settings['graph_legend'] == 1 ? 'yes' : 'no', - $widget_dimensions['x'], - $widget_dimensions['y'], - '&', - 'minigraph-image', - 1 - ); + $widget_settings['title'] = ""; + $type = array_shift(explode('_',$widget_settings['graph_type'],2)); + $widget_settings['graph_'.$type] = json_decode($widget_settings['graph_'.$type],true); + if ($type == 'device') { + $widget_settings['title'] = $widget_settings['graph_device']['name']." / ".$widget_settings['graph_type']; + $param = 'device='.$widget_settings['graph_device']['device_id']; + } + elseif ($type == 'application') { + $param = 'id='.$widget_settings['graph_'.$type]['app_id']; + } + elseif ($type == 'munin') { + $param = 'device='.$widget_settings['graph_'.$type]['device_id'].'&plugin='.$widget_settings['graph_'.$type]['name']; + } + else { + $param = 'id='.$widget_settings['graph_'.$type][$type.'_id']; + } + if (empty($widget_settings['title'])) { + $widget_settings['title'] = $widget_settings['graph_'.$type]['hostname']." / ".$widget_settings['graph_'.$type]['name']." / ".$widget_settings['graph_type']; + } + $common_output[] = ''; } - From a4d27d3eba3e26bdf34ab9e4f640b5689f046c18 Mon Sep 17 00:00:00 2001 From: Daniel Preussker Date: Mon, 7 Sep 2015 19:52:22 +0100 Subject: [PATCH 242/598] scrut fixes --- html/includes/common/generic-graph.inc.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/html/includes/common/generic-graph.inc.php b/html/includes/common/generic-graph.inc.php index 4e75b16ca..81776efe1 100644 --- a/html/includes/common/generic-graph.inc.php +++ b/html/includes/common/generic-graph.inc.php @@ -41,7 +41,8 @@ if( defined('show_settings') || empty($widget_settings) ) { foreach (get_graph_subtypes($type) as $avail_type) { $display_type = is_mib_graph($type, $avail_type) ? $avail_type : nicecase($avail_type); if( strstr($display_type,'_') ) { - $sub = array_shift(explode('_',$display_type,2)); + $sub = explode('_',$display_type,2); + $sub = array_shift($sub); if( $sub != $old ) { $old = $sub; $common_output[] = ''; @@ -304,7 +305,8 @@ $(function() { } else { $widget_settings['title'] = ""; - $type = array_shift(explode('_',$widget_settings['graph_type'],2)); + $type = explode('_',$widget_settings['graph_type'],2); + $type = array_shift($type); $widget_settings['graph_'.$type] = json_decode($widget_settings['graph_'.$type],true); if ($type == 'device') { $widget_settings['title'] = $widget_settings['graph_device']['name']." / ".$widget_settings['graph_type']; From 29c55eb41568e6de2f231d07fa0eac0280600a2f Mon Sep 17 00:00:00 2001 From: Sergiusz Paprzycki Date: Sun, 6 Sep 2015 22:40:08 +0100 Subject: [PATCH 243/598] Leaflet module now checks device permissions --- html/includes/common/worldmap.inc.php | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/html/includes/common/worldmap.inc.php b/html/includes/common/worldmap.inc.php index f6ba921a4..03a3b9603 100644 --- a/html/includes/common/worldmap.inc.php +++ b/html/includes/common/worldmap.inc.php @@ -51,7 +51,26 @@ var greenMarker = L.AwesomeMarkers.icon({ }); '; -foreach (dbFetchRows("SELECT `device_id`,`hostname`,`os`,`status`,`lat`,`lng` FROM `devices` LEFT JOIN `locations` ON `devices`.`location`=`locations`.`location` WHERE `disabled`=0 AND `ignore`=0 AND `lat` != '' AND `lng` != '' ORDER BY `status` ASC, `hostname`") as $map_devices) { +// Checking user permissions +if (is_admin() || is_read()) { +// Admin or global read-only - show all devices + $sql = "SELECT `device_id`,`hostname`,`os`,`status`,`lat`,`lng` FROM `devices` + LEFT JOIN `locations` ON `devices`.`location`=`locations`.`location` + WHERE `disabled`=0 AND `ignore`=0 AND `lat` != '' AND `lng` != '' + ORDER BY `status` ASC, `hostname`"; +} +else { +// Normal user - grab devices that user has permissions to + $sql = "SELECT `devices`.`device_id` as `device_id`,`hostname`,`os`,`status`,`lat`,`lng` + FROM `devices_perms`, `devices` + LEFT JOIN `locations` ON `devices`.`location`=`locations`.`location` + WHERE `disabled`=0 AND `ignore`=0 AND `lat` != '' AND `lng` != '' + AND `devices`.`device_id` = `devices_perms`.`device_id` + AND `devices_perms`.`user_id` = '".$_SESSION['user_id']."' + ORDER BY `status` ASC, `hostname`"; +} +// Slightly modified foreach - grabbing SQL query string from above +foreach (dbFetchRows($sql) as $map_devices) { $icon = 'greenMarker'; if ($map_devices['status'] == 0) { $icon = 'redMarker'; From d568830df35518974c4bdef61767c66f3f822f67 Mon Sep 17 00:00:00 2001 From: Sergiusz Paprzycki Date: Sun, 6 Sep 2015 23:14:52 +0100 Subject: [PATCH 244/598] Leaflet map permissions check #1855 --- html/includes/common/worldmap.inc.php | 1 - 1 file changed, 1 deletion(-) diff --git a/html/includes/common/worldmap.inc.php b/html/includes/common/worldmap.inc.php index 03a3b9603..7feae55a5 100644 --- a/html/includes/common/worldmap.inc.php +++ b/html/includes/common/worldmap.inc.php @@ -69,7 +69,6 @@ else { AND `devices_perms`.`user_id` = '".$_SESSION['user_id']."' ORDER BY `status` ASC, `hostname`"; } -// Slightly modified foreach - grabbing SQL query string from above foreach (dbFetchRows($sql) as $map_devices) { $icon = 'greenMarker'; if ($map_devices['status'] == 0) { From a54dcd76ab764b5389fba8434e0d04ebab5ae146 Mon Sep 17 00:00:00 2001 From: Sergiusz Paprzycki Date: Mon, 7 Sep 2015 15:45:27 +0100 Subject: [PATCH 245/598] Leaflet map permissions check #1855; SQL/query modified as requested --- html/includes/common/worldmap.inc.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/html/includes/common/worldmap.inc.php b/html/includes/common/worldmap.inc.php index 7feae55a5..dea7224e7 100644 --- a/html/includes/common/worldmap.inc.php +++ b/html/includes/common/worldmap.inc.php @@ -66,10 +66,10 @@ else { LEFT JOIN `locations` ON `devices`.`location`=`locations`.`location` WHERE `disabled`=0 AND `ignore`=0 AND `lat` != '' AND `lng` != '' AND `devices`.`device_id` = `devices_perms`.`device_id` - AND `devices_perms`.`user_id` = '".$_SESSION['user_id']."' + AND `devices_perms`.`user_id` = ? ORDER BY `status` ASC, `hostname`"; } -foreach (dbFetchRows($sql) as $map_devices) { +foreach (dbFetchRows($sql, array($_SESSION['user_id'])) as $map_devices) { $icon = 'greenMarker'; if ($map_devices['status'] == 0) { $icon = 'redMarker'; From 98b50b60bafddad04348e7ecac5cf5a8be6749dd Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 2 Sep 2015 11:54:27 -0400 Subject: [PATCH 246/598] thread locking in python --- poller-service.py | 62 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 45 insertions(+), 17 deletions(-) diff --git a/poller-service.py b/poller-service.py index 099bf7213..a310541e0 100755 --- a/poller-service.py +++ b/poller-service.py @@ -33,6 +33,7 @@ import MySQLdb import logging import logging.handlers from datetime import datetime, timedelta +from collections import namedtuple log = logging.getLogger('poller-service') log.setLevel(logging.DEBUG) @@ -129,17 +130,20 @@ try: except KeyError: down_retry = 60 -try: - if db_port == 0: - db = MySQLdb.connect(host=db_server, user=db_username, passwd=db_password, db=db_dbname) - else: - db = MySQLdb.connect(host=db_server, port=db_port, user=db_username, passwd=db_password, db=db_dbname) - db.autocommit(True) - cursor = db.cursor() -except: - log.critical("ERROR: Could not connect to MySQL database!") - sys.exit(2) +def connectDB(): + try: + if db_port == 0: + db_inst = MySQLdb.connect(host=db_server, user=db_username, passwd=db_password, db=db_dbname) + else: + db_inst = MySQLdb.connect(host=db_server, port=db_port, user=db_username, passwd=db_password, db=db_dbname) + db_inst.autocommit(True) + cursor_inst = db_inst.cursor() + return cursor_inst + except: + log.critical("ERROR: Could not connect to MySQL database!") + sys.exit(2) +cursor = connectDB() def poll_worker(device_id, action): try: @@ -148,7 +152,9 @@ def poll_worker(device_id, action): if action == 'discovery': path = discover_path command = "/usr/bin/env php %s -h %s >> /dev/null 2>&1" % (path, device_id) - subprocess.check_call(command, shell=True) + if getThreadLock('{0}.{1}'.format(action, device_id)): + subprocess.check_call(command, shell=True) + releaseThreadLock('{0}.{1}'.format(action, device_id)) elapsed_time = int(time.time() - start_time) if elapsed_time < 300: log.debug("DEBUG: worker finished %s of device %s in %s seconds" % (action, device_id, elapsed_time)) @@ -160,27 +166,49 @@ def poll_worker(device_id, action): pass -def lockFree(lock): - global cursor +def lockFree(lock, cursor=cursor): query = "SELECT IS_FREE_LOCK('{0}')".format(lock) cursor.execute(query) return cursor.fetchall()[0][0] == 1 -def getLock(lock): - global cursor +def getLock(lock, cursor=cursor): query = "SELECT GET_LOCK('{0}', 0)".format(lock) cursor.execute(query) return cursor.fetchall()[0][0] == 1 -def releaseLock(lock): - global cursor +thread_cursors = [] +for i in range(0, amount_of_workers): + thread_cursors.append(namedtuple('Cursor{}'.format(i), ['in_use', 'cursor'])) + thread_cursors[i].in_use = False + thread_cursors[i].cursor = connectDB + + +def getThreadLock(lock): + global thread_cursors + for thread_cursor in thread_cursors: + if not thread_cursor.in_use: + thread_cursor.in_use = lock + return getLock(lock, thread_cursor.cursor) + return False + + +def releaseLock(lock, cursor=cursor): query = "SELECT RELEASE_LOCK('{0}')".format(lock) cursor.execute(query) return cursor.fetchall()[0][0] == 1 +def releaseThreadLock(lock): + global thread_cursors + for thread_cursor in thread_cursors: + if thread_cursor.in_use == lock: + thread_cursor.in_use = False + return releaseLock(lock, thread_cursor.cursor) + return False + + def sleep_until(timestamp): now = datetime.now() if timestamp > now: From 964896d6b09a0d65dbb9ffcfca14125d5f9582ff Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 2 Sep 2015 12:46:01 -0400 Subject: [PATCH 247/598] return db object to keep it from going out of scope --- poller-service.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/poller-service.py b/poller-service.py index a310541e0..60f737068 100755 --- a/poller-service.py +++ b/poller-service.py @@ -138,12 +138,17 @@ def connectDB(): db_inst = MySQLdb.connect(host=db_server, port=db_port, user=db_username, passwd=db_password, db=db_dbname) db_inst.autocommit(True) cursor_inst = db_inst.cursor() - return cursor_inst + ret = namedtuple('db_connection', ['db', 'cursor']) + ret.db = db_inst + ret.cursor = cursor_inst + return ret except: log.critical("ERROR: Could not connect to MySQL database!") sys.exit(2) -cursor = connectDB() +db_connection = connectDB() +db = db_connection.db +cursor = db_connection.cursor def poll_worker(device_id, action): try: @@ -180,9 +185,11 @@ def getLock(lock, cursor=cursor): thread_cursors = [] for i in range(0, amount_of_workers): - thread_cursors.append(namedtuple('Cursor{}'.format(i), ['in_use', 'cursor'])) + thread_cursors.append(namedtuple('Cursor{}'.format(i), ['in_use', 'cursor', 'db'])) thread_cursors[i].in_use = False - thread_cursors[i].cursor = connectDB + thread_db_connection = connectDB() + thread_cursors[i].cursor = thread_db_connection.cursor + thread_cursors[i].db = thread_db_connection.db def getThreadLock(lock): From aafca03ec706e7f3d2fb240c743ba1be15464419 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 2 Sep 2015 12:50:24 -0400 Subject: [PATCH 248/598] queue locks are no longer necessary --- poller-service.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/poller-service.py b/poller-service.py index 60f737068..6c5fd2c88 100755 --- a/poller-service.py +++ b/poller-service.py @@ -251,7 +251,6 @@ dev_query = ('SELECT device_id, status, 'FROM devices WHERE ' 'disabled = 0 ' 'AND IS_FREE_LOCK(CONCAT("polling.", device_id)) ' - 'AND IS_FREE_LOCK(CONCAT("queued.", device_id)) ' 'AND ( last_poll_attempted < DATE_SUB(NOW(), INTERVAL {2} SECOND ) ' ' OR last_poll_attempted IS NULL ) ' '{3} ' @@ -305,14 +304,6 @@ while True: devices = cursor.fetchall() for device_id, status, next_poll, next_discovery in devices: - # add queue lock, so we lock the next device against any other pollers - # if this fails, the device is locked by another poller already - if not getLock('queued.{0}'.format(device_id)): - continue - if not lockFree('polling.{0}'.format(device_id)): - releaseLock('queued.{0}'.format(device_id)) - continue - if next_poll and next_poll > datetime.now(): log.debug('DEBUG: Sleeping until {0} before polling {1}'.format(next_poll, device_id)) sleep_until(next_poll) From d11ad883bb44a695dcbbef52896294454a4b0b9c Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 2 Sep 2015 12:56:59 -0400 Subject: [PATCH 249/598] make sure lock name matches action --- poller-service.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/poller-service.py b/poller-service.py index 6c5fd2c88..c5fed7077 100755 --- a/poller-service.py +++ b/poller-service.py @@ -250,7 +250,8 @@ dev_query = ('SELECT device_id, status, ') as next_discovery ' 'FROM devices WHERE ' 'disabled = 0 ' - 'AND IS_FREE_LOCK(CONCAT("polling.", device_id)) ' + 'AND IS_FREE_LOCK(CONCAT("poll.", device_id)) ' + 'AND IS_FREE_LOCK(CONCAT("discovery.", device_id)) ' 'AND ( last_poll_attempted < DATE_SUB(NOW(), INTERVAL {2} SECOND ) ' ' OR last_poll_attempted IS NULL ) ' '{3} ' From 020e40ab7f31ff521bdd1083b197182351c9e547 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 2 Sep 2015 13:01:38 -0400 Subject: [PATCH 250/598] python 2.6 compat --- poller-service.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poller-service.py b/poller-service.py index c5fed7077..9f75d6a94 100755 --- a/poller-service.py +++ b/poller-service.py @@ -185,7 +185,7 @@ def getLock(lock, cursor=cursor): thread_cursors = [] for i in range(0, amount_of_workers): - thread_cursors.append(namedtuple('Cursor{}'.format(i), ['in_use', 'cursor', 'db'])) + thread_cursors.append(namedtuple('Cursor{0}'.format(i), ['in_use', 'cursor', 'db'])) thread_cursors[i].in_use = False thread_db_connection = connectDB() thread_cursors[i].cursor = thread_db_connection.cursor From fb899c1ebe05fae10169a3b99e14c01041e7b96b Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 2 Sep 2015 13:30:33 -0400 Subject: [PATCH 251/598] log when can't get lock --- poller-service.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/poller-service.py b/poller-service.py index 9f75d6a94..38eb8c397 100755 --- a/poller-service.py +++ b/poller-service.py @@ -160,6 +160,8 @@ def poll_worker(device_id, action): if getThreadLock('{0}.{1}'.format(action, device_id)): subprocess.check_call(command, shell=True) releaseThreadLock('{0}.{1}'.format(action, device_id)) + else: + log.debug("DEBUG: Couldn't get lock on {0}.{1}".format(action, device_id)) elapsed_time = int(time.time() - start_time) if elapsed_time < 300: log.debug("DEBUG: worker finished %s of device %s in %s seconds" % (action, device_id, elapsed_time)) From 8d7a937e03f20dd990226146f801090657a52ce2 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 2 Sep 2015 14:22:42 -0400 Subject: [PATCH 252/598] move thread control to lock threads --- poller-service.py | 45 ++++++++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/poller-service.py b/poller-service.py index 38eb8c397..9ebbb46b9 100755 --- a/poller-service.py +++ b/poller-service.py @@ -157,11 +157,7 @@ def poll_worker(device_id, action): if action == 'discovery': path = discover_path command = "/usr/bin/env php %s -h %s >> /dev/null 2>&1" % (path, device_id) - if getThreadLock('{0}.{1}'.format(action, device_id)): - subprocess.check_call(command, shell=True) - releaseThreadLock('{0}.{1}'.format(action, device_id)) - else: - log.debug("DEBUG: Couldn't get lock on {0}.{1}".format(action, device_id)) + subprocess.check_call(command, shell=True) elapsed_time = int(time.time() - start_time) if elapsed_time < 300: log.debug("DEBUG: worker finished %s of device %s in %s seconds" % (action, device_id, elapsed_time)) @@ -171,6 +167,9 @@ def poll_worker(device_id, action): raise except: pass + finally: + releaseThreadLock(device_id, action) + def lockFree(lock, cursor=cursor): @@ -194,12 +193,24 @@ for i in range(0, amount_of_workers): thread_cursors[i].db = thread_db_connection.db -def getThreadLock(lock): +def getThreadQueueLock(device_id): global thread_cursors + # This is how threads are limited, by the numver of cursors available + while True: + for thread_cursor in thread_cursors: + if not thread_cursor.in_use: + thread_cursor.in_use = 'queue.{0}'.format(device_id) + return getLock('queue.{0}'.format(device_id), thread_cursor.cursor) + time.sleep(.5) + + +def getThreadActionLock(device_id, action): + global thread_cursors + # This is how threads are limited, by the numver of cursors available for thread_cursor in thread_cursors: - if not thread_cursor.in_use: - thread_cursor.in_use = lock - return getLock(lock, thread_cursor.cursor) + if thread_cursor.in_use == 'queue.{0}'.format(device_id): + thread_cursor.in_use = '{0}.{1}'.format(action, device_id) + return getLock('{0}.{1}'.format(action, device_id), thread_cursor.cursor) return False @@ -209,12 +220,12 @@ def releaseLock(lock, cursor=cursor): return cursor.fetchall()[0][0] == 1 -def releaseThreadLock(lock): +def releaseThreadLock(device_id, action): global thread_cursors for thread_cursor in thread_cursors: - if thread_cursor.in_use == lock: + if thread_cursor.in_use == '{0}.{1}'.format(action, device_id): thread_cursor.in_use = False - return releaseLock(lock, thread_cursor.cursor) + return releaseLock('{0}.{1}'.format(action, device_id), thread_cursor.cursor) return False @@ -254,6 +265,7 @@ dev_query = ('SELECT device_id, status, 'disabled = 0 ' 'AND IS_FREE_LOCK(CONCAT("poll.", device_id)) ' 'AND IS_FREE_LOCK(CONCAT("discovery.", device_id)) ' + 'AND IS_FREE_LOCK(CONCAT("queue.", device_id)) ' 'AND ( last_poll_attempted < DATE_SUB(NOW(), INTERVAL {2} SECOND ) ' ' OR last_poll_attempted IS NULL ) ' '{3} ' @@ -296,9 +308,6 @@ while True: devices_scanned = 0 next_update = datetime.now() + timedelta(minutes=1) - while threading.active_count() >= amount_of_workers or not lockFree('schema_update'): - time.sleep(.5) - try: cursor.execute(dev_query) except: @@ -307,6 +316,9 @@ while True: devices = cursor.fetchall() for device_id, status, next_poll, next_discovery in devices: + if not getThreadQueueLock(device_id): + continue + if next_poll and next_poll > datetime.now(): log.debug('DEBUG: Sleeping until {0} before polling {1}'.format(next_poll, device_id)) sleep_until(next_poll) @@ -321,6 +333,9 @@ while True: cursor.execute('UPDATE devices SET last_poll_attempted = NOW() WHERE device_id = {0}'.format(device_id)) cursor.fetchall() + if not getThreadActionLock(device_id, action): + continue + t = threading.Thread(target=poll_worker, args=[device_id, action]) t.start() From b7ecea93233f538198acfc40fd2efdb772577bac Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 2 Sep 2015 14:42:57 -0400 Subject: [PATCH 253/598] make sure to clear the thread if unsuccessful --- poller-service.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/poller-service.py b/poller-service.py index 9ebbb46b9..ccab47f48 100755 --- a/poller-service.py +++ b/poller-service.py @@ -200,7 +200,10 @@ def getThreadQueueLock(device_id): for thread_cursor in thread_cursors: if not thread_cursor.in_use: thread_cursor.in_use = 'queue.{0}'.format(device_id) - return getLock('queue.{0}'.format(device_id), thread_cursor.cursor) + if getLock('queue.{0}'.format(device_id), thread_cursor.cursor): + return True + else: + thread_cursor.in_use = False time.sleep(.5) @@ -210,7 +213,10 @@ def getThreadActionLock(device_id, action): for thread_cursor in thread_cursors: if thread_cursor.in_use == 'queue.{0}'.format(device_id): thread_cursor.in_use = '{0}.{1}'.format(action, device_id) - return getLock('{0}.{1}'.format(action, device_id), thread_cursor.cursor) + if getLock('{0}.{1}'.format(action, device_id), thread_cursor.cursor): + return True + else: + thread_cursor.in_use = False return False From ecc4a696c7c9f7a4a1c857900d5ac7ae8e50e3d0 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 2 Sep 2015 15:01:25 -0400 Subject: [PATCH 254/598] release queue if getting action lock fails --- poller-service.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/poller-service.py b/poller-service.py index ccab47f48..9c17e0fe5 100755 --- a/poller-service.py +++ b/poller-service.py @@ -204,6 +204,8 @@ def getThreadQueueLock(device_id): return True else: thread_cursor.in_use = False + return False + log.debug("DEBUG: No threads avaliable") time.sleep(.5) @@ -217,6 +219,8 @@ def getThreadActionLock(device_id, action): return True else: thread_cursor.in_use = False + releaseLock('queue.{0}'.format(device_id), thread_cursor.cursor) + return False return False From 65b7d69e9a1183f787f93b429911421beb88974a Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 2 Sep 2015 15:23:47 -0400 Subject: [PATCH 255/598] always release queue lock --- poller-service.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poller-service.py b/poller-service.py index 9c17e0fe5..6d4296207 100755 --- a/poller-service.py +++ b/poller-service.py @@ -215,11 +215,11 @@ def getThreadActionLock(device_id, action): for thread_cursor in thread_cursors: if thread_cursor.in_use == 'queue.{0}'.format(device_id): thread_cursor.in_use = '{0}.{1}'.format(action, device_id) + releaseLock('queue.{0}'.format(device_id), thread_cursor.cursor) if getLock('{0}.{1}'.format(action, device_id), thread_cursor.cursor): return True else: thread_cursor.in_use = False - releaseLock('queue.{0}'.format(device_id), thread_cursor.cursor) return False return False From ca7daae7cdfbbce74f7ab14e8425bf63a55f699b Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 2 Sep 2015 15:38:45 -0400 Subject: [PATCH 256/598] remove spammy debug log --- poller-service.py | 1 - 1 file changed, 1 deletion(-) diff --git a/poller-service.py b/poller-service.py index 6d4296207..a9b292e4e 100755 --- a/poller-service.py +++ b/poller-service.py @@ -205,7 +205,6 @@ def getThreadQueueLock(device_id): else: thread_cursor.in_use = False return False - log.debug("DEBUG: No threads avaliable") time.sleep(.5) From dde75439d27aacc0004f4afaf5c3fa004b7ed809 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 2 Sep 2015 15:39:27 -0400 Subject: [PATCH 257/598] only log worker threads, not main python thread --- poller-service.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poller-service.py b/poller-service.py index a9b292e4e..e393f9ac7 100755 --- a/poller-service.py +++ b/poller-service.py @@ -292,7 +292,7 @@ while True: cur_threads = threading.active_count() if cur_threads != threads: threads = cur_threads - log.debug('DEBUG: {0} threads currently active'.format(threads)) + log.debug('DEBUG: {0} threads currently active'.format(str(threads - 1))) if next_update < datetime.now(): seconds_taken = (datetime.now() - (next_update - timedelta(minutes=1))).seconds From 68a970663fd1213e1a9cb1aca3e19e07b620d36d Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Tue, 8 Sep 2015 10:30:08 -0400 Subject: [PATCH 258/598] MySQL doesn't support specifying microsecond precision, and MariaDB defaults to zero, so it can be removed to be compatible with both. --- poller-service.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/poller-service.py b/poller-service.py index e393f9ac7..3f72ca4b9 100755 --- a/poller-service.py +++ b/poller-service.py @@ -259,7 +259,7 @@ dev_query = ('SELECT device_id, status, ' INTERVAL last_polled_timetaken SECOND ' ' ), ' ' INTERVAL {0} SECOND) ' - ' AS DATETIME(0) ' + ' AS DATETIME ' ') AS next_poll, ' 'CAST( ' ' DATE_ADD( ' @@ -268,7 +268,7 @@ dev_query = ('SELECT device_id, status, ' INTERVAL last_discovered_timetaken SECOND ' ' ), ' ' INTERVAL {1} SECOND) ' - ' AS DATETIME(0) ' + ' AS DATETIME ' ') as next_discovery ' 'FROM devices WHERE ' 'disabled = 0 ' From 49c786f394ffae4a322dbfc0d6956228427509a8 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Tue, 8 Sep 2015 13:51:10 -0400 Subject: [PATCH 259/598] make more resiliant to MySQL disconnects --- poller-service.py | 73 ++++++++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/poller-service.py b/poller-service.py index 3f72ca4b9..a11064e3f 100755 --- a/poller-service.py +++ b/poller-service.py @@ -49,6 +49,27 @@ config_file = install_dir + '/config.php' log.info('INFO: Starting poller-service') +class DB: + conn = None + + def connect(self): + if db_port == 0: + self.conn = MySQLdb.connect(host=db_server, user=db_username, passwd=db_password, db=db_dbname) + else: + self.conn = MySQLdb.connect(host=db_server, port=db_port, user=db_username, passwd=db_password, db=db_dbname) + self.conn.autocommit(True) + + def query(self, sql): + try: + cursor = self.conn.cursor() + cursor.execute(sql) + except (AttributeError, MySQLdb.OperationalError): + self.connect() + cursor = self.conn.cursor() + cursor.execute(sql) + return cursor + + def get_config_data(): config_cmd = ['/usr/bin/env', 'php', '%s/config_to_json.php' % install_dir] try: @@ -130,25 +151,7 @@ try: except KeyError: down_retry = 60 -def connectDB(): - try: - if db_port == 0: - db_inst = MySQLdb.connect(host=db_server, user=db_username, passwd=db_password, db=db_dbname) - else: - db_inst = MySQLdb.connect(host=db_server, port=db_port, user=db_username, passwd=db_password, db=db_dbname) - db_inst.autocommit(True) - cursor_inst = db_inst.cursor() - ret = namedtuple('db_connection', ['db', 'cursor']) - ret.db = db_inst - ret.cursor = cursor_inst - return ret - except: - log.critical("ERROR: Could not connect to MySQL database!") - sys.exit(2) - -db_connection = connectDB() -db = db_connection.db -cursor = db_connection.cursor +db = DB() def poll_worker(device_id, action): try: @@ -172,25 +175,23 @@ def poll_worker(device_id, action): -def lockFree(lock, cursor=cursor): +def lockFree(lock, db=db): query = "SELECT IS_FREE_LOCK('{0}')".format(lock) - cursor.execute(query) + cursor = db.query(query) return cursor.fetchall()[0][0] == 1 -def getLock(lock, cursor=cursor): +def getLock(lock, db=db): query = "SELECT GET_LOCK('{0}', 0)".format(lock) - cursor.execute(query) + cursor = db.query(query) return cursor.fetchall()[0][0] == 1 thread_cursors = [] for i in range(0, amount_of_workers): - thread_cursors.append(namedtuple('Cursor{0}'.format(i), ['in_use', 'cursor', 'db'])) + thread_cursors.append(namedtuple('Cursor{0}'.format(i), ['in_use', 'db'])) thread_cursors[i].in_use = False - thread_db_connection = connectDB() - thread_cursors[i].cursor = thread_db_connection.cursor - thread_cursors[i].db = thread_db_connection.db + thread_cursors[i].db = DB() def getThreadQueueLock(device_id): @@ -200,7 +201,7 @@ def getThreadQueueLock(device_id): for thread_cursor in thread_cursors: if not thread_cursor.in_use: thread_cursor.in_use = 'queue.{0}'.format(device_id) - if getLock('queue.{0}'.format(device_id), thread_cursor.cursor): + if getLock('queue.{0}'.format(device_id), thread_cursor.db): return True else: thread_cursor.in_use = False @@ -214,8 +215,8 @@ def getThreadActionLock(device_id, action): for thread_cursor in thread_cursors: if thread_cursor.in_use == 'queue.{0}'.format(device_id): thread_cursor.in_use = '{0}.{1}'.format(action, device_id) - releaseLock('queue.{0}'.format(device_id), thread_cursor.cursor) - if getLock('{0}.{1}'.format(action, device_id), thread_cursor.cursor): + releaseLock('queue.{0}'.format(device_id), thread_cursor.db) + if getLock('{0}.{1}'.format(action, device_id), thread_cursor.db): return True else: thread_cursor.in_use = False @@ -223,9 +224,9 @@ def getThreadActionLock(device_id, action): return False -def releaseLock(lock, cursor=cursor): +def releaseLock(lock, db=db): query = "SELECT RELEASE_LOCK('{0}')".format(lock) - cursor.execute(query) + cursor = db.query(query) return cursor.fetchall()[0][0] == 1 @@ -234,7 +235,7 @@ def releaseThreadLock(device_id, action): for thread_cursor in thread_cursors: if thread_cursor.in_use == '{0}.{1}'.format(action, device_id): thread_cursor.in_use = False - return releaseLock('{0}.{1}'.format(action, device_id), thread_cursor.cursor) + return releaseLock('{0}.{1}'.format(action, device_id), thread_cursor.db) return False @@ -308,7 +309,7 @@ while True: devices_scanned, seconds_taken) try: - cursor.execute(update_query) + cursor = db.query(update_query) except: log.critical('ERROR: MySQL query error. Is your schema up to date?') sys.exit(2) @@ -318,7 +319,7 @@ while True: next_update = datetime.now() + timedelta(minutes=1) try: - cursor.execute(dev_query) + cursor = db.query(dev_query) except: log.critical('ERROR: MySQL query error. Is your schema up to date?') sys.exit(2) @@ -339,7 +340,7 @@ while True: log.debug('DEBUG: Starting {0} of device {1}'.format(action, device_id)) devices_scanned += 1 - cursor.execute('UPDATE devices SET last_poll_attempted = NOW() WHERE device_id = {0}'.format(device_id)) + cursor = db.query('UPDATE devices SET last_poll_attempted = NOW() WHERE device_id = {0}'.format(device_id)) cursor.fetchall() if not getThreadActionLock(device_id, action): From 31cb8dddb7d65fd0589aad26f1894d3b5002e313 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 2 Sep 2015 11:54:27 -0400 Subject: [PATCH 260/598] thread locking in python --- poller-service.py | 124 ++++++++++++++++++---------------------------- 1 file changed, 49 insertions(+), 75 deletions(-) diff --git a/poller-service.py b/poller-service.py index a11064e3f..a310541e0 100755 --- a/poller-service.py +++ b/poller-service.py @@ -49,27 +49,6 @@ config_file = install_dir + '/config.php' log.info('INFO: Starting poller-service') -class DB: - conn = None - - def connect(self): - if db_port == 0: - self.conn = MySQLdb.connect(host=db_server, user=db_username, passwd=db_password, db=db_dbname) - else: - self.conn = MySQLdb.connect(host=db_server, port=db_port, user=db_username, passwd=db_password, db=db_dbname) - self.conn.autocommit(True) - - def query(self, sql): - try: - cursor = self.conn.cursor() - cursor.execute(sql) - except (AttributeError, MySQLdb.OperationalError): - self.connect() - cursor = self.conn.cursor() - cursor.execute(sql) - return cursor - - def get_config_data(): config_cmd = ['/usr/bin/env', 'php', '%s/config_to_json.php' % install_dir] try: @@ -151,7 +130,20 @@ try: except KeyError: down_retry = 60 -db = DB() +def connectDB(): + try: + if db_port == 0: + db_inst = MySQLdb.connect(host=db_server, user=db_username, passwd=db_password, db=db_dbname) + else: + db_inst = MySQLdb.connect(host=db_server, port=db_port, user=db_username, passwd=db_password, db=db_dbname) + db_inst.autocommit(True) + cursor_inst = db_inst.cursor() + return cursor_inst + except: + log.critical("ERROR: Could not connect to MySQL database!") + sys.exit(2) + +cursor = connectDB() def poll_worker(device_id, action): try: @@ -160,7 +152,9 @@ def poll_worker(device_id, action): if action == 'discovery': path = discover_path command = "/usr/bin/env php %s -h %s >> /dev/null 2>&1" % (path, device_id) - subprocess.check_call(command, shell=True) + if getThreadLock('{0}.{1}'.format(action, device_id)): + subprocess.check_call(command, shell=True) + releaseThreadLock('{0}.{1}'.format(action, device_id)) elapsed_time = int(time.time() - start_time) if elapsed_time < 300: log.debug("DEBUG: worker finished %s of device %s in %s seconds" % (action, device_id, elapsed_time)) @@ -170,72 +164,48 @@ def poll_worker(device_id, action): raise except: pass - finally: - releaseThreadLock(device_id, action) - -def lockFree(lock, db=db): +def lockFree(lock, cursor=cursor): query = "SELECT IS_FREE_LOCK('{0}')".format(lock) - cursor = db.query(query) + cursor.execute(query) return cursor.fetchall()[0][0] == 1 -def getLock(lock, db=db): +def getLock(lock, cursor=cursor): query = "SELECT GET_LOCK('{0}', 0)".format(lock) - cursor = db.query(query) + cursor.execute(query) return cursor.fetchall()[0][0] == 1 thread_cursors = [] for i in range(0, amount_of_workers): - thread_cursors.append(namedtuple('Cursor{0}'.format(i), ['in_use', 'db'])) + thread_cursors.append(namedtuple('Cursor{}'.format(i), ['in_use', 'cursor'])) thread_cursors[i].in_use = False - thread_cursors[i].db = DB() + thread_cursors[i].cursor = connectDB -def getThreadQueueLock(device_id): +def getThreadLock(lock): global thread_cursors - # This is how threads are limited, by the numver of cursors available - while True: - for thread_cursor in thread_cursors: - if not thread_cursor.in_use: - thread_cursor.in_use = 'queue.{0}'.format(device_id) - if getLock('queue.{0}'.format(device_id), thread_cursor.db): - return True - else: - thread_cursor.in_use = False - return False - time.sleep(.5) - - -def getThreadActionLock(device_id, action): - global thread_cursors - # This is how threads are limited, by the numver of cursors available for thread_cursor in thread_cursors: - if thread_cursor.in_use == 'queue.{0}'.format(device_id): - thread_cursor.in_use = '{0}.{1}'.format(action, device_id) - releaseLock('queue.{0}'.format(device_id), thread_cursor.db) - if getLock('{0}.{1}'.format(action, device_id), thread_cursor.db): - return True - else: - thread_cursor.in_use = False - return False + if not thread_cursor.in_use: + thread_cursor.in_use = lock + return getLock(lock, thread_cursor.cursor) return False -def releaseLock(lock, db=db): +def releaseLock(lock, cursor=cursor): query = "SELECT RELEASE_LOCK('{0}')".format(lock) - cursor = db.query(query) + cursor.execute(query) return cursor.fetchall()[0][0] == 1 -def releaseThreadLock(device_id, action): +def releaseThreadLock(lock): global thread_cursors for thread_cursor in thread_cursors: - if thread_cursor.in_use == '{0}.{1}'.format(action, device_id): + if thread_cursor.in_use == lock: thread_cursor.in_use = False - return releaseLock('{0}.{1}'.format(action, device_id), thread_cursor.db) + return releaseLock(lock, thread_cursor.cursor) return False @@ -260,7 +230,7 @@ dev_query = ('SELECT device_id, status, ' INTERVAL last_polled_timetaken SECOND ' ' ), ' ' INTERVAL {0} SECOND) ' - ' AS DATETIME ' + ' AS DATETIME(0) ' ') AS next_poll, ' 'CAST( ' ' DATE_ADD( ' @@ -269,13 +239,12 @@ dev_query = ('SELECT device_id, status, ' INTERVAL last_discovered_timetaken SECOND ' ' ), ' ' INTERVAL {1} SECOND) ' - ' AS DATETIME ' + ' AS DATETIME(0) ' ') as next_discovery ' 'FROM devices WHERE ' 'disabled = 0 ' - 'AND IS_FREE_LOCK(CONCAT("poll.", device_id)) ' - 'AND IS_FREE_LOCK(CONCAT("discovery.", device_id)) ' - 'AND IS_FREE_LOCK(CONCAT("queue.", device_id)) ' + 'AND IS_FREE_LOCK(CONCAT("polling.", device_id)) ' + 'AND IS_FREE_LOCK(CONCAT("queued.", device_id)) ' 'AND ( last_poll_attempted < DATE_SUB(NOW(), INTERVAL {2} SECOND ) ' ' OR last_poll_attempted IS NULL ) ' '{3} ' @@ -293,7 +262,7 @@ while True: cur_threads = threading.active_count() if cur_threads != threads: threads = cur_threads - log.debug('DEBUG: {0} threads currently active'.format(str(threads - 1))) + log.debug('DEBUG: {0} threads currently active'.format(threads)) if next_update < datetime.now(): seconds_taken = (datetime.now() - (next_update - timedelta(minutes=1))).seconds @@ -309,7 +278,7 @@ while True: devices_scanned, seconds_taken) try: - cursor = db.query(update_query) + cursor.execute(update_query) except: log.critical('ERROR: MySQL query error. Is your schema up to date?') sys.exit(2) @@ -318,15 +287,23 @@ while True: devices_scanned = 0 next_update = datetime.now() + timedelta(minutes=1) + while threading.active_count() >= amount_of_workers or not lockFree('schema_update'): + time.sleep(.5) + try: - cursor = db.query(dev_query) + cursor.execute(dev_query) except: log.critical('ERROR: MySQL query error. Is your schema up to date?') sys.exit(2) devices = cursor.fetchall() for device_id, status, next_poll, next_discovery in devices: - if not getThreadQueueLock(device_id): + # add queue lock, so we lock the next device against any other pollers + # if this fails, the device is locked by another poller already + if not getLock('queued.{0}'.format(device_id)): + continue + if not lockFree('polling.{0}'.format(device_id)): + releaseLock('queued.{0}'.format(device_id)) continue if next_poll and next_poll > datetime.now(): @@ -340,12 +317,9 @@ while True: log.debug('DEBUG: Starting {0} of device {1}'.format(action, device_id)) devices_scanned += 1 - cursor = db.query('UPDATE devices SET last_poll_attempted = NOW() WHERE device_id = {0}'.format(device_id)) + cursor.execute('UPDATE devices SET last_poll_attempted = NOW() WHERE device_id = {0}'.format(device_id)) cursor.fetchall() - if not getThreadActionLock(device_id, action): - continue - t = threading.Thread(target=poll_worker, args=[device_id, action]) t.start() From a63a748a21ac003cfc5cfc21ba8a41733cc7d41b Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 2 Sep 2015 12:46:01 -0400 Subject: [PATCH 261/598] return db object to keep it from going out of scope --- poller-service.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/poller-service.py b/poller-service.py index a310541e0..60f737068 100755 --- a/poller-service.py +++ b/poller-service.py @@ -138,12 +138,17 @@ def connectDB(): db_inst = MySQLdb.connect(host=db_server, port=db_port, user=db_username, passwd=db_password, db=db_dbname) db_inst.autocommit(True) cursor_inst = db_inst.cursor() - return cursor_inst + ret = namedtuple('db_connection', ['db', 'cursor']) + ret.db = db_inst + ret.cursor = cursor_inst + return ret except: log.critical("ERROR: Could not connect to MySQL database!") sys.exit(2) -cursor = connectDB() +db_connection = connectDB() +db = db_connection.db +cursor = db_connection.cursor def poll_worker(device_id, action): try: @@ -180,9 +185,11 @@ def getLock(lock, cursor=cursor): thread_cursors = [] for i in range(0, amount_of_workers): - thread_cursors.append(namedtuple('Cursor{}'.format(i), ['in_use', 'cursor'])) + thread_cursors.append(namedtuple('Cursor{}'.format(i), ['in_use', 'cursor', 'db'])) thread_cursors[i].in_use = False - thread_cursors[i].cursor = connectDB + thread_db_connection = connectDB() + thread_cursors[i].cursor = thread_db_connection.cursor + thread_cursors[i].db = thread_db_connection.db def getThreadLock(lock): From d60dc000a3052bc716d6505ed6768231533b7cb9 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 2 Sep 2015 12:50:24 -0400 Subject: [PATCH 262/598] queue locks are no longer necessary --- poller-service.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/poller-service.py b/poller-service.py index 60f737068..6c5fd2c88 100755 --- a/poller-service.py +++ b/poller-service.py @@ -251,7 +251,6 @@ dev_query = ('SELECT device_id, status, 'FROM devices WHERE ' 'disabled = 0 ' 'AND IS_FREE_LOCK(CONCAT("polling.", device_id)) ' - 'AND IS_FREE_LOCK(CONCAT("queued.", device_id)) ' 'AND ( last_poll_attempted < DATE_SUB(NOW(), INTERVAL {2} SECOND ) ' ' OR last_poll_attempted IS NULL ) ' '{3} ' @@ -305,14 +304,6 @@ while True: devices = cursor.fetchall() for device_id, status, next_poll, next_discovery in devices: - # add queue lock, so we lock the next device against any other pollers - # if this fails, the device is locked by another poller already - if not getLock('queued.{0}'.format(device_id)): - continue - if not lockFree('polling.{0}'.format(device_id)): - releaseLock('queued.{0}'.format(device_id)) - continue - if next_poll and next_poll > datetime.now(): log.debug('DEBUG: Sleeping until {0} before polling {1}'.format(next_poll, device_id)) sleep_until(next_poll) From d377b70e192428ba53114ca84817b3a815644b9e Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 2 Sep 2015 12:56:59 -0400 Subject: [PATCH 263/598] make sure lock name matches action --- poller-service.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/poller-service.py b/poller-service.py index 6c5fd2c88..c5fed7077 100755 --- a/poller-service.py +++ b/poller-service.py @@ -250,7 +250,8 @@ dev_query = ('SELECT device_id, status, ') as next_discovery ' 'FROM devices WHERE ' 'disabled = 0 ' - 'AND IS_FREE_LOCK(CONCAT("polling.", device_id)) ' + 'AND IS_FREE_LOCK(CONCAT("poll.", device_id)) ' + 'AND IS_FREE_LOCK(CONCAT("discovery.", device_id)) ' 'AND ( last_poll_attempted < DATE_SUB(NOW(), INTERVAL {2} SECOND ) ' ' OR last_poll_attempted IS NULL ) ' '{3} ' From eddb04aaef0064757f490ce31f4b6590cb75d9b7 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 2 Sep 2015 13:01:38 -0400 Subject: [PATCH 264/598] python 2.6 compat --- poller-service.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poller-service.py b/poller-service.py index c5fed7077..9f75d6a94 100755 --- a/poller-service.py +++ b/poller-service.py @@ -185,7 +185,7 @@ def getLock(lock, cursor=cursor): thread_cursors = [] for i in range(0, amount_of_workers): - thread_cursors.append(namedtuple('Cursor{}'.format(i), ['in_use', 'cursor', 'db'])) + thread_cursors.append(namedtuple('Cursor{0}'.format(i), ['in_use', 'cursor', 'db'])) thread_cursors[i].in_use = False thread_db_connection = connectDB() thread_cursors[i].cursor = thread_db_connection.cursor From ca1a6883a82c81a0ff896491d526e20351f5add4 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 2 Sep 2015 13:30:33 -0400 Subject: [PATCH 265/598] log when can't get lock --- poller-service.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/poller-service.py b/poller-service.py index 9f75d6a94..38eb8c397 100755 --- a/poller-service.py +++ b/poller-service.py @@ -160,6 +160,8 @@ def poll_worker(device_id, action): if getThreadLock('{0}.{1}'.format(action, device_id)): subprocess.check_call(command, shell=True) releaseThreadLock('{0}.{1}'.format(action, device_id)) + else: + log.debug("DEBUG: Couldn't get lock on {0}.{1}".format(action, device_id)) elapsed_time = int(time.time() - start_time) if elapsed_time < 300: log.debug("DEBUG: worker finished %s of device %s in %s seconds" % (action, device_id, elapsed_time)) From 3b6e0e68e94efd493639f6e33af5a613040a55c4 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 2 Sep 2015 14:22:42 -0400 Subject: [PATCH 266/598] move thread control to lock threads --- poller-service.py | 45 ++++++++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/poller-service.py b/poller-service.py index 38eb8c397..9ebbb46b9 100755 --- a/poller-service.py +++ b/poller-service.py @@ -157,11 +157,7 @@ def poll_worker(device_id, action): if action == 'discovery': path = discover_path command = "/usr/bin/env php %s -h %s >> /dev/null 2>&1" % (path, device_id) - if getThreadLock('{0}.{1}'.format(action, device_id)): - subprocess.check_call(command, shell=True) - releaseThreadLock('{0}.{1}'.format(action, device_id)) - else: - log.debug("DEBUG: Couldn't get lock on {0}.{1}".format(action, device_id)) + subprocess.check_call(command, shell=True) elapsed_time = int(time.time() - start_time) if elapsed_time < 300: log.debug("DEBUG: worker finished %s of device %s in %s seconds" % (action, device_id, elapsed_time)) @@ -171,6 +167,9 @@ def poll_worker(device_id, action): raise except: pass + finally: + releaseThreadLock(device_id, action) + def lockFree(lock, cursor=cursor): @@ -194,12 +193,24 @@ for i in range(0, amount_of_workers): thread_cursors[i].db = thread_db_connection.db -def getThreadLock(lock): +def getThreadQueueLock(device_id): global thread_cursors + # This is how threads are limited, by the numver of cursors available + while True: + for thread_cursor in thread_cursors: + if not thread_cursor.in_use: + thread_cursor.in_use = 'queue.{0}'.format(device_id) + return getLock('queue.{0}'.format(device_id), thread_cursor.cursor) + time.sleep(.5) + + +def getThreadActionLock(device_id, action): + global thread_cursors + # This is how threads are limited, by the numver of cursors available for thread_cursor in thread_cursors: - if not thread_cursor.in_use: - thread_cursor.in_use = lock - return getLock(lock, thread_cursor.cursor) + if thread_cursor.in_use == 'queue.{0}'.format(device_id): + thread_cursor.in_use = '{0}.{1}'.format(action, device_id) + return getLock('{0}.{1}'.format(action, device_id), thread_cursor.cursor) return False @@ -209,12 +220,12 @@ def releaseLock(lock, cursor=cursor): return cursor.fetchall()[0][0] == 1 -def releaseThreadLock(lock): +def releaseThreadLock(device_id, action): global thread_cursors for thread_cursor in thread_cursors: - if thread_cursor.in_use == lock: + if thread_cursor.in_use == '{0}.{1}'.format(action, device_id): thread_cursor.in_use = False - return releaseLock(lock, thread_cursor.cursor) + return releaseLock('{0}.{1}'.format(action, device_id), thread_cursor.cursor) return False @@ -254,6 +265,7 @@ dev_query = ('SELECT device_id, status, 'disabled = 0 ' 'AND IS_FREE_LOCK(CONCAT("poll.", device_id)) ' 'AND IS_FREE_LOCK(CONCAT("discovery.", device_id)) ' + 'AND IS_FREE_LOCK(CONCAT("queue.", device_id)) ' 'AND ( last_poll_attempted < DATE_SUB(NOW(), INTERVAL {2} SECOND ) ' ' OR last_poll_attempted IS NULL ) ' '{3} ' @@ -296,9 +308,6 @@ while True: devices_scanned = 0 next_update = datetime.now() + timedelta(minutes=1) - while threading.active_count() >= amount_of_workers or not lockFree('schema_update'): - time.sleep(.5) - try: cursor.execute(dev_query) except: @@ -307,6 +316,9 @@ while True: devices = cursor.fetchall() for device_id, status, next_poll, next_discovery in devices: + if not getThreadQueueLock(device_id): + continue + if next_poll and next_poll > datetime.now(): log.debug('DEBUG: Sleeping until {0} before polling {1}'.format(next_poll, device_id)) sleep_until(next_poll) @@ -321,6 +333,9 @@ while True: cursor.execute('UPDATE devices SET last_poll_attempted = NOW() WHERE device_id = {0}'.format(device_id)) cursor.fetchall() + if not getThreadActionLock(device_id, action): + continue + t = threading.Thread(target=poll_worker, args=[device_id, action]) t.start() From 840d1e86b966527097c2e4722c323e1eb85eeac4 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 2 Sep 2015 14:42:57 -0400 Subject: [PATCH 267/598] make sure to clear the thread if unsuccessful --- poller-service.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/poller-service.py b/poller-service.py index 9ebbb46b9..ccab47f48 100755 --- a/poller-service.py +++ b/poller-service.py @@ -200,7 +200,10 @@ def getThreadQueueLock(device_id): for thread_cursor in thread_cursors: if not thread_cursor.in_use: thread_cursor.in_use = 'queue.{0}'.format(device_id) - return getLock('queue.{0}'.format(device_id), thread_cursor.cursor) + if getLock('queue.{0}'.format(device_id), thread_cursor.cursor): + return True + else: + thread_cursor.in_use = False time.sleep(.5) @@ -210,7 +213,10 @@ def getThreadActionLock(device_id, action): for thread_cursor in thread_cursors: if thread_cursor.in_use == 'queue.{0}'.format(device_id): thread_cursor.in_use = '{0}.{1}'.format(action, device_id) - return getLock('{0}.{1}'.format(action, device_id), thread_cursor.cursor) + if getLock('{0}.{1}'.format(action, device_id), thread_cursor.cursor): + return True + else: + thread_cursor.in_use = False return False From 5b647d8e70c8a3ca4c52cba4f330da8271a54b8c Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 2 Sep 2015 15:01:25 -0400 Subject: [PATCH 268/598] release queue if getting action lock fails --- poller-service.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/poller-service.py b/poller-service.py index ccab47f48..9c17e0fe5 100755 --- a/poller-service.py +++ b/poller-service.py @@ -204,6 +204,8 @@ def getThreadQueueLock(device_id): return True else: thread_cursor.in_use = False + return False + log.debug("DEBUG: No threads avaliable") time.sleep(.5) @@ -217,6 +219,8 @@ def getThreadActionLock(device_id, action): return True else: thread_cursor.in_use = False + releaseLock('queue.{0}'.format(device_id), thread_cursor.cursor) + return False return False From b0e7c9346b02f033f0733574f302de1cd2b1f7ba Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 2 Sep 2015 15:23:47 -0400 Subject: [PATCH 269/598] always release queue lock --- poller-service.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poller-service.py b/poller-service.py index 9c17e0fe5..6d4296207 100755 --- a/poller-service.py +++ b/poller-service.py @@ -215,11 +215,11 @@ def getThreadActionLock(device_id, action): for thread_cursor in thread_cursors: if thread_cursor.in_use == 'queue.{0}'.format(device_id): thread_cursor.in_use = '{0}.{1}'.format(action, device_id) + releaseLock('queue.{0}'.format(device_id), thread_cursor.cursor) if getLock('{0}.{1}'.format(action, device_id), thread_cursor.cursor): return True else: thread_cursor.in_use = False - releaseLock('queue.{0}'.format(device_id), thread_cursor.cursor) return False return False From 0a00bb617866f3901b3926e066d2fe6f98dff32a Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 2 Sep 2015 15:38:45 -0400 Subject: [PATCH 270/598] remove spammy debug log --- poller-service.py | 1 - 1 file changed, 1 deletion(-) diff --git a/poller-service.py b/poller-service.py index 6d4296207..a9b292e4e 100755 --- a/poller-service.py +++ b/poller-service.py @@ -205,7 +205,6 @@ def getThreadQueueLock(device_id): else: thread_cursor.in_use = False return False - log.debug("DEBUG: No threads avaliable") time.sleep(.5) From 32adff03f147546a6eea11804c63eaa3da296dca Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 2 Sep 2015 15:39:27 -0400 Subject: [PATCH 271/598] only log worker threads, not main python thread --- poller-service.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poller-service.py b/poller-service.py index a9b292e4e..e393f9ac7 100755 --- a/poller-service.py +++ b/poller-service.py @@ -292,7 +292,7 @@ while True: cur_threads = threading.active_count() if cur_threads != threads: threads = cur_threads - log.debug('DEBUG: {0} threads currently active'.format(threads)) + log.debug('DEBUG: {0} threads currently active'.format(str(threads - 1))) if next_update < datetime.now(): seconds_taken = (datetime.now() - (next_update - timedelta(minutes=1))).seconds From ac63a8937aa8f1386d4162f23c597e0b3c2a5ce7 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Tue, 8 Sep 2015 10:30:08 -0400 Subject: [PATCH 272/598] MySQL doesn't support specifying microsecond precision, and MariaDB defaults to zero, so it can be removed to be compatible with both. --- poller-service.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/poller-service.py b/poller-service.py index e393f9ac7..3f72ca4b9 100755 --- a/poller-service.py +++ b/poller-service.py @@ -259,7 +259,7 @@ dev_query = ('SELECT device_id, status, ' INTERVAL last_polled_timetaken SECOND ' ' ), ' ' INTERVAL {0} SECOND) ' - ' AS DATETIME(0) ' + ' AS DATETIME ' ') AS next_poll, ' 'CAST( ' ' DATE_ADD( ' @@ -268,7 +268,7 @@ dev_query = ('SELECT device_id, status, ' INTERVAL last_discovered_timetaken SECOND ' ' ), ' ' INTERVAL {1} SECOND) ' - ' AS DATETIME(0) ' + ' AS DATETIME ' ') as next_discovery ' 'FROM devices WHERE ' 'disabled = 0 ' From b08300e42510d038bce038d427c09cfed6dc98e4 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Tue, 8 Sep 2015 13:51:10 -0400 Subject: [PATCH 273/598] make more resiliant to MySQL disconnects --- poller-service.py | 73 ++++++++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/poller-service.py b/poller-service.py index 3f72ca4b9..a11064e3f 100755 --- a/poller-service.py +++ b/poller-service.py @@ -49,6 +49,27 @@ config_file = install_dir + '/config.php' log.info('INFO: Starting poller-service') +class DB: + conn = None + + def connect(self): + if db_port == 0: + self.conn = MySQLdb.connect(host=db_server, user=db_username, passwd=db_password, db=db_dbname) + else: + self.conn = MySQLdb.connect(host=db_server, port=db_port, user=db_username, passwd=db_password, db=db_dbname) + self.conn.autocommit(True) + + def query(self, sql): + try: + cursor = self.conn.cursor() + cursor.execute(sql) + except (AttributeError, MySQLdb.OperationalError): + self.connect() + cursor = self.conn.cursor() + cursor.execute(sql) + return cursor + + def get_config_data(): config_cmd = ['/usr/bin/env', 'php', '%s/config_to_json.php' % install_dir] try: @@ -130,25 +151,7 @@ try: except KeyError: down_retry = 60 -def connectDB(): - try: - if db_port == 0: - db_inst = MySQLdb.connect(host=db_server, user=db_username, passwd=db_password, db=db_dbname) - else: - db_inst = MySQLdb.connect(host=db_server, port=db_port, user=db_username, passwd=db_password, db=db_dbname) - db_inst.autocommit(True) - cursor_inst = db_inst.cursor() - ret = namedtuple('db_connection', ['db', 'cursor']) - ret.db = db_inst - ret.cursor = cursor_inst - return ret - except: - log.critical("ERROR: Could not connect to MySQL database!") - sys.exit(2) - -db_connection = connectDB() -db = db_connection.db -cursor = db_connection.cursor +db = DB() def poll_worker(device_id, action): try: @@ -172,25 +175,23 @@ def poll_worker(device_id, action): -def lockFree(lock, cursor=cursor): +def lockFree(lock, db=db): query = "SELECT IS_FREE_LOCK('{0}')".format(lock) - cursor.execute(query) + cursor = db.query(query) return cursor.fetchall()[0][0] == 1 -def getLock(lock, cursor=cursor): +def getLock(lock, db=db): query = "SELECT GET_LOCK('{0}', 0)".format(lock) - cursor.execute(query) + cursor = db.query(query) return cursor.fetchall()[0][0] == 1 thread_cursors = [] for i in range(0, amount_of_workers): - thread_cursors.append(namedtuple('Cursor{0}'.format(i), ['in_use', 'cursor', 'db'])) + thread_cursors.append(namedtuple('Cursor{0}'.format(i), ['in_use', 'db'])) thread_cursors[i].in_use = False - thread_db_connection = connectDB() - thread_cursors[i].cursor = thread_db_connection.cursor - thread_cursors[i].db = thread_db_connection.db + thread_cursors[i].db = DB() def getThreadQueueLock(device_id): @@ -200,7 +201,7 @@ def getThreadQueueLock(device_id): for thread_cursor in thread_cursors: if not thread_cursor.in_use: thread_cursor.in_use = 'queue.{0}'.format(device_id) - if getLock('queue.{0}'.format(device_id), thread_cursor.cursor): + if getLock('queue.{0}'.format(device_id), thread_cursor.db): return True else: thread_cursor.in_use = False @@ -214,8 +215,8 @@ def getThreadActionLock(device_id, action): for thread_cursor in thread_cursors: if thread_cursor.in_use == 'queue.{0}'.format(device_id): thread_cursor.in_use = '{0}.{1}'.format(action, device_id) - releaseLock('queue.{0}'.format(device_id), thread_cursor.cursor) - if getLock('{0}.{1}'.format(action, device_id), thread_cursor.cursor): + releaseLock('queue.{0}'.format(device_id), thread_cursor.db) + if getLock('{0}.{1}'.format(action, device_id), thread_cursor.db): return True else: thread_cursor.in_use = False @@ -223,9 +224,9 @@ def getThreadActionLock(device_id, action): return False -def releaseLock(lock, cursor=cursor): +def releaseLock(lock, db=db): query = "SELECT RELEASE_LOCK('{0}')".format(lock) - cursor.execute(query) + cursor = db.query(query) return cursor.fetchall()[0][0] == 1 @@ -234,7 +235,7 @@ def releaseThreadLock(device_id, action): for thread_cursor in thread_cursors: if thread_cursor.in_use == '{0}.{1}'.format(action, device_id): thread_cursor.in_use = False - return releaseLock('{0}.{1}'.format(action, device_id), thread_cursor.cursor) + return releaseLock('{0}.{1}'.format(action, device_id), thread_cursor.db) return False @@ -308,7 +309,7 @@ while True: devices_scanned, seconds_taken) try: - cursor.execute(update_query) + cursor = db.query(update_query) except: log.critical('ERROR: MySQL query error. Is your schema up to date?') sys.exit(2) @@ -318,7 +319,7 @@ while True: next_update = datetime.now() + timedelta(minutes=1) try: - cursor.execute(dev_query) + cursor = db.query(dev_query) except: log.critical('ERROR: MySQL query error. Is your schema up to date?') sys.exit(2) @@ -339,7 +340,7 @@ while True: log.debug('DEBUG: Starting {0} of device {1}'.format(action, device_id)) devices_scanned += 1 - cursor.execute('UPDATE devices SET last_poll_attempted = NOW() WHERE device_id = {0}'.format(device_id)) + cursor = db.query('UPDATE devices SET last_poll_attempted = NOW() WHERE device_id = {0}'.format(device_id)) cursor.fetchall() if not getThreadActionLock(device_id, action): From 9610dac1301f7611e1f10d6f6bc3eb3a252fc9b8 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 9 Sep 2015 08:25:00 -0400 Subject: [PATCH 274/598] mysql ping with reconnect --- poller-service.py | 1 + 1 file changed, 1 insertion(+) diff --git a/poller-service.py b/poller-service.py index a11064e3f..61dcc84cf 100755 --- a/poller-service.py +++ b/poller-service.py @@ -58,6 +58,7 @@ class DB: else: self.conn = MySQLdb.connect(host=db_server, port=db_port, user=db_username, passwd=db_password, db=db_dbname) self.conn.autocommit(True) + self.conn.ping(True) def query(self, sql): try: From 55768cf4c90d2139e563765639f780ba3feb66b5 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 9 Sep 2015 08:37:00 -0400 Subject: [PATCH 275/598] catch error during connectino and retry --- poller-service.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/poller-service.py b/poller-service.py index 61dcc84cf..289c29867 100755 --- a/poller-service.py +++ b/poller-service.py @@ -53,10 +53,18 @@ class DB: conn = None def connect(self): - if db_port == 0: - self.conn = MySQLdb.connect(host=db_server, user=db_username, passwd=db_password, db=db_dbname) - else: - self.conn = MySQLdb.connect(host=db_server, port=db_port, user=db_username, passwd=db_password, db=db_dbname) + while True: + try: + if db_port == 0: + self.conn = MySQLdb.connect(host=db_server, user=db_username, passwd=db_password, db=db_dbname) + else: + self.conn = MySQLdb.connect(host=db_server, port=db_port, user=db_username, passwd=db_password, db=db_dbname) + break + except (AttributeError, MySQLdb.OperationalError): + log.warning('WARNING: MySQL Error, reconnecting.') + time.sleep(.5) + pass + self.conn.autocommit(True) self.conn.ping(True) From 201f516a76283884b9b09bc13e18aec0f1815650 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 9 Sep 2015 08:42:37 -0400 Subject: [PATCH 276/598] better log messages --- poller-service.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/poller-service.py b/poller-service.py index 289c29867..41d17efff 100755 --- a/poller-service.py +++ b/poller-service.py @@ -61,7 +61,7 @@ class DB: self.conn = MySQLdb.connect(host=db_server, port=db_port, user=db_username, passwd=db_password, db=db_dbname) break except (AttributeError, MySQLdb.OperationalError): - log.warning('WARNING: MySQL Error, reconnecting.') + log.warning('WARNING: MySQL Error during connect, reconnecting.') time.sleep(.5) pass @@ -73,6 +73,7 @@ class DB: cursor = self.conn.cursor() cursor.execute(sql) except (AttributeError, MySQLdb.OperationalError): + log.warning('WARNING: MySQL Error during query, reconnecting.') self.connect() cursor = self.conn.cursor() cursor.execute(sql) From 004111574af426c45810929acefbb3f502908084 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 9 Sep 2015 09:20:03 -0400 Subject: [PATCH 277/598] close cursor after query --- poller-service.py | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/poller-service.py b/poller-service.py index 41d17efff..b72aaa953 100755 --- a/poller-service.py +++ b/poller-service.py @@ -61,23 +61,25 @@ class DB: self.conn = MySQLdb.connect(host=db_server, port=db_port, user=db_username, passwd=db_password, db=db_dbname) break except (AttributeError, MySQLdb.OperationalError): - log.warning('WARNING: MySQL Error during connect, reconnecting.') + log.warning('WARNING: MySQL Error, reconnecting.') time.sleep(.5) - pass self.conn.autocommit(True) self.conn.ping(True) def query(self, sql): - try: - cursor = self.conn.cursor() - cursor.execute(sql) - except (AttributeError, MySQLdb.OperationalError): - log.warning('WARNING: MySQL Error during query, reconnecting.') - self.connect() - cursor = self.conn.cursor() - cursor.execute(sql) - return cursor + while True: + try: + cursor = self.conn.cursor() + cursor.execute(sql) + ret = cursor.fetchall() + cursor.close() + return ret + except (AttributeError, MySQLdb.OperationalError): + log.warning('WARNING: MySQL Operational Error during query, reconnecting.') + self.connect() + except (AttributeError, MySQLdb.ProgrammingError): + log.warning('WARNING: MySQL Programming Error during query, attempting query again.') def get_config_data(): From 7f69855f418197bcfd3ade95a83a7050fdbca555 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 9 Sep 2015 09:22:31 -0400 Subject: [PATCH 278/598] all cursor handling in db class --- poller-service.py | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/poller-service.py b/poller-service.py index b72aaa953..c78e12e53 100755 --- a/poller-service.py +++ b/poller-service.py @@ -189,14 +189,12 @@ def poll_worker(device_id, action): def lockFree(lock, db=db): query = "SELECT IS_FREE_LOCK('{0}')".format(lock) - cursor = db.query(query) - return cursor.fetchall()[0][0] == 1 + return db.query(query)[0][0] == 1 def getLock(lock, db=db): query = "SELECT GET_LOCK('{0}', 0)".format(lock) - cursor = db.query(query) - return cursor.fetchall()[0][0] == 1 + return db.query(query)[0][0] == 1 thread_cursors = [] @@ -239,7 +237,7 @@ def getThreadActionLock(device_id, action): def releaseLock(lock, db=db): query = "SELECT RELEASE_LOCK('{0}')".format(lock) cursor = db.query(query) - return cursor.fetchall()[0][0] == 1 + return db.query(query)[0][0] == 1 def releaseThreadLock(device_id, action): @@ -321,22 +319,20 @@ while True: devices_scanned, seconds_taken) try: - cursor = db.query(update_query) + db.query(update_query) except: log.critical('ERROR: MySQL query error. Is your schema up to date?') sys.exit(2) - cursor.fetchall() log.info('INFO: {0} devices scanned in the last minute'.format(devices_scanned)) devices_scanned = 0 next_update = datetime.now() + timedelta(minutes=1) try: - cursor = db.query(dev_query) + devices = db.query(dev_query) except: log.critical('ERROR: MySQL query error. Is your schema up to date?') sys.exit(2) - devices = cursor.fetchall() for device_id, status, next_poll, next_discovery in devices: if not getThreadQueueLock(device_id): continue @@ -352,8 +348,7 @@ while True: log.debug('DEBUG: Starting {0} of device {1}'.format(action, device_id)) devices_scanned += 1 - cursor = db.query('UPDATE devices SET last_poll_attempted = NOW() WHERE device_id = {0}'.format(device_id)) - cursor.fetchall() + db.query('UPDATE devices SET last_poll_attempted = NOW() WHERE device_id = {0}'.format(device_id)) if not getThreadActionLock(device_id, action): continue From b2f7eba5c72de978be839b0cabf9fc6ca13b09b6 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 9 Sep 2015 09:26:00 -0400 Subject: [PATCH 279/598] always close cursor --- poller-service.py | 1 + 1 file changed, 1 insertion(+) diff --git a/poller-service.py b/poller-service.py index c78e12e53..fc42af4a1 100755 --- a/poller-service.py +++ b/poller-service.py @@ -80,6 +80,7 @@ class DB: self.connect() except (AttributeError, MySQLdb.ProgrammingError): log.warning('WARNING: MySQL Programming Error during query, attempting query again.') + cursor.close() def get_config_data(): From 969a22ffa91e81035a23fa049a0c3ea587b46075 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 9 Sep 2015 14:47:32 -0400 Subject: [PATCH 280/598] move everything into the thread --- poller-service.py | 169 +++++++++++++++------------------------------- 1 file changed, 56 insertions(+), 113 deletions(-) diff --git a/poller-service.py b/poller-service.py index fc42af4a1..342aaa6ad 100755 --- a/poller-service.py +++ b/poller-service.py @@ -166,27 +166,6 @@ except KeyError: db = DB() -def poll_worker(device_id, action): - try: - start_time = time.time() - path = poller_path - if action == 'discovery': - path = discover_path - command = "/usr/bin/env php %s -h %s >> /dev/null 2>&1" % (path, device_id) - subprocess.check_call(command, shell=True) - elapsed_time = int(time.time() - start_time) - if elapsed_time < 300: - log.debug("DEBUG: worker finished %s of device %s in %s seconds" % (action, device_id, elapsed_time)) - else: - log.warning("WARNING: worker finished %s of device %s in %s seconds" % (action, device_id, elapsed_time)) - except (KeyboardInterrupt, SystemExit): - raise - except: - pass - finally: - releaseThreadLock(device_id, action) - - def lockFree(lock, db=db): query = "SELECT IS_FREE_LOCK('{0}')".format(lock) @@ -198,58 +177,12 @@ def getLock(lock, db=db): return db.query(query)[0][0] == 1 -thread_cursors = [] -for i in range(0, amount_of_workers): - thread_cursors.append(namedtuple('Cursor{0}'.format(i), ['in_use', 'db'])) - thread_cursors[i].in_use = False - thread_cursors[i].db = DB() - - -def getThreadQueueLock(device_id): - global thread_cursors - # This is how threads are limited, by the numver of cursors available - while True: - for thread_cursor in thread_cursors: - if not thread_cursor.in_use: - thread_cursor.in_use = 'queue.{0}'.format(device_id) - if getLock('queue.{0}'.format(device_id), thread_cursor.db): - return True - else: - thread_cursor.in_use = False - return False - time.sleep(.5) - - -def getThreadActionLock(device_id, action): - global thread_cursors - # This is how threads are limited, by the numver of cursors available - for thread_cursor in thread_cursors: - if thread_cursor.in_use == 'queue.{0}'.format(device_id): - thread_cursor.in_use = '{0}.{1}'.format(action, device_id) - releaseLock('queue.{0}'.format(device_id), thread_cursor.db) - if getLock('{0}.{1}'.format(action, device_id), thread_cursor.db): - return True - else: - thread_cursor.in_use = False - return False - return False - - def releaseLock(lock, db=db): query = "SELECT RELEASE_LOCK('{0}')".format(lock) cursor = db.query(query) return db.query(query)[0][0] == 1 -def releaseThreadLock(device_id, action): - global thread_cursors - for thread_cursor in thread_cursors: - if thread_cursor.in_use == '{0}.{1}'.format(action, device_id): - thread_cursor.in_use = False - return releaseLock('{0}.{1}'.format(action, device_id), thread_cursor.db) - return False - - def sleep_until(timestamp): now = datetime.now() if timestamp > now: @@ -291,21 +224,70 @@ dev_query = ('SELECT device_id, status, ' OR last_poll_attempted IS NULL ) ' '{3} ' 'ORDER BY next_poll asc ' - 'LIMIT 5 ').format(poll_frequency, + 'LIMIT 1 ').format(poll_frequency, discover_frequency, down_retry, poller_group) -threads = 0 next_update = datetime.now() + timedelta(minutes=1) devices_scanned = 0 -while True: - cur_threads = threading.active_count() - if cur_threads != threads: - threads = cur_threads - log.debug('DEBUG: {0} threads currently active'.format(str(threads - 1))) +def poll_worker(): + global dev_query + global devices_scanned + db = DB() + while True: + device_id, status, next_poll, next_discovery = db.query(dev_query)[0] + + if not getLock('queue.{0}'.format(device_id), db): + continue + + if next_poll and next_poll > datetime.now(): + log.debug('DEBUG: Sleeping until {0} before polling {1}'.format(next_poll, device_id)) + sleep_until(next_poll) + + action = 'poll' + if (not next_discovery or next_discovery < datetime.now()) and status == 1: + action = 'discovery' + + log.debug('DEBUG: Starting {0} of device {1}'.format(action, device_id)) + devices_scanned += 1 + + db.query('UPDATE devices SET last_poll_attempted = NOW() WHERE device_id = {0}'.format(device_id)) + + if not getLock('{0}.{1}'.format(action, device_id), db): + releaseLock('{0}.{1}'.format(action, device_id), db) + continue + + releaseLock('{0}.{1}'.format(action, device_id), db) + try: + start_time = time.time() + path = poller_path + if action == 'discovery': + path = discover_path + command = "/usr/bin/env php %s -h %s >> /dev/null 2>&1" % (path, device_id) + subprocess.check_call(command, shell=True) + elapsed_time = int(time.time() - start_time) + if elapsed_time < 300: + log.debug("DEBUG: worker finished %s of device %s in %s seconds" % (action, device_id, elapsed_time)) + else: + log.warning("WARNING: worker finished %s of device %s in %s seconds" % (action, device_id, elapsed_time)) + except (KeyboardInterrupt, SystemExit): + raise + except: + pass + finally: + releaseLock('{0}.{1}'.format(action, device_id), db) + + +t = [] +for i in range(0, amount_of_workers): + t.append(threading.Thread(target=poll_worker)) + t[i].start() + + +while True: if next_update < datetime.now(): seconds_taken = (datetime.now() - (next_update - timedelta(minutes=1))).seconds update_query = ('INSERT INTO pollers(poller_name, ' @@ -327,42 +309,3 @@ while True: log.info('INFO: {0} devices scanned in the last minute'.format(devices_scanned)) devices_scanned = 0 next_update = datetime.now() + timedelta(minutes=1) - - try: - devices = db.query(dev_query) - except: - log.critical('ERROR: MySQL query error. Is your schema up to date?') - sys.exit(2) - - for device_id, status, next_poll, next_discovery in devices: - if not getThreadQueueLock(device_id): - continue - - if next_poll and next_poll > datetime.now(): - log.debug('DEBUG: Sleeping until {0} before polling {1}'.format(next_poll, device_id)) - sleep_until(next_poll) - - action = 'poll' - if (not next_discovery or next_discovery < datetime.now()) and status == 1: - action = 'discovery' - - log.debug('DEBUG: Starting {0} of device {1}'.format(action, device_id)) - devices_scanned += 1 - - db.query('UPDATE devices SET last_poll_attempted = NOW() WHERE device_id = {0}'.format(device_id)) - - if not getThreadActionLock(device_id, action): - continue - - t = threading.Thread(target=poll_worker, args=[device_id, action]) - t.start() - - # If we made it this far, break out of the loop and query again. - break - - # This point is only reached if the query is empty, so sleep half a second before querying again. - time.sleep(.5) - - # Make sure we're not holding any device queue locks in this connection before querying again - # by locking a different string. - getLock('unlock.{0}'.format(config['distributed_poller_name'])) From c914ba75a1829de4abccd8efc137ce25da04ee50 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 9 Sep 2015 14:58:39 -0400 Subject: [PATCH 281/598] identify thread numbers --- poller-service.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/poller-service.py b/poller-service.py index 342aaa6ad..8cfa1ee40 100755 --- a/poller-service.py +++ b/poller-service.py @@ -233,7 +233,7 @@ next_update = datetime.now() + timedelta(minutes=1) devices_scanned = 0 -def poll_worker(): +def poll_worker(thread_id): global dev_query global devices_scanned db = DB() @@ -244,14 +244,14 @@ def poll_worker(): continue if next_poll and next_poll > datetime.now(): - log.debug('DEBUG: Sleeping until {0} before polling {1}'.format(next_poll, device_id)) + log.debug('DEBUG: Thread {0} Sleeping until {1} before polling {2}'.format(thread_id, next_poll, device_id)) sleep_until(next_poll) action = 'poll' if (not next_discovery or next_discovery < datetime.now()) and status == 1: action = 'discovery' - log.debug('DEBUG: Starting {0} of device {1}'.format(action, device_id)) + log.debug('DEBUG: Thread {0} Starting {1} of device {2}'.format(thread_id, action, device_id)) devices_scanned += 1 db.query('UPDATE devices SET last_poll_attempted = NOW() WHERE device_id = {0}'.format(device_id)) @@ -270,9 +270,9 @@ def poll_worker(): subprocess.check_call(command, shell=True) elapsed_time = int(time.time() - start_time) if elapsed_time < 300: - log.debug("DEBUG: worker finished %s of device %s in %s seconds" % (action, device_id, elapsed_time)) + log.debug("DEBUG: Thread {0} finished {1} of device {2} in {3} seconds".format(thread_id, action, device_id, elapsed_time)) else: - log.warning("WARNING: worker finished %s of device %s in %s seconds" % (action, device_id, elapsed_time)) + log.warning("WARNING: Thread {0} finished {1} of device {2} in {3} seconds".format(thread_id, action, device_id, elapsed_time)) except (KeyboardInterrupt, SystemExit): raise except: @@ -283,7 +283,7 @@ def poll_worker(): t = [] for i in range(0, amount_of_workers): - t.append(threading.Thread(target=poll_worker)) + t.append(threading.Thread(target=poll_worker, args=[i])) t[i].start() From 8de136f50c5eba0fcd1db903192770bcc7c6ce4f Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 9 Sep 2015 15:01:27 -0400 Subject: [PATCH 282/598] warn on empty queries --- poller-service.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/poller-service.py b/poller-service.py index 8cfa1ee40..fbf681c93 100755 --- a/poller-service.py +++ b/poller-service.py @@ -238,7 +238,12 @@ def poll_worker(thread_id): global devices_scanned db = DB() while True: - device_id, status, next_poll, next_discovery = db.query(dev_query)[0] + dev_row = db.query(dev_query) + if len(dev_row) < 1: + log.warning("WARNING: Thread {0} returned no devices from query".format(thread_id)) + continue + + device_id, status, next_poll, next_discovery = dev_row[0] if not getLock('queue.{0}'.format(device_id), db): continue From d76e9e78891e73e77e21f8e477fd88db85695329 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 9 Sep 2015 15:05:39 -0400 Subject: [PATCH 283/598] release queue locks --- poller-service.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/poller-service.py b/poller-service.py index fbf681c93..b42404130 100755 --- a/poller-service.py +++ b/poller-service.py @@ -240,12 +240,13 @@ def poll_worker(thread_id): while True: dev_row = db.query(dev_query) if len(dev_row) < 1: - log.warning("WARNING: Thread {0} returned no devices from query".format(thread_id)) + #log.warning("WARNING: Thread {0} returned no devices from query".format(thread_id)) continue device_id, status, next_poll, next_discovery = dev_row[0] if not getLock('queue.{0}'.format(device_id), db): + releaseLock('queue.{0}'.format(device_id), db): continue if next_poll and next_poll > datetime.now(): @@ -263,9 +264,10 @@ def poll_worker(thread_id): if not getLock('{0}.{1}'.format(action, device_id), db): releaseLock('{0}.{1}'.format(action, device_id), db) + releaseLock('queue.{0}'.format(device_id), db): continue - releaseLock('{0}.{1}'.format(action, device_id), db) + releaseLock('queue.{0}'.format(device_id), db): try: start_time = time.time() path = poller_path From 2ce10cf6dfeee820b5c8c2e274a9a84ece883ef7 Mon Sep 17 00:00:00 2001 From: Daniel Preussker Date: Wed, 9 Sep 2015 20:06:10 +0100 Subject: [PATCH 284/598] Add multiple dashboard support --- html/includes/forms/add-dashboard.inc.php | 41 +++++ html/includes/forms/delete-dashboard.inc.php | 45 ++++++ html/includes/forms/edit-dashboard.inc.php | 44 ++++++ .../forms/update-dashboard-config.inc.php | 9 +- html/pages/front/tiles.php | 142 ++++++++++++++++-- sql-schema/069.sql | 2 + 6 files changed, 264 insertions(+), 19 deletions(-) create mode 100644 html/includes/forms/add-dashboard.inc.php create mode 100644 html/includes/forms/delete-dashboard.inc.php create mode 100644 html/includes/forms/edit-dashboard.inc.php create mode 100644 sql-schema/069.sql diff --git a/html/includes/forms/add-dashboard.inc.php b/html/includes/forms/add-dashboard.inc.php new file mode 100644 index 000000000..e34993a6e --- /dev/null +++ b/html/includes/forms/add-dashboard.inc.php @@ -0,0 +1,41 @@ + + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + +/** + * Create Dashboards + * @author Daniel Preussker + * @copyright 2015 Daniel Preussker, QuxLabs UG + * @license GPL + * @package LibreNMS + * @subpackage Dashboards + */ + +$status = 'error'; +$message = 'unknown error'; +if (isset($_REQUEST['dashboard_name']) && ($dash_id = dbInsert(array('dashboard_name'=>$_REQUEST['dashboard_name'],'user_id'=>$_SESSION['user_id']),'dashboards'))) { + $status = 'ok'; + $message = 'Created'; +} +else { + $status = 'error'; + $message = 'ERROR: Could not create'; +} + +die(json_encode(array( + 'status' => $status, + 'message' => $message, + 'dashboard_id' => $dash_id +))); + diff --git a/html/includes/forms/delete-dashboard.inc.php b/html/includes/forms/delete-dashboard.inc.php new file mode 100644 index 000000000..2874dec6e --- /dev/null +++ b/html/includes/forms/delete-dashboard.inc.php @@ -0,0 +1,45 @@ + + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + +/** + * Delete Dashboards + * @author Daniel Preussker + * @copyright 2015 Daniel Preussker, QuxLabs UG + * @license GPL + * @package LibreNMS + * @subpackage Dashboards + */ + +$status = 'error'; +$message = 'unknown error'; +if (isset($_REQUEST['dashboard_id'])) { + dbDelete('users_widgets','user_id = ? && dashboard_id = ?',array($_SESSION['user_id'],$_REQUEST['dashboard_id'])); + if (dbDelete('dashboards','user_id = ? && dashboard_id = ?',array($_SESSION['user_id'],$_REQUEST['dashboard_id']))) { + $status = 'ok'; + $message = 'Deleted dashboard'; + } + else { + $message = 'ERROR: Could not delete dashboard '.$_REQUEST['dashboard_id']; + } +} +else { + $message = 'ERROR: Not enough params'; +} + +die(json_encode(array( + 'status' => $status, + 'message' => $message, +))); + diff --git a/html/includes/forms/edit-dashboard.inc.php b/html/includes/forms/edit-dashboard.inc.php new file mode 100644 index 000000000..7e87af0a1 --- /dev/null +++ b/html/includes/forms/edit-dashboard.inc.php @@ -0,0 +1,44 @@ + + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + +/** + * Edit Dashboards + * @author Daniel Preussker + * @copyright 2015 Daniel Preussker, QuxLabs UG + * @license GPL + * @package LibreNMS + * @subpackage Dashboards + */ + +$status = 'error'; +$message = 'unknown error'; +if (isset($_REQUEST['dashboard_id']) && isset($_REQUEST['dashboard_name'])) { + if(dbUpdate(array('dashboard_name'=>$_REQUEST['dashboard_name']),'dashboards','user_id = ? && dashboard_id = ?',array($_SESSION['user_id'],$_REQUEST['dashboard_id']))) { + $status = 'ok'; + $message = 'Updated dashboard'; + } + else { + $message = 'ERROR: Could not update dashboard '.$_REQUEST['dashboard_id']; + } +} +else { + $message = 'ERROR: Not enough params'; +} + +die(json_encode(array( + 'status' => $status, + 'message' => $message, +))); + diff --git a/html/includes/forms/update-dashboard-config.inc.php b/html/includes/forms/update-dashboard-config.inc.php index de278fd91..35168905f 100644 --- a/html/includes/forms/update-dashboard-config.inc.php +++ b/html/includes/forms/update-dashboard-config.inc.php @@ -6,15 +6,16 @@ $message = 'Error updating user dashboard config'; $data = json_decode($_POST['data'],true); $sub_type = mres($_POST['sub_type']); $widget_id = mres($_POST['widget_id']); +$dasboard_id = mres($_POST['dashboard_id']); if ($sub_type == 'remove' && is_numeric($widget_id)) { - if ($widget_id == 0 || dbDelete('users_widgets','`user_id`=? AND `user_widget_id`=?', array($_SESSION['user_id'],$widget_id))) { + if ($widget_id == 0 || dbDelete('users_widgets','`user_id`=? AND `user_widget_id`=? AND `dashboard_id`=?', array($_SESSION['user_id'],$widget_id,$dasboard_id))) { $status = 'ok'; $message = ''; } } elseif ($sub_type == 'remove-all') { - if (dbDelete('users_widgets','`user_id`=?', array($_SESSION['user_id']))) { + if (dbDelete('users_widgets','`user_id`=? AND `dashboard_id`=?', array($_SESSION['user_id'],$dasboard_id))) { $status = 'ok'; $message = ''; } @@ -23,7 +24,7 @@ elseif ($sub_type == 'add' && is_numeric($widget_id)) { $widget = dbFetchRow('SELECT * FROM `widgets` WHERE `widget_id`=?', array($widget_id)); if (is_array($widget)) { list($x,$y) = explode(',',$widget['base_dimensions']); - $item_id = dbInsert(array('user_id'=>$_SESSION['user_id'],'widget_id'=>$widget_id, 'col'=>1,'row'=>1,'refresh'=>60,'title'=>$widget['widget_title'],'size_x'=>$x,'size_y'=>$y),'users_widgets'); + $item_id = dbInsert(array('user_id'=>$_SESSION['user_id'],'widget_id'=>$widget_id, 'col'=>1,'row'=>1,'refresh'=>60,'title'=>$widget['widget_title'],'size_x'=>$x,'size_y'=>$y,'settings'=>'','dashboard_id'=>$dasboard_id),'users_widgets'); if (is_numeric($item_id)) { $extra = array('user_widget_id'=>$item_id,'widget_id'=>$item_id,'title'=>$widget['widget_title'],'widget'=>$widget['widget'],'refresh'=>60,'size_x'=>$x,'size_y'=>$y); $status = 'ok'; @@ -38,7 +39,7 @@ else { foreach ($data as $line) { if (is_array($line)) { $update = array('col'=>$line['col'],'row'=>$line['row'],'size_x'=>$line['size_x'],'size_y'=>$line['size_y']); - dbUpdate($update, 'users_widgets', '`user_widget_id`=?', array($line['id'])); + dbUpdate($update, 'users_widgets', '`user_widget_id`=? AND `user_id`=? AND `dashboard_id`=?', array($line['id'],$_SESSION['user_id'],$dasboard_id)); } } } diff --git a/html/pages/front/tiles.php b/html/pages/front/tiles.php index 9c7c5c933..f5999d1c6 100644 --- a/html/pages/front/tiles.php +++ b/html/pages/front/tiles.php @@ -17,34 +17,94 @@ */ $no_refresh = true; - -foreach (dbFetchRows('SELECT user_widget_id,users_widgets.widget_id,title,widget,col,row,size_x,size_y,refresh FROM `users_widgets` LEFT JOIN `widgets` ON `widgets`.`widget_id`=`users_widgets`.`widget_id` WHERE `user_id`=?',array($_SESSION['user_id'])) as $items) { - $data[] = $items; +if (dbFetchCell('SELECT dashboard_id FROM dashboards WHERE user_id=?',array($_SESSION['user_id'])) == 0) { + $vars['dashboard'] = dbInsert(array('dashboard_name'=>'Default','user_id'=>$_SESSION['user_id']),'dashboards'); } - -if (!is_array($data)) { - $data[] = array('user_widget_id'=>'0','widget_id'=>1,'title'=>'Add a widget','widget'=>'placeholder','col'=>1,'row'=>1,'size_x'=>2,'size_y'=>2,'refresh'=>60); +if (empty($vars['dashboard'])) { + $vars['dashboard'] = dbFetchRow('select dashboard_id,dashboard_name from dashboards where user_id = ? order by dashboard_id limit 1',array($_SESSION['user_id'])); +} else { + $vars['dashboard'] = dbFetchRow('select dashboard_id,dashboard_name from dashboards where user_id = ? && dashboard_id = ? order by dashboard_id limit 1',array($_SESSION['user_id'],$vars['dashboard'])); +} +$data = array(); +foreach (dbFetchRows('SELECT user_widget_id,users_widgets.widget_id,title,widget,col,row,size_x,size_y,refresh FROM `users_widgets` LEFT JOIN `widgets` ON `widgets`.`widget_id`=`users_widgets`.`widget_id` WHERE `user_id`=? AND `dashboard_id`=?',array($_SESSION['user_id'],$vars['dashboard']['dashboard_id'])) as $items) { + $data[] = $items; } $data = serialize(json_encode($data)); $dash_config = unserialize(stripslashes($data)); +$dashboards = dbFetchRows("SELECT * FROM `dashboards` WHERE `user_id` = ?",array($_SESSION['user_id'])); + ?>
    - Widgets - - + Dashboards +'.$dash['dashboard_name'].''; + if ($dash[dashboard_id] == $vars['dashboard']['dashboard_id']) { + echo ''; + } +} +?> +
    -
    + +
    + +
    +
    +
    +
    +
    + + New Dashboard + + + + + +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    + + Dashboard Name + + + + + + +
    +
    +
    +
    +
    + '. $widgets['widget_title'] .' '; + echo ''. $widgets['widget_title'] .' '; } ?> +
    +
    @@ -75,7 +135,7 @@ foreach (dbFetchRows("SELECT * FROM `widgets` ORDER BY `widget_title`") as $widg $.ajax({ type: 'POST', url: 'ajax_form.php', - data: {type: "update-dashboard-config", data: s}, + data: {type: "update-dashboard-config", data: s, dashboard_id: }, dataType: "json", success: function (data) { if (data.status == 'ok') { @@ -129,7 +189,7 @@ foreach (dbFetchRows("SELECT * FROM `widgets` ORDER BY `widget_title`") as $widg $.ajax({ type: 'POST', url: 'ajax_form.php', - data: {type: "update-dashboard-config", sub_type: 'remove-all'}, + data: {type: "update-dashboard-config", sub_type: 'remove-all', dashboard_id: }, dataType: "json", success: function (data) { if (data.status == 'ok') { @@ -150,7 +210,7 @@ foreach (dbFetchRows("SELECT * FROM `widgets` ORDER BY `widget_title`") as $widg $.ajax({ type: 'POST', url: 'ajax_form.php', - data: {type: "update-dashboard-config", sub_type: 'add', widget_id: widget_id}, + data: {type: "update-dashboard-config", sub_type: 'add', widget_id: widget_id, dashboard_id: }, dataType: "json", success: function (data) { if (data.status == 'ok') { @@ -172,7 +232,7 @@ foreach (dbFetchRows("SELECT * FROM `widgets` ORDER BY `widget_title`") as $widg $.ajax({ type: 'POST', url: 'ajax_form.php', - data: {type: "update-dashboard-config", sub_type: 'remove', widget_id: widget_id}, + data: {type: "update-dashboard-config", sub_type: 'remove', widget_id: widget_id, dashboard_id: }, dataType: "json", success: function (data) { if (data.status == 'ok') { @@ -201,6 +261,58 @@ foreach (dbFetchRows("SELECT * FROM `widgets` ORDER BY `widget_title`") as $widg }); + function dashboard_delete(data) { + $.ajax({ + type: 'POST', + url: 'ajax_form.php', + data: {type: 'delete-dashboard', dashboard_id: $(data).data('dashboard')}, + dataType: "json", + success: function (data) { + if( data.status == "ok" ) { + window.location.href="/overview"; + } + } + }); + } + + function dashboard_edit(data) { + datas = $(data).serializeArray(); + data = []; + for( var field in datas ) { + data[datas[field].name] = datas[field].value; + } + $.ajax({ + type: 'POST', + url: 'ajax_form.php', + data: {type: 'edit-dashboard', dashboard_name: data['dashboard_name'], dashboard_id: }, + dataType: "json", + success: function (data) { + if( data.status == "ok" ) { + window.location.href="/overview/dashboard="; + } + } + }); + } + + function dashboard_add(data) { + datas = $(data).serializeArray(); + data = []; + for( var field in datas ) { + data[datas[field].name] = datas[field].value; + } + $.ajax({ + type: 'POST', + url: 'ajax_form.php', + data: {type: 'add-dashboard', dashboard_name: data['dashboard_name']}, + dataType: "json", + success: function (data) { + if( data.status == "ok" ) { + window.location.href="/overview/dashboard="+data.dashboard_id; + } + } + }); + } + function widget_dom(data) { dom = '
  • '+ '
    '+data.title+''+ diff --git a/sql-schema/069.sql b/sql-schema/069.sql new file mode 100644 index 000000000..739c558dd --- /dev/null +++ b/sql-schema/069.sql @@ -0,0 +1,2 @@ +CREATE TABLE `dashboards` ( `dashboard_id` int(11) NOT NULL AUTO_INCREMENT, `user_id` int(11) NOT NULL DEFAULT '0', `dashboard_name` varchar(255) NOT NULL, PRIMARY KEY (`dashboard_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8; +ALTER TABLE `users_widgets` ADD COLUMN `dashboard_id` int(11) NOT NULL; From ae8d29c4b6e11d1162a6a801a62669cd9ce5fcdb Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 9 Sep 2015 15:07:55 -0400 Subject: [PATCH 285/598] make threads daemon threads --- poller-service.py | 1 + 1 file changed, 1 insertion(+) diff --git a/poller-service.py b/poller-service.py index b42404130..9bb9d570d 100755 --- a/poller-service.py +++ b/poller-service.py @@ -291,6 +291,7 @@ def poll_worker(thread_id): t = [] for i in range(0, amount_of_workers): t.append(threading.Thread(target=poll_worker, args=[i])) + t[i].daemon = True t[i].start() From 06a809d96d23c4938e3922c7be7768f4af7f1b29 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 9 Sep 2015 15:09:19 -0400 Subject: [PATCH 286/598] unnecessary commas --- poller-service.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/poller-service.py b/poller-service.py index 9bb9d570d..eccfcd361 100755 --- a/poller-service.py +++ b/poller-service.py @@ -246,7 +246,7 @@ def poll_worker(thread_id): device_id, status, next_poll, next_discovery = dev_row[0] if not getLock('queue.{0}'.format(device_id), db): - releaseLock('queue.{0}'.format(device_id), db): + releaseLock('queue.{0}'.format(device_id), db) continue if next_poll and next_poll > datetime.now(): @@ -264,10 +264,10 @@ def poll_worker(thread_id): if not getLock('{0}.{1}'.format(action, device_id), db): releaseLock('{0}.{1}'.format(action, device_id), db) - releaseLock('queue.{0}'.format(device_id), db): + releaseLock('queue.{0}'.format(device_id), db) continue - releaseLock('queue.{0}'.format(device_id), db): + releaseLock('queue.{0}'.format(device_id), db) try: start_time = time.time() path = poller_path From 4c3b4fb5fa2333ae789f47be8caf98a59564fa95 Mon Sep 17 00:00:00 2001 From: Daniel Preussker Date: Wed, 9 Sep 2015 20:19:13 +0100 Subject: [PATCH 287/598] Add transition from old dashboard to new dashboard --- html/pages/front/tiles.php | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/html/pages/front/tiles.php b/html/pages/front/tiles.php index f5999d1c6..23fd808b4 100644 --- a/html/pages/front/tiles.php +++ b/html/pages/front/tiles.php @@ -19,6 +19,9 @@ $no_refresh = true; if (dbFetchCell('SELECT dashboard_id FROM dashboards WHERE user_id=?',array($_SESSION['user_id'])) == 0) { $vars['dashboard'] = dbInsert(array('dashboard_name'=>'Default','user_id'=>$_SESSION['user_id']),'dashboards'); + if (dbFetchCell('select 1 from users_widgets where user_id = ? && dashboard_id = ?',array($_SESSION['user_id'],0)) == 1) { + dbUpdate(array('dashboard_id'=>$vars['dashboard']),'users_widgets','user_id = ? && dashboard_id = ?',array($_SESSION['user_id'],0)); + } } if (empty($vars['dashboard'])) { $vars['dashboard'] = dbFetchRow('select dashboard_id,dashboard_name from dashboards where user_id = ? order by dashboard_id limit 1',array($_SESSION['user_id'])); @@ -29,12 +32,12 @@ $data = array(); foreach (dbFetchRows('SELECT user_widget_id,users_widgets.widget_id,title,widget,col,row,size_x,size_y,refresh FROM `users_widgets` LEFT JOIN `widgets` ON `widgets`.`widget_id`=`users_widgets`.`widget_id` WHERE `user_id`=? AND `dashboard_id`=?',array($_SESSION['user_id'],$vars['dashboard']['dashboard_id'])) as $items) { $data[] = $items; } - -$data = serialize(json_encode($data)); +if (empty($data)) { + $data[] = array('user_widget_id'=>'0','widget_id'=>1,'title'=>'Add a widget','widget'=>'placeholder','col'=>1,'row'=>1,'size_x'=>2,'size_y'=>2,'refresh'=>60); +} +$data = serialize(json_encode($data)); $dash_config = unserialize(stripslashes($data)); - -$dashboards = dbFetchRows("SELECT * FROM `dashboards` WHERE `user_id` = ?",array($_SESSION['user_id'])); - +$dashboards = dbFetchRows("SELECT * FROM `dashboards` WHERE `user_id` = ?",array($_SESSION['user_id'])); ?>
    From 01bef1ff01a8bb010e08361fff7c15bf4ef9b3b9 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 9 Sep 2015 15:23:04 -0400 Subject: [PATCH 288/598] smarter sleeping to try and lighten cpu load --- poller-service.py | 46 ++++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/poller-service.py b/poller-service.py index eccfcd361..18effffe2 100755 --- a/poller-service.py +++ b/poller-service.py @@ -240,7 +240,8 @@ def poll_worker(thread_id): while True: dev_row = db.query(dev_query) if len(dev_row) < 1: - #log.warning("WARNING: Thread {0} returned no devices from query".format(thread_id)) + # Sleep 1 second after getting an empty query, don't hammer the sql server for no reason. + time.sleep(1) continue device_id, status, next_poll, next_discovery = dev_row[0] @@ -296,24 +297,25 @@ for i in range(0, amount_of_workers): while True: - if next_update < datetime.now(): - seconds_taken = (datetime.now() - (next_update - timedelta(minutes=1))).seconds - update_query = ('INSERT INTO pollers(poller_name, ' - ' last_polled, ' - ' devices, ' - ' time_taken) ' - ' values("{0}", NOW(), "{1}", "{2}") ' - 'ON DUPLICATE KEY UPDATE ' - ' last_polled=values(last_polled), ' - ' devices=values(devices), ' - ' time_taken=values(time_taken) ').format(config['distributed_poller_name'].strip(), - devices_scanned, - seconds_taken) - try: - db.query(update_query) - except: - log.critical('ERROR: MySQL query error. Is your schema up to date?') - sys.exit(2) - log.info('INFO: {0} devices scanned in the last minute'.format(devices_scanned)) - devices_scanned = 0 - next_update = datetime.now() + timedelta(minutes=1) + sleep_until(next_update) + + seconds_taken = (datetime.now() - (next_update - timedelta(minutes=1))).seconds + update_query = ('INSERT INTO pollers(poller_name, ' + ' last_polled, ' + ' devices, ' + ' time_taken) ' + ' values("{0}", NOW(), "{1}", "{2}") ' + 'ON DUPLICATE KEY UPDATE ' + ' last_polled=values(last_polled), ' + ' devices=values(devices), ' + ' time_taken=values(time_taken) ').format(config['distributed_poller_name'].strip(), + devices_scanned, + seconds_taken) + try: + db.query(update_query) + except: + log.critical('ERROR: MySQL query error. Is your schema up to date?') + sys.exit(2) + log.info('INFO: {0} devices scanned in the last minute'.format(devices_scanned)) + devices_scanned = 0 + next_update = datetime.now() + timedelta(minutes=1) From a0288763d9d9a985fa127e61d7bbdd660963b965 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 9 Sep 2015 16:40:33 -0400 Subject: [PATCH 289/598] use native thread id --- poller-service.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/poller-service.py b/poller-service.py index 18effffe2..f724dffe4 100755 --- a/poller-service.py +++ b/poller-service.py @@ -233,9 +233,10 @@ next_update = datetime.now() + timedelta(minutes=1) devices_scanned = 0 -def poll_worker(thread_id): +def poll_worker(): global dev_query global devices_scanned + thread_id = threading.current_thread().ident db = DB() while True: dev_row = db.query(dev_query) @@ -289,11 +290,10 @@ def poll_worker(thread_id): releaseLock('{0}.{1}'.format(action, device_id), db) -t = [] for i in range(0, amount_of_workers): - t.append(threading.Thread(target=poll_worker, args=[i])) - t[i].daemon = True - t[i].start() + t = threading.Thread(target=poll_worker) + t.daemon = True + t.start() while True: From 9b2c9c2fd39c2dd6f694815aa36d180efaa406d5 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 9 Sep 2015 16:52:12 -0400 Subject: [PATCH 290/598] debug stats about threads --- poller-service.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/poller-service.py b/poller-service.py index f724dffe4..25da75edd 100755 --- a/poller-service.py +++ b/poller-service.py @@ -236,7 +236,7 @@ devices_scanned = 0 def poll_worker(): global dev_query global devices_scanned - thread_id = threading.current_thread().ident + thread_id = threading.current_thread().name db = DB() while True: dev_row = db.query(dev_query) @@ -282,6 +282,7 @@ def poll_worker(): log.debug("DEBUG: Thread {0} finished {1} of device {2} in {3} seconds".format(thread_id, action, device_id, elapsed_time)) else: log.warning("WARNING: Thread {0} finished {1} of device {2} in {3} seconds".format(thread_id, action, device_id, elapsed_time)) + thread_stats[thread_id]['last_completed_poll'] = datetime.now() except (KeyboardInterrupt, SystemExit): raise except: @@ -290,8 +291,11 @@ def poll_worker(): releaseLock('{0}.{1}'.format(action, device_id), db) +thread_stats = {} for i in range(0, amount_of_workers): + thread_stats[i] = {} t = threading.Thread(target=poll_worker) + t.name = i t.daemon = True t.start() @@ -299,6 +303,9 @@ for i in range(0, amount_of_workers): while True: sleep_until(next_update) + for thread, data in thread_stats.iteritems(): + log.debug('DEBUG: Thread {0} last completed at {1}'.format(thread, data['last_completed_poll'])) + seconds_taken = (datetime.now() - (next_update - timedelta(minutes=1))).seconds update_query = ('INSERT INTO pollers(poller_name, ' ' last_polled, ' From 310711b4e47568adca955d95386da832c4840f3e Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 9 Sep 2015 16:55:36 -0400 Subject: [PATCH 291/598] prepopulate last completed dict --- poller-service.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poller-service.py b/poller-service.py index 25da75edd..f9a992970 100755 --- a/poller-service.py +++ b/poller-service.py @@ -293,7 +293,7 @@ def poll_worker(): thread_stats = {} for i in range(0, amount_of_workers): - thread_stats[i] = {} + thread_stats[i] = {'last_completed_poll', 0} t = threading.Thread(target=poll_worker) t.name = i t.daemon = True From a74a5c8d814b6b2711e95970a86b1fc171856094 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 9 Sep 2015 17:00:26 -0400 Subject: [PATCH 292/598] Revert "prepopulate last completed dict" This reverts commit 310711b4e47568adca955d95386da832c4840f3e. --- poller-service.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poller-service.py b/poller-service.py index f9a992970..25da75edd 100755 --- a/poller-service.py +++ b/poller-service.py @@ -293,7 +293,7 @@ def poll_worker(): thread_stats = {} for i in range(0, amount_of_workers): - thread_stats[i] = {'last_completed_poll', 0} + thread_stats[i] = {} t = threading.Thread(target=poll_worker) t.name = i t.daemon = True From 39ec135ed3f00fc5c00a19bd669de8231f2c13e7 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 9 Sep 2015 17:00:36 -0400 Subject: [PATCH 293/598] Revert "debug stats about threads" This reverts commit 9b2c9c2fd39c2dd6f694815aa36d180efaa406d5. --- poller-service.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/poller-service.py b/poller-service.py index 25da75edd..f724dffe4 100755 --- a/poller-service.py +++ b/poller-service.py @@ -236,7 +236,7 @@ devices_scanned = 0 def poll_worker(): global dev_query global devices_scanned - thread_id = threading.current_thread().name + thread_id = threading.current_thread().ident db = DB() while True: dev_row = db.query(dev_query) @@ -282,7 +282,6 @@ def poll_worker(): log.debug("DEBUG: Thread {0} finished {1} of device {2} in {3} seconds".format(thread_id, action, device_id, elapsed_time)) else: log.warning("WARNING: Thread {0} finished {1} of device {2} in {3} seconds".format(thread_id, action, device_id, elapsed_time)) - thread_stats[thread_id]['last_completed_poll'] = datetime.now() except (KeyboardInterrupt, SystemExit): raise except: @@ -291,11 +290,8 @@ def poll_worker(): releaseLock('{0}.{1}'.format(action, device_id), db) -thread_stats = {} for i in range(0, amount_of_workers): - thread_stats[i] = {} t = threading.Thread(target=poll_worker) - t.name = i t.daemon = True t.start() @@ -303,9 +299,6 @@ for i in range(0, amount_of_workers): while True: sleep_until(next_update) - for thread, data in thread_stats.iteritems(): - log.debug('DEBUG: Thread {0} last completed at {1}'.format(thread, data['last_completed_poll'])) - seconds_taken = (datetime.now() - (next_update - timedelta(minutes=1))).seconds update_query = ('INSERT INTO pollers(poller_name, ' ' last_polled, ' From a761a4be77e62ac65a90dbc353bcf2ba3144e838 Mon Sep 17 00:00:00 2001 From: Clint Armstrong Date: Wed, 9 Sep 2015 17:01:44 -0400 Subject: [PATCH 294/598] use thread name as id --- poller-service.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/poller-service.py b/poller-service.py index f724dffe4..ce93108e3 100755 --- a/poller-service.py +++ b/poller-service.py @@ -236,7 +236,7 @@ devices_scanned = 0 def poll_worker(): global dev_query global devices_scanned - thread_id = threading.current_thread().ident + thread_id = threading.current_thread().name db = DB() while True: dev_row = db.query(dev_query) @@ -292,6 +292,7 @@ def poll_worker(): for i in range(0, amount_of_workers): t = threading.Thread(target=poll_worker) + t.name = i t.daemon = True t.start() From 1b5b5f1bc77896147f202492e00318ac31b15d56 Mon Sep 17 00:00:00 2001 From: Sergiusz Paprzycki Date: Thu, 10 Sep 2015 15:26:19 +0100 Subject: [PATCH 295/598] Settings page for Worldmap widget --- html/includes/common/worldmap.inc.php | 137 ++++++++++++++++++-------- 1 file changed, 94 insertions(+), 43 deletions(-) diff --git a/html/includes/common/worldmap.inc.php b/html/includes/common/worldmap.inc.php index dea7224e7..493bd0ab1 100644 --- a/html/includes/common/worldmap.inc.php +++ b/html/includes/common/worldmap.inc.php @@ -23,19 +23,72 @@ */ if ($config['map']['engine'] == 'leaflet') { - -$temp_output = ' + if ((defined('show_settings') || empty($widget_settings)) && $config['front_page'] == "pages/front/tiles.php") { + $temp_output = ' +
    +
    +
    + +
    +
    + +
    +
    +
    +
    + +
    +
    + +
    +
    +
    +
    + +
    +
    + +
    +
    +
    +
    + +
    +
    +
    + '; + } + else { + $temp_output = '
    '; - -} else { + } +} +else { $temp_output = 'Mapael engine not supported here'; } From ac282552f5da212d67dcbc3189b4b59ec76b8664 Mon Sep 17 00:00:00 2001 From: Sergiusz Paprzycki Date: Thu, 10 Sep 2015 16:05:22 +0100 Subject: [PATCH 296/598] Clean up of Global/World map mix-up in DB --- sql-schema/070.sql | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 sql-schema/070.sql diff --git a/sql-schema/070.sql b/sql-schema/070.sql new file mode 100644 index 000000000..2503e7f74 --- /dev/null +++ b/sql-schema/070.sql @@ -0,0 +1,4 @@ +UPDATE widgets SET widget_title = 'World map' WHERE widget = 'worldmap'; +UPDATE widgets SET widget_title = 'Globe map' WHERE widget = 'globe'; +UPDATE users_widgets SET title = 'World Map' WHERE widget_id = (SELECT widget_id FROM widgets WHERE widget = 'worldmap'); +UPDATE users_widgets SET title = 'Globe Map' WHERE widget_id = (SELECT widget_id FROM widgets WHERE widget = 'globe'); From ac6e56fa5618f86bf839e4288f3d041d5fbb7445 Mon Sep 17 00:00:00 2001 From: Daniel Preussker Date: Thu, 10 Sep 2015 17:14:36 +0100 Subject: [PATCH 297/598] changed settings icon --- html/pages/front/tiles.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/html/pages/front/tiles.php b/html/pages/front/tiles.php index 23fd808b4..a4d8674ca 100644 --- a/html/pages/front/tiles.php +++ b/html/pages/front/tiles.php @@ -46,7 +46,7 @@ $dashboards = dbFetchRows("SELECT * FROM `dashboards` WHERE `user_id` = ?",arra foreach ($dashboards as $dash) { echo ' '.$dash['dashboard_name'].''; if ($dash[dashboard_id] == $vars['dashboard']['dashboard_id']) { - echo ''; + echo ''; } } ?> From 4b6e17b817afa4819e8d8837bc7d8f2ebee4d2a5 Mon Sep 17 00:00:00 2001 From: Arjit Chaudhary Date: Fri, 11 Sep 2015 01:57:03 +0530 Subject: [PATCH 298/598] Small UI fixes Screenshot 1: http://i.imgur.com/Cj1PMkp.png Screenshot 2: http://i.imgur.com/GsAqJuU.png --- html/pages/delhost.inc.php | 55 +++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/html/pages/delhost.inc.php b/html/pages/delhost.inc.php index 79a2e3f05..d72f47048 100644 --- a/html/pages/delhost.inc.php +++ b/html/pages/delhost.inc.php @@ -25,17 +25,18 @@ else { print_error("Are you sure you want to delete device " . $device['hostname'] . "?"); ?>
    - -
    -
    -
    - - - - +
    + +
    + +
    + + + +
    -
    - + + It will also remove historical data about this device such as Syslog, Eventlog and Alert log data.

    -
    -
    - -
    - + ".$data['hostname'].""); + } - ?> - -
    - -
    -
    -
    -
    + ?> + +
    +
  • +
    + +
    +
    @@ -131,7 +132,7 @@ foreach (array('Private','Shared (Read)','Shared') as $k=>$v) { ?> - +
    @@ -139,32 +140,53 @@ foreach (array('Private','Shared (Read)','Shared') as $k=>$v) {
    + + +
    + Add Widgets +
    + + +
    +
    + +
    - +
    +
    +
    +
    + +
    +
    +
    +
    - @@ -338,8 +360,12 @@ foreach (dbFetchRows("SELECT * FROM `widgets` ORDER BY `widget_title`") as $widg dataType: "json", success: function (data) { if( data.status == "ok" ) { + $("#message").html('
    ' + data.message + '
    '); window.location.href="/overview"; } + else { + $("#message").html('
    ' + data.message + '
    '); + } } }); } @@ -357,8 +383,12 @@ foreach (dbFetchRows("SELECT * FROM `widgets` ORDER BY `widget_title`") as $widg dataType: "json", success: function (data) { if( data.status == "ok" ) { + $("#message").html('
    ' + data.message + '
    '); window.location.href="/overview/dashboard="; } + else { + $("#message").html('
    ' + data.message + '
    '); + } } }); } @@ -376,8 +406,12 @@ foreach (dbFetchRows("SELECT * FROM `widgets` ORDER BY `widget_title`") as $widg dataType: "json", success: function (data) { if( data.status == "ok" ) { + $("#message").html('
    ' + data.message + '
    '); window.location.href="/overview/dashboard="+data.dashboard_id; } + else { + $("#message").html('
    ' + data.message + '
    '); + } } }); } @@ -422,6 +456,9 @@ foreach (dbFetchRows("SELECT * FROM `widgets` ORDER BY `widget_title`") as $widg if( data.status == "ok" ) { widget_reload(widget_id,widget_type); } + else { + $("#message").html('
    ' + data.message + '
    '); + } } }); } From 8859130949974b4de883e4e5f4214ef45c8300ed Mon Sep 17 00:00:00 2001 From: Daniel Preussker Date: Fri, 11 Sep 2015 21:17:49 +0100 Subject: [PATCH 305/598] Fix `base_url` with tailing slash --- html/pages/front/tiles.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/html/pages/front/tiles.php b/html/pages/front/tiles.php index 6297b0a24..79c0e377e 100644 --- a/html/pages/front/tiles.php +++ b/html/pages/front/tiles.php @@ -65,7 +65,7 @@ $nodash = 0; if (sizeof($dashboards) > 0 || $vars['dashboard']['user_id'] != $_SESSION['user_id']) { foreach ($dashboards as $dash) { if ($dash['dashboard_id'] != $vars['dashboard']['dashboard_id']) { - echo '
  • '.$dash['dashboard_name'].'
  • '; + echo '
  • '.$dash['dashboard_name'].'
  • '; $nodash = 1; } } @@ -79,7 +79,7 @@ if (!empty($shared_dashboards)) { echo ' '; foreach ($shared_dashboards as $dash) { if ($dash['dashboard_id'] != $vars['dashboard']['dashboard_id']) { - echo '
  •    '.$dash['username'].':'.$dash['dashboard_name'].($dash['access'] == 1 ? ' (Read)' : '').'
  • '; + echo '
  •    '.$dash['username'].':'.$dash['dashboard_name'].($dash['access'] == 1 ? ' (Read)' : '').'
  • '; } } } @@ -361,7 +361,7 @@ foreach (dbFetchRows("SELECT * FROM `widgets` ORDER BY `widget_title`") as $widg success: function (data) { if( data.status == "ok" ) { $("#message").html('
    ' + data.message + '
    '); - window.location.href="/overview"; + window.location.href="/overview"; } else { $("#message").html('
    ' + data.message + '
    '); @@ -384,7 +384,7 @@ foreach (dbFetchRows("SELECT * FROM `widgets` ORDER BY `widget_title`") as $widg success: function (data) { if( data.status == "ok" ) { $("#message").html('
    ' + data.message + '
    '); - window.location.href="/overview/dashboard="; + window.location.href="/overview/dashboard="; } else { $("#message").html('
    ' + data.message + '
    '); @@ -407,7 +407,7 @@ foreach (dbFetchRows("SELECT * FROM `widgets` ORDER BY `widget_title`") as $widg success: function (data) { if( data.status == "ok" ) { $("#message").html('
    ' + data.message + '
    '); - window.location.href="/overview/dashboard="+data.dashboard_id; + window.location.href="/overview/dashboard="+data.dashboard_id; } else { $("#message").html('
    ' + data.message + '
    '); From baa209ff055c184ed42db9f5a7f4a77e9bf70b7b Mon Sep 17 00:00:00 2001 From: Daniel Preussker Date: Sat, 12 Sep 2015 09:51:58 +0100 Subject: [PATCH 306/598] Fixed width of dashboard-dropdown --- html/pages/front/tiles.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/html/pages/front/tiles.php b/html/pages/front/tiles.php index 79c0e377e..a3669f559 100644 --- a/html/pages/front/tiles.php +++ b/html/pages/front/tiles.php @@ -51,9 +51,9 @@ $dashboards = dbFetchRows("SELECT * FROM `dashboards` WHERE `user_id` = ? && `d
    - +
    - @@ -121,7 +121,7 @@ if (!empty($shared_dashboards)) {
    - Dashboard Name + Dashboard Name -
    -
    - - -
    - - +
    +
    +
    + + +
    +
    + + +
    + +
    +

    + +
    +
    +
    +
    +
    - -
    -
    - -
    -
    -'error','message'=>$auth_message,'title'=>'Login error'); -} -?> - -
    -
    '.$config['login_message'].'
    -
    - '); -} -?> - - - - - From b26aef9e8f876f299daebba6725283ccbd6d6469 Mon Sep 17 00:00:00 2001 From: RobsanInc Date: Sat, 12 Sep 2015 17:47:31 -0400 Subject: [PATCH 313/598] Added CentOS 7 installation, tweaked formatting --- doc/Extensions/RRDCached.md | 71 +++++++++++++++++++++++++++++++++++-- 1 file changed, 68 insertions(+), 3 deletions(-) diff --git a/doc/Extensions/RRDCached.md b/doc/Extensions/RRDCached.md index 27a157c5d..bbd025429 100644 --- a/doc/Extensions/RRDCached.md +++ b/doc/Extensions/RRDCached.md @@ -2,8 +2,8 @@ This document will explain how to setup RRDCached for LibreNMS. -### RRDCached installation -This example is based on a fresh LibreNMS install, on a minimimal CentOS installation. +### RRDCached installation CentOS 6 +This example is based on a fresh LibreNMS install, on a minimimal CentOS 6 installation. In this example, we'll use the Repoforge repository. ```ssh @@ -33,7 +33,72 @@ chkconfig rrdcached on service rrdcached start ``` -Edit config.php to include: +- Edit /opt/librenms/config.php to include: ```ssh $config['rrdcached'] = "unix:/var/run/rrdcached/rrdcached.sock"; ``` +### RRDCached installation CentOS 7 +This example is based on a fresh LibreNMS install, on a minimimal CentOS 7.x installation. +We'll use the epel-release and setup a RRDCached as a service. +It is recommended that you monitor your LibreNMS server with LibreNMS so you can view the disk I/O usage delta. +See [Installation (RHEL CentOS)][1] for localhost monitoring. + +- Install the EPEL and update the repos and RRDtool. +```ssh +yum install epel-release +yum update +yum update rrdtool +``` + +- Create the needed directories, set ownership and permissions. +```ssh +mkdir /var/run/rrdcached +chown librenms:librenms /var/run/rrdcached +chmod 755 /var/run/rrdcached +``` + +- Create an rrdcache service for easy daemon management. +```ssh +touch /etc/systemd/system/rrdcache.service +``` +- Edit rrdcache.service and paste the example config: +```ssh +[Unit] +Description=RRDtool Cache +After=network.service + +[Service] +Type=forking +PIDFile=/run/rrdcached.pid +ExecStart=/usr/bin/rrdcached -w 1800 -z 1800 -f 3600 -s librenms -j /var/tmp -l unix:/var/run/rrdcached/rrdcached.sock -t 4 -F -b /opt/librenms/rrd/ +RRDC_USER=librenms + +[Install] +WantedBy=default.target +``` + +- Restart the systemctl daemon so it can recognize the newly created rrdcache.service. Enable the rrdcache.service on boot, and start the service. +```ssh +systemctl daemon-reload +systemctl enable rrdcache.service +systemctl start rrdcache.service +``` + +- Edit /opt/librenms/config.php to include: +```ssh +$config['rrdcached'] = "unix:/var/run/rrdcached/rrdcached.sock"; +``` + +- Restart Apache +```ssh +systemctl restart httpd +``` + +Check to see if the graphs are being drawn in LibreNMS. This might take a few minutes. +After at least one poll cycle (5 mins), check the LibreNMS disk I/O performance delta. +Disk I/O can be found under the menu Devices>All Devices>[localhost hostname]>Health>Disk I/O +Depending on many factors, you should see the Ops/sec drop by ~30-40%. + + +[1]: http://librenms.readthedocs.org/Installation/Installation-(RHEL-CentOS)/#add-localhost +"Add localhost to LibreNMS" From 4453bebef607a95cec562d4530749bfacfc40373 Mon Sep 17 00:00:00 2001 From: Juho Vanhanen Date: Sun, 13 Sep 2015 12:28:53 +0300 Subject: [PATCH 314/598] I agree to the conditions of the Contributor Agreement contained in doc/General/Contributing.md. --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 610f95b21..035e8383e 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -51,6 +51,7 @@ Contributors to LibreNMS: - Todd Eddy (vrillusions) - Arjit Chaudhary (arjit.c@gmail.com) (arjitc) - Sergiusz Paprzycki (spaprzycki) +- Juho Vanhanen (juhovan) [1]: http://observium.org/ "Observium web site" From 8fd40f463fce1a13041c96d8c63265ab8f974270 Mon Sep 17 00:00:00 2001 From: Arjit Chaudhary Date: Sun, 13 Sep 2015 21:35:59 +0530 Subject: [PATCH 315/598] Various UI changes Screenshots: 1. http://i.imgur.com/smjSuvc.png 2. http://i.imgur.com/0JFyKgE.png --- html/pages/api-access.inc.php | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/html/pages/api-access.inc.php b/html/pages/api-access.inc.php index 3124aad6e..5bad919ee 100644 --- a/html/pages/api-access.inc.php +++ b/html/pages/api-access.inc.php @@ -79,7 +79,7 @@ foreach (dbFetchRows("SELECT user_id,username FROM `users` WHERE `level` >= '10' -
    - +
    +
    + +
    +

    -
    - \ No newline at end of file +
    +
    + +
    +
    From 27dc720892ac08525450cc6a480b41250a24ab44 Mon Sep 17 00:00:00 2001 From: Arjit Chaudhary Date: Wed, 16 Sep 2015 18:38:09 +0530 Subject: [PATCH 342/598] Match button style (ie, with + fontawesome icon) --- html/includes/print-alert-rules.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/html/includes/print-alert-rules.php b/html/includes/print-alert-rules.php index 670a57815..27e15ad36 100644 --- a/html/includes/print-alert-rules.php +++ b/html/includes/print-alert-rules.php @@ -107,7 +107,7 @@ echo '
    echo ''; if ($_SESSION['userlevel'] >= '10') { - echo ''; + echo ''; } echo ' From 99e819d3bbd71e42ae1ceba4cdd228fc43ac5156 Mon Sep 17 00:00:00 2001 From: Arjit Chaudhary Date: Wed, 16 Sep 2015 19:03:46 +0530 Subject: [PATCH 343/598] Add fa-check to Save and move out of table --- html/pages/device/edit/apps.inc.php | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/html/pages/device/edit/apps.inc.php b/html/pages/device/edit/apps.inc.php index 044952ab1..0bed0731c 100644 --- a/html/pages/device/edit/apps.inc.php +++ b/html/pages/device/edit/apps.inc.php @@ -58,10 +58,11 @@ if (count($apps_enabled)) { } } -echo " +echo "
    +
    - +
    @@ -89,12 +90,13 @@ foreach ($applications as $app) { $row++; } -echo ' - - - '; echo '
    Enable Application
    - - -
    '; +echo '
    +
    + +
    +
    +'; echo '
    '; +echo '
    '; +echo '
    '; From 9fcee7a0401388707fff8dd70dc15ee897c1985e Mon Sep 17 00:00:00 2001 From: Arjit Chaudhary Date: Wed, 16 Sep 2015 19:04:29 +0530 Subject: [PATCH 344/598] Added back table-condensed --- html/pages/device/edit/apps.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/html/pages/device/edit/apps.inc.php b/html/pages/device/edit/apps.inc.php index 0bed0731c..9ed743de7 100644 --- a/html/pages/device/edit/apps.inc.php +++ b/html/pages/device/edit/apps.inc.php @@ -62,7 +62,7 @@ echo "
    - +
    From 4393039f6e29968705877cb66b59aef705ea609c Mon Sep 17 00:00:00 2001 From: Daniel Preussker Date: Wed, 16 Sep 2015 14:05:36 +0000 Subject: [PATCH 345/598] Fix typo in URL --- doc/General/Contributing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/General/Contributing.md b/doc/General/Contributing.md index 8561f3f29..c1d49bc22 100644 --- a/doc/General/Contributing.md +++ b/doc/General/Contributing.md @@ -170,7 +170,7 @@ project. Proposed workflow for submitting pull requests ---------------------------------------------- -Please see the new [Using Git](http://doc.librenms.org/Developing/Using-Git/) document which gives you step-by-step +Please see the new [Using Git](http://docs.librenms.org/Developing/Using-Git/) document which gives you step-by-step instructions on using git to submit a pull request. [1]: http://www.gnu.org/licenses/license-list.html From fe537618b1fd8376e56e0fefc521c9f5c7379b69 Mon Sep 17 00:00:00 2001 From: Rosiak Date: Wed, 16 Sep 2015 18:17:04 +0200 Subject: [PATCH 346/598] Minor Fixes --- html/pages/api-access.inc.php | 2 +- includes/definitions.inc.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/html/pages/api-access.inc.php b/html/pages/api-access.inc.php index 5bad919ee..a57cc935b 100644 --- a/html/pages/api-access.inc.php +++ b/html/pages/api-access.inc.php @@ -135,7 +135,7 @@ foreach (dbFetchRows('SELECT `AT`.*,`U`.`username` FROM `api_tokens` AS AT JOIN - + '; } diff --git a/includes/definitions.inc.php b/includes/definitions.inc.php index 5fcdce7b6..618f871b3 100644 --- a/includes/definitions.inc.php +++ b/includes/definitions.inc.php @@ -1278,7 +1278,7 @@ $config['os'][$os]['over'][0]['text'] = 'Traffic'; // MACOSX $os = 'macosx'; -$config['os'][$os]['text'] = 'Apple OSX'; +$config['os'][$os]['text'] = 'Apple OS X'; $config['os'][$os]['type'] = 'server'; $config['os'][$os]['icon'] = 'generic'; $config['os'][$os]['over'][0]['graph'] = 'device_bits'; From 606963cc18df69aed5fabbf4448daa418bcd67aa Mon Sep 17 00:00:00 2001 From: Tom Ferguson Date: Thu, 17 Sep 2015 06:43:55 -0400 Subject: [PATCH 347/598] Added MIBs for Avaya IP Office --- mibs/avaya/AV-SME-PLATFORM-MIB.mib | 334 +++ mibs/avaya/AV-SME-PLATFORM-PROD-MIB.mib | 288 +++ mibs/avaya/AVAYAGEN-MIB.mib | 104 + mibs/avaya/IPO-MIB.mib | 2499 +++++++++++++++++++++++ mibs/avaya/IPO-PHONES-MIB.mib | 691 +++++++ mibs/avaya/IPO-PROD-MIB.mib | 1202 +++++++++++ 6 files changed, 5118 insertions(+) create mode 100644 mibs/avaya/AV-SME-PLATFORM-MIB.mib create mode 100644 mibs/avaya/AV-SME-PLATFORM-PROD-MIB.mib create mode 100644 mibs/avaya/AVAYAGEN-MIB.mib create mode 100644 mibs/avaya/IPO-MIB.mib create mode 100644 mibs/avaya/IPO-PHONES-MIB.mib create mode 100644 mibs/avaya/IPO-PROD-MIB.mib diff --git a/mibs/avaya/AV-SME-PLATFORM-MIB.mib b/mibs/avaya/AV-SME-PLATFORM-MIB.mib new file mode 100644 index 000000000..16bb78e3e --- /dev/null +++ b/mibs/avaya/AV-SME-PLATFORM-MIB.mib @@ -0,0 +1,334 @@ +--======================================================== +-- +-- MIB : SME Platform Avaya Inc. +-- +-- Version : 0.03.00 11 January 2013 +-- +--======================================================== +-- +-- Copyright (c) 2013 Avaya Inc. +-- All Rights Reserved. +-- +--======================================================== +AV-SME-PLATFORM-MIB DEFINITIONS ::= BEGIN + +IMPORTS + MODULE-IDENTITY, OBJECT-TYPE, + NOTIFICATION-TYPE + FROM SNMPv2-SMI + DateAndTime + FROM SNMPv2-TC + MODULE-COMPLIANCE, OBJECT-GROUP, + NOTIFICATION-GROUP + FROM SNMPv2-CONF + SnmpAdminString + FROM SNMP-FRAMEWORK-MIB + sysDescr + FROM SNMPv2-MIB + ItuPerceivedSeverity + FROM ITU-ALARM-TC-MIB + ifIndex + FROM IF-MIB + mibs + FROM AVAYAGEN-MIB +; + +avSMEPlatformMIB MODULE-IDENTITY + LAST-UPDATED "201301111405Z" -- 11 January 2013 + ORGANIZATION "Avaya Inc." + CONTACT-INFO + "Avaya Customer Services + Postal: Avaya, Inc. + 211 Mt Airy Rd. + Basking Ridge, NJ 07920 + USA + Tel: +1 908 953 6000 + + WWW: http://www.avaya.com" + DESCRIPTION + "Avaya IP Office MIBs OID tree. + + This MIB module defines the root items for MIBs for + use with Avaya SME Embedded Platform." + + + REVISION "201301111405Z" -- 11 January 2013 + DESCRIPTION + "Rev 0.03.00 + Added the WebManagement application value for smepGTEventAppIdentity." + REVISION "201007061347Z" -- 06 July 2010 + DESCRIPTION + "Rev 0.02.00 + Corrected base OID to one properly allocated in Avaya tree." + REVISION "201007021437Z" -- 02 July 2010 + DESCRIPTION + "Rev 0.01.00 + The first rough draft of this MIB module." + ::= { mibs 48 } + +-- sub-tree for SME Embedded Platform wide objects and events +-- irrespective of function +smepGeneric OBJECT IDENTIFIER ::= { avSMEPlatformMIB 1 } + +-- sub-tree for SME Embedded Platform functional MIBs +smepGenMibs OBJECT IDENTIFIER ::= { smepGeneric 1 } + +-- sub-tree for SME EMbedded Platform wide traps/notifications +smepGenTraps OBJECT IDENTIFIER ::= { smepGeneric 2 } + +-- sub-tree for SME Embedded Platform wide conformance information +smepGenConformance OBJECT IDENTIFIER ::= { smepGeneric 3 } + +--******************************************************************** +-- SME Embedded Platform wide traps/notifications +--******************************************************************** + +smepGTEvents OBJECT IDENTIFIER ::= { smepGenTraps 0 } +smepGTObjects OBJECT IDENTIFIER ::= { smepGenTraps 1 } + +-- +-- trap objects +-- + +smepGTEventStdSeverity OBJECT-TYPE + SYNTAX ItuPerceivedSeverity + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "Severity of the event that has occurred. + + The event severity depends upon the type of + entity/notification that the operational state change event + relates to. The severity values that are normally used are + detailed below: + + The enterprise versions of standard SNMP traps all have a + severity of major (4). + + GenAppEvents: + Severity depends on event condition + crash - severity is critical (3)" + ::= { smepGTObjects 1 } + +smepGTEventDateTime OBJECT-TYPE + SYNTAX DateAndTime + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "Date and time of the occurence of the event." + ::= { smepGTObjects 2 } + +smepGTEventDevID OBJECT-TYPE + SYNTAX SnmpAdminString (SIZE (10)) + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "A unique textual identifier of the alarming device." + ::= { smepGTObjects 3 } + +smepGTEventAppEntity OBJECT-TYPE + SYNTAX INTEGER { + voiceMailPro(1), + onex(2), + ipOffice(3), + jade(4), + webmanagement(5) + } + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "The SME Embedded Platform application to which a + notification/trap relates." + ::= { smepGTObjects 4 } + +smepGTEventAppEvent OBJECT-TYPE + SYNTAX INTEGER { + crash(1) -- severity: Critical + } + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "SME Embedded Platform application event states. The + associated event severity of the notification/trap the object + is carried in varies depending upon the event condition. The + appropriate severity is detailed against event enumeration." + ::= { smepGTObjects 5 } + +-- +-- traps +-- + +smepGenColdStartEvent NOTIFICATION-TYPE + OBJECTS { + smepGTEventStdSeverity, + smepGTEventDateTime, + smepGTEventDevID, + sysDescr + } + STATUS current + DESCRIPTION + "Enterprise version of standard coldstart trap featuring + device identification information. A coldStart trap + signifies that the sending protocol entity is reinitializing + itself such that the agent's configuration or the protocol + entity implementation may be altered." + ::= { smepGTEvents 1 } + +smepGenWarmStartEvent NOTIFICATION-TYPE + OBJECTS { + smepGTEventStdSeverity, + smepGTEventDateTime, + smepGTEventDevID, + sysDescr + } + STATUS current + DESCRIPTION + "Enterprise version of standard warmstart trap featuring + device identification information. A warmStart trap + signifies that the sending protocol entity is reinitializing + that neither the agent configuration nor the protocol entity + implementation is altered." + ::= { smepGTEvents 2 } + +smepGenLinkDownEvent NOTIFICATION-TYPE + OBJECTS { + smepGTEventStdSeverity, + smepGTEventDateTime, + smepGTEventDevID, + sysDescr, + ifIndex + } + STATUS current + DESCRIPTION + "Enterprise version of standard linkDown trap featuring device + identification information. A linkDown trap signifies that + the sending protocol entity recognizes a failure in one of + the communication links represented in the agent's + configuration." + ::= { smepGTEvents 3 } + +smepGenLinkUpEvent NOTIFICATION-TYPE + OBJECTS { + smepGTEventStdSeverity, + smepGTEventDateTime, + smepGTEventDevID, + sysDescr, + ifIndex + } + STATUS current + DESCRIPTION + "Enterprise version of standard linkUp trap featuring device + identification information. A linkUp trap signifies that the + sending protocol entity recognizes that one of the + communication links represented in the agent's configuration + has come up." + ::= { smepGTEvents 4 } + +smepGenAuthFailureEvent NOTIFICATION-TYPE + OBJECTS { + smepGTEventStdSeverity, + smepGTEventDateTime, + smepGTEventDevID, + sysDescr + } + STATUS current + DESCRIPTION + "Enterprise version of standard authenticationFailure trap + featuring device identification information. An + authenticationFailure trap signifies that the sending + protocol entity is the addressee of a protocol message that + is not properly authenticated. While implementations of the + SNMP must be capable of generating this trap, they must also + be capable of suppressing the emission of such traps via an + implementation- specific mechanism." + ::= { smepGTEvents 5 } + +smepGenAppEvent NOTIFICATION-TYPE + OBJECTS { + smepGTEventStdSeverity, + smepGTEventDateTime, + smepGTEventDevID, + sysDescr, + smepGTEventAppEntity, + smepGTEventAppEvent + } + STATUS current + DESCRIPTION + "A smepGenAppEvent notification is generated whenever a + application entity of the SME Embedded Platform experiences an + event. It signifies that the SNMP entity, acting as a proxy + for the application, has detected an event on the application + entity. + + The event severity varies dependent upon the event condition." + ::= { smepGTEvents 6 } + + +--******************************************************************** +-- SME Embedded Platform wide compliance +--******************************************************************** + +smepGenCompliances OBJECT IDENTIFIER ::= { smepGenConformance 1 } +smepGenGroups OBJECT IDENTIFIER ::= { smepGenConformance 2 } + +-- +-- compliance statements +-- + +smepGenCompliance MODULE-COMPLIANCE + STATUS deprecated + DESCRIPTION + "The compliance statement for SME Embedded Platform agents + which implement this MIB." + MODULE -- this module + MANDATORY-GROUPS { + smepGenNotificationObjectsGroup, + smepGenEntGenNotificationsGroup, + smepGenAppNotificationsGroup + } + ::= { smepGenCompliances 1 } + +-- +-- MIB groupings +-- + +smepGenNotificationObjectsGroup OBJECT-GROUP + OBJECTS { + smepGTEventStdSeverity, + smepGTEventDevID, + smepGTEventDateTime, + smepGTEventAppEntity, + smepGTEventAppEvent + } + STATUS current + DESCRIPTION + "Objects that are contained in SME Embedded Platform wide + notifications." + ::= { smepGenGroups 1 } + +smepGenEntGenNotificationsGroup NOTIFICATION-GROUP + NOTIFICATIONS { + smepGenColdStartEvent, + smepGenWarmStartEvent, + smepGenLinkDownEvent, + smepGenLinkUpEvent, + smepGenAuthFailureEvent + } + STATUS current + DESCRIPTION + "SME Embedded Platform Enterpise versions of the generic traps + as defined RFC1215 that provide more identification of the entity + concerned." + ::= { smepGenGroups 2 } + +smepGenAppNotificationsGroup NOTIFICATION-GROUP + NOTIFICATIONS { + smepGenAppEvent + } + STATUS current + DESCRIPTION + "The service notifications which indicate specific changes in + the state of Applications on the SME Embedded Platform." + ::= { smepGenGroups 3 } + +END diff --git a/mibs/avaya/AV-SME-PLATFORM-PROD-MIB.mib b/mibs/avaya/AV-SME-PLATFORM-PROD-MIB.mib new file mode 100644 index 000000000..08c053723 --- /dev/null +++ b/mibs/avaya/AV-SME-PLATFORM-PROD-MIB.mib @@ -0,0 +1,288 @@ +--======================================================== +-- +-- MIB : AV-SME-PLATFORM-PROD Avaya Inc. +-- +-- Version : 0.14.00 30 May 2014 +-- +--======================================================== +-- +-- Copyright (c) 2010 - 2012 Avaya Inc. +-- All Rights Reserved. +-- +--======================================================== +AV-SME-PLATFORM-PROD-MIB DEFINITIONS ::= BEGIN + +IMPORTS + MODULE-IDENTITY, OBJECT-IDENTITY + FROM SNMPv2-SMI + products + FROM AVAYAGEN-MIB; + +avSMEPlatformProdMIB MODULE-IDENTITY + LAST-UPDATED "201405301200Z" -- 30 May 2014 + ORGANIZATION "Avaya Inc." + CONTACT-INFO + "Avaya Customer Services + Postal: Avaya, Inc. + 211 Mt Airy Rd. + Basking Ridge, NJ 07920 + USA + Tel: +1 908 953 6000 + + WWW: http://www.avaya.com" + DESCRIPTION + "Avaya IP Office Products OID tree. + + This MIB module defines the product/sysObjectID values for + use with Avaya IP Office family of telephone switches." + + REVISION "201405301200Z" -- 30 May 2014 + DESCRIPTION + "Rev 0.14.00 + Added configuration 11, 12, 13 for IP Office Server Edition Primary, + IP Office Server Edition Secondary and + IP Office Server Edition Expansion System (L) Select Mode" + REVISION "201404031200Z" -- 03 April 2014 + DESCRIPTION + "Rev 0.13.00 + Updated service vendor values + Added Contact Recorder service" + REVISION "201301231600Z" -- 23 January 2013 + DESCRIPTION + "Rev 0.12.00 + Updated branding for configuration 1 and 10" + REVISION "201211291200Z" -- 29 November 2012 + DESCRIPTION + "Rev 0.11.00 + Updated branding for configuration 1. + Added configuration 10." + REVISION "201205101235Z" -- 10 May 2012 + DESCRIPTION + "Rev 0.10.00 + Updated branding for configurations 7, 8 and 9." + REVISION "201204091025Z" -- 09 Apr 2012 + DESCRIPTION + "Rev 0.09.00 + Updated branding for configurations 7, 8 and 9." + REVISION "201203051005Z" -- 05 Mar 2012 + DESCRIPTION + "Rev 0.08.00 + Updated configurations 7, 8 and 9." + REVISION "201112161330Z" -- 16 Dec 2011 + DESCRIPTION + "Rev 0.07.01 + Updated configuration 6." + REVISION "201112141535Z" -- 14 Dec 2011 + DESCRIPTION + "Rev 0.07.00 + Added configuration 9, updated configurations 7 and 8." + REVISION "201112071410Z" -- 07 Dec 2011 + DESCRIPTION + "Rev 0.06.00 + Added configurations 7 and 8." + REVISION "201105031330Z" -- 03 May 2011 + DESCRIPTION + "Rev 0.05.00 + Added configuration 6." + REVISION "201103300922Z" -- 30 March 2011 + DESCRIPTION + "Rev 0.04.00 + Added configuration 4 and 5." + REVISION "201007071350Z" -- 07 July 2010 + DESCRIPTION + "Rev 0.03.00 + Simplified the structure." + REVISION "201007061345Z" -- 06 July 2010 + DESCRIPTION + "Rev 0.02.00 + Corrected base OID to one properly allocated in Avaya tree." + REVISION "201007021506Z" -- 02 July 2010 + DESCRIPTION + "Rev 0.01.00 + The first rough draft of this MIB module." + ::= { products 48 } + +-- Product Groups + +smepProdVariants OBJECT IDENTIFIER ::= { avSMEPlatformProdMIB 1 } +smepProdServices OBJECT IDENTIFIER ::= { avSMEPlatformProdMIB 2 } +smepProdPorts OBJECT IDENTIFIER ::= { avSMEPlatformProdMIB 3 } +smepProdDongleModules OBJECT IDENTIFIER ::= { avSMEPlatformProdMIB 4 } + +-- Configuration 1 + +smepCfg1 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Configuration 1 + of the SME Embedded Platform. + Configuration 1 = IP Office Application Server on Linux PC" + ::= { smepProdVariants 1 } + +-- Configuration 2 + +smepCfg2 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Configuration 2 + of the SME Embedded Platform. + Configuration 2 = IP Office on PC." + ::= { smepProdVariants 2 } + +-- Configuration 3 + +smepCfg3 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Configuration 3 + of the SME Embedded Platform. + Configuration 3 = IP Office on HP ProCurve" + ::= { smepProdVariants 3 } + +-- Configuration 4 + +smepCfg4 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Configuration 4 + of the SME Embedded Platform. + Configuration 4 = IP Office on Dell" + ::= { smepProdVariants 4 } + +-- Configuration 5 + +smepCfg5 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Configuration 5 + of the SME Embedded Platform. + Configuration 5 = Branch installations" + ::= { smepProdVariants 5 } + +-- Configuration 6 + +smepCfg6 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Configuration 6 + of the SME Embedded Platform. + Configuration 6 = Standalone Voice Mail" + ::= { smepProdVariants 6 } + +-- Configuration 7 + +smepCfg7 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Configuration 7 + of the SME Embedded Platform. + Configuration 7 = IP Office Server Edition Primary" + ::= { smepProdVariants 7 } + +-- Configuration 8 + +smepCfg8 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Configuration 8 + of the SME Embedded Platform. + Configuration 8 = IP Office Server Edition Secondary" + ::= { smepProdVariants 8 } + +-- Configuration 9 + +smepCfg9 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Configuration 9 + of the SME Embedded Platform. + Configuration 9 = IP Office Server Edition Expansion System (L)" + ::= { smepProdVariants 9 } + +-- Configuration 10 + +smepCfg10 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Configuration 10 + of the SME Embedded Platform. + Configuration 10 = IP Office Application Server on UCM" + ::= { smepProdVariants 10 } + +-- Configuration 11 + +smepCfg11 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Configuration 11 + of the SME Embedded Platform. + Configuration 11 = IP Office Server Edition Primary Select Mode" + ::= { smepProdVariants 11 } + +-- Configuration 12 + +smepCfg12 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Configuration 12 + of the SME Embedded Platform. + Configuration 12 = IP Office Server Edition Secondary Select Mode" + ::= { smepProdVariants 12 } + +-- Configuration 13 + +smepCfg13 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Configuration 13 + of the SME Embedded Platform. + Configuration 13 = IP Office Server Edition Expansion System (L) Select Mode" + ::= { smepProdVariants 13 } + +-- Application Services Groups + +smepProdServiceOneXPortal OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya one-X Portal service + resident on Avaya IP Office on Linux server." + ::= { smepProdServices 1 } + +smepProdServiceVoicemailPro OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya Voicemail Pro service + resident on Avaya IP Office on Linux server." + ::= { smepProdServices 2 } + +smepProdServiceContactRecorder OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya Contact Recorder service + resident on Avaya IP Office on Linux server." + ::= { smepProdServices 3 } + + +-- Ports + +smepProdPortLAN OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office LAN + (10BASE-T/100BASE-TX) Ports" + ::= { smepProdPorts 1 } + + +-- Dongle + +smepProdGenericDongle OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office License + Dongle - A single representation for three dongle types, + Parallel, Serial and USB. The Parallel and USB ones not truly + connected directly to the IP Office but the managing PC." + ::= { smepProdDongleModules 1 } + + +END diff --git a/mibs/avaya/AVAYAGEN-MIB.mib b/mibs/avaya/AVAYAGEN-MIB.mib new file mode 100644 index 000000000..7e013629b --- /dev/null +++ b/mibs/avaya/AVAYAGEN-MIB.mib @@ -0,0 +1,104 @@ +--======================================================== +-- +-- MIB : AvayaGen Avaya Inc. +-- +-- Version : 1.4.0 27 January 2004 +-- ======================================================== +--- This AVAYA SNMP Management Information Base Specification (Specification) +-- embodies AVAYA confidential and Proprietary intellectual property. +-- AVAYA retains all Title and ownership in the Specification, including any +-- revisions. +-- +-- It is AVAYA's intent to encourage the widespread use of this Specification +-- in connection with the management of AVAYA products. AVAYA grants vendors, +-- end-users, and other interested parties a non-exclusive license to use this +-- Specification in connection with the management of AVAYA products. +-- +-- This Specification is supplied "as is," and AVAYA makes no warranty, either +-- express or implied, as to the use, operation, condition, or performance of +-- the Specification. +--======================================================== +AVAYAGEN-MIB DEFINITIONS ::= BEGIN + IMPORTS + enterprises,MODULE-IDENTITY + FROM SNMPv2-SMI; +avaya MODULE-IDENTITY +LAST-UPDATED "0401270900Z" -- 27 January 2004 +ORGANIZATION "Avaya Inc." +CONTACT-INFO + "Avaya Customer Services + Postal: Avaya, Inc. + 211 Mt Airy Rd. + Basking Ridge, NJ 07920 + USA + Tel: +1 908 953 6000 + WWW: http://www.avaya.com + " +DESCRIPTION + "Avaya top-level OID tree. + This MIB module deals defines the Avaya enterprise-specific tree. + Development organizations within Avaya who wish to register MIBs + under the Avaya enterprise OID, should: + a. Contact the maintainer of this module, and get an organization OID and + group OID. + b. Import the definition of their Organization OID from this MIB. + " +REVISION "0401270900Z" -- 27 January 2004 +DESCRIPTION + "Rev 1.4.0 - Meir Deutsch. + adds avGatewayProducts under avayaProducts. + adds avGatewayMibs under avayaMibs. + " +REVISION "0208150900Z" -- 15 August 2002 +DESCRIPTION + "Rev 1.3.0 - Itai Zilbershterin. + adds avayaSystemStats under lsg. + " +REVISION "0207280900Z" -- 28 July 2002 +DESCRIPTION + "Rev 1.2.0 - Itai Zilbershterin. + adds avayaEISTopology under lsg. + " +REVISION "0108091700Z" -- 09 August 2001 +DESCRIPTION + "Rev 1.1.0 - Itai Zilbershterin. + adds products OID to those defined. + " +REVISION "0106211155Z" -- 21 June 2001 +DESCRIPTION + "Rev 1.0.0 - Itai Zilbershterin. + Fixed the mibs placement error. Avaya Mibs + reside under avaya.2 and not avaya.1. + The MIB branch is called avayaMibs." + +REVISION "0010151045Z" -- 15 Oct. 2000 +DESCRIPTION + "Rev 0.9.0 - Itai Zilbershterin. + The initial version of this MIB module. + + The following Organizational top-level groups are defined: + lsg - Mibs of the LAN System Group (Concord & Israel)." +REVISION "0010151305Z" -- 15 Oct. 2000 +DESCRIPTION + "Rev 0.9.1 - Itai Zilbershterin. + Dates in Revisions changed from 'yyyymmddhhmm' to 'yymmddhhmm', to support + older development environments." +::= { enterprises 6889 } +-- **************************** +-- **************************** +-- Product OIDs +products OBJECT IDENTIFIER ::= { avaya 1 } +-- MIBs +mibs OBJECT IDENTIFIER ::= { avaya 2 } +-- Gateway +avGatewayProducts OBJECT IDENTIFIER ::= { products 6 } +avGatewayMibs OBJECT IDENTIFIER ::= { mibs 6 } +-- ********************************** +-- LAN System Group's +-- ********************************** +lsg OBJECT IDENTIFIER ::= { mibs 1 } +-- Sub branches which are NOT MIB modules (MIB modules directly under lsg +-- will define their OID in relation to lsg) +avayaEISTopology OBJECT IDENTIFIER ::= {lsg 10 } +avayaSystemStats OBJECT IDENTIFIER ::= {lsg 11 } +END diff --git a/mibs/avaya/IPO-MIB.mib b/mibs/avaya/IPO-MIB.mib new file mode 100644 index 000000000..c81143844 --- /dev/null +++ b/mibs/avaya/IPO-MIB.mib @@ -0,0 +1,2499 @@ +--======================================================== +-- +-- MIB : IPO Avaya Inc. +-- +-- Version : 2.00.25 04 July 2014 +-- +--======================================================== +-- +-- Copyright (c) 2003 - 2014 Avaya Inc. +-- All Rights Reserved. +-- +--======================================================== +IPO-MIB DEFINITIONS ::= BEGIN + +IMPORTS + MODULE-IDENTITY, OBJECT-TYPE, + NOTIFICATION-TYPE, Unsigned32, Integer32, + IpAddress + FROM SNMPv2-SMI + DateAndTime + FROM SNMPv2-TC + MODULE-COMPLIANCE, OBJECT-GROUP, + NOTIFICATION-GROUP + FROM SNMPv2-CONF + SnmpAdminString + FROM SNMP-FRAMEWORK-MIB + sysDescr + FROM SNMPv2-MIB + ItuPerceivedSeverity + FROM ITU-ALARM-TC-MIB + ifIndex + FROM IF-MIB + mibs + FROM AVAYAGEN-MIB +; + +ipoMIB MODULE-IDENTITY + LAST-UPDATED "201407040000Z" -- 04 July 2014 + ORGANIZATION "Avaya Inc." + CONTACT-INFO + "Avaya Customer Services + Postal: Avaya, Inc. + 211 Mt Airy Rd. + Basking Ridge, NJ 07920 + USA + Tel: +1 908 953 6000 + + WWW: http://www.avaya.com" + DESCRIPTION + "Avaya IP Office MIBs OID tree. + + This MIB module defines the root items for MIBs for + use with Avaya IP Office family of telephone switches." + REVISION "201407040000Z" -- 04 July 2014 + DESCRIPTION + "Rev 2.00.25 + Added new value serviceAMServerNotAvailable" + REVISION "201406250000Z" -- 25 June 2014 + DESCRIPTION + "Rev 2.00.24 + Added new value serviceCCRNotSupported" + REVISION "201406250000Z" -- 25 June 2014 + DESCRIPTION + "Rev 2.00.23 + Added new value serviceNonSelectAlarm" + REVISION "201406160000Z" -- 16 June 2014 + DESCRIPTION + "Rev 2.00.22 + Added new values serviceGeneralAlarm and serviceSystemInfo" + REVISION "201406040000Z" -- 04 June 2014 + DESCRIPTION + "Rev 2.00.21 + Added new value serviceIPDECTSystemError " + REVISION "201405230000Z" -- 23 May 2014 + DESCRIPTION + "Rev 2.00.20 + Added new value monitorLogStamped " + REVISION "201405080000Z" -- 08 May 2014 + DESCRIPTION + "Rev 2.00.19 + Added new values trunkSIPDNSInvalidConfig and trunkSIPDNSTransportError " + REVISION "201401060000Z" -- 06 January 2014 + DESCRIPTION + "Rev 2.00.18 + Added oneXPortal values for ipoGTEventAppEntity" + REVISION "201310080000Z" -- 08 October 2013 + DESCRIPTION + "Rev 2.00.17 + Added new values serviceSystemHardDriveAlarm and serviceAdditionalHardDriveAlarm " + REVISION "201308060000Z" -- 06 August 2013 + DESCRIPTION + "Rev 2.00.16 + Added new values of serviceACCSAlarm for + ipoGTEventReason object" + REVISION "201304241900Z" -- 24 April 2013 + DESCRIPTION + "Rev 2.00.15 + Added new values for ipoGTEventReason object + serviceCpuAlarm, serviceCpuIOAlarm, serviceMemoryAlarm" + REVISION "201304241518Z" -- 24 April 2013 + DESCRIPTION + "Rev 2.00.14 + Added new value of serviceLocalBackup for + ipoGTEventReason object" + REVISION "201211171511Z" -- 17 November 2012 + DESCRIPTION + "Rev 2.00.13 + Added new notification: ipoGenEmergencyCallSvcEvent + Added new value of serviceEmergencyCall to the ipoGTEventReason object." + REVISION "201202281300Z" -- 28 February 2012 + DESCRIPTION + "Rev 2.00.12 + Added new values for ipoGTEventReason object from + servicePortRangeExhausted to serviceWebservicesUWSError." + REVISION "201111012200Z" -- 1 November 2011 + DESCRIPTION + "Rev 2.00.11 + Added new values for ipoGTEventReason object from + servicePlannedMaintenance to serviceSslVpnServerReportedError." + REVISION "201109271130Z" -- 27 September 2011 + DESCRIPTION + "Rev 2.00.10 + Added new value of testAlarm for ipoGTEventReason object." + REVISION "201103151517Z" -- 15 March 2011 + DESCRIPTION + "Rev 2.00.09 + Added new value of securityError for + ipoGTEventReason object" + REVISION "201010131417Z" -- 13 October 2010 + DESCRIPTION + "Rev 2.00.08 + Added new value of serviceLicenseFileInvalid for + ipoGTEventReason object" + REVISION "201007121345Z" -- 12 July 2010 + DESCRIPTION + "Rev 2.00.07 + Introduced new notifications, see ipoGenSvcMiscNotificationsGroup + and new objects, see ipoGenSvcMiscNotificationObjectsGroup" + REVISION "200910190735Z" -- 19 October 2009 + DESCRIPTION + "Rev 2.00.06 + System Running Backup, Invalid Memory Card, No Licence Key Dongle + Notifications added. Corrections to MIB syntax for System + Shutdown Notification." + REVISION "200910091347Z" -- 09 October 2009 + DESCRIPTION + "Rev 2.00.05 + System shutdown Notification added." + REVISION "200909110950Z" -- 11 September 2009 + DESCRIPTION + "Rev 2.00.04 + QOS Monitoring Notification added." + REVISION "200909071620Z" -- 07 September 2009 + DESCRIPTION + "Rev 2.00.03 + smallBusinessContactCenter(3) value for + ipoGTEventAppEntity changed to customerCallReporter." + REVISION "200804281640Z" -- 28 April 2008 + DESCRIPTION + "Rev 2.00.02 + Added smallBusinessContactCenter(3) value to + ipoGTEventAppEntity." + REVISION "200804181450Z" -- 18 April 2008 + DESCRIPTION + "Rev 2.00.01 + Added traps related to Universal PRI licensing." + REVISION "200606290000Z" -- 29 June 2006 + DESCRIPTION + "Rev 2.00.00 + Traps/notifications revised to provide more information about + the entity and device concerned." + REVISION "200410060000Z" -- 06 October 2004 + DESCRIPTION + "Rev 1.00.08 + Corrected description of event severities for physical + entities." + REVISION "200408270000Z" -- 27 August 2004 + DESCRIPTION + "Rev 1.00.07 + Corrected mandatory groups after addition of SOG event + related objects and notifications." + REVISION "200408060000Z" -- 06 August 2004 + DESCRIPTION + "Rev 1.00.06 + Added SOG event related object and notifications." + REVISION "200407100000Z" -- 10 July 2004 + DESCRIPTION + "Rev 1.00.05 + Added application event related object and notifications. + Corrected description of ipoGenLKSCommsOperationalEvent." + REVISION "200405280000Z" -- 28 May 2004 + DESCRIPTION + "Rev 1.00.04 + Revised usage description for ipoGTEventSeverity." + REVISION "200403030000Z" -- 03 March 2004 + DESCRIPTION + "Rev 1.00.03 + Revised for external publication." + REVISION "200312150000Z" -- 15 December 2003 + DESCRIPTION + "Rev 1.00.02 + Added loopback object and notification." + REVISION "200311110000Z" -- 11 November 2003 + DESCRIPTION + "Rev 1.00.01 + Corrected ipoGTEventEntity MAX-ACCESS." + REVISION "200310100000Z" -- 10 October 2003 + DESCRIPTION + "Rev 1.00.00 + The first published version of this MIB module." + ::= { mibs 2 } + +-- sub-tree for IP Office wide objects and events irrespective of function +ipoGeneric OBJECT IDENTIFIER ::= { ipoMIB 1 } + +-- sub-tree for IP Office functional MIBs +ipoGenMibs OBJECT IDENTIFIER ::= { ipoGeneric 1 } + +-- sub-tree for IP Office wide traps/notifications +ipoGenTraps OBJECT IDENTIFIER ::= { ipoGeneric 2 } + +-- sub-tree for IP Office wide conformance information +ipoGenConformance OBJECT IDENTIFIER ::= { ipoGeneric 3 } + +--******************************************************************** +-- IP Office wide traps/notifications +--******************************************************************** + +ipoGTEvents OBJECT IDENTIFIER ::= { ipoGenTraps 0 } +ipoGTObjects OBJECT IDENTIFIER ::= { ipoGenTraps 1 } + +-- +-- trap objects +-- + +ipoGTEventSeverity OBJECT-TYPE + SYNTAX INTEGER { + critical(1), + major(2), + minor(3) + } + MAX-ACCESS accessible-for-notify + STATUS deprecated + DESCRIPTION + "Severity of the event that has occurred. + + The event severity depends upon the type of + entity/notification that the operational state change event + relates to: + + GenEntityEvents: + + Type of physical Severity + entity + container critical + module major + port major + + Known transient errors for entities have a severity of minor. + + LKSCommsEvents: + Severity is major + + GenLoopbackEvent: + Severity is major + + GenAppEvents: + Severity depends on sub-event + Failure/Operational - severity is major + Event - severity depends on event condition + + ipoGenSogEvents: + Severity depends on sub-event + HostFailure - severity is Major + ModeChange: + - Mode survivable: severity is Major + - Mode subTending: severity is Minor + + PhoneChangeEvents: + Severity is minor + + **NOTE: This object is deprecated and replaced by + ipoGTEventStdSeverity." + ::= { ipoGTObjects 1 } + +ipoGTEventDateTime OBJECT-TYPE + SYNTAX DateAndTime + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "Date and time of the occurence of the event." + ::= { ipoGTObjects 2 } + +ipoGTEventEntity OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "A reference, by entPhysicalIndex value, to the + EntPhysicalEntry representing the physical entity that an + event is associated with in an entity MIB instantiation within + the IP Office agent." + ::= { ipoGTObjects 3 } + +ipoGTEventLoopbackStatus OBJECT-TYPE + SYNTAX Integer32 (1..127) + MAX-ACCESS accessible-for-notify + STATUS deprecated + DESCRIPTION + "This variable represents the current state of the + loopback on the DS1 interface. It contains + information about loopbacks established by a + manager and remotely from the far end. + + The ipoGTEventLoopbackStatus is a bit map represented as + a sum, therefore is can represent multiple + loopbacks simultaneously. + + The various bit positions are: + 1 noLoopback + 2 nearEndPayloadLoopback + 4 nearEndLineLoopback + 8 nearEndOtherLoopback + 16 nearEndInwardLoopback + 32 farEndPayloadLoopback + 64 farEndLineLoopback" + ::= { ipoGTObjects 4 } + +ipoGTEventAppEntity OBJECT-TYPE + SYNTAX INTEGER { + voiceMail(1), + deltaServer(2), + customerCallReporter(3), + oneXPortal(4) + } + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "The IP Office application to which a notification/trap + relates." + ::= { ipoGTObjects 5 } + +ipoGTEventAppEvent OBJECT-TYPE + SYNTAX INTEGER { + storageFull(1), -- severity: Critical + storageNearlyFull(2), -- severity: Major + storageOkay(3), -- severity: Minor + backupCommunicationError(4), -- severity: Major + backupFileError(5), -- severity: Major + httpFailure(6), -- severity: Major + httpSslAcceptFailure(7), -- severity: Major + httpSslConnection(8), -- severity: Major + httpSslFailure(9), -- severity: Major + httpSslPortFailure(10), -- severity: Major + ignoringRequest(11), -- severity: Major + imapInitializationFailed(12), -- severity: Major + imapInvalidMsgNr(13), -- severity: Major + imapMailboxNotExist(14), -- severity: Major + imapMessageInvalid(15), -- severity: Major + imapMessageNotExist(16), -- severity: Major + imapMessageNrNotExist(17), -- severity: Major + imapMissingConnection(18), -- severity: Major + imapMissingSettings(19), -- severity: Major + imapNoLicence(20), -- severity: Major + imapNotConfigured(21), -- severity: Major + imapShiftConnection(22), -- severity: Major + mapiInitializationFailed(23), -- severity: Major + mapiMissingSettings(24), -- severity: Major + mapiConnectionFailed(25), -- severity: Major + mapiShiftConnection(26), -- severity: Major + licence(27), -- severity: Major + licenceDistributed(28), -- severity: Major + licenceExpired(29), -- severity: Major + licenceSOG(30), -- severity: Major + loginFailure(31), -- severity: Major + loginFailureInvalidMailbox(32), -- severity: Major + mailboxNotFound(33), -- severity: Major + makeLiveFileAccess(34), -- severity: Major + makeLiveMissingFile(35), -- severity: Major + offlineMakeLive(36), -- severity: Major + onexError(37), -- severity: Major + pbxConnectionLost(38), -- severity: Major + pbxIncompatibility(39), -- severity: Major + smgrSettingsError(40), -- severity: Major + smtpConnectionFailed(41), -- severity: Major + smtpConnectionTimeout(42), -- severity: Major + smtpError(43), -- severity: Major + smtpSecureConnectionFailed(44), -- severity: Major + smtpUnexpectedData(45), -- severity: Major + smtpUnsuportedData(46), -- severity: Major + socketAbortingError(47), -- severity: Major + socketBindError(48), -- severity: Major +socketClientDisconnectedError(49), -- severity: Major + socketConnectionError(50), -- severity: Major + socketNoresponseError(51), -- severity: Major + socketOptionError(52), -- severity: Major + socketReceiveError(53), -- severity: Major + socketRecvFailedError(54), -- severity: Major + socketSendFailedError(55), -- severity: Major + socketSelectError(56), -- severity: Major + socketTimedOutError(57), -- severity: Major + switchedToPrimary(58), -- severity: Major + switchedToSecondary(59), -- severity: Major + tcpAcceptError(60), -- severity: Major + tcpListenError(61), -- severity: Major + tcpSelectError(62), -- severity: Major + tcpError(63), -- severity: Major + testTimeExpired(64), -- severity: Major + tftpConnectionError(65), -- severity: Major + tftpMonitoringError(66), -- severity: Major + tftpReadingError(67), -- severity: Major + tftpReceivingError(68), -- severity: Major + tftpWrittingError(69), -- severity: Major + tooManyClients(70), -- severity: Major + updateEerror(71), -- severity: Major + updateSuccess(72), -- severity: Major + vmScript(73) -- severity: Major + } + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "IP Office application event states. The associated event + severity of the notification/trap the object is carried in + varies depending upon the event condition. The appropriate + severity is detailed against event enumeration." + ::= { ipoGTObjects 6 } + +ipoGTEventHostAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "Address of an IP Office Small Office Gateway Subtending Host." + ::= { ipoGTObjects 7 } + +ipoGTEventSOGMode OBJECT-TYPE + SYNTAX INTEGER { + survivable(1), -- severity: Major + subTending(2) -- severity: Minor + } + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "IP Office Small Office Gateway operating modes. + survivable(1) indicates the control unit has no current host, + either through confguration error or communication failure. + subTending(2) indicates normal operation to a valid Sub- + tending Host." + ::= { ipoGTObjects 8 } + +ipoGTEventStdSeverity OBJECT-TYPE + SYNTAX ItuPerceivedSeverity + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "Severity of the event that has occurred. + + The event severity depends upon the type of + entity/notification that the operational state change event + relates to. The severity values that are normally used are + detailed below: + + The enterprise versions of standard SNMP traps all have a + severity of major (4). + + Operational events which notify the transition back to an + operational state from a failure state have a severity of + cleared (1). + + + GenEntityEvents: + Operational - severity is cleared (1) + + Failure event severity levels + Type of physical Severity for failure + entity + container critical (3) + module major (4) + port major (4) + + Error + Known transient errors for entities have a severity of + warning (6). + + Change - severity is major (4) + + LKSCommsSvcEvents: + Operational - severity is cleared (1) + Failure - severity is major (4) + + GenLoopbackSvcEvent: + Severity is major (4) + + GenAppSvcEvents: + Severity depends on sub-event + Operational - severity is cleared (1) + Failure - severity is major (4) + Event - severity depends on event condition + For voicemail storage conditions the severity is as + follows: + storageOkay - severity is cleared (1) + storageNearlyFull - severity is warning (6) + (Only warning severity as it could be transitory.) + storageFull - severity is critical (3) + + GenSogSvcEvents: + Severity depends on sub-event + HostFailure - severity is Major (4) + ModeChange: + - Mode survivable: severity is Major (4) + - Mode subTending: severity is Minor (5) + + GenUPriLicSvcEvents: + Severity depends on sub-event + ChansReduced - severity is Major (4) + CallRejected - severity is Minor (5) + + GenQoSMonSvcEvent: + QoSWarning - severity is Warning (6) + + PhoneChangeSvcEvents: + Severity is minor (5) + + ipoGenSystemRunningBackupEvent: + Severity is cleared (1) + Severity is critical (3) + + ipoGenInvalidMemoryCardEvent: + Severity is cleared (1) + Severity is Major (4) + + ipoGenNoLicenceKeyDongleEvent: + Severity is cleared (1) + Severity is warning (6) + Severity is critical (3) + + ipoGenMemoryCardCapacityEvent: + Severity depends on sub-event + storageOkay - severity is cleared (1) + storageNearlyFull - severity is warning (6) + storageFull - severity is critical (3)" + ::= { ipoGTObjects 9 } + +ipoGTEventDevID OBJECT-TYPE + SYNTAX SnmpAdminString (SIZE (10)) + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "A unique textual identifier of the alarming device." + ::= { ipoGTObjects 10 } + +ipoGTEventEntityName OBJECT-TYPE + SYNTAX SnmpAdminString (SIZE (0..64)) + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "The textual name of the alarming physical entity. The + contents of this object is made of concatenated + entPhysicalName values that fully identify the object with the + overall IP Office entity. Examples values are: + + Controller, Trunk Slot B, Trunk Module, T1 PRI 2 + = T1 PRI Port 2, on a dual T1 Trunk Module, in Trunk Slot B, + on the IP Office Controller Unit + + Controller, VCM Slot 1, VCM 1 + = VCM Card, in VCM Slot 1, on the IP Office Controller Unit + + Controller, EXP 1, DS EXP 16, DS 12 + = DS Phone Port 12, on a DS16 Expansion Module, attached to + Expansion Port 1, on the IP Office Controller Unit" + ::= { ipoGTObjects 11 } + +ipoGTEventLoopbackStatusBits OBJECT-TYPE + SYNTAX BITS { + noLoopback(0), + nearEndPayloadLoopback(1), + nearEndLineLoopback(2), + nearEndOtherLoopback(3), + nearEndInwardLoopback(4), + farEndPayloadLoopback(5), + farEndLineLoopback(6) + } + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "This variable represents the current state of the loopback on + the DS1 interface. It contains information about loopbacks + established by a manager and remotely from the far end. + + The ipoGTEventLoopbackStatus is a bit map therefore is can + represent multiple loopbacks simultaneously." + ::= { ipoGTObjects 12 } + +ipoGTEventQoSMonJitter OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "IP Office QoS monitoring Received Jitter time in milliseconds." + ::= { ipoGTObjects 13 } + +ipoGTEventQoSMonRndTrip OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "IP Office QoS monitoring Round Trip Delay time in milliseconds." + ::= { ipoGTObjects 14 } + +ipoGTEventQoSMonPktLoss OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "IP Office QoS monitoring Received Packet Loss." + ::= { ipoGTObjects 15 } + +ipoGTEventQoSMonCallId OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "IP Office QoS monitoring Call Identifier." + ::= { ipoGTObjects 16 } + +ipoGTEventQoSMonDevType OBJECT-TYPE + SYNTAX INTEGER { + line(1), + extn(2) + } + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "IP Office QoS monitoring Device Type." + ::= { ipoGTObjects 17 } + +ipoGTEventQoSMonDevId OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "IP Office QoS monitoring Device Identifier." + ::= { ipoGTObjects 18 } + +ipoGTEventQoSMonExtnNo OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "IP Office QoS monitoring Extension Number." + ::= { ipoGTObjects 19 } + +ipoGTEventSystemShutdownSource OBJECT-TYPE + SYNTAX SnmpAdminString (SIZE (0..255)) + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "This variable represents the source from where the system + shutdown was performed. + + Possible values are: + + DTE-Port + - if the system shutdown is performed using the DTE, + AUX-Button + - if the system shutdown is performed using the AUX + button (available only for IP500v2), + Phone + - if the system shutdown is performed from a phone, + Manager + - if the system shutdown is performed from Manager, + SSA + - if the system shutdown is performed from SSA." + ::= { ipoGTObjects 20 } + +ipoGTEventSystemShutdownTimeout OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "This variable represents the period of time the system will be in + the shutdown state for. Possible values are in the 5 to 1440 minutes + range, 0 meaning infinite." + ::= { ipoGTObjects 21 } + +ipoGTEventMemoryCardSlotId OBJECT-TYPE + SYNTAX INTEGER { + compactFlash(1), + systemSD(2), + optionalSD(3) + } + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "This variable indicates a memory card physical position identifier. + System(2) and Optional(3) are valid for the IP500 V2. CF(1) valid + for the IP500." + ::= { ipoGTObjects 22 } + +ipoGTEventNoValidKeyReason OBJECT-TYPE + SYNTAX INTEGER { + noReason(1), + notPresent(2), + noRegisterAccess(3), + invalidRegisters(4), + invalidWatermark(5), + invalidClusterSize(6), + invalidVolume(7), + invalidHeaderFiles(8), + nonSpecificError(9) + } + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "This variable indicates the reason no valid licence feature key is + assumed. This is also the order of importance and check precedence. + noReason(1) - cleared condition + notPresent(2) - license feature key no present + noRegisterAccess(3) - license feature key present, but no access + invalidRegisters(4) - invalid register values + invalidWatermark(5) - watermark invalid or not present + invalidClusterSize(6) - filesystem not as expected" + ::= { ipoGTObjects 23 } + +ipoGTEventReason OBJECT-TYPE + SYNTAX INTEGER { + configurationAgentNotTargeted(1), + configurationSCNDialPlanConflict(2), + configurationNoIncomingCallRoute(3), + configurationHWTypeFailure(4), + serviceFeatureLicenseMissing(5), + serviceAllLicensesInUse(6), + serviceClockSourceChanged(7), + serviceLogonFailed(8), + serviceNoFreeChannelsAvail(9), + serviceHoldMusicFileFailure(10), + serviceAllResourcesInUse(11), + serviceAlarm(12), + serviceNetworkInterconnectFailure(13), + trunkSeizeFailure(14), + trunkIncomingCallOutgoingTrunk(15), + trunkCLINotDelivered(16), + trunkDDIIncomplete(17), + trunkLOS(18), + trunkOOS(19), + trunkRedAlarm(20), + trunkBlueAlarm(21), + trunkYellowAlarm(22), + trunkIPConnectFail(23), + trunkSCNInvalidConnection(24), + linkDeviceChanged(25), + linkLDAPServerCommFailure(26), + linkResourceDown(27), + linkSMTPServerCommFailure(28), + linkVMProConnFailure(29), + serviceTimeServerAlarm(30), + serviceLicenseFileInvalid(31), + serviceLicenseError(32), + securityError(33), + codecError(34), + scepNoRespError(35), + configAppsProcAlarm(36), + serviceAppsProcAlarm(37), + serviceLicenseServerError(38), + testAlarm(39), + servicePlannedMaintenance(40), + serviceNetworkDisconnection(41), + serviceFailedTlsNegotiation(42), + serviceFailedTlsRenegotiation(43), + serviceLackOfResources(44), + serviceInternalError(45), + serviceTooManyMissedHeartbeats(46), + serviceFailedDnsResolution(47), + serviceDuplicateIpAddress(48), + serviceAuthenticationFailure(49), + serviceSslVpnStackProtocolError(50), + serviceSslVpnServerReportedError(51), + servicePortRangeExhausted(52), + serviceWebservicesUWSError(53), + trunkNoFreeVoIPChannel(54), + serviceEmergencyCall(55), + serviceLocationCongestion(56), + serviceCpuAlarm(57), + serviceCpuIOAlarm(58), + serviceMemoryAlarm(59), + serviceLocalBackup(60), + trunkSMConnectAsSIP(61), + trunkSIPConnectAsSM(62), + serviceSipRxPacketSizeError(63), + serviceACCSAlarm(64), + serviceSystemHardDriveAlarm(65), + serviceAdditionalHardDriveAlarm(66), + linkDialerConnFailure(67), + trunkSIPDNSInvalidConfig(68), + trunkSIPDNSTransportError(69), + monitorLogStamped(70), + trunkSCNInvalidSubOperMode(71), + serviceIPDECTSystemError(72), + serviceIPOCCAlarm(73), + serviceGeneralAlarm(74), + serviceSystemInfo(75), + serviceNonSelectAlarm(76), + serviceCCRNotSupported(77), + serviceAMServerNotAvailable(78), + trunkMediaSecuritySettingsIncompatible(79) + } + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "This variable indicates what event took place within Configuration, Service, Trunk + or Link category alarm" + ::= { ipoGTObjects 24 } + +ipoGTEventData OBJECT-TYPE + SYNTAX SnmpAdminString (SIZE (0..255)) + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "This variable contains opaque data that can be used to provide additional information + when the ipoGTEventReason value is not sufficient." + ::= { ipoGTObjects 25 } + +ipoGTEventAlarmDescription OBJECT-TYPE + SYNTAX SnmpAdminString (SIZE (0..255)) + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "This variable describes the alarm" + ::= { ipoGTObjects 26 } + +ipoGTEventAlarmRemedialAction OBJECT-TYPE + SYNTAX SnmpAdminString (SIZE (0..255)) + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "This variable describes the remedial action of the alarm" + ::= { ipoGTObjects 27 } + + + +-- +-- traps +-- + +ipoGenEntityFailureEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventSeverity, + ipoGTEventDateTime, + ipoGTEventEntity + } + STATUS deprecated + DESCRIPTION + "A ipoGenEntityFailureEvent notification is generated whenever a + physical entity on the IP Office fails in its operation. It + signifies that the SNMP entity, acting in an agent role, has + detected that the state of a physical entity of the system has + transitioned from the operational to the failed state + + **NOTE: This notification is deprecated and replaced by + ipoGenEntityFailureSvcEvent" + ::= { ipoGTEvents 1 } + +ipoGenEntityOperationalEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventSeverity, + ipoGTEventDateTime, + ipoGTEventEntity + } + STATUS deprecated + DESCRIPTION + "A ipoGenEntityOperationalEvent notification is generated whenever + a physical entity on the IP Office becomes operational again + after having failed. It signifies that the SNMP entity, acting + in an agent role, has detected that the state of a physical + entity of the system has transitioned from the failed to the + operational state + + **NOTE: This notification is deprecated and replaced by + ipoGenEntityOperationalSvcEvent." + ::= { ipoGTEvents 2 } + +ipoGenEntityErrorEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventSeverity, + ipoGTEventDateTime, + ipoGTEventEntity + } + STATUS deprecated + DESCRIPTION + "A ipoGenEntityErrorEvent notification is generated whenever a + physical entity on the IP Office experiences a temporary + error. It signifies that the SNMP entity, acting in an agent + role, has detected a transitory error on a physical entity of + the system. + + **NOTE: This notification is deprecated and replaced by + ipoGenEntityErrorSvcEvent." + ::= { ipoGTEvents 3 } + +ipoGenEntityChangeEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventSeverity, + ipoGTEventDateTime, + ipoGTEventEntity + } + STATUS deprecated + DESCRIPTION + "A ipoGenEntityChangeEvent notification is generated whenever + a physical entity on the IP Office experiences a change itself + or with other entities associated with it. It signifies that + the SNMP entity, acting in an agent role, has detected a non + error/failure change for a physical entity on the system. + + **NOTE: This notification is deprecated and replaced by + ipoGenEntityChangeSvcEvent." + ::= { ipoGTEvents 4 } + +ipoGenLKSCommsFailureEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventSeverity, + ipoGTEventDateTime + } + STATUS deprecated + DESCRIPTION + "A ipoGenLKSCommsFailureEvent notification is generated + whenever communication with a Licence Key Server fails. It + signifies that the SNMP entity, acting in an agent role, has + detected that the state of the communications between the + Licence Key Server has transitioned from the operational to + the failed state. + + **NOTE: This notification is deprecated and replaced by + ipoGenLKSCommsFailureSvcEvent." + ::= { ipoGTEvents 5 } + +ipoGenLKSCommsOperationalEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventSeverity, + ipoGTEventDateTime + } + STATUS deprecated + DESCRIPTION + "A ipoGenLKSCommsOperationalEvent notification is generated + whenever communication with a Licence Key Server becomes + operational again after having failed. It signifies that the + SNMP entity, acting in an agent role, has detected that the + state of the communications between the Licence Key Server has + transitioned from the failed to the operational state. + + **NOTE: This notification is deprecated and replaced by + ipoGenLKSCommsOperationalSvcEvent." + ::= { ipoGTEvents 6 } + +ipoGenLKSCommsErrorEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventSeverity, + ipoGTEventDateTime + } + STATUS deprecated + DESCRIPTION + "A ipoGenLKSCommsErrorEvent notification is generated whenever + a IP Office experiences a temporary error with License Key + Server communication. It signifies that the SNMP entity, + acting in an agent role, has detected a transitory error with + the communication between the License Key Server and Client + on the system. + + **NOTE: This notification is deprecated and replaced by + ipoGenLKSCommsErrorSvcEvent." + ::= { ipoGTEvents 7 } + +ipoGenLKSCommsChangeEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventSeverity, + ipoGTEventDateTime + } + STATUS deprecated + DESCRIPTION + "A ipoGenLKSCommsChangeEvent notification is generated + whenever a IP Office experiences a change a non error change + License Key Server communication operation. It signifies that + the SNMP entity, acting in an agent role, has detected a non + error/failure change with the License Key Server and Client + operation on the system. + + **NOTE: This notification is deprecated and replaced by + ipoGenLKSCommsChangeSvcEvent." + ::= { ipoGTEvents 8 } + +ipoGenLoopbackEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventSeverity, + ipoGTEventDateTime, + ipoGTEventEntity, + ipoGTEventLoopbackStatus + } + STATUS deprecated + DESCRIPTION + "A ipoGenLoopbackEvent notification is generated whenever a IP + Office T1 (DS1) interface operating as a CSU actions a loopback + status change. + + **NOTE: This notification is deprecated and replaced by + ipoGenLoopbackSvcEvent." + ::= { ipoGTEvents 9 } + +ipoGenAppFailureEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventSeverity, + ipoGTEventDateTime, + ipoGTEventAppEntity + } + STATUS deprecated + DESCRIPTION + "A ipoGenAppFailureEvent notification is generated whenever + communication between a IP Office switch and a IP Office + application fails. It signifies that the SNMP entity, acting + in an agent role, has detected that the state of the + communications between the IP Office switch and a IP Office + application has transitioned from the operational to the + failed state. The IP Office application between which + communication has been lost is identified by the value of + ipoGTEventAppEntity. + + **NOTE: This notification is deprecated and replaced by + ipoGenAppFailureSvcEvent." + ::= { ipoGTEvents 10 } + +ipoGenAppOperationalEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventSeverity, + ipoGTEventDateTime, + ipoGTEventAppEntity + } + STATUS deprecated + DESCRIPTION + "A ipoGenAppOperationalEvent notification is generated + whenever communication between a IP Office switch and a IP + Office application becomes operational again after having + failed. It signifies that the SNMP entity, acting in an agent + role, has detected that the state of the communications + between the IP Office switch and a IP Office application has + transitioned from the failed to the operational state. The IP + Office application between which communication has been lost + is identified by the value of ipoGTEventAppEntity. + + **NOTE: This notification is deprecated and replaced by + ipoGenAppOperationalSvcEvent." + ::= { ipoGTEvents 11 } + +ipoGenAppEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventSeverity, + ipoGTEventDateTime, + ipoGTEventAppEntity, + ipoGTEventAppEvent + } + STATUS deprecated + DESCRIPTION + "A ipoGenAppEvent notification is generated whenever a + application entity of the IP Office system experiences an event. + It signifies that the SNMP entity, acting as a proxy for + the application, has detected an event on the application + entity of the overall IP Office system. + The event severity varies dependent upon the event condition. + + **NOTE: This notification is deprecated and replaced by + ipoGenAppSvcEvent." + ::= { ipoGTEvents 12 } + +ipoGenSogHostFailureEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventSeverity, + ipoGTEventDateTime, + ipoGTEventHostAddress + } + STATUS deprecated + DESCRIPTION + "An ipoGenSogFailureEvent notification is generated whenever a + previously valid Sub-tending host fails during Small Office + Gateway operation. + The ipAddress field indicates the address of the failed host. + The event severity will always indicate Major. + + **NOTE: This notification is deprecated and replaced by + ipoGenSogHostFailureSvcEvent." + ::= { ipoGTEvents 13 } + +ipoGenSogModeChangeEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventSeverity, + ipoGTEventDateTime, + ipoGTEventSOGMode + } + STATUS deprecated + DESCRIPTION + "An ipoGenSogModeChangeEvent notification is generated whenever + the Small Office Gateway operating mode changes. This also + includes entry to the initial mode. + The ipoGTEventSOGMode field indicates the new operating mode. + The event severity will be major(2) for a ipoGTEventSOGMode value + of survivable(1), and minor(3) for a ipoGTEventSOGMode value of + subTending(2). + + **NOTE: This notification is deprecated and replaced by + ipoGenSogModeChangeSvcEvent." + ::= { ipoGTEvents 14 } + +ipoGenColdStartSvcEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventStdSeverity, + ipoGTEventDateTime, + ipoGTEventDevID, + sysDescr + } + STATUS current + DESCRIPTION + "Enterprise version of standard coldstart trap featuring + device identification information. A coldStart trap + signifies that the sending protocol entity is reinitializing + itself such that the agent's configuration or the protocol + entity implementation may be altered." + ::= { ipoGTEvents 15 } + +ipoGenWarmStartSvcEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventStdSeverity, + ipoGTEventDateTime, + ipoGTEventDevID, + sysDescr + } + STATUS current + DESCRIPTION + "Enterprise version of standard warmstart trap featuring + device identification information. A warmStart trap + signifies that the sending protocol entity is reinitializing + that neither the agent configuration nor the protocol entity + implementation is altered." + ::= { ipoGTEvents 16 } + +ipoGenLinkDownSvcEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventStdSeverity, + ipoGTEventDateTime, + ipoGTEventDevID, + sysDescr, + ifIndex + } + STATUS current + DESCRIPTION + "Enterprise version of standard linkDown trap featuring device + identification information. A linkDown trap signifies that + the sending protocol entity recognizes a failure in one of + the communication links represented in the agent's + configuration." + ::= { ipoGTEvents 17 } + +ipoGenLinkUpSvcEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventStdSeverity, + ipoGTEventDateTime, + ipoGTEventDevID, + sysDescr, + ifIndex + } + STATUS current + DESCRIPTION + "Enterprise version of standard linkUp trap featuring device + identification information. A linkUp trap signifies that the + sending protocol entity recognizes that one of the + communication links represented in the agent's configuration + has come up." + ::= { ipoGTEvents 18 } + +ipoGenAuthFailureSvcEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventStdSeverity, + ipoGTEventDateTime, + ipoGTEventDevID, + sysDescr + } + STATUS current + DESCRIPTION + "Enterprise version of standard authenticationFailure trap + featuring device identification information. An + authenticationFailure trap signifies that the sending + protocol entity is the addressee of a protocol message that + is not properly authenticated. While implementations of the + SNMP must be capable of generating this trap, they must also + be capable of suppressing the emission of such traps via an + implementation- specific mechanism." + ::= { ipoGTEvents 19 } + +ipoGenEntityFailureSvcEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventStdSeverity, + ipoGTEventDateTime, + ipoGTEventDevID, + sysDescr, + ipoGTEventEntity, + ipoGTEventEntityName + } + STATUS current + DESCRIPTION + "A ipoGenEntityFailureSvcEvent notification is generated + whenever a physical entity on the IP Office fails in its + operation. It signifies that the SNMP entity, acting in an + agent role, has detected that the state of a physical entity + of the system has transitioned from the operational to the + failed state" + ::= { ipoGTEvents 20 } + +ipoGenEntityOperationalSvcEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventStdSeverity, + ipoGTEventDateTime, + ipoGTEventDevID, + sysDescr, + ipoGTEventEntity, + ipoGTEventEntityName + } + STATUS current + DESCRIPTION + "A ipoGenEntityOperationalSvcEvent notification is generated + whenever a physical entity on the IP Office becomes + operational again after having failed. It signifies that the + SNMP entity, acting in an agent role, has detected that the + state of a physical entity of the system has transitioned from + the failed to the operational state" + ::= { ipoGTEvents 21 } + +ipoGenEntityErrorSvcEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventStdSeverity, + ipoGTEventDateTime, + ipoGTEventDevID, + sysDescr, + ipoGTEventEntity, + ipoGTEventEntityName + } + STATUS current + DESCRIPTION + "A ipoGenEntityErrorSvcEvent notification is generated + whenever a physical entity on the IP Office experiences a + temporary error. It signifies that the SNMP entity, acting in + an agent role, has detected a transitory error on a physical + entity of the system." + ::= { ipoGTEvents 22 } + +ipoGenEntityChangeSvcEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventStdSeverity, + ipoGTEventDateTime, + ipoGTEventDevID, + sysDescr, + ipoGTEventEntity, + ipoGTEventEntityName + } + STATUS current + DESCRIPTION + "A ipoGenEntityChangeSvcEvent notification is generated + whenever a physical entity on the IP Office experiences a + change itself or with other entities associated with it. It + signifies that the SNMP entity, acting in an agent role, has + detected a non error/failure change for a physical entity on + the system." + ::= { ipoGTEvents 23 } + +ipoGenLKSCommsFailureSvcEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventStdSeverity, + ipoGTEventDateTime, + ipoGTEventDevID, + sysDescr + } + STATUS current + DESCRIPTION + "A ipoGenLKSCommsFailureSvcEvent notification is generated + whenever communication with a Licence Key Server fails. It + signifies that the SNMP entity, acting in an agent role, has + detected that the state of the communications between the + Licence Key Server has transitioned from the operational to + the failed state." + ::= { ipoGTEvents 24 } + +ipoGenLKSCommsOperationalSvcEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventStdSeverity, + ipoGTEventDateTime, + ipoGTEventDevID, + sysDescr + } + STATUS current + DESCRIPTION + "A ipoGenLKSCommsOperationalSvcEvent notification is generated + whenever communication with a Licence Key Server becomes + operational again after having failed. It signifies that the + SNMP entity, acting in an agent role, has detected that the + state of the communications between the Licence Key Server has + transitioned from the failed to the operational state." + ::= { ipoGTEvents 25 } + +ipoGenLKSCommsErrorSvcEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventStdSeverity, + ipoGTEventDateTime, + ipoGTEventDevID, + sysDescr + } + STATUS current + DESCRIPTION + "A ipoGenLKSCommsErrorSvcEvent notification is generated + whenever a IP Office experiences a temporary error with + License Key Server communication. It signifies that the SNMP + entity, acting in an agent role, has detected a transitory + error with the communication between the License Key Server + and Client on the system." + ::= { ipoGTEvents 26 } + +ipoGenLKSCommsChangeSvcEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventStdSeverity, + ipoGTEventDateTime, + ipoGTEventDevID, + sysDescr + } + STATUS current + DESCRIPTION + "A ipoGenLKSCommsChangeSvcEvent notification is generated + whenever a IP Office experiences a change a non error change + License Key Server communication operation. It signifies that + the SNMP entity, acting in an agent role, has detected a non + error/failure change with the License Key Server and Client + operation on the system." + ::= { ipoGTEvents 27 } + +ipoGenLoopbackSvcEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventStdSeverity, + ipoGTEventDateTime, + ipoGTEventDevID, + sysDescr, + ipoGTEventEntity, + ipoGTEventEntityName, + ipoGTEventLoopbackStatusBits + } + STATUS current + DESCRIPTION + "A ipoGenLoopbackSvcEvent notification is generated whenever a + IP Office T1 (DS1) interface operating as a CSU actions a + loopback status change." + ::= { ipoGTEvents 28 } + +ipoGenAppFailureSvcEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventStdSeverity, + ipoGTEventDateTime, + ipoGTEventDevID, + sysDescr, + ipoGTEventAppEntity + } + STATUS current + DESCRIPTION + "A ipoGenAppFailureSvcEvent notification is generated whenever + communication between a IP Office switch and a IP Office + application fails. It signifies that the SNMP entity, acting + in an agent role, has detected that the state of the + communications between the IP Office switch and a IP Office + application has transitioned from the operational to the + failed state. The IP Office application between which + communication has been lost is identified by the value of + ipoGTEventAppEntity." + ::= { ipoGTEvents 29 } + +ipoGenAppOperationalSvcEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventStdSeverity, + ipoGTEventDateTime, + ipoGTEventDevID, + sysDescr, + ipoGTEventAppEntity + } + STATUS current + DESCRIPTION + "A ipoGenAppOperationalSvcEvent notification is generated + whenever communication between a IP Office switch and a IP + Office application becomes operational again after having + failed. It signifies that the SNMP entity, acting in an agent + role, has detected that the state of the communications + between the IP Office switch and a IP Office application has + transitioned from the failed to the operational state. The IP + Office application between which communication has been lost + is identified by the value of ipoGTEventAppEntity." + ::= { ipoGTEvents 30 } + +ipoGenAppSvcEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventStdSeverity, + ipoGTEventDateTime, + ipoGTEventDevID, + sysDescr, + ipoGTEventAppEntity, + ipoGTEventAppEvent, + ipoGTEventAlarmDescription + } + STATUS current + DESCRIPTION + "A ipoGenAppSvcEvent notification is generated whenever a + application entity of the IP Office system experiences an + event. It signifies that the SNMP entity, acting as a proxy + for the application, has detected an event on the application + entity of the overall IP Office system. + + The event severity varies dependent upon the event condition." + ::= { ipoGTEvents 31 } + +ipoGenSogHostFailureSvcEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventStdSeverity, + ipoGTEventDateTime, + ipoGTEventDevID, + sysDescr, + ipoGTEventHostAddress + } + STATUS current + DESCRIPTION + "An ipoGenSogFailureSvcEvent notification is generated + whenever a previously valid Sub-tending host fails during + Small Office Gateway operation. + + The ipAddress field indicates the address of the failed host. + The event severity will always indicate major(4)." + ::= { ipoGTEvents 32 } + +ipoGenSogModeChangeSvcEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventStdSeverity, + ipoGTEventDateTime, + ipoGTEventDevID, + sysDescr, + ipoGTEventSOGMode + } + STATUS current + DESCRIPTION + "An ipoGenSogModeChangeSvcEvent notification is generated + whenever the Small Office Gateway operating mode changes. This + also includes entry to the initial mode. + + The ipoGTEventSOGMode field indicates the new operating mode. + The event severity will be major(4) for a ipoGTEventSOGMode + value of survivable(1), and minor(5) for a ipoGTEventSOGMode + value of subTending(2)." + ::= { ipoGTEvents 33 } + +ipoGenUPriLicChansReducedSvcEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventStdSeverity, + ipoGTEventDateTime, + ipoGTEventDevID, + sysDescr + } + STATUS current + DESCRIPTION + "A ipoGenUPriLicChansReducedSvcEvent notification is generated + whenever the number of Universal PRI Licensed channels has + been reduced. It signifies that the SNMP entity, acting in an + agent role, has detected a reduction in the licensed channels + on a Univeral PRI trunk." + ::= { ipoGTEvents 34 } + +ipoGenUPriLicCallRejectedSvcEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventStdSeverity, + ipoGTEventDateTime, + ipoGTEventDevID, + sysDescr + } + STATUS current + DESCRIPTION + "A ipoGenUPriLicCallRejectedSvcEvent notification is generated + whenever a call on a Universal PRI is rejected due to a + licensed channel not being available. It signifies that the + SNMP entity, acting in an agent role, has detected a licensed + channel not available in order to make a call on a Univeral + PRI trunk." + ::= { ipoGTEvents 35 } + +ipoGenQoSMonSvcEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventStdSeverity, + ipoGTEventDateTime, + ipoGTEventDevID, + sysDescr, + ipoGTEventQoSMonJitter, + ipoGTEventQoSMonRndTrip, + ipoGTEventQoSMonPktLoss, + ipoGTEventQoSMonCallId, + ipoGTEventQoSMonDevType, + ipoGTEventQoSMonDevId, + ipoGTEventQoSMonExtnNo + } + STATUS current + DESCRIPTION + "A ipoGenQoSMonSvcEvent notification is generated when one of + the monitored QoS parameters (e.g. round trip delay, jitter, + packet loss, etc) exceeds its pre-selected threshold during + the duration of the call. It signifies that the SNMP entity, + acting in an agent role, has detected a state that one of the + monitored QoS parameters for the call exceeded its + pre-selected threshold. + + The ipoGTEventQOSMonExtnNo value is only valid when the device + monitored is an extension rather than a line." + ::= { ipoGTEvents 36 } + +ipoGenSystemShutdownSvcEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventStdSeverity, + ipoGTEventDateTime, + ipoGTEventDevID, + sysDescr, + ipoGTEventSystemShutdownSource, + ipoGTEventSystemShutdownTimeout + } + STATUS current + DESCRIPTION + "An ipoGenSystemShutdownSvcEvent notification is generated when a + system shutdown is performed. It signifies that the + SNMP entity has detected a system shutdown." + ::= { ipoGTEvents 37 } + +ipoGenSystemRunningBackupEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventStdSeverity, + ipoGTEventDateTime, + ipoGTEventDevID, + sysDescr + } + STATUS current + DESCRIPTION + "An ipoGenSystemRunningBackup notification is generated when a + system is running partially or wholly from alternate/backup + software and/or configuration data. + In the case of an IP500 V2, it indicates that the current boot location + is not the System SD card slot, \system\primary." + ::= { ipoGTEvents 38 } + +ipoGenInvalidMemoryCardEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventStdSeverity, + ipoGTEventDateTime, + ipoGTEventDevID, + sysDescr, + ipoGTEventMemoryCardSlotId + } + STATUS current + DESCRIPTION + "An ipoGenInvalidMemoryCard notification is generated when a memory + card is detected present but cannot be used due to failure in the + filesystem or card type checks. + The checks are carried out on startup and whenever a memory card is + inserted." + ::= { ipoGTEvents 39 } + +ipoGenNoLicenceKeyDongleEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventStdSeverity, + ipoGTEventDateTime, + ipoGTEventDevID, + sysDescr, + ipoGTEventNoValidKeyReason + } + STATUS current + DESCRIPTION + "A ipoGenNoLicenceKeyDongle notification is generated if a system + either does not detect presence, or fails to validate a Licence Feature + Key Dongle. + In the case of an IP500 V2, it indicates that either the System SD card + is not present, or that one of the validation checks has failed. Note + that removing the System SD card will cause this event immediately, + however the licences will remain valid for approximately 2 hours. + + ipoGTEventStdSeverity will indicate the events state: + Severity is cleared(1): license dongle OK + Severity is warning(6): license dongle not OK, in grace period + Severity is critical(3): license dongle not OK, grace period expired + + The first check to fail is contained within ipoGTEventNoKeyReason." + ::= { ipoGTEvents 40 } + +ipoGenMemoryCardCapacityEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventStdSeverity, + ipoGTEventDateTime, + ipoGTEventDevID, + sysDescr, + ipoGTEventMemoryCardSlotId, + ipoGTEventAppEvent + } + STATUS current + DESCRIPTION + "A ipoGenMemoryCardCapacityEvent notification is generated if a memory + card passes one of the preset capacity thresholds. + In the case of an IP500 V2, the thresholds shall be + storageFull(1) - greater than 99% of nominal capacity + storageNearlyFull(2) - greater than 90% of nominal capacity + storageOkay(3) - less than 90% of nominal capacity." + ::= { ipoGTEvents 41 } + + + +ipoGenConfigFailureSvcEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventStdSeverity, + ipoGTEventDateTime, + ipoGTEventDevID, + sysDescr, + ipoGTEventReason, + ipoGTEventData, + ipoGTEventAlarmDescription, + ipoGTEventAlarmRemedialAction + } + STATUS current + DESCRIPTION + "A ipoGenConfigFailureSvcEvent notification is generated + whenever a configuration component fails in its operation. It signifies + that the SNMP entity,acting in an agent role,has detected that + the state of a configuration component has transitioned from the + operational to the failed state. + + This notification event is associated with a configuration + system status category alarm. Details about the alarm are + provided in the included object variables." + ::= { ipoGTEvents 42} + +ipoGenConfigOperationalSvcEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventStdSeverity, + ipoGTEventDateTime, + ipoGTEventDevID, + sysDescr, + ipoGTEventReason, + ipoGTEventData + } + STATUS current + DESCRIPTION + "A ipoGenConfigOperationalSvcEvent notification is generated + whenever a configuration component becomes operational again + after having failed.It signifies that the SNMP entity,acting in an + agent role,has detected that the state of a configuration component + of thesystem has transitioned from the failed to the operational state. + + This notification event is associated with a configuration + system status category alarm. Details about the alarm are + provided in the included object variables." + ::= { ipoGTEvents 43} + +ipoGenConfigErrorSvcEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventStdSeverity, + ipoGTEventDateTime, + ipoGTEventDevID, + sysDescr, + ipoGTEventReason, + ipoGTEventData, + ipoGTEventAlarmDescription, + ipoGTEventAlarmRemedialAction + } + STATUS current + DESCRIPTION + "A ipoGenConfigErrorSvcEvent notification is generated + whenever a configuration component experiences a + temporary error.It signifies that the SNMP entity, acting + in an agent role,has detected a transitory error on a + configuration component of the system. + + This notification event is associated with a configuration + system status category alarm. Details about the alarm are + provided in the included object variables." + ::= { ipoGTEvents 44} + +ipoGenConfigChangeSvcEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventStdSeverity, + ipoGTEventDateTime, + ipoGTEventDevID, + sysDescr, + ipoGTEventReason, + ipoGTEventData, + ipoGTEventAlarmDescription, + ipoGTEventAlarmRemedialAction + } + STATUS current + DESCRIPTION + "A ipoGenConfigChangeSvcEvent notification is generated + whenever a configuration component experiences a change + or a non error change event.It signifies that the SNMP entity, acting + in an agent role,has detected a non error/failure change on a + configuration component of the system. + + This notification event is associated with a configuration + system status category alarm. Details about the alarm are + provided in the included object variables." + ::= { ipoGTEvents 45} + + +ipoGenServiceFailureSvcEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventStdSeverity, + ipoGTEventDateTime, + ipoGTEventDevID, + sysDescr, + ipoGTEventReason, + ipoGTEventData, + ipoGTEventAlarmDescription, + ipoGTEventAlarmRemedialAction + } + STATUS current + DESCRIPTION + "A ipoGenServiceFailureSvcEvent notification is generated + whenever a Service component fails in its operation. It signifies + that the SNMP entity,acting in an agent role,has detected that + the state of a Service component has transitioned from the + operational to the failed state. + + This notification event is associated with a service + system status category alarm. Details about the alarm are + provided in the included object variables." + ::= { ipoGTEvents 46} + +ipoGenServiceOperationalSvcEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventStdSeverity, + ipoGTEventDateTime, + ipoGTEventDevID, + sysDescr, + ipoGTEventReason, + ipoGTEventData + } + STATUS current + DESCRIPTION + "A ipoGenServiceOperationalSvcEvent notificationis generated + whenever a service component becomes operational again + after having failed.It signifiest hat the SNMP entity, acting in an + agent role, has detected that the state of a service component + of the system has transitioned from the failed to the operational state. + + This notification event is associated with a service + system status category alarm. Details about the alarm are + provided in the included object variables." + ::= { ipoGTEvents 47} + +ipoGenServiceErrorSvcEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventStdSeverity, + ipoGTEventDateTime, + ipoGTEventDevID, + sysDescr, + ipoGTEventReason, + ipoGTEventData, + ipoGTEventAlarmDescription, + ipoGTEventAlarmRemedialAction + } + STATUS current + DESCRIPTION + "A ipoGenServiceErrorSvcEvent notification is generated + whenever a service component experiences a + temporary error. It signifiest hat the SNMP entity, acting + in an agent role,has detected a transitory error on a + service component of the system. + + This notification event is associated with a service + system status category alarm. Details about the alarm are + provided in the included object variables." + ::= { ipoGTEvents 48} + +ipoGenServiceChangeSvcEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventStdSeverity, + ipoGTEventDateTime, + ipoGTEventDevID, + sysDescr, + ipoGTEventReason, + ipoGTEventData, + ipoGTEventAlarmDescription, + ipoGTEventAlarmRemedialAction + } + STATUS current + DESCRIPTION + "A ipoGenServiceChangeSvcEvent notification is generated + whenever a service component experiences a change + or a non error change event. It signifies that the SNMP entity, acting + in an agent role,has detected a non error/failure change on a + service component of the system. + + This notification event is associated with a service + system status category alarm. Details about the alarm are + provided in the included object variables." + ::= { ipoGTEvents 49} + +ipoGenTrunkFailureSvcEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventStdSeverity, + ipoGTEventDateTime, + ipoGTEventDevID, + sysDescr, + ipoGTEventReason, + ipoGTEventData, + ipoGTEventAlarmDescription, + ipoGTEventAlarmRemedialAction + } + STATUS current + DESCRIPTION + "A ipoGenTrunkFailureSvcEvent notification is generated + whenever a trunk component fails in its operation. It signifies + that the SNMP entity,acting in an agent role,has detected that + the state of a Trunk component has transitioned from the + operational to the failed state. + + This notification event is associated with a trunk + system status category alarm. Details about the alarm are + provided in the included object variables." + ::= { ipoGTEvents 50} + +ipoGenTrunkOperationalSvcEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventStdSeverity, + ipoGTEventDateTime, + ipoGTEventDevID, + sysDescr, + ipoGTEventReason, + ipoGTEventData + } + STATUS current + DESCRIPTION + "A ipoGenTrunkOperationalSvcEvent notificationis generated + whenever a trunk component becomes operational again + after having failed. It signifies that the SNMP entity, acting in an + agent role,has detected that the state of a trunk component + of the system has transitioned from the failed to the operational state. + + This notification event is associated with a trunk + system status category alarm. Details about the alarm are + provided in the included object variables." + ::= { ipoGTEvents 51} + +ipoGenTrunkErrorSvcEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventStdSeverity, + ipoGTEventDateTime, + ipoGTEventDevID, + sysDescr, + ipoGTEventReason, + ipoGTEventData, + ipoGTEventAlarmDescription, + ipoGTEventAlarmRemedialAction + } + STATUS current + DESCRIPTION + "A ipoGenTrunkErrorSvcEvent notification is generated + whenever a trunk component experiences a + temporary error. It signifies that the SNMP entity, acting + in an agent role, has detected a transitory error on a + trunk component of the system. + + This notification event is associated with a trunk + system status category alarm. Details about the alarm are + provided in the included object variables." + ::= { ipoGTEvents 52} + +ipoGenTrunkChangeSvcEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventStdSeverity, + ipoGTEventDateTime, + ipoGTEventDevID, + sysDescr, + ipoGTEventReason, + ipoGTEventData, + ipoGTEventAlarmDescription, + ipoGTEventAlarmRemedialAction + } + STATUS current + DESCRIPTION + "A ipoGenTrunkChangeSvcEvent notification is generated + whenever a trunk component experiences a change + or a non error change event. It signifies that the SNMP entity, acting + in an agent role, has detected a non error/failure change on a + trunk component of the system. + + This notification event is associated with a trunk + system status category alarm. Details about the alarm are + provided in the included object variables." + ::= { ipoGTEvents 53} + +ipoGenLinkFailureSvcEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventStdSeverity, + ipoGTEventDateTime, + ipoGTEventDevID, + sysDescr, + ipoGTEventReason, + ipoGTEventData, + ipoGTEventAlarmDescription, + ipoGTEventAlarmRemedialAction + } + STATUS current + DESCRIPTION + "A ipoGenLinkFailureSvcEvent notification is generated + whenever a Link component fails in its operation. It signifies + that the SNMP entity,acting in an agent role,has detected that + the state of a Link component has transitioned from the + operational to the failed state. + + This notification event is associated with a link + system status category alarm. Details about the alarm are + provided in the included object variables." + ::= { ipoGTEvents 54} + +ipoGenLinkOperationalSvcEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventStdSeverity, + ipoGTEventDateTime, + ipoGTEventDevID, + sysDescr, + ipoGTEventReason, + ipoGTEventData + } + STATUS current + DESCRIPTION + "A ipoGenLinkOperationalSvcEvent notification is generated + whenever a link component becomes operational again + after having failed. It signifies that the SNMP entity, acting in an + agent role, hasdetected that the state of a link component + of the system has transitioned from the failed to the operational state. + + This notification event is associated with a link + system status category alarm. Details about the alarm are + provided in the included object variables." + ::= { ipoGTEvents 55} + +ipoGenLinkErrorSvcEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventStdSeverity, + ipoGTEventDateTime, + ipoGTEventDevID, + sysDescr, + ipoGTEventReason, + ipoGTEventData, + ipoGTEventAlarmDescription, + ipoGTEventAlarmRemedialAction + } + STATUS current + DESCRIPTION + "A ipoGenLinkErrorSvcEvent notification is generated + whenever a link component experiences a + temporary error. It signifies that the SNMP entity, acting + in an agent role,has detected a transitory error on a + link component of thesystem. + + This notification event is associated with a link + system status category alarm. Details about the alarm are + provided in the included object variables." + ::= { ipoGTEvents 56} + +ipoGenLinkChangeSvcEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventStdSeverity, + ipoGTEventDateTime, + ipoGTEventDevID, + sysDescr, + ipoGTEventReason, + ipoGTEventData, + ipoGTEventAlarmDescription, + ipoGTEventAlarmRemedialAction + } + STATUS current + DESCRIPTION + "A ipoGenLinkChangeSvcEvent notification is generated + whenever a link component experiences a change + or a non error change event. It signifies that the SNMP entity, acting + in an agent role,has detected a non error/failure change on a + link component of the system. + + This notification event is associated with a link + system status category alarm. Details about the alarm are + provided in the included object variables." + ::= { ipoGTEvents 57} + + ipoGenEmergencyCallSvcEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventStdSeverity, + ipoGTEventDateTime, + ipoGTEventDevID, + sysDescr, + ipoGTEventReason, + ipoGTEventData, + ipoGTEventAlarmDescription, + ipoGTEventAlarmRemedialAction + } + STATUS current + DESCRIPTION + "A ipoGenEmergencyCallSvcEvent notification is generated + whenever an emergency call is made, regardless whether successfully or not. + It signifies that the SNMP entity, acting + in an agent role, has detected an emergency call attempt on the system. + + This notification event is associated with a service + system status category alarm. Details about the alarm are + provided in the included object variables." + ::= { ipoGTEvents 58} + + +--******************************************************************** +-- IP Office wide compliance +--******************************************************************** + +ipoGenCompliances OBJECT IDENTIFIER ::= { ipoGenConformance 1 } +ipoGenGroups OBJECT IDENTIFIER ::= { ipoGenConformance 2 } + +-- +-- compliance statements +-- + +ipoGenCompliance MODULE-COMPLIANCE + STATUS deprecated + DESCRIPTION + "The compliance statement for IP Office agents which implement + up to and including version 1.00.05 of this MIB." + MODULE -- this module + MANDATORY-GROUPS { + ipoGenNotificationObjectsGroup, + ipoGenNotificationsGroup + } + ::= { ipoGenCompliances 1 } + +ipoGen2Compliance MODULE-COMPLIANCE + STATUS deprecated + DESCRIPTION + "The compliance statement for IP Office agents which implement + version 1.00.06 and later versions of this MIB." + MODULE -- this module + MANDATORY-GROUPS { + ipoGenNotificationObjectsGroup, + ipoGenNotificationsGroup + } + GROUP ipoGenSOGNotificationObjectsGroup + DESCRIPTION + "Implementation of this group is only mandatory for IP Office + SOG devices." + GROUP ipoGenSOGNotificationsGroup + DESCRIPTION + "Implementation of this group is only mandatory for IP Office + SOG devices." + ::= { ipoGenCompliances 2 } + +ipoGen3Compliance MODULE-COMPLIANCE + STATUS deprecated + DESCRIPTION + "The compliance statement for IP Office agents which implement + version 1.01.01 and later versions of this MIB." + MODULE -- this module + MANDATORY-GROUPS { + ipoGenv2NotificationObjectsGroup, + ipoGenEntGenNotificationsGroup, + ipoGenSvcNotificationsGroup + } + GROUP ipoGenSOGNotificationObjectsGroup + DESCRIPTION + "Implementation of this group is only mandatory for IP Office + SOG devices." + GROUP ipoGenSvcSOGNotificationsGroup + DESCRIPTION + "Implementation of this group is only mandatory for IP Office + SOG devices." + ::= { ipoGenCompliances 3 } + +ipoGen4Compliance MODULE-COMPLIANCE + STATUS deprecated + DESCRIPTION + "The compliance statement for IP Office agents which implement + version 2.00.01 and later versions of this MIB." + MODULE -- this module + MANDATORY-GROUPS { + ipoGenv2NotificationObjectsGroup, + ipoGenEntGenNotificationsGroup, + ipoGenSvcNotificationsGroup + } + GROUP ipoGenSOGNotificationObjectsGroup + DESCRIPTION + "Implementation of this group is only mandatory for IP Office + SOG devices." + GROUP ipoGenSvcSOGNotificationsGroup + DESCRIPTION + "Implementation of this group is only mandatory for IP Office + SOG devices." + GROUP ipoGenUPriLicSvcNotificationsGroup + DESCRIPTION + "Implementation of this group is only mandatory for IP Office + systems that support the Universal PRI trunk module such as + the IP500." + ::= { ipoGenCompliances 4 } + +ipoGen5Compliance MODULE-COMPLIANCE + STATUS deprecated + DESCRIPTION + "The compliance statement for IP Office agents which implement + version 2.00.04 and later versions of this MIB." + MODULE -- this module + MANDATORY-GROUPS { + ipoGenv2NotificationObjectsGroup, + ipoGenEntGenNotificationsGroup, + ipoGenSvcNotificationsGroup + } + GROUP ipoGenSOGNotificationObjectsGroup + DESCRIPTION + "Implementation of this group is only mandatory for IP Office + SOG devices." + GROUP ipoGenSvcSOGNotificationsGroup + DESCRIPTION + "Implementation of this group is only mandatory for IP Office + SOG devices." + GROUP ipoGenUPriLicSvcNotificationsGroup + DESCRIPTION + "Implementation of this group is only mandatory for IP Office + systems that support the Universal PRI trunk module such as + the IP500." + GROUP ipoGenQosMonNotificationObjectsGroup + DESCRIPTION + "Implementation of this group is only mandatory for IP Office + systems that support the QoS monitoring such as the IP500." + GROUP ipoGenSvcQoSMonNotificationsGroup + DESCRIPTION + "Implementation of this group is only mandatory for IP Office + systems that support the QoS monitoring such as the IP500." + ::= { ipoGenCompliances 5 } + +ipoGen6Compliance MODULE-COMPLIANCE + STATUS deprecated + DESCRIPTION + "The compliance statement for IP Office agents which implement + version 2.00.03 and later versions of this MIB." + MODULE -- this module + MANDATORY-GROUPS { + ipoGenv2NotificationObjectsGroup, + ipoGenEntGenNotificationsGroup, + ipoGenSvcNotificationsGroup + } + GROUP ipoGenSOGNotificationObjectsGroup + DESCRIPTION + "Implementation of this group is only mandatory for IP Office + SOG devices." + GROUP ipoGenSvcSOGNotificationsGroup + DESCRIPTION + "Implementation of this group is only mandatory for IP Office + SOG devices." + GROUP ipoGenUPriLicSvcNotificationsGroup + DESCRIPTION + "Implementation of this group is only mandatory for IP Office + systems that support the Universal PRI trunk module such as + the IP500." + GROUP ipoGenSvcQoSMonNotificationsGroup + DESCRIPTION + "Implementation of this group is only mandatory for IP Office + systems that support the QoS monitoring such as the IP500." + GROUP ipoGenSvcSystemShutdownNotificationsGroup + DESCRIPTION + "Implementation of this group is only mandatory for IP Office + systems that support the system shutdown such as the IP406v2, + IP412, IP500 and IP500v2." + GROUP ipoGenSvcSystemShutdownObjectGroup + DESCRIPTION + "Implementation of this group is only mandatory for IP Office + systems that support the system shutdown such as the IP406v2, + IP412, IP500 and IP500v2." + GROUP ipoGenSDcardNotificationsGroup + DESCRIPTION + "Implementation of this group is only mandatory for IP Office + systems that support an SD Card for primary operation" + GROUP ipoGenSDcardNotificationObjectsGroup + DESCRIPTION + "Implementation of this group is only mandatory for IP Office + systems that support an SD Card for primary operation" + ::= { ipoGenCompliances 6 } + +ipoGen7Compliance MODULE-COMPLIANCE + STATUS current + DESCRIPTION + "The compliance statement for IP Office agents which implement + version 2.00.07 and later versions of this MIB." + MODULE -- this module + MANDATORY-GROUPS { + ipoGenv2NotificationObjectsGroup, + ipoGenEntGenNotificationsGroup, + ipoGenSvcNotificationsGroup, + ipoGenSvcMiscNotificationsGroup, + ipoGenSvcMiscNotificationObjectsGroup + } + GROUP ipoGenSOGNotificationObjectsGroup + DESCRIPTION + "Implementation of this group is only mandatory for IP Office + SOG devices." + GROUP ipoGenSvcSOGNotificationsGroup + DESCRIPTION + "Implementation of this group is only mandatory for IP Office + SOG devices." + GROUP ipoGenUPriLicSvcNotificationsGroup + DESCRIPTION + "Implementation of this group is only mandatory for IP Office + systems that support the Universal PRI trunk module such as + the IP500." + GROUP ipoGenSvcQoSMonNotificationsGroup + DESCRIPTION + "Implementation of this group is only mandatory for IP Office + systems that support the QoS monitoring such as the IP500." + GROUP ipoGenSvcSystemShutdownNotificationsGroup + DESCRIPTION + "Implementation of this group is only mandatory for IP Office + systems that support the system shutdown such as the IP406v2, + IP412, IP500 and IP500v2." + GROUP ipoGenSvcSystemShutdownObjectGroup + DESCRIPTION + "Implementation of this group is only mandatory for IP Office + systems that support the system shutdown such as the IP406v2, + IP412, IP500 and IP500v2." + GROUP ipoGenSDcardNotificationsGroup + DESCRIPTION + "Implementation of this group is only mandatory for IP Office + systems that support an SD Card for primary operation" + GROUP ipoGenSDcardNotificationObjectsGroup + DESCRIPTION + "Implementation of this group is only mandatory for IP Office + systems that support an SD Card for primary operation" + ::= { ipoGenCompliances 7 } + +-- +-- MIB groupings +-- + +ipoGenNotificationObjectsGroup OBJECT-GROUP + OBJECTS { + ipoGTEventSeverity, + ipoGTEventDateTime, + ipoGTEventEntity, + ipoGTEventLoopbackStatus, + ipoGTEventAppEntity, + ipoGTEventAppEvent + } + STATUS deprecated + DESCRIPTION + "Objects that are contained in IP Office wide notifications. + + **NOTE: This group is deprecated and replaced by + ipoGenv2NotificationObjectsGroup." + ::= { ipoGenGroups 1 } + +ipoGenNotificationsGroup NOTIFICATION-GROUP + NOTIFICATIONS { + ipoGenEntityFailureEvent, + ipoGenEntityOperationalEvent, + ipoGenEntityErrorEvent, + ipoGenEntityChangeEvent, + ipoGenLKSCommsFailureEvent, + ipoGenLKSCommsOperationalEvent, + ipoGenLKSCommsErrorEvent, + ipoGenLKSCommsChangeEvent, + ipoGenLoopbackEvent, + ipoGenAppOperationalEvent, + ipoGenAppFailureEvent, + ipoGenAppEvent + } + STATUS deprecated + DESCRIPTION + "The notifications which indicate specific changes in the + state of the IP Office system. + + **NOTE: This group is deprecated and replaced by + ipoGenSvcNotificationsGroup." + ::= { ipoGenGroups 2 } + +ipoGenSOGNotificationObjectsGroup OBJECT-GROUP + OBJECTS { + ipoGTEventHostAddress, + ipoGTEventSOGMode + } + STATUS current + DESCRIPTION + "Objects that are contained in IP Office SOG notifications." + ::= { ipoGenGroups 3 } + +ipoGenSOGNotificationsGroup NOTIFICATION-GROUP + NOTIFICATIONS { + ipoGenSogHostFailureEvent, + ipoGenSogModeChangeEvent + } + STATUS deprecated + DESCRIPTION + "The notifications which indicate specific changes in the + state of the IP Office SOG system. + + **NOTE: This group is deprecated and replaced by + ipoGenSvcNotificationsGroup." + ::= { ipoGenGroups 4 } + +ipoGenv2NotificationObjectsGroup OBJECT-GROUP + OBJECTS { + ipoGTEventDateTime, + ipoGTEventEntity, + ipoGTEventAppEntity, + ipoGTEventAppEvent, + ipoGTEventStdSeverity, + ipoGTEventDevID, + ipoGTEventEntityName, + ipoGTEventLoopbackStatusBits + } + STATUS current + DESCRIPTION + "Objects that are contained in IP Office wide notifications." + ::= { ipoGenGroups 5 } + +ipoGenEntGenNotificationsGroup NOTIFICATION-GROUP + NOTIFICATIONS { + ipoGenColdStartSvcEvent, + ipoGenWarmStartSvcEvent, + ipoGenLinkDownSvcEvent, + ipoGenLinkUpSvcEvent, + ipoGenAuthFailureSvcEvent + } + STATUS current + DESCRIPTION + "IP Office Enterpise versions of the generic traps as defined + RFC1215 that provide more identification of the entity + concerned." + ::= { ipoGenGroups 6 } + +ipoGenSvcNotificationsGroup NOTIFICATION-GROUP + NOTIFICATIONS { + ipoGenEntityFailureSvcEvent, + ipoGenEntityOperationalSvcEvent, + ipoGenEntityErrorSvcEvent, + ipoGenEntityChangeSvcEvent, + ipoGenLKSCommsFailureSvcEvent, + ipoGenLKSCommsOperationalSvcEvent, + ipoGenLKSCommsErrorSvcEvent, + ipoGenLKSCommsChangeSvcEvent, + ipoGenLoopbackSvcEvent, + ipoGenAppOperationalSvcEvent, + ipoGenAppFailureSvcEvent, + ipoGenAppSvcEvent + } + STATUS current + DESCRIPTION + "The service notifications which indicate specific changes in + the state of the IP Office system." + ::= { ipoGenGroups 7 } + +ipoGenSvcSOGNotificationsGroup NOTIFICATION-GROUP + NOTIFICATIONS { + ipoGenSogHostFailureSvcEvent, + ipoGenSogModeChangeSvcEvent + } + STATUS current + DESCRIPTION + "The service notifications which indicate specific changes in + the state of the IP Office SOG system." + ::= { ipoGenGroups 8 } + +ipoGenUPriLicSvcNotificationsGroup NOTIFICATION-GROUP + NOTIFICATIONS { + ipoGenUPriLicChansReducedSvcEvent, + ipoGenUPriLicCallRejectedSvcEvent + } + STATUS current + DESCRIPTION + "The service notifications which indicate specific changes + related to the state licensing and Universal PRI trunks on the + IP Office system." + ::= { ipoGenGroups 9 } + +ipoGenQosMonNotificationObjectsGroup OBJECT-GROUP + OBJECTS { + ipoGTEventQoSMonJitter, + ipoGTEventQoSMonRndTrip, + ipoGTEventQoSMonPktLoss, + ipoGTEventQoSMonCallId, + ipoGTEventQoSMonDevType, + ipoGTEventQoSMonDevId, + ipoGTEventQoSMonExtnNo + } + STATUS current + DESCRIPTION + "Additional objects that are contained in IP Office QOS + Monitoring notifications." + ::= { ipoGenGroups 10 } + +ipoGenSvcQoSMonNotificationsGroup NOTIFICATION-GROUP + NOTIFICATIONS { + ipoGenQoSMonSvcEvent + } + STATUS current + DESCRIPTION + "The service notifications which indicate specific changes + related to the value of QoS parameters for a call on a physical + entity on the IP Office system." + ::= { ipoGenGroups 11 } + +ipoGenSvcSystemShutdownObjectGroup OBJECT-GROUP + OBJECTS { + ipoGTEventSystemShutdownSource, + ipoGTEventSystemShutdownTimeout + } + STATUS current + DESCRIPTION + "Additional objects that are contained in the system shutdown + notification" + ::= { ipoGenGroups 12 } + +ipoGenSvcSystemShutdownNotificationsGroup NOTIFICATION-GROUP + NOTIFICATIONS { + ipoGenSystemShutdownSvcEvent + } + STATUS current + DESCRIPTION + "The service notifications which indicate specific changes + related to the system shutdown performed on the IP Office system." + ::= { ipoGenGroups 13 } + + +ipoGenSDcardNotificationObjectsGroup OBJECT-GROUP + OBJECTS { + ipoGTEventMemoryCardSlotId, + ipoGTEventNoValidKeyReason + } + STATUS current + DESCRIPTION + "Additional objects that are contained in IP Office SD card + notifications." + ::= { ipoGenGroups 14 } + +ipoGenSDcardNotificationsGroup NOTIFICATION-GROUP + NOTIFICATIONS { + ipoGenAppOperationalSvcEvent, + ipoGenAppFailureSvcEvent, + ipoGenAppSvcEvent, + ipoGenSystemRunningBackupEvent, + ipoGenInvalidMemoryCardEvent, + ipoGenNoLicenceKeyDongleEvent, + ipoGenMemoryCardCapacityEvent + } + STATUS current + DESCRIPTION + "The notifications associated with IP Office SD card usage." + ::= { ipoGenGroups 15 } + +ipoGenSvcMiscNotificationObjectsGroup OBJECT-GROUP + OBJECTS { + ipoGTEventReason, + ipoGTEventData, + ipoGTEventAlarmDescription, + ipoGTEventAlarmRemedialAction + } + STATUS current + DESCRIPTION + "Additional objects that are contained in IP Office + notifications to provide additional information to + end user" + ::= { ipoGenGroups 16 } + +ipoGenSvcMiscNotificationsGroup NOTIFICATION-GROUP + NOTIFICATIONS { + ipoGenConfigFailureSvcEvent, + ipoGenConfigOperationalSvcEvent, + ipoGenConfigErrorSvcEvent, + ipoGenConfigChangeSvcEvent, + ipoGenServiceFailureSvcEvent, + ipoGenServiceOperationalSvcEvent, + ipoGenServiceErrorSvcEvent, + ipoGenServiceChangeSvcEvent, + ipoGenTrunkFailureSvcEvent, + ipoGenTrunkOperationalSvcEvent, + ipoGenTrunkErrorSvcEvent, + ipoGenTrunkChangeSvcEvent, + ipoGenLinkFailureSvcEvent, + ipoGenLinkOperationalSvcEvent, + ipoGenLinkErrorSvcEvent, + ipoGenLinkChangeSvcEvent, + ipoGenEmergencyCallSvcEvent + } + STATUS current + DESCRIPTION + "The notifications indicating change in status + related to four areas: Configuration, Sevice, + Trunk and Link" + ::= { ipoGenGroups 17 } + + + + +END diff --git a/mibs/avaya/IPO-PHONES-MIB.mib b/mibs/avaya/IPO-PHONES-MIB.mib new file mode 100644 index 000000000..e21706bb5 --- /dev/null +++ b/mibs/avaya/IPO-PHONES-MIB.mib @@ -0,0 +1,691 @@ +--======================================================== +-- +-- MIB : IPO-PHONES Avaya Inc. +-- +-- Version : 2.00.06 9 February 2011 +-- +--======================================================== +-- +-- Copyright (c) 2003 - 2011 Avaya Inc. +-- All Rights Reserved. +-- +--======================================================== +IPO-PHONES-MIB DEFINITIONS ::= BEGIN + +IMPORTS + MODULE-IDENTITY, OBJECT-TYPE, + NOTIFICATION-TYPE, Integer32, Unsigned32, IpAddress + FROM SNMPv2-SMI + TEXTUAL-CONVENTION, DisplayString, PhysAddress + FROM SNMPv2-TC + MODULE-COMPLIANCE, OBJECT-GROUP, + NOTIFICATION-GROUP + FROM SNMPv2-CONF + sysDescr + FROM SNMPv2-MIB + IndexInteger + FROM DIFFSERV-MIB + ipoGenMibs, ipoGTEventDateTime, ipoGTEventSeverity, + ipoGTEventStdSeverity, ipoGTEventDevID, ipoGTEventEntityName + FROM IPO-MIB + ; + +ipoPhonesMIB MODULE-IDENTITY + LAST-UPDATED "201102091521Z" -- 9 February 2011 + ORGANIZATION "Avaya Inc." + CONTACT-INFO + "Avaya Customer Services + Postal: Avaya, Inc. + 211 Mt Airy Rd. + Basking Ridge, NJ 07920 + USA + Tel: +1 908 953 6000 + + WWW: http://www.avaya.com" + DESCRIPTION + "Avaya IP Office Phones MIB + + The MIB module for representing the phones present on a Avaya + IP Office stack." + + + REVISION "201102091521Z" -- 9 February 2011 + DESCRIPTION + "Rev 2.00.06 + PhoneType: adding more original Nortel phone sets." + REVISION "200902181309Z" -- 18 February 2009 + DESCRIPTION + "Rev 2.00.05 + PhoneType enumerations for a number of SIP phones, + the 1400 phones and PhoneManager IP SoftPhone added." + REVISION "200806121506Z" -- 12 June 2008 + DESCRIPTION + "Rev 2.00.04 + PhoneType enumerations for the 1700 phones added." + REVISION "200804171630Z" -- 17 April 2008 + DESCRIPTION + "Rev 2.00.03 + Added descriptions for new PhoneType enumerations + and corrected versioning." + REVISION "200703281209Z" -- 28 March 2007 + DESCRIPTION + "Rev 2.00.02 + Added the port number, module number, ip address, + and physical address, to the ipoPhonesTable" + REVISION "200702241209Z" -- 24 February 2007 + DESCRIPTION + "Rev 2.00.01 + Added descriptions for new PhoneType enumerations + and corrected versioning." + REVISION "200606290000Z" -- 29 June 2006 + DESCRIPTION + "Rev 2.00.00 + Traps/notifications revised to provide more information about + the entity and device concerned." + REVISION "200601310000Z" -- 31 January 2006 + DESCRIPTION + "Rev 1.00.08 + Corrected enumeration for 5621 IP phones." + REVISION "200511220000Z" -- 22 November 2005 + DESCRIPTION + "Rev 1.00.07 + Revised for 5621 IP phones." + REVISION "200507211050Z" -- 21 July 2005 + DESCRIPTION + "Rev 1.00.06 + Revised for 4621 IP phones." + REVISION "200507211030Z" -- 21 July 2005 + DESCRIPTION + "Rev 1.00.05 + Revised for 5601 and 5602 Phones" + REVISION "200503040000Z" -- 4 March 2005 + DESCRIPTION + "Rev 1.00.04 + Revised for IP Soft Phones" + REVISION "200501060000Z" -- 6 January 2005 + DESCRIPTION + "Rev 1.00.03 + Revised for 5610/5620 IP phones." + REVISION "200412200000Z" -- 20 December 2004 + DESCRIPTION + "Rev 1.00.02 + Revised for additional phone support." + REVISION "200403030000Z" -- 3 March 2004 + DESCRIPTION + "Rev 1.00.01 + Revised for external publication." + REVISION "200310100000Z" -- 10 October 2003 + DESCRIPTION + "Rev 1.0.0 + The first published version of this MIB module." + ::= { ipoGenMibs 1 } + +ipoPhonesMibNotifications OBJECT IDENTIFIER ::= { ipoPhonesMIB 0 } +ipoPhonesMibObjects OBJECT IDENTIFIER ::= { ipoPhonesMIB 1 } +ipoPhonesConformance OBJECT IDENTIFIER ::= { ipoPhonesMIB 2 } + +--******************************************************************** +-- IPOPhone Textual Conventions +--******************************************************************** + +PhoneType ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "This data type is used as the syntax of the ipoPhoneType + object in the ipoPhonesTable." + SYNTAX INTEGER { + noPhone(1), -- no phone actually connected + genericPhone(2), -- for phone found that we can handle in + -- some way but exact type not recognised + -- may or may not be needed + potPhone(3), -- Generic Analogue/POT Phone + dtPhone(4), -- Generic DT Phone + a4406Dplus(5), -- Avaya 4406D+ DCP Phone + a4412Dplus(6), -- Avaya 4412D+ DCP Phone + a4424Dplus(7), -- Avaya 4424D+ DCP Phone + a4424LDplus(8), -- Avaya 4424LD+ DCP Phone + a9040TransTalk(9), -- Avaya 9040 TransTalk + a6408Dplus(10), -- Avaya 6408D+ DCP Phone + a6416Dplus(11), -- Avaya 6416D+ DCP Phone + a6424Dplus(12), -- Avaya 6424D+ DCP Phone + a4606ip(13), -- Avaya 4606 IP Phone + a4612ip(14), -- Avaya 4612 IP Phone + a4624ip(15), -- Avaya 4624 IP Phone + a4620ip(16), -- Avaya 4620 IP Phone + a4602ip(17), -- Avaya 4602 IP Phone + a2420(18), -- Avaya 2420 DCP Phone + a2010dt(19), -- Avaya 2010 DT Phone + a2020dt(20), -- Avaya 2020 DT Phone + a2030dt(21), -- Avaya 2030 DT Phone + a2050dt(22), -- Avaya 2050 DT Phone + act5(23), -- Avaya CT5 Phone + att3(24), -- Avaya TT3 Phone + att5(25), -- Avaya TT5 Phone + a5420(26), -- Avaya 5420 DCP Phone + a5410(27), -- Avaya 5410 DCP Phone + a4601ip(28), -- Avaya 4601 IP Phone + a4610ip(29), -- Avaya 4610 IP Phone + ablf(30), -- Avaya BLF Phone + a2402(31), -- Avaya 2402 DCP Phone + a2410(32), -- Avaya 2410 DCP Phone + a5610ip(33), -- Avaya 5610 IP Phone + a5620ip(34), -- Avaya 5620 IP Phone + softIPPhone(35), -- Avaya IP Soft Phone + a5601ip(36), -- Avaya 5601 IP Phone + a5602ip(37), -- Avaya 5602 IP Phone + a4621ip(38), -- Avaya 4621 IP Phone + a5621ip(39), -- Avaya 5621 IP Phone + a4625ip(40), -- Avaya 4625 IP Phone + a5402(41), -- Avaya 5402 DCP Phone + h323Phone(42), -- Generic H.323 Phone + sipPhone(43), -- Generic SIP Phone + t3Compact(44), -- Avaya T3 Compact Phone + t3Classic(45), -- Avaya T3 Classic Phone + t3Comfort(46), -- Avaya T3 Comfort Phone + t3Phone(47), -- Avaya T3 Generic Phone + t3compactIP(48), -- Avaya T3 Compact IP Phone + t3classicIP(49), -- Avaya T3 Classic IP Phone + t3comfortIP(50), -- Avaya T3 Comfort IP Phone + avayaSip(51), -- Avaya Generic SIP Phone + admmPhone(52), -- Avaya Generic ADMM (IP DECT) Phone + a9620ip(53), -- Avaya 9620 IP Phone + a9630ip(54), -- Avaya 9630 IP Phone + telecommuter(55), -- Telecommuting homeworker + mobiletwin(56), -- Mobile one-X phone + a9640ip(57), -- Avaya 9640 IP Phone + a9650ip(58), -- Avaya 9650 IP Phone + a9610ip(59), -- Avaya 9610 IP Phone + a1603ip(60), -- Avaya 1603 IP Phone + a1608ip(61), -- Avaya 1608 IP Phone + a1616ip(62), -- Avaya 1616 IP Phone + a1703ip(63), -- Avaya 1703 IP Phone + a1708ip(64), -- Avaya 1708 IP Phone + a1716ip(65), -- Avaya 1716 IP Phone + s60Sip(66), -- S60 SIP + sp320Sip(67), -- SP320 SIP + sp601Sip(68), -- SP601 SIP + a10ataSip(69), -- A10ATA SIP + pmataSip(70), -- Patton M-ATA SIP + ip22Sip(71), -- Innovaphone IP22 SIP + ip24Sip(72), -- Innovaphone IP24 SIP + gxp2000Sip(73), -- Grandstream GXP2000 SIP + gxp2020Sip(74), -- Grandstream GXP2000 SIP + eyebeamSip(75), -- CounterPath eyeBeam SIP + a1403(76), -- Avaya 1403 Phone + a1408(77), -- Avaya 1408 Phone + a1416(78), -- Avaya 1416 Phone + a1450(79), -- Avaya 1450 Phone + ip28Sip(80), + phoneManagerIP(81), -- Phone Manager IP + a1503(82), -- Avaya 1503 Phone + a1508(83), -- Avaya 1508 Phone + a1516(84), -- Avaya 1516 Phone + a1550(85), -- Avaya 1550 Phone + a1603Lip(86), -- Avaya 1603L IP Phone + a1608Lip(87), -- Avaya 1608L IP Phone + a1616Lip(88), -- Avaya 1616L IP Phone + softPhoneSip(89), -- SIP SoftPhone + etr34d(90), -- ETR-34D + etr18d(91), -- ETR-18D + etr6d(92), -- ETR-6D + etr34(93), -- ETR-34 + etr18(94), -- ETR-18 + etr6(95), -- ETR-6 + etrpots(96), -- ETR Pots + doorphone1(97), -- Door phone 1 + doorphone2(98), -- Door phone 2 + bstT7316e(99), -- BST 7316E + a9620Sip(100), -- Avaya 9620L/C SIP Phone + a9630Sip(101), -- Avaya 9630G SIP Phone + a9640Sip(102), -- Avaya 9640/G SIP Phone + a9650Sip(103), -- Avaya 9650/C SIP Phone + a96xxSip(104), -- Avaya 96xx SIP Phone + a1603Sip(105), -- Avaya 1603 Blaze SIP Phone + a9404(106), -- Avaya 9404 Phone + a9408(107), -- Avaya 9408 Phone + a9504(108), -- Avaya 9504 Phone + a9508(109), -- Avaya 9508 Phone + a9608ip(110), -- Avaya 9608 IP Phone + a9611ip(111), -- Avaya 9611 IP Phone + a9621ip(112), -- Avaya 9621 IP Phone + a9641ip(113), -- Avaya 9641 IP Phone + a3720Admm(114), -- Avaya 3720 ADMM (IP DECT) Phone + a3725Admm(115), -- Avaya 3725 ADMM (IP DECT) Phone + a1010Sip(116), -- Avaya 1010 SIP Video Phone + a1040Sip(117), -- Avaya 1040 SIP Video Phone + a1120ESip(118), -- Avaya 1120E SIP Phone + a1140ESip(119), -- Avaya 1140E SIP Phone + a1220Sip(120), -- Avaya 1220 SIP Phone + a1230Sip(121), -- Avaya 1230 SIP Phone + a1692Sip(122), -- Avaya 1692 SIP Phone + pvvxSip(123), -- Polycom VVX SIP + gxv3140Sip(124), -- Grandstream GXV3140 SIP + a3740Admm(125), -- Avaya 3740 ADMM (IP DECT) Phone + a3749Admm(126), -- Avaya 3749 ADMM (IP DECT) Phone + bstT7316(127), -- Original Nortel T7316 BST Phone + bstT7208(128), -- Original Nortel T7208 BST Phone + bstM7208(129), -- Original Nortel M7208 BST Phone + bstM7310(130), -- Original Nortel M7310 BST Phone + bstM7310blf(131), -- Original Nortel M7310 BST Phone with BLF Module + bstM7324(132), -- Original Nortel M7324 BST Phone with BLF Module + bstM7100(133), -- Original Nortel M7100 BST Phone with BLF Module + bstT7100(134), -- Original Nortel T7100 BST Phone with BLF Module + bstT7000(135), -- Original Nortel T7000 BST Phone with BLF Module + bstDectA(136), -- Original Nortel Dect handset model a + bstDectB(137), -- Original Nortel Dect handset model b + bstDectC(138), -- Original Nortel Dect handset model c + bstDoorphone(139), -- Original Nortel Doorphone + bstT7406(140), -- Original Nortel T7406 cordless phone + bstT7406E(141), -- Original Nortel T7406E cordless phone + bstM7310N(142), -- Original Nortel M7310N stimulus phone + bstAcu(143), -- Original Nortel Audio Conferencing Unit + bstM7100N(144), -- Original Nortel M7100N stimulus phone + bstM7324N (145), -- Original Nortel M7324N stimulus phone + bstM7208N(146), -- Original Nortel M7208N stimulus phone + aB179Sip(147), -- Avaya B179 Sip Phone (Konftel 300IP) + bstAta(148), -- Bst ATA + aA175Sip(149), -- Avaya A175 Sip Phone + aOneXSip(150), -- Avaya oneX Sip Phone + aFlareSip(151), -- Avaya Flare Sip Phone + aD100(152), -- Avaya D100 Sip Phone + aRadvisionXT1000(153), -- Avaya RadvisionXT1000 Sip Phone + aRadvisionXT1200(154), -- Avaya RadvisionXT1200 Sip Phone + aRadvisionXT4000(155), -- Avaya RadvisionXT4000 Sip Phone + aRadvisionXT4200(156), -- Avaya RadvisionXT4200 Sip Phone + aRadvisionXT5000(157), -- Avaya RadvisionXT5000 Sip Phone + aRadvisionXTPiccolo(158),-- Avaya RadvisionXTPiccolo Sip Phone + aRadvisionScopiaMCU(159),-- Avaya RadvisionScopiaMCU Sip Phone + aRadvisionScopiaVC240(160),-- Avaya RadvisionScopiaVC240 Sip Phone + aOneXSipMobile(161), -- Avaya OneX Sip Mobile Phone + aACCSServer(162), -- Avaya Contact Center ACCS + aCIEServer(163), -- Avaya Contact Center CIE + aE129SIP(164), -- Avaya E129 SIP phone (Grandstream OEM) + aE159SIP(165), -- Avaya E159 SIP phone (Invoxia OEM) + aE169SIP(166), -- Avaya E169 SIP phone (Invoxia OEM) + aOneXMsiSIP(167), -- Avaya Microsoft Lync SIP plugin + aRadvisionXT240(168), -- Avaya Radvision XT240 Scopia SIP phone + aWebRTCSIP(169), -- Avaya WebRTC Client + softPhoneSipMac(170) -- SIP Mac SoftPhone + } + +--******************************************************************** +-- IPOPhone Objects +--******************************************************************** + +-- MIB contains a single group + +ipoPhones OBJECT IDENTIFIER ::= { ipoPhonesMibObjects 1 } + +ipoPhonesNumber OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of phone interfaces (regardless of their current + state) present on this system." + ::= { ipoPhones 1 } + +-- the Phones table + +-- The Phones table contains information on the phones connected to a +-- IP Office stack entity. + +ipoPhonesTable OBJECT-TYPE + SYNTAX SEQUENCE OF IpoPhonesEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A list of phone entries. The number of entries is given by + the value of ipoPhonesNumber." + ::= { ipoPhones 2 } + +ipoPhonesEntry OBJECT-TYPE + SYNTAX IpoPhonesEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "An entry containing management information applicable to a + particular IP Office phone." + INDEX { ipoPhonesIndex } + ::= { ipoPhonesTable 1 } + +IpoPhonesEntry ::= + SEQUENCE { + ipoPhonesIndex IndexInteger, + ipoPhonesExtID Integer32, + ipoPhonesExtNumber Integer32, + ipoPhonesUserShort DisplayString, + ipoPhonesUserLong DisplayString, + ipoPhonesType PhoneType, + ipoPhonesPort Unsigned32, + ipoPhonesPortNumber Unsigned32, + ipoPhonesModuleNumber Unsigned32, + ipoPhonesIPAddress IpAddress, + ipoPhonesPhysAddress PhysAddress + } + +ipoPhonesIndex OBJECT-TYPE + SYNTAX IndexInteger + MAX-ACCESS read-only -- for SMIv1 compatability rather than not-accessible + STATUS current + DESCRIPTION + "A unique value, greater than zero, for each phone. It is + recommended that values are assigned contiguously starting + from 1. The value for each phone sub-layer must remain + constant at least from one re-initialization of the entity's + network management system to the next re- initialization." + ::= { ipoPhonesEntry 1 } + +ipoPhonesExtID OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The numerical logical extension entity identifier assigned to + the phone on the IP Office entity." + ::= { ipoPhonesEntry 2 } + +ipoPhonesExtNumber OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number that should be dialed to reach this phone on the + IP Office entity." + ::= { ipoPhonesEntry 3 } + +ipoPhonesUserShort OBJECT-TYPE + SYNTAX DisplayString (SIZE (0..15)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The short form of the name of the user of this phone which is + used in caller display. This is quite often the forename of + the user." + ::= { ipoPhonesEntry 4 } + +ipoPhonesUserLong OBJECT-TYPE + SYNTAX DisplayString (SIZE (0..31)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The long form of the name of the user of this phone. This is + normally the full name (forename and surname) of the user." + ::= { ipoPhonesEntry 5 } + +ipoPhonesType OBJECT-TYPE + SYNTAX PhoneType + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The type of phone that is connected to this IP Office logical + phone extension." + ::= { ipoPhonesEntry 6 } + +ipoPhonesPort OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "A reference, by entPhysicalIndex value, to the + EntPhysicalEntry representing the physical port entity that + this phone entry is associated with in an entity MIB + instantiation within the IP Office agent. If no MIB + definitions specific to the particular media are available, or + the entry is for a IP phone which may not be connected to a + physical port on the IP Office, the value should be set to the + value 0." + ::= { ipoPhonesEntry 7 } + +ipoPhonesPortNumber OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The port number on the module that the operator uses to + identify the port. + + The port numbers on the expansion modules will follow standard + numbering, beginning at 1 and incrementing until the last port. + The phone ports on the base units, however, are numbered + according to how they are collected into 'banks' on the unit. + + IP Office IP500 + The entire front of the product consists of 4 plug-in modules. + Each module has its own numbering from 1..12. + So from the left: 101..112, 201..212, etc. + + IP Office IP412 + There is no way to plug phones into the unit, so only + expansion modules should be present. + + IP Office IP406v2 + The leftmost bank of ports are Digital (DS/DT) and labeled + as 1-8 on the product, and so are labelled ports 101..108 + in the mib. + + The next bank of ports are Analogue and labeled as 1-2 + on the product and so are labelled ports 201..202 in the mib. + + The next bank of phones are LAN and labeled as 1-8 on the + product. Not phones, so not in this mib. + + IP Office Small Office Edition + The leftmost bank of 4 ports are Trunk ports, and so are not + available in this mib. + + The next bank of 8 ports are Digital (DS/DT), and so are + labelled ports 101..108 in the mib. + + The next bank of 4 ports are Analogue, and so are labelled + ports 201..204 in the mib. + + The next bank of ports are LAN, and so are not available in + this mib." + ::= { ipoPhonesEntry 8 } + +ipoPhonesModuleNumber OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number that the operator uses to + identify the module. + + The module numbers are assigned according to the expansion + port number that it's plugged into on the Control unit. + + Example: Module number '2' = Expansion unit plugged into + expansion port 2 on the Control unit. + + Module number '0' is reserved for the Control unit itself." + ::= { ipoPhonesEntry 9 } + +ipoPhonesIPAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The IP Address of the phone. In network-byte order. In the usual + IP Address format - xxx.xxx.xxx.xxx. + + The IP address will only be present if the phone is an IP phone. If + it is not, it will contain zeros (0.0.0.0)." + + ::= { ipoPhonesEntry 10 } + +ipoPhonesPhysAddress OBJECT-TYPE + SYNTAX PhysAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The Physical Address of the phone, such as the MAC Address. + + The physical address will only be present if the phone is an IP + phone. If it is not, it will contain zeros (00.00.00.00.00.00)." + + ::= { ipoPhonesEntry 11 } + +--******************************************************************** +-- IPOPhone Notifications +--******************************************************************** + +-- +-- Notifications +-- + +ipoPhonesChangeEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventSeverity, + ipoGTEventDateTime, + ipoPhonesExtID, + ipoPhonesType, + ipoPhonesPort + } + STATUS deprecated + DESCRIPTION + "This notification is generated whenever the type of phone + connected to a logical extension entity is detected as having + changed after completion of normal start up of the Agent + entity. + + Its purpose is to allow a management application to identify + the removal or switching of phone types on the IP Office + entity. + + **NOTE: This notification is deprecated and replaced by + ipoPhonesChangeSvcEvent." + ::= { ipoPhonesMibNotifications 1 } + +ipoPhonesChangeSvcEvent NOTIFICATION-TYPE + OBJECTS { + ipoGTEventStdSeverity, + ipoGTEventDateTime, + ipoGTEventDevID, + sysDescr, + ipoPhonesExtID, + ipoPhonesType, + ipoPhonesPort, + ipoGTEventEntityName + } + STATUS current + DESCRIPTION + "This notification is generated whenever the type of phone + connected to a logical extension entity is detected as having + changed after completion of normal start up of the Agent + entity. + + Its purpose is to allow a management application to identify + the removal or switching of phone types on the IP Office + entity. + + Newer implementations of this MIB should put in place this + event in favour of ipoPhonesChangeEvent." + ::= { ipoPhonesMibNotifications 2 } + +--******************************************************************** +-- IPO-PHONES compliance +--******************************************************************** + +ipoPhonesCompliances OBJECT IDENTIFIER ::= { ipoPhonesConformance 1 } +ipoPhonesGroups OBJECT IDENTIFIER ::= { ipoPhonesConformance 2 } + +-- +-- compliance statements +-- + +ipoPhonesCompliance MODULE-COMPLIANCE + STATUS deprecated + DESCRIPTION + "The compliance statement for the IP Office Phones MIB" + MODULE -- this module + MANDATORY-GROUPS { + ipoPhonesGroup, + ipoPhonesNotificationsGroup + } + ::= { ipoPhonesCompliances 1 } + +ipoPhonesv2Compliance MODULE-COMPLIANCE + STATUS deprecated + DESCRIPTION + "The compliance statement for the IP Office Phones MIB" + MODULE -- this module + MANDATORY-GROUPS { + ipoPhonesGroup, + ipoPhonesv2NotificationsGroup + } + ::= { ipoPhonesCompliances 2 } + +ipoPhonesv3Compliance MODULE-COMPLIANCE + STATUS current + DESCRIPTION + "The compliance statement for the IP Office Phones MIB" + MODULE -- this module + MANDATORY-GROUPS { + ipoPhonesGroup, + ipoPhones2Group, + ipoPhonesv2NotificationsGroup + } + ::= { ipoPhonesCompliances 3 } + +-- +-- MIB groupings +-- + +ipoPhonesGroup OBJECT-GROUP + OBJECTS { + ipoPhonesNumber, + ipoPhonesIndex, + ipoPhonesExtID, + ipoPhonesExtNumber, + ipoPhonesUserShort, + ipoPhonesUserLong, + ipoPhonesType, + ipoPhonesPort + } + STATUS current + DESCRIPTION + "The collection of objects which are used to represent IP + Office phones, for which a single agent provides management + information." + ::= { ipoPhonesGroups 1 } + +ipoPhonesNotificationsGroup NOTIFICATION-GROUP + NOTIFICATIONS { + ipoPhonesChangeEvent + } + STATUS deprecated + DESCRIPTION + "The notifications which indicate specific changes in the + state of IP Office phones." + ::= { ipoPhonesGroups 2 } + +ipoPhonesv2NotificationsGroup NOTIFICATION-GROUP + NOTIFICATIONS { + ipoPhonesChangeSvcEvent + } + STATUS current + DESCRIPTION + "The notifications which indicate specific changes in the + state of IP Office phones for newer implementations of this + MIB." + ::= { ipoPhonesGroups 3 } + +ipoPhones2Group OBJECT-GROUP + OBJECTS { + ipoPhonesPortNumber, + ipoPhonesModuleNumber, + ipoPhonesIPAddress, + ipoPhonesPhysAddress + } + STATUS current + DESCRIPTION + "Additional collection of objects which are used to represent + physical information about IP Office phones, for which a + single agent provides management information. These objects + provide more information on where phones are directly + connected to an IP Office and further details on IP Phones for + their identification." + ::= { ipoPhonesGroups 4 } + +END diff --git a/mibs/avaya/IPO-PROD-MIB.mib b/mibs/avaya/IPO-PROD-MIB.mib new file mode 100644 index 000000000..d4310f145 --- /dev/null +++ b/mibs/avaya/IPO-PROD-MIB.mib @@ -0,0 +1,1202 @@ +--======================================================== +-- +-- MIB : IPO-PROD Avaya Inc. +-- +-- Version : 1.0.26 06 Aug 2014 +-- +--======================================================== +-- +-- Copyright (c) 2003 - 2012 Avaya Inc. +-- All Rights Reserved. +-- +--======================================================== +IPO-PROD-MIB DEFINITIONS ::= BEGIN + +IMPORTS + MODULE-IDENTITY, OBJECT-IDENTITY + FROM SNMPv2-SMI + products + FROM AVAYAGEN-MIB; + +ipoProdMIB MODULE-IDENTITY + LAST-UPDATED "201408060000Z" -- 06 Aug 2014 + ORGANIZATION "Avaya Inc." + CONTACT-INFO + "Avaya Customer Services + Postal: Avaya, Inc. + 211 Mt Airy Rd. + Basking Ridge, NJ 07920 + USA + Tel: +1 908 953 6000 + + WWW: http://www.avaya.com" + + DESCRIPTION + "Avaya IP Office Products OID tree. + + This MIB module defines the product/sysObjectID values for + use with Avaya IP Office family of telephone switches." + + REVISION "201408060000Z" -- 06 Aug 2014 + DESCRIPTION + "Rev 1.00.26 + J Modules are now part of IP500v2." + + REVISION "201405300000Z" -- 30 May 2014 + DESCRIPTION + "Rev 1.00.25 + Additional IOD for IP500v2 Select and + IP Office Server Edition Expansion Select Mode." + REVISION "201402270000Z" -- 27 Feb 2014 + DESCRIPTION + "Rev 1.00.24 + Additional IOD for IP 500 UCM V2 module" + REVISION "201312100000Z" -- 10 Dec 2013 + DESCRIPTION + "Rev 1.00.23 + Update description for Unified Communications Module" + REVISION "201207230000Z" -- 23 July 2012 + DESCRIPTION + "Rev 1.00.22 + Additional IOD for IP 500 ATM4U V2 module." + REVISION "201203260000Z" -- 26 March 2012 + DESCRIPTION + "Rev 1.00.21 + Additional IOD for IP 500 VCM module." + REVISION "201111141128Z" -- 14 November 2011 + DESCRIPTION + "Rev 1.00.20 + Additional OID for IP Office Server Edition Expansion Mode." + REVISION "201108111658Z" -- 11 August 2011 + DESCRIPTION + "Rev 1.00.19 + Added new C110 UCP Module." + REVISION "201102101457Z" -- 10 February 2011 + DESCRIPTION + "Rev 1.00.18 + Added new OID for TCM 8 card." + REVISION "201102011457Z" -- 01 February 2011 + DESCRIPTION + "Rev 1.00.17 + Added new OID for DS30A Expansion module." + REVISION "201101111630Z" -- 11 January 2011 + DESCRIPTION + "Rev 1.00.16 + Avaya Inside OIDs removed. + Additional OIDs added for Norstar, Branch and Quick IP Office + modes." + REVISION "201006091515Z" -- 09 June 2010 + DESCRIPTION + "Rev 1.00.15 + Added new OID for Combo Card VCM sub module." + REVISION "201004281626Z" -- 28 April 2010 + DESCRIPTION + "Rev 1.00.14 + Added new OID for Avaya Inside." + REVISION "200908261713Z" -- 26 August 2009 + DESCRIPTION + "Rev 1.00.13 + Added new OIDs for IP500v2, combo card and ETR card." + REVISION "200908051048Z" -- 05 August 2009 + DESCRIPTION + "Rev 1.00.12 + Added a new OID for IP500 4 Port Expansion Module." + REVISION "200608161100Z" -- 16 August 2006 + DESCRIPTION + "Rev 1.00.11 + Corrected PRI module defined for IP500 and revised description + for Ethernet wAN link ports to make common across units." + REVISION "200608021752Z" -- 02 August 2006 + DESCRIPTION + "Rev 1.00.10 + Added a new OID for Universal PRI module and revised + descriptions for LAN ports used on IP412." + REVISION "200607132220Z" -- 13 July 2006 + DESCRIPTION + "Rev 1.00.09 + Added further OIDs for missing modules. + Replaced references to IP408 with IP500" + REVISION "200606101416Z" -- 10 June 2006 + DESCRIPTION + "Rev 1.00.08 + Added new OIDs for IP500 chassis and plug-in cards." + REVISION "200606071014Z" -- 07 June 2006 + DESCRIPTION + "Rev 1.00.07 + Added new OID for generic IP Office License dongle." + REVISION "200605241620Z" -- 24 May 2006 + DESCRIPTION + "Rev 1.00.06 + Added new OID for revised variant of ATM4U + trunk module." + REVISION "200605241615Z" -- 24 May 2006 + DESCRIPTION + "Rev 1.00.05 + Corrected descriptions of E1 R2 modules/ports." + REVISION "200604040000Z" -- 04 April 2006 + DESCRIPTION + "Rev 1.00.04 + Added new OIDs for revised (v2) variants of DS and POTS + expansion modules." + REVISION "200408060000Z" -- 06 August 2004 + DESCRIPTION + "Rev 1.00.03 + Added SOG family products." + REVISION "200403030000Z" -- 03 March 2004 + DESCRIPTION + "Rev 1.00.02 + Revised for external publication." + REVISION "200401060000Z" -- 06 January 2004 + DESCRIPTION + "Rev 1.0.1 + New OIDs added for revised 403 and 406 variants." + REVISION "200310100000Z" -- 10 October 2003 + DESCRIPTION + "Rev 1.0.0 + The first published version of this MIB module." + ::= { products 2 } + +-- Product Groups + +ipoProdControllers OBJECT IDENTIFIER ::= { ipoProdMIB 1 } +ipoProdExpModules OBJECT IDENTIFIER ::= { ipoProdMIB 2 } +ipoProdSlots OBJECT IDENTIFIER ::= { ipoProdMIB 3 } +ipoProdSlotModules OBJECT IDENTIFIER ::= { ipoProdMIB 4 } +ipoProdPorts OBJECT IDENTIFIER ::= { ipoProdMIB 5 } +ipoProdDongleModules OBJECT IDENTIFIER ::= { ipoProdMIB 6 } +ipoProdSubModules OBJECT IDENTIFIER ::= { ipoProdMIB 7 } +ipoProdUCModules OBJECT IDENTIFIER ::= { ipoProdMIB 8 } + +-- Controller Product families + +ipoProd401Family OBJECT IDENTIFIER ::= { ipoProdControllers 1 } +ipoProd403Family OBJECT IDENTIFIER ::= { ipoProdControllers 2 } +ipoProd406Family OBJECT IDENTIFIER ::= { ipoProdControllers 3 } +ipoProd412Family OBJECT IDENTIFIER ::= { ipoProdControllers 4 } +ipoProdSmallOfficeEditionFamily OBJECT IDENTIFIER ::= { ipoProdControllers 5 } +ipoProdR403Family OBJECT IDENTIFIER ::= { ipoProdControllers 6 } +ipoProdR406Family OBJECT IDENTIFIER ::= { ipoProdControllers 7 } +ipoProdSogFamily OBJECT IDENTIFIER ::= { ipoProdControllers 8 } +ipoProd500Family OBJECT IDENTIFIER ::= { ipoProdControllers 9 } +ipoProd500v2Family OBJECT IDENTIFIER ::= { ipoProdControllers 10 } + +-- IP Office 401 Family units + +ipoProd401DT2 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office IP401 + Compact Office DT 2 Telephone Switch" + ::= { ipoProd401Family 1 } + +ipoProd401DT4 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office IP401 + Compact Office DT 4 Telephone Switch" + ::= { ipoProd401Family 2 } + +ipoProd401DS2 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office IP401 + Compact Office DS 2 Telephone Switch" + ::= { ipoProd401Family 3 } + +ipoProd401DS4 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office IP401 + Compact Office DS 4 Telephone Switch" + ::= { ipoProd401Family 4 } + +-- IP Office 403 Family units + +ipoProd403DT OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office IP403 DT + Office Platform Telephone Switch Controller Unit" + ::= { ipoProd403Family 1 } + +ipoProd403DS OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office IP403 DS + Office Platform Telephone Switch Controller Unit" + ::= { ipoProd403Family 2 } + +-- IP Office 406 Family units + +ipoProd406 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office IP406 + Office Platform Telephone Switch Controller Unit" + ::= { ipoProd406Family 1 } + +-- IP Office 412 Family units + +ipoProd412 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office IP412 + Office Platform Telephone Switch Controller Unit" + ::= { ipoProd412Family 1 } + +-- IP Office - Small Office Edition Family units + +ipoProdSmallOfficeEditionPOTS4 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office - + Small Office Edition Telephone Switch POTS 4" + ::= { ipoProdSmallOfficeEditionFamily 1 } + +ipoProdSmallOfficeEditionPOTS8 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office - + Small Office Edition Telephone Switch POTS 8" + ::= { ipoProdSmallOfficeEditionFamily 2 } + +ipoProdSmallOfficeEditionDT8 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office - + Small Office Edition Telephone Switch DT 8" + ::= { ipoProdSmallOfficeEditionFamily 3 } + +ipoProdSmallOfficeEditionDS8 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office - + Small Office Edition Telephone Switch DS 8" + ::= { ipoProdSmallOfficeEditionFamily 4 } + +-- IP Office Revised 403 Family units + +ipoProdR403DT OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office Revised IP403 DT + Office Platform Telephone Switch Controller Unit" + ::= { ipoProdR403Family 1 } + +ipoProdR403DS OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office Revised IP403 DS + Office Platform Telephone Switch Controller Unit" + ::= { ipoProdR403Family 2 } + +-- IP Office Revised 406 Family units + +ipoProdR406 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office Revised IP406 + Office Platform Telephone Switch Controller Unit (2 POTs, no DS)" + ::= { ipoProdR406Family 1 } + +ipoProdR406DT OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office Revised IP406 + Office Platform Telephone Switch Controller Unit (2 POTs, 8 DT)" + ::= { ipoProdR406Family 2 } + +ipoProdR406DS OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office Revised IP406 + Office Platform Telephone Switch Controller Unit (2 POTs, 8 DS)" + ::= { ipoProdR406Family 3 } + +ipoProdR406Full OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office Revised IP406 + Office Platform Telephone Switch Controller Unit (Full version)" + ::= { ipoProdR406Family 4 } + +-- IP Office - SOG Family units + +ipoProdSogSOEPOTS4 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office - + Small Office Edition Telephone Switch POTS 4" + ::= { ipoProdSogFamily 1 } + +ipoProdSogSOEPOTS8 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office - + Small Office Edition Telephone Switch POTS 8" + ::= { ipoProdSogFamily 2 } + +ipoProdSogSOEDT8 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office - + Small Office Edition Telephone Switch DT 8" + ::= { ipoProdSogFamily 3 } + +ipoProdSogSOEDS8 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office - + Small Office Edition Telephone Switch DS 8" + ::= { ipoProdSogFamily 4 } + +-- IP Office 500 Family units + +ipoProd500Slot4 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office IP500 + Office Platform Telephone Switch 4 Slot Controller Unit" + ::= { ipoProd500Family 1 } + +ipoProd500Slot8 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office IP500 + Office Platform Telephone Switch 8 Slot Controller Unit" + ::= { ipoProd500Family 2 } + +-- IP Office 500v2 Family units + +ipoProd500v2IPOffice OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office IP500v2 + Office Platform Telephone Switch in IP Office Mode" + ::= { ipoProd500v2Family 1 } + +ipoProd500v2Partner OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office IP500v2 + Office Platform Telephone Switch in Partner Mode" + ::= { ipoProd500v2Family 2 } + +ipoProd500v2Norstar OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office IP500v2 + Office Platform Telephone Switch in Norstar Mode" + ::= { ipoProd500v2Family 3 } + +ipoProd500v2Branch OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office IP500v2 + Office Platform Telephone Switch in Branch Gateway Mode" + ::= { ipoProd500v2Family 4 } + +ipoProd500v2Quick OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office IP500v2 + Office Platform Telephone Switch in Quick Mode" + ::= { ipoProd500v2Family 5 } + +ipoProd500v2SEditionExpansion OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office IP500v2 + Office Platform Telephone Switch in Server Edition Expansion Mode" + ::= { ipoProd500v2Family 6 } + +ipoProd500v2IPOfficeSelect OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office IP500v2 + Office Platform Telephone Switch in IP Office Select Mode" + ::= { ipoProd500v2Family 7 } + +ipoProd500v2SEditionExpansionSelect OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office IP500v2 + Office Platform Telephone Switch in Server Edition Expansion Select Mode" + ::= { ipoProd500v2Family 8 } + +-- Expansion Modules + +ipoProdExpModDT OBJECT IDENTIFIER ::= { ipoProdExpModules 1 } +ipoProdExpModDS OBJECT IDENTIFIER ::= { ipoProdExpModules 2 } +ipoProdExpModPhone OBJECT IDENTIFIER ::= { ipoProdExpModules 3 } +ipoProdExpModS0 OBJECT IDENTIFIER ::= { ipoProdExpModules 4 } +ipoProdExpModAnalog OBJECT IDENTIFIER ::= { ipoProdExpModules 5 } +ipoProdExpModWAN OBJECT IDENTIFIER ::= { ipoProdExpModules 6 } +ipoProdExpModRDS OBJECT IDENTIFIER ::= { ipoProdExpModules 7 } +ipoProdExpModRPhone OBJECT IDENTIFIER ::= { ipoProdExpModules 8 } +ipoProdExpModDSA OBJECT IDENTIFIER ::= { ipoProdExpModules 9 } + +ipoProdExpModDT16 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office Digital + Terminal 16" + ::= { ipoProdExpModDT 1 } + +ipoProdExpModDT30 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office Digital + Terminal 30" + ::= { ipoProdExpModDT 2 } + +ipoProdExpModDS16 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office Digital + Station 16" + ::= { ipoProdExpModDS 1 } + +ipoProdExpModDS30 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office Digital + Station 30" + ::= { ipoProdExpModDS 2 } + +ipoProdExpModPhone8 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office Phone 8" + ::= { ipoProdExpModPhone 1 } + +ipoProdExpModPhone16 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office Phone 16" + ::= { ipoProdExpModPhone 2 } + +ipoProdExpModPhone30 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office Phone 30" + ::= { ipoProdExpModPhone 3 } + +ipoProdExpModS08 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office S0 8" + ::= { ipoProdExpModS0 1 } + +ipoProdExpModS016 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office S0 16" + ::= { ipoProdExpModS0 2 } + +ipoProdExpModATM8 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office Analog Trunk 16" + ::= { ipoProdExpModAnalog 1 } + +ipoProdExpModATM16 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office Analog Trunk 16" + ::= { ipoProdExpModAnalog 2 } + +ipoProdExpModWAN3 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office WAN 3" + ::= { ipoProdExpModWAN 1 } + +ipoProdExpModRDS16 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office Revised + (V2) Digital Station 16" + ::= { ipoProdExpModRDS 1 } + +ipoProdExpModRDS30 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office Revised + (V2) Digital Station 30" + ::= { ipoProdExpModRDS 2 } + +ipoProdExpModRPhone8 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office Revised + (V2) Phone 8" + ::= { ipoProdExpModRPhone 1 } + +ipoProdExpModRPhone16 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office Revised + (V2) Phone 16" + ::= { ipoProdExpModRPhone 2 } + +ipoProdExpModRPhone30 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office Revised + (V2) Phone 30" + ::= { ipoProdExpModRPhone 3 } + +ipoProdExpModDSA16RJ21 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office Revised + (Adaptive) Digital Station 16 RJ21" + ::= { ipoProdExpModDSA 1 } + +ipoProdExpModDSA30RJ21 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office Revised + (Adaptive) Digital Station 30 RJ21" + ::= { ipoProdExpModDSA 2 } + +ipoProdExpModDSA16RJ45 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office Revised + (Adaptive) Digital Station 16 RJ45" + ::= { ipoProdExpModDSA 3 } + +ipoProdExpModDSA30RJ45 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office Revised + (Adaptive) Digital Station 30 RJ45" + ::= { ipoProdExpModDSA 4 } + +-- Slots + +ipoProdSlotVCM OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office VCM Slot" + ::= { ipoProdSlots 1 } + +ipoProdSlotModems OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office Modem Slot" + ::= { ipoProdSlots 2 } + +ipoProdSlotVmailMemory OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office IP401 + Voicemail Memory Slot" + ::= { ipoProdSlots 3 } + +ipoProdSlotWAN OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office IP401 WAN + Slot" + ::= { ipoProdSlots 4 } + +ipoProdSlotPCCard OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office PC-Card + Slot" + ::= { ipoProdSlots 5 } + +ipoProdSlotTrunks OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office Trunk + Slot" + ::= { ipoProdSlots 6 } + +ipoProdSlotExpansion OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office Expansion + Slot" + ::= { ipoProdSlots 7 } + +ipoProdSlot500Generic OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office IP500 + Generic Expansion Slot" + ::= { ipoProdSlots 8 } + +ipoProdSlotMezzanine OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office IP500 + Mezzanine Slot" + ::= { ipoProdSlots 9 } + +ipoProdSlotCarrierVCM OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office IP500 + Carrier Module VCM Slot" + ::= { ipoProdSlots 10 } + +ipoProdSlotCarrierTrunk OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office IP500 + Carrier Module Trunk Slot" + ::= { ipoProdSlots 11 } + + +-- Slot Module Groups + +ipoProdIntegralModules OBJECT IDENTIFIER ::= { ipoProdSlotModules 1 } +ipoProdTrunkModules OBJECT IDENTIFIER ::= { ipoProdSlotModules 2 } +ipoProdPCCardModules OBJECT IDENTIFIER ::= { ipoProdSlotModules 3 } +ipoProdCarrierModules OBJECT IDENTIFIER ::= { ipoProdSlotModules 4 } +ipoProdPhonePortModules OBJECT IDENTIFIER ::= { ipoProdSlotModules 5 } +ipoProdVCMModules OBJECT IDENTIFIER ::= { ipoProdSlotModules 6 } +ipoProdExpansionModules OBJECT IDENTIFIER ::= { ipoProdSlotModules 7 } +ipoProdUCPModules OBJECT IDENTIFIER ::= { ipoProdSlotModules 8 } + +-- Integral Modules + +ipoProdIntModVCM OBJECT IDENTIFIER ::= { ipoProdIntegralModules 1 } +ipoProdIntModModem OBJECT IDENTIFIER ::= { ipoProdIntegralModules 2 } +ipoProdIntModWAN OBJECT IDENTIFIER ::= { ipoProdIntegralModules 3 } +ipoProdIntModMem OBJECT IDENTIFIER ::= { ipoProdIntegralModules 4 } + +ipoProdIntModVCM3 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office VCM 3 Module" + ::= { ipoProdIntModVCM 1 } + +ipoProdIntModVCM5 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office VCM 5 Module" + ::= { ipoProdIntModVCM 2 } + +ipoProdIntModVCM6 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office VCM 6 Module" + ::= { ipoProdIntModVCM 3 } + +ipoProdIntModVCM8 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office VCM 8 + Module." + ::= { ipoProdIntModVCM 4 } + +ipoProdIntModVCM10 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office VCM 10 Module" + ::= { ipoProdIntModVCM 5 } + +ipoProdIntModVCM12 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office VCM 12 Module" + ::= { ipoProdIntModVCM 6 } + +ipoProdIntModVCM16 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office VCM 16 + Module." + ::= { ipoProdIntModVCM 7 } + +ipoProdIntModVCM20 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office VCM 20 Module" + ::= { ipoProdIntModVCM 8 } + +ipoProdIntModVCM30 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office VCM 30 + Module." + ::= { ipoProdIntModVCM 9 } + +ipoProdIntModVCM24 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office VCM 24 + Module." + ::= { ipoProdIntModVCM 10 } + +ipoProdIntModVCM4 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office VCM 4 + Module." + ::= { ipoProdIntModVCM 11 } + +ipoProdIntModModemDual OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office Dual Modem Module" + ::= { ipoProdIntModModem 1 } + +ipoProdIntModModemMulti OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office Multi Modem Module" + ::= { ipoProdIntModModem 2 } + +ipoProdIntModWANModule OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office WAN Module" + ::= { ipoProdIntModWAN 1 } + +ipoProdIntModMemVmail OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office Voicemail + Memory Module" + ::= { ipoProdIntModMem 1 } + + +-- Trunk Modules + +ipoProdTrunkAnalogQuad OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office Quad Analog + Trunk Module" + ::= { ipoProdTrunkModules 1 } + +ipoProdTrunkBRIQuad OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office Quad BRI + Trunk Module" + ::= { ipoProdTrunkModules 2 } + +ipoProdTrunkE1PRISingle OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office Single PRI 30 + E1 Trunk Module" + ::= { ipoProdTrunkModules 3 } + +ipoProdTrunkE1PRIDual OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office Dual PRI 60 + E1 Trunk Module" + ::= { ipoProdTrunkModules 4 } + +ipoProdTrunkJ1PRISingle OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office IP500 + Single PRI 24J Trunk Module" + ::= { ipoProdTrunkModules 5 } + +ipoProdTrunkJ1PRIDual OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office IP500 + Dual PRI 48J Trunk Module" + ::= { ipoProdTrunkModules 6 } + +ipoProdTrunkT1PRISingle OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office Single PRI 24 + T1 Trunk Module" + ::= { ipoProdTrunkModules 7 } + +ipoProdTrunkT1PRIDual OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office Dual PRI 48 + T1 Trunk Module" + ::= { ipoProdTrunkModules 8 } + +ipoProdTrunkIndex OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office Index Module" + ::= { ipoProdTrunkModules 9 } + +ipoProdTrunkR2Single OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office Single E1 R2 30 + Trunk Module" + ::= { ipoProdTrunkModules 10 } + +ipoProdTrunkR2Dual OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office Dual E1 R2 60 + Trunk Module" + ::= { ipoProdTrunkModules 11 } + +ipoProdTrunkR2CoAxSingle OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office Single E1 R2 + CO-AX 30 Trunk Module" + ::= { ipoProdTrunkModules 12 } + +ipoProdTrunkR2CoAxDual OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office Single E1 R2 + CO-AX 30 Trunk Module" + ::= { ipoProdTrunkModules 13 } + +ipoProdTrunkRAnalogQuad OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office Revised Quad + Analog Trunk Module" + ::= { ipoProdTrunkModules 14 } + +ipoProdTrunk500AnalogQuad OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office IP500 + Quad Analog Trunk Module" + ::= { ipoProdTrunkModules 15 } + +ipoProdTrunk500BRIDual OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office IP500 + Dual BRI Trunk Module" + ::= { ipoProdTrunkModules 16 } + +ipoProdTrunk500BRIQuad OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office IP500 + Quad BRI Trunk Module" + ::= { ipoProdTrunkModules 17 } + +ipoProdTrunkUniversalPRIDS0Single OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office IP500 + Single Universal PRI (DS0) Trunk Module + 24 Channels in T1 configuration + 30 Channels in E1 configuration" + ::= { ipoProdTrunkModules 18 } + +ipoProdTrunkUniversalPRIDS0Dual OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office IP500 + Single Universal PRI (DS0) Trunk Module + 48 Channels across two ports in T1 configuration + 60 Channels across two ports in E1 configuration" + ::= { ipoProdTrunkModules 19 } + +ipoProdTrunk500AnalogQuadV2 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office IP500 + Quad Analog Trunk Module V2" + ::= { ipoProdTrunkModules 20 } + + +-- PC-Card Modules + +ipoProdPCCardMemVmail OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office PC-Card + Voicemail Memory Module" + ::= { ipoProdPCCardModules 1 } + +ipoProdPCCardWLAN OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office PC-Card + WLAN Module" + ::= { ipoProdPCCardModules 2 } + +-- Carrier Modules + +ipoProdCarrier OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office IP500 + Carrier Module for older IP Office plug-in modules" + ::= { ipoProdCarrierModules 1 } + +-- Phone Port Modules + +ipoProdPhonePortPOT8 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office IP500 + POT 8 Phone Port Module" + ::= { ipoProdPhonePortModules 1 } + +ipoProdPhonePortDS8 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office IP500 + Digital Station 8 Phone Port Module" + ::= { ipoProdPhonePortModules 2 } + +ipoProdPhonePortPOT2 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office IP500 + POT 2 Phone Port Module" + ::= { ipoProdPhonePortModules 3 } + +ipoProdPhonePortCombo OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office IP500v2 Combo + Phone Port and trunk Module which provides a 10 channel VCM, 6 + Digital Station Phone Ports, 2 POT Phone Ports and either a 4 + port ATM trunk module or a 4 port BRI module." + ::= { ipoProdPhonePortModules 4 } + +ipoProdPhonePortETR6 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office IP500v2 + ETR 6 Phone Port Module" + ::= { ipoProdPhonePortModules 5 } + +ipoProdPhonePortTCM8 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office IP500v2 + TCM 8 Phone Port Module" + ::= { ipoProdPhonePortModules 6 } + +-- VCM Modules + +ipoProdVCMMod32 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office DSP based + VCM 32 Module." + ::= { ipoProdVCMModules 1 } + +ipoProdVCMMod64 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office DSP based + VCM 64 Module." + ::= { ipoProdVCMModules 2 } + +ipoProdVCMMod32V2 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office DSP based + VCM 32 V2 Module." + ::= { ipoProdVCMModules 3 } + +ipoProdVCMMod64V2 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office DSP based + VCM 64 V2 Module." + ::= { ipoProdVCMModules 4 } + +-- Expansion Modules + +ipoProdExpMod4Port OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office 4 Port + Expansion Module." + ::= { ipoProdExpansionModules 1 } + +-- Ports + +ipoProdPortBRI OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office BRI Ports" + ::= { ipoProdPorts 1 } + +ipoProdPortE1PRI OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office E1 PRI Ports" + ::= { ipoProdPorts 2 } + +ipoProdPortJ1PRI OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office J1 PRI Ports" + ::= { ipoProdPorts 3 } + +ipoProdPortT1PRI OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office T1 PRI Ports" + ::= { ipoProdPorts 4 } + +ipoProdPortR2 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office E1 R2 Ports" + ::= { ipoProdPorts 5 } + +ipoProdPortR2CoAx OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office E1 R2 CO-AX + Ports" + ::= { ipoProdPorts 6 } + +ipoProdPortWAN OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office WAN Ports" + ::= { ipoProdPorts 7 } + +ipoProdPortAnalog OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office Analog Ports" + ::= { ipoProdPorts 8 } + +ipoProdPortPower OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office Power Port" + ::= { ipoProdPorts 9 } + +ipoProdPortDT OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office DT Phone Ports" + ::= { ipoProdPorts 10 } + +ipoProdPortDS OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office DS Phone Ports" + ::= { ipoProdPorts 11 } + +ipoProdPortPOT OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office POT Ports" + ::= { ipoProdPorts 12 } + +ipoProdPortS0 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office ISDN BRI S-Bus Ports" + ::= { ipoProdPorts 13 } + +ipoProdPortLAN OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office LAN + (10BASE-T/100BASE-TX) Ports" + ::= { ipoProdPorts 14 } + +ipoProdPortWLAN OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office LAN + WLAN (802.11) Ports" + ::= { ipoProdPorts 15 } + +ipoProdPortDTE OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office DTE Port" + ::= { ipoProdPorts 16 } + +ipoProdPortUSB OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office USB Port" + ::= { ipoProdPorts 17 } + +ipoProdPortAudio OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office Audio I/P Port" + ::= { ipoProdPorts 18 } + +ipoProdPortEtherWANLink OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office Fast + Ethernet (10BASE-T/100BASE-TX) WAN Link Port" + ::= { ipoProdPorts 19 } + +ipoProdPortExtOP OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office - Small + Office Edition Telephone Switch Ethernet Ext O/P Port" + ::= { ipoProdPorts 20 } + +ipoProdPortNet1 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office + Fast Ethernet (10BASE-T/100BASE-TX) Network 1 Port" + ::= { ipoProdPorts 21 } + +ipoProdPortNet2 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office + Fast Ethernet (10BASE-T/100BASE-TX) Network 2 Port" + ::= { ipoProdPorts 22 } + +ipoProdGenericDongle OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the Avaya IP Office License + Dongle - A single representation for three dongle types, + Parallel, Serial and USB. The Parallel and USB ones not truly + connected directly to the IP Office but the managing PC." + ::= { ipoProdDongleModules 1 } + +ipoProdSubModVCM10 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for the 10 channel VCM sub module + resident on the Avaya IP Office IP500v2 Combo Phone Port and + trunk Module." + ::= { ipoProdSubModules 1 } + + + -- Unified Communications Module + +ipoProdC110UCM OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office + Unified Communications Module. model C110" + ::= { ipoProdUCModules 1 } + +ipoProdC110UCMV2 OBJECT-IDENTITY + STATUS current + DESCRIPTION + "The authoritative reference for Avaya IP Office + Unified Communications Module V2. model C110" + ::= { ipoProdUCModules 2 } + +END From c3b7363e037f702db22d8a7f70bff253de619a9d Mon Sep 17 00:00:00 2001 From: Tom Ferguson Date: Thu, 17 Sep 2015 06:48:42 -0400 Subject: [PATCH 348/598] Added basic support for Avaya IP Office discovery --- includes/definitions.inc.php | 6 ++++++ includes/discovery/os/avaya-ipo.inc.php | 7 +++++++ includes/polling/os/avaya-ipo.inc.php | 8 ++++++++ 3 files changed, 21 insertions(+) create mode 100644 includes/discovery/os/avaya-ipo.inc.php create mode 100644 includes/polling/os/avaya-ipo.inc.php diff --git a/includes/definitions.inc.php b/includes/definitions.inc.php index 618f871b3..762034ea9 100644 --- a/includes/definitions.inc.php +++ b/includes/definitions.inc.php @@ -634,6 +634,12 @@ $config['os'][$os]['icon'] = 'avaya'; $config['os'][$os]['over'][0]['graph'] = 'device_bits'; $config['os'][$os]['over'][0]['text'] = 'Device Traffic'; +$os = 'avaya-ipo'; +$config['os'][$os]['text'] = 'IP Office Firmware'; +$config['os'][$os]['type'] = 'network'; +$config['os'][$os]['icon'] = 'avaya'; + + $os = 'arista_eos'; $config['os'][$os]['text'] = 'Arista EOS'; $config['os'][$os]['type'] = 'network'; diff --git a/includes/discovery/os/avaya-ipo.inc.php b/includes/discovery/os/avaya-ipo.inc.php new file mode 100644 index 000000000..ec4dcfbae --- /dev/null +++ b/includes/discovery/os/avaya-ipo.inc.php @@ -0,0 +1,7 @@ + Date: Thu, 17 Sep 2015 13:19:26 +0200 Subject: [PATCH 349/598] I agree to the conditions of the Contributor Agreement contained in doc/General/Contributing.md. --- AUTHORS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AUTHORS.md b/AUTHORS.md index 035e8383e..0c80ef0a8 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -52,6 +52,6 @@ Contributors to LibreNMS: - Arjit Chaudhary (arjit.c@gmail.com) (arjitc) - Sergiusz Paprzycki (spaprzycki) - Juho Vanhanen (juhovan) - +- Bart de Bruijn (bartdebruijn) [1]: http://observium.org/ "Observium web site" From 62328dab91106d77ab31a7b67b412f5f4dfd846f Mon Sep 17 00:00:00 2001 From: Rosiak Date: Thu, 17 Sep 2015 16:19:48 +0200 Subject: [PATCH 350/598] Add Device Notes Field MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a “Notes” field for devices to accommodate #1897 --- html/includes/forms/update-notes.inc.php | 32 ++++++++++++++ html/pages/device.inc.php | 6 +++ html/pages/device/notes.inc.php | 56 ++++++++++++++++++++++++ sql-schema/072.sql | 1 + 4 files changed, 95 insertions(+) create mode 100644 html/includes/forms/update-notes.inc.php create mode 100644 html/pages/device/notes.inc.php create mode 100644 sql-schema/072.sql diff --git a/html/includes/forms/update-notes.inc.php b/html/includes/forms/update-notes.inc.php new file mode 100644 index 000000000..4848add6b --- /dev/null +++ b/html/includes/forms/update-notes.inc.php @@ -0,0 +1,32 @@ + + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. Please see LICENSE.txt at the top level of + * the source code distribution for details. + */ + +$status = 'error'; +$message = 'unknown error'; + +$device_id = mres($_POST['device_id']); +$notes = mres($_POST['notes']); + +if (isset($notes) && (dbUpdate(array('notes' => $notes), 'devices', 'device_id = ?', array($device_id)))) { + $status = 'ok'; + $message = 'Updated'; +} +else { + $status = 'error'; + $message = 'ERROR: Could not update'; +} +die(json_encode(array( + 'status' => $status, + 'message' => $message, + 'notes' => $notes, + 'device_id' => $device_id +))); diff --git a/html/pages/device.inc.php b/html/pages/device.inc.php index dfb90a30e..6bb1bf4fa 100644 --- a/html/pages/device.inc.php +++ b/html/pages/device.inc.php @@ -357,6 +357,12 @@ if (device_permitted($vars['device']) || $check_device == $vars['device']) { '; + echo '
  • + + Notes + +
  • '; + echo '
  • https
  • ssh
  • diff --git a/html/pages/device/notes.inc.php b/html/pages/device/notes.inc.php new file mode 100644 index 000000000..94f3372cc --- /dev/null +++ b/html/pages/device/notes.inc.php @@ -0,0 +1,56 @@ + + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. Please see LICENSE.txt at the top level of + * the source code distribution for details. + */ + +$data = dbFetchRow("SELECT `notes` FROM `devices` WHERE device_id = ?", array( + $device['device_id'] +)); +?> + + +

    Device Notes

    +
    +
    +
    + +
    +
    +
    +
    + Submit + '; +?> +
    +
    + + diff --git a/sql-schema/072.sql b/sql-schema/072.sql new file mode 100644 index 000000000..6748b6eb4 --- /dev/null +++ b/sql-schema/072.sql @@ -0,0 +1 @@ +ALTER TABLE `devices` ADD COLUMN `notes` text; From ff7e1f5e845b7725c7a163764ff08ff4b9350383 Mon Sep 17 00:00:00 2001 From: Rosiak Date: Thu, 17 Sep 2015 20:51:10 +0200 Subject: [PATCH 351/598] Use htmlentities --- html/pages/device/notes.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/html/pages/device/notes.inc.php b/html/pages/device/notes.inc.php index 94f3372cc..39e034ff1 100644 --- a/html/pages/device/notes.inc.php +++ b/html/pages/device/notes.inc.php @@ -21,7 +21,7 @@ $data = dbFetchRow("SELECT `notes` FROM `devices` WHERE device_id = ?", array(
    +echo htmlentities($data['notes']); ?>
    From eb1f5c7fcccc4f754432cefe049e1db72b21ba49 Mon Sep 17 00:00:00 2001 From: Tom Ferguson Date: Fri, 18 Sep 2015 04:21:21 -0400 Subject: [PATCH 352/598] Changed sysDescr SNMP request to built in one. --- includes/polling/os/avaya-ipo.inc.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/includes/polling/os/avaya-ipo.inc.php b/includes/polling/os/avaya-ipo.inc.php index d97af2143..0ca43ea34 100644 --- a/includes/polling/os/avaya-ipo.inc.php +++ b/includes/polling/os/avaya-ipo.inc.php @@ -1,8 +1,10 @@ Date: Sat, 19 Sep 2015 00:45:36 +0200 Subject: [PATCH 353/598] Update AUTHORS.md I agree to the conditions of the Contributor Agreement contained in doc/General/Contributing.md. --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 0c80ef0a8..277bb2ad5 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -53,5 +53,6 @@ Contributors to LibreNMS: - Sergiusz Paprzycki (spaprzycki) - Juho Vanhanen (juhovan) - Bart de Bruijn (bartdebruijn) +- Christophe Martinet (chrisgfx) [1]: http://observium.org/ "Observium web site" From 3b3abe06c934905efa9c83a8cedda40ce2fd6f14 Mon Sep 17 00:00:00 2001 From: f0o Date: Sat, 19 Sep 2015 15:51:53 +0100 Subject: [PATCH 354/598] Honour IP Field for DNS Checks --- includes/services/dns/check.inc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/includes/services/dns/check.inc b/includes/services/dns/check.inc index 28fa47993..0b259d68d 100644 --- a/includes/services/dns/check.inc +++ b/includes/services/dns/check.inc @@ -1,9 +1,10 @@ Date: Sat, 19 Sep 2015 23:06:12 +0200 Subject: [PATCH 355/598] fix issue-1931 --- includes/discovery/os/vrp.inc.php | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/includes/discovery/os/vrp.inc.php b/includes/discovery/os/vrp.inc.php index 6c49cf862..b57689271 100644 --- a/includes/discovery/os/vrp.inc.php +++ b/includes/discovery/os/vrp.inc.php @@ -1,15 +1,7 @@ Date: Sun, 20 Sep 2015 10:13:56 +0100 Subject: [PATCH 356/598] Added ability to filter top interfaces by type --- html/ajax_search.php | 22 ++++ html/includes/common/top-interfaces.inc.php | 124 +++++++++++++------- 2 files changed, 102 insertions(+), 44 deletions(-) diff --git a/html/ajax_search.php b/html/ajax_search.php index e42655ee9..7d82a1ac9 100644 --- a/html/ajax_search.php +++ b/html/ajax_search.php @@ -294,6 +294,28 @@ if (isset($_REQUEST['search'])) { }//end foreach }//end if + $json = json_encode($device); + die($json); + } + else if ($_REQUEST['type'] == 'iftype') { + // Device search + if (is_admin() === true || is_read() === true) { + $results = dbFetchRows("SELECT `ports`.ifType FROM `ports` WHERE `ifType` LIKE '%".$search."%' GROUP BY ifType ORDER BY ifType LIMIT 8"); + } + else { + $results = dbFetchRows("SELECT `I`.ifType FROM `ports` AS `I`, `devices` AS `D`, `devices_perms` AS `P`, `ports_perms` AS `PP` WHERE ((`P`.`user_id` = ? AND `P`.`device_id` = `D`.`device_id`) OR (`PP`.`user_id` = ? AND `PP`.`port_id` = `I`.`port_id` AND `I`.`device_id` = `D`.`device_id`)) AND `D`.`device_id` = `I`.`device_id` AND (`ifType` LIKE '%".$search."%') GROUP BY ifType ORDER BY ifType LIMIT 8", array($_SESSION['user_id'], $_SESSION['user_id'])); + } + if (count($results)) { + $found = 1; + $devices = count($results); + + foreach ($results as $result) { + $device[] = array( + 'filter' => $result['ifType'], + ); + }//end foreach + }//end if + $json = json_encode($device); die($json); }//end if diff --git a/html/includes/common/top-interfaces.inc.php b/html/includes/common/top-interfaces.inc.php index 3299be1ae..07ebabf55 100644 --- a/html/includes/common/top-interfaces.inc.php +++ b/html/includes/common/top-interfaces.inc.php @@ -27,74 +27,110 @@ if( defined('show_settings') || empty($widget_settings) ) { $common_output[] = ' -
    +
    -
    - -
    -
    - -
    -
    -
    -
    -
    - -
    -
    - + +
    +
    -
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    +
    + + '; } else { $interval = $widget_settings['time_interval']; - (integer) $interval_seconds = ($interval * 60); + (integer) $lastpoll_seconds = ($interval * 60); (integer) $interface_count = $widget_settings['interface_count']; - $common_output[] = ' -

    Top '.$interface_count.' interfaces (last '.$interval.' minutes)

    - '; - $params = array('user' => $_SESSION['user_id'], 'interval' => array($interval_seconds), 'count' => array($interface_count)); + $params = array('user' => $_SESSION['user_id'], 'lastpoll' => array($lastpoll_seconds), 'count' => array($interface_count), 'filter' => ($widget_settings['interface_filter']?:(int)1)); if (is_admin() || is_read()) { $query = ' SELECT *, p.ifInOctets_rate + p.ifOutOctets_rate as total - FROM ports as p, devices as d - WHERE d.device_id = p.device_id - AND unix_timestamp() - p.poll_time < :interval - AND ( p.ifInOctets_rate > 0 - OR p.ifOutOctets_rate > 0 ) - ORDER BY total desc + FROM ports as p + INNER JOIN devices ON p.device_id = devices.device_id + AND unix_timestamp() - p.poll_time <= :lastpoll + AND ( p.ifType = :filter || 1 = :filter ) + AND ( p.ifInOctets_rate > 0 || p.ifOutOctets_rate > 0 ) + ORDER BY total DESC LIMIT :count '; } else { $query = ' - SELECT ports.*, devices.hostname, ports.ifInOctets_rate + ports.ifOutOctets_rate as total - FROM devices, ports - LEFT JOIN ports_perms ON ports.port_id = ports_perms.port_id - WHERE ports_perms.user_id = :user - AND unix_timestamp() - ports.poll_time < :interval - AND (ports.ifInOctets_rate > 0 OR ports.ifOutOctets_rate > 0) - GROUP BY ports.port_id - UNION ALL - SELECT ports.*, devices.hostname, ports.ifInOctets_rate + ports.ifOutOctets_rate as total - FROM ports, devices LEFT JOIN devices_perms ON devices.device_id = devices_perms.device_id - WHERE devices_perms.user_id = :user - AND ports.device_id = devices.device_id - AND unix_timestamp() - ports.poll_time < :interval - AND (ports.ifInOctets_rate > 0 OR ports.ifOutOctets_rate > 0) - GROUP BY ports.port_id - ORDER BY total DESC LIMIT :count + SELECT ports.*, devices.hostname, ports.ifInOctets_rate + ports.ifOutOctets_rate as total + FROM ports + INNER JOIN devices ON ports.device_id = devices.device_id + LEFT JOIN ports_perms ON ports.port_id = ports_perms.port_id + LEFT JOIN devices_perms ON devices.device_id = devices_perms.device_id + WHERE ( ports_perms.user_id = :user || devices_perms.user_id = :user ) + AND unix_timestamp() - ports.poll_time <= :lastpoll + AND ( ports.ifType = :filter || 1 = :filter ) + AND ( ports.ifInOctets_rate > 0 || ports.ifOutOctets_rate > 0 ) + GROUP BY ports.port_id + ORDER BY total DESC + LIMIT :count '; } - $common_output[] = ' +

    Top '.$interface_count.' interfaces polled within '.$interval.' minutes

    Enable Application'.$api['token_hash'].' '.$api['description'].'
    From 6aafa2c94945d379583e5ad4af4f4bec75afc8c7 Mon Sep 17 00:00:00 2001 From: laf Date: Sun, 20 Sep 2015 19:28:43 +0000 Subject: [PATCH 357/598] Updated changelog 20/09/2015 --- doc/General/Changelog.md | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/doc/General/Changelog.md b/doc/General/Changelog.md index 86c04213e..f4d083117 100644 --- a/doc/General/Changelog.md +++ b/doc/General/Changelog.md @@ -5,6 +5,13 @@ - Process followups if there are changes (PR1817) - Typo in alert_window setting (PR1841) - Issue alert-trigger as test object (PR1850) + - WebUI: + - Fix permissions for World-map widget (PR1866) + - Clean up Gloabl / World Map name mixup (PR1874) + - Services: + - Honour IP field for DNS checks (PR1933) + - Discovery / Poller: + - Fix Huawei VRP os detection (PR1931)t - General: - Remove 'sh' from cronjob (PR1818) - Remove MySQL Locks (PR1822,PR1826,PR1829,PR1836) @@ -15,19 +22,26 @@ - Honour Mouseout/Mouseleave on map widget (PR1814) - Make syslog/eventlog responsive (PR1816) - Reformat Proxmox UI (PR1825,PR1827) - - Misc Changes (PR1828,PR1830) + - Misc Changes (PR1828,PR1830,PR1875,PR1885,PR1886,PR1887,PR1891,PR1896,PR1901,PR1913) - Added support for Oxidized versioning (PR1842) - - Added graph widget + settings for widgets (PR1835) + - Added graph widget + settings for widgets (PR1835,PR1861) + - Added Support for multiple dashboards (PR1869) + - Added settings page for Worldmap widget (PR1872) + - Added uptime to availability widget (PR1881) + - Added top devices and ports widgets (PR1903) + - Added support for saving notes for devices (PR1927) - Added detection for: - FortiOS (PR1815) - Discovery / Poller: - Added Proxmox support (PR1789) - Documentation: - Add varnish docs (PR1809) + - Added CentOS 7 RRCached docs (1893) - General: - Make installer more responsive (PR1832) - Update fping millisec option to 200 default (PR1833) - Reduced cleanup of device_perf (PR1837) + - Added support for negative values in munin-plugins (PR1907) ### August 2015 From e6965765f58e9544d80dced002ef19ceb4db3766 Mon Sep 17 00:00:00 2001 From: Arjit Chaudhary Date: Mon, 21 Sep 2015 01:30:23 +0530 Subject: [PATCH 358/598] Various UI changes --- html/pages/device/alert-stats.inc.php | 2 +- html/pages/device/alerts.inc.php | 1 - html/pages/device/edit/alerts.inc.php | 2 +- html/pages/device/edit/apps.inc.php | 4 +- html/pages/device/health/diskio.inc.php | 34 +++++++-------- html/pages/device/health/mempool.inc.php | 26 ++++-------- html/pages/device/health/processor.inc.php | 27 ++++-------- html/pages/device/health/sensors.inc.php | 24 +++++------ html/pages/device/health/storage.inc.php | 27 ++++-------- html/pages/device/hrdevice.inc.php | 5 ++- html/pages/device/performance.inc.php | 26 ++++++------ html/pages/device/port/events.inc.php | 3 +- html/pages/device/port/graphs.inc.php | 48 ++++++++++++++++------ html/pages/device/ports.inc.php | 2 +- html/pages/device/ports/arp.inc.php | 2 +- 15 files changed, 108 insertions(+), 125 deletions(-) diff --git a/html/pages/device/alert-stats.inc.php b/html/pages/device/alert-stats.inc.php index 8c5eaaf79..ab9a0c57f 100644 --- a/html/pages/device/alert-stats.inc.php +++ b/html/pages/device/alert-stats.inc.php @@ -9,5 +9,5 @@ * option) any later version. Please see LICENSE.txt at the top level of * the source code distribution for details. */ -echo "
    "; + require_once 'includes/print-graph-alerts.inc.php'; diff --git a/html/pages/device/alerts.inc.php b/html/pages/device/alerts.inc.php index bdde37582..ef355a841 100644 --- a/html/pages/device/alerts.inc.php +++ b/html/pages/device/alerts.inc.php @@ -11,6 +11,5 @@ * option) any later version. Please see LICENSE.txt at the top level of * the source code distribution for details. */ - require_once 'includes/common/alerts.inc.php'; echo implode('',$common_output); diff --git a/html/pages/device/edit/alerts.inc.php b/html/pages/device/edit/alerts.inc.php index 1465b686b..7320c94fc 100644 --- a/html/pages/device/edit/alerts.inc.php +++ b/html/pages/device/edit/alerts.inc.php @@ -107,4 +107,4 @@ require_once 'includes/modal/new_alert_rule.inc.php';
    - + \ No newline at end of file diff --git a/html/pages/device/edit/apps.inc.php b/html/pages/device/edit/apps.inc.php index 9ed743de7..c885666df 100644 --- a/html/pages/device/edit/apps.inc.php +++ b/html/pages/device/edit/apps.inc.php @@ -62,7 +62,7 @@ echo "
    -
    +
    @@ -99,4 +99,4 @@ echo '
    '; echo ''; echo '
    '; -echo ''; +echo ''; \ No newline at end of file diff --git a/html/pages/device/health/diskio.inc.php b/html/pages/device/health/diskio.inc.php index dd425d273..b612d2d4a 100644 --- a/html/pages/device/health/diskio.inc.php +++ b/html/pages/device/health/diskio.inc.php @@ -1,13 +1,5 @@ '; - -// echo(" -// -// -// -// -// "); $row = 1; foreach (dbFetchRows('SELECT * FROM `ucd_diskio` WHERE device_id = ? ORDER BY diskio_descr', array($device['device_id'])) as $drive) { @@ -27,9 +19,7 @@ foreach (dbFetchRows('SELECT * FROM `ucd_diskio` WHERE device_id = ? ORDER BY di $graph_array_zoom['from'] = $config['time']['twoday']; $graph_array_zoom['to'] = $config['time']['now']; - echo "'; + $overlib_link = overlib_link($fs_url, $drive['diskio_descr'], generate_graph_tag($graph_array_zoom), null); $types = array( 'diskio_bits', @@ -37,18 +27,24 @@ foreach (dbFetchRows('SELECT * FROM `ucd_diskio` WHERE device_id = ? ORDER BY di ); foreach ($types as $graph_type) { - echo ''; + if($graph_array['type']=="diskio_ops") { + $graph_type_title="Ops/sec"; + } + if($graph_array['type']=="diskio_bits") { + $graph_type_title="bps"; + } + echo "
    +
    +

    $overlib_link - $graph_type_title

    +
    "; + echo "
    "; + include 'includes/print-graphrow.inc.php'; + echo '
    '; } $row++; -} - -echo '
    Enable Application
    DriveUsageFree
    "; - echo overlib_link($fs_url, $drive['diskio_descr'], generate_graph_tag($graph_array_zoom), null); - echo '
    '; $graph_array = array(); $graph_array['id'] = $drive['diskio_id']; $graph_array['type'] = $graph_type; - - include 'includes/print-graphrow.inc.php'; - - echo '
    '; +} \ No newline at end of file diff --git a/html/pages/device/health/mempool.inc.php b/html/pages/device/health/mempool.inc.php index e2a6eaa51..2cfbcd207 100644 --- a/html/pages/device/health/mempool.inc.php +++ b/html/pages/device/health/mempool.inc.php @@ -2,9 +2,6 @@ $graph_type = 'mempool_usage'; -echo "
    "; -echo ''; - $i = '1'; // FIXME css alternating colours @@ -46,25 +43,16 @@ foreach (dbFetchRows('SELECT * FROM `mempools` WHERE device_id = ?', array($devi $right_background = $background['right']; $left_background = $background['left']; - echo " - - - - '; - - echo "'; + echo ""; $i++; -}//end foreach - -echo '
    ".$text_descr." - ".print_percentage_bar(400, 20, $perc, "$used / $total", 'ffffff', $left_background, $free, 'ffffff', $right_background).' - '.$perc.'%
    "; - $graph_array['id'] = $mempool['mempool_id']; $graph_array['type'] = $graph_type; + echo "
    +
    +

    $text_descr
    $used/$total - $perc% used

    +
    "; + echo "
    "; include 'includes/print-graphrow.inc.php'; - - echo '
    '; -echo '
    '; +}//end foreach \ No newline at end of file diff --git a/html/pages/device/health/processor.inc.php b/html/pages/device/health/processor.inc.php index 725e37c21..dd60448a3 100644 --- a/html/pages/device/health/processor.inc.php +++ b/html/pages/device/health/processor.inc.php @@ -2,9 +2,6 @@ $graph_type = 'processor_usage'; -echo "
    "; -echo ''; - $i = '1'; foreach (dbFetchRows('SELECT * FROM `processors` WHERE device_id = ?', array($device['device_id'])) as $proc) { $proc_url = 'graphs/id='.$proc['processor_id'].'/type=processor_usage/'; @@ -18,26 +15,16 @@ foreach (dbFetchRows('SELECT * FROM `processors` WHERE device_id = ?', array($de $proc_popup = "onmouseover=\"return overlib('
    ".$device['hostname'].' - '.$text_descr; $proc_popup .= "
    "; $proc_popup .= "', RIGHT".$config['overlib_defaults'].');" onmouseout="return nd();"'; - $percent = round($proc['processor_usage']); - $background = get_percentage_colours($percent); - - echo (" - - - - '); - - echo "
    ".$text_descr." - ".print_percentage_bar(400, 20, $percent, $percent.'%', 'ffffff', $background['left'], (100 - $percent).'%', 'ffffff', $background['right']).' -
    "; - $graph_array['id'] = $proc['processor_id']; $graph_array['type'] = $graph_type; + echo "
    +
    +

    $text_descr
    $percent% used

    +
    "; + echo "
    "; include 'includes/print-graphrow.inc.php'; -}//end foreach - -echo '
    '; -echo '
    '; + echo "
    "; +}//end foreach \ No newline at end of file diff --git a/html/pages/device/health/sensors.inc.php b/html/pages/device/health/sensors.inc.php index 7e38a58f9..b8523a493 100644 --- a/html/pages/device/health/sensors.inc.php +++ b/html/pages/device/health/sensors.inc.php @@ -1,6 +1,6 @@ '; +//echo ''; $row = 1; @@ -11,24 +11,24 @@ foreach (dbFetchRows('SELECT * FROM `sensors` WHERE `sensor_class` = ? AND `devi else { $row_colour = $list_colour_b; } - - echo " - - - - - - \n"; - echo "'; + echo ''; $row++; } -echo '
    ".$sensor['sensor_descr'].''.$sensor['sensor_type'].''.format_si($sensor['sensor_current']).$unit.''.format_si($sensor['sensor_limit']).$unit.''.format_si($sensor['sensor_limit_low']).$unit."
    "; + $sensor_descr = $sensor['sensor_descr']; + $sensor_current = format_si($sensor['sensor_current']).$unit; + $sensor_limit = format_si($sensor['sensor_limit']).$unit; + $sensor_limit_low = format_si($sensor['sensor_limit_low']).$unit; + echo "
    +
    +

    $sensor_descr
    $sensor_current | $sensor_limit_low <> $sensor_limit

    +
    "; + echo "
    "; $graph_array['id'] = $sensor['sensor_id']; $graph_array['type'] = $graph_type; include 'includes/print-graphrow.inc.php'; - echo '
    '; +//echo ''; diff --git a/html/pages/device/health/storage.inc.php b/html/pages/device/health/storage.inc.php index d5f330c07..e65217457 100644 --- a/html/pages/device/health/storage.inc.php +++ b/html/pages/device/health/storage.inc.php @@ -2,15 +2,6 @@ $graph_type = 'storage_usage'; -echo ''; - -echo ' - - - - - '; - $row = 1; foreach (dbFetchRows('SELECT * FROM `storage` WHERE device_id = ? ORDER BY storage_descr', array($device['device_id'])) as $drive) { @@ -28,6 +19,7 @@ foreach (dbFetchRows('SELECT * FROM `storage` WHERE device_id = ? ORDER BY stora $used = formatStorage($used); $total = formatStorage($total); $free = formatStorage($free); + $storage_descr = $drive['storage_descr']; $fs_url = 'graphs/id='.$drive['storage_id'].'/type=storage_usage/'; @@ -35,22 +27,17 @@ foreach (dbFetchRows('SELECT * FROM `storage` WHERE device_id = ? ORDER BY stora $fs_popup .= ""; $fs_popup .= "', RIGHT, FGCOLOR, '#e5e5e5');\" onmouseout=\"return nd();\""; - $background = get_percentage_colours($percent); - - echo "'; $graph_array['id'] = $drive['storage_id']; $graph_array['type'] = $graph_type; - echo "'; + echo ""; $row++; }//end foreach - -echo '
    DriveUsageFree
    ".$drive['storage_descr']." - ".print_percentage_bar(400, 20, $perc, "$used / $total", 'ffffff', $background['left'], $perc.'%', 'ffffff', $background['right']).' - '.$free.'
    "; - + echo "
    +
    +

    $storage_descr
    $used/$total - $perc% used

    +
    "; + echo "
    "; include 'includes/print-graphrow.inc.php'; - - echo '
    '; diff --git a/html/pages/device/hrdevice.inc.php b/html/pages/device/hrdevice.inc.php index 4b92a907c..e792f29ce 100644 --- a/html/pages/device/hrdevice.inc.php +++ b/html/pages/device/hrdevice.inc.php @@ -1,6 +1,7 @@ '; +echo '

    Inventory

    '; +echo '
    '; +echo ''; // FIXME missing heading foreach (dbFetchRows('SELECT * FROM `hrDevice` WHERE `device_id` = ? ORDER BY `hrDeviceIndex`', array($device['device_id'])) as $hrdevice) { diff --git a/html/pages/device/performance.inc.php b/html/pages/device/performance.inc.php index dd5d15194..b03c7b696 100644 --- a/html/pages/device/performance.inc.php +++ b/html/pages/device/performance.inc.php @@ -35,19 +35,19 @@ if (empty($vars['dtpickerto'])) { ?>
    -
    -
    -
    - - -
    -
    - - -
    - - -
    +
    +
    +
    + + +
    +
    + + +
    + + +

    +

    Global Settings


    diff --git a/html/pages/settings/alerting.inc.php b/html/pages/settings/alerting.inc.php index f6c1bda0a..d76303183 100644 --- a/html/pages/settings/alerting.inc.php +++ b/html/pages/settings/alerting.inc.php @@ -195,197 +195,95 @@ else { $callback = urlencode($callback); +$general_conf = array( + array('name' => 'alert.admins', + 'descr' => 'Issue alerts to admins', + 'type' => 'checkbox', + ), + array('name' => 'alert.globals', + 'descr' => 'Issue alerts to read only users', + 'type' => 'checkbox', + ), + array('name' => 'alert.syscontact', + 'descr' => 'Issue alerts to sysContact', + 'type' => 'checkbox', + ), + array('name' => 'alert.default_only', + 'descr' => 'Send alerts to default contact only', + 'type' => 'checkbox', + ), + array('name' => 'alert.default_mail', + 'descr' => 'Default contact', + 'type' => 'text', + ), + array('name' => 'alert.tolerance_window', + 'descr' => 'Tolerance window for cron', + 'type' => 'text', + ), + array('name' => 'alert.fixed-contacts', + 'descr' => 'Updates to contact email addresses not honored', + 'type' => 'checkbox', + ), +); + +$mail_conf = array( + array('name' => 'alert.transports.mail', + 'descr' => 'Enable email alerting', + 'type' => 'checkbox', + ), + array('name' => 'email_backend', + 'descr' => 'How to deliver mail', + 'options' => $dyn_config['email_backend'], + 'type' => 'select', + ), + array('name' => 'email_user', + 'descr' => 'From name', + 'type' => 'text', + ), + array('name' => 'email_sendmail_path', + 'descr' => 'Sendmail path', + 'type' => 'text', + ), + array('name' => 'email_smtp_host', + 'descr' => 'SMTP Host', + 'type' => 'text', + ), + array('name' => 'email_smtp_port', + 'descr' => 'SMTP Port', + 'type' => 'text', + ), + array('name' => 'email_smtp_timeout', + 'descr' => 'SMTP Timeout', + 'type' => 'text', + ), + array('name' => 'email_smtp_secure', + 'descr' => 'SMTP Secure', + 'type' => 'select', + 'options' => $dyn_config['email_smtp_secure'], + ), + array('name' => 'email_smtp_auth', + 'descr' => 'SMTP Authentication', + 'type' => 'checkbox', + ), + array('name' => 'email_smtp_username', + 'descr' => 'SMTP Authentication Username', + 'type' => 'text', + ), + array('name' => 'email_smtp_password', + 'descr' => 'SMTP Authentication Password', + 'type' => 'text', + ), +); + echo '
    -
    - -
    -
    -
    - -
    -
    - -
    -
    -
    - -
    -
    - -
    -
    -
    - -
    -
    - -
    -
    -
    - -
    -
    - -
    -
    -
    - -
    -
    - - -
    -
    -
    - -
    -
    - - -
    -
    -
    - -
    -
    - -
    -
    -
    -
    -
    -
    -
    -

    - Email transport -

    -
    -
    -
    -
    - -
    -
    - -
    -
    -
    - -
    -
    - - -
    -
    -
    - -
    -
    - - -
    -
    -
    - -
    -
    - - -
    -
    -
    - -
    -
    - - -
    -
    -
    - -
    -
    - - -
    -
    -
    - -
    -
    - - -
    -
    -
    - -
    -
    - - -
    -
    -
    - -
    -
    - - -
    -
    -
    - -
    -
    - -
    -
    -
    - -
    -
    - - -
    -
    -
    - -
    -
    - - -
    -
    -
    -
    -
    +echo '

    @@ -1158,58 +1056,6 @@ echo '
    }); });// End delete Boxcar config - $("[name='global-config-check']").bootstrapSwitch('offColor','danger'); - $('input[name="global-config-check"]').on('switchChange.bootstrapSwitch', function(event, state) { - event.preventDefault(); - var config_id = $(this).data("config_id"); - $.ajax({ - type: 'POST', - url: 'ajax_form.php', - data: {type: "update-config-item", config_id: config_id, config_value: state}, - dataType: "json", - success: function (data) { - if (data.status == 'ok') { - } else { - $("#message").html('
    ' + data.message + '
    '); - } - }, - error: function () { - $("#message").html('
    An error occurred.
    '); - } - }); - }); - $(document).on('blur', 'input[name="global-config-input"]', function(event) { - event.preventDefault(); - var $this = $(this); - var config_id = $this.data("config_id"); - var config_value = $this.val(); - $.ajax({ - type: 'POST', - url: 'ajax_form.php', - data: {type: "update-config-item", config_id: config_id, config_value: config_value}, - dataType: "json", - success: function (data) { - if (data.status == 'ok') { - $this.closest('.form-group').addClass('has-success'); - $this.next().addClass('glyphicon-ok'); - setTimeout(function(){ - $this.closest('.form-group').removeClass('has-success'); - $this.next().removeClass('glyphicon-ok'); - }, 2000); - } else { - $(this).closest('.form-group').addClass('has-error'); - $this.next().addClass('glyphicon-remove'); - setTimeout(function(){ - $this.closest('.form-group').removeClass('has-error'); - $this.next().removeClass('glyphicon-remove'); - }, 2000); - } - }, - error: function () { - $("#message").html('
    An error occurred.
    '); - } - }); - }); $( 'select[name="global-config-select"]').change(function(event) { event.preventDefault(); var $this = $(this); From 502e1f88b5c52544046bf91605710ea7ec9df8c7 Mon Sep 17 00:00:00 2001 From: laf Date: Mon, 12 Oct 2015 21:49:35 +0000 Subject: [PATCH 555/598] Added docs on how to add dynamic config options --- doc/Developing/Dynamic-Config.md | 48 ++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 doc/Developing/Dynamic-Config.md diff --git a/doc/Developing/Dynamic-Config.md b/doc/Developing/Dynamic-Config.md new file mode 100644 index 000000000..a1d2309f8 --- /dev/null +++ b/doc/Developing/Dynamic-Config.md @@ -0,0 +1,48 @@ +# Adding new config options to WebUI + +Adding support for users to update a new config option via the WebUI is now a lot easier for general options. This +document shows you how to add a new config option and even section to the WebUI. + +#### Update DB + +Firstly you will need to add the config option to the database. Here's an example: + +```sql +insert into config (config_name,config_value,config_default,config_descr,config_group,config_group_order,config_sub_group,config_sub_group_order,config_hidden,config_disabled) values ('alert.tolerance_window','','','Tolerance window in seconds','alerting',0,'general',0,'0','0'); +``` + +This will determine the default config option for `$config['alert']['tolerance_window']`. + +#### Update WebUI + +If the sub-section you want to add the new config option already exists then update the relevant file within +`html/pages/settings/` otherwise you will need to create the new sub-section page. Here's an example of this: + +```php + 'alert.tolerance_window', + 'descr' => 'Tolerance window for cron', + 'type' => 'text', + ), +); + +echo ' +
    + +'; + +echo generate_dynamic_config_panel('Email transport',true,$config_groups,$mail_conf,'mail'); + +echo ' + +
    +'; +``` + +And that should be it! From c5998f9ee27acdac0c0f7d3092fc830c51ff684c Mon Sep 17 00:00:00 2001 From: laf Date: Mon, 12 Oct 2015 22:06:17 +0000 Subject: [PATCH 556/598] Example for adding new dynamic config options for WebUI --- html/pages/settings/external.inc.php | 32 ++++++++++++++++++++++++++++ sql-schema/074.sql | 1 + 2 files changed, 33 insertions(+) create mode 100644 html/pages/settings/external.inc.php create mode 100644 sql-schema/074.sql diff --git a/html/pages/settings/external.inc.php b/html/pages/settings/external.inc.php new file mode 100644 index 000000000..2960b2e25 --- /dev/null +++ b/html/pages/settings/external.inc.php @@ -0,0 +1,32 @@ + 'oxidized.enabled', + 'descr' => 'Enable Oxidized support', + 'type' => 'checkbox', + ), + array('name' => 'oxidized.url', + 'descr' => 'URL to your Oxidized API', + 'type' => 'text', + ), + array('name' => 'oxidized.features.versioning', + 'descr' => 'Enable config versioning access', + 'type' => 'checkbox', + ), +); + +echo ' +
    +
    +'; + +echo generate_dynamic_config_panel('Oxidized integration',true,$config_groups,$oxidized_conf); + +echo ' + +
    +'; diff --git a/sql-schema/074.sql b/sql-schema/074.sql new file mode 100644 index 000000000..2b086026b --- /dev/null +++ b/sql-schema/074.sql @@ -0,0 +1 @@ +INSERT INTO config (config_name,config_value,config_default,config_descr,config_group,config_group_order,config_sub_group,config_sub_group_order,config_hidden,config_disabled) values ('oxidized.enabled','false','false','Enable Oxidized support','external',0,'oxidized',0,'0','0'),('oxidized.url','','','Oxidized API url','external',0,'oxidized',0,'0','0'),('oxidized.features.versioning','false','false','Enable Oxidized config versioning','external',0,'oxidized',0,'0','0'); From 1cbe42e0c7442100fb9a23295379deafea6a2b89 Mon Sep 17 00:00:00 2001 From: laf Date: Mon, 12 Oct 2015 22:08:30 +0000 Subject: [PATCH 557/598] Added commit url example --- doc/Developing/Dynamic-Config.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/Developing/Dynamic-Config.md b/doc/Developing/Dynamic-Config.md index a1d2309f8..73e808f5c 100644 --- a/doc/Developing/Dynamic-Config.md +++ b/doc/Developing/Dynamic-Config.md @@ -18,6 +18,8 @@ This will determine the default config option for `$config['alert']['tolerance_w If the sub-section you want to add the new config option already exists then update the relevant file within `html/pages/settings/` otherwise you will need to create the new sub-section page. Here's an example of this: +[Commit example](https://github.com/librenm/librenms/commit/c5998f9ee27acdac0c0f7d3092fc830c51ff684c) + ```php Date: Mon, 12 Oct 2015 22:14:04 +0000 Subject: [PATCH 558/598] Some page updates --- .../includes/forms/update-config-item.inc.php | 2 +- html/pages/settings.inc.php | 20 ++++++++++++++++--- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/html/includes/forms/update-config-item.inc.php b/html/includes/forms/update-config-item.inc.php index b15444d9e..4b9ffe75d 100644 --- a/html/includes/forms/update-config-item.inc.php +++ b/html/includes/forms/update-config-item.inc.php @@ -23,7 +23,7 @@ $config_type = mres($_POST['config_type']); $status = 'error'; if (!is_numeric($config_id)) { - $message = 'ERROR: No alert selected'; + $message = 'ERROR: No config item'; } else if ($action == 'update-textarea') { $extras = explode(PHP_EOL, $_POST['config_value']); diff --git a/html/pages/settings.inc.php b/html/pages/settings.inc.php index 71c3cc3ee..f2a85f740 100644 --- a/html/pages/settings.inc.php +++ b/html/pages/settings.inc.php @@ -23,14 +23,28 @@ * @package LibreNMS * @subpackage Page */ -$pagetitle[] = 'Global Settings'; + +if (empty($vars['sub'])) { + $page_name = 'Global'; +} +else { + $page_name = ucfirst($vars['sub']); +} + +$pagetitle[] = $page_name . ' Settings'; $config['memcached']['enable'] = false; ?>
    -

    Global Settings

    +

    + +


    @@ -61,7 +75,7 @@ else { foreach (dbFetchRows("SELECT `config_group` FROM `config` GROUP BY `config_group`") as $sub_page) { $sub_page = $sub_page['config_group']; ?> -
    + Date: Mon, 12 Oct 2015 22:37:34 +0000 Subject: [PATCH 559/598] Added docs about passworded channels --- doc/Extensions/IRC-Bot.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/Extensions/IRC-Bot.md b/doc/Extensions/IRC-Bot.md index 7410869f1..fcb51e583 100644 --- a/doc/Extensions/IRC-Bot.md +++ b/doc/Extensions/IRC-Bot.md @@ -25,7 +25,7 @@ Option | Default-Value | Notes `$config['irc_alert_chan']` | `false` | Optional; Multiple channels can be defined as Array or delimited with `,`. `EXPERIMENTAL` `$config['irc_alert_utf8']` | `false` | Optional; Enables use of strikethrough in alerts via UTF-8 encoded characters. Might cause trouble for some clients. `$config['irc_authtime']` | `3` | Optional; Defines how long in Hours an auth-session is valid. -`$config['irc_chan']` | `##librenms` | Optional; Multiple channels can be defined as Array or delimited with `,` +`$config['irc_chan']` | `##librenms` | Optional; Multiple channels can be defined as Array or delimited with `,`. Passwords are defined after a `space-character`. `$config['irc_debug']` | `false` | Optional; Enables debug output (Wall of text) `$config['irc_external']` | | Optional; Array or `,` delimited string with commands to include from `includes/ircbot/*.inc.php` `$config['irc_host']` | | Required; Domain or IP to connect. If it's an IPv6 Address, embed it in `[]`. (Example: `[::1]`) From 22f4221df72ca5366f3d6ace17ed865deac4f6f3 Mon Sep 17 00:00:00 2001 From: f0o Date: Tue, 13 Oct 2015 14:19:17 +0000 Subject: [PATCH 560/598] Fixed images in docs --- doc/Extensions/Distributed-Poller.md | 2 +- doc/Extensions/Varnish.md | 2 +- doc/img/librenms-distributed-diagram.png | Bin 0 -> 100843 bytes 3 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 doc/img/librenms-distributed-diagram.png diff --git a/doc/Extensions/Distributed-Poller.md b/doc/Extensions/Distributed-Poller.md index e6c3e2c9d..2d9ebedf7 100644 --- a/doc/Extensions/Distributed-Poller.md +++ b/doc/Extensions/Distributed-Poller.md @@ -31,7 +31,7 @@ $config['distributed_poller_memcached_port'] = '11211'; Below is an example setup based on a real deployment which at the time of writing covers over 2,500 devices and 50,000 ports. The setup is running within an Openstack environment with some commodity ha rdware for remote pollers. Here's a diagram of how you can scale LibreNMS out: -![Example Setup](http://www.librenms.org/img/librenms-distributed-diagram.png) +![Example Setup](http://docs.librenms.org/img/librenms-distributed-diagram.png) ###Architecture How you setup the distribution is entirely up to you, you can choose to host the majority of the required services on a single virtual machine or server and then a poller to actually query the devices being monitored all the way through to having a dedicated server for each of the individual roles. Below are notes on what you need to consider both from the software layer but also connectivity. diff --git a/doc/Extensions/Varnish.md b/doc/Extensions/Varnish.md index 15c3acc87..98fda2adf 100644 --- a/doc/Extensions/Varnish.md +++ b/doc/Extensions/Varnish.md @@ -7,7 +7,7 @@ Varnish is caching software that sits logically between an HTTP client and an HT

    #####
    Simplified block diagram of an Apache HTTP server with Varnish 4.0 Reverse Proxy.
    ##### -![Block Diagram 1](http://www.librenms.org/img/varnish_block.png) +![Block Diagram 1](http://docs.librenms.org/img/varnish_block.png) ### CentOS 7 Varnish Installation ### diff --git a/doc/img/librenms-distributed-diagram.png b/doc/img/librenms-distributed-diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..0bfb6f89211e649d3753a2589a355037067aff39 GIT binary patch literal 100843 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 Date: Tue, 13 Oct 2015 16:46:31 +0200 Subject: [PATCH 561/598] world map: move markers to foreground for hosts that are down --- html/includes/common/worldmap.inc.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/html/includes/common/worldmap.inc.php b/html/includes/common/worldmap.inc.php index b89e9a3ca..fdec3fc26 100644 --- a/html/includes/common/worldmap.inc.php +++ b/html/includes/common/worldmap.inc.php @@ -123,11 +123,13 @@ var greenMarker = L.AwesomeMarkers.icon({ } foreach (dbFetchRows($sql, array($_SESSION['user_id'])) as $map_devices) { $icon = 'greenMarker'; + $z_offset = 0; if ($map_devices['status'] == 0) { $icon = 'redMarker'; + $z_offset = 10000; // move marker to foreground } $temp_output .= "var title = '\"\"".$map_devices['hostname']."'; -var marker = L.marker(new L.LatLng(".$map_devices['lat'].", ".$map_devices['lng']."), {title: title, icon: $icon}); +var marker = L.marker(new L.LatLng(".$map_devices['lat'].", ".$map_devices['lng']."), {title: title, icon: $icon, zIndexOffset: $z_offset}); marker.bindPopup(title); markers.addLayer(marker);\n"; } From f793428126ad4b5241e191ae3ab3d88c95eb099b Mon Sep 17 00:00:00 2001 From: Sebastian Neuner Date: Tue, 13 Oct 2015 17:20:19 +0200 Subject: [PATCH 562/598] I agree to the conditions of the Contributor Agreement contained in doc/General/Contributing.md. --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 3f1ce8fb8..587faee6e 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -62,5 +62,6 @@ Contributors to LibreNMS: - Xavier Beaudouin (xbeaudouin) - Falk Stern (fstern) - Donovan Bridoux (PandaWawawa) +- Sebastian Neuner (9er) [1]: http://observium.org/ "Observium web site" From 54db5be7f10cd20f6c391f2b6c31c97a0cbec2c6 Mon Sep 17 00:00:00 2001 From: Neil Lathwood Date: Tue, 13 Oct 2015 16:57:34 +0100 Subject: [PATCH 563/598] Revert "Removed what appears to be unecessary STACK text" --- html/includes/graphs/generic_multi_seperated.inc.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/html/includes/graphs/generic_multi_seperated.inc.php b/html/includes/graphs/generic_multi_seperated.inc.php index 25ec8c065..9b37f3751 100644 --- a/html/includes/graphs/generic_multi_seperated.inc.php +++ b/html/includes/graphs/generic_multi_seperated.inc.php @@ -70,7 +70,11 @@ foreach ($rrd_list as $rrd) { $rrd_options .= ' VDEF:tot'.$i.'=octets'.$i.',TOTAL'; } - $rrd_options .= ' AREA:inbits'.$i.'#'.$colour_in.":'".rrdtool_escape($rrd['descr'], 9)."In '"; + if ($i) { + $stack = 'STACK'; + } + + $rrd_options .= ' AREA:inbits'.$i.'#'.$colour_in.":'".rrdtool_escape($rrd['descr'], 9)."In '$stack"; $rrd_options .= ' GPRINT:inbits'.$i.':LAST:%6.2lf%s'; $rrd_options .= ' GPRINT:inbits'.$i.':AVERAGE:%6.2lf%s'; $rrd_options .= ' GPRINT:inbits'.$i.':MAX:%6.2lf%s'; @@ -80,7 +84,7 @@ foreach ($rrd_list as $rrd) { } $rrd_options .= " COMMENT:'\\n'"; - $rrd_optionsb .= ' AREA:outbits'.$i.'_neg#'.$colour_out; + $rrd_optionsb .= ' AREA:outbits'.$i.'_neg#'.$colour_out.":$stack"; $rrd_options .= ' HRULE:999999999999999#'.$colour_out.":'".str_pad('', 10)."Out'"; $rrd_options .= ' GPRINT:outbits'.$i.':LAST:%6.2lf%s'; $rrd_options .= ' GPRINT:outbits'.$i.':AVERAGE:%6.2lf%s'; From 769cc293c30552cc0602a4b8b9735e1f4f69245f Mon Sep 17 00:00:00 2001 From: laf Date: Tue, 13 Oct 2015 19:12:07 +0000 Subject: [PATCH 564/598] Added WebUI override to disable icmp checks for a device --- html/pages/device/edit/misc.inc.php | 6 ++++++ includes/functions.php | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/html/pages/device/edit/misc.inc.php b/html/pages/device/edit/misc.inc.php index 5f66c88fd..8a38293ed 100644 --- a/html/pages/device/edit/misc.inc.php +++ b/html/pages/device/edit/misc.inc.php @@ -2,6 +2,12 @@ echo '
    +
    + +
    + '.dynamic_override_config('checkbox','override_icmp_disable', $device).' +
    +
    diff --git a/includes/functions.php b/includes/functions.php index ba4aeb30a..1da63d4e8 100644 --- a/includes/functions.php +++ b/includes/functions.php @@ -490,7 +490,8 @@ function isSNMPable($device) { function isPingable($hostname, $address_family = AF_INET, $device_id = FALSE) { global $config; - if ($config['icmp_check'] === true) { + $tmp_device = array('device_id'=>$device_id); + if ($config['icmp_check'] === true || get_dev_attrib($tmp_device,'override_icmp_disable') != "true") { $fping_params = ''; if(is_numeric($config['fping_options']['retries']) || $config['fping_options']['retries'] > 1) { From 5f369562a5e5ae3e3224fa61d7731e25255f54d4 Mon Sep 17 00:00:00 2001 From: laf Date: Tue, 13 Oct 2015 19:16:23 +0000 Subject: [PATCH 565/598] Added docs on new config option --- doc/Support/Configuration.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/doc/Support/Configuration.md b/doc/Support/Configuration.md index 865b00b9b..7ffdffe08 100644 --- a/doc/Support/Configuration.md +++ b/doc/Support/Configuration.md @@ -59,6 +59,17 @@ $config['fping_options']['millisec'] = 200; * `count` (`fping` parameter `-c`): Number of request packets to send to each target. * `millisec` (`fping` parameter `-p`): Time in milliseconds that fping waits between successive packets to an individual target. +You can disable the fping / icmp check that is done for a device to be determined to be up on a global or per device basis. +**We don't advice disabling the fping / icmp check unless you know the impact, at worst if you have a large number of devices down +then it's possible that the poller would no longer complete in 5 minutes due to waiting for snmp to timeout.** + +Globally disable fping / icmp check: +```php +$config['icmp_check'] = false; +``` + +If you would like to do this on a per device basis then you can do so under Device -> Edit -> Misc -> Disable ICMP Test? On + ```php $config['snmpwalk'] = "/usr/bin/snmpwalk"; $config['snmpget'] = "/usr/bin/snmpget"; From 2f30848b8758bdb573e247475c99afb6ced5af35 Mon Sep 17 00:00:00 2001 From: laf Date: Tue, 13 Oct 2015 22:14:00 +0000 Subject: [PATCH 566/598] Should have been an && :( --- includes/functions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/functions.php b/includes/functions.php index 1da63d4e8..935d82dff 100644 --- a/includes/functions.php +++ b/includes/functions.php @@ -491,7 +491,7 @@ function isPingable($hostname, $address_family = AF_INET, $device_id = FALSE) { global $config; $tmp_device = array('device_id'=>$device_id); - if ($config['icmp_check'] === true || get_dev_attrib($tmp_device,'override_icmp_disable') != "true") { + if ($config['icmp_check'] === true && get_dev_attrib($tmp_device,'override_icmp_disable') != "true") { $fping_params = ''; if(is_numeric($config['fping_options']['retries']) || $config['fping_options']['retries'] > 1) { From 658f6faba64283deffa3613bf2f1ed4d1178b9e6 Mon Sep 17 00:00:00 2001 From: laf Date: Tue, 13 Oct 2015 22:46:36 +0000 Subject: [PATCH 567/598] Scrut fix --- includes/functions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/functions.php b/includes/functions.php index 935d82dff..319adb074 100644 --- a/includes/functions.php +++ b/includes/functions.php @@ -491,6 +491,7 @@ function isPingable($hostname, $address_family = AF_INET, $device_id = FALSE) { global $config; $tmp_device = array('device_id'=>$device_id); + $response = array(); if ($config['icmp_check'] === true && get_dev_attrib($tmp_device,'override_icmp_disable') != "true") { $fping_params = ''; @@ -506,7 +507,6 @@ function isPingable($hostname, $address_family = AF_INET, $device_id = FALSE) { if(is_numeric($config['fping_options']['millisec']) || $config['fping_options']['millisec'] > 0) { $fping_params .= ' -p ' . $config['fping_options']['millisec']; } - $response = array(); $status = fping($hostname,$fping_params,$address_family); if ($status['loss'] == 100) { $response['result'] = FALSE; From 3bef84fe85f78a8252996554680c20212dbc1bec Mon Sep 17 00:00:00 2001 From: Rosiak Date: Wed, 14 Oct 2015 20:05:22 +0200 Subject: [PATCH 568/598] Fix Riverbed discovery --- includes/discovery/os/linux.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/discovery/os/linux.inc.php b/includes/discovery/os/linux.inc.php index 6ad593373..1ade513e4 100644 --- a/includes/discovery/os/linux.inc.php +++ b/includes/discovery/os/linux.inc.php @@ -1,7 +1,7 @@ Date: Wed, 14 Oct 2015 20:11:12 +0200 Subject: [PATCH 569/598] add missing dot --- includes/discovery/os/linux.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/discovery/os/linux.inc.php b/includes/discovery/os/linux.inc.php index 1ade513e4..799c5875c 100644 --- a/includes/discovery/os/linux.inc.php +++ b/includes/discovery/os/linux.inc.php @@ -1,7 +1,7 @@ Date: Wed, 14 Oct 2015 20:33:59 +0200 Subject: [PATCH 570/598] Fixes issue where snmp_get would not return the value 0 --- includes/snmp.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/snmp.inc.php b/includes/snmp.inc.php index f472732cf..935afff99 100644 --- a/includes/snmp.inc.php +++ b/includes/snmp.inc.php @@ -133,7 +133,7 @@ function snmp_get($device, $oid, $options=null, $mib=null, $mibdir=null) { if (is_string($data) && (preg_match('/(No Such Instance|No Such Object|No more variables left|Authentication failure)/i', $data))) { return false; } - else if ($data) { + elseif ($data || $data === '0') { return $data; } else { From 78f02cb4186d333194e962314e03efec10a12d65 Mon Sep 17 00:00:00 2001 From: Mike Rostermund Date: Wed, 14 Oct 2015 20:44:33 +0200 Subject: [PATCH 571/598] Reformat check a bit to make it easier for adding additional oids in the future --- includes/discovery/os/linux.inc.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/includes/discovery/os/linux.inc.php b/includes/discovery/os/linux.inc.php index 799c5875c..4d49d25e0 100644 --- a/includes/discovery/os/linux.inc.php +++ b/includes/discovery/os/linux.inc.php @@ -1,7 +1,11 @@ Date: Wed, 14 Oct 2015 21:31:03 +0200 Subject: [PATCH 572/598] Remove old comment to kickstart scrut --- includes/snmp.inc.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/includes/snmp.inc.php b/includes/snmp.inc.php index 935afff99..f4603e513 100644 --- a/includes/snmp.inc.php +++ b/includes/snmp.inc.php @@ -1,11 +1,5 @@ Date: Wed, 14 Oct 2015 23:30:16 +0200 Subject: [PATCH 573/598] Updated Two-Factor-Auth.md RE: Google Authenticator --- doc/Extensions/Two-Factor-Auth.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/Extensions/Two-Factor-Auth.md b/doc/Extensions/Two-Factor-Auth.md index de6ee6d83..99696e631 100644 --- a/doc/Extensions/Two-Factor-Auth.md +++ b/doc/Extensions/Two-Factor-Auth.md @@ -62,7 +62,7 @@ Create a Two-Factor key: ## Google Authenticator -__Note__: Google Authenticator only allows counterbased OTP when scanned via QR codes. +~~__Note__: Google Authenticator only allows counterbased OTP when scanned via QR codes.~~ Tested as working with the latest version of Google Authenticator. Installation guides for Google Authneticator can be found [here](https://support.google.com/accounts/answer/1066447?hl=en). From 7275bcc668b1ad3457ba3bb6d3761c282711ec4c Mon Sep 17 00:00:00 2001 From: Mattz0r Date: Wed, 14 Oct 2015 23:56:32 +0200 Subject: [PATCH 574/598] Updated Two-Factor-Auth.md RE: Google Authenticator --- doc/Extensions/Two-Factor-Auth.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/Extensions/Two-Factor-Auth.md b/doc/Extensions/Two-Factor-Auth.md index 99696e631..fae1af856 100644 --- a/doc/Extensions/Two-Factor-Auth.md +++ b/doc/Extensions/Two-Factor-Auth.md @@ -62,7 +62,7 @@ Create a Two-Factor key: ## Google Authenticator -~~__Note__: Google Authenticator only allows counterbased OTP when scanned via QR codes.~~ Tested as working with the latest version of Google Authenticator. +__Note__: Google Authenticator only allows counterbased OTP when scanned via QR codes. Tested as working with the latest version of Google Authenticator. Installation guides for Google Authneticator can be found [here](https://support.google.com/accounts/answer/1066447?hl=en). From 50dbaef290310da5e2518a05a9e60c9dfa5182fb Mon Sep 17 00:00:00 2001 From: Mattz0r Date: Thu, 15 Oct 2015 00:14:16 +0200 Subject: [PATCH 575/598] Updated Two-Factor-Auth.md RE: Google Authenticator --- doc/Extensions/Two-Factor-Auth.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/doc/Extensions/Two-Factor-Auth.md b/doc/Extensions/Two-Factor-Auth.md index fae1af856..d2c74a197 100644 --- a/doc/Extensions/Two-Factor-Auth.md +++ b/doc/Extensions/Two-Factor-Auth.md @@ -62,8 +62,6 @@ Create a Two-Factor key: ## Google Authenticator -__Note__: Google Authenticator only allows counterbased OTP when scanned via QR codes. Tested as working with the latest version of Google Authenticator. - Installation guides for Google Authneticator can be found [here](https://support.google.com/accounts/answer/1066447?hl=en). Usage: From e908c2529041e870d79bf1db286afa6fb96b6f3c Mon Sep 17 00:00:00 2001 From: Mattz0r Date: Thu, 15 Oct 2015 19:21:09 +0200 Subject: [PATCH 576/598] Styled the two factor auth token prompt --- .../includes/authentication/twofactor.lib.php | 29 ++++++++++++------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/html/includes/authentication/twofactor.lib.php b/html/includes/authentication/twofactor.lib.php index 70cfed8ac..af175a5ec 100644 --- a/html/includes/authentication/twofactor.lib.php +++ b/html/includes/authentication/twofactor.lib.php @@ -168,24 +168,31 @@ function twofactor_form($form=true){ $ret = ""; if( $form ) { $ret .= ' - '; +
    +
    +
    +
    +

    +
    + +
    +

    +
    +
    +
    + '; } $ret .= '
    -
    -

    Please Enter TwoFactor Token:

    +
    +
    - -
    - -
    -
    -
    -
    - +
    +
    +
    '; $ret .= ''; if( $form ) { From 70aeb75d12e10ca698eef9c5d78bfd32e467ba9c Mon Sep 17 00:00:00 2001 From: PandaWawawa Date: Fri, 16 Oct 2015 16:18:18 +0200 Subject: [PATCH 577/598] Change on the add_edit_rule to modify a rule without modify the name --- html/includes/api_functions.inc.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/html/includes/api_functions.inc.php b/html/includes/api_functions.inc.php index 83bcb8929..6375188d7 100644 --- a/html/includes/api_functions.inc.php +++ b/html/includes/api_functions.inc.php @@ -693,8 +693,14 @@ function add_edit_rule() { ); $extra_json = json_encode($extra); - if (dbFetchCell('SELECT `name` FROM `alert_rules` WHERE `name`=?', array($name)) == $name) { - $message = 'Name has already been used'; + if(!isset($rule_id)) { + if (dbFetchCell('SELECT `name` FROM `alert_rules` WHERE `name`=?', array($name)) == $name) { + $message = 'Addition failed : Name has already been used'; + } + }else { + if(dbFetchCell("SELECT name FROM alert_rules WHERE name=? AND id !=? ", array($name, $rule_id)) == $name) { + $message = 'Edition failed : Name has already been used'; + } } if (empty($message)) { From 9fef97ffe49f1ca3b6f8ac524e78849836a07932 Mon Sep 17 00:00:00 2001 From: PandaWawawa Date: Fri, 16 Oct 2015 16:31:47 +0200 Subject: [PATCH 578/598] Change on the add_edit_rule to modify a rule without modify the name --- html/includes/api_functions.inc.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/html/includes/api_functions.inc.php b/html/includes/api_functions.inc.php index 6375188d7..1761cabf2 100644 --- a/html/includes/api_functions.inc.php +++ b/html/includes/api_functions.inc.php @@ -697,7 +697,8 @@ function add_edit_rule() { if (dbFetchCell('SELECT `name` FROM `alert_rules` WHERE `name`=?', array($name)) == $name) { $message = 'Addition failed : Name has already been used'; } - }else { + } + else { if(dbFetchCell("SELECT name FROM alert_rules WHERE name=? AND id !=? ", array($name, $rule_id)) == $name) { $message = 'Edition failed : Name has already been used'; } From ee14daf971ee938f2dafd924ce5dd9d18f7cdcf5 Mon Sep 17 00:00:00 2001 From: laf Date: Fri, 16 Oct 2015 18:46:43 +0000 Subject: [PATCH 579/598] Added additional comware detection --- includes/discovery/os/comware.inc.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/includes/discovery/os/comware.inc.php b/includes/discovery/os/comware.inc.php index 906e9c507..5bac4f730 100644 --- a/includes/discovery/os/comware.inc.php +++ b/includes/discovery/os/comware.inc.php @@ -4,7 +4,10 @@ if (!$os) { if (strstr($sysDescr, 'Comware')) { $os = 'comware'; } - else if (preg_match('/HP [a-zA-Z0-9- ]+ Switch Software Version/', $sysDescr)) { + elseif (preg_match('/HP [a-zA-Z0-9- ]+ Switch Software Version/', $sysDescr)) { + $os = 'comware'; + } + elseif (strstr($sysObjectId, '.1.3.6.1.4.1.25506.11.1')) { $os = 'comware'; } } From ce2c60e5ad9c50342fe34501195236351d47e649 Mon Sep 17 00:00:00 2001 From: laf Date: Fri, 16 Oct 2015 19:27:39 +0000 Subject: [PATCH 580/598] Added version detection from Synology MIB --- includes/polling/os/unix.inc.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/includes/polling/os/unix.inc.php b/includes/polling/os/unix.inc.php index 3d56316fc..96403771f 100644 --- a/includes/polling/os/unix.inc.php +++ b/includes/polling/os/unix.inc.php @@ -132,6 +132,9 @@ elseif ($device['os'] == "dsm") { $hardware = $value; } } + + $version = snmp_get($device, "version.0", "-Osqnv", "SYNOLOGY-SYSTEM-MIB"); + } elseif ($device['os'] == "pfsense") { $output = preg_split("/ /", $poll_device['sysDescr']); From 65841f00138920d630aa2b001647038313da2989 Mon Sep 17 00:00:00 2001 From: Rosiak Date: Fri, 16 Oct 2015 23:30:44 +0200 Subject: [PATCH 581/598] Update Font Awesome - Fix #2166 --- lib/Font-Awesome/CONTRIBUTING.md | 15 +- lib/Font-Awesome/Gemfile | 2 + lib/Font-Awesome/Gemfile.lock | 16 +- lib/Font-Awesome/HELP-US-OUT.txt | 7 + lib/Font-Awesome/README.md | 42 +- lib/Font-Awesome/_config.yml | 14 +- lib/Font-Awesome/bower.json | 5 +- lib/Font-Awesome/component.json | 3 +- lib/Font-Awesome/css/font-awesome.css | 235 ++++- lib/Font-Awesome/css/font-awesome.min.css | 4 +- lib/Font-Awesome/fonts/FontAwesome.otf | Bin 93888 -> 106260 bytes .../fonts/fontawesome-webfont.eot | Bin 60767 -> 68875 bytes .../fonts/fontawesome-webfont.svg | 105 ++- .../fonts/fontawesome-webfont.ttf | Bin 122092 -> 138204 bytes .../fonts/fontawesome-webfont.woff | Bin 71508 -> 81284 bytes .../fonts/fontawesome-webfont.woff2 | Bin 56780 -> 64464 bytes lib/Font-Awesome/less/bordered-pulled.less | 9 + lib/Font-Awesome/less/core.less | 3 +- lib/Font-Awesome/less/font-awesome.less | 2 +- lib/Font-Awesome/less/icons.less | 83 +- lib/Font-Awesome/less/mixins.less | 3 +- lib/Font-Awesome/less/variables.less | 88 +- lib/Font-Awesome/package.json | 14 +- lib/Font-Awesome/scss/_bordered-pulled.scss | 9 + lib/Font-Awesome/scss/_core.scss | 3 +- lib/Font-Awesome/scss/_icons.scss | 83 +- lib/Font-Awesome/scss/_mixins.scss | 3 +- lib/Font-Awesome/scss/_variables.scss | 88 +- lib/Font-Awesome/scss/font-awesome.scss | 2 +- .../3.2.1/assets/img/contribution-sample.png | Bin 2441 -> 2290 bytes .../3.2.1/assets/img/glyphicons-halflings.png | Bin 12799 -> 12764 bytes .../src/3.2.1/cheatsheet/index.html | 2 +- .../src/3.2.1/community/index.html | 4 +- .../src/3.2.1/examples/index.html | 2 +- .../src/3.2.1/get-started/index.html | 2 +- .../src/3.2.1/icon/adjust/index.html | 2 +- .../src/3.2.1/icon/adn/index.html | 2 +- .../src/3.2.1/icon/align-center/index.html | 2 +- .../src/3.2.1/icon/align-justify/index.html | 2 +- .../src/3.2.1/icon/align-left/index.html | 2 +- .../src/3.2.1/icon/align-right/index.html | 2 +- .../src/3.2.1/icon/ambulance/index.html | 2 +- .../src/3.2.1/icon/anchor/index.html | 2 +- .../src/3.2.1/icon/android/index.html | 2 +- .../src/3.2.1/icon/angle-down/index.html | 2 +- .../src/3.2.1/icon/angle-left/index.html | 2 +- .../src/3.2.1/icon/angle-right/index.html | 2 +- .../src/3.2.1/icon/angle-up/index.html | 2 +- .../src/3.2.1/icon/apple/index.html | 2 +- .../src/3.2.1/icon/archive/index.html | 2 +- .../src/3.2.1/icon/arrow-down/index.html | 2 +- .../src/3.2.1/icon/arrow-left/index.html | 2 +- .../src/3.2.1/icon/arrow-right/index.html | 2 +- .../src/3.2.1/icon/arrow-up/index.html | 2 +- .../src/3.2.1/icon/asterisk/index.html | 2 +- .../src/3.2.1/icon/backward/index.html | 2 +- .../src/3.2.1/icon/ban-circle/index.html | 2 +- .../src/3.2.1/icon/bar-chart/index.html | 2 +- .../src/3.2.1/icon/barcode/index.html | 2 +- .../src/3.2.1/icon/beaker/index.html | 2 +- .../src/3.2.1/icon/beer/index.html | 2 +- .../src/3.2.1/icon/bell-alt/index.html | 2 +- .../src/3.2.1/icon/bell/index.html | 2 +- .../src/3.2.1/icon/bitbucket-sign/index.html | 2 +- .../src/3.2.1/icon/bitbucket/index.html | 2 +- .../src/3.2.1/icon/bold/index.html | 2 +- .../src/3.2.1/icon/bolt/index.html | 2 +- .../src/3.2.1/icon/book/index.html | 2 +- .../src/3.2.1/icon/bookmark-empty/index.html | 2 +- .../src/3.2.1/icon/bookmark/index.html | 2 +- .../src/3.2.1/icon/briefcase/index.html | 2 +- .../src/3.2.1/icon/btc/index.html | 2 +- .../src/3.2.1/icon/bug/index.html | 2 +- .../src/3.2.1/icon/building/index.html | 2 +- .../src/3.2.1/icon/bullhorn/index.html | 2 +- .../src/3.2.1/icon/bullseye/index.html | 2 +- .../src/3.2.1/icon/calendar-empty/index.html | 2 +- .../src/3.2.1/icon/calendar/index.html | 2 +- .../src/3.2.1/icon/camera-retro/index.html | 2 +- .../src/3.2.1/icon/camera/index.html | 2 +- .../src/3.2.1/icon/caret-down/index.html | 2 +- .../src/3.2.1/icon/caret-left/index.html | 2 +- .../src/3.2.1/icon/caret-right/index.html | 2 +- .../src/3.2.1/icon/caret-up/index.html | 2 +- .../src/3.2.1/icon/certificate/index.html | 2 +- .../src/3.2.1/icon/check-empty/index.html | 2 +- .../src/3.2.1/icon/check-minus/index.html | 2 +- .../src/3.2.1/icon/check-sign/index.html | 2 +- .../src/3.2.1/icon/check/index.html | 2 +- .../src/3.2.1/icon/chevron-down/index.html | 2 +- .../src/3.2.1/icon/chevron-left/index.html | 2 +- .../src/3.2.1/icon/chevron-right/index.html | 2 +- .../3.2.1/icon/chevron-sign-down/index.html | 2 +- .../3.2.1/icon/chevron-sign-left/index.html | 2 +- .../3.2.1/icon/chevron-sign-right/index.html | 2 +- .../src/3.2.1/icon/chevron-sign-up/index.html | 2 +- .../src/3.2.1/icon/chevron-up/index.html | 2 +- .../3.2.1/icon/circle-arrow-down/index.html | 2 +- .../3.2.1/icon/circle-arrow-left/index.html | 2 +- .../3.2.1/icon/circle-arrow-right/index.html | 2 +- .../src/3.2.1/icon/circle-arrow-up/index.html | 2 +- .../src/3.2.1/icon/circle-blank/index.html | 2 +- .../src/3.2.1/icon/circle/index.html | 2 +- .../src/3.2.1/icon/cloud-download/index.html | 2 +- .../src/3.2.1/icon/cloud-upload/index.html | 2 +- .../src/3.2.1/icon/cloud/index.html | 2 +- .../src/3.2.1/icon/cny/index.html | 2 +- .../src/3.2.1/icon/code-fork/index.html | 2 +- .../src/3.2.1/icon/code/index.html | 2 +- .../src/3.2.1/icon/coffee/index.html | 2 +- .../src/3.2.1/icon/cog/index.html | 2 +- .../src/3.2.1/icon/cogs/index.html | 2 +- .../src/3.2.1/icon/collapse-alt/index.html | 2 +- .../src/3.2.1/icon/collapse-top/index.html | 2 +- .../src/3.2.1/icon/collapse/index.html | 2 +- .../src/3.2.1/icon/columns/index.html | 2 +- .../src/3.2.1/icon/comment-alt/index.html | 2 +- .../src/3.2.1/icon/comment/index.html | 2 +- .../src/3.2.1/icon/comments-alt/index.html | 2 +- .../src/3.2.1/icon/comments/index.html | 2 +- .../src/3.2.1/icon/compass/index.html | 2 +- .../src/3.2.1/icon/copy/index.html | 2 +- .../src/3.2.1/icon/credit-card/index.html | 2 +- .../src/3.2.1/icon/crop/index.html | 2 +- .../src/3.2.1/icon/css3/index.html | 2 +- .../src/3.2.1/icon/cut/index.html | 2 +- .../src/3.2.1/icon/dashboard/index.html | 2 +- .../src/3.2.1/icon/desktop/index.html | 2 +- .../3.2.1/icon/double-angle-down/index.html | 2 +- .../3.2.1/icon/double-angle-left/index.html | 2 +- .../3.2.1/icon/double-angle-right/index.html | 2 +- .../src/3.2.1/icon/double-angle-up/index.html | 2 +- .../src/3.2.1/icon/download-alt/index.html | 2 +- .../src/3.2.1/icon/download/index.html | 2 +- .../src/3.2.1/icon/dribbble/index.html | 2 +- .../src/3.2.1/icon/dropbox/index.html | 2 +- .../src/3.2.1/icon/edit-sign/index.html | 2 +- .../src/3.2.1/icon/edit/index.html | 2 +- .../src/3.2.1/icon/eject/index.html | 2 +- .../3.2.1/icon/ellipsis-horizontal/index.html | 2 +- .../3.2.1/icon/ellipsis-vertical/index.html | 2 +- .../src/3.2.1/icon/envelope-alt/index.html | 2 +- .../src/3.2.1/icon/envelope/index.html | 2 +- .../src/3.2.1/icon/eraser/index.html | 2 +- .../src/3.2.1/icon/eur/index.html | 2 +- .../src/3.2.1/icon/exchange/index.html | 2 +- .../3.2.1/icon/exclamation-sign/index.html | 2 +- .../src/3.2.1/icon/exclamation/index.html | 2 +- .../src/3.2.1/icon/expand-alt/index.html | 2 +- .../src/3.2.1/icon/expand/index.html | 2 +- .../3.2.1/icon/external-link-sign/index.html | 2 +- .../src/3.2.1/icon/external-link/index.html | 2 +- .../src/3.2.1/icon/eye-close/index.html | 2 +- .../src/3.2.1/icon/eye-open/index.html | 2 +- .../src/3.2.1/icon/facebook-sign/index.html | 2 +- .../src/3.2.1/icon/facebook/index.html | 2 +- .../src/3.2.1/icon/facetime-video/index.html | 2 +- .../src/3.2.1/icon/fast-backward/index.html | 2 +- .../src/3.2.1/icon/fast-forward/index.html | 2 +- .../src/3.2.1/icon/female/index.html | 2 +- .../src/3.2.1/icon/fighter-jet/index.html | 2 +- .../src/3.2.1/icon/file-alt/index.html | 2 +- .../src/3.2.1/icon/file-text-alt/index.html | 2 +- .../src/3.2.1/icon/file-text/index.html | 2 +- .../src/3.2.1/icon/file/index.html | 2 +- .../src/3.2.1/icon/film/index.html | 2 +- .../src/3.2.1/icon/filter/index.html | 2 +- .../3.2.1/icon/fire-extinguisher/index.html | 2 +- .../src/3.2.1/icon/fire/index.html | 2 +- .../src/3.2.1/icon/flag-alt/index.html | 2 +- .../src/3.2.1/icon/flag-checkered/index.html | 2 +- .../src/3.2.1/icon/flag/index.html | 2 +- .../src/3.2.1/icon/flickr/index.html | 2 +- .../3.2.1/icon/folder-close-alt/index.html | 2 +- .../src/3.2.1/icon/folder-close/index.html | 2 +- .../src/3.2.1/icon/folder-open-alt/index.html | 2 +- .../src/3.2.1/icon/folder-open/index.html | 2 +- .../src/3.2.1/icon/font/index.html | 2 +- .../src/3.2.1/icon/food/index.html | 2 +- .../src/3.2.1/icon/forward/index.html | 2 +- .../src/3.2.1/icon/foursquare/index.html | 2 +- .../src/3.2.1/icon/frown/index.html | 2 +- .../src/3.2.1/icon/fullscreen/index.html | 2 +- .../src/3.2.1/icon/gamepad/index.html | 2 +- .../src/3.2.1/icon/gbp/index.html | 2 +- .../src/3.2.1/icon/gift/index.html | 2 +- .../src/3.2.1/icon/github-alt/index.html | 2 +- .../src/3.2.1/icon/github-sign/index.html | 2 +- .../src/3.2.1/icon/github/index.html | 2 +- .../src/3.2.1/icon/gittip/index.html | 2 +- .../src/3.2.1/icon/glass/index.html | 2 +- .../src/3.2.1/icon/globe/index.html | 2 +- .../3.2.1/icon/google-plus-sign/index.html | 2 +- .../src/3.2.1/icon/google-plus/index.html | 2 +- .../src/3.2.1/icon/group/index.html | 2 +- .../src/3.2.1/icon/h-sign/index.html | 2 +- .../src/3.2.1/icon/hand-down/index.html | 2 +- .../src/3.2.1/icon/hand-left/index.html | 2 +- .../src/3.2.1/icon/hand-right/index.html | 2 +- .../src/3.2.1/icon/hand-up/index.html | 2 +- .../src/3.2.1/icon/hdd/index.html | 2 +- .../src/3.2.1/icon/headphones/index.html | 2 +- .../src/3.2.1/icon/heart-empty/index.html | 2 +- .../src/3.2.1/icon/heart/index.html | 2 +- .../src/3.2.1/icon/home/index.html | 2 +- .../src/3.2.1/icon/hospital/index.html | 2 +- .../src/3.2.1/icon/html5/index.html | 2 +- .../src/3.2.1/icon/inbox/index.html | 2 +- .../src/3.2.1/icon/indent-left/index.html | 2 +- .../src/3.2.1/icon/indent-right/index.html | 2 +- .../src/3.2.1/icon/info-sign/index.html | 2 +- .../src/3.2.1/icon/info/index.html | 2 +- .../src/3.2.1/icon/inr/index.html | 2 +- .../src/3.2.1/icon/instagram/index.html | 2 +- .../src/3.2.1/icon/italic/index.html | 2 +- .../src/3.2.1/icon/jpy/index.html | 2 +- .../src/3.2.1/icon/key/index.html | 2 +- .../src/3.2.1/icon/keyboard/index.html | 2 +- .../src/3.2.1/icon/krw/index.html | 2 +- .../src/3.2.1/icon/laptop/index.html | 2 +- .../src/3.2.1/icon/leaf/index.html | 2 +- .../src/3.2.1/icon/legal/index.html | 2 +- .../src/3.2.1/icon/lemon/index.html | 2 +- .../src/3.2.1/icon/level-down/index.html | 2 +- .../src/3.2.1/icon/level-up/index.html | 2 +- .../src/3.2.1/icon/lightbulb/index.html | 2 +- .../src/3.2.1/icon/link/index.html | 2 +- .../src/3.2.1/icon/linkedin-sign/index.html | 2 +- .../src/3.2.1/icon/linkedin/index.html | 2 +- .../src/3.2.1/icon/linux/index.html | 2 +- .../src/3.2.1/icon/list-alt/index.html | 2 +- .../src/3.2.1/icon/list-ol/index.html | 2 +- .../src/3.2.1/icon/list-ul/index.html | 2 +- .../src/3.2.1/icon/list/index.html | 2 +- .../src/3.2.1/icon/location-arrow/index.html | 2 +- .../src/3.2.1/icon/lock/index.html | 2 +- .../src/3.2.1/icon/long-arrow-down/index.html | 2 +- .../src/3.2.1/icon/long-arrow-left/index.html | 2 +- .../3.2.1/icon/long-arrow-right/index.html | 2 +- .../src/3.2.1/icon/long-arrow-up/index.html | 2 +- .../src/3.2.1/icon/magic/index.html | 2 +- .../src/3.2.1/icon/magnet/index.html | 2 +- .../src/3.2.1/icon/mail-reply-all/index.html | 2 +- .../src/3.2.1/icon/male/index.html | 2 +- .../src/3.2.1/icon/map-marker/index.html | 2 +- .../src/3.2.1/icon/maxcdn/index.html | 2 +- .../src/3.2.1/icon/medkit/index.html | 2 +- .../src/3.2.1/icon/meh/index.html | 2 +- .../src/3.2.1/icon/microphone-off/index.html | 2 +- .../src/3.2.1/icon/microphone/index.html | 2 +- .../src/3.2.1/icon/minus-sign-alt/index.html | 2 +- .../src/3.2.1/icon/minus-sign/index.html | 2 +- .../src/3.2.1/icon/minus/index.html | 2 +- .../src/3.2.1/icon/mobile-phone/index.html | 2 +- .../src/3.2.1/icon/money/index.html | 2 +- .../src/3.2.1/icon/moon/index.html | 2 +- .../src/3.2.1/icon/move/index.html | 2 +- .../src/3.2.1/icon/music/index.html | 2 +- .../src/3.2.1/icon/off/index.html | 2 +- .../src/3.2.1/icon/ok-circle/index.html | 2 +- .../src/3.2.1/icon/ok-sign/index.html | 2 +- lib/Font-Awesome/src/3.2.1/icon/ok/index.html | 2 +- .../src/3.2.1/icon/paper-clip/index.html | 2 +- .../src/3.2.1/icon/paste/index.html | 2 +- .../src/3.2.1/icon/pause/index.html | 2 +- .../src/3.2.1/icon/pencil/index.html | 2 +- .../src/3.2.1/icon/phone-sign/index.html | 2 +- .../src/3.2.1/icon/phone/index.html | 2 +- .../src/3.2.1/icon/picture/index.html | 2 +- .../src/3.2.1/icon/pinterest-sign/index.html | 2 +- .../src/3.2.1/icon/pinterest/index.html | 2 +- .../src/3.2.1/icon/plane/index.html | 2 +- .../src/3.2.1/icon/play-circle/index.html | 2 +- .../src/3.2.1/icon/play-sign/index.html | 2 +- .../src/3.2.1/icon/play/index.html | 2 +- .../src/3.2.1/icon/plus-sign-alt/index.html | 2 +- .../src/3.2.1/icon/plus-sign/index.html | 2 +- .../src/3.2.1/icon/plus/index.html | 2 +- .../src/3.2.1/icon/print/index.html | 2 +- .../src/3.2.1/icon/pushpin/index.html | 2 +- .../src/3.2.1/icon/puzzle-piece/index.html | 2 +- .../src/3.2.1/icon/qrcode/index.html | 2 +- .../src/3.2.1/icon/question-sign/index.html | 2 +- .../src/3.2.1/icon/question/index.html | 2 +- .../src/3.2.1/icon/quote-left/index.html | 2 +- .../src/3.2.1/icon/quote-right/index.html | 2 +- .../src/3.2.1/icon/random/index.html | 2 +- .../src/3.2.1/icon/refresh/index.html | 2 +- .../src/3.2.1/icon/remove-circle/index.html | 2 +- .../src/3.2.1/icon/remove-sign/index.html | 2 +- .../src/3.2.1/icon/remove/index.html | 2 +- .../src/3.2.1/icon/renren/index.html | 2 +- .../src/3.2.1/icon/reorder/index.html | 2 +- .../src/3.2.1/icon/repeat/index.html | 2 +- .../src/3.2.1/icon/reply-all/index.html | 2 +- .../src/3.2.1/icon/reply/index.html | 2 +- .../src/3.2.1/icon/resize-full/index.html | 2 +- .../3.2.1/icon/resize-horizontal/index.html | 2 +- .../src/3.2.1/icon/resize-small/index.html | 2 +- .../src/3.2.1/icon/resize-vertical/index.html | 2 +- .../src/3.2.1/icon/retweet/index.html | 2 +- .../src/3.2.1/icon/road/index.html | 2 +- .../src/3.2.1/icon/rocket/index.html | 2 +- .../src/3.2.1/icon/rss-sign/index.html | 2 +- .../src/3.2.1/icon/rss/index.html | 2 +- .../src/3.2.1/icon/save/index.html | 2 +- .../src/3.2.1/icon/screenshot/index.html | 2 +- .../src/3.2.1/icon/search/index.html | 2 +- .../src/3.2.1/icon/share-alt/index.html | 2 +- .../src/3.2.1/icon/share-sign/index.html | 2 +- .../src/3.2.1/icon/share/index.html | 2 +- .../src/3.2.1/icon/shield/index.html | 2 +- .../src/3.2.1/icon/shopping-cart/index.html | 2 +- .../src/3.2.1/icon/sign-blank/index.html | 2 +- .../src/3.2.1/icon/signal/index.html | 2 +- .../src/3.2.1/icon/signin/index.html | 2 +- .../src/3.2.1/icon/signout/index.html | 2 +- .../src/3.2.1/icon/sitemap/index.html | 2 +- .../src/3.2.1/icon/skype/index.html | 2 +- .../src/3.2.1/icon/smile/index.html | 2 +- .../icon/sort-by-alphabet-alt/index.html | 2 +- .../3.2.1/icon/sort-by-alphabet/index.html | 2 +- .../icon/sort-by-attributes-alt/index.html | 2 +- .../3.2.1/icon/sort-by-attributes/index.html | 2 +- .../3.2.1/icon/sort-by-order-alt/index.html | 2 +- .../src/3.2.1/icon/sort-by-order/index.html | 2 +- .../src/3.2.1/icon/sort-down/index.html | 2 +- .../src/3.2.1/icon/sort-up/index.html | 2 +- .../src/3.2.1/icon/sort/index.html | 2 +- .../src/3.2.1/icon/spinner/index.html | 2 +- .../src/3.2.1/icon/stackexchange/index.html | 2 +- .../src/3.2.1/icon/star-empty/index.html | 2 +- .../src/3.2.1/icon/star-half-empty/index.html | 2 +- .../src/3.2.1/icon/star-half/index.html | 2 +- .../src/3.2.1/icon/star/index.html | 2 +- .../src/3.2.1/icon/step-backward/index.html | 2 +- .../src/3.2.1/icon/step-forward/index.html | 2 +- .../src/3.2.1/icon/stethoscope/index.html | 2 +- .../src/3.2.1/icon/stop/index.html | 2 +- .../src/3.2.1/icon/strikethrough/index.html | 2 +- .../src/3.2.1/icon/subscript/index.html | 2 +- .../src/3.2.1/icon/suitcase/index.html | 2 +- .../src/3.2.1/icon/sun/index.html | 2 +- .../src/3.2.1/icon/superscript/index.html | 2 +- .../src/3.2.1/icon/table/index.html | 2 +- .../src/3.2.1/icon/tablet/index.html | 2 +- .../src/3.2.1/icon/tag/index.html | 2 +- .../src/3.2.1/icon/tags/index.html | 2 +- .../src/3.2.1/icon/tasks/index.html | 2 +- .../src/3.2.1/icon/terminal/index.html | 2 +- .../src/3.2.1/icon/text-height/index.html | 2 +- .../src/3.2.1/icon/text-width/index.html | 2 +- .../src/3.2.1/icon/th-large/index.html | 2 +- .../src/3.2.1/icon/th-list/index.html | 2 +- lib/Font-Awesome/src/3.2.1/icon/th/index.html | 2 +- .../src/3.2.1/icon/thumbs-down-alt/index.html | 2 +- .../src/3.2.1/icon/thumbs-down/index.html | 2 +- .../src/3.2.1/icon/thumbs-up-alt/index.html | 2 +- .../src/3.2.1/icon/thumbs-up/index.html | 2 +- .../src/3.2.1/icon/ticket/index.html | 2 +- .../src/3.2.1/icon/time/index.html | 2 +- .../src/3.2.1/icon/tint/index.html | 2 +- .../src/3.2.1/icon/trash/index.html | 2 +- .../src/3.2.1/icon/trello/index.html | 2 +- .../src/3.2.1/icon/trophy/index.html | 2 +- .../src/3.2.1/icon/truck/index.html | 2 +- .../src/3.2.1/icon/tumblr-sign/index.html | 2 +- .../src/3.2.1/icon/tumblr/index.html | 2 +- .../src/3.2.1/icon/twitter-sign/index.html | 2 +- .../src/3.2.1/icon/twitter/index.html | 2 +- .../src/3.2.1/icon/umbrella/index.html | 2 +- .../src/3.2.1/icon/underline/index.html | 2 +- .../src/3.2.1/icon/undo/index.html | 2 +- .../src/3.2.1/icon/unlink/index.html | 2 +- .../src/3.2.1/icon/unlock-alt/index.html | 2 +- .../src/3.2.1/icon/unlock/index.html | 2 +- .../src/3.2.1/icon/upload-alt/index.html | 2 +- .../src/3.2.1/icon/upload/index.html | 2 +- .../src/3.2.1/icon/usd/index.html | 2 +- .../src/3.2.1/icon/user-md/index.html | 2 +- .../src/3.2.1/icon/user/index.html | 2 +- lib/Font-Awesome/src/3.2.1/icon/vk/index.html | 2 +- .../src/3.2.1/icon/volume-down/index.html | 2 +- .../src/3.2.1/icon/volume-off/index.html | 2 +- .../src/3.2.1/icon/volume-up/index.html | 2 +- .../src/3.2.1/icon/warning-sign/index.html | 2 +- .../src/3.2.1/icon/weibo/index.html | 2 +- .../src/3.2.1/icon/windows/index.html | 2 +- .../src/3.2.1/icon/wrench/index.html | 2 +- .../src/3.2.1/icon/xing-sign/index.html | 2 +- .../src/3.2.1/icon/xing/index.html | 2 +- .../src/3.2.1/icon/youtube-play/index.html | 2 +- .../src/3.2.1/icon/youtube-sign/index.html | 2 +- .../src/3.2.1/icon/youtube/index.html | 2 +- .../src/3.2.1/icon/zoom-in/index.html | 2 +- .../src/3.2.1/icon/zoom-out/index.html | 2 +- lib/Font-Awesome/src/3.2.1/icons/index.html | 2 +- lib/Font-Awesome/src/3.2.1/index.html | 4 +- lib/Font-Awesome/src/3.2.1/license/index.html | 2 +- lib/Font-Awesome/src/3.2.1/test/index.html | 2 +- .../src/3.2.1/whats-new/index.html | 2 +- lib/Font-Awesome/src/Makefile | 6 +- lib/Font-Awesome/src/README.md-nobuild | 38 +- .../src/_includes/ads/fusion.html | 2 +- lib/Font-Awesome/src/_includes/code/core.less | 3 +- lib/Font-Awesome/src/_includes/code/core.scss | 3 +- .../src/_includes/examples/animated.html | 8 +- .../_includes/examples/bordered-pulled.html | 6 +- lib/Font-Awesome/src/_includes/footer.html | 15 +- .../src/_includes/icons/hand.html | 12 + .../src/_includes/jumbotron-carousel.html | 13 +- .../src/_includes/modals/download.html | 34 + lib/Font-Awesome/src/_includes/navbar.html | 8 +- .../src/_includes/stripe-social.html | 21 +- lib/Font-Awesome/src/_includes/thanks-to.html | 2 +- lib/Font-Awesome/src/_layouts/base.html | 67 +- .../src/assets/font-awesome/HELP-US-OUT.txt | 7 + .../assets/font-awesome/fonts/FontAwesome.otf | Bin 93888 -> 106260 bytes .../fonts/fontawesome-webfont.eot | Bin 60767 -> 68875 bytes .../fonts/fontawesome-webfont.svg | 105 ++- .../fonts/fontawesome-webfont.ttf | Bin 122092 -> 138204 bytes .../fonts/fontawesome-webfont.woff | Bin 71508 -> 81284 bytes .../fonts/fontawesome-webfont.woff2 | Bin 56780 -> 64464 bytes .../font-awesome/less/bordered-pulled.less | 9 + .../assets/font-awesome/less/variables.less | 1 + .../font-awesome/scss/_bordered-pulled.scss | 9 + .../assets/font-awesome/scss/_variables.scss | 1 + lib/Font-Awesome/src/assets/ico/favicon.ico | Bin 1150 -> 52047 bytes lib/Font-Awesome/src/assets/img/algolia.png | Bin 0 -> 72993 bytes .../src/assets/img/logo-themeisle.png | Bin 0 -> 5547 bytes .../src/assets/img/logo-wpbeginner.png | Bin 0 -> 7461 bytes lib/Font-Awesome/src/assets/js/search.js | 92 ++ lib/Font-Awesome/src/assets/js/site.js | 139 +-- .../assets/less/bootstrap-3.3.5/.csscomb.json | 304 ++++++ .../assets/less/bootstrap-3.3.5/.csslintrc | 19 + .../assets/less/bootstrap-3.3.5/alerts.less | 73 ++ .../assets/less/bootstrap-3.3.5/badges.less | 66 ++ .../less/bootstrap-3.3.5/bootstrap.less | 56 ++ .../less/bootstrap-3.3.5/breadcrumbs.less | 26 + .../less/bootstrap-3.3.5/button-groups.less | 244 +++++ .../assets/less/bootstrap-3.3.5/buttons.less | 166 ++++ .../assets/less/bootstrap-3.3.5/carousel.less | 269 ++++++ .../assets/less/bootstrap-3.3.5/close.less | 34 + .../src/assets/less/bootstrap-3.3.5/code.less | 69 ++ .../bootstrap-3.3.5/component-animations.less | 33 + .../less/bootstrap-3.3.5/dropdowns.less | 216 +++++ .../assets/less/bootstrap-3.3.5/forms.less | 613 ++++++++++++ .../less/bootstrap-3.3.5/glyphicons.less | 305 ++++++ .../src/assets/less/bootstrap-3.3.5/grid.less | 84 ++ .../less/bootstrap-3.3.5/input-groups.less | 167 ++++ .../less/bootstrap-3.3.5/jumbotron.less | 52 ++ .../assets/less/bootstrap-3.3.5/labels.less | 64 ++ .../less/bootstrap-3.3.5/list-group.less | 130 +++ .../assets/less/bootstrap-3.3.5/media.less | 66 ++ .../assets/less/bootstrap-3.3.5/mixins.less | 40 + .../less/bootstrap-3.3.5/mixins/alerts.less | 14 + .../mixins/background-variant.less | 9 + .../bootstrap-3.3.5/mixins/border-radius.less | 18 + .../less/bootstrap-3.3.5/mixins/buttons.less | 68 ++ .../bootstrap-3.3.5/mixins/center-block.less | 7 + .../less/bootstrap-3.3.5/mixins/clearfix.less | 22 + .../less/bootstrap-3.3.5/mixins/forms.less | 85 ++ .../bootstrap-3.3.5/mixins/gradients.less | 59 ++ .../mixins/grid-framework.less | 91 ++ .../less/bootstrap-3.3.5/mixins/grid.less | 122 +++ .../bootstrap-3.3.5/mixins/hide-text.less | 21 + .../less/bootstrap-3.3.5/mixins/image.less | 33 + .../less/bootstrap-3.3.5/mixins/labels.less | 12 + .../bootstrap-3.3.5/mixins/list-group.less | 30 + .../bootstrap-3.3.5/mixins/nav-divider.less | 10 + .../mixins/nav-vertical-align.less | 9 + .../less/bootstrap-3.3.5/mixins/opacity.less | 8 + .../bootstrap-3.3.5/mixins/pagination.less | 24 + .../less/bootstrap-3.3.5/mixins/panels.less | 24 + .../bootstrap-3.3.5/mixins/progress-bar.less | 10 + .../bootstrap-3.3.5/mixins/reset-filter.less | 8 + .../bootstrap-3.3.5/mixins/reset-text.less | 18 + .../less/bootstrap-3.3.5/mixins/resize.less | 6 + .../mixins/responsive-visibility.less | 15 + .../less/bootstrap-3.3.5/mixins/size.less | 10 + .../bootstrap-3.3.5/mixins/tab-focus.less | 9 + .../bootstrap-3.3.5/mixins/table-row.less | 28 + .../bootstrap-3.3.5/mixins/text-emphasis.less | 9 + .../bootstrap-3.3.5/mixins/text-overflow.less | 8 + .../mixins/vendor-prefixes.less | 227 +++++ .../assets/less/bootstrap-3.3.5/modals.less | 150 +++ .../assets/less/bootstrap-3.3.5/navbar.less | 660 +++++++++++++ .../src/assets/less/bootstrap-3.3.5/navs.less | 242 +++++ .../less/bootstrap-3.3.5/normalize.less | 424 +++++++++ .../assets/less/bootstrap-3.3.5/pager.less | 54 ++ .../less/bootstrap-3.3.5/pagination.less | 89 ++ .../assets/less/bootstrap-3.3.5/panels.less | 271 ++++++ .../assets/less/bootstrap-3.3.5/popovers.less | 131 +++ .../assets/less/bootstrap-3.3.5/print.less | 101 ++ .../less/bootstrap-3.3.5/progress-bars.less | 87 ++ .../bootstrap-3.3.5/responsive-embed.less | 35 + .../bootstrap-3.3.5/responsive-utilities.less | 194 ++++ .../less/bootstrap-3.3.5/scaffolding.less | 161 ++++ .../assets/less/bootstrap-3.3.5/tables.less | 234 +++++ .../assets/less/bootstrap-3.3.5/theme.less | 291 ++++++ .../less/bootstrap-3.3.5/thumbnails.less | 36 + .../assets/less/bootstrap-3.3.5/tooltip.less | 101 ++ .../src/assets/less/bootstrap-3.3.5/type.less | 302 ++++++ .../less/bootstrap-3.3.5/utilities.less | 55 ++ .../less/bootstrap-3.3.5/variables.less | 869 ++++++++++++++++++ .../assets/less/bootstrap-3.3.5/wells.less | 29 + lib/Font-Awesome/src/assets/less/site.less | 3 + .../src/assets/less/site/algolia.less | 12 + .../assets/less/site/bootstrap/alerts.less | 1 + .../assets/less/site/bootstrap/jumbotron.less | 17 +- .../assets/less/site/bootstrap/modals.less | 6 + .../assets/less/site/bootstrap/variables.less | 8 +- .../src/assets/less/site/bootstrap/wells.less | 9 + .../src/assets/less/site/bsap-ad.less | 1 + .../less/site/fontawesome-icon-list.less | 1 + .../src/assets/less/site/footer.less | 41 +- .../src/assets/less/site/lazy.less | 33 +- .../less/site/responsive/screen-sm.less | 2 - .../less/site/responsive/screen-xs.less | 12 +- .../src/assets/less/site/search.less | 27 +- .../src/assets/less/site/social-buttons.less | 10 + lib/Font-Awesome/src/cheatsheet.html | 3 +- lib/Font-Awesome/src/get-started.html | 21 +- lib/Font-Awesome/src/icons.html | 90 +- lib/Font-Awesome/src/icons.yml | 610 +++++++++++- lib/Font-Awesome/src/index.html | 2 + lib/Font-Awesome/src/test.html | 10 +- lib/Font-Awesome/src/thanks.html | 29 + 528 files changed, 11022 insertions(+), 735 deletions(-) create mode 100644 lib/Font-Awesome/HELP-US-OUT.txt create mode 100644 lib/Font-Awesome/src/_includes/icons/hand.html create mode 100644 lib/Font-Awesome/src/_includes/modals/download.html create mode 100644 lib/Font-Awesome/src/assets/font-awesome/HELP-US-OUT.txt create mode 100644 lib/Font-Awesome/src/assets/img/algolia.png create mode 100644 lib/Font-Awesome/src/assets/img/logo-themeisle.png create mode 100644 lib/Font-Awesome/src/assets/img/logo-wpbeginner.png create mode 100644 lib/Font-Awesome/src/assets/js/search.js create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/.csscomb.json create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/.csslintrc create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/alerts.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/badges.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/bootstrap.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/breadcrumbs.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/button-groups.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/buttons.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/carousel.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/close.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/code.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/component-animations.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/dropdowns.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/forms.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/glyphicons.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/grid.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/input-groups.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/jumbotron.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/labels.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/list-group.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/media.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/alerts.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/background-variant.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/border-radius.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/buttons.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/center-block.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/clearfix.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/forms.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/gradients.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/grid-framework.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/grid.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/hide-text.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/image.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/labels.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/list-group.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/nav-divider.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/nav-vertical-align.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/opacity.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/pagination.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/panels.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/progress-bar.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/reset-filter.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/reset-text.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/resize.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/responsive-visibility.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/size.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/tab-focus.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/table-row.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/text-emphasis.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/text-overflow.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/vendor-prefixes.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/modals.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/navbar.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/navs.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/normalize.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/pager.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/pagination.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/panels.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/popovers.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/print.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/progress-bars.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/responsive-embed.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/responsive-utilities.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/scaffolding.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/tables.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/theme.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/thumbnails.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/tooltip.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/type.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/utilities.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/variables.less create mode 100644 lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/wells.less create mode 100644 lib/Font-Awesome/src/assets/less/site/algolia.less create mode 100644 lib/Font-Awesome/src/assets/less/site/bootstrap/alerts.less create mode 100644 lib/Font-Awesome/src/assets/less/site/bootstrap/modals.less create mode 100644 lib/Font-Awesome/src/thanks.html diff --git a/lib/Font-Awesome/CONTRIBUTING.md b/lib/Font-Awesome/CONTRIBUTING.md index a78162ed3..b3d4f878d 100644 --- a/lib/Font-Awesome/CONTRIBUTING.md +++ b/lib/Font-Awesome/CONTRIBUTING.md @@ -20,6 +20,19 @@ New icons mostly start as requests by the [Font Awesome community on GitHub](../ +## Suggesting icon keyword addition/removal + +Icon filters are maintained by the [Font Awesome community on GitHub](../../pulls?q=is%3Apr+label%3Adoc). + +If you feel that an icon + +* is missing keyword(s) +* contains invalid keyword(s) + +please send a [PR](https://help.github.com/articles/using-pull-requests/) to the `master` branch. + + + ## Reporting issues We only accept issues that are icon requests, bug reports, or feature requests. Bugs must be isolated and reproducible problems that we can fix within the Font Awesome core. Please read the following guidelines to ensure you are the paragon of bug reporting. @@ -33,7 +46,7 @@ We only accept issues that are icon requests, bug reports, or feature requests. ## Key branches -- `master` is the latest, deployed version (not to be used for pull requests) +- `master` is the latest, deployed version (use for pull request if they only affect the docs) - `gh-pages` is the hosted docs (not to be used for pull requests) - `*-wip` branches are the official work in progress branches for the next releases. All pull requests should be submitted against the appropriate branch diff --git a/lib/Font-Awesome/Gemfile b/lib/Font-Awesome/Gemfile index b87c4d824..0ca1cbfd5 100644 --- a/lib/Font-Awesome/Gemfile +++ b/lib/Font-Awesome/Gemfile @@ -3,3 +3,5 @@ source 'https://rubygems.org' gem 'jekyll', '~> 1.0' gem 'safe_yaml', '~> 1.0.4' gem 'sass', '~> 3.0' +gem 'less', '~> 2.5.0' +gem 'therubyracer' diff --git a/lib/Font-Awesome/Gemfile.lock b/lib/Font-Awesome/Gemfile.lock index 82bb3d496..9394f2dd5 100644 --- a/lib/Font-Awesome/Gemfile.lock +++ b/lib/Font-Awesome/Gemfile.lock @@ -7,8 +7,9 @@ GEM colorator (0.1) commander (4.1.6) highline (~> 1.6.11) + commonjs (0.2.7) fast-stemmer (1.0.2) - ffi (1.9.8) + ffi (1.9.6) highline (1.6.21) jekyll (1.5.1) classifier (~> 1.3) @@ -21,6 +22,9 @@ GEM redcarpet (~> 2.3.0) safe_yaml (~> 1.0) toml (~> 0.1.0) + less (2.5.1) + commonjs (~> 0.2.7) + libv8 (3.16.14.7) liquid (2.5.5) listen (1.3.1) rb-fsevent (>= 0.9.3) @@ -29,7 +33,7 @@ GEM maruku (0.7.0) parslet (1.5.0) blankslate (~> 2.0) - posix-spawn (0.3.10) + posix-spawn (0.3.9) pygments.rb (0.5.4) posix-spawn (~> 0.3.6) yajl-ruby (~> 1.1.0) @@ -39,8 +43,12 @@ GEM rb-kqueue (0.2.3) ffi (>= 0.5.0) redcarpet (2.3.0) + ref (1.0.5) safe_yaml (1.0.4) - sass (3.4.13) + sass (3.4.11) + therubyracer (0.12.1) + libv8 (~> 3.16.14.0) + ref toml (0.1.2) parslet (~> 1.5.0) yajl-ruby (1.1.0) @@ -50,5 +58,7 @@ PLATFORMS DEPENDENCIES jekyll (~> 1.0) + less (~> 2.5.0) safe_yaml (~> 1.0.4) sass (~> 3.0) + therubyracer diff --git a/lib/Font-Awesome/HELP-US-OUT.txt b/lib/Font-Awesome/HELP-US-OUT.txt new file mode 100644 index 000000000..cfd9d9f3c --- /dev/null +++ b/lib/Font-Awesome/HELP-US-OUT.txt @@ -0,0 +1,7 @@ +I hope you love Font Awesome. If you've found it useful, please do me a favor and check out my latest project, +Fonticons (https://fonticons.com). It makes it easy to put the perfect icons on your website. Choose from our awesome, +comprehensive icon sets or copy and paste your own. + +Please. Check it out. + +-Dave Gandy diff --git a/lib/Font-Awesome/README.md b/lib/Font-Awesome/README.md index 0fe866965..b7b4514bc 100644 --- a/lib/Font-Awesome/README.md +++ b/lib/Font-Awesome/README.md @@ -1,7 +1,7 @@ -#[Font Awesome v4.3.0](http://fontawesome.io) +#[Font Awesome v4.4.0](http://fontawesome.io) ###The iconic font and CSS framework -Font Awesome is a full suite of 519 pictographic icons for easy scalable vector graphics on websites, +Font Awesome is a full suite of 585 pictographic icons for easy scalable vector graphics on websites, created and maintained by [Dave Gandy](http://twitter.com/davegandy). Stay up to date with the latest release and announcements on Twitter: [@fontawesome](http://twitter.com/fontawesome). @@ -20,20 +20,21 @@ Get started at http://fontawesome.io! - Full details: http://fontawesome.io/license ##Changelog -- v3.0.0 - all icons redesigned from scratch, optimized for Bootstrap's 14px default -- v3.0.1 - much improved rendering in webkit, various bug fixes -- v3.0.2 - much improved rendering and alignment in IE7 -- v3.1.0 - Added 54 icons, icon stacking styles, flipping and rotating icons, removed Sass support -- [v3.1.1 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?milestone=4&page=1&state=closed) -- [v3.2.0 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?milestone=3&page=1&state=closed) -- [v3.2.1 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?milestone=5&page=1&state=closed) -- [v4.0.0 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?milestone=2&page=1&state=closed) -- [v4.0.1 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?milestone=7&page=1&state=closed) -- [v4.0.2 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?milestone=8&page=1&state=closed) -- [v4.0.3 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?milestone=9&page=1&state=closed) -- [v4.1.0 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?milestone=6&page=1&state=closed) -- [v4.2.0 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?milestone=12&page=1&state=closed) +- [v4.4.0 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?q=milestone%3A4.4.0+is%3Aclosed) - [v4.3.0 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?q=milestone%3A4.3.0+is%3Aclosed) +- [v4.2.0 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?milestone=12&page=1&state=closed) +- [v4.1.0 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?milestone=6&page=1&state=closed) +- [v4.0.3 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?milestone=9&page=1&state=closed) +- [v4.0.2 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?milestone=8&page=1&state=closed) +- [v4.0.1 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?milestone=7&page=1&state=closed) +- [v4.0.0 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?milestone=2&page=1&state=closed) +- [v3.2.1 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?milestone=5&page=1&state=closed) +- [v3.2.0 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?milestone=3&page=1&state=closed) +- [v3.1.1 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?milestone=4&page=1&state=closed) +- v3.1.0 - Added 54 icons, icon stacking styles, flipping and rotating icons, removed Sass support +- v3.0.2 - much improved rendering and alignment in IE7 +- v3.0.1 - much improved rendering in webkit, various bug fixes +- v3.0.0 - all icons redesigned from scratch, optimized for Bootstrap's 14px default ## Contributing @@ -73,6 +74,17 @@ to the `dependencies` in your `component.json`. ## Hacking on Font Awesome +**Before you can build the project**, you must first have the following installed: + +- [Ruby](https://www.ruby-lang.org/en/) +- Ruby Development Headers + - **Ubuntu:** `sudo apt-get install ruby-dev` *(Only if you're __NOT__ using `rbenv` or `rvm`)* + - **Windows:** [DevKit](http://rubyinstaller.org/) +- [Bundler](http://bundler.io/) (Run `gem install bundler` to install). +- [Node Package Manager (AKA NPM)](https://docs.npmjs.com/getting-started/installing-node) +- [Less](http://lesscss.org/) (Run `npm install -g less` to install). +- [Less Plugin: Clean CSS](https://github.com/less/less-plugin-clean-css) (Run `npm install -g less-plugin-clean-css` to install). + From the root of the repository, install the tools used to develop. $ bundle install diff --git a/lib/Font-Awesome/_config.yml b/lib/Font-Awesome/_config.yml index 86fcb0e6f..9b87a8594 100644 --- a/lib/Font-Awesome/_config.yml +++ b/lib/Font-Awesome/_config.yml @@ -19,9 +19,10 @@ icon_layout: icon.html # Relative to _layouts directory icon_destination: icon # Relative to destination fontawesome: - version: 4.3.0 - minor_version: 4.3 - doc_blob: v4.3.0 + version: 4.4.0 + minor_version: 4.4 + major_version: 4 + doc_blob: v4.4.0 url: http://fontawesome.io legacy_url: http://fortawesome.github.com/Font-Awesome/ blog_url: http://blog.fontawesome.io @@ -49,8 +50,11 @@ fontawesome: url: http://creativecommons.org/licenses/by/3.0/ bootstrap: - version: 3.2.0 + version: 3.3.5 url: http://getbootstrap.com jquery: - version: 1.11.1 + version: 1.11.3 + +jquery_validate: + version: 1.13.1 diff --git a/lib/Font-Awesome/bower.json b/lib/Font-Awesome/bower.json index 716617e01..9e2112659 100644 --- a/lib/Font-Awesome/bower.json +++ b/lib/Font-Awesome/bower.json @@ -1,15 +1,14 @@ { "name": "font-awesome", "description": "Font Awesome", - "version": "4.3.0", "keywords": [], "homepage": "http://fontawesome.io", "dependencies": {}, "devDependencies": {}, "license": ["OFL-1.1", "MIT", "CC-BY-3.0"], "main": [ - "./css/font-awesome.css", - "./fonts/*" + "less/font-awesome.less", + "scss/font-awesome.scss" ], "ignore": [ "*/.*", diff --git a/lib/Font-Awesome/component.json b/lib/Font-Awesome/component.json index dff5a1755..9612e4565 100644 --- a/lib/Font-Awesome/component.json +++ b/lib/Font-Awesome/component.json @@ -2,7 +2,7 @@ "name": "font-awesome", "repo": "FortAwesome/Font-Awesome", "description": "Font Awesome", - "version": "4.3.0", + "version": "4.4.0", "keywords": [], "dependencies": {}, "development": {}, @@ -15,6 +15,7 @@ "fonts/fontawesome-webfont.svg", "fonts/fontawesome-webfont.ttf", "fonts/fontawesome-webfont.woff", + "fonts/fontawesome-webfont.woff2", "fonts/FontAwesome.otf" ] } diff --git a/lib/Font-Awesome/css/font-awesome.css b/lib/Font-Awesome/css/font-awesome.css index 2dcdc2207..880eb8250 100644 --- a/lib/Font-Awesome/css/font-awesome.css +++ b/lib/Font-Awesome/css/font-awesome.css @@ -1,13 +1,13 @@ /*! - * Font Awesome 4.3.0 by @davegandy - http://fontawesome.io - @fontawesome + * Font Awesome 4.4.0 by @davegandy - http://fontawesome.io - @fontawesome * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) */ /* FONT PATH * -------------------------- */ @font-face { font-family: 'FontAwesome'; - src: url('../fonts/fontawesome-webfont.eot?v=4.3.0'); - src: url('../fonts/fontawesome-webfont.eot?#iefix&v=4.3.0') format('embedded-opentype'), url('../fonts/fontawesome-webfont.woff2?v=4.3.0') format('woff2'), url('../fonts/fontawesome-webfont.woff?v=4.3.0') format('woff'), url('../fonts/fontawesome-webfont.ttf?v=4.3.0') format('truetype'), url('../fonts/fontawesome-webfont.svg?v=4.3.0#fontawesomeregular') format('svg'); + src: url('../fonts/fontawesome-webfont.eot?v=4.4.0'); + src: url('../fonts/fontawesome-webfont.eot?#iefix&v=4.4.0') format('embedded-opentype'), url('../fonts/fontawesome-webfont.woff2?v=4.4.0') format('woff2'), url('../fonts/fontawesome-webfont.woff?v=4.4.0') format('woff'), url('../fonts/fontawesome-webfont.ttf?v=4.4.0') format('truetype'), url('../fonts/fontawesome-webfont.svg?v=4.4.0#fontawesomeregular') format('svg'); font-weight: normal; font-style: normal; } @@ -18,7 +18,6 @@ text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - transform: translate(0, 0); } /* makes the font 33% larger relative to the icon container */ .fa-lg { @@ -65,6 +64,19 @@ border: solid 0.08em #eeeeee; border-radius: .1em; } +.fa-pull-left { + float: left; +} +.fa-pull-right { + float: right; +} +.fa.fa-pull-left { + margin-right: .3em; +} +.fa.fa-pull-right { + margin-left: .3em; +} +/* Deprecated as of 4.4.0 */ .pull-right { float: right; } @@ -628,6 +640,7 @@ .fa-credit-card:before { content: "\f09d"; } +.fa-feed:before, .fa-rss:before { content: "\f09e"; } @@ -1509,6 +1522,8 @@ .fa-git:before { content: "\f1d3"; } +.fa-y-combinator-square:before, +.fa-yc-square:before, .fa-hacker-news:before { content: "\f1d4"; } @@ -1533,7 +1548,6 @@ .fa-history:before { content: "\f1da"; } -.fa-genderless:before, .fa-circle-thin:before { content: "\f1db"; } @@ -1738,6 +1752,7 @@ .fa-mercury:before { content: "\f223"; } +.fa-intersex:before, .fa-transgender:before { content: "\f224"; } @@ -1765,6 +1780,9 @@ .fa-neuter:before { content: "\f22c"; } +.fa-genderless:before { + content: "\f22d"; +} .fa-facebook-official:before { content: "\f230"; } @@ -1799,3 +1817,210 @@ .fa-medium:before { content: "\f23a"; } +.fa-yc:before, +.fa-y-combinator:before { + content: "\f23b"; +} +.fa-optin-monster:before { + content: "\f23c"; +} +.fa-opencart:before { + content: "\f23d"; +} +.fa-expeditedssl:before { + content: "\f23e"; +} +.fa-battery-4:before, +.fa-battery-full:before { + content: "\f240"; +} +.fa-battery-3:before, +.fa-battery-three-quarters:before { + content: "\f241"; +} +.fa-battery-2:before, +.fa-battery-half:before { + content: "\f242"; +} +.fa-battery-1:before, +.fa-battery-quarter:before { + content: "\f243"; +} +.fa-battery-0:before, +.fa-battery-empty:before { + content: "\f244"; +} +.fa-mouse-pointer:before { + content: "\f245"; +} +.fa-i-cursor:before { + content: "\f246"; +} +.fa-object-group:before { + content: "\f247"; +} +.fa-object-ungroup:before { + content: "\f248"; +} +.fa-sticky-note:before { + content: "\f249"; +} +.fa-sticky-note-o:before { + content: "\f24a"; +} +.fa-cc-jcb:before { + content: "\f24b"; +} +.fa-cc-diners-club:before { + content: "\f24c"; +} +.fa-clone:before { + content: "\f24d"; +} +.fa-balance-scale:before { + content: "\f24e"; +} +.fa-hourglass-o:before { + content: "\f250"; +} +.fa-hourglass-1:before, +.fa-hourglass-start:before { + content: "\f251"; +} +.fa-hourglass-2:before, +.fa-hourglass-half:before { + content: "\f252"; +} +.fa-hourglass-3:before, +.fa-hourglass-end:before { + content: "\f253"; +} +.fa-hourglass:before { + content: "\f254"; +} +.fa-hand-grab-o:before, +.fa-hand-rock-o:before { + content: "\f255"; +} +.fa-hand-stop-o:before, +.fa-hand-paper-o:before { + content: "\f256"; +} +.fa-hand-scissors-o:before { + content: "\f257"; +} +.fa-hand-lizard-o:before { + content: "\f258"; +} +.fa-hand-spock-o:before { + content: "\f259"; +} +.fa-hand-pointer-o:before { + content: "\f25a"; +} +.fa-hand-peace-o:before { + content: "\f25b"; +} +.fa-trademark:before { + content: "\f25c"; +} +.fa-registered:before { + content: "\f25d"; +} +.fa-creative-commons:before { + content: "\f25e"; +} +.fa-gg:before { + content: "\f260"; +} +.fa-gg-circle:before { + content: "\f261"; +} +.fa-tripadvisor:before { + content: "\f262"; +} +.fa-odnoklassniki:before { + content: "\f263"; +} +.fa-odnoklassniki-square:before { + content: "\f264"; +} +.fa-get-pocket:before { + content: "\f265"; +} +.fa-wikipedia-w:before { + content: "\f266"; +} +.fa-safari:before { + content: "\f267"; +} +.fa-chrome:before { + content: "\f268"; +} +.fa-firefox:before { + content: "\f269"; +} +.fa-opera:before { + content: "\f26a"; +} +.fa-internet-explorer:before { + content: "\f26b"; +} +.fa-tv:before, +.fa-television:before { + content: "\f26c"; +} +.fa-contao:before { + content: "\f26d"; +} +.fa-500px:before { + content: "\f26e"; +} +.fa-amazon:before { + content: "\f270"; +} +.fa-calendar-plus-o:before { + content: "\f271"; +} +.fa-calendar-minus-o:before { + content: "\f272"; +} +.fa-calendar-times-o:before { + content: "\f273"; +} +.fa-calendar-check-o:before { + content: "\f274"; +} +.fa-industry:before { + content: "\f275"; +} +.fa-map-pin:before { + content: "\f276"; +} +.fa-map-signs:before { + content: "\f277"; +} +.fa-map-o:before { + content: "\f278"; +} +.fa-map:before { + content: "\f279"; +} +.fa-commenting:before { + content: "\f27a"; +} +.fa-commenting-o:before { + content: "\f27b"; +} +.fa-houzz:before { + content: "\f27c"; +} +.fa-vimeo:before { + content: "\f27d"; +} +.fa-black-tie:before { + content: "\f27e"; +} +.fa-fonticons:before { + content: "\f280"; +} diff --git a/lib/Font-Awesome/css/font-awesome.min.css b/lib/Font-Awesome/css/font-awesome.min.css index 24fcc04c4..ee4e9782b 100644 --- a/lib/Font-Awesome/css/font-awesome.min.css +++ b/lib/Font-Awesome/css/font-awesome.min.css @@ -1,4 +1,4 @@ /*! - * Font Awesome 4.3.0 by @davegandy - http://fontawesome.io - @fontawesome + * Font Awesome 4.4.0 by @davegandy - http://fontawesome.io - @fontawesome * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) - */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.3.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.3.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.3.0') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.3.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.3.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.3.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;transform:translate(0, 0)}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-genderless:before,.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"} \ No newline at end of file + */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.4.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.4.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.4.0') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.4.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.4.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.4.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-intersex:before,.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-genderless:before{content:"\f22d"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.fa-yc:before,.fa-y-combinator:before{content:"\f23b"}.fa-optin-monster:before{content:"\f23c"}.fa-opencart:before{content:"\f23d"}.fa-expeditedssl:before{content:"\f23e"}.fa-battery-4:before,.fa-battery-full:before{content:"\f240"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-battery-2:before,.fa-battery-half:before{content:"\f242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-mouse-pointer:before{content:"\f245"}.fa-i-cursor:before{content:"\f246"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-sticky-note:before{content:"\f249"}.fa-sticky-note-o:before{content:"\f24a"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-diners-club:before{content:"\f24c"}.fa-clone:before{content:"\f24d"}.fa-balance-scale:before{content:"\f24e"}.fa-hourglass-o:before{content:"\f250"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-hourglass:before{content:"\f254"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255"}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:"\f256"}.fa-hand-scissors-o:before{content:"\f257"}.fa-hand-lizard-o:before{content:"\f258"}.fa-hand-spock-o:before{content:"\f259"}.fa-hand-pointer-o:before{content:"\f25a"}.fa-hand-peace-o:before{content:"\f25b"}.fa-trademark:before{content:"\f25c"}.fa-registered:before{content:"\f25d"}.fa-creative-commons:before{content:"\f25e"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-tripadvisor:before{content:"\f262"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-get-pocket:before{content:"\f265"}.fa-wikipedia-w:before{content:"\f266"}.fa-safari:before{content:"\f267"}.fa-chrome:before{content:"\f268"}.fa-firefox:before{content:"\f269"}.fa-opera:before{content:"\f26a"}.fa-internet-explorer:before{content:"\f26b"}.fa-tv:before,.fa-television:before{content:"\f26c"}.fa-contao:before{content:"\f26d"}.fa-500px:before{content:"\f26e"}.fa-amazon:before{content:"\f270"}.fa-calendar-plus-o:before{content:"\f271"}.fa-calendar-minus-o:before{content:"\f272"}.fa-calendar-times-o:before{content:"\f273"}.fa-calendar-check-o:before{content:"\f274"}.fa-industry:before{content:"\f275"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-map-o:before{content:"\f278"}.fa-map:before{content:"\f279"}.fa-commenting:before{content:"\f27a"}.fa-commenting-o:before{content:"\f27b"}.fa-houzz:before{content:"\f27c"}.fa-vimeo:before{content:"\f27d"}.fa-black-tie:before{content:"\f27e"}.fa-fonticons:before{content:"\f280"} diff --git a/lib/Font-Awesome/fonts/FontAwesome.otf b/lib/Font-Awesome/fonts/FontAwesome.otf index f7936cc1e789eea5438d576d6b12de20191da09d..681bdd4d4c8dddbaeb4d4f2a1f58c38cad92afe0 100644 GIT binary patch delta 44736 zcma&O2YeI9);2yXSt~P(CEJpWu|1MaF}({+$8?AZErQT{Hyr`7!N?d>f@$^&Y+5j; zcL)w4AtWZ3R8m2yB)O@ikjgcTq?MijGqTA|-tYas-{0%i?#|B4&d!`UocI(ZAGKCxIg zdpK?pKX!TH)CIj~rap1sfCo$=B*L+H(K0t0g1?yG@sk{WZiFOXGR_J=G*2^&7YV*R?5Ron5VvP zNR&q6_tA^pA{)yQq8S%wn3ALj884^ioA;&2xi~{Ib_){Gr+7o`A}d~y$ZGHC#2Aqx zu0&38G^h)r)6^ZNi2jj&GE$Tg`Ni>n?jm;tc2V+S-4CDhS2^`sokX=XI%2A*rM5NU z8pAC?r-}61d+86KgqmlH`|{47O|sy6G)vYDDq=2&x_Il*i@^wVMj>y*$`8pzBN95~>d>xUmBl2}b zzD~&33Hdr9Unk`2gnXTluM_fhLcUJO*Qv{__MO^d_aI|hdz>I+8ZxFKV;VB1A!8ac zrlG>lsIW8gbw-7qk*_oIbw<9<$k!S9IwN0a9nijW+nPhWu9G{pZI8VJc4tjm$C^VYq@-c*jJ?a`PVL%aZ-*VZ+aY&5 zr>ZpS=GmmfjG`otG$Kt&52BJ{vX{IjDUw;TNcE&-sgcxNYArdX&Qf=&pEO7sBCV44 zN(ZIW(s}8UbXB^hi`LcGF{|`if*WHhqG=fj(95X{~Rs@1*ah@1^gj&(P1)FVmmYpVdF3|4jdl{(C)- zh>DmSu`FU`#Eyu45w|10jkp_eFXDkA$Ir`Wym&o3^xq#8Y*RjJW_sK zo+Qtd=gCXt<#Lw1M$VJ>%iqX;`A=hnv5wJc>~8F59BLeEoMc>R%<>rXjRnT-#+}A8 z;}^znB57o7WL#uoA5|viU5M`9ITv?;+Q1&PXl*7si<(%@4@{97IuD&j<+q7=ix*2sR z)SX#(Ufm^iv+Ay`TUd8*-D7o6*S%Qx`MMQ#U#Wip5QNKo2nsgo$H91U;OwCNKP5n&c zOqr%9OgW}}Q-NuRX_x7gslxODX8m2$pXNH|D6hIP-M#eDe~_;??GL z=1rKpr_C>#U%_Pk*!;QqJ9A~UAv!KPF}h)Nhv?qXgQJH^! zqc=rwkM`_}-XC2SeLVV1^wZJLMqiD-9{q0gN6~kp@5e;MSYqO05@H-Njbhrzq{j@6 znGiE0WT&ARcM=d z6dTES1s5lF?ru!El@~H@)z7Cqir$smu%ux6Q6`6E-d`)_W3)KCh99lJ*1a?&C$x~W za&od98GH=8VeCQeEkLbWe_pDM;c<43AC3#ZoS+z+Fr@>tE3eWd!<0N$ylsM1&+{o$ z)oq1E4t|T@GAK6gsRzhXA4c5P-!#`Nu!JB^moQ`F(N8u=`0sR(%^ETx)Nwp4IC zMb>tB&yf^ac|SDTXhIVdxd~pcIaU1KHN1MLyCSz|N_%?4#gv}7-IZxBqcVUxl)hP0 zse&%iToafg_rTsBCDWPT8<)=ba%$7=YZtNI7f0TS@%#MYL8RKbwJ}xSZo-_8P$iva zv=hIYZ#v_?Zm6ptQ*P3scuW(jxl)-jfI0Aru~eJLC-QZ_Hblux@)^;d;BWZ_l26iuz8e!;`_3t?Ws*l`5~W5aZ{V zpBW0*=WSn?n78hI>Yo*wRY;XGTJ6e1_nc%wm%MM!>g<_p6q?qMDZ5#fFO>#-tEsY* zj=X+TX+h^KJbv~wc6{L+JGzc3wY9Cw+qix`TD?DKca~jq)r_^~^1MUCw4<^MR2h9~ zN`+!XnTAaBDiu>MjkYV>Xp%;Z{a+dJK3ctcPqy*~hLy-uXvL*V73g~O+#052;$6Fd z-Xgl7*W02ajxSXDjU3reS%X(UPhY1>JIXP-O2C^GQEGdWXF#B$m{*4u;PPLq{hx&7=`y=dF6eFV%)>ftvOlt47>w+_eN)` z+@|)B%kL^?KTt==6>_bjLF;&`_GvzZ-D2CHT2q``GUM6FPtW}#Qb`QWEeOpG%}r3e z)Lv|wDkXT@VqWBSrSoZPhEW}$nRy$nPr3bQ`R*$(@bPTu@a5Ad+PSN{HjKw=GZH^x zIa_kJtafPa`lM>@wLS@aEwcxG@+Z_`>cV)rk-Mlem->ANn1WZcqE=&fs#LJCWB)+} z{+jWw^f3P{|13jc;dZZ@pj>3!W$RCsQWo;Q$3oVcuJ?QAF(sF-c$O+zyL0y2Z*&p^ zTT?5^GQu~t6W9Mkd)r$IEd?&*d|B`>112$2hO;mzD?xs~%IhSb- zwf>Ic71N}i&c~@TiG^If88VE}qg;=v!6!aN6=R26eZR4T9_@oOK2b@E$W^kQTC~Hx zw*IoUtK3TxYMLl>OtdMW95r=!KaZkr;_av=_()+s=1ZcObjl{`x87vR>x^$wxRIwQ zw)-8wO0kEmGH-%GxAIwn=ke_<)3}1#GrH0nGC#|+c^TT%4P_&`QN>W~SyhyssQgN2 z(2&peHC1G-gJ#3l!J%aDS-nr;I+kA5bp@MGH?gX&&ww5@?{dn$Tw#iM9-hTpQ^ixf zH-BHE648e#?~iz;zg+M`Wzbx^;J8(0W~8_#VR{rF!nxkD@- zll&J}|LRz-$Na{~qg};Cd-o+MPI_1ITe(%4+j;Vg8IyC@tnqArBJvhf(^{u`(rK0J zBN}jlA915#F^^%+;epEGr56hhAFlsAQ|2+#76t~{q3^A4Hn4AQ_3fZ&e-_NAdS%0g z&6_qjLT=4#Si2!V*OLHAkjZxJ*s^Vh-S6gJ!_FN=yNVN%3>Cb9Dzm_aiQ@lWo4{A| z3A~rg$MNEXnNnkqaZ}O8!u5q!;{xO2mmXf3Hzz^am#BKTZc`m)JNK3yNl+%Ex8jC^ zfnzXipn|(Jo1{OU!cktUwqN|Uraf{`;Oyj&A9n(aH5;qE^Ifo zn;b`e6WcCqHx+J0zigqh(uwlAthn(ksddarD!O(!Qwq3SkhH#dleLgfc=h1X_DO+1Ia`wksVIGTNEsn@Pe z`be9?5BQ~opjQq_+7#`8HmR50gqO7{MlGkGA!kFLCnw<;UAtqgy57FAu<*&E#BJLO zwrq3o%(o3nMk?b8vZiW9io8wCG;kbw&O*#vobVw+Qd?g`Ynow9ZJ<~))(<*m_dsnoak9a|20#-=xq3z ziN5&mJKlul(E7@;9E1D03eT&Fyfts}`I#GzqV0v-wr`Cr-L?DRp#;-FOcTxdE>((m zZrQ3j3b&8gvORH=F*k3+hIMP#dFqD@p(BQN{?Ck<$6rFDNTG@zgc7jw$yD=l?>VYj zl|+a|eunV^#nuWhW8`3er@56X-l8I}Lml5P*~2@0)@I{2hc|c2s&$^xJ>oa4%iFMa z^V-dM+w+Se3zTPsn!>v=)0*Oa>-Q$^-B(yr>`>OMDOg#uMv?ifY%PLEYZDT+N5G`I zX#2FMcs;EvpU-y_O!DOh0?Q!s$J z08U)Et*E}DS$kvl@iN+>uToM{a9~Y|ATX<5$u3$|>`{_YgV(R7wr}GBXZE6Jb7so+WN#335sKB`DmGY zu|pZgGC+ZbtgN+5mnJOTxpaRP*gezS3U9}FQ`{*l+kN^>0;swm$(XBGxKGAoZ9Ql@ z^=Lk02i6^IY&8wKjL`6k3JNzDIXe0`@jv+kLrF==zWoU%4J}gcfA!UUr2v1*lI6>n zELnc=2=B%jwr)obE?;6-M!eT=p?iHUw3-vfwfoC998bLY%6nkFZm=@VC-h{^9kOB| z{`;Ov`<}FbDTPJbRd0fF_%ImgQYGc9j`x*Dm;-UjRQuAED_3MKt!xv&tE6~$$*#!K z!|K%zEj&;f?<<;9&dV?I{=m3X_7>&mDNhz{Dq3HZUy{EkZ@1>)PsD4-!}1R5VHaw; z`!m?!oCA4>58D-VuO33joSLec9aTQQ3R8B!;9#P0fBzQ*=k*WZj`uiwnJ4R$41E+n z*TV!2D!d#G5fig{oR;WjuD2O#1JkAT?r)-g4k+2s~AI2o;4`XA=nQZ><48^ z5ABao^^Al9qc)9S=)%(!*M8UO$Dm4qj$k`#btp$r54fRLbT^KxFUl^ey;CyxH^!dOzEA&PD|QnvTdPKOe4o*QS$ zO7{9y9*^Km?U+*KGin`_e%D9dR7%nPiiUnwcq`iWjv}|A-$Qw=(Z9GA`WK((p#d+n zUC>^O1m0peXD#p9&ncy1;@sfYq=*V`t*5AkyNVpU_IdXg?~DBKnzC-as%~+-(_0}ON1qqouedd0NXXtxlgvm}-JsVlyi8Xr|=Mo0~9qHyGR{ zh+Qy7h#-(-5Of5KN%61quTv5Wj9lgsS1#RlfUjFHOZY@~115r8Yn>@8GaXvCadm$F zYABJ*%1(Q7&Y)8?c{Z12CE&ARiUYECN{dxr&vaFm*Jabxs3V2r0 zB7f29apxHRqLQe^YXn<78Z`mK-GD#NT?#n)I22yGc3BqqNE0m;gDNJVmHYIH)>yme z){Z2s+1f&hNYa{XYEs09vSP=0!}>Np2`c0hp;to?T9ptqJfYC-Rj;Kr^^Dcc25=3W zyd@!R2?3P)E0OYvw1G&Qh_snVTZpucNIQshm`F#7^aIf)5nVf?dz9$1TxSwDgT!qlaTiJ4D`&^!->6wIBdk> zB98kcc{oX4N0PrIDFaB#dD6f}8n{V=Pf3FxNdt{ETtph#NuyUuV>@YlnWSDNO$L%C z)uicl(rhMa_7Z7sCe4SD<^`mMrw3_qnY8$TwCqA!t|BdqNy|@2t0kn>TGFbLv_3%E zQqr~^X~#(W4AOowY5ywepeG$xkq$o)XB*<2M>GlQbK819@M|#{RJzpoiJ|gMwcu4P0NuTzl&sx&w9n!ZB z8JJB5-X()l$e;;i&`C154H?{y4DLV%cO-*ZdSLLOZ~hQ^YipORtY$gpW- z*a|Z28X10;jChkg#>it?#3d8gdNQgr8TADjeTh82os6kZ#w3$5O~{x>$e6ig%n>r? zJn@WqmW+9kjLjfpuamLAl5roA@sr8;95VhpGU0JD;bk&$0h#y_nRJ6pu1_XUBa=^& zDdWgg1DQIIOg%`Z{z9e=Ak)^6=}pM=7s-stWXAJkW`8pC2$}g7nR%bgN+q+pkXZxC ztWjjvQZnlpnRTAbdXCH{WcGA2+q0X@{+`VKoy?KR96OnFnap{a%xz2NYGhtFGVfzD z?^81GGm@D~G8dD~jby%#%>R}wNGA*RWTBlb+(;Hyl0`XW(d%S!OS1S4vg8I?@+Vo^ zlPoPFOTQ({+7WjYaX&`fUyN9i03ZJJx$j3Bx~Oyd40&bQ6#?u$zM+L-yr#alJ!oqelA&mmaKoBtiMAx948y+ z5YLl`Nx?5<%T}^Ajcom#Y@0&1-6h*EknQi19fTArq$r9MO(R8@h^iy%P@?W8>bJyu zns|RCJHIA-EM%{f?A6G=f06w!frAIXH)u-6Mw2J>+N`a&#p*dW{^rNRF%IgoT{!Lry+TPBkZ|0_1ciIn$V& ztw+xONY1&*`Dk*!H#z?*xiFSoTtdqCkV{7L?7zw7(d2TFJU5IyZzRtTAF4r&n4HN^N?4Ykyl?Luk|Ibog}aQKwf{F zyrGge{zKk8LT)(8jSzY37J2&=c_)&*^9FhEHn|y3Zp|mRmJnYT@>$!!O@eVu%^j(p}PpU);=3?W}UL%uYVFP|Y_?IvG0 zC7y3gtd% zk_TTAUP1i3i2qL#=uU$5N$^#o?Il&yNp%lWeU|)rP$H6~3rhNtQUsAA{*(;ml5vV; z{7s5{TdGq>sxwcbkrMTMBPju?ZcvKKkxYq_X|ZJ5FPZB~=I)aDq7uSk1U$VU+#SM_^rAhU2rFx%A@kS}WpA>&eiho{m zG?N_Lq~z&R@)arhrj-1Hlw2*P)R9ugODS(j4bFR{hIgb!iBh8#QsZ?}YC|b?k<=tX zYBE4-vPx=lS!(iy)U>(Otb^1{lUhuH@hr6}kXmn++WacDJt4L0BDFgywU3nAFP5Aw zBO52Gk}P$(Ep??**UzMGcB$JrsryN(M~T$aBK2%8^?X9=`Ly&% z&yS>DO{HG@rSw5k`erHpH>r0UsrNdmPlD8^r_@&`^^K7F%2MA*sV|lK)|L92q`uKo z-&m=yRq7ij^^KSMCP;mgq`r2wU(X3fV=2?D?=kgI&(1o&K>f03g7X5fnm{?AhLF?m zu{D0$_*o zMOY5dLjrXJbqxm&lpQ~wV1mYWKy8tp(&iT$7;6l8`C3Eh%rDfGT)@3S7*P6cP>6f6 zFi2_oj-FN*~j%pttMNPBtOwDTJ z9a#z0^7&$IqMGjrM1+2Y3ceRMFdlN6=})s@l&A z?RkFXL#m}FA<52owN}l=X#;xr@Xr1F9UK`0a{_Y=`}glWd^kZ(>dQQ}=YOwBdtPk( zdDK)}Q8)ofsPiB7Arlu_|Nem53d6*7j6v=6TE7f>`8rtBP~>afJ(^o{8-?3v_yh*C z-YxH8cKCl_=mPfygmkJGd=HNQ5@fi7P}l;7r^xR^)`xjOv*IB&58_kR%DxTiyh*jQ zngC2yN52L$dsBZm{tN%b-_2fy0k;X9v;T+@{c#mGi3FY7O{J&^G(cdN-W?&@?c)?v z=N`~+oP=-^bm64hbq~Ix3Y>xP-=U^CH0TXjGwH?Be(j|J!hEXPZZf|&P;OfXdlNv; ze-Bozscrn?MH_&uY*>8kiX%8EXssS(ta1ilpG}ju;pzJMs(C;{GVt~l!bUCymd}^@ zpR?^Md9rlPE^QHiB;MaLkExFg7}WXz<=t5_c!6vJbm%V!xab6Y7_putLi<*Sre=Ao^{g%c!e{6Cy; zybaR*zBF`&$_KWwzJsjXWh^OHi+4D*d;ZciI!Em~Xsmt+y{7IO)H}5i!zk990YYMT zDg1%9cwQfN++&|=V-rK&v|qGeLfv?8wQ5ky#=lcuk4KMn{^+peYIe=e6VbTw^bJ}s z$?(13ZQGZ#hZm`%2RAYuVZhZ~9pQv9T5?}hHw|tiy{VoVJlL~}iV{4`JFMsps~%)i z*%0omhz2!3+fdMU977QC@W)zZtzo9{be$BS03Qgyml2H0_kZxx(4U|s7x;`z&wU_V zy!vkx9xo&JwSbuDn+aHuZ`LO9N!n&?ldx^Z?ab>8Y(hp0&<%6g#KY5`cH5IQQ`p6t z6mie^blKtZ=LABYF-bl5NP7v=;*pkh0O+8EOMhC8%V=H)lg8%~sF*r9qrJ3FU7g`j zW-wFePfSIteujEC!x?Ex#>ILnE_&-!sF zzXlxa&rM;7_~AUM2P(Jm9ZU{dBg6sH2+{*5)!u50&2Is7wiv;uRU0zGhXhQk=A_E1 zd2Lnb&H(%-%WLWoGuWm<{>YZP+$yIAtPwR=@vzxL$SYft1pY2tLVO`jd z8nuu@iY-Jd<9HjYE*jcRm%`N3LvQ!K!8&W+8yE{uK{3@QMQlkj2j?DMHSj5?qnoMu%nh|iWnLSD=sUZB%uG1d53E8Rh=c6uzisgpf@ zmJg40_RzWuiJ<(nv2l;Ypd3-zBR89W?i);!iklsWcT>-tW1;T+1W$y$-K zd`o?=wqGk-1kqLkEkyT~xo%U_(^0ux^%wDyAjmHsc5=u4j zEN{qpr{=jSw+og-*#&fig00vx1~Rg>fo6FTGYzf}*A8f5s(aMycAU;d&cy zqdq#?k&wbnRURRoy^v`EP-Ld?r}4h*6SZJ;OUpM8@S*eRFi0ZaGu+ zkGG4~&H)Y1;^%mOq0P-@YPZKHOO4dMk2jTusMjCwBh6QhV-QTGHXV~}X~ya{(9|J} zuMKRp@dyf`sg55rJ$eN*2pz%-v1+YnshF?6Go}HG{4vIo7|&jK0bw3HpWIdd$({M$ zyzP??!~{N)OUH)K6VThOql zc{$y};L>w|G`vD)04ZF7ANfT=uSlus4t;R8fQ$=}jf3y8egH?q;iU(>XA?wDHF{ig&m2qyP#@gh-d8}XGU7<8 ztzZie6UNip9PdM$7WH1%j6kg!YV3x`;=vKLzHo&aYFwdJt807?t;(*-77o^cIM#TBxwwNIs$+bd2gj=HKsIt}T{R@b6?-gn zEIx!E(KQ^2TTnQVZ2+_JfmiwPj0)ZtL#TP>X(D{a$P@5h+$)cVTZns&58VR38=%8~ z7OL{Xv3dL~>>R$3!E@kC5_#reHstu*+p_bs0lv3uXYhEk^Evp~`{Vn^6w-W8v4aoR z26M5UXKIrPt&QK%z$IQn)d>?CKavDxMqA-;>2JZ4=$&?O0KxX zHD@B=C*-|r?8m_WHEYmn`w)H}BVVNsoY>H_iD{BiYjjCOT1?@MBDuuDn-Gc&cMOtv zqf3#R1PxR&@tI58gw|d?AuIM1>8FTIM*dht^}9 zmKmuvMBaw-3tA>}^x&D}kb?Re8hPdmyoZPPc!6i4*m!!41wZ#s6afYrd|~lnhnRuY z*HU>Zf(`0xNESE3=c!sM0uFdMNfWUL94UxC2p1CBaEfvUp2;(y@m>SZR0FdGg*E;| zP|Y#zSiIJRH_1t$^&2-1(+mulE!5xD-_^iVI*T&u_DN&SQyC0~o_5m>s7ZR56?{_L zsIGKgncE(4R3-B#sOp^Dzx_5g?~vQhpVOWh#`-kZU_n}kVs-Bvh*bFR^RyhI=!=YvKO6DfcowsJ0+fjuroISH9`?9j{nfmMG z2A=QPp+k-jKQxpb+I{Lwf+@KoNsa?!$bbMrJ?XfyY~F5BOOD&^5T=_U;Hrfes$524 z$r;Mr4|6PY^iHpBRL!dx+;~peA+#ot%)zr^2h9_{a8Tl88Upv0&Zz}cG6ug0q3IV~ zYz_@<^t(MQa4=B0j+si540piZ{l0Z9urY`bAd$ffpZY(2bsQZEhg~b?P$Q=9(2Zm2 zuBk1gVd~3MTQuMUA@_#B-|9E(5v?{HFny;cmZ>0PWXCYqu0g^ zg6GYp>WygwQcpwf+TcO&r5)FXXdfhMA85z<5RL=~A4K6Zf?I>1RMVz6&^2f3_~}!0 zgQ$9SdVO*A@${Q@fm?WaM@+rd(E2aUcwGmHojWsCHyo{(kQNncHu@@dkv;U3oFfxI{zNy9iRm$uaskdg&~iMFXva z7j3*js#fm{Z9t;t?g-^^R=iZGzA~$kTn?ORllFjhUQSg=)vv%#~@K40lF+*S}^VK()th=Sz*4PWq_t5 zxI3uVt1qUfY(<;YjfHm2$z6t`^=lD=74ku>yC5Oek#icf7yuhKkItM$@|bM=RT^Le^2FR;lbmlsfti`xepDM@1yGT za~qGXiDvnS?o#bVVB7yiUlF$5cv^}W2l5R=Myv4(8l+i`f2lCMt`MFC>exKikW0Y1 zf?foc!H)9E=+}G*T9^j7fc!1T0I1pXiidp8{Kv}~AI@VKG&#TbE*fvu2c4jnW>nx{ zd^O#`hC=CeYjI;~wKsIr#;r3z%+SGZ+CD&20&z(3L)TKLW+pz0pj)Wh@)YI}qc8)6 zCkwa;tjiU^;OYZDvRdDO$8J0hcKqzq*fTj^oGjJxA=GBl*XUC*V?j zGjo(45SE%c-=RQL^wtYn!-&rC`J<%9eIf0)MD!K9JkVLxdQN+nXNBtX5!8O1Ab8YRx`tFe zy)aFWQtEdLul;rF%%Vr@%wmQDqX1r2{o+TY5_Ra}xLzGuSd)eJe%E$>#)hSKtsJoH zt#2IQ^&4Q@`Q*!M-aR&kIW%955m1}r2s-`cyQq3-@%kp{X1m|DQuH*ijDS-Ezv-++ z^R`;N-S0IDA{Df(j#yG3m_X(dyC;lp2<;hx*ZxWYDfxIK%yI-^SGk73)PzYQbj;dV z%YItFs^qHVhq0D{WQY``@nzsir~{b;)?EU_sceawq5RuIIBU#K@8KDHi%#WU#E+kmg*&s2rvi6ctQIOS$q3tHWHmW6uBy%+Zz)mcoz&i$@^u-Fmm^Pv`GGbYTDH*C(huS2{dk1uh#$Ff1fo!D9j*s&ZZjB^pPw7T|LNF!Hvd zH!zZ6NF01Ij8rAbBJK^rC=U&}?O`Jik?w&C&1wSzE~Jthv7qR?al-Vr!4C9So@Sv+ z*n~;JWP#Iox!UH5I;LY_<+AAl=mFSaPqqIOFDE||Humrvp*aC~Y3Y!40`LNxLcKnt z+9)fd87#<%iU(9!8dky6tTsf{!!hF2T(CynA!}mDjh=FCR!g!v>rPSiW>%B>$3Tv^ zZ{tDbi0*nX*a#{?UVeVwTU3qB?khd2j?QjDA27sU_+4k&oQvDD^-@|5L>Bl1Y6?u0hI!ES(o#neGan& zuR%rIU7yfhdK95Kcx#p{$H7g=(!rmdDs@6E_h~))7;8s)ACZ0?WMy@Xn zZI<~6ZG^#60n=esc7i3H&tz@e8W8IPyuZ5bosZa^I~->Sn}Bsuge=+lB2GvXrTm-4 zDuqW`jkV(q?&jM8cpAVqOK97+8e9gbm=9t3B095ZFQPN~2tL9P+RQVl2Zc3Ug&)AE z@GsnHD-0Msf^Tn3VdmJv)xacLB}}5CVvj=PssQ@JO%a!-~NFOEbOres15029s$Z-rw1#)qANy<>S0wRgbD3@ikh!+kPM7 z2C9Fj^&LFlGCZ~yH}e5+I(D5ZE2s#K#MFUH&D^p?P41G9sszA#%zsBB#XNcuiffA#nh1afC68 z2tKZbH^k>}7eV^*Jp6}5hMNXcX?O$7_{E0#bS$I_04aFyRM*C? zy0KKu|SjtduZX7CgR8uw`^EAK;oLr%3KcZQ9OReWc`;m)#o_`UG8!|?? zXH2&9VLi1BMA6O*FK$@9CC8z)?3bdo(FXo~aYJ$dKxvYJe`5<31kM=z4R07P!q|a6 zb|chK4i!|LF=$G9MRT5#xQ)p?rQ&CO1qj;YjIr7784muL(c&A;a6P*B{8_Ucp_ZYRhFP=b_a2>46~<#Nr~Tzxc@5|a zJ_v@bE-q-EkU`RVIF7ZjO9J%>w=oPV^@S~oo-(Ro`HkSjV4z_}3{}TgvA{R;f?Ye! zPa7`G>~mstVzrY?=%4gn!of9z1}l?+O@Q;c0Hp#{ul<2e1ZLb58ePPGNcfPj&G=dB z6kJ`#!XjWjkbna7e0VGVuX_R4fxqWf-COtRJ_8Hi*18j{yzU z?_RxMD7msFy{9k>A-`a)Bn8r)IIVy_a&g7BVY-xbNT&3U1h$5#YXSZFtyh^Iv&6Xo zW=6ygs@~br%wgMs!GJ=<7?WO*RZ&3%xi|g(om=0S=EX_``?8t2GoI; zK-$2=0_I@3%+E5OuHGz6b)_RkSOwMIju;u3A+yJ?T)Na@xvY)T#u;3$o!$E-@JX!q zCp)h?Zpbxa&02H3`pMc49MC_u!s2PhcR-{K=R5Qqi@#h&PsRQl!Ovda6x$X!X@_#} z=W2wi>UfM=qE^H=VHv=b{H~S^rj6x%0~*BPy{1%M>~%;_syn=irq0x}C~s+I!mwl0 z&O!-$&f7@YNfRt?E%mOAA60+w&QvDRo7cnd1Q-3ZVSUh$4hG310!G4*Uio zC`#6VuzUifBQ$~BR$@)YczT}(e2b{*KB&>QfK~r_!|xN=v=2+F#KI@YkbEIm!2g8r z5ISV_p9RR`_kq~~nQ-}C=V-MsO@vPoxJ2@3bTaNu2S4P_xKdDUz>3EKV@CW!s1iX9 z*6K<*9NZcn?b)@uj~Md%)bCm(s9^!CIYqk=mAQajWa{c&J$0ineRf^10|D%VT)p9NyFCQ-HR8mnm-dEq+zV+PXs;I zLM{(D5s1ro!qYnhlgsZKq8=*g6g7kjuhtMWNkht=k}fU2qd}Q5aPZPyGM{o^2bLWGy3fLYYFKhM}~KR)G`VILXj!1J%=eo5dj1 z!Uwhord;a@Q-9vuukvi`w`>bLR^xG`1cI{VMMgI>M+d~fClk#{YUvLyF5uAKf0%mSc zx_-mv%^U1bFQ0mJeBw%qkn*yFMZ2DIgi?{)pK8o~>R^6Z;wdUtHIARUc*b&v<%caB zHf&j+h|&D@sd}@YqGHjB-S043DnC40@&3P|8vzf1B{2ZT4S)em(|o*=&{wJ|<1%;; zc0&#uOPUob31%$`dg1B~mILI-z|{?48>N3!_3eS{yxgYt%8rvBE>*l-xPItP>#z ze`)@_8MHBYvl*-k*#7nmAZGIYuR5kUVAE82ZQxAB@Mx-E9k6(4l^g39KnQv4)D5Fp z{U|zpJq7q~t;T5PX6z!$K<0pmwUU-EsH5by@9fRDT~ zPo|Ela^YEpVi9g0x1NP+3Wr*4%to~rwhPu%b+0w3Td;szbK9z1PP7FgP4hTZ%+ef#7gjVZWx0OuDRd2RQ`s_#Ks7>un^q3-CSaVJc0rP% zH8s)_OEA4cUWy&U%(4e!bBOxY!NwjiOKZS+nezIWCqj^w+bny8LpK*v)CVa#XIxl{ z&JRn`rAt?io0EVc1lnemu?$Mqj0l!*z-2FFOIVuLoO48TfKI)4F%u?1emd{ssc#iy z+%Hp0IUZ(t3y-sur-41Yg+34RwY*hrjf01Sos!WP(84t*DA*||*k|OGVG7Q~)hU6_ zy;#;rcY>9A?(ot1}!{VI2d8w`OA~xr@I^+rw1W){lZs4aU8Q!OT?s=Vkw=ctFr? z^KMip(!bY;nu#o)f*uwAwz+7veRE{UrITd zJ}_$+F!O5PY*tkd3;Qzzl{Rqapbyjv9O?kA_T{N*M^Zg$Ou!2cguZ|*gP=}5=x{Q6 zgag>9^3^P6M;ivR)1a@Q%l1v*TOI6GJ~!I=fL417?)rUq_5K;K3MbE=J(+I=&N)Mr z4SDm>hLcdAYaXe&0^f$A3_DMQ7rA`z8w~RI5mxQ3S-Io)o`pjzyzD%ULbnB@0mv;} zFFPS+{nnj`;6z;ylc6l{1PKLPJE4Q#fDL(CZF#iCymY)>z=iJ#Bt<+O+F-jm;(Grn ztpD{9H^b0%^_bujHZNU6!<}hKei5ip5wf8aY6>q@77K^lVUhF>V5biMQEi&-Q>sNb z!7?!TaqN~zEX(|Y&)T>8Z)q^tU#Zs)lDRa0y$BK?U64?y=HI6p}Gf!+u`|_!9cx_Ne%9!XXg|0Nn!t5B6%S z{0aLjq9Kl}{u42t{sJ1R#pDF56HKp$8HXA22aB<$D&k!_5Jbf*-=&%xOZ7m9EsS|Z z`CcHJuTd?0V<1H+2iCe`^-xviKk@`BU!zsEd1~^0$t;7&z;M9^?^0aFk}ugnP@*4C zz>~apQBOo^?U{P!By0H^o*!xiODh+&KN}Zu0(}qU3iQ1?42R98VU%kzJFWUp_O9<` zp^y>ARN#aSXx9;12IQaqoAJf!=u?M0US>(xMu_{o8uyQ&*=0yV7Oc8w$t6khGQIzE z|JB1Rcq24%80-@#1qoO&GMAH#sd|4EN30jtqJx>m3yy~K`eUyO=WqyLn1DxEd}so0 z;Hy^+{%?XW*>>z(yFYu!qx<4l?Z{fYLCrp$+~{!F%jr%sJOWoIjO%f>P>Mf=8)$uh ziob#3y~~hy>ebWrb(i5AJl)O^js#Zgp2?RksD)<+L={tnm57lR6Hxu?Od|Z4RcBHr zK8``s+{PXd`Bjy?fCVZsXhooC?*5sI=#RS~t^x>^yHK<(V|e)uTfPV_&KG*1wTA31 zmmhwTfMT`T-LSf5N8TptsDMXm%w$ApcIV7^hN`pAJ34h>XZBx6tayIT;|>tc3HHR+9Q(G# z2LCP@B}Y9hY014#al11UMP(Fy;k-Su13SI{>6)S_n6+iKeS1wopiuYEkC0BQ1225+ zxeC(=)}l{ne#huvA4kD-zay?K>|Yc<#X{#g(R&t{_$Cb&%4C8Dp`Z| zr6s(G7sbCn<@Ula^CJI+c_&IgMtk>v>eNvC-Ma?Qne+J<5_uo>?WgPOk`d4QbbF)F z@}L5#DHj{aMZ#mKWsHVUU+8toZPafsHL~K1 z9hJs4s;78^ee?G1o3|$-I8RM_Hbpm)s=c1Idw!#B@O=)rk;5JsERxoIh`;p<8(R2= zupL0Cw1^QOD|qJzkRRa~xc`a+1h^sX|HnstgnuPaZW{&726|%6!GohIDY&!19}Yei zcd=-o_6H5{2AA_-$nyV30EqkYjKmseMR<&>{ndvKJyURKS^e;eg?j3}%aaDzs=1IbnNV)z zTAem*wuG?`%un|)Ae}Ik5Z^9B@@!Bce6@bW8nv(`?hjE*o*NP03A`9$`tZTsWxE{U z#G*s=r{HIko}Zcm(hKsSAlh1rnyt-__s{mven?Sj-t!yNVFpy%maKBS*V;F&%X?Bp zUlx{l9N++V-YA2#%3c**o%+a|&i|$&5rm zhU&iBAs(E&6OEKX%quZxH zLWdkPUYs-z9oHA@jn5)vsw1D0V5+Jr2*&Ayalsc+aW6Ud+1w}xYkuKx+Uw{7t$Pc%*&1JHE357!dwA&0TAv*gXN)e zq(U2oR$KgXOV9t71=ett+jatNim3fD@kka7{m82KHD#9fu$Uq6v8He@eKOCH^Q2*` zan~-6(9zY#uh_T2YTk>=mgBr7jG##NpC8$}+A_g*+GgCtjrK_qKce*JJclP|lVO{2 z*G?2SqReXfD;P@0F(d9aWq3@mT(gR~(GfC?4~L426Dv-zhygk;PVhYp81zD^IxevK zOmtE>r4tLexi4Ht!0AUFH6=tpi!UV9RD`R3HJ85d15gXTOSX)+r<$dvXx@A4*@D2- zm(VC-X8aqslC-ro_hx8$FR>Fzh9m3My4M?-98@ds2qhJYLwRea_Pm~=`vEZ?*OxSx z(Lxwg=N2BDGkejZ*>jF9JSRTULn+Lx>g$ViPqB-OUO65iUAP$k z=3pse7K~|i=8ePB>5KHOFQnL+H1s?`A6|#~UysADY0gFe+eJEzc)@#_y2q*Nf6uOK z#?<)t+ls>@@3T2YFnzuRN>{Q=-L(V3B{$$_2!ABTJq%(t8G!~R>vrYtuzPl_d2(%D z$f`Yv7avB;OSr{g(!!$kTeW*T*Ofe3yrX_GzDZP)z}=`3njivfL{)M{pq>q%M0)>y zrt87f-`~Get7(36vpL!waciw!&-XEP^M|X%@gn_by`)3_qL1H|-cYA~^0M@a+W6DY zJ0kYe4W8j0N&W6_4A!C;J6J9vHDIkt1z5$M0q^^)X3+pTC+&7q-D6ChdOM-J2!hfM z%a6V|_H}fyjE@gEu<*xa96*aV?OMOnp%wVs7r&9|}d;c%{i^X9*w zNWuq_{`QF^@u?*7=_GZ)XLog-nA+jIl=tO_cnp?p-N16f zpbxewsG=rb7xLY^hQSWZ5z)pS!BJaX0JUEZ;koQ$-WSVs=3DG4Z;L1|jqCje-a16rN8H}cDuo2K*g$$aA6Mg&;R)&*9M7Tm6VsRbBn~aaz@yD6? zG~YJyX+C~SyJc8k1Z*dg}%`Hqm98^AXfmqp3i> zEl*R;-^A(GP_@Z7kLkQr&H1LiCnNYH--Iu?)D6bjHfp4o)>KQ?hDX8!)lS9s9qV}fotLjvym0OL`nPWU>(sgJU#k_v4`{Im zHMS>Bog1kcjvRUHL}J<5b00kKc+PkDU)wH3-Y8mn>aoPdi}O8;9M||j&wsw=tv7Ia zwSI?%IQLN5AJ5<8@A=~e9$03NZCQSY4heoheLO*mg@O9L9 zR!#e{i{!ny;+@5h$79Qx23bNB4EKTc2VqNG|>c2qGB|~L}R)sCefUMv+(?{Su{`H z_xt|eZ(z#VDQC`{bDz6j_wMNhaU*bD8*XM0y0{yZVfb0@Bndm&Pwt zR!lC6wj;=d>zQ6>-kLa>Z;dvXmxS_2Agw z6wikrpFS--eA@Km;pfjCKYk8ce{Ymco8D4(?z~n;lswW}oVhxDL6n>yofEaeNGH*y zv>P0D%ji;Icum@pvn8)W4&S=!_*vtPOSLx+?vIb$E`NEMI2|Uf^FJZieR4}ch%?BV z={|cm@7s3BbpH7K>C?mK<3Y#Ind!_^W1(PalTMgLUrzSjzI|WmLDP*(Q{FU_#uefv zUKx%s5(|WcWq8ES9tn9FTngWVN1# z5FgT~ET=qo^Hh0B`PxI(#>=NqU)j4$iP|E6a`wmlf972!+kA4Y*23ZpGI5^Iu1&kj z_nA%{T0C#wV*D>Tcp}S82OoQzrvI7o)AE}$e79`bW!q!Aa(dQeGr6ix_m_?j{4Ib% zEX=~+=Q+noMIZd$OWQR6?$a?&lRr+AMX16eGJ~ulJ6sy~tDD4!Bv5)_rjONN@c{`u zKJbakDeJ&@)sfIT&85l(E4XobMWT!6@s0J+k!q%_J|gL(t6hF);Srg>N?v7;EF7|b zim53`Ll1Mxk{X_B!C?(n-A_}$f>_iP*}P^bbOB9XFV@g{z>@(nv0j>W4YQ0UoH*p8 z7=9F(EcEYxTPV6o2c)HZQ$4K~2ZDDB*$IKo^%ieN3DpgD+$G59d zj2nCg8oUC3;v0gSbU(o}v@!CfNqla0PIgX?Z%$@TR&Ew-vynbz5?^$*@lQC3AKyiH zGA;!3YG~6yPBW{Q!o$63BG(a&d>nuL*QRcavXMU`$%o<7*p??Mtrs1~8bv1Voqnh8 zGJ)%cm3x4f;Q-ADzaeeyMc@Wc_Q4tfhJgfu1M$aXfK#D+Q6zgPF+(r#fDh3wscW>t zu8%FQQ8DAU+}5wr-ySI*ktV?fKTM6(o*w2Xm?ybaVJZeae^95H)H|x3SP~7C&6d4s z8s6qMz6FXDN0KQWRs7!+G87v@G6O$daG z#Rk5~>bil4#b5(8uC8_s{Z`K-N&H z9UL=TfyFGFf5{Q%Oug)I^M{qg5rWl8Vhs;81uaWMVK8i}*OW4yr5Es)JtfUQ0y;W} zMG1S3zii%60>hqb!c#OZwLW$9ofrEJ6UZi!UMJU|ckpJfQoilKMFCi9Y_U3~L&sDw zfldpw38NFlPfQ2s)@l&fq@$O`J;@PUR+tFL8)b8lcU} zWEO85sb})v!P|L-pi|%;hEE(X+2jRnpdIKC_7|9`!0f{J+$I^0s0o>3c6xetx(P9b zX2eNuVSDO`wn;6pYWK`9vTZU#|F9|9rsQih5BDD^)eLCGeD2(Kh}2-!O!63Q!vUXd z>(-jdcYY?>YFjh?oo&3$-kRwOmdh5{hLK!IkyJCb4RfDy-j0&C%wOCk9)1VIYr42I zR%e%E{I@kvJee|QCd!sAGGo}UAi6}^z7UxK&R_91A8)1;Gtc2C(IrpP8)`LI2{r}1 zJ_yWzW78po;H$v$1tlYd@nII*(oyC+Ndilj zkga4Vn5mtPW@{(CaiEV0WwtsW=4JgPDDX7>L(MZErVk^e7HBL~Q4#TxY~78F_-YRS zT@N3F`-@QZY7#PD3T)B0J_eW^lrtJIV4wpQ(6$;^7;2snD4c?8mk}s8|4XaNbqBSZ*&ut8_VAftxn0$$jMZaXDf5! z<}B?xz0c55{Raokp-yZ2NB2!1maWeY3(pESt&QEdHp3iEU8AXs;@G$X02Dj=Rp}Lx zdrTycJGf`(!9sJ+=6A_&d0W_n1voU-aO5DSZ;pI*-CX)Vb9`Ob&_U)j@Et ze)(N_*XYh$=9=t3a|@QNd?(dR+`?>g+3)X?zf14x>ul9k z*G_y9g<->RGCsu>&}dkVJtPB0vI<|QQsl2HZCWx!td7WrH1$hp6udxuRn6`*pYK` z!!8ma8iG&0le0vQ=2FtqQ?kr4{#DuR#lyC%X7U#ez{z{oA33X??1xyF!DJ;*o!Nw} z#N-4M5PKseMB)b#H$KOjQ(#^dF*|mVY0&fwpZ)yl!(WdcOkGlGR>*2z?UEyASTZv+ zWm;r+WmD5r(o;-ta4D$;g|=HimTWesY#T(@=Nk(P3Jc{=xngTdQm(m%c6mm6umyRA zd4;BXTwy^?*hGH2&pSA*Ds?1KCP(;Yk|H5pDQdTJ6cS(g;dHf`Xb zIB>Mefo!(sV8MkVv!8B*x(Us^z6W!U!H2L-c#ZLD^A}HcNP7GJrYGWc-nQm7#^f2z zvxbCCw(PA5rFyUlKtix>d5syX?2xES7oTc6=2Nh1F4RNcl*!QmD*nYk^kY|x38m|^ zHzwG7)BpHH^DUSAI*b+=2{F9k38u9mu^)t~zPx63wR-r6yX;sJL*&5sQ{(H?#p*&tyPW(r&9 zz@D5J2JFesVKs;5oA)hVwqQd5r-1@Cif?zP?_x9`R)L@K>y7?ezyF-E-Xz zSRbRNNveZ6Khn+pZoC~j5UlJ(onqz!FjUtnKA<4L^3n0eoR zU$Z!?L23|*N2v>6Gq?})K4WeT;T=wn8c36u_#yv<*FZ993_XO__5P5z$^DoSvut2} z&>NC@@UgBGlPOXKAT@vu6D#(RCcq3%^M%d93aq@mMc*u>z_xv zMQ{(Gc(sqx#Ahw~Es~>%7i15G4Ba~DTgevMp9x_0+cx%Ryme#op5EaY|ew3xi4*!-sa*`3pbldjIJtb>oU13 zw{!#9WQ!imWP+1$31&t*1LQv>nE9G1s0kdxWI&%-Q$39No-vycm`?m8dJ2K**dNle zKLq;-c<_^Kr$;bXe7EpRT@9^*iMIV8D_hA(X4b6D66t;T5KnrOc*)TFl;gmUj-*$_ z&kj=^)g9qT3ejmN90rgmXP8nAFj3vN{I@*u7$_bA+Vi5%I2uJ3NDx^6_o`;XDCR5X zzmbg4rXrdV%HW22@rXkLnaP8H)n&oO5cVlJPPHUrpk9AT!1}h=PjSdgm_1v};D!Xv zzYsz3jz|+LAcOuL0|Ijk0t&R4l97CQ8A9Y`0%TH_NT+qrZ+lutI>8KaL@F#dIYRQA zyr$SLzsXciS_k%ThXcwv!%t_}AolIs_p5vS|7+E=Cu;s2OMVB>eg)6t&yR{b_^+hC z{rcXI=WR7(nC|evvi&rMk@$N&3LTf&+(Q_@cCh_r;Cc=t9Gw)s)s58us^0nup2yzk zdxxZ&@gYoWhII@M+uX5CJLl!REqN?6NJRJmtkzHFkGyAIJDV+^5mr0}o%+sLW>j#? z$dRh{r6un*1D17PLR9wJk`2BaY}=IWCh`%70k)j?em=$=Bg*`)r1=nPB8ux zuqBUUI)*`u6-gtZ#EOJwySqdq$tLbR-)!|BE&bQd?N-OzJ?)IXs;6o|t_y$z1uf-)FwqDU7-*EwOEzIVGodp~B@$2%InMA)$Q z`aeu$dN_yjHs48%telk$=bEg|zoM!yD%xZvH$+tM)Aft$P{H@9^mBW8QAqImfhI@g zzih;mBMuDSb~wcR^PlgNRZ`ujsCykxmtYAd!GFLeLxTqm`oDa_&ps#qkiBQ{Hk)Ou zvdMQ6Od0-U30eAoepj^kKuj`??jn>(L0WeSBK^1@y8riLU{B4`La}Ef{BW}L!w)P_ z?1QG;{3bK6DX${G0YrXuUO(N621e9?2$W6hEy_mU*|SLwH0p2Bw^)=aQV3)Z>Z4mq zF4OHKj^2!*JJ->*bomNesi#jCkR3SdM-w>*g)h8^tIP;VZ|TElbQCwyZgy(6ZR0kJ zZIiDCNvA3B6~D&Y_QdDiQ&Z_e;Z2Z~0k#DsWoSvxfR1HX(V11XR!cSg zLy_IEcY>ZDms!*;TuN z?fevG8MD?FFqN69{g5`52^^RK87LT?)VhGDSZg6)a3dl0%e074Y87#ydcnm(!?Zvm z0WFUM?4VjW5SXw(rZQ8e;VXx_B*N)PQ@lNovesO!;VNiW>(P$dEvyI!0WAwst3e9t zAtxkCP1SH!hGuG>1U9Eyv{$QE&hS93=G1B^%TaFI8pfinbIPewj6)IHs1aB>P( zBdA#{*%fzoS?bc%HzwyS*XOJ~8F|RIvv}{`;%$0^lO8hNAn$}-o6qh~J&^j@KQWa$etvJ|wQ~8C?PhJoVSU5OMpbun5yG`UWSt-VotqP@ky1~HI?>jPR8M=N4eM6ET4G_}` z6ia+sLPcD8Tv>j3*5=fLl!Ca-*yI@7dfWP9eMM?%a=x5Uur571dVTJC%Z9Z03?)TL z(r53m?AU3{FU-!)H(xKgb-Mi1{GHjmQuZaBpSL%>EMt4b{?!Gm3pT7xjnb#3ThdKR zOy>3hH_11W z>Q;XmdTjaj=^N7D$&AjJ6q}^iB2S&1R>e)to}d5Dqbc`BU%_ZxL;tgm9v-g;ikee> z%;#~Rtn88$urz4SBpv5EMFhGV0Ccv7=6;4MM0;-v~z-w&;D*heWu<3yz;DcOGbwAcxF}dmZc@>#i`bm zsLb^lQJGmenYo!cI6K&BV>#}q?fN^Vr{RrLw?*$*l@gJ%dPT;%cVd;fE0t+_gR_%U z>PpM%f{3!Jsrux!wD@SF_WX5; zQA&)0n?G=hEsD)aNli_)#O1}r#m2`f8{+dfTGCU~QVODrW70QfZp@0$q^-yR+WPNw zTrt14B$BNr`7VTawSI;f=PhSvse(9Bvo%+0z{H>M7L7l|gQbq3e0-No2t}buUixso{T0-a4P#e?(vNGkgi9&=Rzf2G&s3CU6@nZaa~V+W?Wp>MiWMhQ_7do z_gCH3XO)&&N=<$Z-}V#Jk8S$<#7X_G-Mf<486)$f@)G2bh^3R_rs)rNaNHxMD784P zIREnlpWm+38$J~MZOZo4iVQr-qPs24m>3sWHZZ(sQR(_hJsI(~7#EkF6Ju6lJ}Lfm z_eFh{?$nlw!ivHzdA&*zNo3LVCLP~ymW#Wyr8yjzE zT9QKzA~14@fqEhWvC+VS;W7{2BE}9HtZgdHKDJpgD#+NhZZ;dO-ByQPT z@Wh+hw=BxdEIr*uXNWU4w#%HcZEbNe=~Q^|R?aQU?QEQqx4ekMj5h*R6$~~QP zDjSbZnw0rU%ChtbWM;AUKfL~@t@V2C@ghtId6~I;^Y-TM%`J#5!bsI?*;J2=C7vVm zo>hhtui}gO@8$2al$<>s`*HTUyc4;~p{&yVc^h)q7H>E{@Yg$sh?~AD<3Rd>3}CQi zTjVUXTvkR_W>z|!1Ty1Fm5LNPoDPMc5J+=}(~b84-|`CWO@?kQEGx;Z(D!N5i}7!c zp7Um|et2%jt21vWA_-M6as4VnZ$O^YcVo{6YNk)2jHm9yGEOKp$^rc+w7-}I3>i6Fmklf#Gx7d{NY_cg$&(vS#MZaTl5TT}3>j*m-D9KOGt=(5S&v|g(<1e~O{Hr9u_Ep65RWIM6=90ftm!2g`i$)K z>`XZ(QQ24+R}{Y^en*-$u{fzDRUeiWmKi2zXUDHih)7=Nt1R6(J7b<+^@|i|4(m96 zc*dI)B(1sL)Lc*ZohEhktcGJ!S4XV)$1DlEwt`(iy24T;s&mv<_Ez>eSpM0ntx$?` zZELP`Xq3(N_D%KTvKD7>dt{5pc-2*2jYOIXUTq&D&Xs2FntybinQ~yCIo;9iyQ_Fw5XMApz3!VuV0g;eh|YN@0n# z+QDu7b1wGu35}rvnukoT1h>=`YNFU|ZG_;uNr^3pF~R9CBgNd3?9C7G7rl7`I}w>| z4=Y`EB=$h5FB$P^RcYCg_yfLlmI}9G&*#bD^l&)b1A}5cxWqcxdN?|o`b_OQ%>2_Z z>T{8fHib}xrXhccQ!owC9BJ|;xSK&)hvUU^2vxLSM-!imKixKWy-j?klF_D?`z)qT zpOOHx#!*3HRfBYhgFwk*2p_FAi5Y)Tj<@V!ZJ3>4V1l8*g6awZkx+7RziVfsouLartO3O2U>tM!n&4?spcQLp;0Fc= zkPSid6JQxp{ z(}8icD}V*DYDOGH1cDuH!o{eUhB4$&Qayi9-1OgjT{W|k;cb6|(*z7y7$RFK+Mu_2${Q*_LAe747jL9x zt3k7AE#_F^kOT9MZ%{2FPmCJWs6owZDlB}c21^cOb1e#~-fFaNl$Y7?`&G^PPzF8Z`c!&rI z$?*^?S9@pwkt1g9=IoIp`|s2OkzUg_s=r)n=zNDPB;h0--|k00-B$IGcxbJ%dqshq zot~7PW};mot#;+|t=ZXm=6wY_b{#fGlO;H3$I5&;BSkyIOhsbm@(Z{pfaLUjgbEy*e{JxKp>&S2w&xnYA6cso8Q#Pv49c5r(Hlli7m_(kR*)BZ#QV5TsWm zv+v5+r4AT!-g7eMrp}j}lepCCjFUCUx(F#2^9l#JlU2J}tyF=b40Kp`_m-O1jzBr=N9s0KZ|5m++ z%f1>91=LrtE`|PcR}Y>qI|SJGX&+NB01=bS!bhuyiBX-$K3v z`i3jFg(}~XJ>Vh7LRYT+V}Aq1Z|rP8&gl~k)!BRzh?7Avwpc+rDw{ez;lckQdN!zYdw)%m6B`TERlkK2GX} zhkz}BzQ%RTTWe>}G?y-4TDZhSJ=+CPL$Vox>XuZpQ=*Z&H}{5|nT;osYxEpToj>bA zI1QZ%rs*A)%7Ptc!+pZ2qgkcsQ2vp_MgpiI-*&{A8l$2z(>BQ0XAeC(&@^|hvTmXI zz}%_jZ=2jOD)9a<{y@Xx8eK8zYYE8AP3^1HojL%Ir^76PMrg@OmZpo!jLO&`54H!e zvy;M?&N4L(CxiH#SKhmI{OE>dJ7m(0D)U%?jp1Tk+R$ESh{J2+<$CrF>p$OYu;<1j zi7#HrK2o=1aai#@6MY%6Q+l3+NDad|;`HOaXIsp7)y{1G?%X|ljB1(=3cyx>Q**Lh zu7f(k2|T(_e0)|$ylja3a(>?nJ@Fz-B<)j060btyrH~x$o$#Hi@k+lpz6TxDhaVPg zhVk}?2Q1w(H;CZ$|j zqGff0(eQQm+CKNg2#zzZO7WHxZ%h&Z8rRl{?Y(8%U(%lveUOLJzHzM z_1=}6Wt%h7Hp`0PYZZAf^kNT=d`Q}{7b*{2ylgc5elzUah!XkG?(HW|8OefWbb)T% zw9vQ4g`NIDCg*hfH|?w3CL`sBCrhqzhz4!yp_>pMHVNQ}dH^wl8~^sn_Y=(NTe7!qfe}Y; zsIO|O=jJV3HGiXd@yV0hEi>BGkq;Jz3EHQATgZdkL-gfHn1ykMGu(yyr74Z?&$6mwkf->+o^;LyEXFGN5 zqUnPR)80zLugPYrw@1WJES?xQ(YKSm13Ne2ofUITO=Gy#tF7hh%=SFBExTmby6Th0 zoA15*iM(ewQp>@Zhb$8-PIn$b1Tx|T{Ol{potvWK%+t=fXv`d34t4V)W zQdUXw(57*T#M&jP}588H^ltTxDKcH58Va;T)gMquW1 zkM3Q4u+98~>dG2sY`J5-`>E0J16cuyFyJZm+z_o%%6Dgvt{P@qvLq#bxw&TMxSeB6 z35i)*31+eyI1H2}t?4VE)|$YuO!cZliUPYAgjd5N9KiKJ3uHJ$}NO(WX%D7U_P6^kI)z9N$%Af*#W(-Z(pJw2~g1mT0Cy^eG!29lmCc zgK~io6_&zkK~Az)ckj4%*W^dn5-Ms`zV__W>04wn(_YEeVeYBocK|V|O4p9YvvfLV z_$7QnjIwgIxdU}!Khe?b2ANIUoUysg*m%T``io6HS_l}qrh_WWkFDIcZ_|DlO1KYB zhmCtHblNyGU4WK+N)~XZPHaE4+dQJ=TG&m~<%dIB zn;R?P;$4;%zbVE<+i@Eck`vO*bd9|{B{nrWCB`?kJf$L~jILJ8eM-_2iZ)`J;$q`B z#%7rZHNVXw`$0j9+~OmLJC~JiD$6#XQokV+?1L3nDJV&?nMiAHQ%NB*zmSRQpwspT zY;1Pv#xfJKQCl_Nyn@2qqAaT(+7s9qyue)5l3A)RJZ2krH{20>PMg|Gh8FA~(u;nw zCnaI4`S`l6^CucF(xYNVK}LQ?zW$f9*Zv}Hjl^#R9A?-P^5zAztQe4IloqD|VuXjv zpQO8vOtCX;LVigqs`M&XQc_TyZ!WM}Y-z=MdnZ5Fqqm{%Xo`f>x#lbh^@LU-@W7~v z`Uklzl3fx^-5toZpQX^teMt~soLQWjmvpM1Phmo4Tymm5J^i&#w6Cdw_tsABOq32J z>}Toi%YATeNv1V5Upu$p#ksvY(S9cSL*sk5p$=)${=oED2Nj4*Lu5mw7#K)S0Lb}m z`Zi)x9Lw!tj~^o_dSFvfQ&0o`AsVtI6b2}}7hL54CH7*Puj))uH&y@G{@u@8|_#?|n7ZG%}oEMAy*B5dlsd0|se%)5Bu#EFY=kW9)JFV3r;I(6Rssaokp zt+aV(mgpb!dOQEuAO8L9;WvLj`zELzPEE`f{a=Uk_Cp*s*Jg>ND^PJgFxtCO59*;n z>gpmGaxVFq^>wk+iGXIldb^4aKf4RjdVkHA*bfB3=s*_!?6^} z(1{>2B^*L-5f*J*sBN|1%nd!%n&AQ@tX{l0^Op1C;}KUjBdS8-#5|s>Ct`^ zhh{s&T^&)=wPcKbR*FBBk42tpOPoQ*q{XX$lo@)0zIqg=*(v|xAr0to@5RS#C zB&Z)0Q8=p@+P9m;b3W0J{Ml?+n^1DS=BKMS^;(jLaU@oqL}Fh;5}H;b$%SY%2kShF zEzQL;m(GDNC(0?x%?NNkJs@4(k|SANIFY^YVYHmw%dTo`_`>kz$# z8amQ>SPV}ra@RY<=dKBx)AKy?6b$+0En&9?dc(c#yCk49BH3T&Hvjvu$&2(PAF$yT4Cx4*FxpB;~{`4aBV`IB?LLztGr zH}-0rAU+y?t5>h#!+Z6*HT=<|Telv`WGVfRSQWBpdH*RR=X8yEEA`@3A2OLv+Pl&+ zbLC3kq@ z`qwVnUsYFe_`?2=rsyr-4}(8U$M0`j6#1jt3(G4O>8F$bh;$Tk_;$b=TM&^^SpL~+ z<+3_~^!1m*EaV6JgCBQ_eoMYJ1RJ*baS|8=zea`YJ$!g?v%O4bU#lAIo@#`;8d;V+ z)wQx(rh7Q*W{}(z+I&u2vBI_uSZx8S5359O-?+cZc)hmv`o6u&daylrA%@+>t4Abf!j6&f6=+ zGihg%PRo-vvT0d~d4;h|!eAzai3~dKW)LHr6S4mktHQtnxR!~?}b*8Y`d6`oVF#6>Ns^A`Dd$@%a6TVCV+)}qX&spcv_wX zhYcQ{2TRFb`#_&hFuTtra0pczVix!ehTo|G%GUFH`tp6+;~4FlrEgN~0b+OB?rmfv zdDCbQC12Wg>X0{~Yf-1t1qGA zA}FyD&W|EAfTB7{4Nf(us=;&-*+zeR0-Z|0pR_QFM!xf8*y&eJJsNtC+IrEUz34Fd zgie8Zd?|S&PI>z7=fp$*V^ZlQi?QU?lC!Vp2j$P{PuZR59BqHYMEkln=4crLnsb`5ZE$ML zF}ZC!NV@p3>gksn=8hDp^fKK(Ys7m&H@B0(`(y-SKPP{E@%< zftbM{k(VF!rX9@cT~!c2BvaRtj{e8>w&jZp7G}bm8~vMhP%`Q00d%Cl-ahmLILKyi zu;=OjMoXVTcw6xo`nB-br@fmdH}_ZDfN|+f-BmN0eC?(_@j`9dyCz~M?~yg+@=s>_ z5w63!!6CGjiH@Czi6y|?n8;mJoiNqiqrd(NTh2W4{a2K=uhbuesMQ+gBu89>@*F6$ zQo|l=41Iw;b^wA1jsQId^e_PTdC{jD7=?!0_Y``JNZ^`p|IUx|`PGHUAiW_|r-r~c z=to`1#i?~N*~!sYNYD9X<#ZA~o*WtrU2J!feB|WYv!OeT+S)1Oa{zcj1notse)D#)u~li>_g&_v|(B)|K(!nT*cK#MjdnLxM$@lLJ0=G?7e1-bLj(jysWA zxgr@&UC2Ue1qMB=(dmgvG?1jzVp=kUrY9#)AT#J%6CEAVH`Y}8?QYV`Vnl|Jq4wXn z4)!ltGL@^jPXvoaF%tfEj}GkzP*>_qT|$1oZnpHWP)~W{8M=e~DwBiXk%c?gfoLru zkN~%07%H1hWdH(FNSX<@1b4W%jmCf^f03WacjOWI=pj_hZLf+=QS?vyY^3iwO-4rB zmdEd2uBZI3z|=dY_BN@#0j;~?_+deWTph(t2#V5oWVAAVFK#|WrN=$i>aJ13z-B~gRkeeCLeHd>63sOTS{Qt=o zvlQT@h%E!-j|`K1057NVfa-vWwz}n5X(<4jB(%?v(i^Qv1=!>T&ovT>6p@tB1Nub!`dq^jc2|i%uC)hT@718E9>$GBv zvTRg*=>%;d6X3=;kxo#68b1NKqVAg4$mK)e7 z*eCeV)nqkpP)(~hDZo>*`Kngc%KFhIO%q;$t1Jxbkq~yCV`BPo3Ecoykw6fD)fTJ9 zwo4s|T`*ZhDsaKWwV~pix%tKO%}vN+)$ocgasJ%2Ii|*X*MA|qjQ~DBg7P9=X)h{b z>4l6NFAV16_)b8607s=9EnC;k#=!oJ7liga!0m{flGKbjfb%Ai~vjP#r zrzLMM>@PS|!#Qhyr#VoxTh~ia%)qY>5?ejQD659k%SA*aMn{{G?6jSh6$=}rG|}Q} z1w@aw=GE#twZ2Y;0vFzx-}A;tO-4m0g<@yLJs= zt`l_YOQOn=IUuFPmc9uQaM^i9W)&x^xT-9r%u-h93%!$--C-@;vCD|ef!h+c#@G3{)(2OYKk31ZOnz!pSJ7zx6bh+WJ}eG4|5D31nV4qLE>xgv0?; zD{u{3{{EfS2$;!qDxw00f?01Ruc3>AXO5kqBq)h_v2aAni`$$~ma{K+Z~pFl5`2UN ze5PQ2<@Cx&w^Hj(YO;#-NaSxsS0JYZ9ttga%RknLwZKDzB?O{9U)j;+0NVTvIhBsv zlR+?Fq*Y4i0SDKp^(*qLX#W@Neo@MbeXJM1VtDeR2IYs+HwKfX)^e|M| zwS(tpKXS!M|Gm&{+kHQ7Ci>UG#$2(OEFK7&I3S;{FNB0@7(h4c%TFA)9y8rPJgZxh zIc@Tyexs<9o;r;To3g|-XTevb|3b5JHj;QOCo@-&x88V24a(bT{gs*Rx(*yUaM*z1 z_X2z_)SuXCGhMC?qQlN2eCl<_Uyz;-yZ%M5pG}Z@#{pydI6-o7uxj9xR}_-hAVcwF z6>p!~{JThR(kqZJuaGqj0$oGSvkh(>T|>`n3Hz$Cv^j<$_mot>gbSMVv|jv~Q)(Zx zRa|W#`!i=-8r+vPJlRjt-TkllPm0*NpK!rnu@HW}#j%-7#+wJ|l9iNVnZ$DMXb3-( z?JsdrDH#=+G6{%hU$=)o($yET6*>6@Ta2owt|-xxC=Z6|>NZE-`2HptN?JW#MZ3y$ z=z6v;J9hJYlloWFU(B>CR4!(^RKfPRpFOI_+`V?{vcHw9{p$YfiVE?m9ho`rS!&vNJkH zVA?X>nAe!zOn)YfnaM0-Rx(LU8e?Jd87s4iDQ9Y(*E#1nZ+715eAM}*^Ihj}oqu%x z#ks+`*@bm^*`=dP7nklXgI&hBRJ!bQ`OBr*)!CJG-RP>6xbAk{?|RhrgzH(?i>{Yl z>s)WK9oPW2E8CNOgB{9_WK-C!>~3~HdxGOR56*}4=h|~2+$L^2SH&IXPI70tE8I2i z0rxHUo9=a8f886pbX}3IOt)RPOLtIrOm|9mPWPVfBi$X{=en=;I(-*?H~mC?m_9-u ztItvNg?gL5Out=!U;j}5qyCpx##XPi>eQ-Fs}Ze2T1{vb+A6D6X{)WRcDCBr>ho3) zTm8wid@H^!--YkR59Y)8Wzg!z@CE!Pemj4S|59)jS___nw_p@xp_4FBm?%sWW(o6! z2q9KT5_SnEgiFH5!X4pr;Tz#6;rG@G+qz@xk*z1RUfw#Ubw=yb);n7tY<;5j+18g@ zKWP0^>%Ut!w()7xzD>6_{n`v`GrG-;HsNiSw^`L@U7M6P`E53}+1h4zn*(i*v^mk{ z<2JY3eA(ukHs81TkDHHMPq#j91KozYjdmOBHrZ{u+Z?y0ZmZokx@EbQxRtwYciZoF z$nB)t4Y!+$+t+U2x&7?+dt0`xSKBUagWHa6JF#t8+c|9)w2f|?+jd9WQ*A$N`&HXN z+p2Aw++ExSciFwW`%w3{-DkUpyDxE%aF2CY+|%4Qx$k#B=l+p~Y)U zp2vNUM;?EAGM;Tb{XE-y_VVoOInZ;6=XlRqo(nxAJ)=F7JTpCWJ*}Rlo?AV4dLHyV z?pfn`#q&eYyPn^A{^9x5Q}t{zxEcgQTZ5Ou*B~1@8-k!^7;6YK%rY!6EH^|NVhoBQ z)sSV#Ggu9!hMhi!!-g}4_Y9vHzA$`m_{H#t;hCY)@EleAv#`(kH#^6!&EK{i&w5(EQrv}A=MJGU}@R*lXTsA z0Z7)N8eW(Hd`v;Z&j)k^VDSZRm?R9uZDA|1+CxWS=BA+`m^tc@DoPDksB<=y}4@ za6lLe6>0d7FO3!st=zj<;6ix3pe*R(BwN`m=4IzulI`*==A@#{Nm!8bPsNrLNoofy z$pQei8;}Lr!5RsN_U=6-1pW_r*~eFTAto*^MyQoE=+&nHW7QVBq(Kp+7nvMd`Sa)F zC1E+@16-f4gz0!qu{|$5KdVTA!c7u1tUCc*j?O9xFJg%NW)P1-;P0UzWg~cdC@dbY z@?sBOh(bFjNIB>TK7rHu$AN43$Bz-75~wwNC>kChlAG<_IZX8A)B<_hdEl?1l}1P!KJ8n8r$xK;8a9l$ zN?H=Pdd>POh~p$-sssnULsDsch0uuyIJ}^nAqnub5WbNbLrDioaHQvRDLNbA2iVzr z0g|#?Y97l`=i5CW!72*?#Gi<>xpA}x8}b3~B5-fu7Cj_ETo1?%isnT|Fabzdg4k0M zEQs4sLmTT6YkARL??_8Jr(rgGA*{>s;U;?!5GaCl!;g2lFimcl(=_)*-U?Mw6Ogz< zK-v?V_LnGzbDyx&tsCBTxq!N=sZSr0V0U)gL#PmcOd%@Q4;vX1WV#7NoWC)2C}!nb>@YLo#B>< z2(1Zw3F=adxUD6(Dz z&wj{*sC2qb3<2h}!lb;UY<*HvMrw+g+8)nm97~Q#%Zd3iET=CPt#2>J7r;P8Mq!}{B;k34qCkVj z6}<2kuP#&T#xhk06U57p!fN4m{WT8*UCDt_37uEjdpD#Dre<8d<}4hzJYZ|JYnCJ-Fx9kvA}_#1+m5I89BtbXsNd!Tyzm!J5{M;75=NtU#l&qcHy6cs9po!+ z<%O@l`l|0i^ud0T;P5$?{ixfJqGw&Z_Ml!mVWj!34Endsh2c){Tbh`417%-Y+8 zqI7~zbnD8MTcG^9q7~ixC?eG@B03I1uCF65RyM?c}1f-HrY)AW1aIgavg3oP~yNj+CNMav?6$mcNh* z>qfXG*|YZARc}@g*}je8>HAL zf){j!+BoB|f@B8Euonr#%Y;fodTOe9+O!cGJufBO&`xR>@)iBc-o@U9{<9@tsa>>k zZHu`8K3-ObpZH42Zq*6k|8t-=Kr;pj&&A^w*;eQo#Me#Y1q2-S6%dG~(58H7?y?O@toPeNRi`4CIyJ9ONi{-V& ztJ0!32tZm%Tg>>+8;ZK18)&h4!gyYr;xuxnH8t5NkxGpSdjZ8jyYEME%NAJLE?djD zjof2^)Iu~KS`l8ma2pm{WX49TkO!z8iT}Qb;HM@mFM8Iq3|Q2~H_A&aj7Z4g&SMy{4Sa;qaNcZ1j<-kY@KOxN}cu%C+j z=>o0R1*2y^_mS%0vEX9k@ z#>>p(|2wFJZJ(P+KdIg8ueTEjV&;nyd%e^~2ghf`R^%ZG)?~@Hcq!BE6$GoNB4Huk z6P5DERD3Z0K;#Y?uY_3!&59Y^_VH52d%-dKhuS>%GkI&mx=oR$$aNc|63jy9;X^yL zuOIS6{^7%qvQ33W#d*b9sB1+cv?4o;cT`j$+#N~D%PR!knzG0pKoBmpW){Jr0mGa7 z=o+$y6R&LO#DOf+ipp{k6XZP(xjfCnT9PXXNDB&PPIoBE8WAB2T=+X%s@8&#Lzxw` zJ!$tIqku1s76Jgd)>g=AB8Ve68q?5)1voH`Y3jm`XlKh_#z=|?x-B3a(;^A>|J-Yg zacR6Nki)QIMU%sV5nL>F|Gg7&7k)-{y|oyrFZAJ~)(;wJ6pRkjdnR#}lM=I&O!KmY znnj1_Xdbk44lk;yIefTA7EUfc2;90QbLSmeeB#8RLnmZG!`+<0=i72Ol^Sd3o>Zm? zzrC9k*wLxM!2chz#jK*Wjb1Y{9qYx8(vLhvQCEyfyM5~EKjEJ}5Zs}|jiLq{W6 z6}dV$f86{u{k*hU85W}ekpo>BNlCe2LDLc1Y`&*YW17{bXj#Z8GUerIe&)Cl#*_F3 z`d@Kn+MW#+!UE7#5u*$x7`un?i7L?QMb_Mc0zpfPBnt;54kM80kWd&D%?q;=M~q-j zx@p+sf^Ny~)dywb#2wtd`yePF)r}ZMxee2cSEkF+7>BNoNY@3tPAJLF-oDv%mn$kr zPR>G2fP~XCffwd1t~ReYSh?YX>B9Cc`-CFY6_pYNcnerj-AFYEalAn!((8f7E^_~Y zN(f3n<(ViT3q8`kS7M0GZGMX--*9AZ<6Eo%x2l)Wk6Lm`LrjQ{2d_hr9|L?gDU^hc zfb0`!J-qnwHkfs^2}WB4KV1SoV6KE`|HJFxsW{k)YA!nL=o>YM7tIlR^-|J%nE;BI zlbeD;W*~`siOonnCp{A4csJcpw4&D@N!X}Z)^Ab-4J;bpRtN4CksgPHa#MMk0C&$& zLC#H1%1J`1DYRP~D$s0BNwNqRE3RH6hv)}2#7B@{Z9f4UuZM=A0s~{d*Rk?8bI}4^S5a{UMB!P6fT=KpUFx3G&vm|nhKs&C0HrTl< o?T+Ui+FNL~t}F!4fiziYT4dM7jgus|leM)c1?bqd$KZ|sKMv}V=Kufz delta 32455 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 ChtR+P diff --git a/lib/Font-Awesome/fonts/fontawesome-webfont.eot b/lib/Font-Awesome/fonts/fontawesome-webfont.eot index 33b2bb80055cc480e797de704925acaba4ba7d7d..a30335d748c65c0bab5880b4e6dba53f5c79206c 100644 GIT binary patch literal 68875 zcmZ^~Wl$VU&@H^c;;`7_65QQg7k77ecbDMq5Zv7zf`u&Z?gYZ(ngk0$0{Ncrt^4Dx zx^;VM>hzrI>FTQaGj(Pf9TN^fhXDtG|8D>R|J&dI>2QGmI2Dcm&Hn%XfAs&@M>9(C z|Kt8IAOOe#+yQO?AAl6VA7Bgc{%_^_9|8a%fYyI#5AX%J04xDs|1q=xz5f`m|6&~f zXAdQS7r_2MlM_G*;0AC4xBz_r#nJyia#H?Z836!kZTbJJVg$J5V>k?QI1DPl&K-FE zB6)EI$FLHDrg|br0SL%1s}gT3{9gQ>5F0R&#$@=8Ms&PWbF7yPrD#Y;+~jL=u)gq>%7Pd(S_umwUQ~x;?<#v}X&J0_rHb@c6&v z&e5yoXi;gOH-tArQ=)GCAvG(z2e6XD5*>JVsi+}r>6`Xj`Jz1N^Hzf3iz24woNfXe z{UC|w83xyVL*v&b8Vg-g_@4lP{<+GY{ef&1rDuNQNg&*rFsR+0R*-nXR!Z+UGP9p& z+ZHw)d+s~#)BvamqBwJelLW)s;ktkT%QrE))q2kJf9jVe>QNYol+-*+1h#e{PHW^m z$;J4;RkXO+c`-m{{PILk2==fnK6NtVGY7Gf-$gOP?ZRO|*1+Wc?t%%Ex zc{nud=frh*bP{SdaScL87E^DEvx%)ra}Kd>PQfce988d3(<2ps)Nb3)pe|yJ*`Rt< zW=urS_77BpQbt)HXt`vxJl1D}NR9`U!17R@)QuL^IrsoA`Y`H3cGW|EJ*lMw>x{=p zO+t#MWiHnwTPFc8RaIge%9fP_r*DDrBuU5Vr?wS$Ysu=0;F(V+1XQG39pk{)==FzM zIayN*8QBO_FY!;_RpU1B`W4Wd4s>QtnrQf>TFoAv=c&EC_0vn?M}l^%KG^v^P2a_Z zq@n9v0?A2m_XcFtClQ}$_caQh>gn1DzwIdzWK-8zRJ;%quZ@xrO$y5B#oYg+>BkUt zaTt&cJkljrDHjy_+?z#yc`U@=iqil3ixo}U_D}Nt)r1#`R_)sX3*Y$SY$BF{KIxY> zEcg<&`vE1uk-5l*(s?ub&B`hr9BoZ;1)JNwhgTiC&)wjs$-Xyu50$%NnBLG>L-5&! zWNjDVNrf<>B)6Gb;JAM01Wh`&aW!Orr;W4}8Am`VVzSek`S9SUEe1lX^4z9P$?TEX zB2EC(&qS2p36~+frBq!ugIh_A(NbUVdo0Y|hk%pb#dF3^>;Y&XKiuCrGrnqD^ zIr%AjGDlHz!#6p?M-2-ux`zfWaQD8V6=sY$QTQ%)h4)CeJy$Tf3X*jB8cicvs3nB6 z-6B(l8Eb7lZ3(ahY)#o3{JzU@(ZXRVRFsOF^;IFX0{_Z}{Arhlj5;3qnYSaTUecPY z>#F>c&ut!GvcZe!6oJ1_;AELT6}8(aXWw9elYjRaOV!e}3B`&zerdFn|Bij&V~wT@ zXgCCYYztxBv~Vgwlz>$B1qs4w$IvFd&|(fhMuZAuKypC;f+bbLlV3LLA9aQ$08G4* zbPoydDd$ikF(&s$y2Alve6ZdBo`eL1b^qZYrq0rmj&_wk82#8n<}6O{B3bAK?xnzE zMMT2k1-RH}?Vk6x3)^bOPkzOSj|UiGA#aP)bezvJ`kZIh-3g*jX;`YTx*d5j+>t;R z+=e^^YtSkzgfp01WzrZ4GBZn4NffwCqS{gPHtmSwi`TH9v`+wc#R%|1HDD)Ykuw_axb0;LTpO7^=W^q zKWUhlxtT!T2G93sWGtu=4go8>D@~p5_bQdF1e(97TF*N&wBufHP6A!y+&;vkq48yu zJD3{R8c+S4J-K!im}DlfU1gobXI3|poUu==V~_@6F7(?D0IUO9pt0AeyboTgl#fCd zXb4a-iLM*gH*gr3F%-nW$F@+h7FEewLZwJ&@v|_{pm1n0y5KV_|81>-{UAfU$!jrE zptmyOF|Va%K#@{@=r}*WQ${uQr!&pg&4o)ke?@5T{+HgdRf6Qm*k$X{xvB|KfYs zJx~Hfr83|MFi0if+_Y!jP24NnAPrYwRMzs%S;@Yhl09%cxe;$8Rg=c*PMx(Rme?RWg6>QnW<_cfB~2|RxP#us zu}z_&#+q8fTGnX&(PIJIlqz2q>8NP`dbaQnSZeSBA?gS;VP0&yW4H{zwZ8@|zMS57 zu2GQN(CK!yJ^uQY55`YgA3Gs3aTLeDH65lDv_G+ebOzXkapYlTSsSKcqiO(7ZivLv zS}HW0v*w<|u@b*b0c(J)2bVq@EgB91;UBt=Jyv|}%711FqG)x!Pd&c;a_YKull z_b|bgm}c)7%-Api8x*s8#GfplC=Bb?QcV(SS>ZfmS!81gSjtXL~v~l%d19_$?-p^=8FH@ZF}x#go6TX zgdO_(bvF=A!*!-us@F4ELlYR1XreR46nagwOXtwFetLRiW+f(?B~>3(4Lv&N(_5PBb!p$L@=y=(m34N zwx)lYLMBC_l#S8G`u-b&Kb3K_L`-e$M>$0I_5q#ws*&*}b#dHJOS;I*pS*7^$1~th zWi5xtvWII4GJZ2$t9Rd~XAN6V)|zXaTJJk24$i5ZTr=e{7bh2@%3W^1Mxtd!&P0xu z9|DB8Xz(u_FHM{}@lkLz#W6pLaB3F`ye=4J%=<()rW3=q!due>L)!Pn$(ZPC%PS3o zBEt}IUCd0~CejbCv zvmN-u{@A5l^^+JFb6Dt2m9`C%dI$1?{S4(6{LqKLScu9o;C_P4fGkv7svax3d<~k! z*z(^v=y=&ena#e!yGFNf2)L)=xb1kU1{{5nnWG44j#|acb=kTKl#RT@It`LA{o9SG zR&g~G7S3kGKI?j?#|ucq;C@cZW&wdu?p1+c4tR<=0=^fv*KuP}g@i_GpPk|OI>jSg zIBqu4Lr9c~r@h%LvF%e6ZdUiij$5kOH514GMX3tw7-58IMk)`8GLjjtI^|ymJcmKn z{z<0c%G6qSM>|4xvSd@%TC*4Rhe1>CaI7NfIc*&#NJHYkG7MdnT=734UG!>nH+7ig zVV8HwdtlNfo87_(;b-+;w}BY4=;30)_V#0mgqN?6?Of7k)U%G}39W>tn7_?gT2J=b zy~VMxQ)cIciKkkshpu63F|kYtIwjv{Z>tjj$Q`yr=0pK${(72+waF?D%GPa+pzLQ< z2l6Z*Q+SK7G(s8$-DPAN)HQsvS)MzOKkn{Xh8sgmDU_ft_L>MZwNY@qgAZ9TdNTZ3CVEQIC30WyIn6$Jbe(%C?QJk= zSx`57@DwJXQ73*Q5co|Vv>e`^P{OW_0U_eOUOQ;ZS$&1#)V_?&by|eZb|jwfm9|}7 z_{h(_*$y!<87q3YVEv0CIXdhBE@*BvVO*jylAH%zwStL}@Qe{V{$ zMpZaN!NUjE4>ZwEl+DTA%zS*Oe$N<0FX77viM~=9BROTH(%>Cdb0htlF9{uMi6Xzu zAWc`GLcOt<8>c-t74jXqd5bZ*#-BP7ccl8U{Jec11#h1?C0C<%YDi+haGT2=Ay*wQ zP>FiZ^COyJ!ZUFCCKh`lL`g5n!Z>-?@d1+vi{G8L&);EBJef(d5&UI#rSp=k1(@en=zwGZ{Ksa#n+OPhWJouSm_!W*>O{kTgBVq zxo8Dqe?(M_50t-ti6%6Z1Y#bNa~0>3*^O~==zvD>RLdLgF=F+HQ{9qgELy@OzhK@n zEDwQ7k%a3MU(3(i*;u@C@>^u{iY+Wr>T00Fs0Sev_qi#_4j9kpJTSVi`wY|`e@}#5 z+cGL&908(n#@oe;lafK`=m)-`RCvwn$S)a?@2O6l_5GRDm47R4$3(R&ZZB}eL<;T+ z^j2EJHMfF-9!l8$<$(f^QH}HJ;VE zby5&r%Q9j$8Osvgt1D^sFh!{OUR%s*HWIv!bl9Q`_!4P6?xeXQ!??voX%a(A;hLdvUaE&jpzqM>atTvD(i*pR)8e>Ra3IgM($ZCeX)S{3 z6meE_{)^+4%)U^D?dO$HP%8>Q6;wKH;%h1vyl&9Q9)WGSOSE5Gg3-+svyZq_hxEEj zzI8}ihM>%zB_hwAC7 zpktgudnCdORyYjUPTi5GJjJZp?~f6F-(-g*-X_`A<|oU^dB`fSq#)6CJFm?rNUV2@ zjEQki#~kdu9M;4eREkf9RxcVtU*J$~094V)IFOgeExhs$EbVutLY=T-o%!gne~ ztw}xBmeVPWl#0=r6m#iWySciwgQ3(U3MEyRZQNai*`Ih-GS0@tzSo@{K4)@jR`BZV zK7WGwcEbq%Odm|GJjflhNssa3ZOFl{kfdKe9iC4{3x>_nw9!^238!ZR(sxRJzA!Kr zv=W7wZ`(T-wWaXk_2fO?Y;Z9`SN4aXFS=q>$B$M%LsP`%=5m-rGPFdogIklswi-e8 zKa|vVDY$6lgps9jgb6%E@=6m5FvFivnx)|0$|+MSjJRBM|EVHqm=(E-`IRZvU_cUi z$kGDMBZkXAU7^Kz>SJ*x&Okfq{czB`YNWztM@SO`-;kDcGZXSIc)x$a)){DJBB=Wg z7{iUvE3d8@T(7AswQks}!i*w8h2WUboJ};)Vn3g@3P~+#NSt))kZH@!k;2Hz&wocE z2PC`>Hff9ZLll(Z8Oxlkf5qq22IbYdoStH&Hian1NHz^}!>2i?WaB&RIxc~1oKiUz zpSXlgr1k>c4+SBJ3K8)?S3b3w+{Dt9GtLq@`KQ6~mlhqrjA$LB5LB&mci2|QXmt&j zr%uuMvs=SqPX}!ZN69F-Cc9C;_xg}9jTK^q7Bs`5T(oQ&-X{LUwZ)6- z%XB;^w~T(9F%Ovz{U!n4B~a(BtZ%q(4t0Zs2`dFDxDlJ(Ql5Y=VFbf8mOsno#U;S~ z_bA3Q=4kQmX|@*&OOp|YY*Y~t_H{g9In$V7N{Fc<=IxRT*Imn@< zUX!{BI`EL;x)=>DK`!c=5U&~lWJ?Ru^|s<(e5~gT?jm+^^$4!U&B|mv+$TThx%bfN z>$lTk06JL7AVpsZD^4d|zreWfzPaXw5Wsyg*_C5 zums8fhmAaYyxj)eE^3?Vk;)kY5?@>$JLD*WVs50j4p+V<-+r>_m~tIrzwaYf~4`Lgi6h zu1gjUk{CL&GI~HhuO-fA%pMYxC%2N`@wmTHTV`uXMP_66K4yiXf~UDh7=c9@8C;5J zt1iV@2!$SSZKtNKXtF>59MOavS=XA_DDiH(nH;TpE$67yM@+e;tZh9?=iOMh1Umo( z&>uqbz^biPm2PCP9D5CGVG8fUg2PEIP%~{gMb|RAx=jKf`IUtxSqh z;Rq(O3=y$l(qWMzEyoWANHMJj;m80&F$^3AEZ2;hLd=3P`Fa7OL&}L|c#0&uSW{Pu zgb2878Q%6t!3_4G!EVf(FI?}c-=T7{uHB<0B(@T+=6Fe~p)O>phL!gdSZpd53_ z5Qw^h(<6YFK}k2@pCVp=lY1f+^N@;;Z6`3V50qz%Ou?1RKKNTDll^ITBTL%?`BXLg zR{aovmIcYubrJ=L5|W^Ya{U7*8t}E^OTFP9QK8mHVg}$P$;FR8b3B-0r|mR0b3uQ^ zyP%|BN&B}REkUIdYh`0LYG5e5ZPyL+lyH^90rglD!StTgyc)??P?Y(%Bbb9RRQs1@ zMZhm2W;?Xjybk6z638(xjj1js(ziec}9M3C;Xj+E<=V+ zpL>X;M;AUu7a$QSUMKu1!2GCVgivkt>aE|W>E;t0NLV6hgjZK&XlE$gBBUs zsqLyOilFjO@NM-G>4 zT_S>X1X62R1H1s3OG~coDdfLLZz{3`(V9VkgQ(Z)`}3+DIM!al(Qz~scc`0jy`>3- zY0+kJKtxU+9=7AJKc84rj#`!wwB%62hzL1(_?mM#OdbpBQZ{09@UwOaNVSU^O10_9p)%yr)Rwty)PJziNH|^^eV5JZypVM_^$U2lTisc{$i?06BW;7`#Q ze>^_0;tFzf>;kCYU&|k$W(hf z@1jLO<6Fu!vVw}ai0Soj=rIBRB#IM!*qXSux1?B3i| z8Qj+evd_e>eiOyRjbFDqSlS0Pg!QEV+9><~k_IM9C=9>EQYXt$VqsT3SX)PrZi5hA zQa*aFaMt28teh^)RLGf6azBmQ#Lu;XDud=lNh=;(mPkH8=VdE9(R?YZwZz=f*8fNs zRauKU6p?^Nk37>1uxvk19#0Uh%OYF+xkAFY*tl_r%@Olo6@(W(Nuy?q4kvc^ETK$I zLoL;m`y*34I)A#z)DPQevEmNib{S&3D6ptsv~T{7{>Zu^&89~GZ`bJx9$p%s&;?sX zjUR+hMDXh)*{DGIFV32D#|0H32p4Pjz#{;}V+J}SV%m+HW|z^E;F9En*4p3z#A&rv zLC-&>Lx}3f{<6;ReMT%J$Jm!^=>OK!P}-bU-_5HW8b}wbvkFB4h8OgZh!y^U&p+-7 zagx%)LKUG0a2=4}i5k*p9HGIKsK$gb>R zB+qi;n$%X1St2}d@lQeM+Hsb0Ki>GJ(p-2kS~9*;Ajs4+MPB29!ap(^!%=_y2TH*S zGO|KC7oa5t*rN$-$lLe&4UJ=x@TD9`E%IhmqD9TFXt_|T59^ak!jeKkS<#kmN$g}d z*!P2LVDJN-keY#s5L+NI-}^N#z=AGF^C_*AQkHAImxw@|HAmX02i^v()AhdFn@B<= zoQ!KNhnUTY!a`R2Cu354@Y7!vrr5y_TXN(qBDvFp5{l@%jFuKCD0s@@QA@G~r6RW} zhicb}2^;K?aX`|5$b~S$IJrUv=`=SmXr#1N6m1s>NZ;}5R;yxg=WKw}GFHo6%H8Tz zMJss76_i;&y@eVE`od3|HeYE!ZeGnrIQ)!A3EEIY#SY-*4j495uVO=e0UzPym)!x}y)k1?8Ga@KQ=+(c&bNA>myXvivs>Kfviccg{LQQk&(}vyZjh`P zFV{3H&!zm!mWn71XCNFX%1^)ElTZiLE;twYmD@yaWA$eo>;pBq@`mTlWEzJQ?+J0jS>QxiMA<;<;bixK9Xx^k#X=yF^^37Ld+w*0X zmr+mUJs#yEN82-h@a!k>x-oAByVAehqN;cC5h7>Y9=xEqRCZ84jkO>QLt7ZknK;ns z&5CL{Am`M~j30z#4#IN3d-IXXj7=VYEloh8#;@d-8bleiHjTBsvMv~Dz8&WdMuP`a z%kZ~A)Wmezl>y&CQ^Cb3Wvn3XDQd;cQ0 zU!d?olCqI)L`Om@w8)cl>0fawFW~-|V{OkPOS%gV0jPN=emd+qIP$gv*93pGrC33q zNH$SJ&g1p617k&`;23_wL8gcZi}y~;PDHY_-jI+#rQeD3_=)2R16s+l-Dd_|tTP$D zgbs`Zr<l5oNz3enCC>?#BtHz?f>@ZGFp`c>Q!%$R$@**&jU2 z52|a+{e+5Fif)i~8$DEM7jM0L0tm!d8=-`yL zN7&rBzCyO4UWA_94URgaLYtp^1rE`SfWV}MHi{qU59&psjrM}4R-KU{fWSE}5J4FQ z5sagq%mVx=Okdr+%OXgh*H3a2E^D7^7_fb|hL$TrC4EoL$wAbp-6Gov$AR7F4K9;n zQk^u={-n6;feo1_7uh*ixsNlI`A;8Qk1LIswAIV;dp8xTmzv&{ORo2d@Z+Qim=WDM znxymswa09I!kHg4!vaBMeE^s+C+QT#F&Sg)*Gm!To^+g67!NolKIEK_khRGM4OCay z?oZsjQsLFz_2s>den%`(5@k1*8^?|=a=1Ajh>l3TyX1Ol<%}YPP90S{26fm>L`I}E z3g%@Q%In%)Iu+k~XE=5yeN%4=;+!Qxi%7uBAsnl5xx?tvFwtY$Mr!7lOq+Ae7B^6D zma&6kKjfdI+EPY7cL!y{gTV*?slJKvI?wsT{y6rA6J|gPPD#x9`@m(yKC$73ks8cP zF-F2gCC-rm)XDmLDU4?qh+w&=x~2UZy9E+Z2Oe>7D^g>iG? zeO2zecSi63e%sNx5cvC_V@Lxzv;m{oUg=h0)6~9u_70horY@&2riK!@+Kl2cl1O{Y z*Sa!*F$=w)br_yyEiQFR2;dHB7X;DC&N}ZPNrvI$ZEp+e+Z&5p6*Py6CFL*L8hK%0 z7>bQdG>8g0P(O+ItE*}qJI;Q?K&t*yo1v?!${NV{(>Rdq#RoM;3m@Y0Mnokc5PwHC z+B`vMUStFzmFhRiOd2@bbq|ZNF%k-}9i6I?)V-rDYb(oH`DC#{O1Ls(6I+=&^@io7 zl-0TP(=;6O@1u-=Bwi8QXL#IX%$8W7F7*Z%wiX6kZrsJ;J%@SZhIp;!v3+my*3a_k zj#&qX&u6r|*s5x|rN_Irp{PeO-9Sg}Bx2v*G;(rEj%iTR@##uPBuu>kOU+fkB{1$< zp0|j32lv31Byl9tNK-u>g8CwlD-OB?Zp2@Ur7RH-;6AFN;Y-B7CQsQUrT1Wd!&yNC>3(NrJf6nyYgB9ErSqT;}@p^U3t7l-NLb-tXK=T3@=FOTsPC8($-XevgAl{E`+;}(gXE-79s zWb7+TjfTaHmQN{!;VC()qC-en?N+JlEJz8CR*dbeO!(PM`)MRUishk+gQNza3<}86 z+bvfXa;_Q#j*^cf-Uz*puHQlWMmQQ?xIiOty$uyF!R;6{+i%`PfyuQ<`MOlvvf33n8=b=W-YneExiXHSr~ zY&Taw$V0ag`HTQdLD6U-sl*%8d<84(l~Dlh>&;TWSEOZ&B< zyfE!$KU%LEfoE%8D&v_F*3yYRZ|Uvg_}QdHfRwh6xVTyQ0|cD#*BFO{PoBwRDCEGh z{ew`sIWJk(0~#O`0?8Ox{Ge^|L=@Y~4Q4Tuky;dpL(B$n^8Wlg4$t_F>TgHh#2zcJ6B~ISrU+z zm1MN4AqY=z2FtT!_<&Jp^M99D`^gIhFlLw7A=HZFbhGl8_oa|tc`;5khewp&JC(b6 zjeIRL;X|1+D-X0Rkw;IgDSS}+ieAcpSyW=PyEeGcX z02=v%F178T(U&>*or^WZKNIlcKp8O&u#M+6lU@U(KX;xGA!H( zJT8@@2nGB+zf1Zk2O?wBB}C3ky7mdHAF|p~q$)gdOmo7AFLq?6FS%po6YI@~c|OAJ z*$Ay(%A7xLMI?mR`=|(Ur+rBDxL&gimFQA_aDExqs<$NrSsTGl0B(|zGXf5XeQE$r zV4Ejl0E!)_nh&>6&C@YeplYJ#eFDJg5=frgD|7>hE zA)e1PFM-wc`v`wALD%?ZQI?VpJ5_bgV`E0Raf>AyH4nnXpp5-sSyF|nzULo{f_ean zBd0z_Kf<85nR64|z{(f=JH#sNT^x$_{r4srXuoI=8O{`CNAvy*N1h-7!q2Qe5R*a( z8e#~Tp)ld9_4jzDwv9`P^6!t%*++-G+`)E+*fZY}i|HJS8~wO-`0grJQ%BZ2X$k9? zYPbFfnrxc{$%_El?jt+DJ;y78&8BSrlWiEc@XI$ldeydN9MFiG;d;sKcyYh5UVz$F z9||AEN+c~4D8uVe)mw4ni&@D>r^-}YUjJm~tUIVh&{raL8j^&M<2jJThGuMt0%Ff& zxa$`vB2TS>0w3f&<73UgMWEn%=RF`?PnHdA`Go*Isy20ZLfoKY%fSIygSY4(eT2;P5{HDWo`Sy8}cMI6siD!z*}XyQ+%fM zjBIrp=OA*$i~#7BO6Eg;jq1(RrJYd^`H-%t0OyvuFcR0LRJY?2Se?u8n$N{Zza0|} zAmRMk&hRl?ImO2}YqlXEHPj?PNwk>9Q)v3US8<;0@mQo!)1Kf<-Csd1sX-#?Sis2i zD;qb{W!f};xE7vNR8$dkhdQUgRPz;mPfC1{XKyO-B>XGwFQ$2tyXfKM=7UnT`5<+o z`cX1TPq7~I5E71T{AYy)$x&B{@bYbsyh4*MmSM0Iz`&y!!%0Sx!;En?wsZ z(Je*dt3+2OC5r7#x|~FAwq_P`)$f%b=-*BUwI)8N-R#qyiE1T*)K(F}6xyS5#IJ#( zXeO@9OPm(OZGrIrwsxIMGEP(u$|BjT=WN@Xxow4=$A+pE_Fe&wxkNL+IE~P-y{60V zs=o=g%e9XPd?GHTm=AP~owe?{Y2A`RViFeU!2fuK-JCrKQ>d| zH1H#i-SLb4=*VYYV<4mhX25*(6h229YEVK(QmYsA5iUX zRz2<-Ob=woD9JV6|4(ZL<3J|qBzb4>MUSh9sY4Xtqs?3uYQ)o>Axa>Pwd7rx5$ z-0*-P!Fm5%r1`rIysAzwn!VG(4DThOyB^_kPRWq+Z;iBHHAZ4{p*iQ4mXl$GsPrIo z^q&dZLF+d#n`Q>lWg>$qK8L9Vda^I?zJQTIsd5N`pC{^J!nz=ma~w^lPUvRQVJ; zR-}(dhF}t4<@}apg%Q04br;jwVIUWv)r`hH6y(9df^iIBx2{nP#MzD>Z_#JIu9L9v zE{xU!Yh*|N7RObTO>z3l2$Z{ibx@!2xKUz#1B@BC zmCtcpwdHS3FfS46-%6|O@+pxE3G9vB7=;$62l?$b74$}mf_fEX!s#f`v5~`RcxV+B zfa8z6hD$NjX7q6w9o1vE5!*bDg|x1EAu=Rh*2o(fOl@<}=0WmoOE?%mLGdgQFk8<_ zUu^4!DXn5D26^zpO4Nn_ArUWMr;HJ+Z2V)UAPrr@3j%}wVItcfc^^+D=`6`^9vy-6 zFvRgm)*4al`h2mL73Q0*rOJ62%NS-RAjP_A^GjXHa+ydK9Tm?d^s@p>d8&r7C27c1 zlS+AgJr8MEAM`?@tc+69mU6eyT*pl7*Q7emP?@lI-3?Io(2yoY$4~ zcHcVLQIEeD`=wvfqH~LsD(1;!iAg0+{5$<*+ugz-SrO9yLBI6B)%^g9+0;OkXt&Lh zRO`hVMw&*)aR;VY1kX-h`*Q}52%y7A^F)AQN1I4%ThRf{exl^&MaL3uRTM!nwlaH; z`?4Lu8;xpT>Ulsg3_s6(b?mwgU4qV5D-k;%K+wnax@4HsKO!4v zd_0~SBf@B`myQn*)BqL_uckj831uNW++sxi z({N$lb&j4NaF`FVvbW?1L=<4^JvU}zKc$)Pl$Yh?8QO^F4~F{;pv0+~x~?s1wO=M)}c@GY&AS{v*b zB-|YmBq+(TjcUSIK$)w)j_WHKqD`2u3`xhn@6nSif2bDnk^pMr~eid%PjZrvwq?JcU$+Fn^SWwRF z0-qFVw4h-taA|kQ=XYW;X5$Te-~8B&tYiBtVcX{d81BO%c|`vO?6knwp3y;kXqoa8 z^*74Y3ZK7SJXRih^vKerOIUCLgPr^i-LfITX%Y2}XQXnWI{K6cPqG9Lw#_JM*52z5 z=38|zFCpDOEt4f-t9D*Y7 zk&nyF?K3cEZlVkP;e$Dlhu7bu!wYw))$k@%FN(+o*w6+W#IupqB()7hZ*$-A?fX9(>NjV=$n*ejvy$Gf5eW`q_tz-D z>$#<6+xx<6VYnV{kEp8I^kAQK3t|&>Bt#H4g?CD*e#)@mBT^0?Ns*5*@2W^{vW#V& zKgWTR=b7Wj;2p`<1HN0Ahz%LC{kSNrPq~>{7SW-@$5{PmPd5xma$$KxTr*mc$}?bSYg)@P}H-7{ghj!>Eq0q9`pC zF)oF1sJQdOTt6nbSs~nRE$|EjPbb{eemr;Ji@KTBKY_S11n_`*&KIN-wE8l`Uzb=P zkl-!;83`0-h&Gys-bKTAHOGgo5zEqdxDkp{kz5H)_9V10L!_wm$$rq0LjqTEHLfe@ zz0WIU;yHLLeMjb2k_j3=RZ>)@ew~_VD5`Rp7?GY@PN7ini+1ojEb=}ENYhj71tZeN z@WH27!%`uXCp_vUS{|P76ylw>@UfF)4&>34wp&g#2A2h7DP3d_y?Q5nC888EAs1g* zSoZQP32l;yAYcE`AoX)TiD^)z%l}#u?wiJriJkh1>vI-~=eo?OWP#X&YtCnojCT4g zz=Rx|aOpi9xyqbdrc}-tA85();}DcaWzr^zdIJ!5|MsfMsDk>jJ00c2=kJR^M_wvO zQ+ms!32k9_44g#8=J>7E7$yN#GRA3YxFt=IBgOSm*m2(xVwvgsE6;V(W8uEIVxH9?(aDi$ z*;wHG9IU+kC^tia^)E}fatUi;E?g#8`*@nm2TsXAY|4ZNl)vyFH=8`(ctypb0ceXr?qFf5#Nb`Ksd#qw+6P9VQI^i0uSfr# zouj#4C+EOb{$D+EMD-t50zrhy&*lZqq(O|209FL}HTW zf@FFF$*a&Q;K|`7aO0`5+2W`R;1md;HMRoqVBm4u^xV4`h9uLb5*4fQE;q=Jq4;bg zTT21=2~MPNzP4~0uF)oZ*ntcfJt-PgZxu*@HR4-SY-N)! znnD~bIjr58XD+k1n#;kUG@L|4_zZ6DZ^=9gR`NY?M!)9V7sv)><3hT?D9yJ<_1hAX z1~1qk=D@AE zN5r&9ZWVdlmzCKqnjf|)9l38v;N9m`O03z0TMmc;<7d_owGoYNLXg^2>IAH9a`S^f z;qt_MLy;qICdN%62=pgMh?{NTa5G1&4p&&VchsEt$lQ8*@4X$2`6Zx&j(`=u0Fem1>((lf>@S=S&lJHV~3nN(8w%;3As)5-UCXKQ0>f}GrL`N&G@$D9+k^9 z@4cPqEi*Mym1hr_ppclB7;Q>POhfataK<%FU+q8dXh7-y74<85CbcLbY^QH7xLB1V zI1JnAaR?OP>|QkLIKb~@<=_?<8Teo+%q973OmZd}hcBF?K9S+7m5Knjgm~L8YzxTw zfM6|)zo+M&60c8LtlKAtR~*97i~7^SompG;Dycr5GVl13xm%!5-SwLS_Tt8u9sL$b z*hJYmZahiM+x)XHAkWO_<$IWKSIV(Qjc_^!(HAoEbZ)}f>1HX$tV~hdo)*0*t$l|{ zM!l4-#&yfc&|-PTi1wYB`sJRPO4m>|T$)c9+l$-rmo=Xc%M}Xt^&L2oIyHD>&hf#&-LPE8|Bhng zlhFhHtByI}3A*NfJ1_!B2Hh1qtBOe)?%(Me@ta@^NT)3V4qsGQ6$v68W;&{n% zI?4nFjKSZBE4^{N3kcsTN6vXU%$FWx#!U{W#v_x*3m>SnrR`C8R6ea2z6T!~pw%qB z@g{%2_4!ZQQ<3=S5?o@9oRrjWU z@bYV0y=IiKf*TRJK*ww&1FMqR{_J=k{~j ze_q9`j6^y!Vml1I{tcvxhLh_raAifMUFl@#crzPOL-g6FRO~bd<6US0DnNyVKe!=S z(S{GNBh2i|2N|+EXBSoZe`(cR2k$Wa#k$}{EG1+N{9|H*W#ZVuok#)KTDEvexbTss zSY9*BHmgKME612cF%~#CUUfY|7}L{dy;d<>oR*KjU1uW=4vY?VRXc^RH4m=%;j!~2 z2Raga8q4-PvK*T}mVfgh=VsD9H!x?4-6moi`7px}Xz^*(A26G#gqZU;N-r1>@D09T z|W%)On``QanX!Yu_HyWtB(KQ&hssm^}k=p_gdD@ z3afB9T2Wb_z!ar6%ub5fpv*?xLDTLJ4k;4qCg?|Rktiwsf1xn)lnCgY0N5b9hn`gv zRd)R)pPJGFD7&UR-|V&Bb+1_k;ly#)$;?hHv~AHZC6!{5jE>Zi-cka>B;|EFWt_ai zRMH4AVGiZ!w%f#7Fpo0Er<`i4)yCJ6&{&c5?p>`eU-69X+Ig{0g+f`_;CeQ-Ds$qB z6t@7pG~yglq!09BwvS4d4>YRLhj!!NPo;zV?Ui_bJc;H7*&vP_0cKp{Gd+b4?x_Ps zy-gucSgZV-^3t-&B~U8VQqrC-bempTZbrQ-%$kzDcBvK>4!hy*o08fPG@hW3;X$nU zg16g7J^tYs<%aG7`3Z6aE{*IgSYYWs+Z6f&^Eicukd$*eM$++mogt8uGaos(4mo#R z_QY-@#>h71{W!QaALdw6V$})wkz0QujZ`VsJOBj=eYe{t&-tv-KkfRJ;fJ`0vwggN zW&CC^wDbv2q|1Wl^$`d=F~~vHjSGP;-0Z!@_QR$?;j81dR_$X8(&s$%2P5n?Bj7ZY z?6&_8GeFG05Od6X5e8N2`uP=KY)G3<4Ic$-r2+KuDV{n6OtsF21pxGe*rk@5tHHgQ ziz(5F*5Xu{!a+C)Z+Px*i}qo1~7|+yB0*U%R*Xp z(I=gIYPb5_s0ebiEeSoG%Y%hwR+h$Y)o|jILVV~C+gT6*Ku!ypl2zQORKjaUTlLZb zQ3}Kps0B{ecnNsJfJbS}6hN6|aEn2$CiIsVZUhjG5cqOkG9_Ntta#2Z!9WMkMu8YbU%AQbq@4s}xx8$yVWPh0of( z%pWc=l@vFG!8JRiwSSgm#JEYc{k(3FfUq#{@Y9-eG*W?pDQTt*75B@1q#ZFYT>q4Z zEfWCt*tomKiVnLp5L!O#x=1YyuHTWV=+;{YPGAhlQ#zXK%bfk&S(xe75QH-Hf*zGal~Mr z7KXq=7ltMAfBzI={*XTreuXG;Z&jQE97)UYL%Wp(*WIGkH-p|tcL-?~j&9hDV7;TPGd*(pqz~+)20-#UAy~^_F*MDT6m`39B~UdWVvwj2bvXu@_ohQ3dXogs zrgC&F@Ul3T3-bu*_UCKJ+^rITO)Tco4ztCk9wn+5)v7drqq9b}w1K&F6&bdgG+ex% zE9jFW&>^%hc(}i98yaL6Dx~e|7p?+&-H5mFfXGF44#SRjvU73RfO7k4_O$5qA{qo) z_^J*Oj!sV=t)Y~k-Ax~~S{M|Y^ zKkxWRe_xD>yxQ`R2nf$gwC{OBeQT73dfN~F;hgY>Ewyg{&fbw&y zm~9$QJR8+YI1SAmBt28xQYw?`_wkVci>2{r7Y+dV(7Het`8nTE0x5}jv>x|7u=F!u zijr6t1HvzB;vI6eUwxh0KKb?S4r7d@Wf z_`^_=Nx%h#hpDDSf|{*(0FDN#;|<-dbgM-o{1-{8Q?c_5v`2NER3V7D3fdXOWqSRn z_I8J{W+2~7@QkSBCH2Nq=;(GBD_Xk7{94Cz)O5A<1hwwAI%*ZhVPheT4aE(0(R&xz zTsZ>vfu<5?TN@qhFw^>zN&Z@|#9N$PRPVXgE5?<^@e>VGj8b!fi}+kHbGKa^v5>S~ zRT5Dd6nIQL6Z)V@msq!#<(^$dpIqEx3x%&cvVSWDaY9H2)+w}4oVSMa5d=vwvlB{S z-*(YPDm|umtjKc}dms@pPS>)sVID(40i~{;+;ag`=RpIK zVhjW}i3_FSSC5{i8J0b;sSTLpX?d4Ezvk3}!C@Q|`$3RU%nM^ZB!w4Kho=xUJkNyV zZHcLpZ*6(5)&M%Xo}AvlX+KI0K+7haAv{v)h4>XIspsHZn87kwYayeweNaz9U-S{E zn_-=WY>%oKtSB=rE9re{AQzxlh!JAl3-`)#ULZw^*iZ_z5m|*%v_yD>p-g#-jv-6Y zJ5Y_fDtTDmF%0srl|qHc0PlVUgkhvxt`Z=a9q5qc2s#9VXdM(B$)5@*MO_Q`f^89$ zC+OgVSlllds>d9mb$MU_QlPheHpY-(F9u5+LWk~PP$0$M1-?Eg*j5+{f_fsL7)itg z1;C?4uxEJh$RzVLMV3@T8CU?r2v80FpgR?VeW+rC{xpM+~@ICc#zLSGNxc&#p@6kn{{XmUeWCC&fO6(>=BHxu{PmHKd70z6M z^k^c`vzl{xpe_&2HKDLUZUCeYr|vB%GsIY~#d!fC?oflB?nj1~ZaxU`JB1+2_($fV zA9%z{rlUe|5ucAexsqg0ZQxI_0!&gxq!5ED%Bm5AvIzx<~j7ftMJV+adBFX?@f$K_(b-Klr-qih&7bOQ<+J67L2>{ z@eL(}yjVt7+mtGZ#*1)10iIUR0HAr0ekJ3Lk?U4=PNQWDNo!v3I#I;>;a_R zmrxKAn!;lJ6Qqurxc!mU*DvDe7Gdw~2|3NL&~fSBc@IS%Yffw^aS*ghR#f|@W!dV1 z&@{{GWWQfAH%wUkt9yN|p=bv;EE;$Pf3;Ef^hO!%I!i7x#njMEB1$Bx5zYbkV*+EWT;Y>4+zCL$v*KNIbLb! zlmak0ih^DcoQ>O%N$|DgM+0M%%w@6dZSU`3b;CNIwe7wr%Z z7>J!Y491Xr*U}Y`hL@PX-7!YVfDi)~SDV7sApR(Dpn|u&4-CCwh{mmm9{oDzyO$EB zTxe%P;Q&@x2%59>^Caap`9v?dCfexhRBVA=4jQoKyU1WRE?up2#=*fBtyX6;Y(5DU zLKMk7t)wUUffA$8zH>g{41x%)$WJlLTLASoxgLnrUCnoIk&jdCacM8?PlAdsYVg4= zJ$AMHTP(`}zopQlvfvlOWl<(93^g)Mf{X1n3fM{sPb}POYwFf6zET>=nKt+vL{!g3xeX?{&{}#zyJ&I{ll>OGnxjDOzB1#3P|C3pOP_Q5g(ELPSk$QP=ebLU$Lo0-4ajoP~;8p{!-P zO2g%)#?hNg3{yFuPno7PW($GE#j_x;4jqBFj>rv5jRQe;QL}og4e-E~RY*#A2VC+7 z4aIj{fxgiJY>Xdlej4N5lFREzWGV7W`qoN-yeRTLvos9>b8;EyP5}YiEE~|$C59mX z5yXJ|5)iR~mjt60C|6+(b46_0NkeMJrEFeBLP4 zWenSsYBcd_coJo3)@fBa#7A3CGJ<(s+RM0@APi5Mv>1WrE|t8G=rpl5HTyi168-UrAn@ zF#%SfAc;(>jw2ca-{j3xB$N=9#Z)d6SCUTgfEWto5A-+em9KCI%WncKa13&rSQ}Iq zTQP-uBDF!#mPI7y)^yHUuLS3-qx)6dOu#e91g*;g6btU8&iye_`DNnD^s6&rm)v!Lp0 zbKo%1q*Be!D2VcL&y!GW0rO<>mjroLm53pg@t7r0ztAA=X5sh(KVdfFB}Q(6g3~t_ zN=U6(8sRrz`sUow|FU?d00d*B$5UfX(tc2Y#d7)E+c8mUly$`wgzJ4~_jTTalHq>B zt`Q5SCsbv$arEK%5!}xaNnZS$`hc0#<>_QlIisI7J7BHcc($yUj}0Xi7CN=DMalU3 zH1v96=#NQp(HQXGd}Z?<%Gmqt{E4m`R4yDc0LMf*9*LGA z+e~lghvUJMJpu2@ zWpGZp`GA_U9yO%nq|uUh7n;+A2C!u1H*%!|2~e0dzs4hBh@yB+$$&Gt3zjW=&%!n9dgx(7MJ>D@NbI(1!g>+2g$FxQV7=YE1^QXXN5{-^G{)9mXXTreA zPdIX;ouFh*EP?x{NATSP4jLHN;9$t`o)X?_AAC+OifGM{VRnb*12RR;i~C87yz0ZH z_QJ!UL*M>HP<#jUkzxvhLLV}DHZz&|(1Ro`tNsJSqk}PiQZtYms49X(7Rn3cwhnk} zsu62Fw9MVj1O~=b1@^s#@lP>hCVIZIA^Wbv#ekpj$rVX=;BR!n_+liZZg+3Q{ z&t_u`ZpUeIw6)@9N?hXX#*oEWj7ufIo%wdi40jSvUh#wya6jvxI4t99AHDU$%Jsrf zUwDAO=XrqN1N_BFbfUOB3J7Tg2Jplbp~^dGuaZeO-EW!61V}e>C|@l6A`p zT0}ligX#~sS*XAd79Px7c!Okw@LQ|U@rVJTG))^>c53@Bl0`v1 z(QGbLx%7iH!o_$+=6G)7D3l0d2$M7b##jK&fF~Qn5JX~`2}G>lE+h{LHo{01i2b1= z)&eohEj8QtAW;6&1Nx%zsF(g%BA@&_seM@i(GiOiauKg0&_2S!^P-jXRj35j6No45 zy#g5^Z=*+<0Cb6AniS`xa{FW$#WH}`k<0ObGbdrK{v3D-j4lS4VjtYtwA(7SYqfoo z;e&HuzVd^5Nd(_#A4+p@tYZ;B(HXQ;LMGPULGDlq0b@d9+bNcX_EsV=l4f z04O+SNCYrVgV-%d;i1?b@dyK?-8KW|M0ZJS9WF#Y_&gj)ScB}&9yJDE5R3ucOC}Wt zLXkm^_;SbTU7_DQF*B_vuq767vM6=x#J|S4b*vBrKN9C|#sWVm1> z7Rf6o7%uhe6kw!jwp`L|4z;gEO-mP%r#3Q%!ri2w*l?Ux6c7rBPqP9|Ghx4484eAe zDl3qIhCT$^EwcP+Nlg`dWIeEGPHc3!`X7BT47C)o0W)DA{KWH1F?#bQ2Zh>Vw%2At zCf@=Xxb{-zg=a+zDk~GX)ISBDhA28jpc;SpC3V_}H1Y*a1ce`iPk6>Kk2H?3jHnIk zAY0}vmKqWSPBI7jY2C*u^mI|7{SVFL1L(IAbc-Uy*<{VGKtXzJC0ve3^kfc zdC)?n)PbgrIiobK(yhQAy0~+miU@Es>9>K(BPOsB6u0oQll%;zDP zWwRRd7HXACfY?B?2gfPBInW|7Cb`~mpW$U!-6;0hBSwaBU#eg5cNWl~wguHw!2`foXBk2lZAm++e0(k2jsDn1Ly`$Ad1w zD5O;RC$HL;_2CZcPMneElim?&3f)l2&M3~}Gy$RGsb+6LKb)%~Z0I|Av7sn~0+@A4 z#&lMkFST!I_S@H;2LG5a%6l3U_%b(J41fyC^7IP|*#pc21X1-PrRsJA5pDsa*-p#$ z%Hv@t`r@7+?do&{016u$S5CW_~ znM^5(1El3*SbDH8Vvn_;G}>o5U*25^1;8R{w4dU{;#CnuCl_3Ews@4d01N-L#eI*E zZuXfTG2USyWG3+B;_b_Dtf%>umtmBStS?8L1CyHo2bv|)2S7gt4utA(8cs%~`Egt4 zb%t7@3<9W{z_HR%C%@M2g4#QL>=Ws3wV~0THYS7m0AGhQVfwc>*fJ);-D5Ru5CWry zTG%zeC)?T~h{b8IGwm!(Nt;5+k_e78FeAzfQ%@i=HLRNRWv)N=xakmnde8X zn8vE|!AhbM6=S*J<>*5la)}P1YYDa}3+;luC4{ZYrWO?sLPy?ktPIY(vwgWv-60}% ziox|#L?}Q?qL_#hNQ5d87URCV3S1Y~n|36~tV{JaF&VMI;8zJ2!46&et1!hdc@gdA zl~1@Ra*D_uhs`2W!ESnhHw{o`B}K_gJ;8&RxWRcxU7NZ#OyxdkC`iZ`5+v(iqn9ga zrwtbKbe?9^OB5imaWxoBc4&GEaA~&aIH8hNu}QJN>Z7DwBhcI{Xn?ED3d>lo)h9Z` zjK|RjN|pOFltnakxZE2&?T=n=ih{;@yruH3j(MsPH{FqE1k17Q!0YOv$?%LHynuq% z=QFr(eithw%3D~X9o^w*e7Mt*9qSTjGidA~PKg8=%3W8_Ar<&{^E3brr3% zF&PO?Rg8)Rz=9!Cay`L9P)QdDK2JA4Vl<`?bqlz0jUJjEJ8F$tjh7*I>`1>+o>#__XZMfnfsYP97fHfRkoE=+9TX(NDHk##cr zp%A5}Q9dM5BA6-rdPSAQz-*eBc|bPT3V~5pz6}wfl*O5qvSLE$LA`<4Dy3Q$c7VXz z2wN;O2pBrq!|kqn0b0BsmVk^av~>=aR-WWT=S=09Ivtz)l`TLH(__lPanf?w+|!&rR& zQw}(~R`rpsQsgmP>ESp;UZ>$0u2_=zf(G>+N|4&7yPXU!*XaB@;|bEbl`0sbIPWle zb0xw_o^EYTvN3*p#uoy`&^N-YDEv_rDr{naBtlsR_%z61oXJI>Q z5$g3Ieg`>}>{kFcAjmN)j7GfoPU2Z4D-_f9wnpr_xH0r=`1yW)j_FiHdsoLxs*<$;o$REHd-bdA+| z0i6KO=L~VjWzl!GG_v;#D{?D6m6)n;C;(Inm=L9nZ~E{qjxHME*(OyOdfY8QnIGj$ z)r(cCN*cm6f{0a0&r%sAzI3hZy0vaNKIP|3$%JGjhZ=%{ym^AezF15yfwkwbkk)-z z1Y6pkp{@Xq+NmpCgrB1NcN@_c)r|+yOOtc48$Ve9B4gUjGjkohc0^j0O4x15Rqn=JG zf36Q0nr|(};oaCq?Gx@apos_dNLq}v1YeV#M`eOWdeW> zQw$%S1Ht|qKY@UWDdFyHlryGV`j~W?XCt!Yo;5^&*b>Hv*nS^+k%v+A=9l*7F)Wer z+jz)=pt`zaVG%mrA=P4*^3k!n#w;Hwdf_jp4g9(bh(c=23)<_@rum0X>2wt|7pf~zA1HR~IvRYZ#()AlWdH$H#p+O$5+E)ZJbeJ?u^%j^FWdGMyObpHu#1cmjgc>pD79l4HS6L^Kq#-EtG)`=h!9v+3*eCpqjbVj-J#h!vHO(;)f zM4Fqb$}yKQsM-|UO(NxJL7j9O+pawWmk(Wz1)A-y{$~AmuQgx34-NZ*}~LZT!8(lgOA#Shmz=`$X*i(NEDCbP(`k9 z#>gu0w7nyg;JO3r1X8;9!rLtifo{g*h{R5$%rB^YifS5|>MT?ok@o|-IR&c24FFMs zp^3!D6`5uF){CJ4L!n0+#93IjpTnpr&H&WNPEbS$MNbK^Ww{4L2wcUp`7}!j2Molm zA3wuf9he2lODBlO)JFB=|GjQ_gp$%86=%r=0UYrrLdMrDwTgv?{o*mIHOUR&J+EGl zLMA9^jxz#%)eC7XB+hkle8*7jg_07qT;XRQW!9`nAhTUU83b$0b~)yYQF` zGy?r?oDL9$JfS0m6Q8I60&8N>WWt>ju}R!cGcU{XR$GHIBS~WB;@5eM#+^?;c2ODO z!lM(I7~mXLm|-hssnN?MeS+5MIwt)sXG};TP=zlg+`OO))U-g?x=5I#qstgFDimK+ z_(k=Q5Qv0}|LZyZR-K(2+Y7inLqN*?109IQxKb06w`ihasyOT5`_`u1z$v*Z8tk2+ zksA|~43S%R{Q~;T?PNyilp`11-ZP|+RMNbPB4HsMF{R9lg>JwjFjjjiW-gmRD6>;d zL&2tqY*b@d{=%G``Sv6$3NiL7M@F`QyITCC2ad;WlPjtXsIsIMZZWX{-Rr3mnH&h9 zlEc^0_at_VwXDlaLFp2vor{;p52DKFpGuk7>_?gSHOQYK{a3tzB9F-6v$5mFXaE2z z9C$c&fy``L8zor@0;0z!FvQ-X0l$gT;BH2KZ~u{7acvONAZY-N#nF;CK%@`xz8$iG zluw+OoxJ}n`YH$WTpx!A$V@~8J%WluA1Cu#%=n~I6eTzc3>?LOPXw0^r&{cLV+8fZ z4ZC3hsFhX-R<<>Wzy%RH{>nVkTAD+^jipxA#E@cR<`!f2wSt`Hc-eZdv*XWhOV)a<3`kVg$9;L4!s=?A_l%8O`XIT>}nlzzf zRU*Q3U?MbZY{vd?KE_A3B7mEM&DF`;FUra~Jg7HLe`vQo||QzD^e*cq%hDIk1+{|K_X3lY7NfNc~9m(89X>2~~-k zdKF0!!cb{5T8oL;yqE+bYnvAU*D;wIxDPqkw&(TN$HZle5)P zW=D}ZV`^PxRtLgOyNB5UcIXRIN5fwJWPQb8GaB*nBvJ8)dl%}Uz;Xmd>O7T;$SVir zB)e|=fSE0F&XA>F1@0Mo`QVHz7fz<+L-7fIF`zo}P_V^QqKR+z5S0gK_r7NHI5ezC z02rcxq~_%c?eyR69|d;5L-9U_<18)QL149fVb zO2riv2*Sn7dKUj!c{U3c{YCa!}Eft%-~f_!;9HgFl)2R785M2T|z1OynIOz_*u zN)-I~#KLpGUkP*S9agSK2H(q|H9qa<-4HvunE>gv?=^myPWbgz^t|g@DYy_|ZzV(z z+*xYnP&l6;MDB>FvNUo@_IxIH@4Ev)A)e{w-fz#z-!9;8?eKDiMPBhA0;W{>tAEj64mK~@L1>>(Os}}I@8A52>}J%1FWFlOHt8X5$*e$=X|LpQ zKhQeLbjJ$dTrv<3K0HKUlSNhw5!ssuGP2LarQ=yFKLfEQ|4LaT9*Fz{SSsc(nyy20 z2YiDG309TH;Is3(Wx0(aRy=}qXW)15YGE1+5SKb+0*t$S$FK+8o%67G-ZWgZ+xlbZ z*?qTEomgN_k{@zL2i0aAOw>Pz6;-;M)azzfsYWBw_Iwxw17*)1g2Hfv1-5!*Q5_jO zI^vS9|ed)u|X!G*lT~PmqNCeS?pFA8fwoMK4Quz@=~T?6{@*KZCp>zCE{Ep)YcGx zU^5v@B9uSA!Jy|Z*cSqpjft>1mYwO>G_Gjs*=)ZX7m@Z8W(LQ{V(zTY2C~@}TG*It zpo5yZ)u^CixGPC~hgwBwLQpWMmw$~=QYH->(zAOn!k8nNc7B_KxEcD^ANw@&Z2#iYP z-q|ladpn*2ass!FS}4Lb?8b!AI~YRpU3Jbpazgg*h@qGUj64*RP=GMQblw}gxHUXc z)`-HOh`IzXiJMa?BozfV|N1Eh=OrImL7MKO?p{#35?>nrn+Y!;ORit{T7je@BWW( zT)c(<=negZEH=m&7@IE-7mbeJ42Ii6e}`ngXn%Z77ZfHqC?rq`ZBhfyhU(qNfWx%m z5v_Wn*OSB^K*y6*qNv;$kp*3;-SfWAUyjKE&?!I)a^V3Lp`6Gd9uxZ6thH6^V8!@~ zu^= z@RIVxk$)Gqi^e|65BL%_aD*|4wTjsU>qzNlx!~5u$Sj0KEQT+PW&#dL#R1b2^fM{8 zW}shYs#Z=|TFu>yC_^SKG#r$slR7uTrScgRNsA*mP%22n*>g!;dE7J>`3^X?1B$6O z&cQVL`3ERSpy=rePo9%v3KuA3=EoZ41pN zmZHI?vEWG<+mxgH1{%O9B=1E?(P0fMg5_nP=5sklFfTXO{3owzO5Gl!3+?27WW<); zP(Jmb6*CAam+BU1s}_sK6Z9gxNy0{oUFd`Hzusc7j93j$Pa!!0Ag|UN(4|o6qmLk9 z42-%?MI{@;am+_C%bofg+z&d85D+hm5iD481tZ8>?3>`T^P8h9<&odVcgnh^Md2C8 zyU$MTQnpyS8qJFPUjG86`GIA(`8A3`CLN%!3JYd1Aa1O$Y)hR361a`vkg-u)kXLcp z^<5k@(~;IRiWW1x>orYIQTlV!0qssN<<9%n$_M9L8<$xd>y;FeWiS|k`B-8SD>mlS zNi-Qoj^wxc|^> zLvq7Yn^sKQoMoQ9cx2{yn|O2A&_8LZ9fhw&6gQSf3IE`ALM~)Fq8{Yfi$yP|Z3*Ml z3izG{wx}Q=Ek!uKJirvA)c&43X7ae}j)*^3fk}?qNTzDqsy`V_@skU@=>>oXjV@<7 zVx@F6_F%)Qf%%ED|1kl{k%K@X?dia~3`s1w+ZYlTMwJ2CkBGr|C;p;?_x3P5Vqigi zXiH_F3&;t~;x7TM1S&&;YL6@F&d8mhP|sN2aR~w`;IA$0Hu`?lU9AEb>1<@nGA&O` zK5@r)vzYfMEP?Tla93{uvO;(wBp+cFR%-I)w#7!m2QXFbwu zC?`TW#H?JzLkj`O=?7MgVGt<;P6U-SV(730*by=fp+p~8+3jD@W*ymGX@*U`Zy*NVo~<;!+bee|!geLeQ+6ES#=Eq%jj_Q?ub2R(^=ep0S0j($)I>v zRAj9b69~p$qQTU*S9$FX`!L934mZsr#}&d5BC8csh`u9w&Btc2iHOjkXyHTk#l!QM zePr0QZo~c(O`vz|^{)aEJ^1`Y4$eg7OHe7jr?X!Y!?8SV*u8=}D_mMi9*AH&K@)v~ zgatn*3tZ8@Hv%h1NPfi8DE$aX4Nn>YAY-FKNPH3mkP4nKHbce72>_OYU{yiz4F{0&6C(isjtSg*drCqw%Az4Fs~e7l$}GXOXdD82{xl8}S|XJ| zB?TO)8!gxZnvf}!`GmvCLVH!(6aEpOF? zNs#ei$PPRfybm5h?T($+k+{bImy6XXe^?$-mkV|T``w|%;0MhY8D6p4&S8cVJ$qeP zk5VS$*$=BF**WFz!-VN6`;EnkG(Fp!gQ2Z7SC>Wod|)^O0pxV2Y|;9m{K9W{u)&L$ zi~>XMrjOJrSu@bU5)6273>=q+$^+mf3<_-oJv$nQ{B|e@FqVJtIuBsH2?em}%8>seldy1F3Z@i2;3(pE^#@HGZ7&d#k6lC7$` zEBTpmG9y%o^I!=8l;ec8t%!s`=FfoI2ue)GgPt^Y_XKY1vJVkxs6H#{WSI6>bz2on ztI3#9o&0*Ssy>Ro*b-7)!S`j6mmfCS+M`CL||e4xr032Gw&~ zgnp9JN~5sT)*}YBCgjNpfv8G$S-L~RUWWrucp)-T?g2?YnoAmGCXCtP;U+v&guao& zjuV~gsDyDh9@gC}q7*zbU5#0jAg(zvG85V;$76mfk*l&peQ}Xb8|Mct3yalo&R>X| zW8hjVHKN_5bdH~(yQWO15##uT6yRlRr-GV`PO%{kibH7CSD4a!^3=%X+A>Ne-t__u zd)!h`DkTFFrv{%mVK^rgp`hJHDsKF93x&%Oql@BWZ&9Fez3@{=aEPQSPuX&~*uI|% z924AWWew%YKaNnbfF0L?SepE&vC8xm%-Fyk$+yW)?BQ7y=>}uouuIZt^dt1uEIopk(^L1H z!S5EZkEbyPx(domtmF(_GjOTmj4Se3KM0R&97X|TZtS~VuBEg8R&tetRD2fw8^{Ah2E0>a>pIRm1Bj4+Sy4P@7{Z{v|AwFp-kZqk5IlJS%= z2~d{po0@2r4SK3PZ9}1-C6n+`hq$nSkN+T8NMP{xaWa$M7^-BO>5$0l z?PSBGOjk2H1USH^ut9+tx-_9a%lM=H?HdqFL0CGi{8im%zx`AmE+kmt)l}d9t`)t< z<2YR4Jn-ikzaux(TR_C;d~Iby&8T(xR@<}?pVMVCLg8CDR%uviBfl&cH64-P4;JO> zqVvU*L7oJMnrP^(vzL_zSLlnfvNHyxfW#8qT9+WS&=lq%601>N(&Q|{ ztK1s17ci%l)odI?Rz$t0yRy&Pk|a?#qdZ7s|ASyoK#IVuDZ#J~ZUo%%>{u%VjDRpB zj&T7w5#de>lTg-!xo>+d#ZNR;@sLVtcT7rl#N{)RQ?PQ0sj88~cQF++i#H$>~kI*+Me;ghlCxUX?H4WwbzosU}aY ztgvUyQ0qrd1G~gzeO}sfP$WtD%?hxgxP_*EI?4esATWe`(lNt&m>Kt-s@M;ZO8`ji zC6GNMQ8)wMM|5M;YysFKEBsEpn^YX1F@Gws?nvrBTw#7V0aRHQbl;BDlAO~BX`4Ny zq3Npkwl(~~OjEjj?Atv-MA2hs(as4^LZZ+G$NDL6xb zjsU^i|CrnPB48t_>gc9B3)2RWB4}rGpwH`2+~U*gJ!n^3qi2Sf-qXLBFpNC~UhAT) zF)SJ`t_xjuaN@h!ajp%65#d(!56(^dW{Ka4LZnWtU_4;&Ug0O892RuSA1;Kl%(Uei z0RsV|ww@1H3t2a;cc2K-WPcuj&Imo8Cy=I*ptFG^0Pk6#!-rc>L}22qT7-l>EY|&U<2tJ04b4fbur=-z1B55w z$5c1IYuuj5!}usvmY+;!W>>K*?`#BsT06%rJnt4_0TW$~3AgBZLEx}tj;i~nSX%lZ zx-1tQ1e7B2hKW)8y_h-I#*FJa-R4Ppw1x@^*}zyFZI6p-mc&OgeG>~Sg_$_cY3Xam zhb!pH5zk*AGuCMJm2m1bMQ8x|h}_L>D4yVCw$d#)ENyN*R71@Sp62k1B!T;SGLcH@T^oKo5JEWD7>%d86q$}0RjIm zJvHaex#MLX*li09z!&?7Hp~kKbcP>l*^Qyz;`t7*&TN{yldsdFuB^4g54ov_5sSaI zu2nvpNbM#ps_qi@a?gthIY;{P3{c;KO|%+1f{0}}`OB9_YUqA|c{LV)Eq+i*piU>( z^5LFh2s~|+3fnEhb0@wIrtN5@SX_loxyUULXz>Jv_25p1LBkNGU@{8fdpNK7;bL5k zmt4pNLqdNi9-b9m1!#(0EWPyE<1NAv=SqCs=DdSPpg?1K54j|VGDKe)K;TA9$D8(L z`MtNr8(X9*SW^DAic(=5U2nrtzAg-7309DZ9xk%09%usPsA6qIB zc7)&w#q>9^ZHPfAl(CU#v#xL&G!NA_$S9PyGco3l9vt@RGAb<*5_cxIy~9cK1M@`f zI@B%dlrO!ZmYM7JK3+O$d;;F?Wr6xa&K$Ug{?7menf>#j)(}vI0-goERmd)T_P8Vq z6B9Oj^jtuR11fZ%)cu(t2(S$h^5!gnOm>OZnerNvh&$8!LjOCiMwI1=2|)LH1Rr#2 zk%L9zl!=GmHQh_uf2HRra{L$}=fGxZ2=m0Y;r8H3e2hpaku3e_(t*@g?X~5ReQ`5x z*oN7V#G$dq!6*nG$KF$GfEf-GP|O+9bxu8D;KGz~wFgq11>m}1XT%PHASpnYRLp~n z?T(fRIj6mr==b8qFk$}MbRJi>I5ociW4M}f@N}yavkrjQnfqlQ>;fBh(+FL8KQIw0 z#S*@CN*4G=3Y!v+S=^2S@HDm7Y^xu{g@{^kA9k?hrMN?1!^{S$C!h=$Ex<4VFY|{T z2M0Bam07_xy;8)A9qdwJ6Z}>}ur#wv1eZ+o!GNB;hP;M;9VD4RY1PNcOOKZr`71s% zcQlE0Kjj84h+mg7O-n!+Mc+BeTt^7hI9@X&4b|F^T=o~n5ULIgsYs8AaR>~fPExef z1XloWya<^L|EEi@!gox|HZs@*sbwE=T!ICko9OnFrcAI@y)#BU1H!;_=ZiRS7D z6J~ScBm9+)0yO$+F$b$FYr|~1?AXzpC8&`ibj+7x2&}Tl0Vc6;#?anL1DsOPYJEoH zC|9zoUsG)Yq$Z%i2@~VWV*lk2@c(_!2~EItwA&GZ{-;_=nnEVX_f*^%7wfZPSk^E(6`u?}JubQ9F{D2Y1**9u>&ZwQ~^zlZKvMZe?<7@l{#ecjv0BI2S zwx!VNoCv4PJw%PN(+tOdH~!#KXqDMa4^baJkO|hM+it^$KsSJFBX8D>cL`xQwv)wy z2qF`i;W!i>sbIVOl5z$1f_F>M02XREp4g!=c3#L(u{QE1OVI?N`8pV?aow zI*p$I^`0)P1HF<{*z|G((2{rhkfj7F2ve=vtLwp7p6aDKAf~$|hRGlIwcx76TP0S< z(+-95dJ$gDNIyk^k1#l&Pm@Hz1>K1S1!}r{18?z+RLsi?NUXO$1&tqmRpOQ5fLJ;J z+)zpsW2h~00bC*A~ds8 z(>Zl>GVx(Qs*pj86Pp2=x71lx!~5pIVwA*6a6o-RJuHaMP7s*obI>HM9L~=#pA%@p zckSPKwl7{+zui|=*PcWJW`YRDP)NVdSrBiHTCot|134an4F%FoLXX7mf?G(qG5fXk z;s9OZ@%NxLw9rTFBF9qeG-!Yo(ab~G2ZBH^bfNAXOL!3TGCh|2WgxD@W@Ij0hC{Ru zdo6WmSCp(5NY6I7v=Q>eB(1>(*fX8#g)-pRwuB`Q$O z96{Wruq2a;DTHce@_+2Wamwi5(=oA zor^oU^6xPbtM#Q)xQ zsJ?Xsz5XMjIS$LKL`Ju4*XPy>@9!r0ai&!qEcZkdIW9F zXJJpiE76hkRzFNl3D{UFFB{>E8{;W~U{$)^RhBz<{t(1-j+OxRd1!u#hK8-i$W$z1 z+7%YHeUHvX^B+Qe=pYZf4HBcoL)Z54a*P3qxYZGeiHjQJuYVCQ+RnlPEU?MD7mJH< zEN@<}!~}LgJ@Z|rl`x=tiTs6jZ=+i@i3^N=6&~UIpD;{K7-ecOh;V`#m?}vkX)w@T z$Zw}I9IHtX*wTNIA|lQr3X_9e}( zF>6l{q-w)rln?yI=%F?R;5`&W*D4v;K(n=&s%ud~W3PGPL~tF_z8+FC^wonT)Y>Zz&`!w@nb+Q*5BTcm0glv@EIz!H?ROGBi*-YM%8yD!pB= zBjILVOhwx*l`!_Jdm_NhO|)n$0B>R}+9plI=1IoFF%_7q&h}~egVuB<%a2M4_l(D5 z5u#Y5$%@MY*<=&Z*z(mdb|l(8gO$++Ir;{eid=KBH2xn^vU5C*8L${BhujD=kl5;F zij8{9UI__a$xooE(ipz~)wbcEZ*a4EO0b=o6-cUE*^HZJivvXcYDqY97bRK`{ZnxV zn6e#*pg@E7;r4rCq6Yv{u#lDH$F%Ye)+aJeBP6Kp@4qaW5@8c~0;yj%E3D?KnB%20 zva=~j48IUTlxO7I)S|TvhW-I!i9FaKdlj58@{=;2lsZ2II~P*bj8rf~lp^P&kYxx} z|KQ3z{?(kE#`r(SC=?F3A@oZf6%O3Ow2U zu<4Ot{nWm)igKWH*{6Y&>{1?4MFO|o`s}%pe(x(jqPUugG=X49eRKDHO}BIzSP~TDyxI z0zzl))nKm57*R4C#U*w?BAriovGXamupS}nn9o#_!{ze&i6HN$!m%f8rj9Qpo+}>R2qE-rjt&-#L$WyLW45gg#+zPc`@F;0%R_^x1k?5nyN(>~b`>IF$_#TdVpvA= zB0FNyHiGdl!;6Lm^(^JLZB&Mwy}W+PUEf>K6}{$6J(ae<;qWq~ne3_AQiJxoBtR3T zmMdB4KyX(Id2MF0#2J1=vZ7dx6*_*1kW`$Ln+gQ7H3AKUtV);OP@}-kR%dbZLNW>RSo`&=}L3m*R6B;En58r(4HS{$(e1yBtd~(G1{Vf=9aG6g6 zu^=$b{t-@Qif4m*D={dw=sgV~0+PO{M!U7Npmv6|Z|I~m85s+Nrhkx6?&Qf3ffnJY zae;tF(Sle_f~*mRSiN*9d}BL(A?Wwpm9& zn%q=Ig?=_(MuGQu1{#Q7+&{{W*afsPYz@pH{4@M)>=(@$FO5;fhKAOrsX`<^;RTe? z>u3+<+EhUw4&XouePFH@lcqBXAk(5C5o_moCK&%65%j?XmEc@KUMoIfORm|e7l$2hkW{4oqq=drMr-ZvqYzQ+u0EtM?=@jhHkMi|AwL`3Ms zh(q50iL|sG0@b(WP7A>aV*g7wf<-{J&~9u4h+?0UCn}P%z81-q>GZI;2~u0BR3?Ke z^7|=c3;?hgOGdeX2@o#?&0wI2MI+I79|_spuimsk-%|BF#Rq{qEGVc5eu8m=1d8;- z7-3RPocZ%`MJD_?Ck^A^#DtTkkn74r>5do55<5(uq*a(zFsWw&H(pq`Q=<#xdu8u* zDcmCMh;NDl_&_3Y_Rz^@fE4jz4Uz(i%rEjTBVqwQ9z*_kf!s+QAalu+a&sE)nMYJQ zVIyebD#Ras+Z}=okodnu1Og@hFWs!ieBGcxH&Hi zDF8*SY?x{m8)HlWY(g>xy3Fhn9Bk4jR{SNz7@XcpU0$ynE1uW1WV3ZDXOpMoTrpFJ=NdZtE1FV8sIr3Rc)W z5wXC?mY{Vw(rbrXYQ{nyrPQ=eP}g$2D>{*!F&I2{w3nf1kG?U8;A*E3; zRnl|S&}fuaT`jC2NsN~pSzN!on%cq*4&7_@N-y6lO@!$YN^`98kaS9%9l$20SOcsZ z&}m1?p#}_JVa8tJ2sRL%XftbiR`+7n6y<%eUiV<&a-Hi@{jrn;SIn_U5_*up8#OM| z9yi;CU(b!ZREI-h6QJ0pwJ!dhI3)}p&Z(@lOpVQ+?Q>diP}v=#2rWr>tqjq2fx-cp zAzG8wtt?GYIAiQOg_AXo4|3X~DQcbElV?UQ;Xow_?Ud1w* z+`e40mJApxT4}lbEtEj-SI}z4FNm;f9BVBSv5&v&NSmtwt35Dh*8+-FjBcQ5C2KKY zJ{Ay^x=2f#Tr=$|xxdd#eBUunh8B;&$v~)p;>|YqH}mPW%5?iqCK6i+0Zm07XqaU7 z^FS3k?{9adj=xF8&km02W6Q^7^!Y!e-dc0|$OQ=*T{&J&5bspR$q!)6ONw}=ky*%C z35R6AZ@AM1%2-gEf%cAdnI-JfyMn27?qI?`M#HX*Y%ijUi!GrGGAdv?&eI+r0#f$E zJ`cxZl0~UL5+EJ4XVKSUY{LS42$qGmVs{#nG_uQRFm0B&R08AsIDuU)DI{drCnXVy zkp;p&Z~l|a!~G}+_Ax46vw(m_VZTS#mRZW!6m%X&0jz^+V40RayjS7ZV{)7!I(`C`>a>|dcAsNqHk^Qp97Jd9RaSumw&5qPqW*f+xY)xlPf<0RDR6k#1 z4h%|+Iz4hoBq}v@^0Sb)I41`v+&l>K$0iLhJqj~&UP&(SRL_l|VNy3s!5yAj1Q@Jh z;bR@rKM<(s)dSj_LAE>~k#A6o5DY9RInWPJy=5^`xh%f4r!L;^(IA5J6&uc%{9v4a_4go;mfLZQ!aG2-d3!NM;p z6Uzakt%dk|FFKjmS7hkdlE4bia#k4N8nKF}cma|816L}lnGiG9`+id?!iZ6}&=V3n zJAcBDi0Q8<9+Wkq<63w`o^A`A7QZrZ8kEn#V+mJgDZ!`Hd4=V)E5cj>q_Bq+PFTaX z_1sQM!2=$H8xb{nv20!djfN1Lwb|& zsu-7%zF$EE9Dj94u`8qkE%2Q{+&w>n!FJ1aCdqr&-jtAuzax!nL^OuBFaTG$rEwFDb)t^E1uGjJHqQ(0ETvYrbIpfwVWq1#)xG;K03bs zxPWz8{G8M~NRVx4;Gker%Z;24V0`HDLz|xm;ykF+2WoS;!DS|Sj5V>il#2K#iW`Vx zXYlb>1SRL|E+SbJ4&FRO{dxU+8_<-jq~~7lFpA#%wr+%22i?YQ9wu~n&NhNc5J3ux zh)1#SMXP$al` zC6CB>D`1v*N^IMK54^<4s{BDD`!Fl|3g}1SpD%5AvnnzWE1>|uhlwbop>6N* z{%r@^ZlW$UKHj3E;juV8jk(Rvq!2N!a|VD`l9st-^7iqS^ng4yQ#YrEhOk$wlu1a6 zz7-Epu0XA4A%;>z8o78J3fY3gV6a)(cLm;<%?aC%=z>cK>aLa9VgYzU=YAjp1tScr zl}*JDqoQ(vFABsP5=FZO@ka3roHJ*@O+D{YvglWc97Zt0c?OWikU&R zId|a`3#S8$^!l3F0A2mKNbsk0$4i5=0NMm=)thj4A(q5Ri-U2`F*~2XXJQ1rkaVX} z__p9yDktZYu3p6M5nJh9U+6Y18*TH~qJYnV$g*l6=HVgE^^?JG9%(MIW6tqS0Dw(z zM5IL3DtyND5ji#}nJX7R!li5$CAlJc;K`8|^dlNWuPCdeh`T%}}7t=$FZ(PMt=eo}^RodgtY^-y`1dhw>qP|U8 z6-2`gCYC)1%@C@R$l^ArN$xj8G!J5yeMH z#Y$m{n`OX|jAv#c7u@}VO~vG+v1V{}AJ(fmQ7kal+hiW#R8vN7{*{y$X(=)5-(bzT zpm!}L@bSPH`IZXmQnio6SVAu0HO!J5Jp(ciTam;65@P(&@@d&;+~&*vAp&jVGgQSBM1&XAE)CxZ}bK1kIgDEK}<<;kOh6G8oJLqOCNIh^f49DS=m) z&mn)(6EP6_N#@g_6PG$4WecEmZ8Iy*OGFEaJrzwhpKvmrANSG}2`glT(5q14a1>RX zawt0?wj5OP;A+8-2@Fei&Z@?=b#hth`J8h#3p8p2ltL2U7p#Mb$tuu9yIo|XnL5-$ z*1!nPenES|sIX`=D33sCZg~qlVUgXCN!<-t5{1N%j6;c$+oHu|;+@`s2m(~5XxBt$ z5dj&6`9hXb*=8YdbL(Zvhb{#&B$gLF22amCN*6P(mb`kE9iu}JutJ&zPAb5^%~$a$ zr^0bNdMWi*g=VlYM`jgtAmxfx%=&e>zl}PepISl!`c&%F>|hqr0|H%{OPCM_oIX~C z#a!mN%L2YBvd!=c|=(q2D9eb!2kVZD9XzPu5In;oZ*0~4aaAkgKbMN_B(iDy3f;HO zp1h@{flHJ?^QWTk$SCVdcF}DOoxcXn#v=j7e$&ey49TGlVG5uiH}p4n02^1W9ZXh# zEr5lF{9*r@Vvj0pk5>dp^?#XdR!K@iYG>rq%}%DSMHaVlbfT}# zEnbYs&5x0NCy5={q93WA804a+S}@JqK)RsUDi9SyEToR7UIZm`>;do{4f-eu$&ox2 zdLT4Zwm1h{9ayoG9Ose|7cX54M90n4KyppUJRuph1lDjp`;JpIvH_8GZUlhR7}q#c zjpyuZPy(}F3ZD;D?LKY!<9_oR>8YU_m|uoakIN8`lX#Di23-}AyDStS?6|wTkSJt? zg#?2FhUHh*AM)*(Es}W!%H(573PIkB&@&WQ52l+#ITWU6@dpz?FwV|uuKCh|tqVYH zjiEt1!dwxE?cghah0ywb^fRS%%I#nZgN={I1_}02m7GDDKr;P>Nl}%l)yW;3X9;VB z=1U+f&SVEe?2-FGb$*=Fs>n<-iyKvS&v9oBjU+-&fFndjdqXBQj%&)}ueE_YuTq~E zwqNkc){?7RF~|IM#H#31_1P~BWfsQcI&M+S#*2{)2yxLnfX8q#;Dl=z_hk|p|G08H z!Y&C@L&kVPFSJL!4bXO?h}f^=`!Zwvv8=d;SS`D${$ip%N075+32rP8ve9{^Hi((Zd49(e-8{uNP zMF8MH2?K0bqNadWqJRLES;|zzKx3K(U8fEuj}aLfzo1mr2T$!Vbj@r)?_x8g&r+|y zJ+ERhm_s7+wo@x=oO6M~;C>iEV43~pWMhUN(0|oIZan=*OH6*z_QrR@AgS!j%YwJ=uFrBo4zi};zS>gt}un}aOZR(0p_9h_6ld|q; zHzb@Q_{NMZBE_i3l!yK7Pz;d2$u5E-Xw0zX_Oa1-o?yrq!y@iVL54n3`U|rfF)yr% zKr4_n=LOpia>m!5k}+v?CKA6X=@2Mf=G# zxdD6wVr{fZkI{nWlafiNM?S9Tnhk7l{@;}dH_Gq{{*?7*Sm6kIs`^h=b zn{Y#gTT#hAtz}MLkk}|l^A!*ok8yEj1SF-v@X9+wf`x>eGSFVun2vVum|jJ}t)FVY z`uGwxEKf5m^A*fMi%d^wH^OBY4^h~~=%8Q$kj)p-2XsC41rx_jAdM>Uo=P+;)GeGU z6dflAVx**9e}1Tj1J#-fUs{wjsL;`}gGbZ+HHdi!#+qd_U$H79t2lS0!IT8VoNUY3U+2m1A!}C?TF#bMbTTW;cetW?gQ||`#CWMI_%qTt~L;&cU&OZiwj}OcuJ;(s5S;X z@TD3}kJFn^yLIt8hEf8e;EjN2mYG{Yy5w*bw9Ae8#E5)CZfqbEdWIinAEY&jkSqHj zm}*Z$8;In*vz7tHNytkn<0YQ7nG_Tj&aaibTxhFO!H#d$Ctp~q;A|zLN{4yib3Pne zC9SR>x}oyRF4+*+>870r0mP)EPKLvwQAxqAs4)0}79ct^n~#89&zuh$8lXOXCP0r% z2L_+FxT}D*S{T$PH7Lu`#R`Wc22wG~)oj3dp(iYo;bfFGd{-Ai(u>44P%oX@rh*=V z-j(=bov3CGI>1Qvp~K5apO+-3_6if>O{I(7hsPelD4Vo`udmyoXAxw4vY; zh&xyUsi0!@CzO6c1SoOgl{qR%Jb#tyJni*p~=ih&l)vWb`ufm`t; znh+P~24K4tPeL}Du;y5sp@sLIYDgI_TqVXI%Z#JrBp08spf6@7qVP&#HbS>f(ntx? zL4pQ(O+t}j%dO3?nX+C18$^!^;GiG@2<(9Rfs<}z$%eO=4I}U$5_oz`A!wwWWb~ox z;x>Goi}(t{$om&$npR!_je_2U)R<&-Z6Kt}kN~9>|36Ld*j*{Z{75_*?ZqGz1*Z*} zxgc)K?pP2U{K*@nYQ(1@A4%t;ET6HCbvmSkr@Qpzy5vBp z&&Aby&V|~oN4#`sCibf?WTm9=U zQ^_K4&e{^)%i%5=&|*G{4GV%bM{E$ucqy5&)gt8f8u_*{`tfb&Vq|^)bGNqY;em8C zU?3TRxy4g~^<75VbCv0%XXY&Cvdojt5aIKbP#e6V13P49GoM!BILbXGZ0Xf3)tqnaD==PQeh zEa|yOrM$uX;IoQ5k?$p30|oSG=Ly&N>*d=FvC^XHRf4Jkz&Tk;i-64KhBKsL2T}B; zz^E4vLd`=s!S!*c#zI4(fagR zLKQqh#?vK7@;!>kDCEfkU7R0vJ`o} zaCEOP8`xYmdYT3n`2+H$ym9O~R9U>w}FtS@Sw75E|?v5lTB+sY+z|3Q2dh($CMLOyQ~ zAO8Y5NQ#|+$v%;S*Gc(u5{vY`yUM!4k@&#Ks*#P>SC!Mxsbro-3wY6DnQD30^~8}M z>HvP`1!=J6Ka8yV`Fmc@AB8zi_Y13^_Lh-%r-WLms!dJM+{mJ$@VTA+vWv z&&nvl^u0Jz~lUzvyR!h`H;r4>-UZF3G7z;IgB zwBWnUq@fD&Pt&OT2}5ImODcL0F)ThEyV(ZSfl-KVe;R1}39cH)=ea&Rn$&_2x<|1g z6vzgefm9J=UMl+0xZohDV~Ps{AW|6RN=>-^84DBGVhJnzw|qqnu*z8pLNUvf4Nhl~ zeN}v>LnH`oG~m_8`Zm~oi4>Yz@;M~ThI0kEi7{`&QRZKe@F#Ww)g$vW81e|5C1H$^ z_9de=b5v=-ezkE^T<{uoU3L?Jx%?l2C8ER_3F1l+n3C8(GZ(uxo3%AS9X_x->|Gk- zA>)y;SO*fE3;wpP_`&^SO`$%L@PT}QS51Ziv| zUFdcnKDHR|4YcXgwM<(S!<0kW2@eX?#DaDpV8TqMonPrif-xh_`r6h|emrj?sZ@f| zqw>)U5Ult;%Hwjjvj+`KLdGfo1e>lWf{LKO?c+1UVk2Ot6h_XoyRGL|&sVOP#Qy#XNykuPm`kIqcMn z;b$qhGV((2y9Ykv)&Wo~A^)jmV50DXrlJ5h_cc(3NKX(1+NvGO z&;<)B;`{fpmm}QLw!w6CElPYIX<8S=&XTZfD#sLJ{E4AX$Ec*$7ExA=TrOtTdb$;m zS%M4=<#gvR7@5bN=EUoJ>_|~i7^uYQH$c2(K*9#`7 z+$5BkC|H_H_WPtN#vZ4epqH@9Mz z*6DM*J&Dol#>%~nQX^MHTxJgK7gu&oDlO2j~7H$j>@qEX2P5!D4fOPVj0NH!fw8CF?n_sk&xiRIz-heT?;T3SPY zv8T_8j?AUA7opJJYB&t2L0*!ZHLX=d7niX(x2)IX8!B2zPyCp{?HqSX?9#irOVH%o z;COcJ@(cukS{Uu=pihlJ2|=OIEBX%2_bX}K>r?+1Rf(fO>Cik zRC#DI`

    7r8$?kb-D3z%-c} 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 F002TuuHFCu literal 60767 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%0DKehr}RFC`2XTB_?==0w^)u1m5PYii@6f)6_5Ydu zv+NIZ_(Rt}Q++LT5!n8!J4x!>sE&v_3*cXat{Zq5;17w;B6$epw}$Rg`0nFJg5D-L zYvw@(goc5TeJjM($AJAZxZHZN}RzBcP0=_>ZI6WVGU zO#Nk-YqZTa3{!84P0K~GsI#32<+_AsXU43wILwZS(8n%S9)lP!Dg$$e2$$9$E?^Nj zql4do#+a8qEP(bD2)DpP|$dp<`TZ#bY6^~7Xv_Lle)77^OsVhMOm(@ z??8O8kA%}ZWpR&2v!7qFSw@TF6d*=9YT^Rtk(n8p=CQWvt1Om=n&5uP;GiT6 zMRvbm39kbp*KB`qoVg12w52Z)T}`X41P>D|q_%K#zuhwb+BpEogY0E)KnSy#@+(m5 z20@LG@LUEvk`I|OIUV^^0_YtG9AElBS!Dsh%k^P9r0moJ25Lkm-gh#igwBDhAOj0!EF&8MxV^-m1U1MEd?H7} zL;r;tfFIT|ei3-Z@gyM=!%Ba7Pa626JRAA`V<2D<{RLRT@0o=bE)XF)nFtUL67`2L z{?_Qz_`Yy2t+I)?9&z#z__Q%L3pnhN}U z_rN#WU)kD59D4whbSYERHY01jM7id50EuI1ctl?<_IT=Y5vP>(sNNkB&U5&F&^kBhm5y{o!y!F+4wdxXoy;!4$W`?_nL(+bK_QDAMUV1O0AwZ| z6j)s}9YEZbY-C^Y)9Ej`aS&~{sXCG2SS3ce$EY;Yv-c8TlrD$C85ATlLZpGP_YWfi z`RQ?z1@zIfa{yqfsUDMEPpwuX%XHdO+ASb3EPi1fBPocvfgsC0xa^CG2SWBPWQ&GS zpCXPti8b>WkYbf#Vg%A?&_UwUsUQE_t4GX?7QqUpKJ2Iw#%)Q4Ft(`9Ja&Yk{C@38 z@%T`)#wWy(kKfEH;ZBQ(m*Iq&L=<)4D7tNO{SsA4Fp4D?(Ex6nQS&f3TK|atgj`fE z2|OX0(&(ZqxJd~IANX&dvX?U14_<~h2(lP6k^H8ep;2HW6oPo?U%v{M>|{sU~;p zLTv$OTx3H^4zNUn4wUfo>j{CEvTC@C+cw+cW*ABH6u@!M2EdBL?1GbL_#e;7YDBas zic?MTazk(khXSyPeDom_I~wkLv?Wr8<%egEfM!*M9^kl$>zsVzaP}S!gcD3;Czy#58RTm?`p)RTS8I<-sC3+*n{A)P*rU!@Npj`e{x9xsif2v zTW`{q3p^?A!Mk60Q{(FLt(&TVe9z z0-!PiOV02JcNeq?AbJaI+B9xC;LB=}Ho0vH(@;Qe0zq~-8ckOa!(u@Wou`p_TR|QT z38H`lJE$G{q1egUX@&v$x7wNLWD#j*!D58GLv^bT+jpdKBrK#SsQsWK(+RO40VA^w z0nA7MN1Y1Fc#5JkwD5TtHG1t;lo=i)U+kFG?1Jh11h9382!marrRE2eZh;JGh`wNO zQA_~n?%97HOKLA^#oG(5*bgSllS%rOc(S%Yj00cYR;!D9G_90{pfq7D4I*$k?byOV zR|epi%oIJ{ou`5zS!-_dnxOa{uNv)(luMo^5TCOItq}2}sxCztLEzBGS)Mf6dzaw< z!GweAgvFYJu&mH(Vl9HJBV%=Jz~~i%nDGIF9ncTET-AQ=fv{L11&K_;ei!iht(!De;ym|y7ksL|^5Ko~B-vSh80++s?unD}bZaYa@ zPH4M$&fw;xEGN3_H1vHW><%-+dg7dfW)F8$bB+h7sThoOtteO(v{&-+iK}r$%G))# z*Nhx^!ZMj1VeG?EkWg+0CYQSX1t96fV9^3c+9C393LU&CHsFCa1q99$`zTMsEWwLc zxsw1|A?k8-m8HCrk6;K7dhNDJN3R9iws%6vTq_}PtR2CZ8TG;ltZ4I}sU+^s8`P3F5QxrypG1-{ zGlr^7$Wsy(lo=xfC~BpKfg<2z4OEeEF@~x{Pi7O#CvqMJy+f+}=CB_$&IuEslB@s# J000000038FvZ??8 diff --git a/lib/Font-Awesome/fonts/fontawesome-webfont.svg b/lib/Font-Awesome/fonts/fontawesome-webfont.svg index 1ee89d436..6fd19abcb 100644 --- a/lib/Font-Awesome/fonts/fontawesome-webfont.svg +++ b/lib/Font-Awesome/fonts/fontawesome-webfont.svg @@ -399,7 +399,7 @@ - + @@ -411,8 +411,8 @@ - - + + @@ -459,7 +459,7 @@ - + @@ -483,13 +483,13 @@ - + - + @@ -523,7 +523,7 @@ - + @@ -531,18 +531,18 @@ - + - + - + - + @@ -556,10 +556,85 @@ - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib/Font-Awesome/fonts/fontawesome-webfont.ttf b/lib/Font-Awesome/fonts/fontawesome-webfont.ttf index ed9372f8ea0fbaa04f42630a48887e4b38945345..d7994e13086b1ac1a216bd754c93e1bccd65f237 100644 GIT binary patch delta 19019 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 a{Y8oiTrq(w))2tr5G>B&2kvjAsQ&|VPX)FB delta 3717 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 b%7NbA42BxTcoSrlSuMv%Lh(uG6hi(FwBy){ diff --git a/lib/Font-Awesome/fonts/fontawesome-webfont.woff b/lib/Font-Awesome/fonts/fontawesome-webfont.woff index 8b280b98fa2fa261aa4b0f8fd061f772073ef83e..6fd4ede0f30f170eecb4156beb7235bf01fff00b 100644 GIT binary patch delta 61681 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 kgu|{=z_EPdwI%aS;AX3)Hq)$ delta 51819 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 diff --git a/lib/Font-Awesome/fonts/fontawesome-webfont.woff2 b/lib/Font-Awesome/fonts/fontawesome-webfont.woff2 index 3311d585145b1cc1b9581e914acbb32d8542b4f5..5560193ccc5d768df40766ba54491f1822ed683c 100644 GIT binary patch literal 64464 zcmV)4K+3;&Pew8T0RR910Q=AY4gdfE0vpr-0Q+$O1OWyB00000000000000000000 z0000#Mn+Uk92y=5U;u?`5eN#0*<6N{SOGQyBm62nVk>KX+wfW(Hek zvyp+(?)D*}+YmVX&(<`Z!i+@NrNIkT9jIaB0KojcX7>O8|Nq%XMaE3R(ryC)Kvh-$ zU)TtXtU;}Nq=b9uDJj@AW62eX%`$1Hntbp{o=%*VFKp~;#HbSWI^EoF@Q}N5qQgP! zXe3uW@<7Kk8y+0!#-n5DD^^Z)ywHbqdfzz6!f3GQI>kDq%MF`XHqXMmk(Fg9TU6mJ z5M(qrZjoUQHivF(b8Wk0(6O0pX^++qmrIy;kEUaaX2bR~0w&v*wz3D>u*oLFhHYMk z-h+bnPojwtd+Pcva?Kg$=$o?syro@!Lu(dOP4U%LW=Old_&$q9xu3I&{GCVKrQk^4IQ4Tt)tA5Wvg*01hHrVb#Mm_>WXRGR z`?Q33zOE|X`%F|-caNkR-DFfQz|-!WSGoy06FETJ>?j)q2?0eyOca%{Fo;x8K(Kpe zfjxC|MlW=8n{F;#yLMf_?N{#it6%^3;$6@)y-(Q#iE7)eqauutrbx~vq5pnA-JH2W z&=!ieLg8~8Fs9a%(Lb(-HLavOmXgCbgA^D7D5-{%jCaS&+2yqLG5p-|0rLPrSS7{I zK^$C!%Qymtr@8%GQrp;I)QBCUMu@~l)Q(X#Xc5@aqe4pIPEeVGl72)HhLxxo2+A4t zzlC5VGYg~s{~P*OXU!~EXYTsUdnyK}$f~v>8`A>m{gr^zj8huR>CuTm0ZTlAHgzZOuaN*4oL6!laS-dWDyakH zs#JCF_4=&#_eKsl2@}V##?&zb+h&a8n3w8QjP`w1^QMu*7T+*WRC!&AFn^4|9O z&w^?irPg>e>A^Y10q8(C&<%70oev2*|7TNMSw7MxEI2NMT}Hve&-MVQDpNhKlVXF|8J0=f+Lyon_s*X;b!*R=x%!LBDS{B9Ok8&dYw&Kw zc5w|oBU6n%veZl%Yj`8|*~#K-=>~)l8JrjL$N>Pi`7c$gD?kx8 zvm75Do_$Yg$5|gCfSKnCuySH(Y?`Wdexg^xOLy=&8d%l+{9~huiig{pHWfz!sFaif>vSC_%Q#!SdK8sA=~xto)AG=_bawA2T}60= zF*|eArIaQV!SZ}8#zk3B2n+P?e{Y$qzlAx8+LsGuH(Q#4q}SzkoQq{0>Ka98g{r8o zAFush2DVupQrUGRtz!#8LpAaC9-kXzP6t-|o~=5ih!FUK4-&|^L~V@B97roNBIj~! zN%B9)Y5ZT5-u0%|Of@Pb1l6_BZLIhH_=#=(|6<8j?asmA5@hjbO-Ft%ZLg%CY?=ah6y*p#&C14+Q97E~OU2J0)`#BGSJdHGkq!Sv? zjEBs>e_EvZ6&-W!7{opt#MRFIn%#nO?AoWMY0?4*Jt#GPE>hGFyJvCcN@{(-88l9CiBokU_O zEoWapTlnwa=k}S+lbM4~rI1NP0v?B8m=GqI31R|d8oH(`vLp&T#}NFj-&?=4erx^4 z`nB~dc&+@O_}#SeB>q$PiJB_+DE0Y&(m%b3f^Q#P$0Y55`)Oh6kW#F#N>2dTABoLy zej|Kxp-WLO*uP4i2gQWBl3_`{cH4r%pg0siUJQzDWl|N>kyk7^O)0hTVo>b!F5)D6 zX%jA+G*-5*9T5SX#+m8{tTGpaPj&}-UA$i1&EvH1uc0-gW$nD zaFoO?(kSV@TOhYv(Ed~nBD8KK1OfCsF=FkR9ngcv#6 zg`r}sL>#FtyPVe8bHNbs6lC?XOY>?@A?+c-(^F(+jgl;&etH9WVu{I++aI{9u-XbV zk<&s(N|)py# z{=Ok$Z>Ls8g-Eu~?5ds!_A?G5hx1vp6t1%NskL=Fn<<4qaUnN5eot4u0|pfFl56Hi z&K;jOUwy>^Ryk$`DAN%Ji>nlGb@Xayx41i8)q=W4^=c?63NMhARDvxTL3Ve&NFkyl zOeWLWb~SrPJdOpKiJ~oc4xa%UKFpA12Q*`msC_;^UwHI)liQYgtFYyGOcWCBVGbrH z1-H*ye{=nMyU9m;e0-1(1{)QLgUpsywV~7{D~_*e_?fw?_77eHYH%O>#hVsd6LH-z zL%W?&%4^H`TZ8`FeC8{d_pH{P}i3orrTQwhMW9E#f)3&KJKQN(TI1U06-J~Hb zX5Ww*42*{O`P$uY@EHWI8u8JSXLz#~>=k`UP^b%!QX6f5Owt_vIsi=SE8C*ooW8f0 zIzrHNtHXX>H~C$XUoqb&ZL}+n#D3x1JnDtYJUoiP0AoOy0ghym zDP+wYZ)K6~iuIx@GB+%kA+$+2zt18%Ae43$h9f@30#T}K<6#*D2fXwTQ;~inVz50z zJ^tBz=E?rJ6gg$p5a9V9w`C!SWF7GHuHk}~aK+XD*QAykGzFCIXw+yCP>(!foiA@@ zgx=@9h^WL@hu6iC1wxMNVdBTI23mK=^(bGFd?dIPSJWZfY{dN}vp8-YaxEzI17mrl z^~vM(171E*5{vEmD7N_svoR!FUSt%mi8<*z6RG^adK34LSt*iAZj61?AsPGJvJ;#S ztBX6~-*Jd(tEaD~}_t-Ej8QnL8dK{j!2J$GWwb__8#a=gxR)E%P zj4~;;K}bX#>1&Myzdy++x>|A7Xwi;_p6h-d5C@|g6=oyLO=QS0j)aLS3hLjY&?(N5 zDpiEUR;nmpYST?i)n(0_hqUUUb3L(XspX1@xngi!-9&4*UmsRQ7o99-vQDhKVi8kW zF@+(klDt@UdA8gPsI0{a1@HX zM+M}sZ4&}%jkZNLOpQp|!2}_z(MS)vOI@u8TISnCtjmIH#!4nfqFr4vxdFmpEQi^^ zj3X7%GzQ14li|SS#x-fWiCAfx6)`JG5JZ70{lFITn=OU<{h8D%%3i;$(-?7Q=2Gf% z36Z75SfZ-1--e`beW%-7-9mMTp>*b&*I#}_0@fm>(C#ur#xnEF(tWheu~Q&W zc+RQnbi$c~&p4tW=tL|LXk%inF!jte)2vdd9@<#WTls)!T>w|>ppMoq$P@U#H9hT(tvD5l?_1rgVyTa4yJJI+6Yw2FtU=Qb&fDh z?YnLh1iM^S>+w32u9Md_HgS7nf3Zl5YBIlm``~a%vTbT;z19<8y@u`Da0o|{)?#?B z^%?Ila`!AYp8<)5pTlZ(9ll!h$}gJPvGJ8b9t3z#n~Kz7!f3Q>XtQJ%CX=MQ+@K&g zU`~qCwWVgWJP%IUMwj;4Iw-5i-Fbkh;83-7>CM5cb+ndcD%n|; z52ZR;59GUJ`AqxvH8=4&jaYkYvJBh%f$^tGLZ)46?<{GDY{va|pd9 zW(~_FJojQou#Dqb%8-ypiZfrkmbN8Zra8at{hY0{+0AX;x24P21clE5ks{=Lw|39UH^_0&&WyiG+FCWIj}hu5Ep- z+T^Usw9*&DecV(lkDc*~x3;mq@f@zYqcBtz5K~!#)V&DzZO-|LiXhba{qN&^+7;d% zUF`Bi8QVvy8Ahq)U#Y!}86=c)zUak>NzKDoo!eY-qkE_4&&x@j8}Y^k4P=i94|=4p zS76(BG`>~%o~63YX9GMDWFl2iNl6Sw~3zEEKK0uT@il>87A<6sD>|5q@Jxmi#B}Q%hM6 zQ+d1q^)SF%#;95Ir2@*E*?tCAD@HswJi2=I9ES{vDb(+ZgtwOjJtJGaw!>GRO{KWn z#2)ZI6-#KJCXuymv{pSSfZ}U-%5kNqvAdJ0(}%saV>EDIbA@J~O*m{8oGzIcFsE^q z#pa;zk@Ct{32Q8js}SY6x#958>}&~^KZv3+Ba|_^^o7{*^fc*{PA@;RMJ^ZisoOi! zu5?~+-4_&;%18_#IGtF>UfDKvL$@A{Ol0y|JFuF@70rN1Ls=7Gc(RN*cw=GYV4E=Z zbcsOhtlvO<;N*QC*-{_CiqCIW@NFfUS?Th>cR$3J2gP^HItkVD)-J^m^Q>N#Wm?RZ zE$$xmtVdSHW} zdIOa&y@NT!gWkvp$}VdzrOtc879s&8+Nx$IVFok zatt|u&X(ntC&X`y`?I95)!<;D1J=$T{L+g{>>mApnVa78Mpy%iV{H`;=8Bv;Q*&pd)hSMvz1VV`N9p^6ri>D?yehdiP-xbHvclBJ} zvkpc_s7$*HF_IXkql?((qLMo`#C3ojW+=C^Y;V3!I1KM-rjtvOV%Qy?zgj|u@PfU) zc?UyI@IXKd_l}vP!Vi8hHWx05spb_sR8vkHy~AfMc30N{0{;fg+8ucy(0{-QLF14F z-iMjh7{pbE8tcP2Mvyy%r2Jbr4sTub*3e>Jstyb&4#wItH!jax_s$ zI@C zE33P#VX-aXZvg72IV+52)}GDVP{zcEf!2Xd+HCf}&7)Jnl`QFf@cX9p7)AgFjzlDL z9uP}yg@)BObVuwY4Sqk?{S<;%iVCg0a5mFCwlf)|{q-X*PE%Z*H4u}{!O+l{BZ!dh z$iM*E0I~FZR9tTy;4nj}jPvJlB*LAJ2scHG|4<_3b`=B7NkHP(kWx194gJ0r z9q73{k2e^i-sulXMlX9JET5IGy+javq}K#2y42dnOLJHk!iGN25J#7l=T`sfd($ALWRZnag1x;lDR_#)q%!7*VRkT>#Gbq>_2@zux(OEX zA_|*-eh^mq=Z8^B@A5;0OiHp&#r0P9Qrawx((+4VjwJE>hSsylgjtk0g62|i2Azu5 zO{7QRsXY)6wvZouQwoZUCsAOO-4}ka33;20G&~qe22R|x;%OQg!Gt4bseU6WlL`)X z&83VJuom*RhOe54mKBt(zX}sO2p?liU3Bvg%^g9eM|q9IeEsvGql1|BABnO$f}q(8 z_>8DmmePN{5kIRpD%V6a-;}B<-wc}6AG5$*DWc60-s?*IDWbbds1=HvTL~BDK(cuE z-Q?4?4YqWTb^wgh%ylu-I4hU6&kA^mIrX*adn~5L2_pJ**W0(Vh1{ts6bEa zi9Ezm9Km9O)kg|hAC{ruhiZhh#LQH$_ z^tDjq34m^KOxlY=n=z?cqu)Nbvwdv!(|sPPv5V> zM|LWE$kl7J=1sD}o(P`H`ho`3o&mq)$kAkg5tSV+A7x!*BF`a3I(|zL=RAgwT!pEy z=siwEr{sC>pVryeE|GV8LCzZR?EM@)zzJXXgLuLWg;+!b&*4xe9EPnTRE2P&P0#Kg zyq2^A)b;O2Hpt5LVYQ^^5d|gGal{R!Lm|M@`YOM~G=)DeDp~zv-c`LDh{lyt9Lr1~ zJJWMm-HYTo?JA#E>ZU9LLXN_WQL**-VAQHK?s{O`@7U828{d1_%SD}fPZ^CcZP(6l zCK`LYnx%&EsGh4cdj% z`+?BA&nSZHKB9Y;>+nnUA*c5o%JtaYWTBHY_g}}em?J2UO7O9il0X1w@*v~>Z>?n2 zrJL?|x{ey`+=j%r*njYEcP@oS(SdN3;YZvyLs!AnA^5My3uJD7{)`m2 zN6`kks?sRU8&6B@{L=~j#hY2XRAAw;z46m<@*`1Ywe0Y)6FEa-V5!d$)11MdO&~Pqo9FUKVq`$Gb>?;3l>0I%R~^UVrx5-!9CDMOCEVU&h*z>D z$}!$u4NvFBgLBiHsZA4qn(juqKoW9=~ODVcb%#Te6M7n1P8X{ z<4D4Vu^>B?gL8<)263E4{GRi)HV!3&sxAehra}}SUZ0tBd=(4qZqqW7hBAgOm+=B_AP5fMSDfJ^L-iy7x0Ic#dvcb1``lCw>y z$Ckqw%w)64S4F~n#yDKL0%k#PyCDBq@B#$4a)!{PM}AuvPHaC?<1%r;ZTCogT7wT< zTPr>&(##2Y0?@f+J65R5D0zhtTvFK!n?lpVqPxQ^7kV6_7a{N~kCR+RWflTc+(MyM z`(8Lts9a3ykZpTfWHfqOOa>*rTPtliqWR+y(VQ;3*VJS2I4uQ>_6M5hI89rN_&v!@ z?WbTA${qH?v6tk%uWXCtqz5>xAi)FF#n&uLINVGRgoJQVL>^>}vCRONUJ?hgP?2+p zF5_SqqD#S46buh>C%|MI{KQcxSv^c>lupOfw8<^RY`wgm;L_>e2t{Zy(59M-%-A6a zQ*Mi3Ta7?>_^6!>rh&M?TH`GjAEcZVnThAIR%Hj7^`>ZWicjGqh$SRAVJC$?WIW=l z{^mVSE&j7flL{5jyb_cO`>GZ!BnpbCkRuZlh}!uYM5d&OUGz!`#HS80V0Ri=9cw>? zJ4oES;Kq5Y&>#Q-jU(D_cm{VPQW5@Iwg$Py>MjbC7gSR#SbEQ>NYi&8#4MuW(~oq# z{a0!WUDy25Wumynz;FdA0j$8{yyLJUH$-dXD2g@>Xt2%UXt8^kE5>2fYgLB1lev!^ z15JRxg}>=#L!Ua{I8)*{rs-i7nhaz(YS_hdPX?Cd2YT+CZYjl^<_Q>I^xA^eF;LrV zS)|U@vQO)X4HY)c{=2tcYU1!coA0*Z3fg|vzaP6`X+?{Tu2i<~XJVx*#)RL0w{;NWxUFKhd54dG&CBQ1X5a_6r<2`DSEYj4jLIXOb2{Fet@b=7nsRvSsurgF!0 zg}%O4H`=1n)82TCLEcDk=r+hhr@O%*m;GtI$=24ffXUqBTLEm%HtT$A&!=ymx0P%7h;tlp@r=)}@{9EW1cX!dO zJajluO>FfFt`~oFbZ+qqjX0@DF+esCYh8cdvx`RLJ-xilP(Rpk zRq;v;REAPc$~0hRDDF(j3W<^;c7|fP`D!83)A=6=sywO3svfnXQTZ^Hz( z`w<9WQzD#Ssz2Qj7n#TaFjI$;GRa??T%j<|kGNN!@91V@OwT+hA8Dx;N= z7q*dA%q45>jWSHP^%KcwkOnuagEe^Dnv?nP{sF$kow-QLT*X1j;~?^?-$`li7q)wqR*c z3TAz3rZm)gB7q)>32RIgze1AXqZC@p&`WQQM8ieI9d<}O86=$0M@){PgEJ*YQxB}d zJ}E-83XR21p^6sZ_8>*ZL1I(%#k6fRN>HEz)D@{VnvNQ5Vf2#Sd(P4ZC1YO=hrISZBluvP@f z75olgIL00vXwuHT*wxSnHqICXFv?y;E)3pJXY+rAQ(m-ny_(j zk3dJ~6L16fz}&T&dZF=As3Q&B_Q8qRW({Q&r)kJB;*q=SB3o=Y!PFPVhCF0W`5Sfm z9=U2VG$wWW4xiHFVkolIlQq)5U+6?|=MAo6sn=7#vU+!s$gZeheN3U;@h0}+b1;L_ z7CQpSu67%uAF+9X#5uachz#+hJT^ikX^Muk)D@Og9$7a}w!hTW`KGFpDdyi^TcCX7`yH%|)1sc8?*V5Jy&kX|>`SqFa7SRm z)2nKMhv#WzET`X_R8?EZZjNb;A2_X*;BSe_KrLUr5KU)=vdL$RC+R=SFSl(hZF)PD z^_-}x@;dMK-knNk*qDOmEvi(j(s>`#Wc7bZRJ8e(R_83VLkVGwb8BI{^qWCc{1_oO+-yyxJYC?!5nT81O`10-Rc(9o#pH0U_W$|a zYhj2W0tjG$xgy?|gjo+#0w@$3XC01d^z0bKy_X4QabG&{5oGeSN2^w{dUfx-(-&wA zJ}5A;r>9z4{*E(&q3R8~p}_zF1QEm#$HUJB>4?z#omfMEp}#*oBzh+63O9Z$AhZhcsXN4kqmR>t@=*)-rn!U|f zGDev-dW`Hv(7wqAY4Un{!=p)D79CgkgJb)-^6owj`gZ!o z$F(l~#k+slVYE7lK;la%Q&=;>rBx|&7u+eP9qchXwgb=2G`l^dUSzY#H&1hLlro6WV#7!yH_XOxC;3kRhb}FTmAEOIrTD zW7!HM8x<%^sE68?VaFS0!{WL4EKfeLOQobG`Ywt7?9zl_DO|=9?EDFHb-zMmg;NY` zDxF;M0c*$40KIF#ZFpwnO_p&p*<7&wQp=BeoAh4nlSto5#6Lm8g|UoSs+nfU`ntN&+rf>X}XieWBckSD21M%6G zgOf7OQIA)ktWli6I;HrcH8Ff%?^Mn(dM~9r+cT!}dDssnM$)Og>*TGgro(i`ZSw&k zw!G$EpHv5Kj4R$YV%Sx+8N+pO4xz&WAjl@|goc4ZK~_Co6&k}`Fb4~@dbbmtk_%?b z7*V)@qp0#*1Wg_+m8;^Xp2Gp$v{@f@I#d6mD;t~c+cN~!v6={tBQYIf9TD_Vh=;Fa zkV7PY3{y-1VhoUBVOqU4BmPb5Rmzwtw)Zr$3#|Bu}d`&$PET7QRtMsS7OaqSc2{wQDP zZ@czHxS$DNpCF*wEWb(z=6?zvIhP3?`YhG81*y=Aq^un-C!me*bpfloME!a5*lMbpp>;v(TQBIyGtW~AVNLyvk)cs-4%8WfG z8?@fJ<9{AFP{JDvWHE@QXbOcH{(n<#Z{XP3k%_ZYi%z?jhnxrDK)o89FLnmZH5|KK zM+;#Y7KLGMl6zBqf(8;d>rU!@AdtJzByPp#`ksb0xM@6^Nqr-Hs_zEnIQM*SoIbf- z!`|0=W2lpJ#vCE)GnS16pV1`dGQ5QDJ6k@miJhHdp<>Kk>-v!?l2JtkjSoKeKJABK z*GO@jk>y=wb46Y8tywSvkhcCkEqu+Z$07Z1E+b;ULS{ z4zVoC@K|J9B4 zW^S$VRLprH{0+Y8v*H&?Lvawb$d3P|?9U|*D z)V7YsFbnI!AMHEPT}E@X?wn>79YQJ1^4K0(Z3(IPa~#C8Uvz>%J{r`?W!7W4E^!=@ z8ePwwHxP|rQrYdA3aVnX{o*}W+&43Zov)c#oj#YrTXO0aj z8kW7Kq?kfC^da3YJ8PuV&Ow4dL`0uTcSbrjWypcvXFSZX;UP;CUT>iCOV_P=n)=L|8E0lrLnTC%b{AE zuiCw(Dq0hUbFcp_^0wg^Qbu`);wmPizHe(4Qls=bS5%^9z zSPV2hkGtvGGq$IZC;h15qmu>Ed^J?6VpyBbvxd_?aLDoVw~tj!Qms|SD?9kOxuQoC zqpd_1d4_8gH4&wkFDiSM@trZLEY8*jpMy$m+W{6B&7>Zgbw4^J`OJat2%WJz!6rk_ zjE58Y^=ie}Qd#VeK0TNv2?Sv6z?+T3RO-Cji~X2<+}UeQ7fuFrKyF~YG5owldy;pq zM+d|U@)mMaS|cx;GRifQfa^#(w!RH37kxfql4H#^tk#j`=Z=|VwJlMiFDG4Q_xP3P z*SSA>KYbxV;XZmZG`?wqw`7C4{poSLhNQ54%TMWrH<0IeERv%yvM#S#WWI;EGsg_D z;@5CcB5QQ**LKeDYYnWTs7mL{I6X#xjUa+e-?gX&J|=(AYRqX4k2fnhToJ@@CKtDH z!$;@Na!1QgjHPbZk?JhRY`YE^dxIL&V8!toKJ4Y5*p8I?W`b{{=QwL-X0rb`@+kXO z6$=jP4K{0pW-ICs(^Pf=V);bqzAcz}|5LNFO`)b&eu@-vEY~gLI}vXfLu%VS_5YCs zfz`EJh?YD;`|hoU(>`^fWNeS`aaXa$_$^`e({cKj5?2vJ+i+ntL%Y{6^GNj(MeIY5)q~f zYW+c_s^ULxbEPOwxT+od0+r!V_Q5l{C!NFd@4G0my^rgcT~kT)b4%d@!_(|I7C6!^ zdF(4LE7WXY|1c`~A!;RCO@o@4p}nS;i8yyKHak%xuVc%itDtO&pLL?0<&tt{DVYUa zqt1cSicVm^#eoymsR0E+cgx&RAm>=!omT^tjC4rV)|?7b2}mrmhfj{tlFKl3Kpl_D z6Xh7l!^68RET=d9D>x;mPE>p$TKVS(r}yn2ixoVGbc2p>UxF{ODd0pIwDN{xVk+yr zOIj*>X9D`0MHi_m3+Nle*c_{^8&vXe|GZks)nmxa93WT#dpuiFX&w{k00Ux%2ws#= zrB|@_$belfyxMgNxRdB+-d0=i)msx0Nr{{f(ahyrBz@s(M-XxJYb-DmZAt(@KwvqoWEgIMh~Soqer_3KVv8ub zTU%gtgWY*2YX%b)>D*hXm>mN7x;# z2j3$b;M}expJBBr2+C-u3JriW*i6Q6R3AB(CVAEO7RTI|eJF=A7(S@J*K5xqK^902 z4MW*{3h!^nS3rkpIg0ECfb2;$ztg=tw_H#%C$k8jQ=+{-KESHfgQ zzlGTcM%ls0L7t;EXdJ}*_F!IM93qqKnL{F%dKzC*!odZ*AaJ4Ttx3h?6Mxk%jGy%; z{P+fr=WqGIX1&H@uugY{XrC!`#k2F(8FU}8V86XEy$y~DO-ntQL&}uEIdh$7XcWm-5mX!x zM}wUn`;<}(urPhr#=A0x92_z6nAM*cm4}@_U&bnZgK6M6H_u>GXO-hv5{G62BO?xu z@~zSs*U?+2hk9T#p`pV=MtjaM)&#G4UUF>4FMo{UY$JOOW2cLpFXl&XkK!A~m6&wd zF#|EK4i7a10BEwIr=9K)ns%E4ttn92OiU77NV|WUSfxkGspsk*SPe|xi8R=KWAlP0 z(M(93qWCxa4`o}|j=E&7lXY^V**hwSOOgK2HJ9%&O`r@F@J+lt4mMd^5G1fi&$an@ zOl%cq*rF<PsS#4d4dN<$7;_H3c26?*8fr^jt}-owK1@u5;d z0fo?RGN(+RXrm)G++EZtuSV)6hg)uF40aKp;AxttC@IGC4U5mRslGBP+h9CKd`1qq z{3j?SG}#(WP0jW7tr#x$0c|$=5(ERGD8ziN%w$@ zEFJ{g2F1HlWqtG{N}Qpj&erU7gD0JykkuZ3M)J6qQ7G_fgVI^CwQ@eWDP3= zVH7mPj#N|XP&*LV_>)XYa#7YCO$LKvI@RAlotq{HnAd0bg{91_yNk$N3v4=?)x;Cw z(&S`Gaiz+7dV1Ylda_~o{r32YF2PM2LTLms>TC}9s0N?bt9?fdImBAA96NSR_?k@p zo;)lAa+1)(<6-YM}pQFOlGPVy0X|FP&vlT&vDsy;^@Ci)8b#Z~tA+=1g8%J8L~IgPMmBDEXq= zjCuuJ_z0@Q5M^7Kn?@W?ckR>%dlW3edPpUd`-?MMG-~b8!;5Kl&Ko{6->m!GZ2Gd|*uI0wz+Lo4tMMKRfi6!R!MuyoRlR~m@T28ydb@+&>@~H4LW5G~VXQcRyL^Q^u$oWBPIFhP zm5U!siAzFLe2V@&VJ~-Rvc?wYZtyixHAmtG(x-#f!lCpEbyT<>fbPkV0?OVfVob#e zaTgLgLy7~I__K$G zJ(7Y4!bE!H6z>z4G>$#vwP2qn@;t?boB`Y767H6-fj+?M!>h+FEEBhlg<>-#;+&K2 znzXfD`8zF1zAH6RsL)2Vm8FX$WMkQ*tKO3WD|U108UTbU@1a`!Ue`fbx*RaxXOJRU zN*kDZI>jAU7(9%<`kf8_g%K2!y6hWOBRq7Ie8d%OjSf*mGt3vHT9ngMJ!(m&p58OR z!jiIHC*A{(ND#ey1LrhGUNi>F8zMF7Mb&4jIuw_3u zAeNzP>pbU@@<|tB7ze~kUp>JorwgHZreW4%KAU(>Pm@M0cdbe!s?;$nweKx$tx0?UyWh6Br`q1w$py~<{_n0ZOt znsVG?nax&Zqzv7&1`e7bdK!PoI#ZX0_obxgM3-MfCF*8g(`$C=5KnY&;sfY;xwu1W z=I~HIrYZn*5b-X1>Tjhuk{URCa4G7!qpRvgluxfv=2hl%gFeCN_Ayn5pW`qk?pO|c z=rv{|&g5f)k8Mo`@|?8sCa0V_?Ik$(=0BO+U<-CQ7~XLzD=rmhHis+91GkT|q)&qJ zuv^4EHmVFEHyU5bi-tz&NvT&^^vj$tgw<%<7`9ASOiM&|3O!7@GGQVP0Ya*_*9$ix(1%qzRXpTl7WYImmp_riMYMZcTcp9(JChcJ&NH|QsF?231 zc{oR9Sy7|(;kt)lk~A=()Mv;Wy4zq&0@Wp{AFUS2PuqZe5N43#gc*Z06fl|E>A@Z) zohp**0_EzZye&3ew+-6UkqQ|TzwcIa|E=t$e2!PzpvuvEz9p$U!Ja`ue99cIX# z&oE~OJ=ya6i!gP;Zh(FcpOpH()2|hBzw$>TO0vz=NorFE7@L1gd=Zg5_$jGKtz~xG zA8`(JG1A5Vm{ABPTU{L)dQY@sqKf+e;K+gZo*aae51~UnUWrw-%fUeO6K!WIw&m*5 z>~5lQf4oC?Sem@RV0zU4>caf^I5mS(!bZsOx+4)p&8x}tf0Qa2EP5)+2P9^-TCXg7 zG%MB0ga#Jyv2mBP2<$k#4`p<4^nr~&vG+?l5$JM{AG5pc(MVGLeDc=h6xJIm{k#Ri zPEtWN(s#uSr6Yt|cpFmmAeWnZa!zGN#~mWN{O4jj=?kz1JdG7h#HkZkqxY?zp;<)6 z#ETba@OrQSD!F^wrv!YHr!3Y~tQVO;?5u3GpYyO$pAQ_CCg1V0as;5}o<<`dW>yo8 z-KOYZMc+A3_|=U*xY6WOyR_Za2)mzSy-o>Z9~BNIQ#y1>EL3g-S}dE7L0vNZzy^bH zNB}e(I=@iN38pPh+pn z+J{FD*mR0bP)<7s_4Z*`ir|cJSG+(Wlw%1LfP0zpoLU?1ct1l_Eag4{nwgJ%JYHzn)5)u zb`YboN(F_-UhRJw)+frb&1TgrQI~0~hgZW&YVtvJCDGGr6-;6ax5qysz;&NGbuGtS zxUHB3KZ?aszZT}VQ8lCGjbkzgH1Ad zKY~~Rhh(pZwi@!OTvp0N3+$lM(Y^AZ35-%S`~S5b7o|@{^s<;b>Z{1wB0-|KF3!Ag z2Ab*BRH~tw9+!eTngGXP#Pe%FjD2wz8Fs$7}RC;HxQynPE^25TBdXGbDch z{#PW$P4UgMS1*pu9Fjlv!+1@Jo$SpWZY!@Ja=z_hWOlK8cCsr1TCUL8Z|gj;fA)iw zfn1P3b>>2G@tM*YHa#^zeez$nOdPB+UYzBLz28)Kb>&oqKFD;~dT30!2!nWKl#ioZ z&u8N!y9#noB|X9pRl=y-(Rp+RXFTT73zz;k^!q4^?UP?&;Y?jDXQB&@h5m1eFg4O5nV+)kl5sXNDxQst)XG6kV(H zh!2Rg_@Srq8EY2wuwK@OY5?fpQ$MZOGM`#J%fZ?>#;#RDm?D`%4x52Yhh~Ru48T z8H;^My}opQ-|}K&_rd$tg2qo9ii;mTU0my^qz1&PjDB~B?qYwzE`k_VjDGGFlycv> zqh~9Y20gzFaEi%U^;cn@?qT31Kk$bbdMh{}Lf>`T#Y|(9D&_OqjB`0sDVBCAD8$9R zTx7{r$;{;(tw;6Q8P4qEv)NtWari+<^Z|6>IYTw;F+BV$kME5?Pe`;131~ z8BJc#dVV%BpviR@i4z)@V!fzEebr$uE3YTr(5N}RnzRcQyoq=VR+jMf4f=bd)Q7!u zBOU!C7tboY`6jRQ-HEm|mGpQOZ}@05A#@&_(gKzo}VXa{KffAG-3vS5p@H699fF=;iKeqsE$U3 z?-cq-W+P8D=@7poT)zQe&aOo_lUVWiF%UiGWyLoh`eoWXbP9fX>0Xv{82sYbfAz_q zKeTd(MIX~JF1&*6Pzu>zZob@_`M&i65dv%XXwV|UNPKebwF|%j;C3*j6j*76UOvt7 zWV~J2acvjw!z7)k2O`?wDj_oizfW>Jqyc2h?9q0|X#Hz)_+x)s)SqMe0 zAzFCn{9MDMa_6*o@2+0g^rQo(Am!TQeTc(qzY&_bM@oM(Wt?pSjhQ3BcpN-1{z9o_ zibH)cf;HYW<~58{fAZEq36{#|?*uK!a3DN0ExUd~hg=mC71y@G<|8+uT!gpWmhF#h zXHYKlbxb>-Uvh{nKUAkWecK&QyV_$fu0P=udbWyh^QNBc)6VsmeT1OCzz!Km zG&wPB4jwO+0QDuEXLBdE`^RsbVGbY@v`YmO<_G__4BS za9>1Xhc+yN9dTLQ-ORSYn@(sfAQl8cq6U=eJB`828Ev=HG9R@tCsNW7; zoN*2qwF*Fx0jpHUz0}$%Uj&f9=%_i0%SNj?oU@VOHPcAxwLYZKkkrECGG=-qTQx08 zC-@Qz!wP><=86MMN?zi2IP+Jj2jtyT_i30l+k*`rJ1x+rM5O4Wz97mbEwTpLCDBp(_dHUW2Xb%P*ij8q)(3eM@q zKjKy<9Dy22RObANDfvO;uE)q5;+^LHU5WP#qI$eUUm6VF#Wr8|2fJDSJAwPR`+7`~ z;urDeC-lBM{?=IAaAke(drzMBdT&RQReGHI?8eYc{V>s@3VecPXeI@D$eIC1#kGE@ zJ%n;X^ibp>I4o?=*ba6QFyZY>6K0z36C7V4P8B;$_JQn>t5C*;`>rq*JbUCz9*zgbhox zC2^Q`wLSkRXN}N^8+4}$CwPVLX_xOoW#_GEktI%-@cs!rjSl7o+DL6yfG1_${@^09 z{NAH9p1R0!UjDdcR}HzFCNRf69Xlt^zf^e8l-n^36Lu%!-o=na9GG0$a3?MzP7oug zf@w|EMP=x1v;i3O3Pfcx34!R6_1CcUcQ0?-P`qIiXt-`!zk~&maBo4Z(cpKZZdWS2 zW!1MYB5siN^CqUkhPrim^6o|am@Qi|yLHPW8hTTT`0ev$v)Q}A9Nf%ZY{PA4M5B)( zr<1j-C~R$b?8p;W-KxhIryU0fiz=61lp0NBQ=O2RXk5ORaRiQ%GN#mzi=C^;;qLxT zON@mMxC*leUshO0Rat#znLGeDdcJiZ6(&~Me1$HNQuc5D`h!xdb@0aXByd06%0l{r z*~oTFYHv{6EiTF~nN;E!BG?aGn5E*!r_?aS`(dzZV|Icw1Ta9LMj@4G=2h*(=J(dp zhFM2LkRS%oXVIro1($S8`3aHgXXC$6WD@NmMhxAg9IHLNpHx^r8|>%tX8bw)84N#x zKLwVa}g6vIX5{2IuTKvLM_V3e>ej-s~5R;Lm zn;)(`iwm4MapMAljo&8~#wRC-+B=TZQ7uMf7s5sBPR4Sv{?rX;5*$+6H6lK8ji;p$2eh$yNaf@%*wAL9rT@_B-RxPKFAE4))ptqKFgY1?~|hDmY8yReQ9 z%10g&eCeI&x8+LLtLXs9JpV|UTKn>gQZKS6c$XL6fWv2T>#GVXrc6_%LWY>SyS0rA z!xOGIWKzvad>)`J(!Em_||3)8_sp~P2n!JnrDG%wJt)q$%0{_!bcVBdxNJ=EVzZ0@wt(>8JZTc@5}S_ zg~nY`32CSdX2(l&e)C5}P(>YVSc8gb1@eo7lw9<~bwp;QadoolkcqD)&Pz3*r6&GR zxk%K-q%of;vzIECdY=`q%q3rA<2ohfUyAxDiyBxk8z=XPGU3OYk8Dp z9QMkGL12WAf2*-tF-7`12VzGYsqF|RCp*Qi6|Be0iQqs7hhnS@Vf2$Ld||)1r=?Cm zjvi5UF-pWIEH095IxUK2@2y|eo~Sq*M})a1{Td$Hg4Epc;ER!fa1qfbB?GEw^J~K$ zZ}eyg{2OMz_9&^1y%e*rWh8lnQ%5VhN0rDou}Ny*YK@Fau{J>6%b&Yf6A+Zh1FlAE z{Cu9?yjFUj8FEdC5BrB|n&aqUKURn`Y+^lF6{mkZ({VxnmB8S;xZ@bht`YKY>n-tZ zx(M(BTg>Va9qc}@m?MR9Cudr-${JaP$7)R5X2)ooO*zeEBl=xM9}JNAOuw-j@f+n! zNiCQEsAhWEQ;`XXt(BkJH7uVwAGMnUtO}5n3Nol+R_rhvsBW%AJAEfnRmAJfb>@-d z20d(ekzlAYf_S<98|!Tq!wNfa)6jPLyG`C81ViHg^-a5M6xBbZ(I#U%HO@Q>9iX6Y zH4ibZ`gPo-)4O+nG=NqPlpiJ?ShP{eA)FsjR4q@?@QhlArt-P2#`Fu5#ASPN@ zy|!4r@qSV0*FS1Esm(#xrGrFAkPc!5v9W~%P(Lmb?xdycm&$uO6jvQLuARD zt6kAEq=6Xrguv56vOUg1EjcXS`2mQP+7keL?;#AU-p zDfd^HRowBQ_dC73e%Qlx49!@;eX&NDM!iMtV?IX}-3lB~t3m|xpip6K?=&IPavLlQ zV{DQeNTdfW?(w@7v_ei%E!Ny{Zx)+{4h_y=iB^;B|JYug0^>uVN%b~{FG4sSA@h=4 zg{DQVaMMjbhw;J>n8-VOV#^&4I_8l@76q4`33q%d5#5YXoX%7ha9#{?{m_X{E(?Gw zfu<^^1`+9)e?3sSn)kCs8dSavAIoAo8&wz+1cichg?%2ew@-hI_%n*?Rp*8UiP_V_ zD447OS8!zF&gJM{7X46AQ+8GLtZBG`GAxzmFx8y1GTFO0a8!k!*)KGM^=Dm|>xxr5 zDk_vV3{UMg;yP&3%_E3fNA<+z@n{p$Lhiw-ev|B!X<0g}nOEfDK^VU1h1$1 zpV4zESv#(R?GV%;&PF&Nj`VfPJvyX*OSbjuk$C6a38q%&M!Yx;U=lH#zQ+)dva zA?>mK`XtdM@av>Y9Sw6R=v70$xfOn0F#%^CynSc%ksyq>BBLioebp%X-k3&8^_0^* z68p~ZlG#6O1EnJx%vX4S6Z3{HrCwA29WrW#WrLF_+7qd~(c8%qZ_%~45NMy<#qzBF zWbNvmyAuxCH7Z|bWVvXdb<1@>|MQ=7)6L3b`xX^N;=slQV-Xig5T-c5%45aty{#V` zjn#|F$9j$M*+qCvr$;0wu2Mya;0`#h_l5sc?^7I~3I7`n9ML+u)8uZ0{2oTBXP_Yp z5vDk!SHWckWg1M(0Lp*HHE9R3nj%|hjwJqk8<3ILEa zm+rk%yW>=))0=nsryZ{JM594cX$a0ZJ&Di^)8U&JC4_KQtixt43!))Id)!jpmY@Q} z?r6UJYZex!a4;_=Q9!&7xSO%{3!?d-r&{a@;m~uYDr@ip?!YYbSZd_!H3SX0o2}Nw zvHEG#t4$T{>Y|-c?&TFwrDIs?Iak#YcT0>;*--(YG7X+Q{%lu!X%!`g@8OX4|HEAI zWh(oQsuk~yPu8-pF=me`XCv4}CMZ+At*Td^sMz_0W}PH_EsSomMV@GL)CtC>0_p1@jN;i}=0t^wd$J?V{^p6G^C-oac~Ib*@mCHgH- z=RgI)Cbv6r&tZ9Y_>+iL<23=fE~f$aFez&L4UNo!c$D$TBHuH?pC)}yCY?bv(83E! z_F~sr$tlZ1f$dk|&jR!=Y_BtizT0Z2axqsu7D3<5op_@A09DcrXC{-^8T{dz)XgTG zqzz|1&fY0eIE`H>2G(qL%S&4T)z<&5&m@enBDMk)fU>5Ik-nov$#;&f!wpclQvmpr z(?ZN&U>c&6{K@m4iB$O6i0@=&@e~S026Ex50wsX!3@s#f4s#dIHOjBLBBKcswJG%` z`L^Ro11Ms&q~K2>2Yk8qCn=Xi6m{;ZSHzQI(RN zYW4yB!`--@dyrGif|P48a!$5w;Iua7XDHLF<@3`ZxEGWe?ItgPgTTrQI&+UX)Un5O zxk|nbS7@tDmpSd16l+eLM-S51#>xI6PPHR49}1Q# zsJtvZY&hDa^LR21ZhM(immtm+R++u*6~A{ClRSi#(AJ4prnbcAO9*NB@WPX*DY0#A zKrX367#_sbvN)AUY3v~}3fg2n7{S2# zajo-^(SX^AnlR;1L9*!!$zNBDde)VwB|WbX3>q#4k!xIp_LPf9HCX;T;;YH}j_n6c zb=$*WCOS&U;(|_|Xzek_PdgbC*UVyWI@JYSaT!=S8b7qmaOmF)@)TrtAjKr{wlZti zOaXhz4Q>ciZWxH?9wjDQEPgs|jm=ZrYO`;kAXYx%bvI$HOQZ8pRuQth+xJdF9GDa7 z=}1_N>JAgqJ&PcuVqT(EvMdc%glP}4NmRaL`S^y|{mVJV?ADy}ytNsJmQfBllw3yt zh0(8}>FJVZN577y?pO};uF=qQL&P5z%AbquM(OdWwAWjzjIhKAO2F4~M=`SIO2Nv! zH|3&=<0dx*)v;t*omeo*M18wYr-=o$;$6vR$qocM(#%GOqqck56oq-3I@|8x>JvFG zn?O|Ho*k}{F`00y41rMYcy1tdoE|Pu93Ij+;=(=&`29F|Dw3w|IId8j^2;HWXCp;f9C4eo&5Xh4~JNAd0?u9M+ z!WQQOk?;<9mo`WFJ(jqxs>(ghXGwtan5TqNs-Gox|L2rB?_hyDPzq=#49F4cOT57i z7)L|ht_SXmKJ)Ik)VrmlEMvkr06o~w<)IA@}Q;@J@+93oh2^8Xprm@TdN0~_uoSuJL?T; zX7~iYX~BKxe+1qV|KR}}6HcH94&X9t9W(l8did(Bp(}HRh6lkTYz8Nl;w7QOFqHIi z@ky*Mp8nnl>ke^qDy;5$dj$UrKxnFHMc?l++f()djmlpyG|kmf;Pa8?n9yU4(n!z< zhs!jA*grrLr+EmGASB^1byk~TL6qDdOg+}Uf6tRtSSqDIz{GkqCiQ&}7*~H36Vo?q z$~`p>CEd_Sd!ODL7qFNl;3aOc;#{YN=-B==umAk>jEsZdzoCsRXY7PL zzd@0B1q;@*RzcYYZ=*#gykBs^4TjZWy$$G( zx-FzuRQ&~F#mJV|U_?{S4lc=n_mx+eR|Oxy5l91c_h_ub8>Kh)%Xu2s!V^pn&Md6u z){9f1eM1T2i)^~a?=)ShY)=f_-LDd-LqB6Z2!J(QO8QHq{wev3Rhj39?}Ttyufn^X z|3sm~pz~s8ewy?Te$&80Yj>}!?k7A13FB&G{l`w4D87&_Ekx03Au)km)TWNzP7n5 z{rNf23+LykA%mXE1kM_0L}tx_Mfaft9>@@kGOp}7ywY%RW^Hv%*ZvUC6CN!kO~EXu%_XzvsaF*wFw{P zF{KKlN#wQe{S-YcXm0P6STj@aWSS$VJ8OM(oamvy6x^L0e2tjK267cLo_|&897t5~ zsn_dhyF)t8R3%@Uu%=h@c1k|N>Bks2efq*6z9I#pnThzNn3Fe&li;s+h%(us*uvRMPsK`u4xt)k<>;)6*^fj|ZX zzC>wV+1O&IDt2-r5S*r4Wd{STD^XtnokvdtU?`ucqXA?qN7X@{^c~$*c;B@x37tkc zQ)~i(J(XkBnec3g_ob$FqEc9#o-QUrYPPXT;Hkg_tg;1t77-cV*^a9N9{l%1>4({s zhQ^3oT?e>zV|ISZbNvqS3SQk1z$ z&#LZQsPa7DhwotN)q#)}wljaL??j`53AX)1x744nJ8x2@$>1PeZ28m_TI#x1)fd)# z!*xPx4!fG0EzAfK=h*ma_}j$^mf5XXrh+uo@XfIa5(_i9+3aeP0n$r9rE(Ml=roM8 zo*8K>>(L-gd;$8|+^jI!d7%_?-qb>dB#wteiRK0xM#lhU(`?EaFGl=8rP_X2AluZ~ zoMe1@y0vvYfO`rG00dzx>yA!i2Z-(d|1=b*I?fpYSd}oHM^`H40`(c_^HakwV?<$i zxRCKTTe=_o&_fg(s5icH#kk&sAXZmzJa9ze-&MR{Mt}2*AsfmJE4*1RlT55!IU%_Y zfH=v7tiJH()iOg2*{?SR^r5a|g+Cg$9SO4SiIw$Fmf{Q)Lkgf3@C2>RiheegtRV0F z3@G1r2p4&W{><97BctL+w7>QoGqw_#hg@-9^OajVR_oL5tSmb6LA&!*k?A7_pJsei zds%zoI&H?T#){kmI<4VZNUGuR^&^~9U+FG?r`kAX{BU)hSh9hp+1}H+MxTCZWudUt z>O#3TeGIE{$!EN6?fQ7ccmO~o2%dFXIw%$0v>x>FC^o7;qa^W3${9OyI6l8x*5%tJ zbNe*x7)3_o)9X&lz18u@5D%%spl#2hT=_8H9nZ3+kih~e3Mn~>91H^(ro|}<5Q5)b z(E9l;MRR~>W}0xH}H#+TZRw*=JH4UBtujOz3E4nIbD5 zTKfk2T3fI4YXh0;? zWsm%lZ2#u3@9mFIRy&;^no;nXu|vMHRlUBrMcBD#-~_>YoG#Wn(4$jYn6nhSiXkB5 zpppU-Y4t_wbTdl|b1{r3V9Rl&Coka1<-z`kLNZspTpCoNu+6T~$LTaekFFCAI_ukV zVJKY<*6NSc?bh`jGFk|r>yLL+`GR^viG2b85pc&sd!6WII9=tU!=q9sN2Qx$A{D?3 zk3`263JB1dE)K$vsi~E-{TL1*8L%lp{@WZw)!bj9!tn5;^WO}lfkpoqt=fC5YQ66g z`-QHn?89*Fesv}%k@Et25jF6(cC2X3v(YQg#jVLU%{9)J&PfC^UA4`-$LScP7bh=F zfle*e8BoZgVB-KSlZ>q1{S^L&Xo7I}W>s)>7+;nSp{yrGUZ@v$407`B+19t*fJ8mJ z>RPKL2#`_0o2=k(l7Lcak}7eS2wDRLS^hDG;lr4&MPfH(P1M<88!-4raU&knfVI;R zt$QUzH}&a!S=+!pfoHAk^hB48h7bi;yJ>+SQbQUtT!?xi{Om93+YVg)VZ0rG7LMxD zvoqdjJP4?Z@3LkoP%+>E=gFp1f#16U18VG_Wmv{y{ty*rfUV1@9FT(n2Rn&<;?7tA z&<8{!0A>t@d^1o0*a*U&8_3${lFe^gLwq5oI7pMrL0}Dah5`t3feq%cgf+P+ISkGi zW(=?=YZY!eXp|~TTjYv=dzZtR+RIlGI0o)idhR>e6xYDfU%nJf=QXfxMEavrV9yoE z$UlxveL@OB8=i%5mH1Vw7I<%F8*1LWt7wsNZ+8UQorP1RS=nOZi5*D;5BZ)FoCYB~!`;xNuP3%G`#G>9BuS0eHsW+IEV19TI@nM1N;z zbb}(Y1s4C&qEEcfvAq+{ZFIi+3{v%HyCy%^KfdJij@f1ZQjdlb$f6(Cuo4SL7_1gM zP)@0|{ZhCYGI&aJ3VaGQo@qnCo!A%~ZVDmVn6m=kpaac9AdzsujuA!{);sNu2-O0&rZ?KEqE26|^g zSDEdR-g>x(9#M8e-DOW4tZ_g_;jw8b4P1u+k+u^V=Pfr`lFHHcT_7?05DHiUj8sfO zc0)Yqy?~{a$@MAmWQP{8E}_`8@(kWHDdYk| zqnkbpHkefjwlJ_`JI;+#t8IflNL7^V{_$G|0ERUL`&gx^pk?qR0cHJKk#GrU9ZV4H z&)XP8%a$mgZcq8KmNHS^tWA{1AE-Q5_s4WEP|f102wIv-73x7qeJ&xHVTXqR zA=4a)s%bwkBwZtF7;-LGZX)+E=)4qmw-?`DoShUJ8O=xE38b$xbkc+Pv`Fpx;j^mT zDquS#=6@_Y-QC-2ckHOejr2o^FrEScE)oq5sd^hX$45IX z@8;q+SF(TNK+&qyH*dxziZIM3TcNM7nP+O6r>RvHUK$z_kYI%(T7|Hm_DtLNV#{l;XK_eRAHzy>nk$7uLZO z@Ej|J*Mg)AGvkR*ib(^BRBZHH0>r_7xqz<_9?1i6Fj<7u$vE362M(1X|HNv;=Mh$C zJ6CP^9L+1N&c(=toq+BT%Kl@VGyphbX<0LuHJk7!7&dxZM}%bJ)~)i(pFc;FJ3-LM zo_J0`$2=c6%%1j^PU-QOVvOk>Fo-s04^A%P#)H8V| ztkeZO0k7|`$B$KT*RV{CSp@|yeo1C#tUro{{DI;Q+j~T{H>Gs#*4X4P=*-K^mh4;_ zvrQ17W*~41cQv9bozULh0@ye#UfuFbqR|*jo5jg%1JOm3YDjBM^EGsFT(J zW@;`J_oFxL9k600?p?wyQYebJlOO@+%`I|}D($&_IxH1$-Y6_Pu#OIZ`U*=$K@J8W z@PEsr2fkgN7i%1FGA7HV%1O<~s#hj8N%;<7*T6`Yi zSbRsbwO3e}6o|3hoSNT_K$*2(Yn@rSFf+lonm3f|P7a`oHMB|E%n{kxW9uf9Z5IT~ zhr2H+!P}b#bMH9)5fL37_n?9u9T5@h?i3Xj&Q)Qi@%@xX4OAk#dCztG8wM!`x~#Nc zUyiIZB-zqi25EP{xXa1gC@R^Q$GNL9=DI{2u0^?<$FXeT+ZhmOR67Z~-J!C`#H!^q17H);AU zxn~*`gZBJdN$qX-Hk5BaxI}T9zkle)wV=4`rkqyVI3LVq-A@+jzm<>5+j%R!0 za`7%93FKDmav&B=@zch3_y-RXs+%B1JGDfoN#mp;(IHN$u80_Q0t@=L#mlP}U~ap! z9De=`|D{kxAXB*S?Xzm1{Q9vAefL;>f(nj(%Px1$&Cn>^gFnu0Jb18?J+3#DR9~OO zc01)5=+gH54x4dDukD%3!0`+ioCUaFjA~Ev%bYA?aN=zQd5PCLR(wzc$;LN-DVT6d z8PcKE2mSI7F#GT|@Tc3!a=%Ewb#KmT!xyA7g~*T&WrNEUk@|~%t!?A8rOpQ58YWwU zoy&qGYj>|Y@hGfink9Q*H(q&gTcuxFhG^dbj|>1ae3Fqk78qJ>LJR9}+Q{EpkF_rU z#b9344B90casbmKP87^Bnl{Ws0N@SNq8-tvAmdQ*A&}&dL!!xu2!&$ksF;pQb7^Gg zNt*s2Fi~&{z9N;%8N|n{CjR`H*v6%8kRoyhm3c})B>utOp3mKdq7S~V8yp&nh?o=s zv;p;aDHn!dsc1MLmtYtIl^w~zLPRHfvJ)AYIMmw5g*GXz$&RFWHxLi$2$!3UJ82t6 zBLU?Zs3!%eG}4A4>BsTNH?+Alu-(G-UKlx=cFQG%A8z8HjLU{9e@n9GOynZbMbHz% zp#o68lIRve*Y`K~9oXiT7I}!81s{vi#{B$1Pwo4Y2i{SpAGK@N@KQ9ofPC!4}3m~%qZ}*mXhEj`_(l0n5bZG2lb?vc zVEXcTugA;4dT{Mkm3-4s_wI|YF2=JRwZMyb(1gX<$3zB8UxZ)FXM8rjlvcZK_Co-` zq_R-qo@ady#rZ3kFHb}`ZOxTFB6OLoh7rIG4;PxzZ?2~Y2uLHsfjuO4{AN3esDN^> zmyZizWoEK8%2<1OQtAEs<9xfQC_Dc6;Nbq|6Pqtz-mEy`?0iD8GCk3}KPyWr<=ta_ zHwS-i^!~({$oSZl1s?vuLpB}o%mgZNih3U}^!#~_mW^rNP${m|Xoq^EsvK3Z#&Fa7W*XSDuWHv#yUB zck#zTwC3A`)hJeIDJ>e12>(1Q8?BeEzE$1hIGXsq$*ZbaeY0LRDm(ipR{})yq-ZCY z8gX9eJkEdIr9LLkI@!8C%m$>q%hJ^M{9V%RyQ967NSl+4%cz+K|H?mbqR%&3% zWnOw{QtG&ECB3aX+E>KUtl7_MO+!+Q6nN12kNKYkx8<$1i!(&kGnzb%ERYa_mOi^D z7#!og6-K(sNl3?K@svRK+|+7%QtA3`EkLQEn!uLBe zt(CQZjfUeZiteVj*;bCHh9;%+QZ5IkvQ$cgPtNFQ?z~reQWZ@^6Swnq>`bIfnuXR@ zPyZ6A%xv+qDbb$}P;lig2F7tlUdgH*>j628r_939orEg7(OUs zb{>GPCv(YR@92C4f%Ls>P99oK%za4|5UXA;v(9`n;!wSDx)P%K zXNPdugnz`LSoVf{U7i>N8o@X`;#u$HDHac$%?3s=?E;W}aS9Nt2rRa;yLkjwJiN_s zNQ$FicI@BZ)<$`N4eXE$EhP{>1QfEb2UqEGpo-L+wK}-e9yUA$Qs+%5~*wa3&=Aj_W#9bM$iOxHd;HJsp*VwvGsC#gH?7U}zzFygO4r)?Hh{dkLw0 z@#jfPB#8btw43mc-|t_7GWOJB1D24W1#M#Te}H`eV&=|! zz*lWQzP5pAYo3a8>i0I+RheOeUVHHv**KwXFXIu_=ZtsszwI?VtixhZljIAqv%B|S(uKb$e zfS#`k91l9BstbDM6^ITu$7mFpI$QGvwiZn9fOhOZsC7UJ!PO2OJuArcOJXJ3Ie+;r zlGKt$Q+gR9kjMywmy(v|N{ZY?PPa>BCHZAyx}(u{h%78kvdKyE?;FQUj~SRAp--oc z`T7+CQ25F-XXN2X%un0QZEAdk3mC+eb*$bs5+`>FP2&tmDFA$7LwU9*lbrxLIzT7| z06%XXj@22M4-_~TFWLQDR5c;S65}Fu4_6BJ#aY+{@cjfxQ|kkX)O6q8Uf*<^a|!9D za5<#g+F~t_?$oe;s(8@STXI)45P%fPFQ$>PylH>`X`bc_ZdDrx889GH>5vf5F8`}i zZeXr3Em;h=ZwUuae7JYSvv7y?QlBH^`R=Y<(3S>=RH!{;q8K+YUkMdCslWn;YIRgB zBdlg9e(yQ+N_xk!V;!qfvI;RN{`9ikkVJF9``e#p8>4wL`Ee&_m;e7^{jz~f-%1KH`X=-H$%t3ohhYnY$%zL<*drVI#@AoUcE1P!4W3%J_3n>uvZ7=d&&v(x+dn8#lGri4&@( zauP7IUb7?Lc2Di14NZcQsSWoU!Olp%)Jzr|Bw~=XoCg?w`UeZcio!9dt$q}J>R!5Y zp~pjWU^;IoY(>23z~f>=@9qhp4H^`ljia0SZmS|9pw>{8AgL9wcC!6D^8 zYQewSU+j=jaC(EjU3@HXy8cyHxImA8I7C(O)0G;RTmLg#OZ%p#1C8e7jgI7PyJHmM zvXs1TKrsiT5c#^$g<|E+vKCvu-KbTkNGy1;vUOT9RmW|D{UR)XZy(ZNR;@jV)AMKsk-2=c8LFcAW65nK7PWTYqtq-g1*mUd6|8Hqrl<5jS z_0WeSP?rvi3J>N5PK%EN5?P4y_pxIV2{|6+%i~|*p1eEbR_E z6A{y!)9Odud5W`h%gtbJ_;+_onR(Kw&ISM99a+%&(aI6bRaZhgxW@S;R z6?E+UZYyx2Y4aWAz*r0z^BV?a?Ibp-%>z-@6djVfk@D+bgX&hVEEwdKAGN|iLt>T= zfn9-_js&?(I?6J$P>=+n4|TIsNN!tBtTJdNRGn0`*9ix9=mJg_Kpa1c?}Y!`oIW?$ zb(hZhW+`>woAN<``mGLF$v10qIo`+Em9bGLHQPFP2Kg`wd3F%w7$p+dIOhJ|2Q3Fl z{df>_)?@0^|I`}6zerM*_*ra5Iu~1jWqr6`j#T$Y#;(rhdy}1pJL7>l3flcV=m*#` zKh-qS1;S)loj$D=gQOA{xSYL}*a9<l<{~3RwZKHl3 z-_e{05~p9yYva6d{+Kopnwd z8F|#>f)g^^f7`lRq+C0&iE{ia?<;+_TqyBEaZhSP@Iwy|;PLzv)0PFytf<-Y9YQT~nY(S|{U=0Qe1OpgM zP-5jIXnVFS08U1LWYp6vaj%Y!s~BRZaSVjo^4agHrk_)eJbJx(9NK6(7}gB4|@u-s0*Tm`tdW*JOz5#E#uGarkZ ze*d`WWJZ@s;#TA}43j0*ZKi?#`T^dxcHy?vC1?S710X?Q{`j?P<9xeW-v4v9GVLX> zGVK-J$3OBIcKq=xS9jU+$GW@5Prlr^Yn*TMH){h7E@!oSQ&A?Qw#Z_%3;3)Pi`;25Lm+>R2?TJ3hdy{bGHn zxi7YFpf=PJA1laQO^pcW7i~+3UfIaFqG0&r-S+T{Ta9DHO z{m`dX%}NN&49jr4J}Tw8Ul42vHSL@4vY7@7$wnC*PtgIr!zD#baTyy|yUIl_L592T z?hM0rdEiU}k2hsfDguCNM{ui|(fc$=#z!mHudnRP$nYLCD=Awy`RK{ehO&~xq;V_c zRV2JWDLF!!o!>v4pBEnP-D>_(%a4lUYd?y`qcoD9MCl$M|CFB~t+X2NW3{EF+Su!2 zaYhq^dM&cK(Sud0VPBm;h>R8B&U8Vl;t`2C3R~IH|@&y9_7^?u%4tsvC z>1eID(4Puo^7;M4%^y?6CYLdI3Q*`|ev}QH86{u~+~3&}E)$q;y1=qz|3F2CR>l%( zHJ)N$Gc+i9V`$ob1PW1^-^r>nA~OoyfQ_zJ#PT6&cxO}oQ1YqPDETWDC?Xp9B7tH6 zSZ(y_(7lCTsR;+#4Q)+OR)vkgvdD4RA`)H~WD~YG3UCRn3fm(K^qi!4DRVtL zeRqq3A4XIXuDlP_spa+n1ZFNM1;;Gf1+iOAXwe#QIpn7QEjZcy7(dAMS{2-c3ZB7j zVT(Of?u#+ZxZG&F(y2eR+|AkYb&)1%hyj>B5GtnIOl5#>gY>$q=HcLKE0i8?>V73v zZlV83G_|p;gxA1MV+s-B>z(+DfH41jav^14royv|$qNe#$5vTKu2&s1Yt?5p9RgR{ z!N8MpV0mcN7h06+_0G0jI(Gb^kk>YmO7p2ZJ zLCvyr=UD&y;?@0WB!eS9ZP8s1Il~jk@n_rxf`8ex6aD0P%K$@!RO%Mk1|u*CUwQhp z9IggygU*UMy9lhSJRgAPQz0y(U|eMKA*u7=2cA{dgR$BSM)B*WUVU9^$6LFpMZ+!+ zNrRPsnBOYPCkH0lNSi(8ee?W-YmcwY`7}~ib>VqqZ{C4`rj+;w_jXZk-Lo&3W62UkIU#4xL7iaD`17_OZ5t4`bMM#l7B7!NBvu_Laqep zBlVuH78ldZ*d@*N3p((t^DjEdy1JSJ^8DQW{tYQ{b?$A#?1;5W@>xajT7EQ`6gzVL z?)KrW8=Gf4-sJ}=q92vgE3naI9}eFqSXUAyFG*W(n}HlZl=ZL40DCG#Ss~ZBMcBxk z7$Og*k4R0^A{dyB$PFVw*H^dqDv&{f2p%_5M=Rh2hw6j4>Nr|)-nE!e^Tg56?ADkh zV_h;%c$MH$y310-dhZ{@X3)h)RV1aQb5M;#UXUP1;NzkmoM`ZPbKtmxoEhX1VN-e1 z$TxmHSklG&7kf-6htDTL% zWiip&?%6?_ST-a(FEF1F&-P6UAv}9g>bv@z*o*pw!p(sfIcoj5i9D$!za+51-gjT& zJ==&!1&{6)-+fpBETdSeaj|T0r808p447hEe!j|Wjk3N`H6kED<~|nPvvshqJcwyV z&sBo_u{#{#lj1qFlP76&6xa*!3GsIJ%+qlIpA35;Q5g{0A00n01t?OD##A^h`X*(0 ztQq;rVhhcFhwMxJT;QxuakCM^aY^&N9$QWdB$BvQiSzAwe|4mHNtu=2Y!Jb9g6$f2 zZL5<#>2TLarmc~)s-X#?BYftLGa6eE!9a6n2cJ0-AF6+E`*6iTXoNOL#pI?7GLiu7 z^qOa3&ysxrd0v_htj$PMgk`60%}AC1;pnfh$x~NFhw8+_ooqJ+sQ0tBc32-cbW-Y< z?GQS5W7)JJSwsUtw#WS@p`UG3zgR^5i=?)pmQQPv0k%2v&9x)rrl<{7jpo zLHoT7P&5Jv1M>?suh@LLV;$R=Uh&DkBWM`Lt*VtJRD=D01Jmzk4+A)4*&EiVs#-w zfLuQyK5HCH@4oqNWl8VlW<|6QF~v6CQ#~3|SFojBY#Mwu*rB7dO3s^6JTy$Z+I!0G zibUT0u0z;sWSQr$+mo%$8%^;`^`k|h_nuIw;Njx|j;j>YUO%clL`UDLHXq!m&1N!9 zQvW3M-46K0Uq;VR&$eGALA#)qBCB}U;Y@Ecoy!g~tHFTaQluO`hB6D=e!VBH6p98) zMlCYmU8#$J;CB>$Y%nt-7}|>NB7i^ftoU}7<0iRW2BMp#Qf1=Z!4g}9u#nDh9$ae- z9^)A(u2#(DiMUfJn<=g+Z>~zQvg*%EY*5#!S|JXM@q~|A!g+8C!QtTlOkL-RRaTMD z1~&gf=>jcJrT2UEr>Blk8BK!Ew#+4g_g)@gxVtZJ*S>R6NMZEtmn%Px_>uu8i7t^y zgF6=ZaF*3v(#c`rlWe)Tz9^!@qnjW=>dLc35feQVhB2$YUj+y>Rw;@wWUkFFSqu#4 zmHE8$b?WYR;#@s%$b8P^MY5BH@L&jk{;FVWJ-+XJcx8d%i`gY>Gh(;*l^o=s5D*~Y zn!x0*k^}$~n5k!H=t?+3O9)z>08XRYd!6vej2@6*O-!}Urnig8l6+owVQOP- ze-|qb{Beja8tKCUWjXO8M3nf-pd=&M6hluPEX`=W64Kk6Bc;+C!q37V_uXCK9dQ31 zCsEDz{dO0Nt2SByFoQi_CPL)I2b9r=EgCV9J2(BnMuzxPZ%b&1G_9>?(qyTOmz->y zMnAgW32+jLCSCA-j{N?3>hpp8qr+zC%^!G9^+z1{!TU{U+(6$y2R5VI!uorXoMpk8 zer4_hd@=@XFKGi%0N<>KD3EagTh^ga&4$oX^2-IjQ3M1h{=XtKPKRz7jKPvjB3y2l z$Vq-f)npC7)8vB8mGG?tG(&(-!Li16Y3Yu-wOT6gdn=qtD1LUUi~tn|#j>97(9p8+ z@nwLMcuj!?kR;?95DPG7hw$-*7?Y|$4+I##wE3P@MRN}DT<8x;bIHee&%#Vf31gc)b^(W<_9qT$-NSzpfL^f>ztCPPo2!qg`X zFvhE65QM8f7n~x5Lx3VdmQr}uWti;QP1GX9rgg(Y2{?}7=%kRbTg63{9E@`(RS=Mf zkkI!6Fn~=&vwTNnl8)0&v=qq+Cn;b#u}WQkj>>yD{j7dY|J2l6V2#+A*Gi4Rg+SaK zAN?*(O~oi+@=!oD{QU!dotH+X`;b61a&P|VKT1%*-&uGYk?*ICIZojl2ZI+ zjheR`lq&>VOxjmobrOdp39{l!{-rAq_G0`Y$5=xgljfXhLn;NkeYH?939*D>o#}?PE++Jhb&kokyquqUM`mm+G;4DWJS zPLJCW=U}-r!w)xZR_%t*Vynm%W!>I5Z>@S-G)mc~vy$KHTaXRGz75ykw+?b*Q>tBZ zi#JCX#&`2J^|o+jv74ic9-nP>GDp%n1Q3+CW=s*RIG88;Qa9YNY*D&}5ay@a4O$gG zRfOX$3+>mOkzR;o6et*|--!}cUZWj>@tvFf?phaa=?V;hGh-pQsseXg;FSImNWZ>f zS$C=De}d4fYwBx#S#KD#B5MZ#7ODTiZTfcg#O1nQmq5;aw`Ung@<=!6f=tVdz4A1ZGdy4E+?MKT`@-U>Ws+UH z&t|Kz@>9NLZgH*+<7Eq%eSG{BaEONZsP^AEW0$1|_n+IXHofS?tx~_Pi^twn^*Shp zeDUIQ2G%#$9=AB8Z_xcnH*eIlP{0>XbUN4Vp`M854^#8h&i2>_`G2U=Jmmd*(^K_x z#8cDPt~&}KyPTkSOZ^dUfN-7&_%E9+Fn_c` zaAsHV3@_bM@F(Zmn^C^b7FBQ;EkfDq_%mf$|NLFZgJdsvbk5^|nBHku7$A;6=(=>9 zaC|<_eXVVP8f-j|w6pn;3wWra;tft(ZIm2Lu3A$kK(JQBsK5RmBaU?uyZ-(bWf23& z2I}h10HkeUvLWMdi+&{_Un{wly)@RRF5FDeXOw}mVmsCZFg&$E!)OHQ9 zT~2R`vO#^Miz6eW^tnlaSrU8)s`H=R5><((ug=YSI$Txgq9dD^RkQdiEe@Qt{fw+e ze&0-<%-10)U&=d@)!`dOKs6yhTL+>&qnZa)wCw~h_r%a(!46kh+zlJ63)2mkR1K5n z-s+9P%{iJ8AVr>Smp+4U#J~~m++_yMGh3z>y}&Ye$wzm8fEx6xiQTe!)Q8$LTvC5#JEc?MIRr`*^-{hXScFr?J-^NKpFGW@-h!UAIg!rcofZ`7q)7e)oaZB0P`Pah~weXQA?g5_^$(vFZk#02kDw@bCAc_;re@%K021Sd( zw!hp^dKu;9Z5vQd@nE3sfvvOjNl!4o9)!Q-$hhBX^d z+CBgyA~Vx1yO>VRl@2)M<{I()xA|#PQc_ukhuuv~48*9xYK7>>k8$F-Mk5DQ^xNZT zdu?GMz+!{4H&+5;BHtJrUQy$h9`@!ajWhz1X6(pnmM^Y~Z43?je%R#j_pk*DIDm_Q zct_H1*ay%?3g}R3MW3vaj@D*V(M^XKjmoFl3Q_L(U9A^_z|3PcG%_?P9iGwxviIqC z?yrJ&?{^7QxMW9`X&K~Q<{0ed6XxVjvXsDY2Q5kX-aefxv z__;w>S`i}|KOVoD!f*j4Eq|teM{8NY7bX=V_upo9=5T~0IA|9flYY;dR|m>@a<>zJ z$Mx0a1rU}<1ADa_N8+^ql*(zly2_~}&E1hW>G!D@kWa1lGsnxw{vVlj{e$1w<6JMR zxV1|+&sp!PU}7_|FU|_iaID&PW3hP|P*7gF54jDo|H9pM+lU!#P_Qw0Bft_GlaT;& zE0-lG=603R3^)6MEmJS2MB0S_*TYUH762dei?8aw8L6o_zfvfCU1DNYZ|~Nt1OYN( zB?4OEhl_#Ek1H?xl#wBf|FdBT-I-fvV7gyYA-xOZkZN21G&Zwy2>oY+Fg_!rBv8no z2oREhtne?T@P)CgZ?qpL@c};Zw`^e3up90{`%|N46O3qdDCe4!t)=mm1RT_|jp=~^ z25y_^ahpchv z&8~3^L)79GYQoK%3r((Ap?+TH_$=y=YjB2sFTV|<&(kn|?oW<NRqF4sUz3L0c^@#l}9fpk{izW4pqxe3Ztqn)Ia` zeNu(mcMLSzOrHiQBBI+v zP;KSOAW(o3KgLH76* zoxHLVZeVFr-ZrJjYUU6q1XX0Cf61MGjIjJLM&H5L@0nUB8A#YOcVak2Ci#vMq=#17 zT5s_M2E(MyX>|WjvrhErQP-H%6Vqkblc>qnCH}(uKrKU1;XFMJH03+Ocy)llHRob; zeLjDYpI9OO+8u;5ft2o`7~H4^19>h?Z%*gr;3x4pTXJq~g-Mohqsg3` z3)s7#V(9&u5y ze=(vC424(Nl@D8Wn@Cv&DoHuB39ErDum2|L`@VizM+TrTIvgx!l?@=(7G$dcW%1@a z03Tf6uzzAfu76E@k2a}w$O#Ney_rtGzfX!k8UtfRfXw2|`kX~zC~W!6{FbNmA8L#D zL4q7M#Rp8;^NAq^;6pp3Lr4Ih4BSb2GCKO?UNSlBZO*epLV2j@p#MVd5X>RseL>S~ z7oJ^;k4jqs5LTVLNA~ap8A`SQW%8)dC*^dbYeTy7?^Xcz4k1)Gl*4a-D~~Th?pZkt z0b`K8HgC#nUi!tApkkhH2j6PO{#y-qY|f|Thcnmw!LJjZPtKRV9Nu&o5MCb0!B{`$ zj}&kV>cdfiIEIk#+6K98d?3KH6klf*0vR3KPJX%PMQM~NTcUssz}|@fC7}Eq%(K!! z=bkL}G5=?Fq<)VA=%8nzF?l>ru%b*JE@nx%Y5EZUrs#uj2%*ZaFj7Q$y$ zaez29ybVNGqJ(Q5qKQgEojavZM{Fi=noDy^twqrQYC~IB_S{i6jmVT^K7wBN!12yD z;S7}1{qkUJL}@92B;kQ=q_l5$VJx63FO9$km*027*rJurczD}u&__9jNu;rl&SiJC ztwjN%BCko|jV)vczLu(I!e%0*^NqzK*Fq<1Pl_{5h`@sw40bX;q-cPXdDzX-%u@70 zwDBKHx5JrV515lkPJ3p!oO5BkW?taA>@DGe%60*phK~bT>RB56;lGZ}XRqV%G2i#t zXx9n?H+Ld1=uv$?KX5HNdgnYkYJ$((yb|He?#+DOL|v;Fn-}L2&N|IG9Z^M2$fjj) zy%a{NZV6PL^I>mM2I_xEZejbJ3){~Vm5J<TO*#B4#{O93PZAQjqMQoEMNuiTfB=_t4IU4u%TjI(@45GrbdcB%M=qnfkJ} zJd7KS^FHtGYqCnCg(t8H8C0euW?xR^=5&!beShT6$g}AZIfv+ucZQt49TY9OEsefD z`x~MB=a|UhLzq`OcsMrlGNJgRdCS&==$D{J{+o%AOhk4~uXUz1JdD{z&$f%omzo@q z?AGiTN<`WN>fP%7T9HJ!KSJ|If}e`TJX_7~PAH~=tZeLlZUmg-v-G6mhc%H<0VaG!>N8XpVD3pRBH zB@OpMXW~|`Za^L;JF?3)1*oGAw222G=pz zwb2>$!#M;OjWYz7rLYzSav5&XehZ~rz# zd&<7>Egb{^=ncJaAVqHn1^^sw=l-G~MB8J_o5ZbwpEm{w1f8R& zfl;0y;W!vnOaUot^QZDz#@Lg5tKmhy=GOLu&i&)dT>6OQD4VP7zq(ppuj`cw-qb7% z5!yxoiBQqX&Jb~v;qIfwE$3_zxHx3>N+ONuNnqLS{daVi(a<1Q%V4}Yu*JTHw2M?@ zzlBsSJcjC>@2fQB;P zzMQ}Db6c7!!Xs1dHFg@ckK8i92njDdSDMCn7ghrnL*fSv38wL;wWBX;17)-YQySC8 zd+Wn5ghvUq+=DOdAKAT@ZU5IKEc;_EBGXF9khAq(*O_O**~t4+w1)a83!g$hlY)Ob z==W?;qWQ-%eu1!6_gb}Y4*1iU<@67+zxbW8{xm_hShWy;%c@$Mg zca5I#F@1En`qC(y9e&0>E$zM$6jcv?35Kb6>%~Y=={_D9n-G;G{E8D))s*T$%Itj^p)^{Q=v9P{RzkC(f6l6sN`L8eIP<5F^jQT0LO{6h!2>*R z-_9}HUeIYkI$>rWf!A|#GW8<-mX=Kc?&Z;W6Z~|L80hdK(!Bz`<*%x5H-gII&-wpWAOxw+sj8~^#nVgG$a#Gdtl z=?saIJq$)uj^bnzJ=XVD-*7+bzKbyzeU!25!ASfWJ;7Y|41d8mY7$>`Yi@=+s{+4- zF_)PWJBRXp4QDIYSGsYqHy2fEZkG?qK0?{w`Vo_Yrsf|BnJ}tFxwB zpnMZ69&91p`{O`egHz^CZ$Cbro|C8Xw)O-YprIrZi>t}D$qC7I_p-OhH0g#;Dpoj_ zBceA_%4gDEya%;=JHj1KT>($1n$=NU4w}C)=a-%85>1p*XeSuky! zMKxN3vU|V!Q1oD4JAFz-M-WPiY4`%D4wxpk@9FO3|C4{X{b_J^$J-tB_ z*=I$})S!T@D;6mZVLmY&*bF!Y)ZP zlKN}}ZQQu;nPuN0%FQe!@=hS6+V34$a)J8M+^F=xLIyBgR^_8I06Fbg>CcPBWmTq% z)@jPM$%-S^Stc5M;V|;%d^9>7>^(2F3w51eoaTLZ{OUVb5;j7Owy+)=f{Z=VL(Hd2 zX&5>G54z2&>jdnfaIS^6xyX}(=Nj=Yl^J9{JblZYBZ}|aS9AQ20L7_UKQ9=~^jTU3 zJxlK-Vz21EV_6J22a03YMY?AS_<8n$UE&Q;5j2@rMJ-9s&5yl-h%SLiZ8!FB+?<3& z&e-%k#^{nzQGcT)HVx){KWQAaWa_jWFZgqJ?pF&)0hT^O-2Sls>plPmblcBq02uj~ zZcy16-MN~k{O!>2Z*4&X{2#uF`6h@ZF-wuLKCuH6T}gGKB&9bd`(E|k`psSZlV7+a z%;3dOQ{LwtqCdL6ED9U^)%%YXAOJ*kE=>O$8DZ11t?Z7NP%D;lkN*1NA@Ozp9-z%% z7#il^AQ#)UxnVo#93@050`He>z1v@VVN->)@2{~BS3f;BH#9>gOlX9C{-Ur zWLx5Mi0HM()2}#o&NEePa3~597AbSC>eZfUPE54UkDJhG*g* zE!!0B^dgC%B7aR5u%wopNTs!+-myn!jlxHpG`77;3@rNyfn0_GESJihJFVDfNF2?iK7=~HI6wiLn{8@@$N?I{l$D{HD#!ph6uE`3W~KK&1M z4QPdOG{!28p;u@dDcVxz1#}0kR2355!)YN* zrfQ`i5jYvCvDf>BDm= z$2e#VOpBHjre0Gid7*~&tq%#wo*8BsAwZuHW!>Zx8|9N=8qbOVn}|gHZs*pdnsBd} zc{Ns5gw;+U`axrHVr5ONCy7R9#jcb@aa3lo>XvFYg{qMDfLj3xP9z$C3<%XVg+A>0 zFqi@#hhoRBTjqz$Rq1NHoZ+Du0xUdy^IC6|tu-mybUWOw#m0lcBzfIJ&wW64NNlcF;OeQ|i%n z-@@K{$2smr(}|^8+hl3mi=^9K#SyMrp3Vnfc;9;wa1hz}*y=v#SJM-uG<-9&?$zE`2=ce%&)t+>}&ijMF%o%znIN zD96w*ME+AA3M9|{8=_SQrzKM60{ymT5_wU2o|lsQ-gh%M&v&}o7QHjbD}3df#yA(T z!Rp9hFW>MJYdN|8Yq_JiAdNccZRk1)$P9nc%A^XCsczVA3w8+|3X zAYBB{lP5p1j+@Jy_N(?5m~eA*1G)JZ%T+_5g$Rv4Az{xp24n_`0T9n&vnT659$niv z`iM7}Yg=HeepvFYe4;}?j#d}Z~oiee(`(S<~v4v z?pW#1cB~UTe{BjV60fOKmdj}s-ElQR3X?r-=%2;Fhe}lW#I13bn@AC0vYdlqDir`2 zkcc-X0?Pn^okQN)Be+27`f#!aDE(%FwzPo>29j_zW#rJujE`2 z>Cd5Zv(MtsOb821cg;kyi&7_>Mvd{PZNbH@f4sh*&(3jDQ@UlvvW+Wa+QN!yZ;?pF zS{^-A94Cw~?)~)=yfxBVOxe^I2c!hb7x~wL@8+r$>I@g$2?fLzrOW?6v3c_Ua-xp@ zb8QU}H9YQwvBN}8&Z4jraZVzmPEMHUtHwtn$z(Uj?T3XBFL*ey!^E~aC*S_Z-gKSV zZ=Z=Vj?Q68BtDLckMX2l+e_!pkB8Sw$$jddbz~=@kyH?PVD#$M!1rR03qnf9ua7^T zAGDVIB;*O1a+QBoLmrDi1z#RlbpKeQ8i#Oy-|lSv4`x*q@33QTP-mWHKdeak%!6^% z-QmkRxozF29ox2#hg(O8S+&G^akAV1H{RhmVn}3p@l<(Hq#fpn^L9+lXq~pKRI4c~ zQRC5b7-phW;c+?*8^;&)%=U z_gctJ7)NwR7=?4+KkuIZ_GQP)(*eCxatnO?o^L4RxX>ynT%sFyD-x-txSqs z4Is!88^hzcj9u7ycdmuR7#`nWMdNj=-Nzd-G@L3gI=LR!aNG4dP1v|K*J}QUNSM&^ zh}`rr(}Np*O8B5MjkPu|HCtf>!rku|nT&C7Z|f_>K602xJym7Xaj+ zSVGTxrPQ$I&jDtZZ?hn^{FwC!1)`ouW zQw8zm(qM1e^B)WL)tqaa>+v^EU<$kmWp~e`c2jZATLbGgC1GKj(D!cl6?Df7_q`dh zrfTCv`>{FIcBP+AER<<0eH)#(1LDUwh9*ZwpYTI>c&_{~&VmS(Al zLT_jKRurI1hm|J5rFy#~43TJV+~o6u8WkQRGamREE?S8% z$)c9#-$$ZQfTB0M3f;#AG(nptKV{IsT>{#4OP9B|9UZ)Mf!@qke>>2?7I-gSpLHxe znEc3LAp2CJ7cVl!0rF5-@is zADf#AjmLEjbd_F?nR5ray+3dwA}O+bf?rMR+SVg}gU6|^X*2ri45764Sx zv}ms*8N+TujD_?mt@=#dDP0Y!w3;o!=L)5b*(SL!NsTFZO`=h*^MVB-^4#fmkh#ZKCrOxxZ4xJU<~ScSXkJ3R9&q;`r<`75txzk>wTY#oOKOy%8yY6E9=X6 zYZX5&s=5nK=sna?l`3URkz{R{I;x6$H?QkrR-sNG!j&`a-wP}l;*W8m!tb$RhX$gH zZ*Sdsqf&M|I7a1^9~8!$s4G)}>I&Z4`m&51RaBKaOtQA6NC|7DCB}j3z=8Cszv66$ zC2?A4B;??n2?4076=%D!gt@f?y9mM@c!2aq+7k4YsC?|dp{`Ux1diUyNpw;?>H11< z3&5Y}pFXKdc1UiH^fU$NdUVnY-7G5W*~1;4F0MkO_O<91Ohg5pT+VY8)zq4Dy;XKFoFrx%IEw?dxQltE(=z<~&@+T@v6N zp>T^rDud@2rmN$VQzH&PJl;^6Yfcu+!X<0XF>OQh&Bp1umd^Fl9oK?SbZ?Zqc&{k6 zsQuqhBFHljRfPiS&&Zd1dq?%TaD+Ge`*ZEKEX13-gKnA(q&wJ#DpzNAcw^6Lz+(i||T@YwSiqM=VUok6BoN zsLgIur6p4(uO&N5;`hrZzpdqETK}YgHS9Zws#&Y*S=ARb6dgtzdV0ltHZndZMkfqZ zr{s?Jm}kd+8@YXZZSQh_4c)p)7+ew<(cyPptL{>&|CVO1UUhNRsC{*2R{SRkAn-3n z6l16DSr7i)o`X=dQWJ10OGd!Hx`BicS!$nGu0s@^b3D`BF13^y(a@vM1>=rp9|P0S zQjE@S3xARPPY_oojZTB49`|)8_&=JN`Mo6Sxc`3x{Tg_i1fp_vT7E#(WrQCDo z64WND>{WsP>H7DpwT~(`p-1%8Sk1UNktejW>II&}pU8AyF_>*Eg~nK|J%o@V+_m=9PCFcvG|wm+3pD4BPs7(>F-zh zjSsthXA@`y)7!O_X4{+f4T$omzyhRKRij)LHh*=JnfSwgr@xV#YX>KdB*mvC3j zHPnr+9eox5wR&f%rOClO%-6oARyw(F?n^_X)7gL6KeH-LI>cPew-JLXAIksAUq9BD zGuYozifz69OKpaLlCQhCi_9vM5v%UleBteIW@Eo-7M-4lYBHdor5Lcv>X59_F@XGkW@laheSEn5H`)z547RZ-g|*DBM* zQv~6bY_CTooQbxYbFCZSVK?M%6dQjK80*SAo&oAtF*O4i~ZtiF&`H`&Aaz72$T? z2q(}i*FzmN7D%UuCJn!4xRK4sHei3(tZ#C9NLt`g5TAZPM8H5Tp;G)BN|}Dl#z(+7 zP&Pr7ejvUen0g&v=M(b7v!|p3G7y*~L`!oW^QV;gUQ>J$d72<9uq_D7-r&2}(Z=Ru zcl=!524w-QKzz*l6fqnN_s>Gh@{?w|lpBP&2!mFmsQ&GDZAn2Q18PuhRl|8+qK$j{ z(N9$Et&HFp#`#wal;tD?w^U?d@(em zE<_J1j&wLSXvdCD{N6rh+i0RNj{Zabju@(Us9k&#Rz*&htnpn0`{DRe=|jlP%v1Sb z%Mnn<7X8$^ff=V6x4Hwro7mtsjvuId?s5AzSwW0oecrDBPQ5fS+Z<}2eCjQHMgU3O z=g#Ng()gVh;TxykMtW$x=J}l5(v04+r4*Cs6~yaygoiP?HOSg?5h=5?mG4)}Ho6>M zyzzDa-s86yhXR^XTSaqxXR<@KCMF<`#SKkQICAT!O(DSjqWJzC)zdJ?MWeN|+4P;; zYTsi>*=~J+b9X0x8Rx|JD{r9|jo>gxt3!l_Y;Ok54aa8DlpacDCe97{Xa!1|zn6Nh zJYTo@-J9*uCCFhAn6lIS-K(udD-I`c4>HQ9H&&)71H#6gkM7%QJGBWtZDJZPK-SHy zZs^KR|06_xT*z1XDTTgVrHJdHcH@iq8o5R-DsdCkZtbnEompMKCN1^Zi-l_ip-N7q zfE}O^2QVUNtb!M%MpWb$TDNT#;IIw2+p04OZ`dAp>Qt=Vc7kY!|FrgYW6gE}@>&bF zHwXka)8@@3t2{w|x7F&7fSC3KlxR_1-N*ab7niV%KT|XEXM=e)FD@)H6o26hp7gt0xsVYf;yR~&uWXROP$^CHW5~{Z@L*_GTKD+F=M&{x1nmU1A_+%C9phin6 z>d5`_dfO^UJ-OH|+grQp=Hdgj0bt3g2mweG>8|j~vdgh)27-y;him&^E*}mb{OzAM z4dAQD7T$oRUC*2AU);m@ADnr_Kc;7{1N6RQ#p>D?a=gp;E zzd;d}@GX)0M~uN4zW<)u_&1RcqaVJGaYzs<7dH9}<4|6o0}=z=EDq%_T-Yd7IwZVy z{4#H1D2ambErFt#?oWpc55paUDh3N11>yIcgnUpPyXD*lXZe0{F2=mMl6MJS?$ zTQio9iBdvU@XZLkhiN1tZbc-1tz5dHi|E(N#C17)uVnpaR)5!-t9{NfH#c9Dr*&NA zNA?P;WPwPZphV(bCkgRowKL!EA^mST%!!VX!ZNh?4F9WZoL=UZ4Y^r6Mj`tWgLxWW zLw{#Owbj+j-rK&~8v6Iv~D2D{7H%ml=t6e zX`MZL?6b8#m)>HHu+!bh7UJoRtA?Za20Ahl{))vW{IZOnY=haRjC2Y6>}@=XZ*4*H zAAl@%O^fuu!*4R;rg@PoxxX7oFGy9K&Pf?c9`h!i z9=lCE@M8orY2WyND=NzyM96s(Sf+J@-4jw5b0T*CLSf6w!i|RZFHg< z?CebJA%qrU%$YEVt_@>x=&f@%pu4{s^WVYeK@P-vAo96LL5jq)yoY1mxkdt;P$*rW z(`!x>9EpWQN5ba;%QR+VfS@L{qIYXdbxdWAYZ0CGjKBs`s{K9uq=DE`DTz3V>3+6s zTnZ5i@CzZJnBzkJU@#?y8i*kMpj0CeNdz*?z`?L~D{Rib1bvgKyS*tv|1=G2Wk+!w zo}e0_20um`8e?^rK39_wTyMXmi>+z%4Gr^+4Y8(z{2(g!13-?Adf?b@n$jpow7s)* zI`|XVGJeA6kFEm7mMx5evCyuwmhQIHD5Eio+Rba;`Q(q^MIsuPwj8TCxTZBsyaN(h zb8sql*>>e3(O1T}6}&$_u8Y_;MjVTaAG3S(aR+`@4~=!%by+5mkJzISNHq>S5X8<& z2$j%?I6lrTq=Uq`Ob0pjn#1rBER4(mbXXFi-r&0nLzllna$`R|^AomP4qy8i!KruH z05HJ@cJ+2x1`9tu%Z-J68@fztmAG`fm5VE!|0W2Kr+PDs&35xO{6Cr1Y7Jd*u%@gL)Cgp0g6S-XOL%11D&^h)E6Wf|%Y6ZPMv-BxaL6_f ztS)F`l#Xcz9LPQtH4k&p>u<3b?O2<+Ao<>EDu5N8^LTmV3D0B5h2v`k4WM35H} zRS=6{!yBi|N2oC87FJ>X$AYWJS4b%;3r-VM<=LPlU?ib(OR7A=WU)^X2In!bAw!tE^La+IPUb??}!|+GZZjC$U zf{*Q3LHcY?8lWuR;)X?S7=?2@=>$TQ0R!xNs2%aj@?EQy3gMS9aet; zVTuFui{U^MmEqxDEgvi`RR??sxQGYY?);J;bf+r8L~z0~)n0pBR_156R?m$;uA@u# zqW78&mhS3eRQ;{3U3(P+R4`i`F!6r+=QiryvmFOT0p84M6=gpD;)LoDLLp2g1C|kl zeeuwRsfzisWbx`u&LdB?tgfZkoQM7nQuApVk^)B|XTj-%>4;)-j`ey0kLzD3D6U;6Z-PBO%O&3U zL~|Lk@KW;{&3&dgSC;i`zpJIXxjC-HboLvvegJ-`tR+zVA&t7{owwXnom_0^ZP>YV z4Je}cIGcY#JU=OZj_3)`dcqZK@krTsPxy=Q3Q;P3xL~z$0O{R(DCX_g$M!ntK@CRB zCDX%4I+A*QKs@Q5dXeXPlL$zy+noIR?H(wv{A*J=I`(m{kkZ1>P zoMHu()p}QbjCS?P(3i4Xb;yV8GcYrI) zB_c)Pz|k6I>A=h&4=X8tmzZfYco=YsfZ*kL9I{a0SN)AnYeE-Nh|v&?Q&&|oCsNws zwi}Cte!2R&y5z;;Pjag$a6X?M+?iEFCvOR}UN>_n;G;y$@8U-R z^bycAP%2>5KP=p5dYjg%hF3pNwyiyaE>JfD28a|<-FZ>iT#$#-nwCTanr#@9H7lia zqBwAq=w1Od2h@g&9oIF{DkqA-6|=;c9x6x#Tct%p0VbSU6mETtpSiOwbX0aIB;4rc z?PhV&+q={@Zf8gKth>eBO8ZaFni(=(5*F-?_j*RN3QbOf=&*md!qpOCM(0V_<4H7~kuQ&so0ajxpot z60t7uP5Mk}8vb6_LXZXd$`j)vbnl^4c_c$m|0g zA`_;UYP+?D+lhdhS(>*=`as5Q17YYYzOBzH@Pm{%(2xk-<&}iq&RJ-H4EIw*n|b}L zN#!&96xvti;pF$^U9EHE%%Qlm0&05@V&f$@x-hF$X4OnZd+)8rKd}l zIAE_DB4I?@%lY%=Gptf^t%panxa+cH!4?G_iMwrGXyA9jzYl?qTcj~ch>WLZ)GgUI zDui|B~uA%L}oOcmM72-F7qZ`cYv z@Q6?7SEx^7h#viS5+WjiBXA2^?Su9+^I{{*P*l>qd7wl?Gwqw%QsC6)w|X}O2~O4K z?Y#3^;U2#vsU3LDLg@hSvYh)4v0c8^MFy}e^dQAgTW zAGf2%&gYdbrkPod*?3vN>f3tWroL^Zv3h|-50JbSsB8jZUCy0eY;rlxiN^DgiFx@@5AzxJ!W;K2o5ARTR>igS=6 zYJfuj5cA}FY+&qi5D#pBXN}C@sDWnAyhyn|7_mMu(D0#uP8KQE*JqIScDHu$$LVgg z-%Mad=UlUMl929;P^p4t99}RUs^=n(M4s#1>m2KkzHzKKqr7~?j}a+cZT*o)nq0|p zP{XzQ_E*Q0oP^32*gq6iD^ z%;p2ZbEOPut_;bhdOKPp4kT1KYSDcw#dy^Svh|o*Kj;56Gy1td=voAH~dLuDf5ou!0 z!}Pk$kQ{mRLB;iJmS3$rfchcuAJF}da3~52!$J*euDAA<1iAE0y7y3$FJzW?vx=ll zt18pEH8U)k1xs?oV5(mD>9`LPt@M(D@6{Lf)Z8oW$!|IOdr9(_;@Y>db!>0M=@;?K zcah|-=#!>Cn#$Ur41O$eNXJM+z0P7^CU0Svr9yZTwNL&|PF9N6>G!&Bek;+gZne?< zQn7ETCTY1*-HQ!wAf{ct3XGrUp`igl%X}uo*Qz2tUs_T1Qi*5tG0lpU?_M!@IS&Pa zO{~eA_kwc|dQC>E9>bpZcw7->BD;(*s)3hv>n&C97|%E5w2;#pQyS7&A5! z#$UWbxH90)FzmcWvI;tmn!LV&+!QGCcn;-ZYD>Rv9j?amnH3CGH zZ{mqcVo|L=%U}J0^TFoc!@PPoN{h*4%VfqY<`}8xs=;!<>S_9!I9k|AY6wlF)ki<< zb4^R*Y}=k}4H}H4DFE6$Y+G zMy@F^w+o`__)(5%AfBpXbI3?%wDE5-s}Gl78S6h>#@)r=8YwT%A;D9- zf_HzL4B~~IM4lVKNSb>rpD-e6qwP`bQI9ON#H%PG7lHfD#1qQzUf6D~|S)VQA)`;I*{2 z?amWNy(b5vS1--(-DcCbA^1qD-wBUmrGm;>}+gQq1#l>9o6tsB)9$D<~S>D`x_fHtynla8<3(n zx0j2}9eC4qChbf7Prfu-;V=akF9kILY3WP`eS$C5Ia^37uGmKAv&1QIWWg`1$)eE)~p@5*#&%2tkHh4%)?0M%FsvWMa` zE8VImVJzxjVTC@%8#W1qM5Qlbdq#f7CRJf+#6ovL&NZQ!%k8TwQ@c1d!;9DH#`t1D zGh=P@nb7L2K6BcjCXUjLTD~~jJ*#OFU!Y=KT>`4bt#zA?vh8Y|jGyF}%R!Eo}`Cs~FIisLGy2 z^t}j@PZGWO;nKR(*W=G#>(5wk>w-2#U_9U}<->U_C;q}cS0d^*&&G%VdxWyEboZ+N zPh<&k{{0HSPKrA>g@eJ!`NC=+NII; zMe3K^M^MtnmYG1;6wlF0#GLn%sv0TrU~8{IcmZAQ9Z%pKXR(YNfDNk^2jM2|M}8;% zXZSeUn;eab-U<88-vpH98ppnOY5v-3qvhdy|FmXb8EWRHC94+!lTZgNWJT3IEetV0 zk(%Vay}EyCPSNvZWlEEOLWYwxiihz*BcL)N<)ybxxRbRi_tt;VP>acZxNukOK` z-Xz4nD=1bf{wNyb@J_tINj=6tN&%Dvh#++Fr6Y58BTt%`NXkM443)dszVlvCef>vJ zZ(+SpZN(FLzMTw`!SWqx2V-sumu7HwpZ+lRV3Nc^+wA5#wpNEPcav_XRelR7rstr} zk7JAa3x{x>@d+yIS@fvzjfEb-jDx?b!6}G(&w1L!5$F@W|HdEND}g(4#C4}UJG)$m zwr}yh=`n!0fP5C77!0lGw7-^;z<$zbxy4r1z!(r_D|)-HCu84g=Eju1LU#&AAT)&D z7XhvaSg1+#V7d#Pc&!`5`KK91t_r6!%9jregiwQPYYLu$S!4r=vGT{|vk_fbEj8lx zxoT;a!($vV-q`+*pi?)uB~*S{r@`AGiC088(U%yUW{xN}=bu1-F>somXgf;ZrrSsF z-S*oKJOYVINQ_h0zB^^Bky{bjd*ALnarOYvhn141hB@9HRe=YA>hN~iLc_P?<72iH z3w<#wV>bBW`8Mlke5nJR)8qX#w|&)cFeDnIAA#C%x2{{evm=7C-SGHP{Em)3{;UI(wAZ#hoR+@? z5xABTOs=J0Yywz^YzrRSs-^mPXiF8)B6xjYQ$SUtw4knX^ShfO_6vPq>UX}s)tj{u1ojJtL1xzi`Q^ql zd*KN!_Jg_WGwqMN`!p4MUEwTkt?^$-qrrXAYWgMdQ zR>$*pr)})gz^z*qpWp)PDv>GHYTt_!A-&eKw-lo?6H{8V5tamD~U@$<{P^ac+ zESa5R9pMB73>;^>vo3u<`(eUH^;UTnA4HFh#ObJmZrSm)Ze?7~a!lc&2N--0|c3nZ#Wkf3m39+@v|^q~mha zi7>eK$SJOs9jC`4JQw?%GrGv!yGxb4_U>Qpux4K4o28ht3;43*oRx}GAJ!C{;{JOG)i`}xKxh^fy# z!!md8uiN_jSHt1@Pa0syb$6*t%nsKU@9)9P;19>$jgW0{hit{TMZ+Lf&sz1{8BX4{f(Z)X=DH*H0fx9fho~t?CzApto9DAir$M{3=p`UI?PUbWn1ykNCI9Ckio}H!)mGptS!2j8 zdJdF}-wYYpO|@LB8uiUrgjX`j@Z$@A^Hk`lGT5ke(f2Bb+`fY^k_yUok}?vaDoUpK zK;r>7q}9v6)@`6vG1HAt@{HPUsB<5JKplyuaAQ?CShf1vFo2~3W?V|W`Vp-mbO_W; zS&z&2o!y5P@dg1Lj9*CaYhp)|N|W1($*>kRqw2*GDayza3M!r( zV{4`?&RbM1Wi$MHC3YL>v?4b-o}4&oxRED#i0|PobkS)owa`Dw`SKS3A&YI{CtHS5 zuv%^JsNcnLtp%eEGOI+7z&q zADY%V)-XVdX~IOs98y@4a6)$%3sXBW7`IQ?IP-WSJSD?KlI@Xxz>~?xX=#hsO;tD4 zjP=)bq{py~==T?bCl>2MZj{;z1V#~<3jT3&h@Yb>R7XA_EOmkQl!dUFYQetG4TKN~ z)NwC}!zoVH7K>7Z$$?OA!A6zCvsH5mZhlMWGbG99+(E}SlTP0FfggH0i2rc#y~!au z7)e-Z%2J;~5#7b5S)HUSooe<>u`n|7nv&TM@*xrJ;joN2T_Mcm`a$+29c&FFeceY; z0KrLzU;HlDu8nxs@Ou|DojFDjKVMZjo~CCj+Tn>fzQ?3rMg06dd=r+8B28}gC zIxaFu>QrrC)Z{XT&wcPf7Ml}$KW;l1{f)V#2NelL>n_HGgto`(&>vA9z=t#<`TafX zOWlN#eg8QWi#a`}qGPQ&H9>QIj`6!}Je#1Urn+&MxVJU%)a&6J=cJ?ScJ@645RV># zR{eTPTnRyZ{+!uQv9ezo4}z^4>@vD`&^(3mRxb{OWUGsE?%WS$Lr0$QO2kt2#QWCH zq4;dweyiYR_$dvfF<%nd49F5h%l9TFYWL23ko-kkviX6iJmN)<-+$GEXXTb5$7Rf5 zlI;AaHOjW9taekLQ|$she@3K^lo48@?DU zf@r37fiKz5Fu!hib%ayrR+0RDu2K@c((k5P-onAucx>~2Rk(B@rCpDrYec?W>76ct ztzX*xUMTRbbZh~|Qnrzlz&JeYpwm5aw2*5ARj;9)VXg|}@L!HW#eECbKWK>fx5C=ZMIOCb(`RxMM~NUT?5{ukf3PseaAVrAKx z^WSa6uG(z*Rw&}aU9hQSnW1zZy3R)z!vSweTsYij;dAQWrW@jND)_8*bfg~p+A7QP zbFGuWC5nEhCt;DBe3gEHocBIOpssT2cKhk#aGFQ*=?AWDpSQJ>j~oolWgup`d0!jQ zZkC5db7T|yThGw?))RDyI)|2ZQeVQ~rI7+JQW>mVJRs$rD5d=L8R?WOr(C6BXNV<~ z93@1Z&<&@hkvfgNV=^^m()FH8An@=Df5EI%zJqgr66NFzw?>)yr?SVT9Bou7Pe68b z)K2D;&Dq>15;*%*U{C;!v6VAyFmaQjY<5=u^{CeV1?^)0SR@Y@IK+A6s>_zB z$R-8Ib++mZQus|cz}fGENdA-Mz%{$T_ve9A0s&I4V-l&TF{GXFOU)GJv*Wv~ZLaAQmT^grN!6}FfsU$*A zeHTee1VE=AePk6Z9GsloQD+nuc98vSbg=LR)?-a>ss9n)<==}*Q2A%fBmM#o!P_Ct z%ZGF2>+_88VXFAo|4jIU|0lOyrEh;eqyBj5(0BudqqZNrq5~|tPZVCG)3!+aW!f~%H=U5@vc@MmnOF--GMulEx4 zY2*=XofNujekyYJ-}D$JSz1O37JZ{M$Id$*AG;=W3Pc|hpzuXxhRXxBolV6yr_Fn2 zc^P^XoZ{F#VU!fhNR0cFmm7F0C?w=of`HxbVd2;2=kFILeGoQ6*<=N|uYS6k7CRM( zNO2y47L#7of$Thdx8vqA_*5rO--l#1KkOhG{F`MqrzxgF4_z*2G>NW(*+7t1eA(ni z#hCWAgI#$v#TN|;K~{I#($Hvxm(*{E{(KA?rl7B;Ml=6tksbRBA`TB2ri zB_9b)tOuzC*bw((1l0qJ+S@n*$|Bo*`1|%tt$O^|$51(IEe}(HCjD+s(`_`o;QN`44 z`To$6^x1SgRz;4vYwy^t%lLX8%gf2k(o&fY1KLyD@m{>^4S^7jhQzY2s4){GKbV_W z*dkHAsj1IYD|Q!lXkKsB03dyS^&TE50CjS0>dLmg@83{gPM71iog(KzO5TLDFRPgi z4@Xp`pr@nM z>wj+ad;{H9#@I+SloOgdD3JKrW10?Jg;cb{8Q3KCk(jY==j@-eULkGS2Km0bE(5OR z(xw^#>H<8=iah6MpY~cfBaAhh2LiWPBHafKo3qU{ygs=8IFny7adA%D-eb!QPPURrI z-#^7yQLMUMy>d$oNIegeFNx+`+uE*$0Fe!RaV*BT1bGH^3!QLal>dA~(@k~7(mG(M z38TEJfdGhG&o_txtx^J`vK@~xAQeF2Fc;x~1b{I_{+=T`^7k1adHkBWBm^i4FI5(X_{3m0;O_(m%&5g@6S3sA%~bMqsA6BjbpJyHwVx?kkSrDmkSUYh5>@_`zX-IeS z2KBPv#*pY#<__Wbx-0D;3EPnB#oOj0w@qg^;_aG!dAsROY2kjI z*8X5UJ^Q=R>P5R`fR+%r1UKWd!5iztbWz!dB7!jP$^{2%R(kV;^!upWC|3w)S(TWv}rL!-=RuxLtHzPf~^DcD4Mp0@jJLA3@H5`_3n#%dP zLW-hF-nJnUazfd-x!KrkAT?4^tkf?fL2&2uS5@IMIBhxEA}#ON35Q2JweeO+)$tC( z-q1|MKKedO87&!e>D=Qisf+0?`w!rxYn@3_?*`P#8!RI4(;4YIhyXLb${Dtih8v=2 zYJ8zc-V2gWcJ-mRz!1w#I-F+m#2?-yb%`w0x{c+g;zy{?H#An$q;`#;dVT%zjY8OmR#^&d=>lXgr1C3k_44;W3WPK6nipyNB zEuyRQ3qpl{`aAsQ+Nl@Wo%gxis0NuCpbZ7=YCCTAtNOnsesbo8t+CX~2w4E`IA;v9r{YHn z3?+ZazM`KaWdFMFVSafDu%K+fkL4++s_&bJhM9NM^ev{%p_UDu%_Uwk92Gv-2w(nd zO*#!;Vb^KoPBmzcuz@!lolj;kWPIKR~5=XmELnYY)*%$ZgO=!pLIa6jym| z{=4TFcVRzvW*w4*p2TlRpf;sEGWqVN{XtQmd=im{Pj%CdrkCVX8lO|rb_a!loU#>mFBvWxC#Sli`oIEVbYF@a!?z|BK+0sfyRZoT^M2c=!sqs=&aac&A|;pO5f6L76OOPfE(}PQqVRM=e94Had!Ar|dJV&y`#Qq*8Jgh_=%>E7Kfy}J5%!GW+=43lSMMpEVm|cmMN-xn` zIw2E5z^KvZ@*K$G=A@Zd#er&f3b-2BI#3P)&VIB(_YXlQ=78rv4#edfxxx!~ zTPLJ71I^E-9a`PrgtL8<-yovZJTTgcFjrd2SM!J^GfBKS4|%%y6DzCDP`NK5U_cn2 z4Ss$BnHj~$=(so%$(dLuZKes9`m&5Ze_2ezqEGa2_*6vJKDwpFu8TDI2 z1}*okCFZ-0lgVSfV`z*E`6qndbMR@)Vs|Dw?Ey*@P;F{FUnb~)+~Q(Pi6w`B;#rb}7h|CL&>s`=hz&uAcPHFmu{3IKovZ zG-VOmU8j3P3%^RA^4jr0#4?>Jt8>Wlg~|g(e5@?7ph^zs^rXr+d$`)`M7EHCPS1dA z7xUv%y7%w)&CZAD#EV}3zYs3JE>N=lrHGqVWQx-fH zEr17RZal~|ksH34za)abTFq;K;*zk2rB!FZF1gKZl7~r`e;eP-`%YA&+JP(q8h{5b zf>#AaLQt&9e55y_uqx55NnAuRqz^g2 z@G5j}4!hrnCl-{~+xL>uls`Vb0fr3x!EV>ywJ)Zbq+P8PCBsA{jSoOqmtS9J_>_Hx zKy}yCQO;l|rS zL}KSil2;D0M&sF_<{essGp$J6;2z_R7huq$b6uZBgK<3k){Wj>=cfBJ&hv7ZS_LTe z)%13z@#zbe5J(VK3$*b39lhA8a96Tv78WqQCuRkU0s&K)XF5#!4%qy6wAy)Uc>>$e z!m;;{&N1}Bf-;~`C`-RMpf%y%mba_oDDKQwi=kAqYDgbnf?*9aXe-NTM=Gp$(ugcV zDUzk$DkzkjP2+`{BrgmL{&?8!RAB2(z7Rs>9_0tyB8;Mp63N|9$7bY{Zw?`omq5z3 zX9B3Pj&ysb$Fb}5;C8dMsEYT?E>pwQ%y{*2JUjQ%{WBe~6`nJM8U>=cA;ui@OU_gy zO9xC8h-I1IC{GoMTvttTNWvAv{~SM(XzzN}F0|{N1&LlkUOl7ECd2=L0awA`rpB7? zYvN1X|7<2Y$L$csvjYrPF77x)v)p#O+gX7H*SB-3D<9we3}AQk-$PBHJRL z1hqq5)qV)C)Nc7HJU4B~?8^p{sa=guO{eo0*wR zfEK&A2TQ1(BkZG2ksH3fufTsVIH|^qUSqk+NwQo$2AA-H&zeXcy5o}D1&j)HCLlw= za@M4hef6X6D5Y1el-d`|C#cX-g9cKYESPAP#`4t57totG0gsjDrFt#Uv)dV7Fzzeg zR$RdMe;%-_n~)q>3mJu>iIP)8b#1!EUdDDt?`*_Oy_Q(%?u*e%onXjNfxq77%LOm7 zOGh&xBY_Y}Ja*ObFKe&NCPV-UZq26VPN`KU{r$UnJFG71-cc3U>~U-n?2YW=$IBQ2 z`(U-2gJhmnJR|gNyf&`#I|y{E;YtQ%g6w3_lu6iezIzz9%))a!2cj2y^GF=^rL92yzd znp8aq?ul35B~~8edk;~_@GCVsiUlkNkk9uULP6xKKFntWXYbHSIP6-lq`%ajn0>C{#}HLTw6HVKO6jYt_+?aQxv$UF!dnHg{d!+kr$$@6zDZ}{#uT%;1 z9B$9vjlLC@EAa#S?vbnVc_#U!?&T`K&HEzyZR4F5Dg-}a7jBvIFWZ#LN)D&%A2`cq%{|4l}Gfi5N%*fMgOCEGmqS3 zD>&*w5}vslA^j6W*caH1FR@Y}%7MR6r2+C% z|JtP6>7P&S(7Ei?Ru#5TA`KGl?udFo_~Md1$!-_OD(Qv1CK;`K`toOzi2Cgzx=fqh zA`}rBrjm-wi_@X=<9ce$(UPDNo&%<#O60!C+{d---NY5LU$j!dx8F`d>r>j^$MSh! zXoO#V#<^d6HaugY_vD15Ul_5V8zxZFI)BPBW$Kw<6A(1UfK&zvKuWVva?$qh!hmAj z$kQgg_hwy}YH**+=Rd6-nnLqe=zB%f6j<&bE;&mi`T}=DT+kZZ;XV8SXf1^|&~S$| zc4#4>XEfc#X}o;f2~1S-i)m(%oI27W`_WwD+}>BB$IUiqH!gLNs}k7?VFv9v=PwTm zj(=bsX|ccnZA$3YMZl*4K{H3dR=(XE@0jSfaMp3h>ZY zymc|gEvi;4yeDK@8Fm!|j(McdU0(xXfHMRzP1AudJY#AVZz$>pXa2k@2AM9<Fw=XRaVSHTXB!&}O0Rzly6hPD}(M~%C6h`#ak}63`M@c;bF>t6`&D#O^#_F+~#w@-#7v{83CVOGxO{NAg zqBWc7;p8mrhI;|Oj`FqTFnseBpqxiZ?}+A%kzQyVXez;Qc3V9FAa!*_$NQM4h3aVo ziY3K6F%Sw!L8;Huz0dpXDB-fuM}BDe+yKz#p(&z)88Yydk+3*@&PC79Fb>8UQ(|OT zFtZMLEp>_$y(u3SZKaZtAG`_@{8TPZG>PIUE0`2@c#E;pm9^=NH{P(IW_Y~5|ndh^H%(>YN z$fe|2zwvwwt+k0RLHT1*<&if5e{0EsdqXIccB?So8X#l>TpG|r+tQbtWhxzyu?;HF zZJC`<0&n8{Ge*lSrS-Rm&Ppw@jemKVYYAC-m}rR(d>C$_N@TV3j%eYs-kgM4Ro&Dh zyhyI~N>;J&0>jVru`{wkaO~>zJ4*40hi+MUl{mkdUe#wXp2>*#vX~vF46fwGe9n24 zab@3+`A7Bgh?&Hp8+-lqz^D6%^YJZJvr8|2gmIe|e6T7rRCQ>W`Qfsd2!=p6seUwGIKp9eXnCp)f3J-25+zgbR&W!jfkMo}UG z(rMK)xA$GzdG&Jf0SGY!>-!HuB4BzzWB0>Nl?7N++-H zKmK=B<3`SHJUs&cl3Ub(SRqudWZlHo-EYC9UB%Wpc<$uUYf1e1WHz)J-Z_PrfMj_q*nLVk;ne(=X`#nmQ?7Q z-@>T-8U32~_#6;cF|uFJJf4(s1G`RacL?*!9RC4UFg^=hYSXibMzD{dFM<6?cji#o z!o$a^tFC(I)d$1JPXH0(c?`&XKa65N2 z;GtcQ>h3*;=pB!6uH$ytybSTk*~R7&nDz27bfH3r!a#7jhN|RJ4Oq;;y>kIC^O?V> z_bjCtOUY+rF5h;3ZRQ}Lmh_&G{Q58{J5sC0YKuQ;e77YfvVzkwY&p+Ol4o#vH;cmf znhItcbORJ7vY2pSDW<4%MP@zL){wD9+B`*I!CJ_1w&=wKjg8hT#Gy~%7^rg183t>O z=ELbNS!uE6bS@a-*!s!@juB$F#P&Ow#~%H+)MRC*c=&NOI<@&?Hgd<3^7ic=W}x-w z=PKB%9k{XtXXz4Od;MX0-2+LaMto&hF_hqtw|Sc};*JYV_aO?1pZ)DGzMXG%v?24} zaeEW^!n(qu{gXCvhwEuAI)d--7EnK^^8&jlJ1cS>rbRl;`(HlvBgaChB=;TfxID|B$k0%B-v!1*c!S#7914%K}No31ECyN%keYM42rJASjS zF#KQfD1M$FM{a3qd;w)0d~KTAGd*#*FxPT(R|TacMV@`MyaN-h3X!H354+*9wKUa9 zS}wpWitJDU`aXQiE-6j!|h%#kvdMsMIgMUH>WWeEQ#m_pnH}_5CkK2iNzx1OjBv!6z~C;>_cC0;xy6cK^eV&xj>{s; z16Sz$@-4}8z_->k-tC-F?YRi;{1Bqbn+NUj&IWWD7wIpM&r3R6Ne%r%1q+)889-GL z1F|jkRj@MdCf6xk1~9jrWM(L%DK@Zw_!2QW;3Rsd@hARShY@^8op5Pw-byy`&bND+pKSFtm zOn3@DSl1Hu^Es#W`yF|Ut4S6m1$|eIr24g&%P&^Gq>>$fNj}R_1%jO7h`{@r-xER2 zaU#;)%VMA|o9->cGB|`R2~v&=#IKs)v1PF^?-vI-xwU$OR~!$l2BlIf1}UDBM3Dh~ z=*j`PyU5P|Je77&wZ_OKDkRKmnW6A7o82F zbU$HKZQ*halnz{aKZ(xGhG8`aak*L7{R0ms(wa1#{q3>id6eW9&&pNO-@2H{)an`g zd)4}viv7L(rCwy5a-)1}hbO0ax%MmhyL1nPt^AiA!R1CGNpk=+B(&u52Vb_>xDHYp zukvhPLjH>6rM9${ejy_}@KBzNrrDnEbBvzJ-%;bP@!B4KY}e%eqh4~!^rSayq7dDT zKl{y#f^D=_{gQv?$7wmz3Rq(6ck*R&^9uogOxrJHN9a-+IEH}Eo3DTC=CjX*$bo@3 z8~3p_9?3j70WdwzoHO7n{(+&?)icueYo_F;#LJ#Q0a67hS>!yADPP>z^Y1mqrxe~b z1hE@eCK*^A{ZX}9Y3du7Fj6rrfn%$4sESwA?6)6(`Hk zi<4HgtgD+>Mlg({8AkvB1XzP%000pG4QTT+fdiRlc?3kod7?f+q~SmiX6DA`f75N( o-IM%8o*ehr=#Iq=Q0BvwUBdJ3D#O0Nrc=1OUYV00000000000000000000 z0000#Mn+Uk92y=5U;u?e5eN!~<79=jS^+i!Bm600*lcKX+wfW(HdY zfN_R#dm&NLolxqx_tG1O83no>L_x*xw{C^(d@;VG{rRcc|NsBLAX$vz?hm|2KvZ=) zOIuYlvYz^cEXd)e6i3QlvtuZ5)HY)BifjsIEo;AS{=hCrH3#ONR4X&pisNaE6`o9R zCg{jzY$xUj)qIF1h0WrhL?M}8W@&a!Gh9f-773A;`E>=NG$e zQTTn4msXK)xyWnukjC7{D2KVM!UQovQoLP36Ms;#ZSl^uAEd?X=VDINb45_R3pZqZ zIDSR`c&6ED?Z#`2le(q2iuYd=Deu&3#!ySRI&|~R$j+|tJ$mAaCVzKi3FX+15)CaK z?^A^5Yb|>{jf(*U2|VQkK$fsP2p<{aQXcs3gg)c<56{o7w;~tKHezFpF`~wZ++PsA zQ6Zy3Qd-?4S|ue6Kn!eDRIr#CC}$KHb!MG6|39a_XFm_-F+9N)48sVKRv;92e@dZq z3YA@yv1(m6ZfXYr57K@4GMS(GyWsVkN_>l!YT+WE#05TdA*wOmxw#-Y7h}V%1=M-B z1r&~@FDu>7ms9_LB*#grv5IN>kYK=2N({OLNe$YJ?$SDcr;!Xv(Mb$RN&zgv<=hSw zHtpvfQMYB4sWI4hAGuziRDN$t2H7T-1ref;Esy{I{hwOWEKA8^>;Pf`_)03Lsb>q6 z0y+9I{Q1R0fJu?Vg4o$J6Kb+ZsU7SInvjTJgRHY6l9FePiTiL0BXY(a2@WXNhh_td$RP;vh>mu z*hwnjT2OSUf`g%Rfx!dOs^V{1!}D|N0V8@;kI|#X0tOrGuL4$#1*~9WW7J?oZ-9t^ z5+;ZzQ&c=LP{G2$x-{xey-+SH8Qf;b9WfnZdO~`~!^_ui2Y`6_R@(ma&*`hS-i)+( zca>ilGaBKoOl@>rg9tImoI0frXaIPxqa~6AxSv~?DqAncbiVO$ug*S=6lXUx zl9MCg>dNcLvI9%-krFqfR&xvxIH(AU>c4funC_(m^LQ=&Zfi;vRp|(ddV!I!nB?F0 zof@J6XslaoY%~_^QyaC`Me)zcRtJYSu-)E~h=34a00$$t^KYtU3y{Q#m$KF&>q2)f zx?MS?_T1&7pC4wx|NnddGXs#E8Gs}JQX&9K;tU9h0Lk3}21%|yX*X}s9cpUUD~Bxw6*`%>`@byFs}U)yRIPFsr*bG`L`T?WetqF{K(Ig(TPtf-PXpyZL|S{QN}g>q$2cUuk9$ zMuapT8EZ30AxP^G`6y&NV$KQ*nsok5LOg?t9i-Sn>bBY4fqNYz zQ=n@|#Joqj(KX1nx=r-b1O>z)vB4z-vi^ zQhnAu^R0O0=d&W&Dxdc(f_$*Yv#Agn(E0&x5h5fQ6rxW>FX z)O-g)e<4;w#t47|5R_&tBWz@s#AA`#O((TbFqnhrS!$Rht(6d^J~~Ix~WyEyba@TfgA#-$bRZ9rYaa zZpQb7i{kWut)CQcn3+G9GxphJ{|iR<>o-3ct})Uhn_8~!Ppv_O0%bI0xC>I4w5-zO zu_LZCX}TfZ#K?cWv=R(2j1r7t38TalXOSGSvEy9Qa+!IR5g0F(iiTAzT4jkN!ATyh zdXZcu7Z#@2gzHxk7Rx{}NHbm{GW20br{)`XBkoTayP6pU%fZDEJ77TAj-;*USj}G! zDnaLAQdRJvX=X!aa6*^?9%IULU8{3~cs&!t(#=2iWj$W2V(Kid=4~*-?F)$x?6Zt?#L3xW;Uy>L9<`j1#9Vsg zSpQ+EdBNh`@PGJyf~UIKb2;x(_j=JWq_QU!!@x6)wv|tXe;^$R4`yLhn2V%mn5~xYV-86RT_{^9xL)C)pZ(k_HmcQ!Ud!VL}*IY6`w)Vo6>g%u10iI#U3Q(~x z3>NDY?|i*Kc`Cox>`OuIq1-ouJRbzI7bn0UL4+{1_s6;Gf1Fq0BRuusQ z-{-N&1yZRGevvn@L=9I=`7#OBZmYV=p|r12VuVKp%5WNdb?cj(5BPLQRLbjf&C-_! zfF6|%Hqn#-Z_T2z&7v}E1-G4+I$)EwJfEZn@BIyz0&NrM^idp6n$=%;YfnieW;TS8 z$y)RsG+SS#WbcW2GPiN4vj4)w{+rB7kvO^84V7;eoZ*qJ;0oV{xEuTfL*mg`-Fd%G zh;%990Q07^h&{Z9`vb6MOy3g9F1W%P$ihjf<4s@Xr=8XzLOEZs*oR%V{nnY-GoPGxHxbui*F~%WR3Fx4mUFByJ!Ezq72Rc=SU){(smx4&mn(*ejEX$ z%{U@$l2|11aR{4g=wt>xrK#4nmgNx<>mnCgnkaKa(YADKekz2)NEdBd$6csGT14Q8 z^`xn77TYRGwuqFbK95+*1YYQ=+Qc)t{B8=N`MjT~-01T1x;teM`MphO$^}H$5@8L1 zha*VxZt$nG{cQk2ApW}PlUW7!~&OV2^P;xcw zd5s%lo{IQgY3rv08Rla2?xm0b=G1ZvMoyG04Q;5bO2x3!+lv>-sz$4}`@+Bf?sa z`C|q>2AeDd$roR*51!jr3_~N z0`!Lco1wLu1getp<<6^}xTed@^|LF9T)Z`8FjwnZWq1>Kd@G&Wwj*I#2nA!+N7ZIk zq#?ANj>lZqoJ(bK2XM8o4f=(RA`~KA9bfS?&t(^^UN< zn1f)zc>?&W=YdE&3-WNc5z5HpEP$18NTrH>t|RUpz3G{1I-^QKEhkvJoQJ$3dYNBO zQ;wO%+k2B|IM|Qs@t*zu?FM{ zP&$dBc?`8ZHd5%i?X>4@$ro7=g8kr1E#&;cD(HlDIi8M@%e#umoB&`3Um7wvZjls# z)Bf{~`UA>=_vz{$VyDJ?^q8zK`TBbD3y<{sI$yb`UH2MUi1?^;0&q}3XId{a?h$|^BLX8xS z)M6eoM5{+-uWipjqn{0g@Z?8^oOT{ci9jePbqCFSdBQ{|PeFPE>&EF#l8FR+oZq2CI&x(GJtdV^T89-tlsuQ zcim}R%}mi$N+6sVOvnWu;Rh^DNfi(z@XhH#HpoVHeKq|0gh$(VmJ@l!Jii@#3;Slj zl-}M9`UD%>8ylUi4c=_yq2_fu`B#(ooE?Dl1?7R?^lh@Qx4bCZ3U%4^*gkKkijWBV zf`y8UNLH+4JS2$WA@l}RtBm%xug(qvXM{S;{+F-!rR9aJ4MKRYGl-(xO6s^uc z`(-k|i1oasBZI0Q$aXn=BcGzmh2)-rklvjZpQ1>uWpGSm{|;z}F;ps4&6}?j5FUje zAfPNu_Re7G*3H)#+@V;Bq*V}MuM!GIT0XV2XWrISl&xX`c!!d~lrJHnSew|Yo)*BT z^QgwSJ=*@`L8OYWT4pD;z_}I~Ctpz*EDO|^%-&#u#7S0`d!*;vHXis0wP;?3$jrWSHeY)tj7y2B-2h>F?A_z5 zciF}o@8;A*Uz&77uWQ~hEuhB4DS{m+QU-4?!V-2PiJflXU>&&)#OID&5Xhc-FJ^tV znILx~Y(<-M5#mE5@tH9$L+K2&o5oeGdq|GLqeLBO-&!SostVdXYchjYM#v#rZ(qbb7b0G& zFxmjwOC#PGhz#Wo+-~?-dpLPsb!%)#rm`i#NM2I6mM*}6ktz_BAvB|~TYUR{2An=` z3iL%b)YcaEKi(pB!T$b}g7_T-xFfFWnEC)}1hRnVB$0j&s>~$a0*)HSJWO%Johle)zi z*)x{0cm5?@Dw?#-(8GGtrx7Qx#^P}d_Bh-eoSz#9J)rfo8{q~0#dc@U5^EyN#G>E#W zEL-{i16l59%I+KhGH#o|>Eyr3#k%mPpmBQps|l(yZN{+$`LEH$-uzev!4p<$RvKoe zUvq$@fL5_GK>kqBG-Hn%rn+*Mx7ivryiyUH>ee6@4)e;pI8bSD*)w6a1wYr#Hws7?;rj4WKagTxywU+ZbT0MrPO!{a*in(GK)E&$JZp>< z2hS=#7<^OkF+KQ&#Umg^u3>~SD#jiW32T%HS8bViOqiTh9%(hAsiTKtw8gU#+Jn=t z>moLzuWJKa@Yi*)?6hVtOQP#(&P@K3&Y%&}xWW5&XC zXm;BzmH6unu{a|$v+^k)%Y!77Kp_**1UtO!8}!Yl&?9*Io8G<3`KOCzs{Z{aQhEs5(+mAOXt0_>Eh zXqlciCX<-XDjqEA(q88c4U zj)d?1muWF%%KVs36`HcJ>kn1dMt&(G&X0msMqAc`bWh-@_A z7EXlSZrCUiWe5w~)be$Dt?D|}HBT@TWn~Rot(ufkV5?4_&qT=O0y=G^^fREz|1fW5 z^zp2EqGoYgN@*vh~wB|1D`m7DIY#cfVX1pxXT#ctV8*VNo?c&M5~= zQ6?|Ht0FBw=!=(rBf|`lF^KbG)n^(UO5;ubO#36a#V>F3Kr%Jq=Ai2Faq^l zE>seE2r9l^RJzf?xFAnz*QxFa3LcZ%T7xWx$4Cj=J7nZNqGl$QVD7!SbF)*(D`)W@=PM-omz)a%^q8@k@m<91F3i(W%8lMLi84v!T? z#vnfGEntC@Ju1OebUdiAM$@Iz{QL7RT3n)wdTXTPDn-Q!@j*mIH%;gQ^H|9OSJOj} zAcm;`_#me7nQNphyCQYNV}srhAw_MEch``^spG|?L2PG!m*{y~StuCnJGdc9fvvA5 zD47cO#(dDhg+P#>%7F=BVpAwgusC^}wx=Q73r%2z3IrT%U0;~x*a{UmZkD6_V<9ap z3~%N*<1ADBVHqljO`ky*EK%- z+I%&@vRMF30wB1eCy+up68T452-0%&-X?FGd(_Z$gza8s=q(8R?yEc+mLr3K88IGj z)RFgYN-CGre3~?EV<9D6GI@kK@Aj$}Z78jA535LDD`@oe`F!Hu*nD#Jz*Vgan_Tpn zL?8XvU;&*w^tnr~^4d>2D|3nh4t0Y~S4^b;XavK<;G}u)SGByi^d?9g?N=A~nd?Uj1civ%c#?{2Q@{qkS zdKyC4D`se0n<=$UKd?@OGzr1NRA&#)4lu?vie zjCcC(L5JeJ`Prp;QplG7CQQc<)k+xm$0b!GHS8DA_UjiR!fDCw(kSgmd}DcC>&awsbdsv1QdMco4wwnYXlx&vGhgtcz{49va0 z=hP9yDH`*?xoqNiy}3=4m@jGmbQxN(_i!BHu#6l;u8B^JK6m|U#4sztM7*nWssd2o z>{(Rj9@nRLM4k%Wv-#Aa^QSmjz2}5MSK#g^{nyT0O3%uY&zH|{KSRvyF#CcTTZ^>G zZR%A=e2TVXf9x=So#Nd}Jq`ZIt?obm2vk-@SKOWzH#uaY@{ecSaz`{ER!)+tsmmRy z6^(JHW?~bE_Pl*wiem+ZsX;`2-@v!+WRipa+*RC6|o*F^4p;k}A4gObSDB9M{wf+oLuwWs}U zvflQogb7C0f1y1jA*uNdYoeT&mooJ7=b*cArS;Zf;D>D&%@1x4iCcOi?_;m1y(?nh zOVn~Dr_mdrSp>Wz3{3S@ecVw}V=?}qX6f%S!iVKg?G^w$P$2vCJ#Vq6#}-}}(Ww*+ zMEb;lYK2v4=!z6QTaz8NT`f4@F-3u`2ij7(V<922cUCY)ffRm|7>WVxbsYM4c+V>k zp8G9GO=l=pDnbu_a~sbKVEM4xc`PylB&-BoaAYze;CAeUXO)grC$cobVwB7t1q>X) z*Rc@|Mgs6mv}DjME6kzfUw~9E5thstFesxgC{9bjM0zp=J{%rQs`%yN1;>qbrTxjL zMumJy9qb=R!87GF^P~+rlu?yK4t=C42)HSA2u@K|+QCs*T1ca>9i^O_tENyScqjk@ z4v5>3LIy#*BGAWTfk4`3%63frH=H;Q z@PKfz&vPQB=f$U5Jt;vGtuR))92~H?#&yNfnOzczp)|2%%h~}u$q=+jPd4TZ_$Q6Z zRt{;}pvoH=)D)yFPu2H|Ky*DoX;$sClvY_7n1frSW~HNSW<#e0H73$)khVH0QPW1_ z+{XhRscQJXpkIT8rr2RR8n8A{Bn*&YjtlHdMl`@{XyLF-lY$w?!4>96YTEpj0S;Q! zqEem!v0MKCI9YMBV`RbuV7e$^*{^DAe4KIYfDMBLw(F&VyPOshCx&;4+~;OVk}gbM zCTjDEAER<%?sm;LgYb+zEn3~J?*r))#Jb+~+)@hwp+w~pmEjAGu zbwpq-p0v3`jl4sOLjEkc_*q2(R%G}g>iVek3814Fprn?Iy#XO^why_+sH2lHs@sX& zuv$Yl2w{vt7-wI>6}xq$_j#hjmQBI{av7Z}mLVgq{{f1bYzk2rI$4^2om$y45~<*T zxdJiq5Q7USaH;4j3M7#iA}Z0NOt>*K0UL}5?yhHYJC;6U#89i1Ef6W)c~OQ9O*39X zfpDTmsB)7^Xj>YMOvp_7nKt|+pA*fLnoT~=Mf|cIicE2`PD&RUSA-oKlu4@H+RiRN zTt=u_C9EG{Bkb6xed-o0z_>_W0NFmxHX(l6K}#g=#pQK5L`x|cAzU_v;%xddiV;1S zvv-Wya$;svOR3aN;61AF20RB*Y89o(RLA)Vk4Q(ji&ox(^2SF;x>Pb|OFl^}yn}0e zI4=DVT*`1Pj7o*Dh{(ax)r2|_@(f%J?b*gwJKFE#wf>^4x4`?>ZW_{t)p~VbAYWi1iQCf@TUQ@F z^TLL5+oi}2w;#5uJvHh-2myRmiN@=2YxgYkOpD#Xq7-%A3$Ig6bYYVem$@gz#!w0b+*u+`B8|C3lg)kLBB>a%jf5~UhebK zm4geH&8Zl&x5Vth!E*ZAGt37DAGcsr2^A^?1OgJnzZNu@;foe%;_vfQiEtmf`@cqO%^ol}# zhivKxy)Mnz`EiS}V=~a##apt`XK;SS>+n`Wx@mfDkQHh!;xpx?D`pe?7G4<`a5X)2gUry3e-2*uY|6_# zx+`9TT-z~18ue7$GaTAuFXc@x5liIh=l3X4mOuI8!kACxnyDBe zTylOltLSn&=6Y%5;0I1pih1tMw&bJWlX%35haB!3A$n4fG+FBL41CNER1C$Zh%e}dF%a3Z34C@^Ltq^VCva^C=YxBkN_sLd!{Dsql=0EXBmQst($WoIP;w)@KgL8l1 zaPNBe^+vRrjD|T*k0RH$d9^s;>odv(08;*(#X#Mqf2Pc3jxFWgE>u<6h_zQOp&7(s zZ(5FKVcH-@MqHEhx)kxOm0Lx~d??UR0S@Kr;8x*f2N6T1p{x1jP zF3tu2T><|aB>?`NQhCFg7`kM@wbbBXT0Ng7eKFCp)^jK*d91cxyWCy2Um#;E z>F@Ogb>>cT%?E1se^mo^{1^f?>aY$L=t+m6k@6^T9A~gnV{i`^fl%*_`vjCz5Xeei z6hRdjlG!KGlmMx$3{SN&J2dSv3(lwh&)afyS=)aYSqo4mT;phv4`eX2PBh@~t8=3; zP(KM`L=1>93KpRsc~tKELV2}Qx&?azE#gw?a%va5@UQyI0V`f4HOoNN@)xe_ptN?m zP>;J>`|ywc%_saR@WuT=z2cv_OUUIP?U4WHe?Rmu0YrNL3bE!1`Qv^45e&b<2lC_4 zp9z(;=z|Dit(NC?TAu$YdHzBcb^kwesAu}QzxG)eGY?AE^`h%6Ni8RCzl&yeIr?_sG%m6{x?2`XNy$6_U z9r~9EWBin;2x+xKLT#BsO~P9k=m^yeg#*#q;0Uab_;Rf*{T-=D84ov!K`^nu;U(Tc zRbHlxztRl0A>K40%^L-{9Fnirb?!2@ozl5#z3c^0PKjqERArQhjIbB-MxkkDx>{-# zw6U3UA3r=&{3i}n7=#wIfOU%f-m=%TXU~|GQBzA#HBRR(M`5}CxUn2d4TxxX@&a9G z1}imDq{dC|y}*4!&7wCqoctqzkw<6&SEW9=wdQqnkN0HqKUrSyA+I9i)`zRq{yr1A zAF*ek*I&vU!P;jg-Y0xZkeKz65=L$>`}it{ooud1=C1$o1q-sM(uCS4-uzhcV^C|v z#Ac{?*IJ*EXIeUj(FZWv^5yYP;>N>`;ZjE4DaI#FAX>qi`cwmW`Uu@;^a;0sL2!$F zad%ynyA%}{IhI$%xyvXu?ec#UhGjQOh`)v+&Ff3#1W>g=H!dLKQ#f6u+%wf@LgP=h zJfJa`T;(anuT0A9DEUgd|B{h3adN52tW3X>uOBF5TTP0M^x}w7n)PKy9_BO_2Man3 zejQr)z_A_4w&M1#sy0l}BAvuG-6bpyP166{xaYqq2pe(M9N$mUIwMWDsD@J%VwIwL zxld1#{SwX%m*7E zD}ebILdkkp&4dy_owNnc^ENKRNdBU3D{Q8UAU&{A4+PQi+&rNpXeOt3(5xS=>P^Fj zAKqub(MO?K;Oxw~lccDZDrLKtF~~~|DwTYdfOzo>j1WlEKok~8jupH}aD;sHMs{o< zYT=|b?1=?#Zi-Ea&nG^A5n^<~P%1@%BP(wNHwOEKH^?DTFZV2&A_3nAptYl?ABEur zCQnSj9)urFGM#-)+H>?{VY(lwg_@D0gr4vgl2ng8=GmQJJwSGq0+a(|yMg-#dZ>(% z(3u;w)msS{jk;tENcn@6=yR#=wqBMSvfRhO!%{OmVVEpjU!KuiSkyqH>LAkvE)1e4 zPd3@9oWw?vb~5*8R{2#x>S#_)MzFHfrK>im(Y?aj6GdFlC$w@KNhc) zu|H9svdtskl_(RVg7hArGN~p1zQ5qG^??b@%HI`jwAEW;=JPz0zPP%==|a(4u{&E= zJ?i;=_V1#^?$eU)Jg|c{znRq>V+6jUT1wtN< zKM<=`{x1Nrzvsb6;VJ>}?g?lWV_>q*3^AOK{`f>(>D{}EqUa`s#tfB zJ_yL^j}}z-)Wc!g`vK_sGjk|h!1&@I&gpeU&uh9s&ETI zU6phAq>9rW<#8b;7&GevdQtvE^-?iF&Hs8yYbGKnQ(* z)-RN}1tKzxuk@CN4v@myro0bU`%v6mA=K5X8%;yt@VGz;EKqJ`&{;bTCwKRaeWt_) zORwyHsT=($k>%Fv)VhS+{_Aia<6w@Z9oS2)6KmD#GHP{2f*BP^R34R5VZhI2l{$OObL@C?wA1C^C4mf3AZN+Pb5Ibw>wBZ5On6OhGW( zvQF+2bQv%Sn@^lwe;IP+&JhK06P6Akc)*!LjRs-XL@kpq1X-aGg!U`mp;-WF zGsa);St2LI^Lvlp&zN$YEEJDuH%t!0&`IC))}9#Zf{N~@WV&c{7Sg|aR+SrTuN;vjK5 zBsR#eu~y-;SU)evI~Lb)NR5&%S-!@k)bnT`QwDCSgn&ftw7JW^dF^j^ER0_%O3~|! zq_}z0dTYcsO+*>K#7ut$A~=6=_KPic(X8b`P(Kf z{;ox``YFR>O;dE*G#7H~ypwze*IU{IFlFUSldL2%vsxRrIB{v4Hx!mcyEZg*QN)=P z>(QX6WS^$(5U?)Y z5f|s2^gq=P`or(zo|KdSoH9xJ#Up7 z^+SU#Z6!*JTUrWvLJ+((mxJvfs9|U58d$b!&Mjn!1U+GN0b>e^1eH6qEdF3!*S@bk zYmCR_SbjV{m#H%32V;59*h=E@HF0y2PddC}tbzYYo?5Lnvo^O;(^lDANJ5!1)8LIj zPTy(MOKmtB3zTmLcGBU^4mcaZkE8Mu3r0k6{sNEv++aVBVVZiv24qA$0ZkEYU* z_$mszD5%T5>DGt+qSMa{yI&bEGN8{Z_-E0i7^ zW5gNS?z}KlfWNP7zqTX`I3ENR`b=&KJ&E+#AJ5f+ID%uT8s=ennJdAr0NSU^+javf=O>ytU-#8S^rrWAQboA;)3kwEb+@<(X zkld1-jqa~eT;>kFe*Np1h@9c#v3_F~lj-;*0Pv1j^n7U=YX#y5Ou^AbSmrCs=CbY! zON2KhNn|UOiuG7xHVb002w;7dDJf|)|5}g*b(Wo8qTa5{I(ODVIczqgi^0L9U@)7! z_?9gM2iwHGL|(ecw}3- zUX$k#AwHr8&x9us4im*RX_QK*9u6u4nYmDE$Z0+q}-yx+^FQB{x}O#$ICcmzjxDEUo(@_yUiKH?4k_ zCXYJ4-0790K;cWyk21HEe=W54nqFgaQOX@3aGfLw_kn?w$YV1VzCeqpSq<(OZL-Vf zT*pqchDlPErP>SJCpL`=?FODuh2qKxZ5dXNGNT}d$1_HR9`i7wbes@#Ab~rkQ2ztg&k?PfX87Pg9JMqbmK9;u;r@y-_(ZTu~SR`GP9No#M4aM4ys z-DdJF0PHm%^S+{}C{BZsh!nQRWZiK$l5wEwgOkS=W{KIvqci1P1W~s*bm{B6{JFT7 zMxfk_JQp2au?H7O9Ks^R8I}0jbm9@V$ezUn}hr zP$fl_Fc(6+4W-lSKsg5&?kio=^xRG*kJzY!aQ#ldCPO>?H;h{K#5Ik2+8`u2c%0Xy ztJz+d&K&u{Iwi#!d$Z}om12DxdorVJyHXH?sI9T-{<37U<;2hxt~?uam(aB7fzmd8 zF?+oU2*3S=WY>AKrHCsvs(ne&So$@w4)>;ZY(sL)M@D1cUDJ}%) z`f-&rZ(`_Lj840o_&9E5_rMLpR}QI(D8P2IE_H-mwG#2`1ApCkl3Y?rL_*4O9$l+V z2%S=3dgXRe^(7!^yNBIs-I!#;+t?8>dq`|)ha{ z5US{WeK0T0<`(0wv+QTYpxhF~gAE%-9WiF$txiW~)Fhg(WWTWlO6f-f%q#>s$|A$b zX-F&P&&3gFb_#ojJ++h;>p%wX>F(+k$2thX>VLa*6@z+hA0=%-(ArT=!GWEhbx!Dt zpNYm;4-0*Wpr$ZR9%@p5R&tlA}>kA z6%JItKXkI6ButW)+(HOTv@(zqZ@y$^Oo`w2P}m2gUOjXNZe&olPhq91^=CFPDWIX+ zA&jGZ{>*kMauLGp4N9up=LC;biP$EbS#LKE!N3Uj zaEGGx=t#2$LF*sIr1bo@b!B{z?8g*Wo{jAacPjzch)1?Mguvb6qIT~sGBdI}*bDxj zQ1Ya0s?C?ujaAS3_r|C|=ri#7itQVzyRzvOuC>+FRZo@s-}A0@d6#bFNTtMUl$tET zOQKYG<>h?Ly_`Eku^^+CLoMw`{7?M)e2Lm>My`2wm8GtG#c9EI(ep0*?wb9KNP{7( zdXH+@9a{X=2y*Tg<_SuRm7aAy$W$Kx8>c{GeKVn4=bMKu?n=PimG|ZNI`aH;&y@Rl zuIL|Ip2nBD3-`?{Hy)euHaxpX4`yRCBs+Sz>;#BAW%69z{&hhO5Ht(n55O_;Cf4%_ zwoHvI&Z97{MJAMMRtea{tv;{CcjI_l$pVIOE7NvH+iZbA1)Ok)%w7F(eo#T7uGyEs z%wvh_in0d4%-v`K3Gka7U13eV1?JFK(XBhlW?!`);G1n_OX&3X3pFcdeZ6-+%?d^+ zl~Jf?1iMcz9=Il)#AY>BgQG*tA86+?sdN8q{Aw#MO}k`k$JlZ*lk-YYwlyi0$e4(ap7vj$o9fAXRu_D+WU79*O@YQ~w*jkBTGv6lY*veW=_<0a!YC z>NjXuRa#$&Ck_^J?-jV7O%W;!x6XEI(p2gcRz~-pQE?vKrLL!*Tj?UBEB3dtZ<m>;pTV`>=ZMEj=mp2mu&RFcmOgGI9i0 zO!-LC$g9`bTEfHB!#b44h#{}FSgM65)Nhf%D!osoz=vukRl-$$`YWrMaIJ*zd&bnz z@c5-EfuQ>Cjf`E$sJ;p4RmVg9OqU1Gw1EyA>8X}6fF14A!jIp1ZFBALFGHWwa&*c3>Bmmg}-VG(`Lx9gzRIA4@J*&+i< z`&7e}Ha+gwy64ZGFWK^a@aDI4c8xL{EFl0hm*6%iwP28I7QQ{8q|x64Q6Lni+3$k5 zlx|q|giOiGp!SE5T$vk@{}{!@C!oRP=j%bJa0?go$!~+IiEu(yt7w$lgGfX(Eh@WM z&*J%msOP*X;knBtx?YUU9j2uG@@W28u&In=Guf9+m@_H8u?l#HxH+O(UNwreNrZkh zTcTVzAkep9oj(&n278OFH4WzGZzG%2qU0=v=SrfaIqHGeS}|gP`L}k38PlXhm0u?! z@SA>Rg*5aa%thrC2R>hSLDJWCQ)Wz<{qY7h3(Eqk4>{GZQL`QrK72q3=9E;k0y?yJ zQ{_c#Oo}#MZ5Wr!l$RL2`6t){?B?dk%trs*)z^ERoqrA;e#RYBJ)DP})@ z34T$ceflBF?hTTHpLH)7j`BaAeUVCrEEfK{`)iQu|PV0FNVSRL=Y|T)$M4~ zRf9$8dm6qLdW|ZMCP9z7>z4?)lV$H_BpH?aK!4#XyWV)=4|;4$${)^eBpO4b=QjND z3%|QEdyDhl;KpF&4+IlX&xeA7#kkRPTNxq*R;M#%UKoAy&8fH7gI9su!C#DxWoLYP z3FGzSw!L|I7rY&&V6o~TxZ8M?$DNT0Y&e^TrC!1EVFxf4?YT=--}e^CN1*;(QowDa zRu2(~<@DH3@(6fw6WM_-fF3Bdqv+x8=5R2AE*zQei)=1>PGK=Lv0ps;@L zR*4|S5jPnS9)2|~70(mbjP*wem~rE2>q(+kg*q5{YboeSlW3kQVb-76RL@!^w-se= zdBG*k9jR_Wcs|^mX}GS~E=mv|t@lq&nvoEut?q9?jLD6GgzQl&_4f5~v22kdhk-sH zxN*#QI^Efab+3R9?Mly%Q5wiy9!lYP_iTEwV-)Ps<-$VyDeYfkIg-aTOX^V7FP(!A zt?}lqJLK@L0Y_F`kIuXG@#L;)#7>3W77!=Tzr)-L{adm)2rtzbqB7+Rg~ypfr{AOPP049Y1w(#*ER$293f6s1k{Ck`!_g7kPfDZiH44^s;E&58`}c# zVuQ(XARH~>=TM!1$+v&SVzR#O_;GZNiOG!|v zf7OX1XQUYr3Gfk^yVSrXbNV_ukzox`?V$2R4OM01oL^)|k_k$1Cti&$BN?nXK0HbV z&=lHyP^BZE3zUvdGFipmgLT$(eA(}mpH$1x>WXL49ljJC0V#z257DBF zKh`>osJa2sKq6>YEI*aYCLRzrg54=FA|2d3RsptN57T_uv9nz>|J>X3TYl5twMgwD5OLv3 zq>Y;=rKFq)*taM?zc|g;+J&gNX*q6vUYe*x+bNn!ITk|J$QK z35+P+iH`4Ktv|TS>PH+gn)VoV_#bCIM~pIBRgiTq;mGrU_NuiHY1<+_uCBrNT@5tiMy8j=0_@+{Q~RI6_HHDm26 z>8a<~opBI^2r+Cy87SX9%2%vo(Y@<6<(exl*<`J3t`Aa?!9kccY+IBOddSkgkboFA zQEAo2^<5BH`|qO$iRPm(CZQ*iBmIBl)Z8SH|smVg&!>++GLzgyvHuSW0p^*a4? z+1{)b*YAe~yiJ9e=EUOU-=)L>` zuwebJMh@GXs|Newz4|fSp1;GO z!C9~T)-=liEY*Hk7CFh3HZO`(?3LTMe{Y^@rNwyj-V%G(SSwD(9r3;zmh8A(eSc&< z;LMyBg@7dFJcV*V)D-&_>8kxa(M)H-FGJ%L_(f2M{d|B851sp( zdkkI-4fNDMF4b*@r5;CpMqFVOi<}K5#%5zg5(}ss%B6p~7sapmGla8B!PnJ%fE{87 zB%iRXbts#H`dOl8#yNl;FXqD?rxuGo%OUq z4TH&BNMFVx;&#m$UAoay-Bj(fvxS-q>x{frQz3{(g@v=XJ_BBzVsT9BcyA*lG-)kshy)w|lPaWmqS=_AM_USIQF(BOLSr7MIVe8770yfpl= zoc`B=C4=eSfSS zU`jYwL)9MKr2*Bba5aCj$bZQlODE>N_oIP;VoAaN8Zd?5y^!FshaSdp$2ygM{FEQ_ ztF1zG96f_R^&s}8piZD*nb$tHfjs*QMSXR&6BW{@Z{aZj>T6R- zQFP2W?M7oHw5@~)S|(kS8G|LpvfQ$4jbv)M5??!B90vk{<807VyTmz^odc8~aq+0h zQ&N`$MvfE@Lee2&K_c?Kvf6s?($||Gk$oa2h4>>fJLcZ0RVP~ak~lJHCDKt?S3k)M z^0NvLm+XN_Jqz(vPDJNyMi-GtPg|NSn?3)-2G^+?tf@A7#VyZuIYp`2)WoHa0VfDy zr=uv)Fazg!pl9Lv8dOw+eu7@sT|w4vhRBx?FGOyYl;(>9wxJ9Kyy41%W{}&r0UaC% z^^&S7YC_yc^|3hPc9Cfy$fg_)*N-@fOtSy;oWvWc`pIUuYD*s{HT+0cGz)_Zl2aHH z^$bT;+MP{IxqN&~TJoCeh~R5Zd|$dzi~!Js$7?9E54)Q47;qcdYj@BeW_S(Zus z00XgCx+*)u$w?>MHG}nPS`lV@#X&L|2(59xk~cQ8r%kK=0R~yg%^-V)K$+LJYoQmb zx?bB>ZWUcQMg)20{O|z11TN<2^INVRq3UMDZyni3 zXeuh<#nErwuLtE}c2OOhZ{r@1%@274#?PNt3P^g%Gk+eB#l+3k_-Ar9k|0HbRJFo& z+mL@CBW1jM_;?knUuDuhhxnp`>PKY5$wCAdhI1^!G6T+H{3|zJkTqJ5m3_L z##t*to$sYO|8c3MTQ0ri>R$PE-0T`X&{7C~^u`~=@B8@oqV)ZUS6b~Z%kb{HC!~rc z&-2D&nXzI+)a=k~7b~69H#>od)!CMk>cZWN5Z8>l@vm2;MU(MYwdhj6`tO6z-a5CI zxgpwCWtq`pR$1;A0gX?UBfN)7!#CHW44_Q&13+HTR6-ow3r6Z{;smyy4BogsvrtVp z#lKaD@|_8=#K5&s$bk=GB){&G%#&S*heE^Cjd2tBiMuEe2Yj|$gEyIf*RgN>sj|C0 z&mzsB0# zu_hWLaPg=+lJ-+0%}Mj5H5U}zE?h7_Yapbm-XY}4LkJyGIiW0#QB@eILLC)d;{)1d z0hrZ}HB%Uh;4ZBbxoIr9a1!~C4z-6+9ie1eR}lC-gvFK6&+|D1U}z@WHfc4m!vvVA zYHLyf+l9$kL4+diIdkFY7Zn*6gizhtvI7>yfQta!Fm?{~uq>~c)TiaUGq$chvsCoc z7?Z11j*rwx1MT{ki9oah9E&;E)UA#_flq7Mx15zje{o5Y1~Dv%v{CnbK_?_r{KPm} zem(ot?sNioisfRq{TWNhZkttE>2{w^2d` zr){3($U5j>M&W9NccZus7BMo;w2g~i-7#UW)wYdM)p59lWiaskIGkpNe;uc2gH*Y|3py$(@t>$m%d5=*MqKjnQx%KL3& z!b4$lHKbcd3KP8dkRNP}?q5;>j#&85-=U7HIk%bVK*aSbJDyu0-T>&G-H6$0A8dw&Gq3{9yXpdR2NgdRqE#O8X3e5t`$0 z)%vwK(4K0W`64xNWvR7Moxlx@@L;rEo-@`*e zQ0V~_D3*dx3pJvu$w~+mQr3Td&@yvlk|Q*4&lo(3*O?J_1u(E5pIQmnaP3kpt;r4@ znp6T_FfP|QCi+b62dj~VM~@c5Oq#$bve2aS3|2p=-4|0v2PS|3UqZdFtgpA)C~!c- zU=B01VI@uUuY`U9zHCeq05f@TqAu`{U)BLT#Ef^Bt@U5q6g5fL&yry<@@xiuGU~CZ zx<8>}QmKKcDiswA&Ya3K1oK|oRb9y8t|VwK%C$p?RbEcmFb8Uh4ltkV!~BX+Bz zh4aoIJbd=7Fcz2))zq0ho%9zi3?+md6s&&Zp+sWtfZ}Ex{Uu*FN=d5v7O;Mn=fw-n zuy7rKMGSW2ZT7yr%wWQ{ZosDM*Q(AMmFZFFAm5U6m4m^mskUl!XCz#OcgrBRFsq!^ zzEpimp{~eEEZAhVxnTxrZ1ZgNl)sIcViG-1c}_h z22;(ei$GT6-J;uXbu;`LAj zP77D9tB$&R#jx6K;DT>5`wotXrV38w`2PC~n=_osF~3utBfQ+&dQ|qHp>1TBb2`oM zJZ)hPoAc}6T+DD+fkR~DsFB8`PAb#-!YOJj0gDaF66k|^gj9ZV1uThQ^a;2gl@!&v zf;!jN=ge}!3-q_WQ-(l4CE2%zrTJz7n$2FhGH-3SI(1wR_4IO#YIPCUi zO@sWgzy8`4>GQQ#iaaz8l5)$aAg%$IE&Wn=;>TV^}W!VXAQJ6Zwn4Ht*XEn zvBnWo9}XJU00e>siB91TX)vy-C?8L%CaF&r5D;Qv&I%c%wqKGn?`(t0EMKKwv z>X??xTO=108C;!xw>%4VN`-iv{`4Ey*^dC?;H(8kG{dd}cGbgX9fpAU+zl4?2=eAs zT}NOl_CsYnKXIb!K3H|+o~tpx;{N(_=~OEwG;r@gKLaG5Za8A0;n{iZyix#e2Ldf9 z5j#&~v05+b=-79}jc|mDe-9i1S_hah&+LX+P*+5=Ae+lDjMw$+R~K*KQc#x?^}#C& z#odh!tw17xQ5p?15Tf~*!x%pLjE~f3qQ9b<-_8cwtzn30k|r<%k01^aqqYlld4&;7 zF7*tK^x9!(Fa*pN%wcB|lthw=rNPeYfe;)KNUwQG=1=WmW)(6ksza zq+v@g*DlnP-g_jh`C%Q5#OzN8Fyzk=$=MQq^TTOu31$uRS~LS`4m@E*GvvUp*pGcW z-dPNYA|VE4V12~V0l4tZK|e8tuL$@bpUqX~Kf|6dg~JzjM~)V?2?koT($;#{+S=1{ zA?Ns3Uq9MMXKH_(9iXoH2|M1>+N@JuFz7tFbKM0(O}Jc4c3ls#Ay410x~ftDb;&vk zCe-f_3EYma&okInY#iN820w8DvZck3a@JqB`Q-}VCWmEJMd%ua4eKG9k#2kZ$X;)V z(T4N~LxQ%G97mM80=AU%-6{Ek<^;fd8g*ZzHf?IBNO>8GR%K)49_b)MqfOOh4N&Ku ziO!OTb7EcTY!K=xZS7(dPN`W^7X+g~z_-s7?LL1Cz;lDn&OZoLfYv|swq3W%hP->M z%biB8Ici*&4xSOs_?-13blscE>HLfCy&htI?sCftC$Xh3BN~|CZCgBdI9ylPEt842n(6 zO8++fj(bhQ2##-HT>dkdla)vWKO2EfY43+9H&oSbE*h0m&etdfLx3|dQQ{~U4vYf; z56D7*QVCtYDG>lQN?e~Snd0G0&wny}@_gL&5Q#TLAVZiX1PFM8rLMHMWGwPq0spx8^MU_f3XiI$pdKC9pX=qH}L%4riM{dhvoES*{Xmz$M;q#$t0) zXPn=~3(-m(eu2(yvw8`#gTf+U+w7ZTD6^sCc~Qj%)I?Y^M!N>Z*dL@Yq?^mrSO%!Q z<}}MjM~}q<5?^3xx5U}Klooa~KDHaC=DML22jFp-UqOP#5Dp=s&8*Fjt};ZO+%sgr zsG2oaR|np_pGj1U(6L_ounJ6_mp}|<6sn|wfHNusHaeRPP`d1Fv<2P4erl`3^wiJ? z7=W82bn^Cvc52qWD@0wP1H;BFj2x+)V*zm-3Ab1T5TZ-m{;A6~*(T@KLuCTuA|QW)LDG)#)j*-arXL{Tk@q?&XnrJ;69c%=t+7m;Qt7 zJ7@Yb82gtP_DdHGD{M}oZ1TD&U^%{2zMGq~4=vKFcB;{X)0bWhMY4%muw6P!ksb~i z$PS&oeh=@i;*^wLm5mrh_Eg2fBWWS21Q8|*3qx#Wq@UH_sBc_Gif)BToz4@$VqiB7 zc3(E?UI5P(Y$^jn^k-=0S53m?Ih#EQ8_p__Xs&gAMEXHZC(;24D_W3+)Zc73lJNXP z(NZ9rV(Zj!LK?t?BEIOzv=$+PNAa*iq<`m<1uL?@9@Y*Y3^OE&_-_)N*yW`^K5@)i zdatE4)3qnF)mhKL(8+8^ziGQcp^b3`tGa7&Rta1wN_XF1KZTP9R3Jc6uU!bn7q$*1 z@{U~wljXbg_C9o=Uyuho0}ccX_f+Ij2H)Kb77^MZI@%x*uz=7Px7cs_3*)!7_g%(+ z+~l9Z&*y!MV;Rq9u~MjBO{B>EI3OyZ{Bg6 zHzlt(75(pPKY&IgNyRjaSq$n;t&h(Go-a^uYL%+RPpqxSVFj8LXlIzbJ9p}*-e@+I z95lEnJD5dA3bPK%-U4V&L@{?`l7fV}E?Iw^=O2@uP=AgYHCu1fdxJ!Kx#B>K{UfY z%4JCV>q9*T;O$(-o@D@(nz5FB`%H`bk;{Vtpj7h39q||j^#mvTHA3#pnI7|+jT0O8 zsR~@l7O+kG3#tTVb*U2PCk2R4EuuhK#Q_Qw?c2CY!L0y``;j#&hJZ9G|bno$7&V>+qQcOL#k{SuDgF>!?OxXqh|{hmK3 z7At`-e@8DMo1_$kz#&&PfNO#jPKY{M71k77Q*i89vl|%5$B)T#vVvXP=iUJITXFSzX6?vGe%vA?NV}P}Cfd?;xYh*6@$bJQoC#feLZI%? z8EKM<0HAkW=;|6|%(RTqthq`g?$9z>^c?=y5u`XagwG8t!2 z);(CE6k!8s)8Q1;G1E`@#Zvd)?skTgG58Z(?;8RLSbq z!Mxw@VoI8FtbwZ5GlV?`8$zRYf9`g+6vz>*c%?FV*|?;@@#J?7Dn?)2Wn`@v*00Zs ze6Bm-v_WWW(cR5rXzszNrU$+GIA;aOZ>qzGlm)F53CFQSj2h#FInJj{jUmD^33cec ze(VEme;*oOpyz{~#@Yc7FzNP04XNkc=pIIDqlT}~yt!;-gLP`9to^BLYnYn8VX5OJ zZ_jYbwPqyKE6edyHI+P2cNjLwwIsgski*pEtM0HDumm7Oa0Stf<7Sml#;Z4T!Wq$w zaPih;6=qAVTlPUl5-NqHvwcbSzE|*1{z7l7-KSlFVek)D!Slu@eeOP_W#$>$X5Jxz z_~#^~p@cr*Y>j!iX2Y?Hx&+;R>^}HjonEefFbf@;Lrd{VWDerWfE+lWsIgN1#K9v; zVGe^~6&kUIRl-6mowQ;b8pQL)BDa(&>@JIGCNHQK^|Sf~COFjp=GhW2WA(+DK095V zP~lkBaJlpI9E5@hsYl4Y`}QphUX>CmtL`id&OKo#<&QnTL&n~rv_Ip2($9nhg8 z7m-iybyEWf95{{*9c!>+d{{lvOXL}-~@CfC1nd1{!;WD6xv&4k0WDmu zx^P;wXn6|2>S`i*7W}Q{|MQe zv36__PSeX0%<(}9-Q97_B}_%^n{s3 zG+>RNVl?+8pDe!V*IuFD>u@wG(BrKoOdTt)1SKeyYT}n8UpIdFyw~juX*Ib2s;p(> zaQBY$ug*u3O&vi2e4kMO_88;*2vRS+N}k^*?YOkP%b1TA02Ln<0ArTt&^dmEr^_>B zJ;#bRFS4>BXARB3IVcFPCT8A98NeYXG6!Bph)S)q5@r?1;Y@j903kIsz_W;Of~`q; z|NapkDl`<8dSt_fJ$1*%E?*uSIp&yiY($QEtZq+QrAC8%kMLcW{I2;9Mho~7kz7Hb z07Blh!95ieiOXZ}t?|g$xUKP`-VN1|!NGvIJaMiUI%{!TTafpfQU$f!EB|^1>_>@$=2m>kSCy$Vf0oOnueJOyTmRZ=W zuUOXK3y#ndP{gN{l{)MePnL zqSO+yupMK%7(t3HH2~EuKYIAEG@E9(dPKRvJa&o$N}3G;Y$-4%GVm=1xX5tzy>=4 zB26ve-U6DksvRrkZz(^I%_~dH~nRvp#Jc&Od%tYjT+l(Bl zTD{mjrsptutf@R=Q&SkTWhXbWyLT#PrY%D{-B#T~{0ve4^y`d19)@{q*iHY#_46mM z^u245f^|GBwwLfjs@G6LnARBzOC5;rEGbP?+E}J?Q;e|{5wGDJ%-`Wn8E;q@bChAF zozm2Pp+JFG8Vr?rhy(u;LnxE|f)j@FGx5Y_=XjAuxS85imERQw9Vhtgis$2p9BQp-vF>t0NmTs7gy@Sytm+XLeB2L zQf07MeX@n06)%K(Hr|Wq4!KhB?%V@O@s%#)t6VCHw-eLcF)fHToL--2qWRMGBSky( z9en2`-R^Knz#FN|5YI6;!kDM%6Sbp30C(?}6qmwX+)w$RPX?)ps#DW_jp~A(hu-~j z(6(+TZlTjG{qdgG9H-4oW3@;l>!G61?GxoNiFq+xWL>;6Ql8GO+L>_XjBYt+^UzDD=LUGBO5o<(KO04sq|CI3Ix5`m;xeE!)UXn z;-)6cW;35r29{*BnnBgkzqPl{D7tR%EwqXgvDzqyz(AnTkN%lHe0chwM}PuL6@NdD z*kwtpZTL{CXL`uvck9+Y_A18qvx>cV#DNQ9BPimh)5*w0QJ$Y`#9^nCKWz)H3az2^ zluw2uVU)F9q;koNLAydkuUE+zHaRXbo@d$Ets~3fk-EjG8cK=v{g;*GJM=(2INWO6 z%JZwT1nyvh1^0}KBEq?&z^rP{h`k5`p4Mb1`}}y_w9h37B4pYrI0R;6EwHxv;lkDt z@SP<||uM1t4lz1eUzYx;9v z_4WYgX*?>O_aH`)t^=W$Qwl9UswF~!$+s-z#y>paF5B2xLoaXZ>Se%Ad(R1w!RhKX zBHNe1lG)x_2Iu0V{XG2RNHpu12*EQl6#YS&VHLa()P7f1wBm%)+rnc)<2hYcdbTUi zF^?-!+xVU#FoyIB&I(P`@!l3h7=hYDTRFY!VB@mnk3Se&$WL>jz`*WDJD_Hh7wcmT z2!YZW-7DQ|RbThX-vA`{6Zv^Jv2h$WBy=0?-zE{q^m@rHqoVU6f5^J#Ha9vTLh#ti z=ppH4kNNfAw8;W?_}w8>4phk(r9AxKuJtx<>{{tGyJpXt+*fa^#G!@|;wW(J0CG4K zMP4f!uvzwE02%H=- zS`UQx^)CO&s-ZpY0175un-a;8+cuZbHux$jw{!Ex-+k8qvvLc58V8C$|L!o-qDe2n zQ$0P#q*s72FU0u$=+PVrJs}{MLo*??ni>GWJ9zZycSf`(kL2!z5eB@)81zo-^VjN~ z6j!@e?7-=L|ATeu-4v;w&i8*fe@5%iRRP5lz954K27|I6|3n)&6Ea!xOE@7Dd(iM` z?G-oi-2<`Co6~9OdflRVVufG) z*;i#f!0k^B*aCShx46=2eKP$(6w_l%&nf)fNc^oHm|3KR-jQJX+=(oM`MDAiru+w{ zkABHSlt1yt71Eb+>6Q49d?P9#JD_p)U3qr@4_cbSgMOKj2S=e7VCr{xXZsCHr zMxQ*X9gB}=OgZEBm50>oz)WG>mFCXIu5!}MD-uUaaxSfp1j)Vg&V=aSI=YeZEJ;Y{ z43M*&cyJ6J zZexI0ofLIsf>jCkiH)cXs5)nf*Moq@^eP_?IbadMlnqN8kN&y<29dcX$U$*@n`x!= z75YM1WfSny($>}0ev;Zf0G?<&iBsI&VCCsf4S7@nWo$ZI#{Aqo)c|fLh{b!EAqba; zewrU#!2*QW(MbK9%dePq4zQ7?RGC(O<1bS}KmV}Yoy8JI1On(8G}SN~y^258j61&O zA2;4}JWn)BAqH^}bVr*))=?Au7wzBLT0nULO1%1X+qS$8HMh1PL?0jLKCtd0_uDN( z#dbsgZdsY7+}@*)b>%nvH)ni7ohROr(8bL4&;WEz9aY+ZovBe~-NJ*Wd{HDX$BX4j zKsI?-=WUl?Fk65WC57=~v4M`3l?(tYz(dJ-Re+5E3*}&A>mwtfh9(Y$9oQkK1ywN) z)OO|tfW;ILI(?EhI$>hsFYmgsuif-Kvuh!RmK-FPg(`E!jSkDf&!7_!>ZI1}WyUTYv%e&)>@=hVkpO@BLl zVrp2UP`o*->i|-=WXzZ@3Z;3rTX8MjmMUw=I{@V{h_`y}+7TXVp8fw0OA~Gb?9RWb z`|t-g){1xJ%GK?bsngwEM~=T-xa9~h>8yN>lT zOu2_Xs0xl`-jeYjNA9Kv=^rI1_G{92I3?ekgSZ`LH^Y7@Az;9*S1HVwLZxtHcgbAJ zFoEXu(rM7e2~v{X`zKn7^T3Q$<-w^DWkB~zN#Rmb=EChfwj_n5oU^jBR&Ez+P9=I0 zM_5WZ0EjBQ2X$2FJdmmT%U@YvKAc{K-l0=mx^MXY!{H63mI~Dj8h;s&8BA7}@T<*J zeR(xJ9(qvseFP+tK;rME(mm{$Xk$d%;NTbk5RVq)yp4-!Y7)!uNu^afU>_F}V5nHcffbvMtL+ZA`}Fsi&+?2gea5l;-U0Xj|yq) zu>@>jKENu{1y!|aV3g+rFYfi@4KFwETy(u2$9JF%g>Y56h@k)gIn^hH`wFtPi7SoD zP0L~YB}9sTq1i6Ia7>L?V9>ru*ICD2f0?qYnN~n`mj_a){)fmDZz;)WJL~_AW^ER} zk*Cl4QOwE|*s}=&a(AgPbj)JnO(hmn!1P6tZ8BkxjRT+i^KOmJZ4QLEk$n2wZ>3Q} zb~HesOhqNmv1&svr+O`RjNG{laouee!_=LENU2vUFj`vR8O8urYg25s7Hg--DT`_v z`J(TtOAc5U?v{$}Mn!wT#GJs9bf+7z=%_oo!SG5nAsVCYdPx!B75$!}ZJ}R^sY0D3 z7hr?en?r&5TsJebj3MFt3V~O{K;- zny7W6vDW33ry{661-tNmveA&3dZAIk7Mv^fAh0$S*pF#Bd9no~gGcBM8hlF){3~pq z!6y_hNkolZtPi;;Cg68$D{wbsdmR+Yr_Jvy*GkB`-F zZ+VyR&58M-l+!|$GcnF0eo=IZlw(gjfM+1`t|a`e{VG+#I|t~d`c71JsBDGxNk3B_ z>A*AYlPKSPH61GfX4A4;Pl}=owMkrEG8+JHF*@j ze~s6@m5r+c;UrNQ5g#6ftQ8arqrLF5cw}Sl-B_V#bic5=K2~L~QHN45(``z2>&yAy zy2U!BbEHQ?WBB@9uPT!oFG@BgCq>pXv^3+(1IJ9*b|jlHV(W|wvQN%&1hQ!^qCb;f zJmmrEYztFni~T!8nui;nMYw5#St9vJVCH}v9`NgfB?r1m?Y*e(jbP0@4-q{Q z7H@2g9SkhuwI{IA%~B?#z`x5oIh?gOpt>Nw(WfU@1fhgn`@flXL0MMSUZOaxOL}gB znXYuoP4grpDUQVn+rCS zDurEL+S3vu*m(-hQfZ!dSWbj=_ZII~Af)%F-#c|3lyVMsETNZex%iWCO#mSh1jv~g zwm|5X0|=H-&tCC$7LbaBP=pl)$bC8IFE9xWEbBO2%y60iY zr1)MV=A=)3_0McUcrc>4qLE9DxxY1~jre7?I$&WirwQ9Mk8G=9eb{6r4cAQsVA_$1 z!rf5T@l$dGCzyf!)J`aCcLG`Z*5K~qZedA;v6#xNix#Os$j#OBLGz0oK|q$S)Hxzu z$Kh6MkECnaznHlN5^H2_W#m#R^@LMeAZ*n~94@dEE*$pDt2QC;xc21K%`&QU_kpz2 zd9q+I*Q2tfbpZD%m#u!BU0H8$)0Joa7?drok!t4^syuyQLr?v^dZ1wf;H7!BC9hO@ z@s25M*Jze4`;hmLAaVZDz1ZH1dyIWzdmn8Y!;1nX!1HZg5r6C+`#x9ivvvRLU<<026y&9+xc;ut_bQGXzn4q=ax(uPQb_p7pv6dd(94;u zOHzGFf^l!zU15pTQK4(cLmRW$5s+Zh@j&a~%HSV91g|Ur5OV5(ep)q`BSfx*{VKp?%^Y|6EY0q*ooBd{ zS{b5jqMf}g(3Fz<#?iCXgQw0ao=uk@>nuJ8T~#0?`X$KduPz3F4r1!5B)4F&rG${y z*3FM}&;XH(joVnG-Z+mfQ$VzgzEdRF;3Hu%_e?f1)FVlYp&4!+A{ z!mm(s0)N{IlOs_=_=t^wXvZR{sHh*8kJmT`8uH)ktpev#6* zdwi=3Sut?JLT38lC7)IG*-YrheIO?|nu>p|GQ4A`|Kf90olAe}bb8wXJpf^y21{vv z*$Mg0oLzd$$S!wU{Xk5HXx!+qu*ffUQ~R*iLMg5|+%QIZ|8^&cjApoXVfLG)_fL+0 z+?}`Drz2x|+aH@QrxNyKy0l0_p!3hMG14ZpiLnMhU6G&1K`K%O`~-~>xB`f+hd7Wb zkSvQjH1j4RPU(Ds`vvFZkp6F&5DwdJ7G#HnI%lZ3ULq6D5=&sZKD#N1U{^wI2iS%| zDoU-|*g^fWqapA5Di^kevjoTVn1&9tAX1dq^I^?uIC7)`L`F9$unr!fXaZs#?EG+e zd_C-pMs;t1a=y;@sv0y{=Fg^Ils?-($t#w`qZX^!zW~n{w9aCo6u_=~uvYtm6h=jyeL{bGzj%#-(42pe%uQ@%^}1-=fl&NtpQFLclm zj=-^l4mgA}5oU!wBZ#B%jg({K7}^mC0ga5z%qui%7E7fwV_?T*4;2fc)+jF6hzU~= zr5GFy^wMGy=H3l2MTl7IX0c&vwMwm=$z&YaU@8|dRn45yuz)NJ3G(Ye0Adk!EZr^M z<#4=7%tZ=7cFK?z*A&-ZqIoA{hA_jJnVl6lp~A+UY5-M0s=w9MT@Q#umc*etJ8Pkg z&O-s3!*?I3f2VZI;X?u%|AhN+4sDdtc}QU4^v)sFFVp7_6VM#%ees=g$~*>&;Vh`e zq+br}AW}$j5J^ngf0)996a4-#!?}nQlOFwwIZXk(UtW*tqNw*dD+aM^M3Jg;wbCpv zRWafU6nF%FgdYOR%qw@Td3bj^h%2Q_V&MLw;{TWa|3NKSv6T3?wouPbY|va>{hHy9;{2M(qT!i7^qLa zv?x-Td~7U13v6V|^62Ep(>Y7{>N?}n6>A|St_Jp;cS~xi1wU=FS3j-Jjvu?SkI045 zZov?+WedY4UbH9x6>^w?$YtzQZO6#ginJLrQ*Wmk`^o7Q6<;MM52SLZY=$rq;}HRi z)dd~WH?MuotJa*~RJ7f5joqh{6lQbXLLA`@d)K5RAn&g0@0vF-L~$(`L&1EQS+bpd zu(zIRlFx_M-rw0JvPfa`FwlZ^b;%e%sNkTT$}h@>3pPfm67UdDX|>H|os@t9mKl}wKLJm=XOnR$5aR?>QKAHJE%SY=Hn}zstY~;1Bk2Y z+td8AnkHyUJ1QW(RR6(T{_X0H^M+6Egv@-qef!%?Bxsw=Z;^1%g}-6%%*Reu%j5oV zxaN!I{^cFsJ{->LxKYf8-D{HZC&A8mK1tJrgQ-=wP9W@-Dcu=imRt03z3UNmm+}Mf zwOZJ>Q_TTekroaIitWRUEiCjbNN`;UjwdMtE(1=t2z;B34+q8JplHP(?ab7uasW^j zyQs=*$fm2ed*!KIZNLP3lQW($67fU2!-9)?*YoAEzZPG1)nd~)ro1Z$+&coXO=fB8 z&(ZKReO6nVwPQ4F3)9~8=VkqI4CIxMzA=r41zCEri}JrDwo5f{Uzk1R#8_?hnm6YZ zU-vF@5j%AqDJtLe;qg;|gVWTLxQiLnms9rbIkQ9iX8EyOg+5c~r~WPLwOM!OiED2g zaBuV-HaklV>wZManshe{Qk{=>I(F>TIu^{IQnv1=dn_5E?}OA1Ht%YBaf1x%?9Ha@ zdH`}-A{09tWF$tJhDGap73{x$>a3UCu8w}nl|XsMulSuf6B7C5JfmZ!@`S<~1sa?H%K}0{HlZ>xw!^g`iN>T7!HU zTy++2NPL$AGBlBqwj^$STJMmxd`h z@4P=Z<~=DmY}^#gWPZ6MX|t8hLhQ|8TyT;LvIz)-Kmzp6e~Pb))k5Js&P+bM1h|89 zIvULY20iX6k_gZBb9{)Eo1Es)&&vp$Nyc(i6{rtbTtcUQPrwtl%fYdH`j~`3!h4Q1 zTp*E}RJtBH_%xxbKfnNOwu86jI30}9c-rflO&ZNOEl9nC8G|43m3V$OJy|ZX$$3oT zrOeGP5_-UL{Es*(DKm0KcPR20J=-ctSSZ@bW5wSmqR)*jeKU0FoUVgx)Vn`hv>Qao zJ?o{nfm9)IBJ5nOgUn)EmW$4W-$H}8lNxnMYS>)BWwm*f9FFUVy$>Q~vt8gn%BIHyPN>vmU z+ZLK~M=Y_o?j_`u?+g(`H4VcRRRnZ$P=U;yXI0DkQbv1^H+P-`4;$D)0;nzqm2Rq} zR^@Xfxm*=ch1&ogQe!FpBfX$@HyB9t0Nhuf7SKg-&K#7>YXxa+_8Ss*QsL5+xPC1Z zb%fZ5H|pAXM+)-I*^&-6+ftA(7nQau#pyBO&@-y-eX&fl%b;Jm2K>TJ-LB22tu8@du1Zk!&G z&VZ(frLQesp(pK@_6;1`ymPpd8>vv+28 zo0xL!`s+5hic>UNOx?7#lV-RgwA5#@*@fF6lEPM2Xr{3 zQkPT|sRF+~ghot&GV#&0ftFgUsF%(8{eaQR_rL`O4sc-*AB{N-tAI@@2OaVG%9%Fl zC^3``-8KUJwMC=uIOw)DZ9(sPQlC^k+wBQV=k7#S~B?X&0#Z6K4Ch zChznsU}EMA`q?~j@*XA^1))_ zKV!ecyv?9F@sq z`nnTFg@LID_3q!-8${y=2{}ECiE|H zaGdbVl}wq&%g35Lk-49mFwJ=a>oxp=C%gg>(#vz?oUxj|^76j5S(dw??vs4;A8ikfE@xJQTEfU?oA3i8`NJaeVK z4jg}b^pG9q#z>(Muv?e(CO>a|$BzDfCxSvjcsTt4Alcx`RF9ltjw)Gha7Cj{^y=1* zxs+74JrxVzNo%X6r&uK*SU2*+C_O9 zR;O-;*UFYhYjN5UaVhDkxowZP+HD=NvP_~G<};2MZ8I9Bzj-K2VmCAT~x za$tk-nibW``dS$1%v169G{6=fk2w5vtgbO!KWD2EXi2gqK!=Zt56%cbH)VbI4Pp9X zM))47HJxtph^sK+Lhziu!FqWN%DG{_WD}BGL4PEvAHj3NbBPf+b)}=Utlk zp+d8el^A-kJs|_N!KUJrgToW2x{Z&q%g-qt8|U!tYi+|y0;9gy*rRXE8prKZl^Q=Hrkn(TM@Ept0Q`goR zFWZ}!%~%31Y~HW8$ae^;>*|84nV7t{fM{5}0gLEh}2i$eHXdNMy6k5pR&XZjGBK#`N=KimPL# zA=e0VD~k!#+rT~tYl>knFz99yeVd@ zl&4-;(k@iUOy36O7Ro!44bKCoC>d%lC>=Iht{E_QNf59eoUaIQzjGmhWNNR(;1=949N;w-!IbV8t7a zTB0%Z(Tu6a`U)c}as)rSE=(zFd^2{L+V)EtLBJOkVWl^?CCb`|ZqxGP*M>5zS$z}{ zLNoM7Hu>L>hUgE1&YK)8!Zdf|g?dc1B&6}sO#p%GwEd7f@xBfH7v@%NV)P&>uBUOH z?)M8{jdkUR!E_>YI=M7B64Ia7owfD*VOr;Kj?PAnK)~H;jt@_PAKDdD6aye6xRd;_ zzyIMsu}s!mucAW+k*i2^eqiokgpqiDBUPw#^KtQJiNgRvOH8NzpC4z!kY=z{&v@jM zX1a-_A=UbKK5%_UGMc4S05!f2NU*?9w~Qm;D#SkGmt|F-xyBa<$R2Np&#s{SS?O!G zA`f8>&YJjwCkr;mnf*TN+t>+ki(To6|6{H@_gSO^J%S089v`_4aYMBs;AM)VA;o~v zv0&y?mX}_7-W^gA+N;%fNe5(j;Mc?Rmk3W#F86vpNfao&NYY#trM zaMne8@B`617aw|sYhAdg1Q%E*s^W^M-1v zVPw>B^hAS*rXcZ0(?K9IrtljUJote&`c;Nbkvm<;Yk+Y=2-LMEWeh&O%L>sM71>Y6 zttc@z`AcFzz}kk^ti>ZvNQPYi`Fq&Qb_|V647Lt1zg^}X5?0a#;0U#Asq~xNQy>S$ z#Z4t4g=M$R$p)klZaAj>CG33wIg7z|IWn)Rn(U8*(eM)UB>8q$V#jywoBP5g?d3d{ScFB}N)1xvk}RbiJ%OZMldmSIbMy5q z#ryc0=Y~WMoK+A%?AShOhfdm=d^@mJ+l9aRZhU_{`ZWg^tv0#XH_<5~-89QL_H4G` zP#TS1xg35X{8pMT8y9Is<04Mp@QqI04( zB<)Sw{dW^SdTdtJI4%Q+3A7vGR2xe2m~IDrPsx|X44QaFc1pG!L1R#t!$iL%<`wg^ zPFFgOCN{=9nG+4~EdxoBnN!~n?Bf1FaqRwY1_nl`E4x=2{J>l1bs*!^CR3L!u<)$; z&JENbtd>U9$010oIxK#o0;`({*s=#A<^^I`zNP0W>{R^9l}q6lnF&s1^4fq^6Xehx z81fOHHASplI*zyx8@Qpo*BmAlO$>UV5k4irxGJvG4;=Y!kzm}XhUH^7VIf>VZWYu0 zA+64UY+ibOC1W7$CRn~nNbljivWz|$Ky`=(3Sq&}CKJ?|bC--aX&KO|TQlD)t z3?##r&Ntlmb8@#z*$|AUv|sPuY}8?V(zwIuuyK3$^=RMqwnA>TiUe=AY7bB+Vm@xE zwtEt^r&hrNG@|>wW4H6mMHlz^E4auwr}x_-KA-;2o0qrn1lnkkp-7g)*3T=1`{tb~ zNlpJIsLEN2Na$9UyC-N@_dl)nV6iV~v+aluTkd|M-%n(l4n8%yZ}`%G`=3eI^!L@+ z47Avq?Ig9oXLlN&g@5Wt5}E$Wr=>7&rqEvWxW4T175$+fIYmDb^+o9Z9pIm3hNM3j zT}9u7oDWJ5?`OYGuAwjL_*>pFUgq=OQrlHR7bi7l$d(xV1p}PnL)Ic&{1`BeW=ZfI zFLzOF{h)qsqO%yE8+*#vWL&=DjuX=jlS8DVq?H(IIPK(Z>f9OjtSQok=K7!ZmVi%2 za;HagSArvEUfRjlG5)mOmlhZUVRM_#HlVf?A)fkR8TI?=c4W>y2#tbPf{BYey zcT`zS&0eU|NeVXGM{?|4ebB#ZzWqs7&S0>EX}0^Nbz~Nivx4k7lFFZgR}L)j1)ZZ( z{!^-|mAd~dc%)|m1@L;b6_#ih1~LML+Y{MiKc#Y1GNnw4w~!??#SZksyOE!t6?YX) z>$v(sip=~R;3EUlEcJED7mR;;b1Lw^;{2A(ZtAk6Kp#+wL5{}&_=^i z-o=D`1Y*(3+G=n&u=jS%hV8PC6!_Wkj{(~@i&0zmIkQa$_w_WyOd$~eH+6z?rt|K& zn>08%D)MmJYpi2oL`5R^l|`w}+Vn@)&=Mm<*g{nR$c$~L|LbgZdT$Nu-5*W3kQrnDB`9h2pL+&494fc;^IHzAjQmL zJ@YSCtZnjsT{270&P*S%@q|GWJW@R3TLzDxUqiBw?w{B1Jj8mCiHG0xKrC_n2JU;# z^u4YsBqIc|j*RD*-!BF5n`Y&1#5k&8}3C6+>b`+&X%x)1E60x#Ez?U%AsJq7tT~-i=a8HXes6C zaS$eL^A58B$YrwX$`=Xe`nYR03T-@}x+KvMokVl0Uv*Qz2yq4$@6;8J(u<&)=z>=1 zexwAsh}~vtNi&({_pvd>u6_mwx<)r8!{J+rV-Ltt$pMn@Bwu2WF67FLhZT>U44_fI z?#cOEj}-{_yN|u`Zs_-J0D(lykEy^J|1D}qNN?HjN;d!BLw)}?cx{LNb4ki`!!C_o z50A@{cMr8DchOXQba2)`m2raXin+UTvFK6t`%rmD*w(e5i$-!lZ;i zqLg!`%S=I0ec@Sz^C?b3rq4QN4By%|=}XwbGFZx}o#hiXT&HMuWLKTsdo8LYT0cuwIOM;oJzql}fr$mj2{ z0U-n41c&IT^24Nf9HzDEz_Yjjx2a4%aIJIYEfRNV$TgH2-KSIsZ?}*-aBT(*Gz*Cp zBpQZSs#Fx{ksbou+;vcPKZ}k(S2l!JUDbJs{0{~Ip`*@G!D-0so#t*J zmVEK_oC}X8(4nk$*3L?#pHvT*6wOU|()wb8fmv7`~*Y-E6euc)BBf9eDU9u#;HCI>u$D}M9%2+E}wlOmyde9`{1fgsZsI0p8YEl^JzI& zwL}%(Wzn`d%c!g_lBImRWYCp0u;g-7Ntp)oFSoRfF6yd@5}BR#rg_tM2+9a6{~vmP zpeEv{Ai%uN-kyB>^l%x8x$(nvHG5)8p+z6dWelDd)uZJJTOzEOR69Z|}A%ML3GBYRf| zw$A&}^Egh8m}2v-d|E(wT>w#Fra;D`B1jBMUm+|}mwW4dRBXQ5#14~CokF>NUZPM^ zsj-B>0|()7YPaKXOdGdAVB2PHg{^b|VS5d!(amk5d>1r^AYU$0YO#*FaZ587vF#LF zCGSe2%$O4WGXXYyRjm(YH4H_Kk4TJfPcvuO;XN-)ty?HYVi?fKfe__-Ey4OT!h`AI ztT$OU0^Y?V4c$A3EFzZ7`{GUIQ?lW0_kH#s9$BX|G^Dfcz;(-Q-tf9={M4hyJnShh zf3jl92MoGo#`SNo=FHucoH z|1jGtriMD9M_;`N!I*WJO^MSgFYJg64z3Gno68<;;is4vFS)5_j!I~kXGVGtHT{-| z<)+to0k1MJzVb^(G`}0jw;ZUje%hmsYN=AqYkhG9jUXL2Ruoy~DHPo%NG(>3C0;wc zn7m&FLB4jTw4AOGcsL|a<%GxEVIau9VKG^;Mn(BK&aayPHs?}^%CVnSl-;O55(`Zj zL$lv0$#C~t{c*?qy`_7R{lXz;++bW%rXuOS@%nZ1#+(&}oy>fO8Rzt1ffhhcJQx0> zj0_fi{^=7TE7T<+7CrK|WJD4pqlwue&fmIha;|ZiuM9&EBxMH=f8&7Q4T`rcyfE7( z`1o3Z$!*qo50xaBk=`1v6W}&fhLIwp$c)az&ZdFvsiK_ul;iS^U}V&VK_x|n5i>ml zj<0hzdCt4GJ5aQob8-ssd2wmcA{cA(34(HZnM6mY0wA7iygXj@!=b+Z$sFL4%(NQI z*^QEyTK{FyrwyiRE_y*hR2&OTGGUEHED(5IXi@1p+l?$n}pWwL%9lHZ$J zhQf=dA*6de>NR~}!@8^+1p0I)^yTdDCc@n-{TF@^>LKm-uJ%X0oZ*N|XM6N=b2MJA zfwDXwSN`EeF}0D2MR~t&ylp}WmRa`~o8s~&Bh)8O&0bUN&is0_$I*Ng{)wQ%W9z!= zk0gSl!~`ly!_S^Idno~g^y=sU?M1bmbl{XvNo8aI{MX%a{(I8=9s15Y=G6Js1A@<9 z8v~Tg&Ra;qtvwbM zZ5#OM60A>Q$6K|hr8H#nReX2l9lMxhJYhXJC#YOzQ!7eeV zppvJ@V{2O1)s7tSjBoI+jr}x}_XfwA%UGlSjjRJLv73TwaUbBzq&u=XLTNlzSsVN* z%F!af&fw;e|TDFK$fW?T|QX!_!Rm4lGXYh_qb|r_%GRf6-%fh_`m6FGQH4j z>Ue`AR1weANTr3OxENAlY;4!_Sj57FZ_mp);l zpps|WXNOJZaSN<}0G5=pChw(ogw7QQn4fPB#@|oRVqp@e7M?h-(6L-(`x3FPpdcR$ zn^b_!F|O>{^1ouwngO>}X;E7mf;>wF$YoE*M;3*bH9E=~1X00IL?C zO6(SiG`_LmgBxC4zD=GE2x+QqnwA8vOkXy>eC4v-IAk|vK0wT7&FjUOAqVd!&-;s6 zOk^y8l18@&EAZ*NDN9y(J(((4*-K*CRrH=?%Yu>A(A+Y0x9idyysK>SvLiV@6W^G* z)Pzd`s#h@0yVtSlXCVHF%umyBom=cGeXH9bEsCX`kb6!_`mZW?)`vXlIm4&qv*kmO^%gMJBiuYO);M7z6)yQ zcaneX3?)GU%tAE#@!u(slSqh8*~cDNetW@XvvzSc=2i z)p@&ugNxob>CSrL4re2r{(71cj&=Eb+-3>YWv{%{Iq)j9`(mcaa%Xz%Q-j-0I%Dw- z$T-2%>(ElT;lp~g^RNYFMZ^?s*0ePI$I$O8bajSwkjG(;0i5Fwtdt3(QnSw&qK zl`C5D{h!&-+L#a+%!LPhpXIVos%&q=y%u|zkz~q75QtPo@;qc`HJI=6ZDrI7R%umT z05|Zk)AB5&N|i3s68ytj^9j2sWhH23D^!$LHC0Lpb&XkWt3|=-sSLI36LiT!er7mW zpZp^UkN6zCx*$mMfti_G_LIR5*<~ET%(&6o&4b!|G`rHcBwZ{2nPV*>(6R#x=bz7!Tu{~cpf9B^RfxiF)=CcYN< zbx$+EvlS&@)5O}y8l9Xmfi1;$&BHb(Z0y+yJ10}EsKvTnc}S1bP925VlT`! zt%%rR!xnK-Z{o@hc~hKqb2Sg$6(MQLx6zsDv6ma_qr$SFzVf-!rv0ld%}y5ghnD`tumGy5xr5i504`9d*s?$C|EqA8#8CNI@?y@v8pc z)mK#GDGU{Yv}eqVt5!{m-*%U z_AR&Z2kce$O?Th&D|)&|Cw;tCC-yc}U+kw@pC|5WSQnP9#>fqK!w&0dA33V02SUdz z9VHe=aY<>~!jH)Z*DYnuVuH$j!s+p$O3c<;O#3-GtCTDj-dMbviOlSf29<4mthsTcud|~yy|dS0Jqscgi8sfqm?O0Ro}%B@alT_xxH7}QKT7~kRODAgnK#1R z`MN#ZFR_1hYc$9ZJ0(1@EQ&bM`a2?tGC zFY?`P)V^IA@&1yHq}|c+a`}w3f=ET9d%?#E$9ETim&@v1KA08rKjZXa&ALFh)IiAp zLUXOZ8Wom+Rj6vd6xe~xDD+gS&>|+Q2+t9K|JW|Z~<%Eo^ z9V2J$e3ysK{W-Q0|DmnDo!_!A3~&USa367cx>r#6P!HphKk8oArCK`a-OvxjzrFK$8PexMzP`?zxwaU@6wEY-*`QJ4OOG3|3+V$6CdV&U|s-U0)v1? zm7tdB*CI>?n)G!tZWH{{>RJzPDi6F)z|)#&22mlr>LJwK2 zKQP$tF^!7Hovj75LHFV0>e7s7s|e0cQ7(;=VY6NX5qjvvR%Qsy;5d1l5&%b;z-siR zF7wZxxkfcwuw%o6YF?w`wW1K&2r~eKfkhpQ&!}tHG&%2Nz-3Y%6;sEMx;EUd(5qa+ zi$Y@^V1AaO)uYO1&i4*0KTWrc(?MFmMZAHS*d{i8v zc=6szy8xIP0&7=uGzvPUtc_j_QjyPdpp+u!be%R~g`kh=xSp5P6(Q*?cmX>}L|0fP zU(+=_G~&qfyr3kU5Yv_pw1dehJ69^Jwn`0peDjw2Gb>%6F8}YJVy37z4B*MXMx!Aq zEWM@(2a|@!UhXl(#w7jQ?zaO)k--UWy>1C)QwL9rc?eajJsyHXt{U!2g@RIrZPC$9 zz{YODA}PzLt~J}YnlD&(9r)~AP1@YHyXGUC8#j;!Y(#s=kzXgC8|jP*qZgfcEiVY5 z>OONegQ|mu&tpbMUWeO=?3W;%sibPWbUj5YW^v>_L;Bs=oDO*BnXr_j^6+FnyXFsMO7H!S8q&o50AvXMJTdF0pyMp4n{|Ym= zoUPgP=G9i@0%95lM{U!6^I~&h{l!H5Icw|KXt{=;&mH8h?%!hI*hre!(vB3tySA=e zI+9iSi%-BYF;tw#7w6(bB=`)OB_x4FY>|*=NuyLBSykD&u(Ea{Rr~U3;#v`zFA#{Z z`GL~>^e~bP%DqxVYe*y4Z0i6STR;XcW(Ko#d;Ikia>HW)7D8WfQD`XNuAmo*-@cSW zF$lU~UP(#s0_m6nNYb+b7PzVfy@z`4(FN6_KW~{JAK0){UewiMvaNf;PI+L1`~iNP zM;BBeuuuEW?dsDi6oA1hOUVY;Hr5_wZ@^)HW`L2)$36O}Ni!V4mN2TWJQz@^2md*f zU8*f+hx> zsAV=IkEv464k2x-+ZJ*|WO{MEu%9-SyO?_K8cJLYdE=w+ zTlZ{*2&b!+Uxwd}x%)EQq+HCuFzQB)56J%Lp5z{};sXfcsZlXMw)~~(qrD1eRfu>8 zc+g^vAEpZ~3L8r(0#lGc_I--ZK$0)I0EjHlw{ zS~8SYov<^STU@FvP84tE^oB;~8+pZ)H?#uYBk_)*$=X?)vHRq81Q0Wm_hJVWyQ}mlRs^sjsO-?QuaoH zb#e*EGYk>F>3A_!^LB7UmHz@}R|c8waP^9(N= z8le}S^_%w*F#T0KMvRCST$(LBb+JjppQe}X1I0ZCldv-+eU}o_RpZf_qWGRe1UQUA$x8U z^iQ9j`oyI&G4)(6S>*yV6W?6lHX525M$AE|UlGWdkB+@%=|_&ix(ms-ZmUCi$!0iz z0^*ROKV$x}jvwv z+0X{)amM=xe<3TuW{T%2^D*vCT?!~&<@?t+{8DCQJ1u)k%g%b6mX$#(E%seQ{8w64 zI<^Rm9zj&`wDI+RJ0g=&OUp9f!)ko$^maxpW3>D$PCFn|^iDF4&~NBbfUuntDT8yl zjCQ(bChHwq)>zYHt?qrzZ397jDue$z_}I&YQ40jmC4n&l8pfe74ux0IvGf9dW=^g? zNjGB@FcRn=yY*A;dfh2iv{zpG=Eur7KV}rZ85LLEmX`J`E$flHcll?LaUUSOT=LAc&^>OMc5Co>;d1bK zoESOe_)BYk`r*yiwFAPD)B08hrjaUDWc;XS|E`B$K1*mwJX;eta&YyFI;l+%^Xh{m zaT|uimq`A$9z9>|1)VNt8B%<^>UUuEdvHUIEH}W2ZwXFhMaNt;rQrt_Pb}F1Y8UcvCW1m%5BEZ zpQ#^YAn%+;fX(81a;w9?RD(4Lq1yjQ1LtvCHNVMqy*U&at6&&2mkjbVv>c9^F}b?0 zZ+Lj)#?y9FwKX*>2Zl}e1-n}tH=Z$leXBd8%p6WF{f2-2x^s0D$n7zbEN?r56C|a5 zt!HZg7Afg%Q!3Dfs!;Z}u4}K2C9}ijk^)-Nfh`H~Oo|fAjRVn92)G0+Mq{Qe-4Y62 zP)`&RAog>$3c#HWG`Ve1)%!b35^dfuva}$L%wjt!-=!EZU?tiLAVQSH%Cv#sOl z?cet9^;^Gy?%rM1RDb{uvb#!<5Hgc3|35kHo#s2C6(bfaiw4TgU{uNdkJCTYobyH6K=d)| zKJO~;SvaAukLWX4Utc+;Qc#gWG_kMmFIIni-#XQX^8%tD*C$Y^Iy{ZI#86NYMgg0k z_I^9w3Ti65C%Dtjn$5=ubw>59U%|Hjz4M=GPE#TKCz^HE0Ig;`ypUZSFdD>j@BCQi z!lEFuKFx&Y>{}60<4Vd)Eb+X*@!m+QHzJ{sO|(Loq<@%)m|kc5*;k9%M9Us_Vbflr z>k5AH!Nha!9uLOujf7J#S3nv6m7G?0kXz<;;*uB>gS;BwI7*iwzvo zL7Z$-#YY1x@|`mB{RzJIEGn6h-0oR~Kp=Iv(e>I!q(HQTMgqbdOA}Hh6Jxdd}GzC5LTv%F}YfW$4?Z+_?tV7#1G(SQP?^fRQ=IcaixCG2FF? z;)tLqf=;tmsUz_J=S>JFeN1~*Uu`UwT=5)lRU^j(=C&-LQCp|m{VNhv>cNmPyRkT_o^! zex_JwO|U{av$Krj!g+X?Q1iH?nm2i!zkYZ19_U`&XH8$=r}vdqJ4~AYHNkr8N0SOWK8ojTXWS0M)NJVvZ2#s8XddgZ}WujP7W8m2oDI}hkY7>uK*$$$mG21 zr9o8{0!^`odwZX;TvSXUf5B@{e^Z3TZ=%H17;bXUILJ$In-3{Z4<#R_qVxM_{IUO1 zc%jm?93O~}_7U5qM~7Ndxmo({nR+ftP|ER#EcV9|r(*1H+F|x-c)*Bu#++W0TQf-u zOnY@SOYt&p-hXBEeVr+{_5>@z8q}VDp(#XY8VmLhvw!TC8cG?`Wtn|-3kl7$sX!k6 z3Cc7A_p%s8MlICIDPfe%JC3`KyO2WD>YpF=jORu9O41M(##RyDBI}S(qRdO=E%SKm zS|5kKzj!YBrn|kT=Nj6Z+x@J5ip9VwFY0{A`F`u*U5KLM+blIx z`gJ^ARUXz$`fX4dw}lYnBC?HN!e*pX{D&M~AurH| z1ExW&vq%??^_|WNWTrv>10ZJ|e$4F|?v7i3uzwx|j^o6*@9i1wAg|xOjT1rc33Kfc`6X4qb*W)(Q+sfK zV_Tz;sNJ>jWExbElDBeV66aD2Hb8pG>QO+Mz>$bXyfC-GP{*{>mLv8tKDBIE?2!#P z5=m=si=cys?PDdyB~2CCbw@SkArdT4q?xf4=*dt1|Ky6~!QRQuAA z@dmVoD@N`Iq8nUO`PfwGD^C$b3nzWUGPoWhRzQ(BP8|BqcfSG%qK4JKz%w0;<+P6o z#r~;U`L8@Kn^>qAR*?frZsW6j-jCX!%t3rz@f~f&Khr`RdxBwoSl?fNdkufT8{AH| zW+lA%!sf&|?>C4M;mRQ*Wo=|m~{pSeiUFj#7Tla*&!z-6uS zPsgN%{b{V6Sc%njX~(^)-kxiVep9`@phmMB-&VZ{Ef=cx8Yp**=^w3@X!26^PmkCm zfm?0B6_uc3G>z*Rx_r{%RLj@D zpgQebL)2?d_@cnY8r>M53)5n0r#zbwVJRD8)dwby?_OW8`*^4^cGyo7xPWR$RiJ95 zk?onR@RU~8(m-r7#Vfl!EU`Q>aUc-Ce|66$R*!ep*lWFw1~SEe#}7RX-c{okwgSB$ zSUsYfoV5NZJG&`NdyYw|q~qUi<7Y&3$yr+ZO(yNe*~S+ONy*q1wNN-SGd`EpK>r;u zb1InRjM(6oO*L9&XW#Oa(w->kr5+ZQeN%KDT(ou4u(54Bjm^e5vGv6`VPo5FY@3a3 zHRg%U<^*kWV%?1KKm0HE<*xm_#+dtU@3kh*?m7mQpAIngA~Tnk`i*>9s-A*gHgO4C za@+KBk4cnawVaVqtYlai;O~Xhcw2A@n9#R3FZduYJ-+vrE9Ej_LI=gqf5T=T&}h#N z=NbvI608tctfY#Rx|3(c$deb5Pue4t2lr{k`9-js~Hqdd`? zvT*cEr1PqT@+~A~cQDl$fFdhm;z8w|JwysFU*Hzy6KnE+yC9qQxo?DT?c;3X^$fs) zs#6Eu#+V|%FzPF>AlhFOHW;I#&rQQNp56mjtE+ii7~%)~d@L#`>aN^9g?qk~O%`-H zRlW!-=bBmX6q5uS6u3kW&!d&k592TcRWO+WI79$u64&e1YgV3z4;+%1t=mT&g0sjw zKciigw$t?9_0AJ}vwHiXo{er6p8iSmiKcb`YWCwhZSQ97D5ehzKE{$sdww!+0iV8m z=uy-UBSHaoa*@d7I^{4K&yIg`$uC}Zi-Q>*yO!gfOT+H#m;${+c0=n09jtJ|FGIbz45F1*TRpZ4V{5 z4R9vqO~U~%K2dkHRc;k>v#9bK6+JExtfBL8mZ|!i6>V_(O0a_3W6RHU)i@`myG{i> z(UD^RnCfokd7oGoY6YF^<7W$z%o~0|Cpm8mxL#52c11zB)3I3tzUEw<%^B^jZ)y(N zeHC?6KS;lDr1-;)r|WD}vFaR}OSE+FR5ZR%SF^nJKq}{VgzpakojiNAnXsjgq4Zjj zU6o@en@^m8mlnrF=mHb!0tH*@0!bWaXb^<-4V^7dGU$|(%zsvL7Nbzg<_-XtM8#YL zsiHgH4xP3doea&YXm2u`QPuZcn$Wsg53A^5>GH2v)YbR^OA$0kUW$v_Rp zdd+j>4YaO}Wr#r9LC9ZO8$lt8UzPQ#NjJT-IEdGj&c2M_xh!v5o#F4xJPShGI`yCr zgZ;)+wjAqCR2+>PaSZpaBYKXncyd;7H`}y=mcI!3!CCe%<+`1 zOCe&^V4}bXE01fCo^S*1kBsE;ogXQ?^NeG|DgPr$0efGOarZ!nZv9(11~YNy)3DCf zWW|tIWsXMDem&d~%8e*?$Ih%N=TDU_O^&T6d(!7M#DO*u$?UE14s!jR%kf zJaqRlU`nxu3+>j2)lTW;y}<%@Px%&mbD73@Ic=IF?p3sffBo&v{vJ7a(Ppr=^hCv! zv`Q{){6R&F-9hHW?^R1?WKIr5gp2mQcWS1Ny%5Fq$Z@))aH0D3Dpa_CuIa?vyKuMjjOTC^Ur z*|;7V+if2Y6t?51JcOZ3(n}ar|TEiC2T-Au0*Kk+3V z4M?2%;4LYTt$^fnq2v7d)1dBSt>W3x@9X~^5~pZwrqS)90V>=v+n9Rjkc$A2kr)O# z`0yXvs^Uc7?~0Pv;wa`!CwU(;N8(LpzuR^V4H(sB$Lj5ZI?GIf=9}dNmUrbup=0&S zBigQCCax!>{208iK&__eT&E6AXn+{%R&Uh@*vf{tH~+2N7NoxgB}{YmU92zJPqG%9 zZB*Moue;^~co0AI=|j4W)wFcs!WIW`Yu^*@p>tV#&Y5} z6v{6jHk>uf^U7M~g(H-eN{kJvQLuvYm zD?mp@jV4qh6ZqhDOVJawy|tV=VyD)h6>5r-_9NBSvym+I2kWR6^=1%(Udfg-4d%0X z=7xA)GTRRObf!oc#h3Vwa3XFqmxYfLJb!h;2-nDMcVqIpz`oeGxKMd|Zzq9cF^7GM za7W4ruIZoGvl)Ixve658n?70TC0-xeNJrlVP4`bkfziqJ9v>@XG`l&l=Cw0A5BlL* zt!|z#`(R1MF@{cB6Wu6-eBMX{I6ABTb8GqfdK*y^!%N=chkHgx-TrSEt>47T^{6X9 zN@tU75&fvsfnk5CeC^J43OyehDP_tIkGTej#wP7YN4Qi_YE%W|3-(9di`*>OU~Cdw^PVM^J# z)JV+-o9jw%JBL@fd?KNY$-}r}6t(Xv()YwBv?6Nr?ef<5{X7RomKq92N^?2l4>i33 zJ8AYcT(m4(v^|#o(p)c0a;n0b)Vj^8?q;l%B>c~4f3b~&PZilGRcMPCs+=CviYB5| zkwlunSwKt(>_7Q{P&-8My57?)p6!avF_MMU=F0a?TmDtiS>%VlgYfJ(Y{yQgnx1Uqr#+t zr=qjSr8z6ZoF~51s%mnJuJ4D}ThpZtH^GDE;S&1ucc!7a?q_GAm!pvFgu&h84MRF( zN+)*r&)NFy*l|Q`Q$3X2fYB1`6xFo7Pt&)K8X-(w~j=1GNh_d%my_S36t3GloknA|VF|*2jG6 z!BKb~*HKWZ)AtonV{pDf{k6vTy&{lp1!T^uXA0l^Y* zwM>iDg_()@*EmSjH=_6l`u+sW<$GL+=E$Nsn5mn=)@U;-rxDr6VeXFTp-eo~gp)c4 zd#a*So*I9)8SVmO8?!zna;CyB$y>{mlS_t{tIjzkp%rhzixdGoX z83&=<2Lq?uocQXM*v&4trRFD$Dc{5jY*dj}1y zxfXD@COAVmNxeeITX{C>G;<&x@_Mt4ywXH_WtUEq=}887mIX`0xXKLuO1oV=Z&M$X zs&Y>sb9s#HT8>CBHyRVn>$4|%uk(}0_)Jv<*h=442Q@Z-lE%;UK2Eg{YXDog-GnIm_bhsTnTT*4D94zn^TEvzBa~4ON9)0PGeYINQ6P-B zQxEBX#o3;nt6g3CQc#E=?4YO{lU08)?4vvztjG^UM{TzRRW%lsE$F+MK>D6rn?1=~ zEa(-{@0vy1(FRbu7vgVJl~pEQJ2PKMP`dLat5@p}3>;5gy5;x12mV-YkgU!lLn4R* zvf2S&|Jj$g5Ee~73bF|QCubEkdz%(vC80H~d z)izq6wq^xgPD-26`G`=l9nm{_^K7V6HBh-;Vg9|0@}u1C%!SwcRehUO5?|!`%Rj8u zif%5bGMH&mfgDIUjo{nTuw`J|$;F-~+Qrpgof+BB?#XLLBbHwyF$Zf=9y9MVg<keo7X3%{6w}iJ>)XWx9lR^dFngSlo^0>>F%oSMk z9iW;%h$=ikIN&v8spbq5Bw$>KyM3yla7eOw1mH9U;9x% z>z8btwH^wac#%x1UAr0?G1CZEW@k zC<~hDv`OxA0T`YU8X>-!Z^8{NZMk~658ysV9(+lDh6fRx9i#h8_x0D_!!&WnrlIvt z^fQ#-o=W2u6Z4bmLcJabJ3gC_ry*@YA=;gPS^Hw_RtCYF3YG(nLf7eRLzk?KK-a9- z!2qgu5qjvu#V}IGMT2!+3{znk^ZuQQgC^z${-RZW_t}Htj|+n-fRZAPY4Ex9!mjn3 z8^BFZ`OS7TM0)x3`z15xP`)pq21Jnh-1=V40>@EUbApZ$N=QH7ylP^6Ur=qS|Qr$mToM>$gWfU?PpJo zZCDx`y*zFW17fV{oXOL^`!|p(z#pD{o871A4eq5>1Ty<%>2S@79I-YWRfXtxH(tP{ zSj6_$z#Eu48O}EygwujVraXiTd@u9t{eUE;X6?`32j7o!qv+_Hts&dUZ!--qjt?gxoqv@;M?7~mp4gMehGE%;U7H| z3Qfg!U8eeNhd!c+LkxgVU(v~G$BlaOF-)63IY>Dg`F(X)2O7*JM%S3emr*GNQcr`Ou&RtOA7zAI!2QlSvh(bsA zze-_cNtP`TD&ge}AOC|JqWJh+m7n(2T#3QQC^eg3(I<&mk1Z3SbhwV2eJiS z1a5mvKLKyZ#Ial#fiCrg^AKcSZbZ90yR;qU2KJ2MAyRHeO^#Ug)^HvA502phyPE;+ z=Z2phA43FCK;I!=I%YLdEmB6PQ}3C`Zcm~4~AuXU0#!cd=mayXK3!&4RCAE`i}DA*0pf00}`3(mjT zOFo)ZtQCh*!}B>xn*6TWs#@|LE|e)TNf`Kon^&k{$M#M%X6)nApqq|zrypDMi7+p? zcnF(VCV3jVMHw48A7G<%BvW->JVYO{7T0~YHI+=w{#MC=ax^smxWN4*C;jGMUIY$X zgJ2Ln{KWTPG2Ct6^OVoyJ7FC~@B^DTa9pvNiO;}{?cqe1(Mys3X2Te*E@F;F(VE!; z5&5}iazhcBHfDJ729QF2z(L{qSsLY5i$OT>eqb!AV8e@9=S@hms^&UU%MJj2>*aAV z-(vPc)FfuFE}+OP8N-<*y(Nr8(u#+U*-e^m$9uV!WvR^5GU8m!ePKt?Da}3ErGe25 z-Ro?h6X8g^*NhCnI)j{^&4J+b4x)YJs$V#A2_Ba!CTvo)C4nunPD|Bd2>9AKEIuWb zzpwvxT(n?!?VAX6>g&TCdRkyD>rcKht2g7{{fC0sc1EDd&IXS`irCedfVLvcZf7Ht z47rfc#{S+kDKtM{Ndo-xHHB$d$}eEa%&3Ag$pd2)`A6W1RuW>Zh8l@h(B+oC?d8h? z`GC+)Hs2l|yZ8Hue%H$t4UT8{SHe5F(TX?`;qz4=c@-2z;5KI)>H?y=E}lGhhWNk3 zqh#&Lor-1GDaVpb1eLcZpr$_u$6=S=?Q$p%UakFVWBC3=qn0K+2`tVZzc9b2qS%@W> zuuM4}7|P{8?y@H#{!H*uSaTx^KjeS4mPp9&x2{GtA%B49%5uIjvY11BSVHV(8ZmG3 zx)SZij`Whgoo{2^-u*M@h?Ua(NucW-q^s@d&3ySI$R<_l{K@{I z=?=)xC>&0d*#WX3C=mappA~F)dK{P&e=@Cl-=~Z{j$_SaKQqk@|&1quk>gHeo%bQ}THuYnNBAgDrH^}mE z|FA=ZWd=L!36?1H%oJpMryr8Sxf+v;SnPBKNc7EYCchShcU`j0=$@XG&et-`I6d+1 z16|jvN70r0S5)AY6^G{( ztpUa(o8;A?R;(rR_8Iyf^j)WMdpGVQKBMN;Rft~FU;*{&P9xPzqS2n6bctA56*aMK z3^`2~$g1Ef1Q<|9v(!sMca5}zU->WGU&~eMZ21vp@?WiQ_)?En7g1;_K`qj1ViefL zNIM|*PmT+YCgX<=hW%0!gG)3!1vib=wIY!#%r&UrLR9-!*3a~N--mFDzd(Hzs?})> zqtulG`JJ(`-u^Zu(8Vf!Q`*RJD3DW(=ti(-?)fq~>(@_ua&+SBSpD^ehQ=zYIOHm~ zr>XnDMS6RHY*G<0wdUotw6dz;j7;Llr-lo~$3hnp0?O!FrcscM89^Zk0=r?j$QTwI z8ZZmrSgry4Gt}5Pxh-ra<}s33uu=Xq+SET>u#8^b{v*R@(0XO{gEF=uAE3i$7>)tn zFHcg4%v4ucp9yzpBw5MhK9ws6kFA zfDthN@4&-wMn!xYE#$sLme2$9Xhu4c6c7-oKC4<`n!r4cV+>^f9{T<+h643J$naE} diff --git a/lib/Font-Awesome/less/bordered-pulled.less b/lib/Font-Awesome/less/bordered-pulled.less index 0c90eb567..f1c8ad75f 100644 --- a/lib/Font-Awesome/less/bordered-pulled.less +++ b/lib/Font-Awesome/less/bordered-pulled.less @@ -7,6 +7,15 @@ border-radius: .1em; } +.@{fa-css-prefix}-pull-left { float: left; } +.@{fa-css-prefix}-pull-right { float: right; } + +.@{fa-css-prefix} { + &.@{fa-css-prefix}-pull-left { margin-right: .3em; } + &.@{fa-css-prefix}-pull-right { margin-left: .3em; } +} + +/* Deprecated as of 4.4.0 */ .pull-right { float: right; } .pull-left { float: left; } diff --git a/lib/Font-Awesome/less/core.less b/lib/Font-Awesome/less/core.less index f814f1e17..c577ac84a 100644 --- a/lib/Font-Awesome/less/core.less +++ b/lib/Font-Awesome/less/core.less @@ -3,11 +3,10 @@ .@{fa-css-prefix} { display: inline-block; - font: normal normal normal @fa-font-size-base/1 FontAwesome; // shortening font declaration + font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration font-size: inherit; // can't have font-size inherit on line above, so need to override text-rendering: auto; // optimizelegibility throws things off #1094 -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - transform: translate(0, 0); // ensures no half-pixel rendering in firefox } diff --git a/lib/Font-Awesome/less/font-awesome.less b/lib/Font-Awesome/less/font-awesome.less index 1f45c63d1..e3f89c8f6 100644 --- a/lib/Font-Awesome/less/font-awesome.less +++ b/lib/Font-Awesome/less/font-awesome.less @@ -1,5 +1,5 @@ /*! - * Font Awesome 4.3.0 by @davegandy - http://fontawesome.io - @fontawesome + * Font Awesome 4.4.0 by @davegandy - http://fontawesome.io - @fontawesome * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) */ diff --git a/lib/Font-Awesome/less/icons.less b/lib/Font-Awesome/less/icons.less index c265de5a6..6ebe9669e 100644 --- a/lib/Font-Awesome/less/icons.less +++ b/lib/Font-Awesome/less/icons.less @@ -163,6 +163,7 @@ .@{fa-css-prefix}-github:before { content: @fa-var-github; } .@{fa-css-prefix}-unlock:before { content: @fa-var-unlock; } .@{fa-css-prefix}-credit-card:before { content: @fa-var-credit-card; } +.@{fa-css-prefix}-feed:before, .@{fa-css-prefix}-rss:before { content: @fa-var-rss; } .@{fa-css-prefix}-hdd-o:before { content: @fa-var-hdd-o; } .@{fa-css-prefix}-bullhorn:before { content: @fa-var-bullhorn; } @@ -492,6 +493,8 @@ .@{fa-css-prefix}-empire:before { content: @fa-var-empire; } .@{fa-css-prefix}-git-square:before { content: @fa-var-git-square; } .@{fa-css-prefix}-git:before { content: @fa-var-git; } +.@{fa-css-prefix}-y-combinator-square:before, +.@{fa-css-prefix}-yc-square:before, .@{fa-css-prefix}-hacker-news:before { content: @fa-var-hacker-news; } .@{fa-css-prefix}-tencent-weibo:before { content: @fa-var-tencent-weibo; } .@{fa-css-prefix}-qq:before { content: @fa-var-qq; } @@ -502,7 +505,6 @@ .@{fa-css-prefix}-send-o:before, .@{fa-css-prefix}-paper-plane-o:before { content: @fa-var-paper-plane-o; } .@{fa-css-prefix}-history:before { content: @fa-var-history; } -.@{fa-css-prefix}-genderless:before, .@{fa-css-prefix}-circle-thin:before { content: @fa-var-circle-thin; } .@{fa-css-prefix}-header:before { content: @fa-var-header; } .@{fa-css-prefix}-paragraph:before { content: @fa-var-paragraph; } @@ -573,6 +575,7 @@ .@{fa-css-prefix}-venus:before { content: @fa-var-venus; } .@{fa-css-prefix}-mars:before { content: @fa-var-mars; } .@{fa-css-prefix}-mercury:before { content: @fa-var-mercury; } +.@{fa-css-prefix}-intersex:before, .@{fa-css-prefix}-transgender:before { content: @fa-var-transgender; } .@{fa-css-prefix}-transgender-alt:before { content: @fa-var-transgender-alt; } .@{fa-css-prefix}-venus-double:before { content: @fa-var-venus-double; } @@ -582,6 +585,7 @@ .@{fa-css-prefix}-mars-stroke-v:before { content: @fa-var-mars-stroke-v; } .@{fa-css-prefix}-mars-stroke-h:before { content: @fa-var-mars-stroke-h; } .@{fa-css-prefix}-neuter:before { content: @fa-var-neuter; } +.@{fa-css-prefix}-genderless:before { content: @fa-var-genderless; } .@{fa-css-prefix}-facebook-official:before { content: @fa-var-facebook-official; } .@{fa-css-prefix}-pinterest-p:before { content: @fa-var-pinterest-p; } .@{fa-css-prefix}-whatsapp:before { content: @fa-var-whatsapp; } @@ -594,3 +598,80 @@ .@{fa-css-prefix}-train:before { content: @fa-var-train; } .@{fa-css-prefix}-subway:before { content: @fa-var-subway; } .@{fa-css-prefix}-medium:before { content: @fa-var-medium; } +.@{fa-css-prefix}-yc:before, +.@{fa-css-prefix}-y-combinator:before { content: @fa-var-y-combinator; } +.@{fa-css-prefix}-optin-monster:before { content: @fa-var-optin-monster; } +.@{fa-css-prefix}-opencart:before { content: @fa-var-opencart; } +.@{fa-css-prefix}-expeditedssl:before { content: @fa-var-expeditedssl; } +.@{fa-css-prefix}-battery-4:before, +.@{fa-css-prefix}-battery-full:before { content: @fa-var-battery-full; } +.@{fa-css-prefix}-battery-3:before, +.@{fa-css-prefix}-battery-three-quarters:before { content: @fa-var-battery-three-quarters; } +.@{fa-css-prefix}-battery-2:before, +.@{fa-css-prefix}-battery-half:before { content: @fa-var-battery-half; } +.@{fa-css-prefix}-battery-1:before, +.@{fa-css-prefix}-battery-quarter:before { content: @fa-var-battery-quarter; } +.@{fa-css-prefix}-battery-0:before, +.@{fa-css-prefix}-battery-empty:before { content: @fa-var-battery-empty; } +.@{fa-css-prefix}-mouse-pointer:before { content: @fa-var-mouse-pointer; } +.@{fa-css-prefix}-i-cursor:before { content: @fa-var-i-cursor; } +.@{fa-css-prefix}-object-group:before { content: @fa-var-object-group; } +.@{fa-css-prefix}-object-ungroup:before { content: @fa-var-object-ungroup; } +.@{fa-css-prefix}-sticky-note:before { content: @fa-var-sticky-note; } +.@{fa-css-prefix}-sticky-note-o:before { content: @fa-var-sticky-note-o; } +.@{fa-css-prefix}-cc-jcb:before { content: @fa-var-cc-jcb; } +.@{fa-css-prefix}-cc-diners-club:before { content: @fa-var-cc-diners-club; } +.@{fa-css-prefix}-clone:before { content: @fa-var-clone; } +.@{fa-css-prefix}-balance-scale:before { content: @fa-var-balance-scale; } +.@{fa-css-prefix}-hourglass-o:before { content: @fa-var-hourglass-o; } +.@{fa-css-prefix}-hourglass-1:before, +.@{fa-css-prefix}-hourglass-start:before { content: @fa-var-hourglass-start; } +.@{fa-css-prefix}-hourglass-2:before, +.@{fa-css-prefix}-hourglass-half:before { content: @fa-var-hourglass-half; } +.@{fa-css-prefix}-hourglass-3:before, +.@{fa-css-prefix}-hourglass-end:before { content: @fa-var-hourglass-end; } +.@{fa-css-prefix}-hourglass:before { content: @fa-var-hourglass; } +.@{fa-css-prefix}-hand-grab-o:before, +.@{fa-css-prefix}-hand-rock-o:before { content: @fa-var-hand-rock-o; } +.@{fa-css-prefix}-hand-stop-o:before, +.@{fa-css-prefix}-hand-paper-o:before { content: @fa-var-hand-paper-o; } +.@{fa-css-prefix}-hand-scissors-o:before { content: @fa-var-hand-scissors-o; } +.@{fa-css-prefix}-hand-lizard-o:before { content: @fa-var-hand-lizard-o; } +.@{fa-css-prefix}-hand-spock-o:before { content: @fa-var-hand-spock-o; } +.@{fa-css-prefix}-hand-pointer-o:before { content: @fa-var-hand-pointer-o; } +.@{fa-css-prefix}-hand-peace-o:before { content: @fa-var-hand-peace-o; } +.@{fa-css-prefix}-trademark:before { content: @fa-var-trademark; } +.@{fa-css-prefix}-registered:before { content: @fa-var-registered; } +.@{fa-css-prefix}-creative-commons:before { content: @fa-var-creative-commons; } +.@{fa-css-prefix}-gg:before { content: @fa-var-gg; } +.@{fa-css-prefix}-gg-circle:before { content: @fa-var-gg-circle; } +.@{fa-css-prefix}-tripadvisor:before { content: @fa-var-tripadvisor; } +.@{fa-css-prefix}-odnoklassniki:before { content: @fa-var-odnoklassniki; } +.@{fa-css-prefix}-odnoklassniki-square:before { content: @fa-var-odnoklassniki-square; } +.@{fa-css-prefix}-get-pocket:before { content: @fa-var-get-pocket; } +.@{fa-css-prefix}-wikipedia-w:before { content: @fa-var-wikipedia-w; } +.@{fa-css-prefix}-safari:before { content: @fa-var-safari; } +.@{fa-css-prefix}-chrome:before { content: @fa-var-chrome; } +.@{fa-css-prefix}-firefox:before { content: @fa-var-firefox; } +.@{fa-css-prefix}-opera:before { content: @fa-var-opera; } +.@{fa-css-prefix}-internet-explorer:before { content: @fa-var-internet-explorer; } +.@{fa-css-prefix}-tv:before, +.@{fa-css-prefix}-television:before { content: @fa-var-television; } +.@{fa-css-prefix}-contao:before { content: @fa-var-contao; } +.@{fa-css-prefix}-500px:before { content: @fa-var-500px; } +.@{fa-css-prefix}-amazon:before { content: @fa-var-amazon; } +.@{fa-css-prefix}-calendar-plus-o:before { content: @fa-var-calendar-plus-o; } +.@{fa-css-prefix}-calendar-minus-o:before { content: @fa-var-calendar-minus-o; } +.@{fa-css-prefix}-calendar-times-o:before { content: @fa-var-calendar-times-o; } +.@{fa-css-prefix}-calendar-check-o:before { content: @fa-var-calendar-check-o; } +.@{fa-css-prefix}-industry:before { content: @fa-var-industry; } +.@{fa-css-prefix}-map-pin:before { content: @fa-var-map-pin; } +.@{fa-css-prefix}-map-signs:before { content: @fa-var-map-signs; } +.@{fa-css-prefix}-map-o:before { content: @fa-var-map-o; } +.@{fa-css-prefix}-map:before { content: @fa-var-map; } +.@{fa-css-prefix}-commenting:before { content: @fa-var-commenting; } +.@{fa-css-prefix}-commenting-o:before { content: @fa-var-commenting-o; } +.@{fa-css-prefix}-houzz:before { content: @fa-var-houzz; } +.@{fa-css-prefix}-vimeo:before { content: @fa-var-vimeo; } +.@{fa-css-prefix}-black-tie:before { content: @fa-var-black-tie; } +.@{fa-css-prefix}-fonticons:before { content: @fa-var-fonticons; } diff --git a/lib/Font-Awesome/less/mixins.less b/lib/Font-Awesome/less/mixins.less index c97f4604c..d5a43a145 100644 --- a/lib/Font-Awesome/less/mixins.less +++ b/lib/Font-Awesome/less/mixins.less @@ -3,12 +3,11 @@ .fa-icon() { display: inline-block; - font: normal normal normal @fa-font-size-base/1 FontAwesome; // shortening font declaration + font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration font-size: inherit; // can't have font-size inherit on line above, so need to override text-rendering: auto; // optimizelegibility throws things off #1094 -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - transform: translate(0, 0); // ensures no half-pixel rendering in firefox } diff --git a/lib/Font-Awesome/less/variables.less b/lib/Font-Awesome/less/variables.less index d526064c8..00418e757 100644 --- a/lib/Font-Awesome/less/variables.less +++ b/lib/Font-Awesome/less/variables.less @@ -3,19 +3,22 @@ @fa-font-path: "../fonts"; @fa-font-size-base: 14px; -//@fa-font-path: "//netdna.bootstrapcdn.com/font-awesome/4.3.0/fonts"; // for referencing Bootstrap CDN font files directly +@fa-line-height-base: 1; +//@fa-font-path: "//netdna.bootstrapcdn.com/font-awesome/4.4.0/fonts"; // for referencing Bootstrap CDN font files directly @fa-css-prefix: fa; -@fa-version: "4.3.0"; +@fa-version: "4.4.0"; @fa-border-color: #eee; @fa-inverse: #fff; @fa-li-width: (30em / 14); +@fa-var-500px: "\f26e"; @fa-var-adjust: "\f042"; @fa-var-adn: "\f170"; @fa-var-align-center: "\f037"; @fa-var-align-justify: "\f039"; @fa-var-align-left: "\f036"; @fa-var-align-right: "\f038"; +@fa-var-amazon: "\f270"; @fa-var-ambulance: "\f0f9"; @fa-var-anchor: "\f13d"; @fa-var-android: "\f17b"; @@ -51,12 +54,23 @@ @fa-var-at: "\f1fa"; @fa-var-automobile: "\f1b9"; @fa-var-backward: "\f04a"; +@fa-var-balance-scale: "\f24e"; @fa-var-ban: "\f05e"; @fa-var-bank: "\f19c"; @fa-var-bar-chart: "\f080"; @fa-var-bar-chart-o: "\f080"; @fa-var-barcode: "\f02a"; @fa-var-bars: "\f0c9"; +@fa-var-battery-0: "\f244"; +@fa-var-battery-1: "\f243"; +@fa-var-battery-2: "\f242"; +@fa-var-battery-3: "\f241"; +@fa-var-battery-4: "\f240"; +@fa-var-battery-empty: "\f244"; +@fa-var-battery-full: "\f240"; +@fa-var-battery-half: "\f242"; +@fa-var-battery-quarter: "\f243"; +@fa-var-battery-three-quarters: "\f241"; @fa-var-bed: "\f236"; @fa-var-beer: "\f0fc"; @fa-var-behance: "\f1b4"; @@ -71,6 +85,7 @@ @fa-var-bitbucket: "\f171"; @fa-var-bitbucket-square: "\f172"; @fa-var-bitcoin: "\f15a"; +@fa-var-black-tie: "\f27e"; @fa-var-bold: "\f032"; @fa-var-bolt: "\f0e7"; @fa-var-bomb: "\f1e2"; @@ -89,7 +104,11 @@ @fa-var-cab: "\f1ba"; @fa-var-calculator: "\f1ec"; @fa-var-calendar: "\f073"; +@fa-var-calendar-check-o: "\f274"; +@fa-var-calendar-minus-o: "\f272"; @fa-var-calendar-o: "\f133"; +@fa-var-calendar-plus-o: "\f271"; +@fa-var-calendar-times-o: "\f273"; @fa-var-camera: "\f030"; @fa-var-camera-retro: "\f083"; @fa-var-car: "\f1b9"; @@ -105,7 +124,9 @@ @fa-var-cart-plus: "\f217"; @fa-var-cc: "\f20a"; @fa-var-cc-amex: "\f1f3"; +@fa-var-cc-diners-club: "\f24c"; @fa-var-cc-discover: "\f1f2"; +@fa-var-cc-jcb: "\f24b"; @fa-var-cc-mastercard: "\f1f1"; @fa-var-cc-paypal: "\f1f4"; @fa-var-cc-stripe: "\f1f5"; @@ -127,12 +148,14 @@ @fa-var-chevron-right: "\f054"; @fa-var-chevron-up: "\f077"; @fa-var-child: "\f1ae"; +@fa-var-chrome: "\f268"; @fa-var-circle: "\f111"; @fa-var-circle-o: "\f10c"; @fa-var-circle-o-notch: "\f1ce"; @fa-var-circle-thin: "\f1db"; @fa-var-clipboard: "\f0ea"; @fa-var-clock-o: "\f017"; +@fa-var-clone: "\f24d"; @fa-var-close: "\f00d"; @fa-var-cloud: "\f0c2"; @fa-var-cloud-download: "\f0ed"; @@ -147,13 +170,17 @@ @fa-var-columns: "\f0db"; @fa-var-comment: "\f075"; @fa-var-comment-o: "\f0e5"; +@fa-var-commenting: "\f27a"; +@fa-var-commenting-o: "\f27b"; @fa-var-comments: "\f086"; @fa-var-comments-o: "\f0e6"; @fa-var-compass: "\f14e"; @fa-var-compress: "\f066"; @fa-var-connectdevelop: "\f20e"; +@fa-var-contao: "\f26d"; @fa-var-copy: "\f0c5"; @fa-var-copyright: "\f1f9"; +@fa-var-creative-commons: "\f25e"; @fa-var-credit-card: "\f09d"; @fa-var-crop: "\f125"; @fa-var-crosshairs: "\f05b"; @@ -193,6 +220,7 @@ @fa-var-exclamation-circle: "\f06a"; @fa-var-exclamation-triangle: "\f071"; @fa-var-expand: "\f065"; +@fa-var-expeditedssl: "\f23e"; @fa-var-external-link: "\f08e"; @fa-var-external-link-square: "\f14c"; @fa-var-eye: "\f06e"; @@ -205,6 +233,7 @@ @fa-var-fast-backward: "\f049"; @fa-var-fast-forward: "\f050"; @fa-var-fax: "\f1ac"; +@fa-var-feed: "\f09e"; @fa-var-female: "\f182"; @fa-var-fighter-jet: "\f0fb"; @fa-var-file: "\f15b"; @@ -230,6 +259,7 @@ @fa-var-filter: "\f0b0"; @fa-var-fire: "\f06d"; @fa-var-fire-extinguisher: "\f134"; +@fa-var-firefox: "\f269"; @fa-var-flag: "\f024"; @fa-var-flag-checkered: "\f11e"; @fa-var-flag-o: "\f11d"; @@ -242,6 +272,7 @@ @fa-var-folder-open: "\f07c"; @fa-var-folder-open-o: "\f115"; @fa-var-font: "\f031"; +@fa-var-fonticons: "\f280"; @fa-var-forumbee: "\f211"; @fa-var-forward: "\f04e"; @fa-var-foursquare: "\f180"; @@ -253,7 +284,10 @@ @fa-var-ge: "\f1d1"; @fa-var-gear: "\f013"; @fa-var-gears: "\f085"; -@fa-var-genderless: "\f1db"; +@fa-var-genderless: "\f22d"; +@fa-var-get-pocket: "\f265"; +@fa-var-gg: "\f260"; +@fa-var-gg-circle: "\f261"; @fa-var-gift: "\f06b"; @fa-var-git: "\f1d3"; @fa-var-git-square: "\f1d2"; @@ -272,10 +306,19 @@ @fa-var-group: "\f0c0"; @fa-var-h-square: "\f0fd"; @fa-var-hacker-news: "\f1d4"; +@fa-var-hand-grab-o: "\f255"; +@fa-var-hand-lizard-o: "\f258"; @fa-var-hand-o-down: "\f0a7"; @fa-var-hand-o-left: "\f0a5"; @fa-var-hand-o-right: "\f0a4"; @fa-var-hand-o-up: "\f0a6"; +@fa-var-hand-paper-o: "\f256"; +@fa-var-hand-peace-o: "\f25b"; +@fa-var-hand-pointer-o: "\f25a"; +@fa-var-hand-rock-o: "\f255"; +@fa-var-hand-scissors-o: "\f257"; +@fa-var-hand-spock-o: "\f259"; +@fa-var-hand-stop-o: "\f256"; @fa-var-hdd-o: "\f0a0"; @fa-var-header: "\f1dc"; @fa-var-headphones: "\f025"; @@ -286,16 +329,29 @@ @fa-var-home: "\f015"; @fa-var-hospital-o: "\f0f8"; @fa-var-hotel: "\f236"; +@fa-var-hourglass: "\f254"; +@fa-var-hourglass-1: "\f251"; +@fa-var-hourglass-2: "\f252"; +@fa-var-hourglass-3: "\f253"; +@fa-var-hourglass-end: "\f253"; +@fa-var-hourglass-half: "\f252"; +@fa-var-hourglass-o: "\f250"; +@fa-var-hourglass-start: "\f251"; +@fa-var-houzz: "\f27c"; @fa-var-html5: "\f13b"; +@fa-var-i-cursor: "\f246"; @fa-var-ils: "\f20b"; @fa-var-image: "\f03e"; @fa-var-inbox: "\f01c"; @fa-var-indent: "\f03c"; +@fa-var-industry: "\f275"; @fa-var-info: "\f129"; @fa-var-info-circle: "\f05a"; @fa-var-inr: "\f156"; @fa-var-instagram: "\f16d"; @fa-var-institution: "\f19c"; +@fa-var-internet-explorer: "\f26b"; +@fa-var-intersex: "\f224"; @fa-var-ioxhost: "\f208"; @fa-var-italic: "\f033"; @fa-var-joomla: "\f1aa"; @@ -340,7 +396,11 @@ @fa-var-mail-reply: "\f112"; @fa-var-mail-reply-all: "\f122"; @fa-var-male: "\f183"; +@fa-var-map: "\f279"; @fa-var-map-marker: "\f041"; +@fa-var-map-o: "\f278"; +@fa-var-map-pin: "\f276"; +@fa-var-map-signs: "\f277"; @fa-var-mars: "\f222"; @fa-var-mars-double: "\f227"; @fa-var-mars-stroke: "\f229"; @@ -364,11 +424,19 @@ @fa-var-moon-o: "\f186"; @fa-var-mortar-board: "\f19d"; @fa-var-motorcycle: "\f21c"; +@fa-var-mouse-pointer: "\f245"; @fa-var-music: "\f001"; @fa-var-navicon: "\f0c9"; @fa-var-neuter: "\f22c"; @fa-var-newspaper-o: "\f1ea"; +@fa-var-object-group: "\f247"; +@fa-var-object-ungroup: "\f248"; +@fa-var-odnoklassniki: "\f263"; +@fa-var-odnoklassniki-square: "\f264"; +@fa-var-opencart: "\f23d"; @fa-var-openid: "\f19b"; +@fa-var-opera: "\f26a"; +@fa-var-optin-monster: "\f23c"; @fa-var-outdent: "\f03b"; @fa-var-pagelines: "\f18c"; @fa-var-paint-brush: "\f1fc"; @@ -418,6 +486,7 @@ @fa-var-reddit: "\f1a1"; @fa-var-reddit-square: "\f1a2"; @fa-var-refresh: "\f021"; +@fa-var-registered: "\f25d"; @fa-var-remove: "\f00d"; @fa-var-renren: "\f18b"; @fa-var-reorder: "\f0c9"; @@ -436,6 +505,7 @@ @fa-var-rub: "\f158"; @fa-var-ruble: "\f158"; @fa-var-rupee: "\f156"; +@fa-var-safari: "\f267"; @fa-var-save: "\f0c7"; @fa-var-scissors: "\f0c4"; @fa-var-search: "\f002"; @@ -499,6 +569,8 @@ @fa-var-step-backward: "\f048"; @fa-var-step-forward: "\f051"; @fa-var-stethoscope: "\f0f1"; +@fa-var-sticky-note: "\f249"; +@fa-var-sticky-note-o: "\f24a"; @fa-var-stop: "\f04d"; @fa-var-street-view: "\f21d"; @fa-var-strikethrough: "\f0cc"; @@ -517,6 +589,7 @@ @fa-var-tags: "\f02c"; @fa-var-tasks: "\f0ae"; @fa-var-taxi: "\f1ba"; +@fa-var-television: "\f26c"; @fa-var-tencent-weibo: "\f1d5"; @fa-var-terminal: "\f120"; @fa-var-text-height: "\f034"; @@ -540,6 +613,7 @@ @fa-var-toggle-on: "\f205"; @fa-var-toggle-right: "\f152"; @fa-var-toggle-up: "\f151"; +@fa-var-trademark: "\f25c"; @fa-var-train: "\f238"; @fa-var-transgender: "\f224"; @fa-var-transgender-alt: "\f225"; @@ -547,6 +621,7 @@ @fa-var-trash-o: "\f014"; @fa-var-tree: "\f1bb"; @fa-var-trello: "\f181"; +@fa-var-tripadvisor: "\f262"; @fa-var-trophy: "\f091"; @fa-var-truck: "\f0d1"; @fa-var-try: "\f195"; @@ -554,6 +629,7 @@ @fa-var-tumblr: "\f173"; @fa-var-tumblr-square: "\f174"; @fa-var-turkish-lira: "\f195"; +@fa-var-tv: "\f26c"; @fa-var-twitch: "\f1e8"; @fa-var-twitter: "\f099"; @fa-var-twitter-square: "\f081"; @@ -578,6 +654,7 @@ @fa-var-venus-mars: "\f228"; @fa-var-viacoin: "\f237"; @fa-var-video-camera: "\f03d"; +@fa-var-vimeo: "\f27d"; @fa-var-vimeo-square: "\f194"; @fa-var-vine: "\f1ca"; @fa-var-vk: "\f189"; @@ -591,13 +668,18 @@ @fa-var-whatsapp: "\f232"; @fa-var-wheelchair: "\f193"; @fa-var-wifi: "\f1eb"; +@fa-var-wikipedia-w: "\f266"; @fa-var-windows: "\f17a"; @fa-var-won: "\f159"; @fa-var-wordpress: "\f19a"; @fa-var-wrench: "\f0ad"; @fa-var-xing: "\f168"; @fa-var-xing-square: "\f169"; +@fa-var-y-combinator: "\f23b"; +@fa-var-y-combinator-square: "\f1d4"; @fa-var-yahoo: "\f19e"; +@fa-var-yc: "\f23b"; +@fa-var-yc-square: "\f1d4"; @fa-var-yelp: "\f1e9"; @fa-var-yen: "\f157"; @fa-var-youtube: "\f167"; diff --git a/lib/Font-Awesome/package.json b/lib/Font-Awesome/package.json index 6f98fe45a..bd1c19732 100644 --- a/lib/Font-Awesome/package.json +++ b/lib/Font-Awesome/package.json @@ -1,7 +1,8 @@ { "name": "font-awesome", "description": "The iconic font and CSS framework", - "version": "4.3.0", + "version": "4.4.0", + "style": "css/font-awesome.css", "keywords": ["font", "awesome", "fontawesome", "icon", "font", "bootstrap"], "homepage": "http://fontawesome.io/", "bugs": { @@ -30,16 +31,7 @@ "web": "http://twitter.com/supercodepoet" } ], - "licenses": [ - { - "type": "OFL-1.1", - "url": "http://scripts.sil.org/OFL" - }, - { - "type": "MIT", - "url": "http://opensource.org/licenses/mit-license.html" - } - ], + "license": "OFL-1.1 AND MIT", "dependencies": { }, "engines" : { diff --git a/lib/Font-Awesome/scss/_bordered-pulled.scss b/lib/Font-Awesome/scss/_bordered-pulled.scss index 9d3fdf3a0..d4b85a02f 100644 --- a/lib/Font-Awesome/scss/_bordered-pulled.scss +++ b/lib/Font-Awesome/scss/_bordered-pulled.scss @@ -7,6 +7,15 @@ border-radius: .1em; } +.#{$fa-css-prefix}-pull-left { float: left; } +.#{$fa-css-prefix}-pull-right { float: right; } + +.#{$fa-css-prefix} { + &.#{$fa-css-prefix}-pull-left { margin-right: .3em; } + &.#{$fa-css-prefix}-pull-right { margin-left: .3em; } +} + +/* Deprecated as of 4.4.0 */ .pull-right { float: right; } .pull-left { float: left; } diff --git a/lib/Font-Awesome/scss/_core.scss b/lib/Font-Awesome/scss/_core.scss index 5a2db9d56..7425ef85f 100644 --- a/lib/Font-Awesome/scss/_core.scss +++ b/lib/Font-Awesome/scss/_core.scss @@ -3,11 +3,10 @@ .#{$fa-css-prefix} { display: inline-block; - font: normal normal normal #{$fa-font-size-base}/1 FontAwesome; // shortening font declaration + font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration font-size: inherit; // can't have font-size inherit on line above, so need to override text-rendering: auto; // optimizelegibility throws things off #1094 -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - transform: translate(0, 0); // ensures no half-pixel rendering in firefox } diff --git a/lib/Font-Awesome/scss/_icons.scss b/lib/Font-Awesome/scss/_icons.scss index fbcfe8123..62d97677c 100644 --- a/lib/Font-Awesome/scss/_icons.scss +++ b/lib/Font-Awesome/scss/_icons.scss @@ -163,6 +163,7 @@ .#{$fa-css-prefix}-github:before { content: $fa-var-github; } .#{$fa-css-prefix}-unlock:before { content: $fa-var-unlock; } .#{$fa-css-prefix}-credit-card:before { content: $fa-var-credit-card; } +.#{$fa-css-prefix}-feed:before, .#{$fa-css-prefix}-rss:before { content: $fa-var-rss; } .#{$fa-css-prefix}-hdd-o:before { content: $fa-var-hdd-o; } .#{$fa-css-prefix}-bullhorn:before { content: $fa-var-bullhorn; } @@ -492,6 +493,8 @@ .#{$fa-css-prefix}-empire:before { content: $fa-var-empire; } .#{$fa-css-prefix}-git-square:before { content: $fa-var-git-square; } .#{$fa-css-prefix}-git:before { content: $fa-var-git; } +.#{$fa-css-prefix}-y-combinator-square:before, +.#{$fa-css-prefix}-yc-square:before, .#{$fa-css-prefix}-hacker-news:before { content: $fa-var-hacker-news; } .#{$fa-css-prefix}-tencent-weibo:before { content: $fa-var-tencent-weibo; } .#{$fa-css-prefix}-qq:before { content: $fa-var-qq; } @@ -502,7 +505,6 @@ .#{$fa-css-prefix}-send-o:before, .#{$fa-css-prefix}-paper-plane-o:before { content: $fa-var-paper-plane-o; } .#{$fa-css-prefix}-history:before { content: $fa-var-history; } -.#{$fa-css-prefix}-genderless:before, .#{$fa-css-prefix}-circle-thin:before { content: $fa-var-circle-thin; } .#{$fa-css-prefix}-header:before { content: $fa-var-header; } .#{$fa-css-prefix}-paragraph:before { content: $fa-var-paragraph; } @@ -573,6 +575,7 @@ .#{$fa-css-prefix}-venus:before { content: $fa-var-venus; } .#{$fa-css-prefix}-mars:before { content: $fa-var-mars; } .#{$fa-css-prefix}-mercury:before { content: $fa-var-mercury; } +.#{$fa-css-prefix}-intersex:before, .#{$fa-css-prefix}-transgender:before { content: $fa-var-transgender; } .#{$fa-css-prefix}-transgender-alt:before { content: $fa-var-transgender-alt; } .#{$fa-css-prefix}-venus-double:before { content: $fa-var-venus-double; } @@ -582,6 +585,7 @@ .#{$fa-css-prefix}-mars-stroke-v:before { content: $fa-var-mars-stroke-v; } .#{$fa-css-prefix}-mars-stroke-h:before { content: $fa-var-mars-stroke-h; } .#{$fa-css-prefix}-neuter:before { content: $fa-var-neuter; } +.#{$fa-css-prefix}-genderless:before { content: $fa-var-genderless; } .#{$fa-css-prefix}-facebook-official:before { content: $fa-var-facebook-official; } .#{$fa-css-prefix}-pinterest-p:before { content: $fa-var-pinterest-p; } .#{$fa-css-prefix}-whatsapp:before { content: $fa-var-whatsapp; } @@ -594,3 +598,80 @@ .#{$fa-css-prefix}-train:before { content: $fa-var-train; } .#{$fa-css-prefix}-subway:before { content: $fa-var-subway; } .#{$fa-css-prefix}-medium:before { content: $fa-var-medium; } +.#{$fa-css-prefix}-yc:before, +.#{$fa-css-prefix}-y-combinator:before { content: $fa-var-y-combinator; } +.#{$fa-css-prefix}-optin-monster:before { content: $fa-var-optin-monster; } +.#{$fa-css-prefix}-opencart:before { content: $fa-var-opencart; } +.#{$fa-css-prefix}-expeditedssl:before { content: $fa-var-expeditedssl; } +.#{$fa-css-prefix}-battery-4:before, +.#{$fa-css-prefix}-battery-full:before { content: $fa-var-battery-full; } +.#{$fa-css-prefix}-battery-3:before, +.#{$fa-css-prefix}-battery-three-quarters:before { content: $fa-var-battery-three-quarters; } +.#{$fa-css-prefix}-battery-2:before, +.#{$fa-css-prefix}-battery-half:before { content: $fa-var-battery-half; } +.#{$fa-css-prefix}-battery-1:before, +.#{$fa-css-prefix}-battery-quarter:before { content: $fa-var-battery-quarter; } +.#{$fa-css-prefix}-battery-0:before, +.#{$fa-css-prefix}-battery-empty:before { content: $fa-var-battery-empty; } +.#{$fa-css-prefix}-mouse-pointer:before { content: $fa-var-mouse-pointer; } +.#{$fa-css-prefix}-i-cursor:before { content: $fa-var-i-cursor; } +.#{$fa-css-prefix}-object-group:before { content: $fa-var-object-group; } +.#{$fa-css-prefix}-object-ungroup:before { content: $fa-var-object-ungroup; } +.#{$fa-css-prefix}-sticky-note:before { content: $fa-var-sticky-note; } +.#{$fa-css-prefix}-sticky-note-o:before { content: $fa-var-sticky-note-o; } +.#{$fa-css-prefix}-cc-jcb:before { content: $fa-var-cc-jcb; } +.#{$fa-css-prefix}-cc-diners-club:before { content: $fa-var-cc-diners-club; } +.#{$fa-css-prefix}-clone:before { content: $fa-var-clone; } +.#{$fa-css-prefix}-balance-scale:before { content: $fa-var-balance-scale; } +.#{$fa-css-prefix}-hourglass-o:before { content: $fa-var-hourglass-o; } +.#{$fa-css-prefix}-hourglass-1:before, +.#{$fa-css-prefix}-hourglass-start:before { content: $fa-var-hourglass-start; } +.#{$fa-css-prefix}-hourglass-2:before, +.#{$fa-css-prefix}-hourglass-half:before { content: $fa-var-hourglass-half; } +.#{$fa-css-prefix}-hourglass-3:before, +.#{$fa-css-prefix}-hourglass-end:before { content: $fa-var-hourglass-end; } +.#{$fa-css-prefix}-hourglass:before { content: $fa-var-hourglass; } +.#{$fa-css-prefix}-hand-grab-o:before, +.#{$fa-css-prefix}-hand-rock-o:before { content: $fa-var-hand-rock-o; } +.#{$fa-css-prefix}-hand-stop-o:before, +.#{$fa-css-prefix}-hand-paper-o:before { content: $fa-var-hand-paper-o; } +.#{$fa-css-prefix}-hand-scissors-o:before { content: $fa-var-hand-scissors-o; } +.#{$fa-css-prefix}-hand-lizard-o:before { content: $fa-var-hand-lizard-o; } +.#{$fa-css-prefix}-hand-spock-o:before { content: $fa-var-hand-spock-o; } +.#{$fa-css-prefix}-hand-pointer-o:before { content: $fa-var-hand-pointer-o; } +.#{$fa-css-prefix}-hand-peace-o:before { content: $fa-var-hand-peace-o; } +.#{$fa-css-prefix}-trademark:before { content: $fa-var-trademark; } +.#{$fa-css-prefix}-registered:before { content: $fa-var-registered; } +.#{$fa-css-prefix}-creative-commons:before { content: $fa-var-creative-commons; } +.#{$fa-css-prefix}-gg:before { content: $fa-var-gg; } +.#{$fa-css-prefix}-gg-circle:before { content: $fa-var-gg-circle; } +.#{$fa-css-prefix}-tripadvisor:before { content: $fa-var-tripadvisor; } +.#{$fa-css-prefix}-odnoklassniki:before { content: $fa-var-odnoklassniki; } +.#{$fa-css-prefix}-odnoklassniki-square:before { content: $fa-var-odnoklassniki-square; } +.#{$fa-css-prefix}-get-pocket:before { content: $fa-var-get-pocket; } +.#{$fa-css-prefix}-wikipedia-w:before { content: $fa-var-wikipedia-w; } +.#{$fa-css-prefix}-safari:before { content: $fa-var-safari; } +.#{$fa-css-prefix}-chrome:before { content: $fa-var-chrome; } +.#{$fa-css-prefix}-firefox:before { content: $fa-var-firefox; } +.#{$fa-css-prefix}-opera:before { content: $fa-var-opera; } +.#{$fa-css-prefix}-internet-explorer:before { content: $fa-var-internet-explorer; } +.#{$fa-css-prefix}-tv:before, +.#{$fa-css-prefix}-television:before { content: $fa-var-television; } +.#{$fa-css-prefix}-contao:before { content: $fa-var-contao; } +.#{$fa-css-prefix}-500px:before { content: $fa-var-500px; } +.#{$fa-css-prefix}-amazon:before { content: $fa-var-amazon; } +.#{$fa-css-prefix}-calendar-plus-o:before { content: $fa-var-calendar-plus-o; } +.#{$fa-css-prefix}-calendar-minus-o:before { content: $fa-var-calendar-minus-o; } +.#{$fa-css-prefix}-calendar-times-o:before { content: $fa-var-calendar-times-o; } +.#{$fa-css-prefix}-calendar-check-o:before { content: $fa-var-calendar-check-o; } +.#{$fa-css-prefix}-industry:before { content: $fa-var-industry; } +.#{$fa-css-prefix}-map-pin:before { content: $fa-var-map-pin; } +.#{$fa-css-prefix}-map-signs:before { content: $fa-var-map-signs; } +.#{$fa-css-prefix}-map-o:before { content: $fa-var-map-o; } +.#{$fa-css-prefix}-map:before { content: $fa-var-map; } +.#{$fa-css-prefix}-commenting:before { content: $fa-var-commenting; } +.#{$fa-css-prefix}-commenting-o:before { content: $fa-var-commenting-o; } +.#{$fa-css-prefix}-houzz:before { content: $fa-var-houzz; } +.#{$fa-css-prefix}-vimeo:before { content: $fa-var-vimeo; } +.#{$fa-css-prefix}-black-tie:before { content: $fa-var-black-tie; } +.#{$fa-css-prefix}-fonticons:before { content: $fa-var-fonticons; } diff --git a/lib/Font-Awesome/scss/_mixins.scss b/lib/Font-Awesome/scss/_mixins.scss index 6b7f16093..f96719b6a 100644 --- a/lib/Font-Awesome/scss/_mixins.scss +++ b/lib/Font-Awesome/scss/_mixins.scss @@ -3,12 +3,11 @@ @mixin fa-icon() { display: inline-block; - font: normal normal normal #{$fa-font-size-base}/1 FontAwesome; // shortening font declaration + font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration font-size: inherit; // can't have font-size inherit on line above, so need to override text-rendering: auto; // optimizelegibility throws things off #1094 -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - transform: translate(0, 0); // ensures no half-pixel rendering in firefox } diff --git a/lib/Font-Awesome/scss/_variables.scss b/lib/Font-Awesome/scss/_variables.scss index 9b7210e23..c10cd47f7 100644 --- a/lib/Font-Awesome/scss/_variables.scss +++ b/lib/Font-Awesome/scss/_variables.scss @@ -3,19 +3,22 @@ $fa-font-path: "../fonts" !default; $fa-font-size-base: 14px !default; -//$fa-font-path: "//netdna.bootstrapcdn.com/font-awesome/4.3.0/fonts" !default; // for referencing Bootstrap CDN font files directly +$fa-line-height-base: 1 !default; +//$fa-font-path: "//netdna.bootstrapcdn.com/font-awesome/4.4.0/fonts" !default; // for referencing Bootstrap CDN font files directly $fa-css-prefix: fa !default; -$fa-version: "4.3.0" !default; +$fa-version: "4.4.0" !default; $fa-border-color: #eee !default; $fa-inverse: #fff !default; $fa-li-width: (30em / 14) !default; +$fa-var-500px: "\f26e"; $fa-var-adjust: "\f042"; $fa-var-adn: "\f170"; $fa-var-align-center: "\f037"; $fa-var-align-justify: "\f039"; $fa-var-align-left: "\f036"; $fa-var-align-right: "\f038"; +$fa-var-amazon: "\f270"; $fa-var-ambulance: "\f0f9"; $fa-var-anchor: "\f13d"; $fa-var-android: "\f17b"; @@ -51,12 +54,23 @@ $fa-var-asterisk: "\f069"; $fa-var-at: "\f1fa"; $fa-var-automobile: "\f1b9"; $fa-var-backward: "\f04a"; +$fa-var-balance-scale: "\f24e"; $fa-var-ban: "\f05e"; $fa-var-bank: "\f19c"; $fa-var-bar-chart: "\f080"; $fa-var-bar-chart-o: "\f080"; $fa-var-barcode: "\f02a"; $fa-var-bars: "\f0c9"; +$fa-var-battery-0: "\f244"; +$fa-var-battery-1: "\f243"; +$fa-var-battery-2: "\f242"; +$fa-var-battery-3: "\f241"; +$fa-var-battery-4: "\f240"; +$fa-var-battery-empty: "\f244"; +$fa-var-battery-full: "\f240"; +$fa-var-battery-half: "\f242"; +$fa-var-battery-quarter: "\f243"; +$fa-var-battery-three-quarters: "\f241"; $fa-var-bed: "\f236"; $fa-var-beer: "\f0fc"; $fa-var-behance: "\f1b4"; @@ -71,6 +85,7 @@ $fa-var-birthday-cake: "\f1fd"; $fa-var-bitbucket: "\f171"; $fa-var-bitbucket-square: "\f172"; $fa-var-bitcoin: "\f15a"; +$fa-var-black-tie: "\f27e"; $fa-var-bold: "\f032"; $fa-var-bolt: "\f0e7"; $fa-var-bomb: "\f1e2"; @@ -89,7 +104,11 @@ $fa-var-buysellads: "\f20d"; $fa-var-cab: "\f1ba"; $fa-var-calculator: "\f1ec"; $fa-var-calendar: "\f073"; +$fa-var-calendar-check-o: "\f274"; +$fa-var-calendar-minus-o: "\f272"; $fa-var-calendar-o: "\f133"; +$fa-var-calendar-plus-o: "\f271"; +$fa-var-calendar-times-o: "\f273"; $fa-var-camera: "\f030"; $fa-var-camera-retro: "\f083"; $fa-var-car: "\f1b9"; @@ -105,7 +124,9 @@ $fa-var-cart-arrow-down: "\f218"; $fa-var-cart-plus: "\f217"; $fa-var-cc: "\f20a"; $fa-var-cc-amex: "\f1f3"; +$fa-var-cc-diners-club: "\f24c"; $fa-var-cc-discover: "\f1f2"; +$fa-var-cc-jcb: "\f24b"; $fa-var-cc-mastercard: "\f1f1"; $fa-var-cc-paypal: "\f1f4"; $fa-var-cc-stripe: "\f1f5"; @@ -127,12 +148,14 @@ $fa-var-chevron-left: "\f053"; $fa-var-chevron-right: "\f054"; $fa-var-chevron-up: "\f077"; $fa-var-child: "\f1ae"; +$fa-var-chrome: "\f268"; $fa-var-circle: "\f111"; $fa-var-circle-o: "\f10c"; $fa-var-circle-o-notch: "\f1ce"; $fa-var-circle-thin: "\f1db"; $fa-var-clipboard: "\f0ea"; $fa-var-clock-o: "\f017"; +$fa-var-clone: "\f24d"; $fa-var-close: "\f00d"; $fa-var-cloud: "\f0c2"; $fa-var-cloud-download: "\f0ed"; @@ -147,13 +170,17 @@ $fa-var-cogs: "\f085"; $fa-var-columns: "\f0db"; $fa-var-comment: "\f075"; $fa-var-comment-o: "\f0e5"; +$fa-var-commenting: "\f27a"; +$fa-var-commenting-o: "\f27b"; $fa-var-comments: "\f086"; $fa-var-comments-o: "\f0e6"; $fa-var-compass: "\f14e"; $fa-var-compress: "\f066"; $fa-var-connectdevelop: "\f20e"; +$fa-var-contao: "\f26d"; $fa-var-copy: "\f0c5"; $fa-var-copyright: "\f1f9"; +$fa-var-creative-commons: "\f25e"; $fa-var-credit-card: "\f09d"; $fa-var-crop: "\f125"; $fa-var-crosshairs: "\f05b"; @@ -193,6 +220,7 @@ $fa-var-exclamation: "\f12a"; $fa-var-exclamation-circle: "\f06a"; $fa-var-exclamation-triangle: "\f071"; $fa-var-expand: "\f065"; +$fa-var-expeditedssl: "\f23e"; $fa-var-external-link: "\f08e"; $fa-var-external-link-square: "\f14c"; $fa-var-eye: "\f06e"; @@ -205,6 +233,7 @@ $fa-var-facebook-square: "\f082"; $fa-var-fast-backward: "\f049"; $fa-var-fast-forward: "\f050"; $fa-var-fax: "\f1ac"; +$fa-var-feed: "\f09e"; $fa-var-female: "\f182"; $fa-var-fighter-jet: "\f0fb"; $fa-var-file: "\f15b"; @@ -230,6 +259,7 @@ $fa-var-film: "\f008"; $fa-var-filter: "\f0b0"; $fa-var-fire: "\f06d"; $fa-var-fire-extinguisher: "\f134"; +$fa-var-firefox: "\f269"; $fa-var-flag: "\f024"; $fa-var-flag-checkered: "\f11e"; $fa-var-flag-o: "\f11d"; @@ -242,6 +272,7 @@ $fa-var-folder-o: "\f114"; $fa-var-folder-open: "\f07c"; $fa-var-folder-open-o: "\f115"; $fa-var-font: "\f031"; +$fa-var-fonticons: "\f280"; $fa-var-forumbee: "\f211"; $fa-var-forward: "\f04e"; $fa-var-foursquare: "\f180"; @@ -253,7 +284,10 @@ $fa-var-gbp: "\f154"; $fa-var-ge: "\f1d1"; $fa-var-gear: "\f013"; $fa-var-gears: "\f085"; -$fa-var-genderless: "\f1db"; +$fa-var-genderless: "\f22d"; +$fa-var-get-pocket: "\f265"; +$fa-var-gg: "\f260"; +$fa-var-gg-circle: "\f261"; $fa-var-gift: "\f06b"; $fa-var-git: "\f1d3"; $fa-var-git-square: "\f1d2"; @@ -272,10 +306,19 @@ $fa-var-gratipay: "\f184"; $fa-var-group: "\f0c0"; $fa-var-h-square: "\f0fd"; $fa-var-hacker-news: "\f1d4"; +$fa-var-hand-grab-o: "\f255"; +$fa-var-hand-lizard-o: "\f258"; $fa-var-hand-o-down: "\f0a7"; $fa-var-hand-o-left: "\f0a5"; $fa-var-hand-o-right: "\f0a4"; $fa-var-hand-o-up: "\f0a6"; +$fa-var-hand-paper-o: "\f256"; +$fa-var-hand-peace-o: "\f25b"; +$fa-var-hand-pointer-o: "\f25a"; +$fa-var-hand-rock-o: "\f255"; +$fa-var-hand-scissors-o: "\f257"; +$fa-var-hand-spock-o: "\f259"; +$fa-var-hand-stop-o: "\f256"; $fa-var-hdd-o: "\f0a0"; $fa-var-header: "\f1dc"; $fa-var-headphones: "\f025"; @@ -286,16 +329,29 @@ $fa-var-history: "\f1da"; $fa-var-home: "\f015"; $fa-var-hospital-o: "\f0f8"; $fa-var-hotel: "\f236"; +$fa-var-hourglass: "\f254"; +$fa-var-hourglass-1: "\f251"; +$fa-var-hourglass-2: "\f252"; +$fa-var-hourglass-3: "\f253"; +$fa-var-hourglass-end: "\f253"; +$fa-var-hourglass-half: "\f252"; +$fa-var-hourglass-o: "\f250"; +$fa-var-hourglass-start: "\f251"; +$fa-var-houzz: "\f27c"; $fa-var-html5: "\f13b"; +$fa-var-i-cursor: "\f246"; $fa-var-ils: "\f20b"; $fa-var-image: "\f03e"; $fa-var-inbox: "\f01c"; $fa-var-indent: "\f03c"; +$fa-var-industry: "\f275"; $fa-var-info: "\f129"; $fa-var-info-circle: "\f05a"; $fa-var-inr: "\f156"; $fa-var-instagram: "\f16d"; $fa-var-institution: "\f19c"; +$fa-var-internet-explorer: "\f26b"; +$fa-var-intersex: "\f224"; $fa-var-ioxhost: "\f208"; $fa-var-italic: "\f033"; $fa-var-joomla: "\f1aa"; @@ -340,7 +396,11 @@ $fa-var-mail-forward: "\f064"; $fa-var-mail-reply: "\f112"; $fa-var-mail-reply-all: "\f122"; $fa-var-male: "\f183"; +$fa-var-map: "\f279"; $fa-var-map-marker: "\f041"; +$fa-var-map-o: "\f278"; +$fa-var-map-pin: "\f276"; +$fa-var-map-signs: "\f277"; $fa-var-mars: "\f222"; $fa-var-mars-double: "\f227"; $fa-var-mars-stroke: "\f229"; @@ -364,11 +424,19 @@ $fa-var-money: "\f0d6"; $fa-var-moon-o: "\f186"; $fa-var-mortar-board: "\f19d"; $fa-var-motorcycle: "\f21c"; +$fa-var-mouse-pointer: "\f245"; $fa-var-music: "\f001"; $fa-var-navicon: "\f0c9"; $fa-var-neuter: "\f22c"; $fa-var-newspaper-o: "\f1ea"; +$fa-var-object-group: "\f247"; +$fa-var-object-ungroup: "\f248"; +$fa-var-odnoklassniki: "\f263"; +$fa-var-odnoklassniki-square: "\f264"; +$fa-var-opencart: "\f23d"; $fa-var-openid: "\f19b"; +$fa-var-opera: "\f26a"; +$fa-var-optin-monster: "\f23c"; $fa-var-outdent: "\f03b"; $fa-var-pagelines: "\f18c"; $fa-var-paint-brush: "\f1fc"; @@ -418,6 +486,7 @@ $fa-var-recycle: "\f1b8"; $fa-var-reddit: "\f1a1"; $fa-var-reddit-square: "\f1a2"; $fa-var-refresh: "\f021"; +$fa-var-registered: "\f25d"; $fa-var-remove: "\f00d"; $fa-var-renren: "\f18b"; $fa-var-reorder: "\f0c9"; @@ -436,6 +505,7 @@ $fa-var-rss-square: "\f143"; $fa-var-rub: "\f158"; $fa-var-ruble: "\f158"; $fa-var-rupee: "\f156"; +$fa-var-safari: "\f267"; $fa-var-save: "\f0c7"; $fa-var-scissors: "\f0c4"; $fa-var-search: "\f002"; @@ -499,6 +569,8 @@ $fa-var-steam-square: "\f1b7"; $fa-var-step-backward: "\f048"; $fa-var-step-forward: "\f051"; $fa-var-stethoscope: "\f0f1"; +$fa-var-sticky-note: "\f249"; +$fa-var-sticky-note-o: "\f24a"; $fa-var-stop: "\f04d"; $fa-var-street-view: "\f21d"; $fa-var-strikethrough: "\f0cc"; @@ -517,6 +589,7 @@ $fa-var-tag: "\f02b"; $fa-var-tags: "\f02c"; $fa-var-tasks: "\f0ae"; $fa-var-taxi: "\f1ba"; +$fa-var-television: "\f26c"; $fa-var-tencent-weibo: "\f1d5"; $fa-var-terminal: "\f120"; $fa-var-text-height: "\f034"; @@ -540,6 +613,7 @@ $fa-var-toggle-off: "\f204"; $fa-var-toggle-on: "\f205"; $fa-var-toggle-right: "\f152"; $fa-var-toggle-up: "\f151"; +$fa-var-trademark: "\f25c"; $fa-var-train: "\f238"; $fa-var-transgender: "\f224"; $fa-var-transgender-alt: "\f225"; @@ -547,6 +621,7 @@ $fa-var-trash: "\f1f8"; $fa-var-trash-o: "\f014"; $fa-var-tree: "\f1bb"; $fa-var-trello: "\f181"; +$fa-var-tripadvisor: "\f262"; $fa-var-trophy: "\f091"; $fa-var-truck: "\f0d1"; $fa-var-try: "\f195"; @@ -554,6 +629,7 @@ $fa-var-tty: "\f1e4"; $fa-var-tumblr: "\f173"; $fa-var-tumblr-square: "\f174"; $fa-var-turkish-lira: "\f195"; +$fa-var-tv: "\f26c"; $fa-var-twitch: "\f1e8"; $fa-var-twitter: "\f099"; $fa-var-twitter-square: "\f081"; @@ -578,6 +654,7 @@ $fa-var-venus-double: "\f226"; $fa-var-venus-mars: "\f228"; $fa-var-viacoin: "\f237"; $fa-var-video-camera: "\f03d"; +$fa-var-vimeo: "\f27d"; $fa-var-vimeo-square: "\f194"; $fa-var-vine: "\f1ca"; $fa-var-vk: "\f189"; @@ -591,13 +668,18 @@ $fa-var-weixin: "\f1d7"; $fa-var-whatsapp: "\f232"; $fa-var-wheelchair: "\f193"; $fa-var-wifi: "\f1eb"; +$fa-var-wikipedia-w: "\f266"; $fa-var-windows: "\f17a"; $fa-var-won: "\f159"; $fa-var-wordpress: "\f19a"; $fa-var-wrench: "\f0ad"; $fa-var-xing: "\f168"; $fa-var-xing-square: "\f169"; +$fa-var-y-combinator: "\f23b"; +$fa-var-y-combinator-square: "\f1d4"; $fa-var-yahoo: "\f19e"; +$fa-var-yc: "\f23b"; +$fa-var-yc-square: "\f1d4"; $fa-var-yelp: "\f1e9"; $fa-var-yen: "\f157"; $fa-var-youtube: "\f167"; diff --git a/lib/Font-Awesome/scss/font-awesome.scss b/lib/Font-Awesome/scss/font-awesome.scss index 388ac6b0c..ebd9646cc 100644 --- a/lib/Font-Awesome/scss/font-awesome.scss +++ b/lib/Font-Awesome/scss/font-awesome.scss @@ -1,5 +1,5 @@ /*! - * Font Awesome 4.3.0 by @davegandy - http://fontawesome.io - @fontawesome + * Font Awesome 4.4.0 by @davegandy - http://fontawesome.io - @fontawesome * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) */ diff --git a/lib/Font-Awesome/src/3.2.1/assets/img/contribution-sample.png b/lib/Font-Awesome/src/3.2.1/assets/img/contribution-sample.png index fe7647f0be94c09a94202fdeb6bd75e2d877be7e..7e6356279c2a24bf66d2c3e1f802f08be30be2f2 100644 GIT binary patch delta 1395 zcmZvcdo? zHCkOQMXkkXqUKU}Z8RzyDI-NgN+J;hGU_7O zjJOQ3VY6dFzS5q|pr4Nb=lhSgcSgqJ5m%Z+z&~nk^oSstdRn>>AsxX7pHv48n7FxP zeA`p^(}lMSbMxE941oFz6huoqfRy;@wx;o>`ca@Z%9vl@6FKABa7G9z0KusPcvQpu z`oXTbc6l4&#yEAk1GeebVqlpJjTc8hGqm~aY3U59m4H{|cI%?7lCgqJM3L=VIV1B^ zkRCj4w!&Hpds=KKx&!c|%`po!lXJtPl+2#-)yaWo;FL{8L`z(EPuC}u<@s|gEU3hq z>v-CSn3wEc(@S9W*9Id}foo3@$Mz5n$jHa%m2@{+Q>8zm{xm12=k7G_{%Fhf#IshY zoi-KiT&sA!o~)s)+EGqXYd}Y}({kC(;wWy-$&e8zuH(${?8-Iz;(BWZep5U7T`+I| z$gr4_Hh+DO#87uW>eSFeMDm$L!ze~AwERU%Qyj`JsjP;-MGjpC3UI^l-@Q5e>L5lt z2YgJp`p%<=k<=J{@8R<=7L4n*IxdQ3OQ8)&=9GdT_S$WB6=uI{Mxd}LW+nwDd2`V_ z>@Ih#cF+o3%9s(USKO!31{8l>w(CM@B^)#H^&x5-;dMbNI!1}cjT5BFiU-cqLn-S^ ztd_tPf$J*F8{ndYk#fQ3vk{Kr54nX_{w!GIpl8_aR}pk{$fa)Eu5o%$0?^{#I`GBJ zJKw#0QUU!<-A|eRY!Cmuj3z{aZ&3yorLSSbX5>ORYaV}_usMn`hH?%7eYvXgf&=EL z;y1f(@!k972>j*8h6Qqr1t8+D*akoTzrWEaN7CmK&F_-Gxnk$LH!+aL~ z^n-B#sy(- ziY{c9p1AaC@4@B-$9Y(rJ`4ZKOYjo0~Crv@3-h3O2@l-x$F4qy|5CufJv`DSS}nD_0URgk!=eM_dqAM}msx~uBSl@VOp zIDKQHRYXW^k4L~+@|uSHe-Q#3KtD447vYEB z&DBQa{q{lg%B?w#`D>IFMP$t8+o>#%2LS$kZIKayZ%9$d8576v%RgfMz<6V$@YXYk zhYl(Uu3PeqkTH@@a4<>sUL+F53aZy->1emhlYP>(Jg40fw7pM(syzCSTQ%lNZRM{$ U%$eX9NH^%V}o^dwyT3!9RydjJ3c delta 1542 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 literal 12799 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 diff --git a/lib/Font-Awesome/src/3.2.1/cheatsheet/index.html b/lib/Font-Awesome/src/3.2.1/cheatsheet/index.html index ff7745ff8..a531d4275 100644 --- a/lib/Font-Awesome/src/3.2.1/cheatsheet/index.html +++ b/lib/Font-Awesome/src/3.2.1/cheatsheet/index.html @@ -2368,7 +2368,7 @@ Documentation licensed under CC BY 3.0

    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/community/index.html b/lib/Font-Awesome/src/3.2.1/community/index.html index 428a3675f..300dd3015 100644 --- a/lib/Font-Awesome/src/3.2.1/community/index.html +++ b/lib/Font-Awesome/src/3.2.1/community/index.html @@ -292,7 +292,7 @@

    - Thanks to MaxCDN for providing the excellent + Thanks to MaxCDN for providing the excellent BootstrapCDN, the fastest and easiest way to get started with Font Awesome.

    @@ -343,7 +343,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/examples/index.html b/lib/Font-Awesome/src/3.2.1/examples/index.html index 19bea61d3..d35526752 100644 --- a/lib/Font-Awesome/src/3.2.1/examples/index.html +++ b/lib/Font-Awesome/src/3.2.1/examples/index.html @@ -660,7 +660,7 @@ icon-camera on icon-ban-circle Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/get-started/index.html b/lib/Font-Awesome/src/3.2.1/get-started/index.html index 5c1ea6bc7..2b305b78c 100644 --- a/lib/Font-Awesome/src/3.2.1/get-started/index.html +++ b/lib/Font-Awesome/src/3.2.1/get-started/index.html @@ -288,7 +288,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/adjust/index.html b/lib/Font-Awesome/src/3.2.1/icon/adjust/index.html index 54d203cef..224e86474 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/adjust/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/adjust/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/adn/index.html b/lib/Font-Awesome/src/3.2.1/icon/adn/index.html index 7b317e2b0..1a5d95d94 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/adn/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/adn/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/align-center/index.html b/lib/Font-Awesome/src/3.2.1/icon/align-center/index.html index 6a3716b3e..2839e44a7 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/align-center/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/align-center/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/align-justify/index.html b/lib/Font-Awesome/src/3.2.1/icon/align-justify/index.html index 9bdacbe13..649e4bf46 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/align-justify/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/align-justify/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/align-left/index.html b/lib/Font-Awesome/src/3.2.1/icon/align-left/index.html index 651ea4937..77140f3e9 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/align-left/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/align-left/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/align-right/index.html b/lib/Font-Awesome/src/3.2.1/icon/align-right/index.html index a7ce0b367..574d873d6 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/align-right/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/align-right/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/ambulance/index.html b/lib/Font-Awesome/src/3.2.1/icon/ambulance/index.html index 128e161ed..0d726295e 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/ambulance/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/ambulance/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/anchor/index.html b/lib/Font-Awesome/src/3.2.1/icon/anchor/index.html index 987d48880..a3e003901 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/anchor/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/anchor/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/android/index.html b/lib/Font-Awesome/src/3.2.1/icon/android/index.html index 7e1abc6a8..c0dc6ae6a 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/android/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/android/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/angle-down/index.html b/lib/Font-Awesome/src/3.2.1/icon/angle-down/index.html index 980e3f537..48c72f47a 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/angle-down/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/angle-down/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/angle-left/index.html b/lib/Font-Awesome/src/3.2.1/icon/angle-left/index.html index d8fd53679..93a031494 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/angle-left/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/angle-left/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/angle-right/index.html b/lib/Font-Awesome/src/3.2.1/icon/angle-right/index.html index 53dbb4d8c..12d28d893 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/angle-right/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/angle-right/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/angle-up/index.html b/lib/Font-Awesome/src/3.2.1/icon/angle-up/index.html index b7c40876f..83a0e4183 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/angle-up/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/angle-up/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/apple/index.html b/lib/Font-Awesome/src/3.2.1/icon/apple/index.html index 0770f1d4f..037584758 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/apple/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/apple/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/archive/index.html b/lib/Font-Awesome/src/3.2.1/icon/archive/index.html index 5aebb3369..164c88c17 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/archive/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/archive/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/arrow-down/index.html b/lib/Font-Awesome/src/3.2.1/icon/arrow-down/index.html index 2e0c6ab00..433344926 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/arrow-down/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/arrow-down/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/arrow-left/index.html b/lib/Font-Awesome/src/3.2.1/icon/arrow-left/index.html index 50b8aa6d4..79e301ec7 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/arrow-left/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/arrow-left/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/arrow-right/index.html b/lib/Font-Awesome/src/3.2.1/icon/arrow-right/index.html index f1c899d75..fcd194384 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/arrow-right/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/arrow-right/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/arrow-up/index.html b/lib/Font-Awesome/src/3.2.1/icon/arrow-up/index.html index a242ca86d..5f9901dc7 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/arrow-up/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/arrow-up/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/asterisk/index.html b/lib/Font-Awesome/src/3.2.1/icon/asterisk/index.html index 4ebfdeaf2..ba333175e 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/asterisk/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/asterisk/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/backward/index.html b/lib/Font-Awesome/src/3.2.1/icon/backward/index.html index 785965366..d3ece5b4b 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/backward/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/backward/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/ban-circle/index.html b/lib/Font-Awesome/src/3.2.1/icon/ban-circle/index.html index 129111b72..1c6bd2596 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/ban-circle/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/ban-circle/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/bar-chart/index.html b/lib/Font-Awesome/src/3.2.1/icon/bar-chart/index.html index 2c20d951c..a1f64df09 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/bar-chart/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/bar-chart/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/barcode/index.html b/lib/Font-Awesome/src/3.2.1/icon/barcode/index.html index 2a5ca4e5d..8a5b519aa 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/barcode/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/barcode/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/beaker/index.html b/lib/Font-Awesome/src/3.2.1/icon/beaker/index.html index ba77123c7..e17e44e0e 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/beaker/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/beaker/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/beer/index.html b/lib/Font-Awesome/src/3.2.1/icon/beer/index.html index dcda70338..b6df2e650 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/beer/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/beer/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/bell-alt/index.html b/lib/Font-Awesome/src/3.2.1/icon/bell-alt/index.html index 0fbdd7d19..53c39b0f3 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/bell-alt/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/bell-alt/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/bell/index.html b/lib/Font-Awesome/src/3.2.1/icon/bell/index.html index b8ffe8332..90faa9285 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/bell/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/bell/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/bitbucket-sign/index.html b/lib/Font-Awesome/src/3.2.1/icon/bitbucket-sign/index.html index e667aaef5..01025d5d4 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/bitbucket-sign/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/bitbucket-sign/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/bitbucket/index.html b/lib/Font-Awesome/src/3.2.1/icon/bitbucket/index.html index 4ff126539..34168065d 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/bitbucket/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/bitbucket/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/bold/index.html b/lib/Font-Awesome/src/3.2.1/icon/bold/index.html index 69b108297..a425e7e53 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/bold/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/bold/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/bolt/index.html b/lib/Font-Awesome/src/3.2.1/icon/bolt/index.html index aa6e822dc..57b67ea9d 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/bolt/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/bolt/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/book/index.html b/lib/Font-Awesome/src/3.2.1/icon/book/index.html index fb3298eb0..d289d8121 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/book/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/book/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/bookmark-empty/index.html b/lib/Font-Awesome/src/3.2.1/icon/bookmark-empty/index.html index 9fec923ca..ba3530a77 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/bookmark-empty/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/bookmark-empty/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/bookmark/index.html b/lib/Font-Awesome/src/3.2.1/icon/bookmark/index.html index a4901395e..13d291098 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/bookmark/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/bookmark/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/briefcase/index.html b/lib/Font-Awesome/src/3.2.1/icon/briefcase/index.html index 65b5630e4..825a9e88e 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/briefcase/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/briefcase/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/btc/index.html b/lib/Font-Awesome/src/3.2.1/icon/btc/index.html index 09d5a47ac..a32bb2c8d 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/btc/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/btc/index.html @@ -195,7 +195,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/bug/index.html b/lib/Font-Awesome/src/3.2.1/icon/bug/index.html index 69dd4997b..eea0f9275 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/bug/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/bug/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/building/index.html b/lib/Font-Awesome/src/3.2.1/icon/building/index.html index 0d3ea7943..e3079a76f 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/building/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/building/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/bullhorn/index.html b/lib/Font-Awesome/src/3.2.1/icon/bullhorn/index.html index 2a2394977..1720b5f5b 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/bullhorn/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/bullhorn/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/bullseye/index.html b/lib/Font-Awesome/src/3.2.1/icon/bullseye/index.html index 53411ef8f..bf56ffdf2 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/bullseye/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/bullseye/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/calendar-empty/index.html b/lib/Font-Awesome/src/3.2.1/icon/calendar-empty/index.html index 68c6e0bf3..b8f38db16 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/calendar-empty/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/calendar-empty/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/calendar/index.html b/lib/Font-Awesome/src/3.2.1/icon/calendar/index.html index dbc30d3a6..d145011b8 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/calendar/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/calendar/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/camera-retro/index.html b/lib/Font-Awesome/src/3.2.1/icon/camera-retro/index.html index a19377535..accd962cd 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/camera-retro/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/camera-retro/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/camera/index.html b/lib/Font-Awesome/src/3.2.1/icon/camera/index.html index 355951982..ab1137260 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/camera/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/camera/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/caret-down/index.html b/lib/Font-Awesome/src/3.2.1/icon/caret-down/index.html index 217b1c989..c688acf0f 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/caret-down/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/caret-down/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/caret-left/index.html b/lib/Font-Awesome/src/3.2.1/icon/caret-left/index.html index afdd0420c..35c7ca6ca 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/caret-left/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/caret-left/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/caret-right/index.html b/lib/Font-Awesome/src/3.2.1/icon/caret-right/index.html index e73b7eb34..6a457064b 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/caret-right/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/caret-right/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/caret-up/index.html b/lib/Font-Awesome/src/3.2.1/icon/caret-up/index.html index 6d1597a4c..0055994aa 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/caret-up/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/caret-up/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/certificate/index.html b/lib/Font-Awesome/src/3.2.1/icon/certificate/index.html index 3982634bb..f52074cd7 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/certificate/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/certificate/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/check-empty/index.html b/lib/Font-Awesome/src/3.2.1/icon/check-empty/index.html index 99c2238f7..ec039ea62 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/check-empty/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/check-empty/index.html @@ -193,7 +193,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/check-minus/index.html b/lib/Font-Awesome/src/3.2.1/icon/check-minus/index.html index f62ce7367..cbe7c93b5 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/check-minus/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/check-minus/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/check-sign/index.html b/lib/Font-Awesome/src/3.2.1/icon/check-sign/index.html index 6e9e4f082..094bf9b71 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/check-sign/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/check-sign/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/check/index.html b/lib/Font-Awesome/src/3.2.1/icon/check/index.html index aaca7ea4e..7c2c92d12 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/check/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/check/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/chevron-down/index.html b/lib/Font-Awesome/src/3.2.1/icon/chevron-down/index.html index 53f0c97d7..31cadfbd9 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/chevron-down/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/chevron-down/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/chevron-left/index.html b/lib/Font-Awesome/src/3.2.1/icon/chevron-left/index.html index 90c5ed681..82f14932c 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/chevron-left/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/chevron-left/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/chevron-right/index.html b/lib/Font-Awesome/src/3.2.1/icon/chevron-right/index.html index 0be7da63c..3ef5b3b1c 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/chevron-right/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/chevron-right/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/chevron-sign-down/index.html b/lib/Font-Awesome/src/3.2.1/icon/chevron-sign-down/index.html index 55928e6b2..d04d821d4 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/chevron-sign-down/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/chevron-sign-down/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/chevron-sign-left/index.html b/lib/Font-Awesome/src/3.2.1/icon/chevron-sign-left/index.html index 5ec15a4ec..049b5c515 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/chevron-sign-left/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/chevron-sign-left/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/chevron-sign-right/index.html b/lib/Font-Awesome/src/3.2.1/icon/chevron-sign-right/index.html index 9cf013be7..f298ed303 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/chevron-sign-right/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/chevron-sign-right/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/chevron-sign-up/index.html b/lib/Font-Awesome/src/3.2.1/icon/chevron-sign-up/index.html index 6a74cebe1..76d1195ed 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/chevron-sign-up/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/chevron-sign-up/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/chevron-up/index.html b/lib/Font-Awesome/src/3.2.1/icon/chevron-up/index.html index d457d9e60..684dee6b9 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/chevron-up/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/chevron-up/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/circle-arrow-down/index.html b/lib/Font-Awesome/src/3.2.1/icon/circle-arrow-down/index.html index d4b5a4533..43155a9d7 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/circle-arrow-down/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/circle-arrow-down/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/circle-arrow-left/index.html b/lib/Font-Awesome/src/3.2.1/icon/circle-arrow-left/index.html index bf2c12a91..b11e7503e 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/circle-arrow-left/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/circle-arrow-left/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/circle-arrow-right/index.html b/lib/Font-Awesome/src/3.2.1/icon/circle-arrow-right/index.html index 0ed136995..2618571a7 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/circle-arrow-right/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/circle-arrow-right/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/circle-arrow-up/index.html b/lib/Font-Awesome/src/3.2.1/icon/circle-arrow-up/index.html index 7279554a4..c1f0fa533 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/circle-arrow-up/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/circle-arrow-up/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/circle-blank/index.html b/lib/Font-Awesome/src/3.2.1/icon/circle-blank/index.html index 1e87eaa43..56953975c 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/circle-blank/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/circle-blank/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/circle/index.html b/lib/Font-Awesome/src/3.2.1/icon/circle/index.html index 3cb1a0c2f..abf947204 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/circle/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/circle/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/cloud-download/index.html b/lib/Font-Awesome/src/3.2.1/icon/cloud-download/index.html index 8bc71dcb5..e2b89c120 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/cloud-download/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/cloud-download/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/cloud-upload/index.html b/lib/Font-Awesome/src/3.2.1/icon/cloud-upload/index.html index 3bfc45032..affb1a170 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/cloud-upload/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/cloud-upload/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/cloud/index.html b/lib/Font-Awesome/src/3.2.1/icon/cloud/index.html index d4e319e62..1f137dd53 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/cloud/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/cloud/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/cny/index.html b/lib/Font-Awesome/src/3.2.1/icon/cny/index.html index 39ad423ec..af969271c 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/cny/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/cny/index.html @@ -193,7 +193,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/code-fork/index.html b/lib/Font-Awesome/src/3.2.1/icon/code-fork/index.html index e1f7a6445..91b984d58 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/code-fork/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/code-fork/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/code/index.html b/lib/Font-Awesome/src/3.2.1/icon/code/index.html index d28713ce8..6bb7eed20 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/code/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/code/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/coffee/index.html b/lib/Font-Awesome/src/3.2.1/icon/coffee/index.html index 63e06e44e..dd9b94a7e 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/coffee/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/coffee/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/cog/index.html b/lib/Font-Awesome/src/3.2.1/icon/cog/index.html index 8afd03166..a5808ceee 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/cog/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/cog/index.html @@ -193,7 +193,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/cogs/index.html b/lib/Font-Awesome/src/3.2.1/icon/cogs/index.html index 2c4c56d20..0fd8797de 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/cogs/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/cogs/index.html @@ -193,7 +193,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/collapse-alt/index.html b/lib/Font-Awesome/src/3.2.1/icon/collapse-alt/index.html index c56b536df..c3112e8bb 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/collapse-alt/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/collapse-alt/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/collapse-top/index.html b/lib/Font-Awesome/src/3.2.1/icon/collapse-top/index.html index a2416a173..94c53c968 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/collapse-top/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/collapse-top/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/collapse/index.html b/lib/Font-Awesome/src/3.2.1/icon/collapse/index.html index 592d9340d..2cc8f58c9 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/collapse/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/collapse/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/columns/index.html b/lib/Font-Awesome/src/3.2.1/icon/columns/index.html index 2cac42bb8..bda9b9678 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/columns/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/columns/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/comment-alt/index.html b/lib/Font-Awesome/src/3.2.1/icon/comment-alt/index.html index dfe025d1d..2c4845d8f 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/comment-alt/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/comment-alt/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/comment/index.html b/lib/Font-Awesome/src/3.2.1/icon/comment/index.html index d3217e200..e6c60080a 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/comment/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/comment/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/comments-alt/index.html b/lib/Font-Awesome/src/3.2.1/icon/comments-alt/index.html index 1b0d464ca..3460824ca 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/comments-alt/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/comments-alt/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/comments/index.html b/lib/Font-Awesome/src/3.2.1/icon/comments/index.html index a9d57f58f..c801aeeec 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/comments/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/comments/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/compass/index.html b/lib/Font-Awesome/src/3.2.1/icon/compass/index.html index b6bee48cf..899db018d 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/compass/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/compass/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/copy/index.html b/lib/Font-Awesome/src/3.2.1/icon/copy/index.html index 3e6bf6654..0a54d9480 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/copy/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/copy/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/credit-card/index.html b/lib/Font-Awesome/src/3.2.1/icon/credit-card/index.html index 576fe24a5..4d998b8ae 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/credit-card/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/credit-card/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/crop/index.html b/lib/Font-Awesome/src/3.2.1/icon/crop/index.html index 226413b4b..1f1a8a2e9 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/crop/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/crop/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/css3/index.html b/lib/Font-Awesome/src/3.2.1/icon/css3/index.html index 3684786e8..f0370b161 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/css3/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/css3/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/cut/index.html b/lib/Font-Awesome/src/3.2.1/icon/cut/index.html index 6c63fa3c7..b0d907224 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/cut/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/cut/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/dashboard/index.html b/lib/Font-Awesome/src/3.2.1/icon/dashboard/index.html index a509a08d8..291e27c3e 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/dashboard/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/dashboard/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/desktop/index.html b/lib/Font-Awesome/src/3.2.1/icon/desktop/index.html index 1ac39c84a..4166d0e46 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/desktop/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/desktop/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/double-angle-down/index.html b/lib/Font-Awesome/src/3.2.1/icon/double-angle-down/index.html index 6b4f8035c..483a57099 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/double-angle-down/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/double-angle-down/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/double-angle-left/index.html b/lib/Font-Awesome/src/3.2.1/icon/double-angle-left/index.html index cba1443a8..6c4c5b327 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/double-angle-left/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/double-angle-left/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/double-angle-right/index.html b/lib/Font-Awesome/src/3.2.1/icon/double-angle-right/index.html index d62c78740..55eefffbc 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/double-angle-right/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/double-angle-right/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/double-angle-up/index.html b/lib/Font-Awesome/src/3.2.1/icon/double-angle-up/index.html index 1a9988c61..7beb9b09f 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/double-angle-up/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/double-angle-up/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/download-alt/index.html b/lib/Font-Awesome/src/3.2.1/icon/download-alt/index.html index 5763029bf..c64f9b92e 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/download-alt/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/download-alt/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/download/index.html b/lib/Font-Awesome/src/3.2.1/icon/download/index.html index d95fc9385..7d5b12773 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/download/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/download/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/dribbble/index.html b/lib/Font-Awesome/src/3.2.1/icon/dribbble/index.html index 12808af52..2c34de53a 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/dribbble/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/dribbble/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/dropbox/index.html b/lib/Font-Awesome/src/3.2.1/icon/dropbox/index.html index 86a75157d..2b0dc5668 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/dropbox/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/dropbox/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/edit-sign/index.html b/lib/Font-Awesome/src/3.2.1/icon/edit-sign/index.html index 75402f7a7..92ea64ec5 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/edit-sign/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/edit-sign/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/edit/index.html b/lib/Font-Awesome/src/3.2.1/icon/edit/index.html index 254a9cb6c..c9d17888a 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/edit/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/edit/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/eject/index.html b/lib/Font-Awesome/src/3.2.1/icon/eject/index.html index a7712b304..121263dc7 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/eject/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/eject/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/ellipsis-horizontal/index.html b/lib/Font-Awesome/src/3.2.1/icon/ellipsis-horizontal/index.html index 55abf3eb6..8e634acd9 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/ellipsis-horizontal/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/ellipsis-horizontal/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/ellipsis-vertical/index.html b/lib/Font-Awesome/src/3.2.1/icon/ellipsis-vertical/index.html index cccffe37f..34083a745 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/ellipsis-vertical/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/ellipsis-vertical/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/envelope-alt/index.html b/lib/Font-Awesome/src/3.2.1/icon/envelope-alt/index.html index 3d9914411..1cc919524 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/envelope-alt/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/envelope-alt/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/envelope/index.html b/lib/Font-Awesome/src/3.2.1/icon/envelope/index.html index e4d771e87..3164cb065 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/envelope/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/envelope/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/eraser/index.html b/lib/Font-Awesome/src/3.2.1/icon/eraser/index.html index 1f5f8781d..2148290e6 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/eraser/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/eraser/index.html @@ -190,7 +190,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/eur/index.html b/lib/Font-Awesome/src/3.2.1/icon/eur/index.html index d9689868f..da3b8d127 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/eur/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/eur/index.html @@ -193,7 +193,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/exchange/index.html b/lib/Font-Awesome/src/3.2.1/icon/exchange/index.html index afdb30379..7a7160c75 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/exchange/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/exchange/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/exclamation-sign/index.html b/lib/Font-Awesome/src/3.2.1/icon/exclamation-sign/index.html index ad8c95c05..a426e9e32 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/exclamation-sign/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/exclamation-sign/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/exclamation/index.html b/lib/Font-Awesome/src/3.2.1/icon/exclamation/index.html index 0492fa1ae..b3f65d172 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/exclamation/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/exclamation/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/expand-alt/index.html b/lib/Font-Awesome/src/3.2.1/icon/expand-alt/index.html index 9e2bc6870..f580ec489 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/expand-alt/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/expand-alt/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/expand/index.html b/lib/Font-Awesome/src/3.2.1/icon/expand/index.html index 4fddffa25..ca2f9893d 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/expand/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/expand/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/external-link-sign/index.html b/lib/Font-Awesome/src/3.2.1/icon/external-link-sign/index.html index 198521a9a..005da9df9 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/external-link-sign/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/external-link-sign/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/external-link/index.html b/lib/Font-Awesome/src/3.2.1/icon/external-link/index.html index 548d33c23..39f239857 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/external-link/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/external-link/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/eye-close/index.html b/lib/Font-Awesome/src/3.2.1/icon/eye-close/index.html index 59f040bf6..b5fb31efa 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/eye-close/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/eye-close/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/eye-open/index.html b/lib/Font-Awesome/src/3.2.1/icon/eye-open/index.html index c5b5e1272..f141ed36a 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/eye-open/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/eye-open/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/facebook-sign/index.html b/lib/Font-Awesome/src/3.2.1/icon/facebook-sign/index.html index a92946f21..0a5164d6f 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/facebook-sign/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/facebook-sign/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/facebook/index.html b/lib/Font-Awesome/src/3.2.1/icon/facebook/index.html index 3f427cc5e..804133005 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/facebook/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/facebook/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/facetime-video/index.html b/lib/Font-Awesome/src/3.2.1/icon/facetime-video/index.html index f0af71600..96d5a2e6e 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/facetime-video/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/facetime-video/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/fast-backward/index.html b/lib/Font-Awesome/src/3.2.1/icon/fast-backward/index.html index 12575ffea..967803239 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/fast-backward/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/fast-backward/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/fast-forward/index.html b/lib/Font-Awesome/src/3.2.1/icon/fast-forward/index.html index 2847d9ee9..bcf30e5bc 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/fast-forward/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/fast-forward/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/female/index.html b/lib/Font-Awesome/src/3.2.1/icon/female/index.html index 30987c0a3..a08be3b72 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/female/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/female/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/fighter-jet/index.html b/lib/Font-Awesome/src/3.2.1/icon/fighter-jet/index.html index 8c9a52b3a..cae3c7a0d 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/fighter-jet/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/fighter-jet/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/file-alt/index.html b/lib/Font-Awesome/src/3.2.1/icon/file-alt/index.html index e3034a869..146e27a60 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/file-alt/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/file-alt/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/file-text-alt/index.html b/lib/Font-Awesome/src/3.2.1/icon/file-text-alt/index.html index f9284ca2c..8e0182ade 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/file-text-alt/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/file-text-alt/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/file-text/index.html b/lib/Font-Awesome/src/3.2.1/icon/file-text/index.html index 90d7f1501..5af696512 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/file-text/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/file-text/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/file/index.html b/lib/Font-Awesome/src/3.2.1/icon/file/index.html index 7afa11475..6773dfd32 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/file/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/file/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/film/index.html b/lib/Font-Awesome/src/3.2.1/icon/film/index.html index fb03bdc6f..b0fdc40bf 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/film/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/film/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/filter/index.html b/lib/Font-Awesome/src/3.2.1/icon/filter/index.html index 9cb552ce4..c0979d2e1 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/filter/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/filter/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/fire-extinguisher/index.html b/lib/Font-Awesome/src/3.2.1/icon/fire-extinguisher/index.html index 5a00fb90a..87520cb47 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/fire-extinguisher/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/fire-extinguisher/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/fire/index.html b/lib/Font-Awesome/src/3.2.1/icon/fire/index.html index 6ca70f8b1..ea6e175f7 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/fire/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/fire/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/flag-alt/index.html b/lib/Font-Awesome/src/3.2.1/icon/flag-alt/index.html index 5d6295852..4ba87718d 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/flag-alt/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/flag-alt/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/flag-checkered/index.html b/lib/Font-Awesome/src/3.2.1/icon/flag-checkered/index.html index 972ebefae..7fdd0f363 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/flag-checkered/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/flag-checkered/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/flag/index.html b/lib/Font-Awesome/src/3.2.1/icon/flag/index.html index 7f9c8e974..c747c7ace 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/flag/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/flag/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/flickr/index.html b/lib/Font-Awesome/src/3.2.1/icon/flickr/index.html index 5379f5fd7..2f86f323c 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/flickr/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/flickr/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/folder-close-alt/index.html b/lib/Font-Awesome/src/3.2.1/icon/folder-close-alt/index.html index 5bc757e56..f3e0f2ee5 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/folder-close-alt/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/folder-close-alt/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/folder-close/index.html b/lib/Font-Awesome/src/3.2.1/icon/folder-close/index.html index bf006b02a..a355f2e1c 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/folder-close/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/folder-close/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/folder-open-alt/index.html b/lib/Font-Awesome/src/3.2.1/icon/folder-open-alt/index.html index a114fb1d1..12dbc6333 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/folder-open-alt/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/folder-open-alt/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/folder-open/index.html b/lib/Font-Awesome/src/3.2.1/icon/folder-open/index.html index 306c57831..cd8e37488 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/folder-open/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/folder-open/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/font/index.html b/lib/Font-Awesome/src/3.2.1/icon/font/index.html index 2a970e7c8..080e7792d 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/font/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/font/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/food/index.html b/lib/Font-Awesome/src/3.2.1/icon/food/index.html index c5d1837b4..bb787df12 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/food/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/food/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/forward/index.html b/lib/Font-Awesome/src/3.2.1/icon/forward/index.html index c1484cc9a..1580ee502 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/forward/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/forward/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/foursquare/index.html b/lib/Font-Awesome/src/3.2.1/icon/foursquare/index.html index 23e71bb68..bef943e7f 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/foursquare/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/foursquare/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/frown/index.html b/lib/Font-Awesome/src/3.2.1/icon/frown/index.html index 67132a37f..a2569dd6c 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/frown/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/frown/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/fullscreen/index.html b/lib/Font-Awesome/src/3.2.1/icon/fullscreen/index.html index 05d44452e..8c0c0bddc 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/fullscreen/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/fullscreen/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/gamepad/index.html b/lib/Font-Awesome/src/3.2.1/icon/gamepad/index.html index 0bd4ffea8..2589d79f0 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/gamepad/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/gamepad/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/gbp/index.html b/lib/Font-Awesome/src/3.2.1/icon/gbp/index.html index 87d4317b8..e50b2b7b1 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/gbp/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/gbp/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/gift/index.html b/lib/Font-Awesome/src/3.2.1/icon/gift/index.html index 88f346491..4eaab15cf 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/gift/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/gift/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/github-alt/index.html b/lib/Font-Awesome/src/3.2.1/icon/github-alt/index.html index eacd12e34..c6dbe7014 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/github-alt/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/github-alt/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/github-sign/index.html b/lib/Font-Awesome/src/3.2.1/icon/github-sign/index.html index 15fa951e4..84071704e 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/github-sign/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/github-sign/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/github/index.html b/lib/Font-Awesome/src/3.2.1/icon/github/index.html index 102ce0ffa..c6ec97307 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/github/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/github/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/gittip/index.html b/lib/Font-Awesome/src/3.2.1/icon/gittip/index.html index 620da7fb1..569bfb9fa 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/gittip/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/gittip/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/glass/index.html b/lib/Font-Awesome/src/3.2.1/icon/glass/index.html index b03e4d7e2..1d9f1d1fb 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/glass/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/glass/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/globe/index.html b/lib/Font-Awesome/src/3.2.1/icon/globe/index.html index 4892bfee1..6d5e9c8da 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/globe/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/globe/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/google-plus-sign/index.html b/lib/Font-Awesome/src/3.2.1/icon/google-plus-sign/index.html index f4088409c..2a623c4a8 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/google-plus-sign/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/google-plus-sign/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/google-plus/index.html b/lib/Font-Awesome/src/3.2.1/icon/google-plus/index.html index b274b770f..62467b5fa 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/google-plus/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/google-plus/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/group/index.html b/lib/Font-Awesome/src/3.2.1/icon/group/index.html index 27d3857e3..b3c85b5d0 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/group/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/group/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/h-sign/index.html b/lib/Font-Awesome/src/3.2.1/icon/h-sign/index.html index 9bd171d92..bee59ea8a 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/h-sign/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/h-sign/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/hand-down/index.html b/lib/Font-Awesome/src/3.2.1/icon/hand-down/index.html index 59b3355bd..f85f105bf 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/hand-down/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/hand-down/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/hand-left/index.html b/lib/Font-Awesome/src/3.2.1/icon/hand-left/index.html index 12d869cb9..9b26925c4 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/hand-left/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/hand-left/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/hand-right/index.html b/lib/Font-Awesome/src/3.2.1/icon/hand-right/index.html index e41517529..2f309bb55 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/hand-right/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/hand-right/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/hand-up/index.html b/lib/Font-Awesome/src/3.2.1/icon/hand-up/index.html index 52f4c8f9b..e7d6b8edb 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/hand-up/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/hand-up/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/hdd/index.html b/lib/Font-Awesome/src/3.2.1/icon/hdd/index.html index 5d9418d42..fc86fc4b2 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/hdd/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/hdd/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/headphones/index.html b/lib/Font-Awesome/src/3.2.1/icon/headphones/index.html index 643ba0ca3..1107831bd 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/headphones/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/headphones/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/heart-empty/index.html b/lib/Font-Awesome/src/3.2.1/icon/heart-empty/index.html index 4421a0c6c..5a269160a 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/heart-empty/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/heart-empty/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/heart/index.html b/lib/Font-Awesome/src/3.2.1/icon/heart/index.html index 438b76809..11cf98e71 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/heart/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/heart/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/home/index.html b/lib/Font-Awesome/src/3.2.1/icon/home/index.html index 28c9e505f..d4c92fcce 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/home/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/home/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/hospital/index.html b/lib/Font-Awesome/src/3.2.1/icon/hospital/index.html index c349211b4..b0acc0ac9 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/hospital/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/hospital/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/html5/index.html b/lib/Font-Awesome/src/3.2.1/icon/html5/index.html index 0485a6d50..613335a92 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/html5/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/html5/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/inbox/index.html b/lib/Font-Awesome/src/3.2.1/icon/inbox/index.html index 77f22e67e..324310350 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/inbox/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/inbox/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/indent-left/index.html b/lib/Font-Awesome/src/3.2.1/icon/indent-left/index.html index a464fef45..0493c3623 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/indent-left/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/indent-left/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/indent-right/index.html b/lib/Font-Awesome/src/3.2.1/icon/indent-right/index.html index 1b09d480a..343cbc7d0 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/indent-right/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/indent-right/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/info-sign/index.html b/lib/Font-Awesome/src/3.2.1/icon/info-sign/index.html index 77d1039b5..631d30616 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/info-sign/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/info-sign/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/info/index.html b/lib/Font-Awesome/src/3.2.1/icon/info/index.html index 16cf35f2f..a193853ff 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/info/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/info/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/inr/index.html b/lib/Font-Awesome/src/3.2.1/icon/inr/index.html index 0282bbfd1..fd7ad2d09 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/inr/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/inr/index.html @@ -193,7 +193,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/instagram/index.html b/lib/Font-Awesome/src/3.2.1/icon/instagram/index.html index a6bc13eb9..90764c30b 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/instagram/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/instagram/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/italic/index.html b/lib/Font-Awesome/src/3.2.1/icon/italic/index.html index 18695b563..e1bb75680 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/italic/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/italic/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/jpy/index.html b/lib/Font-Awesome/src/3.2.1/icon/jpy/index.html index e2a9a00d4..c6975d574 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/jpy/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/jpy/index.html @@ -193,7 +193,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/key/index.html b/lib/Font-Awesome/src/3.2.1/icon/key/index.html index 7f661965d..3c2e10ab0 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/key/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/key/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/keyboard/index.html b/lib/Font-Awesome/src/3.2.1/icon/keyboard/index.html index 6823e6ea4..e249a8850 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/keyboard/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/keyboard/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/krw/index.html b/lib/Font-Awesome/src/3.2.1/icon/krw/index.html index 01ac3673b..f81ae5110 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/krw/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/krw/index.html @@ -193,7 +193,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/laptop/index.html b/lib/Font-Awesome/src/3.2.1/icon/laptop/index.html index d4d312fd7..abf802eab 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/laptop/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/laptop/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/leaf/index.html b/lib/Font-Awesome/src/3.2.1/icon/leaf/index.html index 63d7917c7..07e82a5f2 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/leaf/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/leaf/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/legal/index.html b/lib/Font-Awesome/src/3.2.1/icon/legal/index.html index 7d07b4f06..bf354824a 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/legal/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/legal/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/lemon/index.html b/lib/Font-Awesome/src/3.2.1/icon/lemon/index.html index 203076f46..bcb216c11 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/lemon/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/lemon/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/level-down/index.html b/lib/Font-Awesome/src/3.2.1/icon/level-down/index.html index 89f85d3d8..6213baff2 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/level-down/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/level-down/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/level-up/index.html b/lib/Font-Awesome/src/3.2.1/icon/level-up/index.html index 9448afa64..8794e48cb 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/level-up/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/level-up/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/lightbulb/index.html b/lib/Font-Awesome/src/3.2.1/icon/lightbulb/index.html index a2be4e497..2bdf4be9f 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/lightbulb/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/lightbulb/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/link/index.html b/lib/Font-Awesome/src/3.2.1/icon/link/index.html index 9dc11e1a5..7d16cd99b 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/link/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/link/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/linkedin-sign/index.html b/lib/Font-Awesome/src/3.2.1/icon/linkedin-sign/index.html index a19f14619..e1766801b 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/linkedin-sign/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/linkedin-sign/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/linkedin/index.html b/lib/Font-Awesome/src/3.2.1/icon/linkedin/index.html index 6fc122840..f16f7c6f0 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/linkedin/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/linkedin/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/linux/index.html b/lib/Font-Awesome/src/3.2.1/icon/linux/index.html index 983e10cf8..ec5c27c50 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/linux/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/linux/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/list-alt/index.html b/lib/Font-Awesome/src/3.2.1/icon/list-alt/index.html index 5a5fa668e..b8b0a522f 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/list-alt/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/list-alt/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/list-ol/index.html b/lib/Font-Awesome/src/3.2.1/icon/list-ol/index.html index f8d995ca4..0e5052fb6 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/list-ol/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/list-ol/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/list-ul/index.html b/lib/Font-Awesome/src/3.2.1/icon/list-ul/index.html index 18216653f..08c259140 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/list-ul/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/list-ul/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/list/index.html b/lib/Font-Awesome/src/3.2.1/icon/list/index.html index 1a0207dee..01626c42c 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/list/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/list/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/location-arrow/index.html b/lib/Font-Awesome/src/3.2.1/icon/location-arrow/index.html index a12c8c16e..42c9bfcb3 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/location-arrow/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/location-arrow/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/lock/index.html b/lib/Font-Awesome/src/3.2.1/icon/lock/index.html index b0c06dfb5..c9b31547d 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/lock/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/lock/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/long-arrow-down/index.html b/lib/Font-Awesome/src/3.2.1/icon/long-arrow-down/index.html index 4de7c4082..638b6853a 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/long-arrow-down/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/long-arrow-down/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/long-arrow-left/index.html b/lib/Font-Awesome/src/3.2.1/icon/long-arrow-left/index.html index 1b6d0ad53..6fe9ea438 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/long-arrow-left/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/long-arrow-left/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/long-arrow-right/index.html b/lib/Font-Awesome/src/3.2.1/icon/long-arrow-right/index.html index 0b57a2b74..fe9fa0274 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/long-arrow-right/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/long-arrow-right/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/long-arrow-up/index.html b/lib/Font-Awesome/src/3.2.1/icon/long-arrow-up/index.html index 2a8e10762..5a4ddf73b 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/long-arrow-up/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/long-arrow-up/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/magic/index.html b/lib/Font-Awesome/src/3.2.1/icon/magic/index.html index b82bd1800..cb26804c1 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/magic/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/magic/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/magnet/index.html b/lib/Font-Awesome/src/3.2.1/icon/magnet/index.html index 4efafbc60..496d471ce 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/magnet/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/magnet/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/mail-reply-all/index.html b/lib/Font-Awesome/src/3.2.1/icon/mail-reply-all/index.html index ed887beac..4569f4119 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/mail-reply-all/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/mail-reply-all/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/male/index.html b/lib/Font-Awesome/src/3.2.1/icon/male/index.html index 56397b460..ef7dacb1f 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/male/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/male/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/map-marker/index.html b/lib/Font-Awesome/src/3.2.1/icon/map-marker/index.html index 4f1c90492..8dc2e49bc 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/map-marker/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/map-marker/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/maxcdn/index.html b/lib/Font-Awesome/src/3.2.1/icon/maxcdn/index.html index 77fe70504..7b9eec0ca 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/maxcdn/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/maxcdn/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/medkit/index.html b/lib/Font-Awesome/src/3.2.1/icon/medkit/index.html index 0dc6de676..aaeb7e49c 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/medkit/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/medkit/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/meh/index.html b/lib/Font-Awesome/src/3.2.1/icon/meh/index.html index b2da54705..9ccb6962e 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/meh/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/meh/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/microphone-off/index.html b/lib/Font-Awesome/src/3.2.1/icon/microphone-off/index.html index 9f07f090e..598f6b1c4 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/microphone-off/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/microphone-off/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/microphone/index.html b/lib/Font-Awesome/src/3.2.1/icon/microphone/index.html index 194f14e00..f2b677198 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/microphone/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/microphone/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/minus-sign-alt/index.html b/lib/Font-Awesome/src/3.2.1/icon/minus-sign-alt/index.html index c051cbb8b..c7315b530 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/minus-sign-alt/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/minus-sign-alt/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/minus-sign/index.html b/lib/Font-Awesome/src/3.2.1/icon/minus-sign/index.html index 0e68e3475..6745b9762 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/minus-sign/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/minus-sign/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/minus/index.html b/lib/Font-Awesome/src/3.2.1/icon/minus/index.html index 3b67868cd..bef81f1ee 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/minus/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/minus/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/mobile-phone/index.html b/lib/Font-Awesome/src/3.2.1/icon/mobile-phone/index.html index 7df04478c..a2775f2af 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/mobile-phone/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/mobile-phone/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/money/index.html b/lib/Font-Awesome/src/3.2.1/icon/money/index.html index 034d08044..6b54d3702 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/money/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/money/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/moon/index.html b/lib/Font-Awesome/src/3.2.1/icon/moon/index.html index 85484ffdd..a3d7f64b1 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/moon/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/moon/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/move/index.html b/lib/Font-Awesome/src/3.2.1/icon/move/index.html index 15b9dbf55..16cc43e2f 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/move/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/move/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/music/index.html b/lib/Font-Awesome/src/3.2.1/icon/music/index.html index 20b12e6b5..996671e6c 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/music/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/music/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/off/index.html b/lib/Font-Awesome/src/3.2.1/icon/off/index.html index 4c048fbe6..e49c18439 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/off/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/off/index.html @@ -193,7 +193,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/ok-circle/index.html b/lib/Font-Awesome/src/3.2.1/icon/ok-circle/index.html index 137d67f5f..39f2dafe4 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/ok-circle/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/ok-circle/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/ok-sign/index.html b/lib/Font-Awesome/src/3.2.1/icon/ok-sign/index.html index b4ff3ab4c..017670fd3 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/ok-sign/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/ok-sign/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/ok/index.html b/lib/Font-Awesome/src/3.2.1/icon/ok/index.html index 8b5295721..7bab082f1 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/ok/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/ok/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/paper-clip/index.html b/lib/Font-Awesome/src/3.2.1/icon/paper-clip/index.html index b1f37a773..03adcebbb 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/paper-clip/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/paper-clip/index.html @@ -193,7 +193,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/paste/index.html b/lib/Font-Awesome/src/3.2.1/icon/paste/index.html index 5c6dd547a..995946183 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/paste/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/paste/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/pause/index.html b/lib/Font-Awesome/src/3.2.1/icon/pause/index.html index 74e629bcd..b0fab04f5 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/pause/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/pause/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/pencil/index.html b/lib/Font-Awesome/src/3.2.1/icon/pencil/index.html index fc624e017..e2cbb58a5 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/pencil/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/pencil/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/phone-sign/index.html b/lib/Font-Awesome/src/3.2.1/icon/phone-sign/index.html index a6020dc1d..4f38a2ae6 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/phone-sign/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/phone-sign/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/phone/index.html b/lib/Font-Awesome/src/3.2.1/icon/phone/index.html index f6195d2c8..9f23f975c 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/phone/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/phone/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/picture/index.html b/lib/Font-Awesome/src/3.2.1/icon/picture/index.html index 0de34f3e0..a923c3e19 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/picture/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/picture/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/pinterest-sign/index.html b/lib/Font-Awesome/src/3.2.1/icon/pinterest-sign/index.html index 699330e61..cd877b692 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/pinterest-sign/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/pinterest-sign/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/pinterest/index.html b/lib/Font-Awesome/src/3.2.1/icon/pinterest/index.html index 89b5ddfc3..3eeb4cebf 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/pinterest/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/pinterest/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/plane/index.html b/lib/Font-Awesome/src/3.2.1/icon/plane/index.html index 5f2c97b66..ad4a9edc9 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/plane/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/plane/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/play-circle/index.html b/lib/Font-Awesome/src/3.2.1/icon/play-circle/index.html index 1a2d2ef20..2f75beff2 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/play-circle/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/play-circle/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/play-sign/index.html b/lib/Font-Awesome/src/3.2.1/icon/play-sign/index.html index fcaf5e928..96db90471 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/play-sign/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/play-sign/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/play/index.html b/lib/Font-Awesome/src/3.2.1/icon/play/index.html index 79d140786..876c16d7e 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/play/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/play/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/plus-sign-alt/index.html b/lib/Font-Awesome/src/3.2.1/icon/plus-sign-alt/index.html index 7a06b3fc9..56c4351e5 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/plus-sign-alt/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/plus-sign-alt/index.html @@ -190,7 +190,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/plus-sign/index.html b/lib/Font-Awesome/src/3.2.1/icon/plus-sign/index.html index 83dcde535..de256268f 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/plus-sign/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/plus-sign/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/plus/index.html b/lib/Font-Awesome/src/3.2.1/icon/plus/index.html index 13f2b25b1..8b47825b1 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/plus/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/plus/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/print/index.html b/lib/Font-Awesome/src/3.2.1/icon/print/index.html index 32740b8ca..34a365b8d 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/print/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/print/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/pushpin/index.html b/lib/Font-Awesome/src/3.2.1/icon/pushpin/index.html index 76058991c..87f3f871f 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/pushpin/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/pushpin/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/puzzle-piece/index.html b/lib/Font-Awesome/src/3.2.1/icon/puzzle-piece/index.html index b0dd14237..a2fe7171e 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/puzzle-piece/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/puzzle-piece/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/qrcode/index.html b/lib/Font-Awesome/src/3.2.1/icon/qrcode/index.html index e3f6ed9ae..81d2128bb 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/qrcode/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/qrcode/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/question-sign/index.html b/lib/Font-Awesome/src/3.2.1/icon/question-sign/index.html index 2f36afda8..3aff22d69 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/question-sign/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/question-sign/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/question/index.html b/lib/Font-Awesome/src/3.2.1/icon/question/index.html index 45b2e299b..1db03b889 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/question/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/question/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/quote-left/index.html b/lib/Font-Awesome/src/3.2.1/icon/quote-left/index.html index e3c3f208e..a86a705bd 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/quote-left/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/quote-left/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/quote-right/index.html b/lib/Font-Awesome/src/3.2.1/icon/quote-right/index.html index c3f4d8ecc..2fa339772 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/quote-right/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/quote-right/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/random/index.html b/lib/Font-Awesome/src/3.2.1/icon/random/index.html index 0d20d95bf..9bc72e1b9 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/random/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/random/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/refresh/index.html b/lib/Font-Awesome/src/3.2.1/icon/refresh/index.html index 2b21bd5fb..7ee478dc6 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/refresh/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/refresh/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/remove-circle/index.html b/lib/Font-Awesome/src/3.2.1/icon/remove-circle/index.html index d0bfb326c..8a7127b78 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/remove-circle/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/remove-circle/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/remove-sign/index.html b/lib/Font-Awesome/src/3.2.1/icon/remove-sign/index.html index a958c9934..c084da9b0 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/remove-sign/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/remove-sign/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/remove/index.html b/lib/Font-Awesome/src/3.2.1/icon/remove/index.html index fc6cd3d79..d882efaa0 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/remove/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/remove/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/renren/index.html b/lib/Font-Awesome/src/3.2.1/icon/renren/index.html index e77e2fed4..dfb65a630 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/renren/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/renren/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/reorder/index.html b/lib/Font-Awesome/src/3.2.1/icon/reorder/index.html index 5ec292581..2c21871e9 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/reorder/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/reorder/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/repeat/index.html b/lib/Font-Awesome/src/3.2.1/icon/repeat/index.html index 1f32a2473..71c2ee47f 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/repeat/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/repeat/index.html @@ -193,7 +193,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/reply-all/index.html b/lib/Font-Awesome/src/3.2.1/icon/reply-all/index.html index c7da49619..5fd850054 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/reply-all/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/reply-all/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/reply/index.html b/lib/Font-Awesome/src/3.2.1/icon/reply/index.html index d8dff552a..5940b0c71 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/reply/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/reply/index.html @@ -193,7 +193,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/resize-full/index.html b/lib/Font-Awesome/src/3.2.1/icon/resize-full/index.html index d22857883..8a4744ad3 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/resize-full/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/resize-full/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/resize-horizontal/index.html b/lib/Font-Awesome/src/3.2.1/icon/resize-horizontal/index.html index 1c0de39a3..7ee56819b 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/resize-horizontal/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/resize-horizontal/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/resize-small/index.html b/lib/Font-Awesome/src/3.2.1/icon/resize-small/index.html index 728efe3a3..5be879d93 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/resize-small/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/resize-small/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/resize-vertical/index.html b/lib/Font-Awesome/src/3.2.1/icon/resize-vertical/index.html index dcc9e3fea..f52c0db23 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/resize-vertical/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/resize-vertical/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/retweet/index.html b/lib/Font-Awesome/src/3.2.1/icon/retweet/index.html index 3e4eebde2..5898726ef 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/retweet/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/retweet/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/road/index.html b/lib/Font-Awesome/src/3.2.1/icon/road/index.html index f5d17355e..261c68a47 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/road/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/road/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/rocket/index.html b/lib/Font-Awesome/src/3.2.1/icon/rocket/index.html index cfbb04acf..f251c50e0 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/rocket/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/rocket/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/rss-sign/index.html b/lib/Font-Awesome/src/3.2.1/icon/rss-sign/index.html index 4babe0a0e..330cf4813 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/rss-sign/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/rss-sign/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/rss/index.html b/lib/Font-Awesome/src/3.2.1/icon/rss/index.html index 86404f591..a24a126c7 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/rss/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/rss/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/save/index.html b/lib/Font-Awesome/src/3.2.1/icon/save/index.html index 2763b39fb..85d6d4598 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/save/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/save/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/screenshot/index.html b/lib/Font-Awesome/src/3.2.1/icon/screenshot/index.html index 9daf41ac1..880dc4d9d 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/screenshot/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/screenshot/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/search/index.html b/lib/Font-Awesome/src/3.2.1/icon/search/index.html index dfe279a90..6e1bd164e 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/search/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/search/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/share-alt/index.html b/lib/Font-Awesome/src/3.2.1/icon/share-alt/index.html index 7126edd4e..6281e61ea 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/share-alt/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/share-alt/index.html @@ -193,7 +193,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/share-sign/index.html b/lib/Font-Awesome/src/3.2.1/icon/share-sign/index.html index 901169dec..f306d30ae 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/share-sign/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/share-sign/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/share/index.html b/lib/Font-Awesome/src/3.2.1/icon/share/index.html index 310604ded..13434c2de 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/share/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/share/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/shield/index.html b/lib/Font-Awesome/src/3.2.1/icon/shield/index.html index f5e38a56b..37cdd58af 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/shield/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/shield/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/shopping-cart/index.html b/lib/Font-Awesome/src/3.2.1/icon/shopping-cart/index.html index e13eb4ae7..51a82a75b 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/shopping-cart/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/shopping-cart/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/sign-blank/index.html b/lib/Font-Awesome/src/3.2.1/icon/sign-blank/index.html index 578b735c3..29fa381c1 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/sign-blank/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/sign-blank/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/signal/index.html b/lib/Font-Awesome/src/3.2.1/icon/signal/index.html index cb7688c92..00b993a26 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/signal/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/signal/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/signin/index.html b/lib/Font-Awesome/src/3.2.1/icon/signin/index.html index 44d7f6de1..8476d212e 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/signin/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/signin/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/signout/index.html b/lib/Font-Awesome/src/3.2.1/icon/signout/index.html index c6b8dca9c..7ed291f8d 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/signout/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/signout/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/sitemap/index.html b/lib/Font-Awesome/src/3.2.1/icon/sitemap/index.html index 297b3bf08..f1c5591c1 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/sitemap/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/sitemap/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/skype/index.html b/lib/Font-Awesome/src/3.2.1/icon/skype/index.html index 857fbc921..2825667b0 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/skype/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/skype/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/smile/index.html b/lib/Font-Awesome/src/3.2.1/icon/smile/index.html index 9ba255071..f104b579d 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/smile/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/smile/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/sort-by-alphabet-alt/index.html b/lib/Font-Awesome/src/3.2.1/icon/sort-by-alphabet-alt/index.html index ada4c5f1f..ef329bb6d 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/sort-by-alphabet-alt/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/sort-by-alphabet-alt/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/sort-by-alphabet/index.html b/lib/Font-Awesome/src/3.2.1/icon/sort-by-alphabet/index.html index 714f9f1b8..201457c6f 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/sort-by-alphabet/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/sort-by-alphabet/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/sort-by-attributes-alt/index.html b/lib/Font-Awesome/src/3.2.1/icon/sort-by-attributes-alt/index.html index 58bc1542b..6acb8483f 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/sort-by-attributes-alt/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/sort-by-attributes-alt/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/sort-by-attributes/index.html b/lib/Font-Awesome/src/3.2.1/icon/sort-by-attributes/index.html index 298d22e4c..37cbc829f 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/sort-by-attributes/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/sort-by-attributes/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/sort-by-order-alt/index.html b/lib/Font-Awesome/src/3.2.1/icon/sort-by-order-alt/index.html index 01ff453bd..73f4226d5 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/sort-by-order-alt/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/sort-by-order-alt/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/sort-by-order/index.html b/lib/Font-Awesome/src/3.2.1/icon/sort-by-order/index.html index 5f03df84a..abdb4c1d1 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/sort-by-order/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/sort-by-order/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/sort-down/index.html b/lib/Font-Awesome/src/3.2.1/icon/sort-down/index.html index cb848f938..aba2e3b12 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/sort-down/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/sort-down/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/sort-up/index.html b/lib/Font-Awesome/src/3.2.1/icon/sort-up/index.html index 241bbc2ce..82c72acd2 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/sort-up/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/sort-up/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/sort/index.html b/lib/Font-Awesome/src/3.2.1/icon/sort/index.html index 566ee7077..29b32084f 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/sort/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/sort/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/spinner/index.html b/lib/Font-Awesome/src/3.2.1/icon/spinner/index.html index 2cf9147f4..ab904cd38 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/spinner/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/spinner/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/stackexchange/index.html b/lib/Font-Awesome/src/3.2.1/icon/stackexchange/index.html index 3e2598b5c..f8bb19c85 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/stackexchange/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/stackexchange/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/star-empty/index.html b/lib/Font-Awesome/src/3.2.1/icon/star-empty/index.html index ca43857ad..3e4ffe955 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/star-empty/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/star-empty/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/star-half-empty/index.html b/lib/Font-Awesome/src/3.2.1/icon/star-half-empty/index.html index 47bd07aa2..869b12683 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/star-half-empty/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/star-half-empty/index.html @@ -193,7 +193,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/star-half/index.html b/lib/Font-Awesome/src/3.2.1/icon/star-half/index.html index efd0ac180..762c891f2 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/star-half/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/star-half/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/star/index.html b/lib/Font-Awesome/src/3.2.1/icon/star/index.html index e61f90c8a..5f917a93c 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/star/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/star/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/step-backward/index.html b/lib/Font-Awesome/src/3.2.1/icon/step-backward/index.html index 578fd703a..66ec8c292 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/step-backward/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/step-backward/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/step-forward/index.html b/lib/Font-Awesome/src/3.2.1/icon/step-forward/index.html index cce1bd4fb..4d7568d9c 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/step-forward/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/step-forward/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/stethoscope/index.html b/lib/Font-Awesome/src/3.2.1/icon/stethoscope/index.html index 86c152710..c55eff083 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/stethoscope/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/stethoscope/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/stop/index.html b/lib/Font-Awesome/src/3.2.1/icon/stop/index.html index 6de86574e..1fefb087a 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/stop/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/stop/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/strikethrough/index.html b/lib/Font-Awesome/src/3.2.1/icon/strikethrough/index.html index 368d80432..0249e23f7 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/strikethrough/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/strikethrough/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/subscript/index.html b/lib/Font-Awesome/src/3.2.1/icon/subscript/index.html index 1310be1e6..8a45bc348 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/subscript/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/subscript/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/suitcase/index.html b/lib/Font-Awesome/src/3.2.1/icon/suitcase/index.html index 320ecf886..439551771 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/suitcase/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/suitcase/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/sun/index.html b/lib/Font-Awesome/src/3.2.1/icon/sun/index.html index dc53ca9b1..c6d260490 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/sun/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/sun/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/superscript/index.html b/lib/Font-Awesome/src/3.2.1/icon/superscript/index.html index 69b333d9a..a8943a7b9 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/superscript/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/superscript/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/table/index.html b/lib/Font-Awesome/src/3.2.1/icon/table/index.html index 86b2ad16c..9b8c01439 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/table/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/table/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/tablet/index.html b/lib/Font-Awesome/src/3.2.1/icon/tablet/index.html index 529db7aa0..2f64560f4 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/tablet/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/tablet/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/tag/index.html b/lib/Font-Awesome/src/3.2.1/icon/tag/index.html index dc823f67e..4c8d7c6ed 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/tag/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/tag/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/tags/index.html b/lib/Font-Awesome/src/3.2.1/icon/tags/index.html index 9d5f0b6d1..a69a3e615 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/tags/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/tags/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/tasks/index.html b/lib/Font-Awesome/src/3.2.1/icon/tasks/index.html index 5c232bd10..5133ebead 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/tasks/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/tasks/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/terminal/index.html b/lib/Font-Awesome/src/3.2.1/icon/terminal/index.html index b608e3fd2..df33a182d 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/terminal/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/terminal/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/text-height/index.html b/lib/Font-Awesome/src/3.2.1/icon/text-height/index.html index 3d7ccdee9..b8f130dbd 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/text-height/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/text-height/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/text-width/index.html b/lib/Font-Awesome/src/3.2.1/icon/text-width/index.html index 8a84f94fc..de2dfaaf6 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/text-width/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/text-width/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/th-large/index.html b/lib/Font-Awesome/src/3.2.1/icon/th-large/index.html index 7eada0040..93114cbe4 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/th-large/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/th-large/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/th-list/index.html b/lib/Font-Awesome/src/3.2.1/icon/th-list/index.html index 67fd825f7..74f926239 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/th-list/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/th-list/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/th/index.html b/lib/Font-Awesome/src/3.2.1/icon/th/index.html index dd086a909..efca82c98 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/th/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/th/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/thumbs-down-alt/index.html b/lib/Font-Awesome/src/3.2.1/icon/thumbs-down-alt/index.html index 42b382dfe..2033ed7a1 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/thumbs-down-alt/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/thumbs-down-alt/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/thumbs-down/index.html b/lib/Font-Awesome/src/3.2.1/icon/thumbs-down/index.html index 401c9183f..ebb59f92a 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/thumbs-down/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/thumbs-down/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/thumbs-up-alt/index.html b/lib/Font-Awesome/src/3.2.1/icon/thumbs-up-alt/index.html index eeacb9e2f..e761495b5 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/thumbs-up-alt/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/thumbs-up-alt/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/thumbs-up/index.html b/lib/Font-Awesome/src/3.2.1/icon/thumbs-up/index.html index 7c9fefe31..0657c8f7f 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/thumbs-up/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/thumbs-up/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/ticket/index.html b/lib/Font-Awesome/src/3.2.1/icon/ticket/index.html index 333f55c36..9f8011856 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/ticket/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/ticket/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/time/index.html b/lib/Font-Awesome/src/3.2.1/icon/time/index.html index af36297bf..1c6648f3d 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/time/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/time/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/tint/index.html b/lib/Font-Awesome/src/3.2.1/icon/tint/index.html index fb7a37587..4e923720f 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/tint/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/tint/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/trash/index.html b/lib/Font-Awesome/src/3.2.1/icon/trash/index.html index 58c9bb740..9afe64bac 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/trash/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/trash/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/trello/index.html b/lib/Font-Awesome/src/3.2.1/icon/trello/index.html index 0f3498d9e..21121641d 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/trello/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/trello/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/trophy/index.html b/lib/Font-Awesome/src/3.2.1/icon/trophy/index.html index ecdd6ead8..7b1beda84 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/trophy/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/trophy/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/truck/index.html b/lib/Font-Awesome/src/3.2.1/icon/truck/index.html index 158dc4731..c224df801 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/truck/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/truck/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/tumblr-sign/index.html b/lib/Font-Awesome/src/3.2.1/icon/tumblr-sign/index.html index 2149ee5b0..9fc48200e 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/tumblr-sign/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/tumblr-sign/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/tumblr/index.html b/lib/Font-Awesome/src/3.2.1/icon/tumblr/index.html index 276c5131c..a61a9382a 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/tumblr/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/tumblr/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/twitter-sign/index.html b/lib/Font-Awesome/src/3.2.1/icon/twitter-sign/index.html index efdf8ef02..57f7840f8 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/twitter-sign/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/twitter-sign/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/twitter/index.html b/lib/Font-Awesome/src/3.2.1/icon/twitter/index.html index d07d9b160..56e5b247b 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/twitter/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/twitter/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/umbrella/index.html b/lib/Font-Awesome/src/3.2.1/icon/umbrella/index.html index 9c54399c8..e95206c22 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/umbrella/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/umbrella/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/underline/index.html b/lib/Font-Awesome/src/3.2.1/icon/underline/index.html index 3128eb4f3..f9c6f6a8b 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/underline/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/underline/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/undo/index.html b/lib/Font-Awesome/src/3.2.1/icon/undo/index.html index 59e600cee..86e022c35 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/undo/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/undo/index.html @@ -193,7 +193,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/unlink/index.html b/lib/Font-Awesome/src/3.2.1/icon/unlink/index.html index 9cb39dcf6..2a792ace6 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/unlink/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/unlink/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/unlock-alt/index.html b/lib/Font-Awesome/src/3.2.1/icon/unlock-alt/index.html index b37ae71b2..ff43c8c71 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/unlock-alt/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/unlock-alt/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/unlock/index.html b/lib/Font-Awesome/src/3.2.1/icon/unlock/index.html index 0436dc039..494dcbb31 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/unlock/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/unlock/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/upload-alt/index.html b/lib/Font-Awesome/src/3.2.1/icon/upload-alt/index.html index 321de9e3d..8c28a645b 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/upload-alt/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/upload-alt/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/upload/index.html b/lib/Font-Awesome/src/3.2.1/icon/upload/index.html index 1a49e7837..1d0f88578 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/upload/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/upload/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/usd/index.html b/lib/Font-Awesome/src/3.2.1/icon/usd/index.html index 36eb1dae6..c8d97ea37 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/usd/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/usd/index.html @@ -193,7 +193,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/user-md/index.html b/lib/Font-Awesome/src/3.2.1/icon/user-md/index.html index e8850dc3e..2b9984955 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/user-md/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/user-md/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/user/index.html b/lib/Font-Awesome/src/3.2.1/icon/user/index.html index 4fe72a21e..672dcb613 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/user/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/user/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/vk/index.html b/lib/Font-Awesome/src/3.2.1/icon/vk/index.html index 3c8f4e8c0..e9178e986 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/vk/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/vk/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/volume-down/index.html b/lib/Font-Awesome/src/3.2.1/icon/volume-down/index.html index 8c538de50..ecc475f74 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/volume-down/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/volume-down/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/volume-off/index.html b/lib/Font-Awesome/src/3.2.1/icon/volume-off/index.html index f00e21634..b5b33e44b 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/volume-off/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/volume-off/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/volume-up/index.html b/lib/Font-Awesome/src/3.2.1/icon/volume-up/index.html index 8157eddf2..f8d27f277 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/volume-up/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/volume-up/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/warning-sign/index.html b/lib/Font-Awesome/src/3.2.1/icon/warning-sign/index.html index 31cd8eede..8432f0d3c 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/warning-sign/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/warning-sign/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/weibo/index.html b/lib/Font-Awesome/src/3.2.1/icon/weibo/index.html index f76ed2a62..553829ee4 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/weibo/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/weibo/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/windows/index.html b/lib/Font-Awesome/src/3.2.1/icon/windows/index.html index 7513f5ac1..c646a8fda 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/windows/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/windows/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/wrench/index.html b/lib/Font-Awesome/src/3.2.1/icon/wrench/index.html index 6562caad3..c0677c982 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/wrench/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/wrench/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/xing-sign/index.html b/lib/Font-Awesome/src/3.2.1/icon/xing-sign/index.html index b2f482f74..685dbed23 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/xing-sign/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/xing-sign/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/xing/index.html b/lib/Font-Awesome/src/3.2.1/icon/xing/index.html index 68aa1532a..86261629c 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/xing/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/xing/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/youtube-play/index.html b/lib/Font-Awesome/src/3.2.1/icon/youtube-play/index.html index 60874dd5c..e4afd1323 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/youtube-play/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/youtube-play/index.html @@ -190,7 +190,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/youtube-sign/index.html b/lib/Font-Awesome/src/3.2.1/icon/youtube-sign/index.html index fe6f624d9..e0c4e4758 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/youtube-sign/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/youtube-sign/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/youtube/index.html b/lib/Font-Awesome/src/3.2.1/icon/youtube/index.html index 51ec01c8d..a4fe62a50 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/youtube/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/youtube/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/zoom-in/index.html b/lib/Font-Awesome/src/3.2.1/icon/zoom-in/index.html index 294842c82..63590f5f8 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/zoom-in/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/zoom-in/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icon/zoom-out/index.html b/lib/Font-Awesome/src/3.2.1/icon/zoom-out/index.html index 2f1f1881c..06cdc9c34 100644 --- a/lib/Font-Awesome/src/3.2.1/icon/zoom-out/index.html +++ b/lib/Font-Awesome/src/3.2.1/icon/zoom-out/index.html @@ -188,7 +188,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/icons/index.html b/lib/Font-Awesome/src/3.2.1/icons/index.html index d5e9c3fbd..be9fd43ed 100644 --- a/lib/Font-Awesome/src/3.2.1/icons/index.html +++ b/lib/Font-Awesome/src/3.2.1/icons/index.html @@ -1191,7 +1191,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/index.html b/lib/Font-Awesome/src/3.2.1/index.html index 417299923..a0fc75dee 100644 --- a/lib/Font-Awesome/src/3.2.1/index.html +++ b/lib/Font-Awesome/src/3.2.1/index.html @@ -282,7 +282,7 @@

    - Thanks to MaxCDN for providing the excellent + Thanks to MaxCDN for providing the excellent BootstrapCDN, the fastest and easiest way to get started with Font Awesome.

    @@ -309,7 +309,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/license/index.html b/lib/Font-Awesome/src/3.2.1/license/index.html index 6c3ce504b..bf2d88726 100644 --- a/lib/Font-Awesome/src/3.2.1/license/index.html +++ b/lib/Font-Awesome/src/3.2.1/license/index.html @@ -250,7 +250,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/test/index.html b/lib/Font-Awesome/src/3.2.1/test/index.html index 29c535fbd..7c63bebd3 100644 --- a/lib/Font-Awesome/src/3.2.1/test/index.html +++ b/lib/Font-Awesome/src/3.2.1/test/index.html @@ -1036,7 +1036,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/3.2.1/whats-new/index.html b/lib/Font-Awesome/src/3.2.1/whats-new/index.html index 6eebfdf8c..307a1b632 100644 --- a/lib/Font-Awesome/src/3.2.1/whats-new/index.html +++ b/lib/Font-Awesome/src/3.2.1/whats-new/index.html @@ -422,7 +422,7 @@ Documentation licensed under CC BY 3.0
    - Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome + Thanks to MaxCDN for providing the excellent BootstrapCDN for Font Awesome
    GitHub Project · diff --git a/lib/Font-Awesome/src/Makefile b/lib/Font-Awesome/src/Makefile index 2058b20c6..bd98b53a2 100644 --- a/lib/Font-Awesome/src/Makefile +++ b/lib/Font-Awesome/src/Makefile @@ -23,11 +23,11 @@ build: @echo "Compiling Less files" @mkdir -p ${FA_CSS_DIRECTORY} - lessc ${FA_LESS_MODERN} > ${FA_CSS_MODERN} - lessc --compress ${FA_LESS_MODERN} > ${FA_CSS_MODERN_MIN} + bundle exec lessc ${FA_LESS_MODERN} > ${FA_CSS_MODERN} + bundle exec lessc --compress ${FA_LESS_MODERN} > ${FA_CSS_MODERN_MIN} # sass ${FA_SCSS_MODERN} ${FA_CSS_MODERN} - lessc --yui-compress ${SITE_LESS} > ${SITE_CSS} + bundle exec lessc --yui-compress ${SITE_LESS} > ${SITE_CSS} cp -r ${FA_ROOT_DIRECTORY}/* ../ mv README.md-nobuild ../README.md cd assets && mv font-awesome font-awesome-{{ site.fontawesome.version }} && zip -r9 font-awesome-{{ site.fontawesome.version }}.zip font-awesome-{{ site.fontawesome.version }} && mv font-awesome-{{ site.fontawesome.version }} font-awesome diff --git a/lib/Font-Awesome/src/README.md-nobuild b/lib/Font-Awesome/src/README.md-nobuild index 0328d3986..728155a7c 100644 --- a/lib/Font-Awesome/src/README.md-nobuild +++ b/lib/Font-Awesome/src/README.md-nobuild @@ -22,20 +22,21 @@ Get started at {{ site.fontawesome.url }}! - Full details: http://fontawesome.io/license ##Changelog -- v3.0.0 - all icons redesigned from scratch, optimized for Bootstrap's 14px default -- v3.0.1 - much improved rendering in webkit, various bug fixes -- v3.0.2 - much improved rendering and alignment in IE7 -- v3.1.0 - Added 54 icons, icon stacking styles, flipping and rotating icons, removed Sass support -- [v3.1.1 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?milestone=4&page=1&state=closed) -- [v3.2.0 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?milestone=3&page=1&state=closed) -- [v3.2.1 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?milestone=5&page=1&state=closed) -- [v4.0.0 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?milestone=2&page=1&state=closed) -- [v4.0.1 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?milestone=7&page=1&state=closed) -- [v4.0.2 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?milestone=8&page=1&state=closed) -- [v4.0.3 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?milestone=9&page=1&state=closed) -- [v4.1.0 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?milestone=6&page=1&state=closed) -- [v4.2.0 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?milestone=12&page=1&state=closed) +- [v4.4.0 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?q=milestone%3A4.4.0+is%3Aclosed) - [v4.3.0 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?q=milestone%3A4.3.0+is%3Aclosed) +- [v4.2.0 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?milestone=12&page=1&state=closed) +- [v4.1.0 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?milestone=6&page=1&state=closed) +- [v4.0.3 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?milestone=9&page=1&state=closed) +- [v4.0.2 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?milestone=8&page=1&state=closed) +- [v4.0.1 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?milestone=7&page=1&state=closed) +- [v4.0.0 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?milestone=2&page=1&state=closed) +- [v3.2.1 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?milestone=5&page=1&state=closed) +- [v3.2.0 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?milestone=3&page=1&state=closed) +- [v3.1.1 GitHub milestones](https://github.com/FortAwesome/Font-Awesome/issues?milestone=4&page=1&state=closed) +- v3.1.0 - Added 54 icons, icon stacking styles, flipping and rotating icons, removed Sass support +- v3.0.2 - much improved rendering and alignment in IE7 +- v3.0.1 - much improved rendering in webkit, various bug fixes +- v3.0.0 - all icons redesigned from scratch, optimized for Bootstrap's 14px default ## Contributing @@ -75,6 +76,17 @@ to the `dependencies` in your `component.json`. ## Hacking on Font Awesome +**Before you can build the project**, you must first have the following installed: + +- [Ruby](https://www.ruby-lang.org/en/) +- Ruby Development Headers + - **Ubuntu:** `sudo apt-get install ruby-dev` *(Only if you're __NOT__ using `rbenv` or `rvm`)* + - **Windows:** [DevKit](http://rubyinstaller.org/) +- [Bundler](http://bundler.io/) (Run `gem install bundler` to install). +- [Node Package Manager (AKA NPM)](https://docs.npmjs.com/getting-started/installing-node) +- [Less](http://lesscss.org/) (Run `npm install -g less` to install). +- [Less Plugin: Clean CSS](https://github.com/less/less-plugin-clean-css) (Run `npm install -g less-plugin-clean-css` to install). + From the root of the repository, install the tools used to develop. $ bundle install diff --git a/lib/Font-Awesome/src/_includes/ads/fusion.html b/lib/Font-Awesome/src/_includes/ads/fusion.html index dc8cb8ae0..c49a9f42c 100644 --- a/lib/Font-Awesome/src/_includes/ads/fusion.html +++ b/lib/Font-Awesome/src/_includes/ads/fusion.html @@ -1 +1 @@ - + diff --git a/lib/Font-Awesome/src/_includes/code/core.less b/lib/Font-Awesome/src/_includes/code/core.less index 406162884..cbd0d1ae7 100644 --- a/lib/Font-Awesome/src/_includes/code/core.less +++ b/lib/Font-Awesome/src/_includes/code/core.less @@ -1,7 +1,6 @@ display: inline-block; - font: normal normal normal @fa-font-size-base/1 FontAwesome; // shortening font declaration + font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration font-size: inherit; // can't have font-size inherit on line above, so need to override text-rendering: auto; // optimizelegibility throws things off #1094 -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - transform: translate(0, 0); // ensures no half-pixel rendering in firefox diff --git a/lib/Font-Awesome/src/_includes/code/core.scss b/lib/Font-Awesome/src/_includes/code/core.scss index 2b02720f9..c7ea6e0e3 100644 --- a/lib/Font-Awesome/src/_includes/code/core.scss +++ b/lib/Font-Awesome/src/_includes/code/core.scss @@ -1,7 +1,6 @@ display: inline-block; - font: normal normal normal #{$fa-font-size-base}/1 FontAwesome; // shortening font declaration + font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration font-size: inherit; // can't have font-size inherit on line above, so need to override text-rendering: auto; // optimizelegibility throws things off #1094 -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - transform: translate(0, 0); // ensures no half-pixel rendering in firefox diff --git a/lib/Font-Awesome/src/_includes/examples/animated.html b/lib/Font-Awesome/src/_includes/examples/animated.html index ba18ae4ae..a5f61ca5c 100644 --- a/lib/Font-Awesome/src/_includes/examples/animated.html +++ b/lib/Font-Awesome/src/_includes/examples/animated.html @@ -29,7 +29,13 @@ {% endhighlight %}

    - CSS3 animations aren't supported in IE8 - IE9. + + Some browsers on some platforms have issues with animated icons resulting in a jittery wobbling effect. See + issue #671 + for examples and possible workarounds. +

    +

    + CSS3 animations aren't supported in IE8 - IE9.

    diff --git a/lib/Font-Awesome/src/_includes/examples/bordered-pulled.html b/lib/Font-Awesome/src/_includes/examples/bordered-pulled.html index 276641cbc..4eb596da1 100644 --- a/lib/Font-Awesome/src/_includes/examples/bordered-pulled.html +++ b/lib/Font-Awesome/src/_includes/examples/bordered-pulled.html @@ -9,18 +9,18 @@

    - + …tomorrow we will run faster, stretch out our arms farther… And then one fine morning— So we beat on, boats against the current, borne back ceaselessly into the past.

    - Use fa-border and pull-right or pull-left for easy pull quotes or + Use fa-border and fa-pull-right or fa-pull-left for easy pull quotes or article icons.

    {% highlight html %} - + ...tomorrow we will run faster, stretch out our arms farther... And then one fine morning— So we beat on, boats against the current, borne back ceaselessly into the past. diff --git a/lib/Font-Awesome/src/_includes/footer.html b/lib/Font-Awesome/src/_includes/footer.html index 137970aa3..cb71330f1 100644 --- a/lib/Font-Awesome/src/_includes/footer.html +++ b/lib/Font-Awesome/src/_includes/footer.html @@ -1,10 +1,19 @@

    xM^K=#Z#=*%gC+Lc4LN!h4m~Jr`5BV@VKx}n{&Wyy&T}qMLDILtr=deSK%yO{c9b;Z? zRboh3JTLUERbFsziV4s`p{pdY zNSNMi5xcE5NvycALp!;o7Ls?&12=Y|WL?!P3pbZjG;2)hgqhaGor1JUQaC5;fO3MXFz9IA zjqe@U&!Yjl&aStK-uuiwrr;@F8?usHAcs75mva{OY2Vzv;$_iAW=~5tI-KXVP@8+x zZ{x|vOmr?=a)X`02b8wNP^owPhQT);&B~RLnefptAIrl5257Cn!S}MPM|tvSR0#Hz zOW(5iB&tx*^x7m76_m0bAwH*Ujola8b7 zbhsg1bP2CRS8W*m>X{36s|EeZ_9n5p zryHH@Onn3G8SAcVuDI~xFa!0>8T!1{Cvyl#INZ>JQIr~X??F3@AxEL*NC?KjqIVA> zaE4{wh%C*bx4fLE%Wej~N?$J`uvpH}#1LL=>Evy9`>0hutUYhWu|dXq(l2_^yH1o( zM%gxJ5LSIEfT7&toc1iQclWb4F@#-%gg4{ovN;%TWBTc!^xH3OgE5IBr|u4Cj+^7~yYVrQYluxS@154M(b+TS(7&N$R(>RGBsx=bkjn|OlIAnhdse5*J0+knE;H0| za_5Atz%3~-)B5QgrqNldR&ZXpJ@)BH{1s-|GbF;b??gmvpEFOU zU0NMn>2kODZuvfLS_WO*)61)G)5V|7W{Bfjb+pfa8$K=L$Qw4@)37{b)Af1xeHsgM zs)pV0{64D`8)VU(Q;H$3i5b(hdSk_o!qtXDKj*R{H-&+D<x{V81pG}8stM-VxvW&Ww$yy=X|)J);~>5Xu~jXyrtze zSac3Zt#M~KT}kb3fiw0#carn$D&pXcnlC6F*2iAdPS({5=80X;>!^p>(t`@l~YUF$m9=}BKz^DO$E zxpxKy^U3gf<(QRQmZxO?hXc#Cr znb8W*b`po*eOFUuQO$o>#(t&|ng!NFAp(q}lc<9wyf&+~o!Z%6v(;S^wPN96CL`mh zgZ-Z4!mAcVYY;qizK6nSNdF5t6Y`ae=o&L78n%@5ZE_|fi@5QqvwhYoSWiwH{g~c< zr|htmsu5mIui-GX(1*o^^Kqo-=HWtJAsce=pLf>&T0Rnww)@^#>Ge7|am1&a$;VXBR9muMlm6f9F4+v9SVEV|xQybXH#n zmw2(FU+->%h>LkY&J|Nn>FHZy(abCA zOuY?e^$wrDu^_%Eu~-cb+uIrmF|B;E5nAM-3K0ByCqkW)Nrc+Thb;Oc*O>{eD{R+G z!!X+Y!=oj#CADG3?@n(l9GFX`uNqzBX`#?#K}4}|*+1|;UgR;I6w4ITu;S&%fS7zB zu1n*Kdm7YII(^n*a*Uss=%8X!nTk}(A{%Uh4acua;UxPoIlxhmz{QGBO8wJHxwXgu^0I}|qN-Lwsd+zdi*CMrJ8OyKqNz2?`YGk-%Pt&1xL+pC^ z>|stJ>p6S&T<`wD+ePS6UR*#>cVs(5xPAk<1 zHWL<9riSgnp>$0#Z`?#j1|MlIl@^k-lYh=Up>=ra-D=^um=AhFMj|l@_u}EcudAJ& z!WyGsj(-NTMC9+Yq($`R6}x=razt$}hTnSIHrEib5|GCrQIO-2hlziHJJlpwx10`9 zkaR4`{j|r&afF3==_#e-Kr_*U;4=t{i{fcf-l{@rWZv|GdZzFMK=|X~Cn;TEDd)THLVEQDmiPgF7O^7%1?D}^$vB_&TWS_(j=1SHqMDRLCu4)b)l@5BP z_ORm4=s}gePEDmOmojwtrRiy^FkToZ3(}7Q5f?MLI1wlt)qW=@Oz+XavDVjZ`t&vazV zDBlP2L|a_{#M9=dU`V|L;So+$S3L_5p$7-SgBYtr>gXQHARnl4#*-7JDL zuiJYcrXrX6&>b`#wD`0rUlfDOkl4t;u@y^MW+;}=;!20Emrg}~t}hU6CLbnYP! z;Kvp`DKKKeY0>dT6rg)-==zN7ee^``mmBI<-K}lqW6=?JOB1>upipTi-^own+BaNK zzq}?$Lf&ggOgdXpwfj_TEejJDwN`8w&-xj9bOcNILlb7l8GYsgb;mNbh8;Q@s?ST% zwIzj~;%r{#2a+oFrllHvqlyzll^JE+gVpM|s2+c;qUd$&He{>Mixo=Y^7WaP5$!x^ zRpQlUP}><6g30Jve9JSO?giNq+u$?U(#Iyu58zcKxY`%IA}(v%B_fq2ebH^Pbi8N|85Wc&Q8L^DeYpy5k9@283Fd&M8$H? zoMC7!x@1L;@%+Ay!pNy^9V4 z9i^T%ZuxJt*_gxxCkvNm4s*)2AJ=z1BvL!k@cfXhGPZR#t?~7liQXzZv^FWPZkO0@ ze&;TKr?;VpI;=K^_Bzl@3?1lRyfl7pxc7<^(j*~PVU!W=7!0tQ z2(_0RmoY6UMk=dI7O(5fF`bYmpDl778Xb@rBzkJ9Q3n*!T0$F3dmJk-8sItLxkoAsHo z6rIueEM;I(%r;y?o>MEZ&|r0tIKQ^R$!4&349%Xcf5madiXmH$@$As31%0r-_4>V# z@#ox1XC}mor?nugsf|toPa1U`jTH6rMTbf+mKp@jzN2(4r4(K$=?ZP_`tS?GrNZ8}@G{=%Mv>*fdY_>oPqA8-qN+;L z-dFZmA^65UEq{mQ*F$+J9fN%HFP>TG8ck^J4o}b@C_Q#5#*I!zN-c&pnl8pAAjB@9 zRD?o=+UuU5SMv85Cg!*~a)kAGEyZV=A$2Khq=`l0bcMqXQop+OFfSZW4^Q`3i4N&~ z6Fd^Dy)SHn7o$794?7ujm?80F-q>bd3w}e%bd_7>TxkBMwRHpybo>ACGw0_v zMe|>y?LU_n)M|P@cZM^RXj`os!CmQ8#F<(Q%Zy{m=qt$Vu7EtFa-UpKnB ze(Qo+s%+nj9sSWlvHGtRjJnK&GxozA--fOjjqrJ};bzA9oy#M|m%e_uU)b%A;Hx*- zsE#Qhvb|M5{60ZHq#;+^e8sc=wzea(A}P3MgcX%jzjWzT5H;%1rM=NMLCYG^*uy6= zZ?2(-V-_W6+kA(~hw~4Hn=y4eX;JcuxJI~HIlxIpTlK$$b1!$+bMm-0O@F1&SzdEm zGm?2}|Ls%l!k+HOZmD9hj%9Su-16(qik{61{Q`0q;`;L`d$A<9Pzt7bVVII`x z6;01xyO7`Xx`sx=IW!k-`PK-T5)4OJ=M*IK6fHH^S*1AiE`*YBA41W2E**Udxopa!p4EC_XgvaF^9kldEsNY(rSumwSx-0_PVeZ<)ZElk5u6KI@cMpj$bYZeXNPk5!*rU$SI@j5=ud?Z^wCu0Z?^emp>kX>m^a zDNIrw<0|Awa_n6b!Y{?du2vI%ZoOn~y4Zw9LZLW+TnwQ;hkN)2z7`#oB5>=uXSlEi z=34{$+msq?Sxqe`ug+K%xhR8L_N~ZaEd86?EtwR~NAAL!l#NCr0#lYAU;bVR{Fj;) z60$n=dwsDxG2X{(-*bJ3B$oad@0w2UIHeTMLH-%?nXXcYhMk`1B3c=Gf`!~8;^Yp; zc!_#von7RY4!eBmAJ~1Nk@rBd{(`B_+7~)_G4g0hS_s7r#~ZD7>6LUeao2PW^KW1q z12mb0uXhyu`gkfx~%TZ)**_ZagMi(7I7S2~L=`&*)UY9lm&GlzQmQ32Q-e%&%ZLR$=Im4cg?5oQ8J+2^RQ!~zg(XLV*@PkU*w+e=ClL&2xXNB;_{0kk~xb+5DF)L2k(tx8u z&FLEYt!(Jb)i&?jy?o)9n4Z#WgcSi_%}>s;>2cyqNjaLeDoJPDo2Yk5DwH_+=ejc&WzygEA!*@@Px^u?+V0f2*L+gr60WC9eScWFijq>1L zIow*~qh;BWC0WmE=4*_I2e)z`N;QtC^`bHd(|jtgn_$9mWK=XPjct88y@tTmL~ zfaaU31Wo8zjqze<#DKQ7?v4E1DbqRIDiQdcMfk>=SI0_9wf)C&So%bY_>|I`#>wH) z!cR1wDw?MsUVv?w_UkW4kcvH6_RlGdnb|2Sv0$TZcJZJxe+6>la#Ix-c`QmdY|cV0Xs>s5|ZPKvPrPbQTo+V3KACeQ~F8P2~|}I8(;KgUam|@ zvU!oELv1=83cJZ{g(DiMy_PtbG9FDeL01JUUE3Uyer=*mRKlLydB#jfsS9h@t{h5Q zqlX7Ft$&q)58drSmrEE0!I$^KipC~7u>&7n>8!f!j3#z@Ee(5=w9Cr$FKhR!ge+^j zK6+#vOk*BMW_&=JwEna})gXDjv6yzH!?!SAzR#~G;F}lCaXW*)Q7xaU8o_Fg!%A7Q zMO80sbl1X?>U-V@DL(RFiI8vW}BxC>0Vxx~KN5;QQxr;+n zy)%*pSN6R$RDdz7?7wMnX)AS8ST6_r3+f`k*t zfqqf0m$E#0AB)UIrOvMxVbocdw!9iG5i+x+rk;x%=KU{v4Z7*nR-oXDHlH|EcX)TV zHc{)f!?v;M7m-$dyr?MNptASXyzcG|7tgR9YSCrVOArWIjHMOnphJ&4&yCY2nTvd* zkR0e?JHnu@_AIsxGD{uEI%wJ`{9d(X8J=3x7Kd)4RFFT5Y35bFZsp9@QF}GOOuZ6v z25o~|!;pttw2ACL&)8B6IoBtBt|gZ!B!hYdJA}`btk;kyz1?(}Hg}mqbjg zse(s_35wJuGX&necQDRcb|IX9X2#h@3cx+I{HO{T zTEuUK%@O3TG_e={I^NvMcY4=RZFz zBheG1vysEb-C{#_=EjCFOzJUTqa!?haUt<-)>W?g>D=sEbl7U4%w;>j)`xNNOD9k3 z#JD`u%Ui3<%IH zzr0Ww`SIN7ttt1_^8)s|C(Je66x5CMkUiz~)r-e4+=&7X4m%>;qTH_Y_Bl00GOyQo z*ExM$-FZdWcD^;(pvwN!L4_V88OqtN7#2$8$TQ~=a@FEF7N-=*c1^J@=cE^4r^#h- z?9!=;?VoK?J-geAQBoLnGI@u;YtpsX#A=vRlRHyxzdt4Lal&gYNa@o)zU;oG*b6iv zth;hfjqD30PS_E;lY*>#^k9G4bvj?0x<&WfTpduXw!m;gY|hN54Fqf!_P%7&>l>oY zVfPg`A#U%{+cBqTTJ|kTAyabV0`+q3HB|3&o8raLqzlE!*GT~-=+WtZRC2$@!yyHO zWL=ZyJSr>{fjZWpFlM{)U4)b@!gjvVNP=s(1UoWfLI(L+iqVZ%;6b}#xEC=(@QmUa z=#uY1Z>gB7xFl9nEz%UetHtlC?ylwrn<|w!M;68I`G*T_4-1M8v^rL&-k58r=xP+{ zKcI2sdQ-U%#c81lgJb(Gjgy8AD;ULe_ba~auTP@SJ=i;_yU?VfYI=I(IQ8qgryR+OPR)IpOE)H&Vo!(pi||PM{g*{sk3G&? zysvz(SQCk)ueL;Uf+-Pp1vHKbx^d>?kcu>_^x2YdK*$U`}~5DrNc+eD|ggNT1ld8@@E3o;M>ZaI@@e1PrkX zQ}E|swC78x{Hko5FPRuPzNV%ks7z z5P20oc}s`X45uEyww_`JPcD4?`P#UnO#7uXemTX<$)|iKmRxhWySn7R?}#z}8udXY zEcKMLksqbrt@vIvWBE?odC!tH&tTjJ6xU+4-cjSsQ=%InN5bt&%C z?}nSC*fbN!wK~W0$sL}YSstBjZA$93t7=<18zMf)GAI*Wk^tNKKpN#snWM}byxdGGDkQ}z|WeDdj zuCI{v=zH-YPSvVucOZZ-L9NReG6F-b=IX4Lx!UUTkMh`Mk1@ad7e zB>R+EE7}$*#NMhoWEr=&-&Sa0Ud^qVl zW~3r>gId8lSyk4kQT)zYiJHvX&ccyXyr-8dsg^D_#4?KYPmJ8qn$05NLAI%4Fawm> zfiWnIxq1P$R_CcZS-pIFW55W7NG)!Ppl=;zkQZ@nzAPr`*p{S|z&!{3@1sxlzQ2rzKa9p}Z_Po!bjmerbP4wz=p?YU}CO$_d^Rq2ZS0 zZR5R7HMa~uWojC;n6e9jfC`^}u=SH9&EBbFbN#Z8lX}a2qNAr3y2`5_=GP^BxFJ;W z{B)ig|Bdyi$;?wZr)x7Yki)_pxGTUT3rdHF3df9(v%l?M7|UTmyW!@U$BJ*_w5+=f zNLwx{nsBzIEb&=>v=AFFOV}vr!{B4kc0TSp=N7$k)*h@L3k&`>i-Rn`@2+c?MH-z7nCXNXO`c_6 zrPI8FIZC?zNSC!j>XTW^$pj%^2j6_-58ZLrLzjXZULH!iVr)gF6jZ5pjz1H1J&Iaq z)=PqBDR}Lb#iEy?X!KGj>iV!GW}N)#s)%C>E{*Z!eH@pM9^@WHLUHaj&SBYxOP#Zc zMXUK8MFL2jiYunKZ=IWr6JK!V6iH-8MKW_Z#TZ^~wPI~u^o4zmDsloRLN($%se6Z4fXm$9o-2=;rLM8&NRgCh3&0x7l? zoB}P0I#a4l*3VYQi&Km{1U4*rXq^t^=ce>#9hlJy5u)t4oM;x&9U?m{bwOVTb#tAtm+th|2M0y#4-*$_HZv?r*C72B%6q(C$# z{?TU%nW#6pBDL(b&=c2S=jMnKA$q4u9OpA~y$Unafc+#+%gLxJEYoZLRYF)v(^yrZ z!bkTQ2cunJwM1yE-Htb~!dca9)X;LAkIB+O9nnu86oL+gv59LesFDvjScVskTO7&1 z83u)JYA)0~IBq+3He5)7L0dZO&SL5r$~%?ycOR}aEZiJ^j=R#|@+xk9^w|N+dTr0r z65J}znF@C+%S0+pwY!r&G{XBTtlgB02?2 z_KCtf^1`!wmUy0`bYNV&qJk_#f?J}H(E_7(KD2E8L!2FmjbcPM^ezEi&njM-K^yB{ zl6tZf_1Y{&p_*DVoP*JDgQZ=Mw9$!5aZ-8|wa*-J!GmGA5WPw>7;UsP=35*Z3oGM= zw^nd3wP~lMCQVpOYTbKmKX^{Dh8J62r8xRJ@pQea$n}cuS*_{UIk(@`*w8K^_ExU$ z7Vv?ghieV9P!BEq0_Q8V)8f{oC74CW-?g1+AY-waX>O)9Qru~H81q3<&plDm##802 z@4oCV4!1si!EhvNl^q9ivUUw#ra@WEH19$>A$v6#hW5dw)$5j)uW0B>Hs{dSs`-u9 z(r3MSvAigpzI>+n;qfXqrUn1B10n~DGSa+ZSMNvXEG@+?)IqjPlIcdasV1yV&B@Q2 z>v0j~LFtEnHYa0WT+eq#7Ay6$Ov_ykxhms4lKH@t7sk;A0*yRGWII3GS$+_%T=zO! z9h7;q<^sv^N$S9{``7gA?;VL}`uP3G#ZbDqGugT%F{>@I`$*jQU>%d?lcciCry|!n z6{$)JbI)SD?BJMu4_;S9`6N zM@9e0*$!E+52~I#ce0KtyjxhhSUi#LrPFGB(6Gt5${oQ&bl4Jp&#Esfo>Gx}Bl^p| z=}9`N74oT>+?w|`OD~-JEW&e8s0|nfZ4gplo+2e<wmM~T4 z`p`4>-M9MF8grYXm~|06xIJ9Tg4_p!8a*VmV`}LFmP{{SO%Yy}X2axq6o0*EK&7_2 z+`r)fGo>jhNJTaCVwx9T%Q^So5;UhVr6Y0AVu-|4+@%W(tddK)N&eX^^M*r0w7)EG zQKp=;Q|V}x^GsEZgk~&#$iVu@p`dFPtsd|jwkzD@XAHF|*6ViDY8MF~%^^wJ=*MA` zWF$~cNgYLVR!M7Lt(J%AN^F;9U`sNK{%E5XFP~_&pcz!fgB#Yp*5!}CEvDS23NOr@ z_%^(AIO~lyoy%>STEz}kz4D~wbc22N2=cp)t}^3-$jCSoIMyoPO#0o)%Uv@8kB1f> z(ZmW~(^T@)Difs}Jh$GzlAV)`8-`}TeV|fv5PE#}pV9NXGLdkYVnuKf_ zd&|QtvL?C}t@|F7=m~kN=GZ=I+Zo2tqjq&+hg%L8_1#3qx+^SoD-v)4FbW`kTARCy?tul-gd z*a+pr1da3fPwb7g_cgx()GdTi{EILn9rS^u6eq!!=;rX%l1LYCSL8G_#0tNF+ zNsni{RI|w+(jim74p(x$sH@#(O8wyRI;J0osgOYpDTpm(ubsaw)J`lgFO*{cE=T`s zfgaL`-r(Kv9^K`kBmSr)YdfR2nlQn>>G{A9rhPi5A{S~kf=8^{0^6<>DT==5H4fle z6Eq!F7`~`~0u?iJNbgWU3hVTAwNB=!4>v|5XNSiD>F~@?Jh}7F77&u1w0)W+x>EX3$6@x!C{4bS#Qn#?YzUh~C;V_RVP9svSmcf!!`;(5bQUW8r+x$p3{ zWf8HR8HiN(aTI9P7tz&ElnM5?9zj7t?F>r(Cgi1;WEZ;5G1UYHI-Z9+8R>W2Zl>w; zknzp`D%_!CImnJn3L_^UvHTuhX@<}nvqKC=>zZ%S@jwB`2QQiv84cdX%k!|s+zSzo zofvt$k_oPgzv?GK@~~oX(QW zQy(O=QJxYv>j-%}vRcU^#l$@P;^lMPBr3e=j~NcQYmK&*bv#&(56q-1@rVA;TV{J7 zwKKj@KUX{~h&8t+bv(q8teEy_Tq*5SVhbP1nP%Q1x_7%@GR?({uI4px_cyffRL-{Z z7U6ypM?JMKiIb;N!+DgDq}#zO zBu0wb56y)p89yiR5@|&0?KH{hanLK6PO|!F(_cPqv$CY=f(ltjphHWPJ}r)@iH5_~ zS=+CcWU5_5+S^5yd2{jF##gIwmx?6osU5rVZ?YutyKHlWhP$KX3u!ev|?gb zMXw+^>Z6x1{;v$2nU0DNYqKh(O3``NKM%DgnzK8pv-mim3}PXgQF7ujsjt&)Jjd&` zR9Xo~VP#(5_=$kqOSO{uDBh`N#iccM*4XJ6YGxAmUJ3|2$Yyci>WFN}Kif1+JX^7} zQazWx(IkE*ien(DwLZoX>1MxgkkNHNqd1QU0^2+;YLB$%Lza#43%5xZG9d(QZ;tm; z7Fj9@`7ydcuL?#LHy!MAo_(ha5kz|Yi8?qcxtQ5EQ$g8I)abQQ&?a<3-6c6a6yd+J3P!aXEXJ*7DtJ(T;|J1|mAisOK zr0=wJjxiIQWJiU@tXIEtDm1`?`{4;~EmJln{x_rrg70AydEY6aW2khnekrs*Zo02E zk#U{QuX__FBBc*@?l=>0SvG2S<=!cJTcZ!w%sa1)E^3?`qSaBL})!f$P z6%vXLdyX4iajNN9%b>Uu;eCk-!daM(o%6#I*x|yNvm13tY8hluOodJ8lXnicpR}nq za0u!7mUO?BhK9}_oj}L25pUb;Z6n?heS41W@IIldIZ3vTRgrFbEGBR@YfI>*uvE|W zUZuV)m$$np&EHoQ+s8GYJwEp-kbbH0T5?*F8S`j})4t9klE%cyD7kHKHE6EfB9Oh;sx~+`Zml+ z6xHs+?os01I`0F$rAcYzrPFaV1`Myrb(CZ1l!S9u&vZV1kL24RyGAk8%k$xcQ+DJf z-o)GM3Vf+gXGh6d$6dn&%irwFrc+qaN>7<7KY*~VPR=wFnhcbUx+N7XJDe&NY!EE6 z%qS`Mxx#_yt))85^$ISPI-opBa=cc~Ox&`F(Z$k;ed$V|#}r4+5ntOz`*h17RLoRD zK|n{d&0#}zw)29q$krX#sTo_1=SN2DTo7$Ob;DGi^mpvjN|nR?CHUr#Unw*ER6DO2 zWso;jq@B!EA9H3+N>f)Lc-nvYpl^0=L*QzUsDO~X!83Vp3rgr2uY&1d6ui_Qp> zT1T55Un6|qM@ROq5?$Xg&zZS?PxyGW^IIlO$12Ce57m86r&`fFX14!88)@bP0_q)mFNUw_WH*m%EvDa4u>>NDEl4?RCK zj~iSI)R6qO%*Y0ugJB(rPzPH4?s1xAZmRK(?@cxLY710D#8;?T|Oz8y`$Xlt1RjG=YeN1o^xh?~Fm3LoaFb%gwr(GJo z!0{#i0B6;cqlM{)ciQbA-^de3JpDEWEUYhf>0Bm+6F*HcI)jM$KaAu$x*LHI{nJR!WboD6 z4c~1Yw`8D1#K6qnwa|+RTC?$qNkK37WTL5M zq|bdRYtThx6)*1DmwkQo6ertNe(kX3&PSOB_1wCjF1kL9b4*BnHPwVJw-awO{6Hss zv!P>o$i2v`Pmvoj>wJK$V7z5mjMQ-iu{=y_tZHgnpIPl8bDW3YN}y(48|4Gh$oAKK zUC3zazJoX9`fI7$2)l1@ThM&Ra)|774DwWO`4kv=Q}sLTj-a_D?Xnf2U6LPk;N2sGba@gC`eV+*?`*}DZnut7OLRR> zuzOXdns$TtaP?_y^WIB+YDABVwmdnc2h{OU7?eQoo79N?N&nOsB%_h zcqLBMj$T zep8)K&Oh>1fMfh&-&{}dnK;#deKR`t-KgNqKuVg3%T+}&MTf}y-6hSc&xdcHcM$%* zpJumKjMdjCRvl-EqmLiUqn(8A2q_-#e5z7zpR)=)|FG+R6z97&j*e1wt7Biusj0=V z1DvPe>`h5=-hC!r4ztp{iOt{1`ca=Mm+VJwo-Oq$KGkpVE$FCt6#QubrNGSvRspN0 z35Q#wEhjkP(x>Dz0z8C`tuamCb;YbiONblEZu@J5=Gxm&oi>W|P~zD5_EF=mvAXQo4y(thw2@pATxWjS0xui2lrLEo^r^0OO#T~3?k z+p2|q170>n=iMwUysp`1rVu-*3Bd#=56NU|AD^0h>jnQF+&6vlrR4xezq}2l?yws3 zO!>2X@##m5vN$JO#|TW|KDF;H_f{9tXMtrwGexb9qOlOlO@0`hGCknlJrZQ|x^3zU z1><_PJky-0qS_2!UIi0=}W8}O~8L|sI z2Ad-PY)Kx$$|LV)&9iuxNZo;v#ph#x#_-LLd0eR>CdM-A)inJEqB8b5o+*6Y2MgHq zIK_?W;+lnIiEYM`{8;N@zgKyS1w_3hlJbc+x=Gh=&Tc+A zWHl|>%gz~ko7BCO?I_AaNq_mYWT|`N=|mYucjrXaDdEO6L5b<|4%ht}(eEf9WEx&^=T5xXd%27!Z-K>Yykx{ePA@0WDlK_DuM*J~ zywSkN)H0kOCi+0eyJK-tc%FqKt;yob1GkwXGuLo-B=^fo{r87n@OgMPl>L9iop(@F zUAN{NP*4z1kqnKB1c@R!G>E9EAc*ADB*{rKG+C4kEh14eN`@xqC>bQv1fdDt#3nY- zW#opswLKT-&~4TSD24PY39F!Qd~h*mN|zcvYc2`@M6| zP&5v%n;@mLdubd#5sOo!)g4*x(j|bMj~z0IBCtTdeN^~hJ9F;;eDPVruCAU`4kO)m z?q88Mc=!g*6A$;ZynHhy*QcXTpoRZ34an*)*!Bx- zx81MBwq{+MV5H>GQE0!W8+MwU4T<((r(U)#@R>35hctHXOfRKTVJgSK#|g|YBt;!} zy@Hn=x-!kK7$+EnscwX>ii;vlz1uVbsSQdKvO1;-Q-kW3vNk!Ofw2xP zX_BhI$tVV@=gfKoSZ`wRroEbL9Fp#FxLy%szvr%rw%A#3+(PQvk6xdy(p+~R^%3W< zg5YpYyhnJTjCmC>L7R7_ETLq9zO;VFPaD=1B}hSc&YTx5SxKAYVBTocA1WYFV-6)x!;AomQ2iY1X90~Bnc9i2ktoAN!m%v0hSZa zly!wBo-G!VHVvL-wgXbUe~eUw$sEk}sxP}5a3q_p*rI=eO)Ko!u-T+Jwjf19@_c{D z=#ZZbHNakYMC_edPr_Fghjw?E_K()f4$v$bZqp@{jLKrggRM(m6dzE`ezStjaK|B1 zqK>0mGx#|?+$m=z1>#JR%bhEPKhLS+8Yy(-IWq9X@K zQ(6QeP4fM;0P9NZyaLm$91@+6loXqkKH8nGklq%>IaAMWMx9JQ{eA6`O6j~aRbJs2 zC^Ju)n^eiYP=4G`Ry$j6-mGP=tE@6NN7L!Dkv@x56`jv397hBO@_8gDY-`2p*2Qqy zK4fVNfwNb)ZFaj|Cl9YJLnV){(ulIq?GyzVpPUbngpEICT5Xf;x1Ef;{sb9JVH8`F3_z`wt7?>efbUl^fY3WhIGhsONNp ztItTjWN)d5aTRD3O48{V(!q`uA1}aa2$+16be*&y!~K&T26E$~C3%&v4NGK)fPT>y ze9lSUCQom6w$oWr^#p9=E?+$KcSL81!caPsnsw!P6Snfc z8m46N82q8Bw;RFRn|}S7fXSxcTu+%MMVVl)L|>@9`C0F6MRw;>5=&I%{<=LuJ-FS? zqsTN3uq$|ZI_POml|;COqfNDI1$ot5@j}(#(ECKsG-*5BM zjj|tSz^*byPMtjauQE1BhBQyT+7AsfxD)+*LG=6n*OAKW*0^|QcUlIrpN|}Kap`SN z^vO~~VQ!Gpb;I{=P&(@Ii0$EgPGX0=EadmK&doc%tIeu1E+(y!a84~C#jz4XKm#e^ zs%365#R`q*s_@obj{V9d|&yd;?g!)TWZt0Y2D&zb-|TyM!Elt zd`|58$WxX6Y_vEah!nNg#|LqkTf1I#>{>7;@w+QSyE_jVMBEhmeCmUp8~DeGX=4wQ z?unJp8)#+KYJ)Pv>_7xv4D1F{8QxVjsq;W*M5w)+g4bv5!fM~WuWA1C*T(tM8zP;$ z$8)pToI}`y7e5V6RU1_@JDNx_W6R-t+Od%z$wM3E>&Tu^y1$bsd^aN3yiv3ht$AXS z@B*Sj#tf-@OL0Y_CO$X6s9%_tSsyU;ZMouv%_NO!*$!YaIryOtGm|H3%6s5tMGs?S zVjTYF$nGSPvO>55ku=^6rUoQL4g~3VtHZYK7Z4yTJ!Uf9cLschlQH}J9hq48FS%we z=Chom3hR4f_^VI4k0|`u0~6EL)FosaKBhz?TW>i3q_E-bcO=Il=?hj~Zqc=0kw1;n zhjli~;d&n*3#Nm6J=%>Q-;Q&=D|d-GFngVRcu(&0fQYdeF_1JkG?8WvfnPvx<=dIcrwN&d%{NcQ?vX(fw4;$v`y*cOgSw}bzZJMV}KuJT zkLzMXGoR5sQIaoOy}>+Mx=LeMLc~eFFCw|+@&>lQv4eTtWKZ%IdzS|1GQ8$j5X%z) zxah;U*u~KB^|_LOAT!9$FK%?E1=N!J+H^&> zEJ=KrDE;T3XFuU_*H~x^k4RHcl&tbelLlV<;!Q+p^3}(CMRXFf&C1Y zqr{)Eml~Fpp}Bvuwos9@=DFCtCBCU*r^bxzDE@ z0DmhbCTy!BPNAMyrtH3R37BdeDc^2cwvq`GPQ&tF8g& zAl;Hz`fALdc?@HJhLvVFPzy0D1W}RXbupY4@@fBY(MNtTwVE)60?Vn#nsH5-Ohw?0 zu1N;JpP1p_&CY67nB+K=!&j{I%KMdAm6HE?(-HF z0U49@24Kt=X9Q8+)+CS2)xJvpk=?Z(zYo-Iw=LB5$_9sKGTGFW_w87Sf7y+CtQ~=? z$M8?wNYd0XcXUe6ZVpCwQ6U%SYNV`5K4?%9sGB!%*jAX=XjjGsejC4n>gXOUu4wwc zUdg76GE86bytHBZ*yTHdNzPo$tt;yj2Xba}NVpI`4Upv+*9L{zz&kdP=5m z7E?$3XU)8rRP~d|mZ$3Nll}6io|68Xgo8wtm0+1pL6EniTb4CoxE7M$qSN9< z;Vpf$RB`t|SOV6GKzskuf8O4|Yr-V>g1$8zqY^BLbh9VO*m-xyxy>YilmmK|#R6Fw z!(-xUK>RL#)!sE#xFTyKlj(lMYNKVpJOMj%Ng7nXeO$ds3e0);{UXK!II54ZQt3-? zaJ_4QbPV(HSHa4&+$gTp-eN1lSVyYM^+oQw_Rd)I!&G9%G!9K?zZewCgDZSaV<&lR z7Xsm&xFjyFe@^JI0^zTb)S9NxAM_7XCf$Vie9IgkKOKC*EHEF|R&B~B;FeZ_UcAL9 zt+4j)PaRS4v!%84UDALXY|gP|KJRIP?E`-`LYgx64;w7u_wyK=5-YwE0_&$ zsAgc)_=XqdngiVj`fR#kBYBz_--=gx^_&j+<6+!&w4Lu8X;m8|8I9^A!CL~;eBO2@ zl?q^F7~(`sxuGIOq!328D#h}s?Tb_o(RwiKMyIkmGZ(~uF?RCqJzuxDth83y~+-AK_{w=3#^kJUN-rTd6;5d{( ze{T`G_STHRp*w`_EmId6y~J>@(z;&N$*+LtH0m~h55nWa!i|_2?-j0Qpt5dbI>WYV1O1SIQQDGPF(SLCG{BUuBTCw}hI-FsuA8v8E(GF9f9eVNTZ z&6Ob<>}ksey#^*szTx1}bsy(%uc6Fqq@#VV?L7}v#V3k z`vw}ueAf_jcDXwTue|@j<0MgU1DSuU=Hu+FxF~LngWdT#PAMz_E@T<3hVM>k4|OKV zS*+0>aoUB+@hT`r>Z=$Ex9iZitG4}29iQ6Ci3&#TS?ClgT*MOSP~-*1^Q};ui$(>bzefT+1&F?<&o=!XQ{wZEb4-rrN(=9r8qwaL9^K}1b zx|vE1-Vzj8t0k#r|HosK-PoGGr0Nhh)| zQ{b={+PXkVgrxU1_fYS9zP$G)Qw!TEk+n;7qhHW5M)z*IQckyi%oiV{7Q@_W-RR2L zL5RGHp=B#tW8&~exT6xb+8+>4=+hNLBznjpLMNN~ap&DWU5Dd`XWVz`j@0zlmYJ6I zs$}}hJDTF^lLs6rxfR>Ai5(5MQOr+%CFSHiz|i}-IphyiYzvWSTP%M+fb!+p(PbTST>09zD?Px6FN45bx_lGQoNV4d+WAcTnU=3Nl1&rc9qVzF`s#$*nyZ0~wzBmt zuwz!M8i2~5GA|2)Qi|5Cgeu$7UDuJ7H=s}6uX;Tx_9jvgW$mpxR*Q(V>vetqXs}=a ze{I?0y0R?)4P4qUG5F;Kn96BbVJ1RoExdJ+sDw4}tv1+BvM0zGm4ppk{myxG3pkPe zGyYCelfmTt7lM{er`e8N1E8E!y|;yLJ8Ouv`e#tQT0D_SZ#8`MqD&76TC8SI^GHg6 zU{!@BYX43KHj=;9&dDU7&MTDP!Ph$JbxHyc|NZyF-T!*H&s|z$_o>o|=|MSbplANO zMP$T{7b)976f>PHS$Hiq`S`DA8^2jRrSMBhYn{6O>z$;>*ZwV#PStOsYSC*~GnE}2 zrY)faPT&RXagwAhh-@+MceSjmuRGi~aigj-sfXgplw-_rPz(xvX;7D{8E#mly1Jgx za9eZHk%4sa{q+^E*uE_0<|Ac-cLRC8E36iqatk(Y^opc1cgpym{1;}Y@3|_dP$rDG zR_Tpy`G}Jz;VBWkGnov0s~&yZS4CkZm(e@cI;j@4Z(I!-SG6sqnDoT^In}xI zLjlpk;dZ0~KS_6EL1cDH#>S6ggie-Vrt%yHvDk}3&}!{0Q<3|!lbuw$*X-mjh-`ta1oJSb%XuQh43dYH}Ie?t0t!_~AA?~?_uD^ex8Amp2~2TG`w zDAR%Z-pgD-ZDCwiJ55oXX8WiYcNPVLsp`si3i{>8VyBk;$Kb;A!hvl|fmpej4Z~nv zlib3o4G__WQE;-rSLRfYh4na$ksFu6e6z?Od!qe#oe`<{Oo6y~^FeyU8zMOgl@ps3 zcezqk>2aZ-$Y1aAn4fj=={?ZLQZSs+@Fa{DJ@}@9aaAxBdFVNH1_X)MgR=FL?16fr zjuKj^=h2u)evg&rLT#f#;n;2m;8@Tip%f1#;MQI86bK=3r6sn3M>@&@q>vNrPv26O z$LGR6YX<8XhI5_*ElF$poe5)y2Va*JV?DKu?)N|bLKLudx!3PK+j2Mczv05HT}zHi z7;J4Lh+Zu^{&cm8ET}N(If+Yw^J#j}M*wExlDrG~-L*OK8$;B$FBnD5eQ~RE%>i7; z*;pi(>QcngzIK$>N)meh&C-qJLyvd`w!+mT2tQU@(CZlHD#SO=Yi}G)^?2`*upe88 zG|Tp!USQBidX*0uH9j^w8ucZH4{=ahj zIIgxeTpQOD$;aas z+4f#+U9Q&PqKXYEqWJKXU#jOR(EiLDXD4czHhhEQ0QYZ`cbA<4d z+yP#s2JeiWWnRG{l4AMDe5T}A)$sABiD!jsovzY)K|XitjMTqpX&}{dD@{UjW3%%0 z@Km!qH;30^gsW;`g9gGH4!TSo8;D08GL+@Z9$iuad>KlFl~Nb5iA`QV1OqFyrC2ui zZm+gXDH-jnIBISSPs%3@$*&E1^=M>b1Yy_WF`hQX?Ln$Q#wEXh2y@Ib9VAOKc2Q{2WTGb&5_iJdSgwfj8zsfR-)kCkm zcr1~<;`!|lW23_}IaNX9ZB5H51E_oO{vq}=a`pBs)wVrQoLnGPB(- z7R%~2qP|-G$G}NuwB*L7bMsIq+6Er?>d$A-@Q!7KdqWS@pgZbZ(cN2*vDQtZlJ=;55G#Y#jeS}cR1?fth+cAY^FGZ zAR#M}Vv0}sGW^Hx$`z^7noUv<8JOc_M3+n+h0ts>J zpXuJh?=it}6MAt1UmN_W+gSh^usWYU>`#UGxK1~|g*M%NdV{lss5Sl*Hp4|^R{;I{ z91S7Ip{|17y0YIQeAQ2P^l?{grNuMc{TipBq+hKFW?D(P;ePIQd{2p(QtqR9g&Qu= zZ?|8GySRczkr|JN)?TS>7~aWtxvLrcBF-a5r?)uQLnA*@xZ~T{oz&`4wwmJ#lYAC^ zMzLr46^;+`#y5`M1#Pz#oI2i8tNU&sN%`xwa+A$2bvkQ~hO%|$$#sRsQC&=L^gHiW zh4PHOE8ZhJML8OATOXt(kv>)%aHG8EhGh>gIJd0|r^YOA4s65~;G|X?@Si)`^B(`Y zKCKU$HfrmoXH=7j;nB1msnb6#C*pjxNG7e4{7vMG7?K)t@~nDOoaclEVG=2i_#dgh#w1Hc-b(8iXP_!AzwvyF?l4K0->o)BGA+o=;us9Uy zUxa_1*zf zN$#WGtAA8JvZ&}i6E9i$vKXdxs5<_ z5@bh>6tqID2_l|I{&|b-E(vp#2)AkbR7+Vum2|+QpXxEsSqh*RQ$3D6_0Tmb6Caf% z{V09r0`kpePA2o$^p+*^FWs4&F6*blfZ?)crex)rJgk!`kRviDj>m*?wJbSW*=s$c zh!xtQ3}Z(qJHJt5=N@fkiP2;}joHgeGxfjQ#B>KzE@n3PBoEaUtef`Vhqz`svEBt;EP>p30bP2esLOQS2~{kPGz#(+T@quJ7lIxToaxg^N!2V)FATi=g^|>4Z1cXL{v@sE)p4H=F4reZWd)fLdS|)&7gj z!Z@=X_}q8sIc*v#mqwiAP=N?C)o*)i_wJEzyJ<_uCqkdQ4(#d0Jvxp z@Hc3FRswfZ3(FEDII?`lkTr4Ns9cXTReF5PG`>;#S&v<>nBj)cj_@Ptoq2e{%67@9rI|XReS`y3IJ-^+r4_8*nvVXll0jzP}L2zeiaY&w@6X^?AAcgqG z6o6BP+5nkN6DM!~A;PqCuSITy8d$$mN?GlOt$iH~pcel*ju!*^#V5%?%+E8$WxFz7 zX>LZKe6s4t`&_@&iY0UnwvJvEG5*kQ{>~EgDA(ELqM1ax7&bLE(+JzJHYkHl_Chr_ z$vo99GJIy1y=Sma(#uYvO~ld0FeBL^`63;~b1dRKZyoHjb>K5#BzSRYPLg zMWm0W6M1n7OU9b}ESZPu*Gb?DZ8)@*ya|E{nhxoTrzTWbULv9m_bZjRUSPR#i1Oqy z9t>ode?#3E_vKEMc>13i<>=%CmL3hL=0PuilNVm*yz@c}vYRmQ0IkRm&~Hjz#vhz7 zaL8z%3w@Y5nK`g~b3FM_fI;iex%K?uhF|4HEo88>L`UqB?_B6};O1L(I?o{axx$s~ z(h;TMR*zxs<-KxLHUXe5bNOcMK8m4G%WXGpmx(TELuTKXOV;X5n>OMzrGQRnh|Xg6 zu@D%I*qgFH?XWLM0f?V*SK~Y{#?q(mQDjao13eK>grF=$dAu_oy_Ma=lCsQa^c$dH zRlywErC62dZZ6EATz7`ZoBYZ%DRMSXWgzXQ|e&6>>Fh>ZT(nElxp7Vz#- z2EQu;{UNpbs1E=&7DLYf&U7Zv{RVD(Wl<7^aGIMmw-R3aj38eOkT=eeHKwg|wyi;h zTuA}*FYgF%>!ptYIqr=bFWmH6mb6EU|C&a3RfN}w*&KXdzDt=rg4Gs(-|td659co( zvDx)JQjt0`Z(>rNJU0Faue!fWpK6>p;9_SokE#ctm6E;ZytZfJasHD>_u)b7 zxRX<5Z-PM!9Id~_vmAORb#-O%(u*PGfF({zzjq{2I!UJ2lAqZaJ_kbDr__FfQ{K&0 z;RF}Ti%#Fu&U^s3>=h_v+yR;vq2N8R0 zkJS!s{%*Jnlo5H~X$U}5Zi$?JNe8Ouh7neZE6OGYw0@p|U$;FEm2^DaUuAB3i=y*I zQt~fPJiBd_|mGqFsV(`#F>?GXyYp>6tXCG}j*VQu~RKl45foE9!=p*e{eu#fz+ z!e6A@o}%A+hY-c6v-PS=jw$cwlqnwP$mhG|8l2_iSFxWUPJ0k5p?MEppE<jyzKWBW>#qp|<{z(`6I#Bto`IdrOiKAXwZ@q>c%kf}PTbyptz{Tmn_|poXRRx3E zkfz(1c}m~IC0ROtY6)OS5TZgaAXyo$v-^GpO&w;4pHO zu=}Cj9UYv<7mBViD9h~82-GV(%47CzQPS-%owr0KkSO95$M%anP{kt!Z%h*+A=q#Gq&yx-9(RfHxl} zA}`KdwCQZBso^+s>o9Vd4AynL>DE-Y9^b!M1DJgrGL~INj)smL!*^LvpBR7xhYmf8 zzr517{cf!-7`EaW@X>7Q;cL}$bOz8OrK_<%QL`zJZQPbitKYc*uih%fTeg z*zRt;Ls;>cd>pKXlXzbzmHl)Aex`MFqIrQeC~UkO2Ct7drGK(G7cG5$LLeTO6qc92 z-0CuXa`Z(JXif&YEH^->y9)(HlvRb~XDU|@YpOIk|CEUV zAKmemST>`Y@*17uL6`Di9QYWZ@f!9qU)JuwEpe}Omw?0i)p#Th5>FGSYdKFZ4PRbl zbd(CBI6t>S>36=**+vbpsxqMok}v%^^v7s}oNv+?Y+rvI2DBLT-+fU};u^jdLU5Jj z>Y5~Ik+0zoqnI99`L&M#qTn*J}_J z6~04Z(DL(nmUE--pVNS7F<7&@C~|91a15b8`t3#VhGZ*T*Mpdo)(F%{!rt$o{6W8QmZ=k^I z^m_q7no0oS{g)D%@llfQ*`cZoUUhK`0OWt9`S_+@Pp$T$@uLJQ8OP5Rs_OmZ%VE!w zjPvj0-j|wjj$AHb`|%n%?%)?b`v71Nsa`g5WOkK$40z6zjdj+QAZOd`ia8Sw|7_+z zIuE@`vL)&~s4w!UZbkY6NF=+m$)wUfNxJ)f=*Nim8g=rc&_ zDzQ5i&naKhGp-P z-i6TEgcO7L1CRYjkhITFs9uu!A8%h$xqDMnBG-)Wk@*{U^YQowh4^a3#~%RIz58!F zUjhn{H!maZr!yJd){_;}qN55+2nebB4MqohlXAE>09b&A(t$kZYxxtxb*ag)j8qLL zr7v=G_=Nf%-}8YB4?JXc7qY0XNzPZeWamG4H|Dm5RUv6M-ZDENpf&(VsA*1Mo-Cs9yaj&R z1;3V^{^4f8?p}MOz=Y#knr^X=M-#14%Go&&w zwcW29@=%q@zc7&%JG@+|*jx|EEeVAYcd_c)8`LttMIH@4eqsEqJ;Q)Ri}NFYqhn}k zj$B~%SC$pqPID;?J;^08raOPI`s%cW%`|Ws$ru$tUhmI3!?GT?dW_ddAFST9HI0;? zZG3coyhZRV%>(ZUrD#CYEqhKBP(gKVV=PvT*(g-&eo4xINnA{_&LKmHab>Ut-l!-* z-+SXBx#8J#;E9i&k)R3NVb`7REUc()n!C!cb+P7qh6roYz-!^hVR8!3OQfJGn_@Yy zfA_n6xBA_=bb;BiKl<%YiyQk2?aPkaIDn#@*;p;_ zpc@5R7!xy-0EZ80l)Nm!N4#jz8+qt$3SpifmW~OjHFt|3X!!Ay>GHM}Y;t6UPm&4j zYAp!kg4*FKmtMW4!LobnZpYN`5q290soAr|Xxlbf0Av`~=YUo|qq)mb{-q*o_~%Ha zjZqx$T3P*voR6CWd!VgL(b}8Zh|cpA58YHSc@(<=uHD_6#`{6J#}H^NgfN-xjdL=K zjQla-SD*YR1Eh^BVU0QU{y8W1K5fs!E}qkNY)1-YIOXa>RL)jglAz{eafL!O&MJf1 zqJRE$cGl{WBMVc}mcwh~vC@Yvly*i%g`t;Ks;%Mfke!PvH`|g}b@hEUB(JQ*vxp9P z#_~K?(!i_`QbLtmimaA4a*8i+Dz1O(3^J%RAoe{SPCZ}wfq`2n-jSq>ST$6)9v&Ji ze^^W~B621CZXn$|f+0FNDu37>lV_^KfEcE~X1vCQWmyB&z~!=(WD+Sb{^w+-Vjr{a zNs)bgyl+~0jpr?ajQgn}F09$0fQY1))#t!)z*$j@_0?=g{)esFcI(B48P|4cKDanV zJ9p}IPo9#v);08czNZ$uQW=iq1?pLwu!ywK2%~iN++0fl>i*5R7%GdmlAFBiEoUs# zh460QovtWW&ky_@)><~(U9L>el{;8#QF3p@h{9({q{{_4MoKi#lkQ$uTV731aw@C- zX>d&Vg&an)%UY}CKJfXbn;os~VF1l(GcN3-!8JX?xoiGNsID~!m)oAG8)e(Gby9Sp zE>p=Z%+|vX<;&(wXl)S1EiD~F2DyguGO-;?lZM3KK7ZMpBS0J?z8iP7YG zOE|cm6V7=$;f^+Xgav$Z#Co=CKsWnGS@semWXK85Z9a?zUc^@)!aZMB>ov37cR9F< zUJiZEbRiIx-b&A0t+nEB)YANskjZ0g$qpBPm|*61PM9WtDrma}pDIg-G>7ztBqxuZ zL^0_lPy19>r4u9vqK}+VBSu8Wg1;tT@U@{Pr$@9jkgVk01@ zl+MwI(4z$n4VQlU9&yny-Q&w&_mF<(YFD;Ec81O&xHlHD%%0Yzp&xE8e2qjP(Rf?% zw|Lk#O<^>0=JoH+MS&BI`kn5=0&J4tHzzxqx*3cj(Qgm1YPS1gw5~Q%+?;cHn#XQ6 z&W9Kn9_rR|%zKh*Glrt}O7!iticn(gVw z|5rk`El$T{OuMqMBiDVgs-s9^nc|$kSpsPUQ>M1v+S})iwGjH|WmLN1msP`!=B?%LFL`p~3L)eznj$Q(lTy1!bWuFRw?QX=HrILY+E= zwWU&9u1e#1m4x@A4Wv0D6!39F_@Uc&l?jFG$(jk)(5IF}DY> zo17MM0zGsbZ)S>D$uB!tjpoHl?}l5JNeBA}bZGH<2`vd4I5B%1Kb__kZyqW)gYO|i zRWmgz_Jk4V{nA7$cAx@^Dw(|9adO&gHfW5HkrdHfRIP!cvssGleLDMjcYhs{$2Y{y6hJ`B?3e};E> zEm;?_DjNjXv5|-+j;%+XtN-;G8kdmD10Z)&0^>z%CGpVK@fYC2rIk*r7-*9<&QMrC=33NAPn%?Q(hWR5Uaxjz z>EbT(xZ zW2<>havh-sOO*M#M?|;3{*Rhi26TCwrGKVC;6~JWOvw^5J66MKPgtIX=8ZT5(Lwz5 zZw)_er7CI5%nJL+o;OVb(^cLuCHq%rOW4Cb)Hp&m+PUO6=N#K8KYyfwD99nWKQ%{`<3>_tTh;x+*v%DRLJs-D-!mj(_EJVSAn*W`6qR@1unKY(> zoQ|kdz{k}~lSMZ)UNxp>6+F?!2I>gtNS>5G;}+0zv`84K*2GtgYHr?aLK9?1#!mmX zn(fg{6%J9!6cGPIvYV0#t=Y?U$oCj1Nx_Wf0HI@v{=XSIAVk3gPCBYDBt036%?rHA z&Av?yPWefQIIrWdhJz|!0k*7X1P@d#Uuw)DKdC3kEGo${P^f=IKwvqR39Vxw(4MQJ zz-P-X54P1v71tRXt={SW$u>~9e2f2AdSvDBBZLTq=ywEqJ7KHbfjO#^We}l?>#>i}b?Ilm-1#o!b9eD;VB0ds z-%(9QZwEQ{_n~8@Aw*rIw$y>hP;<~>`2IC>{SZl_sTsWp5${NU9Os;X6Lr6oZP<8E zS%0amuu?mBldvmN-0gDHb8YBMU~lCDwvSY#s-jD1E6e}cVGRcz`eq`SXGcHUV~xU) z`EJXR-M<6-wwucXi{;%eV@5Hgn3cxwkaTlX*AR#DI)sV{@sO6lT%wcQ_Kl7xlhkD_ z^q%<~OmDFVQ7~g0@7^}J5UO;b4EIc%A(AvE2=)Z!Qyl`NdEz3^+AUb?kB$fOk`9kg zn~zuo7~Si`4}r|uR11KLU#s1MvznJL>uL?6RQB1+WO;L`+m%wh_b0<^ZwBHFc^-I91Dc?4FKnq>x3aKO?s5e6 z|FaP^9+#i)!^Nv!fKS(s!Wzr3Hj_kjp98RG(~lWZ0m-6& zbXKfwz5^HZ2tXzD*IWvck~K)b5WU9g9mHutigBJQ)A^;am>%W_GUeSJr3iB(#<;Z`9&A(PF(1bJIi!55-qF{n3^d6s{$=H(dE2@6$O zrgNy!Q9aA!tN87yH?Q-Z!8itq`ybK>MGQAJr91mV{hWE4nUM|5C0x#jXU{*h)Wh zDp%?d5K^x=pEZ^Cs5GIuDWr*mvZ{~g(jLAraKI;I_c?|R1tCiwY1|MFDQnbS81j=- zFz{%LH@`vQt%H?f_u-1IFdPcBy1R7(@bYb$lCAbXv4 z;w0L0aJIy>Z%$m8E6NL6;=RWF*_N2v%k-?7R_Xm{@xP?+E}DzCuZ+A~6L6@YmlwdN zTes^>d5=>dd#j;v9IRT-+sbYzabd_&Q75eN{M}c1W?tOAI(5CsGOX^2y1|j$q1}Yf zdRU7f2&G*&iSSWz-Ib=VI{Q6AM3zcmgIwAy?_R{<;!o25nJtrcYnYvQjLN_2%Kw)P z2UK0s`TxfmQwPX8wmaW-&z!HSun=~XHxH(Fv>Ar9nn^7-kH6q`32#YHU1TyTsJ&<4 zG-y>Iz2?aC+mvBpu-P=lAufLD@$AVE!ynP|f0-U<6es4kJC8m!v!e)s zUK%qYXRHfNyIx$oHt$Yp5+H5rf|-XY7HM)DI62lhTHhjm(XRIT8tIi;*e>R7;cr&$ zB$%n#G*k@iZFDBdukjJg;3D0eeS^zZ`k6fbilwV{B-;lf@w*cr?FcRz%(d`&ZEfvi zNXv*DB9fKmpxLsRM66SMx$f#*&2q}gk@#{_fK2|z0GUz%Ien1WroRJafiIf8YN%_g?jZnuwZ6ahB5cIp(s8`afBz^6Qcsyr-Sj|YUhb#Zx> z@WCY(Z9ZU66Rk!-Chw-UnbaolA1;?9;TW9%b1Uf{uaHI2>d<)%tWziuAvLC|DE_;Q z7&ybJuQfWVQ?f*yhGu*0bobe4mgnSqEqfH4y(3Xtw2ovdY?0y>4<1UI%G?ExQR)h* z9v$V{EN#uQCIvLo47&-4nn)?{dz-OLa~3*f^2eHhcFNbmKFSU#bKIV5S-vcEY$+dc zRD;&*&i1ELLsSFgM%o;-#phh*SNao<=g8+5zG6--Wvs)ok9n^aCM^N+IV4J6p&tDZ z>d=h?4r@A&7TqK9@j8d<0W{O$$8mx$2B$vTjyD8%Wdn2d_W-f-RkzgwABm3jmAT zaD0-DR)44B5_9ejHXLwmVoYN!9`P#5k+jv*6;DA`_tnY_{MhK!>qzneQu6`usSAe6 zXeX#9{UHaUW+{;scXX`TR!86v(!duTZ4o@Zp_ScV`}O+569e%2Viy zoq{qO-M_`)en(FSPl>nz6&-Ie0FK7oPemvBtLHxQgQeVy zPfE$XP&CAEsb_c(?WRfU9KPcZjua<+Y=|Py1&)-Bl{$AX4BA8-i(1D8K^+`2K)Gd_ z#h?s7quIC<(+LHxDWbmfOXXH2>t{;IPpktSta&@sL<5-D3P}|=^9Sf+g+nYA!==Xj z*s_?~gEPS{&4WT?I@p8XDP*abcS`E=71|fS^O^H{8(ZAK))q1nd{$a=PC8*O7Tr$y z9)~mhyP;I7`7ZuWUfaU*dICHCE%GDhT^oXBuwY?%$jMy;kA;!1nL10s{+XEc7resF z=oMc8=NlurS&cC_INyom2l7oT@KY>3=p&JHFgds z=3_Xc5K5vG@82SQz@OJ!{;k|GalA2?;{})(7n<$f&emyd^*?xG(`yqra@aEnsXLDb z25E1kS*&wDvyT@v3lzZ|vOg@2>Do7J{jo-zy_ULPfAEQ3(~dx!Ftq0y>Nb~x>o zZBOS)2iyHju$@i zi920=VhdFT)&LMtA&Ewe!DIrwYCvxd^|rDUmN#(PGaCAqDewUftmSq#r8Qsy{O{$_ z)2`Q^6w!U*s7I(cbJXwVb8lv`PDbn`+sP|Nx~fM}g@-hL!~F8DgVWT@st#=%c}pB7 zaPC|k$u2Ps^r6{O)mg{>0_HOEFiDfz4ySXJx2b^v(yo(D|C+O!z=O>h4EuNECH_vv z_KO4J)QXAfV$q~Ca-(TA>pK|OgFMd}YH~gsY}9-<-MnF_Gxu!z!3vnNaXygIu70P7 z+aS2=<~~N}spJF?3+vOV0vKZ<#$=T^E_}d4y@?mfZGc4C)iY$HV`drhu}PBuLuaLdH$HQdgpZDJa9=N;B5EkE z1n#{aRekS}(m~vBBqWBjes$ow$!ED%L)WLfK;Re95Zf&W9y%Z~WqU@8`1`SS|MFO( zb!XIhwYi(rCaO^Hq-tF0ksIdj`3I@RIu<91sj(gJb9ol;@;a6ehuib=MNQ|&*>EuA zcnEl<15Zq{Kc=Mi2bug>OGf=HF63 z8?$e+(+R2b#=X2)Aky@n+n3y`-`$+3jES#XUFdY>cf>|KM;`_Op<@c{dy1<|@!ILW zJ_~N^3#=Z~`ayimFjY;`0V(eG^mBT|eo+#C%8g?hctGPPNx>}Ptm%yGL#6Ze3W9FU z?|Cf(F%ut9g>s!5!5I;!jFp->XA?@px{p#e;Zi?j(;t zG>91U_oxmbT0NUwSqy&9qG9;adBF0&>$u0hNR;{mt5-Ex;cyY`Oz}M7ahXUAL&L64K4F; zaClXG{Nx7ljh6eiQLmJhG-$=qSkGB)C4uAOJbZi&>A~sX#9O)DL8}`E;$5CM*3}rT zTQZ1G%pgm*qFb4G9sb|mTh{B<;$7o>(Uccdzb2Fw>0%KwQcAHa7mLqD zx<_ru+e&5bF3VidyPX&~pj^i117~?tkA9nf_yhNd5T8m4b86bYXCYj`)!BH|XMc`t zIGFJqxV%hSA=T&D(yMC@=bmk7z;i9XNpZSZLw0t8#y5YL4j$RSkh+`aP~l$arS1lB z@Zvhx4gS+yG1HP^RO^;tx_^`8(v@FnLp1bVUGxXd)g)$~&CBFV zcfi;dNe6-1ZC|#{-i?r&!_Q)O4FbF2HT2Xyj6P*pLHh=CQ1b1qhdZ{P>o#lG&?I2@ zxm1jPKt3iMbVP;w-F!WqHjdb$Y;z1YJxF6;=xBX2T)q=6;92-zmU=#?d?{_R!ZU$e ze60lS=Es=T#*1*)i)@Vj$px)ca&$1QZ9ueB&dVDNyH~~;P@%g&`Mp=SSbPrWC0RTc zqI$E*2o??vqoS)-Zk^9mKWolK>ZMM&-&DEbI!TTh0#-Rr{XbT@w;tF@>OZDrf1mNV zXOg9#_<#xa@3Ka1{JQ?ELwP5OyKC;?{|bQte*Oi#Z*u)n{%rqxcjAT@0CqS%1?eU@u)+yu-2aSE^Lb&qbN0qu z+sjMvjqb2bTL3ta=@|j)&K=&r^PTUU|KNiUo)@1l@HcUG@E7stiI@HASHHr|LtNuf zKH6~)?3z7*OJZCezy0lRKNk1V{yQGo{lA#}zc}~Yb07QM=RSATb_DM3<5YUnAIG;{O5WPvsvuml75L00007VLKZ8Q I21W)30RCwt83hZ52tAe~2$?nY9&n}ak;cXuf%UDEaL<9#0W zx%d9Zc*pzs{o>d%_FikvIe)X~Izfu^5|5FeBE!MKJ(iLbRfdCmC=Uk*fuyAk2^0ocm11VDXC|^pSz`$+{d%9pmsX!k@P%jzc z^6u4TbLZ5V=gA$h%Qizd8FF`YI|@b&+`YQTv=ZIIPFRufl?_seGZe|Go0mdOJl!=L z{Xc#jCZqN3^}p2+I4S9|aTd~3lRgB)-GfK}|N75MgL_T;SYF~k*C53MsdXIMvny@C z>ygI4P*#amkD24-81Eh`cv%gh#rVBRV73o4u|CISuvSbBVH<;WUDt6;nEKspv-$2m z1)WIN&sRNY(2w;*;r-x1h@?KPd>|(!EyvWHi6=U93pA=WneDV{c{NaH>rMf<{WphL zu$O+m2?x5xkfgR`ko_VX6-aF=M?oR)hb&MhyGwvcTsELhgVb&+?3A{ zF}b8hZzeot4WMV=7kVxIRKx!|un)Xs%A>%Lu%EQB;oz|qGHR)g3e?0KgPkJC?e+y# zUa&JKgZ@|*Od0?%Fvy-mcr$VSJEh9{o?u$SYIhV*act&a%sbHaX%E_1RSg8T5Ead6 zowkpNlqQPxG0SD%)3$ zmA;=fp+r(yzl3%nK7t{r6$N0YKCKD@APIETdqw$;(9T5;LhoQc?}|q~=~kgnX@p1) z&P0!>vSq)FY*&MR!H$#=)YH}*(-EXMW@#=J{WgMpBqouKi*P}P;U{-08Q!$MFWteB zH~)Et&rfLSh}dT0`t0}FJKp8|S`y)_~gVl=C zc{w)pHxs~4@XIC>BqLDAoLEk++Rpnk^o*f3xpRfM@=&z@* zb#OsgLp=rPzgYNB9loXqFSnNoywLq)%m06!-`e*7jz8f33Mm#1$%OCpYsYIFi{*H%s)6Hc(`m5n5@aTvT zxS$yHx8!oaZQ>tKtuhc7tpTLj(G9wiT!yTOxP4Zc+uHpX(bVqg7ERk5&bKW4y}H~% z%j8)yTk3R1#H_Q7W^?18WSyk<7otc2A|d>Ma`)WlRU`j}w?BlB&J7{Ul36)iE}~kq zOQHl9o^`e`5LBLRg1sXBf*a06@jotytJl$MX-!!XI%v3=Ze8&~o9HQ2TwseVqLgNfXbS4%HuRD83WHbT9Pf;^9#|SrGC5~U1!HyIK0flQ<6crYHr~>cMEKsV?iU`~)VOTk3B~z0 z1ruUUu8J#+geT`(QUXBLiNi26`IcZhDnLMbZ3kLcHBhhv4W!L zJ2=oQm}$#h%x3zhoB(b=QhmAF{V{0yT}NenkNN!t4%<0PHLR*1m6^d57RNaEu_=7O zW)CD&{GgWRc>f}5IFKh&XfTZt#om~7`tVe|m%Bmk6F&Z26cR>!9=FgXLkeO5=uiOY zFV9Fu{*{~0%pk^M*Qi?Xx8uUNksCx*-`FREv6srm6QlV9L{0!lLJkO(Y)ke7K+Qji z0DC{cjN_Q<`=RS_+0bNA8xuvNf*IE#bZY6*{vHnW8D@qX1t|>wa0tIa!G;-_Fp-iG zda{I%y_}U=qntoZza{uBD-!X+J$Mi!c$u;_RpR?UH-&Ldq;(W}TQFJp68-AZ3D>e>2XI{s+t0HR-6!h6guhu3DA(2TNBKM9DBUYC?|W z-i!<2`XfyGZ4wY;S`#s4wuh;4L)kQN012b0M2z6TqaWx40m1*Ni~8`(*zXghJ4{>) z=6$72KDsotj;5bw&=&#*0v#oi8_8~C^!dLs=Mk$r1@Z|AzQ~o=9gw;ziC9^5E^P@$RS>6jL@&fp`WV060v{I%qWf+D+5t8IEZrsM@{JctyG(Ft+^h5; zul=uMk838?A(IA2<}QAKCjMQE9!X}nxJ=;HExtlC%Zs$Ks@B7f&K-UP;8_vCbHMbs zQVZ4j(aD-u=2;a#Iu0u<0s?Xbs_*{;b(sw4AsvO8vu-6R-B5u-Px%InZhyewSkWr` zOUEbZGCwkT^)WJv{rzn40($)EFzP>$6jx`~y((mKK-ear^Fk_^y&g5X#T z_V`PYX}s!DjY15Lwl9;+v%deJWCU|~wmoZN*;$)m%9(ub)cMId(mnWxK%TLE6y5q>R&h5qTBv%IwR^SDNi{K~A21}w z>s^Zrpvi<6C?8KwMxmL*&SEVAH`g-@4;VE0FV`u zwi?RuIJy$@KXgd6ftGXZC7c{Dg!H|b6Ww26+nK& z`bpyH;&+*h?8+_5oC$MJYuxj*no^ngsR1MpKC^$Y6;V{Vl~vxIl7KnPDK^+@E^Bt9 zngC)2i)s7~Mf=Lbh%QH{-RmbcsoAU-#$Gr7L-oLt@S(F$qT?TB;`4s7CV|HVvK(+N z5H$-T`eM>DmV9^_d-*-X3H7VI_NFrpy=5-Kv$rCDWwC!)1xO%DwKKFVf*ztSZ#+jl zA(*#-X#4{3%A8LqG{uD(PffJA^&|>6sjs)|L<@z?8UM~uB@8pqDlHqIuvKjmy0IE& z`UP1&AUJRbRHo7tKPg&Tx+^rk(~F<&@#2D_6xKj!!UPdXjnmlAl=OeljtKElD)Y<0 zzHjl4GK7~e`Sx(u$H~wLz%v+t$pI@~xsM6%0_h7mWQ0Z|M5kd+%T&J%0&~#cPZWhU z+{=$$BW`Jw7Q^W*Rxs7ceGuud1c-^f`1VuRf7$hb`vSh!4;ea%VcFYn;R4 zv|py^ucw11pU`HP(KF%KJm4(Z)!7sik>D4kl>lMnb0@x*E{)yI;^rL2Z`={QS+piQ zm=)g}Jo1t;yZ86=Ac{(nmNXEDD7!B}d8H*v2b8vrW<$WG08y*boUv=_*nLm*rruYY z-#3dL*@_7Y-s-)#^CkE1zyqYK|G>%0tz-o6SVZ6VpxhqcdUSDQ{LmDwD4QM#L!w~u zw&Uy4WX!U1<~Z|udV9Tyr9NC=!<>^7uZWoQztaaeEYAn4uZP{wJc-xSYevo(YAOW! zt+TBWNhA3Hji{@7tkVO{Va&~+T_`&0I6W zx}zvbF$idhg9V26RDhw;s3c?H($eSCnB*)#(yDs6L|76)Q~XK;wHfXd=F9$eutx0f zR_3}C9D-l1OBSc7$KE#0j*Or4?OW!G15}0pRF?lR4xf8feJdSag!uCC@*z_FGam>R z+dmnv3g+8tXaSf4!Ui9w3bYqFIWZJAZ)KE%LppT74f`A*6B)lNBGErK~Q$ zsqS!cCsy*W9QQ9G{UkE>5YBLkSS_sd`YU<~OZ;j3q^B!izKqmPjMs^0GT|l6f$ErB zS|)61H&`uZPm>+08HB5}>g8v6=I7+-u%=*|!%Bwl#jvnvF5K6^m zOBol4=Ir=fN@hwByJ=k8pX%l#kN3YX;_8-D?IX$}k;Shvo|!)^0?qP&5r=~yqHu>_ z7DM~lwYLuj#Er%^R2|r*_7J_B&3QpH=zw}W?m$n#U@77emUqd0|0yVmLvH(!3cF_G z?Q@Q6>Z*6s1i#M%`HCc)diSRI<rg_hM%rEcDJcMV##h2(q&0;DM z)TYIc)k2x#Hw|@=NQh~EKSFyy(-=_c?kupoOj{M(*6M2{GTrUkr^m)R4sArP**O+~ zjDx`EmAzz}crDM{D)FpGH4M7*vBXz@yl=nyjk}LniOnxhc;0t~x=HCwvQR0pHMzf) z`mQ|_@zC6{5znKHRK47(^PQSTLr=EXP6svcC3x|HwsUR^{g`QSpF61*GI(|r%AVRR z8*HQ=$(W@42&4o=9GGj1`&qkUYa9|i=vOnIRyY^6CO>Z7L;4EkBlzLrejgwTJ<(~u zH^!vCu**uOFW*u?5HoB~f?};PL)nJ^O6oIfmU{mu=f@jLH_wc)0E(+xb+(t-%pKB< z@p+F4rJM@62IKg+%1kfYcg&QLK~aE#!n}w855Yaq_NI$<&^w)96>c%o;mneMSke{# zdtV58ep#(4v*yW7qO}n72GTy7Xum6>viMSHl~v7~$xIG!m;JJ|ryl~)^DzN|eXsT5 zGfAM7FWo&u6ev3v<4F&i_RO4gv=R2wjcJ3 zik+~&GDETc!zO+OLkendtk3(W?aumQRi}u~iHF>ua9f&rtj4h8loo8-p)A5)_aGex zikw4XD;@&~A0N@f8}%>jCO<7D86Vt%6*_;A0!|wtvAe~pLy+dhKnVH%Gg3J5)L(VP zpVk0G_UvYgp$q#_h!E2TLKO(3JmTGxs;nB$A%LfAswD5lXaSD23WKZ%!j_c6FCu&w z53W!;uS-h`J~tgs9lGbY2f%?o!;-_|+av1PD2f0Jqtc_?O2rAbG8Y#$wR~++qu+Li zoave6NMB5eh)y)Mn{GB4n_1&@T(4wm2Rm*lFQ2dBG!Sf{ch`X}9onYC>}?`32tP}T z;5j&0s2Z^G8T2FvjUo+z=S&hWzT$x<%9u(m4p_>9hymyTLm#ah8#laTQ6N)fg4Jb#06~N;BE5357edULT9Ms9)E6)$u65v`-?|Fo@@h<`E73r0v)Ujy&MHQ8(!UqudY`w=xx7O zcJxOo3IQX&E$jF=F#$p3^bxK{qLY&KDirj?Y6dwm+mCbQ*h z=0@`7mfG%7v!}C@9v#9!NfVt3*lT2KUtdQ@S;?Wa*xFvTjNtIKH@rACJy!bOkiXR* zak5Vt{MNQL56yXanIW>#vssUe@ym_gw&~}y0NlS}{d8tXu@Tus8>%M#wgNi*i-}!S zuh<%_Roa4xVvQGk^HN=p_TO2LAHakBuC=M=fY}Xk))JSkh1s z`>qj7+@>jwe}(m}MGUdBRY%KSSz_Qrn6B$(WYrzAYDM16$11JFvE9*0#cH@M8GYTC zR$iCWy141uRK09co}!C>b`cg!eqaBuVi#Zp4kzboYp@eE(y3`A_YbXo?xDysMo6ko zrr?&BBLU&le^iC^3uwQ{J5%(7kkA+SG)}!qzB-G}FB}|c>e40vV8J->yvYQUP#cSL zQz@%Zc52U*Vu7OvQkjhQF~s+o7ZYoZTM!6MZmHI?6=EFK#A~@Y^yeyE7ufGJhY-QQ z$B6t!!UKoZS65Y5hYOy^%e&LYQ+~OAF1-Q+C|mui#9g6K8k$UXUlL@UdB>UZU=7zR z60jTews4y|Dn0|=i!_2ja~+3du=l3I7StY>Jtby&HX%O8VXtDIG)Zj}D=%r-5xrqu zsV|kh_PutLx@mB)da4G>`FxFAG*|*KVGn_@#aPkm+ibz7qwc45d|$12q?V(^?j7=1 zWM`h<^tUC6sRoPu3SGLBd~*8pVwa0aO==2Kipiku9x@0n8&c1KE~% z7wHwWNKNnIqQU-B4w9X~o-Xav{|cr5r0*Yetkq4txfpG1A}4;dGw~JSzbuEl*Mclt zWZ;=eDQ7(BMy!u)RuWtz;78}xB$~(k-D6s}ec&zw^CK@_C_-4Y=F6stUU_biqs4XHanW=zeqX;R-Jq*lxplKy)J* zB+>-wr_3pR?1|kO}pO=@#${Te3!mqN5K2bSJ9Ac zE9t5J*0W(W;A}TwsNpGW0)Bh7m}G$|pUDVtCcq z9zl#U-N`$(9^Dlen;dr=CAFS}V1lG`FbN z%?_Gz2x^$9F#p0}YwLqgk$i8e6nB)AwLLROFFik+$-+G)8*@}kP#sUf@=-+kol%e) zf;#g@Ff1$gKNQ7@k(`%mAR_+fB$==xTxOGPNAZwE^`@&Ol##X#F}-n9h4t4~U1R=9K77{a2K%CA1)e;E9wR=B5o#3**e;mZ_TdadNP%CZRu%{jmHmlwYf8kp## z6dZEuy5~?L%Qi%&DDZ3fRzbjRoqi7NjZiN>=Pkhw5nBJ)R%61tMTxej8uSY_!^u7s z?(PX^{1{)a`>|fr3;%cNOB%qPd&`r}7P65^#VEYb7Z$ecb*0KNN^IdaYZ7n#E#yC+ z(D4EOM{REDJ(i0{yU12{6K(&no4hVPS_l@u*4<9_L4^M$tN-rw9~<;i2>A5M&hIuz zeO8y`QvI?KqFulc`xN`kHPH`n`hRZotBfG346At83+StR#*bd+BXZ1?$r0g~(Kff2 zea683_isqiO@N&+wmhw?p4A!D&neFmT~PQc{Ir?>y2-f|>3ZJFKq_Ytki!|7q?NMU zYrNQ#;p{Dr|EK%Ltt%t;Mb} z%bFuHa_XM-A+q0DBHMsF(sSgVecL@CK_oxxX~Ros;`r%trM1de?%Y;9Et%oU)dsrA zU6h*17dhA8?8`=<<)pk)j=wJUmm;FbnN(7?$+1%T%J&5H+iD%W2Z{v-Z+&rv;k~Pa zQqc8GEKi7%Y<6z+1J~+Ntv3m>QGq1TKiA`zVnG@aCD~RuN(PFKJbmHIg`>#`Ruh}A z+^6KLKF&CCmL_tUo9e%d3GFQw8%l64SZ+fZwTP|krma4U* z1|9gXWZ!i?uF5JnbPnpRcVxS6=7oE8M$x_(1x`3IdcpZiDFFN40us+L(Plc!P2VuF zD8UW0(;wBl?4ZJxolab8wO6@{Ii|LbicX)osi}=Fa4unHpjGU$&>^DWa%qwnlv|{^ zuUU9%(~9;RXb@O}aL&9_bWg3rUSeF$(|T?DEX-oZOuyF5In+EU>l{H^Yw5(X{|0UE zi*e;?QAx?;y;K|i|ELX2iw?qkitk59pMc|Kz!AM>(GrV`6(_9e5#)#MHZ$*6bh0xM zoV^{Vcxt>lUO}<>dPXlPU4=2}wnURY6o0ysyZxgCc}~N@DH7O28LiCQ}612 z9Dh-ne08#Beo`c%qh4s}(^1azo8_nviV5T8MqHo3%8jHG-lP#^#=135{Va1ICat#$ zGOF2LX_4wnEgMT`R=yTjuwHZgWl8`vBIdQeIPSF7PyiKf~*ryAn7)k&>(or%bz75t7M83rxvkaG|(9Ff4GkS7Q+T~dJbKB z;woETN-cuAMLNuBZiH^=a%*y4L6p`>Ze}L;=RQ&RAv5;rZU65S#ILXw5D_>HR`o*? z44A+%%PQ@8b-}};jY;OcFw(d;;-wxN9raXbX9L>2BrA@rSL`2-zj*~l`q%y{jDH0{ zd==?v1=Qb-Dl2>PNx5YB>J75wPOB@dO)p<-ZD(5#9g}(|M2Q@VDjmiN+uX1CM-lly zGz-HDAFGRe#yjd6xOfTh-Sv~}H7IB^)oJ=3mNzBM_ zGTMJX5Ml$2ML*ssbzs!64NT13vmI23n|=PhMp{|^veT#5+xEP2vImLn-S_b(mV^7h zko`9(_|O1k@xL1Mq+-=`NtGSLp1zIER>-p(73vqYkm$RV2vzd#%YG!ZOK^=L>NQFU zbS?j2%74L#4$klfL7IjaTh_&li-3Mh^+>{l#u{fRN0~P}iuJh-PVa#jMzrju*A$Z62MGka1W3XXG{`^lV%2-VTpigh>0#%9(k%jYf?jd03+6T=VPo9R(jjNU z@&60gqEdjC9k|aaYa3v#zLv~f`3B@nEXDMsAXqC0s;5ZpsYO4wAK#OkGdk2};?WfsrOjEj>R%>K4aoWchc9&A=F|-+SaL9H6*rfMmibCQo`bR zIV8fGPn5RtS9(TBtC-;*`cz$2mu;TYA`v?9hNl^ix{JK6X3eYCAAk2r@1Yrl(DzAq zg$!h#NuRWf>PXLPG8YVGdbYRS+3j%Vc+oPVccd@9=#W4tiCWULHo(X(wMuAy2i|Xg6&v?-B znY-ZIR_A*JY=igFGUDdDj|UI^uZ!0x^RKwuJe#h*5fALRzO^mizGz0^ULe?U8(Od* z8ry4fB5D0pwoBJ@qcyl$zr-AAn_DSwgU6b@`ru+Tc~y6Zg9mCJ8&f0RmpxUJvt*;H z18rPrx_?Jd4tDl_ghE+TXiws z+d3#UCc8?9=K8a^YEW>9$&o5)U1eUgrV*|>)!Jxp>wkCLAO8vgQ^LbKj8L@^7o!4- zc@~~-5(;O^u&9QV@W_UgPQ-U*cMp4oZ&0P$t)hHy1~B(=>U`?84424h7y&%*3Eq3N z7#kDMH9PCv_z`OR)*yzU)=#uw3)(S#!wW@zsIyC!FZ+t@r|ZoN29ri`pY%&er4KWGSwR)kwiy!_QTLMfg))|jYB&5v zT3kqv@aMRYMLo=I>bmXi$90KypFcSV=nNKxkCgQyo}KKbZfZ=-mC2C%OGG|cyei7` zM-7WOf0r`tsUN-)U1t`ei|*YnmD6(iwJ}IxJ@cA2j^_rKL1x#FcgF1M$wjSe<-8x6 zR5ZFl;4^xrpjeJ0U=nTi;?w461dD+8JpDydwoRn zXrZcZjQ||i^)y5K6ETR(3`SP0noH*7x+s2_U8b&|hl1ape{W-7nEh0pS!~Nqk%@f; z2V2B}1x>2%FwN39i@d7gS@GZ8VUlUSjE)M{3%~fH;TEkfSPahr82QLOV{GNbt=(oRx#SiG z2_fbxeE#`8D|bl_u3G001K{1fviUwu}n@RN)NJhSN!9lJOp8z9WRZJW&*7wqFV!g^_ zT^X`aTvsJCw4&)5vUhM-slzwcBv;>`#-|>ojHK`!?KxMd*t&oE^yd5b^uC_`uB#@M zc+R(ZM$&m>RV2K&%UD|UY^oiNSEhX{6utgwWZM*}bTjxB~w)>$xbma31fb?MPVqH3z*6BV20kYS2c@ z?@3Gz=hR?I75E0dzZkSSmV}}&D6Mm<#kMsd7oS3nC>G_{t(>*?rLE8Y+qZjh>SxX+ z)92ll7pCRJI`LL?>qNk5_B9WHN+P^`Mm|u|USLz}zgnID?s?=q)|Aw*R~8iz0l)gN z+PnKgxoO_#bo(^Eb4?JL$@C*IpMq~~gA7cFF3`5{+jPrq631HfLnm|9>tdW#k`Zcl zOUSjfXlNLEiPkW$1C&s-lPA+~ul!TArT%~rb|Aw!?4Q4BAMsN`C9Ll zg^t;rp=y@yGp|YR!7BT_xg)6j#h|Kz*8ZLr%4DNPv|3Bl$miQc-`V_qCi%OY5R1je zx03|h#~@QiU6riRBpM{fi{&%b(s~(Y-sM@bhAGyWjG z%v@)WhkETunedc~t`o}g6ohYuGZE+y*{MAtVFj3vvHj*lvco-mE&CMpQ$mwX9%U`= z=rbOTW7h}v??`E!`qn64xz0+lEPd2YS7BnB^CYgZZA;c_IeJS}wVwdD(u_Qs-$3bV zZ})`ROhM=TNK>Y3Fvk3oAT=(F{DGQ~C@EfDmQzd$2~%vr(|xV$Wxa@ki{n(p=gHLT zzO41`=u3mX_{nIC8e*v|A`-!)WX}?$KtLA1$PJdCb_jRQJu1CwSQ^@NAi;GKE=w z0h6Wc5DQ~OhJ0Y@L5E5S2c2bbhh3B~B75%%m%0BC$!t7zpB@`9&M^lP16mgmy^?-?3w-&jBIU9}eH4Wt``S3h%=}wsDTrycU79@4 zB|eXxixeI-mQ^@S{4?Cqj1|QSlF8zJIeH&01C-dd z+8Lb)J&z}uZ129!FerRS)*~=il!uiX{5W{uM{@_s8*G&4*i?!VY#Z6%pSiIA%CH^# zMnCq2%@Ph1S6oj)#ibtau1AB>alNSrfte5}JE_b(fAO!llsKbZSgV&%^7osYoF% zdz57DP5+cLk+k>C)M&!qt<-vY;B~y>neSCdVduCmEiP+mq@?`vk(k$2mO+iBmYUQi znl|+EYxmK|%o$wjig{}wCnO#wCY3GXM2Cg@WGNjLGZ&h6s3y#&Vk$*<9W_sMm z#zYfy!w29oNNxO9tM~jR_1gJsgN2(UpzxNA3hP7#27@cBojwE=4E3Eu(0bm#8AQq) zJ;bk3iHKAP?%ymH{JPi@MN9vzKGP{|KIklVKK#T_eO-zt=?$*hqm#>rV_O>OW?H?e zX$(mirZ&!du`81bEJ^IQ33VmZwK)o~(E&bl1E%yc%e4g6ocW6$3Lj9z)gA*Y*3~jF z0kp4HslOUshZT=dPUrXYVh_3qWVx5Z(n{qZk#LTvxyY69jbC{(yG3*gi$V;6NG=t_ zR+@Cu4-Kd1W$w?jKmvGga%=9IackB|ly=Ys8Uqo?7 z83@wE#;P~f8XaHeomEHd|IDI!uxMkWyf*rTmmb^SQ^xU3kchl{wh4vyBSqk2!?^^KTbP&Sg)j&PZ<6?Za;6KHweaW{qwz zr#k#lx!IHuvSHtyVws$+_(EXpHY-Eb{K+HD#ZMT_pc8&Gl;AD2F{E3)jzN=pn~pG) zd@f=B;d=J#UzJ&~7raw--lBXbiZhMe5!U^hhoa!37{ggF(cHL31?Pe?sEyY4;`8+@ zgdnUX=O|_Mk9>~IZS

    zhyoN1l)wfX`mzDC)1ctxqP5v^+@-o082RjQY~6UP*77O03XsJoraaY|{j8muVWAf!aVmIdtm zAryM2Mc^5}`pvkIhWHhBoAeL>skEAlPlk`%M0Nl}fFq)_34 zsSwgmQ7e3-TX4enuu=iFHtyK)#G8k4X)d#dcSz5pZ%(=Z)-MTs2UfGotX#ho6;sLz zeSB^ZO|A6Z!MjFD&;jakx@bb@S)%)}rK=K!vo}AshV5t*D(X7%>NXg9W@aHiwMZ!y zgXO+N@4esq`5Otey3tb_J%*ZnOG7@2E(K?X7pf~x*-vdA-7*xl!C@)zxw2RXIWJV7 z$Ki8f$oTa|%AETm($Bksq@-i-O2zI$Ac)YiDDP-L8}ntJj;KoGwEx6_g9dc-#n#LO#h=F39Es#JziFig0O^6dz)Fc zF4?aHAI}eI-64Qf2WiWl%!vSRBW&2-tfp@sK3rxwYS|6GR8PpC~!Reza!5e5>J88Df1x6 zo80GmaLI%3dE^*0q9LOO#DBYa;sw#8TUcvw=kO!})23#ftU{X(S^QRCX^B2;)~_xv zevc0R5U~!4qK9!n5iwR(J(bd-SdfaH;zs#)j~F9Zd;}4gF;jf@{FVyI$PZ0qMhHHO z5Z}{dcXmq(zf6DBr@{ zzn=jNlmeU3B6Yt#2c|J{P=}Os)@ENrLIp44Lj|?e`5WD=!VB@=R8Y!4lwDsyjknfY z(X*Z@laiO5>NDIyGj3V!m)SAXzRK=5z42J5y2yf;LGUn+7Qzbxu6~kJE3#Fd1_GtR z)cA_@$Ofoq!>ver{rh!)(U+HcEcKS? ztNHQ7BQtY-#p@ZF-Ex3Fx9X!8;t9Pw)q8|BpFO!di6*|C*W9zOdgUUXN-I!O{&q*S zMH>s&0RPGkdFLXw+oJivqGo=^{-bWFv7k%3Bln8hPl(r>8@~5gmq~_0hW6>0lWyEegyXX-u-Z%8PH^ zBwwd81yw$cdmIvgyVj)mKzob)$^!>v>wRBp?0f&gy+kGiz%z)&85+CMDmlTWDD#CMY8Q`4SL(y+HENn?QtWu@7&CIjqN&#hb=AL_ z%*2o279AaBCpap@B!Er`=@rdv+-r#6mG8@;L7=fA7bA56<>UlyvPpm8;)3h>Q9;+m zdK}+R9u*>*AigvXm2 z@tigBB$R|Su5Zo=Et}~YugA-{mBo{;M@COm+4O8<6TTPy_qPBR_X>|A5TjP5!Gr7z zLhm)UrXv&bSTsH5OSeAi{!~pwB(vP@U`1Q^Mb)~)LrH7wYq7y?Q#U;xT(m}1q)-0j|Ist(}bwD7^0Yc)$_v$s{( zUd6~_A!hKPd+3pLIzl@k&(=`!C30Bw+1$T0H3x1e3iqem4rqQ_ubK@ni7c8S;T@-L z^anG;ukJ6?&W*Mt)x8;LQrXrZj1S?Z#R7aFnDi-V_7&vZ?8n<%Z8|P5%2?<=16^6# zw#gGp`Nr`*2|Y1viSgdoBs*QX%?s^jE6j^ni2+Ky&$HxL{oJMPTse+$5Z1>eGJejd ze;KX7!oqe`=o>(s+9*Wr6@!ELK6pJ@#v>mtAx?4~URx%4B)+$%l)#e8e#mTVx#w-2 zw{WwJ!5&d}KqgZ}5{N%ma+)5_R7FcVwl%;M*r6Ydp|J6~Li4YYwZKRpLWhztMF(?> zGyvqvX6D;zE+)HqO~{b;AdS(RVwzm!vS=)t3r6@Kug2$gleO>H*huQA^fsZ`Iev^h|~=k$F|2XtGnh9;1n6iEkHbf(W>6H#)r;jo*7ne(UW3VyTKQq zwv}G-a-uOaGZS|;6wcSKy6#1Rob~;ArlI7rrB|VK z0z<;aWo}ufG`&T5Ht7ON(tusaKnx}1d9I~Y3r5ZMqQ-?R3nL|SV<5)(5UQ-*;I(tF z*LOH{F04vSoh?;bboYxD+14^{6H9$~bY>LV{zUH{5AIE@RP43&`a3lmQ4L7^&pzrS z)z(o)R3Sxn=#VUUFZ%LTX6ET~zx1ZNEhdd8fh$xjbG{x-Pq3-=o+qDnVgkF{yiB?C zT2}tY+QW{oLaV6Tpe*Yl|B?p=p*R4=c<{l!7M)Zm;(}Bm^g~E5+|BNTgs~$xf!P4= zsJ1#5=2X6039lc?6$fiE%WWr1R2A+)Br6ou@VfVS61b&r&)R_)uqD^{F|q1jHuk#= zcoJ5%YeT76eH_?%t>dN7LN#SoXe0gUvpV zrl^a5`!yjmla0(G zosw^}(HN0R^bu}lQM*pDMmq{zDefP_Zd0OD1I4ugjaBDGPkTrJo$Z(LifXD)AZj5B zdE@zmTAU&LJL{Iub=zXy^%%~5QVY&&n(4{f*OS8SV+}s)>?PSJJJs)5NS3br|GKM< z?s$)f#wax=-y890*bCoDIX~`X8+HqGJ<|;sjZ!2MO^PSldC+8{?Z>5)JazjTUG8jv znMf|IB_U=ntQm>64a`^~phZj9_H2d-FcWyi;HZ9cw*lek)0z=_^SV+zwPX#ReX=NgL23y)x*)PFnqFbYDXD*M z`Cb|Qr>=a5548vSQ86j@@;LMn+^ai3N)@g^Smhcd_U%xpY5EeYUT=vac)yQQ*NpBqL2(Y-<20=%}y_vmz>@duf2(1CJP1^jEfZ z33#dQ{B|c1R`x#MT2BS;oOmo~p6;(29zWY>%twOEqjbx?)(8v7X5_26tvi~Z5`X*? zd%~EK3~hliq>h?+Mm0b3me(c{OsmX+zDWVkr%J}8gqy<8yIT=Wt8kZSL^_;}dl6=A zAz!QmsyCYZr4NS|<3|!`)shYrL`7k@w;$_YPf3W%ko|Ts4^#jD%VqK zDC9%gmR%nPU}_hZo7)9hJetLWH^o7N;23 zN8ZaJ;L0a{N}u&ty@Vc?_;)fy&(!6j=J|FZ*#e{tS#rIttngm7i5diECgK#~}vT=#wag0XS*U;*pGa^ z^%69g7sQNGKzwkS6~rFs^EV*bYP{eU)KXK<7c&V}t@80v-a%_wtV& zH_W(pDXj-nIZ*SbrH-<(n9P1j=+ZtN?phPIc3aO;0)ZeHcpqc6*gQuHBM_(!K|hCr zx=VbNWT)bEUPFaQzgGnIqUx96LlZJO*b@cH??%d3AsjV5FmHs)Y{C$2Y_z0pzyogwsY7U zCsxJ0=8?SW8J$_#KL}|nzKq)sr@Nv{O0ppB~>lRB=Rh1;GB#}~XT=Gs#LKLvezy-s}5O;gazSE%-<+40m zM+KE9RmAZp$Y{sahV(C5Z9$c#L;Yfw%`~qboX$_$X1Bvet>Kkgzt1o5V~L^}4wm`k zoOltzd0YTFpJ(>)5MtBjw83_^4X4 zZhYBCj;5qS1^bx^pl8c2W_cw{*4;awjggzZiRi-owVTxt$`CiwDpwH8vk$9Q_Bze@ z(%G&zF_`vHEerKHE|dArq7Y)j4XbfG zp%*XN;ZL#gk^;N#ESGQ}Ua})_+{f-4J+&7$D}93fy>6DMYd(bv)c}Vgq&*JkYzh_?eVQXK$4TOY@muHadmXSVB>b2z6bmQ$l)O-rB3>@U>4(oq5bSW)n;7UyQxBvyCcv zTieSsj>_|4fsX6pZfrVV*oqg|D2e(<_o~Pp6&xHt=AUO@Vv{&{4LxSu4cll)V{SFi3~Cw5Ya+EH2ZyHb=zK`aMZpNr$C3-!;xH24ne zMdqMdXx?P*M520?od(2ISsC;^fM{ zmukvti+V5G@34fb;I9*_qiQGf{xRTD;2UNTP^Wn;&4z;YlWUVv>^X_lsX0N=-!MS~ z$)P#lXGSllRhSGpZLU;t&O6#5=`Zi@D@GOndC|YmRQjkQ5=F|<26J|2d>8|dFw$S& zWyfCWK^QwtYqikuM50!kyA(3|q1CA7) ze|9GkqHbpi;1FF(S=nXosWniE_fm}(5H~Co7PQ?oYA(*V&pI;ClPc&f3qxxPNebkt z`(h}9O4PqPTKC9q_feHkNiZBF1Ih|FuOX_34~KuKcJOahgrd8m|RF3RUqlt|PLe@lpjeVC{)>^xvE^7DD+qxfNoDb1GFej6iv zRr!YP=aoX7z2#H0NSL!gT(JDD?dH09#83k7ZhZ;0THWzhXj|K5Vs!#GZkl>;08cgZ93UEp)T}Ty zqm!{cbaC#Zu+m-u^$)U?0dIP(JZU7obOmt=2qi1oQB}$hYbmRRnTnAcXH|~l0^{hG zzFoT``cYcVmA`-2pS_1W{bJrTdsdm`WU7%$F~FBXv7>J1-Z7uiIO}@XDz#QvlE4}K z)S+F&u}h6g1{1k??eA>bHqA?f3V%^ozTj;Ui zu3w>~9bp7jS+g?YZRsE3xk#Fc{MxM!!>p7hCNWUf*i+QIz!bV{oUI-&m2T3lU*XC` zqKM@5odFt9Mnd!SorbnY^7R?oH1vvpp!V$gdhlp?!z0mB#u$X2Z0g1OYzqVMV?qkk zQk?91fmRHw(YO}l)ve?c9=3;F637+WMz=xL@^i>@>)jbUsy{mwNb0O}Bu@O#(xyAI zG7`Myirg;-qqK3fiEdSH?Hx}IOP0@*jVj9BZ!Z%W+fq-c@uZtRx_ zXDg1*!|&whqXpJQ^kTfxn zGju%Tq_z9X5$IRU7F5Rd!Vrr)#NGZbO@_BW-FWPX6n%aerY>uCKh+5E@JI6!Y}`Cl zx(jfR)x?86?0oW{1bU5~ye-=ZK=JIS7$lSjHGfKpU@96Z)wB=W_@^*-jFy=}=M-FT!z~x~i?rXcw!*F=DqKp|j>ql$-Xh!; zFk{QE?RrT0gdoi`;JK0@@x7#VVaKd7@rqJbW&Zi6`!Uab))XOt7(_)60O=}(`k7E_Yljp@Hw`vD2cx{kCUk)%ZDi9R)e07DND(n z&{k61Ejj2{%l7hw+H~KH)x^&qpzlq#>s->=n%}p#8z!3Y{Kh>~ap&lCDVF__leM+M zE>E5kYK@fHKvC_JHkHEQ{=jAo`3sS!`y}Hry8%D{8fN!?hOnDcTXV4$Xq0}Dw)|f_;vJuH6wNgbI%}|PheD=ny0$aJbkX$wZGXN<3 zc+xwr<~Vjm5(;uY@~4)!QR4GHt)1JAj?}zsRkPvI#kqPyF2DFm8iqr2)dBzA{0=?E z2ig$XQRRD+MCLsgE=YAQp=o7;2T}=y4Irxn#uGz)bBnls#H{54i;xWu2LFv z+l{%eUo^)G?h0CPV~}lrPy-Z*n!_2WMcQOR!pi)80`--OdwCh|_#yP>csU-i5_uSP zPVetHrcIQQiQpUH1>KpHf>%}}Xn=pgNGTr8}W=|?T z{0evv1n_ast5T}28bthvDO(ygA8lQp-2bVN5TzcYoe+96k4Uc`2Ub9l#OrjO~;KO8aDDaR?8t(alQ-;{INwd)qdjG_whkICe38UNUgYP2g_SC2!qXgC3Mi<59&^iSa+9F8)Nw-HX%jRt z3YCFos1==TSYqq6&-bAjwobvIKeo?Js{c-@ciVB~vXa~ypDH7y-z+TH^n2ywQyMAe zVcvjnqa2JiMw3cP75lH|oCgDjFYU4~SN*oizn)CO;S}`KR3F!u@+icsHjDJ~7VkO& zqoOiXg|<{rnckH&TKzm(zp&*y{zH;z{fK&p?+`?6AI*a})i@d| zF~EBoPLs-b9KNiC^D_xG)^R0nrR=Ezc~d2_Dw;<&7g}d^=2ifI=D+3_5q2Yw2A~h< zi{@`QJ6^Fv^-}7pE5|2=d&#Iz+w}Da8zT$@1A>)Sy(D@>3Se2In2~C=VdAg81Cr!48*i#(edn^v{(c2#?9K3Z+JVMz@VE*t+iQQSho0x zc5{Bv$RYMD}H8@OrB&^ zfs0g9ow;&M3_9&6({b(?A&>WoD>%I_;h~5L^#;dvjp9jo>k13Kl1RhYFEb?ey*dj? zGC$vsdPWb`UROxou1xpGkq;dw)|_tX%Ie`ir)2`-DPC>5P@7+5neohw*?V0C!)UGS z#)s7`ljlYM)DJtb%e<5=g``F^v7@WA=q$A8{Z2vqzC5=V8r^d1@4j_plw-kS-ezdZ zO{Is>n92JP$+j0Rk5Mz$m@CpRAbv;DVPR>`5ZQ8()m(q{q0jFo@#mll5<-=BU#cd> zgAi*c*B81P(Kp`3urZ^ZVzV9}Sn5N|O1fTBl39GVG)>Ff#WC#lpmAD}USci%^F-w& z(FgV1SS^811Q%@|KbTt1We3e}a{4-}r^ev+$U0xcp^x9|Ei2+ zSadpBLoHT+&8FocSIA8LG{cURxOvW!={}juOICedKTQ#YhICJ=rp&5T2zU8dbDXj- zQL?fI5g%SOJ4t%8vUIfZ1_npnG*jUCe*3k_!I?~V4r-d#aQJ3zSqa-K=^Keu%h_8XL$eJG zabuS0QFMvXf-Qy5f!YB2u>NM!?j1}L-fc=(pZ6zrXDbVPN5tT(Dlu#s{3O#t2JdM0 zZqKy7XO9Jy`zbBrv{${^)gZp6%4>6m^nKGbMT|g+LFL{APfKY_d`h@zPX!I!TBuJJ zK0*ZWAggm?!$s4^L6MDY8V#UJqUmR8lI=;-90T`EtI;ntZ%P3gv%?6NZcmHxf`;zj zy;>~>$760M$OxMHAoOz1qeNiC&pi%>A~b|rv*D(vm<%VcW?AAV3JP^ORRGtdU2z6Ob9 zsP!D?lQEHzlkY_)O_ZK03xK#nPPKVaD4pqT+$$h6sY+4)RNmUwX-`(--1z;VE61L! zKE!)_i~hA6AhO{~>!V3u-o#m+Z>9mXGzpl)GpY6%-M zZ@7kp0To>iHRlnN2fMvMo*k(H0VQ_es88wU4L)jFcChSs8BO-_JPm{c)h{$}5dK7M z|4OH-j0Dn`U&r1iuA(#OYNt;t;tAmV4OnJlkgSe_{4#35Nvq*hgg}W05o;q-pBm(o znvI}3yKz6%Lw&e5oj5z~Af>qOk_pEU_>NQV#5bY|aV?nqP}_ zO%u`R{QT%-O~INJJ4XFZs!HcmwB^Btt2tp%^s)nk=SWmRMCqTV1g8&= zZB9zH-*P-jT7^2QmIs6jo4EEkO+Y}IX%zMkx|U9ysSRmBF2Ap7pxlC?dTG%npF_{< z2n((h${|2$%)J+TS8El`91m(nT;mg3G_8-JUs&g z+^MSP81>!t;8>eo@l&g-0RS<{^`@WVqmbZV^#ma`-Mp0F+5|*;tskMliSPBTtd9Vk zlq~b(qX>HU{8AuYnEBSG3I}yYkeBBcH2Ye` z+*NDCzo+nof63XQ?sy5)EY?gpwj&*=(&UYv?&p&MY&*i*I}xbts3|KYM4zy66|E$| zjBBMvV~$|+dd}q-`|Uv!jKDS*@3zm0(#|DFNJq9}y?pW%Dlf6*zqWic{*&C*krKrM~PkZa2^ORhbsAa%v zp>S9VY<G~0kVP@5C=1X``1$1-9PK+h8QeXZb=Lcs5ZT4qYXEt`Y^eb~&sWf|1Cf|{pm6?p z`CTWZf21b?Q-L#8e<2xHFxDho;$>|3^erHZVcqFC_?#2UQqj54-%Q=8RQ*j#lf&t& zvxvlrrMiQMDwlP~tFQVlgnIVz;pMOy#$BsB@rKv_SgF}g1!6&04V8xNhpreba}R=; z*zeF?ZYqsRaTZI~tyWtW>&iLlg@~GR7fc%yl$vN(C{)ZtFsi&4IMg<1%coseoMl#d zrrG$pl?YQ)vGkbR&}jI?oo<}lc$<8M{l;XNi*cmw;LkPqZAe|rIm@9FYWkF}o_Ed% zR04?C&mV8EcxDK4v}dA#!fnM!$P@dHHgUe81hIak%n4&A9d~-RS;o^RZ+d#ileYMw z#`VDLxreiafE0{quO+ZZDn}2>IpsIbxmKs!hf~$Y#uJ}X)|#W;R`5vF8#p213>$+z zPr(~1cDQwlr^110@bnT)t4pwWrlBT1XwC6K6clk=XU{Z=C!LCg*Y0ahq zw00dszw`@TUO#=o=5@YXJDjxTz^_tNeKV1{b%ZD2Nr7>Eh2^Uk<+>JC%6?@_O2KaIXWvMvgUSMb5^d?@mvCw$ya{Ligfv8~Z5bjsyOUi-MQ&Z*{qde3M2w6NVJ+zVPUiW$ z1BPGOT(S*;=2c|acF9MdYpGj|FGO$=ZMxuX>IF?-%#TGd$!B=?{2Hz!_2!t;OKe#1 z+KkCwwKskJ_XRJzM_Rt*nh%55M!E;|5B9@8Imx{AHgMX&{N=v}02|&`iWn>2iupZU zrDFm+law5b4Gz8*eLt++0V)TE(dYzDqDILsM=QCDl02bwpb$4^ID(G}90j*yp1}77 z`R6rk6~$Pt=2c5gTrMZks7x#|A4m|z#6pTqUKi>I9=)O*S{ae<_;%r-BbHR_Q^Ai5 zPU%Z;7Nm5qS|^0KmJxvm4bBGzu`ADQYAw&{)4g(NxQI9Ze7sh`h%)6Pi~F^j)SKkC z-#pcv>(;w=rpd7t>?v6MTL+CR^g_&!ESB#t%43uA%f8n>=x^S+bqXy!{KjT%G>TK4 zPMui+UbF!06_D-BE;QTzRMz8GNp3El*esDlyKk~|4=?%n3zt|I-`iz4G2Kt$+qHF! z>++G~h_({%6aN8@3|hc8Z>3)Q<5u!DWd4c@|5t;yPa3mWS^a zCDlF~wnzOwapmBNrgvy)H-Z1V2|Uq^W|xJxQj6tQvKH3q=i}L2FKkXwkYv4ReHZqb zZ9dX#TGk?IyM1WFQiawh9f#ck7IxDp!9_9_W?$|FKx?RNnUXsPYlWdQxE!HJ*pVJi zZUfh?LdH)|Hy8 zWGe;#c#g}%o*-a~0gDkZfJoj)AJDhi8W}+QkKyF zuUz#!)uaGk#Q`Zn>3Gw>^RdD1h&o;u6)BtmPFJKY(gFmV5!#tuuwW=qnw0K-KzR{w zbw9i)%Ay5+inRXP;<{D^6JxjHyDIJ$!SyMUx_ifnc8Q4^bxBd;e_ODj@}8+Z?lhZe z<-X2_O2>0qJJbGW8(hFPZYfW{8eQg|Ce&ZQi__vxhxsw9BO2rb^hNg7;MGtQS}i6lv4+x84Q=&<^?s~is!Yl@ z3sPwx;^W~x-eJ#q@0t`|O)O^CvX#~hr$H+D4XO^<+Q*mF;(Ixf4^#_Gs|+*ZP6 z#=DevXzRM&^tgSu=%VAXnwAWzL`V)lle>_Fe(V5_?W@4*su>zPBjWMb>b{lQY75g) z-?Ga{uoQ_Gx)vE6d8=9B)6;y3UkGLcQb}<-Y6yX2>pKCSM2E`7M)`hI0S?~$#4nBb z{4ug4EjuGwf-F~o4O3SNFEKJj@F<%rwwu{dt-5wI{ugmpRo35%pezM3|8TIvrIS78WEB^^a=7COY#D6CAV!pRyjE=g$MXEv-=}i zq3XDGUkWzVzEl2-<5WehFILn=PNn9L^o;rOTf#KM!P&%2Y>prkSJ`h+QY| zoOxXcO|m5+|1_>l^{Lzp)DkU*7Y+DxKx2*om&G4b z;7RDvZO<`1qDyknTdTxb^>L6i@63kI11eVfh+jvH&lqI*-Z6xZbAy^=VK>B5!o5uY zCXV*uQ-}a?JRl-Er@N4g$k99=I;dap$}lmM%hh&kRiXka`1<}k%+IA@{)iBJelIV{ z#En0mQGEszK8DFB=@+LB^O~ER3dUQ^6W^|mty^J>V$udh!;Bn7NuxSSV-1oZa@qgh zUOGHbV%2RXD~czZqXSJy#S(m2P53{j|J+zh{%BdRGLxPAHL28Hy~AL4efop-{S6pWcBG2g`Y!Le?3@ZN!ixrMM5`SwmA}dASV5-4 zS^hPHy@cVniZ;8WV@su~r!!b0T7M-7C#SQ>(ZW=ULhMtZlU8N93HSBl-MA0QNKP0v z%3)r0ZOWAh5WPT)qSI2Rpb7JBu1asp4c}(RZ7YUQWV`dU-6<=7Xpq7GP-2C3AVy^bESR&cLY&F$9KH6^9kqHYN9r7z%#ut0_z zW;!AZuS)rcASp;FKJLEO3qd69L7<@E~rg* zM9#*TAzmHyYb0w+1~cr@E>!M=pQ;Np`xU~9(YJ%6S(Dj!Rs#n?hx64Avovd0gz4$FF)VcyNdh zuMikrT^aU}_<9-n_u(X2*wPq1=eCnO#zndR+6-_YXuBp$XB0J_w`Xl6gAGy0{)|W( zgKd3!sO-;FAGlpm3$>H<9W4v5`qSL1=zDYp$FXN9!j{vZNMaX>msd5Sa-;b&z`+z| zGM(?HDM3o8)iycDR_3Pna+5}1c!5(H1&a_zg;bDr&;F7$(-wf6ab%n+DNU~tv6n1i zwjQp;JPRYsgWe*5ex|iCXrBQ5WP|y&Z*sryxP8@PH3H*2$Ao3PzW<|6IFI%I39Q9; z7a$ZeC>-T2{oR8uCd8Ge<(Vi2`%^jXyA(Xq$c+&L?+bnh_o40lE^D@EmR{V|Ix}Eo zkX0Y~thP6m<(|mOYC}a4d+7~R8kmVR!e%qzjCFKg5&O^7y?};&?GvRLQ%kQ24xE9c zuGPlE{MDs+sKr-J>_@Th$wSjSL9|AV=duPCfq zg53J2Ofzp%Y^8;Qy=VC*Rd@BzJam;{xxBDGY**SP|P)l854H8*&nW5b=V!1~y>dX*i~yKMrZQQyVKF*x<>e*EnN(hX01(%FrDzB= zpFLwcytY^YO<&13tLk!x360jff{HC756+!6M^P5yA?f+iYGvA_Yc7Wt%=YNgUy=tJ zph1aXVV@$IOUqB{BL83lWFim+^$GuJ*X`5q$if4$2IW$=z71#*;|uHa{8C}1Y^K{t z?+x*iN7b@lnSD-?~zvqxa%EY+mn2_e#9KVPV5A_{?0n|CV8`fi{bhA)7FaYgw8 zx3h9tX>vQQ`^IfA*b&LYDDNt!&CAPeCCcYd8>|N@{ck+{)YWPPVeDnX-<0OXU+|FG5X4?$Cws> z)ORVHvq?1;Z^Ki`PKHn*iVy_eXudc_4D@Jq6h>pu5oa=Wk8fi9@nMxx;ZKvfF`PQ_zH?y-EetzUcJFs8-)LR8+BHQlX>0 za>01L^-2m8=PdBQTR!fZ&0PyE`+Nq{D`2H?ohr%B4^nj!Ocr;ijSYejA|!&S5dy+^ zZ0rV^F{~KGZ#{fh`@{utQboOELvlSJZ`NclkWpNeNV=%uaad)-7LjrOg|&Pjda?`# zY)%kaslh67xEs5-^qO^FRttub*01A<4rIxnHaT@O6f;fI>lN5lN<3rOfL-FjDq<3O zuQ0PKPPPW4!o(~*h(96Z_yZ^W!5eCTMJF_sa63^-uwc;gHA7&YgGshHSuoM;XLLA& zb8}8nN|54VcH7G}<)5FNn{s6IA)|#VAQGEP7*)+cJ=gJ_e=|PyfZ#5LpTC%0FxxzifW~+hqvYf+!=K!8HT@sp|yDz`rM29(}Fk74EOs zU6i-@&l6R?wwV9hsZ&I7*dfQ_&*b!!Lv>{)1oce+`oWXnr*C zizR%0x)?9$YU0O^t*RtFfuc$frX~|ht(JLU>Bpq2^k$r{~l9dddyqxTL z^6?1S6L5Y22Vt*(7%P>3{?*NXB9#bgHws!$d$FVg6SYoqMCPV`gx;alg8P&4cT~EcUQ)2pzK9PK%}a|j zLbb`I74(F$<1APK9?tYW{*pViE0;+8zckc%uW%!tE;2S@XjJ+&Xx&%u=)Dhqf&M#3 z2sk$G^#TZ596JcK-XbmqY&L8o-#($S64laZEF&?LNhxPFZs6@9fiaif%AE)%K(c9J%QssU&D-s zS_31&op*4zo2#0w+!($$#V?!x7S0b>)x2B8X%Q5zTx!-@{Ly-N$-hShTn11D3w(+~grkvzw64*Fd=E2!y zapTesPJIs8JN^M7gS}2hoEc2$l7Mr-mi|pdpot^er=bp@o6P?Be^S%zZtJ7Np;TfA zUf?xe7$7G+kU1WEV``d^BVx#aT{P|pM=lbh9HVV%YClE|TzqfX(3C*6I_MKJx(FQ! z%VUeV8uyF=E?K}dFumx5L5nPpa8VYj|s$C zYnq6#JsXQZwNyrkme%G==Lhav?ND1q~mLJc6n(MO@zh{3{1o-k(1Oa?Ob5*J#Wlw(Cm%R_0-L?+_WHUAhRVJ zCcT8kyfo|1_3$bC))-%VV7EtG=F;!|Rsm`p3?Ke;OeiQeIk)ygg-?nDZQ|2R12TnQ z1e$0M&XX`=Bxt-%ZTv+Oz^CJSQ-x@o_nfRsN{ozBKVFk5WO@iuXa+j89Fg5&T*QahH)7ig(Na9Mg*^c73b;A;Kh|1@|4*^&^j_E_^-t_}IDJQi@vdk$f1%8jB zty@0`k@(9KUqcq=51Rddc`V@XZUCP;_D8lzfm8$So$~Y=*bT)(CPzl2c?`c_lw$bJ znaPks{GbnfHFj>tqNiZ?XA6!x@h0gKaUC&T8xWeL&G+F|L#d|17KkD@sj3u~Xg)l+ z!S4nW!eZELQ%oykFct?WsUMk#j@jl8u;OwL5^5qVN9BS((yBJxE$RAZ{V@^yWA#9?d!td7Eba+r;Czh3 zt>Th$Z7Q^u&CYl)$Mct_if9W0103k8!9WnE6h{^oTVHN{FeRxDRkq9Tg|M3;rTyiN zku!T|a5g3N25oOPMe6-2tUMZA1fKyohR&>W(SnUodgdiKF0RI+zw#aM{Uz9FR{zsA;od zKg6T|ow)MepY^dtVjkjIMZv!;4jJ+nvjMoBL5}t|ah9Xlh;7=7?%Y#+e6ts#x!VDT zc4QOtxpM`vW!%uqz-$R%DlL#}DvB>3oJ~Z7prrS?fAQmw%pVefGjJ!2z>{<3Hi~dF zg_P!e_BdLX9M8qZCv(ejC{D!lI{9OoqrZvtXw^D%gLliZOvZXk&1&LeqCuom05#D?HX`(rv-|_~CW-KTj3$7KwYop2E z4AK2%r8t|UfL>FYd0F$xfpTapYI?3Pci$L5RcO3q&DmH{4Y&<&*#!FtC$~UhZ&txCPEIOTKX?1S|AL?>CJ(}$r!;o z^)L7G55?g1zF7oDCI+3Tp8XNIR#Z)|{YrV$G5+|wU|s)!9HH~`70F6c|4l+ycD5%M$aLFM z;97I!dbu}^lIp@Q*f)Q3FYJWZXJMKv!i2jSaY^WflWaeBCv48XY z;#KNu>qEBuu{#bE@Hz9za50~A!O8l&rkkL?uCA#01f%nss&Qh`@_?APA;Y zT)lZxk|}v!LueYw{%Fj>rt6Njt1l4$-OdVdj2Zj2pKW^Gxypla}7E+z+Uy{$BA` zu#j!cEwJ#Cfv8TrV{`+TnBCcF7M>-T3+M+WrBi>N1Nne`~^CStD{On ztr@k0n4;LV8iK$*fzzc#dO%uF5j%s4(0pzi1v@Vq1ykGEqEF{DGE8CbO-c zTE zKAEkWHfXRwGYPqm^N9)5Q?_+8uPMWj@Qp?_flCjk@3i3Ef8nwhc^5?j`{DWLGbF(K zGwsNIeA9b7DJT(m9Cj?VA!l`_A`R=n#QFrv#lm;t{y=hEt6>}VK#Gs_BVD{r7j&zw z@t%!;)YZRzh<`$y;2Ti)aXZ6LNTKgT@2x1Lre<8{m8xJp{`R#jtPU&_A;#b2)IN^T zawJ~&bu5Ngm%t!a{3gQNjU>@8zUF_yhz}epGt;b zB&}iT0Z#Qkc#J43jm)DOZR>B@hc5;k6JaU0Kcd14N%n*+ly~m?l)`cxlWZH0W$Y08 zu7_0oW`4Vr2;k){EhRkHB{OERUE<<@i~y70$|t*4%X0?*P=4$DeA-r_=@NC^5|54a z*FB40VkweBye~W0^iGwne^P%uV{diWcHFwGmMB=cC!sZAPrzb-j@n8dey5JK^_RSR z1BWNf7kr$>gMCxP4Ec#C>gGINYbUEIU#Qxl%Ie8bvA@8{1cXn``5YSm(@`*TH36f{C)gpNcazV0AJ67?{II&hNrz2mFP8%v?$;JDNxBmpZQ8r+-i9+IA+RrUC z!+1;ByK6LKbJRXKAMk~Yd(oBZBMXF!^(>C>WPpQ~xP`r)egwzoWFULS1NBG7LCGvm ztwm&E08itEMd#>~jFf*w2& zw>E43hswNgau@(CPz1+ld86fg2oEN{0*rB!kMFHLG+V5zV{Bts(Y&3>_UFRE@6Mg* zmnvkUzce6IN5s}V##lKqXuqMXG_A0@@WadRKLTi*``TvXzkq`L7NWpaU<@q+HFuxm zt;JcsxHgRIuw0(hlOyD~1Gi=2nQdhwP=>P_%&DTznXdxmE8sUK!!BdNRKyWpvWymI z1Ck-LH%-;ugh27N2F=9cGL8S@r>#N(jF6yU50;z0l}RQYO6L@*8Rs*`a^2UpnA#Fm zwxO9Iu<4ZfpdYt&_t2jxdVBrn_ZbiWI~W{@-2Jx*j;Fy<{(Tx_i43G9ZG1v8l%ab~ zh?{~b!;MzkJPVKAq-V8r+h|XO-fSqJ@!a+mEi%zg-xZ^VW872SpYrEdAGz;EA1Dd+6T%Rh0jq87g*dngDp za@sHfYZ;DMS1YB?OGox8!<JP{Mr?&d#hz0oP``el8hTP@zt`uOKVqB#P-%8{hMQbw!w~m6J(*TFpHd z!wv5LFMSLpXlv{HWmHL8jXdFieb&vn{70$>;I_mrIvuonS($jFy$HeCHv8}B9ZeWx zO%CR3^&du|)O^5Vd}yFuf&2^R3PT&lm_L^ddoVDxT}2!yHrdS&$pkhP9DsgOu_oKq zeD8tm3JU4Xd-xHH9?Y49@3`>6?_7HP<^umKMG@P8AfRQqhz-eGhOum^Hz3_BEUcwxdbZfQr2J;2##Wl<>wiPhBT`66uq0b4% zvd7jWb*8_EZ*VP%yf*?0EIli8GwI23z z^q18bUc3L()&N8G{v660@;=Eh*&}#$@+V=@hZ>G1>r@4&oh;$Bq0Z95w||{O1TREr zugd$NNGRcgOar}K6^sIqnrcLxu$2HhxhMujEO|uOeq^FS_(t&Yvfuu<@xos6FH1+< zg&Iv2OUZ2MeJkh^SfPA}kYprEQzvgSCSZIGI+zF9T&tVwO=IC|#(SRO9IB2NV+)J5 zf{Nm=bvpk1-U15oD+_a#mIaa16DFvEgx=$R3g*!ZrfYWHLDC2kI)`MVwd-A8W0vF| z7lZga4znu+*Uq2uO&yYGnoh1h>DoD2hpRSS&li-a*My>nx6>R!l9gAOjEhGbTcWI! zQ?rkM{`VJ9fJKiBEh!QBm?glGXeagIl$1bO43jq}A35{Hc!fQC`qCq;YvueC_%wX) zkTe9bUgL9DWa1=)?P>N6D8O?i^_7c%wtBA?ke?4xfdQ!Haxcwed35oL)$X(gFR%{fs-2O?li6IhNZN zWRq==>u$VCoQ&&bD8>f~3R5y|@Y~(*v*`|kzIiYG+8;utdafw}=c3MHm_?HnbAW(+ zLFd;76hw}44Ab-j>&X&=+T*sG6EAu7W${C=4&3m>@>D{_(Ce@k*cpzqimHSB>@h6# zSA}MvGqqlS=L~r7v8gP{=pc2`e)a6^;#h&H&!UqZP3m9@(w0Q#o)8;6j{7^xK<-CG zZ7xy+ySk23&kt`~LcM3{^R;HkT4hPhFDOh4a7CYP#|2Oh|x_?HOL)}k;pi2<3J`&Mxh^Q{| z-KuN~_xZpYs_S!CKYHkk;ZPc%k5rC~EvMf1}Y*iz{MbbZhbfFSwAV6S3CWb*E5nMLcmY61N4-IeV!9wg2 z)3A0;3K|tkTZwoWO~oq2CmXV&`qk~n?>?D-WNW8<3rUu{q*)dJx>xs4U$`0?)G;`I zqe=|R%Mbdf(yGdDMLTD8wVi<9m0mm(dYv!(YT1Gn3-?|9eYTw0S<722?t2RC^Np=~>T^2no1& z&2R)ZU;DhnRuCmMftDs@cu)d@aX;VoMuiD-NQ#g;!lAWK>)WJ{yPr?uB%U-z8nm3s zwA{tj?d=~}WecZtpZuR`_Z^g*p{AW#p;lxa%rNGGjFu17f|f54s~n>h>alGR$b-9~ zpk3JGTO@X>!uPW5eZp6X3QOaUHFy9|K?uVeS4@zQDMGHsZU*loJ+fZ5^IPoYO3KZ6 zB)$7N{>F%8vQ3}@Aq73GDD4OCsypPuAyzc~26fhARc$LAk|Zqf+K8vp;>zo?I^Lgu z&QcM+aoLdN0bN@_Su_}v{54{^qJ4o)nH~Gyb$F%a`a9PV_^KB(^Y0ZsI_0OlC@(|!IfQ? zPtVUON}ODmJ#puMQ;=Cf0yTNH8y2aggn-z=3uJs=Bz`pOGR6-ssC=V+xS!b&UN{j1 zp;cTqpbbg71!5=HtPAeZe8^?>Bkqy3sPRX1X~f*p_N($gEVPO9f6^N;i&lE=_nTU` z%0y`a$kRF`H*ptArbBkcmAACeGKZ#eu3yO^F8zzuY<;{Lp1)UJ^5kfILv52xnD$)| z%`dvN4u2fhsUrJAj9<($cKPL#uU8+p)~Aay*~xUP?v>(KEOoPKn4Bi!33}+?{l1zy z;I>U?lj+1b#_{Ttv7-3a>cl7DQ#ZLnH%2;jpDiBoT$~v)@D)G-Ldd2NbZPIFquZMa zg9dd9`Wc8Pu+KolFNhCeY15ciL6aSevAxVT@?Jen^iCEWQ;NKkeK_;$NDxz59{F#( zFp-4qpHOhB(aAAi>(Of>LvpO(tLU~b;6q?HYoANmunX&5Qo&4wba}QD-~O~)%m>kFj;#62j?YNQmlu#FPC2hX_n zJkD3Q3K;fl&}-Y?o{=EI{HnWrAbLLP_oj!T0@9mp;=$N;l_JhNI;ubECIeEdpzkTB z5nH0Fn$_uv%?YBofYN(-rnV)fuuu!~VSCqX!{(@?vogQ9eARXH!|k=rK_wTEq?mvs zlm*RrZ4#Lg67^Pz%~h$yKx3#j*&*mT%ban`FylOrGS={>OY~qITr}sCWY59+Kwbjf zbFxTV-ug^mUMkr#Ws{)?J}n$c^G%3xB2?AB#DFoRP*v{$V_}# zBF6PryGGq2jd~;aKm!j5Y!PG+vd{_QXh#cE*HgVEaxyY?IhqULy&wagr41gJ2pb>B zTrA<|NOf?#sEJ!7DJKOEGyz;rk-;JLy?)*h}Lpi=u5j4Jc#oJlL;um;99D*UKF zJFiTY?Mm-UIfu!5b!Dv%{G$~@Yj;2%$_c3m*dk!(z2s{~?)4u0R^fd$t6QQfGLs8j zL3&GnM$r2svlO%n_>?~eXVL+7CD=2nqPU^hl4aGb)@qKI?9W!%-f?j(zb5Slnoz?g zYWKTXYIl*~RQcQFI+EJpa12y??_r4o3vA%8J?rz_Fj7Nl026-;I0^Tq@7`6*B0 zW4>_PX7T~9(Pct6jjVa>DDR*AF27e2gFseR?cXM)Hd@duCaaR%&7Pv+5#rt-H@XTV zmL3~@)^A6cGW~t&e24Om>=H{pi}-iI%!yCbvPF&*kWP8FfwLQs22iYFRVDwdzmHQ@ z_LK@d(juhH1um{PAuO9XyItU?ZOynvtmTxR%pBs?oN2VF2KzRG+ZH7RM(yz>nR%y( zwnG@!Sp7DV$Jk+sI#tUvJ}21`V^8~`!PE*%B=VW|8+P>vT7O0}#j%3&3UPBzQ@mGZ zQB@|x*}>5<^YfYPF3R!`lm&DT^<(-aMt{Cy5Lx&8Xxa`9wN&z-j0vf#wstSNGcH4j zprgjxQgNl}=FoP(pl{A#+HAbkLOY((77Z?gpRx{qU@Ahd$TYcG;h8AG7NZ~{2VXEi z!{~*hEv56yyFj*cy#uDh?J!{zVV&X%Q7PSW?l+VC719~O3c5xV+11f9b+`7mJ>;L0 zLS2ED0Z_Q(D=$kR3(DCrTPBS@M-%(17T$*##MNEF0e34ypzIy(=U{b}s*4Vaou3?= zzm!5REMRm1(Lkd#5zMvvm9mTZ_t!(MW3$0U(Hlnd0UTd^q2!JCfW?!1A@xEgl_=m( zsJ*d&9>D9h-+bNX_i9*nrh3)NM|Qkeg_Q|gBD2^BL3 z?`DBsAiJo;@doY7H zJ|7GuGhX{|{zO0KSqvn98D3bF#0X55E{|o2;!A=3OjvTuxmS&?JVIxKnwK2kk|f=R zvLR)|M_#`K<}}Sh26`(71qv7XGgO@)mg-9H9Y$JIa*I`&u6Te(65JRXg{@M{gbLi0 zsuzvWhwMego+^Nm0>&5!=^9*_SiZj)joWIs%^tq*nUxmQmnC2+Xuu=4uFkBEz1Ny) z!8aOQt^n12kP%a%YUdjKKbo#Gs;Vy9!sUWo5Gg6?2I&qZq`RcMySw2kARyfhQqtXd zMY<8`?vn0)hwr^NhJSP@p1sdLYp*reoO3nq8AS@I^L8~u;yOYD21&ybfK(-h1zwUo z-)ex}>Z4{IY1u$yyJj}nmOO{ZsvA}iXLa=pt$9xuz-`Gmz=`|HD*h{WL%vRz@{`y2 zUnt*m;3PfT_Nj(gDHFtG>RXAea(^(;1o+8;;5y0}#?qozgbgi&Kr`QE>zR+7mVjH@ z1?@MLcUNu>^!R^V^)MQi$u63|q<6jgrRI@pr>BQ*)T>^3C0`72g6Q;GUS|Y_rk6;Ok%Azxtn1?ZnWsoluM}Zn{(W|#LorqoJ*TPAkyk$} zb$Pe)UZ*FMa_q;DXpOZCW|66Fz zK&4(m)#<%zsmjh>kA)JS%0Hru79_lh!!^S!q(fnBVE-5?SdD$Xw4?`~$>O1E8ydLv z7jo?tt%ah81rcc+ttO@LPKt~&redf;G~Aoby-Xlod0|@c zf;I#kQ!*4MiZW*v#sGwsf3#$mq)pwc)}@bVM&G`@^m?92yOOXwSQzD@)MW7J{Zm5{v-{%Z{hMGb z<>=DIZ@*RXLzrzP{A}>OivV(~p(Q8^Yr2friMVk8T}uyuIbDzi3Ly3F8VvxY_oKxq zy0Kpwvyt&=K{Ibe;w!sBwQRgYy`SYp+0KoYmas1lB)1qa8Ky&oDEw81^mb4AWrl>a zweFUee9Mp>3XoQ*M4*MF2InZYfGeU zxQ?>7(bWGKu83aDk(05w z>>t3qP^m`q+5%m@+DZtH=(~>@GA$lsz$p_QyHlufpKh;@`n!ANC)nYUR@>ctYHM_J zKe`u?NZWE5fy=ARZ83>@{9wRF0Jnu9FIXj!Yess_m()$-^-q$axIlWa+-~3IFuR(z zt3Yo6iVJSeXYpd7yZZAgv_EN7VBraQijY!;G-dva*jW-R=rb#jvRr|wUZK@|>xl#Q zKoD!Zvy*vBpY*YyC=j`cg0GEJPv(&-Q{Ca0AWcADPS|r~E;|8b2hXeUc>UENAeaNE zOn4ehla&A7CfN`=@R;(@l_Nd9s5#CFQh%ioR6{9`$33+$)!}pSZqlB4p71sNmNvje zz~Bi?T4GrJ(o9U32==93)qczS%b$t5qw5DNkPVPQc7-g9Q=VA*31KXAD#b&!vBB4+ zD-2uuO}YO2uU@$93G&2A1cLB;O%i2K-3U_8tA{72wf_lfz@mo#W@F6~#XCi`nH`9} zy@F`U!{%YqR$fbtwkQFG#N|IpzK~WBcZ`4cg)|Yk2|2UsxCyPIA4wN%#n*aIj3kpD z01@o99Nb>H_p1);X`DWs9&;@@8)>o*aK6$Vy7v1i;uT!>-{*+3S+e8{u;8!SrQNtc z78x|A75N;@9_v=#XeZ&F(*(*Jd!ONAeSxDTzeHaSfkEH@_tvC90Hm28XEKdU&+@K@ z5j7?d5nP6r5gJrOdl@~*DxZvKz}>04ySPw?4H%3=H+e_P{n>JXmIz>Z>FKq6$Qx6e z#h~!dQpOt-0W=smw=5$=i4&*+&pwGEIYU{s!w6C)}a{cH3K!Z=h zv%#!WL!p5tB2GPF*@p^Rz}t4mq9f4pkMqR1wPwBDx*|AmFf3D9oEONtE>+yNf`u|wM<2J&)x5LUi+() zegKCSiHB4^niT%g!iRwaDR9H%plz?3A#*4y8z(eDH&dj@;po`+QRvC>@xxW8R$6E9 zC%CU@5@4bN%8LM`;0eS3?VuxI(7mrrU8m}nA>S-Uc)MnWRTT$2^^;}D0In$?QX&GI zU=C)U;Kp2HKlj}BW;+6Ni-vnfZWSk~a*dexOeRsoQaaGV4F%!%eQBzCvqdq*E$jZG zlL02kWbG=?rC`o8xJPDS>$pU4Tj-mjmlyH%A$XtSeb@=y=7CZo+iaZbVte;A$+Kf#r{PcNbN(>^0i4=jAytj*sD~`Yq4{P(cXk6Q z?<8C)*DIUn`;1n6I2)Zjw+A}j`mEsVQzy{?Lci~U465%KxPg4BoG7`tCD#tl8sJPp z45zFlo@t}yOph^TL*xyQeiIgwxk*L-#ACQ3jb}eEPDE7G1DS`R6?o zee}DXV6O!<>$gdNoVXkgW@|4M&9xM4q+xGBD#iMn-x|9JnttKXs@G9vhQ5Li*4pzH z^2s-WAzhs|Y2972E2lKQ#*DWJb`@%NUgLCd#zaR$zCckcdUR%Yl(}$3r$n>IOMAfw z37}n0@rAT)Ibo*bVzq@o_{g!Um>nrl!yUR-OB3n)0Zvs>IGBQRm1?tGX%r@H$|T(5 zL=)JVP26x3UB~}AWA;zV#cyvAvg>~KsHF4}H0LyP_bN28v?A-wE+w>22we}kKZtxK z9du-rKO`Xf0XUIB6>i+s)Ft+7jI}bDL7vkJD-9D3{s8nkDy~uNYn(RF?eL{=tjCxl zI=O(*^u)j%kqzqx00Zp;I)bQUMu3V0jBZ5W*4GGUP@rfN4N(PZR;0Jaj2QiXPQH-DG~U~QXjPngq`Mojr{aM?$~s^EoKpbM%;Vg?*N{PosK|&p z)H6)kQ|%iF{tLFSPaw0z`W11SFLRqfu}u~P{0~8{P4ht>T##AeK!!eBOYu8HGI+`P z+I28OH9bOlAWgimF2qvEGR)Q3x3K&2D1U_y8zxg;lfm#!vs#L5j_?Ik1AfJpl-wd; zaW-et0gHKqRYm8hk|-kPib+#;X**GDd43(ARK*JA zg11Gj1fCmftJ7tIoyaHPNd;TI#7e$f47Ha_0 z$)a=*LNpZLvB43Mpj%Twe?X*C$Awmlg6>s+-|C6_{Koq4HfQJ|Lq*YWCC+``q>IlQi;5CE}NFHQL+AZ--Z(iPjFsPb3hE9s=xbO9}ay7MZpR^$y zXaIhc(5=PuZ~j1kwl^C^p2VEI32@*5TiPuv>co1y7yQpXM&)I_tCY|;bM>9WxsTDP zOMkmbCTb=m#ooSj8sXqCR%`U>hsrPT{>mAH1)s;!5#K_NNN7;E+PG*v|t` zp(O>4Q05$tg6tUUH8BMJfKI%4@CL#^K z`l^G$4~I8e%>Cgo>6)Td8qSY-G)XIEt}OmwESbgEl?1$D29tmk9l5TquDC>5pusgC zC2kZ<#RT*tO76qFr2*$>nWKqz+GxD-i5J#tg+t1(c8nT3jim1a@REZvOXP-dviCR+ zEgboNz}mL4=t_#pMM-U|n@M&}_-HNwz#Rod+M2IY=`ExemR*5I7F#J3>xEP5t#9YB zJPj(vd=++ruP4w_1S{sf@Mys@alpoiNR9Y$IUw~z=j&1K_(06hA0aoNU_CH1 zk@L}y!|@x$d{*rk0hhlm244UbnB1)O;|>pnCowm)%0B=rmmJHcvZSG`y|2h6up9UG!vD<+mKJ@l_p1HVazowm(Zi= zh2(FY9fHk$=Z+6#?F^MZw3c#Lk;sTZcE2kMhk2xG_Q}tuw#k4r&k_QeRS>3dq$oqq zprfaqU)H{e2A7fLyq20m9Iv1(IW<|ulVf=IRUsxY8l3-hyr%+m!=jlKUOJOVn81zZ zONi9P!q&e@Cw~c|>g?^TmofK`RHJOo)1me^RB>#PhV%(qGwBs*Kn4viF%Y(7mvKq|TnbvkXI-hH)E4B_LBoE%? zlVb}BUW~R+8vjaPw0*<)ml=35tdLd6mzfTLuf??u@o^>+1ix8 zQMY;Sao6n|;u`zkcP}nHxan~cL_*B)^P3~?FDwU+tG=qeyXbix{s4Qq`Ev3Hlr?7$ zjiH7W;ppq*&*C^-KdFg!Wb&`?2pL^d-hO!!Rx>n&u~}l$d7iKK8A@L8;F$_MxQ|&bvpRX_ZNLSzYu5gzU-rr#0Ac!pEYS4>&n@{k zcHlQ5G=T{?K#BG%;>YA_^;NCjH+!5UGWdH48C|tr0LzxnMPn>(Tp$U+Ac(l>D2kXZ ze8r~yUm*Q~;mC^dkf_9IRVL>3O2vtOZS*(Xv)t>8XJH_qSlQNu6*jNleQt{svdKOD zX2;F#sPfVJkLltz9;thf5D;G(X~@jD_gRdlCst}{&Kay zl68Gyyv`DIZXViU^Z+i{_S5frdaAkKDDwt`mD@3n@qH77-k0|~r{MK_fk;01J}3Jq zK2VDyXbnSYk9ds^Me=)IoJDY6m^Scp&nR*(vM(b)jtuOd#w&~sDXP;zQ!rrPTOiQ* zD1Z;K8PdttOuGkw$$?Vqa}T#o&cZSkl0K8|7G%UT#7j)_I_rZ_fAr|UVkmZTev6f7 zMGYtLcL%^R&Obkeo)*yD3ol5+z#!sO1c@CofvoC{eyzUj4GZACKO)mf+Ru!YU^6+3 z{R#TDijB5IfQ1|j``2R=r^F*5mdIBul9qJHr)En1a!OcZgss#LnWWNHZF2U!QX?{S z$H=K?eDgQGJ;s)k^@nBg8Tz6EW1;aiXDuGay&7)+w7>29Cp7Ss2(*LBJe_-> z0Konr6b*jh*xzN))g1x=Pw(Xsj?1HGW};o%3dp590!*iP#@vr@k)nbYUF;6fA^O`p9&tRh~UhdNGRtv_hEUsPcwu=H2Hs zv(hhOq!*k{Jn`pWW9z}K+kV#E3atC;?19z=oisrdpVr8#R0(TESQ88qBJVJr^&Sm) z1muW7%1wDFkM4qHj%z`=wB z_kBGzrO(*0<=pAc$NZ}IkPBH@5lmVIXL++=e{Tjm3s`k18Z;=riI02qk1|$hpzzQ8 zUQ~VWS!C5$1|lQ_s{YaP0IGQu8;W&wVj>(h}S1$ zGb~^{5*rlzwdb$|ZJ9TQfoB+SM3}+(_^~C7T5s_@_GlquqQU}rk;{g4?y9 zG_i&RewAM%jHq_U4>2wnP}p+slr`*HVJ)eqgS<|Ed5Eph^lyj63_#*OD=Um*kLBQS z@P`8pxv8rH2B9%%lSC-vgaWV_E9g63Yl^_lg`qfSi+i&~!}wdQ@h^cJDcDM`i4S?W z_OYxtd ze~uGlC?>D~Tvc6%3B^Y5RNeQMO^4dY!m1#{T372-`Frf9LToNs9KY?6)n7_JKw^-u zGz}cAQo-fv`MQuuIgk-1E09AH6>dTfLUKs3Si=JIzzDQ7T=;fe;leY73yr7+%dCUD zKOz#t_gX@XyAOae7J4Oj{5eHF^!Y-FHFyK*u{=NcC4ZKruIw|Fe6WC#k7&-B!%3$B zl=>Vd=zBTAaG-=ikY6}f2wiK4SpD&E&WS>)KatBz@_1t9aQGI- zwMx~0uu(Zuz~?8ink#XvvD)p1G4*peQC1o5ZM(45dX+%@O-{;PRt{c0*#exy*#BT~ z>YV&8m$@tizu%RP2G~CHlT?Zq=o!d`>uh@=x#d(C@X*qrBIYPz7PYv*OYovxZwXA= z;48gX=_Q)vD`}W3sDiKdSApxh{UhJHe%H;qZ15TRs*IV!oi6>;4M1wU*xq0{cp;ev z9)ZV&_#{0DYa0}S*+e7q27@ghQR9Fjpbj7ssRGkW^UKaB48nmguqrYzA#ZRH`?zt0 z=}r{HkFjel|6J{$RrjX%#^U#4Zn*Xp)5C_eG}Y<{D9K#?yvL7U5Tefl{%1J9!hV`! zjinFPoSbDZBX z4&$t_tZo{$|pxC-=vmDHyDOBvvtOL7_yHBE#}%p%VT9^jY{t-0g*}sS~h0 z?(m5m62opZYI`4(q9pH&oUuu@LLE$G5z!~}(LAF3#gqqVH;^f5`wx1yon>T* zsy&v_)mOF`)G7=8wp7+dwj|AV&Z)G>q{EVl zD(8#C`C<8c1kr46j+6Sn3GYn~+Xt>?J+LtM0fe?l`yW%C~vuLMz03$|v}W^;n; zUrD#d^H4vTragO$p4hR6;FklyNF8YAR`1?a7*qKD6+}!{cnB7@@m4>Y`dE7&*Um-x z15jAyfU$Iox#>vtsQ`$b?$okE&8=dGW~p;>PH-OZP%xaXr6upS7&lMZ9e8QS<;Z+L z7KV+dwEMBT+$!2sX3kp&42_EdN4N>Q%B&}hVe#ksa?*v6H)vp2o_7MYxzT#sU2C58 zDI6Z`vs63(f!`x_55Bx1R=9-ok_k*(KGbs=3)fgp)7*z-U(2Z0W(Rz%}QV^U!X23ByvSAKiqH0?^|lMfR;nKNAV|r zD?DDl1nV8wulR4Q-;<~-HgGxk*aMJ~6vzmhu2}EOC*%VVEsVD!zve1@bi0uBTV%qW z6wDkX;NxyfS5&eDs9C4DZy^EU1)neYZZ595Z^aFyV7QFoO;F%J z3nL&oE9AsK91at{yh+okZX6ikQ;RB6QFPdj4ORX8U(Yv4BB#z*1rf9`A9?wPG*Fwi z`>JAX#sm%PBstK(wvkb`egkED^ZYugfKvz=m|jx;B?DK;bdLtXioHy$x{y$39@_zw zQfy_`!aUr6XL!21zwg<|+)fMc2QfT#&+C}Jv`F>6U)*AGuIzmpKgq!P&*I0G=$1Y{ z?G7A`%JiqR7!%&0ke2$*g)nSB-A0 zE6b}*=giAG1=!_ouQxWYH2myaNa2ji2} zP1reL)Ri@L_i~zYbL083hYI_gCrz==3?^Ei9E9Ya4SYtkev>8xswO`X`^|XVeBLDe z#w2O;10YXp8UJq^OvMdPjfY)SvqwwHXo6W!McuBi9NF_|4nJ`K9~y{eRf>To_Wc$B zfCW0>gpWl9ssocwXPfCi)Q-?m>sf8I&6vl15rQXs40 zy9Vb~cpoe(z-#S1aS4_-HhT|R-RepL z0Nn%*yJ}PPD-P@BJN?~JWv5#)Vc<*i4TP*$$((agxnN`Ul2_0^=^WC zi_k0F(CtNv$PLA2sgFuF?!&9(#Q2ixB!p|M@eQeP9Q=}B+W<#&Z0(CFRE=R4$x2M0 z0x)kiESNt&xjrlye;ZPST&jTK;?{wf*kAJ-Nc)6oK`-QERG;xi?gK}$^$#ydYML2W zIW_bNqN-T*h^Je8_*{}@QN3fSq2a+(E4(}Ru@0bkkih}Xb8+}kG&QO#9;coIo$GHU z34>AqUOf+1_$OOVIroWhwQ$4A?>~Ecllca2Q>Fd0DZ}$kyVu6vHC;b@c zl0`yFQ=u8d%;jaxluFcZ6@c3l8@^5CSy2IpvTU<}GcAVhMm2~=i3@TgVmSKyz}iX3 z2a28dW;jUmYSYc4%|2m*6KE>{a0ppWKC6EhQr43GIG8}i^F>cxhp);=sKbLmTwR;j zx0a5`^o@JsQl1PkR@e}%Yr_*pnq5+sPKwWiLIa(}axBlnUq#*#k_EaGSPR<)8&o;; z&_oRdKOzo{Mr-TkK=ZZoXO0&?6p|`9mY6_za2#Ur%CDATV+1*YUa`ahd^|^iUU>ii z^5HeCDx;pTw}9Mq(cR(}hHQz+t1NA%CPS=2=fG{xU!|UBh;e{K6?D0Ol9_k<}eu5?HHK-nM2b3|9EpswpPw;NF; zDysY@m$teBbdxBZ$gb_xejm7XA2SWk>f$J;UUkn_Q`Xmn^~MCEfpsta2p94DU)g#% zdzI8AL1&BRt)$%pzah65q6-fiE267kTwsQz^F+x8&eo^H=XT`Q@Lu5p6$?2X3Xa&!PkwUIi zB;bUCy_O(GAmp^LlSE3fNRxd89WpHmiNL1zssAEp`Esc7HNXE@@)u}(u)c-T?kfi1 zlq&eMsqzt5%1Zhl{AaV#j^TZguI8X?KaIqaD zujT2lk|P|%e288i=g}WfvmypG&39)VOZtA?Q;l9lq%_I<9VO>D-4ux?n@vG;0*ub+ zx`Gd@R^e5zEDO7#0cIxlhXs~ydN`NhJ5hs8XkS#4&7mVXz@MkVsAXryVr2X|4^ZCW zbUzhGGT>&-mBmVP{+CgR0D1NVc6csa;wnKFiqc2%cvuy(7$NVe%C6MulaW@L*IJg` z_NNi~d@n%51Z`-bIqor@g5WXoLK8^vaH7*V=Rg{}BI@9hcr6^0A8n9}7OVSf_}DW9 zskzJIHY4Siq}>6mKBcG?jN>qNOT#MmNt5aP)GLzEJftWNU{djbA|u1{;~yNr4=B#q z75XL(6OI?_*@QOVrraJE zY;hfrO2WNV6*sbQen*wJ3~W?ZD!BZRpA!o_6jYIbeE}b4O19_0&S{pvkwPM6MbOUg zjZ)l^8<%c#CBG}i&V_%TB{9oMD$YB=@ctXf=KTCIkv zkn39S{Ubh&j~c15=T}hz4sq=H=Z{Y%ZYOPai0B`h`??*HfJ@CM%hXK+7_RQy{dq7BeV?aH-P7M?x~ACE zA7+xr7WmS4j-okvsn94Kop&a74-E~=@l`{6hIvqp+Lt!U(M%@ z;cBQ=i*GYEJ(UcIctk$h==T&)ZXLPs5*k1heMOg@%SDzGS0jbMVQePiBRh#86Q(Ig z1oMqr#a?qMYT+Y|q-*}Pb2-MTtjLThUL&0-^ehlj z4GjL65#yOFJ)K(x67V9c+54-l-+=MM6{eC(yZu)U>C~d?U+8y+f>0?CtslKhei;Yp z$|rQzf`Zn(89jSITTKbTw}}ZuWmIHayEWmPKIIpY3dH2AbRNU8=nvG4pxHnrKMqE- z*n`+J2ielQFSJ)>X^}+l(a4~S$gVBK&tb03hs{$_9k?p_3L0iTE0N1s+87={v~|d! z40?E$+a^oA`ICg+Idt=ui>49E(jdzq2E zRAoD~on}7k`$$v_Y1bgOL*a+7w9Rm)#8@X`Fl@A1ZL-1Hc7>0xk+T*#U%V09SG;0` z--5RVn<`}JT&}rJQ;fC_WGhYo2!(zjb-R-lem~IB)+t5LWDb1J<(hzu15&{oHrHNS z+KLHQxKr68Gm8?ClxUhhLN!ukn25K9ym=i2A*Nm+?!S3pl&;Dq^0M?!&|s52_IzKn>9I2SpF5)r=Ed_-TfxB?iX1#*JPZzO&RN0Y8vdO`BD^9ViO#s+>ayn&jU(c?ZyS{` zV1>~T29xf%hCk>_7p94CctN><2fxlNi@yHR`R}@5@Y5iXAI7Ftn94nWdgBv?B0X?y z0qH8+!9PiUg3V+m{1mD6o)hiP%{iJ^EIN9<_f&eLD&LDR7j#-WB6ALGFpHzbn65rH zLw?2I{~-EqvDTI?_}Xv535AGj|OmP5QP`vwU&?$2hkp?+Qh_O#kYbkM9U*V-S2 zq$b?GG=-!tUr43MC_q16DcH&;etjfM$~{bx<;o>YvHnUPn7VOQk*fj#D`<`jhJ0nG zEINO-80+EFc!DNd`Nw}fIwObIsX$i;xXcpW^sAbc7=Bw0vw;T(56pj}Y@J(H5=J+} z(A6;M*Q2fLGH%mI)2)mMJ3>B2=ob}z1AP(oCjN?c7s9It2RlQvDl_X{Y0 zX+Sapw(%eO?kJk~H#N!pva1O4PHX?3)Tqrw+kC_!fs$;M1fVKr3Z^+8w+kqfWy`Bg z4Nvx!c*8EW+&ZRD6{c4?-+(I?hS)(9lxXrfM4Nh^;(gr~Nj&tFIcc02<6Hge*P?2a5fV z3i$L+8d14ke9z2(-(Bv=9zL8s5^0U+jX8AX4kE zlwt#O7`v8p-lSLjUV`a0xJmSVB+8vKYJdISbvWe+<{~i@@mTSz!#&DTZCRJGr((tu zs1mY6f4&<%78}e`3@+owcT>?<;rMX`4;7&MqAXnOM9ms7SBTCFP}NbM6YsVL#XpnQ zcj0wrI1V2V`OwLrqReGqA7tfZG+|XyI#O))IN1r`m7_z)`8QIaeApaC%O%kVw>r7H z1DtxdCi!6b7nimRkjhb84$w|X4G!z0O;rD@oyg6~LiUY82cTEm=;Vhf61#^9QIf|D zG^L_T=4v4nG`%9;3uQ@Gn;!oDd*uJU0G`AQIh@ht!XqJOX7!1)4%su(e zqb4UP!Rj-LkC=DNiX?nSXDm|iyw4Ffoi;V7b$Toysj*;qy0%W4b6WH@pDcHut-cEi zqIRwd#L_;2aP|S5&50HHI+!Uag}3gv>3wv~<3$G(X%zo2z@x<$^aD|W6=4#vkCCwh zvWYX>Su_bhDhwKU>iou%!9fIsba#PxUrXu&##tpSB9+7fxtXosk1^4q71M{Ey*VL` zM&7>Y^eZ~*s~^9Q3VyBow1T*`MJZFdFGwk~h5H)$DO29c=&OW9-b2KoFZjN$nfoRL zZgpkUpkoh}`$mK`mzuTH>0GD!{q;{zL0n0jFvWSj%XT#l#ktjZPMdDc*b>z89|@)g z%W17~QDP!6HA2b>!XOp;$~Pj6W^uv|;4YL5PkN_{p=mno!Df|3hcB4`@_j}gqrAk8 z?%SalK|C~~5#92Mm7@npyRts?d-#n41~D_C$W86*@yJ=OV)^>$^(ud*Qg3js=5Ca& zZs|8JSqDiNJ{C$1Tqd$x{8ezZ>W z)C&rqu7#_QGOfMO=f>hq5~hR3tC}r+%&*|R)toX97%U>Ou~<)EVy|0P1TBqxNN4?U z80|m!R~#3KLPiEVui|eH3GqMJ_g#PDfBiE^o6`I|1_WilRP z_0a>Jxq@e~L)!oqV2He05FoEMz080uzQ7vyFeW0yfP`=^+*Q(txhs9`kNdOiCVjg( z@oYmJk+-5 zyrKk9bX^M1c)c`eq(Do%vSHK(4(OBJxU{-1j&;z4^xzn8+U;Ro+YL?-g{1jfw|wUAu|# zi|2K!&_{wVsK+N-T=4W;`~iVWv(D9XqX+GYbK>P=U-r)M(vEp2DixHG#}pnjQ5+*b z5Q0)ZjfMOrT&-?;e!o-g+3mKpNv*v8d;ND=@!}i_5k2KvIQ2PIRb*L^2Y`KgjJWSq zaO~U$D0amKEp9T`W}FXO=m#}>Y-jA;3LJBIY!BZGd}kJ(&3S*>JCM9Om&Ls!zD~to zR{!e)Rp0}EnBAzM$306Xmw}uu0?OMa{hxSy&eP@E&zl8osxDbVC8I(Ss8Q7Yb z__b7TDITOJFD8{#SWa4uOHSF?D?c&hij5)W4wX54Cj91S{Zj%xL(4$vl#!zFaY0Ds?;JLLe5kLLQKZ|Jt=k>>G2yGTrOgg^8GlaXkNY{`#ZI;9~5)SkV zWp{q768%A7O=zsbMy8Wz&5rCL2<7dAY)i{G1T>W0; zn2^D`q~zGMXa1E!gqk7vvkJWYhI;dUVfoAgnWu&{0=?MQsNLS|#QxHXGkMY9IoS7e zFTcA^ZNWrDwp=CfpfK4^*9SjqbHgv!`>i6iigvk70~mCc>-px}xrl?#S?RCCPbCQS zg_fD--oP7xk&wRGtDaFE$ojmo{#H->mz#<2Ag6EeB3VvDvXP}v3or3W>05P+9J<-- z^rh5lt!wp6Y*sTsc-l8l4Mls(>!80(hT@ODmkJwRdwad}xW@NZuJMH% z`}N%Q`d)FR3G_yEPnwn3B-vHM28z!X5gf~M8mEkbT<4#Q!wt&rj;1v}-s1};l*7Du zZ0%AeSr5%KpLN#=zbFvtrf@je_|5d_N0KlsI@JK%&)K}ks7EEx>8Owp5x4>p6`<_A z+G>65pfri$7b&}xJ5gCzQX3lBhx?}1QHRV4oH-o4(EfPBMY46ysRXjWInItb}ogloP!}aKb zCbH=!tgyseMmm^fil^`kk?c1q(|#vw0$r6GpYx~7bXzYo2CdJ1 z+LJ37RT9O^CH$D5Og7TYIvK4CAQi*>4%3XPM^yDRzrKAL$E2%rnn_&#a_+c zotq84yS8^QsD;?g3Txcx>%pDwgF9f~jH8%?9#f^~bU0DWzTrweYu8;#%AcQpN7Z%E z53fvZb~Lh^T$jC~mC^Puxj#y%Z#;L)@!4NCX4_8|+RtdHJyH+$D|F1_Ug! zKbY2_`n0VcorvSj8}3s{SVf!D!Tr~Sc6rFP*AwSKV3K8cMW%qyiU*AH!SgM2yoolt zM*2&ZyGELo3nA89)*loY4DjU~UXo>?G-KAgCne=r8NHvzC54)ATPa!Xp%Ss5;jTQYkzd!w3Vc?I2{LUwa!+0wf9M<(V;aSBW1DY+YLjBXvQ z^b$P&j#+y_Wuzl3^S{`t=`A(g1l{#gC(}2dTlF;P=b3pklrZqCaBDUSDH|IU-)kWj zXNq6~8?)=D=qvJBeUU3lKE64uen+G5{jpy2kr9g|G1Ym_Tju@b%1676;Dd%`BJkBD z{~G<)eZbngy+x_%P5nw`lYOocyG776pcuKz9GaP)nSR`AS{MyMCUXo8ytJRj@FV3H zU4aUENQvI!K)*oV+8)`CG#@PdD!O7A3DAv{}WxLL=B)YAC3w-pbskd~`!k`&>g))R*Xuw=hHh zwuS>2rBzAV9;Rbku|{RPYIv=64-jdYt(@9?E_A zCjkji3J8|JTX>iQ4B7&$MUSpYIc$Il8V-VMaAsIf!3QLQ8k9wxSc{{V%>(;Ymuoue z**7}b3!0$~h-yMRl8F;oC$uvGmYZu%HIF)Yak2Y59-fg24cac9i9Dtg@(9t zFBZ+xXXAWWQk5OB6ku02A^-mOgg3Uv(;Y z6G?mDCu%IzMZ@Co6VrmLRN`0Cx97Cif1&Mvm*~XGf9!4c7pUBmEU&0-;eXUEz5b=0 znCGMMGt%aYR`d<8+FuFf)O-7}hlhU%V;_GBfKG8{o4l>=gL&*986G2j1v-=!*lPSf zd!(XQmUvDyiyn})t>cv{URcg&(a%!_c(htCO`{hPkk0rtXXnXf@kxv>wHTc@KCh)3 zG?R7;KlhLOUDk7LtdKwHaR23*>geno@}+wEfkh5t!wyY)XPNednt9YoVIC{bN95-F zsO|Q9{r;QJJZYA*(c3^6CK!cXEgAReL3E1m9{G~ys5rwUt)iQl6ExZiGt{^-(UV(9 zzy4yPWav6k-BCDQ8FZYl>!MGs;JU_xtWwPKeLb+WGyaRw&yT34i&>rH-n8lGx{N)< zpM>$|tuI~koQc0*G&#wyrLu>u_?-c(-!}$Q&>D)5=H8@fn9yu+QjX zCk?EPIB;Cs9#7TE zU2ZYxq}IhOob@lsrjkqhkXjcU#$NH7k;T|T?L_Z9PzjtZ!AjfeNVtE3kN3mNxo~_`-uk){+w!Bew|p041Ts7P`f{&Qpu=GI`%q# z;Tm{P=(Z-x{tcs*QA%m%Meo%x-GXvIODgLNtFFffPA5N9D<1MyG4YS3mTnG=9aymN z?ZNtP3820xn?g?PeowZS$e|J$p02e#MQr@h8zFF@mhlri1DwA@cNZmmsLA*99Zn54 zVh$cUz0G#c+^AooXE>SpdHCRyCG$mF8|;Qcnx{Ib4+b}OCuG2J42}!w25k&BBh=o< z1akHay`;?*ocfku!$-95H#c_ld`dN3ZXyiGy>u$tPJd`HXEkm<0hD%Er=pKh=`PuG zu6yhbAFObW)pn1V^!3C`2IgJbT%bzbof_DJtUQ)Ytpe9X$PHsQMkH^85$+H=C~^N$sDalW$oaJ43EX9WyL6wC^|O z`ObHUPw<6$g@NU6bn03@@ge=d00BoV78W9#9PoMP&VVtG#-@R`m9A=AQk!KXK)u3m z^~TxSXK}%MnX6H~tZi@YT0Jf8n=4HV|Iz6-hu|ZzVA{c$-mey#TV-O1WP4i4fiRAq z!<{0vBD3HLo4*7cloB;a>)ft=>`vf&6xZb6Pn-PIiWNMy7K%bO$YT_&{?IlWg%Uzs zmZ_=U`yZ|3w8jcKQ6q^;>x^Eu>N2%!kE>Z|IA z-n+s3E(?-%K@w2v(e$+?8nweuP{cQOWnkp-50IaL&$Gk~)}RBEsEq-ks;Xe!S?@O? z*Q)@#RQDp(PCSj(u4DW5qWw*;&Y9%%G5TgTgT;ASopk0cv^m`-@5yv^&kwonvt5*a z(RNdOQ%cnbOcH)AtR?^CUBFQ3f~TNqP03jxjX~87!7` z7XCV4O*CwIfqN-qX1c=!f3>~C#W6EYOnsd8B%4EmI%DDQ&s}xi#cdqsMs9UT`I=kq z&P*(1S5{hO%8kq@EgSsNVRDz`9d>QdE0|eUG{z%)jz75)IpWc|#cSZ_RBuA%VZI*n=4avG@*QboXY0C2abl=$)jFR& z>KBzbOn&9^_Q}|u;`LjsckdgUaP~yHKyh0+T6 z8oOmzfxF80&t{hfgHw8#hN<{>^CZD*A#Dwv$0FRA=YI_Lvx~ZQX+zby^){awW&~Ud zrrGAoCa8JBR{uJihR&BoX=X2Z4xHHx)jtN?HhK$}vzXpG(dpD?wiyh>f7rKRp&!aO zA&P=$qmm?>oVp{96g!Yn=>Gg&HM?@+FkDrBE6H_oeJp+N+(NNj?21_f+6H8n?{KpS z%`SbvyhfXJy>9Cc1%u9Cl}Wgqm(}et2pmf{WY^kGf6Zl*sWX)}P#%riL=HDe1H;*D z`wdGA?RD)=t*SRJHzh7tw!HhA5q`?1lYVZcJGc-^FbEAXi4ge!dVwHjXg_s=Txo0)gR#LTmzju8 zR+C0ZU36j8wPcu}q-gj}Cf)t!zUo`$F5X3rC_y}nQ?D(3! z=o`mz_aN^;u(Y570f9y(tu<1>yEo4T+X^|fbJ4kP5?GpUv4ZC~=8zP~A`5E7hH<_GNDCE`Y`mLQSFr5%ZY z<2TMs(U1_rHJ37?RsPUNW}+U0VS0r#qwTk^JS3#=AY)=Z@s0cMn4bI71%y1HoXB^yuThjni!YQ zhna1n7gm{d<_3*yd^Zsgj40n|Lz361w(g{6tTnT!sVBMBSq)du)uoV45Ui4-I5vmP zev*vESsfwv zWi;yg5)9{6XXhkLReAVma8x{W@@k*BI<2kk;=-UUw5*?m$VE6oG>ISKsh!fwBw`3i4{~R>~t)zGke8X%mQyj z_t{$S%G$!m>!kcVwsCgp7YZHv$T^}A7n!a?VHD`6uMTU%vGDACsZ zq0Qh5=g{bg*))TgNXR1dY4+ig6>n}egGsl*d+T10jG7uRqRYrmDmBTA^Oxz`#?1zr zPpg(8Y)p#nv3Q%MnIlNPwA6Br{YSTJDeFS#-up6yj>$)nFa-h+$pt|7h+|1`G4i*K z4V{>p=cZc5e$NC$u1F#zJoL%l_X_tN%Q7_dwR$@oC`6o!uAwTn@s?_i2JWCA_u{+F z&dv4VmO6{4tfGdDLrP->w;lSA&{#fwvc;syxfc+=V3+8;y=$x{CqJ7a_lAj4FTbNe zvJS20Nb`*CcRQ}xMvG0CHy)evfe|CcOtZPX6paH>Sw{xAyA$MnY_=8e#O6jSe=IPvA&q@2R zYhn1e%Miu@>|6aMq_U!d>SbX_aU%cRb5A0F&=5okZ$LZp=~+C=^zKnx5f9-Cub8XD zBtNwLdn|r?Z(c#3X&$>%0@{{)9d^$s&%S#dWzXnw2x1!y+fh!1>k+KQn)SFvQn^#$ z!q!Fd4dNpd9WR7v7MZ{ur0S1>epO#(dqJnROW!wKj;f;d-l z&_ddozx{A!MOXPSWTlpqp|xM>H_MDFF* z?F4JSwN~F7rJc9BFWx0HTGledMiJi|)+#eOy@x9HP@J{}=c-RBY~^I{8o&jU-q!04 z_LtdD9gs2;z_9&lCbbR~RB8iBfyS^!MPF0EBbXu9xJ(qy3Z#2Po`ju%Mad`@@fKgz zUw3*lu~>^&Zc#HRAnf@@W%96TireDJH2s%kH}&Lp`f}Cuo>aP1A*X26cQj1!%2H5M z#kJln?}lz^3Km+5sO~z)qRK^e78HMGObNe6z(XETeVI9fkrR%!*OD^iKgPweu@sCw z*_oJsY_!>VQF6@brKQsJmD|D4OMTObGN>^(CzlYHAy)!%b4c3nZG^h`*ES+q@0N~! zU(~}Zm(87ceKQNrbpaEz*XA_4O5l2qxA|^EJh=(68N#^%W^@{ZhO$|Du?6C^ku#R& zZ!_@=@ChC|ha8<8qgU2%zR`U>a@j9Xz<)_|m=f z?7+a9z?N-ijvjZJM7Ghh>F;kU3wYwKV^56YLv=K_VzV(IN+_SXX(MY{`f=o5$__uE zl$T@F#Tjx>0y%!si)T^3c*7UDTY-ez(W{L0afF>^1x%>MbeWiq(_9Z2+rFV6q1o!J z$_FxER8eMTbA{s*E%d%{$1LQM$JFc+wvr$S$r&Gs1cT-gQ<4S4VP=YFhjmi1Tk1*T zU1@sgTfU$&n$L$$PwVSHWDYvPq9l{|Yn_nXDyQ>5Jw6RJ(XQYL^k%~#HbP5CC<2*? z=^N-5dU|=`qdO<;?QD791JarxgTY8@=M$6CRkNIIeR%^ePKG4!FpVb^vZ%=XkQA_@ z3$x?Ag+#2(y?pLCF12c7b7n46Mem2wG51Y-mbO{lv@3GGy^rui#b6)+ zyE}7bx{M?BbrHpoQ^)Hg_^ZS>B1^XAT00IvmMu3*;Kg#`dl%*l;WN*+_b**Mqf1y zE)AZB=yj}JKPGvQ6Pn(b_LzD-BUY&YVaai^Wq;axd!WPIjL%7A4jrjgp^`|`|7{8-XK$`g068U#2t2wD)Tf?a?>i3bryQiR|VTX^k+ZYhB^ch zClWk&YgaKyy6m4dTe|UoLqPocIdF-TB&A#sN^NY37`0n+=W@MnNh+un`5oEk^^Gb~ zFZuWc_SN%l+e2p12Te0|~;P%xupgB`xDGj7N` zrPQUK13VezC4Epwct3h>RK2J^wP4uo04)~e9opL9aY3@qN|*NN3zHSUcO*F;{pi~p z?^NQY>Y?5WhWIIRRQ~=olaq${L@%FzMuNzwPp%#l+es4#rXVBKVny37q!qmWRvg=V z`eX)q%jSFjeSuKHbrhkDN5vG34=QcYkw*d~ry%5WD9BaJ zd_>@g-MB_U%Rui@cx*Z7Ski)&tY-LuR4a>YlzMx3TZ9T}*Gg@C0liOo#X&G7BBR}M zOwWl;?%~bKWB)H*8_&?1qc$4RPn@o#2A$)vV0-bftm<49I|UmQMCkb9tHW#B(U-ftG=RcS)$|X)pPGa^|&#jIY>bZ``Tj+6q6e~esot{h>;EH9U zpx>wxk*3b7B0^c9fi@cKo;*u-P~Y?re4)b-5d^YFpn`Ju`{$|Sp$|{Kp$X>@WHOD1 zs*`_lea<{qvu&M9T&KsrQWR{fzVW&ttli&gH5y}M!r}W=rr|-*wJ+LP2}gyTVgd>h zY~ptMVYHD{g1hA4r?;P!=pzA`H&k<(Ja7AixckD^t*^^iCjF!cFeBZVFd0GwV$pjC zF1v7d38n9M%99c(E_Y3G<>{U1aU_^AV_%?te;9mK_lN{#28CG2WF3LyB`c?VRwGD# z^3?IswK@uVViDH&+(utOoDB8F=~fL?ypM|UmY zAg~*ST3c!!PmwR54ua&{F~DT4Fa>PxBbaU6plQ56brD(|u0&EpL%#H&^R>%J^^^Wh zjdnjYA;c0!v*Lba?A05=@QxQl?%lg=Zi#EOX8bC8YViH87%{p#59`|dcyjYXYFC57 z#x-^)I>GGcC94d_4K6h#li9rzjDd1{5}QH$-%xg%R*)&wNH=UV)~$q~V-GO7;awg_ zD=dgmOX&r320V0Va}mf_NYJCkdEe-ZAQpeQi?aQ>EI2=4<@&{@wz26E)6w#LK#5p1 zXfdB9f5QD8d`*!V1o6&$;qVxJ(zdLZ@(D?Z))tJTPXSlQwB5IV)o?vtzZk)Mu042* z$N^m6aIv!KZNr0 zx_N`%t}Iu`F@LC#KIy~h`@LQf;+T8t21%vc;ju-ViPu)o8HDH7;ISp4rrLzEii^Fn zhfoZs^64%4_ogWD`CT^XyWfl5ygY?9dfG9@2`Cq?$2s=LpSxqoKiL(JuW9z(0ml@KnEH0C%IMD~yhD<4 zTqY};4_i(IC%dJKB{FYh>pX&)Y!9t2ta82eYOuei%ye`aDJ!v&yPca$+&nYy#4h(23)K;(BdUWjRh2)t!)ohH*3^ z-)BdzQcC@>x$`vNq{J9KHN)Ng<<@k6Zp)6gho#ocf;-I- zn#4y}cLYu==+!Kn)A$iCrio=+4R;tqN8}1359W0|?H#w4gBvT7Z+enH4MBHZ2Pp`A z8o3eLBDp2GhOYvOGdziwDNV6Y84x@9S5SE0_{Q=>`Ut!-H%mB?m4*xDXB0cUfE?`! zA)cQ_RhIiZZC#>HBN%VW{Pk2A?dMOfhUPdwEOfbDYt=yKNsKS16T31f=*_RUeO>j( zlWMq*oY6^g4fjIUuBkNhX=KVcCBC%KKeSSmnyxY)XVSIar490ALgk7KQU>i-Z}S?t zoC5_Rk11x3QSM>>@w}QE{Z($f^(#N$ou~dPoO$Zpe&`rc;f*KXZhA&KIb2T&JdByG zEP0+?uv%|cJ*L*enW>>QgLbmYs^d58nYr2_JmA&#N{PMFeaNx5TW42N7zEili5n)o zvI?J`UA@j@u`(ywG;^{2jO0q}p@c@^$vZgibRgk$)Uqc1KKA%ClI$mKY+@DGll!lo zOd(=dI?;gcnTg(hZ--VAu|I~Du|b#aCAcwDwNf^{sm|o#(c^2Q;KFyPNM%IItO=)k z19LKna_es!rk>##XB}f2hwtZ+G^YrTCb*p|H zcpoJw@iSKR=SD?rYA`xlh-v^mwTk%_m#68S+tex~LncDH51*Pm&IP02N9WPG&;DUv z5*&=C=U%n?W1ocq_x3o8%af<#n#Ri5^j6V3?CeNlHx)xvpI~TnLxgQXPVMn>>V^~8 znO%x3V4K#ci?x$>|3Z4YL0(ybA$(mjX6K~$;mI~l*9B`2ZDPz;oUAJI0>!xh-uN1q zZpqaJ4OTAND3{k_=zdr2 z6}3htRltEj&&3osXcZ|(RP&0>X*4*I#)~=Qv7IV zi_bSPet;C0nw@?`Nk%X(RoKlE(o_%r0=*=WZ9C3nj9x+^C-qkUqq&W?!+*Vv{_*GsKt^<_ygtI@4h>QDy`07tc7fMwaB!RAt&9` z!4F8Q^*Da>By=6@;vHeq>`L2&V#ckO(nbd6ftvcyHwc~*tia1XH;~p@Y3uyz<<&da zgAImT5IUB>wG&Rd2j4TDi*Or5$f$Xe0QmR>gLydK-0Py|0>va|1PSy<-vlC#Dwb$H zdzKFoBw21y-oh#cBGl*(6d3X`BU4q1oAPK6U9hL|6# zy;pJ?7+0Rl@$v_Mw~*ti$cuG^^W1rQ;#_|7ff2VMZpNIqF{G8^+C3&TSM_y9?&8eN zP6ZPk;9!u`g*-!_MjARv5Sl-3%(1*qjuK><~%k=-Ct7GIAlDg z>^$1-J_;Lx8x92$nj;lpujQj!!;uG2Sk?Si`Qv`@{UF53&L%PsTXY9Ik{M zsC2S-IdyDg*AywXn$c8F$TDblhAFZlm7SuCv)sC>fXaOm&M?Q2f&`;xtnl;>Yyo)bs9-#Iy$&#~s_> z2E&%7!tsC17&-~zPPP^(C+D(cFD1-xc(lgU3kqRd3tkt?7c&r!zPL=UUWtv;d3O+L zqpFxVT=niqj!jOxx0MbVr8AV@Jb#z z1OY7<$D*A#5_phMp{_wsp(UMM*IDSCGr5^A1i^B9>no7+Rwkp=c&o$B#Oze?l_Svv z8gG&pmrJaR{y|2aj_qdDb=`}&!XQOc-^UJc@u@ch z#?7~-p51|NZ;0vUTQ!rCUu*GlEKc%9HE{R5#-*$Hvb7dKUKc8;l67FHymNG3x@lqI zYKYxS0a%5B>HgUF;bW1y2QL)(O#1O((w*h>X#e0`j|Fa^q5sktO)lq{yyci_6e~x5N+>(JY_uSvPqr~&e6bO>Ee`uew>)SNGeZTttOk>NtqTGAT2N0$_I9X8e?K0C;4LD}lbKyDE;=xPaY#jR)Qn5D&F+KSHD++*es1bstf)pfJU z0g}DDuKN3>QF$CTIAj6gEP9e!tIuOe&V67jUn@77c4i4JOhSsY)iE~V8H6wEcvFfk zWY~=c6J8GDQF0T1(sg7(rzz^tBhu67mxQ()m8-55aq74(kmoFNqm3d`9Y3i4y}YgsOLI?oH>Yv}O(wZk9{cZm4`Egzvz5YFGz3FTWtIrQqr2 zc1^p?7+C+|zPqMff(RHBu_U(ChGy^wT0Y$L1bse}dXv9}{ijz) zn;dL=m=~6K&^=#~;=(h^I03xF3jnhasRASA%+vF{ycq6e{9e5WAN-=K&hd+agCzoV z-6`3vcSgsivkh?1zNAT7h6Fi79y(dq&<~EEg!NTnY#x5UT!I#S>PPueqt1d(R{>%l zj?XBpZ>iqOcAY(YUA&noh>$^MJJuoztKKNzcp_*;huChdZ&Gg~V?yO*hlL4mL}B1S z6>r|8_YSo%&otLW5G@h*LgfM9r^O7OF_wK(q zhGc9=?Z_r_QOJe40k23n&lv8snJ#i2=Xo9N7D*KmkkK-yW)0tSY{r<35!*GFf*!?q z+0HjwYgsgfY-%HkAU2G@5k9W7g9G-vm<Fusr<%6#vlg{&Y3N;*tRyknalvnKt{8sj7Z9KT5!t z?QTPdm>_cM!4^z5nKVz7qB`r85;F-CJbXxMpD474x2IrH#pqfmi;;M^UaMyIz3iJz zeKzZde(GqcYLa!R^R!-cS73WT*zw>CB4ZNv(9-!BHl!K#;Zen{mh!D`+A+R<#%>oO zMhzAQ874Mll~S(E+olw^OXo@W*})UBULZEQaDO7k10?y(;LurZXQ4+kEVGJr-tr@E zYqTsFYuL!*0qSmb&)KDVQH`tCIfWro{{@PpNOC zvYPb8m-9oB08XEaqulBshLD%tI}82HNY{khcVSr2^Ma<;Pr_lL&x_s2nPbrlb90ad z=Vad}jD9910Nd{#60ZO)V_TkE_GbVj4xaX*ZW=!(_{mQSy$bboAG0uCiU~ z3(+RM?ef;2zeQrq&UTt$R13Gx19k5}v!|shZ z5-;`*IHUABG4oAh{W7KPMwF*AS8nl*eg5ttXZcm$fw_l|_U4qbl&gmTAM3%eww|-S zwvYC!H6yyD-bwYGb+6Q^S$fCk?2#Zp{|i2Cc^QMLa5R^Tt8t+Jw=R5=huCfXa&-FQ z25iiq@;opbnFh|SB16J8R}g7*%@s7Q^5cy@0vTMLkf}(xn@C}%2TB-?nFk=)gLXZ?Id=iXXtPKTYWIG(buhu!6li00Li{zR=%z3Y8 z3uGX@OoH{5*Vd*E2QTc;zjYXtVgN=$!eFA7XB{>{ee^&@HHkn>@WRDdWRW*8x zo-2e>zpC1`e~L0nW3ylYuPck|ozZ$K-6Aq{GUXB8ECKPe>JzU*?(==tuSx3(Xe!;B zRkd^q{xlYaD)I+e?=9SIdfasa!b97*8u`V=7ASg?aH4GBz*+olF>?!z5AbrgRDrB! z!Y(fj6F&T9#whEGBAC-`n7u0$A$femvWlbYfi}<%S&{pMx30T)I|*pEU0kS)ZtUrn z@874PBJ^r$1aC4xAPcKE7 zv=_cyR=P)u=hWY|x4IEOH(`lI+k%Td>eRWipxdF;P-m(s7Pd0vW=J%rC|sI6`32C1 zCs~9g5DfUpV|3}Bk)av9O@XC1!N$@{M>B#%AAQQdRqI|@uJs+4Tk+~|6!kdK5Dw%# zC(m!5wwhGg^%W15p&EJrm^z%++XEAH@2=KV4%&vEANr_tBW`FUQ3O_lsO8$D*r`k= zhK2Lf(^wRE;F0;|lPc`?d9q2*S`QN>`tHX*I(RCJG#-=m8HM8|Jd^(AWLs>Kb-7ql zo+3tl)aGFs*~@wA=R=&wVLDN4@V} ziEuIxSj_S5s4aFbFWcXJ^~VB{ioutc;*t~=m*Q=DEMho9t{>`RYY?UGAunS>vQo2& z2ehnDSSYE82Ma?rO^DI*UAn5aQtzi$G;d8*Y<`}WI-m~-4=Ylp1?p7Zpy!A=aUm9x z;~R&^&+!-@y(_tiPfHy9kayTv0><4VXOKDDxKFZZ0-&M}1T)*;1V3AeOAmc(kF{23 zq_N9TKEZcU@(ms0gZk6&r;;cfn(Y$JSyP2Q{SpmsLq%nSG=Vh@Bm^jJ20uU&m&ELa zrjKAxFysxKIYpD)5!tO&tYn8>ASgZk;xlMqtfRM-_HluTDGk$kBXmLad_g$5avLx2 zLHJQc2AfBRpapWI{V*C6{yIS^2V#q)EEa^6U3%A9Po;p*)JqN1+%>`tyM4Qp4lw7` zd8h7&$G%STEtdeiERWbR$nQ$A?!FAu;auADE115{=*Df&B_ zOu%-B*Lo-ePZ9VrCAiAn<-86%;{BSc{V!`KzPi}bn7)EX1p2Sn-o}+krHrX>?9yyR zD?~LK+A z*wgV1gjd{Zeb-V~k*bUx8&ZP#Q7k=L$^kYa!J|tu%GCGain3=y)D>gjetX)Tc*xZE zW6!lyPFE(om0IQwpR6gzn-+oW(|PJ(^u)5%Z{gSD$<%k@*?C^gkP%SrJjP1$L;$!L zqJ*k4+N)R6q8feP^WktP&dSqZi~l$%x-bFjkbTsCsHWm|3fxBRf^1Ad#U>SuWD>B2 zuMs1-$CJWuB0uD(+oo^UEt|O7xTwyXC%r{zqyA~mcnn9%@YGeJOOIV#Di}evGO0lR zVRq)mvfM@_0NkMV$+~yBX%b22U3KlGxoX=fsChMywpdOlI->^0!e5^r`620z2kd3)DAn97hbQ#G0L^&>GhUOl{U-nNY-avEv~oDbS6&zu8epOcZrD~I>*%U zInj@#yeQCn82)PHUU{Gdi@C_9`~FUvbKa+*-Jb+ZvQbbHjQ8&!}l zGJVC;QFPQ&RmH776O{8%zVfkkWXB5`Q)$h5HoTa&aDkMYgaxi?4ilGnN8|$!$@o;_2=tM0&2#CZsyezFarE6`N1VDG@{4Ld z_W4vQ_Gi@*)11sjrHeaU(CW-IZk3RKqcKoJtj#4UC|wzK8VB!`3^i^)iNdAG7s7|4GBUA4GJGAH#)3&z=G3{)ux? zBOl}<<7*uI>0Tm5_3P_Y4>lQnlDheDcg%o4{|TVZv0zqr~P*{EWz*|(PlK4U0P{tXePL>X{I5fVY4Ke*)f0evVxNg?M?{Fs?% z=S)ea;3M)ET>Mx7&N?7z_h0Ey7~?2XFv13JvcT zNgoX2$O1BkM5|H284I2=%3YEPAm`-jejh`1v(W(QOxv1@tf)fn4J=zm}bK7qmz z0D#v`vFQH+xKR;tKsK9Wf+lu`?!3~n>iKza65`*BO70eIzQbbpv*-&VylmfbJ-JO- zgvoRdWah*z>@kDgzgPjlNj>ss?)_znfk%J9QXZ{Z>(-iBLex{>u94hEt}{go{)a_> zA`f^w)&j*#q)!U}fP@f2(Fd*IJZt$Xz6ws}N}{tsS% zXeSlWUK3kv7uVDH8at*kStURF_li4AScdsf{t-ergh$k$t##f7l|KnJ^$5Rc7D#Mt zuQ+n9D3CCi@(ubou>nN{uy25nFZ&;MYn&Kr=a-5#HNvh8N&Sm8fD#n}++*r=yUahE zLHJRIfHA~Td>hkCD$o$_F01T#9?q`V3AN)Am;`zLjeATQ*ga+N zlXxiVALJiASC}0;P;Z+UT}sX4j>MV(2G?8Hy@9vC{|lWF@xZ#s>F1f>{`V#50C6A~ zP5-S=V2vZIcKp={Q6K!O)}8;jfyFTSvxn_pdne(*%M7ccf;axiZ*(mP$ZCvajO5&F z2%|DrFx@VPk(;ret0TGn&1K4fVq`UXh5F}lG_j3Aizey0xtylD;n;y{CSU06dzNLm z501%H#s6jMexB73U{ZXbwEqXtdFZBQiCup`2GHH@R6)l<@zJF<=bvHKGR5P0I{Fs^y zt8Lwg&3DK0de5+$QlNnR+oJ#61q9q;55+w9p|2!zWM&Ta`D?! zv=@2V7IJkg%qN9U-k#?f+E1l!_@;9k=*5P7ljw_|^KYk?sj6JhUy?qeV_cH-v?2hUwM3XNWOp=`G5 z6|Q!TOgUre%Z+Z;mp@cEDz{WdmgKH$$iI(IUb>y!Ohos{?B72uXiLhl>mR4Z&Kr5P zn`2a9 zW_`tf>n&1wcn&r^hO8_(t4?J*N_w$W<&<*8hMbwR4H^1Jc#ckgCYxjHb zqL_2iwpgFD;eTly`zJtR+CB!QOKWzLMD{YBqWMv9%UU1eL3^a-n&Lt7DEBB~Rnn+$ zL3?`B3^U&V-hldbjPC+lsEDqOVJ{aJ?nZ-u8fO|Av?_Zc}x;u~qgn(CxD z?AQ5XQ#QdLav@=V3j@LdZR5h;`A`~=kod{F+!CNoeP{vN0g?dlDi?y!UzBP>LT|PS z}hptF37>tx6%QNc7X$l8elf)x6Soq45E|S33BEni?W&K59;}*^9tu2R! zO&0;K6py@w+(*#tfs^5ja;a8z@zCr%I#s-B_04K6D?af{cCp^g)%P~v92#~$sT11M z2YEkMo@4_?0cm8`BmV1dApIbx_xWm;N+LexCdcDq*IPG z2|A~cC!H(xcF<-Uk5|tLNbc=U`&Xa{Jj1&X@UWIQzohH_dSHYGXw$x^UNRsQZa50m zSUsKk`m8;p&_*7`JX7jFV#W`+NFDddM1LC+KpvprAZ`~yw9t1i=Aa#ZJvuB?gT=#( z#slnst!#7y!jpp=%t6qvucgQojDkE~OPXgWAxM$VISzK|*buMnoJpeO{NFtRBvFJ$ z<9zsyUSQaH<%M7?LFy6;7s3zWM&836pq$0knOa`<_%EfprwzE~o+SEO{=W>KB!UmA zL2NAp8&pVnr7s6Rlrr5TuBhS02Poo5LL$`HGalENtD}&4zX(L+&rc z+=DcsFsrK1ThikHlIa5+Q`6`Sy|c~;e%juXLGxY269xpEX?=^dj)r%$8U%k_#5>O| zA{nq7to&>2zgNFP9g4%x#J9j7){=PpgE7WCjEZNmOPfu1Tc1f2Q|0f_g;YTSkPgJ< zblYD?`XS$lxZ>Cr8!>Cg^a+=*bo9f{4@klZNu;Qo8O2{lS0Mv%eSRD@4qER>IRFLms06q3+%I zo*Rx>MN6{6A4m8X?SXe$L2*!G&3_9T5~Qdt9*cP*jpz}Wr>vNZePsif6WNUtHZ&vu z3sUb!2LRNB(mCqiWQ$G#VIt(&u!;&hG1YmC#Y_6J2|F2P_r8L#s<0<{|DL6Ps=pG2q94@ zuhlR7C4t~aCI(Se*jvc}qM39}xB1xsQ_D7trlL51GG{-ZfawMhwOB|5;TNZXSbx@_ z(j*AOuox7{_R753+=3lQ257>)2FZh1=RZJxBlPzH3?!g?WdA#VEwYM=D)dW~4-Eo@ z48=5}1EV?5ZPh@3a#1uV>^Cm|0r)W~5U#@^1z`RXCkY?#(iO)zUr<2t79!LkHiX{Y zCL`C-W8CoGUyve`?(qXB?j@i9pYTQp0c;z@9rKXr5=Rz<5>6doPJ+K?ei=(=q*aj8 zp^Wtxg+9LkR(J5~iTqN(ARR;{80qz6F=)&2UWAKI&(@blAtTs@kco^*Mi+;v;9rZq z8x;Y@AVU0@`CA77a{zb47<6V~f)`&cAs`mSsh+-SFZ`z{x2-_EC^woz8Sn2Wfb0RE zfZ}uv>vzVi80+b??iD(EIxq9QIuJ@k&KQCi=`vm4cGDgSn{{tPOhQ84av-SYKT3y+ zx-p0#+`*9PHw$q?8@I*>2P4^Tzr*Gp18ur=V#!300@_h&_6*jVya?9_E?_M34{?f! z1OFppdqB=ApdBeH;}_Q{XaOxi;BF2)t<{?rtxNM()|#??g_=-!tv!KE>46CpRmvoksSB6uxQW>_yN(F^}{AH6orOjh| zu&JWUfxdze@k0fQ|Cxw?xT{Fs8x6M>^S6K`t-&83GsrS-s}bN)DsIuGE3DuOAk)b} zz1gS?q1q;Smo|V`D~gVcJ&Fwf9{@kr0Xk%igbed*+yQ9rQ{93A2N-i zNKM?T4L0o~(`d4$ybTDWIPsGiorw!t?+P*zs`w`{^!q3VC4hue(YJg4mH-7BNFdCw zm8pc*Ap|!@XcFH!#Q2yuLm^Vp`XMmLl*=J)UBPo$cVoNSeP<;frczM+E%tEo0N&oY z8kph!!lxjL3fHqyrTLtm{(w#%s-jiXmwQHeUlsoU(#=pYkxf)=^6`oSgXV8ZfoKw1@La8ig z7+Cm@2uvyNDACodRk*}>T{EcV?2qf*px?i){$E`M+=T;JzS|J|MA|u zK`#JIwj2~;;{4`J90k&>m|}yM3XxjLX7yjSS0iLtE=;0wdw3A@MjKM%*GI{AFwCsN zE-lw~2G729UpEV%0!16wYl{~Qul{3+@Bp+f+ozdP|9&=+ZqiM3TkOQd6I$#SPLLQ9 zZZ>@f;F2SW$a78@Q*Vn@B3ps5l}&lF+3=KBezILY1Vx(-m{8;8rPKafc_WklM=9Nd zr+lKJp*$TOtDh|rh-QEJm`?GH=%6Uzt;@pVU5Emg>#({(ELHKhovl+Rm7AYyLpOES@t znx%YQ!6%PS)M#FpSkVv*iu}i@{72#c-(QQLoZY&J4+ywQeD%Bs{F4-w6DfFQ;Pd|g DaT5db literal 0 HcmV?d00001 diff --git a/lib/Font-Awesome/src/assets/img/logo-themeisle.png b/lib/Font-Awesome/src/assets/img/logo-themeisle.png new file mode 100644 index 0000000000000000000000000000000000000000..6fa5fb0c3e7e7e6c0ed8d5eb60c833f5e631317a GIT binary patch literal 5547 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 literal 0 HcmV?d00001 diff --git a/lib/Font-Awesome/src/assets/img/logo-wpbeginner.png b/lib/Font-Awesome/src/assets/img/logo-wpbeginner.png new file mode 100644 index 0000000000000000000000000000000000000000..7a2523f86a31de5fd14a6335018f6ed9b43261b7 GIT binary patch literal 7461 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 0) { + new SearchView({ el: $searchViewElement }); + } +}); diff --git a/lib/Font-Awesome/src/assets/js/site.js b/lib/Font-Awesome/src/assets/js/site.js index adacbdf98..75a7c7158 100644 --- a/lib/Font-Awesome/src/assets/js/site.js +++ b/lib/Font-Awesome/src/assets/js/site.js @@ -1,67 +1,56 @@ -$(function() { +$(function () { + $("#newsletter").validate(); + var ads = [ { quote: "Take your icon game to the next level. Check out Fonticons, from the maker of Font Awesome.", class: "fonticons", - url: "https://fonticons.com/?utm_source=font_awesome_homepage&utm_medium=display&utm_content=ad_1_next_level&utm_campaign=promo_4.3_update", - btn_text: "Gimme Some!" - }, - { - quote: "Subset your icons, add your own, and serve up from a CDN. Check out Fonticons, from the maker of Font Awesome.", - class: "fonticons", - url: "https://fonticons.com/?utm_source=font_awesome_homepage&utm_medium=display&utm_content=ad_2_all_value_add&utm_campaign=promo_4.3_update", + url: "https://fonticons.com/?utm_source=font_awesome_homepage&utm_medium=display&utm_content=ad_1_next_level&utm_campaign=promo_4.4_update", btn_text: "Gimme Some!" }, { quote: "Make your icons load 10x faster! Check out Fonticons, from the maker of Font Awesome.", class: "fonticons", - url: "https://fonticons.com/?utm_source=font_awesome_homepage&utm_medium=display&utm_content=ad_3_faster_loading&utm_campaign=promo_4.3_update", + url: "https://fonticons.com/?utm_source=font_awesome_homepage&utm_medium=display&utm_content=ad_3_faster_loading&utm_campaign=promo_4.4_update", btn_text: "Gimme Some!" }, { quote: "Looking for other great icon sets? Check out Fonticons, from the maker of Font Awesome.", class: "fonticons", - url: "https://fonticons.com/?utm_source=font_awesome_homepage&utm_medium=display&utm_content=ad_4_more_icons&utm_campaign=promo_4.3_update", + url: "https://fonticons.com/?utm_source=font_awesome_homepage&utm_medium=display&utm_content=ad_4_more_icons&utm_campaign=promo_4.4_update", btn_text: "Gimme Some!" }, { - quote: "Need a custom icon in Font Awesome? Check out Fonticons, from the maker of Font Awesome.", + quote: "Want to add your own icon? Check out Fonticons, from the maker of Font Awesome.", class: "fonticons", - url: "https://fonticons.com/?utm_source=font_awesome_homepage&utm_medium=display&utm_content=ad_5_custom_icons&utm_campaign=promo_4.3_update", + url: "https://fonticons.com/?utm_source=font_awesome_homepage&utm_medium=display&utm_content=ad_6_your_own_icon&utm_campaign=promo_4.4_update", btn_text: "Gimme Some!" }, - - { - quote: "So hot right now: Black Tie, the new multi-weight icon font from the maker of Font Awesome.", - class: "black-tie", - url: "http://blacktie.io/?utm_source=font_awesome_homepage&utm_medium=display&utm_content=ad_1_so_hot&utm_campaign=promo_4.3_update", - btn_text: "Buy it Now!" - }, { quote: "Black Tie, from the creator of Font Awesome. On sale at the Kickstarter price for a limited time.", class: "black-tie", - url: "http://blacktie.io/?utm_source=font_awesome_homepage&utm_medium=display&utm_content=ad_2_kickstarter&utm_campaign=promo_4.3_update", - btn_text: "Buy it Now!" - }, - { - quote: "Get more Awesome: Black Tie, the new multi-weight icon font from the maker of Font Awesome.", - class: "black-tie", - url: "http://blacktie.io/?utm_source=font_awesome_homepage&utm_medium=display&utm_content=ad_3_more_awesome&utm_campaign=promo_4.3_update", - btn_text: "Buy it Now!" - }, - { - quote: "The new hotness from the maker of Font Awesome: Black Tie, the multi-weight icon font.", - class: "black-tie", - url: "http://blacktie.io/?utm_source=font_awesome_homepage&utm_medium=display&utm_content=ad_4_new_hotness&utm_campaign=promo_4.3_update", - btn_text: "Buy it Now!" + url: "http://blacktie.io/?utm_source=font_awesome_homepage&utm_medium=display&utm_content=ad_2_kickstarter&utm_campaign=promo_4.4_update", + btn_text: "Check it Out!" }, { quote: "Want clean, minimalist icons? Check out Black Tie, the new multi-weight icon font from the maker of Font Awesome.", class: "black-tie", - url: "http://blacktie.io/?utm_source=font_awesome_homepage&utm_medium=display&utm_content=ad_5_clean_minimalist&utm_campaign=promo_4.3_update", - btn_text: "Buy it Now!" + url: "http://blacktie.io/?utm_source=font_awesome_homepage&utm_medium=display&utm_content=ad_5_clean_minimalist&utm_campaign=promo_4.4_update", + btn_text: "Check it Out!" + }, + { + quote: "Want a different icon look? Check out Black Tie, our new multi-weight icon set.", + class: "black-tie", + url: "http://blacktie.io/?utm_source=font_awesome_homepage&utm_medium=display&utm_content=ad_6_different_look&utm_campaign=promo_4.4_update", + btn_text: "Check it Out!" + }, + { + quote: "Check out Black Tie, our new multi-weight icon set!", + class: "black-tie", + url: "http://blacktie.io/?utm_source=font_awesome_homepage&utm_medium=display&utm_content=ad_7_our_new_multi_weight&utm_campaign=promo_4.4_update", + btn_text: "Check it Out!" } ]; @@ -72,86 +61,10 @@ $(function() { interval: 5000 }); - var $filter_by = $('#filter-by'); - - // Filter icons - if($filter_by.length) { - var $filter_val = $('#filter-val'); - var $filter = $('#filter'); - var $other = $('#new, #web-application, #transportation, #gender, #form-control, #medical, #currency, #text-editor, #directional, #video-player, #brand, #file-type, #spinner, #payment, #chart'); - var $clear = $('#filter-clear'); - var $no_results = $('#no-search-results'); - - var $icons = $('.filter-icon', $filter); - - // Add tab completion - $filter_by.tabcomplete(filterSet, { - arrowKeys: true - }); - - $clear.on('click', function(e) { - e.preventDefault(); - $filter_by - .val('') - .trigger('input') - .trigger('keyup') - .focus(); - - $clear.addClass('hide'); // Hide clear button - }); - - - $filter_by.on('keyup', function() { - var $this = $(this); - var val = $this.val().toLowerCase(); - $filter.toggle(!!val); - $other.toggle(!val); - $clear.toggleClass('hide', !val); - $filter_val.text(val); - - if(!val) return; - - var resultsCount = 0; - $icons.each(function() { - var filter = $(this).attr('data-filter').split('|'); - var show = inFilter(val, filter); - if (!show) { - if (val.slice(-1) === 's') { - // Try to be smart. Make plural terms singular. - show = inFilter(val.slice(0, -1), filter); - } - } - if (show) resultsCount++; - $(this).toggle(!!show); - }); - - if( resultsCount == 0 && val.length != 0 ) { - $no_results.find('span').text(val); - $no_results.show(); - } else { - $no_results.hide(); - } - }); - } - - function inFilter(val, filter) { - for (var i = 0; i < filter.length; i++) { - if (filter[i].match(val)) return true; - } - return false; - } - - $filter_by - .val('') - .trigger('input') - .trigger('keyup'); - - if ($clear) { - $clear.addClass('hide'); // Hide clear button - } + $('[data-toggle="popover"]').popover(); function selectFonticonsAd() { - random_number = Math.floor( Math.random() * ads.length ); + random_number = Math.floor(Math.random() * ads.length); random_ad = ads[random_number]; $('#banner').addClass(random_ad.class); diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/.csscomb.json b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/.csscomb.json new file mode 100644 index 000000000..40695a478 --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/.csscomb.json @@ -0,0 +1,304 @@ +{ + "always-semicolon": true, + "block-indent": 2, + "color-case": "lower", + "color-shorthand": true, + "element-case": "lower", + "eof-newline": true, + "leading-zero": false, + "remove-empty-rulesets": true, + "space-after-colon": 1, + "space-after-combinator": 1, + "space-before-selector-delimiter": 0, + "space-between-declarations": "\n", + "space-after-opening-brace": "\n", + "space-before-closing-brace": "\n", + "space-before-colon": 0, + "space-before-combinator": 1, + "space-before-opening-brace": 1, + "strip-spaces": true, + "unitless-zero": true, + "vendor-prefix-align": true, + "sort-order": [ + [ + "position", + "top", + "right", + "bottom", + "left", + "z-index", + "display", + "float", + "width", + "min-width", + "max-width", + "height", + "min-height", + "max-height", + "-webkit-box-sizing", + "-moz-box-sizing", + "box-sizing", + "-webkit-appearance", + "padding", + "padding-top", + "padding-right", + "padding-bottom", + "padding-left", + "margin", + "margin-top", + "margin-right", + "margin-bottom", + "margin-left", + "overflow", + "overflow-x", + "overflow-y", + "-webkit-overflow-scrolling", + "-ms-overflow-x", + "-ms-overflow-y", + "-ms-overflow-style", + "clip", + "clear", + "font", + "font-family", + "font-size", + "font-style", + "font-weight", + "font-variant", + "font-size-adjust", + "font-stretch", + "font-effect", + "font-emphasize", + "font-emphasize-position", + "font-emphasize-style", + "font-smooth", + "-webkit-hyphens", + "-moz-hyphens", + "hyphens", + "line-height", + "color", + "text-align", + "-webkit-text-align-last", + "-moz-text-align-last", + "-ms-text-align-last", + "text-align-last", + "text-emphasis", + "text-emphasis-color", + "text-emphasis-style", + "text-emphasis-position", + "text-decoration", + "text-indent", + "text-justify", + "text-outline", + "-ms-text-overflow", + "text-overflow", + "text-overflow-ellipsis", + "text-overflow-mode", + "text-shadow", + "text-transform", + "text-wrap", + "-webkit-text-size-adjust", + "-ms-text-size-adjust", + "letter-spacing", + "-ms-word-break", + "word-break", + "word-spacing", + "-ms-word-wrap", + "word-wrap", + "-moz-tab-size", + "-o-tab-size", + "tab-size", + "white-space", + "vertical-align", + "list-style", + "list-style-position", + "list-style-type", + "list-style-image", + "pointer-events", + "-ms-touch-action", + "touch-action", + "cursor", + "visibility", + "zoom", + "flex-direction", + "flex-order", + "flex-pack", + "flex-align", + "table-layout", + "empty-cells", + "caption-side", + "border-spacing", + "border-collapse", + "content", + "quotes", + "counter-reset", + "counter-increment", + "resize", + "-webkit-user-select", + "-moz-user-select", + "-ms-user-select", + "-o-user-select", + "user-select", + "nav-index", + "nav-up", + "nav-right", + "nav-down", + "nav-left", + "background", + "background-color", + "background-image", + "-ms-filter:\\'progid:DXImageTransform.Microsoft.gradient", + "filter:progid:DXImageTransform.Microsoft.gradient", + "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader", + "filter", + "background-repeat", + "background-attachment", + "background-position", + "background-position-x", + "background-position-y", + "-webkit-background-clip", + "-moz-background-clip", + "background-clip", + "background-origin", + "-webkit-background-size", + "-moz-background-size", + "-o-background-size", + "background-size", + "border", + "border-color", + "border-style", + "border-width", + "border-top", + "border-top-color", + "border-top-style", + "border-top-width", + "border-right", + "border-right-color", + "border-right-style", + "border-right-width", + "border-bottom", + "border-bottom-color", + "border-bottom-style", + "border-bottom-width", + "border-left", + "border-left-color", + "border-left-style", + "border-left-width", + "border-radius", + "border-top-left-radius", + "border-top-right-radius", + "border-bottom-right-radius", + "border-bottom-left-radius", + "-webkit-border-image", + "-moz-border-image", + "-o-border-image", + "border-image", + "-webkit-border-image-source", + "-moz-border-image-source", + "-o-border-image-source", + "border-image-source", + "-webkit-border-image-slice", + "-moz-border-image-slice", + "-o-border-image-slice", + "border-image-slice", + "-webkit-border-image-width", + "-moz-border-image-width", + "-o-border-image-width", + "border-image-width", + "-webkit-border-image-outset", + "-moz-border-image-outset", + "-o-border-image-outset", + "border-image-outset", + "-webkit-border-image-repeat", + "-moz-border-image-repeat", + "-o-border-image-repeat", + "border-image-repeat", + "outline", + "outline-width", + "outline-style", + "outline-color", + "outline-offset", + "-webkit-box-shadow", + "-moz-box-shadow", + "box-shadow", + "filter:progid:DXImageTransform.Microsoft.Alpha(Opacity", + "-ms-filter:\\'progid:DXImageTransform.Microsoft.Alpha", + "opacity", + "-ms-interpolation-mode", + "-webkit-transition", + "-moz-transition", + "-ms-transition", + "-o-transition", + "transition", + "-webkit-transition-delay", + "-moz-transition-delay", + "-ms-transition-delay", + "-o-transition-delay", + "transition-delay", + "-webkit-transition-timing-function", + "-moz-transition-timing-function", + "-ms-transition-timing-function", + "-o-transition-timing-function", + "transition-timing-function", + "-webkit-transition-duration", + "-moz-transition-duration", + "-ms-transition-duration", + "-o-transition-duration", + "transition-duration", + "-webkit-transition-property", + "-moz-transition-property", + "-ms-transition-property", + "-o-transition-property", + "transition-property", + "-webkit-transform", + "-moz-transform", + "-ms-transform", + "-o-transform", + "transform", + "-webkit-transform-origin", + "-moz-transform-origin", + "-ms-transform-origin", + "-o-transform-origin", + "transform-origin", + "-webkit-animation", + "-moz-animation", + "-ms-animation", + "-o-animation", + "animation", + "-webkit-animation-name", + "-moz-animation-name", + "-ms-animation-name", + "-o-animation-name", + "animation-name", + "-webkit-animation-duration", + "-moz-animation-duration", + "-ms-animation-duration", + "-o-animation-duration", + "animation-duration", + "-webkit-animation-play-state", + "-moz-animation-play-state", + "-ms-animation-play-state", + "-o-animation-play-state", + "animation-play-state", + "-webkit-animation-timing-function", + "-moz-animation-timing-function", + "-ms-animation-timing-function", + "-o-animation-timing-function", + "animation-timing-function", + "-webkit-animation-delay", + "-moz-animation-delay", + "-ms-animation-delay", + "-o-animation-delay", + "animation-delay", + "-webkit-animation-iteration-count", + "-moz-animation-iteration-count", + "-ms-animation-iteration-count", + "-o-animation-iteration-count", + "animation-iteration-count", + "-webkit-animation-direction", + "-moz-animation-direction", + "-ms-animation-direction", + "-o-animation-direction", + "animation-direction" + ] + ] +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/.csslintrc b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/.csslintrc new file mode 100644 index 000000000..005b86236 --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/.csslintrc @@ -0,0 +1,19 @@ +{ + "adjoining-classes": false, + "box-sizing": false, + "box-model": false, + "compatible-vendor-prefixes": false, + "floats": false, + "font-sizes": false, + "gradients": false, + "important": false, + "known-properties": false, + "outline-none": false, + "qualified-headings": false, + "regex-selectors": false, + "shorthand": false, + "text-indent": false, + "unique-headings": false, + "universal-selector": false, + "unqualified-attributes": false +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/alerts.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/alerts.less new file mode 100644 index 000000000..c4199db92 --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/alerts.less @@ -0,0 +1,73 @@ +// +// Alerts +// -------------------------------------------------- + + +// Base styles +// ------------------------- + +.alert { + padding: @alert-padding; + margin-bottom: @line-height-computed; + border: 1px solid transparent; + border-radius: @alert-border-radius; + + // Headings for larger alerts + h4 { + margin-top: 0; + // Specified for the h4 to prevent conflicts of changing @headings-color + color: inherit; + } + + // Provide class for links that match alerts + .alert-link { + font-weight: @alert-link-font-weight; + } + + // Improve alignment and spacing of inner content + > p, + > ul { + margin-bottom: 0; + } + + > p + p { + margin-top: 5px; + } +} + +// Dismissible alerts +// +// Expand the right padding and account for the close button's positioning. + +.alert-dismissable, // The misspelled .alert-dismissable was deprecated in 3.2.0. +.alert-dismissible { + padding-right: (@alert-padding + 20); + + // Adjust close link position + .close { + position: relative; + top: -2px; + right: -21px; + color: inherit; + } +} + +// Alternate styles +// +// Generate contextual modifier classes for colorizing the alert. + +.alert-success { + .alert-variant(@alert-success-bg; @alert-success-border; @alert-success-text); +} + +.alert-info { + .alert-variant(@alert-info-bg; @alert-info-border; @alert-info-text); +} + +.alert-warning { + .alert-variant(@alert-warning-bg; @alert-warning-border; @alert-warning-text); +} + +.alert-danger { + .alert-variant(@alert-danger-bg; @alert-danger-border; @alert-danger-text); +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/badges.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/badges.less new file mode 100644 index 000000000..6ee16dca4 --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/badges.less @@ -0,0 +1,66 @@ +// +// Badges +// -------------------------------------------------- + + +// Base class +.badge { + display: inline-block; + min-width: 10px; + padding: 3px 7px; + font-size: @font-size-small; + font-weight: @badge-font-weight; + color: @badge-color; + line-height: @badge-line-height; + vertical-align: middle; + white-space: nowrap; + text-align: center; + background-color: @badge-bg; + border-radius: @badge-border-radius; + + // Empty badges collapse automatically (not available in IE8) + &:empty { + display: none; + } + + // Quick fix for badges in buttons + .btn & { + position: relative; + top: -1px; + } + + .btn-xs &, + .btn-group-xs > .btn & { + top: 0; + padding: 1px 5px; + } + + // Hover state, but only for links + a& { + &:hover, + &:focus { + color: @badge-link-hover-color; + text-decoration: none; + cursor: pointer; + } + } + + // Account for badges in navs + .list-group-item.active > &, + .nav-pills > .active > a > & { + color: @badge-active-color; + background-color: @badge-active-bg; + } + + .list-group-item > & { + float: right; + } + + .list-group-item > & + & { + margin-right: 5px; + } + + .nav-pills > li > a > & { + margin-left: 3px; + } +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/bootstrap.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/bootstrap.less new file mode 100644 index 000000000..4b9916e6c --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/bootstrap.less @@ -0,0 +1,56 @@ +/*! + * Bootstrap v3.3.5 (http://getbootstrap.com) + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ + +// Core variables and mixins +@import "variables.less"; +@import "mixins.less"; + +// Reset and dependencies +@import "normalize.less"; +@import "print.less"; +@import "glyphicons.less"; + +// Core CSS +@import "scaffolding.less"; +@import "type.less"; +@import "code.less"; +@import "grid.less"; +@import "tables.less"; +@import "forms.less"; +@import "buttons.less"; + +// Components +@import "component-animations.less"; +@import "dropdowns.less"; +@import "button-groups.less"; +@import "input-groups.less"; +@import "navs.less"; +@import "navbar.less"; +@import "breadcrumbs.less"; +@import "pagination.less"; +@import "pager.less"; +@import "labels.less"; +@import "badges.less"; +@import "jumbotron.less"; +@import "thumbnails.less"; +@import "alerts.less"; +@import "progress-bars.less"; +@import "media.less"; +@import "list-group.less"; +@import "panels.less"; +@import "responsive-embed.less"; +@import "wells.less"; +@import "close.less"; + +// Components w/ JavaScript +@import "modals.less"; +@import "tooltip.less"; +@import "popovers.less"; +@import "carousel.less"; + +// Utility classes +@import "utilities.less"; +@import "responsive-utilities.less"; diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/breadcrumbs.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/breadcrumbs.less new file mode 100644 index 000000000..cb01d503f --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/breadcrumbs.less @@ -0,0 +1,26 @@ +// +// Breadcrumbs +// -------------------------------------------------- + + +.breadcrumb { + padding: @breadcrumb-padding-vertical @breadcrumb-padding-horizontal; + margin-bottom: @line-height-computed; + list-style: none; + background-color: @breadcrumb-bg; + border-radius: @border-radius-base; + + > li { + display: inline-block; + + + li:before { + content: "@{breadcrumb-separator}\00a0"; // Unicode space added since inline-block means non-collapsing white-space + padding: 0 5px; + color: @breadcrumb-color; + } + } + + > .active { + color: @breadcrumb-active-color; + } +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/button-groups.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/button-groups.less new file mode 100644 index 000000000..6a0c5a865 --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/button-groups.less @@ -0,0 +1,244 @@ +// +// Button groups +// -------------------------------------------------- + +// Make the div behave like a button +.btn-group, +.btn-group-vertical { + position: relative; + display: inline-block; + vertical-align: middle; // match .btn alignment given font-size hack above + > .btn { + position: relative; + float: left; + // Bring the "active" button to the front + &:hover, + &:focus, + &:active, + &.active { + z-index: 2; + } + } +} + +// Prevent double borders when buttons are next to each other +.btn-group { + .btn + .btn, + .btn + .btn-group, + .btn-group + .btn, + .btn-group + .btn-group { + margin-left: -1px; + } +} + +// Optional: Group multiple button groups together for a toolbar +.btn-toolbar { + margin-left: -5px; // Offset the first child's margin + &:extend(.clearfix all); + + .btn, + .btn-group, + .input-group { + float: left; + } + > .btn, + > .btn-group, + > .input-group { + margin-left: 5px; + } +} + +.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) { + border-radius: 0; +} + +// Set corners individual because sometimes a single button can be in a .btn-group and we need :first-child and :last-child to both match +.btn-group > .btn:first-child { + margin-left: 0; + &:not(:last-child):not(.dropdown-toggle) { + .border-right-radius(0); + } +} +// Need .dropdown-toggle since :last-child doesn't apply given a .dropdown-menu immediately after it +.btn-group > .btn:last-child:not(:first-child), +.btn-group > .dropdown-toggle:not(:first-child) { + .border-left-radius(0); +} + +// Custom edits for including btn-groups within btn-groups (useful for including dropdown buttons within a btn-group) +.btn-group > .btn-group { + float: left; +} +.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn { + border-radius: 0; +} +.btn-group > .btn-group:first-child:not(:last-child) { + > .btn:last-child, + > .dropdown-toggle { + .border-right-radius(0); + } +} +.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child { + .border-left-radius(0); +} + +// On active and open, don't show outline +.btn-group .dropdown-toggle:active, +.btn-group.open .dropdown-toggle { + outline: 0; +} + + +// Sizing +// +// Remix the default button sizing classes into new ones for easier manipulation. + +.btn-group-xs > .btn { &:extend(.btn-xs); } +.btn-group-sm > .btn { &:extend(.btn-sm); } +.btn-group-lg > .btn { &:extend(.btn-lg); } + + +// Split button dropdowns +// ---------------------- + +// Give the line between buttons some depth +.btn-group > .btn + .dropdown-toggle { + padding-left: 8px; + padding-right: 8px; +} +.btn-group > .btn-lg + .dropdown-toggle { + padding-left: 12px; + padding-right: 12px; +} + +// The clickable button for toggling the menu +// Remove the gradient and set the same inset shadow as the :active state +.btn-group.open .dropdown-toggle { + .box-shadow(inset 0 3px 5px rgba(0,0,0,.125)); + + // Show no shadow for `.btn-link` since it has no other button styles. + &.btn-link { + .box-shadow(none); + } +} + + +// Reposition the caret +.btn .caret { + margin-left: 0; +} +// Carets in other button sizes +.btn-lg .caret { + border-width: @caret-width-large @caret-width-large 0; + border-bottom-width: 0; +} +// Upside down carets for .dropup +.dropup .btn-lg .caret { + border-width: 0 @caret-width-large @caret-width-large; +} + + +// Vertical button groups +// ---------------------- + +.btn-group-vertical { + > .btn, + > .btn-group, + > .btn-group > .btn { + display: block; + float: none; + width: 100%; + max-width: 100%; + } + + // Clear floats so dropdown menus can be properly placed + > .btn-group { + &:extend(.clearfix all); + > .btn { + float: none; + } + } + + > .btn + .btn, + > .btn + .btn-group, + > .btn-group + .btn, + > .btn-group + .btn-group { + margin-top: -1px; + margin-left: 0; + } +} + +.btn-group-vertical > .btn { + &:not(:first-child):not(:last-child) { + border-radius: 0; + } + &:first-child:not(:last-child) { + border-top-right-radius: @btn-border-radius-base; + .border-bottom-radius(0); + } + &:last-child:not(:first-child) { + border-bottom-left-radius: @btn-border-radius-base; + .border-top-radius(0); + } +} +.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn { + border-radius: 0; +} +.btn-group-vertical > .btn-group:first-child:not(:last-child) { + > .btn:last-child, + > .dropdown-toggle { + .border-bottom-radius(0); + } +} +.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child { + .border-top-radius(0); +} + + +// Justified button groups +// ---------------------- + +.btn-group-justified { + display: table; + width: 100%; + table-layout: fixed; + border-collapse: separate; + > .btn, + > .btn-group { + float: none; + display: table-cell; + width: 1%; + } + > .btn-group .btn { + width: 100%; + } + + > .btn-group .dropdown-menu { + left: auto; + } +} + + +// Checkbox and radio options +// +// In order to support the browser's form validation feedback, powered by the +// `required` attribute, we have to "hide" the inputs via `clip`. We cannot use +// `display: none;` or `visibility: hidden;` as that also hides the popover. +// Simply visually hiding the inputs via `opacity` would leave them clickable in +// certain cases which is prevented by using `clip` and `pointer-events`. +// This way, we ensure a DOM element is visible to position the popover from. +// +// See https://github.com/twbs/bootstrap/pull/12794 and +// https://github.com/twbs/bootstrap/pull/14559 for more information. + +[data-toggle="buttons"] { + > .btn, + > .btn-group > .btn { + input[type="radio"], + input[type="checkbox"] { + position: absolute; + clip: rect(0,0,0,0); + pointer-events: none; + } + } +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/buttons.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/buttons.less new file mode 100644 index 000000000..9cbb8f416 --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/buttons.less @@ -0,0 +1,166 @@ +// +// Buttons +// -------------------------------------------------- + + +// Base styles +// -------------------------------------------------- + +.btn { + display: inline-block; + margin-bottom: 0; // For input.btn + font-weight: @btn-font-weight; + text-align: center; + vertical-align: middle; + touch-action: manipulation; + cursor: pointer; + background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214 + border: 1px solid transparent; + white-space: nowrap; + .button-size(@padding-base-vertical; @padding-base-horizontal; @font-size-base; @line-height-base; @btn-border-radius-base); + .user-select(none); + + &, + &:active, + &.active { + &:focus, + &.focus { + .tab-focus(); + } + } + + &:hover, + &:focus, + &.focus { + color: @btn-default-color; + text-decoration: none; + } + + &:active, + &.active { + outline: 0; + background-image: none; + .box-shadow(inset 0 3px 5px rgba(0,0,0,.125)); + } + + &.disabled, + &[disabled], + fieldset[disabled] & { + cursor: @cursor-disabled; + .opacity(.65); + .box-shadow(none); + } + + a& { + &.disabled, + fieldset[disabled] & { + pointer-events: none; // Future-proof disabling of clicks on `` elements + } + } +} + + +// Alternate buttons +// -------------------------------------------------- + +.btn-default { + .button-variant(@btn-default-color; @btn-default-bg; @btn-default-border); +} +.btn-primary { + .button-variant(@btn-primary-color; @btn-primary-bg; @btn-primary-border); +} +// Success appears as green +.btn-success { + .button-variant(@btn-success-color; @btn-success-bg; @btn-success-border); +} +// Info appears as blue-green +.btn-info { + .button-variant(@btn-info-color; @btn-info-bg; @btn-info-border); +} +// Warning appears as orange +.btn-warning { + .button-variant(@btn-warning-color; @btn-warning-bg; @btn-warning-border); +} +// Danger and error appear as red +.btn-danger { + .button-variant(@btn-danger-color; @btn-danger-bg; @btn-danger-border); +} + + +// Link buttons +// ------------------------- + +// Make a button look and behave like a link +.btn-link { + color: @link-color; + font-weight: normal; + border-radius: 0; + + &, + &:active, + &.active, + &[disabled], + fieldset[disabled] & { + background-color: transparent; + .box-shadow(none); + } + &, + &:hover, + &:focus, + &:active { + border-color: transparent; + } + &:hover, + &:focus { + color: @link-hover-color; + text-decoration: @link-hover-decoration; + background-color: transparent; + } + &[disabled], + fieldset[disabled] & { + &:hover, + &:focus { + color: @btn-link-disabled-color; + text-decoration: none; + } + } +} + + +// Button Sizes +// -------------------------------------------------- + +.btn-lg { + // line-height: ensure even-numbered height of button next to large input + .button-size(@padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @btn-border-radius-large); +} +.btn-sm { + // line-height: ensure proper height of button next to small input + .button-size(@padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @btn-border-radius-small); +} +.btn-xs { + .button-size(@padding-xs-vertical; @padding-xs-horizontal; @font-size-small; @line-height-small; @btn-border-radius-small); +} + + +// Block button +// -------------------------------------------------- + +.btn-block { + display: block; + width: 100%; +} + +// Vertically space out multiple block buttons +.btn-block + .btn-block { + margin-top: 5px; +} + +// Specificity overrides +input[type="submit"], +input[type="reset"], +input[type="button"] { + &.btn-block { + width: 100%; + } +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/carousel.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/carousel.less new file mode 100644 index 000000000..87ed6961d --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/carousel.less @@ -0,0 +1,269 @@ +// +// Carousel +// -------------------------------------------------- + + +// Wrapper for the slide container and indicators +.carousel { + position: relative; +} + +.carousel-inner { + position: relative; + overflow: hidden; + width: 100%; + + > .item { + display: none; + position: relative; + .transition(.6s ease-in-out left); + + // Account for jankitude on images + > img, + > a > img { + &:extend(.img-responsive); + line-height: 1; + } + + // WebKit CSS3 transforms for supported devices + @media all and (transform-3d), (-webkit-transform-3d) { + .transition-transform(~'0.6s ease-in-out'); + .backface-visibility(~'hidden'); + .perspective(1000px); + + &.next, + &.active.right { + .translate3d(100%, 0, 0); + left: 0; + } + &.prev, + &.active.left { + .translate3d(-100%, 0, 0); + left: 0; + } + &.next.left, + &.prev.right, + &.active { + .translate3d(0, 0, 0); + left: 0; + } + } + } + + > .active, + > .next, + > .prev { + display: block; + } + + > .active { + left: 0; + } + + > .next, + > .prev { + position: absolute; + top: 0; + width: 100%; + } + + > .next { + left: 100%; + } + > .prev { + left: -100%; + } + > .next.left, + > .prev.right { + left: 0; + } + + > .active.left { + left: -100%; + } + > .active.right { + left: 100%; + } + +} + +// Left/right controls for nav +// --------------------------- + +.carousel-control { + position: absolute; + top: 0; + left: 0; + bottom: 0; + width: @carousel-control-width; + .opacity(@carousel-control-opacity); + font-size: @carousel-control-font-size; + color: @carousel-control-color; + text-align: center; + text-shadow: @carousel-text-shadow; + // We can't have this transition here because WebKit cancels the carousel + // animation if you trip this while in the middle of another animation. + + // Set gradients for backgrounds + &.left { + #gradient > .horizontal(@start-color: rgba(0,0,0,.5); @end-color: rgba(0,0,0,.0001)); + } + &.right { + left: auto; + right: 0; + #gradient > .horizontal(@start-color: rgba(0,0,0,.0001); @end-color: rgba(0,0,0,.5)); + } + + // Hover/focus state + &:hover, + &:focus { + outline: 0; + color: @carousel-control-color; + text-decoration: none; + .opacity(.9); + } + + // Toggles + .icon-prev, + .icon-next, + .glyphicon-chevron-left, + .glyphicon-chevron-right { + position: absolute; + top: 50%; + margin-top: -10px; + z-index: 5; + display: inline-block; + } + .icon-prev, + .glyphicon-chevron-left { + left: 50%; + margin-left: -10px; + } + .icon-next, + .glyphicon-chevron-right { + right: 50%; + margin-right: -10px; + } + .icon-prev, + .icon-next { + width: 20px; + height: 20px; + line-height: 1; + font-family: serif; + } + + + .icon-prev { + &:before { + content: '\2039';// SINGLE LEFT-POINTING ANGLE QUOTATION MARK (U+2039) + } + } + .icon-next { + &:before { + content: '\203a';// SINGLE RIGHT-POINTING ANGLE QUOTATION MARK (U+203A) + } + } +} + +// Optional indicator pips +// +// Add an unordered list with the following class and add a list item for each +// slide your carousel holds. + +.carousel-indicators { + position: absolute; + bottom: 10px; + left: 50%; + z-index: 15; + width: 60%; + margin-left: -30%; + padding-left: 0; + list-style: none; + text-align: center; + + li { + display: inline-block; + width: 10px; + height: 10px; + margin: 1px; + text-indent: -999px; + border: 1px solid @carousel-indicator-border-color; + border-radius: 10px; + cursor: pointer; + + // IE8-9 hack for event handling + // + // Internet Explorer 8-9 does not support clicks on elements without a set + // `background-color`. We cannot use `filter` since that's not viewed as a + // background color by the browser. Thus, a hack is needed. + // See https://developer.mozilla.org/en-US/docs/Web/Events/click#Internet_Explorer + // + // For IE8, we set solid black as it doesn't support `rgba()`. For IE9, we + // set alpha transparency for the best results possible. + background-color: #000 \9; // IE8 + background-color: rgba(0,0,0,0); // IE9 + } + .active { + margin: 0; + width: 12px; + height: 12px; + background-color: @carousel-indicator-active-bg; + } +} + +// Optional captions +// ----------------------------- +// Hidden by default for smaller viewports +.carousel-caption { + position: absolute; + left: 15%; + right: 15%; + bottom: 20px; + z-index: 10; + padding-top: 20px; + padding-bottom: 20px; + color: @carousel-caption-color; + text-align: center; + text-shadow: @carousel-text-shadow; + & .btn { + text-shadow: none; // No shadow for button elements in carousel-caption + } +} + + +// Scale up controls for tablets and up +@media screen and (min-width: @screen-sm-min) { + + // Scale up the controls a smidge + .carousel-control { + .glyphicon-chevron-left, + .glyphicon-chevron-right, + .icon-prev, + .icon-next { + width: 30px; + height: 30px; + margin-top: -15px; + font-size: 30px; + } + .glyphicon-chevron-left, + .icon-prev { + margin-left: -15px; + } + .glyphicon-chevron-right, + .icon-next { + margin-right: -15px; + } + } + + // Show and left align the captions + .carousel-caption { + left: 20%; + right: 20%; + padding-bottom: 30px; + } + + // Move up the indicators + .carousel-indicators { + bottom: 20px; + } +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/close.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/close.less new file mode 100644 index 000000000..6d5bfe087 --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/close.less @@ -0,0 +1,34 @@ +// +// Close icons +// -------------------------------------------------- + + +.close { + float: right; + font-size: (@font-size-base * 1.5); + font-weight: @close-font-weight; + line-height: 1; + color: @close-color; + text-shadow: @close-text-shadow; + .opacity(.2); + + &:hover, + &:focus { + color: @close-color; + text-decoration: none; + cursor: pointer; + .opacity(.5); + } + + // Additional properties for button version + // iOS requires the button element instead of an anchor tag. + // If you want the anchor version, it requires `href="#"`. + // See https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile + button& { + padding: 0; + cursor: pointer; + background: transparent; + border: 0; + -webkit-appearance: none; + } +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/code.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/code.less new file mode 100644 index 000000000..a08b4d48c --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/code.less @@ -0,0 +1,69 @@ +// +// Code (inline and block) +// -------------------------------------------------- + + +// Inline and block code styles +code, +kbd, +pre, +samp { + font-family: @font-family-monospace; +} + +// Inline code +code { + padding: 2px 4px; + font-size: 90%; + color: @code-color; + background-color: @code-bg; + border-radius: @border-radius-base; +} + +// User input typically entered via keyboard +kbd { + padding: 2px 4px; + font-size: 90%; + color: @kbd-color; + background-color: @kbd-bg; + border-radius: @border-radius-small; + box-shadow: inset 0 -1px 0 rgba(0,0,0,.25); + + kbd { + padding: 0; + font-size: 100%; + font-weight: bold; + box-shadow: none; + } +} + +// Blocks of code +pre { + display: block; + padding: ((@line-height-computed - 1) / 2); + margin: 0 0 (@line-height-computed / 2); + font-size: (@font-size-base - 1); // 14px to 13px + line-height: @line-height-base; + word-break: break-all; + word-wrap: break-word; + color: @pre-color; + background-color: @pre-bg; + border: 1px solid @pre-border-color; + border-radius: @border-radius-base; + + // Account for some code outputs that place code tags in pre tags + code { + padding: 0; + font-size: inherit; + color: inherit; + white-space: pre-wrap; + background-color: transparent; + border-radius: 0; + } +} + +// Enable scrollable blocks of code +.pre-scrollable { + max-height: @pre-scrollable-max-height; + overflow-y: scroll; +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/component-animations.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/component-animations.less new file mode 100644 index 000000000..0bcee910a --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/component-animations.less @@ -0,0 +1,33 @@ +// +// Component animations +// -------------------------------------------------- + +// Heads up! +// +// We don't use the `.opacity()` mixin here since it causes a bug with text +// fields in IE7-8. Source: https://github.com/twbs/bootstrap/pull/3552. + +.fade { + opacity: 0; + .transition(opacity .15s linear); + &.in { + opacity: 1; + } +} + +.collapse { + display: none; + + &.in { display: block; } + tr&.in { display: table-row; } + tbody&.in { display: table-row-group; } +} + +.collapsing { + position: relative; + height: 0; + overflow: hidden; + .transition-property(~"height, visibility"); + .transition-duration(.35s); + .transition-timing-function(ease); +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/dropdowns.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/dropdowns.less new file mode 100644 index 000000000..f6876c1a9 --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/dropdowns.less @@ -0,0 +1,216 @@ +// +// Dropdown menus +// -------------------------------------------------- + + +// Dropdown arrow/caret +.caret { + display: inline-block; + width: 0; + height: 0; + margin-left: 2px; + vertical-align: middle; + border-top: @caret-width-base dashed; + border-top: @caret-width-base solid ~"\9"; // IE8 + border-right: @caret-width-base solid transparent; + border-left: @caret-width-base solid transparent; +} + +// The dropdown wrapper (div) +.dropup, +.dropdown { + position: relative; +} + +// Prevent the focus on the dropdown toggle when closing dropdowns +.dropdown-toggle:focus { + outline: 0; +} + +// The dropdown menu (ul) +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: @zindex-dropdown; + display: none; // none by default, but block on "open" of the menu + float: left; + min-width: 160px; + padding: 5px 0; + margin: 2px 0 0; // override default ul + list-style: none; + font-size: @font-size-base; + text-align: left; // Ensures proper alignment if parent has it changed (e.g., modal footer) + background-color: @dropdown-bg; + border: 1px solid @dropdown-fallback-border; // IE8 fallback + border: 1px solid @dropdown-border; + border-radius: @border-radius-base; + .box-shadow(0 6px 12px rgba(0,0,0,.175)); + background-clip: padding-box; + + // Aligns the dropdown menu to right + // + // Deprecated as of 3.1.0 in favor of `.dropdown-menu-[dir]` + &.pull-right { + right: 0; + left: auto; + } + + // Dividers (basically an hr) within the dropdown + .divider { + .nav-divider(@dropdown-divider-bg); + } + + // Links within the dropdown menu + > li > a { + display: block; + padding: 3px 20px; + clear: both; + font-weight: normal; + line-height: @line-height-base; + color: @dropdown-link-color; + white-space: nowrap; // prevent links from randomly breaking onto new lines + } +} + +// Hover/Focus state +.dropdown-menu > li > a { + &:hover, + &:focus { + text-decoration: none; + color: @dropdown-link-hover-color; + background-color: @dropdown-link-hover-bg; + } +} + +// Active state +.dropdown-menu > .active > a { + &, + &:hover, + &:focus { + color: @dropdown-link-active-color; + text-decoration: none; + outline: 0; + background-color: @dropdown-link-active-bg; + } +} + +// Disabled state +// +// Gray out text and ensure the hover/focus state remains gray + +.dropdown-menu > .disabled > a { + &, + &:hover, + &:focus { + color: @dropdown-link-disabled-color; + } + + // Nuke hover/focus effects + &:hover, + &:focus { + text-decoration: none; + background-color: transparent; + background-image: none; // Remove CSS gradient + .reset-filter(); + cursor: @cursor-disabled; + } +} + +// Open state for the dropdown +.open { + // Show the menu + > .dropdown-menu { + display: block; + } + + // Remove the outline when :focus is triggered + > a { + outline: 0; + } +} + +// Menu positioning +// +// Add extra class to `.dropdown-menu` to flip the alignment of the dropdown +// menu with the parent. +.dropdown-menu-right { + left: auto; // Reset the default from `.dropdown-menu` + right: 0; +} +// With v3, we enabled auto-flipping if you have a dropdown within a right +// aligned nav component. To enable the undoing of that, we provide an override +// to restore the default dropdown menu alignment. +// +// This is only for left-aligning a dropdown menu within a `.navbar-right` or +// `.pull-right` nav component. +.dropdown-menu-left { + left: 0; + right: auto; +} + +// Dropdown section headers +.dropdown-header { + display: block; + padding: 3px 20px; + font-size: @font-size-small; + line-height: @line-height-base; + color: @dropdown-header-color; + white-space: nowrap; // as with > li > a +} + +// Backdrop to catch body clicks on mobile, etc. +.dropdown-backdrop { + position: fixed; + left: 0; + right: 0; + bottom: 0; + top: 0; + z-index: (@zindex-dropdown - 10); +} + +// Right aligned dropdowns +.pull-right > .dropdown-menu { + right: 0; + left: auto; +} + +// Allow for dropdowns to go bottom up (aka, dropup-menu) +// +// Just add .dropup after the standard .dropdown class and you're set, bro. +// TODO: abstract this so that the navbar fixed styles are not placed here? + +.dropup, +.navbar-fixed-bottom .dropdown { + // Reverse the caret + .caret { + border-top: 0; + border-bottom: @caret-width-base dashed; + border-bottom: @caret-width-base solid ~"\9"; // IE8 + content: ""; + } + // Different positioning for bottom up menu + .dropdown-menu { + top: auto; + bottom: 100%; + margin-bottom: 2px; + } +} + + +// Component alignment +// +// Reiterate per navbar.less and the modified component alignment there. + +@media (min-width: @grid-float-breakpoint) { + .navbar-right { + .dropdown-menu { + .dropdown-menu-right(); + } + // Necessary for overrides of the default right aligned menu. + // Will remove come v4 in all likelihood. + .dropdown-menu-left { + .dropdown-menu-left(); + } + } +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/forms.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/forms.less new file mode 100644 index 000000000..910c1e13b --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/forms.less @@ -0,0 +1,613 @@ +// +// Forms +// -------------------------------------------------- + + +// Normalize non-controls +// +// Restyle and baseline non-control form elements. + +fieldset { + padding: 0; + margin: 0; + border: 0; + // Chrome and Firefox set a `min-width: min-content;` on fieldsets, + // so we reset that to ensure it behaves more like a standard block element. + // See https://github.com/twbs/bootstrap/issues/12359. + min-width: 0; +} + +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: @line-height-computed; + font-size: (@font-size-base * 1.5); + line-height: inherit; + color: @legend-color; + border: 0; + border-bottom: 1px solid @legend-border-color; +} + +label { + display: inline-block; + max-width: 100%; // Force IE8 to wrap long content (see https://github.com/twbs/bootstrap/issues/13141) + margin-bottom: 5px; + font-weight: bold; +} + + +// Normalize form controls +// +// While most of our form styles require extra classes, some basic normalization +// is required to ensure optimum display with or without those classes to better +// address browser inconsistencies. + +// Override content-box in Normalize (* isn't specific enough) +input[type="search"] { + .box-sizing(border-box); +} + +// Position radios and checkboxes better +input[type="radio"], +input[type="checkbox"] { + margin: 4px 0 0; + margin-top: 1px \9; // IE8-9 + line-height: normal; +} + +input[type="file"] { + display: block; +} + +// Make range inputs behave like textual form controls +input[type="range"] { + display: block; + width: 100%; +} + +// Make multiple select elements height not fixed +select[multiple], +select[size] { + height: auto; +} + +// Focus for file, radio, and checkbox +input[type="file"]:focus, +input[type="radio"]:focus, +input[type="checkbox"]:focus { + .tab-focus(); +} + +// Adjust output element +output { + display: block; + padding-top: (@padding-base-vertical + 1); + font-size: @font-size-base; + line-height: @line-height-base; + color: @input-color; +} + + +// Common form controls +// +// Shared size and type resets for form controls. Apply `.form-control` to any +// of the following form controls: +// +// select +// textarea +// input[type="text"] +// input[type="password"] +// input[type="datetime"] +// input[type="datetime-local"] +// input[type="date"] +// input[type="month"] +// input[type="time"] +// input[type="week"] +// input[type="number"] +// input[type="email"] +// input[type="url"] +// input[type="search"] +// input[type="tel"] +// input[type="color"] + +.form-control { + display: block; + width: 100%; + height: @input-height-base; // Make inputs at least the height of their button counterpart (base line-height + padding + border) + padding: @padding-base-vertical @padding-base-horizontal; + font-size: @font-size-base; + line-height: @line-height-base; + color: @input-color; + background-color: @input-bg; + background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214 + border: 1px solid @input-border; + border-radius: @input-border-radius; // Note: This has no effect on s in CSS. + .box-shadow(inset 0 1px 1px rgba(0,0,0,.075)); + .transition(~"border-color ease-in-out .15s, box-shadow ease-in-out .15s"); + + // Customize the `:focus` state to imitate native WebKit styles. + .form-control-focus(); + + // Placeholder + .placeholder(); + + // Unstyle the caret on `` +// element gets special love because it's special, and that's a fact! +.input-size(@input-height; @padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) { + height: @input-height; + padding: @padding-vertical @padding-horizontal; + font-size: @font-size; + line-height: @line-height; + border-radius: @border-radius; + + select& { + height: @input-height; + line-height: @input-height; + } + + textarea&, + select[multiple]& { + height: auto; + } +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/gradients.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/gradients.less new file mode 100644 index 000000000..0b88a89cc --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/gradients.less @@ -0,0 +1,59 @@ +// Gradients + +#gradient { + + // Horizontal gradient, from left to right + // + // Creates two color stops, start and end, by specifying a color and position for each color stop. + // Color stops are not available in IE9 and below. + .horizontal(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) { + background-image: -webkit-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+ + background-image: -o-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Opera 12 + background-image: linear-gradient(to right, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+ + background-repeat: repeat-x; + filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)",argb(@start-color),argb(@end-color))); // IE9 and down + } + + // Vertical gradient, from top to bottom + // + // Creates two color stops, start and end, by specifying a color and position for each color stop. + // Color stops are not available in IE9 and below. + .vertical(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) { + background-image: -webkit-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+ + background-image: -o-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Opera 12 + background-image: linear-gradient(to bottom, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+ + background-repeat: repeat-x; + filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)",argb(@start-color),argb(@end-color))); // IE9 and down + } + + .directional(@start-color: #555; @end-color: #333; @deg: 45deg) { + background-repeat: repeat-x; + background-image: -webkit-linear-gradient(@deg, @start-color, @end-color); // Safari 5.1-6, Chrome 10+ + background-image: -o-linear-gradient(@deg, @start-color, @end-color); // Opera 12 + background-image: linear-gradient(@deg, @start-color, @end-color); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+ + } + .horizontal-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) { + background-image: -webkit-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color); + background-image: -o-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color); + background-image: linear-gradient(to right, @start-color, @mid-color @color-stop, @end-color); + background-repeat: no-repeat; + filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback + } + .vertical-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) { + background-image: -webkit-linear-gradient(@start-color, @mid-color @color-stop, @end-color); + background-image: -o-linear-gradient(@start-color, @mid-color @color-stop, @end-color); + background-image: linear-gradient(@start-color, @mid-color @color-stop, @end-color); + background-repeat: no-repeat; + filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback + } + .radial(@inner-color: #555; @outer-color: #333) { + background-image: -webkit-radial-gradient(circle, @inner-color, @outer-color); + background-image: radial-gradient(circle, @inner-color, @outer-color); + background-repeat: no-repeat; + } + .striped(@color: rgba(255,255,255,.15); @angle: 45deg) { + background-image: -webkit-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent); + background-image: linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent); + } +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/grid-framework.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/grid-framework.less new file mode 100644 index 000000000..8c23eed24 --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/grid-framework.less @@ -0,0 +1,91 @@ +// Framework grid generation +// +// Used only by Bootstrap to generate the correct number of grid classes given +// any value of `@grid-columns`. + +.make-grid-columns() { + // Common styles for all sizes of grid columns, widths 1-12 + .col(@index) { // initial + @item: ~".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}"; + .col((@index + 1), @item); + } + .col(@index, @list) when (@index =< @grid-columns) { // general; "=<" isn't a typo + @item: ~".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}"; + .col((@index + 1), ~"@{list}, @{item}"); + } + .col(@index, @list) when (@index > @grid-columns) { // terminal + @{list} { + position: relative; + // Prevent columns from collapsing when empty + min-height: 1px; + // Inner gutter via padding + padding-left: ceil((@grid-gutter-width / 2)); + padding-right: floor((@grid-gutter-width / 2)); + } + } + .col(1); // kickstart it +} + +.float-grid-columns(@class) { + .col(@index) { // initial + @item: ~".col-@{class}-@{index}"; + .col((@index + 1), @item); + } + .col(@index, @list) when (@index =< @grid-columns) { // general + @item: ~".col-@{class}-@{index}"; + .col((@index + 1), ~"@{list}, @{item}"); + } + .col(@index, @list) when (@index > @grid-columns) { // terminal + @{list} { + float: left; + } + } + .col(1); // kickstart it +} + +.calc-grid-column(@index, @class, @type) when (@type = width) and (@index > 0) { + .col-@{class}-@{index} { + width: percentage((@index / @grid-columns)); + } +} +.calc-grid-column(@index, @class, @type) when (@type = push) and (@index > 0) { + .col-@{class}-push-@{index} { + left: percentage((@index / @grid-columns)); + } +} +.calc-grid-column(@index, @class, @type) when (@type = push) and (@index = 0) { + .col-@{class}-push-0 { + left: auto; + } +} +.calc-grid-column(@index, @class, @type) when (@type = pull) and (@index > 0) { + .col-@{class}-pull-@{index} { + right: percentage((@index / @grid-columns)); + } +} +.calc-grid-column(@index, @class, @type) when (@type = pull) and (@index = 0) { + .col-@{class}-pull-0 { + right: auto; + } +} +.calc-grid-column(@index, @class, @type) when (@type = offset) { + .col-@{class}-offset-@{index} { + margin-left: percentage((@index / @grid-columns)); + } +} + +// Basic looping in LESS +.loop-grid-columns(@index, @class, @type) when (@index >= 0) { + .calc-grid-column(@index, @class, @type); + // next iteration + .loop-grid-columns((@index - 1), @class, @type); +} + +// Create grid for specific class +.make-grid(@class) { + .float-grid-columns(@class); + .loop-grid-columns(@grid-columns, @class, width); + .loop-grid-columns(@grid-columns, @class, pull); + .loop-grid-columns(@grid-columns, @class, push); + .loop-grid-columns(@grid-columns, @class, offset); +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/grid.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/grid.less new file mode 100644 index 000000000..f144c15f4 --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/grid.less @@ -0,0 +1,122 @@ +// Grid system +// +// Generate semantic grid columns with these mixins. + +// Centered container element +.container-fixed(@gutter: @grid-gutter-width) { + margin-right: auto; + margin-left: auto; + padding-left: (@gutter / 2); + padding-right: (@gutter / 2); + &:extend(.clearfix all); +} + +// Creates a wrapper for a series of columns +.make-row(@gutter: @grid-gutter-width) { + margin-left: ceil((@gutter / -2)); + margin-right: floor((@gutter / -2)); + &:extend(.clearfix all); +} + +// Generate the extra small columns +.make-xs-column(@columns; @gutter: @grid-gutter-width) { + position: relative; + float: left; + width: percentage((@columns / @grid-columns)); + min-height: 1px; + padding-left: (@gutter / 2); + padding-right: (@gutter / 2); +} +.make-xs-column-offset(@columns) { + margin-left: percentage((@columns / @grid-columns)); +} +.make-xs-column-push(@columns) { + left: percentage((@columns / @grid-columns)); +} +.make-xs-column-pull(@columns) { + right: percentage((@columns / @grid-columns)); +} + +// Generate the small columns +.make-sm-column(@columns; @gutter: @grid-gutter-width) { + position: relative; + min-height: 1px; + padding-left: (@gutter / 2); + padding-right: (@gutter / 2); + + @media (min-width: @screen-sm-min) { + float: left; + width: percentage((@columns / @grid-columns)); + } +} +.make-sm-column-offset(@columns) { + @media (min-width: @screen-sm-min) { + margin-left: percentage((@columns / @grid-columns)); + } +} +.make-sm-column-push(@columns) { + @media (min-width: @screen-sm-min) { + left: percentage((@columns / @grid-columns)); + } +} +.make-sm-column-pull(@columns) { + @media (min-width: @screen-sm-min) { + right: percentage((@columns / @grid-columns)); + } +} + +// Generate the medium columns +.make-md-column(@columns; @gutter: @grid-gutter-width) { + position: relative; + min-height: 1px; + padding-left: (@gutter / 2); + padding-right: (@gutter / 2); + + @media (min-width: @screen-md-min) { + float: left; + width: percentage((@columns / @grid-columns)); + } +} +.make-md-column-offset(@columns) { + @media (min-width: @screen-md-min) { + margin-left: percentage((@columns / @grid-columns)); + } +} +.make-md-column-push(@columns) { + @media (min-width: @screen-md-min) { + left: percentage((@columns / @grid-columns)); + } +} +.make-md-column-pull(@columns) { + @media (min-width: @screen-md-min) { + right: percentage((@columns / @grid-columns)); + } +} + +// Generate the large columns +.make-lg-column(@columns; @gutter: @grid-gutter-width) { + position: relative; + min-height: 1px; + padding-left: (@gutter / 2); + padding-right: (@gutter / 2); + + @media (min-width: @screen-lg-min) { + float: left; + width: percentage((@columns / @grid-columns)); + } +} +.make-lg-column-offset(@columns) { + @media (min-width: @screen-lg-min) { + margin-left: percentage((@columns / @grid-columns)); + } +} +.make-lg-column-push(@columns) { + @media (min-width: @screen-lg-min) { + left: percentage((@columns / @grid-columns)); + } +} +.make-lg-column-pull(@columns) { + @media (min-width: @screen-lg-min) { + right: percentage((@columns / @grid-columns)); + } +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/hide-text.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/hide-text.less new file mode 100644 index 000000000..bc7011850 --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/hide-text.less @@ -0,0 +1,21 @@ +// CSS image replacement +// +// Heads up! v3 launched with only `.hide-text()`, but per our pattern for +// mixins being reused as classes with the same name, this doesn't hold up. As +// of v3.0.1 we have added `.text-hide()` and deprecated `.hide-text()`. +// +// Source: https://github.com/h5bp/html5-boilerplate/commit/aa0396eae757 + +// Deprecated as of v3.0.1 (will be removed in v4) +.hide-text() { + font: ~"0/0" a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; +} + +// New mixin to use as of v3.0.1 +.text-hide() { + .hide-text(); +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/image.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/image.less new file mode 100644 index 000000000..f233cb3e1 --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/image.less @@ -0,0 +1,33 @@ +// Image Mixins +// - Responsive image +// - Retina image + + +// Responsive image +// +// Keep images from scaling beyond the width of their parents. +.img-responsive(@display: block) { + display: @display; + max-width: 100%; // Part 1: Set a maximum relative to the parent + height: auto; // Part 2: Scale the height according to the width, otherwise you get stretching +} + + +// Retina image +// +// Short retina mixin for setting background-image and -size. Note that the +// spelling of `min--moz-device-pixel-ratio` is intentional. +.img-retina(@file-1x; @file-2x; @width-1x; @height-1x) { + background-image: url("@{file-1x}"); + + @media + only screen and (-webkit-min-device-pixel-ratio: 2), + only screen and ( min--moz-device-pixel-ratio: 2), + only screen and ( -o-min-device-pixel-ratio: 2/1), + only screen and ( min-device-pixel-ratio: 2), + only screen and ( min-resolution: 192dpi), + only screen and ( min-resolution: 2dppx) { + background-image: url("@{file-2x}"); + background-size: @width-1x @height-1x; + } +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/labels.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/labels.less new file mode 100644 index 000000000..9f7a67ee3 --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/labels.less @@ -0,0 +1,12 @@ +// Labels + +.label-variant(@color) { + background-color: @color; + + &[href] { + &:hover, + &:focus { + background-color: darken(@color, 10%); + } + } +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/list-group.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/list-group.less new file mode 100644 index 000000000..03aa19069 --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/list-group.less @@ -0,0 +1,30 @@ +// List Groups + +.list-group-item-variant(@state; @background; @color) { + .list-group-item-@{state} { + color: @color; + background-color: @background; + + a&, + button& { + color: @color; + + .list-group-item-heading { + color: inherit; + } + + &:hover, + &:focus { + color: @color; + background-color: darken(@background, 5%); + } + &.active, + &.active:hover, + &.active:focus { + color: #fff; + background-color: @color; + border-color: @color; + } + } + } +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/nav-divider.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/nav-divider.less new file mode 100644 index 000000000..feb1e9ed0 --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/nav-divider.less @@ -0,0 +1,10 @@ +// Horizontal dividers +// +// Dividers (basically an hr) within dropdowns and nav lists + +.nav-divider(@color: #e5e5e5) { + height: 1px; + margin: ((@line-height-computed / 2) - 1) 0; + overflow: hidden; + background-color: @color; +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/nav-vertical-align.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/nav-vertical-align.less new file mode 100644 index 000000000..d458c7861 --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/nav-vertical-align.less @@ -0,0 +1,9 @@ +// Navbar vertical align +// +// Vertically center elements in the navbar. +// Example: an element has a height of 30px, so write out `.navbar-vertical-align(30px);` to calculate the appropriate top margin. + +.navbar-vertical-align(@element-height) { + margin-top: ((@navbar-height - @element-height) / 2); + margin-bottom: ((@navbar-height - @element-height) / 2); +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/opacity.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/opacity.less new file mode 100644 index 000000000..33ed25ce6 --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/opacity.less @@ -0,0 +1,8 @@ +// Opacity + +.opacity(@opacity) { + opacity: @opacity; + // IE8 filter + @opacity-ie: (@opacity * 100); + filter: ~"alpha(opacity=@{opacity-ie})"; +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/pagination.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/pagination.less new file mode 100644 index 000000000..618804f2d --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/pagination.less @@ -0,0 +1,24 @@ +// Pagination + +.pagination-size(@padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) { + > li { + > a, + > span { + padding: @padding-vertical @padding-horizontal; + font-size: @font-size; + line-height: @line-height; + } + &:first-child { + > a, + > span { + .border-left-radius(@border-radius); + } + } + &:last-child { + > a, + > span { + .border-right-radius(@border-radius); + } + } + } +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/panels.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/panels.less new file mode 100644 index 000000000..49ee10d4a --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/panels.less @@ -0,0 +1,24 @@ +// Panels + +.panel-variant(@border; @heading-text-color; @heading-bg-color; @heading-border) { + border-color: @border; + + & > .panel-heading { + color: @heading-text-color; + background-color: @heading-bg-color; + border-color: @heading-border; + + + .panel-collapse > .panel-body { + border-top-color: @border; + } + .badge { + color: @heading-bg-color; + background-color: @heading-text-color; + } + } + & > .panel-footer { + + .panel-collapse > .panel-body { + border-bottom-color: @border; + } + } +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/progress-bar.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/progress-bar.less new file mode 100644 index 000000000..f07996a34 --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/progress-bar.less @@ -0,0 +1,10 @@ +// Progress bars + +.progress-bar-variant(@color) { + background-color: @color; + + // Deprecated parent class requirement as of v3.2.0 + .progress-striped & { + #gradient > .striped(); + } +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/reset-filter.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/reset-filter.less new file mode 100644 index 000000000..68cdb5e18 --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/reset-filter.less @@ -0,0 +1,8 @@ +// Reset filters for IE +// +// When you need to remove a gradient background, do not forget to use this to reset +// the IE filter for IE9 and below. + +.reset-filter() { + filter: e(%("progid:DXImageTransform.Microsoft.gradient(enabled = false)")); +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/reset-text.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/reset-text.less new file mode 100644 index 000000000..58dd4d19b --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/reset-text.less @@ -0,0 +1,18 @@ +.reset-text() { + font-family: @font-family-base; + // We deliberately do NOT reset font-size. + font-style: normal; + font-weight: normal; + letter-spacing: normal; + line-break: auto; + line-height: @line-height-base; + text-align: left; // Fallback for where `start` is not supported + text-align: start; + text-decoration: none; + text-shadow: none; + text-transform: none; + white-space: normal; + word-break: normal; + word-spacing: normal; + word-wrap: normal; +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/resize.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/resize.less new file mode 100644 index 000000000..3acd3afdb --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/resize.less @@ -0,0 +1,6 @@ +// Resize anything + +.resizable(@direction) { + resize: @direction; // Options: horizontal, vertical, both + overflow: auto; // Per CSS3 UI, `resize` only applies when `overflow` isn't `visible` +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/responsive-visibility.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/responsive-visibility.less new file mode 100644 index 000000000..ecf1e979f --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/responsive-visibility.less @@ -0,0 +1,15 @@ +// Responsive utilities + +// +// More easily include all the states for responsive-utilities.less. +.responsive-visibility() { + display: block !important; + table& { display: table !important; } + tr& { display: table-row !important; } + th&, + td& { display: table-cell !important; } +} + +.responsive-invisibility() { + display: none !important; +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/size.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/size.less new file mode 100644 index 000000000..a8be65089 --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/size.less @@ -0,0 +1,10 @@ +// Sizing shortcuts + +.size(@width; @height) { + width: @width; + height: @height; +} + +.square(@size) { + .size(@size; @size); +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/tab-focus.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/tab-focus.less new file mode 100644 index 000000000..1f1f05ab0 --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/tab-focus.less @@ -0,0 +1,9 @@ +// WebKit-style focus + +.tab-focus() { + // Default + outline: thin dotted; + // WebKit + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/table-row.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/table-row.less new file mode 100644 index 000000000..0f287f1a8 --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/table-row.less @@ -0,0 +1,28 @@ +// Tables + +.table-row-variant(@state; @background) { + // Exact selectors below required to override `.table-striped` and prevent + // inheritance to nested tables. + .table > thead > tr, + .table > tbody > tr, + .table > tfoot > tr { + > td.@{state}, + > th.@{state}, + &.@{state} > td, + &.@{state} > th { + background-color: @background; + } + } + + // Hover states for `.table-hover` + // Note: this is not available for cells or rows within `thead` or `tfoot`. + .table-hover > tbody > tr { + > td.@{state}:hover, + > th.@{state}:hover, + &.@{state}:hover > td, + &:hover > .@{state}, + &.@{state}:hover > th { + background-color: darken(@background, 5%); + } + } +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/text-emphasis.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/text-emphasis.less new file mode 100644 index 000000000..9e8a77a69 --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/text-emphasis.less @@ -0,0 +1,9 @@ +// Typography + +.text-emphasis-variant(@color) { + color: @color; + a&:hover, + a&:focus { + color: darken(@color, 10%); + } +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/text-overflow.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/text-overflow.less new file mode 100644 index 000000000..c11ad2fb7 --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/text-overflow.less @@ -0,0 +1,8 @@ +// Text overflow +// Requires inline-block or block for proper styling + +.text-overflow() { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/vendor-prefixes.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/vendor-prefixes.less new file mode 100644 index 000000000..afd3331c3 --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/mixins/vendor-prefixes.less @@ -0,0 +1,227 @@ +// Vendor Prefixes +// +// All vendor mixins are deprecated as of v3.2.0 due to the introduction of +// Autoprefixer in our Gruntfile. They will be removed in v4. + +// - Animations +// - Backface visibility +// - Box shadow +// - Box sizing +// - Content columns +// - Hyphens +// - Placeholder text +// - Transformations +// - Transitions +// - User Select + + +// Animations +.animation(@animation) { + -webkit-animation: @animation; + -o-animation: @animation; + animation: @animation; +} +.animation-name(@name) { + -webkit-animation-name: @name; + animation-name: @name; +} +.animation-duration(@duration) { + -webkit-animation-duration: @duration; + animation-duration: @duration; +} +.animation-timing-function(@timing-function) { + -webkit-animation-timing-function: @timing-function; + animation-timing-function: @timing-function; +} +.animation-delay(@delay) { + -webkit-animation-delay: @delay; + animation-delay: @delay; +} +.animation-iteration-count(@iteration-count) { + -webkit-animation-iteration-count: @iteration-count; + animation-iteration-count: @iteration-count; +} +.animation-direction(@direction) { + -webkit-animation-direction: @direction; + animation-direction: @direction; +} +.animation-fill-mode(@fill-mode) { + -webkit-animation-fill-mode: @fill-mode; + animation-fill-mode: @fill-mode; +} + +// Backface visibility +// Prevent browsers from flickering when using CSS 3D transforms. +// Default value is `visible`, but can be changed to `hidden` + +.backface-visibility(@visibility){ + -webkit-backface-visibility: @visibility; + -moz-backface-visibility: @visibility; + backface-visibility: @visibility; +} + +// Drop shadows +// +// Note: Deprecated `.box-shadow()` as of v3.1.0 since all of Bootstrap's +// supported browsers that have box shadow capabilities now support it. + +.box-shadow(@shadow) { + -webkit-box-shadow: @shadow; // iOS <4.3 & Android <4.1 + box-shadow: @shadow; +} + +// Box sizing +.box-sizing(@boxmodel) { + -webkit-box-sizing: @boxmodel; + -moz-box-sizing: @boxmodel; + box-sizing: @boxmodel; +} + +// CSS3 Content Columns +.content-columns(@column-count; @column-gap: @grid-gutter-width) { + -webkit-column-count: @column-count; + -moz-column-count: @column-count; + column-count: @column-count; + -webkit-column-gap: @column-gap; + -moz-column-gap: @column-gap; + column-gap: @column-gap; +} + +// Optional hyphenation +.hyphens(@mode: auto) { + word-wrap: break-word; + -webkit-hyphens: @mode; + -moz-hyphens: @mode; + -ms-hyphens: @mode; // IE10+ + -o-hyphens: @mode; + hyphens: @mode; +} + +// Placeholder text +.placeholder(@color: @input-color-placeholder) { + // Firefox + &::-moz-placeholder { + color: @color; + opacity: 1; // Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526 + } + &:-ms-input-placeholder { color: @color; } // Internet Explorer 10+ + &::-webkit-input-placeholder { color: @color; } // Safari and Chrome +} + +// Transformations +.scale(@ratio) { + -webkit-transform: scale(@ratio); + -ms-transform: scale(@ratio); // IE9 only + -o-transform: scale(@ratio); + transform: scale(@ratio); +} +.scale(@ratioX; @ratioY) { + -webkit-transform: scale(@ratioX, @ratioY); + -ms-transform: scale(@ratioX, @ratioY); // IE9 only + -o-transform: scale(@ratioX, @ratioY); + transform: scale(@ratioX, @ratioY); +} +.scaleX(@ratio) { + -webkit-transform: scaleX(@ratio); + -ms-transform: scaleX(@ratio); // IE9 only + -o-transform: scaleX(@ratio); + transform: scaleX(@ratio); +} +.scaleY(@ratio) { + -webkit-transform: scaleY(@ratio); + -ms-transform: scaleY(@ratio); // IE9 only + -o-transform: scaleY(@ratio); + transform: scaleY(@ratio); +} +.skew(@x; @y) { + -webkit-transform: skewX(@x) skewY(@y); + -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+ + -o-transform: skewX(@x) skewY(@y); + transform: skewX(@x) skewY(@y); +} +.translate(@x; @y) { + -webkit-transform: translate(@x, @y); + -ms-transform: translate(@x, @y); // IE9 only + -o-transform: translate(@x, @y); + transform: translate(@x, @y); +} +.translate3d(@x; @y; @z) { + -webkit-transform: translate3d(@x, @y, @z); + transform: translate3d(@x, @y, @z); +} +.rotate(@degrees) { + -webkit-transform: rotate(@degrees); + -ms-transform: rotate(@degrees); // IE9 only + -o-transform: rotate(@degrees); + transform: rotate(@degrees); +} +.rotateX(@degrees) { + -webkit-transform: rotateX(@degrees); + -ms-transform: rotateX(@degrees); // IE9 only + -o-transform: rotateX(@degrees); + transform: rotateX(@degrees); +} +.rotateY(@degrees) { + -webkit-transform: rotateY(@degrees); + -ms-transform: rotateY(@degrees); // IE9 only + -o-transform: rotateY(@degrees); + transform: rotateY(@degrees); +} +.perspective(@perspective) { + -webkit-perspective: @perspective; + -moz-perspective: @perspective; + perspective: @perspective; +} +.perspective-origin(@perspective) { + -webkit-perspective-origin: @perspective; + -moz-perspective-origin: @perspective; + perspective-origin: @perspective; +} +.transform-origin(@origin) { + -webkit-transform-origin: @origin; + -moz-transform-origin: @origin; + -ms-transform-origin: @origin; // IE9 only + transform-origin: @origin; +} + + +// Transitions + +.transition(@transition) { + -webkit-transition: @transition; + -o-transition: @transition; + transition: @transition; +} +.transition-property(@transition-property) { + -webkit-transition-property: @transition-property; + transition-property: @transition-property; +} +.transition-delay(@transition-delay) { + -webkit-transition-delay: @transition-delay; + transition-delay: @transition-delay; +} +.transition-duration(@transition-duration) { + -webkit-transition-duration: @transition-duration; + transition-duration: @transition-duration; +} +.transition-timing-function(@timing-function) { + -webkit-transition-timing-function: @timing-function; + transition-timing-function: @timing-function; +} +.transition-transform(@transition) { + -webkit-transition: -webkit-transform @transition; + -moz-transition: -moz-transform @transition; + -o-transition: -o-transform @transition; + transition: transform @transition; +} + + +// User select +// For selecting text on the page + +.user-select(@select) { + -webkit-user-select: @select; + -moz-user-select: @select; + -ms-user-select: @select; // IE10+ + user-select: @select; +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/modals.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/modals.less new file mode 100644 index 000000000..1de622050 --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/modals.less @@ -0,0 +1,150 @@ +// +// Modals +// -------------------------------------------------- + +// .modal-open - body class for killing the scroll +// .modal - container to scroll within +// .modal-dialog - positioning shell for the actual modal +// .modal-content - actual modal w/ bg and corners and shit + +// Kill the scroll on the body +.modal-open { + overflow: hidden; +} + +// Container that the modal scrolls within +.modal { + display: none; + overflow: hidden; + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: @zindex-modal; + -webkit-overflow-scrolling: touch; + + // Prevent Chrome on Windows from adding a focus outline. For details, see + // https://github.com/twbs/bootstrap/pull/10951. + outline: 0; + + // When fading in the modal, animate it to slide down + &.fade .modal-dialog { + .translate(0, -25%); + .transition-transform(~"0.3s ease-out"); + } + &.in .modal-dialog { .translate(0, 0) } +} +.modal-open .modal { + overflow-x: hidden; + overflow-y: auto; +} + +// Shell div to position the modal with bottom padding +.modal-dialog { + position: relative; + width: auto; + margin: 10px; +} + +// Actual modal +.modal-content { + position: relative; + background-color: @modal-content-bg; + border: 1px solid @modal-content-fallback-border-color; //old browsers fallback (ie8 etc) + border: 1px solid @modal-content-border-color; + border-radius: @border-radius-large; + .box-shadow(0 3px 9px rgba(0,0,0,.5)); + background-clip: padding-box; + // Remove focus outline from opened modal + outline: 0; +} + +// Modal background +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: @zindex-modal-background; + background-color: @modal-backdrop-bg; + // Fade for backdrop + &.fade { .opacity(0); } + &.in { .opacity(@modal-backdrop-opacity); } +} + +// Modal header +// Top section of the modal w/ title and dismiss +.modal-header { + padding: @modal-title-padding; + border-bottom: 1px solid @modal-header-border-color; + min-height: (@modal-title-padding + @modal-title-line-height); +} +// Close icon +.modal-header .close { + margin-top: -2px; +} + +// Title text within header +.modal-title { + margin: 0; + line-height: @modal-title-line-height; +} + +// Modal body +// Where all modal content resides (sibling of .modal-header and .modal-footer) +.modal-body { + position: relative; + padding: @modal-inner-padding; +} + +// Footer (for actions) +.modal-footer { + padding: @modal-inner-padding; + text-align: right; // right align buttons + border-top: 1px solid @modal-footer-border-color; + &:extend(.clearfix all); // clear it in case folks use .pull-* classes on buttons + + // Properly space out buttons + .btn + .btn { + margin-left: 5px; + margin-bottom: 0; // account for input[type="submit"] which gets the bottom margin like all other inputs + } + // but override that for button groups + .btn-group .btn + .btn { + margin-left: -1px; + } + // and override it for block buttons as well + .btn-block + .btn-block { + margin-left: 0; + } +} + +// Measure scrollbar width for padding body during modal show/hide +.modal-scrollbar-measure { + position: absolute; + top: -9999px; + width: 50px; + height: 50px; + overflow: scroll; +} + +// Scale up the modal +@media (min-width: @screen-sm-min) { + // Automatically set modal's width for larger viewports + .modal-dialog { + width: @modal-md; + margin: 30px auto; + } + .modal-content { + .box-shadow(0 5px 15px rgba(0,0,0,.5)); + } + + // Modal sizes + .modal-sm { width: @modal-sm; } +} + +@media (min-width: @screen-md-min) { + .modal-lg { width: @modal-lg; } +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/navbar.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/navbar.less new file mode 100644 index 000000000..6d751bb9c --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/navbar.less @@ -0,0 +1,660 @@ +// +// Navbars +// -------------------------------------------------- + + +// Wrapper and base class +// +// Provide a static navbar from which we expand to create full-width, fixed, and +// other navbar variations. + +.navbar { + position: relative; + min-height: @navbar-height; // Ensure a navbar always shows (e.g., without a .navbar-brand in collapsed mode) + margin-bottom: @navbar-margin-bottom; + border: 1px solid transparent; + + // Prevent floats from breaking the navbar + &:extend(.clearfix all); + + @media (min-width: @grid-float-breakpoint) { + border-radius: @navbar-border-radius; + } +} + + +// Navbar heading +// +// Groups `.navbar-brand` and `.navbar-toggle` into a single component for easy +// styling of responsive aspects. + +.navbar-header { + &:extend(.clearfix all); + + @media (min-width: @grid-float-breakpoint) { + float: left; + } +} + + +// Navbar collapse (body) +// +// Group your navbar content into this for easy collapsing and expanding across +// various device sizes. By default, this content is collapsed when <768px, but +// will expand past that for a horizontal display. +// +// To start (on mobile devices) the navbar links, forms, and buttons are stacked +// vertically and include a `max-height` to overflow in case you have too much +// content for the user's viewport. + +.navbar-collapse { + overflow-x: visible; + padding-right: @navbar-padding-horizontal; + padding-left: @navbar-padding-horizontal; + border-top: 1px solid transparent; + box-shadow: inset 0 1px 0 rgba(255,255,255,.1); + &:extend(.clearfix all); + -webkit-overflow-scrolling: touch; + + &.in { + overflow-y: auto; + } + + @media (min-width: @grid-float-breakpoint) { + width: auto; + border-top: 0; + box-shadow: none; + + &.collapse { + display: block !important; + height: auto !important; + padding-bottom: 0; // Override default setting + overflow: visible !important; + } + + &.in { + overflow-y: visible; + } + + // Undo the collapse side padding for navbars with containers to ensure + // alignment of right-aligned contents. + .navbar-fixed-top &, + .navbar-static-top &, + .navbar-fixed-bottom & { + padding-left: 0; + padding-right: 0; + } + } +} + +.navbar-fixed-top, +.navbar-fixed-bottom { + .navbar-collapse { + max-height: @navbar-collapse-max-height; + + @media (max-device-width: @screen-xs-min) and (orientation: landscape) { + max-height: 200px; + } + } +} + + +// Both navbar header and collapse +// +// When a container is present, change the behavior of the header and collapse. + +.container, +.container-fluid { + > .navbar-header, + > .navbar-collapse { + margin-right: -@navbar-padding-horizontal; + margin-left: -@navbar-padding-horizontal; + + @media (min-width: @grid-float-breakpoint) { + margin-right: 0; + margin-left: 0; + } + } +} + + +// +// Navbar alignment options +// +// Display the navbar across the entirety of the page or fixed it to the top or +// bottom of the page. + +// Static top (unfixed, but 100% wide) navbar +.navbar-static-top { + z-index: @zindex-navbar; + border-width: 0 0 1px; + + @media (min-width: @grid-float-breakpoint) { + border-radius: 0; + } +} + +// Fix the top/bottom navbars when screen real estate supports it +.navbar-fixed-top, +.navbar-fixed-bottom { + position: fixed; + right: 0; + left: 0; + z-index: @zindex-navbar-fixed; + + // Undo the rounded corners + @media (min-width: @grid-float-breakpoint) { + border-radius: 0; + } +} +.navbar-fixed-top { + top: 0; + border-width: 0 0 1px; +} +.navbar-fixed-bottom { + bottom: 0; + margin-bottom: 0; // override .navbar defaults + border-width: 1px 0 0; +} + + +// Brand/project name + +.navbar-brand { + float: left; + padding: @navbar-padding-vertical @navbar-padding-horizontal; + font-size: @font-size-large; + line-height: @line-height-computed; + height: @navbar-height; + + &:hover, + &:focus { + text-decoration: none; + } + + > img { + display: block; + } + + @media (min-width: @grid-float-breakpoint) { + .navbar > .container &, + .navbar > .container-fluid & { + margin-left: -@navbar-padding-horizontal; + } + } +} + + +// Navbar toggle +// +// Custom button for toggling the `.navbar-collapse`, powered by the collapse +// JavaScript plugin. + +.navbar-toggle { + position: relative; + float: right; + margin-right: @navbar-padding-horizontal; + padding: 9px 10px; + .navbar-vertical-align(34px); + background-color: transparent; + background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214 + border: 1px solid transparent; + border-radius: @border-radius-base; + + // We remove the `outline` here, but later compensate by attaching `:hover` + // styles to `:focus`. + &:focus { + outline: 0; + } + + // Bars + .icon-bar { + display: block; + width: 22px; + height: 2px; + border-radius: 1px; + } + .icon-bar + .icon-bar { + margin-top: 4px; + } + + @media (min-width: @grid-float-breakpoint) { + display: none; + } +} + + +// Navbar nav links +// +// Builds on top of the `.nav` components with its own modifier class to make +// the nav the full height of the horizontal nav (above 768px). + +.navbar-nav { + margin: (@navbar-padding-vertical / 2) -@navbar-padding-horizontal; + + > li > a { + padding-top: 10px; + padding-bottom: 10px; + line-height: @line-height-computed; + } + + @media (max-width: @grid-float-breakpoint-max) { + // Dropdowns get custom display when collapsed + .open .dropdown-menu { + position: static; + float: none; + width: auto; + margin-top: 0; + background-color: transparent; + border: 0; + box-shadow: none; + > li > a, + .dropdown-header { + padding: 5px 15px 5px 25px; + } + > li > a { + line-height: @line-height-computed; + &:hover, + &:focus { + background-image: none; + } + } + } + } + + // Uncollapse the nav + @media (min-width: @grid-float-breakpoint) { + float: left; + margin: 0; + + > li { + float: left; + > a { + padding-top: @navbar-padding-vertical; + padding-bottom: @navbar-padding-vertical; + } + } + } +} + + +// Navbar form +// +// Extension of the `.form-inline` with some extra flavor for optimum display in +// our navbars. + +.navbar-form { + margin-left: -@navbar-padding-horizontal; + margin-right: -@navbar-padding-horizontal; + padding: 10px @navbar-padding-horizontal; + border-top: 1px solid transparent; + border-bottom: 1px solid transparent; + @shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1); + .box-shadow(@shadow); + + // Mixin behavior for optimum display + .form-inline(); + + .form-group { + @media (max-width: @grid-float-breakpoint-max) { + margin-bottom: 5px; + + &:last-child { + margin-bottom: 0; + } + } + } + + // Vertically center in expanded, horizontal navbar + .navbar-vertical-align(@input-height-base); + + // Undo 100% width for pull classes + @media (min-width: @grid-float-breakpoint) { + width: auto; + border: 0; + margin-left: 0; + margin-right: 0; + padding-top: 0; + padding-bottom: 0; + .box-shadow(none); + } +} + + +// Dropdown menus + +// Menu position and menu carets +.navbar-nav > li > .dropdown-menu { + margin-top: 0; + .border-top-radius(0); +} +// Menu position and menu caret support for dropups via extra dropup class +.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu { + margin-bottom: 0; + .border-top-radius(@navbar-border-radius); + .border-bottom-radius(0); +} + + +// Buttons in navbars +// +// Vertically center a button within a navbar (when *not* in a form). + +.navbar-btn { + .navbar-vertical-align(@input-height-base); + + &.btn-sm { + .navbar-vertical-align(@input-height-small); + } + &.btn-xs { + .navbar-vertical-align(22); + } +} + + +// Text in navbars +// +// Add a class to make any element properly align itself vertically within the navbars. + +.navbar-text { + .navbar-vertical-align(@line-height-computed); + + @media (min-width: @grid-float-breakpoint) { + float: left; + margin-left: @navbar-padding-horizontal; + margin-right: @navbar-padding-horizontal; + } +} + + +// Component alignment +// +// Repurpose the pull utilities as their own navbar utilities to avoid specificity +// issues with parents and chaining. Only do this when the navbar is uncollapsed +// though so that navbar contents properly stack and align in mobile. +// +// Declared after the navbar components to ensure more specificity on the margins. + +@media (min-width: @grid-float-breakpoint) { + .navbar-left { .pull-left(); } + .navbar-right { + .pull-right(); + margin-right: -@navbar-padding-horizontal; + + ~ .navbar-right { + margin-right: 0; + } + } +} + + +// Alternate navbars +// -------------------------------------------------- + +// Default navbar +.navbar-default { + background-color: @navbar-default-bg; + border-color: @navbar-default-border; + + .navbar-brand { + color: @navbar-default-brand-color; + &:hover, + &:focus { + color: @navbar-default-brand-hover-color; + background-color: @navbar-default-brand-hover-bg; + } + } + + .navbar-text { + color: @navbar-default-color; + } + + .navbar-nav { + > li > a { + color: @navbar-default-link-color; + + &:hover, + &:focus { + color: @navbar-default-link-hover-color; + background-color: @navbar-default-link-hover-bg; + } + } + > .active > a { + &, + &:hover, + &:focus { + color: @navbar-default-link-active-color; + background-color: @navbar-default-link-active-bg; + } + } + > .disabled > a { + &, + &:hover, + &:focus { + color: @navbar-default-link-disabled-color; + background-color: @navbar-default-link-disabled-bg; + } + } + } + + .navbar-toggle { + border-color: @navbar-default-toggle-border-color; + &:hover, + &:focus { + background-color: @navbar-default-toggle-hover-bg; + } + .icon-bar { + background-color: @navbar-default-toggle-icon-bar-bg; + } + } + + .navbar-collapse, + .navbar-form { + border-color: @navbar-default-border; + } + + // Dropdown menu items + .navbar-nav { + // Remove background color from open dropdown + > .open > a { + &, + &:hover, + &:focus { + background-color: @navbar-default-link-active-bg; + color: @navbar-default-link-active-color; + } + } + + @media (max-width: @grid-float-breakpoint-max) { + // Dropdowns get custom display when collapsed + .open .dropdown-menu { + > li > a { + color: @navbar-default-link-color; + &:hover, + &:focus { + color: @navbar-default-link-hover-color; + background-color: @navbar-default-link-hover-bg; + } + } + > .active > a { + &, + &:hover, + &:focus { + color: @navbar-default-link-active-color; + background-color: @navbar-default-link-active-bg; + } + } + > .disabled > a { + &, + &:hover, + &:focus { + color: @navbar-default-link-disabled-color; + background-color: @navbar-default-link-disabled-bg; + } + } + } + } + } + + + // Links in navbars + // + // Add a class to ensure links outside the navbar nav are colored correctly. + + .navbar-link { + color: @navbar-default-link-color; + &:hover { + color: @navbar-default-link-hover-color; + } + } + + .btn-link { + color: @navbar-default-link-color; + &:hover, + &:focus { + color: @navbar-default-link-hover-color; + } + &[disabled], + fieldset[disabled] & { + &:hover, + &:focus { + color: @navbar-default-link-disabled-color; + } + } + } +} + +// Inverse navbar + +.navbar-inverse { + background-color: @navbar-inverse-bg; + border-color: @navbar-inverse-border; + + .navbar-brand { + color: @navbar-inverse-brand-color; + &:hover, + &:focus { + color: @navbar-inverse-brand-hover-color; + background-color: @navbar-inverse-brand-hover-bg; + } + } + + .navbar-text { + color: @navbar-inverse-color; + } + + .navbar-nav { + > li > a { + color: @navbar-inverse-link-color; + + &:hover, + &:focus { + color: @navbar-inverse-link-hover-color; + background-color: @navbar-inverse-link-hover-bg; + } + } + > .active > a { + &, + &:hover, + &:focus { + color: @navbar-inverse-link-active-color; + background-color: @navbar-inverse-link-active-bg; + } + } + > .disabled > a { + &, + &:hover, + &:focus { + color: @navbar-inverse-link-disabled-color; + background-color: @navbar-inverse-link-disabled-bg; + } + } + } + + // Darken the responsive nav toggle + .navbar-toggle { + border-color: @navbar-inverse-toggle-border-color; + &:hover, + &:focus { + background-color: @navbar-inverse-toggle-hover-bg; + } + .icon-bar { + background-color: @navbar-inverse-toggle-icon-bar-bg; + } + } + + .navbar-collapse, + .navbar-form { + border-color: darken(@navbar-inverse-bg, 7%); + } + + // Dropdowns + .navbar-nav { + > .open > a { + &, + &:hover, + &:focus { + background-color: @navbar-inverse-link-active-bg; + color: @navbar-inverse-link-active-color; + } + } + + @media (max-width: @grid-float-breakpoint-max) { + // Dropdowns get custom display + .open .dropdown-menu { + > .dropdown-header { + border-color: @navbar-inverse-border; + } + .divider { + background-color: @navbar-inverse-border; + } + > li > a { + color: @navbar-inverse-link-color; + &:hover, + &:focus { + color: @navbar-inverse-link-hover-color; + background-color: @navbar-inverse-link-hover-bg; + } + } + > .active > a { + &, + &:hover, + &:focus { + color: @navbar-inverse-link-active-color; + background-color: @navbar-inverse-link-active-bg; + } + } + > .disabled > a { + &, + &:hover, + &:focus { + color: @navbar-inverse-link-disabled-color; + background-color: @navbar-inverse-link-disabled-bg; + } + } + } + } + } + + .navbar-link { + color: @navbar-inverse-link-color; + &:hover { + color: @navbar-inverse-link-hover-color; + } + } + + .btn-link { + color: @navbar-inverse-link-color; + &:hover, + &:focus { + color: @navbar-inverse-link-hover-color; + } + &[disabled], + fieldset[disabled] & { + &:hover, + &:focus { + color: @navbar-inverse-link-disabled-color; + } + } + } +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/navs.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/navs.less new file mode 100644 index 000000000..a3d11b136 --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/navs.less @@ -0,0 +1,242 @@ +// +// Navs +// -------------------------------------------------- + + +// Base class +// -------------------------------------------------- + +.nav { + margin-bottom: 0; + padding-left: 0; // Override default ul/ol + list-style: none; + &:extend(.clearfix all); + + > li { + position: relative; + display: block; + + > a { + position: relative; + display: block; + padding: @nav-link-padding; + &:hover, + &:focus { + text-decoration: none; + background-color: @nav-link-hover-bg; + } + } + + // Disabled state sets text to gray and nukes hover/tab effects + &.disabled > a { + color: @nav-disabled-link-color; + + &:hover, + &:focus { + color: @nav-disabled-link-hover-color; + text-decoration: none; + background-color: transparent; + cursor: @cursor-disabled; + } + } + } + + // Open dropdowns + .open > a { + &, + &:hover, + &:focus { + background-color: @nav-link-hover-bg; + border-color: @link-color; + } + } + + // Nav dividers (deprecated with v3.0.1) + // + // This should have been removed in v3 with the dropping of `.nav-list`, but + // we missed it. We don't currently support this anywhere, but in the interest + // of maintaining backward compatibility in case you use it, it's deprecated. + .nav-divider { + .nav-divider(); + } + + // Prevent IE8 from misplacing imgs + // + // See https://github.com/h5bp/html5-boilerplate/issues/984#issuecomment-3985989 + > li > a > img { + max-width: none; + } +} + + +// Tabs +// ------------------------- + +// Give the tabs something to sit on +.nav-tabs { + border-bottom: 1px solid @nav-tabs-border-color; + > li { + float: left; + // Make the list-items overlay the bottom border + margin-bottom: -1px; + + // Actual tabs (as links) + > a { + margin-right: 2px; + line-height: @line-height-base; + border: 1px solid transparent; + border-radius: @border-radius-base @border-radius-base 0 0; + &:hover { + border-color: @nav-tabs-link-hover-border-color @nav-tabs-link-hover-border-color @nav-tabs-border-color; + } + } + + // Active state, and its :hover to override normal :hover + &.active > a { + &, + &:hover, + &:focus { + color: @nav-tabs-active-link-hover-color; + background-color: @nav-tabs-active-link-hover-bg; + border: 1px solid @nav-tabs-active-link-hover-border-color; + border-bottom-color: transparent; + cursor: default; + } + } + } + // pulling this in mainly for less shorthand + &.nav-justified { + .nav-justified(); + .nav-tabs-justified(); + } +} + + +// Pills +// ------------------------- +.nav-pills { + > li { + float: left; + + // Links rendered as pills + > a { + border-radius: @nav-pills-border-radius; + } + + li { + margin-left: 2px; + } + + // Active state + &.active > a { + &, + &:hover, + &:focus { + color: @nav-pills-active-link-hover-color; + background-color: @nav-pills-active-link-hover-bg; + } + } + } +} + + +// Stacked pills +.nav-stacked { + > li { + float: none; + + li { + margin-top: 2px; + margin-left: 0; // no need for this gap between nav items + } + } +} + + +// Nav variations +// -------------------------------------------------- + +// Justified nav links +// ------------------------- + +.nav-justified { + width: 100%; + + > li { + float: none; + > a { + text-align: center; + margin-bottom: 5px; + } + } + + > .dropdown .dropdown-menu { + top: auto; + left: auto; + } + + @media (min-width: @screen-sm-min) { + > li { + display: table-cell; + width: 1%; + > a { + margin-bottom: 0; + } + } + } +} + +// Move borders to anchors instead of bottom of list +// +// Mixin for adding on top the shared `.nav-justified` styles for our tabs +.nav-tabs-justified { + border-bottom: 0; + + > li > a { + // Override margin from .nav-tabs + margin-right: 0; + border-radius: @border-radius-base; + } + + > .active > a, + > .active > a:hover, + > .active > a:focus { + border: 1px solid @nav-tabs-justified-link-border-color; + } + + @media (min-width: @screen-sm-min) { + > li > a { + border-bottom: 1px solid @nav-tabs-justified-link-border-color; + border-radius: @border-radius-base @border-radius-base 0 0; + } + > .active > a, + > .active > a:hover, + > .active > a:focus { + border-bottom-color: @nav-tabs-justified-active-link-border-color; + } + } +} + + +// Tabbable tabs +// ------------------------- + +// Hide tabbable panes to start, show them when `.active` +.tab-content { + > .tab-pane { + display: none; + } + > .active { + display: block; + } +} + + +// Dropdowns +// ------------------------- + +// Specific dropdowns +.nav-tabs .dropdown-menu { + // make dropdown border overlap tab border + margin-top: -1px; + // Remove the top rounded corners here since there is a hard edge above the menu + .border-top-radius(0); +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/normalize.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/normalize.less new file mode 100644 index 000000000..9dddf73ad --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/normalize.less @@ -0,0 +1,424 @@ +/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */ + +// +// 1. Set default font family to sans-serif. +// 2. Prevent iOS and IE text size adjust after device orientation change, +// without disabling user zoom. +// + +html { + font-family: sans-serif; // 1 + -ms-text-size-adjust: 100%; // 2 + -webkit-text-size-adjust: 100%; // 2 +} + +// +// Remove default margin. +// + +body { + margin: 0; +} + +// HTML5 display definitions +// ========================================================================== + +// +// Correct `block` display not defined for any HTML5 element in IE 8/9. +// Correct `block` display not defined for `details` or `summary` in IE 10/11 +// and Firefox. +// Correct `block` display not defined for `main` in IE 11. +// + +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +main, +menu, +nav, +section, +summary { + display: block; +} + +// +// 1. Correct `inline-block` display not defined in IE 8/9. +// 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. +// + +audio, +canvas, +progress, +video { + display: inline-block; // 1 + vertical-align: baseline; // 2 +} + +// +// Prevent modern browsers from displaying `audio` without controls. +// Remove excess height in iOS 5 devices. +// + +audio:not([controls]) { + display: none; + height: 0; +} + +// +// Address `[hidden]` styling not present in IE 8/9/10. +// Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22. +// + +[hidden], +template { + display: none; +} + +// Links +// ========================================================================== + +// +// Remove the gray background color from active links in IE 10. +// + +a { + background-color: transparent; +} + +// +// Improve readability of focused elements when they are also in an +// active/hover state. +// + +a:active, +a:hover { + outline: 0; +} + +// Text-level semantics +// ========================================================================== + +// +// Address styling not present in IE 8/9/10/11, Safari, and Chrome. +// + +abbr[title] { + border-bottom: 1px dotted; +} + +// +// Address style set to `bolder` in Firefox 4+, Safari, and Chrome. +// + +b, +strong { + font-weight: bold; +} + +// +// Address styling not present in Safari and Chrome. +// + +dfn { + font-style: italic; +} + +// +// Address variable `h1` font-size and margin within `section` and `article` +// contexts in Firefox 4+, Safari, and Chrome. +// + +h1 { + font-size: 2em; + margin: 0.67em 0; +} + +// +// Address styling not present in IE 8/9. +// + +mark { + background: #ff0; + color: #000; +} + +// +// Address inconsistent and variable font size in all browsers. +// + +small { + font-size: 80%; +} + +// +// Prevent `sub` and `sup` affecting `line-height` in all browsers. +// + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sup { + top: -0.5em; +} + +sub { + bottom: -0.25em; +} + +// Embedded content +// ========================================================================== + +// +// Remove border when inside `a` element in IE 8/9/10. +// + +img { + border: 0; +} + +// +// Correct overflow not hidden in IE 9/10/11. +// + +svg:not(:root) { + overflow: hidden; +} + +// Grouping content +// ========================================================================== + +// +// Address margin not present in IE 8/9 and Safari. +// + +figure { + margin: 1em 40px; +} + +// +// Address differences between Firefox and other browsers. +// + +hr { + box-sizing: content-box; + height: 0; +} + +// +// Contain overflow in all browsers. +// + +pre { + overflow: auto; +} + +// +// Address odd `em`-unit font size rendering in all browsers. +// + +code, +kbd, +pre, +samp { + font-family: monospace, monospace; + font-size: 1em; +} + +// Forms +// ========================================================================== + +// +// Known limitation: by default, Chrome and Safari on OS X allow very limited +// styling of `select`, unless a `border` property is set. +// + +// +// 1. Correct color not being inherited. +// Known issue: affects color of disabled elements. +// 2. Correct font properties not being inherited. +// 3. Address margins set differently in Firefox 4+, Safari, and Chrome. +// + +button, +input, +optgroup, +select, +textarea { + color: inherit; // 1 + font: inherit; // 2 + margin: 0; // 3 +} + +// +// Address `overflow` set to `hidden` in IE 8/9/10/11. +// + +button { + overflow: visible; +} + +// +// Address inconsistent `text-transform` inheritance for `button` and `select`. +// All other form control elements do not inherit `text-transform` values. +// Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. +// Correct `select` style inheritance in Firefox. +// + +button, +select { + text-transform: none; +} + +// +// 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` +// and `video` controls. +// 2. Correct inability to style clickable `input` types in iOS. +// 3. Improve usability and consistency of cursor style between image-type +// `input` and others. +// + +button, +html input[type="button"], // 1 +input[type="reset"], +input[type="submit"] { + -webkit-appearance: button; // 2 + cursor: pointer; // 3 +} + +// +// Re-set default cursor for disabled elements. +// + +button[disabled], +html input[disabled] { + cursor: default; +} + +// +// Remove inner padding and border in Firefox 4+. +// + +button::-moz-focus-inner, +input::-moz-focus-inner { + border: 0; + padding: 0; +} + +// +// Address Firefox 4+ setting `line-height` on `input` using `!important` in +// the UA stylesheet. +// + +input { + line-height: normal; +} + +// +// It's recommended that you don't attempt to style these elements. +// Firefox's implementation doesn't respect box-sizing, padding, or width. +// +// 1. Address box sizing set to `content-box` in IE 8/9/10. +// 2. Remove excess padding in IE 8/9/10. +// + +input[type="checkbox"], +input[type="radio"] { + box-sizing: border-box; // 1 + padding: 0; // 2 +} + +// +// Fix the cursor style for Chrome's increment/decrement buttons. For certain +// `font-size` values of the `input`, it causes the cursor style of the +// decrement button to change from `default` to `text`. +// + +input[type="number"]::-webkit-inner-spin-button, +input[type="number"]::-webkit-outer-spin-button { + height: auto; +} + +// +// 1. Address `appearance` set to `searchfield` in Safari and Chrome. +// 2. Address `box-sizing` set to `border-box` in Safari and Chrome. +// + +input[type="search"] { + -webkit-appearance: textfield; // 1 + box-sizing: content-box; //2 +} + +// +// Remove inner padding and search cancel button in Safari and Chrome on OS X. +// Safari (but not Chrome) clips the cancel button when the search input has +// padding (and `textfield` appearance). +// + +input[type="search"]::-webkit-search-cancel-button, +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +// +// Define consistent border, margin, and padding. +// + +fieldset { + border: 1px solid #c0c0c0; + margin: 0 2px; + padding: 0.35em 0.625em 0.75em; +} + +// +// 1. Correct `color` not being inherited in IE 8/9/10/11. +// 2. Remove padding so people aren't caught out if they zero out fieldsets. +// + +legend { + border: 0; // 1 + padding: 0; // 2 +} + +// +// Remove default vertical scrollbar in IE 8/9/10/11. +// + +textarea { + overflow: auto; +} + +// +// Don't inherit the `font-weight` (applied by a rule above). +// NOTE: the default cannot safely be changed in Chrome and Safari on OS X. +// + +optgroup { + font-weight: bold; +} + +// Tables +// ========================================================================== + +// +// Remove most spacing between table cells. +// + +table { + border-collapse: collapse; + border-spacing: 0; +} + +td, +th { + padding: 0; +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/pager.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/pager.less new file mode 100644 index 000000000..41abaaadc --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/pager.less @@ -0,0 +1,54 @@ +// +// Pager pagination +// -------------------------------------------------- + + +.pager { + padding-left: 0; + margin: @line-height-computed 0; + list-style: none; + text-align: center; + &:extend(.clearfix all); + li { + display: inline; + > a, + > span { + display: inline-block; + padding: 5px 14px; + background-color: @pager-bg; + border: 1px solid @pager-border; + border-radius: @pager-border-radius; + } + + > a:hover, + > a:focus { + text-decoration: none; + background-color: @pager-hover-bg; + } + } + + .next { + > a, + > span { + float: right; + } + } + + .previous { + > a, + > span { + float: left; + } + } + + .disabled { + > a, + > a:hover, + > a:focus, + > span { + color: @pager-disabled-color; + background-color: @pager-bg; + cursor: @cursor-disabled; + } + } +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/pagination.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/pagination.less new file mode 100644 index 000000000..31f77aae4 --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/pagination.less @@ -0,0 +1,89 @@ +// +// Pagination (multiple pages) +// -------------------------------------------------- +.pagination { + display: inline-block; + padding-left: 0; + margin: @line-height-computed 0; + border-radius: @border-radius-base; + + > li { + display: inline; // Remove list-style and block-level defaults + > a, + > span { + position: relative; + float: left; // Collapse white-space + padding: @padding-base-vertical @padding-base-horizontal; + line-height: @line-height-base; + text-decoration: none; + color: @pagination-color; + background-color: @pagination-bg; + border: 1px solid @pagination-border; + margin-left: -1px; + } + &:first-child { + > a, + > span { + margin-left: 0; + .border-left-radius(@border-radius-base); + } + } + &:last-child { + > a, + > span { + .border-right-radius(@border-radius-base); + } + } + } + + > li > a, + > li > span { + &:hover, + &:focus { + z-index: 2; + color: @pagination-hover-color; + background-color: @pagination-hover-bg; + border-color: @pagination-hover-border; + } + } + + > .active > a, + > .active > span { + &, + &:hover, + &:focus { + z-index: 3; + color: @pagination-active-color; + background-color: @pagination-active-bg; + border-color: @pagination-active-border; + cursor: default; + } + } + + > .disabled { + > span, + > span:hover, + > span:focus, + > a, + > a:hover, + > a:focus { + color: @pagination-disabled-color; + background-color: @pagination-disabled-bg; + border-color: @pagination-disabled-border; + cursor: @cursor-disabled; + } + } +} + +// Sizing +// -------------------------------------------------- + +// Large +.pagination-lg { + .pagination-size(@padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @border-radius-large); +} + +// Small +.pagination-sm { + .pagination-size(@padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @border-radius-small); +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/panels.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/panels.less new file mode 100644 index 000000000..425eb5e64 --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/panels.less @@ -0,0 +1,271 @@ +// +// Panels +// -------------------------------------------------- + + +// Base class +.panel { + margin-bottom: @line-height-computed; + background-color: @panel-bg; + border: 1px solid transparent; + border-radius: @panel-border-radius; + .box-shadow(0 1px 1px rgba(0,0,0,.05)); +} + +// Panel contents +.panel-body { + padding: @panel-body-padding; + &:extend(.clearfix all); +} + +// Optional heading +.panel-heading { + padding: @panel-heading-padding; + border-bottom: 1px solid transparent; + .border-top-radius((@panel-border-radius - 1)); + + > .dropdown .dropdown-toggle { + color: inherit; + } +} + +// Within heading, strip any `h*` tag of its default margins for spacing. +.panel-title { + margin-top: 0; + margin-bottom: 0; + font-size: ceil((@font-size-base * 1.125)); + color: inherit; + + > a, + > small, + > .small, + > small > a, + > .small > a { + color: inherit; + } +} + +// Optional footer (stays gray in every modifier class) +.panel-footer { + padding: @panel-footer-padding; + background-color: @panel-footer-bg; + border-top: 1px solid @panel-inner-border; + .border-bottom-radius((@panel-border-radius - 1)); +} + + +// List groups in panels +// +// By default, space out list group content from panel headings to account for +// any kind of custom content between the two. + +.panel { + > .list-group, + > .panel-collapse > .list-group { + margin-bottom: 0; + + .list-group-item { + border-width: 1px 0; + border-radius: 0; + } + + // Add border top radius for first one + &:first-child { + .list-group-item:first-child { + border-top: 0; + .border-top-radius((@panel-border-radius - 1)); + } + } + + // Add border bottom radius for last one + &:last-child { + .list-group-item:last-child { + border-bottom: 0; + .border-bottom-radius((@panel-border-radius - 1)); + } + } + } + > .panel-heading + .panel-collapse > .list-group { + .list-group-item:first-child { + .border-top-radius(0); + } + } +} +// Collapse space between when there's no additional content. +.panel-heading + .list-group { + .list-group-item:first-child { + border-top-width: 0; + } +} +.list-group + .panel-footer { + border-top-width: 0; +} + +// Tables in panels +// +// Place a non-bordered `.table` within a panel (not within a `.panel-body`) and +// watch it go full width. + +.panel { + > .table, + > .table-responsive > .table, + > .panel-collapse > .table { + margin-bottom: 0; + + caption { + padding-left: @panel-body-padding; + padding-right: @panel-body-padding; + } + } + // Add border top radius for first one + > .table:first-child, + > .table-responsive:first-child > .table:first-child { + .border-top-radius((@panel-border-radius - 1)); + + > thead:first-child, + > tbody:first-child { + > tr:first-child { + border-top-left-radius: (@panel-border-radius - 1); + border-top-right-radius: (@panel-border-radius - 1); + + td:first-child, + th:first-child { + border-top-left-radius: (@panel-border-radius - 1); + } + td:last-child, + th:last-child { + border-top-right-radius: (@panel-border-radius - 1); + } + } + } + } + // Add border bottom radius for last one + > .table:last-child, + > .table-responsive:last-child > .table:last-child { + .border-bottom-radius((@panel-border-radius - 1)); + + > tbody:last-child, + > tfoot:last-child { + > tr:last-child { + border-bottom-left-radius: (@panel-border-radius - 1); + border-bottom-right-radius: (@panel-border-radius - 1); + + td:first-child, + th:first-child { + border-bottom-left-radius: (@panel-border-radius - 1); + } + td:last-child, + th:last-child { + border-bottom-right-radius: (@panel-border-radius - 1); + } + } + } + } + > .panel-body + .table, + > .panel-body + .table-responsive, + > .table + .panel-body, + > .table-responsive + .panel-body { + border-top: 1px solid @table-border-color; + } + > .table > tbody:first-child > tr:first-child th, + > .table > tbody:first-child > tr:first-child td { + border-top: 0; + } + > .table-bordered, + > .table-responsive > .table-bordered { + border: 0; + > thead, + > tbody, + > tfoot { + > tr { + > th:first-child, + > td:first-child { + border-left: 0; + } + > th:last-child, + > td:last-child { + border-right: 0; + } + } + } + > thead, + > tbody { + > tr:first-child { + > td, + > th { + border-bottom: 0; + } + } + } + > tbody, + > tfoot { + > tr:last-child { + > td, + > th { + border-bottom: 0; + } + } + } + } + > .table-responsive { + border: 0; + margin-bottom: 0; + } +} + + +// Collapsable panels (aka, accordion) +// +// Wrap a series of panels in `.panel-group` to turn them into an accordion with +// the help of our collapse JavaScript plugin. + +.panel-group { + margin-bottom: @line-height-computed; + + // Tighten up margin so it's only between panels + .panel { + margin-bottom: 0; + border-radius: @panel-border-radius; + + + .panel { + margin-top: 5px; + } + } + + .panel-heading { + border-bottom: 0; + + + .panel-collapse > .panel-body, + + .panel-collapse > .list-group { + border-top: 1px solid @panel-inner-border; + } + } + + .panel-footer { + border-top: 0; + + .panel-collapse .panel-body { + border-bottom: 1px solid @panel-inner-border; + } + } +} + + +// Contextual variations +.panel-default { + .panel-variant(@panel-default-border; @panel-default-text; @panel-default-heading-bg; @panel-default-border); +} +.panel-primary { + .panel-variant(@panel-primary-border; @panel-primary-text; @panel-primary-heading-bg; @panel-primary-border); +} +.panel-success { + .panel-variant(@panel-success-border; @panel-success-text; @panel-success-heading-bg; @panel-success-border); +} +.panel-info { + .panel-variant(@panel-info-border; @panel-info-text; @panel-info-heading-bg; @panel-info-border); +} +.panel-warning { + .panel-variant(@panel-warning-border; @panel-warning-text; @panel-warning-heading-bg; @panel-warning-border); +} +.panel-danger { + .panel-variant(@panel-danger-border; @panel-danger-text; @panel-danger-heading-bg; @panel-danger-border); +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/popovers.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/popovers.less new file mode 100644 index 000000000..3a62a6455 --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/popovers.less @@ -0,0 +1,131 @@ +// +// Popovers +// -------------------------------------------------- + + +.popover { + position: absolute; + top: 0; + left: 0; + z-index: @zindex-popover; + display: none; + max-width: @popover-max-width; + padding: 1px; + // Our parent element can be arbitrary since popovers are by default inserted as a sibling of their target element. + // So reset our font and text properties to avoid inheriting weird values. + .reset-text(); + font-size: @font-size-base; + + background-color: @popover-bg; + background-clip: padding-box; + border: 1px solid @popover-fallback-border-color; + border: 1px solid @popover-border-color; + border-radius: @border-radius-large; + .box-shadow(0 5px 10px rgba(0,0,0,.2)); + + // Offset the popover to account for the popover arrow + &.top { margin-top: -@popover-arrow-width; } + &.right { margin-left: @popover-arrow-width; } + &.bottom { margin-top: @popover-arrow-width; } + &.left { margin-left: -@popover-arrow-width; } +} + +.popover-title { + margin: 0; // reset heading margin + padding: 8px 14px; + font-size: @font-size-base; + background-color: @popover-title-bg; + border-bottom: 1px solid darken(@popover-title-bg, 5%); + border-radius: (@border-radius-large - 1) (@border-radius-large - 1) 0 0; +} + +.popover-content { + padding: 9px 14px; +} + +// Arrows +// +// .arrow is outer, .arrow:after is inner + +.popover > .arrow { + &, + &:after { + position: absolute; + display: block; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; + } +} +.popover > .arrow { + border-width: @popover-arrow-outer-width; +} +.popover > .arrow:after { + border-width: @popover-arrow-width; + content: ""; +} + +.popover { + &.top > .arrow { + left: 50%; + margin-left: -@popover-arrow-outer-width; + border-bottom-width: 0; + border-top-color: @popover-arrow-outer-fallback-color; // IE8 fallback + border-top-color: @popover-arrow-outer-color; + bottom: -@popover-arrow-outer-width; + &:after { + content: " "; + bottom: 1px; + margin-left: -@popover-arrow-width; + border-bottom-width: 0; + border-top-color: @popover-arrow-color; + } + } + &.right > .arrow { + top: 50%; + left: -@popover-arrow-outer-width; + margin-top: -@popover-arrow-outer-width; + border-left-width: 0; + border-right-color: @popover-arrow-outer-fallback-color; // IE8 fallback + border-right-color: @popover-arrow-outer-color; + &:after { + content: " "; + left: 1px; + bottom: -@popover-arrow-width; + border-left-width: 0; + border-right-color: @popover-arrow-color; + } + } + &.bottom > .arrow { + left: 50%; + margin-left: -@popover-arrow-outer-width; + border-top-width: 0; + border-bottom-color: @popover-arrow-outer-fallback-color; // IE8 fallback + border-bottom-color: @popover-arrow-outer-color; + top: -@popover-arrow-outer-width; + &:after { + content: " "; + top: 1px; + margin-left: -@popover-arrow-width; + border-top-width: 0; + border-bottom-color: @popover-arrow-color; + } + } + + &.left > .arrow { + top: 50%; + right: -@popover-arrow-outer-width; + margin-top: -@popover-arrow-outer-width; + border-right-width: 0; + border-left-color: @popover-arrow-outer-fallback-color; // IE8 fallback + border-left-color: @popover-arrow-outer-color; + &:after { + content: " "; + right: 1px; + border-right-width: 0; + border-left-color: @popover-arrow-color; + bottom: -@popover-arrow-width; + } + } +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/print.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/print.less new file mode 100644 index 000000000..66e54ab48 --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/print.less @@ -0,0 +1,101 @@ +/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */ + +// ========================================================================== +// Print styles. +// Inlined to avoid the additional HTTP request: h5bp.com/r +// ========================================================================== + +@media print { + *, + *:before, + *:after { + background: transparent !important; + color: #000 !important; // Black prints faster: h5bp.com/s + box-shadow: none !important; + text-shadow: none !important; + } + + a, + a:visited { + text-decoration: underline; + } + + a[href]:after { + content: " (" attr(href) ")"; + } + + abbr[title]:after { + content: " (" attr(title) ")"; + } + + // Don't show links that are fragment identifiers, + // or use the `javascript:` pseudo protocol + a[href^="#"]:after, + a[href^="javascript:"]:after { + content: ""; + } + + pre, + blockquote { + border: 1px solid #999; + page-break-inside: avoid; + } + + thead { + display: table-header-group; // h5bp.com/t + } + + tr, + img { + page-break-inside: avoid; + } + + img { + max-width: 100% !important; + } + + p, + h2, + h3 { + orphans: 3; + widows: 3; + } + + h2, + h3 { + page-break-after: avoid; + } + + // Bootstrap specific changes start + + // Bootstrap components + .navbar { + display: none; + } + .btn, + .dropup > .btn { + > .caret { + border-top-color: #000 !important; + } + } + .label { + border: 1px solid #000; + } + + .table { + border-collapse: collapse !important; + + td, + th { + background-color: #fff !important; + } + } + .table-bordered { + th, + td { + border: 1px solid #ddd !important; + } + } + + // Bootstrap specific changes end +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/progress-bars.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/progress-bars.less new file mode 100644 index 000000000..8868a1fee --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/progress-bars.less @@ -0,0 +1,87 @@ +// +// Progress bars +// -------------------------------------------------- + + +// Bar animations +// ------------------------- + +// WebKit +@-webkit-keyframes progress-bar-stripes { + from { background-position: 40px 0; } + to { background-position: 0 0; } +} + +// Spec and IE10+ +@keyframes progress-bar-stripes { + from { background-position: 40px 0; } + to { background-position: 0 0; } +} + + +// Bar itself +// ------------------------- + +// Outer container +.progress { + overflow: hidden; + height: @line-height-computed; + margin-bottom: @line-height-computed; + background-color: @progress-bg; + border-radius: @progress-border-radius; + .box-shadow(inset 0 1px 2px rgba(0,0,0,.1)); +} + +// Bar of progress +.progress-bar { + float: left; + width: 0%; + height: 100%; + font-size: @font-size-small; + line-height: @line-height-computed; + color: @progress-bar-color; + text-align: center; + background-color: @progress-bar-bg; + .box-shadow(inset 0 -1px 0 rgba(0,0,0,.15)); + .transition(width .6s ease); +} + +// Striped bars +// +// `.progress-striped .progress-bar` is deprecated as of v3.2.0 in favor of the +// `.progress-bar-striped` class, which you just add to an existing +// `.progress-bar`. +.progress-striped .progress-bar, +.progress-bar-striped { + #gradient > .striped(); + background-size: 40px 40px; +} + +// Call animation for the active one +// +// `.progress.active .progress-bar` is deprecated as of v3.2.0 in favor of the +// `.progress-bar.active` approach. +.progress.active .progress-bar, +.progress-bar.active { + .animation(progress-bar-stripes 2s linear infinite); +} + + +// Variations +// ------------------------- + +.progress-bar-success { + .progress-bar-variant(@progress-bar-success-bg); +} + +.progress-bar-info { + .progress-bar-variant(@progress-bar-info-bg); +} + +.progress-bar-warning { + .progress-bar-variant(@progress-bar-warning-bg); +} + +.progress-bar-danger { + .progress-bar-variant(@progress-bar-danger-bg); +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/responsive-embed.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/responsive-embed.less new file mode 100644 index 000000000..080a5118f --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/responsive-embed.less @@ -0,0 +1,35 @@ +// Embeds responsive +// +// Credit: Nicolas Gallagher and SUIT CSS. + +.embed-responsive { + position: relative; + display: block; + height: 0; + padding: 0; + overflow: hidden; + + .embed-responsive-item, + iframe, + embed, + object, + video { + position: absolute; + top: 0; + left: 0; + bottom: 0; + height: 100%; + width: 100%; + border: 0; + } +} + +// Modifier class for 16:9 aspect ratio +.embed-responsive-16by9 { + padding-bottom: 56.25%; +} + +// Modifier class for 4:3 aspect ratio +.embed-responsive-4by3 { + padding-bottom: 75%; +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/responsive-utilities.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/responsive-utilities.less new file mode 100644 index 000000000..b1db31d7b --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/responsive-utilities.less @@ -0,0 +1,194 @@ +// +// Responsive: Utility classes +// -------------------------------------------------- + + +// IE10 in Windows (Phone) 8 +// +// Support for responsive views via media queries is kind of borked in IE10, for +// Surface/desktop in split view and for Windows Phone 8. This particular fix +// must be accompanied by a snippet of JavaScript to sniff the user agent and +// apply some conditional CSS to *only* the Surface/desktop Windows 8. Look at +// our Getting Started page for more information on this bug. +// +// For more information, see the following: +// +// Issue: https://github.com/twbs/bootstrap/issues/10497 +// Docs: http://getbootstrap.com/getting-started/#support-ie10-width +// Source: http://timkadlec.com/2013/01/windows-phone-8-and-device-width/ +// Source: http://timkadlec.com/2012/10/ie10-snap-mode-and-responsive-design/ + +@-ms-viewport { + width: device-width; +} + + +// Visibility utilities +// Note: Deprecated .visible-xs, .visible-sm, .visible-md, and .visible-lg as of v3.2.0 +.visible-xs, +.visible-sm, +.visible-md, +.visible-lg { + .responsive-invisibility(); +} + +.visible-xs-block, +.visible-xs-inline, +.visible-xs-inline-block, +.visible-sm-block, +.visible-sm-inline, +.visible-sm-inline-block, +.visible-md-block, +.visible-md-inline, +.visible-md-inline-block, +.visible-lg-block, +.visible-lg-inline, +.visible-lg-inline-block { + display: none !important; +} + +.visible-xs { + @media (max-width: @screen-xs-max) { + .responsive-visibility(); + } +} +.visible-xs-block { + @media (max-width: @screen-xs-max) { + display: block !important; + } +} +.visible-xs-inline { + @media (max-width: @screen-xs-max) { + display: inline !important; + } +} +.visible-xs-inline-block { + @media (max-width: @screen-xs-max) { + display: inline-block !important; + } +} + +.visible-sm { + @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) { + .responsive-visibility(); + } +} +.visible-sm-block { + @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) { + display: block !important; + } +} +.visible-sm-inline { + @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) { + display: inline !important; + } +} +.visible-sm-inline-block { + @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) { + display: inline-block !important; + } +} + +.visible-md { + @media (min-width: @screen-md-min) and (max-width: @screen-md-max) { + .responsive-visibility(); + } +} +.visible-md-block { + @media (min-width: @screen-md-min) and (max-width: @screen-md-max) { + display: block !important; + } +} +.visible-md-inline { + @media (min-width: @screen-md-min) and (max-width: @screen-md-max) { + display: inline !important; + } +} +.visible-md-inline-block { + @media (min-width: @screen-md-min) and (max-width: @screen-md-max) { + display: inline-block !important; + } +} + +.visible-lg { + @media (min-width: @screen-lg-min) { + .responsive-visibility(); + } +} +.visible-lg-block { + @media (min-width: @screen-lg-min) { + display: block !important; + } +} +.visible-lg-inline { + @media (min-width: @screen-lg-min) { + display: inline !important; + } +} +.visible-lg-inline-block { + @media (min-width: @screen-lg-min) { + display: inline-block !important; + } +} + +.hidden-xs { + @media (max-width: @screen-xs-max) { + .responsive-invisibility(); + } +} +.hidden-sm { + @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) { + .responsive-invisibility(); + } +} +.hidden-md { + @media (min-width: @screen-md-min) and (max-width: @screen-md-max) { + .responsive-invisibility(); + } +} +.hidden-lg { + @media (min-width: @screen-lg-min) { + .responsive-invisibility(); + } +} + + +// Print utilities +// +// Media queries are placed on the inside to be mixin-friendly. + +// Note: Deprecated .visible-print as of v3.2.0 +.visible-print { + .responsive-invisibility(); + + @media print { + .responsive-visibility(); + } +} +.visible-print-block { + display: none !important; + + @media print { + display: block !important; + } +} +.visible-print-inline { + display: none !important; + + @media print { + display: inline !important; + } +} +.visible-print-inline-block { + display: none !important; + + @media print { + display: inline-block !important; + } +} + +.hidden-print { + @media print { + .responsive-invisibility(); + } +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/scaffolding.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/scaffolding.less new file mode 100644 index 000000000..1929bfc5c --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/scaffolding.less @@ -0,0 +1,161 @@ +// +// Scaffolding +// -------------------------------------------------- + + +// Reset the box-sizing +// +// Heads up! This reset may cause conflicts with some third-party widgets. +// For recommendations on resolving such conflicts, see +// http://getbootstrap.com/getting-started/#third-box-sizing +* { + .box-sizing(border-box); +} +*:before, +*:after { + .box-sizing(border-box); +} + + +// Body reset + +html { + font-size: 10px; + -webkit-tap-highlight-color: rgba(0,0,0,0); +} + +body { + font-family: @font-family-base; + font-size: @font-size-base; + line-height: @line-height-base; + color: @text-color; + background-color: @body-bg; +} + +// Reset fonts for relevant elements +input, +button, +select, +textarea { + font-family: inherit; + font-size: inherit; + line-height: inherit; +} + + +// Links + +a { + color: @link-color; + text-decoration: none; + + &:hover, + &:focus { + color: @link-hover-color; + text-decoration: @link-hover-decoration; + } + + &:focus { + .tab-focus(); + } +} + + +// Figures +// +// We reset this here because previously Normalize had no `figure` margins. This +// ensures we don't break anyone's use of the element. + +figure { + margin: 0; +} + + +// Images + +img { + vertical-align: middle; +} + +// Responsive images (ensure images don't scale beyond their parents) +.img-responsive { + .img-responsive(); +} + +// Rounded corners +.img-rounded { + border-radius: @border-radius-large; +} + +// Image thumbnails +// +// Heads up! This is mixin-ed into thumbnails.less for `.thumbnail`. +.img-thumbnail { + padding: @thumbnail-padding; + line-height: @line-height-base; + background-color: @thumbnail-bg; + border: 1px solid @thumbnail-border; + border-radius: @thumbnail-border-radius; + .transition(all .2s ease-in-out); + + // Keep them at most 100% wide + .img-responsive(inline-block); +} + +// Perfect circle +.img-circle { + border-radius: 50%; // set radius in percents +} + + +// Horizontal rules + +hr { + margin-top: @line-height-computed; + margin-bottom: @line-height-computed; + border: 0; + border-top: 1px solid @hr-border; +} + + +// Only display content to screen readers +// +// See: http://a11yproject.com/posts/how-to-hide-content/ + +.sr-only { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + overflow: hidden; + clip: rect(0,0,0,0); + border: 0; +} + +// Use in conjunction with .sr-only to only display content when it's focused. +// Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1 +// Credit: HTML5 Boilerplate + +.sr-only-focusable { + &:active, + &:focus { + position: static; + width: auto; + height: auto; + margin: 0; + overflow: visible; + clip: auto; + } +} + + +// iOS "clickable elements" fix for role="button" +// +// Fixes "clickability" issue (and more generally, the firing of events such as focus as well) +// for traditionally non-focusable elements with role="button" +// see https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile + +[role="button"] { + cursor: pointer; +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/tables.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/tables.less new file mode 100644 index 000000000..2242c0368 --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/tables.less @@ -0,0 +1,234 @@ +// +// Tables +// -------------------------------------------------- + + +table { + background-color: @table-bg; +} +caption { + padding-top: @table-cell-padding; + padding-bottom: @table-cell-padding; + color: @text-muted; + text-align: left; +} +th { + text-align: left; +} + + +// Baseline styles + +.table { + width: 100%; + max-width: 100%; + margin-bottom: @line-height-computed; + // Cells + > thead, + > tbody, + > tfoot { + > tr { + > th, + > td { + padding: @table-cell-padding; + line-height: @line-height-base; + vertical-align: top; + border-top: 1px solid @table-border-color; + } + } + } + // Bottom align for column headings + > thead > tr > th { + vertical-align: bottom; + border-bottom: 2px solid @table-border-color; + } + // Remove top border from thead by default + > caption + thead, + > colgroup + thead, + > thead:first-child { + > tr:first-child { + > th, + > td { + border-top: 0; + } + } + } + // Account for multiple tbody instances + > tbody + tbody { + border-top: 2px solid @table-border-color; + } + + // Nesting + .table { + background-color: @body-bg; + } +} + + +// Condensed table w/ half padding + +.table-condensed { + > thead, + > tbody, + > tfoot { + > tr { + > th, + > td { + padding: @table-condensed-cell-padding; + } + } + } +} + + +// Bordered version +// +// Add borders all around the table and between all the columns. + +.table-bordered { + border: 1px solid @table-border-color; + > thead, + > tbody, + > tfoot { + > tr { + > th, + > td { + border: 1px solid @table-border-color; + } + } + } + > thead > tr { + > th, + > td { + border-bottom-width: 2px; + } + } +} + + +// Zebra-striping +// +// Default zebra-stripe styles (alternating gray and transparent backgrounds) + +.table-striped { + > tbody > tr:nth-of-type(odd) { + background-color: @table-bg-accent; + } +} + + +// Hover effect +// +// Placed here since it has to come after the potential zebra striping + +.table-hover { + > tbody > tr:hover { + background-color: @table-bg-hover; + } +} + + +// Table cell sizing +// +// Reset default table behavior + +table col[class*="col-"] { + position: static; // Prevent border hiding in Firefox and IE9-11 (see https://github.com/twbs/bootstrap/issues/11623) + float: none; + display: table-column; +} +table { + td, + th { + &[class*="col-"] { + position: static; // Prevent border hiding in Firefox and IE9-11 (see https://github.com/twbs/bootstrap/issues/11623) + float: none; + display: table-cell; + } + } +} + + +// Table backgrounds +// +// Exact selectors below required to override `.table-striped` and prevent +// inheritance to nested tables. + +// Generate the contextual variants +.table-row-variant(active; @table-bg-active); +.table-row-variant(success; @state-success-bg); +.table-row-variant(info; @state-info-bg); +.table-row-variant(warning; @state-warning-bg); +.table-row-variant(danger; @state-danger-bg); + + +// Responsive tables +// +// Wrap your tables in `.table-responsive` and we'll make them mobile friendly +// by enabling horizontal scrolling. Only applies <768px. Everything above that +// will display normally. + +.table-responsive { + overflow-x: auto; + min-height: 0.01%; // Workaround for IE9 bug (see https://github.com/twbs/bootstrap/issues/14837) + + @media screen and (max-width: @screen-xs-max) { + width: 100%; + margin-bottom: (@line-height-computed * 0.75); + overflow-y: hidden; + -ms-overflow-style: -ms-autohiding-scrollbar; + border: 1px solid @table-border-color; + + // Tighten up spacing + > .table { + margin-bottom: 0; + + // Ensure the content doesn't wrap + > thead, + > tbody, + > tfoot { + > tr { + > th, + > td { + white-space: nowrap; + } + } + } + } + + // Special overrides for the bordered tables + > .table-bordered { + border: 0; + + // Nuke the appropriate borders so that the parent can handle them + > thead, + > tbody, + > tfoot { + > tr { + > th:first-child, + > td:first-child { + border-left: 0; + } + > th:last-child, + > td:last-child { + border-right: 0; + } + } + } + + // Only nuke the last row's bottom-border in `tbody` and `tfoot` since + // chances are there will be only one `tr` in a `thead` and that would + // remove the border altogether. + > tbody, + > tfoot { + > tr:last-child { + > th, + > td { + border-bottom: 0; + } + } + } + + } + } +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/theme.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/theme.less new file mode 100644 index 000000000..8371872b0 --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/theme.less @@ -0,0 +1,291 @@ +/*! + * Bootstrap v3.3.5 (http://getbootstrap.com) + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ + +// +// Load core variables and mixins +// -------------------------------------------------- + +@import "variables.less"; +@import "mixins.less"; + + +// +// Buttons +// -------------------------------------------------- + +// Common styles +.btn-default, +.btn-primary, +.btn-success, +.btn-info, +.btn-warning, +.btn-danger { + text-shadow: 0 -1px 0 rgba(0,0,0,.2); + @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 1px rgba(0,0,0,.075); + .box-shadow(@shadow); + + // Reset the shadow + &:active, + &.active { + .box-shadow(inset 0 3px 5px rgba(0,0,0,.125)); + } + + &.disabled, + &[disabled], + fieldset[disabled] & { + .box-shadow(none); + } + + .badge { + text-shadow: none; + } +} + +// Mixin for generating new styles +.btn-styles(@btn-color: #555) { + #gradient > .vertical(@start-color: @btn-color; @end-color: darken(@btn-color, 12%)); + .reset-filter(); // Disable gradients for IE9 because filter bleeds through rounded corners; see https://github.com/twbs/bootstrap/issues/10620 + background-repeat: repeat-x; + border-color: darken(@btn-color, 14%); + + &:hover, + &:focus { + background-color: darken(@btn-color, 12%); + background-position: 0 -15px; + } + + &:active, + &.active { + background-color: darken(@btn-color, 12%); + border-color: darken(@btn-color, 14%); + } + + &.disabled, + &[disabled], + fieldset[disabled] & { + &, + &:hover, + &:focus, + &.focus, + &:active, + &.active { + background-color: darken(@btn-color, 12%); + background-image: none; + } + } +} + +// Common styles +.btn { + // Remove the gradient for the pressed/active state + &:active, + &.active { + background-image: none; + } +} + +// Apply the mixin to the buttons +.btn-default { .btn-styles(@btn-default-bg); text-shadow: 0 1px 0 #fff; border-color: #ccc; } +.btn-primary { .btn-styles(@btn-primary-bg); } +.btn-success { .btn-styles(@btn-success-bg); } +.btn-info { .btn-styles(@btn-info-bg); } +.btn-warning { .btn-styles(@btn-warning-bg); } +.btn-danger { .btn-styles(@btn-danger-bg); } + + +// +// Images +// -------------------------------------------------- + +.thumbnail, +.img-thumbnail { + .box-shadow(0 1px 2px rgba(0,0,0,.075)); +} + + +// +// Dropdowns +// -------------------------------------------------- + +.dropdown-menu > li > a:hover, +.dropdown-menu > li > a:focus { + #gradient > .vertical(@start-color: @dropdown-link-hover-bg; @end-color: darken(@dropdown-link-hover-bg, 5%)); + background-color: darken(@dropdown-link-hover-bg, 5%); +} +.dropdown-menu > .active > a, +.dropdown-menu > .active > a:hover, +.dropdown-menu > .active > a:focus { + #gradient > .vertical(@start-color: @dropdown-link-active-bg; @end-color: darken(@dropdown-link-active-bg, 5%)); + background-color: darken(@dropdown-link-active-bg, 5%); +} + + +// +// Navbar +// -------------------------------------------------- + +// Default navbar +.navbar-default { + #gradient > .vertical(@start-color: lighten(@navbar-default-bg, 10%); @end-color: @navbar-default-bg); + .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered + border-radius: @navbar-border-radius; + @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 5px rgba(0,0,0,.075); + .box-shadow(@shadow); + + .navbar-nav > .open > a, + .navbar-nav > .active > a { + #gradient > .vertical(@start-color: darken(@navbar-default-link-active-bg, 5%); @end-color: darken(@navbar-default-link-active-bg, 2%)); + .box-shadow(inset 0 3px 9px rgba(0,0,0,.075)); + } +} +.navbar-brand, +.navbar-nav > li > a { + text-shadow: 0 1px 0 rgba(255,255,255,.25); +} + +// Inverted navbar +.navbar-inverse { + #gradient > .vertical(@start-color: lighten(@navbar-inverse-bg, 10%); @end-color: @navbar-inverse-bg); + .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered; see https://github.com/twbs/bootstrap/issues/10257 + border-radius: @navbar-border-radius; + .navbar-nav > .open > a, + .navbar-nav > .active > a { + #gradient > .vertical(@start-color: @navbar-inverse-link-active-bg; @end-color: lighten(@navbar-inverse-link-active-bg, 2.5%)); + .box-shadow(inset 0 3px 9px rgba(0,0,0,.25)); + } + + .navbar-brand, + .navbar-nav > li > a { + text-shadow: 0 -1px 0 rgba(0,0,0,.25); + } +} + +// Undo rounded corners in static and fixed navbars +.navbar-static-top, +.navbar-fixed-top, +.navbar-fixed-bottom { + border-radius: 0; +} + +// Fix active state of dropdown items in collapsed mode +@media (max-width: @grid-float-breakpoint-max) { + .navbar .navbar-nav .open .dropdown-menu > .active > a { + &, + &:hover, + &:focus { + color: #fff; + #gradient > .vertical(@start-color: @dropdown-link-active-bg; @end-color: darken(@dropdown-link-active-bg, 5%)); + } + } +} + + +// +// Alerts +// -------------------------------------------------- + +// Common styles +.alert { + text-shadow: 0 1px 0 rgba(255,255,255,.2); + @shadow: inset 0 1px 0 rgba(255,255,255,.25), 0 1px 2px rgba(0,0,0,.05); + .box-shadow(@shadow); +} + +// Mixin for generating new styles +.alert-styles(@color) { + #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 7.5%)); + border-color: darken(@color, 15%); +} + +// Apply the mixin to the alerts +.alert-success { .alert-styles(@alert-success-bg); } +.alert-info { .alert-styles(@alert-info-bg); } +.alert-warning { .alert-styles(@alert-warning-bg); } +.alert-danger { .alert-styles(@alert-danger-bg); } + + +// +// Progress bars +// -------------------------------------------------- + +// Give the progress background some depth +.progress { + #gradient > .vertical(@start-color: darken(@progress-bg, 4%); @end-color: @progress-bg) +} + +// Mixin for generating new styles +.progress-bar-styles(@color) { + #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 10%)); +} + +// Apply the mixin to the progress bars +.progress-bar { .progress-bar-styles(@progress-bar-bg); } +.progress-bar-success { .progress-bar-styles(@progress-bar-success-bg); } +.progress-bar-info { .progress-bar-styles(@progress-bar-info-bg); } +.progress-bar-warning { .progress-bar-styles(@progress-bar-warning-bg); } +.progress-bar-danger { .progress-bar-styles(@progress-bar-danger-bg); } + +// Reset the striped class because our mixins don't do multiple gradients and +// the above custom styles override the new `.progress-bar-striped` in v3.2.0. +.progress-bar-striped { + #gradient > .striped(); +} + + +// +// List groups +// -------------------------------------------------- + +.list-group { + border-radius: @border-radius-base; + .box-shadow(0 1px 2px rgba(0,0,0,.075)); +} +.list-group-item.active, +.list-group-item.active:hover, +.list-group-item.active:focus { + text-shadow: 0 -1px 0 darken(@list-group-active-bg, 10%); + #gradient > .vertical(@start-color: @list-group-active-bg; @end-color: darken(@list-group-active-bg, 7.5%)); + border-color: darken(@list-group-active-border, 7.5%); + + .badge { + text-shadow: none; + } +} + + +// +// Panels +// -------------------------------------------------- + +// Common styles +.panel { + .box-shadow(0 1px 2px rgba(0,0,0,.05)); +} + +// Mixin for generating new styles +.panel-heading-styles(@color) { + #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 5%)); +} + +// Apply the mixin to the panel headings only +.panel-default > .panel-heading { .panel-heading-styles(@panel-default-heading-bg); } +.panel-primary > .panel-heading { .panel-heading-styles(@panel-primary-heading-bg); } +.panel-success > .panel-heading { .panel-heading-styles(@panel-success-heading-bg); } +.panel-info > .panel-heading { .panel-heading-styles(@panel-info-heading-bg); } +.panel-warning > .panel-heading { .panel-heading-styles(@panel-warning-heading-bg); } +.panel-danger > .panel-heading { .panel-heading-styles(@panel-danger-heading-bg); } + + +// +// Wells +// -------------------------------------------------- + +.well { + #gradient > .vertical(@start-color: darken(@well-bg, 5%); @end-color: @well-bg); + border-color: darken(@well-bg, 10%); + @shadow: inset 0 1px 3px rgba(0,0,0,.05), 0 1px 0 rgba(255,255,255,.1); + .box-shadow(@shadow); +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/thumbnails.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/thumbnails.less new file mode 100644 index 000000000..0713e67d0 --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/thumbnails.less @@ -0,0 +1,36 @@ +// +// Thumbnails +// -------------------------------------------------- + + +// Mixin and adjust the regular image class +.thumbnail { + display: block; + padding: @thumbnail-padding; + margin-bottom: @line-height-computed; + line-height: @line-height-base; + background-color: @thumbnail-bg; + border: 1px solid @thumbnail-border; + border-radius: @thumbnail-border-radius; + .transition(border .2s ease-in-out); + + > img, + a > img { + &:extend(.img-responsive); + margin-left: auto; + margin-right: auto; + } + + // Add a hover state for linked versions only + a&:hover, + a&:focus, + a&.active { + border-color: @link-color; + } + + // Image captions + .caption { + padding: @thumbnail-caption-padding; + color: @thumbnail-caption-color; + } +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/tooltip.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/tooltip.less new file mode 100644 index 000000000..b48d63e07 --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/tooltip.less @@ -0,0 +1,101 @@ +// +// Tooltips +// -------------------------------------------------- + + +// Base class +.tooltip { + position: absolute; + z-index: @zindex-tooltip; + display: block; + // Our parent element can be arbitrary since tooltips are by default inserted as a sibling of their target element. + // So reset our font and text properties to avoid inheriting weird values. + .reset-text(); + font-size: @font-size-small; + + .opacity(0); + + &.in { .opacity(@tooltip-opacity); } + &.top { margin-top: -3px; padding: @tooltip-arrow-width 0; } + &.right { margin-left: 3px; padding: 0 @tooltip-arrow-width; } + &.bottom { margin-top: 3px; padding: @tooltip-arrow-width 0; } + &.left { margin-left: -3px; padding: 0 @tooltip-arrow-width; } +} + +// Wrapper for the tooltip content +.tooltip-inner { + max-width: @tooltip-max-width; + padding: 3px 8px; + color: @tooltip-color; + text-align: center; + background-color: @tooltip-bg; + border-radius: @border-radius-base; +} + +// Arrows +.tooltip-arrow { + position: absolute; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} +// Note: Deprecated .top-left, .top-right, .bottom-left, and .bottom-right as of v3.3.1 +.tooltip { + &.top .tooltip-arrow { + bottom: 0; + left: 50%; + margin-left: -@tooltip-arrow-width; + border-width: @tooltip-arrow-width @tooltip-arrow-width 0; + border-top-color: @tooltip-arrow-color; + } + &.top-left .tooltip-arrow { + bottom: 0; + right: @tooltip-arrow-width; + margin-bottom: -@tooltip-arrow-width; + border-width: @tooltip-arrow-width @tooltip-arrow-width 0; + border-top-color: @tooltip-arrow-color; + } + &.top-right .tooltip-arrow { + bottom: 0; + left: @tooltip-arrow-width; + margin-bottom: -@tooltip-arrow-width; + border-width: @tooltip-arrow-width @tooltip-arrow-width 0; + border-top-color: @tooltip-arrow-color; + } + &.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -@tooltip-arrow-width; + border-width: @tooltip-arrow-width @tooltip-arrow-width @tooltip-arrow-width 0; + border-right-color: @tooltip-arrow-color; + } + &.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -@tooltip-arrow-width; + border-width: @tooltip-arrow-width 0 @tooltip-arrow-width @tooltip-arrow-width; + border-left-color: @tooltip-arrow-color; + } + &.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -@tooltip-arrow-width; + border-width: 0 @tooltip-arrow-width @tooltip-arrow-width; + border-bottom-color: @tooltip-arrow-color; + } + &.bottom-left .tooltip-arrow { + top: 0; + right: @tooltip-arrow-width; + margin-top: -@tooltip-arrow-width; + border-width: 0 @tooltip-arrow-width @tooltip-arrow-width; + border-bottom-color: @tooltip-arrow-color; + } + &.bottom-right .tooltip-arrow { + top: 0; + left: @tooltip-arrow-width; + margin-top: -@tooltip-arrow-width; + border-width: 0 @tooltip-arrow-width @tooltip-arrow-width; + border-bottom-color: @tooltip-arrow-color; + } +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/type.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/type.less new file mode 100644 index 000000000..0d4fee484 --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/type.less @@ -0,0 +1,302 @@ +// +// Typography +// -------------------------------------------------- + + +// Headings +// ------------------------- + +h1, h2, h3, h4, h5, h6, +.h1, .h2, .h3, .h4, .h5, .h6 { + font-family: @headings-font-family; + font-weight: @headings-font-weight; + line-height: @headings-line-height; + color: @headings-color; + + small, + .small { + font-weight: normal; + line-height: 1; + color: @headings-small-color; + } +} + +h1, .h1, +h2, .h2, +h3, .h3 { + margin-top: @line-height-computed; + margin-bottom: (@line-height-computed / 2); + + small, + .small { + font-size: 65%; + } +} +h4, .h4, +h5, .h5, +h6, .h6 { + margin-top: (@line-height-computed / 2); + margin-bottom: (@line-height-computed / 2); + + small, + .small { + font-size: 75%; + } +} + +h1, .h1 { font-size: @font-size-h1; } +h2, .h2 { font-size: @font-size-h2; } +h3, .h3 { font-size: @font-size-h3; } +h4, .h4 { font-size: @font-size-h4; } +h5, .h5 { font-size: @font-size-h5; } +h6, .h6 { font-size: @font-size-h6; } + + +// Body text +// ------------------------- + +p { + margin: 0 0 (@line-height-computed / 2); +} + +.lead { + margin-bottom: @line-height-computed; + font-size: floor((@font-size-base * 1.15)); + font-weight: 300; + line-height: 1.4; + + @media (min-width: @screen-sm-min) { + font-size: (@font-size-base * 1.5); + } +} + + +// Emphasis & misc +// ------------------------- + +// Ex: (12px small font / 14px base font) * 100% = about 85% +small, +.small { + font-size: floor((100% * @font-size-small / @font-size-base)); +} + +mark, +.mark { + background-color: @state-warning-bg; + padding: .2em; +} + +// Alignment +.text-left { text-align: left; } +.text-right { text-align: right; } +.text-center { text-align: center; } +.text-justify { text-align: justify; } +.text-nowrap { white-space: nowrap; } + +// Transformation +.text-lowercase { text-transform: lowercase; } +.text-uppercase { text-transform: uppercase; } +.text-capitalize { text-transform: capitalize; } + +// Contextual colors +.text-muted { + color: @text-muted; +} +.text-primary { + .text-emphasis-variant(@brand-primary); +} +.text-success { + .text-emphasis-variant(@state-success-text); +} +.text-info { + .text-emphasis-variant(@state-info-text); +} +.text-warning { + .text-emphasis-variant(@state-warning-text); +} +.text-danger { + .text-emphasis-variant(@state-danger-text); +} + +// Contextual backgrounds +// For now we'll leave these alongside the text classes until v4 when we can +// safely shift things around (per SemVer rules). +.bg-primary { + // Given the contrast here, this is the only class to have its color inverted + // automatically. + color: #fff; + .bg-variant(@brand-primary); +} +.bg-success { + .bg-variant(@state-success-bg); +} +.bg-info { + .bg-variant(@state-info-bg); +} +.bg-warning { + .bg-variant(@state-warning-bg); +} +.bg-danger { + .bg-variant(@state-danger-bg); +} + + +// Page header +// ------------------------- + +.page-header { + padding-bottom: ((@line-height-computed / 2) - 1); + margin: (@line-height-computed * 2) 0 @line-height-computed; + border-bottom: 1px solid @page-header-border-color; +} + + +// Lists +// ------------------------- + +// Unordered and Ordered lists +ul, +ol { + margin-top: 0; + margin-bottom: (@line-height-computed / 2); + ul, + ol { + margin-bottom: 0; + } +} + +// List options + +// Unstyled keeps list items block level, just removes default browser padding and list-style +.list-unstyled { + padding-left: 0; + list-style: none; +} + +// Inline turns list items into inline-block +.list-inline { + .list-unstyled(); + margin-left: -5px; + + > li { + display: inline-block; + padding-left: 5px; + padding-right: 5px; + } +} + +// Description Lists +dl { + margin-top: 0; // Remove browser default + margin-bottom: @line-height-computed; +} +dt, +dd { + line-height: @line-height-base; +} +dt { + font-weight: bold; +} +dd { + margin-left: 0; // Undo browser default +} + +// Horizontal description lists +// +// Defaults to being stacked without any of the below styles applied, until the +// grid breakpoint is reached (default of ~768px). + +.dl-horizontal { + dd { + &:extend(.clearfix all); // Clear the floated `dt` if an empty `dd` is present + } + + @media (min-width: @dl-horizontal-breakpoint) { + dt { + float: left; + width: (@dl-horizontal-offset - 20); + clear: left; + text-align: right; + .text-overflow(); + } + dd { + margin-left: @dl-horizontal-offset; + } + } +} + + +// Misc +// ------------------------- + +// Abbreviations and acronyms +abbr[title], +// Add data-* attribute to help out our tooltip plugin, per https://github.com/twbs/bootstrap/issues/5257 +abbr[data-original-title] { + cursor: help; + border-bottom: 1px dotted @abbr-border-color; +} +.initialism { + font-size: 90%; + .text-uppercase(); +} + +// Blockquotes +blockquote { + padding: (@line-height-computed / 2) @line-height-computed; + margin: 0 0 @line-height-computed; + font-size: @blockquote-font-size; + border-left: 5px solid @blockquote-border-color; + + p, + ul, + ol { + &:last-child { + margin-bottom: 0; + } + } + + // Note: Deprecated small and .small as of v3.1.0 + // Context: https://github.com/twbs/bootstrap/issues/11660 + footer, + small, + .small { + display: block; + font-size: 80%; // back to default font-size + line-height: @line-height-base; + color: @blockquote-small-color; + + &:before { + content: '\2014 \00A0'; // em dash, nbsp + } + } +} + +// Opposite alignment of blockquote +// +// Heads up: `blockquote.pull-right` has been deprecated as of v3.1.0. +.blockquote-reverse, +blockquote.pull-right { + padding-right: 15px; + padding-left: 0; + border-right: 5px solid @blockquote-border-color; + border-left: 0; + text-align: right; + + // Account for citation + footer, + small, + .small { + &:before { content: ''; } + &:after { + content: '\00A0 \2014'; // nbsp, em dash + } + } +} + +// Addresses +address { + margin-bottom: @line-height-computed; + font-style: normal; + line-height: @line-height-base; +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/utilities.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/utilities.less new file mode 100644 index 000000000..7a8ca27a8 --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/utilities.less @@ -0,0 +1,55 @@ +// +// Utility classes +// -------------------------------------------------- + + +// Floats +// ------------------------- + +.clearfix { + .clearfix(); +} +.center-block { + .center-block(); +} +.pull-right { + float: right !important; +} +.pull-left { + float: left !important; +} + + +// Toggling content +// ------------------------- + +// Note: Deprecated .hide in favor of .hidden or .sr-only (as appropriate) in v3.0.1 +.hide { + display: none !important; +} +.show { + display: block !important; +} +.invisible { + visibility: hidden; +} +.text-hide { + .text-hide(); +} + + +// Hide from screenreaders and browsers +// +// Credit: HTML5 Boilerplate + +.hidden { + display: none !important; +} + + +// For Affix plugin +// ------------------------- + +.affix { + position: fixed; +} diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/variables.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/variables.less new file mode 100644 index 000000000..b057ef5bf --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/variables.less @@ -0,0 +1,869 @@ +// +// Variables +// -------------------------------------------------- + + +//== Colors +// +//## Gray and brand colors for use across Bootstrap. + +@gray-base: #000; +@gray-darker: lighten(@gray-base, 13.5%); // #222 +@gray-dark: lighten(@gray-base, 20%); // #333 +@gray: lighten(@gray-base, 33.5%); // #555 +@gray-light: lighten(@gray-base, 46.7%); // #777 +@gray-lighter: lighten(@gray-base, 93.5%); // #eee + +@brand-primary: darken(#428bca, 6.5%); // #337ab7 +@brand-success: #5cb85c; +@brand-info: #5bc0de; +@brand-warning: #f0ad4e; +@brand-danger: #d9534f; + + +//== Scaffolding +// +//## Settings for some of the most global styles. + +//** Background color for ``. +@body-bg: #fff; +//** Global text color on ``. +@text-color: @gray-dark; + +//** Global textual link color. +@link-color: @brand-primary; +//** Link hover color set via `darken()` function. +@link-hover-color: darken(@link-color, 15%); +//** Link hover decoration. +@link-hover-decoration: underline; + + +//== Typography +// +//## Font, line-height, and color for body text, headings, and more. + +@font-family-sans-serif: "Helvetica Neue", Helvetica, Arial, sans-serif; +@font-family-serif: Georgia, "Times New Roman", Times, serif; +//** Default monospace fonts for ``, ``, and `
    `.
    +@font-family-monospace:   Menlo, Monaco, Consolas, "Courier New", monospace;
    +@font-family-base:        @font-family-sans-serif;
    +
    +@font-size-base:          14px;
    +@font-size-large:         ceil((@font-size-base * 1.25)); // ~18px
    +@font-size-small:         ceil((@font-size-base * 0.85)); // ~12px
    +
    +@font-size-h1:            floor((@font-size-base * 2.6)); // ~36px
    +@font-size-h2:            floor((@font-size-base * 2.15)); // ~30px
    +@font-size-h3:            ceil((@font-size-base * 1.7)); // ~24px
    +@font-size-h4:            ceil((@font-size-base * 1.25)); // ~18px
    +@font-size-h5:            @font-size-base;
    +@font-size-h6:            ceil((@font-size-base * 0.85)); // ~12px
    +
    +//** Unit-less `line-height` for use in components like buttons.
    +@line-height-base:        1.428571429; // 20/14
    +//** Computed "line-height" (`font-size` * `line-height`) for use with `margin`, `padding`, etc.
    +@line-height-computed:    floor((@font-size-base * @line-height-base)); // ~20px
    +
    +//** By default, this inherits from the ``.
    +@headings-font-family:    inherit;
    +@headings-font-weight:    500;
    +@headings-line-height:    1.1;
    +@headings-color:          inherit;
    +
    +
    +//== Iconography
    +//
    +//## Specify custom location and filename of the included Glyphicons icon font. Useful for those including Bootstrap via Bower.
    +
    +//** Load fonts from this directory.
    +@icon-font-path:          "../fonts/";
    +//** File name for all font files.
    +@icon-font-name:          "glyphicons-halflings-regular";
    +//** Element ID within SVG icon file.
    +@icon-font-svg-id:        "glyphicons_halflingsregular";
    +
    +
    +//== Components
    +//
    +//## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start).
    +
    +@padding-base-vertical:     6px;
    +@padding-base-horizontal:   12px;
    +
    +@padding-large-vertical:    10px;
    +@padding-large-horizontal:  16px;
    +
    +@padding-small-vertical:    5px;
    +@padding-small-horizontal:  10px;
    +
    +@padding-xs-vertical:       1px;
    +@padding-xs-horizontal:     5px;
    +
    +@line-height-large:         1.3333333; // extra decimals for Win 8.1 Chrome
    +@line-height-small:         1.5;
    +
    +@border-radius-base:        4px;
    +@border-radius-large:       6px;
    +@border-radius-small:       3px;
    +
    +//** Global color for active items (e.g., navs or dropdowns).
    +@component-active-color:    #fff;
    +//** Global background color for active items (e.g., navs or dropdowns).
    +@component-active-bg:       @brand-primary;
    +
    +//** Width of the `border` for generating carets that indicator dropdowns.
    +@caret-width-base:          4px;
    +//** Carets increase slightly in size for larger components.
    +@caret-width-large:         5px;
    +
    +
    +//== Tables
    +//
    +//## Customizes the `.table` component with basic values, each used across all table variations.
    +
    +//** Padding for `

    `s and ``s. +@table-cell-padding: 8px; +//** Padding for cells in `.table-condensed`. +@table-condensed-cell-padding: 5px; + +//** Default background color used for all tables. +@table-bg: transparent; +//** Background color used for `.table-striped`. +@table-bg-accent: #f9f9f9; +//** Background color used for `.table-hover`. +@table-bg-hover: #f5f5f5; +@table-bg-active: @table-bg-hover; + +//** Border color for table and cell borders. +@table-border-color: #ddd; + + +//== Buttons +// +//## For each of Bootstrap's buttons, define text, background and border color. + +@btn-font-weight: normal; + +@btn-default-color: #333; +@btn-default-bg: #fff; +@btn-default-border: #ccc; + +@btn-primary-color: #fff; +@btn-primary-bg: @brand-primary; +@btn-primary-border: darken(@btn-primary-bg, 5%); + +@btn-success-color: #fff; +@btn-success-bg: @brand-success; +@btn-success-border: darken(@btn-success-bg, 5%); + +@btn-info-color: #fff; +@btn-info-bg: @brand-info; +@btn-info-border: darken(@btn-info-bg, 5%); + +@btn-warning-color: #fff; +@btn-warning-bg: @brand-warning; +@btn-warning-border: darken(@btn-warning-bg, 5%); + +@btn-danger-color: #fff; +@btn-danger-bg: @brand-danger; +@btn-danger-border: darken(@btn-danger-bg, 5%); + +@btn-link-disabled-color: @gray-light; + +// Allows for customizing button radius independently from global border radius +@btn-border-radius-base: @border-radius-base; +@btn-border-radius-large: @border-radius-large; +@btn-border-radius-small: @border-radius-small; + + +//== Forms +// +//## + +//** `` background color +@input-bg: #fff; +//** `` background color +@input-bg-disabled: @gray-lighter; + +//** Text color for ``s +@input-color: @gray; +//** `` border color +@input-border: #ccc; + +// TODO: Rename `@input-border-radius` to `@input-border-radius-base` in v4 +//** Default `.form-control` border radius +// This has no effect on ``s in CSS. +@input-border-radius: @border-radius-base; +//** Large `.form-control` border radius +@input-border-radius-large: @border-radius-large; +//** Small `.form-control` border radius +@input-border-radius-small: @border-radius-small; + +//** Border color for inputs on focus +@input-border-focus: #66afe9; + +//** Placeholder text color +@input-color-placeholder: #999; + +//** Default `.form-control` height +@input-height-base: (@line-height-computed + (@padding-base-vertical * 2) + 2); +//** Large `.form-control` height +@input-height-large: (ceil(@font-size-large * @line-height-large) + (@padding-large-vertical * 2) + 2); +//** Small `.form-control` height +@input-height-small: (floor(@font-size-small * @line-height-small) + (@padding-small-vertical * 2) + 2); + +//** `.form-group` margin +@form-group-margin-bottom: 15px; + +@legend-color: @gray-dark; +@legend-border-color: #e5e5e5; + +//** Background color for textual input addons +@input-group-addon-bg: @gray-lighter; +//** Border color for textual input addons +@input-group-addon-border-color: @input-border; + +//** Disabled cursor for form controls and buttons. +@cursor-disabled: not-allowed; + + +//== Dropdowns +// +//## Dropdown menu container and contents. + +//** Background for the dropdown menu. +@dropdown-bg: #fff; +//** Dropdown menu `border-color`. +@dropdown-border: rgba(0,0,0,.15); +//** Dropdown menu `border-color` **for IE8**. +@dropdown-fallback-border: #ccc; +//** Divider color for between dropdown items. +@dropdown-divider-bg: #e5e5e5; + +//** Dropdown link text color. +@dropdown-link-color: @gray-dark; +//** Hover color for dropdown links. +@dropdown-link-hover-color: darken(@gray-dark, 5%); +//** Hover background for dropdown links. +@dropdown-link-hover-bg: #f5f5f5; + +//** Active dropdown menu item text color. +@dropdown-link-active-color: @component-active-color; +//** Active dropdown menu item background color. +@dropdown-link-active-bg: @component-active-bg; + +//** Disabled dropdown menu item background color. +@dropdown-link-disabled-color: @gray-light; + +//** Text color for headers within dropdown menus. +@dropdown-header-color: @gray-light; + +//** Deprecated `@dropdown-caret-color` as of v3.1.0 +@dropdown-caret-color: #000; + + +//-- Z-index master list +// +// Warning: Avoid customizing these values. They're used for a bird's eye view +// of components dependent on the z-axis and are designed to all work together. +// +// Note: These variables are not generated into the Customizer. + +@zindex-navbar: 1000; +@zindex-dropdown: 1000; +@zindex-popover: 1060; +@zindex-tooltip: 1070; +@zindex-navbar-fixed: 1030; +@zindex-modal-background: 1040; +@zindex-modal: 1050; + + +//== Media queries breakpoints +// +//## Define the breakpoints at which your layout will change, adapting to different screen sizes. + +// Extra small screen / phone +//** Deprecated `@screen-xs` as of v3.0.1 +@screen-xs: 480px; +//** Deprecated `@screen-xs-min` as of v3.2.0 +@screen-xs-min: @screen-xs; +//** Deprecated `@screen-phone` as of v3.0.1 +@screen-phone: @screen-xs-min; + +// Small screen / tablet +//** Deprecated `@screen-sm` as of v3.0.1 +@screen-sm: 768px; +@screen-sm-min: @screen-sm; +//** Deprecated `@screen-tablet` as of v3.0.1 +@screen-tablet: @screen-sm-min; + +// Medium screen / desktop +//** Deprecated `@screen-md` as of v3.0.1 +@screen-md: 992px; +@screen-md-min: @screen-md; +//** Deprecated `@screen-desktop` as of v3.0.1 +@screen-desktop: @screen-md-min; + +// Large screen / wide desktop +//** Deprecated `@screen-lg` as of v3.0.1 +@screen-lg: 1200px; +@screen-lg-min: @screen-lg; +//** Deprecated `@screen-lg-desktop` as of v3.0.1 +@screen-lg-desktop: @screen-lg-min; + +// So media queries don't overlap when required, provide a maximum +@screen-xs-max: (@screen-sm-min - 1); +@screen-sm-max: (@screen-md-min - 1); +@screen-md-max: (@screen-lg-min - 1); + + +//== Grid system +// +//## Define your custom responsive grid. + +//** Number of columns in the grid. +@grid-columns: 12; +//** Padding between columns. Gets divided in half for the left and right. +@grid-gutter-width: 30px; +// Navbar collapse +//** Point at which the navbar becomes uncollapsed. +@grid-float-breakpoint: @screen-sm-min; +//** Point at which the navbar begins collapsing. +@grid-float-breakpoint-max: (@grid-float-breakpoint - 1); + + +//== Container sizes +// +//## Define the maximum width of `.container` for different screen sizes. + +// Small screen / tablet +@container-tablet: (720px + @grid-gutter-width); +//** For `@screen-sm-min` and up. +@container-sm: @container-tablet; + +// Medium screen / desktop +@container-desktop: (940px + @grid-gutter-width); +//** For `@screen-md-min` and up. +@container-md: @container-desktop; + +// Large screen / wide desktop +@container-large-desktop: (1140px + @grid-gutter-width); +//** For `@screen-lg-min` and up. +@container-lg: @container-large-desktop; + + +//== Navbar +// +//## + +// Basics of a navbar +@navbar-height: 50px; +@navbar-margin-bottom: @line-height-computed; +@navbar-border-radius: @border-radius-base; +@navbar-padding-horizontal: floor((@grid-gutter-width / 2)); +@navbar-padding-vertical: ((@navbar-height - @line-height-computed) / 2); +@navbar-collapse-max-height: 340px; + +@navbar-default-color: #777; +@navbar-default-bg: #f8f8f8; +@navbar-default-border: darken(@navbar-default-bg, 6.5%); + +// Navbar links +@navbar-default-link-color: #777; +@navbar-default-link-hover-color: #333; +@navbar-default-link-hover-bg: transparent; +@navbar-default-link-active-color: #555; +@navbar-default-link-active-bg: darken(@navbar-default-bg, 6.5%); +@navbar-default-link-disabled-color: #ccc; +@navbar-default-link-disabled-bg: transparent; + +// Navbar brand label +@navbar-default-brand-color: @navbar-default-link-color; +@navbar-default-brand-hover-color: darken(@navbar-default-brand-color, 10%); +@navbar-default-brand-hover-bg: transparent; + +// Navbar toggle +@navbar-default-toggle-hover-bg: #ddd; +@navbar-default-toggle-icon-bar-bg: #888; +@navbar-default-toggle-border-color: #ddd; + + +//=== Inverted navbar +// Reset inverted navbar basics +@navbar-inverse-color: lighten(@gray-light, 15%); +@navbar-inverse-bg: #222; +@navbar-inverse-border: darken(@navbar-inverse-bg, 10%); + +// Inverted navbar links +@navbar-inverse-link-color: lighten(@gray-light, 15%); +@navbar-inverse-link-hover-color: #fff; +@navbar-inverse-link-hover-bg: transparent; +@navbar-inverse-link-active-color: @navbar-inverse-link-hover-color; +@navbar-inverse-link-active-bg: darken(@navbar-inverse-bg, 10%); +@navbar-inverse-link-disabled-color: #444; +@navbar-inverse-link-disabled-bg: transparent; + +// Inverted navbar brand label +@navbar-inverse-brand-color: @navbar-inverse-link-color; +@navbar-inverse-brand-hover-color: #fff; +@navbar-inverse-brand-hover-bg: transparent; + +// Inverted navbar toggle +@navbar-inverse-toggle-hover-bg: #333; +@navbar-inverse-toggle-icon-bar-bg: #fff; +@navbar-inverse-toggle-border-color: #333; + + +//== Navs +// +//## + +//=== Shared nav styles +@nav-link-padding: 10px 15px; +@nav-link-hover-bg: @gray-lighter; + +@nav-disabled-link-color: @gray-light; +@nav-disabled-link-hover-color: @gray-light; + +//== Tabs +@nav-tabs-border-color: #ddd; + +@nav-tabs-link-hover-border-color: @gray-lighter; + +@nav-tabs-active-link-hover-bg: @body-bg; +@nav-tabs-active-link-hover-color: @gray; +@nav-tabs-active-link-hover-border-color: #ddd; + +@nav-tabs-justified-link-border-color: #ddd; +@nav-tabs-justified-active-link-border-color: @body-bg; + +//== Pills +@nav-pills-border-radius: @border-radius-base; +@nav-pills-active-link-hover-bg: @component-active-bg; +@nav-pills-active-link-hover-color: @component-active-color; + + +//== Pagination +// +//## + +@pagination-color: @link-color; +@pagination-bg: #fff; +@pagination-border: #ddd; + +@pagination-hover-color: @link-hover-color; +@pagination-hover-bg: @gray-lighter; +@pagination-hover-border: #ddd; + +@pagination-active-color: #fff; +@pagination-active-bg: @brand-primary; +@pagination-active-border: @brand-primary; + +@pagination-disabled-color: @gray-light; +@pagination-disabled-bg: #fff; +@pagination-disabled-border: #ddd; + + +//== Pager +// +//## + +@pager-bg: @pagination-bg; +@pager-border: @pagination-border; +@pager-border-radius: 15px; + +@pager-hover-bg: @pagination-hover-bg; + +@pager-active-bg: @pagination-active-bg; +@pager-active-color: @pagination-active-color; + +@pager-disabled-color: @pagination-disabled-color; + + +//== Jumbotron +// +//## + +@jumbotron-padding: 30px; +@jumbotron-color: inherit; +@jumbotron-bg: @gray-lighter; +@jumbotron-heading-color: inherit; +@jumbotron-font-size: ceil((@font-size-base * 1.5)); +@jumbotron-heading-font-size: ceil((@font-size-base * 4.5)); + + +//== Form states and alerts +// +//## Define colors for form feedback states and, by default, alerts. + +@state-success-text: #3c763d; +@state-success-bg: #dff0d8; +@state-success-border: darken(spin(@state-success-bg, -10), 5%); + +@state-info-text: #31708f; +@state-info-bg: #d9edf7; +@state-info-border: darken(spin(@state-info-bg, -10), 7%); + +@state-warning-text: #8a6d3b; +@state-warning-bg: #fcf8e3; +@state-warning-border: darken(spin(@state-warning-bg, -10), 5%); + +@state-danger-text: #a94442; +@state-danger-bg: #f2dede; +@state-danger-border: darken(spin(@state-danger-bg, -10), 5%); + + +//== Tooltips +// +//## + +//** Tooltip max width +@tooltip-max-width: 200px; +//** Tooltip text color +@tooltip-color: #fff; +//** Tooltip background color +@tooltip-bg: #000; +@tooltip-opacity: .9; + +//** Tooltip arrow width +@tooltip-arrow-width: 5px; +//** Tooltip arrow color +@tooltip-arrow-color: @tooltip-bg; + + +//== Popovers +// +//## + +//** Popover body background color +@popover-bg: #fff; +//** Popover maximum width +@popover-max-width: 276px; +//** Popover border color +@popover-border-color: rgba(0,0,0,.2); +//** Popover fallback border color +@popover-fallback-border-color: #ccc; + +//** Popover title background color +@popover-title-bg: darken(@popover-bg, 3%); + +//** Popover arrow width +@popover-arrow-width: 10px; +//** Popover arrow color +@popover-arrow-color: @popover-bg; + +//** Popover outer arrow width +@popover-arrow-outer-width: (@popover-arrow-width + 1); +//** Popover outer arrow color +@popover-arrow-outer-color: fadein(@popover-border-color, 5%); +//** Popover outer arrow fallback color +@popover-arrow-outer-fallback-color: darken(@popover-fallback-border-color, 20%); + + +//== Labels +// +//## + +//** Default label background color +@label-default-bg: @gray-light; +//** Primary label background color +@label-primary-bg: @brand-primary; +//** Success label background color +@label-success-bg: @brand-success; +//** Info label background color +@label-info-bg: @brand-info; +//** Warning label background color +@label-warning-bg: @brand-warning; +//** Danger label background color +@label-danger-bg: @brand-danger; + +//** Default label text color +@label-color: #fff; +//** Default text color of a linked label +@label-link-hover-color: #fff; + + +//== Modals +// +//## + +//** Padding applied to the modal body +@modal-inner-padding: 15px; + +//** Padding applied to the modal title +@modal-title-padding: 15px; +//** Modal title line-height +@modal-title-line-height: @line-height-base; + +//** Background color of modal content area +@modal-content-bg: #fff; +//** Modal content border color +@modal-content-border-color: rgba(0,0,0,.2); +//** Modal content border color **for IE8** +@modal-content-fallback-border-color: #999; + +//** Modal backdrop background color +@modal-backdrop-bg: #000; +//** Modal backdrop opacity +@modal-backdrop-opacity: .5; +//** Modal header border color +@modal-header-border-color: #e5e5e5; +//** Modal footer border color +@modal-footer-border-color: @modal-header-border-color; + +@modal-lg: 900px; +@modal-md: 600px; +@modal-sm: 300px; + + +//== Alerts +// +//## Define alert colors, border radius, and padding. + +@alert-padding: 15px; +@alert-border-radius: @border-radius-base; +@alert-link-font-weight: bold; + +@alert-success-bg: @state-success-bg; +@alert-success-text: @state-success-text; +@alert-success-border: @state-success-border; + +@alert-info-bg: @state-info-bg; +@alert-info-text: @state-info-text; +@alert-info-border: @state-info-border; + +@alert-warning-bg: @state-warning-bg; +@alert-warning-text: @state-warning-text; +@alert-warning-border: @state-warning-border; + +@alert-danger-bg: @state-danger-bg; +@alert-danger-text: @state-danger-text; +@alert-danger-border: @state-danger-border; + + +//== Progress bars +// +//## + +//** Background color of the whole progress component +@progress-bg: #f5f5f5; +//** Progress bar text color +@progress-bar-color: #fff; +//** Variable for setting rounded corners on progress bar. +@progress-border-radius: @border-radius-base; + +//** Default progress bar color +@progress-bar-bg: @brand-primary; +//** Success progress bar color +@progress-bar-success-bg: @brand-success; +//** Warning progress bar color +@progress-bar-warning-bg: @brand-warning; +//** Danger progress bar color +@progress-bar-danger-bg: @brand-danger; +//** Info progress bar color +@progress-bar-info-bg: @brand-info; + + +//== List group +// +//## + +//** Background color on `.list-group-item` +@list-group-bg: #fff; +//** `.list-group-item` border color +@list-group-border: #ddd; +//** List group border radius +@list-group-border-radius: @border-radius-base; + +//** Background color of single list items on hover +@list-group-hover-bg: #f5f5f5; +//** Text color of active list items +@list-group-active-color: @component-active-color; +//** Background color of active list items +@list-group-active-bg: @component-active-bg; +//** Border color of active list elements +@list-group-active-border: @list-group-active-bg; +//** Text color for content within active list items +@list-group-active-text-color: lighten(@list-group-active-bg, 40%); + +//** Text color of disabled list items +@list-group-disabled-color: @gray-light; +//** Background color of disabled list items +@list-group-disabled-bg: @gray-lighter; +//** Text color for content within disabled list items +@list-group-disabled-text-color: @list-group-disabled-color; + +@list-group-link-color: #555; +@list-group-link-hover-color: @list-group-link-color; +@list-group-link-heading-color: #333; + + +//== Panels +// +//## + +@panel-bg: #fff; +@panel-body-padding: 15px; +@panel-heading-padding: 10px 15px; +@panel-footer-padding: @panel-heading-padding; +@panel-border-radius: @border-radius-base; + +//** Border color for elements within panels +@panel-inner-border: #ddd; +@panel-footer-bg: #f5f5f5; + +@panel-default-text: @gray-dark; +@panel-default-border: #ddd; +@panel-default-heading-bg: #f5f5f5; + +@panel-primary-text: #fff; +@panel-primary-border: @brand-primary; +@panel-primary-heading-bg: @brand-primary; + +@panel-success-text: @state-success-text; +@panel-success-border: @state-success-border; +@panel-success-heading-bg: @state-success-bg; + +@panel-info-text: @state-info-text; +@panel-info-border: @state-info-border; +@panel-info-heading-bg: @state-info-bg; + +@panel-warning-text: @state-warning-text; +@panel-warning-border: @state-warning-border; +@panel-warning-heading-bg: @state-warning-bg; + +@panel-danger-text: @state-danger-text; +@panel-danger-border: @state-danger-border; +@panel-danger-heading-bg: @state-danger-bg; + + +//== Thumbnails +// +//## + +//** Padding around the thumbnail image +@thumbnail-padding: 4px; +//** Thumbnail background color +@thumbnail-bg: @body-bg; +//** Thumbnail border color +@thumbnail-border: #ddd; +//** Thumbnail border radius +@thumbnail-border-radius: @border-radius-base; + +//** Custom text color for thumbnail captions +@thumbnail-caption-color: @text-color; +//** Padding around the thumbnail caption +@thumbnail-caption-padding: 9px; + + +//== Wells +// +//## + +@well-bg: #f5f5f5; +@well-border: darken(@well-bg, 7%); + + +//== Badges +// +//## + +@badge-color: #fff; +//** Linked badge text color on hover +@badge-link-hover-color: #fff; +@badge-bg: @gray-light; + +//** Badge text color in active nav link +@badge-active-color: @link-color; +//** Badge background color in active nav link +@badge-active-bg: #fff; + +@badge-font-weight: bold; +@badge-line-height: 1; +@badge-border-radius: 10px; + + +//== Breadcrumbs +// +//## + +@breadcrumb-padding-vertical: 8px; +@breadcrumb-padding-horizontal: 15px; +//** Breadcrumb background color +@breadcrumb-bg: #f5f5f5; +//** Breadcrumb text color +@breadcrumb-color: #ccc; +//** Text color of current page in the breadcrumb +@breadcrumb-active-color: @gray-light; +//** Textual separator for between breadcrumb elements +@breadcrumb-separator: "/"; + + +//== Carousel +// +//## + +@carousel-text-shadow: 0 1px 2px rgba(0,0,0,.6); + +@carousel-control-color: #fff; +@carousel-control-width: 15%; +@carousel-control-opacity: .5; +@carousel-control-font-size: 20px; + +@carousel-indicator-active-bg: #fff; +@carousel-indicator-border-color: #fff; + +@carousel-caption-color: #fff; + + +//== Close +// +//## + +@close-font-weight: bold; +@close-color: #000; +@close-text-shadow: 0 1px 0 #fff; + + +//== Code +// +//## + +@code-color: #c7254e; +@code-bg: #f9f2f4; + +@kbd-color: #fff; +@kbd-bg: #333; + +@pre-bg: #f5f5f5; +@pre-color: @gray-dark; +@pre-border-color: #ccc; +@pre-scrollable-max-height: 340px; + + +//== Type +// +//## + +//** Horizontal offset for forms and lists. +@component-offset-horizontal: 180px; +//** Text muted color +@text-muted: @gray-light; +//** Abbreviations and acronyms border color +@abbr-border-color: @gray-light; +//** Headings small color +@headings-small-color: @gray-light; +//** Blockquote small color +@blockquote-small-color: @gray-light; +//** Blockquote font size +@blockquote-font-size: (@font-size-base * 1.25); +//** Blockquote border color +@blockquote-border-color: @gray-lighter; +//** Page header border color +@page-header-border-color: @gray-lighter; +//** Width of horizontal description list titles +@dl-horizontal-offset: @component-offset-horizontal; +//** Point at which .dl-horizontal becomes horizontal +@dl-horizontal-breakpoint: @grid-float-breakpoint; +//** Horizontal line color. +@hr-border: @gray-lighter; diff --git a/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/wells.less b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/wells.less new file mode 100644 index 000000000..15d072b0c --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/bootstrap-3.3.5/wells.less @@ -0,0 +1,29 @@ +// +// Wells +// -------------------------------------------------- + + +// Base class +.well { + min-height: 20px; + padding: 19px; + margin-bottom: 20px; + background-color: @well-bg; + border: 1px solid @well-border; + border-radius: @border-radius-base; + .box-shadow(inset 0 1px 1px rgba(0,0,0,.05)); + blockquote { + border-color: #ddd; + border-color: rgba(0,0,0,.15); + } +} + +// Sizes +.well-lg { + padding: 24px; + border-radius: @border-radius-large; +} +.well-sm { + padding: 9px; + border-radius: @border-radius-small; +} diff --git a/lib/Font-Awesome/src/assets/less/site.less b/lib/Font-Awesome/src/assets/less/site.less index 4e40a6a3c..f31be8dbb 100644 --- a/lib/Font-Awesome/src/assets/less/site.less +++ b/lib/Font-Awesome/src/assets/less/site.less @@ -8,6 +8,8 @@ @import "site/bootstrap/jumbotron"; @import "site/bootstrap/wells"; @import "site/bootstrap/type"; +@import "site/bootstrap/alerts"; +@import "site/bootstrap/modals"; @import "site/layout"; @import "site/social-buttons"; @@ -24,6 +26,7 @@ @import "site/fusion-ad"; @import "site/bsap-ad"; @import "site/sumome"; +@import "site/algolia"; @import "site/responsive/screen-lg"; @import "site/responsive/screen-md"; diff --git a/lib/Font-Awesome/src/assets/less/site/algolia.less b/lib/Font-Awesome/src/assets/less/site/algolia.less new file mode 100644 index 000000000..d97fe5950 --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/site/algolia.less @@ -0,0 +1,12 @@ +.algolia { + margin-top: -20px; + padding-top: 49px; + a { + color: @text-color; + &:hover { color: @link-hover-color; } + } + .fas-algolia { + font-size: 32px; + vertical-align: middle; + } +} diff --git a/lib/Font-Awesome/src/assets/less/site/bootstrap/alerts.less b/lib/Font-Awesome/src/assets/less/site/bootstrap/alerts.less new file mode 100644 index 000000000..a82f5ef47 --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/site/bootstrap/alerts.less @@ -0,0 +1 @@ +.alert-link { text-decoration: underline; } diff --git a/lib/Font-Awesome/src/assets/less/site/bootstrap/jumbotron.less b/lib/Font-Awesome/src/assets/less/site/bootstrap/jumbotron.less index 2cf28bb50..9b666fbb0 100644 --- a/lib/Font-Awesome/src/assets/less/site/bootstrap/jumbotron.less +++ b/lib/Font-Awesome/src/assets/less/site/bootstrap/jumbotron.less @@ -10,19 +10,27 @@ font-size: 80px; letter-spacing: -2px; line-height: 1; - text-shadow: 4px 3px 0px @jumbotron-bg, 9px 8px 0px rgba(0,0,0,0.15); // double text shadow margin: 0 0 15px; } p { font-family: @font-family-alt; - color: mix(@jumbotron-color, @jumbotron-bg, 75%); margin-top: 15px; margin-bottom: 15px; font-size: 24px; line-height: 1.3; font-weight: lighter; + } +} + +.jumbotron-ad, .jumbotron-carousel { + h1 { + text-shadow: 4px 3px 0px @jumbotron-bg, 9px 8px 0px rgba(0,0,0,0.15); // double text shadow + } + p { + color: mix(@jumbotron-color, @jumbotron-bg, 75%); text-shadow: 0 1px 0 rgba(0,0,0,0.15); } + } .jumbotron-icon { @@ -34,7 +42,6 @@ border-top-color: mix(#fff, @gray-lighter, 50%); h1 { color: @gray-darker; - font-size: 30px; margin-top: @buffer-lg; small { letter-spacing: normal; @@ -66,3 +73,7 @@ .fa-1, .fa-2, .fa-3, .fa-4, .fa-5, .fa-6 { margin-right: 1/14em; } } + +h1.info-class { + font-size: 30px; +} \ No newline at end of file diff --git a/lib/Font-Awesome/src/assets/less/site/bootstrap/modals.less b/lib/Font-Awesome/src/assets/less/site/bootstrap/modals.less new file mode 100644 index 000000000..275e40c8a --- /dev/null +++ b/lib/Font-Awesome/src/assets/less/site/bootstrap/modals.less @@ -0,0 +1,6 @@ + +// Scale up the modal +@media (min-width: @screen-sm-min) { + // Modal sizes + .modal-md { width: ((@modal-md + @modal-sm) / 2); } +} diff --git a/lib/Font-Awesome/src/assets/less/site/bootstrap/variables.less b/lib/Font-Awesome/src/assets/less/site/bootstrap/variables.less index da534a919..655866484 100644 --- a/lib/Font-Awesome/src/assets/less/site/bootstrap/variables.less +++ b/lib/Font-Awesome/src/assets/less/site/bootstrap/variables.less @@ -49,14 +49,14 @@ @fa-green-dark: darken(@fa-green, 10%); @jumbotron-border: mix(@fa-green, @fa-green-dark, 75%); -@font-family-alt: proxima-nova-sc-osf, "Helvetica Neue", Helvetica, Arial, sans-serif; +@font-family-alt: proxima-nova-sc, "Helvetica Neue", Helvetica, Arial, sans-serif; // BOOTSTRAP OVERRIDES // ------------------- // Brand colors -@brand-success: mix(@fa-green, #fff, 70%); +@brand-success: @fa-green; // Links @@ -107,6 +107,10 @@ @state-info-bg: @blue-lighter; @state-info-border: darken(spin(@state-info-bg, -10), 7%); +@state-danger-text: @brand-danger; +@state-danger-bg: mix(@state-danger-text,#fff,10%); +@state-danger-border: darken(spin(@state-danger-bg, -10), 5%); + // Carousel @carousel-text-shadow: 0 1px 0 rgba(255,255,255,0.25); diff --git a/lib/Font-Awesome/src/assets/less/site/bootstrap/wells.less b/lib/Font-Awesome/src/assets/less/site/bootstrap/wells.less index c090802a0..cd2b24ebd 100644 --- a/lib/Font-Awesome/src/assets/less/site/bootstrap/wells.less +++ b/lib/Font-Awesome/src/assets/less/site/bootstrap/wells.less @@ -1 +1,10 @@ .well-transparent { background-color: transparent; } + +.well-lg { + padding: @buffer-xl; + font-size: @font-size-large + 3; + h1 { font-size: 3em; } + h2 { font-size: 2em; } + h1, h2 { margin-top: 0; } + p { margin-bottom: 30px; } +} diff --git a/lib/Font-Awesome/src/assets/less/site/bsap-ad.less b/lib/Font-Awesome/src/assets/less/site/bsap-ad.less index 36fbef386..387f98e04 100644 --- a/lib/Font-Awesome/src/assets/less/site/bsap-ad.less +++ b/lib/Font-Awesome/src/assets/less/site/bsap-ad.less @@ -3,6 +3,7 @@ div.bsap { a { display: inline-block !important; border-bottom: inherit !important; + margin: 0 15px 20px !important; } a.adhere { background: inherit !important; diff --git a/lib/Font-Awesome/src/assets/less/site/fontawesome-icon-list.less b/lib/Font-Awesome/src/assets/less/site/fontawesome-icon-list.less index 981bdd002..49dc1b003 100644 --- a/lib/Font-Awesome/src/assets/less/site/fontawesome-icon-list.less +++ b/lib/Font-Awesome/src/assets/less/site/fontawesome-icon-list.less @@ -2,6 +2,7 @@ margin-top: 22px; .fa-hover { a { + .text-ellipsis; display: block; color: @gray-darker; line-height: 32px; diff --git a/lib/Font-Awesome/src/assets/less/site/footer.less b/lib/Font-Awesome/src/assets/less/site/footer.less index 936737b0f..92c12b2a8 100644 --- a/lib/Font-Awesome/src/assets/less/site/footer.less +++ b/lib/Font-Awesome/src/assets/less/site/footer.less @@ -1,9 +1,9 @@ #footer { - // #gradient > .vertical(@navbarInverseBackgroundHighlight, @navbarInverseBackground); background-color: lighten(@fa-green, 2%); border-top: 1px solid @jumbotron-border; color: mix(@jumbotron-color, @fa-green, 60%); text-shadow: 0 1px 0 rgba(0,0,0,0.15); + margin-top: 60px; a { color: mix(@jumbotron-color, @fa-green, 80%); border-bottom: dotted 1px mix(@jumbotron-color, @fa-green, 60%); @@ -13,7 +13,10 @@ border-bottom: solid 1px @jumbotron-color; } } - .container { padding-top: 40px; } + .container { + padding-top: 50px; + padding-bottom: 55px; + } .project { margin-top: 10px; } } @@ -21,20 +24,20 @@ // Sticky Footer Styles // -------------------- -html, body { height: 100%; } - -#wrap { - min-height: 100%; - height: auto !important; - height: 100%; -} - -.sticky-footer(); - -.sticky-footer(@footer-height: 251px, @footer-margin: 60px) { - #wrap { - margin: 0 auto -(@footer-height); - padding: 0 0 (@footer-height + @footer-margin); - } - #footer { height: @footer-height; } -} \ No newline at end of file +//html, body { height: 100%; } +// +//#wrap { +// min-height: 100%; +// height: auto !important; +// height: 100%; +//} +// +//.sticky-footer(); +// +//.sticky-footer(@footer-height: 356px, @footer-margin: 60px) { +// #wrap { +// margin: 0 auto -(@footer-height); +// padding: 0 0 (@footer-height + @footer-margin); +// } +// #footer { height: @footer-height; } +//} diff --git a/lib/Font-Awesome/src/assets/less/site/lazy.less b/lib/Font-Awesome/src/assets/less/site/lazy.less index 7207aaeea..8f9e45ced 100644 --- a/lib/Font-Awesome/src/assets/less/site/lazy.less +++ b/lib/Font-Awesome/src/assets/less/site/lazy.less @@ -1,63 +1,80 @@ -@buffer-none: 0px; -@buffer-sm: 5px; -@buffer-md: 10px; -@buffer-lg: 22px; +@buffer-none: 0px; +@buffer-sm: 5px; +@buffer-md: 10px; +@buffer-lg: 22px; +@buffer-xl: 40px; .padding-none { padding: @buffer-none !important; } .padding { padding: @buffer-md !important; } .padding-sm { padding: @buffer-sm !important; } .padding-lg { padding: @buffer-lg !important; } +.padding-xl { padding: @buffer-xl !important; } .padding-top-none { padding-top: @buffer-none !important; } .padding-top { padding-top: @buffer-md !important; } .padding-top-sm { padding-top: @buffer-sm !important; } .padding-top-lg { padding-top: @buffer-lg !important; } +.padding-top-xl { padding-top: @buffer-xl !important; } .padding-right-none { padding-right: @buffer-none !important; } .padding-right { padding-right: @buffer-md !important; } .padding-right-sm { padding-right: @buffer-sm !important; } .padding-right-lg { padding-right: @buffer-lg !important; } +.padding-right-xl { padding-right: @buffer-xl !important; } .padding-bottom-none { padding-bottom: @buffer-none !important; } .padding-bottom { padding-bottom: @buffer-md !important; } .padding-bottom-sm { padding-bottom: @buffer-sm !important; } .padding-bottom-lg { padding-bottom: @buffer-lg !important; } +.padding-bottom-xl { padding-bottom: @buffer-xl !important; } .padding-left-none { padding-left: @buffer-none !important; } .padding-left { padding-left: @buffer-md !important; } .padding-left-sm { padding-left: @buffer-sm !important; } .padding-left-lg { padding-left: @buffer-lg !important; } +.padding-left-xl { padding-left: @buffer-xl !important; } .margin-none { margin: @buffer-none !important; } .margin { margin: @buffer-md !important; } .margin-sm { margin: @buffer-sm !important; } .margin-lg { margin: @buffer-lg !important; } +.margin-xl { margin: @buffer-xl !important; } .margin-top-none { margin-top: @buffer-none !important; } .margin-top { margin-top: @buffer-md !important; } -.margin-top-lg { margin-top: @buffer-lg !important; } .margin-top-sm { margin-top: @buffer-sm !important; } +.margin-top-lg { margin-top: @buffer-lg !important; } +.margin-top-xl { margin-top: @buffer-xl !important; } .margin-right-none { margin-right: @buffer-none !important; } .margin-right { margin-right: @buffer-md !important; } -.margin-right-lg { margin-right: @buffer-lg !important; } .margin-right-sm { margin-right: @buffer-sm !important; } +.margin-right-lg { margin-right: @buffer-lg !important; } +.margin-right-xl { margin-right: @buffer-xl !important; } .margin-bottom-none { margin-bottom: @buffer-none !important; } .margin-bottom { margin-bottom: @buffer-md !important; } -.margin-bottom-lg { margin-bottom: @buffer-lg !important; } .margin-bottom-sm { margin-bottom: @buffer-sm !important; } +.margin-bottom-lg { margin-bottom: @buffer-lg !important; } +.margin-bottom-xl { margin-bottom: @buffer-xl !important; } .margin-left-none { margin-left: @buffer-none !important; } .margin-left { margin-left: @buffer-md !important; } -.margin-left-lg { margin-left: @buffer-lg !important; } .margin-left-sm { margin-left: @buffer-sm !important; } +.margin-left-lg { margin-left: @buffer-lg !important; } +.margin-left-xl { margin-left: @buffer-xl !important; } .border-left-none { border-left: none !important; } .border-right-none { border-right: none !important; } .border-bottom-none { border-bottom: none !important; } .border-top-none { border-top: none !important; } +.text-sm { font-size: @font-size-small !important; } +.text-base { font-size: @font-size-base !important; } +.text-md { font-size: @font-size-base + 2 !important; } +.text-lg { font-size: @font-size-large !important; } + + .display-block { display: block; } // use to swap an anchor tag to span a whole row to make click target larger .no-underline:hover { text-decoration: none; } .clickable { cursor: pointer; } diff --git a/lib/Font-Awesome/src/assets/less/site/responsive/screen-sm.less b/lib/Font-Awesome/src/assets/less/site/responsive/screen-sm.less index 199894e9a..083d35f1d 100644 --- a/lib/Font-Awesome/src/assets/less/site/responsive/screen-sm.less +++ b/lib/Font-Awesome/src/assets/less/site/responsive/screen-sm.less @@ -43,7 +43,5 @@ .action { width: 33%; } } - .sticky-footer(271px, 60px); - .hide-sm { display: none; } } diff --git a/lib/Font-Awesome/src/assets/less/site/responsive/screen-xs.less b/lib/Font-Awesome/src/assets/less/site/responsive/screen-xs.less index b3a43593a..052638c28 100644 --- a/lib/Font-Awesome/src/assets/less/site/responsive/screen-xs.less +++ b/lib/Font-Awesome/src/assets/less/site/responsive/screen-xs.less @@ -71,8 +71,12 @@ .tagline { margin-bottom: 10px; } } - - .sticky-footer(331px, 60px); - .hide-xs { display: none; } -} \ No newline at end of file + + .block-xs { display: block; } + + .modal-footer .block-xs + .block-xs { + margin-left: 0; + margin-top: 10px; + } +} diff --git a/lib/Font-Awesome/src/assets/less/site/search.less b/lib/Font-Awesome/src/assets/less/site/search.less index 79a00d860..a9c8bb686 100644 --- a/lib/Font-Awesome/src/assets/less/site/search.less +++ b/lib/Font-Awesome/src/assets/less/site/search.less @@ -1,25 +1,40 @@ -.filter-parent { +#search { position: relative; font-size: 18px; padding-top: 40px; - margin: -20px auto 50px; + margin: -20px auto 0px; + label { position: absolute; left: 17px; - top: 50px; + top: 51px; } - #filter-by, .hint { + + #search-input, .hint { padding-left: 43px; padding-right: 43px; border-radius: 23px; } + .hint { color: #aaa; } - #filter-clear { + + #search-clear { text-decoration: none; position: absolute; right: 18px; - top: 53px; + top: 54px; + color: @text-muted; + &:hover { + color: mix(#000, @text-muted, 20%); + } + } +} + +#search-results { + em { + font-style: normal; + text-decoration: underline; } } diff --git a/lib/Font-Awesome/src/assets/less/site/social-buttons.less b/lib/Font-Awesome/src/assets/less/site/social-buttons.less index 7409c99d0..5b84d60d0 100644 --- a/lib/Font-Awesome/src/assets/less/site/social-buttons.less +++ b/lib/Font-Awesome/src/assets/less/site/social-buttons.less @@ -7,3 +7,13 @@ border-top: 1px solid #fff; border-bottom: 1px solid #eee; } + +#subscribe { + padding: 22px 0 17px; + text-align: center; +} + +label.error { + color: @state-danger-text; + margin-top: 5px; +} diff --git a/lib/Font-Awesome/src/cheatsheet.html b/lib/Font-Awesome/src/cheatsheet.html index dfd6d13c3..1dd202ca0 100644 --- a/lib/Font-Awesome/src/cheatsheet.html +++ b/lib/Font-Awesome/src/cheatsheet.html @@ -24,10 +24,11 @@ relative_path: ../ {% for icon in sorted_icons %}
    + {% if icon.created >= site.fontawesome.major_version %}{{ icon.created }}{% endif %} &#x{{ icon.unicode }} fa-{{ icon.class }} {% if icon.alias_of %} (alias){% endif %} - [&#x{{ icon.unicode }};] + [&#x{{ icon.unicode }};]
    {% endfor %} diff --git a/lib/Font-Awesome/src/get-started.html b/lib/Font-Awesome/src/get-started.html index 3184a2328..22e11e109 100644 --- a/lib/Font-Awesome/src/get-started.html +++ b/lib/Font-Awesome/src/get-started.html @@ -21,13 +21,13 @@ relative_path: ../ {% include stripe-ad.html %}
    - -

    Thanks to the generous folks at MaxCDN, you can use Bootstrap CDN to add Font Awesome into your website with a single line of code. You don't even have to download or install anything!

    + +

    Thanks to the generous folks at MaxCDN, you can use Bootstrap CDN to add Font Awesome into your website with a single line of code. You don't even have to download or install anything!

    1. Paste the following code into the <head> section of your site's HTML. {% highlight html %} - + {% endhighlight %}

      Immediately after release, it takes a bit of time for BootstrapCDN to catch up and get the newest version live on their CDN.

    2. @@ -146,9 +146,22 @@ $ gem install font-awesome-sass

      In order to provide the best possible experience to old and buggy browsers, Font Awesome uses CSS browser hacks in several places to target special CSS to certain browser versions in order to work around bugs in the browsers themselves. These hacks understandably cause CSS validators to complain that they are invalid. In a couple places, we also use bleeding-edge CSS features that aren't yet fully standardized, but these are used purely for progressive enhancement.

      These validation warnings don't matter in practice since the non-hacky portion of our CSS does fully validate and the hacky portions don't interfere with the proper functioning of the non-hacky portion, hence why we deliberately ignore these particular warnings.

      +

      Getting started - Validators by Bootstrap Team is licensed under CC BY 3.0

      -
      +
      + +

      + IE8 has some issues with @font-face when combined with :before. + Font Awesome uses that combination. If a page is cached, and loaded without the mouse over the window + (i.e. hit the refresh button or load something in an iframe) then the page gets rendered before the font loads. + Hovering over the page (body) will show some of the icons and hovering over the remaining icons will show those as well. + See issue #954 for details. +

      +

      Getting started - Internet Explorer 8 and @font-face by Bootstrap Team is licensed under CC BY 3.0

      +
      + +

      If you need IE7 support, you have my condolences. Really. Font Awesome {{ site.fontawesome.version }} diff --git a/lib/Font-Awesome/src/icons.html b/lib/Font-Awesome/src/icons.html index becbb0299..d91963096 100644 --- a/lib/Font-Awesome/src/icons.html +++ b/lib/Font-Awesome/src/icons.html @@ -10,7 +10,7 @@ relative_path: ../ {% include jumbotron.html %} {% include stripe-social.html %} -

      +
      {% capture stripe_ad_content %}

      You asked, Font Awesome delivers with {{ icons | version:site.fontawesome.minor_version | size }} shiny new icons in version {{ site.fontawesome.minor_version }}. @@ -21,21 +21,77 @@ relative_path: ../ {% endcapture %} {% include stripe-ad.html %} - {% include icons/filter.html %} +

      +
      + +
      + +
      - {% include icons/new.html %} - {% include icons/web-application.html %} - {% include icons/transportation.html %} - {% include icons/gender.html %} - {% include icons/file-type.html %} - {% include icons/spinner.html %} - {% include icons/form-control.html %} - {% include icons/payment.html %} - {% include icons/chart.html %} - {% include icons/currency.html %} - {% include icons/text-editor.html %} - {% include icons/directional.html %} - {% include icons/video-player.html %} - {% include icons/brand.html %} - {% include icons/medical.html %} +
      +
      + {% include icons/new.html %} + {% include icons/web-application.html %} + {% include icons/hand.html %} + {% include icons/transportation.html %} + {% include icons/gender.html %} + {% include icons/file-type.html %} + {% include icons/spinner.html %} + {% include icons/form-control.html %} + {% include icons/payment.html %} + {% include icons/chart.html %} + {% include icons/currency.html %} + {% include icons/text-editor.html %} + {% include icons/directional.html %} + {% include icons/video-player.html %} + {% include icons/brand.html %} + {% include icons/medical.html %} +
      + +
      diff --git a/lib/Font-Awesome/src/icons.yml b/lib/Font-Awesome/src/icons.yml index 538472fa4..a304ee5cd 100644 --- a/lib/Font-Awesome/src/icons.yml +++ b/lib/Font-Awesome/src/icons.yml @@ -155,6 +155,7 @@ icons: - agree - accept - confirm + - tick categories: - Web Application Icons @@ -169,6 +170,7 @@ icons: - close - exit - x + - cross categories: - Web Application Icons @@ -340,6 +342,7 @@ icons: created: 1.0 filter: - reload + - sync categories: - Web Application Icons - Spinner Icons @@ -672,6 +675,9 @@ icons: created: 1.0 filter: - raindrop + - waterdrop + - drop + - droplet categories: - Web Application Icons @@ -963,15 +969,15 @@ icons: id: ban unicode: f05e created: 1.0 + filter: - delete - remove - trash - hide - block - stop - filter: - - block - abort + - cancel categories: - Web Application Icons @@ -1037,7 +1043,9 @@ icons: unicode: f066 created: 1.0 filter: + - collapse - combine + - contract - merge - smaller categories: @@ -1196,8 +1204,10 @@ icons: created: 1.0 filter: - sort + - shuffle categories: - Web Application Icons + - Video Player Icons - name: comment id: comment @@ -1207,6 +1217,9 @@ icons: - speech - notification - note + - chat + - bubble + - feedback categories: - Web Application Icons @@ -1297,6 +1310,7 @@ icons: - bar-chart-o filter: - graph + - analytics categories: - Web Application Icons - Chart Icons @@ -1372,8 +1386,10 @@ icons: - approve - favorite - agree + - hand categories: - Web Application Icons + - Hand Icons - name: Thumbs Down Outlined id: thumbs-o-down @@ -1383,8 +1399,10 @@ icons: - dislike - disapprove - disagree + - hand categories: - Web Application Icons + - Hand Icons - name: star-half id: star-half @@ -1460,6 +1478,8 @@ icons: filter: - enter - join + - log in + - login - sign up - sign in - signin @@ -1514,6 +1534,7 @@ icons: - voice - number - support + - earphone categories: - Web Application Icons @@ -1589,6 +1610,7 @@ icons: - protect - admin - password + - lock categories: - Web Application Icons @@ -1612,8 +1634,9 @@ icons: unicode: f09e created: 2.0 filter: - - feed - blog + aliases: + - feed categories: - Web Application Icons @@ -1674,6 +1697,7 @@ icons: - forward categories: - Directional Icons + - Hand Icons - name: Hand Outlined Left id: hand-o-left @@ -1686,6 +1710,7 @@ icons: - back categories: - Directional Icons + - Hand Icons - name: Hand Outlined Up id: hand-o-up @@ -1695,6 +1720,7 @@ icons: - point categories: - Directional Icons + - Hand Icons - name: Hand Outlined Down id: hand-o-down @@ -1704,6 +1730,7 @@ icons: - point categories: - Directional Icons + - Hand Icons - name: Arrow Circle Left id: arrow-circle-left @@ -1818,6 +1845,7 @@ icons: filter: - expand - enlarge + - fullscreen - bigger - move - reorder @@ -1939,6 +1967,7 @@ icons: - checklist - todo - list + - hamburger categories: - Web Application Icons @@ -2072,6 +2101,7 @@ icons: - more - dropdown - menu + - triangle down categories: - Directional Icons @@ -2079,6 +2109,8 @@ icons: id: caret-up unicode: f0d8 created: 2.0 + filter: + - triangle up categories: - Directional Icons @@ -2089,6 +2121,7 @@ icons: filter: - previous - back + - triangle left categories: - Directional Icons @@ -2099,6 +2132,7 @@ icons: filter: - next - forward + - triangle right categories: - Directional Icons @@ -2126,11 +2160,11 @@ icons: - name: Sort Descending id: sort-desc unicode: f0dd + created: 2.0 filter: - dropdown - more - menu - created: 2.0 aliases: - sort-down categories: @@ -2150,6 +2184,7 @@ icons: id: envelope unicode: f0e0 created: 2.0 + filter: - email - e-mail - letter @@ -2279,8 +2314,12 @@ icons: id: exchange unicode: f0ec created: 3.0 + filter: + - transfer + - arrows categories: - Web Application Icons + - Directional Icons - name: Cloud Download id: cloud-download @@ -2394,6 +2433,7 @@ icons: - business - apartment - office + - company categories: - Web Application Icons @@ -2426,6 +2466,7 @@ icons: - firstaid - help - support + - health categories: - Medical Icons @@ -3432,8 +3473,10 @@ icons: - favorite - approve - agree + - hand categories: - Web Application Icons + - Hand Icons - name: thumbs-down id: thumbs-down @@ -3443,8 +3486,10 @@ icons: - dislike - disapprove - disagree + - hand categories: - Web Application Icons + - Hand Icons - name: YouTube Square id: youtube-square @@ -3602,6 +3647,7 @@ icons: id: windows unicode: f17a created: 3.2 + filter: - microsoft categories: - Brand Icons @@ -3729,6 +3775,7 @@ icons: created: 3.2 filter: - report + - insect categories: - Web Application Icons @@ -3887,7 +3934,7 @@ icons: categories: - Web Application Icons - - name: Wordpress Logo + - name: WordPress Logo id: wordpress unicode: f19a created: 4.1 @@ -3917,6 +3964,10 @@ icons: created: 4.1 aliases: - mortar-board + filter: + - learning + - school + - student categories: - Web Application Icons @@ -4023,6 +4074,12 @@ icons: id: building unicode: f1ad created: 4.1 + filter: + - work + - business + - apartment + - office + - company categories: - Web Application Icons @@ -4038,6 +4095,8 @@ icons: id: paw unicode: f1b0 created: 4.1 + filter: + - pet categories: - Web Application Icons @@ -4315,6 +4374,9 @@ icons: id: hacker-news unicode: f1d4 created: 4.1 + aliases: + - y-combinator-square + - yc-square categories: - Brand Icons @@ -4371,16 +4433,15 @@ icons: id: circle-thin unicode: f1db created: 4.1 - aliases: - - genderless categories: - Web Application Icons - - Gender Icons - name: header id: header unicode: f1dc created: 4.1 + filter: + - heading categories: - Text Editor Icons @@ -4477,6 +4538,8 @@ icons: id: newspaper-o unicode: f1ea created: 4.2 + filter: + - press categories: - Web Application Icons @@ -4502,7 +4565,7 @@ icons: - Brand Icons - Payment Icons - - name: Goole Wallet + - name: Google Wallet id: google-wallet unicode: f1ee created: 4.2 @@ -4539,6 +4602,8 @@ icons: id: cc-amex unicode: f1f3 created: 4.2 + filter: + - amex categories: - Brand Icons - Payment Icons @@ -4577,6 +4642,11 @@ icons: id: trash unicode: f1f8 created: 4.2 + filter: + - garbage + - delete + - remove + - hide categories: - Web Application Icons @@ -4622,6 +4692,9 @@ icons: categories: - Web Application Icons - Chart Icons + filter: + - graph + - analytics - name: Pie Chart @@ -4631,6 +4704,9 @@ icons: categories: - Web Application Icons - Chart Icons + filter: + - graph + - analytics - name: Line Chart id: line-chart @@ -4639,6 +4715,9 @@ icons: categories: - Web Application Icons - Chart Icons + filter: + - graph + - analytics - name: last.fm id: lastfm @@ -4915,6 +4994,8 @@ icons: id: transgender unicode: f224 created: 4.3 + aliases: + - intersex categories: - Gender Icons @@ -4974,6 +5055,13 @@ icons: categories: - Gender Icons + - name: Genderless + id: genderless + unicode: f22d + created: 4.4 + categories: + - Gender Icons + - name: Facebook Official id: facebook-official @@ -5007,6 +5095,9 @@ icons: id: user-plus unicode: f234 created: 4.3 + filter: + - sign up + - signup categories: - Web Application Icons @@ -5056,3 +5147,504 @@ icons: created: 4.3 categories: - Brand Icons + + - name: Y Combinator + id: y-combinator + unicode: f23b + created: 4.4 + aliases: + - yc + categories: + - Brand Icons + + - name: Optin Monster + id: optin-monster + unicode: f23c + created: 4.4 + url: optinmonster.com + categories: + - Brand Icons + + - name: OpenCart + id: opencart + unicode: f23d + created: 4.4 + url: opencart.com + categories: + - Brand Icons + + - name: ExpeditedSSL + id: expeditedssl + unicode: f23e + created: 4.4 + categories: + - Brand Icons + + + - name: Battery Full + id: battery-full + unicode: f240 + created: 4.4 + aliases: + - battery-4 + categories: + - Web Application Icons + + - name: Battery 3/4 Full + id: battery-three-quarters + unicode: f241 + created: 4.4 + aliases: + - battery-3 + categories: + - Web Application Icons + + - name: Battery 1/2 Full + id: battery-half + unicode: f242 + created: 4.4 + aliases: + - battery-2 + categories: + - Web Application Icons + + - name: Battery 1/4 Full + id: battery-quarter + unicode: f243 + created: 4.4 + aliases: + - battery-1 + categories: + - Web Application Icons + + - name: Battery Empty + id: battery-empty + unicode: f244 + created: 4.4 + aliases: + - battery-0 + categories: + - Web Application Icons + + - name: Mouse Pointer + id: mouse-pointer + unicode: f245 + created: 4.4 + categories: + - Web Application Icons + + - name: I Beam Cursor + id: i-cursor + unicode: f246 + created: 4.4 + categories: + - Web Application Icons + + - name: Object Group + id: object-group + unicode: f247 + created: 4.4 + categories: + - Web Application Icons + + - name: Object Ungroup + id: object-ungroup + unicode: f248 + created: 4.4 + categories: + - Web Application Icons + + - name: Sticky Note + id: sticky-note + unicode: f249 + created: 4.4 + categories: + - Web Application Icons + + - name: Sticky Note Outlined + id: sticky-note-o + unicode: f24a + created: 4.4 + categories: + - Web Application Icons + + - name: JCB Credit Card + id: cc-jcb + unicode: f24b + created: 4.4 + categories: + - Brand Icons + - Payment Icons + + - name: Diner's Club Credit Card + id: cc-diners-club + unicode: f24c + created: 4.4 + categories: + - Brand Icons + - Payment Icons + + - name: Clone + id: clone + unicode: f24d + created: 4.4 + filter: + - copy + categories: + - Web Application Icons + + - name: Balance Scale + id: balance-scale + unicode: f24e + created: 4.4 + categories: + - Web Application Icons + + + - name: Hourglass Outlined + id: hourglass-o + unicode: f250 + created: 4.4 + categories: + - Web Application Icons + + - name: Hourglass Start + id: hourglass-start + unicode: f251 + created: 4.4 + aliases: + - hourglass-1 + categories: + - Web Application Icons + + - name: Hourglass Half + id: hourglass-half + unicode: f252 + created: 4.4 + aliases: + - hourglass-2 + categories: + - Web Application Icons + + - name: Hourglass End + id: hourglass-end + unicode: f253 + created: 4.4 + aliases: + - hourglass-3 + categories: + - Web Application Icons + + - name: Hourglass + id: hourglass + unicode: f254 + created: 4.4 + categories: + - Web Application Icons + + - name: Rock (Hand) + id: hand-rock-o + unicode: f255 + created: 4.4 + aliases: + - hand-grab-o + categories: + - Web Application Icons + - Hand Icons + + - name: Paper (Hand) + id: hand-paper-o + unicode: f256 + created: 4.4 + aliases: + - hand-stop-o + categories: + - Web Application Icons + - Hand Icons + + - name: Scissors (Hand) + id: hand-scissors-o + unicode: f257 + created: 4.4 + categories: + - Web Application Icons + - Hand Icons + + - name: Lizard (Hand) + id: hand-lizard-o + unicode: f258 + created: 4.4 + categories: + - Web Application Icons + - Hand Icons + + - name: Spock (Hand) + id: hand-spock-o + unicode: f259 + created: 4.4 + categories: + - Web Application Icons + - Hand Icons + + - name: Hand Pointer + id: hand-pointer-o + unicode: f25a + created: 4.4 + categories: + - Web Application Icons + - Hand Icons + + - name: Hand Peace + id: hand-peace-o + unicode: f25b + created: 4.4 + categories: + - Web Application Icons + - Hand Icons + + - name: Trademark + id: trademark + unicode: f25c + created: 4.4 + categories: + - Web Application Icons + + - name: Registered Trademark + id: registered + unicode: f25d + created: 4.4 + categories: + - Web Application Icons + + - name: Creative Commons + id: creative-commons + unicode: f25e + created: 4.4 + categories: + - Web Application Icons + + + - name: GG Currency + id: gg + unicode: f260 + created: 4.4 + categories: + - Currency Icons + - Brand Icons + + - name: GG Currency Circle + id: gg-circle + unicode: f261 + created: 4.4 + categories: + - Currency Icons + - Brand Icons + + - name: TripAdvisor + id: tripadvisor + unicode: f262 + created: 4.4 + categories: + - Brand Icons + + - name: Odnoklassniki + id: odnoklassniki + unicode: f263 + created: 4.4 + categories: + - Brand Icons + + - name: Odnoklassniki Square + id: odnoklassniki-square + unicode: f264 + created: 4.4 + categories: + - Brand Icons + + - name: Get Pocket + id: get-pocket + unicode: f265 + created: 4.4 + categories: + - Brand Icons + + - name: Wikipedia W + id: wikipedia-w + unicode: f266 + created: 4.4 + categories: + - Brand Icons + + - name: Safari + id: safari + unicode: f267 + created: 4.4 + categories: + - Brand Icons + + - name: Chrome + id: chrome + unicode: f268 + created: 4.4 + categories: + - Brand Icons + + - name: Firefox + id: firefox + unicode: f269 + created: 4.4 + categories: + - Brand Icons + + - name: Opera + id: opera + unicode: f26a + created: 4.4 + categories: + - Brand Icons + + - name: Internet-explorer + id: internet-explorer + unicode: f26b + created: 4.4 + categories: + - Brand Icons + + - name: Television + id: television + unicode: f26c + created: 4.4 + aliases: + - tv + categories: + - Web Application Icons + + - name: Contao + id: contao + unicode: f26d + created: 4.4 + categories: + - Brand Icons + + - name: 500px + id: 500px + unicode: f26e + created: 4.4 + categories: + - Brand Icons + + + - name: Amazon + id: amazon + unicode: f270 + created: 4.4 + categories: + - Brand Icons + + - name: Calendar Plus Outlined + id: calendar-plus-o + unicode: f271 + created: 4.4 + categories: + - Web Application Icons + + - name: Calendar Minus Outlined + id: calendar-minus-o + unicode: f272 + created: 4.4 + categories: + - Web Application Icons + + - name: Calendar Times Outlined + id: calendar-times-o + unicode: f273 + created: 4.4 + categories: + - Web Application Icons + + - name: Calendar Check Outlined + id: calendar-check-o + unicode: f274 + created: 4.4 + categories: + - Web Application Icons + + - name: Industry + id: industry + unicode: f275 + created: 4.4 + categories: + - Web Application Icons + + - name: Map Pin + id: map-pin + unicode: f276 + created: 4.4 + categories: + - Web Application Icons + + - name: Map Signs + id: map-signs + unicode: f277 + created: 4.4 + categories: + - Web Application Icons + + - name: Map Outline + id: map-o + unicode: f278 + created: 4.4 + categories: + - Web Application Icons + + - name: Map + id: map + unicode: f279 + created: 4.4 + categories: + - Web Application Icons + + - name: Commenting + id: commenting + unicode: f27a + created: 4.4 + categories: + - Web Application Icons + + - name: Commenting Outlined + id: commenting-o + unicode: f27b + created: 4.4 + categories: + - Web Application Icons + + - name: Houzz + id: houzz + unicode: f27c + created: 4.4 + categories: + - Brand Icons + + - name: Vimeo + id: vimeo + unicode: f27d + created: 4.4 + categories: + - Brand Icons + + - name: Font Awesome Black Tie + id: black-tie + unicode: f27e + created: 4.4 + url: blacktie.io + categories: + - Brand Icons + + + - name: Fonticons + id: fonticons + unicode: f280 + created: 4.4 + url: fonticons.com + categories: + - Brand Icons diff --git a/lib/Font-Awesome/src/index.html b/lib/Font-Awesome/src/index.html index ebe1750fd..af1f6297d 100644 --- a/lib/Font-Awesome/src/index.html +++ b/lib/Font-Awesome/src/index.html @@ -20,3 +20,5 @@ relative_path: ./ {% include why.html %} {% include thanks-to.html %}
      + +{% include modals/download.html %} diff --git a/lib/Font-Awesome/src/test.html b/lib/Font-Awesome/src/test.html index ac9017229..09a9536e7 100644 --- a/lib/Font-Awesome/src/test.html +++ b/lib/Font-Awesome/src/test.html @@ -509,28 +509,28 @@ relative_path: ../

      - + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam et lectus id nisl hendrerit varius. Aliquam erat volutpat. Suspendisse potenti. Aliquam erat volutpat. Aliquam ut dolor lectus.

      - + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam et lectus id nisl hendrerit varius. Aliquam erat volutpat. Suspendisse potenti. Aliquam erat volutpat. Aliquam ut dolor lectus.

      - + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam et lectus id nisl hendrerit varius. Aliquam erat volutpat. Suspendisse potenti. Aliquam erat volutpat. Aliquam ut dolor lectus.
      - + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam et lectus id nisl hendrerit varius. Aliquam erat volutpat. Suspendisse potenti. Aliquam erat volutpat. Aliquam ut dolor lectus.
      - + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam et lectus id nisl hendrerit varius. Aliquam erat volutpat. Suspendisse potenti. Aliquam erat volutpat. Aliquam ut dolor lectus.
      diff --git a/lib/Font-Awesome/src/thanks.html b/lib/Font-Awesome/src/thanks.html new file mode 100644 index 000000000..3a0ab1c36 --- /dev/null +++ b/lib/Font-Awesome/src/thanks.html @@ -0,0 +1,29 @@ +--- +layout: base +title: Thanks for subscribing! +relative_path: ../ +--- + +
      +
      +
      +
      +

      You're all set!

      +

      + Thanks for signing up! + We'll send you email updates on new Font Awesome releases, icons, and other stuff that we're working on. + We won't spam you. Scout's honor! +

      + +

      What's next?

      +

      + Want to see what we're working on next? Check out Fonticons! We're making it easy to put the perfect icons + on your website. Pick from gorgeous, comprehensive icon sets or copy and paste your own vector icons. +

      + + Check out Fonticons! + +
      +
      +
      +
      From fcf3a806557b990ded2c994e14cf5dc55d26c5bb Mon Sep 17 00:00:00 2001 From: Mike Rostermund Date: Sat, 17 Oct 2015 11:31:57 +0200 Subject: [PATCH 582/598] Allow user to influence when devices are grouped on world map from widget settings --- html/includes/common/worldmap.inc.php | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/html/includes/common/worldmap.inc.php b/html/includes/common/worldmap.inc.php index fdec3fc26..bf9e6f36e 100644 --- a/html/includes/common/worldmap.inc.php +++ b/html/includes/common/worldmap.inc.php @@ -46,7 +46,7 @@ if ($config['map']['engine'] == 'leaflet') {
      -
      +
      +
      +
      + +
      +
      + +
      +
      @@ -87,13 +95,21 @@ if ($config['map']['engine'] == 'leaflet') { $init_lng = $config['leaflet']['default_lng']; $init_zoom = $config['leaflet']['default_zoom']; } + if (!empty($widget_settings['group_radius'])) { + $group_radius = $widget_settings['group_radius']; + } + else { + $group_radius = 80; + } $map_init = "[" . $init_lat . ", " . $init_lng . "], " . sprintf("%01.0f", $init_zoom); $temp_output .= 'var map = L.map(\'leaflet-map\').setView('.$map_init.'); L.tileLayer(\'//{s}.tile.openstreetmap.org/{z}/{x}/{y}.png\', { attribution: \'© OpenStreetMap contributors\' }).addTo(map); -var markers = L.markerClusterGroup(); +var markers = L.markerClusterGroup({ + maxClusterRadius: ' . $group_radius . ', + }); var redMarker = L.AwesomeMarkers.icon({ icon: \'server\', markerColor: \'red\', prefix: \'fa\', iconColor: \'white\' From 0af676ecb91679adabdb0fe6bdf74c58b6872318 Mon Sep 17 00:00:00 2001 From: laf Date: Sat, 17 Oct 2015 11:28:03 +0000 Subject: [PATCH 583/598] Updated for field --- html/pages/device/edit/misc.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/html/pages/device/edit/misc.inc.php b/html/pages/device/edit/misc.inc.php index 8a38293ed..a85689852 100644 --- a/html/pages/device/edit/misc.inc.php +++ b/html/pages/device/edit/misc.inc.php @@ -3,7 +3,7 @@ echo '
      - +
      '.dynamic_override_config('checkbox','override_icmp_disable', $device).'
      From 222191382d1ecb12d165a0992aed4c62d7d98cd8 Mon Sep 17 00:00:00 2001 From: laf Date: Sat, 17 Oct 2015 18:13:11 +0000 Subject: [PATCH 584/598] Fixed services -> Alerts menu link + page --- html/includes/print-menubar.php | 2 +- html/pages/services.inc.php | 20 +++++++++++++------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/html/includes/print-menubar.php b/html/includes/print-menubar.php index 8117e4fbb..09d4b57b7 100644 --- a/html/includes/print-menubar.php +++ b/html/includes/print-menubar.php @@ -190,7 +190,7 @@ if ($config['show_services']) { if ($service_alerts) { echo(' -
    3. Alerts ('.$service_alerts.')
    4. '); +
    5. Alerts ('.$service_alerts.')
    6. '); } if ($_SESSION['userlevel'] >= '10') { diff --git a/html/pages/services.inc.php b/html/pages/services.inc.php index 83af21cfe..0e4d2edfc 100644 --- a/html/pages/services.inc.php +++ b/html/pages/services.inc.php @@ -16,16 +16,14 @@ if (isset($vars['state'])) { if ($vars['state'] == 'up') { $state = '1'; } - else if ($vars['state'] == 'down') { + elseif ($vars['state'] == 'down') { $state = '0'; } } if ($vars['state']) { - $where .= ' AND service_status= ?'; + $where .= " AND service_status= ? AND service_disabled='0' AND `service_ignore`='0'"; $sql_param[] = $state; - $where .= " AND service_disabled='0' AND `service_ignore`='0'"; - $sql_param[] = ''; } if ($vars['disabled']) { @@ -65,8 +63,15 @@ unset($sep); print_optionbar_end(); -echo ''; -// echo(""); +echo '
      +
      DeviceServiceStatusChangedCheckedMessage
      + + + + + + + '; if ($_SESSION['userlevel'] >= '5') { $host_sql = 'SELECT * FROM devices AS D, services AS S WHERE D.device_id = S.device_id GROUP BY D.hostname ORDER BY D.hostname'; $host_par = array(); @@ -123,4 +128,5 @@ foreach (dbFetchRows($host_sql, $host_par) as $device) { unset($samehost); }//end foreach -echo '
      DeviceServiceStatusChangedMessage
      '; +echo '
    +
    '; From bbae6e9c4896515746e2e21859ee485090e7f005 Mon Sep 17 00:00:00 2001 From: laf Date: Sat, 17 Oct 2015 18:49:01 +0000 Subject: [PATCH 585/598] Removed ping + performance graphs and tab if skip ping check --- html/pages/device.inc.php | 12 +++++++----- html/pages/device/graphs.inc.php | 4 +++- includes/common.php | 16 ++++++++++++++++ includes/functions.php | 6 ++---- includes/polling/functions.inc.php | 28 ++++++++++++++++------------ 5 files changed, 44 insertions(+), 22 deletions(-) diff --git a/html/pages/device.inc.php b/html/pages/device.inc.php index d5ccd5212..688a18900 100644 --- a/html/pages/device.inc.php +++ b/html/pages/device.inc.php @@ -353,11 +353,13 @@ if (device_permitted($vars['device']) || $check_device == $vars['device']) {
  • '; } - echo '
  • - - Performance - -
  • '; + if (can_ping_device($attribs) === true) { + echo '
  • + + Performance + +
  • '; + } echo '
  • diff --git a/html/pages/device/graphs.inc.php b/html/pages/device/graphs.inc.php index e4bd13d84..154cbbfb5 100644 --- a/html/pages/device/graphs.inc.php +++ b/html/pages/device/graphs.inc.php @@ -24,7 +24,9 @@ foreach (dbFetchRows('SELECT * FROM device_graphs WHERE device_id = ? ORDER BY g // These are standard graphs we should have for all systems $graph_enable['poller']['poller_perf'] = 'device_poller_perf'; -$graph_enable['poller']['ping_perf'] = 'device_ping_perf'; +if (can_ping_device($attribs) === true) { + $graph_enable['poller']['ping_perf'] = 'device_ping_perf'; +} $sep = ''; foreach ($graph_enable as $section => $nothing) { diff --git a/includes/common.php b/includes/common.php index bcef46da0..248285600 100644 --- a/includes/common.php +++ b/includes/common.php @@ -758,3 +758,19 @@ function round_Nth($val = 0, $round_to) { } } // end round_Nth +/** + * Checks if config allows us to ping this device + * $attribs contains an array of all of this devices + * attributes + * @param array $attribs Device attributes + * @return bool +**/ +function can_ping_device($attribs) { + global $config; + if ($config['icmp_check'] === true && $attribs['override_icmp_disable'] != "true") { + return true; + } + else { + return false; + } +} // end can_ping_device diff --git a/includes/functions.php b/includes/functions.php index 319adb074..d87d38536 100644 --- a/includes/functions.php +++ b/includes/functions.php @@ -487,13 +487,11 @@ function isSNMPable($device) { * * @return bool TRUE if the host responded to at least one ping request, FALSE otherwise. */ -function isPingable($hostname, $address_family = AF_INET, $device_id = FALSE) { +function isPingable($hostname, $address_family = AF_INET, $device_id = FALSE, $attribs = false) { global $config; - $tmp_device = array('device_id'=>$device_id); $response = array(); - if ($config['icmp_check'] === true && get_dev_attrib($tmp_device,'override_icmp_disable') != "true") { - + if (can_ping_device($attribs) === true) { $fping_params = ''; if(is_numeric($config['fping_options']['retries']) || $config['fping_options']['retries'] > 1) { $fping_params .= ' -r ' . $config['fping_options']['retries']; diff --git a/includes/polling/functions.inc.php b/includes/polling/functions.inc.php index bbdad009c..ca28abc79 100644 --- a/includes/polling/functions.inc.php +++ b/includes/polling/functions.inc.php @@ -155,7 +155,7 @@ function poll_device($device, $options) { $address_family = snmpTransportToAddressFamily($device['transport']); - $ping_response = isPingable($device['hostname'], $address_family, $device['device_id']); + $ping_response = isPingable($device['hostname'], $address_family, $device['device_id'], $attribs); $device_perf = $ping_response['db']; $device_perf['device_id'] = $device['device_id']; @@ -265,23 +265,27 @@ function poll_device($device, $options) { } // Ping response rrd - $ping_rrd = $config['rrd_dir'].'/'.$device['hostname'].'/ping-perf.rrd'; - if (!is_file($ping_rrd)) { - rrdtool_create($ping_rrd, 'DS:ping:GAUGE:600:0:65535 '.$config['rrd_rra']); - } + if (can_ping_device($attribs) === true) { + $ping_rrd = $config['rrd_dir'].'/'.$device['hostname'].'/ping-perf.rrd'; + if (!is_file($ping_rrd)) { + rrdtool_create($ping_rrd, 'DS:ping:GAUGE:600:0:65535 '.$config['rrd_rra']); + } - if (!empty($ping_time)) { - $fields = array( - 'ping' => $ping_time, - ); + if (!empty($ping_time)) { + $fields = array( + 'ping' => $ping_time, + ); + + rrdtool_update($ping_rrd, $fields); + } + + $update_array['last_ping'] = array('NOW()'); + $update_array['last_ping_timetaken'] = $ping_time; - rrdtool_update($ping_rrd, $fields); } $update_array['last_polled'] = array('NOW()'); $update_array['last_polled_timetaken'] = $device_time; - $update_array['last_ping'] = array('NOW()'); - $update_array['last_ping_timetaken'] = $ping_time; // echo("$device_end - $device_start; $device_time $device_run"); echo "Polled in $device_time seconds\n"; From 96a0abbeca13254e80a8b87e0de07efb377d919c Mon Sep 17 00:00:00 2001 From: laf Date: Sat, 17 Oct 2015 18:51:14 +0000 Subject: [PATCH 586/598] Stop adding device_perf data if no ping --- includes/polling/functions.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/polling/functions.inc.php b/includes/polling/functions.inc.php index ca28abc79..77017ac94 100644 --- a/includes/polling/functions.inc.php +++ b/includes/polling/functions.inc.php @@ -160,7 +160,7 @@ function poll_device($device, $options) { $device_perf = $ping_response['db']; $device_perf['device_id'] = $device['device_id']; $device_perf['timestamp'] = array('NOW()'); - if (is_array($device_perf)) { + if (can_ping_device($attribs) === true && is_array($device_perf)) { dbInsert($device_perf, 'device_perf'); } From 94c5afb2dbbedbab11d3189dd00d0cfc3e8a4de8 Mon Sep 17 00:00:00 2001 From: laf Date: Sat, 17 Oct 2015 19:11:21 +0000 Subject: [PATCH 587/598] Scrut fixes --- includes/functions.php | 4 ++-- includes/polling/functions.inc.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/includes/functions.php b/includes/functions.php index d87d38536..4682c994f 100644 --- a/includes/functions.php +++ b/includes/functions.php @@ -483,11 +483,11 @@ function isSNMPable($device) { * * @param string $hostname The hostname or IP address to send ping requests to. * @param int $address_family The address family (AF_INET for IPv4 or AF_INET6 for IPv6) to use. Defaults to IPv4. Will *not* be autodetected for IP addresses, so it has to be set to AF_INET6 when pinging an IPv6 address or an IPv6-only host. - * @param int $device_id This parameter is currently ignored. + * @param array $attribs The device attributes * * @return bool TRUE if the host responded to at least one ping request, FALSE otherwise. */ -function isPingable($hostname, $address_family = AF_INET, $device_id = FALSE, $attribs = false) { +function isPingable($hostname, $address_family = AF_INET, $attribs = array()) { global $config; $response = array(); diff --git a/includes/polling/functions.inc.php b/includes/polling/functions.inc.php index 77017ac94..6a993a91d 100644 --- a/includes/polling/functions.inc.php +++ b/includes/polling/functions.inc.php @@ -155,7 +155,7 @@ function poll_device($device, $options) { $address_family = snmpTransportToAddressFamily($device['transport']); - $ping_response = isPingable($device['hostname'], $address_family, $device['device_id'], $attribs); + $ping_response = isPingable($device['hostname'], $address_family, $attribs); $device_perf = $ping_response['db']; $device_perf['device_id'] = $device['device_id']; From 952748fa5b56f036682917891548b4da30e84da5 Mon Sep 17 00:00:00 2001 From: vitalisator Date: Sat, 17 Oct 2015 22:41:30 +0200 Subject: [PATCH 588/598] fixed powerdns snmp checks --- includes/polling/applications/powerdns.inc.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/includes/polling/applications/powerdns.inc.php b/includes/polling/applications/powerdns.inc.php index 94e0076fb..3a7c728c2 100644 --- a/includes/polling/applications/powerdns.inc.php +++ b/includes/polling/applications/powerdns.inc.php @@ -3,9 +3,10 @@ // Polls powerdns statistics from script via SNMP $rrd_filename = $config['rrd_dir'].'/'.$device['hostname'].'/app-powerdns-'.$app['app_id'].'.rrd'; $options = '-O qv'; +$mib = 'NET-SNMP-EXTEND-MIB'; $oid = 'nsExtendOutputFull.8.112.111.119.101.114.100.110.115'; -$powerdns = snmp_get($device, $oid, $options); +$powerdns = snmp_get($device, $oid, $options, $mib); echo ' powerdns'; From 819f6bb78ebff50fc65c1711390eebf062cc00d8 Mon Sep 17 00:00:00 2001 From: laf Date: Sat, 17 Oct 2015 20:57:22 +0000 Subject: [PATCH 589/598] Updated default crons --- librenms.cron | 1 + librenms.nonroot.cron | 1 + 2 files changed, 2 insertions(+) diff --git a/librenms.cron b/librenms.cron index f03f5316d..b72d723f3 100644 --- a/librenms.cron +++ b/librenms.cron @@ -5,3 +5,4 @@ */5 * * * * root /opt/librenms/cronic /opt/librenms/poller-wrapper.py 16 15 0 * * * root /opt/librenms/daily.sh >> /dev/null 2>&1 * * * * * root /opt/librenms/alerts.php >> /dev/null 2>&1 +*/5 * * * * root /opt/librenms/check-services.php >> /dev/null 2>&1 diff --git a/librenms.nonroot.cron b/librenms.nonroot.cron index 3c83bf8b1..d3dfd72d0 100644 --- a/librenms.nonroot.cron +++ b/librenms.nonroot.cron @@ -5,3 +5,4 @@ */5 * * * * librenms /opt/librenms/cronic /opt/librenms/poller-wrapper.py 16 15 0 * * * librenms /opt/librenms/daily.sh >> /dev/null 2>&1 * * * * * librenms /opt/librenms/alerts.php >> /dev/null 2>&1 +*/5 * * * * librenms /opt/librenms/check-services.php >> /dev/null 2>&1 From ff1fc6f143533aa7a3114ad2174b4bece013f493 Mon Sep 17 00:00:00 2001 From: laf Date: Sat, 17 Oct 2015 21:00:53 +0000 Subject: [PATCH 590/598] Scrut fix --- includes/polling/functions.inc.php | 1 + 1 file changed, 1 insertion(+) diff --git a/includes/polling/functions.inc.php b/includes/polling/functions.inc.php index 6a993a91d..fff7bbe45 100644 --- a/includes/polling/functions.inc.php +++ b/includes/polling/functions.inc.php @@ -146,6 +146,7 @@ function poll_device($device, $options) { unset($poll_update_query); unset($poll_separator); $poll_update_array = array(); + $update_array = array(); $host_rrd = $config['rrd_dir'].'/'.$device['hostname']; if (!is_dir($host_rrd)) { From 3cbb1a646294715b2e302cf341d71f07096c9083 Mon Sep 17 00:00:00 2001 From: laf Date: Sat, 17 Oct 2015 21:04:29 +0000 Subject: [PATCH 591/598] Fix alignment --- librenms.cron | 2 +- librenms.nonroot.cron | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/librenms.cron b/librenms.cron index b72d723f3..f5ba93740 100644 --- a/librenms.cron +++ b/librenms.cron @@ -5,4 +5,4 @@ */5 * * * * root /opt/librenms/cronic /opt/librenms/poller-wrapper.py 16 15 0 * * * root /opt/librenms/daily.sh >> /dev/null 2>&1 * * * * * root /opt/librenms/alerts.php >> /dev/null 2>&1 -*/5 * * * * root /opt/librenms/check-services.php >> /dev/null 2>&1 +*/5 * * * * root /opt/librenms/check-services.php >> /dev/null 2>&1 diff --git a/librenms.nonroot.cron b/librenms.nonroot.cron index d3dfd72d0..5f55ad775 100644 --- a/librenms.nonroot.cron +++ b/librenms.nonroot.cron @@ -5,4 +5,4 @@ */5 * * * * librenms /opt/librenms/cronic /opt/librenms/poller-wrapper.py 16 15 0 * * * librenms /opt/librenms/daily.sh >> /dev/null 2>&1 * * * * * librenms /opt/librenms/alerts.php >> /dev/null 2>&1 -*/5 * * * * librenms /opt/librenms/check-services.php >> /dev/null 2>&1 +*/5 * * * * librenms /opt/librenms/check-services.php >> /dev/null 2>&1 From e9deae13151614cad5239fc396b9fcd7f88991b2 Mon Sep 17 00:00:00 2001 From: laf Date: Tue, 20 Oct 2015 21:35:08 +0000 Subject: [PATCH 592/598] Centralised the date selector for graphs for re-use --- html/includes/print-date-selector.inc.php | 40 +++++++++++++++++ html/index.php | 1 + html/js/librenms.js | 12 ++++++ html/pages/device/edit.inc.php | 2 - html/pages/devices.inc.php | 52 +++++++++++++++++------ html/pages/graphs.inc.php | 51 +--------------------- html/pages/settings.inc.php | 2 - 7 files changed, 94 insertions(+), 66 deletions(-) create mode 100644 html/includes/print-date-selector.inc.php diff --git a/html/includes/print-date-selector.inc.php b/html/includes/print-date-selector.inc.php new file mode 100644 index 000000000..3333df0b6 --- /dev/null +++ b/html/includes/print-date-selector.inc.php @@ -0,0 +1,40 @@ + + + +"; + +echo ' +
    + + +
    +
    + + +
    + + + +'; diff --git a/html/index.php b/html/index.php index e42190acc..6499e2c27 100644 --- a/html/index.php +++ b/html/index.php @@ -165,6 +165,7 @@ else { +