ADD: Добавлена работа с UserAgent

* Удалена таблица users_logs, добавлена таблица users_agent_logs
* Введен «шепот» (заметки для модераторов)
* Изменен поиск по IP (по регистрации и логам)
* Доработана админ-панель для отображения дублирующих аккаунтов...
* Добавлены иконки браузеров...
* Незначительные изменения в шаблонах
This commit is contained in:
Evg 2021-09-22 17:47:59 +03:00
parent cd2de35348
commit e4585e738a
43 changed files with 1374 additions and 325 deletions

View file

@ -0,0 +1,38 @@
<?php
namespace App\Controllers;
use Hleb\Scheme\App\Controllers\MainController;
use Hleb\Constructor\Handlers\Request;
use App\Models\AgentModel;
use Agouti\Base;
class AgentController extends MainController
{
public function index()
{
$uid = Base::getUid();
$limit = 100;
$ua_info = AgentModel::getAll($limit);
return $ua_info;
}
public function set()
{
// https://github.com/donatj/PhpUserAgent
require_once HLEB_GLOBAL_DIRECTORY .'/app/ThirdParty/PhpUserAgent/UserAgentParser.php';
$uid = Base::getUid();
$ua_info = parse_user_agent();
$data = [
'log_date' => date("Y-m-d H:i:s"),
'log_user_id' => $uid['user_id'],
'log_user_browser' => $ua_info['browser'] . ' ' . $ua_info['version'],
'log_user_os' => $ua_info['platform'],
'log_user_ip' => Request::getRemoteAddress(),
];
AgentModel::setLog($data);
}
}

View file

@ -51,10 +51,8 @@ class LoginController extends MainController
Base::rememberMe($uid['user_id']);
}
$last_ip = Request::getRemoteAddress();
UserModel::setUserLastLogs($uid['user_id'], $uid['user_login'], $uid['user_trust_level'], $last_ip);
Base::setUserSession($uid);
$set = (new \App\Controllers\AgentController())->set();
redirect('/');
}

View file

