Преглед на файлове

Merge pull request #2 from causefx/v2-develop

V2 develop sync
Rob Gökemeijer преди 8 години
родител
ревизия
9a585bfba1
променени са 42 файла, в които са добавени 1551 реда и са изтрити 469 реда
  1. 9 1
      api/config/default.php
  2. 1 1
      api/functions/auth-functions.php
  3. 1 0
      api/functions/cert/index.html
  4. 500 0
      api/functions/deluge.class.php
  5. 17 0
      api/functions/homepage-connect-functions.php
  6. 100 37
      api/functions/homepage-functions.php
  7. 24 6
      api/functions/organizr-functions.php
  8. 3 1
      api/functions/update-functions.php
  9. 0 0
      css/dark.css
  10. 0 0
      css/horizontal.css
  11. 0 0
      css/light.css
  12. 4 1
      css/organizr.css
  13. 1 1
      css/themes/Organizr.css
  14. 2 2
      index.php
  15. 11 16
      js/custom.js
  16. 141 74
      js/functions.js
  17. 1 0
      js/jquery-2.2.4.min.js
  18. 0 1
      js/jquery.nicescroll.min.js
  19. 260 9
      less/icons/font-awesome/css/font-awesome.css
  20. 1 1
      less/icons/font-awesome/css/font-awesome.min.css
  21. BIN
      less/icons/font-awesome/fonts/FontAwesome.otf
  22. BIN
      less/icons/font-awesome/fonts/fontawesome-webfont.eot
  23. 6 193
      less/icons/font-awesome/fonts/fontawesome-webfont.svg
  24. BIN
      less/icons/font-awesome/fonts/fontawesome-webfont.ttf
  25. BIN
      less/icons/font-awesome/fonts/fontawesome-webfont.woff
  26. BIN
      less/icons/font-awesome/fonts/fontawesome-webfont.woff2
  27. 0 2
      less/icons/font-awesome/less/extras.less
  28. 2 1
      less/icons/font-awesome/less/font-awesome.less
  29. 93 1
      less/icons/font-awesome/less/icons.less
  30. 36 2
      less/icons/font-awesome/less/mixins.less
  31. 7 7
      less/icons/font-awesome/less/path.less
  32. 5 0
      less/icons/font-awesome/less/screen-reader.less
  33. 0 29
      less/icons/font-awesome/less/spinning.less
  34. 95 3
      less/icons/font-awesome/less/variables.less
  35. 0 44
      less/icons/font-awesome/scss/_extras.scss
  36. 93 1
      less/icons/font-awesome/scss/_icons.scss
  37. 36 2
      less/icons/font-awesome/scss/_mixins.scss
  38. 5 0
      less/icons/font-awesome/scss/_screen-reader.scss
  39. 0 29
      less/icons/font-awesome/scss/_spinning.scss
  40. 95 3
      less/icons/font-awesome/scss/_variables.scss
  41. 2 1
      less/icons/font-awesome/scss/font-awesome.scss
  42. BIN
      plugins/images/tabs/deluge.png

+ 9 - 1
api/config/default.php

