diff --git a/VERSION b/VERSION index 8bcc8b3..130165b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v3.5.5 +v3.6.0 diff --git a/adapters/AdapterInterface.php b/adapters/AdapterInterface.php index c967bb2..5de6a5c 100644 --- a/adapters/AdapterInterface.php +++ b/adapters/AdapterInterface.php @@ -79,6 +79,11 @@ interface AdapterInterface */ public static function meta_support_read(): bool; + /** + * Does the implemented service support updating phone status. + */ + public static function meta_support_phone_status(): bool; + /** * Does the implemented service support reception callback. */ @@ -152,6 +157,15 @@ interface AdapterInterface */ public function test(): bool; + + /** + * Method called to verify phone status + * + * @return string : Return one phone status among 'available', 'unavailable', 'no_credit' + */ + public function check_phone_status(): string; + + /** * Method called on reception of a status update notification for a SMS. * diff --git a/adapters/BenchmarkAdapter.php b/adapters/BenchmarkAdapter.php index 493ad6a..5d03ce3 100644 --- a/adapters/BenchmarkAdapter.php +++ b/adapters/BenchmarkAdapter.php @@ -111,6 +111,14 @@ namespace adapters; return false; } + /** + * Does the implemented service support updating phone status. + */ + public static function meta_support_phone_status(): bool + { + return false; + } + /** * Does the implemented service support flash smss. */ @@ -226,6 +234,16 @@ namespace adapters; return []; } + /** + * Method called to verify phone status + * + * @return string : Return one phone status among 'available', 'unavailable', 'no_credit' + */ + public function check_phone_status(): string + { + return \models\Phone::STATUS_AVAILABLE; + } + public static function status_change_callback() { return null; diff --git a/adapters/GammuAdapter.php b/adapters/GammuAdapter.php index da42b49..f1c15e4 100644 --- a/adapters/GammuAdapter.php +++ b/adapters/GammuAdapter.php @@ -121,6 +121,14 @@ namespace adapters; return true; } + /** + * Does the implemented service support updating phone status. + */ + public static function meta_support_phone_status(): bool + { + return false; + } + /** * Does the implemented service support flash smss. */ @@ -301,6 +309,16 @@ namespace adapters; return $response; } + /** + * Method called to verify phone status + * + * @return string : Return one phone status among 'available', 'unavailable', 'no_credit' + */ + public function check_phone_status(): string + { + return \models\Phone::STATUS_AVAILABLE; + } + public function test(): bool { //Always return true as we cannot test because we would be needing a root account diff --git a/adapters/KannelAdapter.php b/adapters/KannelAdapter.php index 4d63802..19782d3 100644 --- a/adapters/KannelAdapter.php +++ b/adapters/KannelAdapter.php @@ -209,6 +209,14 @@ class KannelAdapter implements AdapterInterface return false; } + /** + * Does the implemented service support updating phone status. + */ + public static function meta_support_phone_status(): bool + { + return false; + } + /** * Does the implemented service support flash smss. */ @@ -354,6 +362,16 @@ class KannelAdapter implements AdapterInterface return []; } + /** + * Method called to verify phone status + * + * @return string : Return one phone status among 'available', 'unavailable', 'no_credit' + */ + public function check_phone_status(): string + { + return \models\Phone::STATUS_AVAILABLE; + } + public function test(): bool { try diff --git a/adapters/OctopushShortcodeAdapter.php b/adapters/OctopushShortcodeAdapter.php index 2c70b97..59283a5 100644 --- a/adapters/OctopushShortcodeAdapter.php +++ b/adapters/OctopushShortcodeAdapter.php @@ -174,6 +174,14 @@ class OctopushShortcodeAdapter implements AdapterInterface return false; } + /** + * Does the implemented service support updating phone status. + */ + public static function meta_support_phone_status(): bool + { + return false; + } + /** * Does the implemented service support flash smss. */ @@ -325,6 +333,16 @@ class OctopushShortcodeAdapter implements AdapterInterface return []; } + /** + * Method called to verify phone status + * + * @return string : Return one phone status among 'available', 'unavailable', 'no_credit' + */ + public function check_phone_status(): string + { + return \models\Phone::STATUS_AVAILABLE; + } + public function test(): bool { try diff --git a/adapters/OctopushVirtualNumberAdapter.php b/adapters/OctopushVirtualNumberAdapter.php index 0096f72..f9238a6 100644 --- a/adapters/OctopushVirtualNumberAdapter.php +++ b/adapters/OctopushVirtualNumberAdapter.php @@ -173,6 +173,14 @@ class OctopushVirtualNumberAdapter implements AdapterInterface return false; } + /** + * Does the implemented service support updating phone status. + */ + public static function meta_support_phone_status(): bool + { + return false; + } + /** * Does the implemented service support flash smss. */ @@ -317,6 +325,16 @@ class OctopushVirtualNumberAdapter implements AdapterInterface return []; } + /** + * Method called to verify phone status + * + * @return string : Return one phone status among 'available', 'unavailable', 'no_credit' + */ + public function check_phone_status(): string + { + return \models\Phone::STATUS_AVAILABLE; + } + public function test(): bool { try diff --git a/adapters/OdysseyMessagingAdapter.php b/adapters/OdysseyMessagingAdapter.php new file mode 100644 index 0000000..f48203c --- /dev/null +++ b/adapters/OdysseyMessagingAdapter.php @@ -0,0 +1,511 @@ + + * + * This source file is subject to the GPL-3.0 license that is bundled + * with this source code in the file LICENSE. + */ + +namespace adapters; + +use DateTime; + +/** + * Odyssey Messaging SMS service + */ +class OdysseyMessagingAdapter implements AdapterInterface +{ + const EVENT_TYPES = [ + 'OPT_OUT' => 1, + 'SYSTEM_ERROR' => 2, + 'END_OF_ITEM' => 3, + 'END_OF_JOB' => 4, + 'JOB_STATUS_CHANGED' => 5, + 'REAL_TIME_STATUS' => 6, + 'RETRIEVE_FILE' => 7, + 'INBOUND_SMS' => 8, + 'ITEM_STATUS_CHANGED' => 9, + 'DATA_COLLECTION_FILLED' => 10, + ]; + + /** + * Data used to configure interaction with the implemented service. (e.g : Api credentials, ports numbers, etc.). + */ + private $data; + + /** + * Odyssey login. + */ + private $login; + + /** + * Odyssey password. + */ + private $password; + + /** + * Sender name to use instead of shortcode. + */ + private $sender; + + /** + * Odyssey api baseurl. + */ + private $api_url = 'https://api.odyssey-services.fr/api/v1'; + + /** + * Adapter constructor, called when instanciated by RaspiSMS. + * + * @param json string $data : JSON string of the data to configure interaction with the implemented service + */ + public function __construct(string $data) + { + $this->data = json_decode($data, true); + + $this->login = $this->data['login']; + $this->password = $this->data['password']; + + $this->sender = $this->data['sender'] ?? null; + } + + /** + * Classname of the adapter. + */ + public static function meta_classname(): string + { + return __CLASS__; + } + + /** + * Uniq name of the adapter + * It should be the classname of the adapter un snakecase. + */ + public static function meta_uid(): string + { + return 'odyssey_messaging_adapter'; + } + + /** + * Should this adapter be hidden in user interface for phone creation and + * available to creation through API only. + */ + public static function meta_hidden(): bool + { + return false; + } + + /** + * Should this adapter data be hidden after creation + * this help to prevent API credentials to other service leak if an attacker gain access to RaspiSMS through user credentials. + */ + public static function meta_hide_data(): bool + { + return false; + } + + /** + * Name of the adapter. + * It should probably be the name of the service it adapt (e.g : Gammu SMSD, OVH SMS, SIM800L, etc.). + */ + public static function meta_name(): string + { + return 'Odyssey Messaging'; + } + + /** + * Description of the adapter. + * A short description of the service the adapter implements. + */ + public static function meta_description(): string + { + return ' + Envoi de SMS avec Odyssey Messaging. + Pour plus d\'information sur l\'utilisation de ce type de téléphone, reportez-vous à la documentation sur le téléphone "Odyssey Messaging". + '; + } + + /** + * List of entries we want in data for the adapter. + * + * @return array : Every line is a field as an array with keys : name, title, description, required + */ + public static function meta_data_fields(): array + { + return [ + [ + 'name' => 'login', + 'title' => 'Odyssey login', + 'description' => 'Login du compte Odyssey à employer.', + 'required' => true, + ], + [ + 'name' => 'password', + 'title' => 'Mot de passe', + 'description' => 'Mot de passe du compte Odyssey à employer.', + 'required' => true, + ], + [ + 'name' => 'sender', + 'title' => 'Nom de l\'expéditeur', + 'description' => 'Nom de l\'expéditeur à afficher à la place du numéro (11 caractères max).
+ Laissez vide pour ne pas utiliser d\'expéditeur nommé.
+ Si vous utilisez un expéditeur nommé, le destinataire ne pourra pas répondre.', + 'required' => false, + ], + ]; + } + + /** + * Does the implemented service support reading smss. + */ + public static function meta_support_read(): bool + { + return false; + } + + /** + * Does the implemented service support updating phone status. + */ + public static function meta_support_phone_status(): bool + { + return false; + } + + /** + * Does the implemented service support flash smss. + */ + public static function meta_support_flash(): bool + { + return false; + } + + /** + * Does the implemented service support status change. + */ + public static function meta_support_status_change(): bool + { + return true; + } + + /** + * Does the implemented service support reception callback. + */ + public static function meta_support_reception(): bool + { + return true; + } + + /** + * Does the implemented service support mms reception. + */ + public static function meta_support_mms_reception(): bool + { + return false; + } + + /** + * Does the implemented service support mms sending. + */ + public static function meta_support_mms_sending(): bool + { + return false; + } + + public static function meta_support_inbound_call_callback(): bool + { + return false; + } + + public static function meta_support_end_call_callback(): bool + { + return false; + } + + public function send(string $destination, string $text, bool $flash = false, bool $mms = false, array $medias = []): array + { + $response = [ + 'error' => false, + 'error_message' => null, + 'uid' => null, + ]; + + try + { + $credentials = base64_encode($this->login . ':' . $this->password); + $headers = [ + 'Authorization: Basic ' . $credentials, + 'Content-Type: application/json', + ]; + + $data = [ + 'JobType' => 'SMS', + 'Text' => $text, + 'TrackingID' => uniqid(), + 'AdhocRecipients' => [['Name' => uniqid(), 'Address' => str_replace('+', '00', $destination)]], + ]; + + if ($this->sender) + { + $data['Parameter'] = ['Sender' => $this->sender, 'Media' => 1]; + } + + $data = json_encode($data); + + $endpoint = $this->api_url . '/SMSJobs'; + + $curl = curl_init(); + curl_setopt($curl, CURLOPT_URL, $endpoint); + curl_setopt($curl, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); + curl_setopt($curl, CURLOPT_POST, true); + curl_setopt($curl, CURLOPT_POSTFIELDS, $data); + curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); + + $curl_response = curl_exec($curl); + $http_code = (int) curl_getinfo($curl, CURLINFO_HTTP_CODE); + curl_close($curl); + + if (false === $curl_response) + { + $response['error'] = true; + $response['error_message'] = 'HTTP query failed.'; + + return $response; + } + + $response_decode = json_decode($curl_response, true); + if (null === $response_decode) + { + $response['error'] = true; + $response['error_message'] = 'Invalid JSON for response.'; + + return $response; + } + + if (200 !== $http_code) + { + $response['error'] = true; + $response['error_message'] = 'Response indicate error : ' . $response_decode['Message'] . ' -> """' . json_encode($response_decode['ModelState']) . '""" AND HTTP CODE -> ' . $http_code; + + return $response; + } + + $uid = $response_decode['JobNumber'] ?? false; + if (!$uid) + { + $response['error'] = true; + $response['error_message'] = 'Cannot extract SMS uid'; + + return $response; + } + + $response['uid'] = $uid; + + return $response; + } + catch (\Throwable $t) + { + $response['error'] = true; + $response['error_message'] = $t->getMessage(); + + return $response; + } + } + + public function read(): array + { + return []; + } + + /** + * Method called to verify phone status + * + * @return string : Return one phone status among 'available', 'unavailable', 'no_credit' + */ + public function check_phone_status(): string + { + return \models\Phone::STATUS_AVAILABLE; + } + + public function test(): bool + { + try + { + if ($this->data['sender'] && (mb_strlen($this->data['sender']) < 3 || mb_strlen($this->data['sender'] > 11))) + { + return false; + } + + if (!empty($this->data['sms_type']) && !in_array($this->data['sms_type'], ['premium', 'low cost'])) + { + return false; + } + + $credentials = base64_encode($this->login . ':' . $this->password); + $headers = [ + 'Authorization: Basic ' . $credentials, + 'Content-Type: application/json', + ]; + + //Check service name + $endpoint = $this->api_url . '/JobTypes'; + $curl = curl_init(); + curl_setopt($curl, CURLOPT_URL, $endpoint); + curl_setopt($curl, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); + curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); + $response = curl_exec($curl); + $http_code = (int) curl_getinfo($curl, CURLINFO_HTTP_CODE); + curl_close($curl); + + if (200 !== $http_code) + { + return false; + } + + return true; + } + catch (\Throwable $t) + { + return false; + } + } + + public static function status_change_callback() + { + header('Connection: close'); + header('Content-Encoding: none'); + header('Content-Length: 0'); + + $input = file_get_contents('php://input'); + $content = json_decode($input, true); + if (null === $content) + { + return false; + } + + $event_type = $content['EventType'] ?? false; + if ($event_type != self::EVENT_TYPES['ITEM_STATUS_CHANGED']) + { + return false; + } + + $uid = $content['JobNumber'] ?? false; + $status = $content['Outcome'] ?? false; + + if (false === $uid || false === $status) + { + return false; + } + + switch ($status) + { + case 'S': + $status = \models\Sended::STATUS_DELIVERED; + + break; + + case 'B': + $status = \models\Sended::STATUS_UNKNOWN; + + break; + + default: + $status = \models\Sended::STATUS_FAILED; + + break; + } + + return ['uid' => $uid, 'status' => $status]; + } + + public static function reception_callback(): array + { + $response = [ + 'error' => false, + 'error_message' => null, + 'sms' => null, + ]; + + header('Connection: close'); + header('Content-Encoding: none'); + header('Content-Length: 0'); + + $input = file_get_contents('php://input'); + $content = json_decode($input, true); + if (null === $content) + { + $response['error'] = true; + $response['error_message'] = 'Cannot read input data from callback request.'; + + return $response; + } + + $event_type = $content['EventType'] ?? false; + if ($event_type != self::EVENT_TYPES['INBOUND_SMS']) + { + $response['error'] = true; + $response['error_message'] = 'Invalid event type : ' . $event_type . '.'; + + return $response; + } + + $number = $content['From'] ?? false; + $text = $content['Message'] ?? false; + $at = $content['EventDateTime'] ?? false; + + if (!$number || !$text || !$at) + { + $response['error'] = true; + $response['error_message'] = 'One required data of the callback is missing.'; + + return $response; + } + + $matches = null; + $match = preg_match('#/Date\(([0-9]+)\+([0-9]+)\)/#', $at, $matches); + $timestamp = ($matches[1] ?? null); + if (!$match || !$timestamp) + { + $response['error'] = true; + $response['error_message'] = 'Invalid date.'; + + return $response; + } + + $at = DateTime::createFromFormat('U', $timestamp / 1000); + $at = $at->format('Y-m-d H:i:s'); + + $origin = \controllers\internals\Tool::parse_phone($number); + if (!$origin) + { + $response['error'] = true; + $response['error_message'] = 'Invalid origin number : ' . $number; + + return $response; + } + + $response['sms'] = [ + 'at' => $at, + 'text' => $text, + 'origin' => $origin, + ]; + + return $response; + } + + public function inbound_call_callback(): array + { + return []; + } + + public function end_call_callback(): array + { + return []; + } +} diff --git a/adapters/OvhSmsShortcodeAdapter.php b/adapters/OvhSmsShortcodeAdapter.php index 91a28a3..cf16795 100644 --- a/adapters/OvhSmsShortcodeAdapter.php +++ b/adapters/OvhSmsShortcodeAdapter.php @@ -162,6 +162,14 @@ namespace adapters; return true; } + /** + * Does the implemented service support updating phone status. + */ + public static function meta_support_phone_status(): bool + { + return false; + } + /** * Does the implemented service support flash smss. */ @@ -327,6 +335,16 @@ namespace adapters; } } + /** + * Method called to verify phone status + * + * @return string : Return one phone status among 'available', 'unavailable', 'no_credit' + */ + public function check_phone_status(): string + { + return \models\Phone::STATUS_AVAILABLE; + } + public function test(): bool { try diff --git a/adapters/OvhSmsVirtualNumberAdapter.php b/adapters/OvhSmsVirtualNumberAdapter.php index b1078f9..cfc1b2a 100644 --- a/adapters/OvhSmsVirtualNumberAdapter.php +++ b/adapters/OvhSmsVirtualNumberAdapter.php @@ -166,6 +166,14 @@ namespace adapters; return true; } + /** + * Does the implemented service support updating phone status. + */ + public static function meta_support_phone_status(): bool + { + return false; + } + /** * Does the implemented service support flash smss. */ @@ -317,6 +325,16 @@ namespace adapters; } } + /** + * Method called to verify phone status + * + * @return string : Return one phone status among 'available', 'unavailable', 'no_credit' + */ + public function check_phone_status(): string + { + return \models\Phone::STATUS_AVAILABLE; + } + public function test(): bool { try diff --git a/adapters/TestAdapter.php b/adapters/TestAdapter.php index 048e81c..2ad3c48 100644 --- a/adapters/TestAdapter.php +++ b/adapters/TestAdapter.php @@ -116,6 +116,14 @@ namespace adapters; return true; } + /** + * Does the implemented service support updating phone status. + */ + public static function meta_support_phone_status(): bool + { + return false; + } + /** * Does the implemented service support flash smss. */ @@ -287,6 +295,16 @@ namespace adapters; } } + /** + * Method called to verify phone status + * + * @return string : Return one phone status among 'available', 'unavailable', 'no_credit' + */ + public function check_phone_status(): string + { + return \models\Phone::STATUS_AVAILABLE; + } + public function test(): bool { return true; diff --git a/adapters/TwilioVirtualNumberAdapter.php b/adapters/TwilioVirtualNumberAdapter.php index 5ad0cc9..a17722c 100644 --- a/adapters/TwilioVirtualNumberAdapter.php +++ b/adapters/TwilioVirtualNumberAdapter.php @@ -160,6 +160,14 @@ class TwilioVirtualNumberAdapter implements AdapterInterface return true; } + /** + * Does the implemented service support updating phone status. + */ + public static function meta_support_phone_status(): bool + { + return false; + } + /** * Does the implemented service support flash smss. */ @@ -295,6 +303,16 @@ class TwilioVirtualNumberAdapter implements AdapterInterface } } + /** + * Method called to verify phone status + * + * @return string : Return one phone status among 'available', 'unavailable', 'no_credit' + */ + public function check_phone_status(): string + { + return \models\Phone::STATUS_AVAILABLE; + } + public function test(): bool { try diff --git a/assets/font/fonts-awesome/css/font-awesome.css b/assets/font/fonts-awesome/css/font-awesome.css index 4040b3c..ee906a8 100644 --- a/assets/font/fonts-awesome/css/font-awesome.css +++ b/assets/font/fonts-awesome/css/font-awesome.css @@ -1,13 +1,13 @@ /*! - * Font Awesome 4.2.0 by @davegandy - http://fontawesome.io - @fontawesome + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) */ /* FONT PATH * -------------------------- */ @font-face { font-family: 'FontAwesome'; - src: url('../fonts/fontawesome-webfont.eot?v=4.2.0'); - src: url('../fonts/fontawesome-webfont.eot?#iefix&v=4.2.0') format('embedded-opentype'), url('../fonts/fontawesome-webfont.woff?v=4.2.0') format('woff'), url('../fonts/fontawesome-webfont.ttf?v=4.2.0') format('truetype'), url('../fonts/fontawesome-webfont.svg?v=4.2.0#fontawesomeregular') format('svg'); + src: url('../fonts/fontawesome-webfont.eot?v=4.7.0'); + src: url('../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0') format('embedded-opentype'), url('../fonts/fontawesome-webfont.woff2?v=4.7.0') format('woff2'), url('../fonts/fontawesome-webfont.woff?v=4.7.0') format('woff'), url('../fonts/fontawesome-webfont.ttf?v=4.7.0') format('truetype'), url('../fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular') format('svg'); font-weight: normal; font-style: normal; } @@ -64,6 +64,19 @@ border: solid 0.08em #eeeeee; border-radius: .1em; } +.fa-pull-left { + float: left; +} +.fa-pull-right { + float: right; +} +.fa.fa-pull-left { + margin-right: .3em; +} +.fa.fa-pull-right { + margin-left: .3em; +} +/* Deprecated as of 4.4.0 */ .pull-right { float: right; } @@ -80,6 +93,10 @@ -webkit-animation: fa-spin 2s infinite linear; animation: fa-spin 2s infinite linear; } +.fa-pulse { + -webkit-animation: fa-spin 1s infinite steps(8); + animation: fa-spin 1s infinite steps(8); +} @-webkit-keyframes fa-spin { 0% { -webkit-transform: rotate(0deg); @@ -101,31 +118,31 @@ } } .fa-rotate-90 { - filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1); + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=1)"; -webkit-transform: rotate(90deg); -ms-transform: rotate(90deg); transform: rotate(90deg); } .fa-rotate-180 { - filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2); + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2)"; -webkit-transform: rotate(180deg); -ms-transform: rotate(180deg); transform: rotate(180deg); } .fa-rotate-270 { - filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3); + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=3)"; -webkit-transform: rotate(270deg); -ms-transform: rotate(270deg); transform: rotate(270deg); } .fa-flip-horizontal { - filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1); + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)"; -webkit-transform: scale(-1, 1); -ms-transform: scale(-1, 1); transform: scale(-1, 1); } .fa-flip-vertical { - filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1); + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"; -webkit-transform: scale(1, -1); -ms-transform: scale(1, -1); transform: scale(1, -1); @@ -610,6 +627,7 @@ .fa-twitter:before { content: "\f099"; } +.fa-facebook-f:before, .fa-facebook:before { content: "\f09a"; } @@ -622,6 +640,7 @@ .fa-credit-card:before { content: "\f09d"; } +.fa-feed:before, .fa-rss:before { content: "\f09e"; } @@ -1259,7 +1278,8 @@ .fa-male:before { content: "\f183"; } -.fa-gittip:before { +.fa-gittip:before, +.fa-gratipay:before { content: "\f184"; } .fa-sun-o:before { @@ -1363,7 +1383,7 @@ .fa-digg:before { content: "\f1a6"; } -.fa-pied-piper:before { +.fa-pied-piper-pp:before { content: "\f1a7"; } .fa-pied-piper-alt:before { @@ -1489,6 +1509,7 @@ content: "\f1ce"; } .fa-ra:before, +.fa-resistance:before, .fa-rebel:before { content: "\f1d0"; } @@ -1502,6 +1523,8 @@ .fa-git:before { content: "\f1d3"; } +.fa-y-combinator-square:before, +.fa-yc-square:before, .fa-hacker-news:before { content: "\f1d4"; } @@ -1670,3 +1693,645 @@ .fa-meanpath:before { content: "\f20c"; } +.fa-buysellads:before { + content: "\f20d"; +} +.fa-connectdevelop:before { + content: "\f20e"; +} +.fa-dashcube:before { + content: "\f210"; +} +.fa-forumbee:before { + content: "\f211"; +} +.fa-leanpub:before { + content: "\f212"; +} +.fa-sellsy:before { + content: "\f213"; +} +.fa-shirtsinbulk:before { + content: "\f214"; +} +.fa-simplybuilt:before { + content: "\f215"; +} +.fa-skyatlas:before { + content: "\f216"; +} +.fa-cart-plus:before { + content: "\f217"; +} +.fa-cart-arrow-down:before { + content: "\f218"; +} +.fa-diamond:before { + content: "\f219"; +} +.fa-ship:before { + content: "\f21a"; +} +.fa-user-secret:before { + content: "\f21b"; +} +.fa-motorcycle:before { + content: "\f21c"; +} +.fa-street-view:before { + content: "\f21d"; +} +.fa-heartbeat:before { + content: "\f21e"; +} +.fa-venus:before { + content: "\f221"; +} +.fa-mars:before { + content: "\f222"; +} +.fa-mercury:before { + content: "\f223"; +} +.fa-intersex:before, +.fa-transgender:before { + content: "\f224"; +} +.fa-transgender-alt:before { + content: "\f225"; +} +.fa-venus-double:before { + content: "\f226"; +} +.fa-mars-double:before { + content: "\f227"; +} +.fa-venus-mars:before { + content: "\f228"; +} +.fa-mars-stroke:before { + content: "\f229"; +} +.fa-mars-stroke-v:before { + content: "\f22a"; +} +.fa-mars-stroke-h:before { + content: "\f22b"; +} +.fa-neuter:before { + content: "\f22c"; +} +.fa-genderless:before { + content: "\f22d"; +} +.fa-facebook-official:before { + content: "\f230"; +} +.fa-pinterest-p:before { + content: "\f231"; +} +.fa-whatsapp:before { + content: "\f232"; +} +.fa-server:before { + content: "\f233"; +} +.fa-user-plus:before { + content: "\f234"; +} +.fa-user-times:before { + content: "\f235"; +} +.fa-hotel:before, +.fa-bed:before { + content: "\f236"; +} +.fa-viacoin:before { + content: "\f237"; +} +.fa-train:before { + content: "\f238"; +} +.fa-subway:before { + content: "\f239"; +} +.fa-medium:before { + content: "\f23a"; +} +.fa-yc:before, +.fa-y-combinator:before { + content: "\f23b"; +} +.fa-optin-monster:before { + content: "\f23c"; +} +.fa-opencart:before { + content: "\f23d"; +} +.fa-expeditedssl:before { + content: "\f23e"; +} +.fa-battery-4:before, +.fa-battery:before, +.fa-battery-full:before { + content: "\f240"; +} +.fa-battery-3:before, +.fa-battery-three-quarters:before { + content: "\f241"; +} +.fa-battery-2:before, +.fa-battery-half:before { + content: "\f242"; +} +.fa-battery-1:before, +.fa-battery-quarter:before { + content: "\f243"; +} +.fa-battery-0:before, +.fa-battery-empty:before { + content: "\f244"; +} +.fa-mouse-pointer:before { + content: "\f245"; +} +.fa-i-cursor:before { + content: "\f246"; +} +.fa-object-group:before { + content: "\f247"; +} +.fa-object-ungroup:before { + content: "\f248"; +} +.fa-sticky-note:before { + content: "\f249"; +} +.fa-sticky-note-o:before { + content: "\f24a"; +} +.fa-cc-jcb:before { + content: "\f24b"; +} +.fa-cc-diners-club:before { + content: "\f24c"; +} +.fa-clone:before { + content: "\f24d"; +} +.fa-balance-scale:before { + content: "\f24e"; +} +.fa-hourglass-o:before { + content: "\f250"; +} +.fa-hourglass-1:before, +.fa-hourglass-start:before { + content: "\f251"; +} +.fa-hourglass-2:before, +.fa-hourglass-half:before { + content: "\f252"; +} +.fa-hourglass-3:before, +.fa-hourglass-end:before { + content: "\f253"; +} +.fa-hourglass:before { + content: "\f254"; +} +.fa-hand-grab-o:before, +.fa-hand-rock-o:before { + content: "\f255"; +} +.fa-hand-stop-o:before, +.fa-hand-paper-o:before { + content: "\f256"; +} +.fa-hand-scissors-o:before { + content: "\f257"; +} +.fa-hand-lizard-o:before { + content: "\f258"; +} +.fa-hand-spock-o:before { + content: "\f259"; +} +.fa-hand-pointer-o:before { + content: "\f25a"; +} +.fa-hand-peace-o:before { + content: "\f25b"; +} +.fa-trademark:before { + content: "\f25c"; +} +.fa-registered:before { + content: "\f25d"; +} +.fa-creative-commons:before { + content: "\f25e"; +} +.fa-gg:before { + content: "\f260"; +} +.fa-gg-circle:before { + content: "\f261"; +} +.fa-tripadvisor:before { + content: "\f262"; +} +.fa-odnoklassniki:before { + content: "\f263"; +} +.fa-odnoklassniki-square:before { + content: "\f264"; +} +.fa-get-pocket:before { + content: "\f265"; +} +.fa-wikipedia-w:before { + content: "\f266"; +} +.fa-safari:before { + content: "\f267"; +} +.fa-chrome:before { + content: "\f268"; +} +.fa-firefox:before { + content: "\f269"; +} +.fa-opera:before { + content: "\f26a"; +} +.fa-internet-explorer:before { + content: "\f26b"; +} +.fa-tv:before, +.fa-television:before { + content: "\f26c"; +} +.fa-contao:before { + content: "\f26d"; +} +.fa-500px:before { + content: "\f26e"; +} +.fa-amazon:before { + content: "\f270"; +} +.fa-calendar-plus-o:before { + content: "\f271"; +} +.fa-calendar-minus-o:before { + content: "\f272"; +} +.fa-calendar-times-o:before { + content: "\f273"; +} +.fa-calendar-check-o:before { + content: "\f274"; +} +.fa-industry:before { + content: "\f275"; +} +.fa-map-pin:before { + content: "\f276"; +} +.fa-map-signs:before { + content: "\f277"; +} +.fa-map-o:before { + content: "\f278"; +} +.fa-map:before { + content: "\f279"; +} +.fa-commenting:before { + content: "\f27a"; +} +.fa-commenting-o:before { + content: "\f27b"; +} +.fa-houzz:before { + content: "\f27c"; +} +.fa-vimeo:before { + content: "\f27d"; +} +.fa-black-tie:before { + content: "\f27e"; +} +.fa-fonticons:before { + content: "\f280"; +} +.fa-reddit-alien:before { + content: "\f281"; +} +.fa-edge:before { + content: "\f282"; +} +.fa-credit-card-alt:before { + content: "\f283"; +} +.fa-codiepie:before { + content: "\f284"; +} +.fa-modx:before { + content: "\f285"; +} +.fa-fort-awesome:before { + content: "\f286"; +} +.fa-usb:before { + content: "\f287"; +} +.fa-product-hunt:before { + content: "\f288"; +} +.fa-mixcloud:before { + content: "\f289"; +} +.fa-scribd:before { + content: "\f28a"; +} +.fa-pause-circle:before { + content: "\f28b"; +} +.fa-pause-circle-o:before { + content: "\f28c"; +} +.fa-stop-circle:before { + content: "\f28d"; +} +.fa-stop-circle-o:before { + content: "\f28e"; +} +.fa-shopping-bag:before { + content: "\f290"; +} +.fa-shopping-basket:before { + content: "\f291"; +} +.fa-hashtag:before { + content: "\f292"; +} +.fa-bluetooth:before { + content: "\f293"; +} +.fa-bluetooth-b:before { + content: "\f294"; +} +.fa-percent:before { + content: "\f295"; +} +.fa-gitlab:before { + content: "\f296"; +} +.fa-wpbeginner:before { + content: "\f297"; +} +.fa-wpforms:before { + content: "\f298"; +} +.fa-envira:before { + content: "\f299"; +} +.fa-universal-access:before { + content: "\f29a"; +} +.fa-wheelchair-alt:before { + content: "\f29b"; +} +.fa-question-circle-o:before { + content: "\f29c"; +} +.fa-blind:before { + content: "\f29d"; +} +.fa-audio-description:before { + content: "\f29e"; +} +.fa-volume-control-phone:before { + content: "\f2a0"; +} +.fa-braille:before { + content: "\f2a1"; +} +.fa-assistive-listening-systems:before { + content: "\f2a2"; +} +.fa-asl-interpreting:before, +.fa-american-sign-language-interpreting:before { + content: "\f2a3"; +} +.fa-deafness:before, +.fa-hard-of-hearing:before, +.fa-deaf:before { + content: "\f2a4"; +} +.fa-glide:before { + content: "\f2a5"; +} +.fa-glide-g:before { + content: "\f2a6"; +} +.fa-signing:before, +.fa-sign-language:before { + content: "\f2a7"; +} +.fa-low-vision:before { + content: "\f2a8"; +} +.fa-viadeo:before { + content: "\f2a9"; +} +.fa-viadeo-square:before { + content: "\f2aa"; +} +.fa-snapchat:before { + content: "\f2ab"; +} +.fa-snapchat-ghost:before { + content: "\f2ac"; +} +.fa-snapchat-square:before { + content: "\f2ad"; +} +.fa-pied-piper:before { + content: "\f2ae"; +} +.fa-first-order:before { + content: "\f2b0"; +} +.fa-yoast:before { + content: "\f2b1"; +} +.fa-themeisle:before { + content: "\f2b2"; +} +.fa-google-plus-circle:before, +.fa-google-plus-official:before { + content: "\f2b3"; +} +.fa-fa:before, +.fa-font-awesome:before { + content: "\f2b4"; +} +.fa-handshake-o:before { + content: "\f2b5"; +} +.fa-envelope-open:before { + content: "\f2b6"; +} +.fa-envelope-open-o:before { + content: "\f2b7"; +} +.fa-linode:before { + content: "\f2b8"; +} +.fa-address-book:before { + content: "\f2b9"; +} +.fa-address-book-o:before { + content: "\f2ba"; +} +.fa-vcard:before, +.fa-address-card:before { + content: "\f2bb"; +} +.fa-vcard-o:before, +.fa-address-card-o:before { + content: "\f2bc"; +} +.fa-user-circle:before { + content: "\f2bd"; +} +.fa-user-circle-o:before { + content: "\f2be"; +} +.fa-user-o:before { + content: "\f2c0"; +} +.fa-id-badge:before { + content: "\f2c1"; +} +.fa-drivers-license:before, +.fa-id-card:before { + content: "\f2c2"; +} +.fa-drivers-license-o:before, +.fa-id-card-o:before { + content: "\f2c3"; +} +.fa-quora:before { + content: "\f2c4"; +} +.fa-free-code-camp:before { + content: "\f2c5"; +} +.fa-telegram:before { + content: "\f2c6"; +} +.fa-thermometer-4:before, +.fa-thermometer:before, +.fa-thermometer-full:before { + content: "\f2c7"; +} +.fa-thermometer-3:before, +.fa-thermometer-three-quarters:before { + content: "\f2c8"; +} +.fa-thermometer-2:before, +.fa-thermometer-half:before { + content: "\f2c9"; +} +.fa-thermometer-1:before, +.fa-thermometer-quarter:before { + content: "\f2ca"; +} +.fa-thermometer-0:before, +.fa-thermometer-empty:before { + content: "\f2cb"; +} +.fa-shower:before { + content: "\f2cc"; +} +.fa-bathtub:before, +.fa-s15:before, +.fa-bath:before { + content: "\f2cd"; +} +.fa-podcast:before { + content: "\f2ce"; +} +.fa-window-maximize:before { + content: "\f2d0"; +} +.fa-window-minimize:before { + content: "\f2d1"; +} +.fa-window-restore:before { + content: "\f2d2"; +} +.fa-times-rectangle:before, +.fa-window-close:before { + content: "\f2d3"; +} +.fa-times-rectangle-o:before, +.fa-window-close-o:before { + content: "\f2d4"; +} +.fa-bandcamp:before { + content: "\f2d5"; +} +.fa-grav:before { + content: "\f2d6"; +} +.fa-etsy:before { + content: "\f2d7"; +} +.fa-imdb:before { + content: "\f2d8"; +} +.fa-ravelry:before { + content: "\f2d9"; +} +.fa-eercast:before { + content: "\f2da"; +} +.fa-microchip:before { + content: "\f2db"; +} +.fa-snowflake-o:before { + content: "\f2dc"; +} +.fa-superpowers:before { + content: "\f2dd"; +} +.fa-wpexplorer:before { + content: "\f2de"; +} +.fa-meetup:before { + content: "\f2e0"; +} +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + border: 0; +} +.sr-only-focusable:active, +.sr-only-focusable:focus { + position: static; + width: auto; + height: auto; + margin: 0; + overflow: visible; + clip: auto; +} diff --git a/assets/font/fonts-awesome/css/font-awesome.min.css b/assets/font/fonts-awesome/css/font-awesome.min.css index ec53d4d..540440c 100644 --- a/assets/font/fonts-awesome/css/font-awesome.min.css +++ b/assets/font/fonts-awesome/css/font-awesome.min.css @@ -1,4 +1,4 @@ /*! - * Font Awesome 4.2.0 by @davegandy - http://fontawesome.io - @fontawesome + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) - */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.2.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.2.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff?v=4.2.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.2.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.2.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"} \ No newline at end of file + */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.7.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.7.0') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.7.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.7.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-resistance:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-intersex:before,.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-genderless:before{content:"\f22d"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.fa-yc:before,.fa-y-combinator:before{content:"\f23b"}.fa-optin-monster:before{content:"\f23c"}.fa-opencart:before{content:"\f23d"}.fa-expeditedssl:before{content:"\f23e"}.fa-battery-4:before,.fa-battery:before,.fa-battery-full:before{content:"\f240"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-battery-2:before,.fa-battery-half:before{content:"\f242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-mouse-pointer:before{content:"\f245"}.fa-i-cursor:before{content:"\f246"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-sticky-note:before{content:"\f249"}.fa-sticky-note-o:before{content:"\f24a"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-diners-club:before{content:"\f24c"}.fa-clone:before{content:"\f24d"}.fa-balance-scale:before{content:"\f24e"}.fa-hourglass-o:before{content:"\f250"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-hourglass:before{content:"\f254"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255"}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:"\f256"}.fa-hand-scissors-o:before{content:"\f257"}.fa-hand-lizard-o:before{content:"\f258"}.fa-hand-spock-o:before{content:"\f259"}.fa-hand-pointer-o:before{content:"\f25a"}.fa-hand-peace-o:before{content:"\f25b"}.fa-trademark:before{content:"\f25c"}.fa-registered:before{content:"\f25d"}.fa-creative-commons:before{content:"\f25e"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-tripadvisor:before{content:"\f262"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-get-pocket:before{content:"\f265"}.fa-wikipedia-w:before{content:"\f266"}.fa-safari:before{content:"\f267"}.fa-chrome:before{content:"\f268"}.fa-firefox:before{content:"\f269"}.fa-opera:before{content:"\f26a"}.fa-internet-explorer:before{content:"\f26b"}.fa-tv:before,.fa-television:before{content:"\f26c"}.fa-contao:before{content:"\f26d"}.fa-500px:before{content:"\f26e"}.fa-amazon:before{content:"\f270"}.fa-calendar-plus-o:before{content:"\f271"}.fa-calendar-minus-o:before{content:"\f272"}.fa-calendar-times-o:before{content:"\f273"}.fa-calendar-check-o:before{content:"\f274"}.fa-industry:before{content:"\f275"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-map-o:before{content:"\f278"}.fa-map:before{content:"\f279"}.fa-commenting:before{content:"\f27a"}.fa-commenting-o:before{content:"\f27b"}.fa-houzz:before{content:"\f27c"}.fa-vimeo:before{content:"\f27d"}.fa-black-tie:before{content:"\f27e"}.fa-fonticons:before{content:"\f280"}.fa-reddit-alien:before{content:"\f281"}.fa-edge:before{content:"\f282"}.fa-credit-card-alt:before{content:"\f283"}.fa-codiepie:before{content:"\f284"}.fa-modx:before{content:"\f285"}.fa-fort-awesome:before{content:"\f286"}.fa-usb:before{content:"\f287"}.fa-product-hunt:before{content:"\f288"}.fa-mixcloud:before{content:"\f289"}.fa-scribd:before{content:"\f28a"}.fa-pause-circle:before{content:"\f28b"}.fa-pause-circle-o:before{content:"\f28c"}.fa-stop-circle:before{content:"\f28d"}.fa-stop-circle-o:before{content:"\f28e"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-hashtag:before{content:"\f292"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-percent:before{content:"\f295"}.fa-gitlab:before{content:"\f296"}.fa-wpbeginner:before{content:"\f297"}.fa-wpforms:before{content:"\f298"}.fa-envira:before{content:"\f299"}.fa-universal-access:before{content:"\f29a"}.fa-wheelchair-alt:before{content:"\f29b"}.fa-question-circle-o:before{content:"\f29c"}.fa-blind:before{content:"\f29d"}.fa-audio-description:before{content:"\f29e"}.fa-volume-control-phone:before{content:"\f2a0"}.fa-braille:before{content:"\f2a1"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asl-interpreting:before,.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-deafness:before,.fa-hard-of-hearing:before,.fa-deaf:before{content:"\f2a4"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-signing:before,.fa-sign-language:before{content:"\f2a7"}.fa-low-vision:before{content:"\f2a8"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-pied-piper:before{content:"\f2ae"}.fa-first-order:before{content:"\f2b0"}.fa-yoast:before{content:"\f2b1"}.fa-themeisle:before{content:"\f2b2"}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:"\f2b3"}.fa-fa:before,.fa-font-awesome:before{content:"\f2b4"}.fa-handshake-o:before{content:"\f2b5"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-o:before{content:"\f2b7"}.fa-linode:before{content:"\f2b8"}.fa-address-book:before{content:"\f2b9"}.fa-address-book-o:before{content:"\f2ba"}.fa-vcard:before,.fa-address-card:before{content:"\f2bb"}.fa-vcard-o:before,.fa-address-card-o:before{content:"\f2bc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-circle-o:before{content:"\f2be"}.fa-user-o:before{content:"\f2c0"}.fa-id-badge:before{content:"\f2c1"}.fa-drivers-license:before,.fa-id-card:before{content:"\f2c2"}.fa-drivers-license-o:before,.fa-id-card-o:before{content:"\f2c3"}.fa-quora:before{content:"\f2c4"}.fa-free-code-camp:before{content:"\f2c5"}.fa-telegram:before{content:"\f2c6"}.fa-thermometer-4:before,.fa-thermometer:before,.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-thermometer-2:before,.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:"\f2cb"}.fa-shower:before{content:"\f2cc"}.fa-bathtub:before,.fa-s15:before,.fa-bath:before{content:"\f2cd"}.fa-podcast:before{content:"\f2ce"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-times-rectangle:before,.fa-window-close:before{content:"\f2d3"}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:"\f2d4"}.fa-bandcamp:before{content:"\f2d5"}.fa-grav:before{content:"\f2d6"}.fa-etsy:before{content:"\f2d7"}.fa-imdb:before{content:"\f2d8"}.fa-ravelry:before{content:"\f2d9"}.fa-eercast:before{content:"\f2da"}.fa-microchip:before{content:"\f2db"}.fa-snowflake-o:before{content:"\f2dc"}.fa-superpowers:before{content:"\f2dd"}.fa-wpexplorer:before{content:"\f2de"}.fa-meetup:before{content:"\f2e0"}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto} diff --git a/assets/font/fonts-awesome/fonts/FontAwesome.otf b/assets/font/fonts-awesome/fonts/FontAwesome.otf index 81c9ad9..401ec0f 100644 Binary files a/assets/font/fonts-awesome/fonts/FontAwesome.otf and b/assets/font/fonts-awesome/fonts/FontAwesome.otf differ diff --git a/assets/font/fonts-awesome/fonts/fontawesome-webfont.eot b/assets/font/fonts-awesome/fonts/fontawesome-webfont.eot index 84677bc..e9f60ca 100644 Binary files a/assets/font/fonts-awesome/fonts/fontawesome-webfont.eot and b/assets/font/fonts-awesome/fonts/fontawesome-webfont.eot differ diff --git a/assets/font/fonts-awesome/fonts/fontawesome-webfont.svg b/assets/font/fonts-awesome/fonts/fontawesome-webfont.svg index d907b25..855c845 100644 --- a/assets/font/fonts-awesome/fonts/fontawesome-webfont.svg +++ b/assets/font/fonts-awesome/fonts/fontawesome-webfont.svg @@ -1,520 +1,2671 @@ - - + + +Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 + By ,,, +Copyright Dave Gandy 2016. All rights reserved. + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/font/fonts-awesome/fonts/fontawesome-webfont.ttf b/assets/font/fonts-awesome/fonts/fontawesome-webfont.ttf index 96a3639..35acda2 100644 Binary files a/assets/font/fonts-awesome/fonts/fontawesome-webfont.ttf and b/assets/font/fonts-awesome/fonts/fontawesome-webfont.ttf differ diff --git a/assets/font/fonts-awesome/fonts/fontawesome-webfont.woff b/assets/font/fonts-awesome/fonts/fontawesome-webfont.woff index 628b6a5..400014a 100644 Binary files a/assets/font/fonts-awesome/fonts/fontawesome-webfont.woff and b/assets/font/fonts-awesome/fonts/fontawesome-webfont.woff differ diff --git a/assets/font/fonts-awesome/fonts/fontawesome-webfont.woff2 b/assets/font/fonts-awesome/fonts/fontawesome-webfont.woff2 new file mode 100644 index 0000000..4d13fc6 Binary files /dev/null and b/assets/font/fonts-awesome/fonts/fontawesome-webfont.woff2 differ diff --git a/assets/font/fonts-awesome/less/spinning.less b/assets/font/fonts-awesome/less/animated.less similarity index 79% rename from assets/font/fonts-awesome/less/spinning.less rename to assets/font/fonts-awesome/less/animated.less index 6e1564e..66ad52a 100644 --- a/assets/font/fonts-awesome/less/spinning.less +++ b/assets/font/fonts-awesome/less/animated.less @@ -1,4 +1,4 @@ -// Spinning Icons +// Animated Icons // -------------------------- .@{fa-css-prefix}-spin { @@ -6,6 +6,11 @@ animation: fa-spin 2s infinite linear; } +.@{fa-css-prefix}-pulse { + -webkit-animation: fa-spin 1s infinite steps(8); + animation: fa-spin 1s infinite steps(8); +} + @-webkit-keyframes fa-spin { 0% { -webkit-transform: rotate(0deg); diff --git a/assets/font/fonts-awesome/less/bordered-pulled.less b/assets/font/fonts-awesome/less/bordered-pulled.less index 0c90eb5..f1c8ad7 100644 --- a/assets/font/fonts-awesome/less/bordered-pulled.less +++ b/assets/font/fonts-awesome/less/bordered-pulled.less @@ -7,6 +7,15 @@ border-radius: .1em; } +.@{fa-css-prefix}-pull-left { float: left; } +.@{fa-css-prefix}-pull-right { float: right; } + +.@{fa-css-prefix} { + &.@{fa-css-prefix}-pull-left { margin-right: .3em; } + &.@{fa-css-prefix}-pull-right { margin-left: .3em; } +} + +/* Deprecated as of 4.4.0 */ .pull-right { float: right; } .pull-left { float: left; } diff --git a/assets/font/fonts-awesome/less/core.less b/assets/font/fonts-awesome/less/core.less index 01d1910..c577ac8 100644 --- a/assets/font/fonts-awesome/less/core.less +++ b/assets/font/fonts-awesome/less/core.less @@ -3,9 +3,10 @@ .@{fa-css-prefix} { display: inline-block; - font: normal normal normal 14px/1 FontAwesome; // shortening font declaration + font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration font-size: inherit; // can't have font-size inherit on line above, so need to override text-rendering: auto; // optimizelegibility throws things off #1094 -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; + } diff --git a/assets/font/fonts-awesome/less/font-awesome.less b/assets/font/fonts-awesome/less/font-awesome.less index 195fd46..c3677de 100644 --- a/assets/font/fonts-awesome/less/font-awesome.less +++ b/assets/font/fonts-awesome/less/font-awesome.less @@ -1,5 +1,5 @@ /*! - * Font Awesome 4.2.0 by @davegandy - http://fontawesome.io - @fontawesome + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) */ @@ -11,7 +11,8 @@ @import "fixed-width.less"; @import "list.less"; @import "bordered-pulled.less"; -@import "spinning.less"; +@import "animated.less"; @import "rotated-flipped.less"; @import "stacked.less"; @import "icons.less"; +@import "screen-reader.less"; diff --git a/assets/font/fonts-awesome/less/icons.less b/assets/font/fonts-awesome/less/icons.less index b5c26c7..159d600 100644 --- a/assets/font/fonts-awesome/less/icons.less +++ b/assets/font/fonts-awesome/less/icons.less @@ -158,10 +158,12 @@ .@{fa-css-prefix}-bookmark-o:before { content: @fa-var-bookmark-o; } .@{fa-css-prefix}-phone-square:before { content: @fa-var-phone-square; } .@{fa-css-prefix}-twitter:before { content: @fa-var-twitter; } +.@{fa-css-prefix}-facebook-f:before, .@{fa-css-prefix}-facebook:before { content: @fa-var-facebook; } .@{fa-css-prefix}-github:before { content: @fa-var-github; } .@{fa-css-prefix}-unlock:before { content: @fa-var-unlock; } .@{fa-css-prefix}-credit-card:before { content: @fa-var-credit-card; } +.@{fa-css-prefix}-feed:before, .@{fa-css-prefix}-rss:before { content: @fa-var-rss; } .@{fa-css-prefix}-hdd-o:before { content: @fa-var-hdd-o; } .@{fa-css-prefix}-bullhorn:before { content: @fa-var-bullhorn; } @@ -397,7 +399,8 @@ .@{fa-css-prefix}-trello:before { content: @fa-var-trello; } .@{fa-css-prefix}-female:before { content: @fa-var-female; } .@{fa-css-prefix}-male:before { content: @fa-var-male; } -.@{fa-css-prefix}-gittip:before { content: @fa-var-gittip; } +.@{fa-css-prefix}-gittip:before, +.@{fa-css-prefix}-gratipay:before { content: @fa-var-gratipay; } .@{fa-css-prefix}-sun-o:before { content: @fa-var-sun-o; } .@{fa-css-prefix}-moon-o:before { content: @fa-var-moon-o; } .@{fa-css-prefix}-archive:before { content: @fa-var-archive; } @@ -435,7 +438,7 @@ .@{fa-css-prefix}-stumbleupon:before { content: @fa-var-stumbleupon; } .@{fa-css-prefix}-delicious:before { content: @fa-var-delicious; } .@{fa-css-prefix}-digg:before { content: @fa-var-digg; } -.@{fa-css-prefix}-pied-piper:before { content: @fa-var-pied-piper; } +.@{fa-css-prefix}-pied-piper-pp:before { content: @fa-var-pied-piper-pp; } .@{fa-css-prefix}-pied-piper-alt:before { content: @fa-var-pied-piper-alt; } .@{fa-css-prefix}-drupal:before { content: @fa-var-drupal; } .@{fa-css-prefix}-joomla:before { content: @fa-var-joomla; } @@ -485,11 +488,14 @@ .@{fa-css-prefix}-life-ring:before { content: @fa-var-life-ring; } .@{fa-css-prefix}-circle-o-notch:before { content: @fa-var-circle-o-notch; } .@{fa-css-prefix}-ra:before, +.@{fa-css-prefix}-resistance:before, .@{fa-css-prefix}-rebel:before { content: @fa-var-rebel; } .@{fa-css-prefix}-ge:before, .@{fa-css-prefix}-empire:before { content: @fa-var-empire; } .@{fa-css-prefix}-git-square:before { content: @fa-var-git-square; } .@{fa-css-prefix}-git:before { content: @fa-var-git; } +.@{fa-css-prefix}-y-combinator-square:before, +.@{fa-css-prefix}-yc-square:before, .@{fa-css-prefix}-hacker-news:before { content: @fa-var-hacker-news; } .@{fa-css-prefix}-tencent-weibo:before { content: @fa-var-tencent-weibo; } .@{fa-css-prefix}-qq:before { content: @fa-var-qq; } @@ -550,3 +556,234 @@ .@{fa-css-prefix}-sheqel:before, .@{fa-css-prefix}-ils:before { content: @fa-var-ils; } .@{fa-css-prefix}-meanpath:before { content: @fa-var-meanpath; } +.@{fa-css-prefix}-buysellads:before { content: @fa-var-buysellads; } +.@{fa-css-prefix}-connectdevelop:before { content: @fa-var-connectdevelop; } +.@{fa-css-prefix}-dashcube:before { content: @fa-var-dashcube; } +.@{fa-css-prefix}-forumbee:before { content: @fa-var-forumbee; } +.@{fa-css-prefix}-leanpub:before { content: @fa-var-leanpub; } +.@{fa-css-prefix}-sellsy:before { content: @fa-var-sellsy; } +.@{fa-css-prefix}-shirtsinbulk:before { content: @fa-var-shirtsinbulk; } +.@{fa-css-prefix}-simplybuilt:before { content: @fa-var-simplybuilt; } +.@{fa-css-prefix}-skyatlas:before { content: @fa-var-skyatlas; } +.@{fa-css-prefix}-cart-plus:before { content: @fa-var-cart-plus; } +.@{fa-css-prefix}-cart-arrow-down:before { content: @fa-var-cart-arrow-down; } +.@{fa-css-prefix}-diamond:before { content: @fa-var-diamond; } +.@{fa-css-prefix}-ship:before { content: @fa-var-ship; } +.@{fa-css-prefix}-user-secret:before { content: @fa-var-user-secret; } +.@{fa-css-prefix}-motorcycle:before { content: @fa-var-motorcycle; } +.@{fa-css-prefix}-street-view:before { content: @fa-var-street-view; } +.@{fa-css-prefix}-heartbeat:before { content: @fa-var-heartbeat; } +.@{fa-css-prefix}-venus:before { content: @fa-var-venus; } +.@{fa-css-prefix}-mars:before { content: @fa-var-mars; } +.@{fa-css-prefix}-mercury:before { content: @fa-var-mercury; } +.@{fa-css-prefix}-intersex:before, +.@{fa-css-prefix}-transgender:before { content: @fa-var-transgender; } +.@{fa-css-prefix}-transgender-alt:before { content: @fa-var-transgender-alt; } +.@{fa-css-prefix}-venus-double:before { content: @fa-var-venus-double; } +.@{fa-css-prefix}-mars-double:before { content: @fa-var-mars-double; } +.@{fa-css-prefix}-venus-mars:before { content: @fa-var-venus-mars; } +.@{fa-css-prefix}-mars-stroke:before { content: @fa-var-mars-stroke; } +.@{fa-css-prefix}-mars-stroke-v:before { content: @fa-var-mars-stroke-v; } +.@{fa-css-prefix}-mars-stroke-h:before { content: @fa-var-mars-stroke-h; } +.@{fa-css-prefix}-neuter:before { content: @fa-var-neuter; } +.@{fa-css-prefix}-genderless:before { content: @fa-var-genderless; } +.@{fa-css-prefix}-facebook-official:before { content: @fa-var-facebook-official; } +.@{fa-css-prefix}-pinterest-p:before { content: @fa-var-pinterest-p; } +.@{fa-css-prefix}-whatsapp:before { content: @fa-var-whatsapp; } +.@{fa-css-prefix}-server:before { content: @fa-var-server; } +.@{fa-css-prefix}-user-plus:before { content: @fa-var-user-plus; } +.@{fa-css-prefix}-user-times:before { content: @fa-var-user-times; } +.@{fa-css-prefix}-hotel:before, +.@{fa-css-prefix}-bed:before { content: @fa-var-bed; } +.@{fa-css-prefix}-viacoin:before { content: @fa-var-viacoin; } +.@{fa-css-prefix}-train:before { content: @fa-var-train; } +.@{fa-css-prefix}-subway:before { content: @fa-var-subway; } +.@{fa-css-prefix}-medium:before { content: @fa-var-medium; } +.@{fa-css-prefix}-yc:before, +.@{fa-css-prefix}-y-combinator:before { content: @fa-var-y-combinator; } +.@{fa-css-prefix}-optin-monster:before { content: @fa-var-optin-monster; } +.@{fa-css-prefix}-opencart:before { content: @fa-var-opencart; } +.@{fa-css-prefix}-expeditedssl:before { content: @fa-var-expeditedssl; } +.@{fa-css-prefix}-battery-4:before, +.@{fa-css-prefix}-battery:before, +.@{fa-css-prefix}-battery-full:before { content: @fa-var-battery-full; } +.@{fa-css-prefix}-battery-3:before, +.@{fa-css-prefix}-battery-three-quarters:before { content: @fa-var-battery-three-quarters; } +.@{fa-css-prefix}-battery-2:before, +.@{fa-css-prefix}-battery-half:before { content: @fa-var-battery-half; } +.@{fa-css-prefix}-battery-1:before, +.@{fa-css-prefix}-battery-quarter:before { content: @fa-var-battery-quarter; } +.@{fa-css-prefix}-battery-0:before, +.@{fa-css-prefix}-battery-empty:before { content: @fa-var-battery-empty; } +.@{fa-css-prefix}-mouse-pointer:before { content: @fa-var-mouse-pointer; } +.@{fa-css-prefix}-i-cursor:before { content: @fa-var-i-cursor; } +.@{fa-css-prefix}-object-group:before { content: @fa-var-object-group; } +.@{fa-css-prefix}-object-ungroup:before { content: @fa-var-object-ungroup; } +.@{fa-css-prefix}-sticky-note:before { content: @fa-var-sticky-note; } +.@{fa-css-prefix}-sticky-note-o:before { content: @fa-var-sticky-note-o; } +.@{fa-css-prefix}-cc-jcb:before { content: @fa-var-cc-jcb; } +.@{fa-css-prefix}-cc-diners-club:before { content: @fa-var-cc-diners-club; } +.@{fa-css-prefix}-clone:before { content: @fa-var-clone; } +.@{fa-css-prefix}-balance-scale:before { content: @fa-var-balance-scale; } +.@{fa-css-prefix}-hourglass-o:before { content: @fa-var-hourglass-o; } +.@{fa-css-prefix}-hourglass-1:before, +.@{fa-css-prefix}-hourglass-start:before { content: @fa-var-hourglass-start; } +.@{fa-css-prefix}-hourglass-2:before, +.@{fa-css-prefix}-hourglass-half:before { content: @fa-var-hourglass-half; } +.@{fa-css-prefix}-hourglass-3:before, +.@{fa-css-prefix}-hourglass-end:before { content: @fa-var-hourglass-end; } +.@{fa-css-prefix}-hourglass:before { content: @fa-var-hourglass; } +.@{fa-css-prefix}-hand-grab-o:before, +.@{fa-css-prefix}-hand-rock-o:before { content: @fa-var-hand-rock-o; } +.@{fa-css-prefix}-hand-stop-o:before, +.@{fa-css-prefix}-hand-paper-o:before { content: @fa-var-hand-paper-o; } +.@{fa-css-prefix}-hand-scissors-o:before { content: @fa-var-hand-scissors-o; } +.@{fa-css-prefix}-hand-lizard-o:before { content: @fa-var-hand-lizard-o; } +.@{fa-css-prefix}-hand-spock-o:before { content: @fa-var-hand-spock-o; } +.@{fa-css-prefix}-hand-pointer-o:before { content: @fa-var-hand-pointer-o; } +.@{fa-css-prefix}-hand-peace-o:before { content: @fa-var-hand-peace-o; } +.@{fa-css-prefix}-trademark:before { content: @fa-var-trademark; } +.@{fa-css-prefix}-registered:before { content: @fa-var-registered; } +.@{fa-css-prefix}-creative-commons:before { content: @fa-var-creative-commons; } +.@{fa-css-prefix}-gg:before { content: @fa-var-gg; } +.@{fa-css-prefix}-gg-circle:before { content: @fa-var-gg-circle; } +.@{fa-css-prefix}-tripadvisor:before { content: @fa-var-tripadvisor; } +.@{fa-css-prefix}-odnoklassniki:before { content: @fa-var-odnoklassniki; } +.@{fa-css-prefix}-odnoklassniki-square:before { content: @fa-var-odnoklassniki-square; } +.@{fa-css-prefix}-get-pocket:before { content: @fa-var-get-pocket; } +.@{fa-css-prefix}-wikipedia-w:before { content: @fa-var-wikipedia-w; } +.@{fa-css-prefix}-safari:before { content: @fa-var-safari; } +.@{fa-css-prefix}-chrome:before { content: @fa-var-chrome; } +.@{fa-css-prefix}-firefox:before { content: @fa-var-firefox; } +.@{fa-css-prefix}-opera:before { content: @fa-var-opera; } +.@{fa-css-prefix}-internet-explorer:before { content: @fa-var-internet-explorer; } +.@{fa-css-prefix}-tv:before, +.@{fa-css-prefix}-television:before { content: @fa-var-television; } +.@{fa-css-prefix}-contao:before { content: @fa-var-contao; } +.@{fa-css-prefix}-500px:before { content: @fa-var-500px; } +.@{fa-css-prefix}-amazon:before { content: @fa-var-amazon; } +.@{fa-css-prefix}-calendar-plus-o:before { content: @fa-var-calendar-plus-o; } +.@{fa-css-prefix}-calendar-minus-o:before { content: @fa-var-calendar-minus-o; } +.@{fa-css-prefix}-calendar-times-o:before { content: @fa-var-calendar-times-o; } +.@{fa-css-prefix}-calendar-check-o:before { content: @fa-var-calendar-check-o; } +.@{fa-css-prefix}-industry:before { content: @fa-var-industry; } +.@{fa-css-prefix}-map-pin:before { content: @fa-var-map-pin; } +.@{fa-css-prefix}-map-signs:before { content: @fa-var-map-signs; } +.@{fa-css-prefix}-map-o:before { content: @fa-var-map-o; } +.@{fa-css-prefix}-map:before { content: @fa-var-map; } +.@{fa-css-prefix}-commenting:before { content: @fa-var-commenting; } +.@{fa-css-prefix}-commenting-o:before { content: @fa-var-commenting-o; } +.@{fa-css-prefix}-houzz:before { content: @fa-var-houzz; } +.@{fa-css-prefix}-vimeo:before { content: @fa-var-vimeo; } +.@{fa-css-prefix}-black-tie:before { content: @fa-var-black-tie; } +.@{fa-css-prefix}-fonticons:before { content: @fa-var-fonticons; } +.@{fa-css-prefix}-reddit-alien:before { content: @fa-var-reddit-alien; } +.@{fa-css-prefix}-edge:before { content: @fa-var-edge; } +.@{fa-css-prefix}-credit-card-alt:before { content: @fa-var-credit-card-alt; } +.@{fa-css-prefix}-codiepie:before { content: @fa-var-codiepie; } +.@{fa-css-prefix}-modx:before { content: @fa-var-modx; } +.@{fa-css-prefix}-fort-awesome:before { content: @fa-var-fort-awesome; } +.@{fa-css-prefix}-usb:before { content: @fa-var-usb; } +.@{fa-css-prefix}-product-hunt:before { content: @fa-var-product-hunt; } +.@{fa-css-prefix}-mixcloud:before { content: @fa-var-mixcloud; } +.@{fa-css-prefix}-scribd:before { content: @fa-var-scribd; } +.@{fa-css-prefix}-pause-circle:before { content: @fa-var-pause-circle; } +.@{fa-css-prefix}-pause-circle-o:before { content: @fa-var-pause-circle-o; } +.@{fa-css-prefix}-stop-circle:before { content: @fa-var-stop-circle; } +.@{fa-css-prefix}-stop-circle-o:before { content: @fa-var-stop-circle-o; } +.@{fa-css-prefix}-shopping-bag:before { content: @fa-var-shopping-bag; } +.@{fa-css-prefix}-shopping-basket:before { content: @fa-var-shopping-basket; } +.@{fa-css-prefix}-hashtag:before { content: @fa-var-hashtag; } +.@{fa-css-prefix}-bluetooth:before { content: @fa-var-bluetooth; } +.@{fa-css-prefix}-bluetooth-b:before { content: @fa-var-bluetooth-b; } +.@{fa-css-prefix}-percent:before { content: @fa-var-percent; } +.@{fa-css-prefix}-gitlab:before { content: @fa-var-gitlab; } +.@{fa-css-prefix}-wpbeginner:before { content: @fa-var-wpbeginner; } +.@{fa-css-prefix}-wpforms:before { content: @fa-var-wpforms; } +.@{fa-css-prefix}-envira:before { content: @fa-var-envira; } +.@{fa-css-prefix}-universal-access:before { content: @fa-var-universal-access; } +.@{fa-css-prefix}-wheelchair-alt:before { content: @fa-var-wheelchair-alt; } +.@{fa-css-prefix}-question-circle-o:before { content: @fa-var-question-circle-o; } +.@{fa-css-prefix}-blind:before { content: @fa-var-blind; } +.@{fa-css-prefix}-audio-description:before { content: @fa-var-audio-description; } +.@{fa-css-prefix}-volume-control-phone:before { content: @fa-var-volume-control-phone; } +.@{fa-css-prefix}-braille:before { content: @fa-var-braille; } +.@{fa-css-prefix}-assistive-listening-systems:before { content: @fa-var-assistive-listening-systems; } +.@{fa-css-prefix}-asl-interpreting:before, +.@{fa-css-prefix}-american-sign-language-interpreting:before { content: @fa-var-american-sign-language-interpreting; } +.@{fa-css-prefix}-deafness:before, +.@{fa-css-prefix}-hard-of-hearing:before, +.@{fa-css-prefix}-deaf:before { content: @fa-var-deaf; } +.@{fa-css-prefix}-glide:before { content: @fa-var-glide; } +.@{fa-css-prefix}-glide-g:before { content: @fa-var-glide-g; } +.@{fa-css-prefix}-signing:before, +.@{fa-css-prefix}-sign-language:before { content: @fa-var-sign-language; } +.@{fa-css-prefix}-low-vision:before { content: @fa-var-low-vision; } +.@{fa-css-prefix}-viadeo:before { content: @fa-var-viadeo; } +.@{fa-css-prefix}-viadeo-square:before { content: @fa-var-viadeo-square; } +.@{fa-css-prefix}-snapchat:before { content: @fa-var-snapchat; } +.@{fa-css-prefix}-snapchat-ghost:before { content: @fa-var-snapchat-ghost; } +.@{fa-css-prefix}-snapchat-square:before { content: @fa-var-snapchat-square; } +.@{fa-css-prefix}-pied-piper:before { content: @fa-var-pied-piper; } +.@{fa-css-prefix}-first-order:before { content: @fa-var-first-order; } +.@{fa-css-prefix}-yoast:before { content: @fa-var-yoast; } +.@{fa-css-prefix}-themeisle:before { content: @fa-var-themeisle; } +.@{fa-css-prefix}-google-plus-circle:before, +.@{fa-css-prefix}-google-plus-official:before { content: @fa-var-google-plus-official; } +.@{fa-css-prefix}-fa:before, +.@{fa-css-prefix}-font-awesome:before { content: @fa-var-font-awesome; } +.@{fa-css-prefix}-handshake-o:before { content: @fa-var-handshake-o; } +.@{fa-css-prefix}-envelope-open:before { content: @fa-var-envelope-open; } +.@{fa-css-prefix}-envelope-open-o:before { content: @fa-var-envelope-open-o; } +.@{fa-css-prefix}-linode:before { content: @fa-var-linode; } +.@{fa-css-prefix}-address-book:before { content: @fa-var-address-book; } +.@{fa-css-prefix}-address-book-o:before { content: @fa-var-address-book-o; } +.@{fa-css-prefix}-vcard:before, +.@{fa-css-prefix}-address-card:before { content: @fa-var-address-card; } +.@{fa-css-prefix}-vcard-o:before, +.@{fa-css-prefix}-address-card-o:before { content: @fa-var-address-card-o; } +.@{fa-css-prefix}-user-circle:before { content: @fa-var-user-circle; } +.@{fa-css-prefix}-user-circle-o:before { content: @fa-var-user-circle-o; } +.@{fa-css-prefix}-user-o:before { content: @fa-var-user-o; } +.@{fa-css-prefix}-id-badge:before { content: @fa-var-id-badge; } +.@{fa-css-prefix}-drivers-license:before, +.@{fa-css-prefix}-id-card:before { content: @fa-var-id-card; } +.@{fa-css-prefix}-drivers-license-o:before, +.@{fa-css-prefix}-id-card-o:before { content: @fa-var-id-card-o; } +.@{fa-css-prefix}-quora:before { content: @fa-var-quora; } +.@{fa-css-prefix}-free-code-camp:before { content: @fa-var-free-code-camp; } +.@{fa-css-prefix}-telegram:before { content: @fa-var-telegram; } +.@{fa-css-prefix}-thermometer-4:before, +.@{fa-css-prefix}-thermometer:before, +.@{fa-css-prefix}-thermometer-full:before { content: @fa-var-thermometer-full; } +.@{fa-css-prefix}-thermometer-3:before, +.@{fa-css-prefix}-thermometer-three-quarters:before { content: @fa-var-thermometer-three-quarters; } +.@{fa-css-prefix}-thermometer-2:before, +.@{fa-css-prefix}-thermometer-half:before { content: @fa-var-thermometer-half; } +.@{fa-css-prefix}-thermometer-1:before, +.@{fa-css-prefix}-thermometer-quarter:before { content: @fa-var-thermometer-quarter; } +.@{fa-css-prefix}-thermometer-0:before, +.@{fa-css-prefix}-thermometer-empty:before { content: @fa-var-thermometer-empty; } +.@{fa-css-prefix}-shower:before { content: @fa-var-shower; } +.@{fa-css-prefix}-bathtub:before, +.@{fa-css-prefix}-s15:before, +.@{fa-css-prefix}-bath:before { content: @fa-var-bath; } +.@{fa-css-prefix}-podcast:before { content: @fa-var-podcast; } +.@{fa-css-prefix}-window-maximize:before { content: @fa-var-window-maximize; } +.@{fa-css-prefix}-window-minimize:before { content: @fa-var-window-minimize; } +.@{fa-css-prefix}-window-restore:before { content: @fa-var-window-restore; } +.@{fa-css-prefix}-times-rectangle:before, +.@{fa-css-prefix}-window-close:before { content: @fa-var-window-close; } +.@{fa-css-prefix}-times-rectangle-o:before, +.@{fa-css-prefix}-window-close-o:before { content: @fa-var-window-close-o; } +.@{fa-css-prefix}-bandcamp:before { content: @fa-var-bandcamp; } +.@{fa-css-prefix}-grav:before { content: @fa-var-grav; } +.@{fa-css-prefix}-etsy:before { content: @fa-var-etsy; } +.@{fa-css-prefix}-imdb:before { content: @fa-var-imdb; } +.@{fa-css-prefix}-ravelry:before { content: @fa-var-ravelry; } +.@{fa-css-prefix}-eercast:before { content: @fa-var-eercast; } +.@{fa-css-prefix}-microchip:before { content: @fa-var-microchip; } +.@{fa-css-prefix}-snowflake-o:before { content: @fa-var-snowflake-o; } +.@{fa-css-prefix}-superpowers:before { content: @fa-var-superpowers; } +.@{fa-css-prefix}-wpexplorer:before { content: @fa-var-wpexplorer; } +.@{fa-css-prefix}-meetup:before { content: @fa-var-meetup; } diff --git a/assets/font/fonts-awesome/less/mixins.less b/assets/font/fonts-awesome/less/mixins.less index b7bfadc..beef231 100644 --- a/assets/font/fonts-awesome/less/mixins.less +++ b/assets/font/fonts-awesome/less/mixins.less @@ -3,23 +3,58 @@ .fa-icon() { display: inline-block; - font: normal normal normal 14px/1 FontAwesome; // shortening font declaration + font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration font-size: inherit; // can't have font-size inherit on line above, so need to override text-rendering: auto; // optimizelegibility throws things off #1094 -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; + } .fa-icon-rotate(@degrees, @rotation) { - filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=@rotation); + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation})"; -webkit-transform: rotate(@degrees); -ms-transform: rotate(@degrees); transform: rotate(@degrees); } .fa-icon-flip(@horiz, @vert, @rotation) { - filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=@rotation, mirror=1); + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation}, mirror=1)"; -webkit-transform: scale(@horiz, @vert); -ms-transform: scale(@horiz, @vert); transform: scale(@horiz, @vert); } + + +// Only display content to screen readers. A la Bootstrap 4. +// +// See: http://a11yproject.com/posts/how-to-hide-content/ + +.sr-only() { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0,0,0,0); + border: 0; +} + +// Use in conjunction with .sr-only to only display content when it's focused. +// +// Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1 +// +// Credit: HTML5 Boilerplate + +.sr-only-focusable() { + &:active, + &:focus { + position: static; + width: auto; + height: auto; + margin: 0; + overflow: visible; + clip: auto; + } +} diff --git a/assets/font/fonts-awesome/less/path.less b/assets/font/fonts-awesome/less/path.less index c5a6912..835be41 100644 --- a/assets/font/fonts-awesome/less/path.less +++ b/assets/font/fonts-awesome/less/path.less @@ -5,10 +5,11 @@ font-family: 'FontAwesome'; src: url('@{fa-font-path}/fontawesome-webfont.eot?v=@{fa-version}'); src: url('@{fa-font-path}/fontawesome-webfont.eot?#iefix&v=@{fa-version}') format('embedded-opentype'), + url('@{fa-font-path}/fontawesome-webfont.woff2?v=@{fa-version}') format('woff2'), url('@{fa-font-path}/fontawesome-webfont.woff?v=@{fa-version}') format('woff'), url('@{fa-font-path}/fontawesome-webfont.ttf?v=@{fa-version}') format('truetype'), url('@{fa-font-path}/fontawesome-webfont.svg?v=@{fa-version}#fontawesomeregular') format('svg'); -// src: url('@{fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts + // src: url('@{fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts font-weight: normal; font-style: normal; } diff --git a/assets/font/fonts-awesome/less/screen-reader.less b/assets/font/fonts-awesome/less/screen-reader.less new file mode 100644 index 0000000..11c1881 --- /dev/null +++ b/assets/font/fonts-awesome/less/screen-reader.less @@ -0,0 +1,5 @@ +// Screen Readers +// ------------------------- + +.sr-only { .sr-only(); } +.sr-only-focusable { .sr-only-focusable(); } diff --git a/assets/font/fonts-awesome/less/variables.less b/assets/font/fonts-awesome/less/variables.less index ccf939d..7ddbbc0 100644 --- a/assets/font/fonts-awesome/less/variables.less +++ b/assets/font/fonts-awesome/less/variables.less @@ -2,20 +2,29 @@ // -------------------------- @fa-font-path: "../fonts"; -//@fa-font-path: "//netdna.bootstrapcdn.com/font-awesome/4.2.0/fonts"; // for referencing Bootstrap CDN font files directly +@fa-font-size-base: 14px; +@fa-line-height-base: 1; +//@fa-font-path: "//netdna.bootstrapcdn.com/font-awesome/4.7.0/fonts"; // for referencing Bootstrap CDN font files directly @fa-css-prefix: fa; -@fa-version: "4.2.0"; +@fa-version: "4.7.0"; @fa-border-color: #eee; @fa-inverse: #fff; @fa-li-width: (30em / 14); +@fa-var-500px: "\f26e"; +@fa-var-address-book: "\f2b9"; +@fa-var-address-book-o: "\f2ba"; +@fa-var-address-card: "\f2bb"; +@fa-var-address-card-o: "\f2bc"; @fa-var-adjust: "\f042"; @fa-var-adn: "\f170"; @fa-var-align-center: "\f037"; @fa-var-align-justify: "\f039"; @fa-var-align-left: "\f036"; @fa-var-align-right: "\f038"; +@fa-var-amazon: "\f270"; @fa-var-ambulance: "\f0f9"; +@fa-var-american-sign-language-interpreting: "\f2a3"; @fa-var-anchor: "\f13d"; @fa-var-android: "\f17b"; @fa-var-angellist: "\f209"; @@ -46,16 +55,35 @@ @fa-var-arrows-alt: "\f0b2"; @fa-var-arrows-h: "\f07e"; @fa-var-arrows-v: "\f07d"; +@fa-var-asl-interpreting: "\f2a3"; +@fa-var-assistive-listening-systems: "\f2a2"; @fa-var-asterisk: "\f069"; @fa-var-at: "\f1fa"; +@fa-var-audio-description: "\f29e"; @fa-var-automobile: "\f1b9"; @fa-var-backward: "\f04a"; +@fa-var-balance-scale: "\f24e"; @fa-var-ban: "\f05e"; +@fa-var-bandcamp: "\f2d5"; @fa-var-bank: "\f19c"; @fa-var-bar-chart: "\f080"; @fa-var-bar-chart-o: "\f080"; @fa-var-barcode: "\f02a"; @fa-var-bars: "\f0c9"; +@fa-var-bath: "\f2cd"; +@fa-var-bathtub: "\f2cd"; +@fa-var-battery: "\f240"; +@fa-var-battery-0: "\f244"; +@fa-var-battery-1: "\f243"; +@fa-var-battery-2: "\f242"; +@fa-var-battery-3: "\f241"; +@fa-var-battery-4: "\f240"; +@fa-var-battery-empty: "\f244"; +@fa-var-battery-full: "\f240"; +@fa-var-battery-half: "\f242"; +@fa-var-battery-quarter: "\f243"; +@fa-var-battery-three-quarters: "\f241"; +@fa-var-bed: "\f236"; @fa-var-beer: "\f0fc"; @fa-var-behance: "\f1b4"; @fa-var-behance-square: "\f1b5"; @@ -69,12 +97,17 @@ @fa-var-bitbucket: "\f171"; @fa-var-bitbucket-square: "\f172"; @fa-var-bitcoin: "\f15a"; +@fa-var-black-tie: "\f27e"; +@fa-var-blind: "\f29d"; +@fa-var-bluetooth: "\f293"; +@fa-var-bluetooth-b: "\f294"; @fa-var-bold: "\f032"; @fa-var-bolt: "\f0e7"; @fa-var-bomb: "\f1e2"; @fa-var-book: "\f02d"; @fa-var-bookmark: "\f02e"; @fa-var-bookmark-o: "\f097"; +@fa-var-braille: "\f2a1"; @fa-var-briefcase: "\f0b1"; @fa-var-btc: "\f15a"; @fa-var-bug: "\f188"; @@ -83,10 +116,15 @@ @fa-var-bullhorn: "\f0a1"; @fa-var-bullseye: "\f140"; @fa-var-bus: "\f207"; +@fa-var-buysellads: "\f20d"; @fa-var-cab: "\f1ba"; @fa-var-calculator: "\f1ec"; @fa-var-calendar: "\f073"; +@fa-var-calendar-check-o: "\f274"; +@fa-var-calendar-minus-o: "\f272"; @fa-var-calendar-o: "\f133"; +@fa-var-calendar-plus-o: "\f271"; +@fa-var-calendar-times-o: "\f273"; @fa-var-camera: "\f030"; @fa-var-camera-retro: "\f083"; @fa-var-car: "\f1b9"; @@ -98,9 +136,13 @@ @fa-var-caret-square-o-right: "\f152"; @fa-var-caret-square-o-up: "\f151"; @fa-var-caret-up: "\f0d8"; +@fa-var-cart-arrow-down: "\f218"; +@fa-var-cart-plus: "\f217"; @fa-var-cc: "\f20a"; @fa-var-cc-amex: "\f1f3"; +@fa-var-cc-diners-club: "\f24c"; @fa-var-cc-discover: "\f1f2"; +@fa-var-cc-jcb: "\f24b"; @fa-var-cc-mastercard: "\f1f1"; @fa-var-cc-paypal: "\f1f4"; @fa-var-cc-stripe: "\f1f5"; @@ -122,12 +164,14 @@ @fa-var-chevron-right: "\f054"; @fa-var-chevron-up: "\f077"; @fa-var-child: "\f1ae"; +@fa-var-chrome: "\f268"; @fa-var-circle: "\f111"; @fa-var-circle-o: "\f10c"; @fa-var-circle-o-notch: "\f1ce"; @fa-var-circle-thin: "\f1db"; @fa-var-clipboard: "\f0ea"; @fa-var-clock-o: "\f017"; +@fa-var-clone: "\f24d"; @fa-var-close: "\f00d"; @fa-var-cloud: "\f0c2"; @fa-var-cloud-download: "\f0ed"; @@ -136,19 +180,26 @@ @fa-var-code: "\f121"; @fa-var-code-fork: "\f126"; @fa-var-codepen: "\f1cb"; +@fa-var-codiepie: "\f284"; @fa-var-coffee: "\f0f4"; @fa-var-cog: "\f013"; @fa-var-cogs: "\f085"; @fa-var-columns: "\f0db"; @fa-var-comment: "\f075"; @fa-var-comment-o: "\f0e5"; +@fa-var-commenting: "\f27a"; +@fa-var-commenting-o: "\f27b"; @fa-var-comments: "\f086"; @fa-var-comments-o: "\f0e6"; @fa-var-compass: "\f14e"; @fa-var-compress: "\f066"; +@fa-var-connectdevelop: "\f20e"; +@fa-var-contao: "\f26d"; @fa-var-copy: "\f0c5"; @fa-var-copyright: "\f1f9"; +@fa-var-creative-commons: "\f25e"; @fa-var-credit-card: "\f09d"; +@fa-var-credit-card-alt: "\f283"; @fa-var-crop: "\f125"; @fa-var-crosshairs: "\f05b"; @fa-var-css3: "\f13c"; @@ -157,27 +208,39 @@ @fa-var-cut: "\f0c4"; @fa-var-cutlery: "\f0f5"; @fa-var-dashboard: "\f0e4"; +@fa-var-dashcube: "\f210"; @fa-var-database: "\f1c0"; +@fa-var-deaf: "\f2a4"; +@fa-var-deafness: "\f2a4"; @fa-var-dedent: "\f03b"; @fa-var-delicious: "\f1a5"; @fa-var-desktop: "\f108"; @fa-var-deviantart: "\f1bd"; +@fa-var-diamond: "\f219"; @fa-var-digg: "\f1a6"; @fa-var-dollar: "\f155"; @fa-var-dot-circle-o: "\f192"; @fa-var-download: "\f019"; @fa-var-dribbble: "\f17d"; +@fa-var-drivers-license: "\f2c2"; +@fa-var-drivers-license-o: "\f2c3"; @fa-var-dropbox: "\f16b"; @fa-var-drupal: "\f1a9"; +@fa-var-edge: "\f282"; @fa-var-edit: "\f044"; +@fa-var-eercast: "\f2da"; @fa-var-eject: "\f052"; @fa-var-ellipsis-h: "\f141"; @fa-var-ellipsis-v: "\f142"; @fa-var-empire: "\f1d1"; @fa-var-envelope: "\f0e0"; @fa-var-envelope-o: "\f003"; +@fa-var-envelope-open: "\f2b6"; +@fa-var-envelope-open-o: "\f2b7"; @fa-var-envelope-square: "\f199"; +@fa-var-envira: "\f299"; @fa-var-eraser: "\f12d"; +@fa-var-etsy: "\f2d7"; @fa-var-eur: "\f153"; @fa-var-euro: "\f153"; @fa-var-exchange: "\f0ec"; @@ -185,16 +248,21 @@ @fa-var-exclamation-circle: "\f06a"; @fa-var-exclamation-triangle: "\f071"; @fa-var-expand: "\f065"; +@fa-var-expeditedssl: "\f23e"; @fa-var-external-link: "\f08e"; @fa-var-external-link-square: "\f14c"; @fa-var-eye: "\f06e"; @fa-var-eye-slash: "\f070"; @fa-var-eyedropper: "\f1fb"; +@fa-var-fa: "\f2b4"; @fa-var-facebook: "\f09a"; +@fa-var-facebook-f: "\f09a"; +@fa-var-facebook-official: "\f230"; @fa-var-facebook-square: "\f082"; @fa-var-fast-backward: "\f049"; @fa-var-fast-forward: "\f050"; @fa-var-fax: "\f1ac"; +@fa-var-feed: "\f09e"; @fa-var-female: "\f182"; @fa-var-fighter-jet: "\f0fb"; @fa-var-file: "\f15b"; @@ -220,6 +288,8 @@ @fa-var-filter: "\f0b0"; @fa-var-fire: "\f06d"; @fa-var-fire-extinguisher: "\f134"; +@fa-var-firefox: "\f269"; +@fa-var-first-order: "\f2b0"; @fa-var-flag: "\f024"; @fa-var-flag-checkered: "\f11e"; @fa-var-flag-o: "\f11d"; @@ -232,8 +302,13 @@ @fa-var-folder-open: "\f07c"; @fa-var-folder-open-o: "\f115"; @fa-var-font: "\f031"; +@fa-var-font-awesome: "\f2b4"; +@fa-var-fonticons: "\f280"; +@fa-var-fort-awesome: "\f286"; +@fa-var-forumbee: "\f211"; @fa-var-forward: "\f04e"; @fa-var-foursquare: "\f180"; +@fa-var-free-code-camp: "\f2c5"; @fa-var-frown-o: "\f119"; @fa-var-futbol-o: "\f1e3"; @fa-var-gamepad: "\f11b"; @@ -242,45 +317,87 @@ @fa-var-ge: "\f1d1"; @fa-var-gear: "\f013"; @fa-var-gears: "\f085"; +@fa-var-genderless: "\f22d"; +@fa-var-get-pocket: "\f265"; +@fa-var-gg: "\f260"; +@fa-var-gg-circle: "\f261"; @fa-var-gift: "\f06b"; @fa-var-git: "\f1d3"; @fa-var-git-square: "\f1d2"; @fa-var-github: "\f09b"; @fa-var-github-alt: "\f113"; @fa-var-github-square: "\f092"; +@fa-var-gitlab: "\f296"; @fa-var-gittip: "\f184"; @fa-var-glass: "\f000"; +@fa-var-glide: "\f2a5"; +@fa-var-glide-g: "\f2a6"; @fa-var-globe: "\f0ac"; @fa-var-google: "\f1a0"; @fa-var-google-plus: "\f0d5"; +@fa-var-google-plus-circle: "\f2b3"; +@fa-var-google-plus-official: "\f2b3"; @fa-var-google-plus-square: "\f0d4"; @fa-var-google-wallet: "\f1ee"; @fa-var-graduation-cap: "\f19d"; +@fa-var-gratipay: "\f184"; +@fa-var-grav: "\f2d6"; @fa-var-group: "\f0c0"; @fa-var-h-square: "\f0fd"; @fa-var-hacker-news: "\f1d4"; +@fa-var-hand-grab-o: "\f255"; +@fa-var-hand-lizard-o: "\f258"; @fa-var-hand-o-down: "\f0a7"; @fa-var-hand-o-left: "\f0a5"; @fa-var-hand-o-right: "\f0a4"; @fa-var-hand-o-up: "\f0a6"; +@fa-var-hand-paper-o: "\f256"; +@fa-var-hand-peace-o: "\f25b"; +@fa-var-hand-pointer-o: "\f25a"; +@fa-var-hand-rock-o: "\f255"; +@fa-var-hand-scissors-o: "\f257"; +@fa-var-hand-spock-o: "\f259"; +@fa-var-hand-stop-o: "\f256"; +@fa-var-handshake-o: "\f2b5"; +@fa-var-hard-of-hearing: "\f2a4"; +@fa-var-hashtag: "\f292"; @fa-var-hdd-o: "\f0a0"; @fa-var-header: "\f1dc"; @fa-var-headphones: "\f025"; @fa-var-heart: "\f004"; @fa-var-heart-o: "\f08a"; +@fa-var-heartbeat: "\f21e"; @fa-var-history: "\f1da"; @fa-var-home: "\f015"; @fa-var-hospital-o: "\f0f8"; +@fa-var-hotel: "\f236"; +@fa-var-hourglass: "\f254"; +@fa-var-hourglass-1: "\f251"; +@fa-var-hourglass-2: "\f252"; +@fa-var-hourglass-3: "\f253"; +@fa-var-hourglass-end: "\f253"; +@fa-var-hourglass-half: "\f252"; +@fa-var-hourglass-o: "\f250"; +@fa-var-hourglass-start: "\f251"; +@fa-var-houzz: "\f27c"; @fa-var-html5: "\f13b"; +@fa-var-i-cursor: "\f246"; +@fa-var-id-badge: "\f2c1"; +@fa-var-id-card: "\f2c2"; +@fa-var-id-card-o: "\f2c3"; @fa-var-ils: "\f20b"; @fa-var-image: "\f03e"; +@fa-var-imdb: "\f2d8"; @fa-var-inbox: "\f01c"; @fa-var-indent: "\f03c"; +@fa-var-industry: "\f275"; @fa-var-info: "\f129"; @fa-var-info-circle: "\f05a"; @fa-var-inr: "\f156"; @fa-var-instagram: "\f16d"; @fa-var-institution: "\f19c"; +@fa-var-internet-explorer: "\f26b"; +@fa-var-intersex: "\f224"; @fa-var-ioxhost: "\f208"; @fa-var-italic: "\f033"; @fa-var-joomla: "\f1aa"; @@ -294,6 +411,7 @@ @fa-var-lastfm: "\f202"; @fa-var-lastfm-square: "\f203"; @fa-var-leaf: "\f06c"; +@fa-var-leanpub: "\f212"; @fa-var-legal: "\f0e3"; @fa-var-lemon-o: "\f094"; @fa-var-level-down: "\f149"; @@ -307,6 +425,7 @@ @fa-var-link: "\f0c1"; @fa-var-linkedin: "\f0e1"; @fa-var-linkedin-square: "\f08c"; +@fa-var-linode: "\f2b8"; @fa-var-linux: "\f17c"; @fa-var-list: "\f03a"; @fa-var-list-alt: "\f022"; @@ -318,32 +437,58 @@ @fa-var-long-arrow-left: "\f177"; @fa-var-long-arrow-right: "\f178"; @fa-var-long-arrow-up: "\f176"; +@fa-var-low-vision: "\f2a8"; @fa-var-magic: "\f0d0"; @fa-var-magnet: "\f076"; @fa-var-mail-forward: "\f064"; @fa-var-mail-reply: "\f112"; @fa-var-mail-reply-all: "\f122"; @fa-var-male: "\f183"; +@fa-var-map: "\f279"; @fa-var-map-marker: "\f041"; +@fa-var-map-o: "\f278"; +@fa-var-map-pin: "\f276"; +@fa-var-map-signs: "\f277"; +@fa-var-mars: "\f222"; +@fa-var-mars-double: "\f227"; +@fa-var-mars-stroke: "\f229"; +@fa-var-mars-stroke-h: "\f22b"; +@fa-var-mars-stroke-v: "\f22a"; @fa-var-maxcdn: "\f136"; @fa-var-meanpath: "\f20c"; +@fa-var-medium: "\f23a"; @fa-var-medkit: "\f0fa"; +@fa-var-meetup: "\f2e0"; @fa-var-meh-o: "\f11a"; +@fa-var-mercury: "\f223"; +@fa-var-microchip: "\f2db"; @fa-var-microphone: "\f130"; @fa-var-microphone-slash: "\f131"; @fa-var-minus: "\f068"; @fa-var-minus-circle: "\f056"; @fa-var-minus-square: "\f146"; @fa-var-minus-square-o: "\f147"; +@fa-var-mixcloud: "\f289"; @fa-var-mobile: "\f10b"; @fa-var-mobile-phone: "\f10b"; +@fa-var-modx: "\f285"; @fa-var-money: "\f0d6"; @fa-var-moon-o: "\f186"; @fa-var-mortar-board: "\f19d"; +@fa-var-motorcycle: "\f21c"; +@fa-var-mouse-pointer: "\f245"; @fa-var-music: "\f001"; @fa-var-navicon: "\f0c9"; +@fa-var-neuter: "\f22c"; @fa-var-newspaper-o: "\f1ea"; +@fa-var-object-group: "\f247"; +@fa-var-object-ungroup: "\f248"; +@fa-var-odnoklassniki: "\f263"; +@fa-var-odnoklassniki-square: "\f264"; +@fa-var-opencart: "\f23d"; @fa-var-openid: "\f19b"; +@fa-var-opera: "\f26a"; +@fa-var-optin-monster: "\f23c"; @fa-var-outdent: "\f03b"; @fa-var-pagelines: "\f18c"; @fa-var-paint-brush: "\f1fc"; @@ -353,19 +498,24 @@ @fa-var-paragraph: "\f1dd"; @fa-var-paste: "\f0ea"; @fa-var-pause: "\f04c"; +@fa-var-pause-circle: "\f28b"; +@fa-var-pause-circle-o: "\f28c"; @fa-var-paw: "\f1b0"; @fa-var-paypal: "\f1ed"; @fa-var-pencil: "\f040"; @fa-var-pencil-square: "\f14b"; @fa-var-pencil-square-o: "\f044"; +@fa-var-percent: "\f295"; @fa-var-phone: "\f095"; @fa-var-phone-square: "\f098"; @fa-var-photo: "\f03e"; @fa-var-picture-o: "\f03e"; @fa-var-pie-chart: "\f200"; -@fa-var-pied-piper: "\f1a7"; +@fa-var-pied-piper: "\f2ae"; @fa-var-pied-piper-alt: "\f1a8"; +@fa-var-pied-piper-pp: "\f1a7"; @fa-var-pinterest: "\f0d2"; +@fa-var-pinterest-p: "\f231"; @fa-var-pinterest-square: "\f0d3"; @fa-var-plane: "\f072"; @fa-var-play: "\f04b"; @@ -376,28 +526,36 @@ @fa-var-plus-circle: "\f055"; @fa-var-plus-square: "\f0fe"; @fa-var-plus-square-o: "\f196"; +@fa-var-podcast: "\f2ce"; @fa-var-power-off: "\f011"; @fa-var-print: "\f02f"; +@fa-var-product-hunt: "\f288"; @fa-var-puzzle-piece: "\f12e"; @fa-var-qq: "\f1d6"; @fa-var-qrcode: "\f029"; @fa-var-question: "\f128"; @fa-var-question-circle: "\f059"; +@fa-var-question-circle-o: "\f29c"; +@fa-var-quora: "\f2c4"; @fa-var-quote-left: "\f10d"; @fa-var-quote-right: "\f10e"; @fa-var-ra: "\f1d0"; @fa-var-random: "\f074"; +@fa-var-ravelry: "\f2d9"; @fa-var-rebel: "\f1d0"; @fa-var-recycle: "\f1b8"; @fa-var-reddit: "\f1a1"; +@fa-var-reddit-alien: "\f281"; @fa-var-reddit-square: "\f1a2"; @fa-var-refresh: "\f021"; +@fa-var-registered: "\f25d"; @fa-var-remove: "\f00d"; @fa-var-renren: "\f18b"; @fa-var-reorder: "\f0c9"; @fa-var-repeat: "\f01e"; @fa-var-reply: "\f112"; @fa-var-reply-all: "\f122"; +@fa-var-resistance: "\f1d0"; @fa-var-retweet: "\f079"; @fa-var-rmb: "\f157"; @fa-var-road: "\f018"; @@ -410,13 +568,18 @@ @fa-var-rub: "\f158"; @fa-var-ruble: "\f158"; @fa-var-rupee: "\f156"; +@fa-var-s15: "\f2cd"; +@fa-var-safari: "\f267"; @fa-var-save: "\f0c7"; @fa-var-scissors: "\f0c4"; +@fa-var-scribd: "\f28a"; @fa-var-search: "\f002"; @fa-var-search-minus: "\f010"; @fa-var-search-plus: "\f00e"; +@fa-var-sellsy: "\f213"; @fa-var-send: "\f1d8"; @fa-var-send-o: "\f1d9"; +@fa-var-server: "\f233"; @fa-var-share: "\f064"; @fa-var-share-alt: "\f1e0"; @fa-var-share-alt-square: "\f1e1"; @@ -425,16 +588,29 @@ @fa-var-shekel: "\f20b"; @fa-var-sheqel: "\f20b"; @fa-var-shield: "\f132"; +@fa-var-ship: "\f21a"; +@fa-var-shirtsinbulk: "\f214"; +@fa-var-shopping-bag: "\f290"; +@fa-var-shopping-basket: "\f291"; @fa-var-shopping-cart: "\f07a"; +@fa-var-shower: "\f2cc"; @fa-var-sign-in: "\f090"; +@fa-var-sign-language: "\f2a7"; @fa-var-sign-out: "\f08b"; @fa-var-signal: "\f012"; +@fa-var-signing: "\f2a7"; +@fa-var-simplybuilt: "\f215"; @fa-var-sitemap: "\f0e8"; +@fa-var-skyatlas: "\f216"; @fa-var-skype: "\f17e"; @fa-var-slack: "\f198"; @fa-var-sliders: "\f1de"; @fa-var-slideshare: "\f1e7"; @fa-var-smile-o: "\f118"; +@fa-var-snapchat: "\f2ab"; +@fa-var-snapchat-ghost: "\f2ac"; +@fa-var-snapchat-square: "\f2ad"; +@fa-var-snowflake-o: "\f2dc"; @fa-var-soccer-ball-o: "\f1e3"; @fa-var-sort: "\f0dc"; @fa-var-sort-alpha-asc: "\f15d"; @@ -467,13 +643,20 @@ @fa-var-step-backward: "\f048"; @fa-var-step-forward: "\f051"; @fa-var-stethoscope: "\f0f1"; +@fa-var-sticky-note: "\f249"; +@fa-var-sticky-note-o: "\f24a"; @fa-var-stop: "\f04d"; +@fa-var-stop-circle: "\f28d"; +@fa-var-stop-circle-o: "\f28e"; +@fa-var-street-view: "\f21d"; @fa-var-strikethrough: "\f0cc"; @fa-var-stumbleupon: "\f1a4"; @fa-var-stumbleupon-circle: "\f1a3"; @fa-var-subscript: "\f12c"; +@fa-var-subway: "\f239"; @fa-var-suitcase: "\f0f2"; @fa-var-sun-o: "\f185"; +@fa-var-superpowers: "\f2dd"; @fa-var-superscript: "\f12b"; @fa-var-support: "\f1cd"; @fa-var-table: "\f0ce"; @@ -483,6 +666,8 @@ @fa-var-tags: "\f02c"; @fa-var-tasks: "\f0ae"; @fa-var-taxi: "\f1ba"; +@fa-var-telegram: "\f2c6"; +@fa-var-television: "\f26c"; @fa-var-tencent-weibo: "\f1d5"; @fa-var-terminal: "\f120"; @fa-var-text-height: "\f034"; @@ -490,6 +675,18 @@ @fa-var-th: "\f00a"; @fa-var-th-large: "\f009"; @fa-var-th-list: "\f00b"; +@fa-var-themeisle: "\f2b2"; +@fa-var-thermometer: "\f2c7"; +@fa-var-thermometer-0: "\f2cb"; +@fa-var-thermometer-1: "\f2ca"; +@fa-var-thermometer-2: "\f2c9"; +@fa-var-thermometer-3: "\f2c8"; +@fa-var-thermometer-4: "\f2c7"; +@fa-var-thermometer-empty: "\f2cb"; +@fa-var-thermometer-full: "\f2c7"; +@fa-var-thermometer-half: "\f2c9"; +@fa-var-thermometer-quarter: "\f2ca"; +@fa-var-thermometer-three-quarters: "\f2c8"; @fa-var-thumb-tack: "\f08d"; @fa-var-thumbs-down: "\f165"; @fa-var-thumbs-o-down: "\f088"; @@ -499,6 +696,8 @@ @fa-var-times: "\f00d"; @fa-var-times-circle: "\f057"; @fa-var-times-circle-o: "\f05c"; +@fa-var-times-rectangle: "\f2d3"; +@fa-var-times-rectangle-o: "\f2d4"; @fa-var-tint: "\f043"; @fa-var-toggle-down: "\f150"; @fa-var-toggle-left: "\f191"; @@ -506,10 +705,15 @@ @fa-var-toggle-on: "\f205"; @fa-var-toggle-right: "\f152"; @fa-var-toggle-up: "\f151"; +@fa-var-trademark: "\f25c"; +@fa-var-train: "\f238"; +@fa-var-transgender: "\f224"; +@fa-var-transgender-alt: "\f225"; @fa-var-trash: "\f1f8"; @fa-var-trash-o: "\f014"; @fa-var-tree: "\f1bb"; @fa-var-trello: "\f181"; +@fa-var-tripadvisor: "\f262"; @fa-var-trophy: "\f091"; @fa-var-truck: "\f0d1"; @fa-var-try: "\f195"; @@ -517,26 +721,45 @@ @fa-var-tumblr: "\f173"; @fa-var-tumblr-square: "\f174"; @fa-var-turkish-lira: "\f195"; +@fa-var-tv: "\f26c"; @fa-var-twitch: "\f1e8"; @fa-var-twitter: "\f099"; @fa-var-twitter-square: "\f081"; @fa-var-umbrella: "\f0e9"; @fa-var-underline: "\f0cd"; @fa-var-undo: "\f0e2"; +@fa-var-universal-access: "\f29a"; @fa-var-university: "\f19c"; @fa-var-unlink: "\f127"; @fa-var-unlock: "\f09c"; @fa-var-unlock-alt: "\f13e"; @fa-var-unsorted: "\f0dc"; @fa-var-upload: "\f093"; +@fa-var-usb: "\f287"; @fa-var-usd: "\f155"; @fa-var-user: "\f007"; +@fa-var-user-circle: "\f2bd"; +@fa-var-user-circle-o: "\f2be"; @fa-var-user-md: "\f0f0"; +@fa-var-user-o: "\f2c0"; +@fa-var-user-plus: "\f234"; +@fa-var-user-secret: "\f21b"; +@fa-var-user-times: "\f235"; @fa-var-users: "\f0c0"; +@fa-var-vcard: "\f2bb"; +@fa-var-vcard-o: "\f2bc"; +@fa-var-venus: "\f221"; +@fa-var-venus-double: "\f226"; +@fa-var-venus-mars: "\f228"; +@fa-var-viacoin: "\f237"; +@fa-var-viadeo: "\f2a9"; +@fa-var-viadeo-square: "\f2aa"; @fa-var-video-camera: "\f03d"; +@fa-var-vimeo: "\f27d"; @fa-var-vimeo-square: "\f194"; @fa-var-vine: "\f1ca"; @fa-var-vk: "\f189"; +@fa-var-volume-control-phone: "\f2a0"; @fa-var-volume-down: "\f027"; @fa-var-volume-off: "\f026"; @fa-var-volume-up: "\f028"; @@ -544,17 +767,33 @@ @fa-var-wechat: "\f1d7"; @fa-var-weibo: "\f18a"; @fa-var-weixin: "\f1d7"; +@fa-var-whatsapp: "\f232"; @fa-var-wheelchair: "\f193"; +@fa-var-wheelchair-alt: "\f29b"; @fa-var-wifi: "\f1eb"; +@fa-var-wikipedia-w: "\f266"; +@fa-var-window-close: "\f2d3"; +@fa-var-window-close-o: "\f2d4"; +@fa-var-window-maximize: "\f2d0"; +@fa-var-window-minimize: "\f2d1"; +@fa-var-window-restore: "\f2d2"; @fa-var-windows: "\f17a"; @fa-var-won: "\f159"; @fa-var-wordpress: "\f19a"; +@fa-var-wpbeginner: "\f297"; +@fa-var-wpexplorer: "\f2de"; +@fa-var-wpforms: "\f298"; @fa-var-wrench: "\f0ad"; @fa-var-xing: "\f168"; @fa-var-xing-square: "\f169"; +@fa-var-y-combinator: "\f23b"; +@fa-var-y-combinator-square: "\f1d4"; @fa-var-yahoo: "\f19e"; +@fa-var-yc: "\f23b"; +@fa-var-yc-square: "\f1d4"; @fa-var-yelp: "\f1e9"; @fa-var-yen: "\f157"; +@fa-var-yoast: "\f2b1"; @fa-var-youtube: "\f167"; @fa-var-youtube-play: "\f16a"; @fa-var-youtube-square: "\f166"; diff --git a/assets/font/fonts-awesome/scss/_spinning.scss b/assets/font/fonts-awesome/scss/_animated.scss similarity index 81% rename from assets/font/fonts-awesome/scss/_spinning.scss rename to assets/font/fonts-awesome/scss/_animated.scss index 002c5d5..8a020db 100644 --- a/assets/font/fonts-awesome/scss/_spinning.scss +++ b/assets/font/fonts-awesome/scss/_animated.scss @@ -6,6 +6,11 @@ animation: fa-spin 2s infinite linear; } +.#{$fa-css-prefix}-pulse { + -webkit-animation: fa-spin 1s infinite steps(8); + animation: fa-spin 1s infinite steps(8); +} + @-webkit-keyframes fa-spin { 0% { -webkit-transform: rotate(0deg); diff --git a/assets/font/fonts-awesome/scss/_bordered-pulled.scss b/assets/font/fonts-awesome/scss/_bordered-pulled.scss index 9d3fdf3..d4b85a0 100644 --- a/assets/font/fonts-awesome/scss/_bordered-pulled.scss +++ b/assets/font/fonts-awesome/scss/_bordered-pulled.scss @@ -7,6 +7,15 @@ border-radius: .1em; } +.#{$fa-css-prefix}-pull-left { float: left; } +.#{$fa-css-prefix}-pull-right { float: right; } + +.#{$fa-css-prefix} { + &.#{$fa-css-prefix}-pull-left { margin-right: .3em; } + &.#{$fa-css-prefix}-pull-right { margin-left: .3em; } +} + +/* Deprecated as of 4.4.0 */ .pull-right { float: right; } .pull-left { float: left; } diff --git a/assets/font/fonts-awesome/scss/_core.scss b/assets/font/fonts-awesome/scss/_core.scss index ca46d37..7425ef8 100644 --- a/assets/font/fonts-awesome/scss/_core.scss +++ b/assets/font/fonts-awesome/scss/_core.scss @@ -3,9 +3,10 @@ .#{$fa-css-prefix} { display: inline-block; - font: normal normal normal 14px/1 FontAwesome; // shortening font declaration + font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration font-size: inherit; // can't have font-size inherit on line above, so need to override text-rendering: auto; // optimizelegibility throws things off #1094 -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; + } diff --git a/assets/font/fonts-awesome/scss/_icons.scss b/assets/font/fonts-awesome/scss/_icons.scss index 8dc2939..e63e702 100644 --- a/assets/font/fonts-awesome/scss/_icons.scss +++ b/assets/font/fonts-awesome/scss/_icons.scss @@ -158,10 +158,12 @@ .#{$fa-css-prefix}-bookmark-o:before { content: $fa-var-bookmark-o; } .#{$fa-css-prefix}-phone-square:before { content: $fa-var-phone-square; } .#{$fa-css-prefix}-twitter:before { content: $fa-var-twitter; } +.#{$fa-css-prefix}-facebook-f:before, .#{$fa-css-prefix}-facebook:before { content: $fa-var-facebook; } .#{$fa-css-prefix}-github:before { content: $fa-var-github; } .#{$fa-css-prefix}-unlock:before { content: $fa-var-unlock; } .#{$fa-css-prefix}-credit-card:before { content: $fa-var-credit-card; } +.#{$fa-css-prefix}-feed:before, .#{$fa-css-prefix}-rss:before { content: $fa-var-rss; } .#{$fa-css-prefix}-hdd-o:before { content: $fa-var-hdd-o; } .#{$fa-css-prefix}-bullhorn:before { content: $fa-var-bullhorn; } @@ -397,7 +399,8 @@ .#{$fa-css-prefix}-trello:before { content: $fa-var-trello; } .#{$fa-css-prefix}-female:before { content: $fa-var-female; } .#{$fa-css-prefix}-male:before { content: $fa-var-male; } -.#{$fa-css-prefix}-gittip:before { content: $fa-var-gittip; } +.#{$fa-css-prefix}-gittip:before, +.#{$fa-css-prefix}-gratipay:before { content: $fa-var-gratipay; } .#{$fa-css-prefix}-sun-o:before { content: $fa-var-sun-o; } .#{$fa-css-prefix}-moon-o:before { content: $fa-var-moon-o; } .#{$fa-css-prefix}-archive:before { content: $fa-var-archive; } @@ -435,7 +438,7 @@ .#{$fa-css-prefix}-stumbleupon:before { content: $fa-var-stumbleupon; } .#{$fa-css-prefix}-delicious:before { content: $fa-var-delicious; } .#{$fa-css-prefix}-digg:before { content: $fa-var-digg; } -.#{$fa-css-prefix}-pied-piper:before { content: $fa-var-pied-piper; } +.#{$fa-css-prefix}-pied-piper-pp:before { content: $fa-var-pied-piper-pp; } .#{$fa-css-prefix}-pied-piper-alt:before { content: $fa-var-pied-piper-alt; } .#{$fa-css-prefix}-drupal:before { content: $fa-var-drupal; } .#{$fa-css-prefix}-joomla:before { content: $fa-var-joomla; } @@ -485,11 +488,14 @@ .#{$fa-css-prefix}-life-ring:before { content: $fa-var-life-ring; } .#{$fa-css-prefix}-circle-o-notch:before { content: $fa-var-circle-o-notch; } .#{$fa-css-prefix}-ra:before, +.#{$fa-css-prefix}-resistance:before, .#{$fa-css-prefix}-rebel:before { content: $fa-var-rebel; } .#{$fa-css-prefix}-ge:before, .#{$fa-css-prefix}-empire:before { content: $fa-var-empire; } .#{$fa-css-prefix}-git-square:before { content: $fa-var-git-square; } .#{$fa-css-prefix}-git:before { content: $fa-var-git; } +.#{$fa-css-prefix}-y-combinator-square:before, +.#{$fa-css-prefix}-yc-square:before, .#{$fa-css-prefix}-hacker-news:before { content: $fa-var-hacker-news; } .#{$fa-css-prefix}-tencent-weibo:before { content: $fa-var-tencent-weibo; } .#{$fa-css-prefix}-qq:before { content: $fa-var-qq; } @@ -550,3 +556,234 @@ .#{$fa-css-prefix}-sheqel:before, .#{$fa-css-prefix}-ils:before { content: $fa-var-ils; } .#{$fa-css-prefix}-meanpath:before { content: $fa-var-meanpath; } +.#{$fa-css-prefix}-buysellads:before { content: $fa-var-buysellads; } +.#{$fa-css-prefix}-connectdevelop:before { content: $fa-var-connectdevelop; } +.#{$fa-css-prefix}-dashcube:before { content: $fa-var-dashcube; } +.#{$fa-css-prefix}-forumbee:before { content: $fa-var-forumbee; } +.#{$fa-css-prefix}-leanpub:before { content: $fa-var-leanpub; } +.#{$fa-css-prefix}-sellsy:before { content: $fa-var-sellsy; } +.#{$fa-css-prefix}-shirtsinbulk:before { content: $fa-var-shirtsinbulk; } +.#{$fa-css-prefix}-simplybuilt:before { content: $fa-var-simplybuilt; } +.#{$fa-css-prefix}-skyatlas:before { content: $fa-var-skyatlas; } +.#{$fa-css-prefix}-cart-plus:before { content: $fa-var-cart-plus; } +.#{$fa-css-prefix}-cart-arrow-down:before { content: $fa-var-cart-arrow-down; } +.#{$fa-css-prefix}-diamond:before { content: $fa-var-diamond; } +.#{$fa-css-prefix}-ship:before { content: $fa-var-ship; } +.#{$fa-css-prefix}-user-secret:before { content: $fa-var-user-secret; } +.#{$fa-css-prefix}-motorcycle:before { content: $fa-var-motorcycle; } +.#{$fa-css-prefix}-street-view:before { content: $fa-var-street-view; } +.#{$fa-css-prefix}-heartbeat:before { content: $fa-var-heartbeat; } +.#{$fa-css-prefix}-venus:before { content: $fa-var-venus; } +.#{$fa-css-prefix}-mars:before { content: $fa-var-mars; } +.#{$fa-css-prefix}-mercury:before { content: $fa-var-mercury; } +.#{$fa-css-prefix}-intersex:before, +.#{$fa-css-prefix}-transgender:before { content: $fa-var-transgender; } +.#{$fa-css-prefix}-transgender-alt:before { content: $fa-var-transgender-alt; } +.#{$fa-css-prefix}-venus-double:before { content: $fa-var-venus-double; } +.#{$fa-css-prefix}-mars-double:before { content: $fa-var-mars-double; } +.#{$fa-css-prefix}-venus-mars:before { content: $fa-var-venus-mars; } +.#{$fa-css-prefix}-mars-stroke:before { content: $fa-var-mars-stroke; } +.#{$fa-css-prefix}-mars-stroke-v:before { content: $fa-var-mars-stroke-v; } +.#{$fa-css-prefix}-mars-stroke-h:before { content: $fa-var-mars-stroke-h; } +.#{$fa-css-prefix}-neuter:before { content: $fa-var-neuter; } +.#{$fa-css-prefix}-genderless:before { content: $fa-var-genderless; } +.#{$fa-css-prefix}-facebook-official:before { content: $fa-var-facebook-official; } +.#{$fa-css-prefix}-pinterest-p:before { content: $fa-var-pinterest-p; } +.#{$fa-css-prefix}-whatsapp:before { content: $fa-var-whatsapp; } +.#{$fa-css-prefix}-server:before { content: $fa-var-server; } +.#{$fa-css-prefix}-user-plus:before { content: $fa-var-user-plus; } +.#{$fa-css-prefix}-user-times:before { content: $fa-var-user-times; } +.#{$fa-css-prefix}-hotel:before, +.#{$fa-css-prefix}-bed:before { content: $fa-var-bed; } +.#{$fa-css-prefix}-viacoin:before { content: $fa-var-viacoin; } +.#{$fa-css-prefix}-train:before { content: $fa-var-train; } +.#{$fa-css-prefix}-subway:before { content: $fa-var-subway; } +.#{$fa-css-prefix}-medium:before { content: $fa-var-medium; } +.#{$fa-css-prefix}-yc:before, +.#{$fa-css-prefix}-y-combinator:before { content: $fa-var-y-combinator; } +.#{$fa-css-prefix}-optin-monster:before { content: $fa-var-optin-monster; } +.#{$fa-css-prefix}-opencart:before { content: $fa-var-opencart; } +.#{$fa-css-prefix}-expeditedssl:before { content: $fa-var-expeditedssl; } +.#{$fa-css-prefix}-battery-4:before, +.#{$fa-css-prefix}-battery:before, +.#{$fa-css-prefix}-battery-full:before { content: $fa-var-battery-full; } +.#{$fa-css-prefix}-battery-3:before, +.#{$fa-css-prefix}-battery-three-quarters:before { content: $fa-var-battery-three-quarters; } +.#{$fa-css-prefix}-battery-2:before, +.#{$fa-css-prefix}-battery-half:before { content: $fa-var-battery-half; } +.#{$fa-css-prefix}-battery-1:before, +.#{$fa-css-prefix}-battery-quarter:before { content: $fa-var-battery-quarter; } +.#{$fa-css-prefix}-battery-0:before, +.#{$fa-css-prefix}-battery-empty:before { content: $fa-var-battery-empty; } +.#{$fa-css-prefix}-mouse-pointer:before { content: $fa-var-mouse-pointer; } +.#{$fa-css-prefix}-i-cursor:before { content: $fa-var-i-cursor; } +.#{$fa-css-prefix}-object-group:before { content: $fa-var-object-group; } +.#{$fa-css-prefix}-object-ungroup:before { content: $fa-var-object-ungroup; } +.#{$fa-css-prefix}-sticky-note:before { content: $fa-var-sticky-note; } +.#{$fa-css-prefix}-sticky-note-o:before { content: $fa-var-sticky-note-o; } +.#{$fa-css-prefix}-cc-jcb:before { content: $fa-var-cc-jcb; } +.#{$fa-css-prefix}-cc-diners-club:before { content: $fa-var-cc-diners-club; } +.#{$fa-css-prefix}-clone:before { content: $fa-var-clone; } +.#{$fa-css-prefix}-balance-scale:before { content: $fa-var-balance-scale; } +.#{$fa-css-prefix}-hourglass-o:before { content: $fa-var-hourglass-o; } +.#{$fa-css-prefix}-hourglass-1:before, +.#{$fa-css-prefix}-hourglass-start:before { content: $fa-var-hourglass-start; } +.#{$fa-css-prefix}-hourglass-2:before, +.#{$fa-css-prefix}-hourglass-half:before { content: $fa-var-hourglass-half; } +.#{$fa-css-prefix}-hourglass-3:before, +.#{$fa-css-prefix}-hourglass-end:before { content: $fa-var-hourglass-end; } +.#{$fa-css-prefix}-hourglass:before { content: $fa-var-hourglass; } +.#{$fa-css-prefix}-hand-grab-o:before, +.#{$fa-css-prefix}-hand-rock-o:before { content: $fa-var-hand-rock-o; } +.#{$fa-css-prefix}-hand-stop-o:before, +.#{$fa-css-prefix}-hand-paper-o:before { content: $fa-var-hand-paper-o; } +.#{$fa-css-prefix}-hand-scissors-o:before { content: $fa-var-hand-scissors-o; } +.#{$fa-css-prefix}-hand-lizard-o:before { content: $fa-var-hand-lizard-o; } +.#{$fa-css-prefix}-hand-spock-o:before { content: $fa-var-hand-spock-o; } +.#{$fa-css-prefix}-hand-pointer-o:before { content: $fa-var-hand-pointer-o; } +.#{$fa-css-prefix}-hand-peace-o:before { content: $fa-var-hand-peace-o; } +.#{$fa-css-prefix}-trademark:before { content: $fa-var-trademark; } +.#{$fa-css-prefix}-registered:before { content: $fa-var-registered; } +.#{$fa-css-prefix}-creative-commons:before { content: $fa-var-creative-commons; } +.#{$fa-css-prefix}-gg:before { content: $fa-var-gg; } +.#{$fa-css-prefix}-gg-circle:before { content: $fa-var-gg-circle; } +.#{$fa-css-prefix}-tripadvisor:before { content: $fa-var-tripadvisor; } +.#{$fa-css-prefix}-odnoklassniki:before { content: $fa-var-odnoklassniki; } +.#{$fa-css-prefix}-odnoklassniki-square:before { content: $fa-var-odnoklassniki-square; } +.#{$fa-css-prefix}-get-pocket:before { content: $fa-var-get-pocket; } +.#{$fa-css-prefix}-wikipedia-w:before { content: $fa-var-wikipedia-w; } +.#{$fa-css-prefix}-safari:before { content: $fa-var-safari; } +.#{$fa-css-prefix}-chrome:before { content: $fa-var-chrome; } +.#{$fa-css-prefix}-firefox:before { content: $fa-var-firefox; } +.#{$fa-css-prefix}-opera:before { content: $fa-var-opera; } +.#{$fa-css-prefix}-internet-explorer:before { content: $fa-var-internet-explorer; } +.#{$fa-css-prefix}-tv:before, +.#{$fa-css-prefix}-television:before { content: $fa-var-television; } +.#{$fa-css-prefix}-contao:before { content: $fa-var-contao; } +.#{$fa-css-prefix}-500px:before { content: $fa-var-500px; } +.#{$fa-css-prefix}-amazon:before { content: $fa-var-amazon; } +.#{$fa-css-prefix}-calendar-plus-o:before { content: $fa-var-calendar-plus-o; } +.#{$fa-css-prefix}-calendar-minus-o:before { content: $fa-var-calendar-minus-o; } +.#{$fa-css-prefix}-calendar-times-o:before { content: $fa-var-calendar-times-o; } +.#{$fa-css-prefix}-calendar-check-o:before { content: $fa-var-calendar-check-o; } +.#{$fa-css-prefix}-industry:before { content: $fa-var-industry; } +.#{$fa-css-prefix}-map-pin:before { content: $fa-var-map-pin; } +.#{$fa-css-prefix}-map-signs:before { content: $fa-var-map-signs; } +.#{$fa-css-prefix}-map-o:before { content: $fa-var-map-o; } +.#{$fa-css-prefix}-map:before { content: $fa-var-map; } +.#{$fa-css-prefix}-commenting:before { content: $fa-var-commenting; } +.#{$fa-css-prefix}-commenting-o:before { content: $fa-var-commenting-o; } +.#{$fa-css-prefix}-houzz:before { content: $fa-var-houzz; } +.#{$fa-css-prefix}-vimeo:before { content: $fa-var-vimeo; } +.#{$fa-css-prefix}-black-tie:before { content: $fa-var-black-tie; } +.#{$fa-css-prefix}-fonticons:before { content: $fa-var-fonticons; } +.#{$fa-css-prefix}-reddit-alien:before { content: $fa-var-reddit-alien; } +.#{$fa-css-prefix}-edge:before { content: $fa-var-edge; } +.#{$fa-css-prefix}-credit-card-alt:before { content: $fa-var-credit-card-alt; } +.#{$fa-css-prefix}-codiepie:before { content: $fa-var-codiepie; } +.#{$fa-css-prefix}-modx:before { content: $fa-var-modx; } +.#{$fa-css-prefix}-fort-awesome:before { content: $fa-var-fort-awesome; } +.#{$fa-css-prefix}-usb:before { content: $fa-var-usb; } +.#{$fa-css-prefix}-product-hunt:before { content: $fa-var-product-hunt; } +.#{$fa-css-prefix}-mixcloud:before { content: $fa-var-mixcloud; } +.#{$fa-css-prefix}-scribd:before { content: $fa-var-scribd; } +.#{$fa-css-prefix}-pause-circle:before { content: $fa-var-pause-circle; } +.#{$fa-css-prefix}-pause-circle-o:before { content: $fa-var-pause-circle-o; } +.#{$fa-css-prefix}-stop-circle:before { content: $fa-var-stop-circle; } +.#{$fa-css-prefix}-stop-circle-o:before { content: $fa-var-stop-circle-o; } +.#{$fa-css-prefix}-shopping-bag:before { content: $fa-var-shopping-bag; } +.#{$fa-css-prefix}-shopping-basket:before { content: $fa-var-shopping-basket; } +.#{$fa-css-prefix}-hashtag:before { content: $fa-var-hashtag; } +.#{$fa-css-prefix}-bluetooth:before { content: $fa-var-bluetooth; } +.#{$fa-css-prefix}-bluetooth-b:before { content: $fa-var-bluetooth-b; } +.#{$fa-css-prefix}-percent:before { content: $fa-var-percent; } +.#{$fa-css-prefix}-gitlab:before { content: $fa-var-gitlab; } +.#{$fa-css-prefix}-wpbeginner:before { content: $fa-var-wpbeginner; } +.#{$fa-css-prefix}-wpforms:before { content: $fa-var-wpforms; } +.#{$fa-css-prefix}-envira:before { content: $fa-var-envira; } +.#{$fa-css-prefix}-universal-access:before { content: $fa-var-universal-access; } +.#{$fa-css-prefix}-wheelchair-alt:before { content: $fa-var-wheelchair-alt; } +.#{$fa-css-prefix}-question-circle-o:before { content: $fa-var-question-circle-o; } +.#{$fa-css-prefix}-blind:before { content: $fa-var-blind; } +.#{$fa-css-prefix}-audio-description:before { content: $fa-var-audio-description; } +.#{$fa-css-prefix}-volume-control-phone:before { content: $fa-var-volume-control-phone; } +.#{$fa-css-prefix}-braille:before { content: $fa-var-braille; } +.#{$fa-css-prefix}-assistive-listening-systems:before { content: $fa-var-assistive-listening-systems; } +.#{$fa-css-prefix}-asl-interpreting:before, +.#{$fa-css-prefix}-american-sign-language-interpreting:before { content: $fa-var-american-sign-language-interpreting; } +.#{$fa-css-prefix}-deafness:before, +.#{$fa-css-prefix}-hard-of-hearing:before, +.#{$fa-css-prefix}-deaf:before { content: $fa-var-deaf; } +.#{$fa-css-prefix}-glide:before { content: $fa-var-glide; } +.#{$fa-css-prefix}-glide-g:before { content: $fa-var-glide-g; } +.#{$fa-css-prefix}-signing:before, +.#{$fa-css-prefix}-sign-language:before { content: $fa-var-sign-language; } +.#{$fa-css-prefix}-low-vision:before { content: $fa-var-low-vision; } +.#{$fa-css-prefix}-viadeo:before { content: $fa-var-viadeo; } +.#{$fa-css-prefix}-viadeo-square:before { content: $fa-var-viadeo-square; } +.#{$fa-css-prefix}-snapchat:before { content: $fa-var-snapchat; } +.#{$fa-css-prefix}-snapchat-ghost:before { content: $fa-var-snapchat-ghost; } +.#{$fa-css-prefix}-snapchat-square:before { content: $fa-var-snapchat-square; } +.#{$fa-css-prefix}-pied-piper:before { content: $fa-var-pied-piper; } +.#{$fa-css-prefix}-first-order:before { content: $fa-var-first-order; } +.#{$fa-css-prefix}-yoast:before { content: $fa-var-yoast; } +.#{$fa-css-prefix}-themeisle:before { content: $fa-var-themeisle; } +.#{$fa-css-prefix}-google-plus-circle:before, +.#{$fa-css-prefix}-google-plus-official:before { content: $fa-var-google-plus-official; } +.#{$fa-css-prefix}-fa:before, +.#{$fa-css-prefix}-font-awesome:before { content: $fa-var-font-awesome; } +.#{$fa-css-prefix}-handshake-o:before { content: $fa-var-handshake-o; } +.#{$fa-css-prefix}-envelope-open:before { content: $fa-var-envelope-open; } +.#{$fa-css-prefix}-envelope-open-o:before { content: $fa-var-envelope-open-o; } +.#{$fa-css-prefix}-linode:before { content: $fa-var-linode; } +.#{$fa-css-prefix}-address-book:before { content: $fa-var-address-book; } +.#{$fa-css-prefix}-address-book-o:before { content: $fa-var-address-book-o; } +.#{$fa-css-prefix}-vcard:before, +.#{$fa-css-prefix}-address-card:before { content: $fa-var-address-card; } +.#{$fa-css-prefix}-vcard-o:before, +.#{$fa-css-prefix}-address-card-o:before { content: $fa-var-address-card-o; } +.#{$fa-css-prefix}-user-circle:before { content: $fa-var-user-circle; } +.#{$fa-css-prefix}-user-circle-o:before { content: $fa-var-user-circle-o; } +.#{$fa-css-prefix}-user-o:before { content: $fa-var-user-o; } +.#{$fa-css-prefix}-id-badge:before { content: $fa-var-id-badge; } +.#{$fa-css-prefix}-drivers-license:before, +.#{$fa-css-prefix}-id-card:before { content: $fa-var-id-card; } +.#{$fa-css-prefix}-drivers-license-o:before, +.#{$fa-css-prefix}-id-card-o:before { content: $fa-var-id-card-o; } +.#{$fa-css-prefix}-quora:before { content: $fa-var-quora; } +.#{$fa-css-prefix}-free-code-camp:before { content: $fa-var-free-code-camp; } +.#{$fa-css-prefix}-telegram:before { content: $fa-var-telegram; } +.#{$fa-css-prefix}-thermometer-4:before, +.#{$fa-css-prefix}-thermometer:before, +.#{$fa-css-prefix}-thermometer-full:before { content: $fa-var-thermometer-full; } +.#{$fa-css-prefix}-thermometer-3:before, +.#{$fa-css-prefix}-thermometer-three-quarters:before { content: $fa-var-thermometer-three-quarters; } +.#{$fa-css-prefix}-thermometer-2:before, +.#{$fa-css-prefix}-thermometer-half:before { content: $fa-var-thermometer-half; } +.#{$fa-css-prefix}-thermometer-1:before, +.#{$fa-css-prefix}-thermometer-quarter:before { content: $fa-var-thermometer-quarter; } +.#{$fa-css-prefix}-thermometer-0:before, +.#{$fa-css-prefix}-thermometer-empty:before { content: $fa-var-thermometer-empty; } +.#{$fa-css-prefix}-shower:before { content: $fa-var-shower; } +.#{$fa-css-prefix}-bathtub:before, +.#{$fa-css-prefix}-s15:before, +.#{$fa-css-prefix}-bath:before { content: $fa-var-bath; } +.#{$fa-css-prefix}-podcast:before { content: $fa-var-podcast; } +.#{$fa-css-prefix}-window-maximize:before { content: $fa-var-window-maximize; } +.#{$fa-css-prefix}-window-minimize:before { content: $fa-var-window-minimize; } +.#{$fa-css-prefix}-window-restore:before { content: $fa-var-window-restore; } +.#{$fa-css-prefix}-times-rectangle:before, +.#{$fa-css-prefix}-window-close:before { content: $fa-var-window-close; } +.#{$fa-css-prefix}-times-rectangle-o:before, +.#{$fa-css-prefix}-window-close-o:before { content: $fa-var-window-close-o; } +.#{$fa-css-prefix}-bandcamp:before { content: $fa-var-bandcamp; } +.#{$fa-css-prefix}-grav:before { content: $fa-var-grav; } +.#{$fa-css-prefix}-etsy:before { content: $fa-var-etsy; } +.#{$fa-css-prefix}-imdb:before { content: $fa-var-imdb; } +.#{$fa-css-prefix}-ravelry:before { content: $fa-var-ravelry; } +.#{$fa-css-prefix}-eercast:before { content: $fa-var-eercast; } +.#{$fa-css-prefix}-microchip:before { content: $fa-var-microchip; } +.#{$fa-css-prefix}-snowflake-o:before { content: $fa-var-snowflake-o; } +.#{$fa-css-prefix}-superpowers:before { content: $fa-var-superpowers; } +.#{$fa-css-prefix}-wpexplorer:before { content: $fa-var-wpexplorer; } +.#{$fa-css-prefix}-meetup:before { content: $fa-var-meetup; } diff --git a/assets/font/fonts-awesome/scss/_mixins.scss b/assets/font/fonts-awesome/scss/_mixins.scss index a139dfb..c3bbd57 100644 --- a/assets/font/fonts-awesome/scss/_mixins.scss +++ b/assets/font/fonts-awesome/scss/_mixins.scss @@ -3,23 +3,58 @@ @mixin fa-icon() { display: inline-block; - font: normal normal normal 14px/1 FontAwesome; // shortening font declaration + font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration font-size: inherit; // can't have font-size inherit on line above, so need to override text-rendering: auto; // optimizelegibility throws things off #1094 -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; + } @mixin fa-icon-rotate($degrees, $rotation) { - filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation}); + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation})"; -webkit-transform: rotate($degrees); -ms-transform: rotate($degrees); transform: rotate($degrees); } @mixin fa-icon-flip($horiz, $vert, $rotation) { - filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation}); + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation}, mirror=1)"; -webkit-transform: scale($horiz, $vert); -ms-transform: scale($horiz, $vert); transform: scale($horiz, $vert); } + + +// Only display content to screen readers. A la Bootstrap 4. +// +// See: http://a11yproject.com/posts/how-to-hide-content/ + +@mixin sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0,0,0,0); + border: 0; +} + +// Use in conjunction with .sr-only to only display content when it's focused. +// +// Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1 +// +// Credit: HTML5 Boilerplate + +@mixin sr-only-focusable { + &:active, + &:focus { + position: static; + width: auto; + height: auto; + margin: 0; + overflow: visible; + clip: auto; + } +} diff --git a/assets/font/fonts-awesome/scss/_path.scss b/assets/font/fonts-awesome/scss/_path.scss index fd21c35..bb457c2 100644 --- a/assets/font/fonts-awesome/scss/_path.scss +++ b/assets/font/fonts-awesome/scss/_path.scss @@ -5,10 +5,11 @@ font-family: 'FontAwesome'; src: url('#{$fa-font-path}/fontawesome-webfont.eot?v=#{$fa-version}'); src: url('#{$fa-font-path}/fontawesome-webfont.eot?#iefix&v=#{$fa-version}') format('embedded-opentype'), + url('#{$fa-font-path}/fontawesome-webfont.woff2?v=#{$fa-version}') format('woff2'), url('#{$fa-font-path}/fontawesome-webfont.woff?v=#{$fa-version}') format('woff'), url('#{$fa-font-path}/fontawesome-webfont.ttf?v=#{$fa-version}') format('truetype'), url('#{$fa-font-path}/fontawesome-webfont.svg?v=#{$fa-version}#fontawesomeregular') format('svg'); - //src: url('#{$fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts +// src: url('#{$fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts font-weight: normal; font-style: normal; } diff --git a/assets/font/fonts-awesome/scss/_screen-reader.scss b/assets/font/fonts-awesome/scss/_screen-reader.scss new file mode 100644 index 0000000..637426f --- /dev/null +++ b/assets/font/fonts-awesome/scss/_screen-reader.scss @@ -0,0 +1,5 @@ +// Screen Readers +// ------------------------- + +.sr-only { @include sr-only(); } +.sr-only-focusable { @include sr-only-focusable(); } diff --git a/assets/font/fonts-awesome/scss/_variables.scss b/assets/font/fonts-awesome/scss/_variables.scss index 669c307..498fc4a 100644 --- a/assets/font/fonts-awesome/scss/_variables.scss +++ b/assets/font/fonts-awesome/scss/_variables.scss @@ -2,20 +2,29 @@ // -------------------------- $fa-font-path: "../fonts" !default; -//$fa-font-path: "//netdna.bootstrapcdn.com/font-awesome/4.2.0/fonts" !default; // for referencing Bootstrap CDN font files directly +$fa-font-size-base: 14px !default; +$fa-line-height-base: 1 !default; +//$fa-font-path: "//netdna.bootstrapcdn.com/font-awesome/4.7.0/fonts" !default; // for referencing Bootstrap CDN font files directly $fa-css-prefix: fa !default; -$fa-version: "4.2.0" !default; +$fa-version: "4.7.0" !default; $fa-border-color: #eee !default; $fa-inverse: #fff !default; $fa-li-width: (30em / 14) !default; +$fa-var-500px: "\f26e"; +$fa-var-address-book: "\f2b9"; +$fa-var-address-book-o: "\f2ba"; +$fa-var-address-card: "\f2bb"; +$fa-var-address-card-o: "\f2bc"; $fa-var-adjust: "\f042"; $fa-var-adn: "\f170"; $fa-var-align-center: "\f037"; $fa-var-align-justify: "\f039"; $fa-var-align-left: "\f036"; $fa-var-align-right: "\f038"; +$fa-var-amazon: "\f270"; $fa-var-ambulance: "\f0f9"; +$fa-var-american-sign-language-interpreting: "\f2a3"; $fa-var-anchor: "\f13d"; $fa-var-android: "\f17b"; $fa-var-angellist: "\f209"; @@ -46,16 +55,35 @@ $fa-var-arrows: "\f047"; $fa-var-arrows-alt: "\f0b2"; $fa-var-arrows-h: "\f07e"; $fa-var-arrows-v: "\f07d"; +$fa-var-asl-interpreting: "\f2a3"; +$fa-var-assistive-listening-systems: "\f2a2"; $fa-var-asterisk: "\f069"; $fa-var-at: "\f1fa"; +$fa-var-audio-description: "\f29e"; $fa-var-automobile: "\f1b9"; $fa-var-backward: "\f04a"; +$fa-var-balance-scale: "\f24e"; $fa-var-ban: "\f05e"; +$fa-var-bandcamp: "\f2d5"; $fa-var-bank: "\f19c"; $fa-var-bar-chart: "\f080"; $fa-var-bar-chart-o: "\f080"; $fa-var-barcode: "\f02a"; $fa-var-bars: "\f0c9"; +$fa-var-bath: "\f2cd"; +$fa-var-bathtub: "\f2cd"; +$fa-var-battery: "\f240"; +$fa-var-battery-0: "\f244"; +$fa-var-battery-1: "\f243"; +$fa-var-battery-2: "\f242"; +$fa-var-battery-3: "\f241"; +$fa-var-battery-4: "\f240"; +$fa-var-battery-empty: "\f244"; +$fa-var-battery-full: "\f240"; +$fa-var-battery-half: "\f242"; +$fa-var-battery-quarter: "\f243"; +$fa-var-battery-three-quarters: "\f241"; +$fa-var-bed: "\f236"; $fa-var-beer: "\f0fc"; $fa-var-behance: "\f1b4"; $fa-var-behance-square: "\f1b5"; @@ -69,12 +97,17 @@ $fa-var-birthday-cake: "\f1fd"; $fa-var-bitbucket: "\f171"; $fa-var-bitbucket-square: "\f172"; $fa-var-bitcoin: "\f15a"; +$fa-var-black-tie: "\f27e"; +$fa-var-blind: "\f29d"; +$fa-var-bluetooth: "\f293"; +$fa-var-bluetooth-b: "\f294"; $fa-var-bold: "\f032"; $fa-var-bolt: "\f0e7"; $fa-var-bomb: "\f1e2"; $fa-var-book: "\f02d"; $fa-var-bookmark: "\f02e"; $fa-var-bookmark-o: "\f097"; +$fa-var-braille: "\f2a1"; $fa-var-briefcase: "\f0b1"; $fa-var-btc: "\f15a"; $fa-var-bug: "\f188"; @@ -83,10 +116,15 @@ $fa-var-building-o: "\f0f7"; $fa-var-bullhorn: "\f0a1"; $fa-var-bullseye: "\f140"; $fa-var-bus: "\f207"; +$fa-var-buysellads: "\f20d"; $fa-var-cab: "\f1ba"; $fa-var-calculator: "\f1ec"; $fa-var-calendar: "\f073"; +$fa-var-calendar-check-o: "\f274"; +$fa-var-calendar-minus-o: "\f272"; $fa-var-calendar-o: "\f133"; +$fa-var-calendar-plus-o: "\f271"; +$fa-var-calendar-times-o: "\f273"; $fa-var-camera: "\f030"; $fa-var-camera-retro: "\f083"; $fa-var-car: "\f1b9"; @@ -98,9 +136,13 @@ $fa-var-caret-square-o-left: "\f191"; $fa-var-caret-square-o-right: "\f152"; $fa-var-caret-square-o-up: "\f151"; $fa-var-caret-up: "\f0d8"; +$fa-var-cart-arrow-down: "\f218"; +$fa-var-cart-plus: "\f217"; $fa-var-cc: "\f20a"; $fa-var-cc-amex: "\f1f3"; +$fa-var-cc-diners-club: "\f24c"; $fa-var-cc-discover: "\f1f2"; +$fa-var-cc-jcb: "\f24b"; $fa-var-cc-mastercard: "\f1f1"; $fa-var-cc-paypal: "\f1f4"; $fa-var-cc-stripe: "\f1f5"; @@ -122,12 +164,14 @@ $fa-var-chevron-left: "\f053"; $fa-var-chevron-right: "\f054"; $fa-var-chevron-up: "\f077"; $fa-var-child: "\f1ae"; +$fa-var-chrome: "\f268"; $fa-var-circle: "\f111"; $fa-var-circle-o: "\f10c"; $fa-var-circle-o-notch: "\f1ce"; $fa-var-circle-thin: "\f1db"; $fa-var-clipboard: "\f0ea"; $fa-var-clock-o: "\f017"; +$fa-var-clone: "\f24d"; $fa-var-close: "\f00d"; $fa-var-cloud: "\f0c2"; $fa-var-cloud-download: "\f0ed"; @@ -136,19 +180,26 @@ $fa-var-cny: "\f157"; $fa-var-code: "\f121"; $fa-var-code-fork: "\f126"; $fa-var-codepen: "\f1cb"; +$fa-var-codiepie: "\f284"; $fa-var-coffee: "\f0f4"; $fa-var-cog: "\f013"; $fa-var-cogs: "\f085"; $fa-var-columns: "\f0db"; $fa-var-comment: "\f075"; $fa-var-comment-o: "\f0e5"; +$fa-var-commenting: "\f27a"; +$fa-var-commenting-o: "\f27b"; $fa-var-comments: "\f086"; $fa-var-comments-o: "\f0e6"; $fa-var-compass: "\f14e"; $fa-var-compress: "\f066"; +$fa-var-connectdevelop: "\f20e"; +$fa-var-contao: "\f26d"; $fa-var-copy: "\f0c5"; $fa-var-copyright: "\f1f9"; +$fa-var-creative-commons: "\f25e"; $fa-var-credit-card: "\f09d"; +$fa-var-credit-card-alt: "\f283"; $fa-var-crop: "\f125"; $fa-var-crosshairs: "\f05b"; $fa-var-css3: "\f13c"; @@ -157,27 +208,39 @@ $fa-var-cubes: "\f1b3"; $fa-var-cut: "\f0c4"; $fa-var-cutlery: "\f0f5"; $fa-var-dashboard: "\f0e4"; +$fa-var-dashcube: "\f210"; $fa-var-database: "\f1c0"; +$fa-var-deaf: "\f2a4"; +$fa-var-deafness: "\f2a4"; $fa-var-dedent: "\f03b"; $fa-var-delicious: "\f1a5"; $fa-var-desktop: "\f108"; $fa-var-deviantart: "\f1bd"; +$fa-var-diamond: "\f219"; $fa-var-digg: "\f1a6"; $fa-var-dollar: "\f155"; $fa-var-dot-circle-o: "\f192"; $fa-var-download: "\f019"; $fa-var-dribbble: "\f17d"; +$fa-var-drivers-license: "\f2c2"; +$fa-var-drivers-license-o: "\f2c3"; $fa-var-dropbox: "\f16b"; $fa-var-drupal: "\f1a9"; +$fa-var-edge: "\f282"; $fa-var-edit: "\f044"; +$fa-var-eercast: "\f2da"; $fa-var-eject: "\f052"; $fa-var-ellipsis-h: "\f141"; $fa-var-ellipsis-v: "\f142"; $fa-var-empire: "\f1d1"; $fa-var-envelope: "\f0e0"; $fa-var-envelope-o: "\f003"; +$fa-var-envelope-open: "\f2b6"; +$fa-var-envelope-open-o: "\f2b7"; $fa-var-envelope-square: "\f199"; +$fa-var-envira: "\f299"; $fa-var-eraser: "\f12d"; +$fa-var-etsy: "\f2d7"; $fa-var-eur: "\f153"; $fa-var-euro: "\f153"; $fa-var-exchange: "\f0ec"; @@ -185,16 +248,21 @@ $fa-var-exclamation: "\f12a"; $fa-var-exclamation-circle: "\f06a"; $fa-var-exclamation-triangle: "\f071"; $fa-var-expand: "\f065"; +$fa-var-expeditedssl: "\f23e"; $fa-var-external-link: "\f08e"; $fa-var-external-link-square: "\f14c"; $fa-var-eye: "\f06e"; $fa-var-eye-slash: "\f070"; $fa-var-eyedropper: "\f1fb"; +$fa-var-fa: "\f2b4"; $fa-var-facebook: "\f09a"; +$fa-var-facebook-f: "\f09a"; +$fa-var-facebook-official: "\f230"; $fa-var-facebook-square: "\f082"; $fa-var-fast-backward: "\f049"; $fa-var-fast-forward: "\f050"; $fa-var-fax: "\f1ac"; +$fa-var-feed: "\f09e"; $fa-var-female: "\f182"; $fa-var-fighter-jet: "\f0fb"; $fa-var-file: "\f15b"; @@ -220,6 +288,8 @@ $fa-var-film: "\f008"; $fa-var-filter: "\f0b0"; $fa-var-fire: "\f06d"; $fa-var-fire-extinguisher: "\f134"; +$fa-var-firefox: "\f269"; +$fa-var-first-order: "\f2b0"; $fa-var-flag: "\f024"; $fa-var-flag-checkered: "\f11e"; $fa-var-flag-o: "\f11d"; @@ -232,8 +302,13 @@ $fa-var-folder-o: "\f114"; $fa-var-folder-open: "\f07c"; $fa-var-folder-open-o: "\f115"; $fa-var-font: "\f031"; +$fa-var-font-awesome: "\f2b4"; +$fa-var-fonticons: "\f280"; +$fa-var-fort-awesome: "\f286"; +$fa-var-forumbee: "\f211"; $fa-var-forward: "\f04e"; $fa-var-foursquare: "\f180"; +$fa-var-free-code-camp: "\f2c5"; $fa-var-frown-o: "\f119"; $fa-var-futbol-o: "\f1e3"; $fa-var-gamepad: "\f11b"; @@ -242,45 +317,87 @@ $fa-var-gbp: "\f154"; $fa-var-ge: "\f1d1"; $fa-var-gear: "\f013"; $fa-var-gears: "\f085"; +$fa-var-genderless: "\f22d"; +$fa-var-get-pocket: "\f265"; +$fa-var-gg: "\f260"; +$fa-var-gg-circle: "\f261"; $fa-var-gift: "\f06b"; $fa-var-git: "\f1d3"; $fa-var-git-square: "\f1d2"; $fa-var-github: "\f09b"; $fa-var-github-alt: "\f113"; $fa-var-github-square: "\f092"; +$fa-var-gitlab: "\f296"; $fa-var-gittip: "\f184"; $fa-var-glass: "\f000"; +$fa-var-glide: "\f2a5"; +$fa-var-glide-g: "\f2a6"; $fa-var-globe: "\f0ac"; $fa-var-google: "\f1a0"; $fa-var-google-plus: "\f0d5"; +$fa-var-google-plus-circle: "\f2b3"; +$fa-var-google-plus-official: "\f2b3"; $fa-var-google-plus-square: "\f0d4"; $fa-var-google-wallet: "\f1ee"; $fa-var-graduation-cap: "\f19d"; +$fa-var-gratipay: "\f184"; +$fa-var-grav: "\f2d6"; $fa-var-group: "\f0c0"; $fa-var-h-square: "\f0fd"; $fa-var-hacker-news: "\f1d4"; +$fa-var-hand-grab-o: "\f255"; +$fa-var-hand-lizard-o: "\f258"; $fa-var-hand-o-down: "\f0a7"; $fa-var-hand-o-left: "\f0a5"; $fa-var-hand-o-right: "\f0a4"; $fa-var-hand-o-up: "\f0a6"; +$fa-var-hand-paper-o: "\f256"; +$fa-var-hand-peace-o: "\f25b"; +$fa-var-hand-pointer-o: "\f25a"; +$fa-var-hand-rock-o: "\f255"; +$fa-var-hand-scissors-o: "\f257"; +$fa-var-hand-spock-o: "\f259"; +$fa-var-hand-stop-o: "\f256"; +$fa-var-handshake-o: "\f2b5"; +$fa-var-hard-of-hearing: "\f2a4"; +$fa-var-hashtag: "\f292"; $fa-var-hdd-o: "\f0a0"; $fa-var-header: "\f1dc"; $fa-var-headphones: "\f025"; $fa-var-heart: "\f004"; $fa-var-heart-o: "\f08a"; +$fa-var-heartbeat: "\f21e"; $fa-var-history: "\f1da"; $fa-var-home: "\f015"; $fa-var-hospital-o: "\f0f8"; +$fa-var-hotel: "\f236"; +$fa-var-hourglass: "\f254"; +$fa-var-hourglass-1: "\f251"; +$fa-var-hourglass-2: "\f252"; +$fa-var-hourglass-3: "\f253"; +$fa-var-hourglass-end: "\f253"; +$fa-var-hourglass-half: "\f252"; +$fa-var-hourglass-o: "\f250"; +$fa-var-hourglass-start: "\f251"; +$fa-var-houzz: "\f27c"; $fa-var-html5: "\f13b"; +$fa-var-i-cursor: "\f246"; +$fa-var-id-badge: "\f2c1"; +$fa-var-id-card: "\f2c2"; +$fa-var-id-card-o: "\f2c3"; $fa-var-ils: "\f20b"; $fa-var-image: "\f03e"; +$fa-var-imdb: "\f2d8"; $fa-var-inbox: "\f01c"; $fa-var-indent: "\f03c"; +$fa-var-industry: "\f275"; $fa-var-info: "\f129"; $fa-var-info-circle: "\f05a"; $fa-var-inr: "\f156"; $fa-var-instagram: "\f16d"; $fa-var-institution: "\f19c"; +$fa-var-internet-explorer: "\f26b"; +$fa-var-intersex: "\f224"; $fa-var-ioxhost: "\f208"; $fa-var-italic: "\f033"; $fa-var-joomla: "\f1aa"; @@ -294,6 +411,7 @@ $fa-var-laptop: "\f109"; $fa-var-lastfm: "\f202"; $fa-var-lastfm-square: "\f203"; $fa-var-leaf: "\f06c"; +$fa-var-leanpub: "\f212"; $fa-var-legal: "\f0e3"; $fa-var-lemon-o: "\f094"; $fa-var-level-down: "\f149"; @@ -307,6 +425,7 @@ $fa-var-line-chart: "\f201"; $fa-var-link: "\f0c1"; $fa-var-linkedin: "\f0e1"; $fa-var-linkedin-square: "\f08c"; +$fa-var-linode: "\f2b8"; $fa-var-linux: "\f17c"; $fa-var-list: "\f03a"; $fa-var-list-alt: "\f022"; @@ -318,32 +437,58 @@ $fa-var-long-arrow-down: "\f175"; $fa-var-long-arrow-left: "\f177"; $fa-var-long-arrow-right: "\f178"; $fa-var-long-arrow-up: "\f176"; +$fa-var-low-vision: "\f2a8"; $fa-var-magic: "\f0d0"; $fa-var-magnet: "\f076"; $fa-var-mail-forward: "\f064"; $fa-var-mail-reply: "\f112"; $fa-var-mail-reply-all: "\f122"; $fa-var-male: "\f183"; +$fa-var-map: "\f279"; $fa-var-map-marker: "\f041"; +$fa-var-map-o: "\f278"; +$fa-var-map-pin: "\f276"; +$fa-var-map-signs: "\f277"; +$fa-var-mars: "\f222"; +$fa-var-mars-double: "\f227"; +$fa-var-mars-stroke: "\f229"; +$fa-var-mars-stroke-h: "\f22b"; +$fa-var-mars-stroke-v: "\f22a"; $fa-var-maxcdn: "\f136"; $fa-var-meanpath: "\f20c"; +$fa-var-medium: "\f23a"; $fa-var-medkit: "\f0fa"; +$fa-var-meetup: "\f2e0"; $fa-var-meh-o: "\f11a"; +$fa-var-mercury: "\f223"; +$fa-var-microchip: "\f2db"; $fa-var-microphone: "\f130"; $fa-var-microphone-slash: "\f131"; $fa-var-minus: "\f068"; $fa-var-minus-circle: "\f056"; $fa-var-minus-square: "\f146"; $fa-var-minus-square-o: "\f147"; +$fa-var-mixcloud: "\f289"; $fa-var-mobile: "\f10b"; $fa-var-mobile-phone: "\f10b"; +$fa-var-modx: "\f285"; $fa-var-money: "\f0d6"; $fa-var-moon-o: "\f186"; $fa-var-mortar-board: "\f19d"; +$fa-var-motorcycle: "\f21c"; +$fa-var-mouse-pointer: "\f245"; $fa-var-music: "\f001"; $fa-var-navicon: "\f0c9"; +$fa-var-neuter: "\f22c"; $fa-var-newspaper-o: "\f1ea"; +$fa-var-object-group: "\f247"; +$fa-var-object-ungroup: "\f248"; +$fa-var-odnoklassniki: "\f263"; +$fa-var-odnoklassniki-square: "\f264"; +$fa-var-opencart: "\f23d"; $fa-var-openid: "\f19b"; +$fa-var-opera: "\f26a"; +$fa-var-optin-monster: "\f23c"; $fa-var-outdent: "\f03b"; $fa-var-pagelines: "\f18c"; $fa-var-paint-brush: "\f1fc"; @@ -353,19 +498,24 @@ $fa-var-paperclip: "\f0c6"; $fa-var-paragraph: "\f1dd"; $fa-var-paste: "\f0ea"; $fa-var-pause: "\f04c"; +$fa-var-pause-circle: "\f28b"; +$fa-var-pause-circle-o: "\f28c"; $fa-var-paw: "\f1b0"; $fa-var-paypal: "\f1ed"; $fa-var-pencil: "\f040"; $fa-var-pencil-square: "\f14b"; $fa-var-pencil-square-o: "\f044"; +$fa-var-percent: "\f295"; $fa-var-phone: "\f095"; $fa-var-phone-square: "\f098"; $fa-var-photo: "\f03e"; $fa-var-picture-o: "\f03e"; $fa-var-pie-chart: "\f200"; -$fa-var-pied-piper: "\f1a7"; +$fa-var-pied-piper: "\f2ae"; $fa-var-pied-piper-alt: "\f1a8"; +$fa-var-pied-piper-pp: "\f1a7"; $fa-var-pinterest: "\f0d2"; +$fa-var-pinterest-p: "\f231"; $fa-var-pinterest-square: "\f0d3"; $fa-var-plane: "\f072"; $fa-var-play: "\f04b"; @@ -376,28 +526,36 @@ $fa-var-plus: "\f067"; $fa-var-plus-circle: "\f055"; $fa-var-plus-square: "\f0fe"; $fa-var-plus-square-o: "\f196"; +$fa-var-podcast: "\f2ce"; $fa-var-power-off: "\f011"; $fa-var-print: "\f02f"; +$fa-var-product-hunt: "\f288"; $fa-var-puzzle-piece: "\f12e"; $fa-var-qq: "\f1d6"; $fa-var-qrcode: "\f029"; $fa-var-question: "\f128"; $fa-var-question-circle: "\f059"; +$fa-var-question-circle-o: "\f29c"; +$fa-var-quora: "\f2c4"; $fa-var-quote-left: "\f10d"; $fa-var-quote-right: "\f10e"; $fa-var-ra: "\f1d0"; $fa-var-random: "\f074"; +$fa-var-ravelry: "\f2d9"; $fa-var-rebel: "\f1d0"; $fa-var-recycle: "\f1b8"; $fa-var-reddit: "\f1a1"; +$fa-var-reddit-alien: "\f281"; $fa-var-reddit-square: "\f1a2"; $fa-var-refresh: "\f021"; +$fa-var-registered: "\f25d"; $fa-var-remove: "\f00d"; $fa-var-renren: "\f18b"; $fa-var-reorder: "\f0c9"; $fa-var-repeat: "\f01e"; $fa-var-reply: "\f112"; $fa-var-reply-all: "\f122"; +$fa-var-resistance: "\f1d0"; $fa-var-retweet: "\f079"; $fa-var-rmb: "\f157"; $fa-var-road: "\f018"; @@ -410,13 +568,18 @@ $fa-var-rss-square: "\f143"; $fa-var-rub: "\f158"; $fa-var-ruble: "\f158"; $fa-var-rupee: "\f156"; +$fa-var-s15: "\f2cd"; +$fa-var-safari: "\f267"; $fa-var-save: "\f0c7"; $fa-var-scissors: "\f0c4"; +$fa-var-scribd: "\f28a"; $fa-var-search: "\f002"; $fa-var-search-minus: "\f010"; $fa-var-search-plus: "\f00e"; +$fa-var-sellsy: "\f213"; $fa-var-send: "\f1d8"; $fa-var-send-o: "\f1d9"; +$fa-var-server: "\f233"; $fa-var-share: "\f064"; $fa-var-share-alt: "\f1e0"; $fa-var-share-alt-square: "\f1e1"; @@ -425,16 +588,29 @@ $fa-var-share-square-o: "\f045"; $fa-var-shekel: "\f20b"; $fa-var-sheqel: "\f20b"; $fa-var-shield: "\f132"; +$fa-var-ship: "\f21a"; +$fa-var-shirtsinbulk: "\f214"; +$fa-var-shopping-bag: "\f290"; +$fa-var-shopping-basket: "\f291"; $fa-var-shopping-cart: "\f07a"; +$fa-var-shower: "\f2cc"; $fa-var-sign-in: "\f090"; +$fa-var-sign-language: "\f2a7"; $fa-var-sign-out: "\f08b"; $fa-var-signal: "\f012"; +$fa-var-signing: "\f2a7"; +$fa-var-simplybuilt: "\f215"; $fa-var-sitemap: "\f0e8"; +$fa-var-skyatlas: "\f216"; $fa-var-skype: "\f17e"; $fa-var-slack: "\f198"; $fa-var-sliders: "\f1de"; $fa-var-slideshare: "\f1e7"; $fa-var-smile-o: "\f118"; +$fa-var-snapchat: "\f2ab"; +$fa-var-snapchat-ghost: "\f2ac"; +$fa-var-snapchat-square: "\f2ad"; +$fa-var-snowflake-o: "\f2dc"; $fa-var-soccer-ball-o: "\f1e3"; $fa-var-sort: "\f0dc"; $fa-var-sort-alpha-asc: "\f15d"; @@ -467,13 +643,20 @@ $fa-var-steam-square: "\f1b7"; $fa-var-step-backward: "\f048"; $fa-var-step-forward: "\f051"; $fa-var-stethoscope: "\f0f1"; +$fa-var-sticky-note: "\f249"; +$fa-var-sticky-note-o: "\f24a"; $fa-var-stop: "\f04d"; +$fa-var-stop-circle: "\f28d"; +$fa-var-stop-circle-o: "\f28e"; +$fa-var-street-view: "\f21d"; $fa-var-strikethrough: "\f0cc"; $fa-var-stumbleupon: "\f1a4"; $fa-var-stumbleupon-circle: "\f1a3"; $fa-var-subscript: "\f12c"; +$fa-var-subway: "\f239"; $fa-var-suitcase: "\f0f2"; $fa-var-sun-o: "\f185"; +$fa-var-superpowers: "\f2dd"; $fa-var-superscript: "\f12b"; $fa-var-support: "\f1cd"; $fa-var-table: "\f0ce"; @@ -483,6 +666,8 @@ $fa-var-tag: "\f02b"; $fa-var-tags: "\f02c"; $fa-var-tasks: "\f0ae"; $fa-var-taxi: "\f1ba"; +$fa-var-telegram: "\f2c6"; +$fa-var-television: "\f26c"; $fa-var-tencent-weibo: "\f1d5"; $fa-var-terminal: "\f120"; $fa-var-text-height: "\f034"; @@ -490,6 +675,18 @@ $fa-var-text-width: "\f035"; $fa-var-th: "\f00a"; $fa-var-th-large: "\f009"; $fa-var-th-list: "\f00b"; +$fa-var-themeisle: "\f2b2"; +$fa-var-thermometer: "\f2c7"; +$fa-var-thermometer-0: "\f2cb"; +$fa-var-thermometer-1: "\f2ca"; +$fa-var-thermometer-2: "\f2c9"; +$fa-var-thermometer-3: "\f2c8"; +$fa-var-thermometer-4: "\f2c7"; +$fa-var-thermometer-empty: "\f2cb"; +$fa-var-thermometer-full: "\f2c7"; +$fa-var-thermometer-half: "\f2c9"; +$fa-var-thermometer-quarter: "\f2ca"; +$fa-var-thermometer-three-quarters: "\f2c8"; $fa-var-thumb-tack: "\f08d"; $fa-var-thumbs-down: "\f165"; $fa-var-thumbs-o-down: "\f088"; @@ -499,6 +696,8 @@ $fa-var-ticket: "\f145"; $fa-var-times: "\f00d"; $fa-var-times-circle: "\f057"; $fa-var-times-circle-o: "\f05c"; +$fa-var-times-rectangle: "\f2d3"; +$fa-var-times-rectangle-o: "\f2d4"; $fa-var-tint: "\f043"; $fa-var-toggle-down: "\f150"; $fa-var-toggle-left: "\f191"; @@ -506,10 +705,15 @@ $fa-var-toggle-off: "\f204"; $fa-var-toggle-on: "\f205"; $fa-var-toggle-right: "\f152"; $fa-var-toggle-up: "\f151"; +$fa-var-trademark: "\f25c"; +$fa-var-train: "\f238"; +$fa-var-transgender: "\f224"; +$fa-var-transgender-alt: "\f225"; $fa-var-trash: "\f1f8"; $fa-var-trash-o: "\f014"; $fa-var-tree: "\f1bb"; $fa-var-trello: "\f181"; +$fa-var-tripadvisor: "\f262"; $fa-var-trophy: "\f091"; $fa-var-truck: "\f0d1"; $fa-var-try: "\f195"; @@ -517,26 +721,45 @@ $fa-var-tty: "\f1e4"; $fa-var-tumblr: "\f173"; $fa-var-tumblr-square: "\f174"; $fa-var-turkish-lira: "\f195"; +$fa-var-tv: "\f26c"; $fa-var-twitch: "\f1e8"; $fa-var-twitter: "\f099"; $fa-var-twitter-square: "\f081"; $fa-var-umbrella: "\f0e9"; $fa-var-underline: "\f0cd"; $fa-var-undo: "\f0e2"; +$fa-var-universal-access: "\f29a"; $fa-var-university: "\f19c"; $fa-var-unlink: "\f127"; $fa-var-unlock: "\f09c"; $fa-var-unlock-alt: "\f13e"; $fa-var-unsorted: "\f0dc"; $fa-var-upload: "\f093"; +$fa-var-usb: "\f287"; $fa-var-usd: "\f155"; $fa-var-user: "\f007"; +$fa-var-user-circle: "\f2bd"; +$fa-var-user-circle-o: "\f2be"; $fa-var-user-md: "\f0f0"; +$fa-var-user-o: "\f2c0"; +$fa-var-user-plus: "\f234"; +$fa-var-user-secret: "\f21b"; +$fa-var-user-times: "\f235"; $fa-var-users: "\f0c0"; +$fa-var-vcard: "\f2bb"; +$fa-var-vcard-o: "\f2bc"; +$fa-var-venus: "\f221"; +$fa-var-venus-double: "\f226"; +$fa-var-venus-mars: "\f228"; +$fa-var-viacoin: "\f237"; +$fa-var-viadeo: "\f2a9"; +$fa-var-viadeo-square: "\f2aa"; $fa-var-video-camera: "\f03d"; +$fa-var-vimeo: "\f27d"; $fa-var-vimeo-square: "\f194"; $fa-var-vine: "\f1ca"; $fa-var-vk: "\f189"; +$fa-var-volume-control-phone: "\f2a0"; $fa-var-volume-down: "\f027"; $fa-var-volume-off: "\f026"; $fa-var-volume-up: "\f028"; @@ -544,17 +767,33 @@ $fa-var-warning: "\f071"; $fa-var-wechat: "\f1d7"; $fa-var-weibo: "\f18a"; $fa-var-weixin: "\f1d7"; +$fa-var-whatsapp: "\f232"; $fa-var-wheelchair: "\f193"; +$fa-var-wheelchair-alt: "\f29b"; $fa-var-wifi: "\f1eb"; +$fa-var-wikipedia-w: "\f266"; +$fa-var-window-close: "\f2d3"; +$fa-var-window-close-o: "\f2d4"; +$fa-var-window-maximize: "\f2d0"; +$fa-var-window-minimize: "\f2d1"; +$fa-var-window-restore: "\f2d2"; $fa-var-windows: "\f17a"; $fa-var-won: "\f159"; $fa-var-wordpress: "\f19a"; +$fa-var-wpbeginner: "\f297"; +$fa-var-wpexplorer: "\f2de"; +$fa-var-wpforms: "\f298"; $fa-var-wrench: "\f0ad"; $fa-var-xing: "\f168"; $fa-var-xing-square: "\f169"; +$fa-var-y-combinator: "\f23b"; +$fa-var-y-combinator-square: "\f1d4"; $fa-var-yahoo: "\f19e"; +$fa-var-yc: "\f23b"; +$fa-var-yc-square: "\f1d4"; $fa-var-yelp: "\f1e9"; $fa-var-yen: "\f157"; +$fa-var-yoast: "\f2b1"; $fa-var-youtube: "\f167"; $fa-var-youtube-play: "\f16a"; $fa-var-youtube-square: "\f166"; diff --git a/assets/font/fonts-awesome/scss/font-awesome.scss b/assets/font/fonts-awesome/scss/font-awesome.scss index f300c09..f1c83aa 100644 --- a/assets/font/fonts-awesome/scss/font-awesome.scss +++ b/assets/font/fonts-awesome/scss/font-awesome.scss @@ -1,5 +1,5 @@ /*! - * Font Awesome 4.2.0 by @davegandy - http://fontawesome.io - @fontawesome + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) */ @@ -11,7 +11,8 @@ @import "fixed-width"; @import "list"; @import "bordered-pulled"; -@import "spinning"; +@import "animated"; @import "rotated-flipped"; @import "stacked"; @import "icons"; +@import "screen-reader"; diff --git a/controllers/internals/Media.php b/controllers/internals/Media.php index 25fb988..c9d2642 100644 --- a/controllers/internals/Media.php +++ b/controllers/internals/Media.php @@ -48,7 +48,7 @@ class Media extends StandardController if (!file_put_contents($new_file_path, 'a')) { - throw new \Exception('pute de merde'); + throw new \Exception('Cannot write file ' . $new_file_path); } if (!rename($tmpfile_path, $new_file_path)) @@ -56,16 +56,6 @@ class Media extends StandardController throw new \Exception('Cannot create file ' . $new_file_path); } - if (!chown($new_file_path, fileowner($user_path))) - { - throw new \Exception('Cannot give file ' . $new_file_path . ' to user : ' . fileowner($user_path)); - } - - if (!chgrp($new_file_path, filegroup($user_path))) - { - throw new \Exception('Cannot give file ' . $new_file_path . ' to group : ' . filegroup($user_path)); - } - if (!chmod($new_file_path, self::DEFAULT_CHMOD)) { throw new \Exception('Cannot give file ' . $new_file_path . ' rights : ' . self::DEFAULT_CHMOD); diff --git a/controllers/internals/Phone.php b/controllers/internals/Phone.php index 9bdeac7..a2cebf5 100644 --- a/controllers/internals/Phone.php +++ b/controllers/internals/Phone.php @@ -236,6 +236,19 @@ namespace controllers\internals; return true; } + /** + * Update a phone status. + * + * @param int $id : Phone id + * @param string $status : The new status of the phone + * + * @return bool : false on error, true on success + */ + public function update_status(int $id, string $status) : bool + { + return (bool) $this->get_model()->update($id, ['status' => $status]); + } + /** * Get the model for the Controller. */ diff --git a/controllers/internals/PhoneGroup.php b/controllers/internals/PhoneGroup.php new file mode 100644 index 0000000..5ce213e --- /dev/null +++ b/controllers/internals/PhoneGroup.php @@ -0,0 +1,139 @@ + + * + * This source file is subject to the GPL-3.0 license that is bundled + * with this source code in the file LICENSE. + */ + +namespace controllers\internals; + + /** + * Classe des groups. + */ + class PhoneGroup extends StandardController + { + protected $model; + + /** + * Create a new phone group for a user. + * + * @param int $id_user : user id + * @param stirng $name : Group name + * @param array $phones_ids : Ids of the phones of the group + * + * @return mixed bool|int : false on error, new group id + */ + public function create(int $id_user, string $name, array $phones_ids) + { + $group = [ + 'id_user' => $id_user, + 'name' => $name, + ]; + + $id_group = $this->get_model()->insert($group); + if (!$id_group) + { + return false; + } + + $internal_phone = new Phone($this->bdd); + foreach ($phones_ids as $phone_id) + { + $phone = $internal_phone->get_for_user($id_user, $phone_id); + if (!$phone) + { + continue; + } + + $this->get_model()->insert_phone_group_phone_relation($id_group, $phone_id); + } + + $internal_event = new Event($this->bdd); + $internal_event->create($id_user, 'PHONE_GROUP_ADD', 'Ajout phone group : ' . $name); + + return $id_group; + } + + /** + * Update a phone group for a user. + * + * @param int $id_user : User id + * @param int $id_group : Group id + * @param stirng $name : Group name + * @param array $phones_ids : Ids of the phones of the group + * + * @return bool : False on error, true on success + */ + public function update_for_user(int $id_user, int $id_group, string $name, array $phones_ids) + { + $group = [ + 'name' => $name, + ]; + + $result = $this->get_model()->update_for_user($id_user, $id_group, $group); + + $this->get_model()->delete_phone_group_phone_relations($id_group); + + $internal_phone = new Phone($this->bdd); + $nb_phone_insert = 0; + foreach ($phones_ids as $phone_id) + { + $phone = $internal_phone->get_for_user($id_user, $phone_id); + if (!$phone) + { + continue; + } + + if ($this->get_model()->insert_phone_group_phone_relation($id_group, $phone_id)) + { + ++$nb_phone_insert; + } + } + + if (!$result && $nb_phone_insert !== \count($phones_ids)) + { + return false; + } + + return true; + } + + /** + * Return a group by his name for a user. + * + * @param int $id_user : User id + * @param string $name : Group name + * + * @return array + */ + public function get_by_name_for_user(int $id_user, string $name) + { + return $this->get_model()->get_by_name_for_user($id_user, $name); + } + + /** + * Get groups phones. + * + * @param int $id_group : Group id + * + * @return array : phones of the group + */ + public function get_phones($id_group) + { + return $this->get_model()->get_phones($id_group); + } + + /** + * Get the model for the Controller. + */ + protected function get_model(): \models\PhoneGroup + { + $this->model = $this->model ?? new \models\PhoneGroup($this->bdd); + + return $this->model; + } + } diff --git a/controllers/internals/Scheduled.php b/controllers/internals/Scheduled.php index 4f0c3f7..1b61a90 100644 --- a/controllers/internals/Scheduled.php +++ b/controllers/internals/Scheduled.php @@ -23,27 +23,31 @@ use Monolog\Logger; * * @param int $id_user : User to insert scheduled for * @param $at : Scheduled date to send - * @param string $text : Text of the message - * @param ?int $id_phone : Id of the phone to send message with, null by default - * @param bool $flash : Is the sms a flash sms, by default false - * @param bool $mms : Is the sms a mms, by default false - * @param array $numbers : Array of numbers to send message to, a number is an array ['number' => '+33XXX', 'data' => '{"key":"value", ...}'] - * @param array $contacts_ids : Contact ids to send message to - * @param array $groups_ids : Group ids to send message to - * @param array $conditional_group_ids : Conditional Groups ids to send message to - * @param array $media_ids : Ids of the medias to link to scheduled message + * @param string $text : Text of the message + * @param ?int $id_phone : Id of the phone to send message with, null by default + * @param ?int $id_phone_group : Id of the phone group to send message with, null by default + * @param bool $flash : Is the sms a flash sms, by default false + * @param bool $mms : Is the sms a mms, by default false + * @param ?string $tag : A string tag to associate to sended SMS + * @param array $numbers : Array of numbers to send message to, a number is an array ['number' => '+33XXX', 'data' => '{"key":"value", ...}'] + * @param array $contacts_ids : Contact ids to send message to + * @param array $groups_ids : Group ids to send message to + * @param array $conditional_group_ids : Conditional Groups ids to send message to + * @param array $media_ids : Ids of the medias to link to scheduled message * * @return bool : false on error, new id on success */ - public function create(int $id_user, $at, string $text, ?int $id_phone = null, bool $flash = false, bool $mms = false, array $numbers = [], array $contacts_ids = [], array $groups_ids = [], array $conditional_group_ids = [], array $media_ids = []) + public function create(int $id_user, $at, string $text, ?int $id_phone = null, ?int $id_phone_group = null, bool $flash = false, bool $mms = false, ?string $tag = null, array $numbers = [], array $contacts_ids = [], array $groups_ids = [], array $conditional_group_ids = [], array $media_ids = []) { $scheduled = [ 'id_user' => $id_user, 'at' => $at, 'text' => $text, 'id_phone' => $id_phone, + 'id_phone_group' => $id_phone_group, 'flash' => $flash, 'mms' => $mms, + 'tag' => $tag, ]; if ('' === $text) @@ -62,6 +66,17 @@ use Monolog\Logger; } } + if (null !== $id_phone_group) + { + $internal_phone_group = new PhoneGroup($this->bdd); + $find_phone_group = $internal_phone_group->get_for_user($id_user, $id_phone_group); + + if (!$find_phone_group) + { + return false; + } + } + //Use transaction to garanty atomicity $this->bdd->beginTransaction(); @@ -147,8 +162,10 @@ use Monolog\Logger; * @param $at : Scheduled date to send * @param string $text : Text of the message * @param ?int $id_phone : Id of the phone to send message with, null by default + * @param ?int $id_phone_group : Id of the phone group to send message with, null by default * @param bool $flash : Is the sms a flash sms, by default false * @param bool $mms : Is the sms a mms, by default false + * @param ?string $tag : A string tag to associate to sended SMS * @param array $numbers : Array of numbers to send message to, a number is an array ['number' => '+33XXX', 'data' => '{"key":"value", ...}'] * @param array $contacts_ids : Contact ids to send message to * @param array $groups_ids : Group ids to send message to @@ -157,15 +174,17 @@ use Monolog\Logger; * * @return bool : false on error, true on success */ - public function update_for_user(int $id_user, int $id_scheduled, $at, string $text, ?string $id_phone = null, bool $flash = false, bool $mms = false, array $numbers = [], array $contacts_ids = [], array $groups_ids = [], array $conditional_group_ids = [], array $media_ids = []) + public function update_for_user(int $id_user, int $id_scheduled, $at, string $text, ?int $id_phone = null, ?int $id_phone_group = null, bool $flash = false, bool $mms = false, ?string $tag = null, array $numbers = [], array $contacts_ids = [], array $groups_ids = [], array $conditional_group_ids = [], array $media_ids = []) { $scheduled = [ 'id_user' => $id_user, 'at' => $at, 'text' => $text, 'id_phone' => $id_phone, + 'id_phone_group' => $id_phone_group, 'mms' => $mms, 'flash' => $flash, + 'tag' => $tag, ]; if (null !== $id_phone) @@ -179,6 +198,17 @@ use Monolog\Logger; } } + if (null !== $id_phone_group) + { + $internal_phone_group = new PhoneGroup($this->bdd); + $find_phone_group = $internal_phone_group->get_for_user($id_user, $id_phone_group); + + if (!$find_phone_group) + { + return false; + } + } + //Ensure atomicity $this->bdd->beginTransaction(); @@ -413,13 +443,14 @@ use Monolog\Logger; $internal_group = new \controllers\internals\Group($this->bdd); $internal_conditional_group = new \controllers\internals\ConditionalGroup($this->bdd); $internal_phone = new \controllers\internals\Phone($this->bdd); + $internal_phone_group = new \controllers\internals\PhoneGroup($this->bdd); $internal_smsstop = new \controllers\internals\SmsStop($this->bdd); $internal_sended = new \controllers\internals\Sended($this->bdd); $users_smsstops = []; $users_settings = []; $users_phones = []; - $users_mms_phones = []; + $users_phone_groups = []; $now = new \DateTime(); $now = $now->format('Y-m-d H:i:s'); @@ -457,7 +488,6 @@ use Monolog\Logger; if (!isset($users_phones[$id_user])) { $users_phones[$id_user] = []; - $users_mms_phones[$id_user] = []; $phones = $internal_phone->gets_for_user($id_user); foreach ($phones as &$phone) @@ -475,25 +505,25 @@ use Monolog\Logger; $phone['remaining_volume'] = $remaining_volume; $users_phones[$id_user][$phone['id']] = $phone; } - - $mms_phones = $internal_phone->gets_phone_supporting_mms_for_user($id_user, $internal_phone::MMS_SENDING); - foreach ($mms_phones as &$mms_phone) - { - $limits = $internal_phone->get_limits($mms_phone['id']); - - $remaining_volume = PHP_INT_MAX; - foreach ($limits as $limit) - { - $startpoint = new \DateTime($limit['startpoint']); - $consumed = $internal_sended->count_since_for_phone_and_user($id_user, $mms_phone['id'], $startpoint); - $remaining_volume = min(($limit['volume'] - $consumed), $remaining_volume); - } - - $mms_phone['remaining_volume'] = $remaining_volume; - $users_mms_phones[$id_user][$mms_phone['id']] = $mms_phone; - } } + if (!isset($users_phone_groups[$id_user])) + { + $users_phone_groups[$id_user] = []; + + $phone_groups = $internal_phone_group->gets_for_user($id_user); + foreach ($phone_groups as $phone_group) + { + $phones = $internal_phone_group->get_phones($phone_group['id']); + $phone_group['phones'] = []; + foreach ($phones as $phone) + { + $phone_group['phones'][] = $phone['id']; + } + + $users_phone_groups[$id_user][$phone_group['id']] = $phone_group; + } + } //Add medias to mms $scheduled['medias'] = []; @@ -509,6 +539,12 @@ use Monolog\Logger; $phone_to_use = $users_phones[$id_user][$scheduled['id_phone']] ?? null; } + $phone_group_to_use = null; + if ($scheduled['id_phone_group']) + { + $phone_group_to_use = $users_phone_groups[$id_user][$scheduled['id_phone_group']] ?? null; + } + // We turn all contacts, groups and conditional groups into just contacts $contacts = $this->get_contacts($id_scheduled); @@ -620,36 +656,63 @@ use Monolog\Logger; if (null === $phone_to_use) { $phones_subset = $users_phones[$id_user]; - if ($scheduled['mms']) + + if ($phone_group_to_use) { - $phones_subset = $users_mms_phones[$id_user] ?: $phones_subset; + $phones_subset = array_filter($phones_subset, function ($phone) use ($phone_group_to_use) { + return in_array($phone['id'], $phone_group_to_use['phones']); + }); } + if ($scheduled['mms']) + { + $mms_only = array_filter($phones_subset, function ($phone) { + return $phone['adapter']::meta_support_mms_sending(); + }); + + $phones_subset = $mms_only ?: $phones_subset; + } + + // Keep only available phones $remaining_volume_phones = array_filter($phones_subset, function ($phone) { - return $phone['remaining_volume'] > 0; + return $phone['status'] == \models\Phone::STATUS_AVAILABLE; }); $phones_subset = $remaining_volume_phones ?: $phones_subset; - $max_priority_phones = []; - $max_priority = PHP_INT_MIN; - foreach ($phones_subset as $phone) + + // Keep only phones with remaining volume + if ((int) ($users_settings[$id_user]['phone_limit'] ?? false)) { - if ($phone['priority'] < $max_priority) - { - continue; - } - elseif ($phone['priority'] == $max_priority) - { - $max_priority_phones[] = $phone; - } - elseif ($phone['priority'] > $max_priority) - { - $max_priority_phones = [$phone]; - $max_priority = $phone['priority']; - } + $remaining_volume_phones = array_filter($phones_subset, function ($phone) { + return $phone['remaining_volume'] > 0; + }); + $phones_subset = $remaining_volume_phones ?: $phones_subset; } - $phones_subset = $max_priority_phones; + if ((int) ($users_settings[$id_user]['phone_priority'] ?? false)) + { + $max_priority_phones = []; + $max_priority = PHP_INT_MIN; + foreach ($phones_subset as $phone) + { + if ($phone['priority'] < $max_priority) + { + continue; + } + elseif ($phone['priority'] == $max_priority) + { + $max_priority_phones[] = $phone; + } + elseif ($phone['priority'] > $max_priority) + { + $max_priority_phones = [$phone]; + $max_priority = $phone['priority']; + } + } + + $phones_subset = $max_priority_phones; + } + if ($phones_subset) { $random_phone = $phones_subset[array_rand($phones_subset)]; @@ -670,16 +733,13 @@ use Monolog\Logger; 'destination' => $target['number'], 'flash' => $scheduled['flash'], 'mms' => $scheduled['mms'], + 'tag' => $scheduled['tag'], 'medias' => $scheduled['medias'], 'text' => $text, ]; - // Consume one sms from remaining volume of phone, dont forget to do the same for the entry in mms phones + // Consume one sms from remaining volume of phone $users_phones[$id_user][$id_phone]['remaining_volume'] --; - if ($users_mms_phones[$id_user][$id_phone] ?? false) - { - $users_mms_phones[$id_user][$id_phone] --; - } } } diff --git a/controllers/internals/Sended.php b/controllers/internals/Sended.php index 6a9276c..e58577c 100644 --- a/controllers/internals/Sended.php +++ b/controllers/internals/Sended.php @@ -11,6 +11,8 @@ namespace controllers\internals; +use Exception; + class Sended extends StandardController { protected $model; @@ -44,13 +46,14 @@ namespace controllers\internals; * @param string $adapter : Name of the adapter service used to send the message * @param bool $flash : Is the sms a flash * @param bool $mms : Is the sms a MMS. By default false. + * @param ?string $tag : A string tag to associate to sended SMS * @param array $medias : Array of medias to link to the MMS * @param ?int $originating_scheduled : Id of the scheduled message that was responsible for sending this message. By default null. * @param string $status : Status of a the sms. By default \models\Sended::STATUS_UNKNOWN * * @return mixed : false on error, new sended id else */ - public function create(int $id_user, int $id_phone, $at, string $text, string $destination, string $uid, string $adapter, bool $flash = false, bool $mms = false, array $medias = [], ?int $originating_scheduled = null, ?string $status = \models\Sended::STATUS_UNKNOWN) + public function create(int $id_user, int $id_phone, $at, string $text, string $destination, string $uid, string $adapter, bool $flash = false, bool $mms = false, ?string $tag = null, array $medias = [], ?int $originating_scheduled = null, ?string $status = \models\Sended::STATUS_UNKNOWN) { $sended = [ 'id_user' => $id_user, @@ -62,6 +65,7 @@ namespace controllers\internals; 'adapter' => $adapter, 'flash' => $flash, 'mms' => $mms, + 'tag' => $tag, 'status' => $status, 'originating_scheduled' => $originating_scheduled, ]; @@ -184,13 +188,15 @@ namespace controllers\internals; * * @param int $id_user : User id * @param int $id_phone : Phone id we want the number of sended message for - * @param \DateTime $since : Date since which we want sended number + * @param ?\DateTime $since : Date since which we want sended number. Default to null. + * @param ?\DateTime $before : Date up to which we want sended number. Default to null. + * @param ?string $tag_like : Tag to filter sms by, this is not a = but a LIKE operator * * @return int */ - public function count_since_for_phone_and_user(int $id_user, int $id_phone, \DateTime $since): int + public function count_since_for_phone_and_user(int $id_user, int $id_phone, ?\DateTime $since, ?\DateTime $before = null, ?string $tag_like = null): int { - return $this->get_model()->count_since_for_phone_and_user($id_user, $id_phone, $since); + return $this->get_model()->count_since_for_phone_and_user($id_user, $id_phone, $since, $before, $tag_like); } /** @@ -236,6 +242,7 @@ namespace controllers\internals; * @param $text : Text of the message * @param string $destination : Number of the receiver * @param bool $flash : Is the sms a flash. By default false. + * @param ?string $tag : A string tag to associate to sended SMS * @param bool $mms : Is the sms a MMS. By default false. * @param array $medias : Array of medias to link to the MMS * @param string $status : Status of a the sms. By default \models\Sended::STATUS_UNKNOWN @@ -246,13 +253,16 @@ namespace controllers\internals; * ?string 'error_message' => null if success, error message else * ] */ - public function send(\adapters\AdapterInterface $adapter, int $id_user, int $id_phone, string $text, string $destination, bool $flash = false, bool $mms = false, array $medias = [], $originating_scheduled = null, string $status = \models\Sended::STATUS_UNKNOWN): array + public function send(\adapters\AdapterInterface $adapter, int $id_user, int $id_phone, string $text, string $destination, bool $flash = false, bool $mms = false, ?string $tag = null, array $medias = [], $originating_scheduled = null, string $status = \models\Sended::STATUS_UNKNOWN): array { $return = [ 'error' => false, 'error_message' => null, ]; + $internal_setting = new Setting(); + $user_settings = $internal_setting->gets_for_user($id_user); + $at = (new \DateTime())->format('Y-m-d H:i:s'); $media_uris = []; foreach ($medias as $media) @@ -275,71 +285,87 @@ namespace controllers\internals; $text .= "\n" . join(' - ', $media_urls); } - //If we reached our max quota, do not send the message - $internal_quota = new Quota($this->bdd); - $nb_credits = $internal_quota::compute_credits_for_message($text); //Calculate how much credit the message require - if (!$internal_quota->has_enough_credit($id_user, $nb_credits)) + try { - $return['error'] = true; - $return['error_message'] = 'Not enough credit to send message.'; - } + //If we reached our max quota, do not send the message + $internal_quota = new Quota($this->bdd); + $nb_credits = $internal_quota::compute_credits_for_message($text); //Calculate how much credit the message require + if (!$internal_quota->has_enough_credit($id_user, $nb_credits)) + { + throw new Exception('Not enough credit to send message.'); + } - //If we reached limit for this phone, do not send the message - $internal_phone = new Phone($this->bdd); - $internal_sended = new Sended($this->bdd); - $limits = $internal_phone->get_limits($id_phone); + // If this phone status indicate it is not available + $internal_phone = new Phone($this->bdd); + $phone = $internal_phone->get_for_user($id_user, $id_phone); + if (!$phone || $phone['status'] != \models\Phone::STATUS_AVAILABLE) + { + throw new Exception('Invalid phone status : ' . $phone['status']); + } - $remaining_volume = PHP_INT_MAX; - foreach ($limits as $limit) - { - $startpoint = new \DateTime($limit['startpoint']); - $consumed = $internal_sended->count_since_for_phone_and_user($id_user, $id_phone, $startpoint); - $remaining_volume = min(($limit['volume'] - $consumed), $remaining_volume); - } + //If we reached limit for this phone and phone limits are enabled, do not send the message + if ((int) ($user_settings['phone_limit'] ?? false)) + { + $limits = $internal_phone->get_limits($id_phone); - if ($remaining_volume < 1) - { - $return['error'] = true; - $return['error_message'] = 'Phone send limit have been reached.'; - } + $remaining_volume = PHP_INT_MAX; + foreach ($limits as $limit) + { + $startpoint = new \DateTime($limit['startpoint']); + $consumed = $this->count_since_for_phone_and_user($id_user, $id_phone, $startpoint); + $remaining_volume = min(($limit['volume'] - $consumed), $remaining_volume); + } + + if ($remaining_volume < 1) + { + throw new Exception('Phone send limit have been reached.'); + } + } - $uid = uniqid(); - if (!$return['error']) - { $response = $adapter->send($destination, $text, $flash, $mms, $media_uris); - $uid = $response['uid'] ?? $uid; if ($response['error']) { - $return['error'] = true; - $return['error_message'] = $response['error_message']; - } - else // If send with success, consume credit - { - $internal_quota->consume_credit($id_user, $nb_credits); + throw new Exception($response['error_message']); } + + $uid = $response['uid']; + $status = \models\Sended::STATUS_UNKNOWN; + + // If send with success, consume credit + $internal_quota->consume_credit($id_user, $nb_credits); } + catch (Exception $e) + { + $return['error'] = true; + $return['error_message'] = $e->getMessage(); - // If we fail to send or not, we will always save message as sended, only the status will change. - $status = $return['error'] ? \models\Sended::STATUS_FAILED : \models\Sended::STATUS_UNKNOWN; - $sended_id = $this->create($id_user, $id_phone, $at, $text, $destination, $uid, $adapter->meta_classname(), $flash, $mms, $medias, $originating_scheduled, $status); - - $webhook_body = [ - 'id' => $sended_id, - 'at' => $at, - 'status' => $status, - 'text' => $text, - 'destination' => $destination, - 'origin' => $id_phone, - 'mms' => $mms, - 'medias' => $medias, - 'originating_scheduled' => $originating_scheduled, - ]; + $status = \models\Sended::STATUS_FAILED; + + return $return; + } + finally + { + $uid = $uid ?? uniqid(); + $sended_id = $this->create($id_user, $id_phone, $at, $text, $destination, $uid, $adapter->meta_classname(), $flash, $mms, $tag, $medias, $originating_scheduled, $status); + + $webhook_body = [ + 'id' => $sended_id, + 'at' => $at, + 'status' => $status, + 'text' => $text, + 'destination' => $destination, + 'origin' => $id_phone, + 'mms' => $mms, + 'medias' => $medias, + 'originating_scheduled' => $originating_scheduled, + ]; - $internal_webhook = new Webhook($this->bdd); - $internal_webhook->trigger($id_user, \models\Webhook::TYPE_SEND_SMS, $webhook_body); + $internal_webhook = new Webhook($this->bdd); + $internal_webhook->trigger($id_user, \models\Webhook::TYPE_SEND_SMS, $webhook_body); - return $return; + return $return; + } } /** diff --git a/controllers/publics/Api.php b/controllers/publics/Api.php index 7ee0d36..c2e0636 100644 --- a/controllers/publics/Api.php +++ b/controllers/publics/Api.php @@ -49,6 +49,7 @@ namespace controllers\publics; private $internal_user; private $internal_phone; + private $internal_phone_group; private $internal_received; private $internal_sended; private $internal_scheduled; @@ -72,6 +73,7 @@ namespace controllers\publics; $bdd = \descartes\Model::_connect(DATABASE_HOST, DATABASE_NAME, DATABASE_USER, DATABASE_PASSWORD); $this->internal_user = new \controllers\internals\User($bdd); $this->internal_phone = new \controllers\internals\Phone($bdd); + $this->internal_phone_group = new \controllers\internals\PhoneGroup($bdd); $this->internal_received = new \controllers\internals\Received($bdd); $this->internal_sended = new \controllers\internals\Sended($bdd); $this->internal_scheduled = new \controllers\internals\Scheduled($bdd); @@ -118,14 +120,14 @@ namespace controllers\publics; /** * List all entries of a certain type for the current user, sorted by id. * - * @param string $entry_type : Type of entries we want to list ['sended', 'received', 'scheduled', 'contact', 'group', 'conditional_group', 'phone', 'media'] + * @param string $entry_type : Type of entries we want to list ['sended', 'received', 'scheduled', 'contact', 'group', 'conditional_group', 'phone', 'phone_group', 'media'] * @param int $page : Pagination number, Default = 0. Group of 25 results. * * @return : List of entries */ public function get_entries(string $entry_type, int $page = 0) { - $entry_types = ['sended', 'received', 'scheduled', 'contact', 'group', 'conditional_group', 'phone', 'media']; + $entry_types = ['sended', 'received', 'scheduled', 'contact', 'group', 'conditional_group', 'phone', 'phone_group', 'media']; if (!\in_array($entry_type, $entry_types, true)) { @@ -191,6 +193,26 @@ namespace controllers\publics; unset($entries[$key]['adapter_data']); } } + // Special case for phone group we must add phones because its a join + elseif ('phone_group' === $entry_type) + { + foreach ($entries as $key => $entry) + { + $phones = $this->internal_phone_group->get_phones($entry['id']); + // Hide meta data of phones if needed + foreach ($phones as &$phone) + { + if (!$phone['adapter']::meta_hide_data()) + { + continue; + } + + unset($phone['adapter_data']); + } + + $entries[$key]['phones'] = $phones; + } + } $return = self::DEFAULT_RETURN; $return['response'] = $entries; @@ -210,14 +232,84 @@ namespace controllers\publics; return $this->json($return); } + /** + * Return info about volume of sms sended for a period + * + * @param ?string $_POST['start'] : Date from which to get sms volume, format Y-m-d H:i:s. Default to null. + * @param ?string $_POST['end'] : Date up to which to get sms volume, format Y-m-d H:i:s. Default to null. + * @param ?string $_POST['tag'] : Tag to filter SMS by. If set, only sended sms with a matching tag will be counted. Default to null. + * + * @return : List of entries + */ + public function get_usage() + { + $start = $_GET['start'] ?? null; + $end = $_GET['end'] ?? null; + $tag = $_GET['tag'] ?? null; + + $return = self::DEFAULT_RETURN; + + if ($start) + { + if (!\controllers\internals\Tool::validate_date($start, 'Y-m-d H:i:s')) + { + $return = self::DEFAULT_RETURN; + $return['error'] = self::ERROR_CODES['INVALID_PARAMETER']; + $return['message'] = self::ERROR_MESSAGES['INVALID_PARAMETER'] . 'start must be a date of format "Y-m-d H:i:s".'; + $this->auto_http_code(false); + + return $this->json($return); + } + + $start = new \DateTime($start); + } + + if ($end) + { + if (!\controllers\internals\Tool::validate_date($end, 'Y-m-d H:i:s')) + { + $return = self::DEFAULT_RETURN; + $return['error'] = self::ERROR_CODES['INVALID_PARAMETER']; + $return['message'] = self::ERROR_MESSAGES['INVALID_PARAMETER'] . 'end must be a date of format "Y-m-d H:i:s".'; + $this->auto_http_code(false); + + return $this->json($return); + } + + $end = new \DateTime($end); + } + + $total_sended = 0; + $phones_volumes = []; + + $phones = $this->internal_phone->gets_for_user($this->user['id']); + foreach ($phones as $phone) + { + $nb_sended = $this->internal_sended->count_since_for_phone_and_user($this->user['id'], $phone['id'], $start, $end, $tag); + $total_sended += $nb_sended; + $phones_volumes[$phone['id']] = $nb_sended; + } + + $return['response'] = [ + 'total' => $total_sended, + 'phones_volumes' => $phones_volumes, + ]; + + $this->auto_http_code(true); + + return $this->json($return); + } + /** * Schedule a message to be send. * * @param string $_POST['at'] : Date to send message at format Y-m-d H:i:s * @param string $_POST['text'] : Text of the message to send - * @param string $_POST['id_phone'] : Default null. Id of phone to send the message from. If null use a random phone + * @param string $_POST['id_phone'] : Default null. Id of phone to send the message from. If null and id_phone_group null, use a random phone + * @param string $_POST['id_phone_group'] : Default null. Id of phone group to send the message from. If null abd id_phone null, use a random phone * @param string $_POST['flash'] : Default false. Is the sms a flash sms. * @param string $_POST['mms'] : Default false. Is the sms a mms. + * @param string $_POST['tag'] : Default null. Tag to associate to every sms of the campaign. * @param string $_POST['numbers'] : Array of numbers to send message to * @param string $_POST['contacts'] : Array of ids of contacts to send message to * @param string $_POST['groups'] : Array of ids of groups to send message to @@ -231,8 +323,10 @@ namespace controllers\publics; $at = $_POST['at'] ?? false; $text = $_POST['text'] ?? false; $id_phone = empty($_POST['id_phone']) ? null : $_POST['id_phone']; + $id_phone_group = empty($_POST['id_phone_group']) ? null : $_POST['id_phone_group']; $flash = (bool) ($_POST['flash'] ?? false); $mms = (bool) ($_POST['mms'] ?? false); + $tag = $_POST['tag'] ?? null; $numbers = $_POST['numbers'] ?? []; $contacts = $_POST['contacts'] ?? []; $groups = $_POST['groups'] ?? []; @@ -417,6 +511,16 @@ namespace controllers\publics; return $this->json($return); } + if ($id_phone && $id_phone_group) + { + $return = self::DEFAULT_RETURN; + $return['error'] = self::ERROR_CODES['INVALID_PARAMETER']; + $return['message'] = self::ERROR_MESSAGES['INVALID_PARAMETER'] . 'id_phone, id_phone_group : You must specify at most one of id_phone or id_phone_group, not both.'; + $this->auto_http_code(false); + + return $this->json($return); + } + $phone = null; if ($id_phone) { @@ -433,6 +537,22 @@ namespace controllers\publics; return $this->json($return); } + $phone_group = null; + if ($id_phone_group) + { + $phone_group = $this->internal_phone_group->get_for_user($this->user['id'], $id_phone_group); + } + + if ($id_phone_group && !$phone_group) + { + $return = self::DEFAULT_RETURN; + $return['error'] = self::ERROR_CODES['INVALID_PARAMETER']; + $return['message'] = self::ERROR_MESSAGES['INVALID_PARAMETER'] . 'id_phone_group : You must specify an id_phone_group number among thoses of user phone groups.'; + $this->auto_http_code(false); + + return $this->json($return); + } + if ($mms) { foreach ($files_arrays as $file) @@ -455,7 +575,7 @@ namespace controllers\publics; } } - $scheduled_id = $this->internal_scheduled->create($this->user['id'], $at, $text, $id_phone, $flash, $mms, $numbers, $contacts, $groups, $conditional_groups, $media_ids); + $scheduled_id = $this->internal_scheduled->create($this->user['id'], $at, $text, $id_phone, $id_phone_group, $flash, $mms, $tag, $numbers, $contacts, $groups, $conditional_groups, $media_ids); if (!$scheduled_id) { $return = self::DEFAULT_RETURN; @@ -710,7 +830,7 @@ namespace controllers\publics; $priority = $_POST['priority'] ?? $phone['priority']; $priority = max(((int) $priority), 0); $adapter = $_POST['adapter'] ?? $phone['adapter']; - $adapter_data = !empty($_POST['adapter_data']) ? $_POST['adapter_data'] : json_decode($phone['adapter_data']); + $adapter_data = !empty($_POST['adapter_data']) ? $_POST['adapter_data'] : json_decode($phone['adapter_data'], true); $adapter_data = is_array($adapter_data) ? $adapter_data : [$adapter_data]; $limits = $_POST['limits'] ?? $limits; $limits = is_array($limits) ? $limits : [$limits]; @@ -890,4 +1010,35 @@ namespace controllers\publics; return $this->json($return); } + + /** + * Trigger re-checking of a phone status + * + * @param int $id : Id of phone to re-check status + */ + public function post_update_phone_status ($id) + { + $return = self::DEFAULT_RETURN; + + $phone = $this->internal_phone->get_for_user($this->user['id'], $id); + if (!$phone) + { + $return['error'] = self::ERROR_CODES['CANNOT_UPDATE']; + $return['message'] = self::ERROR_MESSAGES['CANNOT_UPDATE']; + $this->auto_http_code(false); + + return $this->json($return); + } + + //Check adapter is working correctly with thoses names and data + $adapter_classname = $phone['adapter']; + $adapter_instance = new $adapter_classname($phone['adapter_data']); + $new_status = $adapter_instance->check_phone_status(); + + $status_update = $this->internal_phone->update_status($id, $new_status); + $return['response'] = $new_status; + $this->auto_http_code(true); + + return $this->json($return); + } } diff --git a/controllers/publics/Discussion.php b/controllers/publics/Discussion.php index 7729908..77e6829 100644 --- a/controllers/publics/Discussion.php +++ b/controllers/publics/Discussion.php @@ -234,6 +234,7 @@ namespace controllers\publics; $at = $now; $text = $_POST['text'] ?? ''; $destination = $_POST['destination'] ?? false; + $tag = $_POST['tag'] ?? null; $id_phone = $_POST['id_phone'] ?? false; $files = $_FILES['medias'] ?? false; @@ -315,7 +316,7 @@ namespace controllers\publics; //Destinations must be an array of number $destinations = [['number' => $destination, 'data' => '[]']]; - if (!$this->internal_scheduled->create($id_user, $at, $text, $id_phone, false, $mms, $destinations, [], [], [], $media_ids)) + if (!$this->internal_scheduled->create($id_user, $at, $text, $id_phone, null, false, $mms, $tag, $destinations, [], [], [], $media_ids)) { $return['success'] = false; $return['message'] = 'Impossible de créer le Sms'; diff --git a/controllers/publics/Phone.php b/controllers/publics/Phone.php index 7451288..3ce81e0 100644 --- a/controllers/publics/Phone.php +++ b/controllers/publics/Phone.php @@ -88,6 +88,11 @@ class Phone extends \descartes\Controller { $phone['callback_end_call'] = \descartes\Router::url('Callback', 'end_call', ['id_phone' => $phone['id']], ['api_key' => $api_key]); } + + if ($adapter['meta_support_phone_status']) + { + $phone['support_phone_status'] = true; + } } header('Content-Type: application/json'); @@ -425,7 +430,14 @@ class Phone extends \descartes\Controller continue; } - if ($find_adapter['meta_hidden']) + $current_phone = $this->internal_phone->get_for_user($id_user, $id_phone); + if (!$current_phone) + { + continue; + } + + // We can only use an hidden adapter if it was already the adapter we was using + if ($find_adapter['meta_hidden'] && $adapter != $current_phone['adapter']) { continue; } @@ -499,4 +511,53 @@ class Phone extends \descartes\Controller return $this->redirect(\descartes\Router::url('Phone', 'list')); } + + + /** + * Re-check phone status + * @param array int $_GET['ids'] : ids of phones we want to update status + * @param $csrf : CSRF token + */ + public function update_status ($csrf) + { + if (!$this->verify_csrf($csrf)) + { + \FlashMessage\FlashMessage::push('danger', 'Jeton CSRF invalid !'); + + return $this->redirect(\descartes\Router::url('Phone', 'add')); + } + + $ids = $_GET['ids'] ?? []; + $id_user = $_SESSION['user']['id']; + + foreach ($ids as $id) + { + $phone = $this->internal_phone->get_for_user($id_user, $id); + + //Check adapter is working correctly with thoses names and data + $adapter_classname = $phone['adapter']; + if (!call_user_func([$adapter_classname, 'meta_support_phone_status'])) + { + continue; + } + + $adapter_instance = new $adapter_classname($phone['adapter_data']); + $new_status = $adapter_instance->check_phone_status(); + + $status_update = $this->internal_phone->update_status($id, $new_status); + } + + \FlashMessage\FlashMessage::push('success', 'Les status des téléphones ont bien été mis à jour.'); + + return $this->redirect(\descartes\Router::url('Phone', 'list')); + } + + /** + * Return a list of phones as a JSON array + */ + public function json_list() + { + header('Content-Type: application/json'); + echo json_encode($this->internal_phone->list_for_user($_SESSION['user']['id'])); + } } diff --git a/controllers/publics/PhoneGroup.php b/controllers/publics/PhoneGroup.php new file mode 100644 index 0000000..57d6fb7 --- /dev/null +++ b/controllers/publics/PhoneGroup.php @@ -0,0 +1,245 @@ + + * + * This source file is subject to the GPL-3.0 license that is bundled + * with this source code in the file LICENSE. + */ + +namespace controllers\publics; + + /** + * Page of phone groups. + */ + class PhoneGroup extends \descartes\Controller + { + private $internal_phone_group; + private $internal_phone; + private $internal_event; + + /** + * Call before any other func to check user is connected + * + * @return void; + */ + public function __construct() + { + $bdd = \descartes\Model::_connect(DATABASE_HOST, DATABASE_NAME, DATABASE_USER, DATABASE_PASSWORD); + + $this->internal_phone_group = new \controllers\internals\PhoneGroup($bdd); + $this->internal_phone = new \controllers\internals\Phone($bdd); + $this->internal_event = new \controllers\internals\Event($bdd); + + \controllers\internals\Tool::verifyconnect(); + } + + /** + * Return all groups as an array for administration. + */ + public function list() + { + $this->render('phone_group/list'); + } + + /** + * Return groups as json. + */ + public function list_json() + { + $entities = $this->internal_phone_group->list_for_user($_SESSION['user']['id']); + header('Content-Type: application/json'); + echo json_encode(['data' => $entities]); + } + + /** + * Delete a list of phone groups + * + * @param array int $_GET['ids'] : Ids of phone groups to delete + * @param mixed $csrf + * + * @return boolean; + */ + public function delete($csrf) + { + if (!$this->verify_csrf($csrf)) + { + \FlashMessage\FlashMessage::push('danger', 'Jeton CSRF invalid !'); + + return $this->redirect(\descartes\Router::url('PhoneGroup', 'list')); + } + + $ids = $_GET['ids'] ?? []; + foreach ($ids as $id) + { + $this->internal_phone_group->delete_for_user($_SESSION['user']['id'], $id); + } + + return $this->redirect(\descartes\Router::url('PhoneGroup', 'list')); + } + + /** + * Return the creation page of a group + */ + public function add() + { + $this->render('phone_group/add'); + } + + /** + * Return the edition page for phone groups + * + * @param array $_GET['ids'] : Ids of phone groups to edit + */ + public function edit() + { + $ids = $_GET['ids'] ?? []; + + $groups = $this->internal_phone_group->gets_in_for_user($_SESSION['user']['id'], $ids); + + foreach ($groups as $key => $group) + { + $groups[$key]['phones'] = $this->internal_phone_group->get_phones($group['id']); + } + + $this->render('phone_group/edit', [ + 'phone_groups' => $groups, + ]); + } + + /** + * Create a new phone group + * + * @param $csrf : CSRF token + * @param string $_POST['name'] : Name of phone group + * @param array $_POST['phones'] : Ids of phones to put in the group + */ + public function create($csrf) + { + if (!$this->verify_csrf($csrf)) + { + \FlashMessage\FlashMessage::push('danger', 'Jeton CSRF invalid !'); + + return $this->redirect(\descartes\Router::url('PhoneGroup', 'add')); + } + + $name = $_POST['name'] ?? false; + $phones_ids = $_POST['phones'] ?? false; + + if (!$name || !$phones_ids) + { + \FlashMessage\FlashMessage::push('danger', 'Des champs sont manquants !'); + + return $this->redirect(\descartes\Router::url('PhoneGroup', 'add')); + } + + $id_group = $this->internal_phone_group->create($_SESSION['user']['id'], $name, $phones_ids); + if (!$id_group) + { + \FlashMessage\FlashMessage::push('danger', 'Impossible de créer ce groupe.'); + + return $this->redirect(\descartes\Router::url('PhoneGroup', 'add')); + } + + \FlashMessage\FlashMessage::push('success', 'Le groupe a bien été créé.'); + + return $this->redirect(\descartes\Router::url('PhoneGroup', 'list')); + } + + /** + * Update a list of phone groups + * + * @param $csrf : CSRF token + * @param array $_POST['phone_groups'] : An array of phone groups with group id as keys + * + * @return boolean; + */ + public function update($csrf) + { + if (!$this->verify_csrf($csrf)) + { + \FlashMessage\FlashMessage::push('danger', 'Jeton CSRF invalid !'); + + return $this->redirect(\descartes\Router::url('PhoneGroup', 'list')); + } + + $groups = $_POST['phone_groups'] ?? []; + + $nb_groups_update = 0; + foreach ($groups as $id => $group) + { + foreach ($group['phones_ids'] as $key => $value) + { + $group['phones_ids'][$key] = (int) $value; + } + + $nb_groups_update += (int) $this->internal_phone_group->update_for_user($_SESSION['user']['id'], $id, $group['name'], $group['phones_ids']); + } + + if ($nb_groups_update !== \count($groups)) + { + \FlashMessage\FlashMessage::push('danger', 'Certains groupes n\'ont pas pu êtres mis à jour.'); + + return $this->redirect(\descartes\Router::url('PhoneGroup', 'list')); + } + + \FlashMessage\FlashMessage::push('success', 'Tous les groupes ont été modifiés avec succès.'); + + return $this->redirect(\descartes\Router::url('PhoneGroup', 'list')); + } + + /** + * Return phones of a group as json array + * @param int $id_group = PhoneGroup id + * + * @return json + */ + public function preview (int $id_group) + { + $return = [ + 'success' => false, + 'result' => 'Une erreur inconnue est survenue.', + ]; + + $group = $this->internal_phone_group->get_for_user($_SESSION['user']['id'], $id_group); + + if (!$group) + { + $return['result'] = 'Ce groupe n\'existe pas.'; + echo json_encode($return); + + return false; + } + + $phones = $this->internal_phone_group->get_phones($id_group); + if (!$phones) + { + $return['result'] = 'Aucun téléphone dans le groupe.'; + echo json_encode($return); + + return false; + } + + foreach ($phones as &$phone) + { + $phone['adapter_name'] = call_user_func([$phone['adapter'], 'meta_name']); + } + + $return['success'] = true; + $return['result'] = $phones; + echo json_encode($return); + + return true; + } + + /** + * Cette fonction retourne la liste des groups sous forme JSON. + */ + public function json_list() + { + header('Content-Type: application/json'); + echo json_encode($this->internal_phone_group->list_for_user($_SESSION['user']['id'])); + } + } diff --git a/controllers/publics/Scheduled.php b/controllers/publics/Scheduled.php index 2c6e0e3..eb2decb 100644 --- a/controllers/publics/Scheduled.php +++ b/controllers/publics/Scheduled.php @@ -18,6 +18,7 @@ namespace controllers\publics; { private $internal_scheduled; private $internal_phone; + private $internal_phone_group; private $internal_contact; private $internal_group; private $internal_conditional_group; @@ -34,6 +35,7 @@ namespace controllers\publics; $bdd = \descartes\Model::_connect(DATABASE_HOST, DATABASE_NAME, DATABASE_USER, DATABASE_PASSWORD); $this->internal_scheduled = new \controllers\internals\Scheduled($bdd); $this->internal_phone = new \controllers\internals\Phone($bdd); + $this->internal_phone_group = new \controllers\internals\PhoneGroup($bdd); $this->internal_contact = new \controllers\internals\Contact($bdd); $this->internal_group = new \controllers\internals\Group($bdd); $this->internal_conditional_group = new \controllers\internals\ConditionalGroup($bdd); @@ -118,6 +120,7 @@ namespace controllers\publics; $contacts = $this->internal_contact->gets_for_user($id_user); $phones = $this->internal_phone->gets_for_user($id_user); + $phone_groups = $this->internal_phone_group->gets_for_user($id_user); $contact_ids = (isset($_GET['contact_ids']) && \is_array($_GET['contact_ids'])) ? $_GET['contact_ids'] : []; $group_ids = (isset($_GET['group_ids']) && \is_array($_GET['group_ids'])) ? $_GET['group_ids'] : []; @@ -153,6 +156,7 @@ namespace controllers\publics; 'now' => $now->format('Y-m-d H:i'), 'contacts' => $contacts, 'phones' => $phones, + 'phone_groups' => $phone_groups, 'prefilled_contacts' => $prefilled_contacts, 'prefilled_groups' => $prefilled_groups, 'prefilled_conditional_groups' => $prefilled_conditional_groups, @@ -179,6 +183,7 @@ namespace controllers\publics; $all_contacts = $this->internal_contact->gets_for_user($_SESSION['user']['id']); $phones = $this->internal_phone->gets_for_user($_SESSION['user']['id']); + $phone_groups = $this->internal_phone_group->gets_for_user($id_user); $scheduleds = $this->internal_scheduled->gets_in_for_user($_SESSION['user']['id'], $ids); //Pour chaque message on ajoute les numéros, les contacts & les groups @@ -226,6 +231,7 @@ namespace controllers\publics; $this->render('scheduled/edit', [ 'scheduleds' => $scheduleds, 'phones' => $phones, + 'phone_groups' => $phone_groups, 'contacts' => $all_contacts, ]); } @@ -238,7 +244,7 @@ namespace controllers\publics; * @param string $_POST['at'] : Date to send message for * @param string $_POST['text'] : Text of the message * @param ?bool $_POST['flash'] : Is the message a flash message (by default false) - * @param ?int $_POST['id_phone'] : Id of the phone to send message from, if null use random phone + * @param ?int $_POST['id_phone'] : Id of the phone or phone group to send message from. id will be preceed by phone_ of phonegroup_ depending on type of ressource to use, if null use random phone * @param ?array $_POST['numbers'] : Numbers to send the message to * @param ?array $_POST['contacts'] : Numbers to send the message to * @param ?array $_POST['groups'] : Numbers to send the message to @@ -258,6 +264,7 @@ namespace controllers\publics; $at = $_POST['at'] ?? false; $text = $_POST['text'] ?? false; $flash = (bool) ($_POST['flash'] ?? false); + $tag = ($_POST['tag'] ?? null) ?: null; $id_phone = empty($_POST['id_phone']) ? null : $_POST['id_phone']; $numbers = $_POST['numbers'] ?? []; $numbers = is_array($numbers) ? $numbers : [$numbers]; @@ -433,7 +440,12 @@ namespace controllers\publics; $mms = (bool) count($media_ids); - $scheduled_id = $this->internal_scheduled->create($id_user, $at, $text, $id_phone, $flash, $mms, $numbers, $contacts, $groups, $conditional_groups, $media_ids); + // Check if we must send message to a phone or a phone_group based on if id_phone start with 'phone_' or 'phonegroup_' + $original_id_phone = $id_phone; + $id_phone = str_starts_with($original_id_phone, 'phone_') ? mb_substr($original_id_phone, mb_strlen('phone_')) : null; + $id_phone_group = str_starts_with($original_id_phone, 'phonegroup_') ? mb_substr($original_id_phone, mb_strlen('phonegroup_')) : null; + + $scheduled_id = $this->internal_scheduled->create($id_user, $at, $text, $id_phone, $id_phone_group, $flash, $mms, $tag, $numbers, $contacts, $groups, $conditional_groups, $media_ids); if (!$scheduled_id) { \FlashMessage\FlashMessage::push('danger', 'Impossible de créer le Sms.'); @@ -473,6 +485,7 @@ namespace controllers\publics; $text = $scheduled['text'] ?? false; $id_phone = empty($scheduled['id_phone']) ? null : $scheduled['id_phone']; $flash = (bool) ($scheduled['flash'] ?? false); + $tag = ($scheduled['tag'] ?? null) ?: null; $numbers = $scheduled['numbers'] ?? []; $contacts = $scheduled['contacts'] ?? []; $groups = $scheduled['groups'] ?? []; @@ -650,7 +663,11 @@ namespace controllers\publics; $mms = (bool) count($media_ids); - $this->internal_scheduled->update_for_user($id_user, $id_scheduled, $at, $text, $id_phone, $flash, $mms, $numbers, $contacts, $groups, $conditional_groups, $media_ids); + $original_id_phone = $id_phone; + $id_phone = str_starts_with($original_id_phone, 'phone_') ? mb_substr($original_id_phone, mb_strlen('phone_')) : null; + $id_phone_group = str_starts_with($original_id_phone, 'phonegroup_') ? mb_substr($original_id_phone, mb_strlen('phonegroup_')) : null; + + $this->internal_scheduled->update_for_user($id_user, $id_scheduled, $at, $text, $id_phone, $id_phone_group, $flash, $mms, $tag, $numbers, $contacts, $groups, $conditional_groups, $media_ids); ++$nb_update; } diff --git a/controllers/publics/Sended.php b/controllers/publics/Sended.php index d82bed6..7761352 100644 --- a/controllers/publics/Sended.php +++ b/controllers/publics/Sended.php @@ -59,8 +59,9 @@ namespace controllers\publics; 0 => 'phone_name', 1 => 'searchable_destination', 2 => 'text', - 3 => 'at', - 4 => 'status', + 3 => 'tag', + 4 => 'at', + 5 => 'status', ]; $search = $_GET['search']['value'] ?? null; diff --git a/daemons/Phone.php b/daemons/Phone.php index 585ce20..1348a9e 100644 --- a/daemons/Phone.php +++ b/daemons/Phone.php @@ -144,7 +144,7 @@ class Phone extends AbstractDaemon //Do message sending $this->logger->info('Try send message : ' . json_encode($message)); - $response = $internal_sended->send($this->adapter, $this->phone['id_user'], $this->phone['id'], $message['text'], $message['destination'], $message['flash'], $message['mms'], $message['medias'], $message['id_scheduled']); + $response = $internal_sended->send($this->adapter, $this->phone['id_user'], $this->phone['id'], $message['text'], $message['destination'], $message['flash'], $message['mms'], $message['tag'], $message['medias'], $message['id_scheduled']); if ($response['error']) { $this->logger->error('Failed send message : ' . json_encode($message) . ' with error : ' . $response['error_message']); diff --git a/daemons/Sender.php b/daemons/Sender.php index d462739..9acb00a 100644 --- a/daemons/Sender.php +++ b/daemons/Sender.php @@ -80,6 +80,7 @@ class Sender extends AbstractDaemon 'destination' => $sms['destination'], 'flash' => $sms['flash'], 'mms' => $sms['mms'], + 'tag' => $sms['tag'], 'medias' => $sms['medias'] ?? [], ]; diff --git a/db/migrations/20230218113648_add_status_phone.php b/db/migrations/20230218113648_add_status_phone.php new file mode 100644 index 0000000..97c397e --- /dev/null +++ b/db/migrations/20230218113648_add_status_phone.php @@ -0,0 +1,38 @@ +table('phone'); + $table->addColumn('status', 'enum', ['values' => ['available', 'unavailable', 'no_credit'], 'default' => 'available']); + $table->update(); + } +} diff --git a/db/migrations/20230219014653_create_phone_group.php b/db/migrations/20230219014653_create_phone_group.php new file mode 100644 index 0000000..d8e3b4b --- /dev/null +++ b/db/migrations/20230219014653_create_phone_group.php @@ -0,0 +1,52 @@ +table('phone_group') + ->addColumn('id_user', 'integer', ['null' => false]) + ->addColumn('name', 'string', ['null' => false, 'limit' => 100]) + ->addColumn('created_at', 'timestamp', ['null' => false, 'default' => 'CURRENT_TIMESTAMP']) + ->addColumn('updated_at', 'timestamp', ['null' => true, 'update' => 'CURRENT_TIMESTAMP']) + ->addForeignKey('id_user', 'user', 'id', ['delete' => 'CASCADE', 'update' => 'CASCADE']) + ->create(); + + $this->table('phone_group_phone') + ->addColumn('id_phone_group', 'integer', ['null' => false]) + ->addColumn('id_phone', 'integer', ['null' => false]) + ->addColumn('created_at', 'timestamp', ['null' => false, 'default' => 'CURRENT_TIMESTAMP']) + ->addColumn('updated_at', 'timestamp', ['null' => true, 'update' => 'CURRENT_TIMESTAMP']) + ->addForeignKey('id_phone_group', 'phone_group', 'id', ['delete' => 'CASCADE', 'update' => 'CASCADE']) + ->addForeignKey('id_phone', 'phone', 'id', ['delete' => 'CASCADE', 'update' => 'CASCADE']) + ->create(); + } +} diff --git a/db/migrations/20230219102411_add_id_phone_group_to_scheduled.php b/db/migrations/20230219102411_add_id_phone_group_to_scheduled.php new file mode 100644 index 0000000..ee12008 --- /dev/null +++ b/db/migrations/20230219102411_add_id_phone_group_to_scheduled.php @@ -0,0 +1,39 @@ +table('scheduled') + ->addColumn('id_phone_group', 'integer', ['null' => true, 'default' => null, 'after' => 'id_phone']) + ->addForeignKey('id_phone_group', 'phone_group', 'id', ['delete' => 'CASCADE', 'update' => 'CASCADE']) + ->update(); + } +} diff --git a/db/migrations/20230224133515_add_scheduled_tag.php b/db/migrations/20230224133515_add_scheduled_tag.php new file mode 100644 index 0000000..2ca4e08 --- /dev/null +++ b/db/migrations/20230224133515_add_scheduled_tag.php @@ -0,0 +1,42 @@ +table('scheduled'); + $table->addColumn('tag', 'string', ['default' => NULL, 'null' => true, 'limit' => 1000]) + ->update(); + + $table = $this->table('sended'); + $table->addColumn('tag', 'string', ['default' => NULL, 'null' => true, 'limit' => 255]) + ->update(); + } +} diff --git a/descartes/Model.php b/descartes/Model.php index ad14075..0580cde 100644 --- a/descartes/Model.php +++ b/descartes/Model.php @@ -144,7 +144,7 @@ /** * Generate IN query params and values - * @param string $values : Values to generate in array from + * @param array $values : Values to generate in array from * @return array : Array ['QUERY' => string 'IN(...)', 'PARAMS' => [parameters to pass to execute]] */ protected function _generate_in_from_array ($values) @@ -214,6 +214,11 @@ $operator = '>'; break; + case ('%' == $first_char) : + $true_fieldname = mb_substr($fieldname, 1); + $operator = 'LIKE'; + break; + case ('=' == $first_char) : $true_fieldname = mb_substr($fieldname, 1); $operator = '='; @@ -227,8 +232,11 @@ //Protect against injection in fieldname $true_fieldname = preg_replace('#[^a-zA-Z0-9_]#', '', $true_fieldname); - $query = '`' . $true_fieldname . '` ' . $operator . ' :where_' . $true_fieldname; - $param = ['where_' . $true_fieldname => $value]; + // Add a uid to fieldname so we can combine multiple rules on same field + $uid = uniqid(); + + $query = '`' . $true_fieldname . '` ' . $operator . ' :where_' . $true_fieldname . '_' . $uid; + $param = ['where_' . $true_fieldname . '_' . $uid => $value]; return ['QUERY' => $query, 'PARAM' => $param]; } @@ -358,7 +366,6 @@ } $query = "SELECT COUNT(*) as `count` FROM `" . $table . "` WHERE 1 " . (count($wheres) ? 'AND ' : '') . implode(' AND ', $wheres); - $query = $this->pdo->prepare($query); foreach ($params as $label => &$param) diff --git a/env.php.dist b/env.php.dist index c544ba0..2c13aab 100644 --- a/env.php.dist +++ b/env.php.dist @@ -83,6 +83,8 @@ 'alert_quota_limit_close' => 0.9, 'hide_menus' => '', 'force_gsm_alphabet' => 0, + 'phone_limit' => 0, + 'phone_priority' => 0, ], ]; diff --git a/models/Phone.php b/models/Phone.php index 4579b22..41fde4d 100644 --- a/models/Phone.php +++ b/models/Phone.php @@ -14,6 +14,10 @@ namespace models; class Phone extends StandardModel { + const STATUS_AVAILABLE = 'available'; + const STATUS_UNAVAILABLE = 'unavailable'; + const STATUS_NO_CREDIT = 'no_credit'; + /** * Return all phones that belongs to active users * diff --git a/models/PhoneGroup.php b/models/PhoneGroup.php new file mode 100644 index 0000000..0a71a24 --- /dev/null +++ b/models/PhoneGroup.php @@ -0,0 +1,123 @@ + + * + * This source file is subject to the GPL-3.0 license that is bundled + * with this source code in the file LICENSE. + */ + +namespace models; + + class PhoneGroup extends StandardModel + { + /** + * Return a list of phone groups for a user. + * Add a column nb_phone. + * + * @param int $id_user : user id + * @param ?int $limit : Number of entry to return or null + * @param ?int $offset : Number of entry to ignore or null + * + * @return array + */ + public function list_for_user(int $id_user, $limit, $offset) + { + $query = ' + SELECT pg.*, COUNT(pgp.id) as nb_phone + FROM `phone_group` as pg + LEFT JOIN phone_group_phone as pgp + ON pg.id = pgp.id_phone_group + WHERE pg.id_user = :id_user + GROUP BY pg.id + '; + + if (null !== $limit) + { + $limit = (int) $limit; + + $query .= ' LIMIT ' . $limit; + if (null !== $offset) + { + $offset = (int) $offset; + $query .= ' OFFSET ' . $offset; + } + } + + $params = [ + 'id_user' => $id_user, + ]; + + return $this->_run_query($query, $params); + } + + /** + * Return a phone group by his name for a user. + * + * @param int $id_user : User id + * @param string $name : Group name + * + * @return array + */ + public function get_by_name_for_user(int $id_user, string $name) + { + return $this->_select_one($this->get_table_name(), ['id_user' => $id_user, 'name' => $name]); + } + + /** + * Delete relations between phone group and phone for a group. + * + * @param int $id_phone_group : Group id + * + * @return int : Number of deleted rows + */ + public function delete_phone_group_phone_relations(int $id_phone_group) + { + return $this->_delete('phone_group_phone', ['id_phone_group' => $id_phone_group]); + } + + /** + * Insert a relation between a phone group and a phone. + * + * @param int $id_phone_group : Phone Group id + * @param int $id_phone : Phone id + * + * @return mixed (bool|int) : False on error, new row id else + */ + public function insert_phone_group_phone_relation(int $id_phone_group, int $id_phone) + { + $success = (bool) $this->_insert('phone_group_phone', ['id_phone_group' => $id_phone_group, 'id_phone' => $id_phone]); + + return $success ? $this->_last_id() : false; + } + + /** + * Get phone groups phones. + * + * @param int $id_phone_group : Phone Group id + * + * @return array : Phones of the group + */ + public function get_phones(int $id_phone_group) + { + $query = ' + SELECT * + FROM `phone` + WHERE id IN (SELECT id_phone FROM `phone_group_phone` WHERE id_phone_group = :id_phone_group) + '; + + $params = ['id_phone_group' => $id_phone_group]; + + return $this->_run_query($query, $params); + } + + /** + * Return table name. + */ + protected function get_table_name(): string + { + return 'phone_group'; + } + } diff --git a/models/Sended.php b/models/Sended.php index 0acdb20..3644dee 100644 --- a/models/Sended.php +++ b/models/Sended.php @@ -183,13 +183,35 @@ namespace models; * * @param int $id_user : User id * @param int $id_phone : Phone id we want the number of sended message for - * @param \DateTime $since : Date since which we want sended number + * @param ?\DateTime $since : Date since which we want sended Number. Default to null. + * @param ?\DateTime $before : Date up to which we want sended number. Default to null. + * @param ?string $tag_like : Tag to filter sms by, this is not a = but a LIKE operator * * @return int */ - public function count_since_for_phone_and_user(int $id_user, int $id_phone, \DateTime $since) : int + public function count_since_for_phone_and_user(int $id_user, int $id_phone, ?\DateTime $since = null, ?\DateTime $before = null, ?string $tag_like = null) : int { - return $this->_count('sended', ['id_user' => $id_user, 'id_phone' => $id_phone, '>=at' => $since->format('c')]); + $data = [ + 'id_user' => $id_user, + 'id_phone' => $id_phone, + ]; + + if ($since) + { + $data['>=at'] = $since->format('c'); + } + + if ($before) + { + $data['<=at'] = $before->format('c'); + } + + if ($tag_like) + { + $data['%tag'] = $tag_like; + } + + return $this->_count('sended', $data); } /** diff --git a/routes.php b/routes.php index a5e87cd..ccb7279 100644 --- a/routes.php +++ b/routes.php @@ -164,6 +164,20 @@ 'delete' => '/phone/delete/{csrf}/', 'edit' => '/phone/edit/', 'update' => '/phone/update/{csrf}/', + 'update_status' => '/phone/update_status/{csrf}/', + 'json_list' => '/phones.json/', + ], + + 'PhoneGroup' => [ + 'list' => '/phone_group/', + 'list_json' => '/phone_group/json/', + 'add' => '/phone_group/add/', + 'create' => '/phone_group/create/{csrf}/', + 'delete' => '/phone_group/delete/{csrf}/', + 'edit' => '/phone_group/edit/', + 'update' => '/phone_group/update/{csrf}/', + 'preview' => '/phone_group/preview/{id_group}/', + 'json_list' => '/phone_group.json/', ], 'Call' => [ @@ -194,6 +208,7 @@ '/api/list/{entry_type}/', '/api/list/{entry_type}/{page}/', ], + 'get_usage' => '/api/usage/', 'post_scheduled' => [ '/api/scheduled/', ], @@ -206,6 +221,9 @@ 'post_update_phone' => [ '/api/phone/{id}/', ], + 'post_update_phone_status' => [ + '/api/phone/{id}/status/', + ], 'delete_phone' => [ '/api/phone/{id}/', ], diff --git a/templates/group/list.php b/templates/group/list.php index 5da0452..2b7728c 100644 --- a/templates/group/list.php +++ b/templates/group/list.php @@ -111,7 +111,7 @@ jQuery(document).ready(function () { data: '_', render: function (data, type, row, meta) { - return ''; + return ''; }, }, { @@ -145,7 +145,6 @@ jQuery(document).ready(function () html += '
' + jQuery.fn.dataTable.render.text().display(contact.number) + '
' html += ' ' + jQuery.fn.dataTable.render.text().display(contact.data) + '' html += ''; - console.log(contact); } jQuery('#preview-text-modal').find('.modal-body').html(html); diff --git a/templates/incs/nav.php b/templates/incs/nav.php index 91e2340..b232d1b 100644 --- a/templates/incs/nav.php +++ b/templates/incs/nav.php @@ -110,8 +110,16 @@ -
  • > - Téléphones +
  • + Téléphones +
  • diff --git a/templates/phone/add.php b/templates/phone/add.php index ab2e143..b7fb0ee 100644 --- a/templates/phone/add.php +++ b/templates/phone/add.php @@ -44,18 +44,22 @@ Le nom du téléphone qui enverra et recevra les messages.

    - -
    - -
    - -

    - Lors de l'envoi de SMS sans téléphone spécifié, les téléphones avec la plus haute priorité seront utilisés en premier. -

    -
    - +
    + + +
    + +

    + Lors de l'envoi de SMS sans téléphone spécifié, les téléphones avec la plus haute priorité seront utilisés en premier. +

    +
    + +
    +
    + +

    @@ -87,15 +91,19 @@

    -
    - -

    - Défini le nombre maximum de SMS qui pourront être envoyés avec ce téléphone sur des périodes de temps données. -

    -
    -
    + + +
    + +

    + Défini le nombre maximum de SMS qui pourront être envoyés avec ce téléphone sur des périodes de temps données. +

    +
    +
    +
    -
    + + Annuler diff --git a/templates/phone/edit.php b/templates/phone/edit.php index a1b2446..835fdf7 100644 --- a/templates/phone/edit.php +++ b/templates/phone/edit.php @@ -40,6 +40,7 @@
    +

    @@ -49,15 +50,19 @@

    -
    - -

    - Lors de l'envoi de SMS sans téléphone spécifié, les téléphones avec la plus haute priorité seront utilisés en premier. -

    + +
    - + +

    + Lors de l'envoi de SMS sans téléphone spécifié, les téléphones avec la plus haute priorité seront utilisés en premier. +

    +
    + +
    -
    + +

    @@ -65,13 +70,15 @@

    - - - - - - - - - - - - - -
    -
    - -
    - + + +
    + +

    + Défini le nombre maximum de SMS qui pourront être envoyés avec ce téléphone sur des périodes de temps données. +

    +
    + +
    +
    +
    + +
    +
    + +
    + +
    +
    +
    - -
    - -
    + +
    +
    -
    + +

    diff --git a/templates/phone/list.php b/templates/phone/list.php index 59a701c..d0b192d 100644 --- a/templates/phone/list.php +++ b/templates/phone/list.php @@ -41,10 +41,14 @@ ID Nom - Priorité + + Priorité + Type de téléphone Callbacks - Limites + + Limites + @@ -58,6 +62,7 @@
    Action pour la séléction : +
    @@ -90,8 +95,31 @@ jQuery(document).ready(function () }, "columns" : [ {data: 'id', render: jQuery.fn.dataTable.render.text()}, - {data: 'name', render: jQuery.fn.dataTable.render.text()}, - {data: 'priority', render: jQuery.fn.dataTable.render.text()}, + { + data: 'name', + render: function (data, type, row, meta) { + html = jQuery.fn.dataTable.render.text().display(data) + switch (row.status) + { + case 'available': + html += ' - Disponible' + break; + + case 'unavailable': + html += ' - Indisponible' + break; + + case 'no_credit': + html += ' - Plus de crédit' + break; + } + + return html + }, + }, + + {data: 'priority', render: jQuery.fn.dataTable.render.text()}, + {data: 'adapter', render: jQuery.fn.dataTable.render.text()}, { data: '_', @@ -127,61 +155,63 @@ jQuery(document).ready(function () return html; }, }, - { - data: 'limits', - render: function (limits) { - if (!limits.length) - { - return 'Pas de limites.'; - } - - var html = ''; - for (limit of limits) - { - switch (limit.startpoint) + + { + data: 'limits', + render: function (limits) { + if (!limits.length) { - case "today" : - var startpoint = 'Par jour'; - break; - case "-24 hours" : - var startpoint = '24 heures glissantes'; - break; - case "this week midnight" : - var startpoint = 'Cette semaine'; - break; - case "-7 days" : - var startpoint = '7 jours glissants'; - break; - case "this week midnight -1 week" : - var startpoint = 'Ces deux dernières semaines'; - break; - case "-14 days" : - var startpoint = '14 jours glissants'; - break; - case "this month midnight" : - var startpoint = 'Ce mois'; - break; - case "-1 month" : - var startpoint = '1 mois glissant'; - break; - case "-28 days" : - var startpoint = '28 jours glissants'; - break; - case "-30 days" : - var startpoint = '30 jours glissants'; - break; - case "-31 days" : - var startpoint = '31 jours glissants'; - break; - default : - var startpoint = 'Inconnu' + return 'Pas de limites.'; } - html += '
    ' + jQuery.fn.dataTable.render.text().display(startpoint) + ' : ' + jQuery.fn.dataTable.render.text().display(limit.volume) + '
    '; - } - return html; + var html = ''; + for (limit of limits) + { + switch (limit.startpoint) + { + case "today" : + var startpoint = 'Par jour'; + break; + case "-24 hours" : + var startpoint = '24 heures glissantes'; + break; + case "this week midnight" : + var startpoint = 'Cette semaine'; + break; + case "-7 days" : + var startpoint = '7 jours glissants'; + break; + case "this week midnight -1 week" : + var startpoint = 'Ces deux dernières semaines'; + break; + case "-14 days" : + var startpoint = '14 jours glissants'; + break; + case "this month midnight" : + var startpoint = 'Ce mois'; + break; + case "-1 month" : + var startpoint = '1 mois glissant'; + break; + case "-28 days" : + var startpoint = '28 jours glissants'; + break; + case "-30 days" : + var startpoint = '30 jours glissants'; + break; + case "-31 days" : + var startpoint = '31 jours glissants'; + break; + default : + var startpoint = 'Inconnu' + } + html += '
    ' + jQuery.fn.dataTable.render.text().display(startpoint) + ' : ' + jQuery.fn.dataTable.render.text().display(limit.volume) + '
    '; + } + + return html; + }, }, - }, + { data: 'id', render: function (data, type, row, meta) { diff --git a/templates/phone_group/add.php b/templates/phone_group/add.php new file mode 100644 index 0000000..c062db7 --- /dev/null +++ b/templates/phone_group/add.php @@ -0,0 +1,78 @@ +render('incs/head', ['title' => 'Groupes de Téléphones - Add']) +?> +
    +render('incs/nav', ['page' => 'phone_groups']) +?> +
    +
    + +
    +
    +

    + Nouveau groupe de téléphones +

    + +
    +
    + + +
    +
    +
    +
    +

    Ajout d'un groupe de téléphones

    +
    +
    + +
    + +
    + + +
    +
    +
    + + +
    + Annuler + + +
    +
    +
    +
    +
    +
    +
    + +render('incs/footer'); diff --git a/templates/phone_group/edit.php b/templates/phone_group/edit.php new file mode 100644 index 0000000..5432b71 --- /dev/null +++ b/templates/phone_group/edit.php @@ -0,0 +1,93 @@ +render('incs/head', ['title' => 'Groupes de Téléphones - Edit']) +?> +
    +render('incs/nav', ['page' => 'phone_groups']) +?> +
    +
    + +
    +
    +

    + Modification groupes de téléphones +

    + +
    +
    + + +
    +
    +
    +
    +

    Modification des groupes de téléphones

    +
    +
    +
    + + +
    + +
    + + +
    +
    +
    + + +
    +
    + + Annuler + +
    +
    +
    +
    +
    +
    +
    +
    + +render('incs/footer'); diff --git a/templates/phone_group/list.php b/templates/phone_group/list.php new file mode 100644 index 0000000..28d653e --- /dev/null +++ b/templates/phone_group/list.php @@ -0,0 +1,159 @@ +render('incs/head', ['title' => 'Groupes de Téléphones - Show All']) +?> +
    +render('incs/nav', ['page' => 'phone_groups']) +?> +
    +
    + +
    +
    +

    + Dashboard Groupes de téléphones +

    + +
    +
    + + +
    +
    +
    +
    +

    Liste des groupes de téléphones

    +
    +
    +
    +
    + + + + + + + + + + + + + +
    NomNombre de téléphonesDate de créationDernière modificationPreview
    +
    +
    + +
    + Action pour la séléction : + + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + + +render('incs/footer'); diff --git a/templates/scheduled/add.php b/templates/scheduled/add.php index bd744de..0c3349f 100644 --- a/templates/scheduled/add.php +++ b/templates/scheduled/add.php @@ -131,14 +131,32 @@ - + +
    + +

    + Vous pouvez renseigner une chaine de caractère qui sera associée à tous les SMS envoyés. Utile pour associer un identifiant interne à vos systèmes. Laissez vide si vous ne voulez pas associé de chaine. +

    +
    + +
    +
    + +
    diff --git a/templates/scheduled/edit.php b/templates/scheduled/edit.php index e982389..30f8d27 100644 --- a/templates/scheduled/edit.php +++ b/templates/scheduled/edit.php @@ -152,13 +152,29 @@ +
    + +

    + Vous pouvez renseigner une chaine de caractère qui sera associée à tous les SMS envoyés. Utile pour associer un identifiant interne à vos systèmes. Laissez vide si vous ne voulez pas associé de chaine. +

    +
    + +
    +

    diff --git a/templates/sended/list.php b/templates/sended/list.php index 7f1ada0..a5ced56 100644 --- a/templates/sended/list.php +++ b/templates/sended/list.php @@ -42,6 +42,7 @@ Expéditeur Destinataire Message + Tag Date Statut @@ -74,7 +75,7 @@ jQuery(document).ready(function () "url": HTTP_PWD + "/assets/js/datatables/french.json", }, "orderMulti": false, - "order": [[3, "desc"]], + "order": [[4, "desc"]], "columnDefs": [{ 'targets': 'checkcolumn', 'orderable': false, @@ -111,6 +112,7 @@ jQuery(document).ready(function () return jQuery.fn.dataTable.render.text().display(data); }, }, + {data: 'tag', render: jQuery.fn.dataTable.render.text()}, {data: 'at', render: jQuery.fn.dataTable.render.text()}, { data: 'status', diff --git a/templates/setting/show.php b/templates/setting/show.php index afe8cff..bc64c83 100644 --- a/templates/setting/show.php +++ b/templates/setting/show.php @@ -34,26 +34,64 @@

    Les réglages de RaspiSMS

    -
    +
    -

    Transfert des SMS par e-mail

    +

    Pays par défaut numéros internationaux

    -
    +
    - - + +
    -
    +
    +
    + +
    +
    +
    +

    Pays préférés numéros internationaux

    +
    +
    +
    +
    + + +
    +
    + +
    +
    +
    +
    +
    + +
    +
    +
    +

    Pays autorisés pour l'envoi

    +
    +
    +
    +
    + + +
    +
    + +
    +
    +
    +
    +
    + +

    Alphabet SMS optimisé

    @@ -73,7 +111,10 @@
    -
    +
    + +
    +

    Support des MMS

    @@ -92,17 +133,20 @@
    +
    + +
    -

    Détection des URL dans les discussions

    +

    Support des SMS Flash

    -
    +
    - +
    @@ -111,96 +155,8 @@
    -
    -
    -

    Pays préférés numéros internationaux

    -
    -
    -
    -
    - - -
    -
    - -
    -
    -
    -
    -
    -
    -

    Pays autorisés pour l'envoi

    -
    -
    -
    -
    - - -
    -
    - -
    -
    -
    -
    -
    -
    -

    Son sur reception d'un SMS

    -
    -
    -
    -
    - - -
    -
    - -
    -
    -
    -
    -
    -
    -

    Alerte limite de SMS atteinte

    -
    -
    -
    -
    - - -
    -
    - -
    -
    -
    -
    -
    -
    -

    Affichage de l'aide

    -
    -
    -
    -
    - - -
    -
    - -
    -
    -
    -
    -
    +
    +
    @@ -221,79 +177,9 @@
    -
    -
    -

    Activation de Webhooks

    -
    -
    -
    -
    - - -
    -
    - -
    -
    -
    -
    -
    -
    -

    Pays par défaut numéros internationaux

    -
    -
    -
    -
    - - -
    -
    - -
    -
    -
    -
    -
    -
    -

    Support des SMS Flash

    -
    -
    -
    -
    - - -
    -
    - -
    -
    -
    -
    -
    -
    -

    Support des groupes conditionnels

    -
    -
    -
    -
    - - -
    -
    - -
    -
    -
    -
    +
    + +

    Support du templating

    @@ -313,6 +199,141 @@
    +
    + +
    +
    +
    +

    Support des groupes conditionnels

    +
    +
    +
    +
    + + +
    +
    + +
    +
    +
    +
    +
    + +
    +
    +
    +

    Support des limites d'envoi par téléphones

    +
    +
    +
    +
    + + +
    +
    + +
    +
    +
    +
    +
    + +
    +
    +
    +

    Support des téléphones prioritaires

    +
    +
    +
    +
    + + +
    +
    + +
    +
    +
    +
    +
    + +
    +
    +
    +

    Activation de Webhooks

    +
    +
    +
    +
    + + +
    +
    + +
    +
    +
    +
    +
    + +
    +
    +
    +

    Transfert des SMS par e-mail

    +
    +
    +
    +
    + + +
    +
    + +
    +
    +
    +
    +
    + +
    +
    +
    +

    Alerte limite de SMS atteinte

    +
    +
    +
    +
    + + +
    +
    + +
    +
    +
    +
    +
    + +

    Alerte limite de SMS proche

    @@ -337,6 +358,75 @@
    +
    + +
    +
    +
    +

    Son sur reception d'un SMS

    +
    +
    +
    +
    + + +
    +
    + +
    +
    +
    +
    +
    + +
    +
    +
    +

    Détection des URL dans les discussions

    +
    +
    +
    +
    + + +
    +
    + +
    +
    +
    +
    +
    + +
    +
    +
    +

    Affichage de l'aide

    +
    +
    +
    +
    + + +
    +
    + +
    +
    +
    +
    +
    + +

    Cacher des menus

    @@ -346,7 +436,7 @@
    - +
    @@ -354,7 +444,7 @@
    -
    +