@ -14,6 +14,7 @@ return [
'The post' => 'Post',
'Bodies' => 'Corp',
'Thanks' => 'Mulțumiri',
'Whisper' => 'șoaptă',
'Report' => 'Steag',
'Reports' => 'Steaguri',
'complained about' => 'S-a plâns',

View file

@ -18,6 +18,7 @@ return [
'The post' => 'Поста',
'Bodies' => 'Тела',
'Thanks' => 'Спасибо',
'Whisper' => 'Шёпот',
'Report' => 'Флаг',
'Reports' => 'Флаги',
'complained about' => 'пожаловался на',

View file

@ -12,6 +12,7 @@ class Integration
{
$api_url = 'https://www.google.com/recaptcha/api/siteverify';
// https://github.com/php-mod/curl
if (!function_exists('curl_init')) {
$data = @file_get_contents($api_url . '?' . http_build_query($params));

91
app/Models/AgentModel.php Normal file
View file

@ -0,0 +1,91 @@
<?php
namespace App\Models;
use Hleb\Scheme\App\Models\MainModel;
use DB;
use PDO;
class AgentModel extends MainModel
{
public static function getAll($limit)
{
$sql = "SELECT log_id,
log_date,
log_user_id,
log_user_browser,
log_user_os,
log_user_ip
FROM users_agent_logs ORDER BY log_id DESC LIMIT :limit";
return DB::run($sql, ['limit' =>$limit])->fetchAll(PDO::FETCH_ASSOC);
}
public static function getUser($user_id)
{
$sql = "SELECT log_id,
log_date,
log_user_id,
log_user_browser,
log_user_os,
log_user_ip
FROM users_agent_logs WHERE log_user_id = :user_id";
return DB::run($sql, ['user_id' => $user_id])->fetch(PDO::FETCH_ASSOC);
}
public static function setLog($data)
{
$params = [
'log_date' => $data['log_date'],
'log_user_id' => $data['log_user_id'],
'log_user_browser' => $data['log_user_browser'],
'log_user_os' => $data['log_user_os'],
'log_user_ip' => $data['log_user_ip'],
];
$sql = "INSERT INTO users_agent_logs(log_date,
log_user_id,
log_user_browser,
log_user_os,
log_user_ip)
VALUES(:log_date,
:log_user_id,
:log_user_browser,
:log_user_os,
:log_user_ip)";
return DB::run($sql, $params);
}
// Последние визиты
public static function getLastVisit()
{
$sql = "SELECT
user_id,
user_login,
user_name,
user_email,
user_avatar,
user_created_at,
user_reg_ip,
user_invitation_id,
user_trust_level,
latest_date
FROM users
JOIN
( SELECT
MAX(log_date) as latest_date,
log_user_id
FROM users_agent_logs
GROUP BY log_user_id
) as latest_date
ON latest_date.log_user_id = user_id
ORDER BY latest_date DESC LIMIT 10 ";
return DB::run($sql)->fetchAll(PDO::FETCH_ASSOC);
}
}

View file

@ -50,6 +50,7 @@ class UserModel extends MainModel
user_id,
user_login,
user_name,
user_whisper,
user_activated,
user_limiting_mode,
user_reg_ip,
@ -100,18 +101,22 @@ class UserModel extends MainModel
}
$params = [
'user_login' => $login,
'user_email' => $email,
'user_password' => $password,
'user_limiting_mode' => 0, // Режим заморозки выключен
'user_activated' => $activated,
'user_reg_ip' => $reg_ip,
'user_trust_level' => $trust_level,
'user_invitation_id' => $invitation_id,
'user_login' => $login,
'user_email' => $email,
'user_design_is_minimal' => 0, // По умолчанию, дизайн блоговый
'user_whisper' => '',
'user_password' => $password,
'user_limiting_mode' => 0, // Режим заморозки выключен
'user_activated' => $activated,
'user_reg_ip' => $reg_ip,
'user_trust_level' => $trust_level,
'user_invitation_id' => $invitation_id,
];
$sql = "INSERT INTO users(user_login,
user_email,
user_email,
user_design_is_minimal,
user_whisper,
user_password,
user_limiting_mode,
user_activated,
@ -121,6 +126,8 @@ class UserModel extends MainModel
VALUES(:user_login,
:user_email,
:user_design_is_minimal,
:user_whisper,
:user_password,
:user_limiting_mode,
:user_activated,
@ -345,22 +352,6 @@ class UserModel extends MainModel
return DB::run($sql, $params);
}
// Записываем последние данные авторизации
public static function setUserLastLogs($user_id, $login, $trust_level, $last_ip)
{
$params = [
'logs_user_id' => $user_id,
'logs_login' => $login,
'logs_trust_level' => $trust_level,
'logs_ip_address' => $last_ip,
];
$sql = "INSERT INTO users_logs(logs_user_id, logs_login, logs_trust_level, logs_ip_address)
VALUES(:logs_user_id, :logs_login, :logs_trust_level, :logs_ip_address)";
return DB::run($sql, $params);
}
// Находит ли пользователь в бан- листе
public static function isBan($user_id)
{

22
app/ThirdParty/PhpUserAgent/LICENSE.md vendored Normal file
View file

@ -0,0 +1,22 @@
The MIT License
===============
Copyright (c) 2013 Jesse G. Donat
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

192
app/ThirdParty/PhpUserAgent/README.md vendored Normal file
View file

@ -0,0 +1,192 @@
# PHP User Agent Parser
[![Join the chat at https://gitter.im/PhpUserAgentParser/Lobby](https://badges.gitter.im/PhpUserAgentParser/Lobby.svg)](https://gitter.im/PhpUserAgentParser/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Latest Stable Version](https://poser.pugx.org/donatj/phpuseragentparser/version)](https://packagist.org/packages/donatj/phpuseragentparser)
[![Total Downloads](https://poser.pugx.org/donatj/phpuseragentparser/downloads)](https://packagist.org/packages/donatj/phpuseragentparser)
[![License](https://poser.pugx.org/donatj/phpuseragentparser/license)](https://packagist.org/packages/donatj/phpuseragentparser)
[![CI](https://github.com/donatj/phpUserAgent/workflows/CI/badge.svg?)](https://github.com/donatj/phpUserAgent/actions?query=workflow%3ACI)
## What It Is
A simple, streamlined PHP user-agent parser!
Licensed under the MIT license: https://www.opensource.org/licenses/mit-license.php
## Upgrading to `1.*`
The new `1.*` release **does not break compatibility** with `0.*` and nothing need to change to upgrade. However, the global `parse_user_agent` is now deprecated; it has been replaced with the namespaced `\donatj\UserAgent\parse_user_agent` and functions exactly the same. You can easily replace any existing call to `parse_user_agent` with `\donatj\UserAgent\parse_user_agent`
In addition, 1.x adds a convenience object wrapper you may use should you prefer. More information on this is in the Usage section below.
## Why Use This
You have your choice in user-agent parsers. This one detects **all modern browsers** in a very light, quick, understandable fashion.
It is less than 200 lines of code, and consists of just three regular expressions!
It can also correctly identify exotic versions of IE others fail on.
It offers 100% unit test coverage, is installable via Composer, and is very easy to use.
## What It Does Not Do
This is not meant as a browser "knowledge engine" but rather a simple parser. Anything not adequately provided directly by the user agent string itself will simply not be provided by this.
### OS Versions
User-agent strings **are not** a reliable source of OS Version!
- Many agents simply don't send the information.
- Others provide varying levels of accuracy.
- Parsing Windows versions alone almost nearly doubles the size of the code.
I'm much more interested in keeping this thing *tiny* and accurate than adding niché features and would rather focus on things that can be **done well**.
All that said, there is the start of a [branch to do it](https://github.com/donatj/PhpUserAgent/tree/os_version_detection) I created for a client if you want to poke it, I update it from time to time, but frankly if you need to *reliably detect OS Version*, using user-agent isn't the way to do it. I'd go with JavaScript.
### Undetectable Browsers
- **Brave** - Brave is simply not differentiable from Chrome. This was a design decision on their part.
### Undetectable Platforms
- **iPadOS 13+** - Starting with iPadOS 13 and further hardened in 14, iPadOS returns the **exact** same string as macOS. It is no longer distinguishable by UA string. (See: [#69](https://github.com/donatj/PhpUserAgent/issues/69))
## Requirements
- **php**: >=5.4.0
## Installing
PHP User Agent is available through Packagist via Composer.
Install the latest version with:
```bash
composer require 'donatj/phpuseragentparser'
```
## Usage
The classic procedural use is as simple as:
```php
$ua_info = parse_user_agent();
/*
[
'platform' => '[Detected Platform]',
'browser' => '[Detected Browser]',
'version' => '[Detected Browser Version]',
]
*/
```
The new object oriented wrapper form:
```php
$parser = new UserAgentParser();
$ua = $parser->parse();
// or
$ua = $parser();
$ua->platform();
$ua->browser();
$ua->browserVersion();
```
## Currently Detected Platforms
Predefined helper constants from `donatj\UserAgent\Platforms`
| Constant | Platform |
|----------|----------|
| `Platforms::MACINTOSH` | Macintosh |
| `Platforms::CHROME_OS` | Chrome OS |
| `Platforms::LINUX` | Linux |
| `Platforms::WINDOWS` | Windows |
| `Platforms::ANDROID` | Android |
| `Platforms::BLACKBERRY` | BlackBerry |
| `Platforms::FREEBSD` | FreeBSD |
| `Platforms::IPAD` | iPad |
| `Platforms::IPHONE` | iPhone |
| `Platforms::IPOD` | iPod |
| `Platforms::KINDLE` | Kindle |
| `Platforms::KINDLE_FIRE` | Kindle Fire |
| `Platforms::NETBSD` | NetBSD |
| `Platforms::NEW_NINTENDO_3DS` | New Nintendo 3DS |
| `Platforms::NINTENDO_3DS` | Nintendo 3DS |
| `Platforms::NINTENDO_DS` | Nintendo DS |
| `Platforms::NINTENDO_SWITCH` | Nintendo Switch |
| `Platforms::NINTENDO_WII` | Nintendo Wii |
| `Platforms::NINTENDO_WIIU` | Nintendo WiiU |
| `Platforms::OPENBSD` | OpenBSD |
| `Platforms::PLAYBOOK` | PlayBook |
| `Platforms::PLAYSTATION_3` | PlayStation 3 |
| `Platforms::PLAYSTATION_4` | PlayStation 4 |
| `Platforms::PLAYSTATION_5` | PlayStation 5 |
| `Platforms::PLAYSTATION_VITA` | PlayStation Vita |
| `Platforms::SAILFISH` | Sailfish |
| `Platforms::SYMBIAN` | Symbian |
| `Platforms::TIZEN` | Tizen |
| `Platforms::WINDOWS_PHONE` | Windows Phone |
| `Platforms::XBOX` | Xbox |
| `Platforms::XBOX_ONE` | Xbox One |
## Currently Detected Browsers
Predefined helper constants from `donatj\UserAgent\Browsers`
| Constant | Browser |
|----------|----------|
| `Browsers::ADSBOT_GOOGLE` | AdsBot-Google |
| `Browsers::ANDROID_BROWSER` | Android Browser |
| `Browsers::APPLEBOT` | Applebot |
| `Browsers::BAIDUSPIDER` | Baiduspider |
| `Browsers::BINGBOT` | bingbot |
| `Browsers::BLACKBERRY_BROWSER` | BlackBerry Browser |
| `Browsers::BROWSER` | Browser |
| `Browsers::BUNJALLOO` | Bunjalloo |
| `Browsers::CAMINO` | Camino |
| `Browsers::CHROME` | Chrome |
| `Browsers::CURL` | curl |
| `Browsers::EDGE` | Edge |
| `Browsers::FACEBOOKEXTERNALHIT` | facebookexternalhit |
| `Browsers::FEEDVALIDATOR` | FeedValidator |
| `Browsers::FIREFOX` | Firefox |
| `Browsers::GOOGLEBOT` | Googlebot |
| `Browsers::GOOGLEBOT_IMAGE` | Googlebot-Image |
| `Browsers::GOOGLEBOT_VIDEO` | Googlebot-Video |
| `Browsers::HEADLESSCHROME` | HeadlessChrome |
| `Browsers::IEMOBILE` | IEMobile |
| `Browsers::IMESSAGEBOT` | iMessageBot |
| `Browsers::KINDLE` | Kindle |
| `Browsers::LYNX` | Lynx |
| `Browsers::MIDORI` | Midori |
| `Browsers::MIUIBROWSER` | MiuiBrowser |
| `Browsers::MSIE` | MSIE |
| `Browsers::MSNBOT_MEDIA` | msnbot-media |
| `Browsers::NETFRONT` | NetFront |
| `Browsers::NINTENDOBROWSER` | NintendoBrowser |
| `Browsers::OCULUSBROWSER` | OculusBrowser |
| `Browsers::OPERA` | Opera |
| `Browsers::PUFFIN` | Puffin |
| `Browsers::SAFARI` | Safari |
| `Browsers::SAILFISHBROWSER` | SailfishBrowser |
| `Browsers::SAMSUNGBROWSER` | SamsungBrowser |
| `Browsers::SILK` | Silk |
| `Browsers::TELEGRAMBOT` | TelegramBot |
| `Browsers::TIZENBROWSER` | TizenBrowser |
| `Browsers::TWITTERBOT` | Twitterbot |
| `Browsers::UC_BROWSER` | UC Browser |
| `Browsers::VALVE_STEAM_TENFOOT` | Valve Steam Tenfoot |
| `Browsers::VIVALDI` | Vivaldi |
| `Browsers::WGET` | Wget |
| `Browsers::WORDPRESS` | WordPress |
| `Browsers::YANDEX` | Yandex |
| `Browsers::YANDEXBOT` | YandexBot |
More information is available at [Donat Studios](https://donatstudios.com/PHP-Parser-HTTP_USER_AGENT).

View file

@ -0,0 +1,57 @@
<?php
// DO NOT EDIT THIS FILE - IT IS GENERATED BY constant_generator.php
namespace donatj\UserAgent;
interface Browsers {
const ADSBOT_GOOGLE = 'AdsBot-Google';
const ANDROID_BROWSER = 'Android Browser';
const APPLEBOT = 'Applebot';
const BAIDUSPIDER = 'Baiduspider';
const BINGBOT = 'bingbot';
const BLACKBERRY_BROWSER = 'BlackBerry Browser';
const BROWSER = 'Browser';
const BUNJALLOO = 'Bunjalloo';
const CAMINO = 'Camino';
const CHROME = 'Chrome';
const CURL = 'curl';
const EDGE = 'Edge';
const FACEBOOKEXTERNALHIT = 'facebookexternalhit';
const FEEDVALIDATOR = 'FeedValidator';
const FIREFOX = 'Firefox';
const GOOGLEBOT = 'Googlebot';
const GOOGLEBOT_IMAGE = 'Googlebot-Image';
const GOOGLEBOT_VIDEO = 'Googlebot-Video';
const HEADLESSCHROME = 'HeadlessChrome';
const IEMOBILE = 'IEMobile';
const IMESSAGEBOT = 'iMessageBot';
const KINDLE = 'Kindle';
const LYNX = 'Lynx';
const MIDORI = 'Midori';
const MIUIBROWSER = 'MiuiBrowser';
const MSIE = 'MSIE';
const MSNBOT_MEDIA = 'msnbot-media';
const NETFRONT = 'NetFront';
const NINTENDOBROWSER = 'NintendoBrowser';
const OCULUSBROWSER = 'OculusBrowser';
const OPERA = 'Opera';
const PUFFIN = 'Puffin';
const SAFARI = 'Safari';
const SAILFISHBROWSER = 'SailfishBrowser';
const SAMSUNGBROWSER = 'SamsungBrowser';
const SILK = 'Silk';
const TELEGRAMBOT = 'TelegramBot';
const TIZENBROWSER = 'TizenBrowser';
const TWITTERBOT = 'Twitterbot';
const UC_BROWSER = 'UC Browser';
const VALVE_STEAM_TENFOOT = 'Valve Steam Tenfoot';
const VIVALDI = 'Vivaldi';
const WGET = 'Wget';
const WORDPRESS = 'WordPress';
const YANDEX = 'Yandex';
const YANDEXBOT = 'YandexBot';
}

View file

@ -0,0 +1,42 @@
<?php
// DO NOT EDIT THIS FILE - IT IS GENERATED BY constant_generator.php
namespace donatj\UserAgent;
interface Platforms {
const MACINTOSH = 'Macintosh';
const CHROME_OS = 'Chrome OS';
const LINUX = 'Linux';
const WINDOWS = 'Windows';
const ANDROID = 'Android';
const BLACKBERRY = 'BlackBerry';
const FREEBSD = 'FreeBSD';
const IPAD = 'iPad';
const IPHONE = 'iPhone';
const IPOD = 'iPod';
const KINDLE = 'Kindle';
const KINDLE_FIRE = 'Kindle Fire';
const NETBSD = 'NetBSD';
const NEW_NINTENDO_3DS = 'New Nintendo 3DS';
const NINTENDO_3DS = 'Nintendo 3DS';
const NINTENDO_DS = 'Nintendo DS';
const NINTENDO_SWITCH = 'Nintendo Switch';
const NINTENDO_WII = 'Nintendo Wii';
const NINTENDO_WIIU = 'Nintendo WiiU';
const OPENBSD = 'OpenBSD';
const PLAYBOOK = 'PlayBook';
const PLAYSTATION_3 = 'PlayStation 3';
const PLAYSTATION_4 = 'PlayStation 4';
const PLAYSTATION_5 = 'PlayStation 5';
const PLAYSTATION_VITA = 'PlayStation Vita';
const SAILFISH = 'Sailfish';
const SYMBIAN = 'Symbian';
const TIZEN = 'Tizen';
const WINDOWS_PHONE = 'Windows Phone';
const XBOX = 'Xbox';
const XBOX_ONE = 'Xbox One';
}

View file

@ -0,0 +1,57 @@
<?php
namespace donatj\UserAgent;
class UserAgent implements UserAgentInterface {
/**
* @var string|null
*/
private $platform;
/**
* @var string|null
*/
private $browser;
/**
* @var string|null
*/
private $browserVersion;
/**
* UserAgent constructor.
*
* @param string|null $platform
* @param string|null $browser
* @param string|null $browserVersion
*/
public function __construct( $platform, $browser, $browserVersion ) {
$this->platform = $platform;
$this->browser = $browser;
$this->browserVersion = $browserVersion;
}
/**
* @return string|null
* @see \donatj\UserAgent\Platforms for a list of tested platforms
*/
public function platform() {
return $this->platform;
}
/**
* @return string|null
* @see \donatj\UserAgent\Browsers for a list of tested browsers.
*/
public function browser() {
return $this->browser;
}
/**
* The version string. Formatting depends on the browser.
*
* @return string|null
*/
public function browserVersion() {
return $this->browserVersion;
}
}

View file

@ -0,0 +1,25 @@
<?php
namespace donatj\UserAgent;
interface UserAgentInterface {
/**
* @return string|null
* @see \donatj\UserAgent\Platforms for a list of tested platforms
*/
public function platform();
/**
* @return string|null
* @see \donatj\UserAgent\Browsers for a list of tested browsers.
*/
public function browser();
/**
* The version string. Formatting depends on the browser.
*
* @return string|null
*/
public function browserVersion();
}

View file

@ -0,0 +1,39 @@
<?php
namespace donatj\UserAgent;
class UserAgentParser {
/**
* Parses a user agent string into its important parts, provide an object
*
* @param string|null $u_agent User agent string to parse or null. Uses $_SERVER['HTTP_USER_AGENT'] on NULL
* @return UserAgent an object with 'browser', 'browserVersion' and 'platform' methods
* @throws \InvalidArgumentException on not having a proper user agent to parse.
* @see \donatj\UserAgent\parse_user_agent()
*
*/
public function parse( $u_agent = null ) {
$parsed = parse_user_agent($u_agent);
return new UserAgent(
$parsed[PLATFORM],
$parsed[BROWSER],
$parsed[BROWSER_VERSION]
);
}
/**
* Parses a user agent string into its important parts
*
* @param string|null $u_agent User agent string to parse or null. Uses $_SERVER['HTTP_USER_AGENT'] on NULL
* @return UserAgent an object with 'browser', 'browserVersion' and 'platform' methods
* @throws \InvalidArgumentException on not having a proper user agent to parse.
* @see \donatj\UserAgent\parse_user_agent()
*
*/
public function __invoke( $u_agent = null ) {
return $this->parse($u_agent);
}
}

View file

@ -0,0 +1,213 @@
<?php
/**
* @author Jesse G. Donat <donatj@gmail.com>
*
* @link https://donatstudios.com/PHP-Parser-HTTP_USER_AGENT
* @link https://github.com/donatj/PhpUserAgent
*
* @license MIT https://github.com/donatj/PhpUserAgent/blob/master/LICENSE.md
*/
namespace {
/**
* Parses a user agent string into its important parts
*
* This method is defined for backwards comparability with the old global method.
*
* @param string|null $u_agent User agent string to parse or null. Uses $_SERVER['HTTP_USER_AGENT'] on NULL
* @return string[] an array with 'browser', 'version' and 'platform' keys
* @throws \InvalidArgumentException on not having a proper user agent to parse.
*
* @deprecated This exists for backwards compatibility with 0.x and will likely be removed in 2.x
* @see \donatj\UserAgent\parse_user_agent
*/
function parse_user_agent( $u_agent = null ) {
return \donatj\UserAgent\parse_user_agent($u_agent);
}
}
namespace donatj\UserAgent {
const PLATFORM = 'platform';
const BROWSER = 'browser';
const BROWSER_VERSION = 'version';
/**
* Parses a user agent string into its important parts
*
* @param string|null $u_agent User agent string to parse or null. Uses $_SERVER['HTTP_USER_AGENT'] on NULL
* @return string[] an array with 'browser', 'version' and 'platform' keys
* @throws \InvalidArgumentException on not having a proper user agent to parse.
*/
function parse_user_agent( $u_agent = null ) {
if( $u_agent === null && isset($_SERVER['HTTP_USER_AGENT']) ) {
$u_agent = (string)$_SERVER['HTTP_USER_AGENT'];
}
if( $u_agent === null ) {
throw new \InvalidArgumentException('parse_user_agent requires a user agent');
}
$platform = null;
$browser = null;
$version = null;
$return = [ PLATFORM => &$platform, BROWSER => &$browser, BROWSER_VERSION => &$version ];
if( !$u_agent ) {
return $return;
}
if( preg_match('/\((.*?)\)/m', $u_agent, $parent_matches) ) {
preg_match_all(<<<'REGEX'
/(?P<platform>BB\d+;|Android|Adr|Symbian|Sailfish|CrOS|Tizen|iPhone|iPad|iPod|Linux|(Open|Net|Free)BSD|Macintosh|Windows(\ Phone)?|Silk|linux-gnu|BlackBerry|PlayBook|X11|(New\ )?Nintendo\ (WiiU?|3?DS|Switch)|Xbox(\ One)?)
(?:\ [^;]*)?
(?:;|$)/imx
REGEX
, $parent_matches[1], $result);
$priority = [ 'Xbox One', 'Xbox', 'Windows Phone', 'Tizen', 'Android', 'FreeBSD', 'NetBSD', 'OpenBSD', 'CrOS', 'X11', 'Sailfish' ];
$result[PLATFORM] = array_unique($result[PLATFORM]);
if( count($result[PLATFORM]) > 1 ) {
if( $keys = array_intersect($priority, $result[PLATFORM]) ) {
$platform = reset($keys);
} else {
$platform = $result[PLATFORM][0];
}
} elseif( isset($result[PLATFORM][0]) ) {
$platform = $result[PLATFORM][0];
}
}
if( $platform == 'linux-gnu' || $platform == 'X11' ) {
$platform = 'Linux';
} elseif( $platform == 'CrOS' ) {
$platform = 'Chrome OS';
} elseif( $platform == 'Adr' ) {
$platform = 'Android';
}
preg_match_all(<<<'REGEX'
%(?P<browser>Camino|Kindle(\ Fire)?|Firefox|Iceweasel|IceCat|Safari|MSIE|Trident|AppleWebKit|
TizenBrowser|(?:Headless)?Chrome|YaBrowser|Vivaldi|IEMobile|Opera|OPR|Silk|Midori|Edge|Edg|CriOS|UCBrowser|Puffin|
OculusBrowser|SamsungBrowser|SailfishBrowser|XiaoMi/MiuiBrowser|
Baiduspider|Applebot|Facebot|Googlebot|YandexBot|bingbot|Lynx|Version|Wget|curl|
Valve\ Steam\ Tenfoot|
NintendoBrowser|PLAYSTATION\ (\d|Vita)+)
\)?;?
(?:[:/ ](?P<version>[0-9A-Z.]+)|/[A-Z]*)%ix
REGEX
, $u_agent, $result);
// If nothing matched, return null (to avoid undefined index errors)
if( !isset($result[BROWSER][0]) || !isset($result[BROWSER_VERSION][0]) ) {
if( preg_match('%^(?!Mozilla)(?P<browser>[A-Z0-9\-]+)(/(?P<version>[0-9A-Z.]+))?%ix', $u_agent, $result) ) {
return [ PLATFORM => $platform ?: null, BROWSER => $result[BROWSER], BROWSER_VERSION => empty($result[BROWSER_VERSION]) ? null : $result[BROWSER_VERSION] ];
}
return $return;
}
if( preg_match('/rv:(?P<version>[0-9A-Z.]+)/i', $u_agent, $rv_result) ) {
$rv_result = $rv_result[BROWSER_VERSION];
}
$browser = $result[BROWSER][0];
$version = $result[BROWSER_VERSION][0];
$lowerBrowser = array_map('strtolower', $result[BROWSER]);
$find = function ( $search, &$key = null, &$value = null ) use ( $lowerBrowser ) {
$search = (array)$search;
foreach( $search as $val ) {
$xkey = array_search(strtolower($val), $lowerBrowser);
if( $xkey !== false ) {
$value = $val;
$key = $xkey;
return true;
}
}
return false;
};
$findT = function ( array $search, &$key = null, &$value = null ) use ( $find ) {
$value2 = null;
if( $find(array_keys($search), $key, $value2) ) {
$value = $search[$value2];
return true;
}
return false;
};
$key = 0;
$val = '';
if( $findT([ 'OPR' => 'Opera', 'Facebot' => 'iMessageBot', 'UCBrowser' => 'UC Browser', 'YaBrowser' => 'Yandex', 'Iceweasel' => 'Firefox', 'Icecat' => 'Firefox', 'CriOS' => 'Chrome', 'Edg' => 'Edge', 'XiaoMi/MiuiBrowser' => 'MiuiBrowser' ], $key, $browser) ) {
$version = is_numeric(substr($result[BROWSER_VERSION][$key], 0, 1)) ? $result[BROWSER_VERSION][$key] : null;
} elseif( $find('Playstation Vita', $key, $platform) ) {
$platform = 'PlayStation Vita';
$browser = 'Browser';
} elseif( $find([ 'Kindle Fire', 'Silk' ], $key, $val) ) {
$browser = $val == 'Silk' ? 'Silk' : 'Kindle';
$platform = 'Kindle Fire';
if( !($version = $result[BROWSER_VERSION][$key]) || !is_numeric($version[0]) ) {
$version = $result[BROWSER_VERSION][array_search('Version', $result[BROWSER])];
}
} elseif( $find('NintendoBrowser', $key) || $platform == 'Nintendo 3DS' ) {
$browser = 'NintendoBrowser';
$version = $result[BROWSER_VERSION][$key];
} elseif( $find('Kindle', $key, $platform) ) {
$browser = $result[BROWSER][$key];
$version = $result[BROWSER_VERSION][$key];
} elseif( $find('Opera', $key, $browser) ) {
$find('Version', $key);
$version = $result[BROWSER_VERSION][$key];
} elseif( $find('Puffin', $key, $browser) ) {
$version = $result[BROWSER_VERSION][$key];
if( strlen($version) > 3 ) {
$part = substr($version, -2);
if( ctype_upper($part) ) {
$version = substr($version, 0, -2);
$flags = [ 'IP' => 'iPhone', 'IT' => 'iPad', 'AP' => 'Android', 'AT' => 'Android', 'WP' => 'Windows Phone', 'WT' => 'Windows' ];
if( isset($flags[$part]) ) {
$platform = $flags[$part];
}
}
}
} elseif( $find([ 'Applebot', 'IEMobile', 'Edge', 'Midori', 'Vivaldi', 'OculusBrowser', 'SamsungBrowser', 'Valve Steam Tenfoot', 'Chrome', 'HeadlessChrome', 'SailfishBrowser' ], $key, $browser) ) {
$version = $result[BROWSER_VERSION][$key];
} elseif( $rv_result && $find('Trident') ) {
$browser = 'MSIE';
$version = $rv_result;
} elseif( $browser == 'AppleWebKit' ) {
if( $platform == 'Android' ) {
$browser = 'Android Browser';
} elseif( strpos($platform, 'BB') === 0 ) {
$browser = 'BlackBerry Browser';
$platform = 'BlackBerry';
} elseif( $platform == 'BlackBerry' || $platform == 'PlayBook' ) {
$browser = 'BlackBerry Browser';
} else {
$find('Safari', $key, $browser) || $find('TizenBrowser', $key, $browser);
}
$find('Version', $key);
$version = $result[BROWSER_VERSION][$key];
} elseif( $pKey = preg_grep('/playstation \d/i', $result[BROWSER]) ) {
$pKey = reset($pKey);
$platform = 'PlayStation ' . preg_replace('/\D/', '', $pKey);
$browser = 'NetFront';
}
return $return;
}
}

View file

@ -488,8 +488,10 @@ CREATE TABLE `users` (
`user_trust_level` int(11) NOT NULL COMMENT 'Уровень доверия. По умолчанию 0 (5 - админ)',
`user_created_at` datetime NOT NULL DEFAULT current_timestamp(),
`user_updated_at` datetime NOT NULL DEFAULT current_timestamp(),
`user_invitation_available` int(10) NOT NULL DEFAULT 0,
`user_invitation_available` int(11) NOT NULL DEFAULT 0,
`user_invitation_id` int(11) NOT NULL DEFAULT 0,
`user_design_is_minimal` tinyint(1) DEFAULT 0,
`user_whisper` varchar(255) NOT NULL,
`user_avatar` varchar(255) NOT NULL DEFAULT 'noavatar.png',
`user_cover_art` varchar(255) NOT NULL DEFAULT 'cover_art.jpeg',
`user_color` varchar(12) NOT NULL DEFAULT '#f56400',
@ -512,9 +514,9 @@ CREATE TABLE `users` (
-- Дамп данных таблицы `users`
--
INSERT INTO `users` (`user_id`, `user_login`, `user_name`, `user_email`, `user_password`, `user_activated`, `user_limiting_mode`, `user_reg_ip`, `user_trust_level`, `user_created_at`, `user_updated_at`, `user_invitation_available`, `user_invitation_id`, `user_avatar`, `user_cover_art`, `user_color`, `user_about`, `user_website`, `user_location`, `user_public_email`, `user_skype`, `user_twitter`, `user_telegram`, `user_vk`, `user_rating`, `user_my_post`, `user_ban_list`, `user_hits_count`, `user_is_deleted`) VALUES
(1, 'AdreS', 'Олег', 'ss@sdf.ru', '$2y$10$oR5VZ.zk7IN/og70gQq/f.0Sb.GQJ33VZHIES4pyIpU3W2vF6aiaW', 1, 0, '127.0.0.1', 5, '2021-03-08 21:37:04', '2021-03-08 21:37:04', 0, 0, 'img_1.jpg', 'cover_art.jpeg', '#f56400', 'Тестовый аккаунт', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0),
(2, 'test', NULL, 'test@test.ru', '$2y$10$Iahcsh3ima0kGqgk6S/SSui5/ETU5bQueYROFhOsjUU/z1.xynR7W', 1, 0, '127.0.0.1', 1, '2021-04-30 07:42:52', '2021-04-30 07:42:52', 0, 0, 'noavatar.png', 'cover_art.jpeg', '#339900', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0);
INSERT INTO `users` (`user_id`, `user_login`, `user_name`, `user_email`, `user_password`, `user_activated`, `user_limiting_mode`, `user_reg_ip`, `user_trust_level`, `user_created_at`, `user_updated_at`, `user_invitation_available`, `user_invitation_id`, `user_design_is_minimal`, `user_whisper`, `user_avatar`, `user_cover_art`, `user_color`, `user_about`, `user_website`, `user_location`, `user_public_email`, `user_skype`, `user_twitter`, `user_telegram`, `user_vk`, `user_rating`, `user_my_post`, `user_ban_list`, `user_hits_count`, `user_is_deleted`) VALUES
(1, 'AdreS', 'Олег', 'ss@sdf.ru', '$2y$10$oR5VZ.zk7IN/og70gQq/f.0Sb.GQJ33VZHIES4pyIpU3W2vF6aiaW', 1, 0, '127.0.0.1', 5, '2021-03-08 21:37:04', '2021-03-08 21:37:04', 0, 0, 0, '', 'img_1.jpg', 'cover_art.jpeg', '#f56400', 'Тестовый аккаунт', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0),
(2, 'test', NULL, 'test@test.ru', '$2y$10$Iahcsh3ima0kGqgk6S/SSui5/ETU5bQueYROFhOsjUU/z1.xynR7W', 1, 0, '127.0.0.1', 1, '2021-04-30 07:42:52', '2021-04-30 07:42:52', 0, 0, 0, '', 'noavatar.png', 'cover_art.jpeg', '#339900', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0);
-- --------------------------------------------------------
@ -578,34 +580,6 @@ CREATE TABLE `users_email_activate` (
-- --------------------------------------------------------
--
-- Структура таблицы `users_logs`
--
CREATE TABLE `users_logs` (
`logs_id` int(11) NOT NULL,
`logs_user_id` int(11) NOT NULL,
`logs_login` varchar(255) NOT NULL,
`logs_trust_level` int(11) NOT NULL,
`logs_ip_address` varchar(45) NOT NULL,
`logs_date` datetime NOT NULL DEFAULT current_timestamp()
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
--
-- Дамп данных таблицы `users_logs`
--
INSERT INTO `users_logs` (`logs_id`, `logs_user_id`, `logs_login`, `logs_trust_level`, `logs_ip_address`, `logs_date`) VALUES
(1, 1, 'AdreS', 5, '127.0.0.1', '2021-04-30 07:19:27'),
(2, 2, 'test', 1, '127.0.0.1', '2021-04-30 07:43:04'),
(3, 1, 'AdreS', 5, '127.0.0.1', '2021-07-02 07:33:25'),
(4, 2, 'test', 1, '127.0.0.1', '2021-07-02 07:34:26'),
(5, 1, 'AdreS', 5, '127.0.0.1', '2021-07-02 07:35:28'),
(6, 1, 'AdreS', 5, '127.0.0.1', '2021-08-16 17:23:55'),
(7, 1, 'AdreS', 5, '127.0.0.1', '2021-09-18 16:57:18');
-- --------------------------------------------------------
--
-- Структура таблицы `users_setting`
--
@ -711,6 +685,32 @@ CREATE TABLE `votes_post` (
INSERT INTO `votes_post` (`votes_post_id`, `votes_post_item_id`, `votes_post_points`, `votes_post_ip`, `votes_post_user_id`, `votes_post_date`) VALUES
(1, 2, 1, '127.0.0.1', 1, '2021-08-16 16:29:32');
--
-- Дамп, данные и индексы таблицы `users_agent_logs`
--
CREATE TABLE `users_agent_logs` (
`log_id` int(10) UNSIGNED NOT NULL,
`log_date` timestamp NOT NULL DEFAULT current_timestamp(),
`log_user_id` int(10) UNSIGNED NOT NULL,
`log_user_browser` varchar(64) NOT NULL,
`log_user_os` varchar(64) NOT NULL,
`log_user_ip` varchar(64) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
INSERT INTO `users_agent_logs` (`log_id`, `log_date`, `log_user_id`, `log_user_browser`, `log_user_os`, `log_user_ip`) VALUES
(1, '2021-09-21 13:09:38', 1, 'Firefox 92.0', 'Windows', '127.0.0.1'),
(2, '2021-09-21 13:57:57', 2, 'Chrome 93.0.4577.82', 'Windows', '127.0.0.1');
ALTER TABLE `users_agent_logs`
ADD PRIMARY KEY (`log_id`),
ADD KEY `log_user_ip` (`log_user_ip`);
ALTER TABLE `users_agent_logs`
MODIFY `log_id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=3;
--
-- Индексы сохранённых таблиц
--
@ -929,12 +929,6 @@ ALTER TABLE `users_banlist`
ALTER TABLE `users_email_activate`
ADD PRIMARY KEY (`id`);
--
-- Индексы таблицы `users_logs`
--
ALTER TABLE `users_logs`
ADD PRIMARY KEY (`logs_id`);
--
-- Индексы таблицы `users_setting`
--
@ -1150,12 +1144,6 @@ ALTER TABLE `users_banlist`
ALTER TABLE `users_email_activate`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
--
-- AUTO_INCREMENT для таблицы `users_logs`
--
ALTER TABLE `users_logs`
MODIFY `logs_id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=8;
--
-- AUTO_INCREMENT для таблицы `users_setting`
--

View file

@ -113,11 +113,6 @@ class TopicsController extends MainController
$topic = TopicModel::getTopic($topic_id, 'id');
Base::PageError404($topic);
$post_fields = Request::getPost() ?? [];
$topic_parent_id = implode(',', $post_fields['topic_parent_id'] ?? []);
$topic_related = implode(',', $post_fields['topic_related'] ?? []);
$topic_post_related = implode(',', $post_fields['post_related'] ?? []);
// Если убираем тему из корневой, то должны очистеть те темы, которые были подтемами
if ($topic['topic_is_parent'] == 1 && $topic_is_parent == 0) {
TopicModel::clearBinding($topic['topic_id']);
@ -132,11 +127,6 @@ class TopicsController extends MainController
Validation::Limits($topic_description, lang('Meta Description'), '44', '225', $redirect);
Validation::Limits($topic_info, lang('Info'), '14', '5000', $redirect);
$topic_merged_id = $topic_merged_id ?? 0;
$topic_parent_id = $topic_parent_id ?? 0;
$topic_is_parent = $topic_is_parent ?? 0;
$topic_count = $topic_count ?? 0;
// Запишем img
$img = $_FILES['images'];
$check_img = $_FILES['images']['name'][0];
@ -144,23 +134,21 @@ class TopicsController extends MainController
UploadImage::img($img, $topic['topic_id'], 'topic');
}
$topic_add_date = date("Y-m-d H:i:s");
$post_fields = Request::getPost() ?? [];
$data = [
'topic_id' => $topic_id,
'topic_title' => $topic_title,
'topic_description' => $topic_description,
'topic_info' => $topic_info,
'topic_slug' => $topic_slug,
'topic_add_date' => $topic_add_date,
'topic_seo_title' => $topic_seo_title,
'topic_merged_id' => $topic_merged_id,
'topic_parent_id' => $topic_parent_id,
'topic_parent_id' => implode(',', $post_fields['topic_parent_id'] ?? ['0']),
'topic_is_parent' => $topic_is_parent,
'topic_post_related' => $topic_post_related,
'topic_related' => $topic_related,
'topic_post_related' => implode(',', $post_fields['topic_post_related'] ?? ['0']),
'topic_related' => implode(',', $post_fields['topic_related'] ?? ['0']),
'topic_count' => $topic_count,
];
TopicModel::edit($data);
addMsg(lang('Changes saved'), 'success');
@ -191,20 +179,15 @@ class TopicsController extends MainController
Validation::Limits($topic_slug, lang('Slug'), '3', '43', $redirect);
Validation::Limits($topic_seo_title, lang('Slug'), '4', '225', $redirect);
$topic_merged_id = $topic_merged_id ?? 0;
$topic_related = $topic_related ?? '';
$topic_img = 'topic-default.png';
$topic_add_date = date("Y-m-d H:i:s");
$data = [
'topic_title' => $topic_title,
'topic_description' => $topic_description,
'topic_slug' => $topic_slug,
'topic_img' => $topic_img,
'topic_add_date' => $topic_add_date,
'topic_img' => 'topic-default.png',
'topic_add_date' => date("Y-m-d H:i:s"),
'topic_seo_title' => $topic_seo_title,
'topic_merged_id' => $topic_merged_id,
'topic_related' => $topic_related,
'topic_merged_id' => $topic_merged_id ?? 0,
'topic_related' => $topic_related ?? 0,
'topic_count' => 0,
];

View file

@ -4,7 +4,7 @@ namespace Modules\Admin\Controllers;
use Hleb\Scheme\App\Controllers\MainController;
use Hleb\Constructor\Handlers\Request;
use Modules\Admin\Models\{UserModel, BadgeModel};
use Modules\Admin\Models\{UserModel, BadgeModel, AgentModel};
use App\Models\SpaceModel;
use Agouti\{Base, Validation};
@ -21,9 +21,9 @@ class UsersController extends MainController
$result = array();
foreach ($user_all as $ind => $row) {
$row['replayIp'] = UserModel::replayIp($row['user_reg_ip']);
$row['duplicat_ip_reg'] = AgentModel::duplicatesRegistrationCount($row['user_reg_ip']);
$row['isBan'] = UserModel::isBan($row['user_id']);
$row['logs'] = UserModel::userLogId($row['user_id']);
$row['last_visit_logs'] = AgentModel::lastVisitLogs($row['user_id']);
$row['created_at'] = lang_date($row['user_created_at']);
$row['user_updated_at'] = lang_date($row['user_updated_at']);
$result[$ind] = $row;
@ -45,25 +45,31 @@ class UsersController extends MainController
}
// Повторы IP
public function logsIp()
public function logsIp($option)
{
$user_ip = Request::get('ip');
$user_all = UserModel::getUserLogsId($user_ip);
if ($option == 'logs') {
$user_all = AgentModel::getUserLogsId($user_ip);
} else {
$user_all = AgentModel::getUserRegsId($user_ip);
}
$results = array();
foreach ($user_all as $ind => $row) {
$row['replayIp'] = UserModel::replayIp($row['user_reg_ip']);
$row['duplicat_ip_reg'] = AgentModel::duplicatesRegistrationCount($row['user_id']);
$row['isBan'] = UserModel::isBan($row['user_id']);
$results[$ind] = $row;
}
$meta = [
'meta_title' => lang('Search'),
'sheet' => 'users',
];
$data = [
'alluser' => $results,
'results' => $results,
'option' => $option,
];
return view('/user/logip', ['meta' => $meta, 'uid' => Base::getUid(), 'data' => $data]);
@ -88,10 +94,10 @@ class UsersController extends MainController
redirect('/admin');
}
$user['isBan'] = UserModel::isBan($user_id);
$user['replayIp'] = UserModel::replayIp($user_id);
$user['logs'] = UserModel::userLogId($user_id);
$user['badges'] = BadgeModel::getBadgeUserAll($user_id);
$user['isBan'] = UserModel::isBan($user_id);
$user['duplicat_ip_reg'] = AgentModel::duplicatesRegistrationCount($user_id);
$user['last_visit_logs'] = AgentModel::lastVisitLogs($user_id);
$user['badges'] = BadgeModel::getBadgeUserAll($user_id);
$counts = UserModel::contentCount($user_id);
@ -126,6 +132,7 @@ class UsersController extends MainController
$login = Request::getPost('login');
$name = Request::getPost('name');
$about = Request::getPost('about');
$whisper = Request::getPost('whisper');
$activated = Request::getPostInt('activated');
$limiting_mode = Request::getPostInt('limiting_mode');
$trust_level = Request::getPostInt('trust_level');
@ -143,18 +150,19 @@ class UsersController extends MainController
'user_id' => $user_id,
'user_email' => $email,
'user_login' => $login,
'user_name' => empty($name) ? '' : $name,
'user_whisper' => $whisper ?? '',
'user_name' => $name ?? '',
'user_activated' => $activated,
'user_limiting_mode' => $limiting_mode,
'user_trust_level' => $trust_level,
'user_about' => empty($about) ? '' : $about,
'user_website' => empty($website) ? '' : $website,
'user_location' => empty($location) ? '' : $location,
'user_public_email' => empty($public_email) ? '' : $public_email,
'user_skype' => empty($skype) ? '' : $skype,
'user_twitter' => empty($twitter) ? '' : $twitter,
'user_telegram' => empty($telegram) ? '' : $telegram,
'user_vk' => empty($vk) ? '' : $vk,
'user_about' => $about ?? '',
'user_website' => $website ?? '',
'user_location' => $location ?? '',
'user_public_email' => $public_email ?? '',
'user_skype' => $skype ?? '',
'user_twitter' => $twitter ?? '',
'user_telegram' => $telegram ?? '',
'user_vk' => $vk ?? '',
];
UserModel::setUserEdit($data);

View file

@ -4,7 +4,7 @@ namespace Modules\Admin;
use Hleb\Scheme\App\Controllers\MainController;
use Modules\Admin\Models\UserModel;
use App\Models\{SpaceModel, HomeModel, AnswerModel, CommentModel, WebModel, TopicModel};
use App\Models\{SpaceModel, HomeModel, AnswerModel, CommentModel, WebModel, TopicModel, AgentModel};
use Agouti\Base;
class HomeController extends MainController
@ -28,6 +28,7 @@ class HomeController extends MainController
'answers_count' => AnswerModel::getAnswersAllCount(),
'comments_count' => CommentModel::getCommentAllCount(),
'links_count' => WebModel::getLinksAllCount(),
'last_visit' => AgentModel::getLastVisit(),
'bytes' => $bytes,
];

View file

@ -0,0 +1,77 @@
<?php
namespace Modules\Admin\Models;
use Hleb\Scheme\App\Models\MainModel;
use DB;
use PDO;
class AgentModel extends MainModel
{
// Количество дублей IP по полю user_reg_ip
public static function duplicatesRegistrationCount($ip)
{
$sql = "SELECT
user_id,
user_reg_ip
FROM users WHERE user_reg_ip = :ip";
return DB::run($sql, ['ip' => $ip])->rowCount();
}
// По логам
public static function lastVisitLogs($user_id)
{
$sql = "SELECT
MAX(log_date) as latest_date,
MAX(log_user_ip) as latest_ip,
log_user_id
FROM users_agent_logs
WHERE log_user_id = :user_id GROUP BY log_user_id";
return DB::run($sql, ['user_id' => $user_id])->fetch(PDO::FETCH_ASSOC);
}
public static function getUserRegsId($ip)
{
$sql = "SELECT
user_id,
user_login,
user_name,
user_email,
user_avatar,
user_created_at,
user_reg_ip,
user_invitation_id,
user_trust_level
FROM users WHERE user_reg_ip = :ip";
return DB::run($sql, ['ip' => $ip])->fetchAll(PDO::FETCH_ASSOC);
}
// ip для логов
public static function getUserLogsId($ip)
{
$sql = "SELECT
user_id,
user_login,
user_name,
user_email,
user_avatar,
user_created_at,
user_reg_ip,
user_invitation_id,
user_trust_level,
latest_date
FROM users
JOIN
( SELECT
MAX(log_date) as latest_date,
log_user_id
FROM users_agent_logs
WHERE log_user_ip = :ip GROUP BY log_user_id
) as latest_date
ON latest_date.log_user_id = user_id";
return DB::run($sql, ['ip' => $ip])->fetchAll(PDO::FETCH_ASSOC);
}
}

View file

@ -174,7 +174,7 @@ class TopicModel extends MainModel
topic_related = :topic_related,
topic_count = :topic_count
WHERE topic_id = :topic_id";
return DB::run($sql, $params);
}

View file

@ -24,7 +24,9 @@ class UserModel extends MainModel
user_name,
user_avatar,
user_created_at,
user_whisper,
user_updated_at,
user_whisper,
user_trust_level,
user_activated,
user_invitation_id,
@ -49,59 +51,6 @@ class UserModel extends MainModel
return DB::run($sql)->rowCount();
}
// По логам
public static function userLogId($user_id)
{
$sql = "SELECT
logs_id,
logs_user_id,
logs_login,
logs_trust_level,
logs_ip_address,
logs_date
FROM users_logs
WHERE logs_user_id = :user_id ORDER BY logs_user_id DESC";
return DB::run($sql, ['user_id' => $user_id])->fetch(PDO::FETCH_ASSOC);
}
// Получение информации по ip для сопоставления
public static function getUserLogsId($ip)
{
$sql = "SELECT
logs_id,
logs_user_id,
logs_login,
logs_trust_level,
logs_ip_address,
logs_date,
user_id,
user_login,
user_name,
user_email,
user_avatar,
user_created_at,
user_reg_ip,
user_invitation_id,
user_trust_level
FROM users_logs
LEFT JOIN users ON user_id = logs_user_id
WHERE logs_ip_address = :ip OR user_reg_ip = :ip";
return DB::run($sql, ['ip' => $ip])->fetchAll(PDO::FETCH_ASSOC);
}
// Проверка IP на дубликаты
public static function replayIp($ip)
{
$sql = "SELECT
user_id,
user_reg_ip
FROM users WHERE user_reg_ip = :ip";
return DB::run($sql, ['ip' => $ip])->rowCount();
}
// Находит ли пользователь в бан- листе и рабанен ли был он
public static function isBan($user_id)
{
@ -230,6 +179,7 @@ class UserModel extends MainModel
'user_id' => $data['user_id'],
'user_email' => $data['user_email'],
'user_login' => $data['user_login'],
'user_whisper' => $data['user_whisper'],
'user_name' => $data['user_name'],
'user_activated' => $data['user_activated'],
'user_limiting_mode' => $data['user_limiting_mode'],
@ -247,6 +197,7 @@ class UserModel extends MainModel
$sql = "UPDATE users SET
user_email = :user_email,
user_login = :user_login,
user_whisper = :user_whisper,
user_name = :user_name,
user_activated = :user_activated,
user_limiting_mode = :user_limiting_mode,
@ -280,6 +231,7 @@ class UserModel extends MainModel
user_limiting_mode,
user_reg_ip,
user_email,
user_whisper,
user_avatar,
user_trust_level,
user_cover_art,
@ -294,6 +246,7 @@ class UserModel extends MainModel
user_telegram,
user_vk,
user_created_at,
user_updated_at,
user_my_post,
user_ban_list,
user_hits_count,

View file

@ -20,4 +20,12 @@
<?= getRequestResources()->getBottomScripts(); ?>
<script src="/assets/js/admin.js"></script>
<script nonce="<?= $_SERVER['nonce']; ?>">
$(document).on('click', '.tips', function () {
let title = $(this).data('id');
layer.tips (title, '.tips', {
tips: [1, '#339900']
});
});
</script>
</html>

View file

@ -46,6 +46,17 @@
</div>
</div>
</div>
<div class="white-box mt10 pt5 pr15 pb5 pl15">
<h4 class="mt5"><?= lang('Users'); ?> <small>(15)</small></h4>
<?php foreach ($data['last_visit'] as $user) { ?>
<div class="gray size-15">
id<?= $user['user_id']; ?>
<a href="/u/<?= $user['user_login']; ?>"><?= $user['user_login']; ?></a>
<span class="size-13"> <?= $user['latest_date']; ?></span>
</div>
<?php } ?>
</div>
<div class="white-box mt10 pt5 pr15 pb5 pl15">
<h4 class="mt5"><?= lang('Useful resources'); ?></h4>
<i class="icon-record-outline gray-light"></i> <a rel="noreferrer" href="https://agouti.ru">Agouti.ru</a></br>

View file

@ -61,6 +61,8 @@
<?= $data['answers_count']; ?>
</a>
<br>
<?php } else { ?>
---
<?php } ?>
<?php if ($data['comments_count'] != 0) { ?>
<label class="required"><?= lang('Comments'); ?>:</label>
@ -68,6 +70,8 @@
<?= $data['comments_count']; ?>
</a>
<br>
<?php } else { ?>
---
<?php } ?>
<?php if ($data['spaces_user']) { ?>
<br>
@ -81,6 +85,8 @@
</div>
<?php } ?>
</span>
<?php } else { ?>
---
<?php } ?>
</div>
<hr>
@ -100,6 +106,10 @@
---
<?php } ?>
</div>
<div class="boxline">
<label class="form-label" for="post_title"><?= lang('Whisper'); ?></label>
<input class="form-input" type="text" name="whisper" value="<?= $data['user']['user_whisper']; ?>">
</div>
<div class="boxline">
<label for="post_title"><?= lang('Views'); ?></label>
<?= $data['user']['user_hits_count']; ?>
@ -108,9 +118,10 @@
<label class="form-label" for="post_title"><?= lang('Sign up'); ?></label>
<?= $data['user']['user_created_at']; ?> |
<?= $data['user']['user_reg_ip']; ?>
<?php if ($data['user']['replayIp'] > 1) { ?>
<sup class="red">(<?= $data['user']['replayIp']; ?>)</sup>
<?php if ($data['user']['duplicat_ip_reg'] > 1) { ?>
<sup class="red">(<?= $data['user']['duplicat_ip_reg']; ?>)</sup>
<?php } ?>
(<?= lang('ed')?>. <?= $data['user']['user_updated_at']; ?>)
</div>
<hr>
<div class="boxline">

View file

@ -8,11 +8,17 @@
<th><?= lang('Information'); ?></th>
<th>E-mail</th>
<th><?= lang('Sign up'); ?></th>
<th>IP <?= lang('registrations'); ?></th>
<th>
<?php if ($data['option'] == 'logs') { ?>
<?= lang('Last'); ?>
<?php } else { ?>
IP
<?php } ?>
</th>
<th>Ban</th>
<th><?= lang('Action'); ?></th>
</thead>
<?php foreach ($data['alluser'] as $user) { ?>
<?php foreach ($data['results'] as $user) { ?>
<tr>
<td class="center">
<?= $user['user_id']; ?>
@ -26,7 +32,7 @@
(<?= $user['user_name']; ?>)
<?php } ?>
<sup class="red">TL:<?= $user['user_trust_level']; ?></sup>
<?php if ($user['user_invitation_id'] != 0) { ?><sup>+ inv. id<?= $user['user_invitation_id']; ?></sup><?php } ?> <br>
</td>
<td>
<span class="date"><?= $user['user_email']; ?></span>
@ -34,10 +40,16 @@
<td>
<?= $user['user_created_at']; ?>
</td>
<td>
<?= $user['user_reg_ip']; ?> <?php if ($user['replayIp'] > 1) { ?>
<sup class="red">(<?= $user['replayIp']; ?>)</sup>
<td>
<?php if ($data['option'] == 'logs') { ?>
<?= $user['latest_date']; ?>
<?php } else { ?>
<?= $user['user_reg_ip']; ?>
<?php } ?>
<?php if ($user['duplicat_ip_reg'] > 1) { ?>
<br> <sup class="red">(<?= $user['duplicat_ip_reg']; ?>)</sup>
<?php } ?>
</td>
<td class="center">
<?php if ($user['user_trust_level'] != 5) { ?>

View file

@ -35,40 +35,45 @@
<?php } ?>
<sup class="red">TL:<?= $user['user_trust_level']; ?></sup>
<?php if ($user['user_invitation_id'] != 0) { ?><sup>+ inv. id<?= $user['user_invitation_id']; ?></sup><?php } ?>
<?php if ($user['user_whisper']) { ?>
<span data-id="<?= $user['user_whisper']; ?>" class="tips size-13 gray-light">
<i class="icon-info green"></i>
</span>
<?php } ?>
<div class="size-13">
<?= $user['user_email']; ?>
<?php if ($user['user_activated'] == 1) { ?>
<div class="gray-light"><?= lang('Email activated'); ?></div>
<?php } else { ?>
<div class="red"><?= lang('Not activated'); ?> e-mail</div>
<?php } ?>
</div>
<?php if ($user['user_limiting_mode'] == 1) { ?>
<div class="red"><?= lang('Dumb mode'); ?></div>
<?php } ?>
<?php if (!empty($user['isBan']['banlist_int_num'])) { ?>
bans: <?= $user['isBan']['banlist_int_num']; ?>
<?php } ?>
</td>
<td class="size-13 align-right">
<a class="gray-light ml10" href="/admin/logip/<?= $user['user_reg_ip']; ?>">
<?= $user['user_reg_ip']; ?>
<a class="gray-light ml10" href="/admin/regip/<?= $user['user_reg_ip']; ?>">
<?= $user['user_reg_ip']; ?>
</a>
<?php if ($user['replayIp'] > 1) { ?>
<sup class="red">(<?= $user['replayIp']; ?>)</sup>
<?php if ($user['duplicat_ip_reg'] > 1) { ?>
<sup class="red">(<?= $user['duplicat_ip_reg']; ?>)</sup>
<?php } ?>
<br>
<?= $user['created_at']; ?>
(<?= lang('ed')?>. <?= $user['user_updated_at']; ?>)
</td>
<td class="size-13 align-right">
<?php if (!empty($user['logs']['logs_ip_address'])) { ?>
<a class="gray-light ml10" href="/admin/logip/<?= $user['logs']['logs_ip_address']; ?>">
<?= $user['logs']['logs_ip_address']; ?>
<?php if (!empty($user['last_visit_logs']['latest_ip'])) { ?>
<a class="gray-light ml10" href="/admin/logip/<?= $user['last_visit_logs']['latest_ip']; ?>">
<?= $user['last_visit_logs']['latest_ip']; ?>
</a>
<br>
<?= $user['logs']['logs_date']; ?>
<?php } ?>
<?php if ($user['user_activated'] == 1) { ?>
<div><?= lang('Email activated'); ?></div>
<?php } else { ?>
<span class="red"><?= lang('Not activated'); ?> e-mail</span>
<?php if (!empty($user['last_visit_logs']['latest_date'])) { ?>
<?= $user['last_visit_logs']['latest_date']; ?>
<?php } ?>
</td>
<td class="center">

View file

@ -1,14 +1,13 @@
@font-face {
font-family: 'fontello';
src: url('./icons/fontello.eot?35739612');
src: url('./icons/fontello.eot?35739612#iefix') format('embedded-opentype'),
url('./icons/fontello.woff2?35739612') format('woff2'),
url('./icons/fontello.woff?35739612') format('woff'),
url('./icons/fontello.ttf?35739612') format('truetype'),
url('./icons/fontello.svg?35739612#fontello') format('svg');
src: url('./icons/fontello.eot?97855587');
src: url('./icons/fontello.eot?97855587#iefix') format('embedded-opentype'),
url('./icons/fontello.woff2?97855587') format('woff2'),
url('./icons/fontello.woff?97855587') format('woff'),
url('./icons/fontello.ttf?97855587') format('truetype'),
url('./icons/fontello.svg?97855587#fontello') format('svg');
font-weight: normal;
font-style: normal;
font-display: swap;
}
[class^="icon-"]:before, [class*=" icon-"]:before {
@ -32,87 +31,114 @@
-moz-osx-font-smoothing: grayscale;
}
.icon-mail:before { content: '\e800'; }
.icon-bell:before { content: '\e801'; }
.icon-bold:before { content: '\e802'; }
.icon-italic:before { content: '\e803'; }
.icon-cog-outline:before { content: '\e804'; }
.icon-sun:before { content: '\e805'; }
.icon-plus:before { content: '\e806'; }
.icon-up-bold:before { content: '\e807'; }
.icon-right-open-big:before { content: '\e808'; }
.icon-camera-outline:before { content: '\e809'; }
.icon-down-dir:before { content: '\e80a'; }
.icon-pencil:before { content: '\e80b'; }
.icon-link:before { content: '\e80c'; }
.icon-warning-empty:before { content: '\e80d'; }
.icon-logout:before { content: '\e80e'; }
.icon-reply-outline:before { content: '\e80f'; }
.icon-ok-outline:before { content: '\e810'; }
.icon-pin-outline:before { content: '\e811'; }
.icon-upload-cloud-outline:before { content: '\e812'; }
.icon-home-outline:before { content: '\e813'; }
.icon-record-outline:before { content: '\e814'; }
.icon-attach:before { content: '\e815'; }
.icon-quote:before { content: '\e816'; }
.icon-lock:before { content: '\e817'; }
.icon-calendar:before { content: '\e818'; }
.icon-trash-empty:before { content: '\e819'; }
.icon-tools:before { content: '\e81a'; }
.icon-lightbulb:before { content: '\e81b'; }
.icon-minus-outline:before { content: '\e81c'; }
.icon-user-add-outline:before { content: '\e81d'; }
.icon-trophy:before { content: '\e81e'; }
.icon-infinity:before { content: '\e81f'; }
.icon-award:before { content: '\e820'; }
.icon-export:before { content: '\e821'; }
.icon-edit:before { content: '\e822'; }
.icon-air:before { content: '\e823'; }
.icon-book-open:before { content: '\e824'; }
.icon-cancel:before { content: '\e82e'; }
.icon-users-outline:before { content: '\e825'; }
.icon-scissors:before { content: '\e826'; }
.icon-gift:before { content: '\e827'; }
.icon-chart-bar:before { content: '\e828'; }
.icon-desktop:before { content: '\e829'; }
.icon-mobile:before { content: '\e82a'; }
.icon-search:before { content: '\e82b'; }
.icon-heart-empty:before { content: '\e82c'; }
.icon-star-empty:before { content: '\e82d'; }
.icon-move:before { content: '\f047'; }
.icon-link-ext:before { content: '\f08e'; }
.icon-check-empty:before { content: '\f096'; }
.icon-bookmark-empty:before { content: '\f097'; }
.icon-twitter:before { content: '\f099'; }
.icon-facebook:before { content: '\f09a'; }
.icon-github-circled:before { content: '\f09b'; }
.icon-docs:before { content: '\f0c5'; }
.icon-list-bullet:before { content: '\f0ca'; }
.icon-strike:before { content: '\f0cc'; }
.icon-comment-empty:before { content: '\f0e5'; }
.icon-doc-text:before { content: '\f0f6'; }
.icon-smile:before { content: '\f118'; }
.icon-flag-empty:before { content: '\f11d'; }
.icon-terminal:before { content: '\f120'; }
.icon-code:before { content: '\f121'; }
.icon-help:before { content: '\f128'; }
.icon-info:before { content: '\f129'; }
.icon-ellipsis:before { content: '\f141'; }
.icon-linux:before { content: '\f17c'; }
.icon-bug:before { content: '\f188'; }
.icon-vkontakte:before { content: '\f189'; }
.icon-paw:before { content: '\f1b0'; }
.icon-file-code:before { content: '\f1c9'; }
.icon-wechat:before { content: '\f1d7'; }
.icon-header:before { content: '\f1dc'; }
.icon-at:before { content: '\f1fa'; }
.icon-diamond:before { content: '\f219'; }
.icon-pinterest:before { content: '\f231'; }
.icon-object-group:before { content: '\f247'; }
.icon-object-ungroup:before { content: '\f248'; }
.icon-sticky-note-o:before { content: '\f24a'; }
.icon-clone:before { content: '\f24d'; }
.icon-gg:before { content: '\f260'; }
.icon-commenting-o:before { content: '\f27b'; }
.icon-user-o:before { content: '\f2c0'; }
.icon-id-card-o:before { content: '\f2c3'; }
.icon-mail:before { content: '\e800'; } /* '' */
.icon-bell:before { content: '\e801'; } /* '' */
.icon-bold:before { content: '\e802'; } /* '' */
.icon-italic:before { content: '\e803'; } /* '' */
.icon-cog-outline:before { content: '\e804'; } /* '' */
.icon-sun:before { content: '\e805'; } /* '' */
.icon-plus:before { content: '\e806'; } /* '' */
.icon-up-bold:before { content: '\e807'; } /* '' */
.icon-right-open-big:before { content: '\e808'; } /* '' */
.icon-camera-outline:before { content: '\e809'; } /* '' */
.icon-down-dir:before { content: '\e80a'; } /* '' */
.icon-pencil:before { content: '\e80b'; } /* '' */
.icon-link:before { content: '\e80c'; } /* '' */
.icon-warning-empty:before { content: '\e80d'; } /* '' */
.icon-logout:before { content: '\e80e'; } /* '' */
.icon-reply-outline:before { content: '\e80f'; } /* '' */
.icon-ok-outline:before { content: '\e810'; } /* '' */
.icon-pin-outline:before { content: '\e811'; } /* '' */
.icon-upload-cloud-outline:before { content: '\e812'; } /* '' */
.icon-home-outline:before { content: '\e813'; } /* '' */
.icon-record-outline:before { content: '\e814'; } /* '' */
.icon-attach:before { content: '\e815'; } /* '' */
.icon-quote:before { content: '\e816'; } /* '' */
.icon-lock:before { content: '\e817'; } /* '' */
.icon-calendar:before { content: '\e818'; } /* '' */
.icon-trash-empty:before { content: '\e819'; } /* '' */
.icon-tools:before { content: '\e81a'; } /* '' */
.icon-lightbulb:before { content: '\e81b'; } /* '' */
.icon-minus-outline:before { content: '\e81c'; } /* '' */
.icon-user-add-outline:before { content: '\e81d'; } /* '' */
.icon-trophy:before { content: '\e81e'; } /* '' */
.icon-infinity:before { content: '\e81f'; } /* '' */
.icon-award:before { content: '\e820'; } /* '' */
.icon-export:before { content: '\e821'; } /* '' */
.icon-edit:before { content: '\e822'; } /* '' */
.icon-air:before { content: '\e823'; } /* '' */
.icon-book-open:before { content: '\e824'; } /* '' */
.icon-users-outline:before { content: '\e825'; } /* '' */
.icon-scissors:before { content: '\e826'; } /* '' */
.icon-gift:before { content: '\e827'; } /* '' */
.icon-chart-bar:before { content: '\e828'; } /* '' */
.icon-search:before { content: '\e82b'; } /* '' */
.icon-heart-empty:before { content: '\e82c'; } /* '' */
.icon-star-empty:before { content: '\e82d'; } /* '' */
.icon-cancel:before { content: '\e82e'; } /* '' */
.icon-book:before { content: '\e82f'; } /* '' */
.icon-comment:before { content: '\e830'; } /* '' */
.icon-eye:before { content: '\e831'; } /* '' */
.icon-thumbs-up-1:before { content: '\e832'; } /* '' */
.icon-cog-alt:before { content: '\e833'; } /* '' */
.icon-wrench:before { content: '\e834'; } /* '' */
.icon-move:before { content: '\f047'; } /* '' */
.icon-link-ext:before { content: '\f08e'; } /* '' */
.icon-check-empty:before { content: '\f096'; } /* '' */
.icon-bookmark-empty:before { content: '\f097'; } /* '' */
.icon-twitter:before { content: '\f099'; } /* '' */
.icon-facebook:before { content: '\f09a'; } /* '' */
.icon-github-circled:before { content: '\f09b'; } /* '' */
.icon-docs:before { content: '\f0c5'; } /* '' */
.icon-list-bullet:before { content: '\f0ca'; } /* '' */
.icon-strike:before { content: '\f0cc'; } /* '' */
.icon-comment-empty:before { content: '\f0e5'; } /* '' */
.icon-coffee:before { content: '\f0f4'; } /* '' */
.icon-doc-text:before { content: '\f0f6'; } /* '' */
.icon-folder-empty:before { content: '\f114'; } /* '' */
.icon-folder-open-empty:before { content: '\f115'; } /* '' */
.icon-smile:before { content: '\f118'; } /* '' */
.icon-flag-empty:before { content: '\f11d'; } /* '' */
.icon-terminal:before { content: '\f120'; } /* '' */
.icon-code:before { content: '\f121'; } /* '' */
.icon-help:before { content: '\f128'; } /* '' */
.icon-info:before { content: '\f129'; } /* '' */
.icon-ellipsis:before { content: '\f141'; } /* '' */
.icon-minus-squared-alt:before { content: '\f147'; } /* '' */
.icon-youtube:before { content: '\f167'; } /* '' */
.icon-windows:before { content: '\f17a'; } /* '' */
.icon-android:before { content: '\f17b'; } /* '' */
.icon-linux:before { content: '\f17c'; } /* '' */
.icon-bug:before { content: '\f188'; } /* '' */
.icon-vkontakte:before { content: '\f189'; } /* '' */
.icon-plus-squared-alt:before { content: '\f196'; } /* '' */
.icon-wordpress:before { content: '\f19a'; } /* '' */
.icon-graduation-cap:before { content: '\f19d'; } /* '' */
.icon-yahoo:before { content: '\f19e'; } /* '' */
.icon-google:before { content: '\f1a0'; } /* '' */
.icon-paw:before { content: '\f1b0'; } /* '' */
.icon-file-code:before { content: '\f1c9'; } /* '' */
.icon-git:before { content: '\f1d3'; } /* '' */
.icon-wechat:before { content: '\f1d7'; } /* '' */
.icon-header:before { content: '\f1dc'; } /* '' */
.icon-at:before { content: '\f1fa'; } /* '' */
.icon-diamond:before { content: '\f219'; } /* '' */
.icon-pinterest:before { content: '\f231'; } /* '' */
.icon-medium:before { content: '\f23a'; } /* '' */
.icon-object-group:before { content: '\f247'; } /* '' */
.icon-object-ungroup:before { content: '\f248'; } /* '' */
.icon-sticky-note-o:before { content: '\f24a'; } /* '' */
.icon-clone:before { content: '\f24d'; } /* '' */
.icon-gg:before { content: '\f260'; } /* '' */
.icon-odnoklassniki:before { content: '\f263'; } /* '' */
.icon-wikipedia-w:before { content: '\f266'; } /* '' */
.icon-safari:before { content: '\f267'; } /* '' */
.icon-chrome-1:before { content: '\f268'; } /* '' */
.icon-firefox-1:before { content: '\f269'; } /* '' */
.icon-opera:before { content: '\f26a'; } /* '' */
.icon-internet-explorer:before { content: '\f26b'; } /* '' */
.icon-television:before { content: '\f26c'; } /* '' */
.icon-commenting-o:before { content: '\f27b'; } /* '' */
.icon-user-o:before { content: '\f2c0'; } /* '' */
.icon-id-card-o:before { content: '\f2c3'; } /* '' */
.icon-quora:before { content: '\f2c4'; } /* '' */

View file

@ -0,0 +1,39 @@
Font license info
## Font Awesome
Copyright (C) 2016 by Dave Gandy
Author: Dave Gandy
License: SIL ()
Homepage: http://fortawesome.github.com/Font-Awesome/
## Typicons
(c) Stephen Hutchings 2012
Author: Stephen Hutchings
License: SIL (http://scripts.sil.org/OFL)
Homepage: http://typicons.com/
## Entypo
Copyright (C) 2012 by Daniel Bruce
Author: Daniel Bruce
License: SIL (http://scripts.sil.org/OFL)
Homepage: http://www.entypo.com
## Iconic
Copyright (C) 2012 by P.J. Onori
Author: P.J. Onori
License: SIL (http://scripts.sil.org/OFL)
Homepage: http://somerandomdude.com/work/iconic/

View file

@ -1,7 +1,6 @@
<!DOCTYPE html>
<html>
<head>
<!--[if lt IE 9]><script language="javascript" type="text/javascript" src="//html5shim.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
<meta charset="UTF-8">
<style>
html {
@ -146,11 +145,11 @@
}
@font-face {
font-family: 'fontello';
src: url('./fontello.eot?91620186');
src: url('./fontello.eot?91620186#iefix') format('embedded-opentype'),
url('./fontello.woff?91620186') format('woff'),
url('./fontello.ttf?91620186') format('truetype'),
url('./fontello.svg?91620186#fontello') format('svg');
src: url('./fontello.eot?10690357');
src: url('./fontello.eot?10690357#iefix') format('embedded-opentype'),
url('./fontello.woff?10690357') format('woff'),
url('./fontello.ttf?10690357') format('truetype'),
url('./fontello.svg?10690357#fontello') format('svg');
font-weight: normal;
font-style: normal;
}
@ -354,26 +353,40 @@
<div class="span3" title="Code: 0xe828">
<i class="demo-icon icon-chart-bar">&#xe828;</i> <span class="i-name">icon-chart-bar</span><span class="i-code">0xe828</span>
</div>
<div class="span3" title="Code: 0xe829">
<i class="demo-icon icon-desktop">&#xe829;</i> <span class="i-name">icon-desktop</span><span class="i-code">0xe829</span>
</div>
<div class="span3" title="Code: 0xe82a">
<i class="demo-icon icon-mobile">&#xe82a;</i> <span class="i-name">icon-mobile</span><span class="i-code">0xe82a</span>
</div>
<div class="span3" title="Code: 0xe82b">
<i class="demo-icon icon-search">&#xe82b;</i> <span class="i-name">icon-search</span><span class="i-code">0xe82b</span>
</div>
</div>
<div class="row">
<div class="span3" title="Code: 0xe82c">
<i class="demo-icon icon-heart-empty">&#xe82c;</i> <span class="i-name">icon-heart-empty</span><span class="i-code">0xe82c</span>
</div>
<div class="span3" title="Code: 0xe82d">
<i class="demo-icon icon-star-empty">&#xe82d;</i> <span class="i-name">icon-star-empty</span><span class="i-code">0xe82d</span>
</div>
</div>
<div class="row">
<div class="span3" title="Code: 0xe82e">
<i class="demo-icon icon-cancel">&#xe82e;</i> <span class="i-name">icon-cancel</span><span class="i-code">0xe82e</span>
</div>
<div class="span3" title="Code: 0xe82f">
<i class="demo-icon icon-book">&#xe82f;</i> <span class="i-name">icon-book</span><span class="i-code">0xe82f</span>
</div>
<div class="span3" title="Code: 0xe830">
<i class="demo-icon icon-comment">&#xe830;</i> <span class="i-name">icon-comment</span><span class="i-code">0xe830</span>
</div>
<div class="span3" title="Code: 0xe831">
<i class="demo-icon icon-eye">&#xe831;</i> <span class="i-name">icon-eye</span><span class="i-code">0xe831</span>
</div>
</div>
<div class="row">
<div class="span3" title="Code: 0xe832">
<i class="demo-icon icon-thumbs-up-1">&#xe832;</i> <span class="i-name">icon-thumbs-up-1</span><span class="i-code">0xe832</span>
</div>
<div class="span3" title="Code: 0xe833">
<i class="demo-icon icon-cog-alt">&#xe833;</i> <span class="i-name">icon-cog-alt</span><span class="i-code">0xe833</span>
</div>
<div class="span3" title="Code: 0xe834">
<i class="demo-icon icon-wrench">&#xe834;</i> <span class="i-name">icon-wrench</span><span class="i-code">0xe834</span>
</div>
<div class="span3" title="Code: 0xf047">
<i class="demo-icon icon-move">&#xf047;</i> <span class="i-name">icon-move</span><span class="i-code">0xf047</span>
</div>
@ -413,17 +426,28 @@
<div class="span3" title="Code: 0xf0e5">
<i class="demo-icon icon-comment-empty">&#xf0e5;</i> <span class="i-name">icon-comment-empty</span><span class="i-code">0xf0e5</span>
</div>
<div class="span3" title="Code: 0xf0f4">
<i class="demo-icon icon-coffee">&#xf0f4;</i> <span class="i-name">icon-coffee</span><span class="i-code">0xf0f4</span>
</div>
<div class="span3" title="Code: 0xf0f6">
<i class="demo-icon icon-doc-text">&#xf0f6;</i> <span class="i-name">icon-doc-text</span><span class="i-code">0xf0f6</span>
</div>
</div>
<div class="row">
<div class="span3" title="Code: 0xf114">
<i class="demo-icon icon-folder-empty">&#xf114;</i> <span class="i-name">icon-folder-empty</span><span class="i-code">0xf114</span>
</div>
<div class="span3" title="Code: 0xf115">
<i class="demo-icon icon-folder-open-empty">&#xf115;</i> <span class="i-name">icon-folder-open-empty</span><span class="i-code">0xf115</span>
</div>
<div class="span3" title="Code: 0xf118">
<i class="demo-icon icon-smile">&#xf118;</i> <span class="i-name">icon-smile</span><span class="i-code">0xf118</span>
</div>
</div>
<div class="row">
<div class="span3" title="Code: 0xf11d">
<i class="demo-icon icon-flag-empty">&#xf11d;</i> <span class="i-name">icon-flag-empty</span><span class="i-code">0xf11d</span>
</div>
</div>
<div class="row">
<div class="span3" title="Code: 0xf120">
<i class="demo-icon icon-terminal">&#xf120;</i> <span class="i-name">icon-terminal</span><span class="i-code">0xf120</span>
</div>
@ -433,36 +457,70 @@
<div class="span3" title="Code: 0xf128">
<i class="demo-icon icon-help">&#xf128;</i> <span class="i-name">icon-help</span><span class="i-code">0xf128</span>
</div>
</div>
<div class="row">
<div class="span3" title="Code: 0xf129">
<i class="demo-icon icon-info">&#xf129;</i> <span class="i-name">icon-info</span><span class="i-code">0xf129</span>
</div>
</div>
<div class="row">
<div class="span3" title="Code: 0xf141">
<i class="demo-icon icon-ellipsis">&#xf141;</i> <span class="i-name">icon-ellipsis</span><span class="i-code">0xf141</span>
</div>
<div class="span3" title="Code: 0xf147">
<i class="demo-icon icon-minus-squared-alt">&#xf147;</i> <span class="i-name">icon-minus-squared-alt</span><span class="i-code">0xf147</span>
</div>
<div class="span3" title="Code: 0xf167">
<i class="demo-icon icon-youtube">&#xf167;</i> <span class="i-name">icon-youtube</span><span class="i-code">0xf167</span>
</div>
<div class="span3" title="Code: 0xf17a">
<i class="demo-icon icon-windows">&#xf17a;</i> <span class="i-name">icon-windows</span><span class="i-code">0xf17a</span>
</div>
</div>
<div class="row">
<div class="span3" title="Code: 0xf17b">
<i class="demo-icon icon-android">&#xf17b;</i> <span class="i-name">icon-android</span><span class="i-code">0xf17b</span>
</div>
<div class="span3" title="Code: 0xf17c">
<i class="demo-icon icon-linux">&#xf17c;</i> <span class="i-name">icon-linux</span><span class="i-code">0xf17c</span>
</div>
<div class="span3" title="Code: 0xf188">
<i class="demo-icon icon-bug">&#xf188;</i> <span class="i-name">icon-bug</span><span class="i-code">0xf188</span>
</div>
</div>
<div class="row">
<div class="span3" title="Code: 0xf189">
<i class="demo-icon icon-vkontakte">&#xf189;</i> <span class="i-name">icon-vkontakte</span><span class="i-code">0xf189</span>
</div>
</div>
<div class="row">
<div class="span3" title="Code: 0xf196">
<i class="demo-icon icon-plus-squared-alt">&#xf196;</i> <span class="i-name">icon-plus-squared-alt</span><span class="i-code">0xf196</span>
</div>
<div class="span3" title="Code: 0xf19a">
<i class="demo-icon icon-wordpress">&#xf19a;</i> <span class="i-name">icon-wordpress</span><span class="i-code">0xf19a</span>
</div>
<div class="span3" title="Code: 0xf19d">
<i class="demo-icon icon-graduation-cap">&#xf19d;</i> <span class="i-name">icon-graduation-cap</span><span class="i-code">0xf19d</span>
</div>
<div class="span3" title="Code: 0xf19e">
<i class="demo-icon icon-yahoo">&#xf19e;</i> <span class="i-name">icon-yahoo</span><span class="i-code">0xf19e</span>
</div>
</div>
<div class="row">
<div class="span3" title="Code: 0xf1a0">
<i class="demo-icon icon-google">&#xf1a0;</i> <span class="i-name">icon-google</span><span class="i-code">0xf1a0</span>
</div>
<div class="span3" title="Code: 0xf1b0">
<i class="demo-icon icon-paw">&#xf1b0;</i> <span class="i-name">icon-paw</span><span class="i-code">0xf1b0</span>
</div>
<div class="span3" title="Code: 0xf1c9">
<i class="demo-icon icon-file-code">&#xf1c9;</i> <span class="i-name">icon-file-code</span><span class="i-code">0xf1c9</span>
</div>
<div class="span3" title="Code: 0xf1d7">
<i class="demo-icon icon-wechat">&#xf1d7;</i> <span class="i-name">icon-wechat</span><span class="i-code">0xf1d7</span>
<div class="span3" title="Code: 0xf1d3">
<i class="demo-icon icon-git">&#xf1d3;</i> <span class="i-name">icon-git</span><span class="i-code">0xf1d3</span>
</div>
</div>
<div class="row">
<div class="span3" title="Code: 0xf1d7">
<i class="demo-icon icon-wechat">&#xf1d7;</i> <span class="i-name">icon-wechat</span><span class="i-code">0xf1d7</span>
</div>
<div class="span3" title="Code: 0xf1dc">
<i class="demo-icon icon-header">&#xf1dc;</i> <span class="i-name">icon-header</span><span class="i-code">0xf1dc</span>
</div>
@ -472,37 +530,73 @@
<div class="span3" title="Code: 0xf219">
<i class="demo-icon icon-diamond">&#xf219;</i> <span class="i-name">icon-diamond</span><span class="i-code">0xf219</span>
</div>
</div>
<div class="row">
<div class="span3" title="Code: 0xf231">
<i class="demo-icon icon-pinterest">&#xf231;</i> <span class="i-name">icon-pinterest</span><span class="i-code">0xf231</span>
</div>
</div>
<div class="row">
<div class="span3" title="Code: 0xf23a">
<i class="demo-icon icon-medium">&#xf23a;</i> <span class="i-name">icon-medium</span><span class="i-code">0xf23a</span>
</div>
<div class="span3" title="Code: 0xf247">
<i class="demo-icon icon-object-group">&#xf247;</i> <span class="i-name">icon-object-group</span><span class="i-code">0xf247</span>
</div>
<div class="span3" title="Code: 0xf248">
<i class="demo-icon icon-object-ungroup">&#xf248;</i> <span class="i-name">icon-object-ungroup</span><span class="i-code">0xf248</span>
</div>
</div>
<div class="row">
<div class="span3" title="Code: 0xf24a">
<i class="demo-icon icon-sticky-note-o">&#xf24a;</i> <span class="i-name">icon-sticky-note-o</span><span class="i-code">0xf24a</span>
</div>
<div class="span3" title="Code: 0xf24d">
<i class="demo-icon icon-clone">&#xf24d;</i> <span class="i-name">icon-clone</span><span class="i-code">0xf24d</span>
</div>
</div>
<div class="row">
<div class="span3" title="Code: 0xf260">
<i class="demo-icon icon-gg">&#xf260;</i> <span class="i-name">icon-gg</span><span class="i-code">0xf260</span>
</div>
<div class="span3" title="Code: 0xf263">
<i class="demo-icon icon-odnoklassniki">&#xf263;</i> <span class="i-name">icon-odnoklassniki</span><span class="i-code">0xf263</span>
</div>
</div>
<div class="row">
<div class="span3" title="Code: 0xf266">
<i class="demo-icon icon-wikipedia-w">&#xf266;</i> <span class="i-name">icon-wikipedia-w</span><span class="i-code">0xf266</span>
</div>
<div class="span3" title="Code: 0xf267">
<i class="demo-icon icon-safari">&#xf267;</i> <span class="i-name">icon-safari</span><span class="i-code">0xf267</span>
</div>
<div class="span3" title="Code: 0xf268">
<i class="demo-icon icon-chrome-1">&#xf268;</i> <span class="i-name">icon-chrome-1</span><span class="i-code">0xf268</span>
</div>
<div class="span3" title="Code: 0xf269">
<i class="demo-icon icon-firefox-1">&#xf269;</i> <span class="i-name">icon-firefox-1</span><span class="i-code">0xf269</span>
</div>
</div>
<div class="row">
<div class="span3" title="Code: 0xf26a">
<i class="demo-icon icon-opera">&#xf26a;</i> <span class="i-name">icon-opera</span><span class="i-code">0xf26a</span>
</div>
<div class="span3" title="Code: 0xf26b">
<i class="demo-icon icon-internet-explorer">&#xf26b;</i> <span class="i-name">icon-internet-explorer</span><span class="i-code">0xf26b</span>
</div>
<div class="span3" title="Code: 0xf26c">
<i class="demo-icon icon-television">&#xf26c;</i> <span class="i-name">icon-television</span><span class="i-code">0xf26c</span>
</div>
<div class="span3" title="Code: 0xf27b">
<i class="demo-icon icon-commenting-o">&#xf27b;</i> <span class="i-name">icon-commenting-o</span><span class="i-code">0xf27b</span>
</div>
</div>
<div class="row">
<div class="span3" title="Code: 0xf2c0">
<i class="demo-icon icon-user-o">&#xf2c0;</i> <span class="i-name">icon-user-o</span><span class="i-code">0xf2c0</span>
</div>
<div class="span3" title="Code: 0xf2c3">
<i class="demo-icon icon-id-card-o">&#xf2c3;</i> <span class="i-name">icon-id-card-o</span><span class="i-code">0xf2c3</span>
</div>
<div class="span3" title="Code: 0xf2c4">
<i class="demo-icon icon-quora">&#xf2c4;</i> <span class="i-name">icon-quora</span><span class="i-code">0xf2c4</span>
</div>
</div>
<div class="container footer">Generated by <a href="https://fontello.com">fontello.com</a></div>
</body>

Binary file not shown.

View file

@ -88,10 +88,6 @@
<glyph glyph-name="chart-bar" unicode="&#xe828;" d="M357 350v-286h-143v286h143z m214 286v-572h-142v572h142z m572-643v-72h-1143v858h71v-786h1072z m-357 500v-429h-143v429h143z m214 214v-643h-143v643h143z" horiz-adv-x="1142.9" />
<glyph glyph-name="desktop" unicode="&#xe829;" d="M1094 897q65 0 110-46t46-110l0-573q0-65-46-110t-110-46l-313 0 0-104 157 0q21 0 36-15t16-37-16-37-36-16l-625 0q-22 0-37 16t-16 37 16 37 37 15l156 0 0 104-313 0q-65 0-110 46t-46 110l0 573q0 65 46 110t110 46l938 0z m-365-989l0 104-208 0 0-104 208 0z m417 260l0 573q0 21-15 37t-37 15l-938 0q-21 0-37-15t-15-37l0-573q0-21 15-37t37-15l938 0q21 0 37 15t15 37z m-105 573q22 0 37-15t16-36l0-418q0-21-16-36t-37-15l-832 0q-21 0-37 15t-16 36l0 418q0 21 16 36t37 15l832 0z m0-469l0 418-832 0 0-418 832 0z" horiz-adv-x="1250" />
<glyph glyph-name="mobile" unicode="&#xe82a;" d="M521 819q65 0 111-46t46-110l0-625q0-65-46-111t-111-46l-365 0q-65 0-110 46t-46 111l0 625q0 65 46 110t110 46l365 0z m52-781l0 625q0 21-15 37t-37 15l-365 0q-21 0-37-15t-15-37l0-625q0-21 15-37t37-16l365 0q22 0 37 16t15 37z m-104 625q21 0 37-16t15-37l0-468q0-22-15-37t-37-15l-79 0q0-21-15-37t-36-15-37 15-16 37l-77 0q-21 0-37 15t-16 37l0 468q0 22 16 37t37 16l260 0z m0-521l0 468-260 0 0-468 260 0z" horiz-adv-x="678" />
<glyph glyph-name="search" unicode="&#xe82b;" d="M643 386q0 103-73 176t-177 74-177-74-73-176 73-177 177-73 177 73 73 177z m286-465q0-29-22-50t-50-21q-30 0-50 21l-191 191q-100-69-223-69-80 0-153 31t-125 84-84 125-31 153 31 152 84 126 125 84 153 31 153-31 125-84 84-126 31-152q0-123-69-223l191-191q21-21 21-51z" horiz-adv-x="928.6" />
<glyph glyph-name="heart-empty" unicode="&#xe82c;" d="M929 517q0 46-12 80t-31 55-46 33-52 18-55 4-62-14-62-36-48-40-34-34q-10-13-27-13t-27 13q-14 15-34 34t-48 40-62 36-62 14-55-4-52-18-46-33-31-55-12-80q0-93 105-198l324-312 324 312q105 105 105 198z m71 0q0-123-128-251l-347-335q-10-10-25-10t-25 10l-348 336q-5 5-15 15t-31 37-38 54-30 67-13 77q0 123 71 192t196 70q34 0 70-12t67-33 54-38 42-38q20 20 42 38t54 38 67 33 70 12q125 0 196-70t71-192z" horiz-adv-x="1000" />
@ -100,6 +96,18 @@
<glyph glyph-name="cancel" unicode="&#xe82e;" d="M452 194q18-18 18-43t-18-43q-18-16-43-16t-43 16l-132 152-132-152q-18-16-43-16t-43 16q-16 18-16 43t16 43l138 156-138 158q-16 18-16 43t16 43q18 16 43 16t43-16l132-152 132 152q18 16 43 16t43-16q18-18 18-43t-18-43l-138-158z" horiz-adv-x="470" />
<glyph glyph-name="book" unicode="&#xe82f;" d="M915 583q22-31 10-72l-154-505q-10-36-42-60t-69-25h-515q-43 0-83 30t-55 74q-14 37-1 71 0 2 1 15t3 20q0 5-2 12t-2 11q1 6 5 12t9 13 9 13q13 21 25 51t17 51q2 6 0 17t0 16q2 6 9 15t10 13q12 20 23 51t14 51q1 5-1 17t0 16q2 7 12 17t13 13q10 14 23 47t16 54q0 4-2 14t-1 15q1 4 5 10t10 13 10 11q4 7 9 17t8 20 9 20 11 18 15 13 20 6 26-3l0-1q21 5 28 5h425q41 0 64-32t10-72l-153-506q-20-66-40-85t-72-20h-485q-15 0-21-8-6-9-1-24 14-39 81-39h515q16 0 31 9t20 23l167 550q4 13 3 32 21-8 33-24z m-594-1q-2-7 1-12t11-6h339q8 0 15 6t9 12l12 36q2 7-1 12t-12 6h-339q-7 0-14-6t-9-12z m-46-143q-3-7 1-12t11-6h339q7 0 14 6t10 12l11 36q3 7-1 13t-11 5h-339q-7 0-14-5t-10-13z" horiz-adv-x="928.6" />
<glyph glyph-name="comment" unicode="&#xe830;" d="M576 629l-278 0q-70 0-119-49t-49-119l0-278q0-58 44-90 68 90 179 90l223 0q92 0 158 65t65 158-65 157-158 66z m0 112q139 0 237-99t98-236-98-237-237-98l-223 0q-46 0-79-33t-33-79q-92 0-157 66t-66 158l0 278q0 115 82 197t198 83l278 0z" horiz-adv-x="928" />
<glyph glyph-name="eye" unicode="&#xe831;" d="M929 314q-85 132-213 197 34-58 34-125 0-103-73-177t-177-73-177 73-73 177q0 67 34 125-128-65-213-197 75-114 187-182t242-68 243 68 186 182z m-402 215q0 11-8 19t-19 7q-70 0-120-50t-50-119q0-11 8-19t19-8 19 8 8 19q0 48 34 82t82 34q11 0 19 8t8 19z m473-215q0-19-11-38-78-129-210-206t-279-77-279 77-210 206q-11 19-11 38t11 39q78 128 210 205t279 78 279-78 210-205q11-20 11-39z" horiz-adv-x="1000" />
<glyph glyph-name="thumbs-up-1" unicode="&#xe832;" d="M811 470q38-13 58-51t15-77l-35-312q-6-39-32-70t-58-44q-5-1-26-9t-29-11-30-7-45-6-56-2q-83 0-174 26t-130 56q-1 1-3 2t-4 4-3 4q-46-40-103-40-65 0-110 45t-46 111l0 313q0 65 46 110t110 46q77 0 124-63 44 44 64 85t21 108q0 54 38 92t92 39 92-39 38-92q0-94-16-188 170-17 202-30z m-655-432q22 0 37 15t16 36l0 313q0 21-16 36t-37 16-37-16-15-36l0-313q0-21 15-36t37-15z m590 7l35 312q3 12-6 16-15 4-107 15t-119 14l-69-10 16 73q25 117 25 223 0 10-8 18t-18 8-18-8-8-18q0-54-11-98t-32-78-37-51-40-43q-36-36-36-69l0-260q0-30 18-44 24-17 99-38t143-22q26 0 45 1t35 5 23 5 23 9 24 9q6 3 14 13t9 18z" horiz-adv-x="885" />
<glyph glyph-name="cog-alt" unicode="&#xe833;" d="M500 350q0 59-42 101t-101 42-101-42-42-101 42-101 101-42 101 42 42 101z m429-286q0 29-22 51t-50 21-50-21-21-51q0-29 21-50t50-21 51 21 21 50z m0 572q0 29-22 50t-50 21-50-21-21-50q0-30 21-51t50-21 51 21 21 51z m-215-235v-103q0-6-4-11t-8-6l-87-14q-6-19-18-42 19-27 50-64 4-6 4-11 0-7-4-11-12-17-46-50t-43-33q-7 0-12 4l-64 50q-21-11-43-17-6-60-13-87-4-13-17-13h-104q-6 0-11 4t-5 10l-13 85q-19 6-42 18l-66-50q-4-4-11-4-6 0-12 4-80 75-80 90 0 5 4 10 5 8 23 30t26 34q-13 24-20 46l-85 13q-5 1-9 5t-4 11v104q0 5 4 10t9 6l86 14q7 19 18 42-19 27-50 64-4 6-4 11 0 7 4 12 12 16 46 49t44 33q6 0 12-4l64-50q19 10 43 18 6 60 13 86 3 13 16 13h104q6 0 11-4t6-10l13-85q19-6 42-17l65 49q5 4 12 4 6 0 11-4 81-75 81-90 0-4-4-10-7-9-24-30t-25-34q13-27 19-46l85-12q6-2 9-6t4-11z m357-298v-78q0-9-83-17-6-15-16-29 28-63 28-77 0-2-2-4-68-40-69-40-5 0-26 27t-29 37q-11-1-17-1t-17 1q-7-11-29-37t-25-27q-1 0-69 40-3 2-3 4 0 14 29 77-10 14-17 29-83 8-83 17v78q0 9 83 18 7 16 17 29-29 63-29 77 0 2 3 4 2 1 19 11t33 19 17 9q4 0 25-26t29-38q12 1 17 1t17-1q28 40 51 63l4 1q2 0 69-39 2-2 2-4 0-14-28-77 9-13 16-29 83-9 83-18z m0 572v-78q0-9-83-18-6-15-16-29 28-63 28-77 0-2-2-4-68-39-69-39-5 0-26 26t-29 38q-11-1-17-1t-17 1q-7-12-29-38t-25-26q-1 0-69 39-3 2-3 4 0 14 29 77-10 14-17 29-83 9-83 18v78q0 9 83 17 7 16 17 29-29 63-29 77 0 2 3 4 2 1 19 11t33 19 17 9q4 0 25-26t29-37q12 1 17 1t17-1q28 39 51 62l4 1q2 0 69-39 2-2 2-4 0-14-28-77 9-13 16-29 83-8 83-17z" horiz-adv-x="1071.4" />
<glyph glyph-name="wrench" unicode="&#xe834;" d="M214 29q0 14-10 25t-25 10-25-10-11-25 11-25 25-11 25 11 10 25z m360 234l-381-381q-21-20-50-20-29 0-51 20l-59 61q-21 20-21 50 0 29 21 51l380 380q22-55 64-97t97-64z m354 243q0-22-13-59-27-75-92-122t-144-46q-104 0-177 73t-73 177 73 176 177 74q32 0 67-10t60-26q9-6 9-15t-9-16l-163-94v-125l108-60q2 2 44 27t75 45 40 20q8 0 13-5t5-14z" horiz-adv-x="928.6" />
<glyph glyph-name="move" unicode="&#xf047;" d="M1000 350q0-14-11-25l-142-143q-11-11-26-11t-25 11-10 25v72h-215v-215h72q14 0 25-10t11-25-11-25l-143-143q-10-11-25-11t-25 11l-143 143q-11 10-11 25t11 25 25 10h72v215h-215v-72q0-14-10-25t-25-11-25 11l-143 143q-11 11-11 25t11 25l143 143q10 11 25 11t25-11 10-25v-72h215v215h-72q-14 0-25 10t-11 25 11 26l143 142q11 11 25 11t25-11l143-142q11-11 11-26t-11-25-25-10h-72v-215h215v72q0 14 10 25t25 11 26-11l142-143q11-10 11-25z" horiz-adv-x="1000" />
<glyph glyph-name="link-ext" unicode="&#xf08e;" d="M786 332v-178q0-67-47-114t-114-47h-464q-67 0-114 47t-47 114v464q0 66 47 113t114 48h393q7 0 12-5t5-13v-36q0-8-5-13t-12-5h-393q-37 0-63-26t-27-63v-464q0-37 27-63t63-27h464q37 0 63 27t26 63v178q0 8 5 13t13 5h36q8 0 13-5t5-13z m214 482v-285q0-15-11-25t-25-11-25 11l-98 98-364-364q-5-6-13-6t-12 6l-64 64q-6 5-6 12t6 13l364 364-98 98q-11 11-11 25t11 25 25 11h285q15 0 25-11t11-25z" horiz-adv-x="1000" />
@ -122,8 +130,14 @@
<glyph glyph-name="comment-empty" unicode="&#xf0e5;" d="M500 636q-114 0-213-39t-157-105-59-142q0-62 40-119t113-98l48-28-15-53q-13-51-39-97 85 36 154 96l24 21 32-3q38-5 72-5 114 0 213 39t157 105 59 142-59 142-157 105-213 39z m500-286q0-97-67-179t-182-130-251-48q-39 0-81 4-110-97-257-135-27-8-63-12h-3q-8 0-15 6t-9 15v1q-2 2 0 6t1 6 2 5l4 5t4 5 4 5q4 5 17 19t20 22 17 22 18 28 15 33 15 42q-88 50-138 123t-51 157q0 97 67 179t182 130 251 48 251-48 182-130 67-179z" horiz-adv-x="1000" />
<glyph glyph-name="coffee" unicode="&#xf0f4;" d="M929 493q0 45-32 76t-76 31h-35v-214h35q45 0 76 31t32 76z m-929-429h1000q0-59-42-101t-101-42h-714q-59 0-101 42t-42 101z m1036 429q0-89-63-152t-152-62h-35v-18q0-52-37-88t-88-37h-393q-51 0-88 37t-37 88v410q0 15 11 26t25 10h642q89 0 152-63t63-151z" horiz-adv-x="1071.4" />
<glyph glyph-name="doc-text" unicode="&#xf0f6;" d="M819 638q16-16 27-42t11-50v-642q0-23-15-38t-38-16h-750q-23 0-38 16t-16 38v892q0 23 16 38t38 16h500q22 0 49-11t42-27z m-248 136v-210h210q-5 17-12 23l-175 175q-6 7-23 12z m215-853v572h-232q-23 0-38 16t-16 37v233h-429v-858h715z m-572 483q0 7 5 12t13 5h393q8 0 13-5t5-12v-36q0-8-5-13t-13-5h-393q-8 0-13 5t-5 13v36z m411-125q8 0 13-5t5-13v-36q0-8-5-13t-13-5h-393q-8 0-13 5t-5 13v36q0 8 5 13t13 5h393z m0-143q8 0 13-5t5-13v-36q0-8-5-13t-13-5h-393q-8 0-13 5t-5 13v36q0 8 5 13t13 5h393z" horiz-adv-x="857.1" />
<glyph glyph-name="folder-empty" unicode="&#xf114;" d="M857 118v393q0 22-15 38t-38 15h-393q-23 0-38 16t-16 38v36q0 22-15 38t-38 15h-179q-22 0-38-15t-16-38v-536q0-22 16-38t38-16h679q22 0 38 16t15 38z m72 393v-393q0-51-37-88t-88-37h-679q-51 0-88 37t-37 88v536q0 51 37 88t88 37h179q51 0 88-37t37-88v-18h375q51 0 88-37t37-88z" horiz-adv-x="928.6" />
<glyph glyph-name="folder-open-empty" unicode="&#xf115;" d="M994 331q0 19-30 19h-607q-22 0-48-12t-39-29l-164-203q-11-13-11-22 0-20 30-20h607q23 0 48 13t40 29l164 203q10 12 10 22z m-637 90h429v90q0 22-16 38t-38 15h-321q-23 0-38 16t-16 38v36q0 22-15 38t-38 15h-179q-22 0-38-15t-16-38v-476l143 175q25 30 65 49t78 19z m708-90q0-35-25-67l-165-203q-24-30-65-49t-78-19h-607q-51 0-88 37t-37 88v536q0 51 37 88t88 37h179q51 0 88-37t37-88v-18h303q52 0 88-37t37-88v-90h107q30 0 56-13t37-40q8-17 8-37z" horiz-adv-x="1071.4" />
<glyph glyph-name="smile" unicode="&#xf118;" d="M633 250q-21-67-77-109t-127-41-128 41-77 109q-4 14 3 27t21 18q14 4 27-2t17-22q14-44 52-72t85-28 84 28 52 72q4 15 18 22t27 2 21-18 2-27z m-276 243q0-30-21-51t-50-21-51 21-21 51 21 50 51 21 50-21 21-50z m286 0q0-30-21-51t-51-21-50 21-21 51 21 50 50 21 51-21 21-50z m143-143q0 73-29 139t-76 114-114 76-138 28-139-28-114-76-76-114-29-139 29-139 76-113 114-77 139-28 138 28 114 77 76 113 29 139z m71 0q0-117-57-215t-156-156-215-58-216 58-155 156-58 215 58 215 155 156 216 58 215-58 156-156 57-215z" horiz-adv-x="857.1" />
<glyph glyph-name="flag-empty" unicode="&#xf11d;" d="M929 267v344q-95-51-171-51-46 0-81 18-56 27-103 42t-99 16q-97 0-225-71v-334q137 63 242 63 30 0 57-4t55-15 43-17 46-22l16-8q24-12 56-12 67 0 164 51z m-750 440q0-19-10-36t-26-25v-707q0-8-5-13t-13-5h-36q-7 0-12 5t-6 13v707q-16 9-25 25t-10 36q0 30 21 51t50 21 51-21 21-51z m821-36v-425q0-22-19-32-6-3-10-5-122-65-206-65-49 0-88 20l-16 7q-35 19-55 27t-51 16-63 8q-57 0-132-24t-127-57q-9-5-19-5-9 0-18 4-17 11-17 31v415q0 19 17 30 19 12 44 24t63 29 85 28 87 10q62 0 117-17t116-48q21-11 50-11 68 0 173 63 12 6 17 9 17 9 35-1 17-11 17-31z" horiz-adv-x="1000" />
@ -138,16 +152,36 @@
<glyph glyph-name="ellipsis" unicode="&#xf141;" d="M214 439v-107q0-22-15-38t-38-15h-107q-23 0-38 15t-16 38v107q0 23 16 38t38 16h107q22 0 38-16t15-38z m286 0v-107q0-22-16-38t-38-15h-107q-22 0-38 15t-15 38v107q0 23 15 38t38 16h107q23 0 38-16t16-38z m286 0v-107q0-22-16-38t-38-15h-107q-22 0-38 15t-16 38v107q0 23 16 38t38 16h107q23 0 38-16t16-38z" horiz-adv-x="785.7" />
<glyph glyph-name="minus-squared-alt" unicode="&#xf147;" d="M643 404v-36q0-8-5-13t-13-5h-464q-8 0-13 5t-5 13v36q0 7 5 12t13 5h464q8 0 13-5t5-12z m71-250v464q0 37-26 63t-63 26h-464q-37 0-63-26t-27-63v-464q0-37 27-63t63-27h464q37 0 63 27t26 63z m72 464v-464q0-67-47-114t-114-47h-464q-67 0-114 47t-47 114v464q0 66 47 113t114 48h464q66 0 114-48t47-113z" horiz-adv-x="785.7" />
<glyph glyph-name="youtube" unicode="&#xf167;" d="M542 156v-118q0-37-22-37-13 0-25 12v168q12 12 25 12 22 0 22-37z m189-1v-25h-51v25q0 38 25 38t26-38z m-540 122h60v52h-174v-52h59v-318h55v318z m161-318h50v276h-50v-211q-17-23-32-23-10 0-11 11-1 2-1 20v203h-50v-218q0-28 5-41 7-21 32-21 27 0 57 34v-30z m240 83v110q0 41-5 55-10 31-40 31-28 0-52-30v121h-50v-370h50v27q25-31 52-31 30 0 40 31 5 15 5 56z m188 6v7h-51q0-29-1-34-4-20-22-20-26 0-26 38v49h100v57q0 44-15 65-22 28-59 28-38 0-60-28-15-21-15-65v-96q0-44 16-65 22-29 60-29 40 0 60 30 10 15 12 30 1 5 1 33z m-339 509v117q0 39-24 39t-24-39v-117q0-39 24-39t24 39z m401-419q0-131-14-195-8-33-33-56t-57-25q-102-12-309-12t-310 12q-32 3-57 25t-32 56q-15 62-15 195 0 131 15 195 7 33 32 56t57 26q103 11 310 11t309-11q33-4 58-26t32-56q14-62 14-195z m-557 712h57l-67-223v-151h-56v151q-8 42-34 119-21 57-37 104h60l39-147z m207-186v-97q0-46-16-66-21-29-59-29-37 0-59 29-15 21-15 66v97q0 45 15 66 22 28 59 28 38 0 59-28 16-21 16-66z m187 91v-279h-51v31q-30-35-58-35-25 0-33 21-4 13-4 42v220h51v-205q0-19 0-20 2-12 12-12 15 0 32 24v213h51z" horiz-adv-x="857.1" />
<glyph glyph-name="windows" unicode="&#xf17a;" d="M381 289v-364l-381 53v311h381z m0 414v-367h-381v315z m548-414v-439l-507 70v369h507z m0 490v-443h-507v373z" horiz-adv-x="928.6" />
<glyph glyph-name="android" unicode="&#xf17b;" d="M275 581q9 0 16 6t6 15-6 16-16 6-15-6-6-16 6-15 15-6z m236 0q9 0 15 6t6 15-6 16-15 6-16-6-6-16 6-15 16-6z m-453-103q23 0 40-17t16-40v-240q0-24-16-41t-40-17-41 17-17 41v240q0 23 17 40t41 17z m591-11v-371q0-26-18-44t-43-18h-42v-127q0-24-16-40t-41-17-41 17-17 40v127h-77v-127q0-24-16-40t-41-17q-24 0-40 17t-17 40l-1 127h-41q-26 0-43 18t-18 44v371h512z m-129 226q59-30 95-85t36-121h-516q0 66 35 121t96 85l-39 73q-4 8 2 12 8 3 12-4l40-74q53 24 112 24t112-24l40 74q4 7 11 4 7-4 3-12z m266-272v-240q0-24-17-41t-41-17q-23 0-40 17t-17 41v240q0 24 17 40t40 17q24 0 41-17t17-40z" horiz-adv-x="785.7" />
<glyph glyph-name="linux" unicode="&#xf17c;" d="M370 621q-6-1-9-6t-4-5q-3-1-3 2 0 7 10 9h6z m49-8q-3-1-7 4t-10 2q14 6 18-1 2-3-1-5z m-196-238q-3 0-4-2t-2-7-3-8-6-7q-5-6 0-7 2 0 7 4t7 10q0 2 1 4t1 4 1 2 0 2v2t-1 1-1 2z m477-201q0 10-31 24 2 8 4 15t3 15 2 12 0 12 0 11-2 12-3 12-2 14-4 14q-5 27-26 58t-40 42q13-11 32-47 48-90 30-155-6-22-28-23-17-2-21 10t-5 47-6 60q-5 21-11 38t-11 25-9 14-7 8-4 4q-8 35-17 58t-17 31-13 19-8 22q-3 12 3 30t2 27-24 14q-9 2-25 10t-20 9q-4 1-6 15t4 28 20 15q21 2 29-16t2-33q-6-10-1-15t17 0q7 2 7 20v21q-3 17-8 28t-11 17-13 8-15 4q-60-4-50-74 0-9-1-9-5 5-16 6t-19 0-8 3q0 31-9 50t-25 19q-15 0-23-16t-10-33q0-8 2-20t8-21 8-8q6 2 9 8 2 5-4 4-4 0-8 8t-6 19q0 12 5 21t19 8q10 0 15-12t6-22-1-12q-12-9-17-16-5-7-16-13t-11-7q-7-8-9-16t4-10q8-4 14-10t9-11 11-7 19-4q27-1 57 8 1 1 13 4t19 6 17 7 12 10q5 8 11 5 2-2 3-5t-1-7-10-5q-11-3-31-12t-25-11q-25-11-40-13-14-3-44 1-5 1-5-1t10-10q14-13 37-13 10 1 20 4t20 8 19 10 17 9 13 7 10 1 5-6q0-1-1-2t-2-3-3-3-5-2-5-3-5-3-6-2q-15-8-37-25t-38-24-27 0q-12 6-35 41-12 17-14 12-1-2-1-6 0-14-8-31t-16-31-12-33 6-35q-13-3-35-50t-26-79q-1-10-1-38t-3-33q-4-14-16-2-18 17-20 53-1 15 2 31 2 10-1 10-1-1-2-3-20-36 6-92 3-7 14-16t13-11q11-13 58-51t52-42q9-9 10-22t-8-24-25-13q4-8 16-24t15-31 4-39q26 13 4 51-2 5-6 9t-5 7-1 3q2 3 7 6t11-2q26-29 93-20 74 9 99 49 13 21 19 17 6-4 5-30 0-13-13-51-5-13-3-21t14-8q1 10 8 43t7 50q1 12-3 41t-5 54 13 39q9 10 29 10 0 21 19 30t40 6 34-13z m-351 462q2 9-1 17t-6 8q-5 1-5-4 1-3 2-3 6 0 4-9-1-11 5-11 1 0 1 2z m234-110q-1 4-3 6t-8 3-8 3q-3 2-5 5t-4 4-3 4-2 2-3-1q-7-9 4-24t22-18q5 0 8 5t2 11z m-99 119q0 6-3 11t-6 7-5 1q-3 0-5-1t0-2 3-2q8-2 10-17 0-2 5 1 1 1 1 2z m30 130q0 1-1 3t-5 3-6 4q-8 8-13 8-5 0-7-4t0-7 0-7q-1-3-4-6t-3-5 2-5q2-2 4 0t6 5 9 5q0 1 5 1t8 1 5 4z m315-749q11-6 18-13t6-14-1-12-9-13-13-10-17-11-17-9-18-9-15-7q-21-11-48-31t-42-36q-9-9-38-11t-50 8q-10 5-16 13t-9 15-13 11-26 5q-24 0-72 0-11 0-32 0t-32-2q-25 0-45-8t-30-17-24-16-30-6q-16 0-62 17t-81 24q-11 2-29 5t-28 5-22 6-18 8-10 11q-5 12 4 37t10 30q1 9-2 23t-6 23-2 21 6 15q7 6 31 8t34 6q17 10 23 20t7 28q12-41-18-59-18-11-46-8-19 1-24-6-7-8 3-32 1-3 4-10t5-10 2-9 1-13q0-8-9-27t-8-27q1-9 20-14 12-4 47-11t56-11q13-3 41-12t46-13 31-2q24 3 36 15t13 27-4 33-11 29-11 20q-67 106-94 135-38 42-63 23-6-5-9 8-1 9-1 21 1 16 6 29t13 26 13 24q4 12 14 40t17 43 17 35 21 30q62 79 70 108-7 63-9 173-1 51 13 85t59 58q22 12 58 12 30 1 59-7t50-24q32-23 51-67t17-83q-3-53 16-119 19-63 75-122 30-33 55-91t33-106q5-28 3-48t-7-30-11-13q-5-1-13-10t-15-20-23-19-34-8q-10 1-17 3t-13 8-7 8-7 12-5 11q-12 20-23 16t-15-27 4-54q11-39 0-109-5-36 10-56t41-19 47 20q33 28 50 37t58 24q30 10 43 20t10 20-14 16-28 13q-19 6-28 27t-8 40 8 27q1-18 5-32t8-23 11-15 12-11 12-7 9-6z" horiz-adv-x="857.1" />
<glyph glyph-name="bug" unicode="&#xf188;" d="M911 314q0-14-11-25t-25-10h-125q0-96-37-162l116-117q10-11 10-25t-10-25q-10-11-25-11t-25 11l-111 110q-3-3-8-7t-24-16-36-21-46-16-54-7v500h-71v-500q-29 0-57 7t-49 19-36 22-25 18l-8 8-102-116q-11-12-27-12-13 0-24 9-11 10-11 25t8 26l113 127q-32 63-32 153h-125q-15 0-25 10t-11 25 11 25 25 11h125v164l-97 97q-11 10-11 25t11 25 25 10 25-10l97-97h471l96 97q11 10 25 10t26-10 10-25-10-25l-97-97v-164h125q15 0 25-11t11-25z m-268 322h-357q0 74 52 126t126 52 127-52 52-126z" horiz-adv-x="928.6" />
<glyph glyph-name="vkontakte" unicode="&#xf189;" d="M1070 560q13-36-84-164-13-18-36-48-22-28-31-40t-17-27-7-24 8-19 18-24 32-30q2-1 2-2 79-73 107-123 2-3 4-7t4-15-1-19-14-15-33-7l-142-3q-14-2-32 3t-29 13l-11 6q-17 12-39 36t-38 43-34 33-32 8q-1 0-4-2t-10-8-12-16-9-29-4-44q0-8-2-15t-4-10l-2-3q-10-11-30-12h-64q-40-3-81 9t-74 29-57 37-40 32l-14 14q-5 5-15 17t-40 50-59 85-68 117-73 152q-4 9-4 15t2 9l2 3q9 11 32 11l153 1q7-1 13-3t9-5l3-2q9-6 13-18 11-28 26-57t23-46l9-16q16-34 31-58t27-38 23-22 19-8 15 3q1 1 3 3t7 12 7 26 5 46 0 69q-1 23-5 41t-7 26l-4 6q-14 19-47 24-8 2 3 14 8 10 21 17 29 14 133 13 46-1 75-7 12-3 19-8t12-13 5-18 2-25 0-31-2-40 0-46q0-6-1-23t0-27 2-22 6-22 13-14q4-1 9-2t15 6 21 19 29 38 38 60q33 58 60 125 2 6 5 10t6 6l3 2 2 1t8 2 11 0l160 1q22 3 36-1t17-10z" horiz-adv-x="1071.4" />
<glyph glyph-name="plus-squared-alt" unicode="&#xf196;" d="M643 404v-36q0-8-5-13t-13-5h-196v-196q0-8-5-13t-13-5h-36q-8 0-13 5t-5 13v196h-196q-8 0-13 5t-5 13v36q0 7 5 12t13 5h196v197q0 8 5 13t13 5h36q8 0 13-5t5-13v-197h196q8 0 13-5t5-12z m71-250v464q0 37-26 63t-63 26h-464q-37 0-63-26t-27-63v-464q0-37 27-63t63-27h464q37 0 63 27t26 63z m72 464v-464q0-67-47-114t-114-47h-464q-67 0-114 47t-47 114v464q0 66 47 113t114 48h464q66 0 114-48t47-113z" horiz-adv-x="785.7" />
<glyph glyph-name="wordpress" unicode="&#xf19a;" d="M71 350q0 91 37 175l205-561q-109 53-176 157t-66 229z m719 22q0-11-2-22t-5-27-7-25-9-33-10-32l-43-143-155 461q26 2 49 4 11 2 15 11t-2 17-15 8l-115-6q-42 1-113 6-6 0-11-3t-6-9-1-10 5-9 11-5l44-4 67-183-94-281-156 464q26 2 49 4 11 2 15 11t-2 17-15 8l-115-6q-4 0-13 0t-14 1q58 89 153 141t205 52q82 0 157-29t133-84h-6q-31 0-51-22t-21-53q0-7 1-14t2-12 5-13 5-11 7-13 7-12 8-13 8-13q35-60 35-118z m-283-59l133-361q0-4 2-7-70-24-142-24-62 0-121 18z m369 243q53-97 53-206 0-117-58-215t-156-156l132 379q33 94 33 154 0 23-4 44z m-376 294q102 0 194-40t160-106 106-160 40-194-40-194-106-160-160-106-194-40-194 40-160 106-106 160-40 194 40 194 106 160 160 106 194 40z m0-977q97 0 185 38t152 102 102 152 38 185-38 185-102 152-152 102-185 38-185-38-152-102-102-152-38-185 38-185 102-152 152-102 185-38z" horiz-adv-x="1000" />
<glyph glyph-name="graduation-cap" unicode="&#xf19d;" d="M990 384l10-177q2-38-46-71t-131-52-180-20-180 20-131 52-46 71l10 177 320-101q12-4 27-4t27 4z m296 180q0-12-13-17l-625-196q-2-1-5-1t-6 1l-364 115q-24-19-39-63t-19-99q35-20 35-61 0-39-32-60l32-242q1-7-4-13-5-7-14-7h-107q-8 0-13 7-6 6-5 13l33 242q-33 21-33 60 0 41 36 62 7 115 55 184l-186 58q-12 5-12 17t12 18l625 196q3 1 6 1t5-1l625-196q13-5 13-18z" horiz-adv-x="1285.7" />
<glyph glyph-name="yahoo" unicode="&#xf19e;" d="M479 316l8-395q-35 7-59 7-23 0-59-7l8 395q-23 39-94 165t-121 209-101 160q32-8 60-8 25 0 62 8 35-62 75-128t93-154 77-127q21 34 61 99t66 106 58 98 60 106q30-8 60-8 31 0 63 8-15-22-33-49t-28-44-31-54-28-47q-81-138-197-340z" horiz-adv-x="857.1" />
<glyph glyph-name="google" unicode="&#xf1a0;" d="M429 411h404q7-37 7-71 0-121-51-216t-145-149-215-54q-88 0-167 34t-137 91-91 137-34 167 34 167 91 137 137 91 167 34q167 0 287-113l-117-112q-68 67-170 67-72 0-133-37t-97-98-36-136 36-136 97-98 133-37q48 0 89 14t67 33 46 46 28 49 13 43h-243v147z" horiz-adv-x="857.1" />
<glyph glyph-name="paw" unicode="&#xf1b0;" d="M435 587q0-34-10-64t-35-51-59-22q-42 0-77 32t-51 76-17 84q0 33 10 63t36 52 58 22q43 0 78-32t51-76 16-84z m-191-270q0-45-23-77t-66-33q-43 0-79 31t-56 74-20 85q0 45 23 78t67 33q42 0 79-31t56-75 19-85z m220 15q66 0 143-54t127-132 52-142q0-26-10-43t-27-25-36-12-42-3q-38 0-105 25t-102 26q-36 0-107-25t-112-25q-102 0-102 82 0 48 31 106t78 108 105 81 107 33z m134 118q-34 0-59 22t-35 51-11 64q0 41 17 84t51 76 77 32q34 0 59-22t35-52 11-63q0-41-17-84t-51-76-77-32z m241 58q43 0 66-33t24-78q0-41-20-85t-56-74-79-31q-43 0-66 33t-24 77q0 41 20 85t56 75 79 31z" horiz-adv-x="928.6" />
<glyph glyph-name="file-code" unicode="&#xf1c9;" d="M819 638q16-16 27-42t11-50v-642q0-23-15-38t-38-16h-750q-23 0-38 16t-16 38v892q0 23 16 38t38 16h500q22 0 49-11t42-27z m-248 136v-210h210q-5 17-12 23l-175 175q-6 7-23 12z m215-853v572h-232q-23 0-38 16t-16 37v233h-429v-858h715z m-518 500q4 7 12 7t13-3l28-21q7-5 7-12t-3-13l-102-136 102-136q4-6 3-13t-7-12l-28-21q-6-4-13-4t-12 7l-126 168q-8 11 0 22z m447-167q8-11 0-22l-126-168q-4-6-11-7t-14 4l-28 21q-6 5-7 12t3 13l102 136-102 136q-4 6-3 13t7 12l28 21q6 4 14 3t11-7z m-346-258q-7 1-11 8t-3 13l77 464q1 7 7 11t14 3l35-5q7-2 11-8t3-13l-77-464q-1-7-7-11t-13-3z" horiz-adv-x="857.1" />
<glyph glyph-name="git" unicode="&#xf1d3;" d="M332 5q0 56-92 56-88 0-88-58 0-57 96-57 84 0 84 59z m-33 422q0 34-17 56t-49 23q-69 0-69-81 0-75 69-75 66 0 66 77z m150 180v-112q-20-7-44-13 9-24 9-47 0-70-41-120t-110-63q-22-5-33-15t-11-33q0-17 13-28t32-18 44-12 48-15 44-21 32-35 13-55q0-170-203-170-38 0-72 7t-65 23-49 46-18 71q0 92 102 125v3q-38 22-38 70 0 61 35 76v3q-40 13-66 60t-27 93q0 77 53 129t131 51q54 0 100-26 54 0 121 26z m178-491h-124q2 25 2 74v340q0 53-2 72h124q-3-19-3-69v-343q0-49 3-74z m335 124v-110q-40-22-97-22-35 0-60 12t-39 27-22 44-10 51-2 58v196h1v2q-4 0-11 0t-10 1q-12 0-33-3v106h54v42q0 30-4 50h127q-3-23-3-92h95v-106q-8 0-24 1t-24 1h-47v-204q0-73 48-73 34 0 61 19z m-321 528q0-32-22-57t-54-24q-32 0-54 24t-23 57q0 33 22 57t55 25q33 0 54-25t22-57z" horiz-adv-x="1000" />
<glyph glyph-name="wechat" unicode="&#xf1d7;" d="M324 593q0 23-14 37t-37 14q-24 0-42-15t-19-36q0-22 19-36t42-14q23 0 37 13t14 37z m414-283q0 15-14 28t-36 12q-16 0-28-13t-13-27q0-16 13-28t28-13q22 0 36 12t14 29z m-131 283q0 23-14 37t-37 14q-24 0-42-15t-18-36q0-22 18-36t42-14q23 0 37 13t14 37z m354-283q0 15-15 28t-36 12q-15 0-27-13t-13-27q0-16 13-28t27-13q22 0 36 12t15 29z m-148 221q-18 3-40 3-94 0-173-43t-125-117-45-160q0-44 13-85-20-2-38-2-15 0-28 1t-31 4-25 4-30 6-28 5l-141-70 40 121q-162 114-162 274 0 94 54 173t148 125 203 45q98 0 185-36t146-102 77-146z m330-313q0-65-38-124t-104-108l31-101-111 60q-84-20-122-20-94 0-173 39t-125 107-46 147 46 148 125 107 173 39q90 0 169-39t127-108 48-147z" horiz-adv-x="1142.9" />
<glyph glyph-name="header" unicode="&#xf1dc;" d="M939-79q-25 0-74 2t-75 2q-24 0-73-2t-74-2q-13 0-21 12t-7 25q0 18 9 26t22 9 29 4 25 9q18 11 18 78l0 218q0 12-1 17-7 3-28 3h-376q-22 0-29-3 0-5 0-17l-1-207q0-79 21-91 9-6 26-8t32-2 25-8 11-26q0-14-6-26t-21-13q-26 0-78 2t-77 2q-24 0-71-2t-71-2q-13 0-20 12t-7 25q0 17 9 25t20 10 26 4 24 9q18 13 18 80l-1 31v454q0 2 1 15t0 20-1 21-2 24-4 20-6 18-9 10q-8 5-25 7t-29 1-23 7-10 26q0 14 6 26t20 13q26 0 78-2t77-2q23 0 71 2t70 2q14 0 21-13t7-26q0-17-9-25t-22-8-27-2-24-7q-20-12-20-90l1-178q0-12 0-18 7-2 22-2h390q14 0 21 2 1 6 1 18l0 178q0 78-19 90-10 6-33 7t-37 7-14 28q0 14 7 26t21 13q24 0 74-2t73-2q24 0 72 2t72 2q14 0 21-13t7-26q0-17-10-25t-22-8-29-2-24-7q-20-13-20-90l1-526q0-66 19-78 9-6 25-8t30-2 23-9 10-25q0-14-6-26t-20-13z" horiz-adv-x="1000" />
@ -158,6 +192,8 @@
<glyph glyph-name="pinterest" unicode="&#xf231;" d="M0 517q0 60 21 113t58 93 85 69 103 44 113 14q88 0 164-37t123-108 47-160q0-54-10-105t-34-99-56-83-80-58-106-21q-38 0-75 18t-54 49q-5-22-15-63t-14-53-11-40-15-39-17-35-26-44-35-48l-7-3-5 6q-9 88-9 105 0 51 12 115t37 161 29 113q-18 36-18 94 0 47 29 87t74 41q34 0 53-23t19-57q0-37-24-106t-25-105q0-35 25-58t61-23q31 0 57 14t44 38 31 53 21 61 11 62 4 56q0 96-61 150t-160 54q-111 0-186-72t-75-183q0-25 7-48t15-36 15-26 7-17q0-15-8-40t-21-25q-1 0-9 1-29 9-51 31t-34 53-18 60-6 60z" horiz-adv-x="714.3" />
<glyph glyph-name="medium" unicode="&#xf23a;" d="M333 615v-655q0-14-7-23t-20-10q-10 0-19 4l-259 131q-12 5-20 18t-8 26v636q0 12 6 19t16 8q8 0 24-8l286-143q1-2 1-3z m36-56l298-484-298 149v335z m631-10v-589q0-14-8-22t-21-9-26 7l-246 123z m-2 67q0-2-143-234t-167-272l-218 353 181 294q9 16 29 16 8 0 14-3l302-151q2-1 2-3z" horiz-adv-x="1000" />
<glyph glyph-name="object-group" unicode="&#xf247;" d="M1143 636h-72v-572h72v-214h-214v71h-715v-71h-214v214h71v572h-71v214h214v-71h715v71h214v-214z m-143 143v-72h71v72h-71z m-929 0v-72h72v72h-72z m72-858v72h-72v-72h72z m786 72v71h71v572h-71v71h-715v-71h-71v-572h71v-71h715z m142-72v72h-71v-72h71z m-357 572h215v-429h-500v143h-215v429h500v-143z m-428-214h357v285h-357v-285z m571-143v285h-143v-214h-214v-71h357z" horiz-adv-x="1142.9" />
<glyph glyph-name="object-ungroup" unicode="&#xf248;" d="M1286 421h-72v-357h72v-214h-215v71h-500v-71h-214v214h72v72h-215v-72h-214v215h71v357h-71v214h214v-71h500v71h215v-214h-72v-72h214v72h215v-215z m-143 143v-71h71v71h-71z m-357 215v-72h71v72h-71z m-715 0v-72h72v72h-72z m72-643v71h-72v-71h72z m714 71h-71v-71h71v71z m-643 0h500v72h72v357h-72v71h-500v-71h-71v-357h71v-72z m286-286v72h-71v-72h71z m714 0v72h-71v-72h71z m-71 143v357h-72v72h-214v-214h72v-215h-215v72h-214v-72h71v-71h500v71h72z" horiz-adv-x="1285.7" />
@ -168,11 +204,29 @@
<glyph glyph-name="gg" unicode="&#xf260;" d="M411 404l214-215-214-214-375 375 375 375 94-94-54-53-40 40-268-268 268-268 107 108-161 160z m321 321l375-375-375-375-94 94 54 53 40-40 268 268-268 268-108-108 162-160-54-54-214 215z" horiz-adv-x="1142.9" />
<glyph glyph-name="odnoklassniki" unicode="&#xf263;" d="M357 344q-105 0-179 74t-74 179q0 105 74 179t179 74 179-74 75-179q0-105-75-179t-179-74z m0 378q-51 0-88-37t-36-88q0-52 36-88t88-37 88 37 37 88q0 52-37 88t-88 37z m292-409q7-15 8-27t-2-23-15-21-24-21-34-23q-64-41-176-53l41-40 149-149q17-17 17-41t-17-41l-7-7q-17-17-41-17t-41 17q-38 38-149 149l-149-149q-18-17-42-17t-40 17l-7 7q-17 17-17 41t17 41l149 149 40 40q-113 12-177 53-21 14-34 23t-24 21-15 21-2 23 8 27q6 11 16 20t23 12 32-1 36-20q3-2 8-6t24-13 39-17 51-14 63-6q51 0 97 14t67 28l21 14q19 15 37 20t31 1 23-12 16-20z" horiz-adv-x="714.3" />
<glyph glyph-name="wikipedia-w" unicode="&#xf266;" d="M834-65l-165 388q-14-27-88-170t-111-218q-1 0-15 0t-15 1q-46 108-143 328t-145 332q-11 28-37 60t-57 56-57 24q0 3-1 14t0 15h325v-28q-21-1-44-9t-37-24-6-36q15-33 121-278t132-302q17 34 78 149t73 138q-11 22-71 157t-75 165q-22 38-113 39v28l287 0v-27q-34-1-52-14t-7-38q18-39 48-106t48-105q61 120 97 203 13 31-6 44t-72 15q1 4 1 14v14q35 0 95 0t100 0 52 1v-28q-35-1-67-18t-50-45l-119-247q8-18 71-162t68-153l246 568q-7 21-27 35t-37 17-30 5v28l256-3 1-1-1-24q-77-2-112-81-293-679-312-721h-27z" horiz-adv-x="1285.7" />
<glyph glyph-name="safari" unicode="&#xf267;" d="M530 352q0-15-10-25t-23-11q-14 0-25 9t-10 23q0 15 9 25t23 11 25-9 11-23z m8-33l195 325q-5-5-37-35t-70-65-77-71-65-62-28-29l-195-323q4 4 38 34t70 65 76 71 65 62 28 28z m361 31q0-112-58-207-2 1-9 6t-15 9-9 5q-8 0-8-8 0-5 33-24-41-63-103-107t-135-61l-8 37q-1 6-9 6-3 0-4-3t-1-6l9-38q-41-8-82-8-111 0-208 59 1 1 8 11t12 19 5 10q0 8-7 8-4 0-10-8t-12-20-8-13q-63 42-107 105t-61 137l38 8q6 2 6 8 0 3-3 5t-6 1l-38-9q-8 41-8 78 0 115 61 212 1-1 10-7t17-11 10-4q7 0 7 6 0 4-7 9t-18 12l-11 7q43 62 105 105t136 60l9-37q1-6 8-6 3 0 5 3t1 6l-9 37q40 7 75 7 114 0 212-61-22-31-22-36 0-7 6-7 7 0 27 35 62-41 105-103t60-135l-31-7q-6-1-6-8 0-3 3-5t5-1l32 7q8-40 8-78z m47 0q0 91-35 174t-95 142-142 95-174 35-173-35-143-95-95-142-35-174 35-173 95-143 143-95 173-35 174 35 142 95 95 143 35 173z m54 0q0-102-40-194t-106-160-160-106-194-40-194 40-160 106-106 160-40 194 40 194 106 160 160 106 194 40 194-40 160-106 106-160 40-194z" horiz-adv-x="1000" />
<glyph glyph-name="chrome-1" unicode="&#xf268;" d="M498 850q134 1 252-67 130-75 196-208l-414 22q-89 5-164-41t-103-128l-154 236q72 89 174 137t213 49z m-416-226l188-370q40-80 117-121t164-25l-129-252q-118 19-214 88t-152 176-56 230q0 149 82 274z m885-94q32-84 33-174t-27-170-86-152-137-117q-128-74-278-66l226 347q49 73 46 162t-59 155z m-467-11q70 0 119-50t50-119-50-119-119-49-119 49-49 119 49 119 119 50z" horiz-adv-x="1000" />
<glyph glyph-name="firefox-1" unicode="&#xf269;" d="M504-150q-158 0-282 84t-183 222q-33 74-38 168t15 186 62 174 100 135l-7-156q7 7 38 8t39-8q24 45 90 77t131 32q-30-25-67-82t-33-92q14-4 35-7t36-4 37-3 29-1q8-3 5-26t-17-42q-3-4-9-10t-32-20-56-19l8-105-77 37q-10-24-5-45t21-38 36-23 45-3q29 5 55 19t47 25 41 10q34-2 50-19t10-36q0-1-1-3t-5-7-10-9-17-5-26-1q-34-53-81-76t-117-16q41-34 91-46t94-3 86 29 71 48 45 58q24 51 22 108t-21 105-44 70q49-21 77-45t43-62q8 95-32 191t-117 159q148-43 230-156t84-289q1-71-23-143t-68-132-106-110-138-75-161-28z" horiz-adv-x="1000" />
<glyph glyph-name="opera" unicode="&#xf26a;" d="M833 723q-92 61-200 61-87 0-164-41t-134-111q-41-52-66-122t-27-148v-24q2-78 27-148t66-122q57-71 134-111t164-41q108 0 200 61-67-60-153-94t-180-33q-16 0-24 1-98 4-186 45t-152 108-101 157-37 189q0 102 40 194t106 160 160 106 194 40h2q93-1 179-34t152-93z m167-373q0-107-43-202t-119-166q-58-35-124-35-76 0-142 47 86 31 141 130t56 226q0 127-55 225t-141 131q66 46 141 46 67 0 126-36 76-70 118-164t42-202z" horiz-adv-x="1000" />
<glyph glyph-name="internet-explorer" unicode="&#xf26b;" d="M1000 327q0-31-4-58h-642q0-81 61-136t144-55q55 0 103 26t76 73h236q-31-89-95-157t-149-106-179-37q-105 0-199 47-127-65-220-65-132 0-132 147 0 64 25 153 10 34 61 128 111 201 265 338-103-44-238-197 35 153 158 250t280 98q17 0 25 0 142 65 242 65 35 0 64-7t53-23 37-42 14-65q0-64-42-159 56-102 56-218z m-39 357q0 47-30 74t-76 27q-60 0-142-39 68-26 124-73t96-109q28 75 28 120z m-890-690q0-48 28-74t75-26q64 0 148 46-68 41-119 103t-77 136q-55-114-55-185z m282 398h406q-3 79-63 132t-140 53q-81 0-140-53t-63-132z" horiz-adv-x="1000" />
<glyph glyph-name="television" unicode="&#xf26c;" d="M1000 154v535q0 8-5 13t-13 5h-893q-7 0-12-5t-6-13v-535q0-8 6-13t12-5h893q7 0 13 5t5 13z m71 535v-535q0-37-26-63t-63-27h-411v-71h197q8 0 13-5t5-13v-36q0-8-5-13t-13-5h-464q-8 0-13 5t-5 13v36q0 8 5 13t13 5h196v71h-411q-36 0-63 27t-26 63v535q0 37 26 63t63 27h893q37 0 63-27t26-63z" horiz-adv-x="1142.9" />
<glyph glyph-name="commenting-o" unicode="&#xf27b;" d="M357 350q0-30-21-50t-50-21-51 21-21 50 21 51 51 20 50-20 21-51z m214 0q0-30-20-50t-51-21-50 21-21 50 21 51 50 20 51-20 20-51z m215 0q0-30-21-50t-51-21-50 21-21 50 21 51 50 20 51-20 21-51z m-286 286q-114 0-213-39t-157-105-59-142q0-62 40-119t113-98l48-28-15-53q-13-51-39-97 85 36 154 96l24 21 32-3q38-5 72-5 114 0 213 39t157 105 59 142-59 142-157 105-213 39z m500-286q0-97-67-179t-182-130-251-48q-39 0-81 4-110-97-257-135-27-8-63-12h-3q-8 0-15 6t-9 15v1q-2 2 0 6t1 6 2 5l4 5t4 5 4 5q4 5 17 19t20 22 17 22 18 28 15 33 15 42q-88 50-138 123t-51 157q0 73 40 139t106 114 160 76 194 28 194-28 160-76 106-114 40-139z" horiz-adv-x="1000" />
<glyph glyph-name="user-o" unicode="&#xf2c0;" d="M670 413q26-8 50-22t50-40 44-65 31-96 12-132q0-86-56-147t-134-61h-477q-78 0-134 61t-56 147q0 73 12 132t31 96 44 65 50 40 50 22q-44 69-44 151 0 58 23 111t61 91 91 61 111 23 110-23 92-61 61-91 22-111q0-82-44-151z m-241 366q-89 0-152-63t-63-152 63-151 152-63 151 63 63 151-63 152-151 63z m238-858q49 0 84 40t35 97q0 134-44 211t-126 80q-81-70-187-70t-188 70q-82-3-126-80t-44-211q0-57 35-97t84-40h477z" horiz-adv-x="857.1" />
<glyph glyph-name="id-card-o" unicode="&#xf2c3;" d="M500 174q0-31-18-52t-42-22h-237q-25 0-43 22t-17 52q0 30 4 56t14 50 28 38 45 14q36-36 87-36t88 36q26 0 45-14t28-38 14-50 4-56z m-71 247q0-44-32-75t-76-32-75 32-32 75 32 76 75 32 76-32 32-76z m571-232v-35q0-8-5-13t-13-5h-393q-7 0-12 5t-6 13v35q0 8 6 13t12 5h393q8 0 13-5t5-13z m-214 143v-36q0-7-5-12t-13-5h-179q-7 0-12 5t-6 12v36q0 8 6 13t12 5h179q8 0 13-5t5-13z m214 0v-36q0-7-5-12t-13-5h-107q-8 0-13 5t-5 12v36q0 8 5 13t13 5h107q8 0 13-5t5-13z m0 143v-36q0-7-5-12t-13-6h-393q-7 0-12 6t-6 12v36q0 8 6 13t12 5h393q8 0 13-5t5-13z m71-464v625h-1000v-625q0-7 6-13t12-5h965q7 0 12 5t5 13z m72 678v-678q0-37-26-63t-63-27h-965q-36 0-63 27t-26 63v678q0 37 26 63t63 27h965q36 0 63-27t26-63z" horiz-adv-x="1142.9" />
<glyph glyph-name="quora" unicode="&#xf2c4;" d="M700 411q0 177-58 265t-184 87q-124 0-182-88t-58-264q0-176 58-263t182-87q41 0 73 9-13 24-22 41t-25 36-29 32-36 20-43 8q-26 0-44-9l-27 54q58 51 154 51 73 0 120-30t84-86q37 83 37 224z m218-353h65q2-15-1-37t-15-53-32-56-60-44-90-18q-40 0-73 11t-59 31-44 43-37 54q-54-15-114-15-84 0-164 32t-141 89-99 139-38 177q0 95 38 178t100 140 141 89 163 32q67 0 133-20t121-59 98-92 67-122 24-146q0-106-45-194t-122-148q26-39 52-59t58-21q34 0 53 21t21 48z" horiz-adv-x="1000" />
</font>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

View file

@ -830,6 +830,11 @@ footer a.footer:hover { color: #ddd; }
height: 160px;
}
@media (max-width: 1150px) {
.no-mob-max { display: none; }
}
@media (max-width: 910px) {
.no-mob,
aside { display: none; }

View file

@ -5,7 +5,7 @@
margin: 0 auto;
text-align: left;
position: relative;
margin-bottom: 15px;
margin: 15px 0 15px 0;
border: 1px solid #ddd;
z-index: 333;
}

View file

@ -42,11 +42,11 @@
<div>
<a class="gray-light-2 ml30 no-mob" title="<?= lang('Spaces'); ?>" href="<?= getUrlByName('spaces'); ?>">
<i class="icon-infinity size-21"></i>
<span><?= lang('Spaces'); ?></span>
<span class="no-mob-max"><?= lang('Spaces'); ?></span>
</a>
<a class="gray-light-2 ml30 no-mob" title="<?= lang('Topics'); ?>" href="<?= getUrlByName('topics'); ?>">
<i class="icon-clone size-21"></i>
<span><?= lang('Topics'); ?></span>
<span class="no-mob-max"><?= lang('Topics'); ?></span>
</a>
</div>
</div>

View file

@ -6,7 +6,7 @@
Код сайта имеет лицензию [MIT](https://ru.wikipedia.org/wiki/%D0%9B%D0%B8%D1%86%D0%B5%D0%BD%D0%B7%D0%B8%D1%8F_MIT).
### Какие технологии используются на сайте?
В разделе документация есть статья: [Какие технологии использует сайт?](https://agouti.info/info/hleb)
В разделе документация есть статья: [Какие технологии использует сайт?](https://agouti.info/support/article/hleb)
### Где можно подробней ознакомится с документацией?
В разделе документация: [agouti.info](https://agouti.info)

View file

@ -32,7 +32,7 @@
<?php } ?>
<?php } ?>
<a title="<?= lang('Info'); ?>" class="size-13 lowercase right gray" href="<?= getUrlByName('topic', ['slug' => $data['topic']['topic_slug']]); ?>/info">
<i class="icon-info"></i>
<i class="icon-info green"></i>
</a>
</div>
</div>

View file

@ -1,6 +1,6 @@
<div class="wrap">
<main>
<div class="white-box pt5 pr15 pb5 pl15">
<div class="white-box pt5 pr15 pb0 pl15">
<?= breadcrumb('/', lang('Home'), getUrlByName('user', ['login' => $uid['user_login']]), lang('Profile'), lang('Favorites'));
$pages = array(
array('id' => 'favorites', 'url' => getUrlByName('favorites', ['login' => $uid['user_login']]), 'content' => lang('Favorites')),

View file

@ -231,6 +231,11 @@
<i class="icon-award middle"></i>
<span class="middle"><?= lang('Reward the user'); ?></span>
</a>
<?php if ($data['user']['user_whisper']) { ?>
<div class="tips size-13 pt15 pb10 gray-light">
<i class="icon-info green"></i> <?= $data['user']['user_whisper']; ?>
</div>
<?php } ?>
<hr>
<span class="gray">id<?= $data['user']['user_id']; ?> | <?= $data['user']['user_email']; ?></span>
</div>

View file

@ -29,8 +29,9 @@ Route::before('Authorization@admin')->getGroup();
Route::get('/users/ban')->module('admin', 'Controllers\UsersController', ['ban']);
Route::get('/users/{id}/edit')->module('admin', 'Controllers\UsersController@userEditPage')->where(['id' => '[0-9]+'])->name('admin.user.edit');
Route::get('/users/page/{page?}')->module('admin', 'Controllers\UsersController', ['all'])->where(['page' => '[0-9]+']);
Route::get('/logip/{ip}')->module('admin', 'Controllers\UsersController@logsIp')->where(['ip' => '[0-9].+']);
Route::get('/logip/{ip}')->module('admin', 'Controllers\UsersController@logsIp', ['logs'])->where(['ip' => '[0-9].+']);
Route::get('/regip/{ip}')->module('admin', 'Controllers\UsersController@logsIp', ['reg'])->where(['ip' => '[0-9].+']);
Route::get('/audits')->module('admin', 'Controllers\AuditsController', ['all'])->name('admin.audits');
Route::get('/audits/approved')->module('admin', 'Controllers\AuditsController', ['approved']);