@@ -21,6 +21,7 @@ return array(
     'plexTabURL' => '',
     'plexToken' => '',
     'plexTabName' => '',
+    'plexAdmin' => '',
     'embyTabURL' => '',
     'embyTabName' => '',
     'embyURL' => '',
@@ -49,13 +50,19 @@ return array(
     'transmissionPassword' => '',
     'transmissionHideSeeding' => false,
     'transmissionHideCompleted' => false,
+    'delugeURL' => '',
+    'delugePassword' => '',
+    'delugeHideSeeding' => false,
+    'delugeHideCompleted' => false,
     'qBittorrentURL' => '',
     'qBittorrentUsername' => '',
     'qBittorrentPassword' => '',
     'qBittorrentHideSeeding' => false,
     'qBittorrentHideCompleted' => false,
     'qBittorrentSortOrder' => 'eta',
-    'qBittorrentReverseSorting' => false,    
+    'qBittorrentReverseSorting' => false,
+    'homepageDelugeEnabled' => false,
+    'homepageDelugeAuth' => '1',
     'homepageSabnzbdEnabled' => false,
     'homepageSabnzbdAuth' => '1',
 	'homepageSonarrEnabled' => false,
@@ -92,6 +99,7 @@ return array(
 	'homepageOrdernoticeguest' => '14',
     'homepageOrdertransmission' => '15',
     'homepageOrderqBittorrent' => '16',
+    'homepageOrderdeluge' => '17',
     'homepageShowStreamNames' => false,
     'homepageShowStreamNamesAuth' => '1',
     'homepageStreamRefresh' => '60000',

+ 1 - 1
api/functions/auth-functions.php

@@ -42,7 +42,7 @@ function checkPlexUser($username){
 function plugin_auth_plex($username, $password) {
 	try{
 		$usernameLower = strtolower($username);
-		if(checkPlexUser($username)){
+		if((!empty($GLOBALS['plexAdmin']) && strtolower($GLOBALS['plexAdmin']) == $usernameLower) || checkPlexUser($username)){
 			//Login User
 			$url = 'https://plex.tv/users/sign_in.json';
 			$headers = array(

+ 1 - 0
api/functions/cert/index.html

@@ -0,0 +1 @@
+cert file in this directory

+ 500 - 0
api/functions/deluge.class.php

@@ -0,0 +1,500 @@
+<?php
+
+class deluge {
+	private $ch;
+	private $url;
+	private $request_id;
+
+	function __construct($host, $password)
+	{
+		$this->url = $host . (substr($host, -1) == "/" ? "" : "/") . "json";
+		$this->request_id = 0;
+		$this->ch = curl_init($this->url);
+		$curl_options = array(
+			CURLOPT_RETURNTRANSFER => true,
+			CURLOPT_HTTPHEADER => array("Accept: application/json", "Content-Type: application/json"),
+			CURLOPT_ENCODING => "",
+			CURLOPT_COOKIEJAR  => "",
+			CURLOPT_CONNECTTIMEOUT => 10,
+			CURLOPT_TIMEOUT => 10,
+			CURLOPT_CAINFO => getCert(),
+	        CURLOPT_SSL_VERIFYHOST => localURL($host) ? 0 : 2,
+	        CURLOPT_SSL_VERIFYPEER => localURL($host) ? 0 : 2,
+			//CURLOPT_SSL_VERIFYPEER => false, THIS IS INSECURE!! However, deluge appears not to send intermediate certificates, so it can be necessary. Use with caution!
+		);
+		curl_setopt_array($this->ch, $curl_options);
+
+		//Log in and get cookies
+		try {
+			$result = $this->makeRequest("auth.login", array($password));
+			if ($result === false)
+				throw new Exception("Login failed");
+		}
+		catch (Exception $e) {
+			throw new Exception("Failed to initiate deluge api", 0, $e);
+		}
+	}
+
+	/////////////////////////////
+	//
+	//webapi functions (https://github.com/idlesign/deluge-webapi)
+	//
+	/////////////////////////////
+
+	//ids is an array of hashes, or null for all
+	//params is an array of params:
+	//active_time, all_time_download, comment, compact, distributed_copies, download_payload_rate, eta, file_priorities, file_progress, files, hash, is_auto_managed, is_finished, is_seed, max_connections, max_download_speed, max_upload_slots, max_upload_speed, message, move_completed, move_completed_path, move_on_completed, move_on_completed_path, name, next_announce, num_files, num_peers, num_pieces, num_seeds, paused, peers, piece_length, prioritize_first_last, private, progress, queue, ratio, remove_at_ratio, save_path, seed_rank, seeding_time, seeds_peers_ratio, state, stop_at_ratio, stop_ratio, time_added, total_done, total_payload_download, total_payload_upload, total_peers, total_seeds, total_size, total_uploaded, total_wanted, tracker, tracker_host, tracker_status, trackers, upload_payload_rate
+	//or an empty array for all (or null, which returns comment, hash, name, save_path)
+	public function getTorrents($ids, $params) {
+		return $this->makeRequest("webapi.get_torrents", array($ids, $params))->torrents;
+	}
+
+	//metainfo is base64 encoded torrent data or a magnet url
+	//returns a torrent hash or null if the torrent wasn't aded
+	//params are torrent addition parameters like download_location?
+	public function addTorrent($metaInfo, $params) {
+		return $this->makeRequest("webapi.add_torrent", array($metaInfo, $params));
+	}
+
+	/*implemented in core
+	public function removeTorrent($hash, $removeData) {
+		return $this->makeRequest("webapi.remove_torrent", array($hash, $removeData));
+	}*/
+
+	public function getWebAPIVersion() {
+		return $this->makeRequest("webapi.get_api_version", array());
+	}
+
+	/////////////////////////////
+	//
+	//core functions
+	//
+	//parsed from https://web.archive.org/web/20150423162855/http://deluge-torrent.org:80/docs/master/core/rpc.html
+	//
+	/////////////////////////////
+
+	//Adds a torrent file to the session.
+	//Parameters:
+	//filename (string) – the filename of the torrent
+	//filedump (string) – a base64 encoded string of the torrent file contents
+	//options (dict) – the options to apply to the torrent on add
+	public function addTorrentFile($filename, $filedump, $options) {
+		return $this->makeRequest("core.add_torrent_file", array($filename, $filedump, $options));
+	}
+
+	//Adds a torrent from a magnet link.
+	//Parameters:
+	//uri (string) – the magnet link
+	//options (dict) – the options to apply to the torrent on add
+	public function addTorrentMagnet($uri, $options) {
+		return $this->makeRequest("core.add_torrent_magnet", array($uri, $options));
+	}
+
+	//Adds a torrent from a url. Deluge will attempt to fetch the torrentfrom url prior to adding it to the session.
+	//Parameters:
+	//url (string) – the url pointing to the torrent file
+	//options (dict) – the options to apply to the torrent on add
+	//headers (dict) – any optional headers to send
+	public function addTorrentUrl($url, $options, $headers) {
+		return $this->makeRequest("core.add_torrent_url", array($url, $options, $headers));
+	}
+
+	public function connectPeer($torrentId, $ip, $port) {
+		return $this->makeRequest("core.connect_peer", array($torrentId, $ip, $port));
+	}
+
+	public function createTorrent($path, $tracker, $pieceLength, $comment, $target, $webseeds, $private, $createdBy, $trackers, $addToSession) {
+		return $this->makeRequest("core.create_torrent", array($path, $tracker, $pieceLength, $comment, $target, $webseeds, $private, $createdBy, $trackers, $addToSession));
+	}
+
+	public function disablePlugin($plugin) {
+		return $this->makeRequest("core.disable_plugin", array($plugin));
+	}
+
+	public function enablePlugin($plugin) {
+		return $this->makeRequest("core.enable_plugin", array($plugin));
+	}
+
+	public function forceReannounce($torrentIds) {
+		return $this->makeRequest("core.force_reannounce", array($torrentIds));
+	}
+
+	//Forces a data recheck on torrent_ids
+	public function forceRecheck($torrentIds) {
+		return $this->makeRequest("core.force_recheck", array($torrentIds));
+	}
+
+	//Returns a list of plugins available in the core
+	public function getAvailablePlugins() {
+		return $this->makeRequest("core.get_available_plugins", array());
+	}
+
+	//Returns a dictionary of the session’s cache status.
+	public function getCacheStatus() {
+		return $this->makeRequest("core.get_cache_status", array());
+	}
+
+	//Get all the preferences as a dictionary
+	public function getConfig() {
+		return $this->makeRequest("core.get_config", array());
+	}
+
+	//Get the config value for key
+	public function getConfigValue($key) {
+		return $this->makeRequest("core.get_config_value", array($key));
+	}
+
+	//Get the config values for the entered keys
+	public function getConfigValues($keys) {
+		return $this->makeRequest("core.get_config_values", array($keys));
+	}
+
+	//Returns a list of enabled plugins in the core
+	public function getEnabledPlugins() {
+		return $this->makeRequest("core.get_enabled_plugins", array());
+	}
+
+	//returns {field: [(value,count)] }for use in sidebar(s)
+	public function getFilterTree($showZeroHits, $hideCat) {
+		return $this->makeRequest("core.get_filter_tree", array($showZeroHits, $hideCat));
+	}
+
+	//Returns the number of free bytes at path
+	public function getFreeSpace($path) {
+		return $this->makeRequest("core.get_free_space", array($path));
+	}
+
+	//Returns the libtorrent version.
+	public function getLibtorrentVersion() {
+		return $this->makeRequest("core.get_libtorrent_version", array());
+	}
+
+	//Returns the active listen port
+	public function getListenPort() {
+		return $this->makeRequest("core.get_listen_port", array());
+	}
+
+	//Returns the current number of connections
+	public function getNumConnections() {
+		return $this->makeRequest("core.get_num_connections", array());
+	}
+
+	public function getPathSize($path) {
+		return $this->makeRequest("core.get_path_size", array($path));
+	}
+
+	//Returns a list of torrent_ids in the session.
+	public function getSessionState() {
+		return $this->makeRequest("core.get_session_state", array());
+	}
+
+	//Gets the session status values for ‘keys’, these keys are takingfrom libtorrent’s session status.
+	public function getSessionStatus($keys) {
+		return $this->makeRequest("core.get_session_status", array($keys));
+	}
+
+	public function getTorrentStatus($torrentId, $keys, $diff) {
+		return $this->makeRequest("core.get_torrent_status", array($torrentId, $keys, $diff));
+	}
+
+	//returns all torrents , optionally filtered by filter_dict.
+	public function getTorrentsStatus($filterDict, $keys, $diff) {
+		return $this->makeRequest("core.get_torrents_status", array($filterDict, $keys, $diff));
+	}
+
+	public function glob($path) {
+		return $this->makeRequest("core.glob", array($path));
+	}
+
+	public function moveStorage($torrentIds, $dest) {
+		return $this->makeRequest("core.move_storage", array($torrentIds, $dest));
+	}
+
+	//Pause all torrents in the session
+	public function pauseAllTorrents() {
+		return $this->makeRequest("core.pause_all_torrents", array());
+	}
+
+	public function pauseTorrent($torrentIds) {
+		return $this->makeRequest("core.pause_torrent", array($torrentIds));
+	}
+
+	public function queueBottom($torrentIds) {
+		return $this->makeRequest("core.queue_bottom", array($torrentIds));
+	}
+
+	public function queueDown($torrentIds) {
+		return $this->makeRequest("core.queue_down", array($torrentIds));
+	}
+
+	public function queueTop($torrentIds) {
+		return $this->makeRequest("core.queue_top", array($torrentIds));
+	}
+
+	public function queueUp($torrentIds) {
+		return $this->makeRequest("core.queue_up", array($torrentIds));
+	}
+
+	//Removes a torrent from the session.
+	//Parameters:
+	//torrentId (string) – the torrentId of the torrent to remove
+	//removeData (boolean) – if True, remove the data associated with this torrent
+	public function removeTorrent($torrentId, $removeData) {
+		return $this->makeRequest("core.remove_torrent", array($torrentId, $removeData));
+	}
+
+	//Rename files in torrent_id.  Since this is an asynchronous operation bylibtorrent, watch for the TorrentFileRenamedEvent to know when thefiles have been renamed.
+	//Parameters:
+	//torrentId (string) – the torrentId to rename files
+	//filenames (((index, filename), ...)) – a list of index, filename pairs
+	public function renameFiles($torrentId, $filenames) {
+		return $this->makeRequest("core.rename_files", array($torrentId, $filenames));
+	}
+
+	//Renames the ‘folder’ to ‘new_folder’ in ‘torrent_id’.  Watch for theTorrentFolderRenamedEvent which is emitted when the folder has beenrenamed successfully.
+	//Parameters:
+	//torrentId (string) – the torrent to rename folder in
+	//folder (string) – the folder to rename
+	//newFolder (string) – the new folder name
+	public function renameFolder($torrentId, $folder, $newFolder) {
+		return $this->makeRequest("core.rename_folder", array($torrentId, $folder, $newFolder));
+	}
+
+	//Rescans the plugin folders for new plugins
+	public function rescanPlugins() {
+		return $this->makeRequest("core.rescan_plugins", array());
+	}
+
+	//Resume all torrents in the session
+	public function resumeAllTorrents() {
+		return $this->makeRequest("core.resume_all_torrents", array());
+	}
+
+	public function resumeTorrent($torrentIds) {
+		return $this->makeRequest("core.resume_torrent", array($torrentIds));
+	}
+
+	//Set the config with values from dictionary
+	public function setConfig($config) {
+		return $this->makeRequest("core.set_config", array($config));
+	}
+
+	//Sets the auto managed flag for queueing purposes
+	public function setTorrentAutoManaged($torrentId, $value) {
+		return $this->makeRequest("core.set_torrent_auto_managed", array($torrentId, $value));
+	}
+
+	//Sets a torrents file priorities
+	public function setTorrentFilePriorities($torrentId, $priorities) {
+		return $this->makeRequest("core.set_torrent_file_priorities", array($torrentId, $priorities));
+	}
+
+	//Sets a torrents max number of connections
+	public function setTorrentMaxConnections($torrentId, $value) {
+		return $this->makeRequest("core.set_torrent_max_connections", array($torrentId, $value));
+	}
+
+	//Sets a torrents max download speed
+	public function setTorrentMaxDownloadSpeed($torrentId, $value) {
+		return $this->makeRequest("core.set_torrent_max_download_speed", array($torrentId, $value));
+	}
+
+	//Sets a torrents max number of upload slots
+	public function setTorrentMaxUploadSlots($torrentId, $value) {
+		return $this->makeRequest("core.set_torrent_max_upload_slots", array($torrentId, $value));
+	}
+
+	//Sets a torrents max upload speed
+	public function setTorrentMaxUploadSpeed($torrentId, $value) {
+		return $this->makeRequest("core.set_torrent_max_upload_speed", array($torrentId, $value));
+	}
+
+	//Sets the torrent to be moved when completed
+	public function setTorrentMoveCompleted($torrentId, $value) {
+		return $this->makeRequest("core.set_torrent_move_completed", array($torrentId, $value));
+	}
+
+	//Sets the path for the torrent to be moved when completed
+	public function setTorrentMoveCompletedPath($torrentId, $value) {
+		return $this->makeRequest("core.set_torrent_move_completed_path", array($torrentId, $value));
+	}
+
+	//Sets the torrent options for torrent_ids
+	public function setTorrentOptions($torrentIds, $options) {
+		return $this->makeRequest("core.set_torrent_options", array($torrentIds, $options));
+	}
+
+	//Sets a higher priority to the first and last pieces
+	public function setTorrentPrioritizeFirstLast($torrentId, $value) {
+		return $this->makeRequest("core.set_torrent_prioritize_first_last", array($torrentId, $value));
+	}
+
+	//Sets the torrent to be removed at ‘stop_ratio’
+	public function setTorrentRemoveAtRatio($torrentId, $value) {
+		return $this->makeRequest("core.set_torrent_remove_at_ratio", array($torrentId, $value));
+	}
+
+	//Sets the torrent to stop at ‘stop_ratio’
+	public function setTorrentStopAtRatio($torrentId, $value) {
+		return $this->makeRequest("core.set_torrent_stop_at_ratio", array($torrentId, $value));
+	}
+
+	//Sets the ratio when to stop a torrent if ‘stop_at_ratio’ is set
+	public function setTorrentStopRatio($torrentId, $value) {
+		return $this->makeRequest("core.set_torrent_stop_ratio", array($torrentId, $value));
+	}
+
+	//Sets a torrents tracker list.  trackers will be [{“url”, “tier”}]
+	public function setTorrentTrackers($torrentId, $trackers) {
+		return $this->makeRequest("core.set_torrent_trackers", array($torrentId, $trackers));
+	}
+
+	//Checks if the active port is open
+	public function testListenPort() {
+		return $this->makeRequest("core.test_listen_port", array());
+	}
+
+	public function uploadPlugin($filename, $filedump) {
+		return $this->makeRequest("core.upload_plugin", array($filename, $filedump));
+	}
+
+	//Returns a list of the exported methods.
+	public function getMethodList() {
+		return $this->makeRequest("daemon.get_method_list", array());
+	}
+
+	//Returns some info from the daemon.
+	public function info() {
+		return $this->makeRequest("daemon.info", array());
+	}
+
+	public function shutdown(...$params) {
+		return $this->makeRequest("daemon.shutdown", $params);
+	}
+
+	/////////////////////////////
+	//
+	//web ui functions
+	//
+	//parsed from https://web.archive.org/web/20150423143401/http://deluge-torrent.org:80/docs/master/modules/ui/web/json_api.html#module-deluge.ui.web.json_api
+	//
+	/////////////////////////////
+
+	//Parameters:
+	//host (string) – the hostname
+	//port (int) – the port
+	//username (string) – the username to login as
+	//password (string) – the password to login with
+	public function addHost($host, $port, $username, $password) {
+		return $this->makeRequest("web.add_host", array($host, $port, $username, $password));
+	}
+
+	//Usage
+	public function addTorrents($torrents) {
+		return $this->makeRequest("web.add_torrents", array($torrents));
+	}
+
+	public function connect($hostId) {
+		return $this->makeRequest("web.connect", array($hostId));
+	}
+
+	public function connected() {
+		return $this->makeRequest("web.connected", array());
+	}
+
+	public function deregisterEventListener($event) {
+		return $this->makeRequest("web.deregister_event_listener", array($event));
+	}
+
+	public function disconnect() {
+		return $this->makeRequest("web.disconnect", array());
+	}
+
+	public function downloadTorrentFromUrl($url, $cookie) {
+		return $this->makeRequest("web.download_torrent_from_url", array($url, $cookie));
+	}
+
+	/* in core
+	public function getConfig() {
+		return $this->makeRequest("web.get_config", array());
+	}*/
+
+	public function getEvents() {
+		return $this->makeRequest("web.get_events", array());
+	}
+
+	public function getHost($hostId) {
+		return $this->makeRequest("web.get_host", array($hostId));
+	}
+
+	public function getHostStatus($hostId) {
+		return $this->makeRequest("web.get_host_status", array($hostId));
+	}
+
+	public function getHosts() {
+		return $this->makeRequest("web.get_hosts", array());
+	}
+
+	public function getTorrentFiles($torrentId) {
+		return $this->makeRequest("web.get_torrent_files", array($torrentId));
+	}
+
+	public function getTorrentInfo($filename) {
+		return $this->makeRequest("web.get_torrent_info", array($filename));
+	}
+
+	public function registerEventListener($event) {
+		return $this->makeRequest("web.register_event_listener", array($event));
+	}
+
+	public function removeHost($connectionId) {
+		return $this->makeRequest("web.remove_host", array($connectionId));
+	}
+
+	/*in core
+	public function setConfig($config) {
+		return $this->makeRequest("web.set_config", array($config));
+	}*/
+
+	public function startDaemon($port) {
+		return $this->makeRequest("web.start_daemon", array($port));
+	}
+
+	public function stopDaemon($hostId) {
+		return $this->makeRequest("web.stop_daemon", array($hostId));
+	}
+
+	//Parameters:
+	//keys (list) – the information about the torrents to gather
+	//filterDict (dictionary) – the filters to apply when selecting torrents.
+	public function updateUi($keys, $filterDict) {
+		return $this->makeRequest("web.update_ui", array($keys, $filterDict));
+	}
+
+	private function makeRequest($method, $params) {
+		$post_data = array("id" => $this->request_id, "method" => $method, "params" => $params);
+		curl_setopt($this->ch, CURLOPT_POSTFIELDS, json_encode($post_data));
+
+		$result = curl_exec($this->ch);
+
+		if ($result === false)
+			throw new Exception("Could not log in due to curl error (no. " . curl_errno($this->ch) . "): " . curl_error($this->ch));
+
+		$http_code = curl_getinfo($this->ch, CURLINFO_HTTP_CODE);
+
+		if ($http_code != 200)
+			throw new Exception("Request for method $method returned http code $http_code");
+
+		$result = json_decode($result);
+		if (!is_null($result->error))
+			throw new Exception("Method request returned an error (no. " . $result->error->code . "): " . $result->error->message);
+
+		if ($result->id != $this->request_id)
+			throw new Exception("Response id did not match request id");
+
+		$this->request_id++;
+		return $result->result;
+	}
+}
+
+?>

+ 17 - 0
api/functions/homepage-connect-functions.php

@@ -32,6 +32,9 @@ function homepageConnect($array){
         case 'getqBittorrent':
             return qBittorrentConnect();
             break;
+		case 'getDeluge':
+			return delugeConnect();
+			break;
         case 'getCalendar':
             return getCalendar();
             break;
@@ -663,6 +666,20 @@ function qBittorrentConnect() {
         return $api;
     }
 }
+function delugeConnect(){
+	if($GLOBALS['homepageDelugeEnabled'] && !empty($GLOBALS['delugeURL']) && qualifyRequest($GLOBALS['homepageDelugeAuth'])){
+		try{
+			$deluge = new deluge($GLOBALS['delugeURL'], decrypt($GLOBALS['delugePassword']));
+			$torrents = $deluge->getTorrents(null, 'comment, download_payload_rate, eta, is_finished, is_seed, message, name, paused, progress, queue, state, total_size, upload_payload_rate');
+			$api['content']['queueItems'] = $torrents;
+			$api['content']['historyItems'] = false;
+		}catch( Excecption $e){
+			writeLog('error', 'Deluge Connect Function - Error: '.$e->getMessage(), 'SYSTEM');
+		}
+	}
+	$api['content'] = isset($api['content']) ? $api['content'] : false;
+	return $api;
+}
 function getCalendar(){
 	$startDate = date('Y-m-d',strtotime("-".$GLOBALS['calendarStart']." days"));
 	$endDate = date('Y-m-d',strtotime("+".$GLOBALS['calendarEnd']." days"));

+ 100 - 37
api/functions/homepage-functions.php

@@ -17,7 +17,8 @@ function homepageOrder(){
 		"homepageOrdercalendar" => $GLOBALS['homepageOrdercalendar'],
 		"homepageOrdernoticeguest" => $GLOBALS['homepageOrdernoticeguest'],
         "homepageOrdertransmission" => $GLOBALS['homepageOrdertransmission'],
-        "homepageOrderqBittorrent" => $GLOBALS['homepageOrderqBittorrent'],
+		"homepageOrderqBittorrent" => $GLOBALS['homepageOrderqBittorrent'],
+        "homepageOrderdeluge" => $GLOBALS['homepageOrderdeluge'],
 	);
 	asort($homepageOrder);
 	return $homepageOrder;
@@ -53,24 +54,29 @@ function buildHomepageItem($homepageItem){
                 $item .= '
                 <script>
                 // homepageOrderqBittorrent
-                homepageDownloader("qBittorrent");
-                setInterval(function() {
-                    homepageDownloader("qBittorrent");
-                }, '.$GLOBALS['homepageDownloadRefresh'].');
+                homepageDownloader("qBittorrent", "'.$GLOBALS['homepageDownloadRefresh'].'");
                 // End homepageOrderqBittorrent
                 </script>
                 ';
             }
             break;
+		case 'homepageOrderdeluge':
+			if($GLOBALS['homepageDelugeEnabled']){
+				$item .= '
+				<script>
+				// Deluge
+				homepageDownloader("deluge", "'.$GLOBALS['homepageDownloadRefresh'].'");
+				// End Deluge
+				</script>
+				';
+			}
+			break;
 		case 'homepageOrdertransmission':
 			if($GLOBALS['homepageTransmissionEnabled']){
 				$item .= '
 				<script>
 				// Transmission
-				homepageDownloader("transmission");
-				setInterval(function() {
-					homepageDownloader("transmission");
-				}, '.$GLOBALS['homepageDownloadRefresh'].');
+				homepageDownloader("transmission", "'.$GLOBALS['homepageDownloadRefresh'].'");
 				// End Transmission
 				</script>
 				';
@@ -81,10 +87,7 @@ function buildHomepageItem($homepageItem){
 				$item .= '
 				<script>
 				// NZBGet
-				homepageDownloader("nzbget");
-				setInterval(function() {
-					homepageDownloader("nzbget");
-				}, '.$GLOBALS['homepageDownloadRefresh'].');
+				homepageDownloader("nzbget", "'.$GLOBALS['homepageDownloadRefresh'].'");
 				// End NZBGet
 				</script>
 				';
@@ -95,10 +98,7 @@ function buildHomepageItem($homepageItem){
 				$item .= '
 				<script>
 				// SabNZBd
-				homepageDownloader("sabnzbd");
-				setInterval(function() {
-					homepageDownloader("sabnzbd");
-				}, '.$GLOBALS['homepageDownloadRefresh'].');
+				homepageDownloader("sabnzbd", "'.$GLOBALS['homepageDownloadRefresh'].'");
 				// End SabNZBd
 				</script>
 				';
@@ -109,10 +109,7 @@ function buildHomepageItem($homepageItem){
 				$item .= '
 				<script>
 				// Plex Stream
-				homepageStream("plex");
-				setInterval(function() {
-				    homepageStream("plex");
-				}, '.$GLOBALS['homepageStreamRefresh'].');
+				homepageStream("plex", "'.$GLOBALS['homepageStreamRefresh'].'");
 				// End Plex Stream
 				</script>
 				';
@@ -123,10 +120,7 @@ function buildHomepageItem($homepageItem){
 				$item .= '
 				<script>
 				// Plex Recent
-				homepageRecent("plex");
-				setInterval(function() {
-					homepageRecent("plex");
-				}, '.$GLOBALS['homepageRecentRefresh'].');
+				homepageRecent("plex", "'.$GLOBALS['homepageRecentRefresh'].'");
 				// End Plex Recent
 				</script>
 				';
@@ -140,10 +134,7 @@ function buildHomepageItem($homepageItem){
 				$item .= '
 				<script>
 				// Emby Stream
-				homepageStream("emby");
-				setInterval(function() {
-					homepageStream("emby");
-				}, '.$GLOBALS['homepageStreamRefresh'].');
+				homepageStream("emby", "'.$GLOBALS['homepageStreamRefresh'].'");
 				// End Emby Stream
 				</script>
 				';
@@ -154,10 +145,7 @@ function buildHomepageItem($homepageItem){
 				$item .= '
 				<script>
 				// Emby Recent
-				homepageRecent("emby");
-				setInterval(function() {
-					homepageRecent("emby");
-				}, '.$GLOBALS['homepageRecentRefresh'].');
+				homepageRecent("emby", "'.$GLOBALS['homepageRecentRefresh'].'");
 				// End Emby Recent
 				</script>
 				';
@@ -171,10 +159,7 @@ function buildHomepageItem($homepageItem){
 			<div id="calendar" class="fc fc-ltr"></div>
 			<script>
 			// Calendar
-			homepageCalendar();
-			setInterval(function() {
-				homepageCalendar();
-			}, '.$GLOBALS['calendarRefresh'].');
+			homepageCalendar("'.$GLOBALS['calendarRefresh'].'");
 			// End Calendar
 			</script>
 			';
@@ -859,6 +844,84 @@ function getHomepageList(){
                     )
                 )
             )
+        ),
+		array(
+            'name' => 'Deluge',
+            'enabled' => false,
+            'image' => 'plugins/images/tabs/deluge.png',
+            'category' => 'Downloader',
+            'settings' => array(
+				'custom' => '
+				<div class="row">
+                    <div class="col-lg-12">
+                        <div class="panel panel-info">
+                            <div class="panel-heading">
+								<span lang="en">Notice</span>
+                            </div>
+                            <div class="panel-wrapper collapse in" aria-expanded="true">
+                                <div class="panel-body">
+									<ul class="list-icons">
+                                        <li><i class="fa fa-chevron-right text-danger"></i> <a href="https://github.com/idlesign/deluge-webapi/raw/master/dist/WebAPI-0.2.0-py2.7.egg" target="_blank">Download Plugin</a></li>
+                                        <li><i class="fa fa-chevron-right text-danger"></i> Open Deluge Web UI, go to "Preferences -> Plugins -> Install plugin" and choose egg file.</li>
+                                        <li><i class="fa fa-chevron-right text-danger"></i> Activate WebAPI plugin </li>
+                                    </ul>
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+				</div>
+				',
+                'Enable' => array(
+                    array(
+                        'type' => 'switch',
+                        'name' => 'homepageDelugeEnabled',
+                        'label' => 'Enable',
+                        'value' => $GLOBALS['homepageDelugeEnabled']
+                    ),
+                    array(
+                        'type' => 'select',
+                        'name' => 'homepageDelugeAuth',
+                        'label' => 'Minimum Authentication',
+                        'value' => $GLOBALS['homepageDelugeAuth'],
+                        'options' => $groups
+                    )
+                ),
+                'Connection' => array(
+                    array(
+                        'type' => 'input',
+                        'name' => 'delugeURL',
+                        'label' => 'URL',
+                        'value' => $GLOBALS['delugeURL'],
+                        'placeholder' => 'http(s)://hostname:port'
+                    ),
+                    array(
+                        'type' => 'password',
+                        'name' => 'delugePassword',
+                        'label' => 'Password',
+                        'value' => $GLOBALS['delugePassword']
+                    )
+                ),
+                'Misc Options' => array(
+                    array(
+                        'type' => 'switch',
+                        'name' => 'delugeHideSeeding',
+                        'label' => 'Hide Seeding',
+                        'value' => $GLOBALS['delugeHideSeeding']
+                    ),array(
+                        'type' => 'switch',
+                        'name' => 'delugeHideCompleted',
+                        'label' => 'Hide Completed',
+                        'value' => $GLOBALS['delugeHideCompleted']
+                    ),
+                    array(
+                        'type' => 'select',
+                        'name' => 'homepageDownloadRefresh',
+                        'label' => 'Refresh Seconds',
+                        'value' => $GLOBALS['homepageDownloadRefresh'],
+                        'options' => $time
+                    )
+                )
+            )
         ),
         array(
             'name' => 'Sonarr',

+ 24 - 6
api/functions/organizr-functions.php

@@ -306,6 +306,17 @@ function getSSO(){
     			'href' => '#sso-plex-machine-form',
     			'attr' => 'data-effect="mfp-3d-unfold"'
     		),
+			array(
+    			'type' => 'input',
+    			'name' => 'plexAdmin',
+    			'label' => 'Admin Username',
+    			'value' => $GLOBALS['plexAdmin'],
+    			'placeholder' => 'Admin username for Plex'
+    		),
+            array(
+                'type' => 'blank',
+                'label' => ''
+            ),
     		array(
     			'type' => 'html',
     			'label' => 'Plex Note',
@@ -541,24 +552,31 @@ function auth(){
     $ban = isset($_GET['ban']) ? strtoupper($_GET['ban']) : "";
     $whitelist = isset($_GET['whitelist']) ? $_GET['whitelist'] : false;
     $blacklist = isset($_GET['blacklist']) ? $_GET['blacklist'] : false;
-    $group = isset($_GET['group']) ? $_GET['group'] : 0;
+    $group = isset($_GET['group']) ? (int)$_GET['group'] : (int)0;
     $currentIP = userIP();
-    $currentUser = $GLOBALS['organizrUser']['username'];
+	if(isset($GLOBALS['organizrUser'])){
+		$currentUser = $GLOBALS['organizrUser']['username'];
+        $currentGroup = $GLOBALS['organizrUser']['groupID'];
+    }else{
+		$currentUser = 'Guest';
+		$currentGroup = getUserLevel();
+	}
+	$userInfo = "User: $currentUser | Group: $currentGroup | IP: $currentIP | Requesting Access to Group $group | Result: ";
     if ($whitelist) {
         if(in_array($currentIP, arrayIP($whitelist))) {
-           !$debug ? exit(http_response_code(200)) : die("$currentIP Whitelist Authorized");
+           !$debug ? exit(http_response_code(200)) : die("$userInfo Whitelist Authorized");
     	}
     }
     if ($blacklist) {
         if(in_array($currentIP, arrayIP($blacklist))) {
-           !$debug ? exit(http_response_code(401)) : die("$currentIP Blacklisted");
+           !$debug ? exit(http_response_code(401)) : die("$userInfo Blacklisted");
     	}
     }
     if($group !== null){
         if(qualifyRequest($group)){
-            !$debug ? exit(http_response_code(200)) : die("$currentUser on $currentIP Authorized");
+            !$debug ? exit(http_response_code(200)) : die("$userInfo Authorized");
         }else{
-            !$debug ? exit(http_response_code(401)) : die("$currentUser on $currentIP Not Authorized");
+            !$debug ? exit(http_response_code(401)) : die("$userInfo Not Authorized");
         }
     }else{
         !$debug ? exit(http_response_code(401)) : die("Not Authorized Due To No Parameters Set");

+ 3 - 1
api/functions/update-functions.php

@@ -3,6 +3,8 @@
 
 // Upgrade the installation
 function upgradeInstall($branch = 'v2-master', $stage) {
+	ini_set('max_execution_time',0);
+	set_time_limit(0);
     $url = 'https://github.com/causefx/Organizr/archive/'.$branch.'.zip';
     $file = "upgrade.zip";
     $source = dirname(__DIR__,2).DIRECTORY_SEPARATOR.'upgrade'.DIRECTORY_SEPARATOR.'Organizr-'.str_replace('v2','2',$branch).DIRECTORY_SEPARATOR;
@@ -48,7 +50,7 @@ function upgradeInstall($branch = 'v2-master', $stage) {
 			}
 			break;
 		default:
-			# code...
+			return false;
 			break;
 	}
 	return false;

Файловите разлики са ограничени, защото са твърде много
+ 0 - 0
css/dark.css


Файловите разлики са ограничени, защото са твърде много
+ 0 - 0
css/horizontal.css


Файловите разлики са ограничени, защото са твърде много
+ 0 - 0
css/light.css


+ 4 - 1
css/organizr.css

@@ -173,7 +173,7 @@ object-fit: contain;
   overflow: hidden;
   position: relative;
   background-size: cover;
-  background-position: center;
+  background-position: top;
   background-repeat: no-repeat;
 }
 h2.m-b-0.font-medium.pull-right {
@@ -254,3 +254,6 @@ background: #2cabe3;
   margin: 0;
   padding: 19px 20px 11px 20px;
 }
+.fc-unthemed .fc-today {
+  color: inherit !important;
+}

+ 1 - 1
css/themes/Organizr.css

@@ -319,7 +319,7 @@ a.mytooltip {
   padding: 8px;
   line-height: 1.42857143;
   vertical-align: middle;
-  border-top: transparent;
+  /*border-top: transparent;*/
 }
 .jq-icon-info { background-color: rgba(71, 68, 68, 0.93); color: #FFF; border-color: #bce8f1; }
 .jq-icon-warning { background-color: rgba(154, 83, 20, 0.93); color: #fcf8e3; border-color: #faebcc; }

+ 2 - 2
index.php

@@ -100,11 +100,11 @@
 		<!-- ============================================================== -->
 	</div><!-- /#wrapper -->
 	<!-- jQuery -->
-	<script src="plugins/bower_components/jquery/dist/jquery.min.js"></script>
+	<!--<script src="plugins/bower_components/jquery/dist/jquery.min.js"></script>-->
+	<script src="js/jquery-2.2.4.min.js"></script>
 	<script src="bootstrap/dist/js/bootstrap.min.js"></script>
 	<script src="plugins/bower_components/sidebar-nav/dist/sidebar-nav.js"></script>
 	<script src="js/jquery.slimscroll.js"></script>
-	<script src="js/jquery.nicescroll.min.js"></script>
 	<script src="js/waves.js"></script>
 	<script src="plugins/bower_components/toast-master/js/jquery.toast.js"></script>
 	<script src="plugins/bower_components/styleswitcher/jQuery.style.switcher.js"></script>

+ 11 - 16
js/custom.js

@@ -6,19 +6,12 @@ $(document).ajaxComplete(function () {
     pageLoad();
 });
 $(document).ready(function () {
-    $("body").niceScroll({
-        grabcursorenabled: false,
-        zindex:1000000
-    });
     pageLoad();
     var clipboard = new Clipboard('.clipboard');
     clipboard.on('success', function(e) {
         message('Clipboard',e.text,'bottom-right','#FFF','info','5000');
         e.clearSelection();
     });
-});
-function pageLoad(){
-	$("body").getNiceScroll().resize();
 	"use strict";
     var body = $("body");
     $(function () {
@@ -72,6 +65,9 @@ function pageLoad(){
     $(this).keypress(function (e) {
         idleTime = 0;
     });
+});
+function pageLoad(){
+	"use strict";
     //Start Organizr
     $(function () {
         $('#side-menu').metisMenu();
@@ -1577,10 +1573,10 @@ $(document).on("click", ".refreshImage", function(e) {
 	message('',' Refreshing Image...','bottom-right','#FFF','success','1000');
 	e.preventDefault;
 	var orginalElement = $(this).parent().parent().parent().parent().find('.imageSource');
-    console.log(orginalElement)
+    //console.log(orginalElement)
 	var original = $(this).attr('data-image');
 	orginalElement.attr('src', original);
-	console.log('replaced image with : '+original);
+	//console.log('replaced image with : '+original);
 	setTimeout(function(){
         message('Image Refreshed ',' Clear Cache Please','bottom-right','#FFF','success','3000');
 	}, 1000);
@@ -1605,7 +1601,6 @@ $(document).on("click", ".openTab", function(e) {
 });
 // metadata start
 $(document).on("click", ".metadata-get", function(e) {
-    $('.metadata-info').html('');
     var key = $(this).attr('data-key');
 	var uid = $(this).attr('data-uid');
     var source = $(this).attr('data-source');
@@ -1622,7 +1617,7 @@ $(document).on("click", ".metadata-get", function(e) {
     ajaxloader(".content-wrap","in");
 	organizrAPI('POST','api/?v1/homepage/connect',{action:action, key:key}).success(function(data) {
 		var response = JSON.parse(data);
-        console.log(response);
+        $('.'+uid+'-metadata-info').html('');
 		$('.'+uid+'-metadata-info').html(buildMetadata(response.data, source));
         $('.'+uid).trigger('click')
 	}).fail(function(xhr) {
@@ -1631,18 +1626,18 @@ $(document).on("click", ".metadata-get", function(e) {
 	ajaxloader();
 
 });
-// sad play/resume
+// sab play/resume
 $(document).on("click", ".downloader", function(e) {
     var action = $(this).attr('data-action');
     var source = $(this).attr('data-source');
     var target = $(this).attr('data-target');
-    console.log(action);
-    console.log(source);
-    console.log(target);
+    //console.log(action);
+    //console.log(source);
+    //console.log(target);
     ajaxloader(".content-wrap","in");
 	organizrAPI('POST','api/?v1/downloader',{action:action, source:source, target:target}).success(function(data) {
 		var response = JSON.parse(data);
-        console.log(response);
+        //console.log(response);
 		homepageDownloader(source);
 	}).fail(function(xhr) {
 		console.error("Organizr Function: API Connection Failed");

+ 141 - 74
js/functions.js

@@ -14,6 +14,23 @@ lang.init({
 // Start Organizr
 launch();
 /* NORMAL FUNCTIONS */
+function getHiddenProp(){
+    var prefixes = ['webkit','moz','ms','o'];
+    // if 'hidden' is natively supported just return it
+    if ('hidden' in document) return 'hidden';
+    // otherwise loop over all the known prefixes until we find one
+    for (var i = 0; i < prefixes.length; i++){
+        if ((prefixes[i] + 'Hidden') in document)
+            return prefixes[i] + 'Hidden';
+    }
+    // otherwise it's not supported
+    return null;
+}
+function isHidden() {
+    var prop = getHiddenProp();
+    if (!prop) return false;
+    return document[prop];
+}
 function loadLanguageList(){
 	var languages = languageList();
 	$.each(languages, function(i,v) {
@@ -310,7 +327,7 @@ function popTab(tab, type){
 		case '_blank':
 		case 'popout':
 			console.log('Tab Function: Creating New Window for tab: '+tab);
-			var url = $('#container-'+cleanClass(tab)).attr('data-url');
+			var url = $('#menu-'+cleanClass(tab)).attr('data-url');
 			window.open(url, '_blank');
 			break;
 		default:
@@ -691,30 +708,34 @@ function buildFormGroup(array){
 	$.each(array, function(i,v) {
 		var count = 0;
 		var total = v.length;
-		group += `
-			<!-- FORM GROUP -->
-			<h4 class="box-title" lang="en">`+i+`</h4>
-			<hr class="m-t-0 m-b-40">
-			<div class="row">
-		`;
-		$.each(v, function(i,v) {
-			count++;
-			if(count%2 !== 0 ){ group += '<div class="row start">'; };
+		if(i == 'custom'){
+			group += v;
+		}else{
 			group += `
-				<!-- INPUT BOX -->
-				<div class="col-md-6 p-b-10">
-					<div class="form-group">
-						<label class="control-label col-md-3" lang="en">`+v.label+`</label>
-						<div class="col-md-9">
-							`+buildFormItem(v)+`
+				<!-- FORM GROUP -->
+				<h4 class="box-title" lang="en">`+i+`</h4>
+				<hr class="m-t-0 m-b-40">
+				<div class="row">
+			`;
+			$.each(v, function(i,v) {
+				count++;
+				if(count%2 !== 0 ){ group += '<div class="row start">'; };
+				group += `
+					<!-- INPUT BOX -->
+					<div class="col-md-6 p-b-10">
+						<div class="form-group">
+							<label class="control-label col-md-3" lang="en">`+v.label+`</label>
+							<div class="col-md-9">
+								`+buildFormItem(v)+`
+							</div>
 						</div>
 					</div>
-				</div>
-				<!--/ INPUT BOX -->
-			`;
-			if(count%2 == 0 || count == total ){ group += '</div><!--end-->'; };
-		});
-		group += '</div>';
+					<!--/ INPUT BOX -->
+				`;
+				if(count%2 == 0 || count == total ){ group += '</div><!--end-->'; };
+			});
+			group += '</div>';
+		}
 	});
 	return group;
 }
@@ -784,7 +805,6 @@ function buildSettingsMain(){
 	ajaxloader(".content-wrap","in");
 	organizrAPI('GET','api/?v1/settings/main').success(function(data) {
 		var response = JSON.parse(data);
-		console.log(response)
 		$('#settings-main-form').html(buildFormGroup(response.data));
 		changeAuth();
 		;
@@ -817,7 +837,6 @@ function buildTabEditor(){
 	ajaxloader(".content-wrap","in");
 	organizrAPI('GET','api/?v1/tab/list').success(function(data) {
 		var response = JSON.parse(data);
-		console.log(response.data);
 		$('#tabEditorTable').html(buildTabEditorItem(response.data));
 	}).fail(function(xhr) {
 		console.error("Organizr Function: API Connection Failed");
@@ -838,7 +857,6 @@ function settingsAPI(post, callbacks=null){
 	ajaxloader(".content-wrap","in");
 	organizrAPI('POST',post.api,post).success(function(data) {
 		var response = JSON.parse(data);
-		console.log(response);
 		message(post.messageTitle,post.messageBody,"bottom-right","#FFF","success","5000");
 		if(callbacks){ callbacks.fire(); }
 	}).fail(function(xhr) {
@@ -969,7 +987,7 @@ function buildInternalContainer(name,url,type){
 	return `<div id="internal-`+cleanClass(name)+`" data-type="`+type+`" class="internal-container frame-`+cleanClass(name)+` hidden" data-url="`+url+`" data-name="`+cleanClass(name)+`"></div>`;
 }
 function buildMenuList(name,url,type,icon){
-	return `<li id="menu-`+cleanClass(name)+`" type="`+type+`"><a class="waves-effect" onclick="tabActions(event,'`+cleanClass(name)+`',`+type+`);">`+iconPrefix(icon)+`<span class="hide-menu">`+name+`</span></a></li>`;
+	return `<li id="menu-`+cleanClass(name)+`" type="`+type+`" data-url="`+url+`"><a class="waves-effect" onclick="tabActions(event,'`+cleanClass(name)+`',`+type+`);">`+iconPrefix(icon)+`<span class="hide-menu">`+name+`</span></a></li>`;
 }
 function tabProcess(arrayItems) {
 	var iFrameList = '';
@@ -1278,7 +1296,6 @@ function submitCategoryOrder(){
 		messageBody:window.lang.translate('Category Order Saved'),
 		error:'Organizr Function: API Connection Failed'
 	};
-	console.log(post);
 	settingsAPI(post);
 	buildCategoryEditor();
 }
@@ -1469,6 +1486,7 @@ function organizrAPI(type,path,data=null){
 				beforeSend: function(request) {
 					request.setRequestHeader("Token", activeInfo.token);
 				},
+				timeout: 10000,
 			});
 			break;
 		case 'post':
@@ -1912,36 +1930,40 @@ function buildStreamItem(array,source){
 	});
 	return cards;
 }
-function buildRecentItem(array, type){
+function buildRecentItem(array, type, extra=null){
 	var items = '';
 	$.each(array, function(i,v) {
-		var className = '';
-		switch (v.type) {
-			case 'music':
-				className = 'recent-cover recent-item recent-music';
-				break;
-			case 'movie':
-				className = 'recent-poster recent-item recent-movie';
-				break;
-			case 'tv':
-				className = 'recent-poster recent-item recent-tv';
-				break;
-			case 'video':
-				className = 'recent-poster recent-item recent-video';
-				break;
-			default:
+		if(extra == null){
+			var className = '';
+			switch (v.type) {
+				case 'music':
+					className = 'recent-cover recent-item recent-music';
+					break;
+				case 'movie':
+					className = 'recent-poster recent-item recent-movie';
+					break;
+				case 'tv':
+					className = 'recent-poster recent-item recent-tv';
+					break;
+				case 'video':
+					className = 'recent-poster recent-item recent-video';
+					break;
+				default:
 
-		}
-		items += `
-		<div class="item lazyload `+className+` metadata-get mouse" data-source="`+type+`" data-key="`+v.metadataKey+`" data-uid="`+v.uid+`" data-src="`+v.imageURL+`">
-			<span class="elip recent-title">`+v.title+`</span>
+			}
+			items += `
+			<div class="item lazyload `+className+` metadata-get mouse" data-source="`+type+`" data-key="`+v.metadataKey+`" data-uid="`+v.uid+`" data-src="`+v.imageURL+`">
+				<span class="elip recent-title">`+v.title+`</span>
+				<div id="`+v.uid+`-metadata-div" class="white-popup mfp-with-anim mfp-hide">
+			        <div class="col-md-8 col-md-offset-2 `+v.uid+`-metadata-info"></div>
+			    </div>
+			</div>
+			`;
+		}else{
+			items += `
 			<a class="inline-popups `+v.uid+` hidden" href="#`+v.uid+`-metadata-div" data-effect="mfp-zoom-out"></a>
-			<div id="`+v.uid+`-metadata-div" class="white-popup mfp-with-anim mfp-hide">
-		        <div class="col-md-8 col-md-offset-2 `+v.uid+`-metadata-info"></div>
-		    </div>
-		</div>
-		`;
-
+			`;
+		}
 
 	});
 	return items;
@@ -1950,7 +1972,7 @@ function buildStream(array, type){
 	var streams = (typeof array.content !== 'undefined') ? array.content.length : false;
 	return (streams) ? `
 	<div id="`+type+`Streams">
-		<div class="el-element-overlay m-b-20">
+		<div class="el-element-overlay">
 		    <div class="col-md-12">
 		        <h4 class="pull-left" lang="en">Active `+toUpper(type)+` Stream(s): </h4><h4 class="pull-left">&nbsp;<span class="label label-info m-l-5">`+streams+`</span></h4>
 		        <hr>
@@ -1991,6 +2013,7 @@ function buildRecent(array, type){
                     <div class="owl-carousel owl-theme recent-items `+type+`-recent">
 						`+buildRecentItem(array.content, type)+`
                     </div>
+					`+buildRecentItem(array.content, type, true)+`
                 </div>
             </div>
         </div>
@@ -2058,7 +2081,7 @@ function buildDownloaderItem(array, source, type='none'){
 					$.each(array.result, function(i,v) {
 						var action = (v.Status == "Downloading") ? 'pause' : 'resume';
 						var actionIcon = (v.Status == "Downloading") ? 'pause' : 'play';
-						var percent = Math.floor((v.FileSizeMB - v.RemainingSizeMB) / v.FileSizeMB);
+						var percent = Math.floor((v.FileSizeMB - v.RemainingSizeMB) * 100 / v.FileSizeMB);
 						v.Category = (v.Category !== '') ? v.Category : 'Not Set';
 						items += `
 						<tr>
@@ -2104,7 +2127,6 @@ function buildDownloaderItem(array, source, type='none'){
 		case 'transmission':
 			switch (type) {
 				case 'queue':
-				console.log(array);
 					if(array.arguments.torrents == 0){
 						return '<tr><td class="max-texts" lang="en">Nothing in queue</td></tr>';
 					}
@@ -2170,7 +2192,6 @@ function buildDownloaderItem(array, source, type='none'){
 		case 'qBittorrent':
 			switch (type) {
 				case 'queue':
-				console.log(array);
 					if(array.arguments.torrents == 0){
 						return '<tr><td class="max-texts" lang="en">Nothing in queue</td></tr>';
 					}
@@ -2226,6 +2247,37 @@ function buildDownloaderItem(array, source, type='none'){
 					break;
 				default:
 
+			}
+			break;
+		case 'deluge':
+			switch (type) {
+				case 'queue':
+					if(array.length == 0){
+						return '<tr><td class="max-texts" lang="en">Nothing in queue</td></tr>';
+					}
+					$.each(array, function(i,v) {
+						var percent = Math.floor(v.progress);
+						var size = v.total_size != -1 ? humanFileSize(v.total_size,true) : "?";
+						var upload = v.upload_payload_rate != -1 ? humanFileSize(v.upload_payload_rate,true) : "?";
+						var download = v.download_payload_rate != -1 ? humanFileSize(v.download_payload_rate,true) : "?";
+						items += `
+						<tr>
+							<td class="max-texts">`+v.name+`</td>
+							<td class="hidden-xs">`+v.state+`</td>
+							<td class="hidden-xs">`+size+`</td>
+							<td class="hidden-xs"><i class="fa fa-download"></i>&nbsp;`+download+`</td>
+							<td class="hidden-xs"><i class="fa fa-upload"></i>&nbsp;`+upload+`</td>
+							<td class="text-right">
+								<div class="progress progress-lg m-b-0">
+									<div class="progress-bar progress-bar-info" style="width: `+percent+`%;" role="progressbar">`+percent+`%</div>
+								</div>
+							</td>
+						</tr>
+						`;
+					});
+					break;
+				default:
+
 			}
 			break;
 		default:
@@ -2241,10 +2293,10 @@ function buildDownloader(array, source){
 	var downloader = (queueItems || historyItems) ? true : false;
 	var state = '';
 	var active = '';
-	console.log(array);
-	console.log(queueItems);
-	console.log(historyItems);
-	console.log(downloader);
+	//console.log(array);
+	//console.log(queueItems);
+	//console.log(historyItems);
+	//console.log(downloader);
 	if(queueItems){
 		switch (source) {
 			case 'sabnzbd':
@@ -2296,7 +2348,7 @@ function buildDownloader(array, source){
 	            `+menu+`
 				<div class="clearfix"></div>
 	        </div>
-	        <div class="white-box p-0">
+	        <div class="white-box p-0 m-b-0">
 	            <div class="tab-content m-t-0">`+listing+`</div>
 	        </div>
 		</div>
@@ -2359,7 +2411,8 @@ function buildMetadata(array, source){
 	});
 	return metadata;
 }
-function homepageDownloader(type){
+function homepageDownloader(type, timeout=30000){
+	//if(isHidden()){ return; }
 	switch (type) {
 		case 'sabnzbd':
 			var action = 'getSabnzbd';
@@ -2373,18 +2426,25 @@ function homepageDownloader(type){
 		case 'qBittorrent':
 			var action = 'getqBittorrent';
 			break;
+		case 'deluge':
+			var action = 'getDeluge';
+			break;
 		default:
 
 	}
-	console.log('#homepageOrder'+type);
 	organizrAPI('POST','api/?v1/homepage/connect',{action:action}).success(function(data) {
 		var response = JSON.parse(data);
+		document.getElementById('homepageOrder'+type).innerHTML = '';
 		$('#homepageOrder'+type).html(buildDownloader(response.data, type));
 	}).fail(function(xhr) {
 		console.error("Organizr Function: API Connection Failed");
 	});
+	setTimeout(function(){
+		homepageDownloader(type, timeout);
+	}, timeout)
 }
-function homepageStream(type){
+function homepageStream(type, timeout=30000){
+	//if(isHidden()){ return; }
 	switch (type) {
 		case 'plex':
 			var action = 'getPlexStreams';
@@ -2398,13 +2458,18 @@ function homepageStream(type){
 	ajaxloader(".content-wrap","in");
 	organizrAPI('POST','api/?v1/homepage/connect',{action:action}).success(function(data) {
 		var response = JSON.parse(data);
+		document.getElementById('homepageOrder'+type+'nowplaying').innerHTML = '';
 		$('#homepageOrder'+type+'nowplaying').html(buildStream(response.data, type));
 	}).fail(function(xhr) {
 		console.error("Organizr Function: API Connection Failed");
 	});
 	ajaxloader();
+	setTimeout(function(){
+		homepageStream(type, timeout);
+	}, timeout)
 }
-function homepageRecent(type){
+function homepageRecent(type, timeout=30000){
+	//if(isHidden()){ return; }
 	switch (type) {
 		case 'plex':
 			var action = 'getPlexRecent';
@@ -2418,25 +2483,31 @@ function homepageRecent(type){
 	ajaxloader(".content-wrap","in");
 	organizrAPI('POST','api/?v1/homepage/connect',{action:action}).success(function(data) {
 		var response = JSON.parse(data);
+		document.getElementById('homepageOrder'+type+'recent').innerHTML = '';
 		$('#homepageOrder'+type+'recent').html(buildRecent(response.data, type));
 	}).fail(function(xhr) {
 		console.error("Organizr Function: API Connection Failed");
 	});
 	ajaxloader();
+	setTimeout(function(){
+		homepageRecent(type, timeout);
+	}, timeout)
 }
-function homepageCalendar(){
+function homepageCalendar(timeout=30000){
+	//if(isHidden()){ return; }
 	ajaxloader(".content-wrap","in");
 	organizrAPI('POST','api/?v1/homepage/connect',{action:'getCalendar'}).success(function(data) {
 		var response = JSON.parse(data);
-		console.log(response);
         $('#calendar').fullCalendar('removeEvents');
         $('#calendar').fullCalendar('addEventSource', response.data);
-        console.log('Calendar Entries Added');
-		//$('#homepageOrder'+type+'recent').html(buildRecent(response.data, type));
+		response = '';
 	}).fail(function(xhr) {
 		console.error("Organizr Function: API Connection Failed");
 	});
 	ajaxloader();
+	setTimeout(function(){
+		homepageCalendar(timeout);
+	}, timeout)
 }
 //Generate API
 function generateCode() {
@@ -2481,7 +2552,6 @@ function changeAuth(){
             $('.switchAuth').parent().parent().parent().hide();
             $('.backendAuth').parent().parent().parent().show();
             $('.plexAuth').parent().parent().parent().show();
-            console.log(service);
             break;
         case 'emby_local':
         case 'emby_connect':
@@ -2489,19 +2559,16 @@ function changeAuth(){
             $('.switchAuth').parent().parent().parent().hide();
             $('.backendAuth').parent().parent().parent().show();
             $('.embyAuth').parent().parent().parent().show();
-            console.log(service);
             break;
         case 'ftp':
             $('.switchAuth').parent().parent().parent().hide();
             $('.backendAuth').parent().parent().parent().show();
             $('.ftpAuth').parent().parent().parent().show();
-            console.log(service);
             break;
         case 'ldap':
             $('.switchAuth').parent().parent().parent().hide();
             $('.backendAuth').parent().parent().parent().show();
             $('.ldapAuth').parent().parent().parent().show();
-            console.log(service);
             break;
         default:
             $('.switchAuth').parent().parent().parent().hide();

Файловите разлики са ограничени, защото са твърде много
+ 1 - 0
js/jquery-2.2.4.min.js


Файловите разлики са ограничени, защото са твърде много
+ 0 - 1
js/jquery.nicescroll.min.js


+ 260 - 9
less/icons/font-awesome/css/font-awesome.css

@@ -1,13 +1,13 @@
 /*!
- *  Font Awesome 4.5.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.5.0');
-  src: url('../fonts/fontawesome-webfont.eot?#iefix&v=4.5.0') format('embedded-opentype'), url('../fonts/fontawesome-webfont.woff2?v=4.5.0') format('woff2'), url('../fonts/fontawesome-webfont.woff?v=4.5.0') format('woff'), url('../fonts/fontawesome-webfont.ttf?v=4.5.0') format('truetype'), url('../fonts/fontawesome-webfont.svg?v=4.5.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;
 }
@@ -118,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);
@@ -1383,7 +1383,7 @@
 .fa-digg:before {
   content: "\f1a6";
 }
-.fa-pied-piper:before {
+.fa-pied-piper-pp:before {
   content: "\f1a7";
 }
 .fa-pied-piper-alt:before {
@@ -1509,6 +1509,7 @@
   content: "\f1ce";
 }
 .fa-ra:before,
+.fa-resistance:before,
 .fa-rebel:before {
   content: "\f1d0";
 }
@@ -1831,6 +1832,7 @@
   content: "\f23e";
 }
 .fa-battery-4:before,
+.fa-battery:before,
 .fa-battery-full:before {
   content: "\f240";
 }
@@ -2084,3 +2086,252 @@
 .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;
+}

Файловите разлики са ограничени, защото са твърде много
+ 1 - 1
less/icons/font-awesome/css/font-awesome.min.css


BIN
less/icons/font-awesome/fonts/FontAwesome.otf


BIN
less/icons/font-awesome/fonts/fontawesome-webfont.eot


Файловите разлики са ограничени, защото са твърде много
+ 6 - 193
less/icons/font-awesome/fonts/fontawesome-webfont.svg


BIN
less/icons/font-awesome/fonts/fontawesome-webfont.ttf


BIN
less/icons/font-awesome/fonts/fontawesome-webfont.woff


BIN
less/icons/font-awesome/fonts/fontawesome-webfont.woff2


+ 0 - 2
less/icons/font-awesome/less/extras.less

@@ -1,2 +0,0 @@
-// Extras
-// --------------------------

+ 2 - 1
less/icons/font-awesome/less/font-awesome.less

@@ -1,5 +1,5 @@
 /*!
- *  Font Awesome 4.5.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)
  */
 
@@ -15,3 +15,4 @@
 @import "rotated-flipped.less";
 @import "stacked.less";
 @import "icons.less";
+@import "screen-reader.less";

+ 93 - 1
less/icons/font-awesome/less/icons.less

@@ -438,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; }
@@ -488,6 +488,7 @@
 .@{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; }
@@ -604,6 +605,7 @@
 .@{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; }
@@ -695,3 +697,93 @@
 .@{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; }

+ 36 - 2
less/icons/font-awesome/less/mixins.less

@@ -12,15 +12,49 @@
 }
 
 .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;
+  }
+}

+ 7 - 7
less/icons/font-awesome/less/path.less

@@ -3,13 +3,13 @@
 
 @font-face {
   font-family: 'FontAwesome';
-  src: url('../less/icons/font-awesome/fonts/fontawesome-webfont.eot?v=@{fa-version}');
-  src: url('../less/icons/font-awesome/fonts/fontawesome-webfont.eot?#iefix&v=@{fa-version}') format('embedded-opentype'),
-    url('../less/icons/font-awesome/fonts/fontawesome-webfont.woff2?v=@{fa-version}') format('woff2'),
-    url('../less/icons/font-awesome/fonts/fontawesome-webfont.woff?v=@{fa-version}') format('woff'),
-    url('../less/icons/font-awesome/fonts/fontawesome-webfont.ttf?v=@{fa-version}') format('truetype'),
-    url('../less/icons/font-awesome/fonts/fontawesome-webfont.svg?v=@{fa-version}#fontawesomeregular') format('svg');
-//  src: url('../less/icons/font-awesome/fonts/FontAwesome.otf') format('opentype'); // used when developing fonts
+  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
   font-weight: normal;
   font-style: normal;
 }

+ 5 - 0
less/icons/font-awesome/less/screen-reader.less

@@ -0,0 +1,5 @@
+// Screen Readers
+// -------------------------
+
+.sr-only { .sr-only(); }
+.sr-only-focusable { .sr-only-focusable(); }

+ 0 - 29
less/icons/font-awesome/less/spinning.less

@@ -1,29 +0,0 @@
-// Spinning Icons
-// --------------------------
-
-.@{fa-css-prefix}-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);
-  }
-}

+ 95 - 3
less/icons/font-awesome/less/variables.less

@@ -4,14 +4,18 @@
 @fa-font-path:        "../fonts";
 @fa-font-size-base:   14px;
 @fa-line-height-base: 1;
-//@fa-font-path:        "//netdna.bootstrapcdn.com/font-awesome/4.5.0/fonts"; // for referencing Bootstrap CDN font files directly
+//@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.5.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";
@@ -20,6 +24,7 @@
 @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";
@@ -50,17 +55,24 @@
 @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";
@@ -86,6 +98,7 @@
 @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";
@@ -94,6 +107,7 @@
 @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";
@@ -196,6 +210,8 @@
 @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";
@@ -206,18 +222,25 @@
 @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";
@@ -231,6 +254,7 @@
 @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";
@@ -265,6 +289,7 @@
 @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";
@@ -277,11 +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";
@@ -300,15 +327,21 @@
 @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";
@@ -325,6 +358,8 @@
 @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";
@@ -347,8 +382,12 @@
 @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";
@@ -386,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";
@@ -397,6 +437,7 @@
 @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";
@@ -417,8 +458,10 @@
 @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";
@@ -468,8 +511,9 @@
 @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";
@@ -482,6 +526,7 @@
 @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";
@@ -490,10 +535,13 @@
 @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";
@@ -507,6 +555,7 @@
 @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";
@@ -519,6 +568,7 @@
 @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";
@@ -543,9 +593,12 @@
 @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";
@@ -554,6 +607,10 @@
 @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";
@@ -599,6 +656,7 @@
 @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";
@@ -608,6 +666,7 @@
 @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";
@@ -616,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";
@@ -625,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";
@@ -655,6 +728,7 @@
 @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";
@@ -664,20 +738,28 @@
 @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";
@@ -687,11 +769,20 @@
 @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";
@@ -702,6 +793,7 @@
 @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";

+ 0 - 44
less/icons/font-awesome/scss/_extras.scss

@@ -1,44 +0,0 @@
-/* EXTRAS
- * -------------------------- */
-
-/* Stacked and layered icon */
-
-/* Animated rotating icon */
-.#{$fa-css-prefix}-spin {
-  -webkit-animation: spin 2s infinite linear;
-  -moz-animation: spin 2s infinite linear;
-  -o-animation: spin 2s infinite linear;
-  animation: spin 2s infinite linear;
-}
-
-@-moz-keyframes spin {
-  0% { -moz-transform: rotate(0deg); }
-  100% { -moz-transform: rotate(359deg); }
-}
-@-webkit-keyframes spin {
-  0% { -webkit-transform: rotate(0deg); }
-  100% { -webkit-transform: rotate(359deg); }
-}
-@-o-keyframes spin {
-  0% { -o-transform: rotate(0deg); }
-  100% { -o-transform: rotate(359deg); }
-}
-@-ms-keyframes spin {
-  0% { -ms-transform: rotate(0deg); }
-  100% { -ms-transform: rotate(359deg); }
-}
-@keyframes spin {
-  0% { transform: rotate(0deg); }
-  100% { transform: rotate(359deg); }
-}
-
-
-// Icon rotations & flipping
-// -------------------------
-
-.#{$fa-css-prefix}-rotate-90  { @include fa-icon-rotate(90deg, 1);  }
-.#{$fa-css-prefix}-rotate-180 { @include fa-icon-rotate(180deg, 2); }
-.#{$fa-css-prefix}-rotate-270 { @include fa-icon-rotate(270deg, 3); }
-
-.#{$fa-css-prefix}-flip-horizontal { @include fa-icon-flip(-1, 1, 0); }
-.#{$fa-css-prefix}-flip-vertical   { @include fa-icon-flip(1, -1, 2); }

+ 93 - 1
less/icons/font-awesome/scss/_icons.scss

@@ -438,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; }
@@ -488,6 +488,7 @@
 .#{$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; }
@@ -604,6 +605,7 @@
 .#{$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; }
@@ -695,3 +697,93 @@
 .#{$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; }

+ 36 - 2
less/icons/font-awesome/scss/_mixins.scss

@@ -12,15 +12,49 @@
 }
 
 @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;
+  }
+}

+ 5 - 0
less/icons/font-awesome/scss/_screen-reader.scss

@@ -0,0 +1,5 @@
+// Screen Readers
+// -------------------------
+
+.sr-only { @include sr-only(); }
+.sr-only-focusable { @include sr-only-focusable(); }

+ 0 - 29
less/icons/font-awesome/scss/_spinning.scss

@@ -1,29 +0,0 @@
-// Spinning Icons
-// --------------------------
-
-.#{$fa-css-prefix}-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);
-  }
-}

+ 95 - 3
less/icons/font-awesome/scss/_variables.scss

@@ -4,14 +4,18 @@
 $fa-font-path:        "../fonts" !default;
 $fa-font-size-base:   14px !default;
 $fa-line-height-base: 1 !default;
-//$fa-font-path:        "//netdna.bootstrapcdn.com/font-awesome/4.5.0/fonts" !default; // for referencing Bootstrap CDN font files directly
+//$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.5.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";
@@ -20,6 +24,7 @@ $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";
@@ -50,17 +55,24 @@ $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";
@@ -86,6 +98,7 @@ $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";
@@ -94,6 +107,7 @@ $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";
@@ -196,6 +210,8 @@ $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";
@@ -206,18 +222,25 @@ $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";
@@ -231,6 +254,7 @@ $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";
@@ -265,6 +289,7 @@ $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";
@@ -277,11 +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";
@@ -300,15 +327,21 @@ $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";
@@ -325,6 +358,8 @@ $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";
@@ -347,8 +382,12 @@ $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";
@@ -386,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";
@@ -397,6 +437,7 @@ $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";
@@ -417,8 +458,10 @@ $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";
@@ -468,8 +511,9 @@ $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";
@@ -482,6 +526,7 @@ $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";
@@ -490,10 +535,13 @@ $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";
@@ -507,6 +555,7 @@ $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";
@@ -519,6 +568,7 @@ $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";
@@ -543,9 +593,12 @@ $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";
@@ -554,6 +607,10 @@ $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";
@@ -599,6 +656,7 @@ $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";
@@ -608,6 +666,7 @@ $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";
@@ -616,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";
@@ -625,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";
@@ -655,6 +728,7 @@ $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";
@@ -664,20 +738,28 @@ $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";
@@ -687,11 +769,20 @@ $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";
@@ -702,6 +793,7 @@ $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";

+ 2 - 1
less/icons/font-awesome/scss/font-awesome.scss

@@ -1,5 +1,5 @@
 /*!
- *  Font Awesome 4.5.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)
  */
 
@@ -15,3 +15,4 @@
 @import "rotated-flipped";
 @import "stacked";
 @import "icons";
+@import "screen-reader";

BIN
plugins/images/tabs/deluge.png


Някои файлове не бяха показани, защото твърде много файлове са промени