diff --git a/.htaccess b/.htaccess new file mode 100644 index 0000000..9e25198 --- /dev/null +++ b/.htaccess @@ -0,0 +1,4 @@ +RewriteEngine On +RewriteCond %{REQUEST_FILENAME} !-f +RewriteCond %{REQUEST_FILENAME} !-d +RewriteRule ^(.*)$ index.php/$1 [L] \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..311f0d2 --- /dev/null +++ b/README.md @@ -0,0 +1,47 @@ +# ImgURL +ImgURL是一款简单、好用的图床程序,使用PHP + SQLite 3开发,不需要复杂的配置,开箱即用。 + +![](https://i.bmp.ovh/imgs/2018/12/06cf0ac3b7625b6b.png) + +![](https://i.bmp.ovh/imgs/2018/12/f0b565e2e0ffa166.png) + +![](https://i.bmp.ovh/imgs/2018/12/017c5e66b53db4d1.png) + +### 主要功能 +* 支持拽拖上传、多图上传、Ctrl + V粘贴上传、URL上传 +* 支持图片裁剪,自动生成缩略图 +* 限制访客上传数量 +* 图片压缩 +* 图片鉴黄 +* 友好的后台管理界面 + +### 环境要求 +* PHP >= 5.6 +* PDO_SQLite +* GD2 +* ImageMagick +* fileinfo +* pathinfo + +### 安装 +请参考帮助文档:[https://doc.xiaoz.me/](https://doc.xiaoz.me/#/imgurl2/) + +### Demo +* [http://test.imgurl.org/](http://test.imgurl.org/) +* 账号:xiaoz +* 密码:xiaoz.me + +### 请我喝一杯咖啡 +![](https://www.xiaoz.me/wp-content/uploads/2013/12/juanzeng260.png) + +### 鸣谢 +* [LayUI](https://github.com/sentsin/layui) +* [CodeIgniter](https://github.com/bcit-ci/CodeIgniter) +* [clipBoard.js](https://github.com/baixuexiyang/clipBoard.js) +* [Parsedown](https://github.com/erusev/parsedown) +* [jQuery](https://github.com/jquery/jquery) + +### 联系我 +* Blog:[https://www.xiaoz.me/](https://www.xiaoz.me/) +* 社区支持:[https://ttt.sh/](https://ttt.sh/category/6/) +* QQ:337003006 \ No newline at end of file diff --git a/application/.htaccess b/application/.htaccess new file mode 100644 index 0000000..6c63ed4 --- /dev/null +++ b/application/.htaccess @@ -0,0 +1,6 @@ + + Require all denied + + + Deny from all + \ No newline at end of file diff --git a/application/cache/index.html b/application/cache/index.html new file mode 100644 index 0000000..b702fbc --- /dev/null +++ b/application/cache/index.html @@ -0,0 +1,11 @@ + + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + diff --git a/application/config/autoload.php b/application/config/autoload.php new file mode 100644 index 0000000..7cdc901 --- /dev/null +++ b/application/config/autoload.php @@ -0,0 +1,135 @@ + 'ua'); +*/ +$autoload['libraries'] = array(); + +/* +| ------------------------------------------------------------------- +| Auto-load Drivers +| ------------------------------------------------------------------- +| These classes are located in system/libraries/ or in your +| application/libraries/ directory, but are also placed inside their +| own subdirectory and they extend the CI_Driver_Library class. They +| offer multiple interchangeable driver options. +| +| Prototype: +| +| $autoload['drivers'] = array('cache'); +| +| You can also supply an alternative property name to be assigned in +| the controller: +| +| $autoload['drivers'] = array('cache' => 'cch'); +| +*/ +$autoload['drivers'] = array(); + +/* +| ------------------------------------------------------------------- +| Auto-load Helper Files +| ------------------------------------------------------------------- +| Prototype: +| +| $autoload['helper'] = array('url', 'file'); +*/ +$autoload['helper'] = array(); + +/* +| ------------------------------------------------------------------- +| Auto-load Config files +| ------------------------------------------------------------------- +| Prototype: +| +| $autoload['config'] = array('config1', 'config2'); +| +| NOTE: This item is intended for use ONLY if you have created custom +| config files. Otherwise, leave it blank. +| +*/ +$autoload['config'] = array(); + +/* +| ------------------------------------------------------------------- +| Auto-load Language files +| ------------------------------------------------------------------- +| Prototype: +| +| $autoload['language'] = array('lang1', 'lang2'); +| +| NOTE: Do not include the "_lang" part of your file. For example +| "codeigniter_lang.php" would be referenced as array('codeigniter'); +| +*/ +$autoload['language'] = array(); + +/* +| ------------------------------------------------------------------- +| Auto-load Models +| ------------------------------------------------------------------- +| Prototype: +| +| $autoload['model'] = array('first_model', 'second_model'); +| +| You can also supply an alternative model name to be assigned +| in the controller: +| +| $autoload['model'] = array('first_model' => 'first'); +*/ +$autoload['model'] = array(); diff --git a/application/config/config.php b/application/config/config.php new file mode 100644 index 0000000..3a28882 --- /dev/null +++ b/application/config/config.php @@ -0,0 +1,523 @@ +]+$/i +| +| DO NOT CHANGE THIS UNLESS YOU FULLY UNDERSTAND THE REPERCUSSIONS!! +| +*/ +$config['permitted_uri_chars'] = 'a-z 0-9~%.:_\-'; + +/* +|-------------------------------------------------------------------------- +| Enable Query Strings +|-------------------------------------------------------------------------- +| +| By default CodeIgniter uses search-engine friendly segment based URLs: +| example.com/who/what/where/ +| +| You can optionally enable standard query string based URLs: +| example.com?who=me&what=something&where=here +| +| Options are: TRUE or FALSE (boolean) +| +| The other items let you set the query string 'words' that will +| invoke your controllers and its functions: +| example.com/index.php?c=controller&m=function +| +| Please note that some of the helpers won't work as expected when +| this feature is enabled, since CodeIgniter is designed primarily to +| use segment based URLs. +| +*/ +$config['enable_query_strings'] = FALSE; +$config['controller_trigger'] = 'c'; +$config['function_trigger'] = 'm'; +$config['directory_trigger'] = 'd'; + +/* +|-------------------------------------------------------------------------- +| Allow $_GET array +|-------------------------------------------------------------------------- +| +| By default CodeIgniter enables access to the $_GET array. If for some +| reason you would like to disable it, set 'allow_get_array' to FALSE. +| +| WARNING: This feature is DEPRECATED and currently available only +| for backwards compatibility purposes! +| +*/ +$config['allow_get_array'] = TRUE; + +/* +|-------------------------------------------------------------------------- +| Error Logging Threshold +|-------------------------------------------------------------------------- +| +| You can enable error logging by setting a threshold over zero. The +| threshold determines what gets logged. Threshold options are: +| +| 0 = Disables logging, Error logging TURNED OFF +| 1 = Error Messages (including PHP errors) +| 2 = Debug Messages +| 3 = Informational Messages +| 4 = All Messages +| +| You can also pass an array with threshold levels to show individual error types +| +| array(2) = Debug Messages, without Error Messages +| +| For a live site you'll usually only enable Errors (1) to be logged otherwise +| your log files will fill up very fast. +| +*/ +$config['log_threshold'] = 0; + +/* +|-------------------------------------------------------------------------- +| Error Logging Directory Path +|-------------------------------------------------------------------------- +| +| Leave this BLANK unless you would like to set something other than the default +| application/logs/ directory. Use a full server path with trailing slash. +| +*/ +$config['log_path'] = ''; + +/* +|-------------------------------------------------------------------------- +| Log File Extension +|-------------------------------------------------------------------------- +| +| The default filename extension for log files. The default 'php' allows for +| protecting the log files via basic scripting, when they are to be stored +| under a publicly accessible directory. +| +| Note: Leaving it blank will default to 'php'. +| +*/ +$config['log_file_extension'] = ''; + +/* +|-------------------------------------------------------------------------- +| Log File Permissions +|-------------------------------------------------------------------------- +| +| The file system permissions to be applied on newly created log files. +| +| IMPORTANT: This MUST be an integer (no quotes) and you MUST use octal +| integer notation (i.e. 0700, 0644, etc.) +*/ +$config['log_file_permissions'] = 0644; + +/* +|-------------------------------------------------------------------------- +| Date Format for Logs +|-------------------------------------------------------------------------- +| +| Each item that is logged has an associated date. You can use PHP date +| codes to set your own date formatting +| +*/ +$config['log_date_format'] = 'Y-m-d H:i:s'; + +/* +|-------------------------------------------------------------------------- +| Error Views Directory Path +|-------------------------------------------------------------------------- +| +| Leave this BLANK unless you would like to set something other than the default +| application/views/errors/ directory. Use a full server path with trailing slash. +| +*/ +$config['error_views_path'] = ''; + +/* +|-------------------------------------------------------------------------- +| Cache Directory Path +|-------------------------------------------------------------------------- +| +| Leave this BLANK unless you would like to set something other than the default +| application/cache/ directory. Use a full server path with trailing slash. +| +*/ +$config['cache_path'] = ''; + +/* +|-------------------------------------------------------------------------- +| Cache Include Query String +|-------------------------------------------------------------------------- +| +| Whether to take the URL query string into consideration when generating +| output cache files. Valid options are: +| +| FALSE = Disabled +| TRUE = Enabled, take all query parameters into account. +| Please be aware that this may result in numerous cache +| files generated for the same page over and over again. +| array('q') = Enabled, but only take into account the specified list +| of query parameters. +| +*/ +$config['cache_query_string'] = FALSE; + +/* +|-------------------------------------------------------------------------- +| Encryption Key +|-------------------------------------------------------------------------- +| +| If you use the Encryption class, you must set an encryption key. +| See the user guide for more info. +| +| https://codeigniter.com/user_guide/libraries/encryption.html +| +*/ +$config['encryption_key'] = ''; + +/* +|-------------------------------------------------------------------------- +| Session Variables +|-------------------------------------------------------------------------- +| +| 'sess_driver' +| +| The storage driver to use: files, database, redis, memcached +| +| 'sess_cookie_name' +| +| The session cookie name, must contain only [0-9a-z_-] characters +| +| 'sess_expiration' +| +| The number of SECONDS you want the session to last. +| Setting to 0 (zero) means expire when the browser is closed. +| +| 'sess_save_path' +| +| The location to save sessions to, driver dependent. +| +| For the 'files' driver, it's a path to a writable directory. +| WARNING: Only absolute paths are supported! +| +| For the 'database' driver, it's a table name. +| Please read up the manual for the format with other session drivers. +| +| IMPORTANT: You are REQUIRED to set a valid save path! +| +| 'sess_match_ip' +| +| Whether to match the user's IP address when reading the session data. +| +| WARNING: If you're using the database driver, don't forget to update +| your session table's PRIMARY KEY when changing this setting. +| +| 'sess_time_to_update' +| +| How many seconds between CI regenerating the session ID. +| +| 'sess_regenerate_destroy' +| +| Whether to destroy session data associated with the old session ID +| when auto-regenerating the session ID. When set to FALSE, the data +| will be later deleted by the garbage collector. +| +| Other session cookie settings are shared with the rest of the application, +| except for 'cookie_prefix' and 'cookie_httponly', which are ignored here. +| +*/ +$config['sess_driver'] = 'files'; +$config['sess_cookie_name'] = 'ci_session'; +$config['sess_expiration'] = 7200; +$config['sess_save_path'] = NULL; +$config['sess_match_ip'] = FALSE; +$config['sess_time_to_update'] = 300; +$config['sess_regenerate_destroy'] = FALSE; + +/* +|-------------------------------------------------------------------------- +| Cookie Related Variables +|-------------------------------------------------------------------------- +| +| 'cookie_prefix' = Set a cookie name prefix if you need to avoid collisions +| 'cookie_domain' = Set to .your-domain.com for site-wide cookies +| 'cookie_path' = Typically will be a forward slash +| 'cookie_secure' = Cookie will only be set if a secure HTTPS connection exists. +| 'cookie_httponly' = Cookie will only be accessible via HTTP(S) (no javascript) +| +| Note: These settings (with the exception of 'cookie_prefix' and +| 'cookie_httponly') will also affect sessions. +| +*/ +$config['cookie_prefix'] = ''; +$config['cookie_domain'] = ''; +$config['cookie_path'] = '/'; +$config['cookie_secure'] = FALSE; +$config['cookie_httponly'] = FALSE; + +/* +|-------------------------------------------------------------------------- +| Standardize newlines +|-------------------------------------------------------------------------- +| +| Determines whether to standardize newline characters in input data, +| meaning to replace \r\n, \r, \n occurrences with the PHP_EOL value. +| +| WARNING: This feature is DEPRECATED and currently available only +| for backwards compatibility purposes! +| +*/ +$config['standardize_newlines'] = FALSE; + +/* +|-------------------------------------------------------------------------- +| Global XSS Filtering +|-------------------------------------------------------------------------- +| +| Determines whether the XSS filter is always active when GET, POST or +| COOKIE data is encountered +| +| WARNING: This feature is DEPRECATED and currently available only +| for backwards compatibility purposes! +| +*/ +$config['global_xss_filtering'] = FALSE; + +/* +|-------------------------------------------------------------------------- +| Cross Site Request Forgery +|-------------------------------------------------------------------------- +| Enables a CSRF cookie token to be set. When set to TRUE, token will be +| checked on a submitted form. If you are accepting user data, it is strongly +| recommended CSRF protection be enabled. +| +| 'csrf_token_name' = The token name +| 'csrf_cookie_name' = The cookie name +| 'csrf_expire' = The number in seconds the token should expire. +| 'csrf_regenerate' = Regenerate token on every submission +| 'csrf_exclude_uris' = Array of URIs which ignore CSRF checks +*/ +$config['csrf_protection'] = FALSE; +$config['csrf_token_name'] = 'csrf_test_name'; +$config['csrf_cookie_name'] = 'csrf_cookie_name'; +$config['csrf_expire'] = 7200; +$config['csrf_regenerate'] = TRUE; +$config['csrf_exclude_uris'] = array(); + +/* +|-------------------------------------------------------------------------- +| Output Compression +|-------------------------------------------------------------------------- +| +| Enables Gzip output compression for faster page loads. When enabled, +| the output class will test whether your server supports Gzip. +| Even if it does, however, not all browsers support compression +| so enable only if you are reasonably sure your visitors can handle it. +| +| Only used if zlib.output_compression is turned off in your php.ini. +| Please do not use it together with httpd-level output compression. +| +| VERY IMPORTANT: If you are getting a blank page when compression is enabled it +| means you are prematurely outputting something to your browser. It could +| even be a line of whitespace at the end of one of your scripts. For +| compression to work, nothing can be sent before the output buffer is called +| by the output class. Do not 'echo' any values with compression enabled. +| +*/ +$config['compress_output'] = FALSE; + +/* +|-------------------------------------------------------------------------- +| Master Time Reference +|-------------------------------------------------------------------------- +| +| Options are 'local' or any PHP supported timezone. This preference tells +| the system whether to use your server's local time as the master 'now' +| reference, or convert it to the configured one timezone. See the 'date +| helper' page of the user guide for information regarding date handling. +| +*/ +$config['time_reference'] = 'local'; + +/* +|-------------------------------------------------------------------------- +| Rewrite PHP Short Tags +|-------------------------------------------------------------------------- +| +| If your PHP installation does not have short tag support enabled CI +| can rewrite the tags on-the-fly, enabling you to utilize that syntax +| in your view files. Options are TRUE or FALSE (boolean) +| +| Note: You need to have eval() enabled for this to work. +| +*/ +$config['rewrite_short_tags'] = FALSE; + +/* +|-------------------------------------------------------------------------- +| Reverse Proxy IPs +|-------------------------------------------------------------------------- +| +| If your server is behind a reverse proxy, you must whitelist the proxy +| IP addresses from which CodeIgniter should trust headers such as +| HTTP_X_FORWARDED_FOR and HTTP_CLIENT_IP in order to properly identify +| the visitor's IP address. +| +| You can use both an array or a comma-separated list of proxy addresses, +| as well as specifying whole subnets. Here are a few examples: +| +| Comma-separated: '10.0.1.200,192.168.5.0/24' +| Array: array('10.0.1.200', '192.168.5.0/24') +*/ +$config['proxy_ips'] = ''; diff --git a/application/config/constants.php b/application/config/constants.php new file mode 100644 index 0000000..18d3b4b --- /dev/null +++ b/application/config/constants.php @@ -0,0 +1,85 @@ +db->last_query() and profiling of DB queries. +| When you run a query, with this setting set to TRUE (default), +| CodeIgniter will store the SQL statement for debugging purposes. +| However, this may cause high memory usage, especially if you run +| a lot of SQL queries ... disable this to avoid that problem. +| +| The $active_group variable lets you choose which connection group to +| make active. By default there is only one group (the 'default' group). +| +| The $query_builder variables lets you determine whether or not to load +| the query builder class. +*/ +$active_group = 'default'; +$query_builder = TRUE; + +$db['default'] = array( + 'dsn' => 'sqlite:'.FCPATH.'data/imgurl.db3', + 'hostname' => 'localhost', + 'username' => '', + 'password' => '', + 'database' => '', + 'dbdriver' => 'pdo', + 'dbprefix' => 'img_', + 'pconnect' => FALSE, + 'db_debug' => (ENVIRONMENT !== 'production'), + 'cache_on' => FALSE, + 'cachedir' => '', + 'char_set' => 'utf8', + 'dbcollat' => 'utf8_general_ci', + 'swap_pre' => '', + 'encrypt' => FALSE, + 'compress' => FALSE, + 'stricton' => FALSE, + 'failover' => array(), + 'save_queries' => TRUE +); diff --git a/application/config/doctypes.php b/application/config/doctypes.php new file mode 100644 index 0000000..59a7991 --- /dev/null +++ b/application/config/doctypes.php @@ -0,0 +1,24 @@ + '', + 'xhtml1-strict' => '', + 'xhtml1-trans' => '', + 'xhtml1-frame' => '', + 'xhtml-basic11' => '', + 'html5' => '', + 'html4-strict' => '', + 'html4-trans' => '', + 'html4-frame' => '', + 'mathml1' => '', + 'mathml2' => '', + 'svg10' => '', + 'svg11' => '', + 'svg11-basic' => '', + 'svg11-tiny' => '', + 'xhtml-math-svg-xh' => '', + 'xhtml-math-svg-sh' => '', + 'xhtml-rdfa-1' => '', + 'xhtml-rdfa-2' => '' +); diff --git a/application/config/foreign_chars.php b/application/config/foreign_chars.php new file mode 100644 index 0000000..995f483 --- /dev/null +++ b/application/config/foreign_chars.php @@ -0,0 +1,103 @@ + 'ae', + '/ö|œ/' => 'oe', + '/ü/' => 'ue', + '/Ä/' => 'Ae', + '/Ü/' => 'Ue', + '/Ö/' => 'Oe', + '/À|Á|Â|Ã|Ä|Å|Ǻ|Ā|Ă|Ą|Ǎ|Α|Ά|Ả|Ạ|Ầ|Ẫ|Ẩ|Ậ|Ằ|Ắ|Ẵ|Ẳ|Ặ|А/' => 'A', + '/à|á|â|ã|å|ǻ|ā|ă|ą|ǎ|ª|α|ά|ả|ạ|ầ|ấ|ẫ|ẩ|ậ|ằ|ắ|ẵ|ẳ|ặ|а/' => 'a', + '/Б/' => 'B', + '/б/' => 'b', + '/Ç|Ć|Ĉ|Ċ|Č/' => 'C', + '/ç|ć|ĉ|ċ|č/' => 'c', + '/Д/' => 'D', + '/д/' => 'd', + '/Ð|Ď|Đ|Δ/' => 'Dj', + '/ð|ď|đ|δ/' => 'dj', + '/È|É|Ê|Ë|Ē|Ĕ|Ė|Ę|Ě|Ε|Έ|Ẽ|Ẻ|Ẹ|Ề|Ế|Ễ|Ể|Ệ|Е|Э/' => 'E', + '/è|é|ê|ë|ē|ĕ|ė|ę|ě|έ|ε|ẽ|ẻ|ẹ|ề|ế|ễ|ể|ệ|е|э/' => 'e', + '/Ф/' => 'F', + '/ф/' => 'f', + '/Ĝ|Ğ|Ġ|Ģ|Γ|Г|Ґ/' => 'G', + '/ĝ|ğ|ġ|ģ|γ|г|ґ/' => 'g', + '/Ĥ|Ħ/' => 'H', + '/ĥ|ħ/' => 'h', + '/Ì|Í|Î|Ï|Ĩ|Ī|Ĭ|Ǐ|Į|İ|Η|Ή|Ί|Ι|Ϊ|Ỉ|Ị|И|Ы/' => 'I', + '/ì|í|î|ï|ĩ|ī|ĭ|ǐ|į|ı|η|ή|ί|ι|ϊ|ỉ|ị|и|ы|ї/' => 'i', + '/Ĵ/' => 'J', + '/ĵ/' => 'j', + '/Ķ|Κ|К/' => 'K', + '/ķ|κ|к/' => 'k', + '/Ĺ|Ļ|Ľ|Ŀ|Ł|Λ|Л/' => 'L', + '/ĺ|ļ|ľ|ŀ|ł|λ|л/' => 'l', + '/М/' => 'M', + '/м/' => 'm', + '/Ñ|Ń|Ņ|Ň|Ν|Н/' => 'N', + '/ñ|ń|ņ|ň|ʼn|ν|н/' => 'n', + '/Ò|Ó|Ô|Õ|Ō|Ŏ|Ǒ|Ő|Ơ|Ø|Ǿ|Ο|Ό|Ω|Ώ|Ỏ|Ọ|Ồ|Ố|Ỗ|Ổ|Ộ|Ờ|Ớ|Ỡ|Ở|Ợ|О/' => 'O', + '/ò|ó|ô|õ|ō|ŏ|ǒ|ő|ơ|ø|ǿ|º|ο|ό|ω|ώ|ỏ|ọ|ồ|ố|ỗ|ổ|ộ|ờ|ớ|ỡ|ở|ợ|о/' => 'o', + '/П/' => 'P', + '/п/' => 'p', + '/Ŕ|Ŗ|Ř|Ρ|Р/' => 'R', + '/ŕ|ŗ|ř|ρ|р/' => 'r', + '/Ś|Ŝ|Ş|Ș|Š|Σ|С/' => 'S', + '/ś|ŝ|ş|ș|š|ſ|σ|ς|с/' => 's', + '/Ț|Ţ|Ť|Ŧ|τ|Т/' => 'T', + '/ț|ţ|ť|ŧ|т/' => 't', + '/Þ|þ/' => 'th', + '/Ù|Ú|Û|Ũ|Ū|Ŭ|Ů|Ű|Ų|Ư|Ǔ|Ǖ|Ǘ|Ǚ|Ǜ|Ũ|Ủ|Ụ|Ừ|Ứ|Ữ|Ử|Ự|У/' => 'U', + '/ù|ú|û|ũ|ū|ŭ|ů|ű|ų|ư|ǔ|ǖ|ǘ|ǚ|ǜ|υ|ύ|ϋ|ủ|ụ|ừ|ứ|ữ|ử|ự|у/' => 'u', + '/Ƴ|Ɏ|Ỵ|Ẏ|Ӳ|Ӯ|Ў|Ý|Ÿ|Ŷ|Υ|Ύ|Ϋ|Ỳ|Ỹ|Ỷ|Ỵ|Й/' => 'Y', + '/ẙ|ʏ|ƴ|ɏ|ỵ|ẏ|ӳ|ӯ|ў|ý|ÿ|ŷ|ỳ|ỹ|ỷ|ỵ|й/' => 'y', + '/В/' => 'V', + '/в/' => 'v', + '/Ŵ/' => 'W', + '/ŵ/' => 'w', + '/Ź|Ż|Ž|Ζ|З/' => 'Z', + '/ź|ż|ž|ζ|з/' => 'z', + '/Æ|Ǽ/' => 'AE', + '/ß/' => 'ss', + '/IJ/' => 'IJ', + '/ij/' => 'ij', + '/Œ/' => 'OE', + '/ƒ/' => 'f', + '/ξ/' => 'ks', + '/π/' => 'p', + '/β/' => 'v', + '/μ/' => 'm', + '/ψ/' => 'ps', + '/Ё/' => 'Yo', + '/ё/' => 'yo', + '/Є/' => 'Ye', + '/є/' => 'ye', + '/Ї/' => 'Yi', + '/Ж/' => 'Zh', + '/ж/' => 'zh', + '/Х/' => 'Kh', + '/х/' => 'kh', + '/Ц/' => 'Ts', + '/ц/' => 'ts', + '/Ч/' => 'Ch', + '/ч/' => 'ch', + '/Ш/' => 'Sh', + '/ш/' => 'sh', + '/Щ/' => 'Shch', + '/щ/' => 'shch', + '/Ъ|ъ|Ь|ь/' => '', + '/Ю/' => 'Yu', + '/ю/' => 'yu', + '/Я/' => 'Ya', + '/я/' => 'ya' +); diff --git a/application/config/hooks.php b/application/config/hooks.php new file mode 100644 index 0000000..a8f38a5 --- /dev/null +++ b/application/config/hooks.php @@ -0,0 +1,13 @@ + + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + diff --git a/application/config/memcached.php b/application/config/memcached.php new file mode 100644 index 0000000..5c23b39 --- /dev/null +++ b/application/config/memcached.php @@ -0,0 +1,19 @@ + array( + 'hostname' => '127.0.0.1', + 'port' => '11211', + 'weight' => '1', + ), +); diff --git a/application/config/migration.php b/application/config/migration.php new file mode 100644 index 0000000..4b585a6 --- /dev/null +++ b/application/config/migration.php @@ -0,0 +1,84 @@ +migration->current() this is the version that schema will +| be upgraded / downgraded to. +| +*/ +$config['migration_version'] = 0; + +/* +|-------------------------------------------------------------------------- +| Migrations Path +|-------------------------------------------------------------------------- +| +| Path to your migrations folder. +| Typically, it will be within your application path. +| Also, writing permission is required within the migrations path. +| +*/ +$config['migration_path'] = APPPATH.'migrations/'; diff --git a/application/config/mimes.php b/application/config/mimes.php new file mode 100644 index 0000000..0ec9db0 --- /dev/null +++ b/application/config/mimes.php @@ -0,0 +1,184 @@ + array('application/mac-binhex40', 'application/mac-binhex', 'application/x-binhex40', 'application/x-mac-binhex40'), + 'cpt' => 'application/mac-compactpro', + 'csv' => array('text/x-comma-separated-values', 'text/comma-separated-values', 'application/octet-stream', 'application/vnd.ms-excel', 'application/x-csv', 'text/x-csv', 'text/csv', 'application/csv', 'application/excel', 'application/vnd.msexcel', 'text/plain'), + 'bin' => array('application/macbinary', 'application/mac-binary', 'application/octet-stream', 'application/x-binary', 'application/x-macbinary'), + 'dms' => 'application/octet-stream', + 'lha' => 'application/octet-stream', + 'lzh' => 'application/octet-stream', + 'exe' => array('application/octet-stream', 'application/x-msdownload'), + 'class' => 'application/octet-stream', + 'psd' => array('application/x-photoshop', 'image/vnd.adobe.photoshop'), + 'so' => 'application/octet-stream', + 'sea' => 'application/octet-stream', + 'dll' => 'application/octet-stream', + 'oda' => 'application/oda', + 'pdf' => array('application/pdf', 'application/force-download', 'application/x-download', 'binary/octet-stream'), + 'ai' => array('application/pdf', 'application/postscript'), + 'eps' => 'application/postscript', + 'ps' => 'application/postscript', + 'smi' => 'application/smil', + 'smil' => 'application/smil', + 'mif' => 'application/vnd.mif', + 'xls' => array('application/vnd.ms-excel', 'application/msexcel', 'application/x-msexcel', 'application/x-ms-excel', 'application/x-excel', 'application/x-dos_ms_excel', 'application/xls', 'application/x-xls', 'application/excel', 'application/download', 'application/vnd.ms-office', 'application/msword'), + 'ppt' => array('application/powerpoint', 'application/vnd.ms-powerpoint', 'application/vnd.ms-office', 'application/msword'), + 'pptx' => array('application/vnd.openxmlformats-officedocument.presentationml.presentation', 'application/x-zip', 'application/zip'), + 'wbxml' => 'application/wbxml', + 'wmlc' => 'application/wmlc', + 'dcr' => 'application/x-director', + 'dir' => 'application/x-director', + 'dxr' => 'application/x-director', + 'dvi' => 'application/x-dvi', + 'gtar' => 'application/x-gtar', + 'gz' => 'application/x-gzip', + 'gzip' => 'application/x-gzip', + 'php' => array('application/x-httpd-php', 'application/php', 'application/x-php', 'text/php', 'text/x-php', 'application/x-httpd-php-source'), + 'php4' => 'application/x-httpd-php', + 'php3' => 'application/x-httpd-php', + 'phtml' => 'application/x-httpd-php', + 'phps' => 'application/x-httpd-php-source', + 'js' => array('application/x-javascript', 'text/plain'), + 'swf' => 'application/x-shockwave-flash', + 'sit' => 'application/x-stuffit', + 'tar' => 'application/x-tar', + 'tgz' => array('application/x-tar', 'application/x-gzip-compressed'), + 'z' => 'application/x-compress', + 'xhtml' => 'application/xhtml+xml', + 'xht' => 'application/xhtml+xml', + 'zip' => array('application/x-zip', 'application/zip', 'application/x-zip-compressed', 'application/s-compressed', 'multipart/x-zip'), + 'rar' => array('application/x-rar', 'application/rar', 'application/x-rar-compressed'), + 'mid' => 'audio/midi', + 'midi' => 'audio/midi', + 'mpga' => 'audio/mpeg', + 'mp2' => 'audio/mpeg', + 'mp3' => array('audio/mpeg', 'audio/mpg', 'audio/mpeg3', 'audio/mp3'), + 'aif' => array('audio/x-aiff', 'audio/aiff'), + 'aiff' => array('audio/x-aiff', 'audio/aiff'), + 'aifc' => 'audio/x-aiff', + 'ram' => 'audio/x-pn-realaudio', + 'rm' => 'audio/x-pn-realaudio', + 'rpm' => 'audio/x-pn-realaudio-plugin', + 'ra' => 'audio/x-realaudio', + 'rv' => 'video/vnd.rn-realvideo', + 'wav' => array('audio/x-wav', 'audio/wave', 'audio/wav'), + 'bmp' => array('image/bmp', 'image/x-bmp', 'image/x-bitmap', 'image/x-xbitmap', 'image/x-win-bitmap', 'image/x-windows-bmp', 'image/ms-bmp', 'image/x-ms-bmp', 'application/bmp', 'application/x-bmp', 'application/x-win-bitmap'), + 'gif' => 'image/gif', + 'jpeg' => array('image/jpeg', 'image/pjpeg'), + 'jpg' => array('image/jpeg', 'image/pjpeg'), + 'jpe' => array('image/jpeg', 'image/pjpeg'), + 'jp2' => array('image/jp2', 'video/mj2', 'image/jpx', 'image/jpm'), + 'j2k' => array('image/jp2', 'video/mj2', 'image/jpx', 'image/jpm'), + 'jpf' => array('image/jp2', 'video/mj2', 'image/jpx', 'image/jpm'), + 'jpg2' => array('image/jp2', 'video/mj2', 'image/jpx', 'image/jpm'), + 'jpx' => array('image/jp2', 'video/mj2', 'image/jpx', 'image/jpm'), + 'jpm' => array('image/jp2', 'video/mj2', 'image/jpx', 'image/jpm'), + 'mj2' => array('image/jp2', 'video/mj2', 'image/jpx', 'image/jpm'), + 'mjp2' => array('image/jp2', 'video/mj2', 'image/jpx', 'image/jpm'), + 'png' => array('image/png', 'image/x-png'), + 'tiff' => 'image/tiff', + 'tif' => 'image/tiff', + 'css' => array('text/css', 'text/plain'), + 'html' => array('text/html', 'text/plain'), + 'htm' => array('text/html', 'text/plain'), + 'shtml' => array('text/html', 'text/plain'), + 'txt' => 'text/plain', + 'text' => 'text/plain', + 'log' => array('text/plain', 'text/x-log'), + 'rtx' => 'text/richtext', + 'rtf' => 'text/rtf', + 'xml' => array('application/xml', 'text/xml', 'text/plain'), + 'xsl' => array('application/xml', 'text/xsl', 'text/xml'), + 'mpeg' => 'video/mpeg', + 'mpg' => 'video/mpeg', + 'mpe' => 'video/mpeg', + 'qt' => 'video/quicktime', + 'mov' => 'video/quicktime', + 'avi' => array('video/x-msvideo', 'video/msvideo', 'video/avi', 'application/x-troff-msvideo'), + 'movie' => 'video/x-sgi-movie', + 'doc' => array('application/msword', 'application/vnd.ms-office'), + 'docx' => array('application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/zip', 'application/msword', 'application/x-zip'), + 'dot' => array('application/msword', 'application/vnd.ms-office'), + 'dotx' => array('application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/zip', 'application/msword'), + 'xlsx' => array('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/zip', 'application/vnd.ms-excel', 'application/msword', 'application/x-zip'), + 'word' => array('application/msword', 'application/octet-stream'), + 'xl' => 'application/excel', + 'eml' => 'message/rfc822', + 'json' => array('application/json', 'text/json'), + 'pem' => array('application/x-x509-user-cert', 'application/x-pem-file', 'application/octet-stream'), + 'p10' => array('application/x-pkcs10', 'application/pkcs10'), + 'p12' => 'application/x-pkcs12', + 'p7a' => 'application/x-pkcs7-signature', + 'p7c' => array('application/pkcs7-mime', 'application/x-pkcs7-mime'), + 'p7m' => array('application/pkcs7-mime', 'application/x-pkcs7-mime'), + 'p7r' => 'application/x-pkcs7-certreqresp', + 'p7s' => 'application/pkcs7-signature', + 'crt' => array('application/x-x509-ca-cert', 'application/x-x509-user-cert', 'application/pkix-cert'), + 'crl' => array('application/pkix-crl', 'application/pkcs-crl'), + 'der' => 'application/x-x509-ca-cert', + 'kdb' => 'application/octet-stream', + 'pgp' => 'application/pgp', + 'gpg' => 'application/gpg-keys', + 'sst' => 'application/octet-stream', + 'csr' => 'application/octet-stream', + 'rsa' => 'application/x-pkcs7', + 'cer' => array('application/pkix-cert', 'application/x-x509-ca-cert'), + '3g2' => 'video/3gpp2', + '3gp' => array('video/3gp', 'video/3gpp'), + 'mp4' => 'video/mp4', + 'm4a' => 'audio/x-m4a', + 'f4v' => array('video/mp4', 'video/x-f4v'), + 'flv' => 'video/x-flv', + 'webm' => 'video/webm', + 'aac' => 'audio/x-acc', + 'm4u' => 'application/vnd.mpegurl', + 'm3u' => 'text/plain', + 'xspf' => 'application/xspf+xml', + 'vlc' => 'application/videolan', + 'wmv' => array('video/x-ms-wmv', 'video/x-ms-asf'), + 'au' => 'audio/x-au', + 'ac3' => 'audio/ac3', + 'flac' => 'audio/x-flac', + 'ogg' => array('audio/ogg', 'video/ogg', 'application/ogg'), + 'kmz' => array('application/vnd.google-earth.kmz', 'application/zip', 'application/x-zip'), + 'kml' => array('application/vnd.google-earth.kml+xml', 'application/xml', 'text/xml'), + 'ics' => 'text/calendar', + 'ical' => 'text/calendar', + 'zsh' => 'text/x-scriptzsh', + '7z' => array('application/x-7z-compressed', 'application/x-compressed', 'application/x-zip-compressed', 'application/zip', 'multipart/x-zip'), + '7zip' => array('application/x-7z-compressed', 'application/x-compressed', 'application/x-zip-compressed', 'application/zip', 'multipart/x-zip'), + 'cdr' => array('application/cdr', 'application/coreldraw', 'application/x-cdr', 'application/x-coreldraw', 'image/cdr', 'image/x-cdr', 'zz-application/zz-winassoc-cdr'), + 'wma' => array('audio/x-ms-wma', 'video/x-ms-asf'), + 'jar' => array('application/java-archive', 'application/x-java-application', 'application/x-jar', 'application/x-compressed'), + 'svg' => array('image/svg+xml', 'application/xml', 'text/xml'), + 'vcf' => 'text/x-vcard', + 'srt' => array('text/srt', 'text/plain'), + 'vtt' => array('text/vtt', 'text/plain'), + 'ico' => array('image/x-icon', 'image/x-ico', 'image/vnd.microsoft.icon'), + 'odc' => 'application/vnd.oasis.opendocument.chart', + 'otc' => 'application/vnd.oasis.opendocument.chart-template', + 'odf' => 'application/vnd.oasis.opendocument.formula', + 'otf' => 'application/vnd.oasis.opendocument.formula-template', + 'odg' => 'application/vnd.oasis.opendocument.graphics', + 'otg' => 'application/vnd.oasis.opendocument.graphics-template', + 'odi' => 'application/vnd.oasis.opendocument.image', + 'oti' => 'application/vnd.oasis.opendocument.image-template', + 'odp' => 'application/vnd.oasis.opendocument.presentation', + 'otp' => 'application/vnd.oasis.opendocument.presentation-template', + 'ods' => 'application/vnd.oasis.opendocument.spreadsheet', + 'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template', + 'odt' => 'application/vnd.oasis.opendocument.text', + 'odm' => 'application/vnd.oasis.opendocument.text-master', + 'ott' => 'application/vnd.oasis.opendocument.text-template', + 'oth' => 'application/vnd.oasis.opendocument.text-web' +); diff --git a/application/config/profiler.php b/application/config/profiler.php new file mode 100644 index 0000000..3db22e3 --- /dev/null +++ b/application/config/profiler.php @@ -0,0 +1,14 @@ + my_controller/index +| my-controller/my-method -> my_controller/my_method +*/ +$route['default_controller'] = 'home'; +$route['404_override'] = ''; +$route['translate_uri_dashes'] = FALSE; diff --git a/application/config/smileys.php b/application/config/smileys.php new file mode 100644 index 0000000..abf9a89 --- /dev/null +++ b/application/config/smileys.php @@ -0,0 +1,64 @@ + array('grin.gif', '19', '19', 'grin'), + ':lol:' => array('lol.gif', '19', '19', 'LOL'), + ':cheese:' => array('cheese.gif', '19', '19', 'cheese'), + ':)' => array('smile.gif', '19', '19', 'smile'), + ';-)' => array('wink.gif', '19', '19', 'wink'), + ';)' => array('wink.gif', '19', '19', 'wink'), + ':smirk:' => array('smirk.gif', '19', '19', 'smirk'), + ':roll:' => array('rolleyes.gif', '19', '19', 'rolleyes'), + ':-S' => array('confused.gif', '19', '19', 'confused'), + ':wow:' => array('surprise.gif', '19', '19', 'surprised'), + ':bug:' => array('bigsurprise.gif', '19', '19', 'big surprise'), + ':-P' => array('tongue_laugh.gif', '19', '19', 'tongue laugh'), + '%-P' => array('tongue_rolleye.gif', '19', '19', 'tongue rolleye'), + ';-P' => array('tongue_wink.gif', '19', '19', 'tongue wink'), + ':P' => array('raspberry.gif', '19', '19', 'raspberry'), + ':blank:' => array('blank.gif', '19', '19', 'blank stare'), + ':long:' => array('longface.gif', '19', '19', 'long face'), + ':ohh:' => array('ohh.gif', '19', '19', 'ohh'), + ':grrr:' => array('grrr.gif', '19', '19', 'grrr'), + ':gulp:' => array('gulp.gif', '19', '19', 'gulp'), + '8-/' => array('ohoh.gif', '19', '19', 'oh oh'), + ':down:' => array('downer.gif', '19', '19', 'downer'), + ':red:' => array('embarrassed.gif', '19', '19', 'red face'), + ':sick:' => array('sick.gif', '19', '19', 'sick'), + ':shut:' => array('shuteye.gif', '19', '19', 'shut eye'), + ':-/' => array('hmm.gif', '19', '19', 'hmmm'), + '>:(' => array('mad.gif', '19', '19', 'mad'), + ':mad:' => array('mad.gif', '19', '19', 'mad'), + '>:-(' => array('angry.gif', '19', '19', 'angry'), + ':angry:' => array('angry.gif', '19', '19', 'angry'), + ':zip:' => array('zip.gif', '19', '19', 'zipper'), + ':kiss:' => array('kiss.gif', '19', '19', 'kiss'), + ':ahhh:' => array('shock.gif', '19', '19', 'shock'), + ':coolsmile:' => array('shade_smile.gif', '19', '19', 'cool smile'), + ':coolsmirk:' => array('shade_smirk.gif', '19', '19', 'cool smirk'), + ':coolgrin:' => array('shade_grin.gif', '19', '19', 'cool grin'), + ':coolhmm:' => array('shade_hmm.gif', '19', '19', 'cool hmm'), + ':coolmad:' => array('shade_mad.gif', '19', '19', 'cool mad'), + ':coolcheese:' => array('shade_cheese.gif', '19', '19', 'cool cheese'), + ':vampire:' => array('vampire.gif', '19', '19', 'vampire'), + ':snake:' => array('snake.gif', '19', '19', 'snake'), + ':exclaim:' => array('exclaim.gif', '19', '19', 'exclaim'), + ':question:' => array('question.gif', '19', '19', 'question') + +); diff --git a/application/config/user_agents.php b/application/config/user_agents.php new file mode 100644 index 0000000..b6c8563 --- /dev/null +++ b/application/config/user_agents.php @@ -0,0 +1,214 @@ + 'Windows 10', + 'windows nt 6.3' => 'Windows 8.1', + 'windows nt 6.2' => 'Windows 8', + 'windows nt 6.1' => 'Windows 7', + 'windows nt 6.0' => 'Windows Vista', + 'windows nt 5.2' => 'Windows 2003', + 'windows nt 5.1' => 'Windows XP', + 'windows nt 5.0' => 'Windows 2000', + 'windows nt 4.0' => 'Windows NT 4.0', + 'winnt4.0' => 'Windows NT 4.0', + 'winnt 4.0' => 'Windows NT', + 'winnt' => 'Windows NT', + 'windows 98' => 'Windows 98', + 'win98' => 'Windows 98', + 'windows 95' => 'Windows 95', + 'win95' => 'Windows 95', + 'windows phone' => 'Windows Phone', + 'windows' => 'Unknown Windows OS', + 'android' => 'Android', + 'blackberry' => 'BlackBerry', + 'iphone' => 'iOS', + 'ipad' => 'iOS', + 'ipod' => 'iOS', + 'os x' => 'Mac OS X', + 'ppc mac' => 'Power PC Mac', + 'freebsd' => 'FreeBSD', + 'ppc' => 'Macintosh', + 'linux' => 'Linux', + 'debian' => 'Debian', + 'sunos' => 'Sun Solaris', + 'beos' => 'BeOS', + 'apachebench' => 'ApacheBench', + 'aix' => 'AIX', + 'irix' => 'Irix', + 'osf' => 'DEC OSF', + 'hp-ux' => 'HP-UX', + 'netbsd' => 'NetBSD', + 'bsdi' => 'BSDi', + 'openbsd' => 'OpenBSD', + 'gnu' => 'GNU/Linux', + 'unix' => 'Unknown Unix OS', + 'symbian' => 'Symbian OS' +); + + +// The order of this array should NOT be changed. Many browsers return +// multiple browser types so we want to identify the sub-type first. +$browsers = array( + 'OPR' => 'Opera', + 'Flock' => 'Flock', + 'Edge' => 'Edge', + 'Chrome' => 'Chrome', + // Opera 10+ always reports Opera/9.80 and appends Version/ to the user agent string + 'Opera.*?Version' => 'Opera', + 'Opera' => 'Opera', + 'MSIE' => 'Internet Explorer', + 'Internet Explorer' => 'Internet Explorer', + 'Trident.* rv' => 'Internet Explorer', + 'Shiira' => 'Shiira', + 'Firefox' => 'Firefox', + 'Chimera' => 'Chimera', + 'Phoenix' => 'Phoenix', + 'Firebird' => 'Firebird', + 'Camino' => 'Camino', + 'Netscape' => 'Netscape', + 'OmniWeb' => 'OmniWeb', + 'Safari' => 'Safari', + 'Mozilla' => 'Mozilla', + 'Konqueror' => 'Konqueror', + 'icab' => 'iCab', + 'Lynx' => 'Lynx', + 'Links' => 'Links', + 'hotjava' => 'HotJava', + 'amaya' => 'Amaya', + 'IBrowse' => 'IBrowse', + 'Maxthon' => 'Maxthon', + 'Ubuntu' => 'Ubuntu Web Browser' +); + +$mobiles = array( + // legacy array, old values commented out + 'mobileexplorer' => 'Mobile Explorer', +// 'openwave' => 'Open Wave', +// 'opera mini' => 'Opera Mini', +// 'operamini' => 'Opera Mini', +// 'elaine' => 'Palm', + 'palmsource' => 'Palm', +// 'digital paths' => 'Palm', +// 'avantgo' => 'Avantgo', +// 'xiino' => 'Xiino', + 'palmscape' => 'Palmscape', +// 'nokia' => 'Nokia', +// 'ericsson' => 'Ericsson', +// 'blackberry' => 'BlackBerry', +// 'motorola' => 'Motorola' + + // Phones and Manufacturers + 'motorola' => 'Motorola', + 'nokia' => 'Nokia', + 'palm' => 'Palm', + 'iphone' => 'Apple iPhone', + 'ipad' => 'iPad', + 'ipod' => 'Apple iPod Touch', + 'sony' => 'Sony Ericsson', + 'ericsson' => 'Sony Ericsson', + 'blackberry' => 'BlackBerry', + 'cocoon' => 'O2 Cocoon', + 'blazer' => 'Treo', + 'lg' => 'LG', + 'amoi' => 'Amoi', + 'xda' => 'XDA', + 'mda' => 'MDA', + 'vario' => 'Vario', + 'htc' => 'HTC', + 'samsung' => 'Samsung', + 'sharp' => 'Sharp', + 'sie-' => 'Siemens', + 'alcatel' => 'Alcatel', + 'benq' => 'BenQ', + 'ipaq' => 'HP iPaq', + 'mot-' => 'Motorola', + 'playstation portable' => 'PlayStation Portable', + 'playstation 3' => 'PlayStation 3', + 'playstation vita' => 'PlayStation Vita', + 'hiptop' => 'Danger Hiptop', + 'nec-' => 'NEC', + 'panasonic' => 'Panasonic', + 'philips' => 'Philips', + 'sagem' => 'Sagem', + 'sanyo' => 'Sanyo', + 'spv' => 'SPV', + 'zte' => 'ZTE', + 'sendo' => 'Sendo', + 'nintendo dsi' => 'Nintendo DSi', + 'nintendo ds' => 'Nintendo DS', + 'nintendo 3ds' => 'Nintendo 3DS', + 'wii' => 'Nintendo Wii', + 'open web' => 'Open Web', + 'openweb' => 'OpenWeb', + + // Operating Systems + 'android' => 'Android', + 'symbian' => 'Symbian', + 'SymbianOS' => 'SymbianOS', + 'elaine' => 'Palm', + 'series60' => 'Symbian S60', + 'windows ce' => 'Windows CE', + + // Browsers + 'obigo' => 'Obigo', + 'netfront' => 'Netfront Browser', + 'openwave' => 'Openwave Browser', + 'mobilexplorer' => 'Mobile Explorer', + 'operamini' => 'Opera Mini', + 'opera mini' => 'Opera Mini', + 'opera mobi' => 'Opera Mobile', + 'fennec' => 'Firefox Mobile', + + // Other + 'digital paths' => 'Digital Paths', + 'avantgo' => 'AvantGo', + 'xiino' => 'Xiino', + 'novarra' => 'Novarra Transcoder', + 'vodafone' => 'Vodafone', + 'docomo' => 'NTT DoCoMo', + 'o2' => 'O2', + + // Fallback + 'mobile' => 'Generic Mobile', + 'wireless' => 'Generic Mobile', + 'j2me' => 'Generic Mobile', + 'midp' => 'Generic Mobile', + 'cldc' => 'Generic Mobile', + 'up.link' => 'Generic Mobile', + 'up.browser' => 'Generic Mobile', + 'smartphone' => 'Generic Mobile', + 'cellphone' => 'Generic Mobile' +); + +// There are hundreds of bots but these are the most common. +$robots = array( + 'googlebot' => 'Googlebot', + 'msnbot' => 'MSNBot', + 'baiduspider' => 'Baiduspider', + 'bingbot' => 'Bing', + 'slurp' => 'Inktomi Slurp', + 'yahoo' => 'Yahoo', + 'ask jeeves' => 'Ask Jeeves', + 'fastcrawler' => 'FastCrawler', + 'infoseek' => 'InfoSeek Robot 1.0', + 'lycos' => 'Lycos', + 'yandex' => 'YandexBot', + 'mediapartners-google' => 'MediaPartners Google', + 'CRAZYWEBCRAWLER' => 'Crazy Webcrawler', + 'adsbot-google' => 'AdsBot Google', + 'feedfetcher-google' => 'Feedfetcher Google', + 'curious george' => 'Curious George', + 'ia_archiver' => 'Alexa Crawler', + 'MJ12bot' => 'Majestic-12', + 'Uptimebot' => 'Uptimebot' +); diff --git a/application/controllers/Admin.php b/application/controllers/Admin.php new file mode 100644 index 0000000..89d5f64 --- /dev/null +++ b/application/controllers/Admin.php @@ -0,0 +1,41 @@ +load->model('query','',TRUE); + //加载辅助函数 + $this->load->helper('basic'); + $info = $this->query->userinfo()->values; + $info = json_decode($info); + + //验证用户是否登录 + is_login($info->username,$info->password); + } + //后台首页 + public function index(){ + $this->load->library('basic'); + $data = $this->basic->analyze(); + $data['admin_title'] = '后台首页'; + + //加载视图 + $this->load->view('admin/header',$data); + $this->load->view('admin/left'); + $this->load->view('admin/index'); + $this->load->view('admin/footer'); + } + //URL上传 + public function urlup(){ + $data['admin_title'] = 'URL上传'; + //加载视图 + $this->load->view('admin/header',$data); + $this->load->view('admin/left'); + $this->load->view('admin/urlup'); + $this->load->view('admin/footer'); + } + + } +?> \ No newline at end of file diff --git a/application/controllers/Compress.php b/application/controllers/Compress.php new file mode 100644 index 0000000..50579e9 --- /dev/null +++ b/application/controllers/Compress.php @@ -0,0 +1,107 @@ +load->model('query','',TRUE); + $img = $this->query->img($id); + + //如果图片没有压缩过,则调用压缩接口 + if($img->compression == 0){ + //获取图片完整路径 + $fullpath = FCPATH.$img->path; + $this->tinypng($fullpath); + //更新数据库 + $this->load->model('update','',TRUE); + $this->update->compress($id); + $t2 = microtime(true); + //计算执行时间 + $used_time = round($t2 - $t1).'s'; + $info = array( + "code" => 200, + "used_time" => $used_time, + "msg" => 'compressing.' + ); + $info = json_encode($info); + echo $info; + } + //图片已经压缩过情况 + else{ + $info = array( + "code" => 0, + "msg" => 'error:The image has been compressed!' + ); + $info = json_encode($info); + echo $info; + } + + + } + //请求tinypng压缩接口,传入图片完整路径 + protected function tinypng($path){ + + //tinypng API地址 + $api_url = "https://api.tinify.com/shrink"; + $data = file_get_contents($path); + //$post_data = array ("username" => "bob","key" => "12345"); + //$ch = curl_init(); + $ch = curl_init(); + $user = "api"; + $pass = "F8rNr5lh25WYcOECQvAqvcilBMAkhtIM"; + curl_setopt($ch, CURLOPT_URL, $api_url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + //curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY); + curl_setopt($ch, CURLOPT_USERPWD, "{$user}:{$pass}"); + // post数据 + curl_setopt($ch, CURLOPT_POST, 1); + // post的变量 + curl_setopt($ch, CURLOPT_POSTFIELDS, $data); + //https + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); + $output = curl_exec($ch); + curl_close($ch); + //打印获得的数据 + $data = json_decode($output); + //获取图片压缩后的URL + $url = $data->output->url; + //保存图片 + $this->save($url,$path); + } + //传递图片URL,并保存文件 + protected function save($url,$path){ + //获取图片数据并保存 + $curl = curl_init($url); + + curl_setopt($curl, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36"); + curl_setopt($curl, CURLOPT_FAILONERROR, true); + curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false); + #设置超时时间,最小为1s(可选) + #curl_setopt($curl , CURLOPT_TIMEOUT, 1); + + $filedata = curl_exec($curl); + curl_close($curl); + + //将图片数据覆盖源文件 + file_put_contents($path,$filedata); + } + } +?> \ No newline at end of file diff --git a/application/controllers/Deal.php b/application/controllers/Deal.php new file mode 100644 index 0000000..abcfc57 --- /dev/null +++ b/application/controllers/Deal.php @@ -0,0 +1,195 @@ +load->database(); + } + //图片压缩服务,传入images的id + public function compress($id){ + //只有管理员才有压缩权限 + $this->load->library('basic'); + $this->basic->is_login(TRUE); + $id = (int)$id; + //生成SQL语句 + $sql = "SELECT a.`id`,a.`path`,a.`compression`,b.`mime` FROM img_images AS a INNER JOIN img_imginfo AS b ON a.imgid = b.imgid AND a.id = $id"; + $query = $this->db->query($sql); + $row = $query->row_array(); + //图片绝对路径 + $path = FCPATH.$row['path']; + + //如果图片已经压缩过,就不要再压缩了 + if($row['compression'] == 1){ + $this->err_msg('此图片已经压缩!'); + } + //检查MIME类型,仅压缩jpeg & png + if(($row['mime'] != 'image/jpeg') && ($row['mime'] != 'image/png')){ + $this->err_msg('此图片类型不支持压缩!'); + } + + //先取出tinypng信息 + $sql = "SELECT * FROM img_options WHERE name = 'tinypng' LIMIT 1"; + $row = $this->db->query($sql)->row_array(); + + //验证是否启用了压缩功能 + if($row['switch'] == 'OFF'){ + $this->err_msg('您没有启用压缩功能!'); + } + //上面验证通过,继续执行 + //取出tinypng key + $kyes = $row['values']; + $kyes = json_decode($kyes); + $i = 'api'.rand(1,2); + $key = $kyes->$i; + + $url = "https://api.tinify.com/shrink"; + $data = file_get_contents($path); + + $ch = curl_init(); + $user = "api"; + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + //curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY); + curl_setopt($ch, CURLOPT_USERPWD, "{$user}:{$key}"); + // post数据 + curl_setopt($ch, CURLOPT_POST, 1); + // post的变量 + curl_setopt($ch, CURLOPT_POSTFIELDS, $data); + //https + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); + $output = curl_exec($ch); + curl_close($ch); + $output = json_decode($output); + //获取压缩后的图片链接 + $outurl = $output->output->url; + + //先判断是否是正常的URL,万一请求接口失败了呢 + if(!filter_var($outurl, FILTER_VALIDATE_URL)){ + //糟糕,没有验证通过,那就结束了 + $this->err_msg('请求接口失败!'); + } + + //下载图片并保存覆盖 + $curl = curl_init($outurl); + curl_setopt($curl, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36"); + curl_setopt($curl, CURLOPT_FAILONERROR, true); + curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false); + #设置超时时间,最小为1s(可选) + + $data = curl_exec($curl); + curl_close($curl); + + //重新保存图片 + file_put_contents($path,$data); + + //最后别忘了更新数据库呀 + $sql = "UPDATE img_images SET compression = 1 WHERE `id` = $id"; + if($this->db->query($sql)){ + $this->suc_msg('压缩完成!'); + } + } + //图片鉴黄识别 + public function identify($id){ + $id = (int)$id; + //生成SQL语句 + $sql = "SELECT a.id,a.path,a.level,b.domains FROM img_images AS a INNER JOIN img_storage AS b ON b.engine = 'localhost' AND a.id = $id"; + $query = $this->db->query($sql); + $row = $query->row_array(); + $imgurl = $row['domains'].$row['path']; + //echo $row['level']; + //如果图片已经识别过,就不要再次识别了 + if(($row['level'] != 'unknown') && ($row['level'] != NULL)){ + $this->err_msg('此图片已经识别过!'); + } + //继续执行 + $sql = "SELECT * FROM img_options WHERE name = 'moderate' LIMIT 1"; + $row = $this->db->query($sql)->row_array(); + //如果没有启用压缩功能 + if($row['switch'] == 'OFF'){ + $this->err_msg('未启用图片鉴黄识别!'); + } + + $apiurl = "https://www.moderatecontent.com/api/v2?key=".$row['values']."&url=".$imgurl; + $curl = curl_init($apiurl); + curl_setopt($curl, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36"); + curl_setopt($curl, CURLOPT_FAILONERROR, true); + curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false); + + $html = curl_exec($curl); + curl_close($curl); + + $html = json_decode($html); + @$level = $html->rating_label; + @$error_code = (int)$html->error_code; + + //最后更新数据库 + $sql = "UPDATE img_images SET level = '$level' WHERE `id` = $id"; + + //如果执行成功才进行更新 + if($error_code === 0){ + //更新数据库 + $this->db->query($sql); + if($level == 'adult'){ + $arr = array( + "code" => 400, + "msg" => '您的IP已记录,请不要上传违规图片!' + ); + $arr = json_encode($arr); + echo $arr; + } + else{ + $this->suc_msg('识别完成!'); + } + } + else{ + $this->err_msg('识别失败!'); + } + } + //批量识别图片 + public function identify_more(){ + $sql = "SELECT * FROM img_images WHERE (`level` = 'unknown') OR (`level` = NULL) ORDER BY `id` DESC LIMIT 5"; + //查询数据库 + $query = $this->db->query($sql); + $result = $query->result(); + + //循环识别图片 + foreach($result as $row){ + $this->identify($row->id); + } + } + + //返回错误码 + protected function err_msg($msg){ + $arr = array( + "code" => 0, + "msg" => $msg + ); + $arr = json_encode($arr); + echo $arr; + exit; + } + //成功,返回正确的状态码 + protected function suc_msg($msg){ + $arr = array( + "code" => 200, + "msg" => $msg + ); + $arr = json_encode($arr); + echo $arr; + } + } +?> \ No newline at end of file diff --git a/application/controllers/Del.php b/application/controllers/Del.php new file mode 100644 index 0000000..7536a67 --- /dev/null +++ b/application/controllers/Del.php @@ -0,0 +1,42 @@ +load->model('query','',TRUE); + //加载类 + $this->load->library('basic'); + //检测是否登录 + $this->basic->is_login(TRUE); + + } + //根据img_images ID删除图片 + public function id($id){ + @$id = (int)$id; + + $img = $this->query->img_id($id); + //加载数据库模型 + $this->load->model('delete','',TRUE); + //从数据库中删除 + $this->delete->del_img($img->imgid); + //从磁盘中删除 + $path = FCPATH.$img->path; + $thumbnail_path = FCPATH.$img->thumb_path; + //缩略图地址 + unlink($path); + unlink($thumbnail_path); + + $re = array( + "code" => 200, + "id" => $id, + "msg" => "删除成功!" + ); + $re = json_encode($re); + echo $re; + } + } +?> \ No newline at end of file diff --git a/application/controllers/Found.php b/application/controllers/Found.php new file mode 100644 index 0000000..978c91b --- /dev/null +++ b/application/controllers/Found.php @@ -0,0 +1,52 @@ +load->model('query','',TRUE); + //加载辅助函数 + } + //探索发现页面 + public function index(){ + $siteinfo = $this->query->site_setting(); + $siteinfo = $siteinfo->values; + $siteinfo = json_decode($siteinfo); + + $siteinfo->title = '探索发现 - '.$siteinfo->title; + + //查询图片信息,返回对象 + $data['imgs'] = $this->query->found(32); + //查询域名 + $data['domain'] = $this->query->domain('localhost'); + + //加载视图 + $this->load->view('user/header',$siteinfo); + $this->load->view('user/found',$data); + + $this->load->view('user/footer'); + } + //链接页面 + public function link($id){ + $id = strip_tags($id); + $id = (int)$id; + $siteinfo = $this->query->site_setting(); + $siteinfo = $siteinfo->values; + $siteinfo = json_decode($siteinfo); + + //查询图片信息,返回对象 + $data['imgs'] = $this->query->found(32); + //查询域名 + $data['domain'] = $this->query->domain('localhost'); + + //加载视图 + $this->load->view('user/header',$siteinfo); + $this->load->view('user/link',$data); + + $this->load->view('user/footer'); + } + + } +?> \ No newline at end of file diff --git a/application/controllers/Home.php b/application/controllers/Home.php new file mode 100644 index 0000000..ba5f652 --- /dev/null +++ b/application/controllers/Home.php @@ -0,0 +1,44 @@ +load->model('query','',TRUE); + $siteinfo = $this->query->site_setting(); + $siteinfo = json_decode($siteinfo->values); + //echo $siteinfo->title; + //$data['title'] = '图片上传'; + $this->load->view('user/header.php',$siteinfo); + $this->load->view('user/home.php'); + $this->load->view('user/footer.php'); + } + //首页多图上传 + public function multiple(){ + //加载数据库模型 + $this->load->model('query','',TRUE); + $siteinfo = $this->query->site_setting(); + $siteinfo = json_decode($siteinfo->values); + //echo $siteinfo->title; + //$data['title'] = '图片上传'; + $this->load->view('user/header.php',$siteinfo); + $this->load->view('user/multiple.php'); + $this->load->view('user/footer.php'); + } + } +?> \ No newline at end of file diff --git a/application/controllers/Img.php b/application/controllers/Img.php new file mode 100644 index 0000000..a6890b1 --- /dev/null +++ b/application/controllers/Img.php @@ -0,0 +1,75 @@ +load->model('query','',TRUE); + $siteinfo = $this->query->site_setting(); + $siteinfo = json_decode($siteinfo->values); + + //过滤imgid + $imgid = strip_tags($imgid); + //计算imgid长度 + $id_length = strlen($imgid); + //判断是否是有效的ID + if($id_length != 16){ + show_404(); + } + //继续执行 + //加载模型 + $this->load->model('query','',TRUE); + $this->load->model('update','',TRUE); + //浏览测试+1 + $this->update->views($imgid); + //查询图片信息 + $imginfo = $this->query->onepic($imgid); + //查询的img_imginfo + $picinfo = $this->query->imginfo($imgid); + //查询图片域名 + @$domain = $this->query->domain($imginfo->storage); + + //如果没有查询到结果 + if(!$domain){ + show_404(); + } + + //var_dump($siteinfo); + //获取文件大小 + $this->load->helper('basic'); + $fullpath = FCPATH.$imginfo->path; + + $size = file_size($fullpath); + + //重组数组 + $datas = array( + "logo" => $siteinfo->logo, + "title" => $picinfo->client_name, + "url" => $domain.$imginfo->path, + "date" => $imginfo->date, + "mime" => $picinfo->mime, + "width" => $picinfo->width, + "height" => $picinfo->height, + "views" => $picinfo->views, + "tags" => $picinfo->tags, + "keywords" => $picinfo->client_name, + "analytics" => $siteinfo->analytics, + "description" => $siteinfo->description, + "comments" => $siteinfo->comments, + "ext" => $picinfo->ext, + "size" => $size + ); + + // $data['title'] = '图片浏览'; + // $data['url'] = $domain.$imginfo->path; + // $data['date'] = $imginfo->date; + + //echo $domain.$imginfo->path; + + //加载视图 + $this->load->view('user/header',$datas); + $this->load->view('user/img',$datas); + $this->load->view('user/footer'); + } + } +?> \ No newline at end of file diff --git a/application/controllers/Install.php b/application/controllers/Install.php new file mode 100644 index 0000000..110fd0d --- /dev/null +++ b/application/controllers/Install.php @@ -0,0 +1,273 @@ +is_install(); + $setup = (int)$_GET['setup']; + $data['env'] = $this->check('full'); + $data['sum'] = $this->check('part'); + //var_dump($data['sum']); + $data['title'] = "ImgURL安装向导"; + $data['logo'] = "/static/images/logo.png"; + + //安装步骤 + switch ($setup) { + //安装步骤1 + case 1: + $this->load->view('user/header.php',$data); + $this->load->view('user/install1.php',$data); + $this->load->view('user/footer.php'); + break; + //安装步骤2 + case 2: + //获取网站域名 + $data['domain'] = $this->get_domain(); + //加载视图 + $this->load->view('user/header.php',$data); + $this->load->view('user/install2.php',$data); + $this->load->view('user/footer.php'); + break; + case 3: + //获取域名 + @$info['domain'] = $this->input->post('domain',TRUE); + //获取用户名 + @$info['user'] = $this->input->post('user',TRUE); + //获取密码 + @$info['pass1'] = $this->input->post('pass1',TRUE); + @$info['pass2'] = $this->input->post('pass2',TRUE); + //验证信息 + $this->verify($info,'domain'); + $this->verify($info,'user'); + $this->verify($info,'pass'); + $this->verify($info,'pass2'); + //开始安装ImgURL + $this->setup($info); + //加载视图 + $this->load->view('user/header.php',$data); + $this->load->view('user/install3.php',$data); + $this->load->view('user/footer.php'); + break; + default: + header("location:/install/?setup=1"); + break; + } + } + + //环境检测 + protected function check($type){ + //检测通过 + $yes = '通过!'; + $no = '未通过!'; + //获取组件信息 + $ext = get_loaded_extensions(); + //PHP版本信息 + $env['php'] = array( + "name" => 'PHP', + "requir" => 'PHP >= 5.6', + "info" => PHP_VERSION, + "result" => is_php('5.6') ? $yes : $no + ); + //PDO_SQLite + $env['sqlite'] = array( + "name" => 'PDO_SQLite', + "requir" => '必须支持', + "info" => array_search('pdo_sqlite',$ext) ? 'Yes':'No', + "result" => array_search('pdo_sqlite',$ext) ? $yes : $no + ); + //GD2 + $env['gd'] = array( + "name" => 'GD2', + "requir" => '必须支持', + "info" => array_search('gd',$ext) ? 'Yes':'No', + "result" => array_search('gd',$ext) ? $yes : $no + ); + //imagick + $env['imagick'] = array( + "name" => 'ImageMagick', + "requir" => '必须支持', + "info" => array_search('imagick',$ext) ? 'Yes':'No', + "result" => array_search('imagick',$ext) ? $yes : $no + ); + //fileinfo + $env['fileinfo'] = array( + "name" => 'Fileinfo', + "requir" => '必须支持', + "info" => array_search('fileinfo',$ext) ? 'Yes':'No', + "result" => array_search('fileinfo',$ext) ? $yes : $no + ); + //检查目录是否可写 + $env['data'] = array( + "name" => '/data', + "requir" => '可写', + "info" => is_writable(FCPATH.'data') ? 'Yes':'No', + "result" => is_writable(FCPATH.'data') ? $yes : $no + ); + $env['upload'] = array( + "name" => '/imgs', + "requir" => '可写', + "info" => is_writable(FCPATH.'imgs') ? 'Yes':'No', + "result" => is_writable(FCPATH.'imgs') ? $yes : $no + ); + + //遍历结果 + if($type == 'part'){ + //检测不通过 + foreach($env as $value){ + //echo $value['result']; + if($value['result'] == $no){ + return FALSE; + exit; + } + } + } + else{ + return $env; + } + } + //获取网站域名 + protected function get_domain(){ + $port = $_SERVER["SERVER_PORT"]; + //对端口进行判断 + switch ( $port ) + { + case 80: + $protocol = "http://"; + $port = ''; + break; + case 443: + $protocol = "https://"; + $port = ''; + break; + default: + $protocol = "http://"; + $port = ":".$port; + break; + } + $uri = $_SERVER["REQUEST_URI"]; + $uri = str_replace("check.php","",$uri); + //组合为完整的URL + $domain = $protocol.$_SERVER['SERVER_NAME'].$port; + //$domain = str_replace("install.php?setup=2","",$domain); + return $domain; + } + //验证函数 + protected function verify($data,$type){ + switch ($type) { + //检查用户名 + case 'user': + $pattern = '/^[a-zA-Z0-9]+$/'; + if($data['user'] == ''){ + echo '请填写用户名!'; + exit; + } + if(!preg_match($pattern,$data['user'])){ + echo '用户名格式有误!'; + exit; + } + break; + case 'pass': + $pattern = '/^[a-zA-Z0-9!@#$%^&*.]+$/'; + if(!preg_match($pattern,$data['pass1'])){ + echo '密码格式有误!'; + exit; + } + break; + case 'pass2': + $pass1 = $data['pass1']; + $pass2 = $data['pass2']; + + if($pass1 != $pass2){ + echo '两次密码不一致!'; + exit; + } + break; + case 'domain': + $domain = $data['domain']; + if(!filter_var($domain, FILTER_VALIDATE_URL)){ + echo '域名格式有误!(需要包含https://)'; + exit; + } + break; + default: + # code... + break; + } + } + //安装函数 + protected function setup($data){ + //默认数据库路径 + $default_db = FCPATH."data/imgurl-simple.db3"; + //数据库路径 + $db_path = FCPATH."data/imgurl.db3"; + //锁文件 + $lock_file = FCPATH."data/install.lock"; + //用户密码 + $password = md5($data['pass2'].'imgurl'); + //用户信息,json格式 + $user_values = array( + "username" => $data['user'], + "password" => $password + ); + $user_values = json_encode($user_values); + + //拷贝数据库 + copy($default_db,$db_path); + //写入默认数据 + //连接数据库 + $this->load->database(); + //用户信息 + $userinfo = array( + 'name' => 'userinfo', + 'values' => $user_values + ); + + //本地存储信息 + $local_storage = array( + "engine" => "localhost", + "domains" => $data['domain'], + "switch" => 'ON' + ); + //站点地址 + $site_url = array( + "name" => 'site_url', + "values" => $data['domain'] + ); + //$where = "name = 'site_url'"; + + // var_dump($this->db->update_string('options', $site_url, $where)); + // exit; + // var_dump($site_url); + // exit; + //设置用户信息 + $this->db->insert('options', $userinfo); + $this->db->insert('options', $site_url); + + //设置默认存储 + $this->db->insert('storage', $local_storage); + + //创建锁文件 + $myfile = fopen($lock_file, "w") or die("Unable to open file!"); + $txt = "ImgURL"; + fwrite($myfile, $txt); + fclose($myfile); + + return TRUE; + } + //检查是否已经安装过 + protected function is_install(){ + //锁文件 + $lock_file = FCPATH."data/install.lock"; + if(is_file($lock_file)){ + header("location:/"); + exit; + } + } + public function test(){ + echo $this->get_domain(); + + } + } +?> \ No newline at end of file diff --git a/application/controllers/Maintain.php b/application/controllers/Maintain.php new file mode 100644 index 0000000..62293af --- /dev/null +++ b/application/controllers/Maintain.php @@ -0,0 +1,63 @@ +load->library('basic'); + $this->basic->is_login(TRUE); + //加载模型 + $this->load->model('query','',TRUE); + } + //后台首页 + public function index(){ + + $data['admin_title'] = '管理维护'; + + //加载视图 + $this->load->view('admin/header',$data); + $this->load->view('admin/left'); + $this->load->view('admin/index'); + $this->load->view('admin/footer'); + } + //当前版本 + public function version(){ + $v_file = FCPATH.'data/version.txt'; + $version = file_get_contents($v_file); + echo $version; + } + //升级至2.0 + public function upto2(){ + $data['admin_title'] = '1.x升级至2.x'; + + //加载视图 + $this->load->view('admin/header',$data); + $this->load->view('admin/left'); + $this->load->view('admin/upto2'); + $this->load->view('admin/footer'); + } + //导入1.x的数据 + public function import($id){ + $id = (int)$id; + + //加载medoo + include_once(APPPATH.'libraries/Medoo.php'); + + echo APPPATH.'libraries/Medoo.php'; + + $database = new Medoo([ + 'database_type' => 'sqlite', + 'database_file' => FCPATH.'/data/temp/imgurl.db3' + ]); + + //$this->load->database($db['old']); + + // $sql = "SELECT * FROM imginfo WHERE id = $id"; + // $query = $this->db->query($sql)->row(); + // var_dump($query); + } + + } +?> \ No newline at end of file diff --git a/application/controllers/Manage.php b/application/controllers/Manage.php new file mode 100644 index 0000000..152ec3f --- /dev/null +++ b/application/controllers/Manage.php @@ -0,0 +1,92 @@ +load->library('basic'); + //验证用户是否登录 + $this->basic->is_login(TRUE); + //加载查询模型 + $this->load->model('query','',TRUE); + } + //管理员上传 + public function images($type = 'all',$page = 0){ + $type = strip_tags($type); + $page = (int)strip_tags($page); + $limit = 16; //要查询的条数 + $data['admin_title'] = '图片管理'; + $sql1 = "SELECT a.id,a.imgid,a.path,a.thumb_path,a.date,a.compression,a.level,b.mime,b.width,b.height,b.views,b.ext,b.client_name FROM img_images AS a INNER JOIN img_imginfo AS b ON a.imgid = b.imgid "; + //根据不同的条件生成不同的SQL语句 + switch ($type) { + case 'all': + $sql = $sql1."ORDER BY a.id DESC LIMIT $limit OFFSET $page"; + $num = $this->db->count_all("images"); + break; + case 'admin': + $sql = $sql1."AND a.user = 'admin' ORDER BY a.id DESC LIMIT $limit OFFSET $page"; + $num = $this->query->count_num('admin')->num; + break; + case 'visitor': + $sql = $sql1."AND a.user = 'visitor' ORDER BY a.id DESC LIMIT $limit OFFSET $page"; + $num = $this->query->count_num('visitor')->num; + break; + case 'dubious': + $sql = $sql1."AND a.level = 'adult' ORDER BY a.id DESC"; + //$num = $this->query->count_num('visitor')->num; + break; + default: + $sql = $sql1."AND a.user = '$type' ORDER BY a.id DESC LIMIT $limit OFFSET $page"; + break; + } + //连接数据库 + $this->load->database(); + $data['imgs'] = $this->db->query($sql)->result_array(); + + //调用分页类 + $this->load->library('pagination'); + $config['base_url'] = "/manage/images/$type/"; + $config['total_rows'] = $num; + $config['per_page'] = $limit; + $config['first_url'] = 0; + $config['first_link'] = '首页'; + $config['last_link'] = '尾页'; + $config['attributes'] = array('class' => 'paging'); //设置分页的class + $config['next_link'] = '下一页'; //下一页文本 + $config['prev_link'] = '上一页'; //上一页文本 + + $this->pagination->initialize($config); + $data['page'] = $this->pagination->create_links(); + + //获取域名 + $data['domain'] = $this->query->domain('localhost'); + + //加载视图 + $this->load->view('admin/header',$data); + $this->load->view('admin/left'); + $this->load->view('admin/images',$data); + $this->load->view('admin/footer'); + } + //获取单张图片信息 + public function imginfo($imgid){ + $imgid = strip_tags($imgid); + $row = $this->query->picinfo($imgid); + //获取文件大小 + $this->load->helper('basic'); + $fullpath = FCPATH.$row->path; + + $size = file_size($fullpath); + $row->size = $size; + + //加载视图 + $this->load->view("admin/imginfo",$row); + } + } +?> \ No newline at end of file diff --git a/application/controllers/Page.php b/application/controllers/Page.php new file mode 100644 index 0000000..b698458 --- /dev/null +++ b/application/controllers/Page.php @@ -0,0 +1,37 @@ +load->library("parsedown"); + $content = $this->parsedown->text($content); + + //$data['content'] = $content; + //加载数据库视图 + $this->load->model('query','',TRUE); + $data = $this->query->site_setting('1'); + $data->content = $content; + //载入页面视图 + $this->load->view('/user/header',$data); + $this->load->view('/user/page',$data); + $this->load->view('/user/footer'); + } + } +?> \ No newline at end of file diff --git a/application/controllers/Set.php b/application/controllers/Set.php new file mode 100644 index 0000000..4c69590 --- /dev/null +++ b/application/controllers/Set.php @@ -0,0 +1,172 @@ +load->model('update','',TRUE); + //加载类 + $this->load->library('basic'); + //验证用户是否登录 + $this->basic->is_login(TRUE); + } + //更新站点设置 + public function site(){ + //var_dump($data); + //接收表单数据 + $data['logo'] = $this->input->post('logo',TRUE); + $data['title'] = $this->input->post('title',TRUE); + $data['keywords'] = $this->input->post('keywords',TRUE); + $data['description'] = $this->input->post('description',TRUE); + $data['analytics'] = $this->input->post('analytics'); + //$data['comments'] = $this->input->post('comments'); + + + $data = json_encode($data); + + + //如果更新成功 + if($this->update->site('site_setting',$data)){ + $ref = $_SERVER["HTTP_REFERER"]; + echo '更新成功,3s后返回上一页!'; + header("Refresh:3;url=$ref"); + } + else{ + echo '更新发生错误!'; + exit; + } + } + //更新上传限制 + public function uplimit(){ + $data['max_size'] = (int)$this->input->post('max_size',TRUE); + $data['limit'] = (int)$this->input->post('limit',TRUE); + + $data = json_encode($data); + + //如果更新成功 + if($this->update->site('uplimit',$data)){ + $ref = $_SERVER["HTTP_REFERER"]; + echo '更新成功,3s后返回上一页!'; + header("Refresh:3;url=$ref"); + } + else{ + echo '更新发生错误!'; + exit; + } + } + //更新tinypng设置 + public function tinypng(){ + $data['api1'] = $this->input->post('api1',TRUE); + $data['api2'] = $this->input->post('api2',TRUE); + @$switch = $this->input->post('switch',TRUE); + if($switch != 'on'){ + $switch = 'OFF'; + } + else{ + $switch = 'ON'; + } + + $data = json_encode($data); + //如果更新成功 + if($this->update->tinypng($data,$switch)){ + $ref = $_SERVER["HTTP_REFERER"]; + echo '更新成功,3s后返回上一页!'; + header("Refresh:3;url=$ref"); + } + else{ + echo '更新发生错误!'; + exit; + } + } + //更新moderate + public function moderate(){ + //获取API key + $data['api'] = $this->input->post('api',TRUE); + //获取开关 + @$switch = $this->input->post('switch',TRUE); + if($switch != 'on'){ + $switch = 'OFF'; + } + else{ + $switch = 'ON'; + } + //更新数据库 + //如果更新成功 + if($this->update->moderate($data['api'],$switch)){ + $ref = $_SERVER["HTTP_REFERER"]; + echo '更新成功,3s后返回上一页!'; + header("Refresh:3;url=$ref"); + } + else{ + echo '更新发生错误!'; + exit; + } + } + //更新存储引擎 + public function storage($engine){ + //获取API key + $data['domains'] = $this->input->post('domain',TRUE); + $data['switch'] = 'ON'; + + //更新数据库 + //如果更新成功 + if($this->update->storage($data,$engine)){ + $ref = $_SERVER["HTTP_REFERER"]; + echo '更新成功,3s后返回上一页!'; + header("Refresh:3;url=$ref"); + } + else{ + echo '更新发生错误!'; + exit; + } + } + //删除单张图片,需传入图片ID,及文件路径 + public function del_img(){ + //获取数据 + @$imgid = $this->input->post('imgid',TRUE); + @$path = $this->input->post('path',TRUE); + @$thumbnail_path = $this->input->post('thumbnail_path',TRUE); + //加载数据库模型 + $this->load->model('delete','',TRUE); + //从数据库中删除 + $this->delete->del_img($imgid); + //从磁盘中删除 + $path = FCPATH.$path; + $thumbnail_path = FCPATH.$thumbnail_path; + //缩略图地址 + unlink($path); + unlink($thumbnail_path); + + $re = array( + "code" => 200, + "msg" => "删除成功!" + ); + $re = json_encode($re); + echo $re; + } + //取消图片可疑状态 + public function cancel($id){ + $id = (int)$id; + + $sql = "UPDATE img_images SET level = 'everyone' WHERE `id` = $id"; + $this->load->database(); + if($this->db->query($sql)){ + $this->suc_msg('操作成功!'); + } + } + //操作成功返回json + protected function suc_msg($msg){ + $arr = array( + "code" => 200, + "msg" => $msg + ); + $info = json_encode($arr); + echo $info; + } + } +?> \ No newline at end of file diff --git a/application/controllers/Setting.php b/application/controllers/Setting.php new file mode 100644 index 0000000..9c072c3 --- /dev/null +++ b/application/controllers/Setting.php @@ -0,0 +1,106 @@ +load->model('query','',TRUE); + //加载辅助函数 + $this->load->helper('basic'); + $info = $this->query->userinfo()->values; + $info = json_decode($info); + + //验证用户是否登录 + is_login($info->username,$info->password); + } + //站点设置 + public function site(){ + $siteinfo = $this->query->site_setting(); + $siteinfo = json_decode($siteinfo->values); + + //页面标题 + $siteinfo->admin_title = '站点设置'; + + //加载视图 + $this->load->view('admin/header',$siteinfo); + $this->load->view('admin/left'); + $this->load->view('admin/site'); + $this->load->view('admin/footer'); + } + //上传限制 + public function uplimit(){ + + $siteinfo = $this->query->option('uplimit'); + + $siteinfo = json_decode($siteinfo->values); + if($siteinfo->limit != 0){ + $switch = 'checked'; + } + else{ + $switch = ''; + } + //页面标题 + $siteinfo->admin_title = '上传限制'; + $siteinfo->switch = $switch; + //var_dump($siteinfo); + //加载视图 + $this->load->view('admin/header',$siteinfo); + $this->load->view('admin/left'); + $this->load->view('admin/uplimit'); + $this->load->view('admin/footer'); + } + //图片压缩 + public function compress(){ + //页面标题 + $data['admin_title'] = '图片压缩'; + + //加载模型 + $this->load->model('query','',TRUE); + + $tinypng = $this->query->option('tinypng'); + $data['switch'] = $tinypng->switch; + if($data['switch'] == 'OFF'){ + $data['switch'] = ''; + } + else{ + $data['switch'] = 'checked'; + } + + $data['values'] = json_decode($tinypng->values); + + //var_dump($data['values']->api1); + //exit; + + //加载视图 + $this->load->view('admin/header',$data); + $this->load->view('admin/left'); + $this->load->view('admin/tinypng',$data); + $this->load->view('admin/footer'); + } + //图片鉴黄 + public function identify(){ + //页面标题 + $data['admin_title'] = '图片鉴黄'; + //加载模型 + $this->load->model('query','',TRUE); + $moderate = $this->query->option('moderate'); + + $data['switch'] = $moderate->switch; + $data['values'] = $moderate->values; + if($data['switch'] == 'OFF'){ + $data['switch'] = ''; + } + else{ + $data['switch'] = 'checked'; + } + + //加载视图 + $this->load->view('admin/header',$data); + $this->load->view('admin/left'); + $this->load->view('admin/identify'); + $this->load->view('admin/footer'); + } + } +?> \ No newline at end of file diff --git a/application/controllers/Storage.php b/application/controllers/Storage.php new file mode 100644 index 0000000..6f94c07 --- /dev/null +++ b/application/controllers/Storage.php @@ -0,0 +1,32 @@ +load->model('query','',TRUE); + //加载辅助函数 + $this->load->helper('basic'); + $info = $this->query->userinfo()->values; + $info = json_decode($info); + + //验证用户是否登录 + is_login($info->username,$info->password); + } + //后台首页 + public function localhost(){ + $localhost = $this->query->storage('localhost'); + + $data['admin_title'] = '存储设置(localhost)'; + $data['domains'] = $localhost->domains; + //加载视图 + $this->load->view('admin/header',$data); + $this->load->view('admin/left'); + $this->load->view('admin/localhost',$data); + $this->load->view('admin/footer'); + } + + } +?> \ No newline at end of file diff --git a/application/controllers/Upload.php b/application/controllers/Upload.php new file mode 100644 index 0000000..8d161ee --- /dev/null +++ b/application/controllers/Upload.php @@ -0,0 +1,402 @@ +upload_path = FCPATH.'imgs/'.date('Y',time()).'/'.date('m',time()).'/'; + $this->upload_path = str_replace('\\','/',$this->upload_path); + $this->relative_path = "/imgs/".date('Y',time()).'/'.date('m',time()).'/'; + $this->relative_path = str_replace('\\','/',$this->relative_path); + $this->temp = FCPATH.'data/temp/'; + //如果文件夹不存在,则创建文件夹 + if(!is_dir($this->upload_path)){ + //递归模式创建目录 + mkdir($this->upload_path,0777,TRUE); + } + $this->date = date('Y-m-d H:i',time()); + //加载辅助函数 + $this->load->helper('basic'); + $ip = get_ip(); + //加载基本类 + $this->load->library('basic'); + //加载查询模型 + $this->load->model('query','',TRUE); + //用户已经登录 + if($this->basic->is_login(FALSE)){ + $this->user = 'admin'; + } + else{ + $this->user = 'visitor'; + //限制上传数量 + if($this->query->uplimit($ip) === FALSE){ + $this->error_msg("上传达到上限!"); + } + } + } + //通用上传设置 + protected function config($upload_path = ''){ + //设置上传路径 + if($upload_path == ''){ + $upload_path = $this->upload_path; + } + // var_dump(); + $config['upload_path'] = $upload_path; + $config['allowed_types'] = 'gif|jpg|png|bmp|webp'; + $config['max_size'] = 5120; + $config['file_ext_tolower'] = TRUE; //文件名转换为小写 + $config['overwrite'] = TRUE; //覆盖同名文件 + $config['encrypt_name'] = TRUE; //随机命名图片 + return $config; + } + public function localhost(){ + //加载上传的配置选项 + $config = $this->config(); + //加载上传类 + $this->load->library('upload', $config); + + //上传失败 + if ( ! $this->upload->do_upload('file')) + { + $msg = $this->upload->display_errors(); + $msg = strip_tags($msg); + + $this->error_msg($msg); + } + else + { + $data = $this->upload->data(); + //加载模型 + $this->load->model('insert','',TRUE); + $this->load->model('query','',TRUE); + //计算文件MD5 + $file_name = md5_file($data['full_path']); + $file_name = substr($file_name,8,16); + //图片唯一ID + $imgid = $file_name; + $file_name = $file_name.$data['file_ext']; + //新图片完整路径 + $full_path = $this->upload_path.$file_name; + $full_path = str_replace("\\","/",$full_path); + //新图片相对路径 + $relative_path = $this->relative_path.$file_name; + //缩略图相对路径 + $thumbnail_path = $this->relative_path.$imgid.'_thumb'.$data['file_ext']; + //获取域名 + $domain = $this->query->domain('localhost'); + + //获取图片URL地址 + $url = $domain.$relative_path; + //缩略图地址 + $thumbnail_url = $domain.$thumbnail_path; + + //重命名文件 + rename($data['full_path'],$full_path); + + //生成缩略图 + $this->load->library('image'); + $this->image->thumbnail($full_path,290,175); + + //查询图片是否上传过 + if($imginfo = $this->query->repeat($imgid)){ + $id = $imginfo->id; + //重组数组 + $info = array( + "code" => 200, + "id" => $id, + "imgid" => $imgid, + "relative_path" => $relative_path, + "url" => $url, + "thumbnail_url" => $thumbnail_url, + "width" => $data['image_width'], + "height" => $data['image_height'] + ); + $this->succeed_msg($info); + } + //图片没有上传过 + else{ + //需要插入到images表的数据 + $datas = array( + "imgid" => $imgid, + "path" => $relative_path, + "thumb_path"=> $thumbnail_path, + "storage" => "localhost", + "ip" => get_ip(), + "ua" => get_ua(), + "date" => $this->date, + "user" => $this->user, + "level" => 'unknown' + ); + //需要插入到imginfo表的数据 + $imginfo = array( + "imgid" => $imgid, + "mime" => $data['file_type'], + "width" => $data['image_width'], + "height" => $data['image_height'], + "ext" => $data['file_ext'], + "client_name" => $data['client_name'] + ); + + //插入数据到img_images表 + $id = $this->insert->images($datas); + $this->insert->imginfo($imginfo); + //重组数组 + $info = array( + "code" => 200, + "id" => $id, + "imgid" => $imgid, + "relative_path" => $relative_path, + "url" => $url, + "thumbnail_url" => $thumbnail_url, + "width" => $data['image_width'], + "height" => $data['image_height'] + ); + } + //var_dump($info); + //exit; + $this->succeed_msg($info); + } + } + //上传成功返回json + protected function succeed_msg($data){ + $info = json_encode($data); + echo $info; + exit; + } + //上传失败返回json + protected function error_msg($msg){ + $data = array( + "code" => 0, + "msg" => $msg + ); + + $data = json_encode($data); + echo $data; + exit; + } + //URL上传 + public function url(){ + $url = @$this->input->post('url',TRUE); + $url = trim($url); + //检测用户是否登录 + $this->load->library('basic'); + $this->basic->is_login(TRUE); + //判断URL是否合法 + if(!filter_var($url, FILTER_VALIDATE_URL)){ + $this->error_msg('不是有效的URL地址!'); + } + //继续执行 + //获取图片后缀名 + $url_arr = explode('.',$url); + $ext = strtolower(end($url_arr)); + + + //判断是否是允许的后缀 + switch($ext){ + case 'png': + case 'jpg': + case 'jpeg': + case 'bmp': + case 'gif': + case 'bmp': + break; + default: + $this->error_msg('不是有效的图片地址!'); + exit; + } + + //继续执行 + //下载图片 + $pic_data = $this->basic->dl_pic($url); + //临时文件路径 + $tmp_name = $this->temp.md5($url); + //写入临时文件 + file_put_contents($tmp_name,$pic_data); + //计算文件MD5 + $imgid = md5_file($tmp_name); + $imgid = substr($imgid,8,16); + $file_name = $imgid.'.'.$ext; + //图片相对路径 + $relative_path = $this->relative_path.$file_name; + $ext = '.'.$ext; + //查询图片是否已经上传过 + if($this->query->repeat($imgid)){ + //删除临时文件 + unlink($tmp_name); + $this->error_msg('文件已经上传过!'); + exit; + } + //没有上传过继续执行 + //复制图片到上传目录 + $full_path = $this->upload_path.$file_name; + copy($tmp_name,$full_path); + //删除临时文件 + unlink($tmp_name); + //生成缩略图 + $this->load->library('image'); + $this->image->thumbnail($full_path,290,175); + + //获取图片信息 + $img_info = getimagesize($full_path); + //缩略图相对地址 + $thumbnail_path = $this->relative_path.$imgid.'_thumb'.$ext; + + //需要插入到images表的数据 + $datas = array( + "imgid" => $imgid, + "path" => $relative_path, + "thumb_path"=> $thumbnail_path, + "storage" => "localhost", + "ip" => get_ip(), + "ua" => get_ua(), + "date" => $this->date, + "user" => $this->user, + "level" => 'unknown' + ); + //需要插入到imginfo表的数据 + $imginfo = array( + "imgid" => $imgid, + "mime" => $img_info['mime'], + "width" => $img_info[0], + "height" => $img_info[1], + "ext" => $ext, + "client_name" => $file_name + ); + //加载数据库模型 + $this->load->model('insert','',TRUE); + //插入数据到img_images表 + $id = $this->insert->images($datas); + $this->insert->imginfo($imginfo); + //获取域名 + $domain = $this->query->domain('localhost'); + //获取图片URL地址 + $url = $domain.$relative_path; + //返回成功的信息 + $re = array( + "code" => 200, + "msg" => $url + ); + $re = json_encode($re); + echo $re; + } + //粘贴上传 + public function parse(){ + $date = date('Y-m-d H:i:s',time()); + //临时文件名 + $tmp_name = get_ip().get_ua().$date; + $tmp_name = md5($tmp_name); + //图片临时路径 + $tmp_file = $this->temp.$tmp_name; + //接接收ase64图片 + $picfile = $_POST['content']; + $picfile = base64_decode($picfile); + //echo $picfile; + //存储图片 + file_put_contents($tmp_file, $picfile); + + //判断图片MIME类型 + if(!mime($tmp_file)){ + unlink($tmp_file); + $this->error_msg('不允许的文件类型!'); + exit; + } + //继续执行 + //计算文件MD5 + $imgid = md5_file($tmp_file); + $imgid = substr($imgid,8,16); + //获取文件后缀 + $ext = ext($tmp_file); + $file_name = $imgid.$ext; + //图片相对路径 + $relative_path = $this->relative_path.$file_name; + //图片完整路径 + $full_path = $this->upload_path.$file_name; + //查询图片是否已经上传过 + if($this->query->repeat($imgid)){ + //删除临时文件 + unlink($tmp_file); + $this->error_msg('文件已经上传过!'); + exit; + } + //没有上传过继续执行 + //复制图片到上传目录 + copy($tmp_file,$full_path); + $file_name = $imgid.$ext; + //删除临时文件 + unlink($tmp_file); + //生成缩略图 + $this->load->library('image'); + $this->image->thumbnail($full_path,290,175); + //缩略图地址 + $thumbnail_path = $this->relative_path.$imgid.'_thumb.'.$ext; + + //获取图片信息 + $img_info = getimagesize($full_path); + + //需要插入到images表的数据 + $datas = array( + "imgid" => $imgid, + "path" => $relative_path, + "thumb_path"=> $thumbnail_path, + "storage" => "localhost", + "ip" => get_ip(), + "ua" => get_ua(), + "date" => $this->date, + "user" => $this->user, + "level" => 'unknown' + ); + //需要插入到imginfo表的数据 + $imginfo = array( + "imgid" => $imgid, + "mime" => $img_info['mime'], + "width" => $img_info[0], + "height" => $img_info[1], + "ext" => $ext, + "client_name" => $file_name + ); + //加载数据库模型 + $this->load->model('insert','',TRUE); + //插入数据到img_images表 + $id = $this->insert->images($datas); + $this->insert->imginfo($imginfo); + //获取域名 + $domain = $this->query->domain('localhost'); + //获取图片URL地址 + $url = $domain.$relative_path; + $thumbnail_url = $domain.$this->relative_path.$imgid.'_thumb'.$ext; + //返回成功的信息 + //重组数组 + $info = array( + "code" => 200, + "id" => $id, + "imgid" => $imgid, + "relative_path" => $relative_path, + "url" => $url, + "thumbnail_url" => $thumbnail_url, + "width" => $img_info[0], + "height" => $img_info[1] + ); + $this->succeed_msg($info); + //echo $re; + } + } +?> \ No newline at end of file diff --git a/application/controllers/User.php b/application/controllers/User.php new file mode 100644 index 0000000..8fee6a0 --- /dev/null +++ b/application/controllers/User.php @@ -0,0 +1,91 @@ +load->helper('basic'); + } + //用户登录 + public function login(){ + //加载基础类 + $this->load->library('basic'); + //判断用户是否登录 + if($this->basic->is_login(FALSE)){ + //如果已经登录,则跳转到后台 + header("location:/admin/"); + } + //加载数据库模型 + $this->load->model('query','',TRUE); + //查询站点信息 + $siteinfo = $this->query->site_setting('1'); + $siteinfo->title = '管理员登录 - '.$siteinfo->title; + + //加载登录视图 + $this->load->view('user/header',$siteinfo); + $this->load->view('user/login'); + $this->load->view('user/footer'); + } + //验证用户名、密码是否正确 + public function verify(){ + //获取用户输入的信息 + $user = $this->input->post('user',TRUE); + $pass = $this->input->post('password',TRUE); + $pass = md5($pass.'imgurl'); + + //加载模型 + $this->load->model("query",'',TRUE); + $info = $this->query->userinfo()->values; + + $info = json_decode($info); + + //获取真正的用户名 + $username = $info->username; + + $password = $info->password; + + if(($user == $username) && ($pass == $password)){ + $token = token($username,$password); + //生成COOKIE + setcookie("user", $username, time()+ 7 * 24 * 60 * 60,"/"); + setcookie("token", $token, time()+ 7 * 24 * 60 * 60,"/"); + //跳转到后台 + $data = array( + "code" => 200, + "msg" => '登录成功!' + ); + $data = json_encode($data); + echo $data; + exit; + } + else{ + $this->err_msg('用户名或密码不正确'); + //清除cookie + $this->clean_cookies(); + exit; + } + } + public function logout(){ + echo '您已退出,将在5s后返回首页!'; + $this->clean_cookies(); + header("Refresh:5;url=/"); + exit; + } + //清除COOKIE + protected function clean_cookies(){ + setcookie("user", '', time()-3600,"/"); + setcookie("token", '', time()-3600,"/"); + } + //错误消息 + protected function err_msg($msg){ + $data = array( + "code" => 0, + "msg" => $msg + ); + $data = json_encode($data); + echo $data; + } + } +?> \ No newline at end of file diff --git a/application/controllers/Welcome.php b/application/controllers/Welcome.php new file mode 100644 index 0000000..9213c0c --- /dev/null +++ b/application/controllers/Welcome.php @@ -0,0 +1,25 @@ + + * @see https://codeigniter.com/user_guide/general/urls.html + */ + public function index() + { + $this->load->view('welcome_message'); + } +} diff --git a/application/controllers/index.html b/application/controllers/index.html new file mode 100644 index 0000000..b702fbc --- /dev/null +++ b/application/controllers/index.html @@ -0,0 +1,11 @@ + + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + diff --git a/application/core/index.html b/application/core/index.html new file mode 100644 index 0000000..b702fbc --- /dev/null +++ b/application/core/index.html @@ -0,0 +1,11 @@ + + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + diff --git a/application/helpers/basic_helper.php b/application/helpers/basic_helper.php new file mode 100644 index 0000000..2820b52 --- /dev/null +++ b/application/helpers/basic_helper.php @@ -0,0 +1,142 @@ += 1024){ + $size = $size / 1024; + $size = round($size,1); + $name = $size.' MB'; + } + + } + return $name; + } + //缩略图函数 + function thumbnail($img){ + //返回路径 + $dir = dirname($img['path']); + $thumbnail_name = $dir.'/'.$img['imgid'].'_thumb'.$img['ext']; + + + //缩略图完整地址 + $fullpath = FCPATH.$thumbnail_name; + //echo $fullpath; + //判断缩略图是否存在 + if(is_file($fullpath)){ + return $thumbnail_name; + } + //$thumbnail_name = $dir.$name.'_thumb'; + //返回缩略图地址,不带文件名 + //返回原图 + else{ + return $img['path']; + } + } +?> \ No newline at end of file diff --git a/application/helpers/index.html b/application/helpers/index.html new file mode 100644 index 0000000..b702fbc --- /dev/null +++ b/application/helpers/index.html @@ -0,0 +1,11 @@ + + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + diff --git a/application/hooks/index.html b/application/hooks/index.html new file mode 100644 index 0000000..b702fbc --- /dev/null +++ b/application/hooks/index.html @@ -0,0 +1,11 @@ + + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + diff --git a/application/index.html b/application/index.html new file mode 100644 index 0000000..b702fbc --- /dev/null +++ b/application/index.html @@ -0,0 +1,11 @@ + + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + diff --git a/application/language/english/index.html b/application/language/english/index.html new file mode 100644 index 0000000..b702fbc --- /dev/null +++ b/application/language/english/index.html @@ -0,0 +1,11 @@ + + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + diff --git a/application/language/index.html b/application/language/index.html new file mode 100644 index 0000000..b702fbc --- /dev/null +++ b/application/language/index.html @@ -0,0 +1,11 @@ + + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + diff --git a/application/libraries/Basic.php b/application/libraries/Basic.php new file mode 100644 index 0000000..040861a --- /dev/null +++ b/application/libraries/Basic.php @@ -0,0 +1,106 @@ +CI = & get_instance(); + } + + /* + 该函数检测用户是否已经登录,只需要一个参数 + 如果参数为FALSE时,不会exit中断只执行,仅返回bool类型结果 + 如果参数为TURE时,如果没有登录会exit终止执行 + */ + public function is_login($type = FALSE){ + //获取COOKIE信息 + @$user = $_COOKIE['user']; + @$token = $_COOKIE['token']; + + //加载模型 + $this->CI->load->model('query','',TRUE); + //加载辅助函数 + $this->CI->load->helper('basic'); + + //如果查询成功 + if($this->CI->query->userinfo()){ + $userinfo = $this->CI->query->userinfo(); + $userinfo = json_decode($userinfo->values); + + $username = $userinfo->username; + $password = $userinfo->password; + //echo get_ip(); + $password = $username.$password.get_ip().get_ua(); + $password = md5($password); + + + //判断用户名是否正确,用户名密码正确的情况 + if(($user == $username) && ($token == $password)){ + //判断需要的类型 + return TRUE; + } + //用户名和密码不正确的情况下 + else{ + if($type === FALSE){ + + return false; + } + else{ + echo '权限不足!'; + exit; + } + } + } + else{ + echo '数据库查询错误!'; + exit; + } + } + //查询上传数量限制,需要传入访客IP + public function uplimit($ip){ + + } + //CURL下载图片 + public function dl_pic($url){ + $curl = curl_init($url); + + curl_setopt($curl, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36"); + //伪造reffer + curl_setopt ($ch, CURLOPT_REFERER, $url); + curl_setopt($curl, CURLOPT_FAILONERROR, true); + curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false); + #设置超时时间,最小为1s(可选) + curl_setopt($curl , CURLOPT_TIMEOUT, 60); + + $html = curl_exec($curl); + curl_close($curl); + //返回数据 + return $html; + } + //网站数据分析 + public function analyze(){ + //图片总数 + $data['num'] = $this->CI->db->count_all("images"); + //本月总数 + $data['month'] = $this->CI->query->count_num('month')->num; + //今日总数 + $data['day'] = $this->CI->query->count_num('day')->num; + //管理员上传总数 + $data['admin'] = $this->CI->query->count_num('admin')->num; + //游客上传总数 + $data['visitor'] = $this->CI->query->count_num('visitor')->num; + //可疑图片总数 + $data['dubious'] = $this->CI->query->count_num('dubious')->num; + + return $data; + } + } +?> \ No newline at end of file diff --git a/application/libraries/Image.php b/application/libraries/Image.php new file mode 100644 index 0000000..23f283a --- /dev/null +++ b/application/libraries/Image.php @@ -0,0 +1,46 @@ + $width) || ($img_h > $height)){ + //$image->setImageCompressionQuality(90); + $image->cropThumbnailImage( $width, $height ); + } + + //将缩略图输出到文件 + $image->writeImage( $thumbnail_full ); + + //清理工作 + $image->clear(); + } + //压缩图片 + public function compress($source){ + + } + } + +?> \ No newline at end of file diff --git a/application/libraries/Medoo.php b/application/libraries/Medoo.php new file mode 100644 index 0000000..dcdcb04 --- /dev/null +++ b/application/libraries/Medoo.php @@ -0,0 +1,1692 @@ +type = strtolower($options[ 'database_type' ]); + + if ($this->type === 'mariadb') + { + $this->type = 'mysql'; + } + } + + if (isset($options[ 'prefix' ])) + { + $this->prefix = $options[ 'prefix' ]; + } + + if (isset($options[ 'logging' ]) && is_bool($options[ 'logging' ])) + { + $this->logging = $options[ 'logging' ]; + } + + $option = isset($options[ 'option' ]) ? $options[ 'option' ] : []; + $commands = (isset($options[ 'command' ]) && is_array($options[ 'command' ])) ? $options[ 'command' ] : []; + + switch ($this->type) + { + case 'mysql': + // Make MySQL using standard quoted identifier + $commands[] = 'SET SQL_MODE=ANSI_QUOTES'; + + break; + + case 'mssql': + // Keep MSSQL QUOTED_IDENTIFIER is ON for standard quoting + $commands[] = 'SET QUOTED_IDENTIFIER ON'; + + // Make ANSI_NULLS is ON for NULL value + $commands[] = 'SET ANSI_NULLS ON'; + + break; + } + + if (isset($options[ 'pdo' ])) + { + if (!$options[ 'pdo' ] instanceof PDO) + { + throw new InvalidArgumentException('Invalid PDO object supplied'); + } + + $this->pdo = $options[ 'pdo' ]; + + foreach ($commands as $value) + { + $this->pdo->exec($value); + } + + return; + } + + if (isset($options[ 'dsn' ])) + { + if (is_array($options[ 'dsn' ]) && isset($options[ 'dsn' ][ 'driver' ])) + { + $attr = $options[ 'dsn' ]; + } + else + { + throw new InvalidArgumentException('Invalid DSN option supplied'); + } + } + else + { + if ( + isset($options[ 'port' ]) && + is_int($options[ 'port' ] * 1) + ) + { + $port = $options[ 'port' ]; + } + + $is_port = isset($port); + + switch ($this->type) + { + case 'mysql': + $attr = [ + 'driver' => 'mysql', + 'dbname' => $options[ 'database_name' ] + ]; + + if (isset($options[ 'socket' ])) + { + $attr[ 'unix_socket' ] = $options[ 'socket' ]; + } + else + { + $attr[ 'host' ] = $options[ 'server' ]; + + if ($is_port) + { + $attr[ 'port' ] = $port; + } + } + + break; + + case 'pgsql': + $attr = [ + 'driver' => 'pgsql', + 'host' => $options[ 'server' ], + 'dbname' => $options[ 'database_name' ] + ]; + + if ($is_port) + { + $attr[ 'port' ] = $port; + } + + break; + + case 'sybase': + $attr = [ + 'driver' => 'dblib', + 'host' => $options[ 'server' ], + 'dbname' => $options[ 'database_name' ] + ]; + + if ($is_port) + { + $attr[ 'port' ] = $port; + } + + break; + + case 'oracle': + $attr = [ + 'driver' => 'oci', + 'dbname' => $options[ 'server' ] ? + '//' . $options[ 'server' ] . ($is_port ? ':' . $port : ':1521') . '/' . $options[ 'database_name' ] : + $options[ 'database_name' ] + ]; + + if (isset($options[ 'charset' ])) + { + $attr[ 'charset' ] = $options[ 'charset' ]; + } + + break; + + case 'mssql': + if (isset($options[ 'driver' ]) && $options[ 'driver' ] === 'dblib') + { + $attr = [ + 'driver' => 'dblib', + 'host' => $options[ 'server' ] . ($is_port ? ':' . $port : ''), + 'dbname' => $options[ 'database_name' ] + ]; + + if (isset($options[ 'appname' ])) + { + $attr[ 'appname' ] = $options[ 'appname' ]; + } + + if (isset($options[ 'charset' ])) + { + $attr[ 'charset' ] = $options[ 'charset' ]; + } + } + else + { + $attr = [ + 'driver' => 'sqlsrv', + 'Server' => $options[ 'server' ] . ($is_port ? ',' . $port : ''), + 'Database' => $options[ 'database_name' ] + ]; + + if (isset($options[ 'appname' ])) + { + $attr[ 'APP' ] = $options[ 'appname' ]; + } + + $config = [ + 'ApplicationIntent', + 'AttachDBFileName', + 'Authentication', + 'ColumnEncryption', + 'ConnectionPooling', + 'Encrypt', + 'Failover_Partner', + 'KeyStoreAuthentication', + 'KeyStorePrincipalId', + 'KeyStoreSecret', + 'LoginTimeout', + 'MultipleActiveResultSets', + 'MultiSubnetFailover', + 'Scrollable', + 'TraceFile', + 'TraceOn', + 'TransactionIsolation', + 'TransparentNetworkIPResolution', + 'TrustServerCertificate', + 'WSID', + ]; + + foreach ($config as $value) + { + $keyname = strtolower(preg_replace(['/([a-z\d])([A-Z])/', '/([^_])([A-Z][a-z])/'], '$1_$2', $value)); + + if (isset($options[ $keyname ])) + { + $attr[ $value ] = $options[ $keyname ]; + } + } + } + + break; + + case 'sqlite': + $attr = [ + 'driver' => 'sqlite', + $options[ 'database_file' ] + ]; + + break; + } + } + + if (!isset($attr)) + { + throw new InvalidArgumentException('Incorrect connection options'); + } + + $driver = $attr[ 'driver' ]; + + if (!in_array($driver, PDO::getAvailableDrivers())) + { + throw new InvalidArgumentException("Unsupported PDO driver: {$driver}"); + } + + unset($attr[ 'driver' ]); + + $stack = []; + + foreach ($attr as $key => $value) + { + $stack[] = is_int($key) ? $value : $key . '=' . $value; + } + + $dsn = $driver . ':' . implode($stack, ';'); + + if ( + in_array($this->type, ['mysql', 'pgsql', 'sybase', 'mssql']) && + isset($options[ 'charset' ]) + ) + { + $commands[] = "SET NAMES '{$options[ 'charset' ]}'" . ( + $this->type === 'mysql' && isset($options[ 'collation' ]) ? + " COLLATE '{$options[ 'collation' ]}'" : '' + ); + } + + $this->dsn = $dsn; + + try { + $this->pdo = new PDO( + $dsn, + isset($options[ 'username' ]) ? $options[ 'username' ] : null, + isset($options[ 'password' ]) ? $options[ 'password' ] : null, + $option + ); + + foreach ($commands as $value) + { + $this->pdo->exec($value); + } + } + catch (PDOException $e) { + throw new PDOException($e->getMessage()); + } + } + + public function query($query, $map = []) + { + $raw = $this->raw($query, $map); + + $query = $this->buildRaw($raw, $map); + + return $this->exec($query, $map); + } + + public function exec($query, $map = []) + { + if ($this->debug_mode) + { + echo $this->generate($query, $map); + + $this->debug_mode = false; + + return false; + } + + if ($this->logging) + { + $this->logs[] = [$query, $map]; + } + else + { + $this->logs = [[$query, $map]]; + } + + $statement = $this->pdo->prepare($query); + + if ($statement) + { + foreach ($map as $key => $value) + { + $statement->bindValue($key, $value[ 0 ], $value[ 1 ]); + } + + $statement->execute(); + + $this->statement = $statement; + + return $statement; + } + + return false; + } + + protected function generate($query, $map) + { + $identifier = [ + 'mysql' => '`$1`', + 'mssql' => '[$1]' + ]; + + $query = preg_replace( + '/"([a-zA-Z0-9_]+)"/i', + isset($identifier[ $this->type ]) ? $identifier[ $this->type ] : '"$1"', + $query + ); + + foreach ($map as $key => $value) + { + if ($value[ 1 ] === PDO::PARAM_STR) + { + $replace = $this->quote($value[ 0 ]); + } + elseif ($value[ 1 ] === PDO::PARAM_NULL) + { + $replace = 'NULL'; + } + elseif ($value[ 1 ] === PDO::PARAM_LOB) + { + $replace = '{LOB_DATA}'; + } + else + { + $replace = $value[ 0 ]; + } + + $query = str_replace($key, $replace, $query); + } + + return $query; + } + + public static function raw($string, $map = []) + { + $raw = new Raw(); + + $raw->map = $map; + $raw->value = $string; + + return $raw; + } + + protected function isRaw($object) + { + return $object instanceof Raw; + } + + protected function buildRaw($raw, &$map) + { + if (!$this->isRaw($raw)) + { + return false; + } + + $query = preg_replace_callback( + '/((FROM|TABLE|INTO|UPDATE)\s*)?\<([a-zA-Z0-9_\.]+)\>/i', + function ($matches) + { + if (!empty($matches[ 2 ])) + { + return $matches[ 2 ] . ' ' . $this->tableQuote($matches[ 3 ]); + } + + return $this->columnQuote($matches[ 3 ]); + }, + $raw->value); + + $raw_map = $raw->map; + + if (!empty($raw_map)) + { + foreach ($raw_map as $key => $value) + { + $map[ $key ] = $this->typeMap($value, gettype($value)); + } + } + + return $query; + } + + public function quote($string) + { + return $this->pdo->quote($string); + } + + protected function tableQuote($table) + { + return '"' . $this->prefix . $table . '"'; + } + + protected function mapKey() + { + return ':MeDoO_' . $this->guid++ . '_mEdOo'; + } + + protected function typeMap($value, $type) + { + $map = [ + 'NULL' => PDO::PARAM_NULL, + 'integer' => PDO::PARAM_INT, + 'double' => PDO::PARAM_STR, + 'boolean' => PDO::PARAM_BOOL, + 'string' => PDO::PARAM_STR, + 'object' => PDO::PARAM_STR, + 'resource' => PDO::PARAM_LOB + ]; + + if ($type === 'boolean') + { + $value = ($value ? '1' : '0'); + } + elseif ($type === 'NULL') + { + $value = null; + } + + return [$value, $map[ $type ]]; + } + + protected function columnQuote($string) + { + if (strpos($string, '.') !== false) + { + return '"' . $this->prefix . str_replace('.', '"."', $string) . '"'; + } + + return '"' . $string . '"'; + } + + protected function columnPush(&$columns, &$map) + { + if ($columns === '*') + { + return $columns; + } + + $stack = []; + + if (is_string($columns)) + { + $columns = [$columns]; + } + + foreach ($columns as $key => $value) + { + if (is_array($value)) + { + $stack[] = $this->columnPush($value, $map); + } + elseif (!is_int($key) && $raw = $this->buildRaw($value, $map)) + { + preg_match('/(?[a-zA-Z0-9_\.]+)(\s*\[(?(String|Bool|Int|Number))\])?/i', $key, $match); + + $stack[] = $raw . ' AS ' . $this->columnQuote( $match[ 'column' ] ); + } + elseif (is_int($key) && is_string($value)) + { + preg_match('/(?[a-zA-Z0-9_\.]+)(?:\s*\((?[a-zA-Z0-9_]+)\))?(?:\s*\[(?(?:String|Bool|Int|Number|Object|JSON))\])?/i', $value, $match); + + if (!empty($match[ 'alias' ])) + { + $stack[] = $this->columnQuote( $match[ 'column' ] ) . ' AS ' . $this->columnQuote( $match[ 'alias' ] ); + + $columns[ $key ] = $match[ 'alias' ]; + + if (!empty($match[ 'type' ])) + { + $columns[ $key ] .= ' [' . $match[ 'type' ] . ']'; + } + } + else + { + $stack[] = $this->columnQuote( $match[ 'column' ] ); + } + } + } + + return implode($stack, ','); + } + + protected function arrayQuote($array) + { + $stack = []; + + foreach ($array as $value) + { + $stack[] = is_int($value) ? $value : $this->pdo->quote($value); + } + + return implode($stack, ','); + } + + protected function innerConjunct($data, $map, $conjunctor, $outer_conjunctor) + { + $stack = []; + + foreach ($data as $value) + { + $stack[] = '(' . $this->dataImplode($value, $map, $conjunctor) . ')'; + } + + return implode($outer_conjunctor . ' ', $stack); + } + + protected function dataImplode($data, &$map, $conjunctor) + { + $stack = []; + + foreach ($data as $key => $value) + { + $type = gettype($value); + + if ( + $type === 'array' && + preg_match("/^(AND|OR)(\s+#.*)?$/", $key, $relation_match) + ) + { + $relationship = $relation_match[ 1 ]; + + $stack[] = $value !== array_keys(array_keys($value)) ? + '(' . $this->dataImplode($value, $map, ' ' . $relationship) . ')' : + '(' . $this->innerConjunct($value, $map, ' ' . $relationship, $conjunctor) . ')'; + + continue; + } + + $map_key = $this->mapKey(); + + if ( + is_int($key) && + preg_match('/([a-zA-Z0-9_\.]+)\[(?\>\=?|\<\=?|\!?\=)\]([a-zA-Z0-9_\.]+)/i', $value, $match) + ) + { + $stack[] = $this->columnQuote($match[ 1 ]) . ' ' . $match[ 'operator' ] . ' ' . $this->columnQuote($match[ 3 ]); + } + else + { + preg_match('/([a-zA-Z0-9_\.]+)(\[(?\>\=?|\<\=?|\!|\<\>|\>\<|\!?~|REGEXP)\])?/i', $key, $match); + $column = $this->columnQuote($match[ 1 ]); + + if (isset($match[ 'operator' ])) + { + $operator = $match[ 'operator' ]; + + if (in_array($operator, ['>', '>=', '<', '<='])) + { + $condition = $column . ' ' . $operator . ' '; + + if (is_numeric($value)) + { + $condition .= $map_key; + $map[ $map_key ] = [$value, PDO::PARAM_INT]; + } + elseif ($raw = $this->buildRaw($value, $map)) + { + $condition .= $raw; + } + else + { + $condition .= $map_key; + $map[ $map_key ] = [$value, PDO::PARAM_STR]; + } + + $stack[] = $condition; + } + elseif ($operator === '!') + { + switch ($type) + { + case 'NULL': + $stack[] = $column . ' IS NOT NULL'; + break; + + case 'array': + $placeholders = []; + + foreach ($value as $index => $item) + { + $placeholders[] = $map_key . $index . '_i'; + $map[ $map_key . $index . '_i' ] = $this->typeMap($item, gettype($item)); + } + + $stack[] = $column . ' NOT IN (' . implode(', ', $placeholders) . ')'; + break; + + case 'object': + if ($raw = $this->buildRaw($value, $map)) + { + $stack[] = $column . ' != ' . $raw; + } + break; + + case 'integer': + case 'double': + case 'boolean': + case 'string': + $stack[] = $column . ' != ' . $map_key; + $map[ $map_key ] = $this->typeMap($value, $type); + break; + } + } + elseif ($operator === '~' || $operator === '!~') + { + if ($type !== 'array') + { + $value = [ $value ]; + } + + $connector = ' OR '; + $data = array_values($value); + + if (is_array($data[ 0 ])) + { + if (isset($value[ 'AND' ]) || isset($value[ 'OR' ])) + { + $connector = ' ' . array_keys($value)[ 0 ] . ' '; + $value = $data[ 0 ]; + } + } + + $like_clauses = []; + + foreach ($value as $index => $item) + { + $item = strval($item); + + if (!preg_match('/(\[.+\]|_|%.+|.+%)/', $item)) + { + $item = '%' . $item . '%'; + } + + $like_clauses[] = $column . ($operator === '!~' ? ' NOT' : '') . ' LIKE ' . $map_key . 'L' . $index; + $map[ $map_key . 'L' . $index ] = [$item, PDO::PARAM_STR]; + } + + $stack[] = '(' . implode($connector, $like_clauses) . ')'; + } + elseif ($operator === '<>' || $operator === '><') + { + if ($type === 'array') + { + if ($operator === '><') + { + $column .= ' NOT'; + } + + $stack[] = '(' . $column . ' BETWEEN ' . $map_key . 'a AND ' . $map_key . 'b)'; + + $data_type = (is_numeric($value[ 0 ]) && is_numeric($value[ 1 ])) ? PDO::PARAM_INT : PDO::PARAM_STR; + + $map[ $map_key . 'a' ] = [$value[ 0 ], $data_type]; + $map[ $map_key . 'b' ] = [$value[ 1 ], $data_type]; + } + } + elseif ($operator === 'REGEXP') + { + $stack[] = $column . ' REGEXP ' . $map_key; + $map[ $map_key ] = [$value, PDO::PARAM_STR]; + } + } + else + { + switch ($type) + { + case 'NULL': + $stack[] = $column . ' IS NULL'; + break; + + case 'array': + $placeholders = []; + + foreach ($value as $index => $item) + { + $placeholders[] = $map_key . $index . '_i'; + $map[ $map_key . $index . '_i' ] = $this->typeMap($item, gettype($item)); + } + + $stack[] = $column . ' IN (' . implode(', ', $placeholders) . ')'; + break; + + case 'object': + if ($raw = $this->buildRaw($value, $map)) + { + $stack[] = $column . ' = ' . $raw; + } + break; + + case 'integer': + case 'double': + case 'boolean': + case 'string': + $stack[] = $column . ' = ' . $map_key; + $map[ $map_key ] = $this->typeMap($value, $type); + break; + } + } + } + } + + return implode($conjunctor . ' ', $stack); + } + + protected function whereClause($where, &$map) + { + $where_clause = ''; + + if (is_array($where)) + { + $where_keys = array_keys($where); + + $conditions = array_diff_key($where, array_flip( + ['GROUP', 'ORDER', 'HAVING', 'LIMIT', 'LIKE', 'MATCH'] + )); + + if (!empty($conditions)) + { + $where_clause = ' WHERE ' . $this->dataImplode($conditions, $map, ' AND'); + } + + if (isset($where[ 'MATCH' ]) && $this->type === 'mysql') + { + $MATCH = $where[ 'MATCH' ]; + + if (is_array($MATCH) && isset($MATCH[ 'columns' ], $MATCH[ 'keyword' ])) + { + $mode = ''; + + $mode_array = [ + 'natural' => 'IN NATURAL LANGUAGE MODE', + 'natural+query' => 'IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION', + 'boolean' => 'IN BOOLEAN MODE', + 'query' => 'WITH QUERY EXPANSION' + ]; + + if (isset($MATCH[ 'mode' ], $mode_array[ $MATCH[ 'mode' ] ])) + { + $mode = ' ' . $mode_array[ $MATCH[ 'mode' ] ]; + } + + $columns = implode(array_map([$this, 'columnQuote'], $MATCH[ 'columns' ]), ', '); + $map_key = $this->mapKey(); + $map[ $map_key ] = [$MATCH[ 'keyword' ], PDO::PARAM_STR]; + + $where_clause .= ($where_clause !== '' ? ' AND ' : ' WHERE') . ' MATCH (' . $columns . ') AGAINST (' . $map_key . $mode . ')'; + } + } + + if (isset($where[ 'GROUP' ])) + { + $GROUP = $where[ 'GROUP' ]; + + if (is_array($GROUP)) + { + $stack = []; + + foreach ($GROUP as $column => $value) + { + $stack[] = $this->columnQuote($value); + } + + $where_clause .= ' GROUP BY ' . implode($stack, ','); + } + elseif ($raw = $this->buildRaw($GROUP, $map)) + { + $where_clause .= ' GROUP BY ' . $raw; + } + else + { + $where_clause .= ' GROUP BY ' . $this->columnQuote($GROUP); + } + + if (isset($where[ 'HAVING' ])) + { + if ($raw = $this->buildRaw($where[ 'HAVING' ], $map)) + { + $where_clause .= ' HAVING ' . $raw; + } + else + { + $where_clause .= ' HAVING ' . $this->dataImplode($where[ 'HAVING' ], $map, ' AND'); + } + } + } + + if (isset($where[ 'ORDER' ])) + { + $ORDER = $where[ 'ORDER' ]; + + if (is_array($ORDER)) + { + $stack = []; + + foreach ($ORDER as $column => $value) + { + if (is_array($value)) + { + $stack[] = 'FIELD(' . $this->columnQuote($column) . ', ' . $this->arrayQuote($value) . ')'; + } + elseif ($value === 'ASC' || $value === 'DESC') + { + $stack[] = $this->columnQuote($column) . ' ' . $value; + } + elseif (is_int($column)) + { + $stack[] = $this->columnQuote($value); + } + } + + $where_clause .= ' ORDER BY ' . implode($stack, ','); + } + elseif ($raw = $this->buildRaw($ORDER, $map)) + { + $where_clause .= ' ORDER BY ' . $raw; + } + else + { + $where_clause .= ' ORDER BY ' . $this->columnQuote($ORDER); + } + + if ( + isset($where[ 'LIMIT' ]) && + in_array($this->type, ['oracle', 'mssql']) + ) + { + $LIMIT = $where[ 'LIMIT' ]; + + if (is_numeric($LIMIT)) + { + $LIMIT = [0, $LIMIT]; + } + + if ( + is_array($LIMIT) && + is_numeric($LIMIT[ 0 ]) && + is_numeric($LIMIT[ 1 ]) + ) + { + $where_clause .= ' OFFSET ' . $LIMIT[ 0 ] . ' ROWS FETCH NEXT ' . $LIMIT[ 1 ] . ' ROWS ONLY'; + } + } + } + + if (isset($where[ 'LIMIT' ]) && !in_array($this->type, ['oracle', 'mssql'])) + { + $LIMIT = $where[ 'LIMIT' ]; + + if (is_numeric($LIMIT)) + { + $where_clause .= ' LIMIT ' . $LIMIT; + } + elseif ( + is_array($LIMIT) && + is_numeric($LIMIT[ 0 ]) && + is_numeric($LIMIT[ 1 ]) + ) + { + $where_clause .= ' LIMIT ' . $LIMIT[ 1 ] . ' OFFSET ' . $LIMIT[ 0 ]; + } + } + } + elseif ($raw = $this->buildRaw($where, $map)) + { + $where_clause .= ' ' . $raw; + } + + return $where_clause; + } + + protected function selectContext($table, &$map, $join, &$columns = null, $where = null, $column_fn = null) + { + preg_match('/(?[a-zA-Z0-9_]+)\s*\((?[a-zA-Z0-9_]+)\)/i', $table, $table_match); + + if (isset($table_match[ 'table' ], $table_match[ 'alias' ])) + { + $table = $this->tableQuote($table_match[ 'table' ]); + + $table_query = $table . ' AS ' . $this->tableQuote($table_match[ 'alias' ]); + } + else + { + $table = $this->tableQuote($table); + + $table_query = $table; + } + + $join_key = is_array($join) ? array_keys($join) : null; + + if ( + isset($join_key[ 0 ]) && + strpos($join_key[ 0 ], '[') === 0 + ) + { + $table_join = []; + + $join_array = [ + '>' => 'LEFT', + '<' => 'RIGHT', + '<>' => 'FULL', + '><' => 'INNER' + ]; + + foreach($join as $sub_table => $relation) + { + preg_match('/(\[(?\<\>?|\>\[a-zA-Z0-9_]+)\s?(\((?[a-zA-Z0-9_]+)\))?/', $sub_table, $match); + + if ($match[ 'join' ] !== '' && $match[ 'table' ] !== '') + { + if (is_string($relation)) + { + $relation = 'USING ("' . $relation . '")'; + } + + if (is_array($relation)) + { + // For ['column1', 'column2'] + if (isset($relation[ 0 ])) + { + $relation = 'USING ("' . implode($relation, '", "') . '")'; + } + else + { + $joins = []; + + foreach ($relation as $key => $value) + { + $joins[] = ( + strpos($key, '.') > 0 ? + // For ['tableB.column' => 'column'] + $this->columnQuote($key) : + + // For ['column1' => 'column2'] + $table . '."' . $key . '"' + ) . + ' = ' . + $this->tableQuote(isset($match[ 'alias' ]) ? $match[ 'alias' ] : $match[ 'table' ]) . '."' . $value . '"'; + } + + $relation = 'ON ' . implode($joins, ' AND '); + } + } + + $table_name = $this->tableQuote($match[ 'table' ]) . ' '; + + if (isset($match[ 'alias' ])) + { + $table_name .= 'AS ' . $this->tableQuote($match[ 'alias' ]) . ' '; + } + + $table_join[] = $join_array[ $match[ 'join' ] ] . ' JOIN ' . $table_name . $relation; + } + } + + $table_query .= ' ' . implode($table_join, ' '); + } + else + { + if (is_null($columns)) + { + if ( + !is_null($where) || + (is_array($join) && isset($column_fn)) + ) + { + $where = $join; + $columns = null; + } + else + { + $where = null; + $columns = $join; + } + } + else + { + $where = $columns; + $columns = $join; + } + } + + if (isset($column_fn)) + { + if ($column_fn === 1) + { + $column = '1'; + + if (is_null($where)) + { + $where = $columns; + } + } + elseif ($raw = $this->buildRaw($column_fn, $map)) + { + $column = $raw; + } + else + { + if (empty($columns) || $this->isRaw($columns)) + { + $columns = '*'; + $where = $join; + } + + $column = $column_fn . '(' . $this->columnPush($columns, $map) . ')'; + } + } + else + { + $column = $this->columnPush($columns, $map); + } + + return 'SELECT ' . $column . ' FROM ' . $table_query . $this->whereClause($where, $map); + } + + protected function columnMap($columns, &$stack) + { + if ($columns === '*') + { + return $stack; + } + + foreach ($columns as $key => $value) + { + if (is_int($key)) + { + preg_match('/([a-zA-Z0-9_]+\.)?(?[a-zA-Z0-9_]+)(?:\s*\((?[a-zA-Z0-9_]+)\))?(?:\s*\[(?(?:String|Bool|Int|Number|Object|JSON))\])?/i', $value, $key_match); + + $column_key = !empty($key_match[ 'alias' ]) ? + $key_match[ 'alias' ] : + $key_match[ 'column' ]; + + if (isset($key_match[ 'type' ])) + { + $stack[ $value ] = [$column_key, $key_match[ 'type' ]]; + } + else + { + $stack[ $value ] = [$column_key, 'String']; + } + } + elseif ($this->isRaw($value)) + { + preg_match('/([a-zA-Z0-9_]+\.)?(?[a-zA-Z0-9_]+)(\s*\[(?(String|Bool|Int|Number))\])?/i', $key, $key_match); + + $column_key = $key_match[ 'column' ]; + + if (isset($key_match[ 'type' ])) + { + $stack[ $key ] = [$column_key, $key_match[ 'type' ]]; + } + else + { + $stack[ $key ] = [$column_key, 'String']; + } + } + elseif (!is_int($key) && is_array($value)) + { + $this->columnMap($value, $stack); + } + } + + return $stack; + } + + protected function dataMap($data, $columns, $column_map, &$stack) + { + foreach ($columns as $key => $value) + { + $isRaw = $this->isRaw($value); + + if (is_int($key) || $isRaw) + { + $map = $column_map[ $isRaw ? $key : $value ]; + + $column_key = $map[ 0 ]; + + $result = $data[ $column_key ]; + + if (isset($map[ 1 ])) + { + if ($isRaw && in_array($map[ 1 ], ['Object', 'JSON'])) + { + continue; + } + + if (is_null($result)) + { + $stack[ $column_key ] = null; + continue; + } + + switch ($map[ 1 ]) + { + case 'Number': + $stack[ $column_key ] = (double) $result; + break; + + case 'Int': + $stack[ $column_key ] = (int) $result; + break; + + case 'Bool': + $stack[ $column_key ] = (bool) $result; + break; + + case 'Object': + $stack[ $column_key ] = unserialize($result); + break; + + case 'JSON': + $stack[ $column_key ] = json_decode($result, true); + break; + + case 'String': + $stack[ $column_key ] = $result; + break; + } + } + else + { + $stack[ $column_key ] = $result; + } + } + else + { + $current_stack = []; + + $this->dataMap($data, $value, $column_map, $current_stack); + + $stack[ $key ] = $current_stack; + } + } + } + + public function select($table, $join, $columns = null, $where = null) + { + $map = []; + $stack = []; + $column_map = []; + + $index = 0; + + $column = $where === null ? $join : $columns; + + $is_single = (is_string($column) && $column !== '*'); + + $query = $this->exec($this->selectContext($table, $map, $join, $columns, $where), $map); + + $this->columnMap($columns, $column_map); + + if (!$query) + { + return false; + } + + if ($columns === '*') + { + return $query->fetchAll(PDO::FETCH_ASSOC); + } + + if ($is_single) + { + return $query->fetchAll(PDO::FETCH_COLUMN); + } + + while ($data = $query->fetch(PDO::FETCH_ASSOC)) + { + $current_stack = []; + + $this->dataMap($data, $columns, $column_map, $current_stack); + + $stack[ $index ] = $current_stack; + + $index++; + } + + return $stack; + } + + public function insert($table, $datas) + { + $stack = []; + $columns = []; + $fields = []; + $map = []; + + if (!isset($datas[ 0 ])) + { + $datas = [$datas]; + } + + foreach ($datas as $data) + { + foreach ($data as $key => $value) + { + $columns[] = $key; + } + } + + $columns = array_unique($columns); + + foreach ($datas as $data) + { + $values = []; + + foreach ($columns as $key) + { + if ($raw = $this->buildRaw($data[ $key ], $map)) + { + $values[] = $raw; + continue; + } + + $map_key =$this->mapKey(); + + $values[] = $map_key; + + if (!isset($data[ $key ])) + { + $map[ $map_key ] = [null, PDO::PARAM_NULL]; + } + else + { + $value = $data[ $key ]; + + $type = gettype($value); + + switch ($type) + { + case 'array': + $map[ $map_key ] = [ + strpos($key, '[JSON]') === strlen($key) - 6 ? + json_encode($value) : + serialize($value), + PDO::PARAM_STR + ]; + break; + + case 'object': + $value = serialize($value); + + case 'NULL': + case 'resource': + case 'boolean': + case 'integer': + case 'double': + case 'string': + $map[ $map_key ] = $this->typeMap($value, $type); + break; + } + } + } + + $stack[] = '(' . implode($values, ', ') . ')'; + } + + foreach ($columns as $key) + { + $fields[] = $this->columnQuote(preg_replace("/(\s*\[JSON\]$)/i", '', $key)); + } + + return $this->exec('INSERT INTO ' . $this->tableQuote($table) . ' (' . implode(', ', $fields) . ') VALUES ' . implode(', ', $stack), $map); + } + + public function update($table, $data, $where = null) + { + $fields = []; + $map = []; + + foreach ($data as $key => $value) + { + $column = $this->columnQuote(preg_replace("/(\s*\[(JSON|\+|\-|\*|\/)\]$)/i", '', $key)); + + if ($raw = $this->buildRaw($value, $map)) + { + $fields[] = $column . ' = ' . $raw; + continue; + } + + $map_key = $this->mapKey(); + + preg_match('/(?[a-zA-Z0-9_]+)(\[(?\+|\-|\*|\/)\])?/i', $key, $match); + + if (isset($match[ 'operator' ])) + { + if (is_numeric($value)) + { + $fields[] = $column . ' = ' . $column . ' ' . $match[ 'operator' ] . ' ' . $value; + } + } + else + { + $fields[] = $column . ' = ' . $map_key; + + $type = gettype($value); + + switch ($type) + { + case 'array': + $map[ $map_key ] = [ + strpos($key, '[JSON]') === strlen($key) - 6 ? + json_encode($value) : + serialize($value), + PDO::PARAM_STR + ]; + break; + + case 'object': + $value = serialize($value); + + case 'NULL': + case 'resource': + case 'boolean': + case 'integer': + case 'double': + case 'string': + $map[ $map_key ] = $this->typeMap($value, $type); + break; + } + } + } + + return $this->exec('UPDATE ' . $this->tableQuote($table) . ' SET ' . implode(', ', $fields) . $this->whereClause($where, $map), $map); + } + + public function delete($table, $where) + { + $map = []; + + return $this->exec('DELETE FROM ' . $this->tableQuote($table) . $this->whereClause($where, $map), $map); + } + + public function replace($table, $columns, $where = null) + { + if (!is_array($columns) || empty($columns)) + { + return false; + } + + $map = []; + $stack = []; + + foreach ($columns as $column => $replacements) + { + if (is_array($replacements)) + { + foreach ($replacements as $old => $new) + { + $map_key = $this->mapKey(); + + $stack[] = $this->columnQuote($column) . ' = REPLACE(' . $this->columnQuote($column) . ', ' . $map_key . 'a, ' . $map_key . 'b)'; + + $map[ $map_key . 'a' ] = [$old, PDO::PARAM_STR]; + $map[ $map_key . 'b' ] = [$new, PDO::PARAM_STR]; + } + } + } + + if (!empty($stack)) + { + return $this->exec('UPDATE ' . $this->tableQuote($table) . ' SET ' . implode(', ', $stack) . $this->whereClause($where, $map), $map); + } + + return false; + } + + public function get($table, $join = null, $columns = null, $where = null) + { + $map = []; + $stack = []; + $column_map = []; + + if ($where === null) + { + $column = $join; + unset($columns[ 'LIMIT' ]); + } + else + { + $column = $columns; + unset($where[ 'LIMIT' ]); + } + + $is_single = (is_string($column) && $column !== '*'); + + $query = $this->exec($this->selectContext($table, $map, $join, $columns, $where) . ' LIMIT 1', $map); + + if ($query) + { + $data = $query->fetchAll(PDO::FETCH_ASSOC); + + if (isset($data[ 0 ])) + { + if ($column === '*') + { + return $data[ 0 ]; + } + + $this->columnMap($columns, $column_map); + + $this->dataMap($data[ 0 ], $columns, $column_map, $stack); + + if ($is_single) + { + return $stack[ $column_map[ $column ][ 0 ] ]; + } + + return $stack; + } + } + } + + public function has($table, $join, $where = null) + { + $map = []; + $column = null; + + if ($this->type === 'mssql') + { + $query = $this->exec($this->selectContext($table, $map, $join, $column, $where, Medoo::raw('TOP 1 1')), $map); + } + else + { + $query = $this->exec('SELECT EXISTS(' . $this->selectContext($table, $map, $join, $column, $where, 1) . ')', $map); + } + + if ($query) + { + $result = $query->fetchColumn(); + + return $result === '1' || $result === 1 || $result === true; + } + + return false; + } + + public function rand($table, $join = null, $columns = null, $where = null) + { + $type = $this->type; + + $order = 'RANDOM()'; + + if ($type === 'mysql') + { + $order = 'RAND()'; + } + elseif ($type === 'mssql') + { + $order = 'NEWID()'; + } + + $order_raw = $this->raw($order); + + if ($where === null) + { + if ($columns === null) + { + $columns = [ + 'ORDER' => $order_raw + ]; + } + else + { + $column = $join; + unset($columns[ 'ORDER' ]); + + $columns[ 'ORDER' ] = $order_raw; + } + } + else + { + unset($where[ 'ORDER' ]); + + $where[ 'ORDER' ] = $order_raw; + } + + return $this->select($table, $join, $columns, $where); + } + + private function aggregate($type, $table, $join = null, $column = null, $where = null) + { + $map = []; + + $query = $this->exec($this->selectContext($table, $map, $join, $column, $where, strtoupper($type)), $map); + + if ($query) + { + $number = $query->fetchColumn(); + + return is_numeric($number) ? $number + 0 : $number; + } + + return false; + } + + public function count($table, $join = null, $column = null, $where = null) + { + return $this->aggregate('count', $table, $join, $column, $where); + } + + public function avg($table, $join, $column = null, $where = null) + { + return $this->aggregate('avg', $table, $join, $column, $where); + } + + public function max($table, $join, $column = null, $where = null) + { + return $this->aggregate('max', $table, $join, $column, $where); + } + + public function min($table, $join, $column = null, $where = null) + { + return $this->aggregate('min', $table, $join, $column, $where); + } + + public function sum($table, $join, $column = null, $where = null) + { + return $this->aggregate('sum', $table, $join, $column, $where); + } + + public function action($actions) + { + if (is_callable($actions)) + { + $this->pdo->beginTransaction(); + + try { + $result = $actions($this); + + if ($result === false) + { + $this->pdo->rollBack(); + } + else + { + $this->pdo->commit(); + } + } + catch (Exception $e) { + $this->pdo->rollBack(); + + throw $e; + } + + return $result; + } + + return false; + } + + public function id() + { + $type = $this->type; + + if ($type === 'oracle') + { + return 0; + } + elseif ($type === 'pgsql') + { + return $this->pdo->query('SELECT LASTVAL()')->fetchColumn(); + } + + return $this->pdo->lastInsertId(); + } + + public function debug() + { + $this->debug_mode = true; + + return $this; + } + + public function error() + { + return $this->statement ? $this->statement->errorInfo() : null; + } + + public function last() + { + $log = end($this->logs); + + return $this->generate($log[ 0 ], $log[ 1 ]); + } + + public function log() + { + return array_map(function ($log) + { + return $this->generate($log[ 0 ], $log[ 1 ]); + }, + $this->logs + ); + } + + public function info() + { + $output = [ + 'server' => 'SERVER_INFO', + 'driver' => 'DRIVER_NAME', + 'client' => 'CLIENT_VERSION', + 'version' => 'SERVER_VERSION', + 'connection' => 'CONNECTION_STATUS' + ]; + + foreach ($output as $key => $value) + { + $output[ $key ] = @$this->pdo->getAttribute(constant('PDO::ATTR_' . $value)); + } + + $output[ 'dsn' ] = $this->dsn; + + return $output; + } +} \ No newline at end of file diff --git a/application/libraries/Parsedown.php b/application/libraries/Parsedown.php new file mode 100644 index 0000000..87d612a --- /dev/null +++ b/application/libraries/Parsedown.php @@ -0,0 +1,1679 @@ +DefinitionData = array(); + + # standardize line breaks + $text = str_replace(array("\r\n", "\r"), "\n", $text); + + # remove surrounding line breaks + $text = trim($text, "\n"); + + # split text into lines + $lines = explode("\n", $text); + + # iterate through lines to identify blocks + $markup = $this->lines($lines); + + # trim line breaks + $markup = trim($markup, "\n"); + + return $markup; + } + + # + # Setters + # + + function setBreaksEnabled($breaksEnabled) + { + $this->breaksEnabled = $breaksEnabled; + + return $this; + } + + protected $breaksEnabled; + + function setMarkupEscaped($markupEscaped) + { + $this->markupEscaped = $markupEscaped; + + return $this; + } + + protected $markupEscaped; + + function setUrlsLinked($urlsLinked) + { + $this->urlsLinked = $urlsLinked; + + return $this; + } + + protected $urlsLinked = true; + + function setSafeMode($safeMode) + { + $this->safeMode = (bool) $safeMode; + + return $this; + } + + protected $safeMode; + + protected $safeLinksWhitelist = array( + 'http://', + 'https://', + 'ftp://', + 'ftps://', + 'mailto:', + 'data:image/png;base64,', + 'data:image/gif;base64,', + 'data:image/jpeg;base64,', + 'irc:', + 'ircs:', + 'git:', + 'ssh:', + 'news:', + 'steam:', + ); + + # + # Lines + # + + protected $BlockTypes = array( + '#' => array('Header'), + '*' => array('Rule', 'List'), + '+' => array('List'), + '-' => array('SetextHeader', 'Table', 'Rule', 'List'), + '0' => array('List'), + '1' => array('List'), + '2' => array('List'), + '3' => array('List'), + '4' => array('List'), + '5' => array('List'), + '6' => array('List'), + '7' => array('List'), + '8' => array('List'), + '9' => array('List'), + ':' => array('Table'), + '<' => array('Comment', 'Markup'), + '=' => array('SetextHeader'), + '>' => array('Quote'), + '[' => array('Reference'), + '_' => array('Rule'), + '`' => array('FencedCode'), + '|' => array('Table'), + '~' => array('FencedCode'), + ); + + # ~ + + protected $unmarkedBlockTypes = array( + 'Code', + ); + + # + # Blocks + # + + protected function lines(array $lines) + { + $CurrentBlock = null; + + foreach ($lines as $line) + { + if (chop($line) === '') + { + if (isset($CurrentBlock)) + { + $CurrentBlock['interrupted'] = true; + } + + continue; + } + + if (strpos($line, "\t") !== false) + { + $parts = explode("\t", $line); + + $line = $parts[0]; + + unset($parts[0]); + + foreach ($parts as $part) + { + $shortage = 4 - mb_strlen($line, 'utf-8') % 4; + + $line .= str_repeat(' ', $shortage); + $line .= $part; + } + } + + $indent = 0; + + while (isset($line[$indent]) and $line[$indent] === ' ') + { + $indent ++; + } + + $text = $indent > 0 ? substr($line, $indent) : $line; + + # ~ + + $Line = array('body' => $line, 'indent' => $indent, 'text' => $text); + + # ~ + + if (isset($CurrentBlock['continuable'])) + { + $Block = $this->{'block'.$CurrentBlock['type'].'Continue'}($Line, $CurrentBlock); + + if (isset($Block)) + { + $CurrentBlock = $Block; + + continue; + } + else + { + if ($this->isBlockCompletable($CurrentBlock['type'])) + { + $CurrentBlock = $this->{'block'.$CurrentBlock['type'].'Complete'}($CurrentBlock); + } + } + } + + # ~ + + $marker = $text[0]; + + # ~ + + $blockTypes = $this->unmarkedBlockTypes; + + if (isset($this->BlockTypes[$marker])) + { + foreach ($this->BlockTypes[$marker] as $blockType) + { + $blockTypes []= $blockType; + } + } + + # + # ~ + + foreach ($blockTypes as $blockType) + { + $Block = $this->{'block'.$blockType}($Line, $CurrentBlock); + + if (isset($Block)) + { + $Block['type'] = $blockType; + + if ( ! isset($Block['identified'])) + { + $Blocks []= $CurrentBlock; + + $Block['identified'] = true; + } + + if ($this->isBlockContinuable($blockType)) + { + $Block['continuable'] = true; + } + + $CurrentBlock = $Block; + + continue 2; + } + } + + # ~ + + if (isset($CurrentBlock) and ! isset($CurrentBlock['type']) and ! isset($CurrentBlock['interrupted'])) + { + $CurrentBlock['element']['text'] .= "\n".$text; + } + else + { + $Blocks []= $CurrentBlock; + + $CurrentBlock = $this->paragraph($Line); + + $CurrentBlock['identified'] = true; + } + } + + # ~ + + if (isset($CurrentBlock['continuable']) and $this->isBlockCompletable($CurrentBlock['type'])) + { + $CurrentBlock = $this->{'block'.$CurrentBlock['type'].'Complete'}($CurrentBlock); + } + + # ~ + + $Blocks []= $CurrentBlock; + + unset($Blocks[0]); + + # ~ + + $markup = ''; + + foreach ($Blocks as $Block) + { + if (isset($Block['hidden'])) + { + continue; + } + + $markup .= "\n"; + $markup .= isset($Block['markup']) ? $Block['markup'] : $this->element($Block['element']); + } + + $markup .= "\n"; + + # ~ + + return $markup; + } + + protected function isBlockContinuable($Type) + { + return method_exists($this, 'block'.$Type.'Continue'); + } + + protected function isBlockCompletable($Type) + { + return method_exists($this, 'block'.$Type.'Complete'); + } + + # + # Code + + protected function blockCode($Line, $Block = null) + { + if (isset($Block) and ! isset($Block['type']) and ! isset($Block['interrupted'])) + { + return; + } + + if ($Line['indent'] >= 4) + { + $text = substr($Line['body'], 4); + + $Block = array( + 'element' => array( + 'name' => 'pre', + 'handler' => 'element', + 'text' => array( + 'name' => 'code', + 'text' => $text, + ), + ), + ); + + return $Block; + } + } + + protected function blockCodeContinue($Line, $Block) + { + if ($Line['indent'] >= 4) + { + if (isset($Block['interrupted'])) + { + $Block['element']['text']['text'] .= "\n"; + + unset($Block['interrupted']); + } + + $Block['element']['text']['text'] .= "\n"; + + $text = substr($Line['body'], 4); + + $Block['element']['text']['text'] .= $text; + + return $Block; + } + } + + protected function blockCodeComplete($Block) + { + $text = $Block['element']['text']['text']; + + $Block['element']['text']['text'] = $text; + + return $Block; + } + + # + # Comment + + protected function blockComment($Line) + { + if ($this->markupEscaped or $this->safeMode) + { + return; + } + + if (isset($Line['text'][3]) and $Line['text'][3] === '-' and $Line['text'][2] === '-' and $Line['text'][1] === '!') + { + $Block = array( + 'markup' => $Line['body'], + ); + + if (preg_match('/-->$/', $Line['text'])) + { + $Block['closed'] = true; + } + + return $Block; + } + } + + protected function blockCommentContinue($Line, array $Block) + { + if (isset($Block['closed'])) + { + return; + } + + $Block['markup'] .= "\n" . $Line['body']; + + if (preg_match('/-->$/', $Line['text'])) + { + $Block['closed'] = true; + } + + return $Block; + } + + # + # Fenced Code + + protected function blockFencedCode($Line) + { + if (preg_match('/^['.$Line['text'][0].']{3,}[ ]*([^`]+)?[ ]*$/', $Line['text'], $matches)) + { + $Element = array( + 'name' => 'code', + 'text' => '', + ); + + if (isset($matches[1])) + { + $class = 'language-'.$matches[1]; + + $Element['attributes'] = array( + 'class' => $class, + ); + } + + $Block = array( + 'char' => $Line['text'][0], + 'element' => array( + 'name' => 'pre', + 'handler' => 'element', + 'text' => $Element, + ), + ); + + return $Block; + } + } + + protected function blockFencedCodeContinue($Line, $Block) + { + if (isset($Block['complete'])) + { + return; + } + + if (isset($Block['interrupted'])) + { + $Block['element']['text']['text'] .= "\n"; + + unset($Block['interrupted']); + } + + if (preg_match('/^'.$Block['char'].'{3,}[ ]*$/', $Line['text'])) + { + $Block['element']['text']['text'] = substr($Block['element']['text']['text'], 1); + + $Block['complete'] = true; + + return $Block; + } + + $Block['element']['text']['text'] .= "\n".$Line['body']; + + return $Block; + } + + protected function blockFencedCodeComplete($Block) + { + $text = $Block['element']['text']['text']; + + $Block['element']['text']['text'] = $text; + + return $Block; + } + + # + # Header + + protected function blockHeader($Line) + { + if (isset($Line['text'][1])) + { + $level = 1; + + while (isset($Line['text'][$level]) and $Line['text'][$level] === '#') + { + $level ++; + } + + if ($level > 6) + { + return; + } + + $text = trim($Line['text'], '# '); + + $Block = array( + 'element' => array( + 'name' => 'h' . min(6, $level), + 'text' => $text, + 'handler' => 'line', + ), + ); + + return $Block; + } + } + + # + # List + + protected function blockList($Line) + { + list($name, $pattern) = $Line['text'][0] <= '-' ? array('ul', '[*+-]') : array('ol', '[0-9]+[.]'); + + if (preg_match('/^('.$pattern.'[ ]+)(.*)/', $Line['text'], $matches)) + { + $Block = array( + 'indent' => $Line['indent'], + 'pattern' => $pattern, + 'element' => array( + 'name' => $name, + 'handler' => 'elements', + ), + ); + + if($name === 'ol') + { + $listStart = stristr($matches[0], '.', true); + + if($listStart !== '1') + { + $Block['element']['attributes'] = array('start' => $listStart); + } + } + + $Block['li'] = array( + 'name' => 'li', + 'handler' => 'li', + 'text' => array( + $matches[2], + ), + ); + + $Block['element']['text'] []= & $Block['li']; + + return $Block; + } + } + + protected function blockListContinue($Line, array $Block) + { + if ($Block['indent'] === $Line['indent'] and preg_match('/^'.$Block['pattern'].'(?:[ ]+(.*)|$)/', $Line['text'], $matches)) + { + if (isset($Block['interrupted'])) + { + $Block['li']['text'] []= ''; + + $Block['loose'] = true; + + unset($Block['interrupted']); + } + + unset($Block['li']); + + $text = isset($matches[1]) ? $matches[1] : ''; + + $Block['li'] = array( + 'name' => 'li', + 'handler' => 'li', + 'text' => array( + $text, + ), + ); + + $Block['element']['text'] []= & $Block['li']; + + return $Block; + } + + if ($Line['text'][0] === '[' and $this->blockReference($Line)) + { + return $Block; + } + + if ( ! isset($Block['interrupted'])) + { + $text = preg_replace('/^[ ]{0,4}/', '', $Line['body']); + + $Block['li']['text'] []= $text; + + return $Block; + } + + if ($Line['indent'] > 0) + { + $Block['li']['text'] []= ''; + + $text = preg_replace('/^[ ]{0,4}/', '', $Line['body']); + + $Block['li']['text'] []= $text; + + unset($Block['interrupted']); + + return $Block; + } + } + + protected function blockListComplete(array $Block) + { + if (isset($Block['loose'])) + { + foreach ($Block['element']['text'] as &$li) + { + if (end($li['text']) !== '') + { + $li['text'] []= ''; + } + } + } + + return $Block; + } + + # + # Quote + + protected function blockQuote($Line) + { + if (preg_match('/^>[ ]?(.*)/', $Line['text'], $matches)) + { + $Block = array( + 'element' => array( + 'name' => 'blockquote', + 'handler' => 'lines', + 'text' => (array) $matches[1], + ), + ); + + return $Block; + } + } + + protected function blockQuoteContinue($Line, array $Block) + { + if ($Line['text'][0] === '>' and preg_match('/^>[ ]?(.*)/', $Line['text'], $matches)) + { + if (isset($Block['interrupted'])) + { + $Block['element']['text'] []= ''; + + unset($Block['interrupted']); + } + + $Block['element']['text'] []= $matches[1]; + + return $Block; + } + + if ( ! isset($Block['interrupted'])) + { + $Block['element']['text'] []= $Line['text']; + + return $Block; + } + } + + # + # Rule + + protected function blockRule($Line) + { + if (preg_match('/^(['.$Line['text'][0].'])([ ]*\1){2,}[ ]*$/', $Line['text'])) + { + $Block = array( + 'element' => array( + 'name' => 'hr' + ), + ); + + return $Block; + } + } + + # + # Setext + + protected function blockSetextHeader($Line, array $Block = null) + { + if ( ! isset($Block) or isset($Block['type']) or isset($Block['interrupted'])) + { + return; + } + + if (chop($Line['text'], $Line['text'][0]) === '') + { + $Block['element']['name'] = $Line['text'][0] === '=' ? 'h1' : 'h2'; + + return $Block; + } + } + + # + # Markup + + protected function blockMarkup($Line) + { + if ($this->markupEscaped or $this->safeMode) + { + return; + } + + if (preg_match('/^<(\w[\w-]*)(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*(\/)?>/', $Line['text'], $matches)) + { + $element = strtolower($matches[1]); + + if (in_array($element, $this->textLevelElements)) + { + return; + } + + $Block = array( + 'name' => $matches[1], + 'depth' => 0, + 'markup' => $Line['text'], + ); + + $length = strlen($matches[0]); + + $remainder = substr($Line['text'], $length); + + if (trim($remainder) === '') + { + if (isset($matches[2]) or in_array($matches[1], $this->voidElements)) + { + $Block['closed'] = true; + + $Block['void'] = true; + } + } + else + { + if (isset($matches[2]) or in_array($matches[1], $this->voidElements)) + { + return; + } + + if (preg_match('/<\/'.$matches[1].'>[ ]*$/i', $remainder)) + { + $Block['closed'] = true; + } + } + + return $Block; + } + } + + protected function blockMarkupContinue($Line, array $Block) + { + if (isset($Block['closed'])) + { + return; + } + + if (preg_match('/^<'.$Block['name'].'(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*>/i', $Line['text'])) # open + { + $Block['depth'] ++; + } + + if (preg_match('/(.*?)<\/'.$Block['name'].'>[ ]*$/i', $Line['text'], $matches)) # close + { + if ($Block['depth'] > 0) + { + $Block['depth'] --; + } + else + { + $Block['closed'] = true; + } + } + + if (isset($Block['interrupted'])) + { + $Block['markup'] .= "\n"; + + unset($Block['interrupted']); + } + + $Block['markup'] .= "\n".$Line['body']; + + return $Block; + } + + # + # Reference + + protected function blockReference($Line) + { + if (preg_match('/^\[(.+?)\]:[ ]*?(?:[ ]+["\'(](.+)["\')])?[ ]*$/', $Line['text'], $matches)) + { + $id = strtolower($matches[1]); + + $Data = array( + 'url' => $matches[2], + 'title' => null, + ); + + if (isset($matches[3])) + { + $Data['title'] = $matches[3]; + } + + $this->DefinitionData['Reference'][$id] = $Data; + + $Block = array( + 'hidden' => true, + ); + + return $Block; + } + } + + # + # Table + + protected function blockTable($Line, array $Block = null) + { + if ( ! isset($Block) or isset($Block['type']) or isset($Block['interrupted'])) + { + return; + } + + if (strpos($Block['element']['text'], '|') !== false and chop($Line['text'], ' -:|') === '') + { + $alignments = array(); + + $divider = $Line['text']; + + $divider = trim($divider); + $divider = trim($divider, '|'); + + $dividerCells = explode('|', $divider); + + foreach ($dividerCells as $dividerCell) + { + $dividerCell = trim($dividerCell); + + if ($dividerCell === '') + { + continue; + } + + $alignment = null; + + if ($dividerCell[0] === ':') + { + $alignment = 'left'; + } + + if (substr($dividerCell, - 1) === ':') + { + $alignment = $alignment === 'left' ? 'center' : 'right'; + } + + $alignments []= $alignment; + } + + # ~ + + $HeaderElements = array(); + + $header = $Block['element']['text']; + + $header = trim($header); + $header = trim($header, '|'); + + $headerCells = explode('|', $header); + + foreach ($headerCells as $index => $headerCell) + { + $headerCell = trim($headerCell); + + $HeaderElement = array( + 'name' => 'th', + 'text' => $headerCell, + 'handler' => 'line', + ); + + if (isset($alignments[$index])) + { + $alignment = $alignments[$index]; + + $HeaderElement['attributes'] = array( + 'style' => 'text-align: '.$alignment.';', + ); + } + + $HeaderElements []= $HeaderElement; + } + + # ~ + + $Block = array( + 'alignments' => $alignments, + 'identified' => true, + 'element' => array( + 'name' => 'table', + 'handler' => 'elements', + ), + ); + + $Block['element']['text'] []= array( + 'name' => 'thead', + 'handler' => 'elements', + ); + + $Block['element']['text'] []= array( + 'name' => 'tbody', + 'handler' => 'elements', + 'text' => array(), + ); + + $Block['element']['text'][0]['text'] []= array( + 'name' => 'tr', + 'handler' => 'elements', + 'text' => $HeaderElements, + ); + + return $Block; + } + } + + protected function blockTableContinue($Line, array $Block) + { + if (isset($Block['interrupted'])) + { + return; + } + + if ($Line['text'][0] === '|' or strpos($Line['text'], '|')) + { + $Elements = array(); + + $row = $Line['text']; + + $row = trim($row); + $row = trim($row, '|'); + + preg_match_all('/(?:(\\\\[|])|[^|`]|`[^`]+`|`)+/', $row, $matches); + + foreach ($matches[0] as $index => $cell) + { + $cell = trim($cell); + + $Element = array( + 'name' => 'td', + 'handler' => 'line', + 'text' => $cell, + ); + + if (isset($Block['alignments'][$index])) + { + $Element['attributes'] = array( + 'style' => 'text-align: '.$Block['alignments'][$index].';', + ); + } + + $Elements []= $Element; + } + + $Element = array( + 'name' => 'tr', + 'handler' => 'elements', + 'text' => $Elements, + ); + + $Block['element']['text'][1]['text'] []= $Element; + + return $Block; + } + } + + # + # ~ + # + + protected function paragraph($Line) + { + $Block = array( + 'element' => array( + 'name' => 'p', + 'text' => $Line['text'], + 'handler' => 'line', + ), + ); + + return $Block; + } + + # + # Inline Elements + # + + protected $InlineTypes = array( + '"' => array('SpecialCharacter'), + '!' => array('Image'), + '&' => array('SpecialCharacter'), + '*' => array('Emphasis'), + ':' => array('Url'), + '<' => array('UrlTag', 'EmailTag', 'Markup', 'SpecialCharacter'), + '>' => array('SpecialCharacter'), + '[' => array('Link'), + '_' => array('Emphasis'), + '`' => array('Code'), + '~' => array('Strikethrough'), + '\\' => array('EscapeSequence'), + ); + + # ~ + + protected $inlineMarkerList = '!"*_&[:<>`~\\'; + + # + # ~ + # + + public function line($text, $nonNestables=array()) + { + $markup = ''; + + # $excerpt is based on the first occurrence of a marker + + while ($excerpt = strpbrk($text, $this->inlineMarkerList)) + { + $marker = $excerpt[0]; + + $markerPosition = strpos($text, $marker); + + $Excerpt = array('text' => $excerpt, 'context' => $text); + + foreach ($this->InlineTypes[$marker] as $inlineType) + { + # check to see if the current inline type is nestable in the current context + + if ( ! empty($nonNestables) and in_array($inlineType, $nonNestables)) + { + continue; + } + + $Inline = $this->{'inline'.$inlineType}($Excerpt); + + if ( ! isset($Inline)) + { + continue; + } + + # makes sure that the inline belongs to "our" marker + + if (isset($Inline['position']) and $Inline['position'] > $markerPosition) + { + continue; + } + + # sets a default inline position + + if ( ! isset($Inline['position'])) + { + $Inline['position'] = $markerPosition; + } + + # cause the new element to 'inherit' our non nestables + + foreach ($nonNestables as $non_nestable) + { + $Inline['element']['nonNestables'][] = $non_nestable; + } + + # the text that comes before the inline + $unmarkedText = substr($text, 0, $Inline['position']); + + # compile the unmarked text + $markup .= $this->unmarkedText($unmarkedText); + + # compile the inline + $markup .= isset($Inline['markup']) ? $Inline['markup'] : $this->element($Inline['element']); + + # remove the examined text + $text = substr($text, $Inline['position'] + $Inline['extent']); + + continue 2; + } + + # the marker does not belong to an inline + + $unmarkedText = substr($text, 0, $markerPosition + 1); + + $markup .= $this->unmarkedText($unmarkedText); + + $text = substr($text, $markerPosition + 1); + } + + $markup .= $this->unmarkedText($text); + + return $markup; + } + + # + # ~ + # + + protected function inlineCode($Excerpt) + { + $marker = $Excerpt['text'][0]; + + if (preg_match('/^('.$marker.'+)[ ]*(.+?)[ ]*(? strlen($matches[0]), + 'element' => array( + 'name' => 'code', + 'text' => $text, + ), + ); + } + } + + protected function inlineEmailTag($Excerpt) + { + if (strpos($Excerpt['text'], '>') !== false and preg_match('/^<((mailto:)?\S+?@\S+?)>/i', $Excerpt['text'], $matches)) + { + $url = $matches[1]; + + if ( ! isset($matches[2])) + { + $url = 'mailto:' . $url; + } + + return array( + 'extent' => strlen($matches[0]), + 'element' => array( + 'name' => 'a', + 'text' => $matches[1], + 'attributes' => array( + 'href' => $url, + ), + ), + ); + } + } + + protected function inlineEmphasis($Excerpt) + { + if ( ! isset($Excerpt['text'][1])) + { + return; + } + + $marker = $Excerpt['text'][0]; + + if ($Excerpt['text'][1] === $marker and preg_match($this->StrongRegex[$marker], $Excerpt['text'], $matches)) + { + $emphasis = 'strong'; + } + elseif (preg_match($this->EmRegex[$marker], $Excerpt['text'], $matches)) + { + $emphasis = 'em'; + } + else + { + return; + } + + return array( + 'extent' => strlen($matches[0]), + 'element' => array( + 'name' => $emphasis, + 'handler' => 'line', + 'text' => $matches[1], + ), + ); + } + + protected function inlineEscapeSequence($Excerpt) + { + if (isset($Excerpt['text'][1]) and in_array($Excerpt['text'][1], $this->specialCharacters)) + { + return array( + 'markup' => $Excerpt['text'][1], + 'extent' => 2, + ); + } + } + + protected function inlineImage($Excerpt) + { + if ( ! isset($Excerpt['text'][1]) or $Excerpt['text'][1] !== '[') + { + return; + } + + $Excerpt['text']= substr($Excerpt['text'], 1); + + $Link = $this->inlineLink($Excerpt); + + if ($Link === null) + { + return; + } + + $Inline = array( + 'extent' => $Link['extent'] + 1, + 'element' => array( + 'name' => 'img', + 'attributes' => array( + 'src' => $Link['element']['attributes']['href'], + 'alt' => $Link['element']['text'], + ), + ), + ); + + $Inline['element']['attributes'] += $Link['element']['attributes']; + + unset($Inline['element']['attributes']['href']); + + return $Inline; + } + + protected function inlineLink($Excerpt) + { + $Element = array( + 'name' => 'a', + 'handler' => 'line', + 'nonNestables' => array('Url', 'Link'), + 'text' => null, + 'attributes' => array( + 'href' => null, + 'title' => null, + ), + ); + + $extent = 0; + + $remainder = $Excerpt['text']; + + if (preg_match('/\[((?:[^][]++|(?R))*+)\]/', $remainder, $matches)) + { + $Element['text'] = $matches[1]; + + $extent += strlen($matches[0]); + + $remainder = substr($remainder, $extent); + } + else + { + return; + } + + if (preg_match('/^[(]\s*+((?:[^ ()]++|[(][^ )]+[)])++)(?:[ ]+("[^"]*"|\'[^\']*\'))?\s*[)]/', $remainder, $matches)) + { + $Element['attributes']['href'] = $matches[1]; + + if (isset($matches[2])) + { + $Element['attributes']['title'] = substr($matches[2], 1, - 1); + } + + $extent += strlen($matches[0]); + } + else + { + if (preg_match('/^\s*\[(.*?)\]/', $remainder, $matches)) + { + $definition = strlen($matches[1]) ? $matches[1] : $Element['text']; + $definition = strtolower($definition); + + $extent += strlen($matches[0]); + } + else + { + $definition = strtolower($Element['text']); + } + + if ( ! isset($this->DefinitionData['Reference'][$definition])) + { + return; + } + + $Definition = $this->DefinitionData['Reference'][$definition]; + + $Element['attributes']['href'] = $Definition['url']; + $Element['attributes']['title'] = $Definition['title']; + } + + return array( + 'extent' => $extent, + 'element' => $Element, + ); + } + + protected function inlineMarkup($Excerpt) + { + if ($this->markupEscaped or $this->safeMode or strpos($Excerpt['text'], '>') === false) + { + return; + } + + if ($Excerpt['text'][1] === '/' and preg_match('/^<\/\w[\w-]*[ ]*>/s', $Excerpt['text'], $matches)) + { + return array( + 'markup' => $matches[0], + 'extent' => strlen($matches[0]), + ); + } + + if ($Excerpt['text'][1] === '!' and preg_match('/^/s', $Excerpt['text'], $matches)) + { + return array( + 'markup' => $matches[0], + 'extent' => strlen($matches[0]), + ); + } + + if ($Excerpt['text'][1] !== ' ' and preg_match('/^<\w[\w-]*(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*\/?>/s', $Excerpt['text'], $matches)) + { + return array( + 'markup' => $matches[0], + 'extent' => strlen($matches[0]), + ); + } + } + + protected function inlineSpecialCharacter($Excerpt) + { + if ($Excerpt['text'][0] === '&' and ! preg_match('/^&#?\w+;/', $Excerpt['text'])) + { + return array( + 'markup' => '&', + 'extent' => 1, + ); + } + + $SpecialCharacter = array('>' => 'gt', '<' => 'lt', '"' => 'quot'); + + if (isset($SpecialCharacter[$Excerpt['text'][0]])) + { + return array( + 'markup' => '&'.$SpecialCharacter[$Excerpt['text'][0]].';', + 'extent' => 1, + ); + } + } + + protected function inlineStrikethrough($Excerpt) + { + if ( ! isset($Excerpt['text'][1])) + { + return; + } + + if ($Excerpt['text'][1] === '~' and preg_match('/^~~(?=\S)(.+?)(?<=\S)~~/', $Excerpt['text'], $matches)) + { + return array( + 'extent' => strlen($matches[0]), + 'element' => array( + 'name' => 'del', + 'text' => $matches[1], + 'handler' => 'line', + ), + ); + } + } + + protected function inlineUrl($Excerpt) + { + if ($this->urlsLinked !== true or ! isset($Excerpt['text'][2]) or $Excerpt['text'][2] !== '/') + { + return; + } + + if (preg_match('/\bhttps?:[\/]{2}[^\s<]+\b\/*/ui', $Excerpt['context'], $matches, PREG_OFFSET_CAPTURE)) + { + $url = $matches[0][0]; + + $Inline = array( + 'extent' => strlen($matches[0][0]), + 'position' => $matches[0][1], + 'element' => array( + 'name' => 'a', + 'text' => $url, + 'attributes' => array( + 'href' => $url, + ), + ), + ); + + return $Inline; + } + } + + protected function inlineUrlTag($Excerpt) + { + if (strpos($Excerpt['text'], '>') !== false and preg_match('/^<(\w+:\/{2}[^ >]+)>/i', $Excerpt['text'], $matches)) + { + $url = $matches[1]; + + return array( + 'extent' => strlen($matches[0]), + 'element' => array( + 'name' => 'a', + 'text' => $url, + 'attributes' => array( + 'href' => $url, + ), + ), + ); + } + } + + # ~ + + protected function unmarkedText($text) + { + if ($this->breaksEnabled) + { + $text = preg_replace('/[ ]*\n/', "
\n", $text); + } + else + { + $text = preg_replace('/(?:[ ][ ]+|[ ]*\\\\)\n/', "
\n", $text); + $text = str_replace(" \n", "\n", $text); + } + + return $text; + } + + # + # Handlers + # + + protected function element(array $Element) + { + if ($this->safeMode) + { + $Element = $this->sanitiseElement($Element); + } + + $markup = '<'.$Element['name']; + + if (isset($Element['attributes'])) + { + foreach ($Element['attributes'] as $name => $value) + { + if ($value === null) + { + continue; + } + + $markup .= ' '.$name.'="'.self::escape($value).'"'; + } + } + + if (isset($Element['text'])) + { + $markup .= '>'; + + if (!isset($Element['nonNestables'])) + { + $Element['nonNestables'] = array(); + } + + if (isset($Element['handler'])) + { + $markup .= $this->{$Element['handler']}($Element['text'], $Element['nonNestables']); + } + else + { + $markup .= self::escape($Element['text'], true); + } + + $markup .= ''; + } + else + { + $markup .= ' />'; + } + + return $markup; + } + + protected function elements(array $Elements) + { + $markup = ''; + + foreach ($Elements as $Element) + { + $markup .= "\n" . $this->element($Element); + } + + $markup .= "\n"; + + return $markup; + } + + # ~ + + protected function li($lines) + { + $markup = $this->lines($lines); + + $trimmedMarkup = trim($markup); + + if ( ! in_array('', $lines) and substr($trimmedMarkup, 0, 3) === '

') + { + $markup = $trimmedMarkup; + $markup = substr($markup, 3); + + $position = strpos($markup, "

"); + + $markup = substr_replace($markup, '', $position, 4); + } + + return $markup; + } + + # + # Deprecated Methods + # + + function parse($text) + { + $markup = $this->text($text); + + return $markup; + } + + protected function sanitiseElement(array $Element) + { + static $goodAttribute = '/^[a-zA-Z0-9][a-zA-Z0-9-_]*+$/'; + static $safeUrlNameToAtt = array( + 'a' => 'href', + 'img' => 'src', + ); + + if (isset($safeUrlNameToAtt[$Element['name']])) + { + $Element = $this->filterUnsafeUrlInAttribute($Element, $safeUrlNameToAtt[$Element['name']]); + } + + if ( ! empty($Element['attributes'])) + { + foreach ($Element['attributes'] as $att => $val) + { + # filter out badly parsed attribute + if ( ! preg_match($goodAttribute, $att)) + { + unset($Element['attributes'][$att]); + } + # dump onevent attribute + elseif (self::striAtStart($att, 'on')) + { + unset($Element['attributes'][$att]); + } + } + } + + return $Element; + } + + protected function filterUnsafeUrlInAttribute(array $Element, $attribute) + { + foreach ($this->safeLinksWhitelist as $scheme) + { + if (self::striAtStart($Element['attributes'][$attribute], $scheme)) + { + return $Element; + } + } + + $Element['attributes'][$attribute] = str_replace(':', '%3A', $Element['attributes'][$attribute]); + + return $Element; + } + + # + # Static Methods + # + + protected static function escape($text, $allowQuotes = false) + { + return htmlspecialchars($text, $allowQuotes ? ENT_NOQUOTES : ENT_QUOTES, 'UTF-8'); + } + + protected static function striAtStart($string, $needle) + { + $len = strlen($needle); + + if ($len > strlen($string)) + { + return false; + } + else + { + return strtolower(substr($string, 0, $len)) === strtolower($needle); + } + } + + static function instance($name = 'default') + { + if (isset(self::$instances[$name])) + { + return self::$instances[$name]; + } + + $instance = new static(); + + self::$instances[$name] = $instance; + + return $instance; + } + + private static $instances = array(); + + # + # Fields + # + + protected $DefinitionData; + + # + # Read-Only + + protected $specialCharacters = array( + '\\', '`', '*', '_', '{', '}', '[', ']', '(', ')', '>', '#', '+', '-', '.', '!', '|', + ); + + protected $StrongRegex = array( + '*' => '/^[*]{2}((?:\\\\\*|[^*]|[*][^*]*[*])+?)[*]{2}(?![*])/s', + '_' => '/^__((?:\\\\_|[^_]|_[^_]*_)+?)__(?!_)/us', + ); + + protected $EmRegex = array( + '*' => '/^[*]((?:\\\\\*|[^*]|[*][*][^*]+?[*][*])+?)[*](?![*])/s', + '_' => '/^_((?:\\\\_|[^_]|__[^_]*__)+?)_(?!_)\b/us', + ); + + protected $regexHtmlAttribute = '[a-zA-Z_:][\w:.-]*(?:\s*=\s*(?:[^"\'=<>`\s]+|"[^"]*"|\'[^\']*\'))?'; + + protected $voidElements = array( + 'area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', + ); + + protected $textLevelElements = array( + 'a', 'br', 'bdo', 'abbr', 'blink', 'nextid', 'acronym', 'basefont', + 'b', 'em', 'big', 'cite', 'small', 'spacer', 'listing', + 'i', 'rp', 'del', 'code', 'strike', 'marquee', + 'q', 'rt', 'ins', 'font', 'strong', + 's', 'tt', 'kbd', 'mark', + 'u', 'xm', 'sub', 'nobr', + 'sup', 'ruby', + 'var', 'span', + 'wbr', 'time', + ); +} diff --git a/application/libraries/index.html b/application/libraries/index.html new file mode 100644 index 0000000..b702fbc --- /dev/null +++ b/application/libraries/index.html @@ -0,0 +1,11 @@ + + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + diff --git a/application/logs/index.html b/application/logs/index.html new file mode 100644 index 0000000..b702fbc --- /dev/null +++ b/application/logs/index.html @@ -0,0 +1,11 @@ + + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + diff --git a/application/models/Delete.php b/application/models/Delete.php new file mode 100644 index 0000000..e69fcff --- /dev/null +++ b/application/models/Delete.php @@ -0,0 +1,21 @@ +db->query($sql1); + $this->db->query($sql2); + } + + + } +?> \ No newline at end of file diff --git a/application/models/Insert.php b/application/models/Insert.php new file mode 100644 index 0000000..ba0bfbd --- /dev/null +++ b/application/models/Insert.php @@ -0,0 +1,56 @@ +db->insert('images', $datas)){ + + //如果插入成功返回ID + return $this->db->insert_id(); + } + else{ + return false; + exit; + + } + } + //插入到imginfo表 + public function imginfo($datas){ + if($this->db->insert('imginfo', $datas)){ + + //如果插入成功返回ID + return $this->db->insert_id(); + } + else{ + return false; + exit; + } + } + //插入安装的默认数据 + public function default(){ + //上传限制初始数据 + // $uplimit_values = array( + // "max_size" => 5, + // "number" => 10 + // ); + // $uplimit_values = json_encode($uplimit_values); + // $uplimit = array( + // "name" => "uplimit", + // "values" => $uplimit_values, + // "switch" => "ON" + // ); + // //插入数据 + // $this->db->insert('options',$uplimit); + + //图片压缩初始数据 + + } + + } +?> \ No newline at end of file diff --git a/application/models/Query.php b/application/models/Query.php new file mode 100644 index 0000000..56d774a --- /dev/null +++ b/application/models/Query.php @@ -0,0 +1,269 @@ +db->query($sql); + + + if($query){ + $row = $query->row(); + $domain = $row->domains; + //var_dump($domain); + return $domain; + + } + else{ + return FALSE; + } + } + //查询是否重复 + public function repeat($imgid){ + $sql = "SELECT * FROM img_images WHERE `imgid` = '$imgid'"; + + $query = $this->db->query($sql); + if($query){ + $row = $query->row(); + //var_dump($domain); + return $row; + } + else{ + return false; + } + } + //根据ID查询1张图片 + public function onepic($imgid){ + $sql = "SELECT * FROM img_images WHERE `imgid` = '$imgid'"; + + $query = $this->db->query($sql); + if($query){ + $row = $query->row(); + //var_dump($domain); + return $row; + } + else{ + return false; + } + } + public function img($id){ + $id = strip_tags($id); + $id = (int)$id; + $sql = "SELECT * FROM img_images WHERE `id` = '$id'"; + + $query = $this->db->query($sql); + if($query){ + $row = $query->row(); + //var_dump($domain); + return $row; + } + else{ + return false; + } + } + //查询图片信息 + public function imginfo($imgid){ + $sql = "SELECT * FROM img_imginfo WHERE `imgid` = '$imgid'"; + + $query = $this->db->query($sql); + if($query){ + $row = $query->row(); + //var_dump($domain); + return $row; + } + else{ + return false; + } + } + //查询用户信息 + public function userinfo(){ + $sql = "SELECT * FROM `img_options` WHERE `name` = 'userinfo' LIMIT 1"; + + $query = $this->db->query($sql); + + if($query){ + $row = $query->row(); + + return $row; + } + else{ + return false; + } + } + //查询tinypng设置 + public function tinypng(){ + $sql = "SELECT * FROM `img_options` WHERE `name` = 'tinypng' LIMIT 1"; + @$query = $this->db->query($sql); + + if($query){ + $row = $query->row(); + return $row; + } + else{ + return FALSE; + } + } + //查询站点信息 + public function site_setting($type = ''){ + $sql = "SELECT * FROM 'img_options' WHERE name = 'site_setting' LIMIT 1"; + $query = $this->db->query($sql); + + //如果类型为空,则返回完整对象 + if($type == '') { + if($query){ + $row = $query->row(); + + return $row; + } + else{ + return FALSE; + } + } + else{ + if($query){ + $row = $query->row(); + $row = json_decode($row->values); + return $row; + } + else{ + return FALSE; + } + } + + + } + //新版查询站点信息 + public function siteinfo(){ + $sql = "SELECT * FROM 'img_options' WHERE name = 'site_setting' LIMIT 1"; + $query = $this->db->query($sql); + + if($query){ + $row = $query->row(); + var_dump($row); + return $row; + } + else{ + return FALSE; + } + } + //查询各种设置 + public function option($name){ + $sql = "SELECT * FROM 'img_options' WHERE name = '$name' LIMIT 1"; + $query = $this->db->query($sql); + + if($query){ + $row = $query->row(); + + return $row; + } + else{ + return FALSE; + } + } + //查询上传数量限制,传入参数IP + public function uplimit($ip){ + //获取今天的日期 + $date = date('Y-m-d',time()); + $date = $date.'%'; + //查询出今天上传的数量 + $sql = "select count(*) num from img_images where `ip` = '$ip' AND `user` = 'visitor' AND `date` LIKE '$date'"; + $query = $this->db->query($sql); + //获取用户已经上传的数量 + $num = (int)$query->row()->num; + // var_dump($num); + + // exit; + //查询系统限制的条数 + $sql = "SELECT * FROM 'img_options' WHERE name = 'uplimit' LIMIT 1"; + $query = $this->db->query($sql); + $limit = $query->row(); + $limit = $limit->values; + $limit = json_decode($limit); + $limit = $limit->limit; + + //进行判断 + //上传达到限制了,返回FALSE + if($num >= $limit){ + return FALSE; + } + else{ + return TRUE; + } + } + //查询图片完整信息,用于探索发现,$num为要查询的图片数量 + public function found($num){ + //先写一个强大的SQL语句 + $sql = "SELECT a.id,a.imgid,a.path,a.date,b.mime,b.width,b.height,b.views,b.ext,b.client_name FROM img_images AS a INNER JOIN img_imginfo AS b ON a.imgid = b.imgid AND a.user = 'visitor' AND a.level != 'adult' ORDER BY a.id DESC LIMIT $num"; + + $query = $this->db->query($sql); + + $query = $query->result_array(); + return $query; + } + //查询存储引擎 + public function storage($name){ + $sql = "SELECT * FROM `img_storage` WHERE `engine` = '$name' LIMIT 1"; + + $query = $this->db->query($sql); + if($query){ + $row = $query->row(); + return $row; + } + else{ + return FALSE; + } + } + //统计数量 + public function count_num($type){ + switch ($type) { + case 'admin': + $sql = "SELECT count(*) AS num FROM `img_images` WHERE `user` = 'admin'"; + break; + case 'visitor': + $sql = "SELECT count(*) AS num FROM `img_images` WHERE `user` = 'visitor'"; + break; + case 'dubious': + $sql = "SELECT count(*) AS num FROM `img_images` WHERE `level` = 'adult'"; + break; + case 'day': + $sql = "SELECT count(*) AS num FROM `img_images` WHERE date LIKE date('now') || '%'"; + break; + case 'month': + $sql = "SELECT count(*) AS num FROM `img_images` WHERE date LIKE strftime('%Y-%m','now') || '%'"; + break; + default: + # code... + break; + } + $query = $this->db->query($sql); + $row = $query->row(); + return $row; + } + //查询单张图片信息 + public function picinfo($imgid){ + $sql = "SELECT a.id,a.ip,a.imgid,a.path,a.date,b.mime,b.width,b.height,b.views,b.ext,b.client_name FROM img_images AS a INNER JOIN img_imginfo AS b ON a.imgid = b.imgid AND b.imgid = '$imgid' LIMIT 1"; + + $query = $this->db->query($sql); + + $query = $query->row(); + return $query; + } + //根据img_images id查出图片信息 + public function img_id($id){ + $id = (int)$id; + //先获取img id + $sql = "SELECT a.*,b.mime,b.width,b.height,b.views,b.ext,b.client_name FROM img_images AS a INNER JOIN img_imginfo AS b ON a.id = $id AND a.imgid = b.imgid"; + $imginfo = $this->db->query($sql)->row(); + + + return $imginfo; + + } + } +?> \ No newline at end of file diff --git a/application/models/Update.php b/application/models/Update.php new file mode 100644 index 0000000..4b90a12 --- /dev/null +++ b/application/models/Update.php @@ -0,0 +1,86 @@ +db->query($sql); + if($query){ + return true; + } + else{ + return false; + } + } + //更新图片压缩 + public function compress($id){ + $id = strip_tags($id); + $id = (int)$id; + $sql = "UPDATE img_images SET `compression` = 1"; + $query = $this->db->query($sql); + if($query){ + return TRUE; + } + else{ + return FALSE; + } + } + //更新站点信息 + public function site($name,$data){ + $id = strip_tags($name); + + $sql = "UPDATE img_options SET `values` = '$data' WHERE `name` = '$name'"; + $query = $this->db->query($sql); + if($query){ + return TRUE; + } + else{ + return FALSE; + } + } + //更新tinypng设置 + public function tinypng($values,$switch){ + $sql = "UPDATE img_options SET `values` = '$values',`switch` = '$switch' WHERE `name` = 'tinypng'"; + + //echo $sql; + + $query = $this->db->query($sql); + if($query){ + return TRUE; + } + else{ + return FALSE; + } + } + //更新moderate + public function moderate($values,$switch){ + $sql = "UPDATE img_options SET `values` = '$values',`switch` = '$switch' WHERE `name` = 'moderate'"; + $query = $this->db->query($sql); + if($query){ + return TRUE; + } + else{ + return FALSE; + } + } + //更新存储引擎 + public function storage($data,$engine){ + $this->db->where('engine', $engine); + $up = $this->db->update('storage', $data); + + if($up){ + return TRUE; + } + else{ + return FALSE; + } + } + + } +?> \ No newline at end of file diff --git a/application/models/index.html b/application/models/index.html new file mode 100644 index 0000000..b702fbc --- /dev/null +++ b/application/models/index.html @@ -0,0 +1,11 @@ + + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + diff --git a/application/third_party/index.html b/application/third_party/index.html new file mode 100644 index 0000000..b702fbc --- /dev/null +++ b/application/third_party/index.html @@ -0,0 +1,11 @@ + + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + diff --git a/application/views/admin/footer.php b/application/views/admin/footer.php new file mode 100644 index 0000000..9a20a23 --- /dev/null +++ b/application/views/admin/footer.php @@ -0,0 +1,59 @@ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
URL复制
HTML复制
Markdown复制
BBCode复制
+ + + + + + + + \ No newline at end of file diff --git a/application/views/admin/header.php b/application/views/admin/header.php new file mode 100644 index 0000000..d1d0422 --- /dev/null +++ b/application/views/admin/header.php @@ -0,0 +1,49 @@ + + + + + + + <?php echo $admin_title; ?> - ImgURL后台管理 + + + + + + +
+ \ No newline at end of file diff --git a/application/views/admin/identify.php b/application/views/admin/identify.php new file mode 100644 index 0000000..0e30baa --- /dev/null +++ b/application/views/admin/identify.php @@ -0,0 +1,40 @@ +
+
+
+
+ ImgURL需要使用Moderate Content提供的API来进行鉴黄识别,详细说明请参考帮助文档。 +
+
+
    +
  1. 由于某些原因可能接口会超时或者识别错误,建议配合 crontab 来定时识别图片。
  2. +
  3. 鉴黄接口地址为:/deal/identify_more
  4. +
  5. Moderate Content无法做到100%精准,可能存在误判,识别后的图片会标记为可疑图片。
  6. +
+
+
+
+
+
+
+ +
+ +
+
+
+ +
+ > +
+
+ +
+
+ +
+
+
+
+
+
+
\ No newline at end of file diff --git a/application/views/admin/images.php b/application/views/admin/images.php new file mode 100644 index 0000000..a7d6808 --- /dev/null +++ b/application/views/admin/images.php @@ -0,0 +1,85 @@ +
+
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+
+ <?php echo $img['client_name']; ?> +
+
+ +
+ +
+
+ +
+
+ +
+
+ +
+ diff --git a/application/views/admin/imginfo.php b/application/views/admin/imginfo.php new file mode 100644 index 0000000..bde15a3 --- /dev/null +++ b/application/views/admin/imginfo.php @@ -0,0 +1,59 @@ + + + + + New Document + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
分辨率 x
MIME类型
扩展名
上传时间
上传者IP
浏览次数
文件大小
+
+
+
+ + + diff --git a/application/views/admin/index.html b/application/views/admin/index.html new file mode 100644 index 0000000..e69de29 diff --git a/application/views/admin/index.php b/application/views/admin/index.php new file mode 100644 index 0000000..abc1325 --- /dev/null +++ b/application/views/admin/index.php @@ -0,0 +1,55 @@ +
+
+
+
+

累计上传

+

+
+
+
+
+

管理员累积上传

+

+
+
+
+
+

游客累积上传

+

+
+
+
+
+

可疑图片

+

+
+
+
+
+

本月上传

+

+
+
+
+
+

今日上传

+

+
+
+
+
+

社区支持

+

https://ttt.sh/

+
+
+
+
+

源码下载

+

https://github.com/

+
+
+
+
+ + + \ No newline at end of file diff --git a/application/views/admin/left.php b/application/views/admin/left.php new file mode 100644 index 0000000..a8a4693 --- /dev/null +++ b/application/views/admin/left.php @@ -0,0 +1,50 @@ + +
\ No newline at end of file diff --git a/application/views/admin/localhost.php b/application/views/admin/localhost.php new file mode 100644 index 0000000..68f63ed --- /dev/null +++ b/application/views/admin/localhost.php @@ -0,0 +1,26 @@ +
+
+
+
+ 请在下方填写localhost绑定域名(默认为站点域名),需要带有http(s),注意末尾没有/ +
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+
+
+
+
+
+
\ No newline at end of file diff --git a/application/views/admin/site.php b/application/views/admin/site.php new file mode 100644 index 0000000..8729af2 --- /dev/null +++ b/application/views/admin/site.php @@ -0,0 +1,54 @@ +
+
+
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+
+ +
+
+
+
+
+
+
diff --git a/application/views/admin/tinypng.php b/application/views/admin/tinypng.php new file mode 100644 index 0000000..204bcc6 --- /dev/null +++ b/application/views/admin/tinypng.php @@ -0,0 +1,39 @@ +
+
+
+
+ ImgURL需要使用TinyPNG提供的API来压缩图片,可同时设置2个API KEY,详细说明请查看帮助文档。 +
+
+
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ > +
+
+ +
+
+ +
+
+
+
+
+
+
\ No newline at end of file diff --git a/application/views/admin/uplimit.php b/application/views/admin/uplimit.php new file mode 100644 index 0000000..b8413f7 --- /dev/null +++ b/application/views/admin/uplimit.php @@ -0,0 +1,33 @@ +
+
+
+
+
+
+ +
+ > +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+ +
+
+
+
+
+
+
\ No newline at end of file diff --git a/application/views/admin/upto2.php b/application/views/admin/upto2.php new file mode 100644 index 0000000..f7d289d --- /dev/null +++ b/application/views/admin/upto2.php @@ -0,0 +1,16 @@ +
+
+
+
+
    +
  1. 1. 访问 imgurl_import.zip 将解压后的 import.php 放到站点根目录
  2. +
  3. 2. 请将ImgURL 1.x的数据库放到2.x的data/temp/目录,看起来应该是data/temp/imgurl.db3
  4. +
  5. 3. 将1.x的图片目录upload、temp放到2.x根目录
  6. +
  7. 4. 准备完毕后点击下方按钮进行升级
  8. +
  9. 5. 升级完毕后删除data/temp/imgurl.db3import.php
  10. +
+
+ +
+
+
\ No newline at end of file diff --git a/application/views/admin/urlup.php b/application/views/admin/urlup.php new file mode 100644 index 0000000..2e3979e --- /dev/null +++ b/application/views/admin/urlup.php @@ -0,0 +1,24 @@ +
+
+
+
+ 请输入图片地址,一行一个,一次不超过10个 +
+
+
+
+ + +
+ +
+
+
+ + +
+
+
+
\ No newline at end of file diff --git a/application/views/errors/cli/error_404.php b/application/views/errors/cli/error_404.php new file mode 100644 index 0000000..6984b61 --- /dev/null +++ b/application/views/errors/cli/error_404.php @@ -0,0 +1,8 @@ + + +An uncaught Exception was encountered + +Type: +Message: +Filename: getFile(), "\n"; ?> +Line Number: getLine(); ?> + + + +Backtrace: +getTrace() as $error): ?> + + File: + Line: + Function: + + + + diff --git a/application/views/errors/cli/error_general.php b/application/views/errors/cli/error_general.php new file mode 100644 index 0000000..6984b61 --- /dev/null +++ b/application/views/errors/cli/error_general.php @@ -0,0 +1,8 @@ + + +A PHP Error was encountered + +Severity: +Message: +Filename: +Line Number: + + + +Backtrace: + + + File: + Line: + Function: + + + + diff --git a/application/views/errors/cli/index.html b/application/views/errors/cli/index.html new file mode 100644 index 0000000..b702fbc --- /dev/null +++ b/application/views/errors/cli/index.html @@ -0,0 +1,11 @@ + + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + diff --git a/application/views/errors/html/error_404.php b/application/views/errors/html/error_404.php new file mode 100644 index 0000000..756ea9d --- /dev/null +++ b/application/views/errors/html/error_404.php @@ -0,0 +1,64 @@ + + + + +404 Page Not Found + + + +
+

+ +
+ + \ No newline at end of file diff --git a/application/views/errors/html/error_db.php b/application/views/errors/html/error_db.php new file mode 100644 index 0000000..f5a43f6 --- /dev/null +++ b/application/views/errors/html/error_db.php @@ -0,0 +1,64 @@ + + + + +Database Error + + + +
+

+ +
+ + \ No newline at end of file diff --git a/application/views/errors/html/error_exception.php b/application/views/errors/html/error_exception.php new file mode 100644 index 0000000..8784886 --- /dev/null +++ b/application/views/errors/html/error_exception.php @@ -0,0 +1,32 @@ + + +
+ +

An uncaught Exception was encountered

+ +

Type:

+

Message:

+

Filename: getFile(); ?>

+

Line Number: getLine(); ?>

+ + + +

Backtrace:

+ getTrace() as $error): ?> + + + +

+ File:
+ Line:
+ Function: +

+ + + + + + +
\ No newline at end of file diff --git a/application/views/errors/html/error_general.php b/application/views/errors/html/error_general.php new file mode 100644 index 0000000..fc3b2eb --- /dev/null +++ b/application/views/errors/html/error_general.php @@ -0,0 +1,64 @@ + + + + +Error + + + +
+

+ +
+ + \ No newline at end of file diff --git a/application/views/errors/html/error_php.php b/application/views/errors/html/error_php.php new file mode 100644 index 0000000..b146f9c --- /dev/null +++ b/application/views/errors/html/error_php.php @@ -0,0 +1,33 @@ + + +
+ +

A PHP Error was encountered

+ +

Severity:

+

Message:

+

Filename:

+

Line Number:

+ + + +

Backtrace:

+ + + + +

+ File:
+ Line:
+ Function: +

+ + + + + + + +
\ No newline at end of file diff --git a/application/views/errors/html/index.html b/application/views/errors/html/index.html new file mode 100644 index 0000000..b702fbc --- /dev/null +++ b/application/views/errors/html/index.html @@ -0,0 +1,11 @@ + + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + diff --git a/application/views/errors/index.html b/application/views/errors/index.html new file mode 100644 index 0000000..b702fbc --- /dev/null +++ b/application/views/errors/index.html @@ -0,0 +1,11 @@ + + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + diff --git a/application/views/index.html b/application/views/index.html new file mode 100644 index 0000000..b702fbc --- /dev/null +++ b/application/views/index.html @@ -0,0 +1,11 @@ + + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + diff --git a/application/views/user/footer.php b/application/views/user/footer.php new file mode 100644 index 0000000..ba9e1e5 --- /dev/null +++ b/application/views/user/footer.php @@ -0,0 +1,31 @@ + + + + + + + + + + \ No newline at end of file diff --git a/application/views/user/found.php b/application/views/user/found.php new file mode 100644 index 0000000..e706a01 --- /dev/null +++ b/application/views/user/found.php @@ -0,0 +1,77 @@ +load->helper('basic'); +?> +
+
+ +
+
+ <?php echo $img['client_name']; ?> +
+ + + +
+
+
+ +
+
+ + \ No newline at end of file diff --git a/application/views/user/header.php b/application/views/user/header.php new file mode 100644 index 0000000..4e39827 --- /dev/null +++ b/application/views/user/header.php @@ -0,0 +1,65 @@ + + + + + + <?php echo @$title; ?> + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/application/views/user/home.php b/application/views/user/home.php new file mode 100644 index 0000000..aad0747 --- /dev/null +++ b/application/views/user/home.php @@ -0,0 +1,136 @@ +
+
+ +
+
+ + + + + + +
+
+ +

将图片拖拽到此处,支持Ctrl + V粘贴上传

+
+
+ +
+
+ +
+
+
+ + +
+
+
+ +
+ +
+ +
+
+
+ + + + \ No newline at end of file diff --git a/application/views/user/img.php b/application/views/user/img.php new file mode 100644 index 0000000..eeeaa40 --- /dev/null +++ b/application/views/user/img.php @@ -0,0 +1,139 @@ +
+
+ +
+
+
+

+
+ <?php echo $title; ?> +
+
+ +
+

+ + + 下载 +

+
+ 此图片来自网友上传,不代表本站立场,若有侵权,请联系管理员删除!(QQ:337003006) +
+
+ +
+ +
+ +
+ + + +
+
+ + +
+ +
+ +
+ +
+
+ \ No newline at end of file diff --git a/application/views/user/install1.php b/application/views/user/install1.php new file mode 100644 index 0000000..0847693 --- /dev/null +++ b/application/views/user/install1.php @@ -0,0 +1,55 @@ +
+
+
+

ImgURL安装向导(1/3)

+ + + + + + + + + + + + + + + + + + + + + + + + +
名称要求当前信息检测结果
+ 不支持!'; + } + else{ + echo $info; + } + ?> +
+ + +
+ + 下一步'; + } + elseif($sum === FALSE){ + echo '您必须先解决上述问题才能进一步安装!'; + } + ?> +
+ +
+
+
\ No newline at end of file diff --git a/application/views/user/install2.php b/application/views/user/install2.php new file mode 100644 index 0000000..11f6bc1 --- /dev/null +++ b/application/views/user/install2.php @@ -0,0 +1,45 @@ +
+
+
+

ImgURL安装向导(2/3)

+ +
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+ +
+
+ 上一步 + +
+
+
+ + + + +
+
+
\ No newline at end of file diff --git a/application/views/user/install3.php b/application/views/user/install3.php new file mode 100644 index 0000000..10a1e08 --- /dev/null +++ b/application/views/user/install3.php @@ -0,0 +1,17 @@ +
+
+
+

安装完成!(3/3)

+ + + +
+
+
\ No newline at end of file diff --git a/application/views/user/login.php b/application/views/user/login.php new file mode 100644 index 0000000..d56c9ad --- /dev/null +++ b/application/views/user/login.php @@ -0,0 +1,23 @@ + +
+
+
+
+ + + +
+
+
+
+ \ No newline at end of file diff --git a/application/views/user/multiple.php b/application/views/user/multiple.php new file mode 100644 index 0000000..2009897 --- /dev/null +++ b/application/views/user/multiple.php @@ -0,0 +1,106 @@ +
+
+ +
+
+ + +
+
+ +

点击这里可选择多张图片,支持拖拽。

+
+
+ +
+
+ +
+
+
    +
  • URL
  • +
  • HTML
  • +
  • Markdown
  • +
  • BBCode
  • +
+
+ +
+

+                
+ +
+

+                
+ +
+

+                
+ +
+

+                
+
+
+
+ + +
+
+ + + + \ No newline at end of file diff --git a/application/views/user/page.php b/application/views/user/page.php new file mode 100644 index 0000000..2dd63cb --- /dev/null +++ b/application/views/user/page.php @@ -0,0 +1,19 @@ +
+
+
+
+
+
+
+ + +
+
+
+
\ No newline at end of file diff --git a/application/views/welcome_message.php b/application/views/welcome_message.php new file mode 100644 index 0000000..f511563 --- /dev/null +++ b/application/views/welcome_message.php @@ -0,0 +1,89 @@ + + + + + Welcome to CodeIgniter + + + + + +
+

Welcome to CodeIgniter!

+ +
+

The page you are looking at is being generated dynamically by CodeIgniter.

+ +

If you would like to edit this page you'll find it located at:

+ application/views/welcome_message.php + +

The corresponding controller for this page is found at:

+ application/controllers/Welcome.php + +

If you are exploring CodeIgniter for the very first time, you should start by reading the User Guide.

+
+ + +
+ + + \ No newline at end of file diff --git a/data/.htaccess b/data/.htaccess new file mode 100644 index 0000000..e3bd7d5 --- /dev/null +++ b/data/.htaccess @@ -0,0 +1,2 @@ +order allow,deny +deny from all \ No newline at end of file diff --git a/data/imgurl-simple.db3 b/data/imgurl-simple.db3 new file mode 100644 index 0000000..66e7b22 Binary files /dev/null and b/data/imgurl-simple.db3 differ diff --git a/data/index.html b/data/index.html new file mode 100644 index 0000000..e69de29 diff --git a/data/pages/readme.md b/data/pages/readme.md new file mode 100644 index 0000000..237ed17 --- /dev/null +++ b/data/pages/readme.md @@ -0,0 +1,39 @@ +# zdir +使用PHP开发的目录列表程序 + +![](https://imgurl.org/upload/1806/349f3b54028d58d6.png) + +### 使用方法 +* 下载源码放到站点根目录 +* 修改`config.php`设置自己的网站标题/关键词/描述 +* 如果需要排除某个目录,再次修改`config.php` ,里面有说明 +* 更多说明请查看帮助文档:[https://doc.xiaoz.me/docs/zdir](https://doc.xiaoz.me/docs/zdir) + +### 主要功能 +* 目录浏览 +* MarkDown文件预览 +* CSS/JavaScript一键复制 +* 文件hash +* 图片预览 +* 视频播放(仅支持mp4格式) +* 文本查看器(支持的格式有.txt .sh .py .go .c .cpp) +* 文件索引 +* 二维码生成 +* 文件删除 +* 详细说明请访问: [Zdir 实用的目录列表程序](https://www.xiaoz.me/archives/10465) + +### 注意事项 +* ~~不要使用中文命名目录/文件,否则可能发生不可预料的错误。~~ +* 2018.08.30 已解决中文命名问题(仅在Linux下做过测试) + +### Demo +* [http://soft.xiaoz.org/](http://soft.xiaoz.org/) + +### 获取捐赠版 +扫描下方二维码,并留言您的网址可获取捐赠版,捐赠版可去除底部版权。 + +![](https://imgurl.org/upload/1712/cb349aa4a1b95997.png) + +### 联系我 +* Blog:[https://www.xiaoz.me/](https://www.xiaoz.me/) +* QQ:337003006 \ No newline at end of file diff --git a/data/pages/use.md b/data/pages/use.md new file mode 100644 index 0000000..e2edda0 --- /dev/null +++ b/data/pages/use.md @@ -0,0 +1,40 @@ +# ImgURL使用协议 + +### 介绍 +ImgURL诞生于2017年12月,是一款开源的图片管理系统(简称图床),使用PHP + SQLite3开发,您可以自行部署,也可使用[https://imgurl.org/](https://imgurl.org/) 提供的在线服务,但需遵守以下协议。 + +### ImgURL在线服务 +* 不得上传色情、暴力、政治等内容 +* 不得上传侵犯版权、个人隐私权等内容 +* 违法以上规定直接删除图片不另行通知 +* 单张图片限制大小为5M,游客限制每天上传10张,图片长期保存,直到xiaoz无法维持 + +### 开源说明 + +1. ImgURL提供给任何人免费使用,鼓励二次开发和代码贡献 +2. 未经作者允许不得用于商业用途,不得去除版权 +3. 如需去除版权或用于商业用途请联系作者授权 +4. 最终解释权归原作者(xiaoz.me)所有 + +### ImgURL主要功能 +* 图片上传与预览 +* URL上传/Ctrl + V粘贴上传 +* 图片查看器、图片管理 +* 图片自动裁剪 +* 图片压缩 +* 图片智能鉴黄 +* 图片水印 +* API支持 + +### 获取帮助 +* 安装和使用请参考帮助文档:[https://doc.xiaoz.me/](https://doc.xiaoz.me/#/imgurl2/) +* 使用中遇到问题或者建议可以在[官方社区](https://ttt.sh/category/6/)反馈 +* 需要提供技术支持请联系QQ:337003006(付费) + +### 请我喝一杯咖啡 +![](https://www.xiaoz.me/wp-content/uploads/2013/12/juanzeng260.png) + +### 联系方式 +* ImgURL官方社区:[https://ttt.sh/](https://ttt.sh/category/6/) +* Blog:[https://www.xiaoz.me/](https://www.xiaoz.me/) +* QQ:337003006 \ No newline at end of file diff --git a/data/temp/index.html b/data/temp/index.html new file mode 100644 index 0000000..e69de29 diff --git a/data/version.txt b/data/version.txt new file mode 100644 index 0000000..06e4d88 --- /dev/null +++ b/data/version.txt @@ -0,0 +1 @@ +v2.0-20181219 \ No newline at end of file diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 0000000..ea533d6 Binary files /dev/null and b/favicon.ico differ diff --git a/imgs/index.html b/imgs/index.html new file mode 100644 index 0000000..e69de29 diff --git a/import.php b/import.php new file mode 100644 index 0000000..552b8bd --- /dev/null +++ b/import.php @@ -0,0 +1,134 @@ + 'sqlite', + 'database_file' => './data/temp/imgurl.db3' + ]); + + @$id = (int)$_GET['id']; + $nextid = $id + 1; + + $query1 = $db1->get("imginfo","*",[ + "id" => $id + ]); + + $endid = $db1->get("imginfo","id",[ + 'LIMIT' => 1, + "ORDER" => [ + "id" => "DESC" + ] + ]); + if($id > $endid){ + echo '全部导入完毕,请关闭此页面!'; + exit; + } + if(!$query1){ + echo '【请不要关闭此页面】没有查询成功,执行下一个!'; + header("Refresh:0.1;url=import.php?id=$nextid"); + exit; + } + //var_dump($query1); + //对imgurl 1.x数据进行处理 + //文件路径 + $data['path'] = '/'.$query1['path']; + //文件上传日期 + $data['date'] = $query1['date'].' 00:00'; + //文件所有者 + if($query1['dir'] == 'temp'){ + $data['user'] = 'visitor'; + } + else{ + $data['user'] = 'admin'; + } + //图片是否压缩 + $data['compression'] = $query1['compress']; + $query1['level'] = (int)$query1['level']; + //图片等级 + if($query1['level'] === 3){ + $data['level'] = 'adult'; + } + else{ + $data['level'] = 'everyone'; + } + //获取imgid + $file_name = basename($query1['path']); + //分割为数组 + $file_arr = explode('.',$file_name); + //获取imgid + $data['imgid'] = $file_arr[0]; + @$data['ext'] = '.'.$file_arr[1]; + + //设置存储引擎 + $data['storage'] = 'localhost'; + //图片水印 + $data['watermark'] = 0; + + //获取图片MIME类型 + switch ( @$file_arr[1] ) + { + case 'jpg': + $data['mime'] = 'image/jpeg'; + break; + case 'png': + $data['mime'] = 'image/png'; + break; + case 'gif': + $data['mime'] = 'image/gif'; + break; + case 'bmp': + $data['mime'] = 'image/bmp'; + break; + default: + $data['mime'] = 'image/jpeg'; + break; + } + + //获取图片尺寸 + @$sizeinfo = getimagesize($query1['path']); + $data['width'] = $sizeinfo[0]; + $data['height'] = $sizeinfo[1]; + + //将数据写入到IimgURL 2.x + $db2 = new Medoo([ + 'database_type' => 'sqlite', + 'database_file' => './data/imgurl.db3' + ]); + + if($id <= $endid){ + //数据插入到img_images + $db2->insert("img_images", [ + "imgid" => $data['imgid'], + "path" => $data['path'], + "storage" => $data['storage'], + "ip" => $query1['ip'], + "ua" => $query1['ua'], + "date" => $data['date'], + "user" => $data['user'], + "compression" => $data['compression'], + "watermark" => 0, + "level" => $data['level'] + ]); + //数据插入到imginfo + $db2->insert("img_imginfo", [ + "imgid" => $data['imgid'], + "mime" => $data['mime'], + "width" => $data['width'], + "height" => $data['height'], + "views" => 0, + "ext" => $data['ext'], + "client_name" => $file_name + ]); + echo '【请不要关闭此页面】导入成功,执行下一个!'; + header("Refresh:0.1;url=import.php?id=$nextid"); + } + else{ + echo '全部导入完成!'; + exit; + } + +?> \ No newline at end of file diff --git a/index.php b/index.php new file mode 100644 index 0000000..ca1304a --- /dev/null +++ b/index.php @@ -0,0 +1,315 @@ +=')) + { + error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED & ~E_STRICT & ~E_USER_NOTICE & ~E_USER_DEPRECATED); + } + else + { + error_reporting(E_ALL & ~E_NOTICE & ~E_STRICT & ~E_USER_NOTICE); + } + break; + + default: + header('HTTP/1.1 503 Service Unavailable.', TRUE, 503); + echo 'The application environment is not set correctly.'; + exit(1); // EXIT_ERROR +} + +/* + *--------------------------------------------------------------- + * SYSTEM DIRECTORY NAME + *--------------------------------------------------------------- + * + * This variable must contain the name of your "system" directory. + * Set the path if it is not in the same directory as this file. + */ + $system_path = 'system'; + +/* + *--------------------------------------------------------------- + * APPLICATION DIRECTORY NAME + *--------------------------------------------------------------- + * + * If you want this front controller to use a different "application" + * directory than the default one you can set its name here. The directory + * can also be renamed or relocated anywhere on your server. If you do, + * use an absolute (full) server path. + * For more info please see the user guide: + * + * https://codeigniter.com/user_guide/general/managing_apps.html + * + * NO TRAILING SLASH! + */ + $application_folder = 'application'; + +/* + *--------------------------------------------------------------- + * VIEW DIRECTORY NAME + *--------------------------------------------------------------- + * + * If you want to move the view directory out of the application + * directory, set the path to it here. The directory can be renamed + * and relocated anywhere on your server. If blank, it will default + * to the standard location inside your application directory. + * If you do move this, use an absolute (full) server path. + * + * NO TRAILING SLASH! + */ + $view_folder = ''; + + +/* + * -------------------------------------------------------------------- + * DEFAULT CONTROLLER + * -------------------------------------------------------------------- + * + * Normally you will set your default controller in the routes.php file. + * You can, however, force a custom routing by hard-coding a + * specific controller class/function here. For most applications, you + * WILL NOT set your routing here, but it's an option for those + * special instances where you might want to override the standard + * routing in a specific front controller that shares a common CI installation. + * + * IMPORTANT: If you set the routing here, NO OTHER controller will be + * callable. In essence, this preference limits your application to ONE + * specific controller. Leave the function name blank if you need + * to call functions dynamically via the URI. + * + * Un-comment the $routing array below to use this feature + */ + // The directory name, relative to the "controllers" directory. Leave blank + // if your controller is not in a sub-directory within the "controllers" one + // $routing['directory'] = ''; + + // The controller class file name. Example: mycontroller + // $routing['controller'] = ''; + + // The controller function you wish to be called. + // $routing['function'] = ''; + + +/* + * ------------------------------------------------------------------- + * CUSTOM CONFIG VALUES + * ------------------------------------------------------------------- + * + * The $assign_to_config array below will be passed dynamically to the + * config class when initialized. This allows you to set custom config + * items or override any default config values found in the config.php file. + * This can be handy as it permits you to share one application between + * multiple front controller files, with each file containing different + * config values. + * + * Un-comment the $assign_to_config array below to use this feature + */ + // $assign_to_config['name_of_config_item'] = 'value of config item'; + + + +// -------------------------------------------------------------------- +// END OF USER CONFIGURABLE SETTINGS. DO NOT EDIT BELOW THIS LINE +// -------------------------------------------------------------------- + +/* + * --------------------------------------------------------------- + * Resolve the system path for increased reliability + * --------------------------------------------------------------- + */ + + // Set the current directory correctly for CLI requests + if (defined('STDIN')) + { + chdir(dirname(__FILE__)); + } + + if (($_temp = realpath($system_path)) !== FALSE) + { + $system_path = $_temp.DIRECTORY_SEPARATOR; + } + else + { + // Ensure there's a trailing slash + $system_path = strtr( + rtrim($system_path, '/\\'), + '/\\', + DIRECTORY_SEPARATOR.DIRECTORY_SEPARATOR + ).DIRECTORY_SEPARATOR; + } + + // Is the system path correct? + if ( ! is_dir($system_path)) + { + header('HTTP/1.1 503 Service Unavailable.', TRUE, 503); + echo 'Your system folder path does not appear to be set correctly. Please open the following file and correct this: '.pathinfo(__FILE__, PATHINFO_BASENAME); + exit(3); // EXIT_CONFIG + } + +/* + * ------------------------------------------------------------------- + * Now that we know the path, set the main path constants + * ------------------------------------------------------------------- + */ + // The name of THIS file + define('SELF', pathinfo(__FILE__, PATHINFO_BASENAME)); + + // Path to the system directory + define('BASEPATH', $system_path); + + // Path to the front controller (this file) directory + define('FCPATH', dirname(__FILE__).DIRECTORY_SEPARATOR); + + // Name of the "system" directory + define('SYSDIR', basename(BASEPATH)); + + // The path to the "application" directory + if (is_dir($application_folder)) + { + if (($_temp = realpath($application_folder)) !== FALSE) + { + $application_folder = $_temp; + } + else + { + $application_folder = strtr( + rtrim($application_folder, '/\\'), + '/\\', + DIRECTORY_SEPARATOR.DIRECTORY_SEPARATOR + ); + } + } + elseif (is_dir(BASEPATH.$application_folder.DIRECTORY_SEPARATOR)) + { + $application_folder = BASEPATH.strtr( + trim($application_folder, '/\\'), + '/\\', + DIRECTORY_SEPARATOR.DIRECTORY_SEPARATOR + ); + } + else + { + header('HTTP/1.1 503 Service Unavailable.', TRUE, 503); + echo 'Your application folder path does not appear to be set correctly. Please open the following file and correct this: '.SELF; + exit(3); // EXIT_CONFIG + } + + define('APPPATH', $application_folder.DIRECTORY_SEPARATOR); + + // The path to the "views" directory + if ( ! isset($view_folder[0]) && is_dir(APPPATH.'views'.DIRECTORY_SEPARATOR)) + { + $view_folder = APPPATH.'views'; + } + elseif (is_dir($view_folder)) + { + if (($_temp = realpath($view_folder)) !== FALSE) + { + $view_folder = $_temp; + } + else + { + $view_folder = strtr( + rtrim($view_folder, '/\\'), + '/\\', + DIRECTORY_SEPARATOR.DIRECTORY_SEPARATOR + ); + } + } + elseif (is_dir(APPPATH.$view_folder.DIRECTORY_SEPARATOR)) + { + $view_folder = APPPATH.strtr( + trim($view_folder, '/\\'), + '/\\', + DIRECTORY_SEPARATOR.DIRECTORY_SEPARATOR + ); + } + else + { + header('HTTP/1.1 503 Service Unavailable.', TRUE, 503); + echo 'Your view folder path does not appear to be set correctly. Please open the following file and correct this: '.SELF; + exit(3); // EXIT_CONFIG + } + + define('VIEWPATH', $view_folder.DIRECTORY_SEPARATOR); + +/* + * -------------------------------------------------------------------- + * LOAD THE BOOTSTRAP FILE + * -------------------------------------------------------------------- + * + * And away we go... + */ +require_once BASEPATH.'core/CodeIgniter.php'; diff --git a/static/bg.png b/static/bg.png new file mode 100644 index 0000000..77e81bb Binary files /dev/null and b/static/bg.png differ diff --git a/static/clipBoard.min.js b/static/clipBoard.min.js new file mode 100644 index 0000000..9fc81f8 --- /dev/null +++ b/static/clipBoard.min.js @@ -0,0 +1,8 @@ +/** + * clipboard.js + * width clipboard.js, you can copy cut and paste clipboard data + * the main methods ard execCommand for modern browser and clipboardData for ie + * @author ganzw@gmail.com + * @url https://github.com/baixuexiyang/clipBoard.js + */ +!function(t,e){"undefined"!=typeof module&&module.exports?module.exports=e():"function"==typeof define&&define.amd?define(e):this[t]=e()}("clipBoard",function(){"use strict";function t(t,e){this.options=e||{},this.tar=t[0]||t,this.options.copy&&this.copyd(),this.options.cut&&this.cut(),this.options.paste&&this.paste()}return t.prototype.copyd=function(t){if(this.options.beforeCopy&&this.options.beforeCopy(),t=t||this.tar.value||this.tar.innerText,this.options.copy&&(t=this.options.copy()),document.execCommand){var e=document.createElement("SPAN");if(e.textContent=t,document.body.appendChild(e),document.selection){var o=document.body.createTextRange();o.moveToElementText(e),o.select()}else if(window.getSelection){var o=document.createRange();o.selectNode(e),window.getSelection().removeAllRanges(),window.getSelection().addRange(o)}document.execCommand("copy"),e.remove?e.remove():e.removeNode(!0)}window.clipboardData&&window.clipboardData.setData("text",t),this.options.afterCopy&&this.options.afterCopy()},t.prototype.cut=function(){if("text"===this.tar.type||"textarea"===this.tar.type){if(this.options.beforeCut&&this.options.beforeCut(),document.execCommand){var t=this.tar;if(document.selection){var e=document.body.createTextRange();e.moveToElementText(t),e.select()}else window.getSelection&&t.select();document.execCommand("cut")}window.clipboardData&&(window.clipboardData.setData("text",this.tar.value),this.tar.value=""),this.options.afterCut&&this.options.afterCut()}},t.prototype.paste=function(){if("text"===this.tar.type||"textarea"===this.tar.type){if(this.options.beforePaste&&this.options.beforePaste(),document.execCommand){var t=this.tar;if(t.setSelectionRange)t.focus(),t.setSelectionRange(t.value.length,t.value.length);else if(t.createTextRange){var e=t.createTextRange();e.collapse(!0),e.moveEnd("character",t.value.length),e.moveStart("character",t.value.length),e.select()}document.execCommand("paste")}!document.execCommand&&window.clipboardData&&(this.tar.value+=window.clipboardData.getData("text")),this.options.afterPaste&&this.options.afterPaste()}},t}); diff --git a/static/css/admin.css b/static/css/admin.css new file mode 100644 index 0000000..cc38b14 --- /dev/null +++ b/static/css/admin.css @@ -0,0 +1,133 @@ +body a{ + color:#009688; +} +.layui-logo a{ + color:#009688; +} +.site{ + margin-top:2em; +} +.setting{ + margin-top:2em; +} +.setting-msg{ + width:100%; + color: #fff; + background-color: #fc7c5f; + padding:0.8em; + border-radius: 5px; + margin-bottom:2em; +} +.identify-msg{ + margin-bottom: 2em; +} +.identify-msg li{ + list-style:decimal; +} +.identify-msg ol{ + margin-left:2em; + +} +.urltext label,.urlupmsg label{ + margin-bottom:1em; + display:block; +} +.showimgs{ + +} +#found-img{ + margin-top:1em; + +} +.showimgs img{ + max-width: 100%; + max-height:100%; + /*border:1px solid #ECECEC;*/ + /* border-radius:5px; */ + /*margin-top:1em;*/ + margin-left:auto; + margin-right:auto; + margin:0 auto; + display: block; +} +.img_thumb{ + + border:1px solid #dddddd; + /* border-radius: 5px; */ + text-align:center; + height:166.25px; + background: #F6F6F6; + display: block; + /* display: flex; + align-items: center; */ + +} +.img_thumb img{ + /* width:290px; + height:175px; */ + max-width: 100%; + /* margin: 2px 2px 2px 2px; */ + /* max-height: 100%; */ +} +/* 分页CSS样式 */ + +#paging .paging{ + padding:0.6em; + background: #eeeeee; + margin-right: 0.5em; +} +#paging strong{ + padding:0.6em; + background: #5FB878; + margin-right: 0.5em; + color:#FFFFFF; +} +.operate{ + /* border-top:1px solid #dddddd; + border-left:1px solid #dddddd; + border-right:1px solid #dddddd; */ + background-color:#F0F0F0; + padding:0.3em; +} +.operate div{ + display: inline; + margin-right:0.5em; +} +.operate .choose{ + height: 22px; + line-height: 22px; + padding: 0 5px; + font-size: 12px; +} +/* #operate .choose{ + height: 22px; + line-height: 22px; + padding: 0 5px; + font-size: 12px; +} */ +#imglink{ + z-index: 990; + display: none; +} +.statistics{ + background-color:#009688; + text-align: center; + font-size:30px; +} +.statistics a{ + color:#FFFFFF; +} +.analyze{ + background-color:#009688; + text-align:center; + color:#FFFFFF; +} +.analyze h3{ + line-height: 2.4em; +} +.analyze p{ + line-height: 2em; +} +.analyze a{ + color:#FFFFFF; +} \ No newline at end of file diff --git a/static/css/page.css b/static/css/page.css new file mode 100644 index 0000000..e69de29 diff --git a/static/embed.js b/static/embed.js new file mode 100644 index 0000000..127935f --- /dev/null +++ b/static/embed.js @@ -0,0 +1,210 @@ +// 选择按钮 +// $(document).ready(function(){ +// //获取默认上传方式 +// storage = $('#storage input[name="storage"]:checked ').val(); +// $("#upurl").text(storage); +// //用户自行选择上传方式 +// $("#storage").click(function(){ +// storage = $('#storage input[name="storage"]:checked ').val(); +// $("#upurl").text(storage); +// }); +// }); +// 这个东西没值,你拿不到 +layui.use(['upload','form','element','layer'], function(){ + var upload = layui.upload; + var form = layui.form; + var element = layui.element; + var layer = layui.layer; + var storage = $('#storage input[name="storage"]:checked ').val(); + + //图片查看器 + layer.photos({ + photos: '#found' + ,anim: 5 //0-6的选择,指定弹出图片动画类型,默认随机(请注意,3.0之前的版本用shift参数) + }); + layer.photos({ + photos: '#lightgallery' + ,anim: 5 //0-6的选择,指定弹出图片动画类型,默认随机(请注意,3.0之前的版本用shift参数) + }); + + //执行实例 + var uploadInst = upload.render({ + elem: '#upimg' //绑定元素 + //选择的时候触发 + ,choose: function(obj){ //obj参数包含的信息,跟 choose回调完全一致,可参见上文。 + //uploadListIns.config.data.storage = storage; + storage = $('#storage input[name="storage"]:checked ').val(); + //this.url = '/upload/' + storage; + //console.log(this.url); + } + ,size:5120 + ,before: function(obj){ //obj参数包含的信息,跟 choose回调完全一致,可参见上文。 + layer.load(); //上传loading + } + ,url: '/upload/localhost' //上传接口 + ,done: function(res){ + //console.log(res); + //上传完毕回调 + //如果上传失败 + if(res.code == 0){ + layer.open({ + title: '温馨提示' + ,content: res.msg + }); + layer.closeAll('loading'); + } + else if(res.code == 200){ + layer.closeAll('loading'); + $("#img-thumb a").attr('href','/img/' + res.imgid); + $("#img-thumb img").attr('src',res.thumbnail_url); + $("#url").val(res.url); + $("#html").val(""); + $("#markdown").val("![](" + res.url + ")"); + $("#bbcode").val("[img]" + res.url + "[/img]"); + $("#imgshow").show(); + //对图片进行鉴黄识别 + identify(res.id); + } + } + ,error: function(){ + //请求异常回调 + layer.closeAll('loading'); + } + }); + //单文件上传END + //多文件上传开始 + upload.render({ + elem: '#multiple' + ,url: '/upload/localhost' + ,multiple:true + ,size:5120 + ,number:5 //可同时上传数量 + ,before: function(obj){ //上传之前的回调 + //清空显示区域 + $("#re-url pre").empty(); + $("#re-html pre").empty(); + $("#re-md pre").empty(); + $("#re-bbc pre").empty(); + layer.load(); //上传loading + n = 0; + } + ,allDone: function(obj){ //当文件全部被提交后,才触发 + //显示上传结果 + $("#multiple-re").show(); + //得到文件总数 + layer.closeAll('loading'); //关闭loading + } + ,done: function(res, index, upload){ //上传后的回调 + //n = n + 1; + + if(res.code == 200){ + //得到百分比 + //var col = (n / total) * 100; + multiple(res.url); + //对图片进行鉴黄识别 + identify(res.id); + //element.progress('up-status', col + '%'); + } + } + ,error: function(index, upload){ + layer.closeAll('loading'); //关闭loading + } + }) + //多文件上传END +}); + +//显示多图上传结果 +function multiple(url){ + $("#re-url pre").append(url + "
"); + $("#re-html pre").append("<img src = '" + url + "' />" + "
"); + $("#re-md pre").append("![](" + url + ")" + "
"); + $("#re-bbc pre").append("[img]" + url + "[/img]" + "
"); +} + +//复制链接 +//复制链接 +function copyurl(info){ + var copy = new clipBoard(document.getElementById('links'), { + beforeCopy: function() { + info = $("#" + info).val(); + }, + copy: function() { + return info; + }, + afterCopy: function() { + + } + }); + layui.use('layer', function(){ + var layer = layui.layer; + + layer.msg('链接已复制!', {time: 2000}) + }); +} + +//用户登录 +function login(){ + // 获取用户提交的信息 + var user = $("#user").val(); + var password = $("#password").val(); + + if((user == '') || (password == '')){ + layer.msg('用户名或密码不能为空!'); + return false; + } + + $.post("/user/verify",{user:user,password:password},function(data,status){ + var re = JSON.parse(data); + if(re.code == 200){ + window.location.href = "/admin/"; + } + else{ + layer.msg(re.msg,{time:2000}); + } + //layer.msg(data,{time:2000}); + }); +} + +//显示图片操作按钮 +function show_imgcon(id){ + $("#imgcon" + id).show(); +} +//隐藏图片操作按钮 +function hide_imgcon(id){ + $("#imgcon" + id).hide(); +} + +//显示图片链接 +function showlink(url,thumburl){ + layer.open({ + type: 1, + title: false, + content: $('#imglink'), + area: ['680px', '500px'] + }); + $("#img-thumb a").attr('href', thumburl); + $("#img-thumb img").attr('src',thumburl); + $("#url").val(url); + $("#html").val(""); + $("#markdown").val("![](" + url + ")"); + $("#bbcode").val("[img]" + url + "[/img]"); + $("#imglink").show(); +} + +//对图片进行鉴黄识别 +function identify(id){ + //对图片进行鉴黄识别 + $.get("/deal/identify/" + id,function(data,status){ + var re = JSON.parse(data); + //状态码为400,说明该图片存在异常 + if(re.code == 400){ + layer.open({ + title: '警告!' + ,content: '您的IP已被记录,请不要上传违规图片!' + }); + } + else{ + console.log(re.code); + } + }); +} \ No newline at end of file diff --git a/static/font-awesome/HELP-US-OUT.txt b/static/font-awesome/HELP-US-OUT.txt new file mode 100644 index 0000000..83d083d --- /dev/null +++ b/static/font-awesome/HELP-US-OUT.txt @@ -0,0 +1,7 @@ +I hope you love Font Awesome. If you've found it useful, please do me a favor and check out my latest project, +Fort Awesome (https://fortawesome.com). It makes it easy to put the perfect icons on your website. Choose from our awesome, +comprehensive icon sets or copy and paste your own. + +Please. Check it out. + +-Dave Gandy diff --git a/static/font-awesome/css/font-awesome.css b/static/font-awesome/css/font-awesome.css new file mode 100644 index 0000000..ee906a8 --- /dev/null +++ b/static/font-awesome/css/font-awesome.css @@ -0,0 +1,2337 @@ +/*! + * 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.7.0'); + src: url('../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0') format('embedded-opentype'), url('../fonts/fontawesome-webfont.woff2?v=4.7.0') format('woff2'), url('../fonts/fontawesome-webfont.woff?v=4.7.0') format('woff'), url('../fonts/fontawesome-webfont.ttf?v=4.7.0') format('truetype'), url('../fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular') format('svg'); + font-weight: normal; + font-style: normal; +} +.fa { + display: inline-block; + font: normal normal normal 14px/1 FontAwesome; + font-size: inherit; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} +/* makes the font 33% larger relative to the icon container */ +.fa-lg { + font-size: 1.33333333em; + line-height: 0.75em; + vertical-align: -15%; +} +.fa-2x { + font-size: 2em; +} +.fa-3x { + font-size: 3em; +} +.fa-4x { + font-size: 4em; +} +.fa-5x { + font-size: 5em; +} +.fa-fw { + width: 1.28571429em; + text-align: center; +} +.fa-ul { + padding-left: 0; + margin-left: 2.14285714em; + list-style-type: none; +} +.fa-ul > li { + position: relative; +} +.fa-li { + position: absolute; + left: -2.14285714em; + width: 2.14285714em; + top: 0.14285714em; + text-align: center; +} +.fa-li.fa-lg { + left: -1.85714286em; +} +.fa-border { + padding: .2em .25em .15em; + border: solid 0.08em #eeeeee; + border-radius: .1em; +} +.fa-pull-left { + float: left; +} +.fa-pull-right { + float: right; +} +.fa.fa-pull-left { + margin-right: .3em; +} +.fa.fa-pull-right { + margin-left: .3em; +} +/* Deprecated as of 4.4.0 */ +.pull-right { + float: right; +} +.pull-left { + float: left; +} +.fa.pull-left { + margin-right: .3em; +} +.fa.pull-right { + margin-left: .3em; +} +.fa-spin { + -webkit-animation: fa-spin 2s infinite linear; + animation: fa-spin 2s infinite linear; +} +.fa-pulse { + -webkit-animation: fa-spin 1s infinite steps(8); + animation: fa-spin 1s infinite steps(8); +} +@-webkit-keyframes fa-spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} +@keyframes fa-spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} +.fa-rotate-90 { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=1)"; + -webkit-transform: rotate(90deg); + -ms-transform: rotate(90deg); + transform: rotate(90deg); +} +.fa-rotate-180 { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2)"; + -webkit-transform: rotate(180deg); + -ms-transform: rotate(180deg); + transform: rotate(180deg); +} +.fa-rotate-270 { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=3)"; + -webkit-transform: rotate(270deg); + -ms-transform: rotate(270deg); + transform: rotate(270deg); +} +.fa-flip-horizontal { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)"; + -webkit-transform: scale(-1, 1); + -ms-transform: scale(-1, 1); + transform: scale(-1, 1); +} +.fa-flip-vertical { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"; + -webkit-transform: scale(1, -1); + -ms-transform: scale(1, -1); + transform: scale(1, -1); +} +:root .fa-rotate-90, +:root .fa-rotate-180, +:root .fa-rotate-270, +:root .fa-flip-horizontal, +:root .fa-flip-vertical { + filter: none; +} +.fa-stack { + position: relative; + display: inline-block; + width: 2em; + height: 2em; + line-height: 2em; + vertical-align: middle; +} +.fa-stack-1x, +.fa-stack-2x { + position: absolute; + left: 0; + width: 100%; + text-align: center; +} +.fa-stack-1x { + line-height: inherit; +} +.fa-stack-2x { + font-size: 2em; +} +.fa-inverse { + color: #ffffff; +} +/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen + readers do not read off random characters that represent icons */ +.fa-glass:before { + content: "\f000"; +} +.fa-music:before { + content: "\f001"; +} +.fa-search:before { + content: "\f002"; +} +.fa-envelope-o:before { + content: "\f003"; +} +.fa-heart:before { + content: "\f004"; +} +.fa-star:before { + content: "\f005"; +} +.fa-star-o:before { + content: "\f006"; +} +.fa-user:before { + content: "\f007"; +} +.fa-film:before { + content: "\f008"; +} +.fa-th-large:before { + content: "\f009"; +} +.fa-th:before { + content: "\f00a"; +} +.fa-th-list:before { + content: "\f00b"; +} +.fa-check:before { + content: "\f00c"; +} +.fa-remove:before, +.fa-close:before, +.fa-times:before { + content: "\f00d"; +} +.fa-search-plus:before { + content: "\f00e"; +} +.fa-search-minus:before { + content: "\f010"; +} +.fa-power-off:before { + content: "\f011"; +} +.fa-signal:before { + content: "\f012"; +} +.fa-gear:before, +.fa-cog:before { + content: "\f013"; +} +.fa-trash-o:before { + content: "\f014"; +} +.fa-home:before { + content: "\f015"; +} +.fa-file-o:before { + content: "\f016"; +} +.fa-clock-o:before { + content: "\f017"; +} +.fa-road:before { + content: "\f018"; +} +.fa-download:before { + content: "\f019"; +} +.fa-arrow-circle-o-down:before { + content: "\f01a"; +} +.fa-arrow-circle-o-up:before { + content: "\f01b"; +} +.fa-inbox:before { + content: "\f01c"; +} +.fa-play-circle-o:before { + content: "\f01d"; +} +.fa-rotate-right:before, +.fa-repeat:before { + content: "\f01e"; +} +.fa-refresh:before { + content: "\f021"; +} +.fa-list-alt:before { + content: "\f022"; +} +.fa-lock:before { + content: "\f023"; +} +.fa-flag:before { + content: "\f024"; +} +.fa-headphones:before { + content: "\f025"; +} +.fa-volume-off:before { + content: "\f026"; +} +.fa-volume-down:before { + content: "\f027"; +} +.fa-volume-up:before { + content: "\f028"; +} +.fa-qrcode:before { + content: "\f029"; +} +.fa-barcode:before { + content: "\f02a"; +} +.fa-tag:before { + content: "\f02b"; +} +.fa-tags:before { + content: "\f02c"; +} +.fa-book:before { + content: "\f02d"; +} +.fa-bookmark:before { + content: "\f02e"; +} +.fa-print:before { + content: "\f02f"; +} +.fa-camera:before { + content: "\f030"; +} +.fa-font:before { + content: "\f031"; +} +.fa-bold:before { + content: "\f032"; +} +.fa-italic:before { + content: "\f033"; +} +.fa-text-height:before { + content: "\f034"; +} +.fa-text-width:before { + content: "\f035"; +} +.fa-align-left:before { + content: "\f036"; +} +.fa-align-center:before { + content: "\f037"; +} +.fa-align-right:before { + content: "\f038"; +} +.fa-align-justify:before { + content: "\f039"; +} +.fa-list:before { + content: "\f03a"; +} +.fa-dedent:before, +.fa-outdent:before { + content: "\f03b"; +} +.fa-indent:before { + content: "\f03c"; +} +.fa-video-camera:before { + content: "\f03d"; +} +.fa-photo:before, +.fa-image:before, +.fa-picture-o:before { + content: "\f03e"; +} +.fa-pencil:before { + content: "\f040"; +} +.fa-map-marker:before { + content: "\f041"; +} +.fa-adjust:before { + content: "\f042"; +} +.fa-tint:before { + content: "\f043"; +} +.fa-edit:before, +.fa-pencil-square-o:before { + content: "\f044"; +} +.fa-share-square-o:before { + content: "\f045"; +} +.fa-check-square-o:before { + content: "\f046"; +} +.fa-arrows:before { + content: "\f047"; +} +.fa-step-backward:before { + content: "\f048"; +} +.fa-fast-backward:before { + content: "\f049"; +} +.fa-backward:before { + content: "\f04a"; +} +.fa-play:before { + content: "\f04b"; +} +.fa-pause:before { + content: "\f04c"; +} +.fa-stop:before { + content: "\f04d"; +} +.fa-forward:before { + content: "\f04e"; +} +.fa-fast-forward:before { + content: "\f050"; +} +.fa-step-forward:before { + content: "\f051"; +} +.fa-eject:before { + content: "\f052"; +} +.fa-chevron-left:before { + content: "\f053"; +} +.fa-chevron-right:before { + content: "\f054"; +} +.fa-plus-circle:before { + content: "\f055"; +} +.fa-minus-circle:before { + content: "\f056"; +} +.fa-times-circle:before { + content: "\f057"; +} +.fa-check-circle:before { + content: "\f058"; +} +.fa-question-circle:before { + content: "\f059"; +} +.fa-info-circle:before { + content: "\f05a"; +} +.fa-crosshairs:before { + content: "\f05b"; +} +.fa-times-circle-o:before { + content: "\f05c"; +} +.fa-check-circle-o:before { + content: "\f05d"; +} +.fa-ban:before { + content: "\f05e"; +} +.fa-arrow-left:before { + content: "\f060"; +} +.fa-arrow-right:before { + content: "\f061"; +} +.fa-arrow-up:before { + content: "\f062"; +} +.fa-arrow-down:before { + content: "\f063"; +} +.fa-mail-forward:before, +.fa-share:before { + content: "\f064"; +} +.fa-expand:before { + content: "\f065"; +} +.fa-compress:before { + content: "\f066"; +} +.fa-plus:before { + content: "\f067"; +} +.fa-minus:before { + content: "\f068"; +} +.fa-asterisk:before { + content: "\f069"; +} +.fa-exclamation-circle:before { + content: "\f06a"; +} +.fa-gift:before { + content: "\f06b"; +} +.fa-leaf:before { + content: "\f06c"; +} +.fa-fire:before { + content: "\f06d"; +} +.fa-eye:before { + content: "\f06e"; +} +.fa-eye-slash:before { + content: "\f070"; +} +.fa-warning:before, +.fa-exclamation-triangle:before { + content: "\f071"; +} +.fa-plane:before { + content: "\f072"; +} +.fa-calendar:before { + content: "\f073"; +} +.fa-random:before { + content: "\f074"; +} +.fa-comment:before { + content: "\f075"; +} +.fa-magnet:before { + content: "\f076"; +} +.fa-chevron-up:before { + content: "\f077"; +} +.fa-chevron-down:before { + content: "\f078"; +} +.fa-retweet:before { + content: "\f079"; +} +.fa-shopping-cart:before { + content: "\f07a"; +} +.fa-folder:before { + content: "\f07b"; +} +.fa-folder-open:before { + content: "\f07c"; +} +.fa-arrows-v:before { + content: "\f07d"; +} +.fa-arrows-h:before { + content: "\f07e"; +} +.fa-bar-chart-o:before, +.fa-bar-chart:before { + content: "\f080"; +} +.fa-twitter-square:before { + content: "\f081"; +} +.fa-facebook-square:before { + content: "\f082"; +} +.fa-camera-retro:before { + content: "\f083"; +} +.fa-key:before { + content: "\f084"; +} +.fa-gears:before, +.fa-cogs:before { + content: "\f085"; +} +.fa-comments:before { + content: "\f086"; +} +.fa-thumbs-o-up:before { + content: "\f087"; +} +.fa-thumbs-o-down:before { + content: "\f088"; +} +.fa-star-half:before { + content: "\f089"; +} +.fa-heart-o:before { + content: "\f08a"; +} +.fa-sign-out:before { + content: "\f08b"; +} +.fa-linkedin-square:before { + content: "\f08c"; +} +.fa-thumb-tack:before { + content: "\f08d"; +} +.fa-external-link:before { + content: "\f08e"; +} +.fa-sign-in:before { + content: "\f090"; +} +.fa-trophy:before { + content: "\f091"; +} +.fa-github-square:before { + content: "\f092"; +} +.fa-upload:before { + content: "\f093"; +} +.fa-lemon-o:before { + content: "\f094"; +} +.fa-phone:before { + content: "\f095"; +} +.fa-square-o:before { + content: "\f096"; +} +.fa-bookmark-o:before { + content: "\f097"; +} +.fa-phone-square:before { + content: "\f098"; +} +.fa-twitter:before { + content: "\f099"; +} +.fa-facebook-f:before, +.fa-facebook:before { + content: "\f09a"; +} +.fa-github:before { + content: "\f09b"; +} +.fa-unlock:before { + content: "\f09c"; +} +.fa-credit-card:before { + content: "\f09d"; +} +.fa-feed:before, +.fa-rss:before { + content: "\f09e"; +} +.fa-hdd-o:before { + content: "\f0a0"; +} +.fa-bullhorn:before { + content: "\f0a1"; +} +.fa-bell:before { + content: "\f0f3"; +} +.fa-certificate:before { + content: "\f0a3"; +} +.fa-hand-o-right:before { + content: "\f0a4"; +} +.fa-hand-o-left:before { + content: "\f0a5"; +} +.fa-hand-o-up:before { + content: "\f0a6"; +} +.fa-hand-o-down:before { + content: "\f0a7"; +} +.fa-arrow-circle-left:before { + content: "\f0a8"; +} +.fa-arrow-circle-right:before { + content: "\f0a9"; +} +.fa-arrow-circle-up:before { + content: "\f0aa"; +} +.fa-arrow-circle-down:before { + content: "\f0ab"; +} +.fa-globe:before { + content: "\f0ac"; +} +.fa-wrench:before { + content: "\f0ad"; +} +.fa-tasks:before { + content: "\f0ae"; +} +.fa-filter:before { + content: "\f0b0"; +} +.fa-briefcase:before { + content: "\f0b1"; +} +.fa-arrows-alt:before { + content: "\f0b2"; +} +.fa-group:before, +.fa-users:before { + content: "\f0c0"; +} +.fa-chain:before, +.fa-link:before { + content: "\f0c1"; +} +.fa-cloud:before { + content: "\f0c2"; +} +.fa-flask:before { + content: "\f0c3"; +} +.fa-cut:before, +.fa-scissors:before { + content: "\f0c4"; +} +.fa-copy:before, +.fa-files-o:before { + content: "\f0c5"; +} +.fa-paperclip:before { + content: "\f0c6"; +} +.fa-save:before, +.fa-floppy-o:before { + content: "\f0c7"; +} +.fa-square:before { + content: "\f0c8"; +} +.fa-navicon:before, +.fa-reorder:before, +.fa-bars:before { + content: "\f0c9"; +} +.fa-list-ul:before { + content: "\f0ca"; +} +.fa-list-ol:before { + content: "\f0cb"; +} +.fa-strikethrough:before { + content: "\f0cc"; +} +.fa-underline:before { + content: "\f0cd"; +} +.fa-table:before { + content: "\f0ce"; +} +.fa-magic:before { + content: "\f0d0"; +} +.fa-truck:before { + content: "\f0d1"; +} +.fa-pinterest:before { + content: "\f0d2"; +} +.fa-pinterest-square:before { + content: "\f0d3"; +} +.fa-google-plus-square:before { + content: "\f0d4"; +} +.fa-google-plus:before { + content: "\f0d5"; +} +.fa-money:before { + content: "\f0d6"; +} +.fa-caret-down:before { + content: "\f0d7"; +} +.fa-caret-up:before { + content: "\f0d8"; +} +.fa-caret-left:before { + content: "\f0d9"; +} +.fa-caret-right:before { + content: "\f0da"; +} +.fa-columns:before { + content: "\f0db"; +} +.fa-unsorted:before, +.fa-sort:before { + content: "\f0dc"; +} +.fa-sort-down:before, +.fa-sort-desc:before { + content: "\f0dd"; +} +.fa-sort-up:before, +.fa-sort-asc:before { + content: "\f0de"; +} +.fa-envelope:before { + content: "\f0e0"; +} +.fa-linkedin:before { + content: "\f0e1"; +} +.fa-rotate-left:before, +.fa-undo:before { + content: "\f0e2"; +} +.fa-legal:before, +.fa-gavel:before { + content: "\f0e3"; +} +.fa-dashboard:before, +.fa-tachometer:before { + content: "\f0e4"; +} +.fa-comment-o:before { + content: "\f0e5"; +} +.fa-comments-o:before { + content: "\f0e6"; +} +.fa-flash:before, +.fa-bolt:before { + content: "\f0e7"; +} +.fa-sitemap:before { + content: "\f0e8"; +} +.fa-umbrella:before { + content: "\f0e9"; +} +.fa-paste:before, +.fa-clipboard:before { + content: "\f0ea"; +} +.fa-lightbulb-o:before { + content: "\f0eb"; +} +.fa-exchange:before { + content: "\f0ec"; +} +.fa-cloud-download:before { + content: "\f0ed"; +} +.fa-cloud-upload:before { + content: "\f0ee"; +} +.fa-user-md:before { + content: "\f0f0"; +} +.fa-stethoscope:before { + content: "\f0f1"; +} +.fa-suitcase:before { + content: "\f0f2"; +} +.fa-bell-o:before { + content: "\f0a2"; +} +.fa-coffee:before { + content: "\f0f4"; +} +.fa-cutlery:before { + content: "\f0f5"; +} +.fa-file-text-o:before { + content: "\f0f6"; +} +.fa-building-o:before { + content: "\f0f7"; +} +.fa-hospital-o:before { + content: "\f0f8"; +} +.fa-ambulance:before { + content: "\f0f9"; +} +.fa-medkit:before { + content: "\f0fa"; +} +.fa-fighter-jet:before { + content: "\f0fb"; +} +.fa-beer:before { + content: "\f0fc"; +} +.fa-h-square:before { + content: "\f0fd"; +} +.fa-plus-square:before { + content: "\f0fe"; +} +.fa-angle-double-left:before { + content: "\f100"; +} +.fa-angle-double-right:before { + content: "\f101"; +} +.fa-angle-double-up:before { + content: "\f102"; +} +.fa-angle-double-down:before { + content: "\f103"; +} +.fa-angle-left:before { + content: "\f104"; +} +.fa-angle-right:before { + content: "\f105"; +} +.fa-angle-up:before { + content: "\f106"; +} +.fa-angle-down:before { + content: "\f107"; +} +.fa-desktop:before { + content: "\f108"; +} +.fa-laptop:before { + content: "\f109"; +} +.fa-tablet:before { + content: "\f10a"; +} +.fa-mobile-phone:before, +.fa-mobile:before { + content: "\f10b"; +} +.fa-circle-o:before { + content: "\f10c"; +} +.fa-quote-left:before { + content: "\f10d"; +} +.fa-quote-right:before { + content: "\f10e"; +} +.fa-spinner:before { + content: "\f110"; +} +.fa-circle:before { + content: "\f111"; +} +.fa-mail-reply:before, +.fa-reply:before { + content: "\f112"; +} +.fa-github-alt:before { + content: "\f113"; +} +.fa-folder-o:before { + content: "\f114"; +} +.fa-folder-open-o:before { + content: "\f115"; +} +.fa-smile-o:before { + content: "\f118"; +} +.fa-frown-o:before { + content: "\f119"; +} +.fa-meh-o:before { + content: "\f11a"; +} +.fa-gamepad:before { + content: "\f11b"; +} +.fa-keyboard-o:before { + content: "\f11c"; +} +.fa-flag-o:before { + content: "\f11d"; +} +.fa-flag-checkered:before { + content: "\f11e"; +} +.fa-terminal:before { + content: "\f120"; +} +.fa-code:before { + content: "\f121"; +} +.fa-mail-reply-all:before, +.fa-reply-all:before { + content: "\f122"; +} +.fa-star-half-empty:before, +.fa-star-half-full:before, +.fa-star-half-o:before { + content: "\f123"; +} +.fa-location-arrow:before { + content: "\f124"; +} +.fa-crop:before { + content: "\f125"; +} +.fa-code-fork:before { + content: "\f126"; +} +.fa-unlink:before, +.fa-chain-broken:before { + content: "\f127"; +} +.fa-question:before { + content: "\f128"; +} +.fa-info:before { + content: "\f129"; +} +.fa-exclamation:before { + content: "\f12a"; +} +.fa-superscript:before { + content: "\f12b"; +} +.fa-subscript:before { + content: "\f12c"; +} +.fa-eraser:before { + content: "\f12d"; +} +.fa-puzzle-piece:before { + content: "\f12e"; +} +.fa-microphone:before { + content: "\f130"; +} +.fa-microphone-slash:before { + content: "\f131"; +} +.fa-shield:before { + content: "\f132"; +} +.fa-calendar-o:before { + content: "\f133"; +} +.fa-fire-extinguisher:before { + content: "\f134"; +} +.fa-rocket:before { + content: "\f135"; +} +.fa-maxcdn:before { + content: "\f136"; +} +.fa-chevron-circle-left:before { + content: "\f137"; +} +.fa-chevron-circle-right:before { + content: "\f138"; +} +.fa-chevron-circle-up:before { + content: "\f139"; +} +.fa-chevron-circle-down:before { + content: "\f13a"; +} +.fa-html5:before { + content: "\f13b"; +} +.fa-css3:before { + content: "\f13c"; +} +.fa-anchor:before { + content: "\f13d"; +} +.fa-unlock-alt:before { + content: "\f13e"; +} +.fa-bullseye:before { + content: "\f140"; +} +.fa-ellipsis-h:before { + content: "\f141"; +} +.fa-ellipsis-v:before { + content: "\f142"; +} +.fa-rss-square:before { + content: "\f143"; +} +.fa-play-circle:before { + content: "\f144"; +} +.fa-ticket:before { + content: "\f145"; +} +.fa-minus-square:before { + content: "\f146"; +} +.fa-minus-square-o:before { + content: "\f147"; +} +.fa-level-up:before { + content: "\f148"; +} +.fa-level-down:before { + content: "\f149"; +} +.fa-check-square:before { + content: "\f14a"; +} +.fa-pencil-square:before { + content: "\f14b"; +} +.fa-external-link-square:before { + content: "\f14c"; +} +.fa-share-square:before { + content: "\f14d"; +} +.fa-compass:before { + content: "\f14e"; +} +.fa-toggle-down:before, +.fa-caret-square-o-down:before { + content: "\f150"; +} +.fa-toggle-up:before, +.fa-caret-square-o-up:before { + content: "\f151"; +} +.fa-toggle-right:before, +.fa-caret-square-o-right:before { + content: "\f152"; +} +.fa-euro:before, +.fa-eur:before { + content: "\f153"; +} +.fa-gbp:before { + content: "\f154"; +} +.fa-dollar:before, +.fa-usd:before { + content: "\f155"; +} +.fa-rupee:before, +.fa-inr:before { + content: "\f156"; +} +.fa-cny:before, +.fa-rmb:before, +.fa-yen:before, +.fa-jpy:before { + content: "\f157"; +} +.fa-ruble:before, +.fa-rouble:before, +.fa-rub:before { + content: "\f158"; +} +.fa-won:before, +.fa-krw:before { + content: "\f159"; +} +.fa-bitcoin:before, +.fa-btc:before { + content: "\f15a"; +} +.fa-file:before { + content: "\f15b"; +} +.fa-file-text:before { + content: "\f15c"; +} +.fa-sort-alpha-asc:before { + content: "\f15d"; +} +.fa-sort-alpha-desc:before { + content: "\f15e"; +} +.fa-sort-amount-asc:before { + content: "\f160"; +} +.fa-sort-amount-desc:before { + content: "\f161"; +} +.fa-sort-numeric-asc:before { + content: "\f162"; +} +.fa-sort-numeric-desc:before { + content: "\f163"; +} +.fa-thumbs-up:before { + content: "\f164"; +} +.fa-thumbs-down:before { + content: "\f165"; +} +.fa-youtube-square:before { + content: "\f166"; +} +.fa-youtube:before { + content: "\f167"; +} +.fa-xing:before { + content: "\f168"; +} +.fa-xing-square:before { + content: "\f169"; +} +.fa-youtube-play:before { + content: "\f16a"; +} +.fa-dropbox:before { + content: "\f16b"; +} +.fa-stack-overflow:before { + content: "\f16c"; +} +.fa-instagram:before { + content: "\f16d"; +} +.fa-flickr:before { + content: "\f16e"; +} +.fa-adn:before { + content: "\f170"; +} +.fa-bitbucket:before { + content: "\f171"; +} +.fa-bitbucket-square:before { + content: "\f172"; +} +.fa-tumblr:before { + content: "\f173"; +} +.fa-tumblr-square:before { + content: "\f174"; +} +.fa-long-arrow-down:before { + content: "\f175"; +} +.fa-long-arrow-up:before { + content: "\f176"; +} +.fa-long-arrow-left:before { + content: "\f177"; +} +.fa-long-arrow-right:before { + content: "\f178"; +} +.fa-apple:before { + content: "\f179"; +} +.fa-windows:before { + content: "\f17a"; +} +.fa-android:before { + content: "\f17b"; +} +.fa-linux:before { + content: "\f17c"; +} +.fa-dribbble:before { + content: "\f17d"; +} +.fa-skype:before { + content: "\f17e"; +} +.fa-foursquare:before { + content: "\f180"; +} +.fa-trello:before { + content: "\f181"; +} +.fa-female:before { + content: "\f182"; +} +.fa-male:before { + content: "\f183"; +} +.fa-gittip:before, +.fa-gratipay:before { + content: "\f184"; +} +.fa-sun-o:before { + content: "\f185"; +} +.fa-moon-o:before { + content: "\f186"; +} +.fa-archive:before { + content: "\f187"; +} +.fa-bug:before { + content: "\f188"; +} +.fa-vk:before { + content: "\f189"; +} +.fa-weibo:before { + content: "\f18a"; +} +.fa-renren:before { + content: "\f18b"; +} +.fa-pagelines:before { + content: "\f18c"; +} +.fa-stack-exchange:before { + content: "\f18d"; +} +.fa-arrow-circle-o-right:before { + content: "\f18e"; +} +.fa-arrow-circle-o-left:before { + content: "\f190"; +} +.fa-toggle-left:before, +.fa-caret-square-o-left:before { + content: "\f191"; +} +.fa-dot-circle-o:before { + content: "\f192"; +} +.fa-wheelchair:before { + content: "\f193"; +} +.fa-vimeo-square:before { + content: "\f194"; +} +.fa-turkish-lira:before, +.fa-try:before { + content: "\f195"; +} +.fa-plus-square-o:before { + content: "\f196"; +} +.fa-space-shuttle:before { + content: "\f197"; +} +.fa-slack:before { + content: "\f198"; +} +.fa-envelope-square:before { + content: "\f199"; +} +.fa-wordpress:before { + content: "\f19a"; +} +.fa-openid:before { + content: "\f19b"; +} +.fa-institution:before, +.fa-bank:before, +.fa-university:before { + content: "\f19c"; +} +.fa-mortar-board:before, +.fa-graduation-cap:before { + content: "\f19d"; +} +.fa-yahoo:before { + content: "\f19e"; +} +.fa-google:before { + content: "\f1a0"; +} +.fa-reddit:before { + content: "\f1a1"; +} +.fa-reddit-square:before { + content: "\f1a2"; +} +.fa-stumbleupon-circle:before { + content: "\f1a3"; +} +.fa-stumbleupon:before { + content: "\f1a4"; +} +.fa-delicious:before { + content: "\f1a5"; +} +.fa-digg:before { + content: "\f1a6"; +} +.fa-pied-piper-pp:before { + content: "\f1a7"; +} +.fa-pied-piper-alt:before { + content: "\f1a8"; +} +.fa-drupal:before { + content: "\f1a9"; +} +.fa-joomla:before { + content: "\f1aa"; +} +.fa-language:before { + content: "\f1ab"; +} +.fa-fax:before { + content: "\f1ac"; +} +.fa-building:before { + content: "\f1ad"; +} +.fa-child:before { + content: "\f1ae"; +} +.fa-paw:before { + content: "\f1b0"; +} +.fa-spoon:before { + content: "\f1b1"; +} +.fa-cube:before { + content: "\f1b2"; +} +.fa-cubes:before { + content: "\f1b3"; +} +.fa-behance:before { + content: "\f1b4"; +} +.fa-behance-square:before { + content: "\f1b5"; +} +.fa-steam:before { + content: "\f1b6"; +} +.fa-steam-square:before { + content: "\f1b7"; +} +.fa-recycle:before { + content: "\f1b8"; +} +.fa-automobile:before, +.fa-car:before { + content: "\f1b9"; +} +.fa-cab:before, +.fa-taxi:before { + content: "\f1ba"; +} +.fa-tree:before { + content: "\f1bb"; +} +.fa-spotify:before { + content: "\f1bc"; +} +.fa-deviantart:before { + content: "\f1bd"; +} +.fa-soundcloud:before { + content: "\f1be"; +} +.fa-database:before { + content: "\f1c0"; +} +.fa-file-pdf-o:before { + content: "\f1c1"; +} +.fa-file-word-o:before { + content: "\f1c2"; +} +.fa-file-excel-o:before { + content: "\f1c3"; +} +.fa-file-powerpoint-o:before { + content: "\f1c4"; +} +.fa-file-photo-o:before, +.fa-file-picture-o:before, +.fa-file-image-o:before { + content: "\f1c5"; +} +.fa-file-zip-o:before, +.fa-file-archive-o:before { + content: "\f1c6"; +} +.fa-file-sound-o:before, +.fa-file-audio-o:before { + content: "\f1c7"; +} +.fa-file-movie-o:before, +.fa-file-video-o:before { + content: "\f1c8"; +} +.fa-file-code-o:before { + content: "\f1c9"; +} +.fa-vine:before { + content: "\f1ca"; +} +.fa-codepen:before { + content: "\f1cb"; +} +.fa-jsfiddle:before { + content: "\f1cc"; +} +.fa-life-bouy:before, +.fa-life-buoy:before, +.fa-life-saver:before, +.fa-support:before, +.fa-life-ring:before { + content: "\f1cd"; +} +.fa-circle-o-notch:before { + content: "\f1ce"; +} +.fa-ra:before, +.fa-resistance:before, +.fa-rebel:before { + content: "\f1d0"; +} +.fa-ge:before, +.fa-empire:before { + content: "\f1d1"; +} +.fa-git-square:before { + content: "\f1d2"; +} +.fa-git:before { + content: "\f1d3"; +} +.fa-y-combinator-square:before, +.fa-yc-square:before, +.fa-hacker-news:before { + content: "\f1d4"; +} +.fa-tencent-weibo:before { + content: "\f1d5"; +} +.fa-qq:before { + content: "\f1d6"; +} +.fa-wechat:before, +.fa-weixin:before { + content: "\f1d7"; +} +.fa-send:before, +.fa-paper-plane:before { + content: "\f1d8"; +} +.fa-send-o:before, +.fa-paper-plane-o:before { + content: "\f1d9"; +} +.fa-history:before { + content: "\f1da"; +} +.fa-circle-thin:before { + content: "\f1db"; +} +.fa-header:before { + content: "\f1dc"; +} +.fa-paragraph:before { + content: "\f1dd"; +} +.fa-sliders:before { + content: "\f1de"; +} +.fa-share-alt:before { + content: "\f1e0"; +} +.fa-share-alt-square:before { + content: "\f1e1"; +} +.fa-bomb:before { + content: "\f1e2"; +} +.fa-soccer-ball-o:before, +.fa-futbol-o:before { + content: "\f1e3"; +} +.fa-tty:before { + content: "\f1e4"; +} +.fa-binoculars:before { + content: "\f1e5"; +} +.fa-plug:before { + content: "\f1e6"; +} +.fa-slideshare:before { + content: "\f1e7"; +} +.fa-twitch:before { + content: "\f1e8"; +} +.fa-yelp:before { + content: "\f1e9"; +} +.fa-newspaper-o:before { + content: "\f1ea"; +} +.fa-wifi:before { + content: "\f1eb"; +} +.fa-calculator:before { + content: "\f1ec"; +} +.fa-paypal:before { + content: "\f1ed"; +} +.fa-google-wallet:before { + content: "\f1ee"; +} +.fa-cc-visa:before { + content: "\f1f0"; +} +.fa-cc-mastercard:before { + content: "\f1f1"; +} +.fa-cc-discover:before { + content: "\f1f2"; +} +.fa-cc-amex:before { + content: "\f1f3"; +} +.fa-cc-paypal:before { + content: "\f1f4"; +} +.fa-cc-stripe:before { + content: "\f1f5"; +} +.fa-bell-slash:before { + content: "\f1f6"; +} +.fa-bell-slash-o:before { + content: "\f1f7"; +} +.fa-trash:before { + content: "\f1f8"; +} +.fa-copyright:before { + content: "\f1f9"; +} +.fa-at:before { + content: "\f1fa"; +} +.fa-eyedropper:before { + content: "\f1fb"; +} +.fa-paint-brush:before { + content: "\f1fc"; +} +.fa-birthday-cake:before { + content: "\f1fd"; +} +.fa-area-chart:before { + content: "\f1fe"; +} +.fa-pie-chart:before { + content: "\f200"; +} +.fa-line-chart:before { + content: "\f201"; +} +.fa-lastfm:before { + content: "\f202"; +} +.fa-lastfm-square:before { + content: "\f203"; +} +.fa-toggle-off:before { + content: "\f204"; +} +.fa-toggle-on:before { + content: "\f205"; +} +.fa-bicycle:before { + content: "\f206"; +} +.fa-bus:before { + content: "\f207"; +} +.fa-ioxhost:before { + content: "\f208"; +} +.fa-angellist:before { + content: "\f209"; +} +.fa-cc:before { + content: "\f20a"; +} +.fa-shekel:before, +.fa-sheqel:before, +.fa-ils:before { + content: "\f20b"; +} +.fa-meanpath:before { + content: "\f20c"; +} +.fa-buysellads:before { + content: "\f20d"; +} +.fa-connectdevelop:before { + content: "\f20e"; +} +.fa-dashcube:before { + content: "\f210"; +} +.fa-forumbee:before { + content: "\f211"; +} +.fa-leanpub:before { + content: "\f212"; +} +.fa-sellsy:before { + content: "\f213"; +} +.fa-shirtsinbulk:before { + content: "\f214"; +} +.fa-simplybuilt:before { + content: "\f215"; +} +.fa-skyatlas:before { + content: "\f216"; +} +.fa-cart-plus:before { + content: "\f217"; +} +.fa-cart-arrow-down:before { + content: "\f218"; +} +.fa-diamond:before { + content: "\f219"; +} +.fa-ship:before { + content: "\f21a"; +} +.fa-user-secret:before { + content: "\f21b"; +} +.fa-motorcycle:before { + content: "\f21c"; +} +.fa-street-view:before { + content: "\f21d"; +} +.fa-heartbeat:before { + content: "\f21e"; +} +.fa-venus:before { + content: "\f221"; +} +.fa-mars:before { + content: "\f222"; +} +.fa-mercury:before { + content: "\f223"; +} +.fa-intersex:before, +.fa-transgender:before { + content: "\f224"; +} +.fa-transgender-alt:before { + content: "\f225"; +} +.fa-venus-double:before { + content: "\f226"; +} +.fa-mars-double:before { + content: "\f227"; +} +.fa-venus-mars:before { + content: "\f228"; +} +.fa-mars-stroke:before { + content: "\f229"; +} +.fa-mars-stroke-v:before { + content: "\f22a"; +} +.fa-mars-stroke-h:before { + content: "\f22b"; +} +.fa-neuter:before { + content: "\f22c"; +} +.fa-genderless:before { + content: "\f22d"; +} +.fa-facebook-official:before { + content: "\f230"; +} +.fa-pinterest-p:before { + content: "\f231"; +} +.fa-whatsapp:before { + content: "\f232"; +} +.fa-server:before { + content: "\f233"; +} +.fa-user-plus:before { + content: "\f234"; +} +.fa-user-times:before { + content: "\f235"; +} +.fa-hotel:before, +.fa-bed:before { + content: "\f236"; +} +.fa-viacoin:before { + content: "\f237"; +} +.fa-train:before { + content: "\f238"; +} +.fa-subway:before { + content: "\f239"; +} +.fa-medium:before { + content: "\f23a"; +} +.fa-yc:before, +.fa-y-combinator:before { + content: "\f23b"; +} +.fa-optin-monster:before { + content: "\f23c"; +} +.fa-opencart:before { + content: "\f23d"; +} +.fa-expeditedssl:before { + content: "\f23e"; +} +.fa-battery-4:before, +.fa-battery:before, +.fa-battery-full:before { + content: "\f240"; +} +.fa-battery-3:before, +.fa-battery-three-quarters:before { + content: "\f241"; +} +.fa-battery-2:before, +.fa-battery-half:before { + content: "\f242"; +} +.fa-battery-1:before, +.fa-battery-quarter:before { + content: "\f243"; +} +.fa-battery-0:before, +.fa-battery-empty:before { + content: "\f244"; +} +.fa-mouse-pointer:before { + content: "\f245"; +} +.fa-i-cursor:before { + content: "\f246"; +} +.fa-object-group:before { + content: "\f247"; +} +.fa-object-ungroup:before { + content: "\f248"; +} +.fa-sticky-note:before { + content: "\f249"; +} +.fa-sticky-note-o:before { + content: "\f24a"; +} +.fa-cc-jcb:before { + content: "\f24b"; +} +.fa-cc-diners-club:before { + content: "\f24c"; +} +.fa-clone:before { + content: "\f24d"; +} +.fa-balance-scale:before { + content: "\f24e"; +} +.fa-hourglass-o:before { + content: "\f250"; +} +.fa-hourglass-1:before, +.fa-hourglass-start:before { + content: "\f251"; +} +.fa-hourglass-2:before, +.fa-hourglass-half:before { + content: "\f252"; +} +.fa-hourglass-3:before, +.fa-hourglass-end:before { + content: "\f253"; +} +.fa-hourglass:before { + content: "\f254"; +} +.fa-hand-grab-o:before, +.fa-hand-rock-o:before { + content: "\f255"; +} +.fa-hand-stop-o:before, +.fa-hand-paper-o:before { + content: "\f256"; +} +.fa-hand-scissors-o:before { + content: "\f257"; +} +.fa-hand-lizard-o:before { + content: "\f258"; +} +.fa-hand-spock-o:before { + content: "\f259"; +} +.fa-hand-pointer-o:before { + content: "\f25a"; +} +.fa-hand-peace-o:before { + content: "\f25b"; +} +.fa-trademark:before { + content: "\f25c"; +} +.fa-registered:before { + content: "\f25d"; +} +.fa-creative-commons:before { + content: "\f25e"; +} +.fa-gg:before { + content: "\f260"; +} +.fa-gg-circle:before { + content: "\f261"; +} +.fa-tripadvisor:before { + content: "\f262"; +} +.fa-odnoklassniki:before { + content: "\f263"; +} +.fa-odnoklassniki-square:before { + content: "\f264"; +} +.fa-get-pocket:before { + content: "\f265"; +} +.fa-wikipedia-w:before { + content: "\f266"; +} +.fa-safari:before { + content: "\f267"; +} +.fa-chrome:before { + content: "\f268"; +} +.fa-firefox:before { + content: "\f269"; +} +.fa-opera:before { + content: "\f26a"; +} +.fa-internet-explorer:before { + content: "\f26b"; +} +.fa-tv:before, +.fa-television:before { + content: "\f26c"; +} +.fa-contao:before { + content: "\f26d"; +} +.fa-500px:before { + content: "\f26e"; +} +.fa-amazon:before { + content: "\f270"; +} +.fa-calendar-plus-o:before { + content: "\f271"; +} +.fa-calendar-minus-o:before { + content: "\f272"; +} +.fa-calendar-times-o:before { + content: "\f273"; +} +.fa-calendar-check-o:before { + content: "\f274"; +} +.fa-industry:before { + content: "\f275"; +} +.fa-map-pin:before { + content: "\f276"; +} +.fa-map-signs:before { + content: "\f277"; +} +.fa-map-o:before { + content: "\f278"; +} +.fa-map:before { + content: "\f279"; +} +.fa-commenting:before { + content: "\f27a"; +} +.fa-commenting-o:before { + content: "\f27b"; +} +.fa-houzz:before { + content: "\f27c"; +} +.fa-vimeo:before { + content: "\f27d"; +} +.fa-black-tie:before { + content: "\f27e"; +} +.fa-fonticons:before { + content: "\f280"; +} +.fa-reddit-alien:before { + content: "\f281"; +} +.fa-edge:before { + content: "\f282"; +} +.fa-credit-card-alt:before { + content: "\f283"; +} +.fa-codiepie:before { + content: "\f284"; +} +.fa-modx:before { + content: "\f285"; +} +.fa-fort-awesome:before { + content: "\f286"; +} +.fa-usb:before { + content: "\f287"; +} +.fa-product-hunt:before { + content: "\f288"; +} +.fa-mixcloud:before { + content: "\f289"; +} +.fa-scribd:before { + content: "\f28a"; +} +.fa-pause-circle:before { + content: "\f28b"; +} +.fa-pause-circle-o:before { + content: "\f28c"; +} +.fa-stop-circle:before { + content: "\f28d"; +} +.fa-stop-circle-o:before { + content: "\f28e"; +} +.fa-shopping-bag:before { + content: "\f290"; +} +.fa-shopping-basket:before { + content: "\f291"; +} +.fa-hashtag:before { + content: "\f292"; +} +.fa-bluetooth:before { + content: "\f293"; +} +.fa-bluetooth-b:before { + content: "\f294"; +} +.fa-percent:before { + content: "\f295"; +} +.fa-gitlab:before { + content: "\f296"; +} +.fa-wpbeginner:before { + content: "\f297"; +} +.fa-wpforms:before { + content: "\f298"; +} +.fa-envira:before { + content: "\f299"; +} +.fa-universal-access:before { + content: "\f29a"; +} +.fa-wheelchair-alt:before { + content: "\f29b"; +} +.fa-question-circle-o:before { + content: "\f29c"; +} +.fa-blind:before { + content: "\f29d"; +} +.fa-audio-description:before { + content: "\f29e"; +} +.fa-volume-control-phone:before { + content: "\f2a0"; +} +.fa-braille:before { + content: "\f2a1"; +} +.fa-assistive-listening-systems:before { + content: "\f2a2"; +} +.fa-asl-interpreting:before, +.fa-american-sign-language-interpreting:before { + content: "\f2a3"; +} +.fa-deafness:before, +.fa-hard-of-hearing:before, +.fa-deaf:before { + content: "\f2a4"; +} +.fa-glide:before { + content: "\f2a5"; +} +.fa-glide-g:before { + content: "\f2a6"; +} +.fa-signing:before, +.fa-sign-language:before { + content: "\f2a7"; +} +.fa-low-vision:before { + content: "\f2a8"; +} +.fa-viadeo:before { + content: "\f2a9"; +} +.fa-viadeo-square:before { + content: "\f2aa"; +} +.fa-snapchat:before { + content: "\f2ab"; +} +.fa-snapchat-ghost:before { + content: "\f2ac"; +} +.fa-snapchat-square:before { + content: "\f2ad"; +} +.fa-pied-piper:before { + content: "\f2ae"; +} +.fa-first-order:before { + content: "\f2b0"; +} +.fa-yoast:before { + content: "\f2b1"; +} +.fa-themeisle:before { + content: "\f2b2"; +} +.fa-google-plus-circle:before, +.fa-google-plus-official:before { + content: "\f2b3"; +} +.fa-fa:before, +.fa-font-awesome:before { + content: "\f2b4"; +} +.fa-handshake-o:before { + content: "\f2b5"; +} +.fa-envelope-open:before { + content: "\f2b6"; +} +.fa-envelope-open-o:before { + content: "\f2b7"; +} +.fa-linode:before { + content: "\f2b8"; +} +.fa-address-book:before { + content: "\f2b9"; +} +.fa-address-book-o:before { + content: "\f2ba"; +} +.fa-vcard:before, +.fa-address-card:before { + content: "\f2bb"; +} +.fa-vcard-o:before, +.fa-address-card-o:before { + content: "\f2bc"; +} +.fa-user-circle:before { + content: "\f2bd"; +} +.fa-user-circle-o:before { + content: "\f2be"; +} +.fa-user-o:before { + content: "\f2c0"; +} +.fa-id-badge:before { + content: "\f2c1"; +} +.fa-drivers-license:before, +.fa-id-card:before { + content: "\f2c2"; +} +.fa-drivers-license-o:before, +.fa-id-card-o:before { + content: "\f2c3"; +} +.fa-quora:before { + content: "\f2c4"; +} +.fa-free-code-camp:before { + content: "\f2c5"; +} +.fa-telegram:before { + content: "\f2c6"; +} +.fa-thermometer-4:before, +.fa-thermometer:before, +.fa-thermometer-full:before { + content: "\f2c7"; +} +.fa-thermometer-3:before, +.fa-thermometer-three-quarters:before { + content: "\f2c8"; +} +.fa-thermometer-2:before, +.fa-thermometer-half:before { + content: "\f2c9"; +} +.fa-thermometer-1:before, +.fa-thermometer-quarter:before { + content: "\f2ca"; +} +.fa-thermometer-0:before, +.fa-thermometer-empty:before { + content: "\f2cb"; +} +.fa-shower:before { + content: "\f2cc"; +} +.fa-bathtub:before, +.fa-s15:before, +.fa-bath:before { + content: "\f2cd"; +} +.fa-podcast:before { + content: "\f2ce"; +} +.fa-window-maximize:before { + content: "\f2d0"; +} +.fa-window-minimize:before { + content: "\f2d1"; +} +.fa-window-restore:before { + content: "\f2d2"; +} +.fa-times-rectangle:before, +.fa-window-close:before { + content: "\f2d3"; +} +.fa-times-rectangle-o:before, +.fa-window-close-o:before { + content: "\f2d4"; +} +.fa-bandcamp:before { + content: "\f2d5"; +} +.fa-grav:before { + content: "\f2d6"; +} +.fa-etsy:before { + content: "\f2d7"; +} +.fa-imdb:before { + content: "\f2d8"; +} +.fa-ravelry:before { + content: "\f2d9"; +} +.fa-eercast:before { + content: "\f2da"; +} +.fa-microchip:before { + content: "\f2db"; +} +.fa-snowflake-o:before { + content: "\f2dc"; +} +.fa-superpowers:before { + content: "\f2dd"; +} +.fa-wpexplorer:before { + content: "\f2de"; +} +.fa-meetup:before { + content: "\f2e0"; +} +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + border: 0; +} +.sr-only-focusable:active, +.sr-only-focusable:focus { + position: static; + width: auto; + height: auto; + margin: 0; + overflow: visible; + clip: auto; +} diff --git a/static/font-awesome/css/font-awesome.min.css b/static/font-awesome/css/font-awesome.min.css new file mode 100644 index 0000000..540440c --- /dev/null +++ b/static/font-awesome/css/font-awesome.min.css @@ -0,0 +1,4 @@ +/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.7.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.7.0') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.7.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.7.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-resistance:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-intersex:before,.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-genderless:before{content:"\f22d"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.fa-yc:before,.fa-y-combinator:before{content:"\f23b"}.fa-optin-monster:before{content:"\f23c"}.fa-opencart:before{content:"\f23d"}.fa-expeditedssl:before{content:"\f23e"}.fa-battery-4:before,.fa-battery:before,.fa-battery-full:before{content:"\f240"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-battery-2:before,.fa-battery-half:before{content:"\f242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-mouse-pointer:before{content:"\f245"}.fa-i-cursor:before{content:"\f246"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-sticky-note:before{content:"\f249"}.fa-sticky-note-o:before{content:"\f24a"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-diners-club:before{content:"\f24c"}.fa-clone:before{content:"\f24d"}.fa-balance-scale:before{content:"\f24e"}.fa-hourglass-o:before{content:"\f250"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-hourglass:before{content:"\f254"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255"}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:"\f256"}.fa-hand-scissors-o:before{content:"\f257"}.fa-hand-lizard-o:before{content:"\f258"}.fa-hand-spock-o:before{content:"\f259"}.fa-hand-pointer-o:before{content:"\f25a"}.fa-hand-peace-o:before{content:"\f25b"}.fa-trademark:before{content:"\f25c"}.fa-registered:before{content:"\f25d"}.fa-creative-commons:before{content:"\f25e"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-tripadvisor:before{content:"\f262"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-get-pocket:before{content:"\f265"}.fa-wikipedia-w:before{content:"\f266"}.fa-safari:before{content:"\f267"}.fa-chrome:before{content:"\f268"}.fa-firefox:before{content:"\f269"}.fa-opera:before{content:"\f26a"}.fa-internet-explorer:before{content:"\f26b"}.fa-tv:before,.fa-television:before{content:"\f26c"}.fa-contao:before{content:"\f26d"}.fa-500px:before{content:"\f26e"}.fa-amazon:before{content:"\f270"}.fa-calendar-plus-o:before{content:"\f271"}.fa-calendar-minus-o:before{content:"\f272"}.fa-calendar-times-o:before{content:"\f273"}.fa-calendar-check-o:before{content:"\f274"}.fa-industry:before{content:"\f275"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-map-o:before{content:"\f278"}.fa-map:before{content:"\f279"}.fa-commenting:before{content:"\f27a"}.fa-commenting-o:before{content:"\f27b"}.fa-houzz:before{content:"\f27c"}.fa-vimeo:before{content:"\f27d"}.fa-black-tie:before{content:"\f27e"}.fa-fonticons:before{content:"\f280"}.fa-reddit-alien:before{content:"\f281"}.fa-edge:before{content:"\f282"}.fa-credit-card-alt:before{content:"\f283"}.fa-codiepie:before{content:"\f284"}.fa-modx:before{content:"\f285"}.fa-fort-awesome:before{content:"\f286"}.fa-usb:before{content:"\f287"}.fa-product-hunt:before{content:"\f288"}.fa-mixcloud:before{content:"\f289"}.fa-scribd:before{content:"\f28a"}.fa-pause-circle:before{content:"\f28b"}.fa-pause-circle-o:before{content:"\f28c"}.fa-stop-circle:before{content:"\f28d"}.fa-stop-circle-o:before{content:"\f28e"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-hashtag:before{content:"\f292"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-percent:before{content:"\f295"}.fa-gitlab:before{content:"\f296"}.fa-wpbeginner:before{content:"\f297"}.fa-wpforms:before{content:"\f298"}.fa-envira:before{content:"\f299"}.fa-universal-access:before{content:"\f29a"}.fa-wheelchair-alt:before{content:"\f29b"}.fa-question-circle-o:before{content:"\f29c"}.fa-blind:before{content:"\f29d"}.fa-audio-description:before{content:"\f29e"}.fa-volume-control-phone:before{content:"\f2a0"}.fa-braille:before{content:"\f2a1"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asl-interpreting:before,.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-deafness:before,.fa-hard-of-hearing:before,.fa-deaf:before{content:"\f2a4"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-signing:before,.fa-sign-language:before{content:"\f2a7"}.fa-low-vision:before{content:"\f2a8"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-pied-piper:before{content:"\f2ae"}.fa-first-order:before{content:"\f2b0"}.fa-yoast:before{content:"\f2b1"}.fa-themeisle:before{content:"\f2b2"}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:"\f2b3"}.fa-fa:before,.fa-font-awesome:before{content:"\f2b4"}.fa-handshake-o:before{content:"\f2b5"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-o:before{content:"\f2b7"}.fa-linode:before{content:"\f2b8"}.fa-address-book:before{content:"\f2b9"}.fa-address-book-o:before{content:"\f2ba"}.fa-vcard:before,.fa-address-card:before{content:"\f2bb"}.fa-vcard-o:before,.fa-address-card-o:before{content:"\f2bc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-circle-o:before{content:"\f2be"}.fa-user-o:before{content:"\f2c0"}.fa-id-badge:before{content:"\f2c1"}.fa-drivers-license:before,.fa-id-card:before{content:"\f2c2"}.fa-drivers-license-o:before,.fa-id-card-o:before{content:"\f2c3"}.fa-quora:before{content:"\f2c4"}.fa-free-code-camp:before{content:"\f2c5"}.fa-telegram:before{content:"\f2c6"}.fa-thermometer-4:before,.fa-thermometer:before,.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-thermometer-2:before,.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:"\f2cb"}.fa-shower:before{content:"\f2cc"}.fa-bathtub:before,.fa-s15:before,.fa-bath:before{content:"\f2cd"}.fa-podcast:before{content:"\f2ce"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-times-rectangle:before,.fa-window-close:before{content:"\f2d3"}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:"\f2d4"}.fa-bandcamp:before{content:"\f2d5"}.fa-grav:before{content:"\f2d6"}.fa-etsy:before{content:"\f2d7"}.fa-imdb:before{content:"\f2d8"}.fa-ravelry:before{content:"\f2d9"}.fa-eercast:before{content:"\f2da"}.fa-microchip:before{content:"\f2db"}.fa-snowflake-o:before{content:"\f2dc"}.fa-superpowers:before{content:"\f2dd"}.fa-wpexplorer:before{content:"\f2de"}.fa-meetup:before{content:"\f2e0"}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto} diff --git a/static/font-awesome/fonts/FontAwesome.otf b/static/font-awesome/fonts/FontAwesome.otf new file mode 100644 index 0000000..401ec0f Binary files /dev/null and b/static/font-awesome/fonts/FontAwesome.otf differ diff --git a/static/font-awesome/fonts/fontawesome-webfont.eot b/static/font-awesome/fonts/fontawesome-webfont.eot new file mode 100644 index 0000000..e9f60ca Binary files /dev/null and b/static/font-awesome/fonts/fontawesome-webfont.eot differ diff --git a/static/font-awesome/fonts/fontawesome-webfont.svg b/static/font-awesome/fonts/fontawesome-webfont.svg new file mode 100644 index 0000000..855c845 --- /dev/null +++ b/static/font-awesome/fonts/fontawesome-webfont.svg @@ -0,0 +1,2671 @@ + + + + +Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 + By ,,, +Copyright Dave Gandy 2016. All rights reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/static/font-awesome/fonts/fontawesome-webfont.ttf b/static/font-awesome/fonts/fontawesome-webfont.ttf new file mode 100644 index 0000000..35acda2 Binary files /dev/null and b/static/font-awesome/fonts/fontawesome-webfont.ttf differ diff --git a/static/font-awesome/fonts/fontawesome-webfont.woff b/static/font-awesome/fonts/fontawesome-webfont.woff new file mode 100644 index 0000000..400014a Binary files /dev/null and b/static/font-awesome/fonts/fontawesome-webfont.woff differ diff --git a/static/font-awesome/fonts/fontawesome-webfont.woff2 b/static/font-awesome/fonts/fontawesome-webfont.woff2 new file mode 100644 index 0000000..4d13fc6 Binary files /dev/null and b/static/font-awesome/fonts/fontawesome-webfont.woff2 differ diff --git a/static/font-awesome/less/animated.less b/static/font-awesome/less/animated.less new file mode 100644 index 0000000..66ad52a --- /dev/null +++ b/static/font-awesome/less/animated.less @@ -0,0 +1,34 @@ +// Animated Icons +// -------------------------- + +.@{fa-css-prefix}-spin { + -webkit-animation: fa-spin 2s infinite linear; + animation: fa-spin 2s infinite linear; +} + +.@{fa-css-prefix}-pulse { + -webkit-animation: fa-spin 1s infinite steps(8); + animation: fa-spin 1s infinite steps(8); +} + +@-webkit-keyframes fa-spin { + 0% { + -webkit-transform: rotate(0deg); + 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); + } +} diff --git a/static/font-awesome/less/bordered-pulled.less b/static/font-awesome/less/bordered-pulled.less new file mode 100644 index 0000000..f1c8ad7 --- /dev/null +++ b/static/font-awesome/less/bordered-pulled.less @@ -0,0 +1,25 @@ +// Bordered & Pulled +// ------------------------- + +.@{fa-css-prefix}-border { + padding: .2em .25em .15em; + border: solid .08em @fa-border-color; + border-radius: .1em; +} + +.@{fa-css-prefix}-pull-left { float: left; } +.@{fa-css-prefix}-pull-right { float: right; } + +.@{fa-css-prefix} { + &.@{fa-css-prefix}-pull-left { margin-right: .3em; } + &.@{fa-css-prefix}-pull-right { margin-left: .3em; } +} + +/* Deprecated as of 4.4.0 */ +.pull-right { float: right; } +.pull-left { float: left; } + +.@{fa-css-prefix} { + &.pull-left { margin-right: .3em; } + &.pull-right { margin-left: .3em; } +} diff --git a/static/font-awesome/less/core.less b/static/font-awesome/less/core.less new file mode 100644 index 0000000..c577ac8 --- /dev/null +++ b/static/font-awesome/less/core.less @@ -0,0 +1,12 @@ +// Base Class Definition +// ------------------------- + +.@{fa-css-prefix} { + display: inline-block; + font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration + font-size: inherit; // can't have font-size inherit on line above, so need to override + text-rendering: auto; // optimizelegibility throws things off #1094 + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + +} diff --git a/static/font-awesome/less/fixed-width.less b/static/font-awesome/less/fixed-width.less new file mode 100644 index 0000000..110289f --- /dev/null +++ b/static/font-awesome/less/fixed-width.less @@ -0,0 +1,6 @@ +// Fixed Width Icons +// ------------------------- +.@{fa-css-prefix}-fw { + width: (18em / 14); + text-align: center; +} diff --git a/static/font-awesome/less/font-awesome.less b/static/font-awesome/less/font-awesome.less new file mode 100644 index 0000000..c3677de --- /dev/null +++ b/static/font-awesome/less/font-awesome.less @@ -0,0 +1,18 @@ +/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */ + +@import "variables.less"; +@import "mixins.less"; +@import "path.less"; +@import "core.less"; +@import "larger.less"; +@import "fixed-width.less"; +@import "list.less"; +@import "bordered-pulled.less"; +@import "animated.less"; +@import "rotated-flipped.less"; +@import "stacked.less"; +@import "icons.less"; +@import "screen-reader.less"; diff --git a/static/font-awesome/less/icons.less b/static/font-awesome/less/icons.less new file mode 100644 index 0000000..159d600 --- /dev/null +++ b/static/font-awesome/less/icons.less @@ -0,0 +1,789 @@ +/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen + readers do not read off random characters that represent icons */ + +.@{fa-css-prefix}-glass:before { content: @fa-var-glass; } +.@{fa-css-prefix}-music:before { content: @fa-var-music; } +.@{fa-css-prefix}-search:before { content: @fa-var-search; } +.@{fa-css-prefix}-envelope-o:before { content: @fa-var-envelope-o; } +.@{fa-css-prefix}-heart:before { content: @fa-var-heart; } +.@{fa-css-prefix}-star:before { content: @fa-var-star; } +.@{fa-css-prefix}-star-o:before { content: @fa-var-star-o; } +.@{fa-css-prefix}-user:before { content: @fa-var-user; } +.@{fa-css-prefix}-film:before { content: @fa-var-film; } +.@{fa-css-prefix}-th-large:before { content: @fa-var-th-large; } +.@{fa-css-prefix}-th:before { content: @fa-var-th; } +.@{fa-css-prefix}-th-list:before { content: @fa-var-th-list; } +.@{fa-css-prefix}-check:before { content: @fa-var-check; } +.@{fa-css-prefix}-remove:before, +.@{fa-css-prefix}-close:before, +.@{fa-css-prefix}-times:before { content: @fa-var-times; } +.@{fa-css-prefix}-search-plus:before { content: @fa-var-search-plus; } +.@{fa-css-prefix}-search-minus:before { content: @fa-var-search-minus; } +.@{fa-css-prefix}-power-off:before { content: @fa-var-power-off; } +.@{fa-css-prefix}-signal:before { content: @fa-var-signal; } +.@{fa-css-prefix}-gear:before, +.@{fa-css-prefix}-cog:before { content: @fa-var-cog; } +.@{fa-css-prefix}-trash-o:before { content: @fa-var-trash-o; } +.@{fa-css-prefix}-home:before { content: @fa-var-home; } +.@{fa-css-prefix}-file-o:before { content: @fa-var-file-o; } +.@{fa-css-prefix}-clock-o:before { content: @fa-var-clock-o; } +.@{fa-css-prefix}-road:before { content: @fa-var-road; } +.@{fa-css-prefix}-download:before { content: @fa-var-download; } +.@{fa-css-prefix}-arrow-circle-o-down:before { content: @fa-var-arrow-circle-o-down; } +.@{fa-css-prefix}-arrow-circle-o-up:before { content: @fa-var-arrow-circle-o-up; } +.@{fa-css-prefix}-inbox:before { content: @fa-var-inbox; } +.@{fa-css-prefix}-play-circle-o:before { content: @fa-var-play-circle-o; } +.@{fa-css-prefix}-rotate-right:before, +.@{fa-css-prefix}-repeat:before { content: @fa-var-repeat; } +.@{fa-css-prefix}-refresh:before { content: @fa-var-refresh; } +.@{fa-css-prefix}-list-alt:before { content: @fa-var-list-alt; } +.@{fa-css-prefix}-lock:before { content: @fa-var-lock; } +.@{fa-css-prefix}-flag:before { content: @fa-var-flag; } +.@{fa-css-prefix}-headphones:before { content: @fa-var-headphones; } +.@{fa-css-prefix}-volume-off:before { content: @fa-var-volume-off; } +.@{fa-css-prefix}-volume-down:before { content: @fa-var-volume-down; } +.@{fa-css-prefix}-volume-up:before { content: @fa-var-volume-up; } +.@{fa-css-prefix}-qrcode:before { content: @fa-var-qrcode; } +.@{fa-css-prefix}-barcode:before { content: @fa-var-barcode; } +.@{fa-css-prefix}-tag:before { content: @fa-var-tag; } +.@{fa-css-prefix}-tags:before { content: @fa-var-tags; } +.@{fa-css-prefix}-book:before { content: @fa-var-book; } +.@{fa-css-prefix}-bookmark:before { content: @fa-var-bookmark; } +.@{fa-css-prefix}-print:before { content: @fa-var-print; } +.@{fa-css-prefix}-camera:before { content: @fa-var-camera; } +.@{fa-css-prefix}-font:before { content: @fa-var-font; } +.@{fa-css-prefix}-bold:before { content: @fa-var-bold; } +.@{fa-css-prefix}-italic:before { content: @fa-var-italic; } +.@{fa-css-prefix}-text-height:before { content: @fa-var-text-height; } +.@{fa-css-prefix}-text-width:before { content: @fa-var-text-width; } +.@{fa-css-prefix}-align-left:before { content: @fa-var-align-left; } +.@{fa-css-prefix}-align-center:before { content: @fa-var-align-center; } +.@{fa-css-prefix}-align-right:before { content: @fa-var-align-right; } +.@{fa-css-prefix}-align-justify:before { content: @fa-var-align-justify; } +.@{fa-css-prefix}-list:before { content: @fa-var-list; } +.@{fa-css-prefix}-dedent:before, +.@{fa-css-prefix}-outdent:before { content: @fa-var-outdent; } +.@{fa-css-prefix}-indent:before { content: @fa-var-indent; } +.@{fa-css-prefix}-video-camera:before { content: @fa-var-video-camera; } +.@{fa-css-prefix}-photo:before, +.@{fa-css-prefix}-image:before, +.@{fa-css-prefix}-picture-o:before { content: @fa-var-picture-o; } +.@{fa-css-prefix}-pencil:before { content: @fa-var-pencil; } +.@{fa-css-prefix}-map-marker:before { content: @fa-var-map-marker; } +.@{fa-css-prefix}-adjust:before { content: @fa-var-adjust; } +.@{fa-css-prefix}-tint:before { content: @fa-var-tint; } +.@{fa-css-prefix}-edit:before, +.@{fa-css-prefix}-pencil-square-o:before { content: @fa-var-pencil-square-o; } +.@{fa-css-prefix}-share-square-o:before { content: @fa-var-share-square-o; } +.@{fa-css-prefix}-check-square-o:before { content: @fa-var-check-square-o; } +.@{fa-css-prefix}-arrows:before { content: @fa-var-arrows; } +.@{fa-css-prefix}-step-backward:before { content: @fa-var-step-backward; } +.@{fa-css-prefix}-fast-backward:before { content: @fa-var-fast-backward; } +.@{fa-css-prefix}-backward:before { content: @fa-var-backward; } +.@{fa-css-prefix}-play:before { content: @fa-var-play; } +.@{fa-css-prefix}-pause:before { content: @fa-var-pause; } +.@{fa-css-prefix}-stop:before { content: @fa-var-stop; } +.@{fa-css-prefix}-forward:before { content: @fa-var-forward; } +.@{fa-css-prefix}-fast-forward:before { content: @fa-var-fast-forward; } +.@{fa-css-prefix}-step-forward:before { content: @fa-var-step-forward; } +.@{fa-css-prefix}-eject:before { content: @fa-var-eject; } +.@{fa-css-prefix}-chevron-left:before { content: @fa-var-chevron-left; } +.@{fa-css-prefix}-chevron-right:before { content: @fa-var-chevron-right; } +.@{fa-css-prefix}-plus-circle:before { content: @fa-var-plus-circle; } +.@{fa-css-prefix}-minus-circle:before { content: @fa-var-minus-circle; } +.@{fa-css-prefix}-times-circle:before { content: @fa-var-times-circle; } +.@{fa-css-prefix}-check-circle:before { content: @fa-var-check-circle; } +.@{fa-css-prefix}-question-circle:before { content: @fa-var-question-circle; } +.@{fa-css-prefix}-info-circle:before { content: @fa-var-info-circle; } +.@{fa-css-prefix}-crosshairs:before { content: @fa-var-crosshairs; } +.@{fa-css-prefix}-times-circle-o:before { content: @fa-var-times-circle-o; } +.@{fa-css-prefix}-check-circle-o:before { content: @fa-var-check-circle-o; } +.@{fa-css-prefix}-ban:before { content: @fa-var-ban; } +.@{fa-css-prefix}-arrow-left:before { content: @fa-var-arrow-left; } +.@{fa-css-prefix}-arrow-right:before { content: @fa-var-arrow-right; } +.@{fa-css-prefix}-arrow-up:before { content: @fa-var-arrow-up; } +.@{fa-css-prefix}-arrow-down:before { content: @fa-var-arrow-down; } +.@{fa-css-prefix}-mail-forward:before, +.@{fa-css-prefix}-share:before { content: @fa-var-share; } +.@{fa-css-prefix}-expand:before { content: @fa-var-expand; } +.@{fa-css-prefix}-compress:before { content: @fa-var-compress; } +.@{fa-css-prefix}-plus:before { content: @fa-var-plus; } +.@{fa-css-prefix}-minus:before { content: @fa-var-minus; } +.@{fa-css-prefix}-asterisk:before { content: @fa-var-asterisk; } +.@{fa-css-prefix}-exclamation-circle:before { content: @fa-var-exclamation-circle; } +.@{fa-css-prefix}-gift:before { content: @fa-var-gift; } +.@{fa-css-prefix}-leaf:before { content: @fa-var-leaf; } +.@{fa-css-prefix}-fire:before { content: @fa-var-fire; } +.@{fa-css-prefix}-eye:before { content: @fa-var-eye; } +.@{fa-css-prefix}-eye-slash:before { content: @fa-var-eye-slash; } +.@{fa-css-prefix}-warning:before, +.@{fa-css-prefix}-exclamation-triangle:before { content: @fa-var-exclamation-triangle; } +.@{fa-css-prefix}-plane:before { content: @fa-var-plane; } +.@{fa-css-prefix}-calendar:before { content: @fa-var-calendar; } +.@{fa-css-prefix}-random:before { content: @fa-var-random; } +.@{fa-css-prefix}-comment:before { content: @fa-var-comment; } +.@{fa-css-prefix}-magnet:before { content: @fa-var-magnet; } +.@{fa-css-prefix}-chevron-up:before { content: @fa-var-chevron-up; } +.@{fa-css-prefix}-chevron-down:before { content: @fa-var-chevron-down; } +.@{fa-css-prefix}-retweet:before { content: @fa-var-retweet; } +.@{fa-css-prefix}-shopping-cart:before { content: @fa-var-shopping-cart; } +.@{fa-css-prefix}-folder:before { content: @fa-var-folder; } +.@{fa-css-prefix}-folder-open:before { content: @fa-var-folder-open; } +.@{fa-css-prefix}-arrows-v:before { content: @fa-var-arrows-v; } +.@{fa-css-prefix}-arrows-h:before { content: @fa-var-arrows-h; } +.@{fa-css-prefix}-bar-chart-o:before, +.@{fa-css-prefix}-bar-chart:before { content: @fa-var-bar-chart; } +.@{fa-css-prefix}-twitter-square:before { content: @fa-var-twitter-square; } +.@{fa-css-prefix}-facebook-square:before { content: @fa-var-facebook-square; } +.@{fa-css-prefix}-camera-retro:before { content: @fa-var-camera-retro; } +.@{fa-css-prefix}-key:before { content: @fa-var-key; } +.@{fa-css-prefix}-gears:before, +.@{fa-css-prefix}-cogs:before { content: @fa-var-cogs; } +.@{fa-css-prefix}-comments:before { content: @fa-var-comments; } +.@{fa-css-prefix}-thumbs-o-up:before { content: @fa-var-thumbs-o-up; } +.@{fa-css-prefix}-thumbs-o-down:before { content: @fa-var-thumbs-o-down; } +.@{fa-css-prefix}-star-half:before { content: @fa-var-star-half; } +.@{fa-css-prefix}-heart-o:before { content: @fa-var-heart-o; } +.@{fa-css-prefix}-sign-out:before { content: @fa-var-sign-out; } +.@{fa-css-prefix}-linkedin-square:before { content: @fa-var-linkedin-square; } +.@{fa-css-prefix}-thumb-tack:before { content: @fa-var-thumb-tack; } +.@{fa-css-prefix}-external-link:before { content: @fa-var-external-link; } +.@{fa-css-prefix}-sign-in:before { content: @fa-var-sign-in; } +.@{fa-css-prefix}-trophy:before { content: @fa-var-trophy; } +.@{fa-css-prefix}-github-square:before { content: @fa-var-github-square; } +.@{fa-css-prefix}-upload:before { content: @fa-var-upload; } +.@{fa-css-prefix}-lemon-o:before { content: @fa-var-lemon-o; } +.@{fa-css-prefix}-phone:before { content: @fa-var-phone; } +.@{fa-css-prefix}-square-o:before { content: @fa-var-square-o; } +.@{fa-css-prefix}-bookmark-o:before { content: @fa-var-bookmark-o; } +.@{fa-css-prefix}-phone-square:before { content: @fa-var-phone-square; } +.@{fa-css-prefix}-twitter:before { content: @fa-var-twitter; } +.@{fa-css-prefix}-facebook-f:before, +.@{fa-css-prefix}-facebook:before { content: @fa-var-facebook; } +.@{fa-css-prefix}-github:before { content: @fa-var-github; } +.@{fa-css-prefix}-unlock:before { content: @fa-var-unlock; } +.@{fa-css-prefix}-credit-card:before { content: @fa-var-credit-card; } +.@{fa-css-prefix}-feed:before, +.@{fa-css-prefix}-rss:before { content: @fa-var-rss; } +.@{fa-css-prefix}-hdd-o:before { content: @fa-var-hdd-o; } +.@{fa-css-prefix}-bullhorn:before { content: @fa-var-bullhorn; } +.@{fa-css-prefix}-bell:before { content: @fa-var-bell; } +.@{fa-css-prefix}-certificate:before { content: @fa-var-certificate; } +.@{fa-css-prefix}-hand-o-right:before { content: @fa-var-hand-o-right; } +.@{fa-css-prefix}-hand-o-left:before { content: @fa-var-hand-o-left; } +.@{fa-css-prefix}-hand-o-up:before { content: @fa-var-hand-o-up; } +.@{fa-css-prefix}-hand-o-down:before { content: @fa-var-hand-o-down; } +.@{fa-css-prefix}-arrow-circle-left:before { content: @fa-var-arrow-circle-left; } +.@{fa-css-prefix}-arrow-circle-right:before { content: @fa-var-arrow-circle-right; } +.@{fa-css-prefix}-arrow-circle-up:before { content: @fa-var-arrow-circle-up; } +.@{fa-css-prefix}-arrow-circle-down:before { content: @fa-var-arrow-circle-down; } +.@{fa-css-prefix}-globe:before { content: @fa-var-globe; } +.@{fa-css-prefix}-wrench:before { content: @fa-var-wrench; } +.@{fa-css-prefix}-tasks:before { content: @fa-var-tasks; } +.@{fa-css-prefix}-filter:before { content: @fa-var-filter; } +.@{fa-css-prefix}-briefcase:before { content: @fa-var-briefcase; } +.@{fa-css-prefix}-arrows-alt:before { content: @fa-var-arrows-alt; } +.@{fa-css-prefix}-group:before, +.@{fa-css-prefix}-users:before { content: @fa-var-users; } +.@{fa-css-prefix}-chain:before, +.@{fa-css-prefix}-link:before { content: @fa-var-link; } +.@{fa-css-prefix}-cloud:before { content: @fa-var-cloud; } +.@{fa-css-prefix}-flask:before { content: @fa-var-flask; } +.@{fa-css-prefix}-cut:before, +.@{fa-css-prefix}-scissors:before { content: @fa-var-scissors; } +.@{fa-css-prefix}-copy:before, +.@{fa-css-prefix}-files-o:before { content: @fa-var-files-o; } +.@{fa-css-prefix}-paperclip:before { content: @fa-var-paperclip; } +.@{fa-css-prefix}-save:before, +.@{fa-css-prefix}-floppy-o:before { content: @fa-var-floppy-o; } +.@{fa-css-prefix}-square:before { content: @fa-var-square; } +.@{fa-css-prefix}-navicon:before, +.@{fa-css-prefix}-reorder:before, +.@{fa-css-prefix}-bars:before { content: @fa-var-bars; } +.@{fa-css-prefix}-list-ul:before { content: @fa-var-list-ul; } +.@{fa-css-prefix}-list-ol:before { content: @fa-var-list-ol; } +.@{fa-css-prefix}-strikethrough:before { content: @fa-var-strikethrough; } +.@{fa-css-prefix}-underline:before { content: @fa-var-underline; } +.@{fa-css-prefix}-table:before { content: @fa-var-table; } +.@{fa-css-prefix}-magic:before { content: @fa-var-magic; } +.@{fa-css-prefix}-truck:before { content: @fa-var-truck; } +.@{fa-css-prefix}-pinterest:before { content: @fa-var-pinterest; } +.@{fa-css-prefix}-pinterest-square:before { content: @fa-var-pinterest-square; } +.@{fa-css-prefix}-google-plus-square:before { content: @fa-var-google-plus-square; } +.@{fa-css-prefix}-google-plus:before { content: @fa-var-google-plus; } +.@{fa-css-prefix}-money:before { content: @fa-var-money; } +.@{fa-css-prefix}-caret-down:before { content: @fa-var-caret-down; } +.@{fa-css-prefix}-caret-up:before { content: @fa-var-caret-up; } +.@{fa-css-prefix}-caret-left:before { content: @fa-var-caret-left; } +.@{fa-css-prefix}-caret-right:before { content: @fa-var-caret-right; } +.@{fa-css-prefix}-columns:before { content: @fa-var-columns; } +.@{fa-css-prefix}-unsorted:before, +.@{fa-css-prefix}-sort:before { content: @fa-var-sort; } +.@{fa-css-prefix}-sort-down:before, +.@{fa-css-prefix}-sort-desc:before { content: @fa-var-sort-desc; } +.@{fa-css-prefix}-sort-up:before, +.@{fa-css-prefix}-sort-asc:before { content: @fa-var-sort-asc; } +.@{fa-css-prefix}-envelope:before { content: @fa-var-envelope; } +.@{fa-css-prefix}-linkedin:before { content: @fa-var-linkedin; } +.@{fa-css-prefix}-rotate-left:before, +.@{fa-css-prefix}-undo:before { content: @fa-var-undo; } +.@{fa-css-prefix}-legal:before, +.@{fa-css-prefix}-gavel:before { content: @fa-var-gavel; } +.@{fa-css-prefix}-dashboard:before, +.@{fa-css-prefix}-tachometer:before { content: @fa-var-tachometer; } +.@{fa-css-prefix}-comment-o:before { content: @fa-var-comment-o; } +.@{fa-css-prefix}-comments-o:before { content: @fa-var-comments-o; } +.@{fa-css-prefix}-flash:before, +.@{fa-css-prefix}-bolt:before { content: @fa-var-bolt; } +.@{fa-css-prefix}-sitemap:before { content: @fa-var-sitemap; } +.@{fa-css-prefix}-umbrella:before { content: @fa-var-umbrella; } +.@{fa-css-prefix}-paste:before, +.@{fa-css-prefix}-clipboard:before { content: @fa-var-clipboard; } +.@{fa-css-prefix}-lightbulb-o:before { content: @fa-var-lightbulb-o; } +.@{fa-css-prefix}-exchange:before { content: @fa-var-exchange; } +.@{fa-css-prefix}-cloud-download:before { content: @fa-var-cloud-download; } +.@{fa-css-prefix}-cloud-upload:before { content: @fa-var-cloud-upload; } +.@{fa-css-prefix}-user-md:before { content: @fa-var-user-md; } +.@{fa-css-prefix}-stethoscope:before { content: @fa-var-stethoscope; } +.@{fa-css-prefix}-suitcase:before { content: @fa-var-suitcase; } +.@{fa-css-prefix}-bell-o:before { content: @fa-var-bell-o; } +.@{fa-css-prefix}-coffee:before { content: @fa-var-coffee; } +.@{fa-css-prefix}-cutlery:before { content: @fa-var-cutlery; } +.@{fa-css-prefix}-file-text-o:before { content: @fa-var-file-text-o; } +.@{fa-css-prefix}-building-o:before { content: @fa-var-building-o; } +.@{fa-css-prefix}-hospital-o:before { content: @fa-var-hospital-o; } +.@{fa-css-prefix}-ambulance:before { content: @fa-var-ambulance; } +.@{fa-css-prefix}-medkit:before { content: @fa-var-medkit; } +.@{fa-css-prefix}-fighter-jet:before { content: @fa-var-fighter-jet; } +.@{fa-css-prefix}-beer:before { content: @fa-var-beer; } +.@{fa-css-prefix}-h-square:before { content: @fa-var-h-square; } +.@{fa-css-prefix}-plus-square:before { content: @fa-var-plus-square; } +.@{fa-css-prefix}-angle-double-left:before { content: @fa-var-angle-double-left; } +.@{fa-css-prefix}-angle-double-right:before { content: @fa-var-angle-double-right; } +.@{fa-css-prefix}-angle-double-up:before { content: @fa-var-angle-double-up; } +.@{fa-css-prefix}-angle-double-down:before { content: @fa-var-angle-double-down; } +.@{fa-css-prefix}-angle-left:before { content: @fa-var-angle-left; } +.@{fa-css-prefix}-angle-right:before { content: @fa-var-angle-right; } +.@{fa-css-prefix}-angle-up:before { content: @fa-var-angle-up; } +.@{fa-css-prefix}-angle-down:before { content: @fa-var-angle-down; } +.@{fa-css-prefix}-desktop:before { content: @fa-var-desktop; } +.@{fa-css-prefix}-laptop:before { content: @fa-var-laptop; } +.@{fa-css-prefix}-tablet:before { content: @fa-var-tablet; } +.@{fa-css-prefix}-mobile-phone:before, +.@{fa-css-prefix}-mobile:before { content: @fa-var-mobile; } +.@{fa-css-prefix}-circle-o:before { content: @fa-var-circle-o; } +.@{fa-css-prefix}-quote-left:before { content: @fa-var-quote-left; } +.@{fa-css-prefix}-quote-right:before { content: @fa-var-quote-right; } +.@{fa-css-prefix}-spinner:before { content: @fa-var-spinner; } +.@{fa-css-prefix}-circle:before { content: @fa-var-circle; } +.@{fa-css-prefix}-mail-reply:before, +.@{fa-css-prefix}-reply:before { content: @fa-var-reply; } +.@{fa-css-prefix}-github-alt:before { content: @fa-var-github-alt; } +.@{fa-css-prefix}-folder-o:before { content: @fa-var-folder-o; } +.@{fa-css-prefix}-folder-open-o:before { content: @fa-var-folder-open-o; } +.@{fa-css-prefix}-smile-o:before { content: @fa-var-smile-o; } +.@{fa-css-prefix}-frown-o:before { content: @fa-var-frown-o; } +.@{fa-css-prefix}-meh-o:before { content: @fa-var-meh-o; } +.@{fa-css-prefix}-gamepad:before { content: @fa-var-gamepad; } +.@{fa-css-prefix}-keyboard-o:before { content: @fa-var-keyboard-o; } +.@{fa-css-prefix}-flag-o:before { content: @fa-var-flag-o; } +.@{fa-css-prefix}-flag-checkered:before { content: @fa-var-flag-checkered; } +.@{fa-css-prefix}-terminal:before { content: @fa-var-terminal; } +.@{fa-css-prefix}-code:before { content: @fa-var-code; } +.@{fa-css-prefix}-mail-reply-all:before, +.@{fa-css-prefix}-reply-all:before { content: @fa-var-reply-all; } +.@{fa-css-prefix}-star-half-empty:before, +.@{fa-css-prefix}-star-half-full:before, +.@{fa-css-prefix}-star-half-o:before { content: @fa-var-star-half-o; } +.@{fa-css-prefix}-location-arrow:before { content: @fa-var-location-arrow; } +.@{fa-css-prefix}-crop:before { content: @fa-var-crop; } +.@{fa-css-prefix}-code-fork:before { content: @fa-var-code-fork; } +.@{fa-css-prefix}-unlink:before, +.@{fa-css-prefix}-chain-broken:before { content: @fa-var-chain-broken; } +.@{fa-css-prefix}-question:before { content: @fa-var-question; } +.@{fa-css-prefix}-info:before { content: @fa-var-info; } +.@{fa-css-prefix}-exclamation:before { content: @fa-var-exclamation; } +.@{fa-css-prefix}-superscript:before { content: @fa-var-superscript; } +.@{fa-css-prefix}-subscript:before { content: @fa-var-subscript; } +.@{fa-css-prefix}-eraser:before { content: @fa-var-eraser; } +.@{fa-css-prefix}-puzzle-piece:before { content: @fa-var-puzzle-piece; } +.@{fa-css-prefix}-microphone:before { content: @fa-var-microphone; } +.@{fa-css-prefix}-microphone-slash:before { content: @fa-var-microphone-slash; } +.@{fa-css-prefix}-shield:before { content: @fa-var-shield; } +.@{fa-css-prefix}-calendar-o:before { content: @fa-var-calendar-o; } +.@{fa-css-prefix}-fire-extinguisher:before { content: @fa-var-fire-extinguisher; } +.@{fa-css-prefix}-rocket:before { content: @fa-var-rocket; } +.@{fa-css-prefix}-maxcdn:before { content: @fa-var-maxcdn; } +.@{fa-css-prefix}-chevron-circle-left:before { content: @fa-var-chevron-circle-left; } +.@{fa-css-prefix}-chevron-circle-right:before { content: @fa-var-chevron-circle-right; } +.@{fa-css-prefix}-chevron-circle-up:before { content: @fa-var-chevron-circle-up; } +.@{fa-css-prefix}-chevron-circle-down:before { content: @fa-var-chevron-circle-down; } +.@{fa-css-prefix}-html5:before { content: @fa-var-html5; } +.@{fa-css-prefix}-css3:before { content: @fa-var-css3; } +.@{fa-css-prefix}-anchor:before { content: @fa-var-anchor; } +.@{fa-css-prefix}-unlock-alt:before { content: @fa-var-unlock-alt; } +.@{fa-css-prefix}-bullseye:before { content: @fa-var-bullseye; } +.@{fa-css-prefix}-ellipsis-h:before { content: @fa-var-ellipsis-h; } +.@{fa-css-prefix}-ellipsis-v:before { content: @fa-var-ellipsis-v; } +.@{fa-css-prefix}-rss-square:before { content: @fa-var-rss-square; } +.@{fa-css-prefix}-play-circle:before { content: @fa-var-play-circle; } +.@{fa-css-prefix}-ticket:before { content: @fa-var-ticket; } +.@{fa-css-prefix}-minus-square:before { content: @fa-var-minus-square; } +.@{fa-css-prefix}-minus-square-o:before { content: @fa-var-minus-square-o; } +.@{fa-css-prefix}-level-up:before { content: @fa-var-level-up; } +.@{fa-css-prefix}-level-down:before { content: @fa-var-level-down; } +.@{fa-css-prefix}-check-square:before { content: @fa-var-check-square; } +.@{fa-css-prefix}-pencil-square:before { content: @fa-var-pencil-square; } +.@{fa-css-prefix}-external-link-square:before { content: @fa-var-external-link-square; } +.@{fa-css-prefix}-share-square:before { content: @fa-var-share-square; } +.@{fa-css-prefix}-compass:before { content: @fa-var-compass; } +.@{fa-css-prefix}-toggle-down:before, +.@{fa-css-prefix}-caret-square-o-down:before { content: @fa-var-caret-square-o-down; } +.@{fa-css-prefix}-toggle-up:before, +.@{fa-css-prefix}-caret-square-o-up:before { content: @fa-var-caret-square-o-up; } +.@{fa-css-prefix}-toggle-right:before, +.@{fa-css-prefix}-caret-square-o-right:before { content: @fa-var-caret-square-o-right; } +.@{fa-css-prefix}-euro:before, +.@{fa-css-prefix}-eur:before { content: @fa-var-eur; } +.@{fa-css-prefix}-gbp:before { content: @fa-var-gbp; } +.@{fa-css-prefix}-dollar:before, +.@{fa-css-prefix}-usd:before { content: @fa-var-usd; } +.@{fa-css-prefix}-rupee:before, +.@{fa-css-prefix}-inr:before { content: @fa-var-inr; } +.@{fa-css-prefix}-cny:before, +.@{fa-css-prefix}-rmb:before, +.@{fa-css-prefix}-yen:before, +.@{fa-css-prefix}-jpy:before { content: @fa-var-jpy; } +.@{fa-css-prefix}-ruble:before, +.@{fa-css-prefix}-rouble:before, +.@{fa-css-prefix}-rub:before { content: @fa-var-rub; } +.@{fa-css-prefix}-won:before, +.@{fa-css-prefix}-krw:before { content: @fa-var-krw; } +.@{fa-css-prefix}-bitcoin:before, +.@{fa-css-prefix}-btc:before { content: @fa-var-btc; } +.@{fa-css-prefix}-file:before { content: @fa-var-file; } +.@{fa-css-prefix}-file-text:before { content: @fa-var-file-text; } +.@{fa-css-prefix}-sort-alpha-asc:before { content: @fa-var-sort-alpha-asc; } +.@{fa-css-prefix}-sort-alpha-desc:before { content: @fa-var-sort-alpha-desc; } +.@{fa-css-prefix}-sort-amount-asc:before { content: @fa-var-sort-amount-asc; } +.@{fa-css-prefix}-sort-amount-desc:before { content: @fa-var-sort-amount-desc; } +.@{fa-css-prefix}-sort-numeric-asc:before { content: @fa-var-sort-numeric-asc; } +.@{fa-css-prefix}-sort-numeric-desc:before { content: @fa-var-sort-numeric-desc; } +.@{fa-css-prefix}-thumbs-up:before { content: @fa-var-thumbs-up; } +.@{fa-css-prefix}-thumbs-down:before { content: @fa-var-thumbs-down; } +.@{fa-css-prefix}-youtube-square:before { content: @fa-var-youtube-square; } +.@{fa-css-prefix}-youtube:before { content: @fa-var-youtube; } +.@{fa-css-prefix}-xing:before { content: @fa-var-xing; } +.@{fa-css-prefix}-xing-square:before { content: @fa-var-xing-square; } +.@{fa-css-prefix}-youtube-play:before { content: @fa-var-youtube-play; } +.@{fa-css-prefix}-dropbox:before { content: @fa-var-dropbox; } +.@{fa-css-prefix}-stack-overflow:before { content: @fa-var-stack-overflow; } +.@{fa-css-prefix}-instagram:before { content: @fa-var-instagram; } +.@{fa-css-prefix}-flickr:before { content: @fa-var-flickr; } +.@{fa-css-prefix}-adn:before { content: @fa-var-adn; } +.@{fa-css-prefix}-bitbucket:before { content: @fa-var-bitbucket; } +.@{fa-css-prefix}-bitbucket-square:before { content: @fa-var-bitbucket-square; } +.@{fa-css-prefix}-tumblr:before { content: @fa-var-tumblr; } +.@{fa-css-prefix}-tumblr-square:before { content: @fa-var-tumblr-square; } +.@{fa-css-prefix}-long-arrow-down:before { content: @fa-var-long-arrow-down; } +.@{fa-css-prefix}-long-arrow-up:before { content: @fa-var-long-arrow-up; } +.@{fa-css-prefix}-long-arrow-left:before { content: @fa-var-long-arrow-left; } +.@{fa-css-prefix}-long-arrow-right:before { content: @fa-var-long-arrow-right; } +.@{fa-css-prefix}-apple:before { content: @fa-var-apple; } +.@{fa-css-prefix}-windows:before { content: @fa-var-windows; } +.@{fa-css-prefix}-android:before { content: @fa-var-android; } +.@{fa-css-prefix}-linux:before { content: @fa-var-linux; } +.@{fa-css-prefix}-dribbble:before { content: @fa-var-dribbble; } +.@{fa-css-prefix}-skype:before { content: @fa-var-skype; } +.@{fa-css-prefix}-foursquare:before { content: @fa-var-foursquare; } +.@{fa-css-prefix}-trello:before { content: @fa-var-trello; } +.@{fa-css-prefix}-female:before { content: @fa-var-female; } +.@{fa-css-prefix}-male:before { content: @fa-var-male; } +.@{fa-css-prefix}-gittip:before, +.@{fa-css-prefix}-gratipay:before { content: @fa-var-gratipay; } +.@{fa-css-prefix}-sun-o:before { content: @fa-var-sun-o; } +.@{fa-css-prefix}-moon-o:before { content: @fa-var-moon-o; } +.@{fa-css-prefix}-archive:before { content: @fa-var-archive; } +.@{fa-css-prefix}-bug:before { content: @fa-var-bug; } +.@{fa-css-prefix}-vk:before { content: @fa-var-vk; } +.@{fa-css-prefix}-weibo:before { content: @fa-var-weibo; } +.@{fa-css-prefix}-renren:before { content: @fa-var-renren; } +.@{fa-css-prefix}-pagelines:before { content: @fa-var-pagelines; } +.@{fa-css-prefix}-stack-exchange:before { content: @fa-var-stack-exchange; } +.@{fa-css-prefix}-arrow-circle-o-right:before { content: @fa-var-arrow-circle-o-right; } +.@{fa-css-prefix}-arrow-circle-o-left:before { content: @fa-var-arrow-circle-o-left; } +.@{fa-css-prefix}-toggle-left:before, +.@{fa-css-prefix}-caret-square-o-left:before { content: @fa-var-caret-square-o-left; } +.@{fa-css-prefix}-dot-circle-o:before { content: @fa-var-dot-circle-o; } +.@{fa-css-prefix}-wheelchair:before { content: @fa-var-wheelchair; } +.@{fa-css-prefix}-vimeo-square:before { content: @fa-var-vimeo-square; } +.@{fa-css-prefix}-turkish-lira:before, +.@{fa-css-prefix}-try:before { content: @fa-var-try; } +.@{fa-css-prefix}-plus-square-o:before { content: @fa-var-plus-square-o; } +.@{fa-css-prefix}-space-shuttle:before { content: @fa-var-space-shuttle; } +.@{fa-css-prefix}-slack:before { content: @fa-var-slack; } +.@{fa-css-prefix}-envelope-square:before { content: @fa-var-envelope-square; } +.@{fa-css-prefix}-wordpress:before { content: @fa-var-wordpress; } +.@{fa-css-prefix}-openid:before { content: @fa-var-openid; } +.@{fa-css-prefix}-institution:before, +.@{fa-css-prefix}-bank:before, +.@{fa-css-prefix}-university:before { content: @fa-var-university; } +.@{fa-css-prefix}-mortar-board:before, +.@{fa-css-prefix}-graduation-cap:before { content: @fa-var-graduation-cap; } +.@{fa-css-prefix}-yahoo:before { content: @fa-var-yahoo; } +.@{fa-css-prefix}-google:before { content: @fa-var-google; } +.@{fa-css-prefix}-reddit:before { content: @fa-var-reddit; } +.@{fa-css-prefix}-reddit-square:before { content: @fa-var-reddit-square; } +.@{fa-css-prefix}-stumbleupon-circle:before { content: @fa-var-stumbleupon-circle; } +.@{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-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; } +.@{fa-css-prefix}-language:before { content: @fa-var-language; } +.@{fa-css-prefix}-fax:before { content: @fa-var-fax; } +.@{fa-css-prefix}-building:before { content: @fa-var-building; } +.@{fa-css-prefix}-child:before { content: @fa-var-child; } +.@{fa-css-prefix}-paw:before { content: @fa-var-paw; } +.@{fa-css-prefix}-spoon:before { content: @fa-var-spoon; } +.@{fa-css-prefix}-cube:before { content: @fa-var-cube; } +.@{fa-css-prefix}-cubes:before { content: @fa-var-cubes; } +.@{fa-css-prefix}-behance:before { content: @fa-var-behance; } +.@{fa-css-prefix}-behance-square:before { content: @fa-var-behance-square; } +.@{fa-css-prefix}-steam:before { content: @fa-var-steam; } +.@{fa-css-prefix}-steam-square:before { content: @fa-var-steam-square; } +.@{fa-css-prefix}-recycle:before { content: @fa-var-recycle; } +.@{fa-css-prefix}-automobile:before, +.@{fa-css-prefix}-car:before { content: @fa-var-car; } +.@{fa-css-prefix}-cab:before, +.@{fa-css-prefix}-taxi:before { content: @fa-var-taxi; } +.@{fa-css-prefix}-tree:before { content: @fa-var-tree; } +.@{fa-css-prefix}-spotify:before { content: @fa-var-spotify; } +.@{fa-css-prefix}-deviantart:before { content: @fa-var-deviantart; } +.@{fa-css-prefix}-soundcloud:before { content: @fa-var-soundcloud; } +.@{fa-css-prefix}-database:before { content: @fa-var-database; } +.@{fa-css-prefix}-file-pdf-o:before { content: @fa-var-file-pdf-o; } +.@{fa-css-prefix}-file-word-o:before { content: @fa-var-file-word-o; } +.@{fa-css-prefix}-file-excel-o:before { content: @fa-var-file-excel-o; } +.@{fa-css-prefix}-file-powerpoint-o:before { content: @fa-var-file-powerpoint-o; } +.@{fa-css-prefix}-file-photo-o:before, +.@{fa-css-prefix}-file-picture-o:before, +.@{fa-css-prefix}-file-image-o:before { content: @fa-var-file-image-o; } +.@{fa-css-prefix}-file-zip-o:before, +.@{fa-css-prefix}-file-archive-o:before { content: @fa-var-file-archive-o; } +.@{fa-css-prefix}-file-sound-o:before, +.@{fa-css-prefix}-file-audio-o:before { content: @fa-var-file-audio-o; } +.@{fa-css-prefix}-file-movie-o:before, +.@{fa-css-prefix}-file-video-o:before { content: @fa-var-file-video-o; } +.@{fa-css-prefix}-file-code-o:before { content: @fa-var-file-code-o; } +.@{fa-css-prefix}-vine:before { content: @fa-var-vine; } +.@{fa-css-prefix}-codepen:before { content: @fa-var-codepen; } +.@{fa-css-prefix}-jsfiddle:before { content: @fa-var-jsfiddle; } +.@{fa-css-prefix}-life-bouy:before, +.@{fa-css-prefix}-life-buoy:before, +.@{fa-css-prefix}-life-saver:before, +.@{fa-css-prefix}-support:before, +.@{fa-css-prefix}-life-ring:before { content: @fa-var-life-ring; } +.@{fa-css-prefix}-circle-o-notch:before { content: @fa-var-circle-o-notch; } +.@{fa-css-prefix}-ra:before, +.@{fa-css-prefix}-resistance:before, +.@{fa-css-prefix}-rebel:before { content: @fa-var-rebel; } +.@{fa-css-prefix}-ge:before, +.@{fa-css-prefix}-empire:before { content: @fa-var-empire; } +.@{fa-css-prefix}-git-square:before { content: @fa-var-git-square; } +.@{fa-css-prefix}-git:before { content: @fa-var-git; } +.@{fa-css-prefix}-y-combinator-square:before, +.@{fa-css-prefix}-yc-square:before, +.@{fa-css-prefix}-hacker-news:before { content: @fa-var-hacker-news; } +.@{fa-css-prefix}-tencent-weibo:before { content: @fa-var-tencent-weibo; } +.@{fa-css-prefix}-qq:before { content: @fa-var-qq; } +.@{fa-css-prefix}-wechat:before, +.@{fa-css-prefix}-weixin:before { content: @fa-var-weixin; } +.@{fa-css-prefix}-send:before, +.@{fa-css-prefix}-paper-plane:before { content: @fa-var-paper-plane; } +.@{fa-css-prefix}-send-o:before, +.@{fa-css-prefix}-paper-plane-o:before { content: @fa-var-paper-plane-o; } +.@{fa-css-prefix}-history:before { content: @fa-var-history; } +.@{fa-css-prefix}-circle-thin:before { content: @fa-var-circle-thin; } +.@{fa-css-prefix}-header:before { content: @fa-var-header; } +.@{fa-css-prefix}-paragraph:before { content: @fa-var-paragraph; } +.@{fa-css-prefix}-sliders:before { content: @fa-var-sliders; } +.@{fa-css-prefix}-share-alt:before { content: @fa-var-share-alt; } +.@{fa-css-prefix}-share-alt-square:before { content: @fa-var-share-alt-square; } +.@{fa-css-prefix}-bomb:before { content: @fa-var-bomb; } +.@{fa-css-prefix}-soccer-ball-o:before, +.@{fa-css-prefix}-futbol-o:before { content: @fa-var-futbol-o; } +.@{fa-css-prefix}-tty:before { content: @fa-var-tty; } +.@{fa-css-prefix}-binoculars:before { content: @fa-var-binoculars; } +.@{fa-css-prefix}-plug:before { content: @fa-var-plug; } +.@{fa-css-prefix}-slideshare:before { content: @fa-var-slideshare; } +.@{fa-css-prefix}-twitch:before { content: @fa-var-twitch; } +.@{fa-css-prefix}-yelp:before { content: @fa-var-yelp; } +.@{fa-css-prefix}-newspaper-o:before { content: @fa-var-newspaper-o; } +.@{fa-css-prefix}-wifi:before { content: @fa-var-wifi; } +.@{fa-css-prefix}-calculator:before { content: @fa-var-calculator; } +.@{fa-css-prefix}-paypal:before { content: @fa-var-paypal; } +.@{fa-css-prefix}-google-wallet:before { content: @fa-var-google-wallet; } +.@{fa-css-prefix}-cc-visa:before { content: @fa-var-cc-visa; } +.@{fa-css-prefix}-cc-mastercard:before { content: @fa-var-cc-mastercard; } +.@{fa-css-prefix}-cc-discover:before { content: @fa-var-cc-discover; } +.@{fa-css-prefix}-cc-amex:before { content: @fa-var-cc-amex; } +.@{fa-css-prefix}-cc-paypal:before { content: @fa-var-cc-paypal; } +.@{fa-css-prefix}-cc-stripe:before { content: @fa-var-cc-stripe; } +.@{fa-css-prefix}-bell-slash:before { content: @fa-var-bell-slash; } +.@{fa-css-prefix}-bell-slash-o:before { content: @fa-var-bell-slash-o; } +.@{fa-css-prefix}-trash:before { content: @fa-var-trash; } +.@{fa-css-prefix}-copyright:before { content: @fa-var-copyright; } +.@{fa-css-prefix}-at:before { content: @fa-var-at; } +.@{fa-css-prefix}-eyedropper:before { content: @fa-var-eyedropper; } +.@{fa-css-prefix}-paint-brush:before { content: @fa-var-paint-brush; } +.@{fa-css-prefix}-birthday-cake:before { content: @fa-var-birthday-cake; } +.@{fa-css-prefix}-area-chart:before { content: @fa-var-area-chart; } +.@{fa-css-prefix}-pie-chart:before { content: @fa-var-pie-chart; } +.@{fa-css-prefix}-line-chart:before { content: @fa-var-line-chart; } +.@{fa-css-prefix}-lastfm:before { content: @fa-var-lastfm; } +.@{fa-css-prefix}-lastfm-square:before { content: @fa-var-lastfm-square; } +.@{fa-css-prefix}-toggle-off:before { content: @fa-var-toggle-off; } +.@{fa-css-prefix}-toggle-on:before { content: @fa-var-toggle-on; } +.@{fa-css-prefix}-bicycle:before { content: @fa-var-bicycle; } +.@{fa-css-prefix}-bus:before { content: @fa-var-bus; } +.@{fa-css-prefix}-ioxhost:before { content: @fa-var-ioxhost; } +.@{fa-css-prefix}-angellist:before { content: @fa-var-angellist; } +.@{fa-css-prefix}-cc:before { content: @fa-var-cc; } +.@{fa-css-prefix}-shekel:before, +.@{fa-css-prefix}-sheqel:before, +.@{fa-css-prefix}-ils:before { content: @fa-var-ils; } +.@{fa-css-prefix}-meanpath:before { content: @fa-var-meanpath; } +.@{fa-css-prefix}-buysellads:before { content: @fa-var-buysellads; } +.@{fa-css-prefix}-connectdevelop:before { content: @fa-var-connectdevelop; } +.@{fa-css-prefix}-dashcube:before { content: @fa-var-dashcube; } +.@{fa-css-prefix}-forumbee:before { content: @fa-var-forumbee; } +.@{fa-css-prefix}-leanpub:before { content: @fa-var-leanpub; } +.@{fa-css-prefix}-sellsy:before { content: @fa-var-sellsy; } +.@{fa-css-prefix}-shirtsinbulk:before { content: @fa-var-shirtsinbulk; } +.@{fa-css-prefix}-simplybuilt:before { content: @fa-var-simplybuilt; } +.@{fa-css-prefix}-skyatlas:before { content: @fa-var-skyatlas; } +.@{fa-css-prefix}-cart-plus:before { content: @fa-var-cart-plus; } +.@{fa-css-prefix}-cart-arrow-down:before { content: @fa-var-cart-arrow-down; } +.@{fa-css-prefix}-diamond:before { content: @fa-var-diamond; } +.@{fa-css-prefix}-ship:before { content: @fa-var-ship; } +.@{fa-css-prefix}-user-secret:before { content: @fa-var-user-secret; } +.@{fa-css-prefix}-motorcycle:before { content: @fa-var-motorcycle; } +.@{fa-css-prefix}-street-view:before { content: @fa-var-street-view; } +.@{fa-css-prefix}-heartbeat:before { content: @fa-var-heartbeat; } +.@{fa-css-prefix}-venus:before { content: @fa-var-venus; } +.@{fa-css-prefix}-mars:before { content: @fa-var-mars; } +.@{fa-css-prefix}-mercury:before { content: @fa-var-mercury; } +.@{fa-css-prefix}-intersex:before, +.@{fa-css-prefix}-transgender:before { content: @fa-var-transgender; } +.@{fa-css-prefix}-transgender-alt:before { content: @fa-var-transgender-alt; } +.@{fa-css-prefix}-venus-double:before { content: @fa-var-venus-double; } +.@{fa-css-prefix}-mars-double:before { content: @fa-var-mars-double; } +.@{fa-css-prefix}-venus-mars:before { content: @fa-var-venus-mars; } +.@{fa-css-prefix}-mars-stroke:before { content: @fa-var-mars-stroke; } +.@{fa-css-prefix}-mars-stroke-v:before { content: @fa-var-mars-stroke-v; } +.@{fa-css-prefix}-mars-stroke-h:before { content: @fa-var-mars-stroke-h; } +.@{fa-css-prefix}-neuter:before { content: @fa-var-neuter; } +.@{fa-css-prefix}-genderless:before { content: @fa-var-genderless; } +.@{fa-css-prefix}-facebook-official:before { content: @fa-var-facebook-official; } +.@{fa-css-prefix}-pinterest-p:before { content: @fa-var-pinterest-p; } +.@{fa-css-prefix}-whatsapp:before { content: @fa-var-whatsapp; } +.@{fa-css-prefix}-server:before { content: @fa-var-server; } +.@{fa-css-prefix}-user-plus:before { content: @fa-var-user-plus; } +.@{fa-css-prefix}-user-times:before { content: @fa-var-user-times; } +.@{fa-css-prefix}-hotel:before, +.@{fa-css-prefix}-bed:before { content: @fa-var-bed; } +.@{fa-css-prefix}-viacoin:before { content: @fa-var-viacoin; } +.@{fa-css-prefix}-train:before { content: @fa-var-train; } +.@{fa-css-prefix}-subway:before { content: @fa-var-subway; } +.@{fa-css-prefix}-medium:before { content: @fa-var-medium; } +.@{fa-css-prefix}-yc:before, +.@{fa-css-prefix}-y-combinator:before { content: @fa-var-y-combinator; } +.@{fa-css-prefix}-optin-monster:before { content: @fa-var-optin-monster; } +.@{fa-css-prefix}-opencart:before { content: @fa-var-opencart; } +.@{fa-css-prefix}-expeditedssl:before { content: @fa-var-expeditedssl; } +.@{fa-css-prefix}-battery-4:before, +.@{fa-css-prefix}-battery:before, +.@{fa-css-prefix}-battery-full:before { content: @fa-var-battery-full; } +.@{fa-css-prefix}-battery-3:before, +.@{fa-css-prefix}-battery-three-quarters:before { content: @fa-var-battery-three-quarters; } +.@{fa-css-prefix}-battery-2:before, +.@{fa-css-prefix}-battery-half:before { content: @fa-var-battery-half; } +.@{fa-css-prefix}-battery-1:before, +.@{fa-css-prefix}-battery-quarter:before { content: @fa-var-battery-quarter; } +.@{fa-css-prefix}-battery-0:before, +.@{fa-css-prefix}-battery-empty:before { content: @fa-var-battery-empty; } +.@{fa-css-prefix}-mouse-pointer:before { content: @fa-var-mouse-pointer; } +.@{fa-css-prefix}-i-cursor:before { content: @fa-var-i-cursor; } +.@{fa-css-prefix}-object-group:before { content: @fa-var-object-group; } +.@{fa-css-prefix}-object-ungroup:before { content: @fa-var-object-ungroup; } +.@{fa-css-prefix}-sticky-note:before { content: @fa-var-sticky-note; } +.@{fa-css-prefix}-sticky-note-o:before { content: @fa-var-sticky-note-o; } +.@{fa-css-prefix}-cc-jcb:before { content: @fa-var-cc-jcb; } +.@{fa-css-prefix}-cc-diners-club:before { content: @fa-var-cc-diners-club; } +.@{fa-css-prefix}-clone:before { content: @fa-var-clone; } +.@{fa-css-prefix}-balance-scale:before { content: @fa-var-balance-scale; } +.@{fa-css-prefix}-hourglass-o:before { content: @fa-var-hourglass-o; } +.@{fa-css-prefix}-hourglass-1:before, +.@{fa-css-prefix}-hourglass-start:before { content: @fa-var-hourglass-start; } +.@{fa-css-prefix}-hourglass-2:before, +.@{fa-css-prefix}-hourglass-half:before { content: @fa-var-hourglass-half; } +.@{fa-css-prefix}-hourglass-3:before, +.@{fa-css-prefix}-hourglass-end:before { content: @fa-var-hourglass-end; } +.@{fa-css-prefix}-hourglass:before { content: @fa-var-hourglass; } +.@{fa-css-prefix}-hand-grab-o:before, +.@{fa-css-prefix}-hand-rock-o:before { content: @fa-var-hand-rock-o; } +.@{fa-css-prefix}-hand-stop-o:before, +.@{fa-css-prefix}-hand-paper-o:before { content: @fa-var-hand-paper-o; } +.@{fa-css-prefix}-hand-scissors-o:before { content: @fa-var-hand-scissors-o; } +.@{fa-css-prefix}-hand-lizard-o:before { content: @fa-var-hand-lizard-o; } +.@{fa-css-prefix}-hand-spock-o:before { content: @fa-var-hand-spock-o; } +.@{fa-css-prefix}-hand-pointer-o:before { content: @fa-var-hand-pointer-o; } +.@{fa-css-prefix}-hand-peace-o:before { content: @fa-var-hand-peace-o; } +.@{fa-css-prefix}-trademark:before { content: @fa-var-trademark; } +.@{fa-css-prefix}-registered:before { content: @fa-var-registered; } +.@{fa-css-prefix}-creative-commons:before { content: @fa-var-creative-commons; } +.@{fa-css-prefix}-gg:before { content: @fa-var-gg; } +.@{fa-css-prefix}-gg-circle:before { content: @fa-var-gg-circle; } +.@{fa-css-prefix}-tripadvisor:before { content: @fa-var-tripadvisor; } +.@{fa-css-prefix}-odnoklassniki:before { content: @fa-var-odnoklassniki; } +.@{fa-css-prefix}-odnoklassniki-square:before { content: @fa-var-odnoklassniki-square; } +.@{fa-css-prefix}-get-pocket:before { content: @fa-var-get-pocket; } +.@{fa-css-prefix}-wikipedia-w:before { content: @fa-var-wikipedia-w; } +.@{fa-css-prefix}-safari:before { content: @fa-var-safari; } +.@{fa-css-prefix}-chrome:before { content: @fa-var-chrome; } +.@{fa-css-prefix}-firefox:before { content: @fa-var-firefox; } +.@{fa-css-prefix}-opera:before { content: @fa-var-opera; } +.@{fa-css-prefix}-internet-explorer:before { content: @fa-var-internet-explorer; } +.@{fa-css-prefix}-tv:before, +.@{fa-css-prefix}-television:before { content: @fa-var-television; } +.@{fa-css-prefix}-contao:before { content: @fa-var-contao; } +.@{fa-css-prefix}-500px:before { content: @fa-var-500px; } +.@{fa-css-prefix}-amazon:before { content: @fa-var-amazon; } +.@{fa-css-prefix}-calendar-plus-o:before { content: @fa-var-calendar-plus-o; } +.@{fa-css-prefix}-calendar-minus-o:before { content: @fa-var-calendar-minus-o; } +.@{fa-css-prefix}-calendar-times-o:before { content: @fa-var-calendar-times-o; } +.@{fa-css-prefix}-calendar-check-o:before { content: @fa-var-calendar-check-o; } +.@{fa-css-prefix}-industry:before { content: @fa-var-industry; } +.@{fa-css-prefix}-map-pin:before { content: @fa-var-map-pin; } +.@{fa-css-prefix}-map-signs:before { content: @fa-var-map-signs; } +.@{fa-css-prefix}-map-o:before { content: @fa-var-map-o; } +.@{fa-css-prefix}-map:before { content: @fa-var-map; } +.@{fa-css-prefix}-commenting:before { content: @fa-var-commenting; } +.@{fa-css-prefix}-commenting-o:before { content: @fa-var-commenting-o; } +.@{fa-css-prefix}-houzz:before { content: @fa-var-houzz; } +.@{fa-css-prefix}-vimeo:before { content: @fa-var-vimeo; } +.@{fa-css-prefix}-black-tie:before { content: @fa-var-black-tie; } +.@{fa-css-prefix}-fonticons:before { content: @fa-var-fonticons; } +.@{fa-css-prefix}-reddit-alien:before { content: @fa-var-reddit-alien; } +.@{fa-css-prefix}-edge:before { content: @fa-var-edge; } +.@{fa-css-prefix}-credit-card-alt:before { content: @fa-var-credit-card-alt; } +.@{fa-css-prefix}-codiepie:before { content: @fa-var-codiepie; } +.@{fa-css-prefix}-modx:before { content: @fa-var-modx; } +.@{fa-css-prefix}-fort-awesome:before { content: @fa-var-fort-awesome; } +.@{fa-css-prefix}-usb:before { content: @fa-var-usb; } +.@{fa-css-prefix}-product-hunt:before { content: @fa-var-product-hunt; } +.@{fa-css-prefix}-mixcloud:before { content: @fa-var-mixcloud; } +.@{fa-css-prefix}-scribd:before { content: @fa-var-scribd; } +.@{fa-css-prefix}-pause-circle:before { content: @fa-var-pause-circle; } +.@{fa-css-prefix}-pause-circle-o:before { content: @fa-var-pause-circle-o; } +.@{fa-css-prefix}-stop-circle:before { content: @fa-var-stop-circle; } +.@{fa-css-prefix}-stop-circle-o:before { content: @fa-var-stop-circle-o; } +.@{fa-css-prefix}-shopping-bag:before { content: @fa-var-shopping-bag; } +.@{fa-css-prefix}-shopping-basket:before { content: @fa-var-shopping-basket; } +.@{fa-css-prefix}-hashtag:before { content: @fa-var-hashtag; } +.@{fa-css-prefix}-bluetooth:before { content: @fa-var-bluetooth; } +.@{fa-css-prefix}-bluetooth-b:before { content: @fa-var-bluetooth-b; } +.@{fa-css-prefix}-percent:before { content: @fa-var-percent; } +.@{fa-css-prefix}-gitlab:before { content: @fa-var-gitlab; } +.@{fa-css-prefix}-wpbeginner:before { content: @fa-var-wpbeginner; } +.@{fa-css-prefix}-wpforms:before { content: @fa-var-wpforms; } +.@{fa-css-prefix}-envira:before { content: @fa-var-envira; } +.@{fa-css-prefix}-universal-access:before { content: @fa-var-universal-access; } +.@{fa-css-prefix}-wheelchair-alt:before { content: @fa-var-wheelchair-alt; } +.@{fa-css-prefix}-question-circle-o:before { content: @fa-var-question-circle-o; } +.@{fa-css-prefix}-blind:before { content: @fa-var-blind; } +.@{fa-css-prefix}-audio-description:before { content: @fa-var-audio-description; } +.@{fa-css-prefix}-volume-control-phone:before { content: @fa-var-volume-control-phone; } +.@{fa-css-prefix}-braille:before { content: @fa-var-braille; } +.@{fa-css-prefix}-assistive-listening-systems:before { content: @fa-var-assistive-listening-systems; } +.@{fa-css-prefix}-asl-interpreting:before, +.@{fa-css-prefix}-american-sign-language-interpreting:before { content: @fa-var-american-sign-language-interpreting; } +.@{fa-css-prefix}-deafness:before, +.@{fa-css-prefix}-hard-of-hearing:before, +.@{fa-css-prefix}-deaf:before { content: @fa-var-deaf; } +.@{fa-css-prefix}-glide:before { content: @fa-var-glide; } +.@{fa-css-prefix}-glide-g:before { content: @fa-var-glide-g; } +.@{fa-css-prefix}-signing:before, +.@{fa-css-prefix}-sign-language:before { content: @fa-var-sign-language; } +.@{fa-css-prefix}-low-vision:before { content: @fa-var-low-vision; } +.@{fa-css-prefix}-viadeo:before { content: @fa-var-viadeo; } +.@{fa-css-prefix}-viadeo-square:before { content: @fa-var-viadeo-square; } +.@{fa-css-prefix}-snapchat:before { content: @fa-var-snapchat; } +.@{fa-css-prefix}-snapchat-ghost:before { content: @fa-var-snapchat-ghost; } +.@{fa-css-prefix}-snapchat-square:before { content: @fa-var-snapchat-square; } +.@{fa-css-prefix}-pied-piper:before { content: @fa-var-pied-piper; } +.@{fa-css-prefix}-first-order:before { content: @fa-var-first-order; } +.@{fa-css-prefix}-yoast:before { content: @fa-var-yoast; } +.@{fa-css-prefix}-themeisle:before { content: @fa-var-themeisle; } +.@{fa-css-prefix}-google-plus-circle:before, +.@{fa-css-prefix}-google-plus-official:before { content: @fa-var-google-plus-official; } +.@{fa-css-prefix}-fa:before, +.@{fa-css-prefix}-font-awesome:before { content: @fa-var-font-awesome; } +.@{fa-css-prefix}-handshake-o:before { content: @fa-var-handshake-o; } +.@{fa-css-prefix}-envelope-open:before { content: @fa-var-envelope-open; } +.@{fa-css-prefix}-envelope-open-o:before { content: @fa-var-envelope-open-o; } +.@{fa-css-prefix}-linode:before { content: @fa-var-linode; } +.@{fa-css-prefix}-address-book:before { content: @fa-var-address-book; } +.@{fa-css-prefix}-address-book-o:before { content: @fa-var-address-book-o; } +.@{fa-css-prefix}-vcard:before, +.@{fa-css-prefix}-address-card:before { content: @fa-var-address-card; } +.@{fa-css-prefix}-vcard-o:before, +.@{fa-css-prefix}-address-card-o:before { content: @fa-var-address-card-o; } +.@{fa-css-prefix}-user-circle:before { content: @fa-var-user-circle; } +.@{fa-css-prefix}-user-circle-o:before { content: @fa-var-user-circle-o; } +.@{fa-css-prefix}-user-o:before { content: @fa-var-user-o; } +.@{fa-css-prefix}-id-badge:before { content: @fa-var-id-badge; } +.@{fa-css-prefix}-drivers-license:before, +.@{fa-css-prefix}-id-card:before { content: @fa-var-id-card; } +.@{fa-css-prefix}-drivers-license-o:before, +.@{fa-css-prefix}-id-card-o:before { content: @fa-var-id-card-o; } +.@{fa-css-prefix}-quora:before { content: @fa-var-quora; } +.@{fa-css-prefix}-free-code-camp:before { content: @fa-var-free-code-camp; } +.@{fa-css-prefix}-telegram:before { content: @fa-var-telegram; } +.@{fa-css-prefix}-thermometer-4:before, +.@{fa-css-prefix}-thermometer:before, +.@{fa-css-prefix}-thermometer-full:before { content: @fa-var-thermometer-full; } +.@{fa-css-prefix}-thermometer-3:before, +.@{fa-css-prefix}-thermometer-three-quarters:before { content: @fa-var-thermometer-three-quarters; } +.@{fa-css-prefix}-thermometer-2:before, +.@{fa-css-prefix}-thermometer-half:before { content: @fa-var-thermometer-half; } +.@{fa-css-prefix}-thermometer-1:before, +.@{fa-css-prefix}-thermometer-quarter:before { content: @fa-var-thermometer-quarter; } +.@{fa-css-prefix}-thermometer-0:before, +.@{fa-css-prefix}-thermometer-empty:before { content: @fa-var-thermometer-empty; } +.@{fa-css-prefix}-shower:before { content: @fa-var-shower; } +.@{fa-css-prefix}-bathtub:before, +.@{fa-css-prefix}-s15:before, +.@{fa-css-prefix}-bath:before { content: @fa-var-bath; } +.@{fa-css-prefix}-podcast:before { content: @fa-var-podcast; } +.@{fa-css-prefix}-window-maximize:before { content: @fa-var-window-maximize; } +.@{fa-css-prefix}-window-minimize:before { content: @fa-var-window-minimize; } +.@{fa-css-prefix}-window-restore:before { content: @fa-var-window-restore; } +.@{fa-css-prefix}-times-rectangle:before, +.@{fa-css-prefix}-window-close:before { content: @fa-var-window-close; } +.@{fa-css-prefix}-times-rectangle-o:before, +.@{fa-css-prefix}-window-close-o:before { content: @fa-var-window-close-o; } +.@{fa-css-prefix}-bandcamp:before { content: @fa-var-bandcamp; } +.@{fa-css-prefix}-grav:before { content: @fa-var-grav; } +.@{fa-css-prefix}-etsy:before { content: @fa-var-etsy; } +.@{fa-css-prefix}-imdb:before { content: @fa-var-imdb; } +.@{fa-css-prefix}-ravelry:before { content: @fa-var-ravelry; } +.@{fa-css-prefix}-eercast:before { content: @fa-var-eercast; } +.@{fa-css-prefix}-microchip:before { content: @fa-var-microchip; } +.@{fa-css-prefix}-snowflake-o:before { content: @fa-var-snowflake-o; } +.@{fa-css-prefix}-superpowers:before { content: @fa-var-superpowers; } +.@{fa-css-prefix}-wpexplorer:before { content: @fa-var-wpexplorer; } +.@{fa-css-prefix}-meetup:before { content: @fa-var-meetup; } diff --git a/static/font-awesome/less/larger.less b/static/font-awesome/less/larger.less new file mode 100644 index 0000000..c9d6467 --- /dev/null +++ b/static/font-awesome/less/larger.less @@ -0,0 +1,13 @@ +// Icon Sizes +// ------------------------- + +/* makes the font 33% larger relative to the icon container */ +.@{fa-css-prefix}-lg { + font-size: (4em / 3); + line-height: (3em / 4); + vertical-align: -15%; +} +.@{fa-css-prefix}-2x { font-size: 2em; } +.@{fa-css-prefix}-3x { font-size: 3em; } +.@{fa-css-prefix}-4x { font-size: 4em; } +.@{fa-css-prefix}-5x { font-size: 5em; } diff --git a/static/font-awesome/less/list.less b/static/font-awesome/less/list.less new file mode 100644 index 0000000..0b44038 --- /dev/null +++ b/static/font-awesome/less/list.less @@ -0,0 +1,19 @@ +// List Icons +// ------------------------- + +.@{fa-css-prefix}-ul { + padding-left: 0; + margin-left: @fa-li-width; + list-style-type: none; + > li { position: relative; } +} +.@{fa-css-prefix}-li { + position: absolute; + left: -@fa-li-width; + width: @fa-li-width; + top: (2em / 14); + text-align: center; + &.@{fa-css-prefix}-lg { + left: (-@fa-li-width + (4em / 14)); + } +} diff --git a/static/font-awesome/less/mixins.less b/static/font-awesome/less/mixins.less new file mode 100644 index 0000000..beef231 --- /dev/null +++ b/static/font-awesome/less/mixins.less @@ -0,0 +1,60 @@ +// Mixins +// -------------------------- + +.fa-icon() { + display: inline-block; + font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration + font-size: inherit; // can't have font-size inherit on line above, so need to override + text-rendering: auto; // optimizelegibility throws things off #1094 + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + +} + +.fa-icon-rotate(@degrees, @rotation) { + -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) { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation}, mirror=1)"; + -webkit-transform: scale(@horiz, @vert); + -ms-transform: scale(@horiz, @vert); + transform: scale(@horiz, @vert); +} + + +// Only display content to screen readers. A la Bootstrap 4. +// +// See: http://a11yproject.com/posts/how-to-hide-content/ + +.sr-only() { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0,0,0,0); + border: 0; +} + +// Use in conjunction with .sr-only to only display content when it's focused. +// +// Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1 +// +// Credit: HTML5 Boilerplate + +.sr-only-focusable() { + &:active, + &:focus { + position: static; + width: auto; + height: auto; + margin: 0; + overflow: visible; + clip: auto; + } +} diff --git a/static/font-awesome/less/path.less b/static/font-awesome/less/path.less new file mode 100644 index 0000000..835be41 --- /dev/null +++ b/static/font-awesome/less/path.less @@ -0,0 +1,15 @@ +/* FONT PATH + * -------------------------- */ + +@font-face { + font-family: 'FontAwesome'; + src: url('@{fa-font-path}/fontawesome-webfont.eot?v=@{fa-version}'); + src: url('@{fa-font-path}/fontawesome-webfont.eot?#iefix&v=@{fa-version}') format('embedded-opentype'), + url('@{fa-font-path}/fontawesome-webfont.woff2?v=@{fa-version}') format('woff2'), + url('@{fa-font-path}/fontawesome-webfont.woff?v=@{fa-version}') format('woff'), + url('@{fa-font-path}/fontawesome-webfont.ttf?v=@{fa-version}') format('truetype'), + url('@{fa-font-path}/fontawesome-webfont.svg?v=@{fa-version}#fontawesomeregular') format('svg'); + // src: url('@{fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts + font-weight: normal; + font-style: normal; +} diff --git a/static/font-awesome/less/rotated-flipped.less b/static/font-awesome/less/rotated-flipped.less new file mode 100644 index 0000000..f6ba814 --- /dev/null +++ b/static/font-awesome/less/rotated-flipped.less @@ -0,0 +1,20 @@ +// Rotated & Flipped Icons +// ------------------------- + +.@{fa-css-prefix}-rotate-90 { .fa-icon-rotate(90deg, 1); } +.@{fa-css-prefix}-rotate-180 { .fa-icon-rotate(180deg, 2); } +.@{fa-css-prefix}-rotate-270 { .fa-icon-rotate(270deg, 3); } + +.@{fa-css-prefix}-flip-horizontal { .fa-icon-flip(-1, 1, 0); } +.@{fa-css-prefix}-flip-vertical { .fa-icon-flip(1, -1, 2); } + +// Hook for IE8-9 +// ------------------------- + +:root .@{fa-css-prefix}-rotate-90, +:root .@{fa-css-prefix}-rotate-180, +:root .@{fa-css-prefix}-rotate-270, +:root .@{fa-css-prefix}-flip-horizontal, +:root .@{fa-css-prefix}-flip-vertical { + filter: none; +} diff --git a/static/font-awesome/less/screen-reader.less b/static/font-awesome/less/screen-reader.less new file mode 100644 index 0000000..11c1881 --- /dev/null +++ b/static/font-awesome/less/screen-reader.less @@ -0,0 +1,5 @@ +// Screen Readers +// ------------------------- + +.sr-only { .sr-only(); } +.sr-only-focusable { .sr-only-focusable(); } diff --git a/static/font-awesome/less/stacked.less b/static/font-awesome/less/stacked.less new file mode 100644 index 0000000..fc53fb0 --- /dev/null +++ b/static/font-awesome/less/stacked.less @@ -0,0 +1,20 @@ +// Stacked Icons +// ------------------------- + +.@{fa-css-prefix}-stack { + position: relative; + display: inline-block; + width: 2em; + height: 2em; + line-height: 2em; + vertical-align: middle; +} +.@{fa-css-prefix}-stack-1x, .@{fa-css-prefix}-stack-2x { + position: absolute; + left: 0; + width: 100%; + text-align: center; +} +.@{fa-css-prefix}-stack-1x { line-height: inherit; } +.@{fa-css-prefix}-stack-2x { font-size: 2em; } +.@{fa-css-prefix}-inverse { color: @fa-inverse; } diff --git a/static/font-awesome/less/variables.less b/static/font-awesome/less/variables.less new file mode 100644 index 0000000..7ddbbc0 --- /dev/null +++ b/static/font-awesome/less/variables.less @@ -0,0 +1,800 @@ +// Variables +// -------------------------- + +@fa-font-path: "../fonts"; +@fa-font-size-base: 14px; +@fa-line-height-base: 1; +//@fa-font-path: "//netdna.bootstrapcdn.com/font-awesome/4.7.0/fonts"; // for referencing Bootstrap CDN font files directly +@fa-css-prefix: fa; +@fa-version: "4.7.0"; +@fa-border-color: #eee; +@fa-inverse: #fff; +@fa-li-width: (30em / 14); + +@fa-var-500px: "\f26e"; +@fa-var-address-book: "\f2b9"; +@fa-var-address-book-o: "\f2ba"; +@fa-var-address-card: "\f2bb"; +@fa-var-address-card-o: "\f2bc"; +@fa-var-adjust: "\f042"; +@fa-var-adn: "\f170"; +@fa-var-align-center: "\f037"; +@fa-var-align-justify: "\f039"; +@fa-var-align-left: "\f036"; +@fa-var-align-right: "\f038"; +@fa-var-amazon: "\f270"; +@fa-var-ambulance: "\f0f9"; +@fa-var-american-sign-language-interpreting: "\f2a3"; +@fa-var-anchor: "\f13d"; +@fa-var-android: "\f17b"; +@fa-var-angellist: "\f209"; +@fa-var-angle-double-down: "\f103"; +@fa-var-angle-double-left: "\f100"; +@fa-var-angle-double-right: "\f101"; +@fa-var-angle-double-up: "\f102"; +@fa-var-angle-down: "\f107"; +@fa-var-angle-left: "\f104"; +@fa-var-angle-right: "\f105"; +@fa-var-angle-up: "\f106"; +@fa-var-apple: "\f179"; +@fa-var-archive: "\f187"; +@fa-var-area-chart: "\f1fe"; +@fa-var-arrow-circle-down: "\f0ab"; +@fa-var-arrow-circle-left: "\f0a8"; +@fa-var-arrow-circle-o-down: "\f01a"; +@fa-var-arrow-circle-o-left: "\f190"; +@fa-var-arrow-circle-o-right: "\f18e"; +@fa-var-arrow-circle-o-up: "\f01b"; +@fa-var-arrow-circle-right: "\f0a9"; +@fa-var-arrow-circle-up: "\f0aa"; +@fa-var-arrow-down: "\f063"; +@fa-var-arrow-left: "\f060"; +@fa-var-arrow-right: "\f061"; +@fa-var-arrow-up: "\f062"; +@fa-var-arrows: "\f047"; +@fa-var-arrows-alt: "\f0b2"; +@fa-var-arrows-h: "\f07e"; +@fa-var-arrows-v: "\f07d"; +@fa-var-asl-interpreting: "\f2a3"; +@fa-var-assistive-listening-systems: "\f2a2"; +@fa-var-asterisk: "\f069"; +@fa-var-at: "\f1fa"; +@fa-var-audio-description: "\f29e"; +@fa-var-automobile: "\f1b9"; +@fa-var-backward: "\f04a"; +@fa-var-balance-scale: "\f24e"; +@fa-var-ban: "\f05e"; +@fa-var-bandcamp: "\f2d5"; +@fa-var-bank: "\f19c"; +@fa-var-bar-chart: "\f080"; +@fa-var-bar-chart-o: "\f080"; +@fa-var-barcode: "\f02a"; +@fa-var-bars: "\f0c9"; +@fa-var-bath: "\f2cd"; +@fa-var-bathtub: "\f2cd"; +@fa-var-battery: "\f240"; +@fa-var-battery-0: "\f244"; +@fa-var-battery-1: "\f243"; +@fa-var-battery-2: "\f242"; +@fa-var-battery-3: "\f241"; +@fa-var-battery-4: "\f240"; +@fa-var-battery-empty: "\f244"; +@fa-var-battery-full: "\f240"; +@fa-var-battery-half: "\f242"; +@fa-var-battery-quarter: "\f243"; +@fa-var-battery-three-quarters: "\f241"; +@fa-var-bed: "\f236"; +@fa-var-beer: "\f0fc"; +@fa-var-behance: "\f1b4"; +@fa-var-behance-square: "\f1b5"; +@fa-var-bell: "\f0f3"; +@fa-var-bell-o: "\f0a2"; +@fa-var-bell-slash: "\f1f6"; +@fa-var-bell-slash-o: "\f1f7"; +@fa-var-bicycle: "\f206"; +@fa-var-binoculars: "\f1e5"; +@fa-var-birthday-cake: "\f1fd"; +@fa-var-bitbucket: "\f171"; +@fa-var-bitbucket-square: "\f172"; +@fa-var-bitcoin: "\f15a"; +@fa-var-black-tie: "\f27e"; +@fa-var-blind: "\f29d"; +@fa-var-bluetooth: "\f293"; +@fa-var-bluetooth-b: "\f294"; +@fa-var-bold: "\f032"; +@fa-var-bolt: "\f0e7"; +@fa-var-bomb: "\f1e2"; +@fa-var-book: "\f02d"; +@fa-var-bookmark: "\f02e"; +@fa-var-bookmark-o: "\f097"; +@fa-var-braille: "\f2a1"; +@fa-var-briefcase: "\f0b1"; +@fa-var-btc: "\f15a"; +@fa-var-bug: "\f188"; +@fa-var-building: "\f1ad"; +@fa-var-building-o: "\f0f7"; +@fa-var-bullhorn: "\f0a1"; +@fa-var-bullseye: "\f140"; +@fa-var-bus: "\f207"; +@fa-var-buysellads: "\f20d"; +@fa-var-cab: "\f1ba"; +@fa-var-calculator: "\f1ec"; +@fa-var-calendar: "\f073"; +@fa-var-calendar-check-o: "\f274"; +@fa-var-calendar-minus-o: "\f272"; +@fa-var-calendar-o: "\f133"; +@fa-var-calendar-plus-o: "\f271"; +@fa-var-calendar-times-o: "\f273"; +@fa-var-camera: "\f030"; +@fa-var-camera-retro: "\f083"; +@fa-var-car: "\f1b9"; +@fa-var-caret-down: "\f0d7"; +@fa-var-caret-left: "\f0d9"; +@fa-var-caret-right: "\f0da"; +@fa-var-caret-square-o-down: "\f150"; +@fa-var-caret-square-o-left: "\f191"; +@fa-var-caret-square-o-right: "\f152"; +@fa-var-caret-square-o-up: "\f151"; +@fa-var-caret-up: "\f0d8"; +@fa-var-cart-arrow-down: "\f218"; +@fa-var-cart-plus: "\f217"; +@fa-var-cc: "\f20a"; +@fa-var-cc-amex: "\f1f3"; +@fa-var-cc-diners-club: "\f24c"; +@fa-var-cc-discover: "\f1f2"; +@fa-var-cc-jcb: "\f24b"; +@fa-var-cc-mastercard: "\f1f1"; +@fa-var-cc-paypal: "\f1f4"; +@fa-var-cc-stripe: "\f1f5"; +@fa-var-cc-visa: "\f1f0"; +@fa-var-certificate: "\f0a3"; +@fa-var-chain: "\f0c1"; +@fa-var-chain-broken: "\f127"; +@fa-var-check: "\f00c"; +@fa-var-check-circle: "\f058"; +@fa-var-check-circle-o: "\f05d"; +@fa-var-check-square: "\f14a"; +@fa-var-check-square-o: "\f046"; +@fa-var-chevron-circle-down: "\f13a"; +@fa-var-chevron-circle-left: "\f137"; +@fa-var-chevron-circle-right: "\f138"; +@fa-var-chevron-circle-up: "\f139"; +@fa-var-chevron-down: "\f078"; +@fa-var-chevron-left: "\f053"; +@fa-var-chevron-right: "\f054"; +@fa-var-chevron-up: "\f077"; +@fa-var-child: "\f1ae"; +@fa-var-chrome: "\f268"; +@fa-var-circle: "\f111"; +@fa-var-circle-o: "\f10c"; +@fa-var-circle-o-notch: "\f1ce"; +@fa-var-circle-thin: "\f1db"; +@fa-var-clipboard: "\f0ea"; +@fa-var-clock-o: "\f017"; +@fa-var-clone: "\f24d"; +@fa-var-close: "\f00d"; +@fa-var-cloud: "\f0c2"; +@fa-var-cloud-download: "\f0ed"; +@fa-var-cloud-upload: "\f0ee"; +@fa-var-cny: "\f157"; +@fa-var-code: "\f121"; +@fa-var-code-fork: "\f126"; +@fa-var-codepen: "\f1cb"; +@fa-var-codiepie: "\f284"; +@fa-var-coffee: "\f0f4"; +@fa-var-cog: "\f013"; +@fa-var-cogs: "\f085"; +@fa-var-columns: "\f0db"; +@fa-var-comment: "\f075"; +@fa-var-comment-o: "\f0e5"; +@fa-var-commenting: "\f27a"; +@fa-var-commenting-o: "\f27b"; +@fa-var-comments: "\f086"; +@fa-var-comments-o: "\f0e6"; +@fa-var-compass: "\f14e"; +@fa-var-compress: "\f066"; +@fa-var-connectdevelop: "\f20e"; +@fa-var-contao: "\f26d"; +@fa-var-copy: "\f0c5"; +@fa-var-copyright: "\f1f9"; +@fa-var-creative-commons: "\f25e"; +@fa-var-credit-card: "\f09d"; +@fa-var-credit-card-alt: "\f283"; +@fa-var-crop: "\f125"; +@fa-var-crosshairs: "\f05b"; +@fa-var-css3: "\f13c"; +@fa-var-cube: "\f1b2"; +@fa-var-cubes: "\f1b3"; +@fa-var-cut: "\f0c4"; +@fa-var-cutlery: "\f0f5"; +@fa-var-dashboard: "\f0e4"; +@fa-var-dashcube: "\f210"; +@fa-var-database: "\f1c0"; +@fa-var-deaf: "\f2a4"; +@fa-var-deafness: "\f2a4"; +@fa-var-dedent: "\f03b"; +@fa-var-delicious: "\f1a5"; +@fa-var-desktop: "\f108"; +@fa-var-deviantart: "\f1bd"; +@fa-var-diamond: "\f219"; +@fa-var-digg: "\f1a6"; +@fa-var-dollar: "\f155"; +@fa-var-dot-circle-o: "\f192"; +@fa-var-download: "\f019"; +@fa-var-dribbble: "\f17d"; +@fa-var-drivers-license: "\f2c2"; +@fa-var-drivers-license-o: "\f2c3"; +@fa-var-dropbox: "\f16b"; +@fa-var-drupal: "\f1a9"; +@fa-var-edge: "\f282"; +@fa-var-edit: "\f044"; +@fa-var-eercast: "\f2da"; +@fa-var-eject: "\f052"; +@fa-var-ellipsis-h: "\f141"; +@fa-var-ellipsis-v: "\f142"; +@fa-var-empire: "\f1d1"; +@fa-var-envelope: "\f0e0"; +@fa-var-envelope-o: "\f003"; +@fa-var-envelope-open: "\f2b6"; +@fa-var-envelope-open-o: "\f2b7"; +@fa-var-envelope-square: "\f199"; +@fa-var-envira: "\f299"; +@fa-var-eraser: "\f12d"; +@fa-var-etsy: "\f2d7"; +@fa-var-eur: "\f153"; +@fa-var-euro: "\f153"; +@fa-var-exchange: "\f0ec"; +@fa-var-exclamation: "\f12a"; +@fa-var-exclamation-circle: "\f06a"; +@fa-var-exclamation-triangle: "\f071"; +@fa-var-expand: "\f065"; +@fa-var-expeditedssl: "\f23e"; +@fa-var-external-link: "\f08e"; +@fa-var-external-link-square: "\f14c"; +@fa-var-eye: "\f06e"; +@fa-var-eye-slash: "\f070"; +@fa-var-eyedropper: "\f1fb"; +@fa-var-fa: "\f2b4"; +@fa-var-facebook: "\f09a"; +@fa-var-facebook-f: "\f09a"; +@fa-var-facebook-official: "\f230"; +@fa-var-facebook-square: "\f082"; +@fa-var-fast-backward: "\f049"; +@fa-var-fast-forward: "\f050"; +@fa-var-fax: "\f1ac"; +@fa-var-feed: "\f09e"; +@fa-var-female: "\f182"; +@fa-var-fighter-jet: "\f0fb"; +@fa-var-file: "\f15b"; +@fa-var-file-archive-o: "\f1c6"; +@fa-var-file-audio-o: "\f1c7"; +@fa-var-file-code-o: "\f1c9"; +@fa-var-file-excel-o: "\f1c3"; +@fa-var-file-image-o: "\f1c5"; +@fa-var-file-movie-o: "\f1c8"; +@fa-var-file-o: "\f016"; +@fa-var-file-pdf-o: "\f1c1"; +@fa-var-file-photo-o: "\f1c5"; +@fa-var-file-picture-o: "\f1c5"; +@fa-var-file-powerpoint-o: "\f1c4"; +@fa-var-file-sound-o: "\f1c7"; +@fa-var-file-text: "\f15c"; +@fa-var-file-text-o: "\f0f6"; +@fa-var-file-video-o: "\f1c8"; +@fa-var-file-word-o: "\f1c2"; +@fa-var-file-zip-o: "\f1c6"; +@fa-var-files-o: "\f0c5"; +@fa-var-film: "\f008"; +@fa-var-filter: "\f0b0"; +@fa-var-fire: "\f06d"; +@fa-var-fire-extinguisher: "\f134"; +@fa-var-firefox: "\f269"; +@fa-var-first-order: "\f2b0"; +@fa-var-flag: "\f024"; +@fa-var-flag-checkered: "\f11e"; +@fa-var-flag-o: "\f11d"; +@fa-var-flash: "\f0e7"; +@fa-var-flask: "\f0c3"; +@fa-var-flickr: "\f16e"; +@fa-var-floppy-o: "\f0c7"; +@fa-var-folder: "\f07b"; +@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"; +@fa-var-gavel: "\f0e3"; +@fa-var-gbp: "\f154"; +@fa-var-ge: "\f1d1"; +@fa-var-gear: "\f013"; +@fa-var-gears: "\f085"; +@fa-var-genderless: "\f22d"; +@fa-var-get-pocket: "\f265"; +@fa-var-gg: "\f260"; +@fa-var-gg-circle: "\f261"; +@fa-var-gift: "\f06b"; +@fa-var-git: "\f1d3"; +@fa-var-git-square: "\f1d2"; +@fa-var-github: "\f09b"; +@fa-var-github-alt: "\f113"; +@fa-var-github-square: "\f092"; +@fa-var-gitlab: "\f296"; +@fa-var-gittip: "\f184"; +@fa-var-glass: "\f000"; +@fa-var-glide: "\f2a5"; +@fa-var-glide-g: "\f2a6"; +@fa-var-globe: "\f0ac"; +@fa-var-google: "\f1a0"; +@fa-var-google-plus: "\f0d5"; +@fa-var-google-plus-circle: "\f2b3"; +@fa-var-google-plus-official: "\f2b3"; +@fa-var-google-plus-square: "\f0d4"; +@fa-var-google-wallet: "\f1ee"; +@fa-var-graduation-cap: "\f19d"; +@fa-var-gratipay: "\f184"; +@fa-var-grav: "\f2d6"; +@fa-var-group: "\f0c0"; +@fa-var-h-square: "\f0fd"; +@fa-var-hacker-news: "\f1d4"; +@fa-var-hand-grab-o: "\f255"; +@fa-var-hand-lizard-o: "\f258"; +@fa-var-hand-o-down: "\f0a7"; +@fa-var-hand-o-left: "\f0a5"; +@fa-var-hand-o-right: "\f0a4"; +@fa-var-hand-o-up: "\f0a6"; +@fa-var-hand-paper-o: "\f256"; +@fa-var-hand-peace-o: "\f25b"; +@fa-var-hand-pointer-o: "\f25a"; +@fa-var-hand-rock-o: "\f255"; +@fa-var-hand-scissors-o: "\f257"; +@fa-var-hand-spock-o: "\f259"; +@fa-var-hand-stop-o: "\f256"; +@fa-var-handshake-o: "\f2b5"; +@fa-var-hard-of-hearing: "\f2a4"; +@fa-var-hashtag: "\f292"; +@fa-var-hdd-o: "\f0a0"; +@fa-var-header: "\f1dc"; +@fa-var-headphones: "\f025"; +@fa-var-heart: "\f004"; +@fa-var-heart-o: "\f08a"; +@fa-var-heartbeat: "\f21e"; +@fa-var-history: "\f1da"; +@fa-var-home: "\f015"; +@fa-var-hospital-o: "\f0f8"; +@fa-var-hotel: "\f236"; +@fa-var-hourglass: "\f254"; +@fa-var-hourglass-1: "\f251"; +@fa-var-hourglass-2: "\f252"; +@fa-var-hourglass-3: "\f253"; +@fa-var-hourglass-end: "\f253"; +@fa-var-hourglass-half: "\f252"; +@fa-var-hourglass-o: "\f250"; +@fa-var-hourglass-start: "\f251"; +@fa-var-houzz: "\f27c"; +@fa-var-html5: "\f13b"; +@fa-var-i-cursor: "\f246"; +@fa-var-id-badge: "\f2c1"; +@fa-var-id-card: "\f2c2"; +@fa-var-id-card-o: "\f2c3"; +@fa-var-ils: "\f20b"; +@fa-var-image: "\f03e"; +@fa-var-imdb: "\f2d8"; +@fa-var-inbox: "\f01c"; +@fa-var-indent: "\f03c"; +@fa-var-industry: "\f275"; +@fa-var-info: "\f129"; +@fa-var-info-circle: "\f05a"; +@fa-var-inr: "\f156"; +@fa-var-instagram: "\f16d"; +@fa-var-institution: "\f19c"; +@fa-var-internet-explorer: "\f26b"; +@fa-var-intersex: "\f224"; +@fa-var-ioxhost: "\f208"; +@fa-var-italic: "\f033"; +@fa-var-joomla: "\f1aa"; +@fa-var-jpy: "\f157"; +@fa-var-jsfiddle: "\f1cc"; +@fa-var-key: "\f084"; +@fa-var-keyboard-o: "\f11c"; +@fa-var-krw: "\f159"; +@fa-var-language: "\f1ab"; +@fa-var-laptop: "\f109"; +@fa-var-lastfm: "\f202"; +@fa-var-lastfm-square: "\f203"; +@fa-var-leaf: "\f06c"; +@fa-var-leanpub: "\f212"; +@fa-var-legal: "\f0e3"; +@fa-var-lemon-o: "\f094"; +@fa-var-level-down: "\f149"; +@fa-var-level-up: "\f148"; +@fa-var-life-bouy: "\f1cd"; +@fa-var-life-buoy: "\f1cd"; +@fa-var-life-ring: "\f1cd"; +@fa-var-life-saver: "\f1cd"; +@fa-var-lightbulb-o: "\f0eb"; +@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"; +@fa-var-list-ol: "\f0cb"; +@fa-var-list-ul: "\f0ca"; +@fa-var-location-arrow: "\f124"; +@fa-var-lock: "\f023"; +@fa-var-long-arrow-down: "\f175"; +@fa-var-long-arrow-left: "\f177"; +@fa-var-long-arrow-right: "\f178"; +@fa-var-long-arrow-up: "\f176"; +@fa-var-low-vision: "\f2a8"; +@fa-var-magic: "\f0d0"; +@fa-var-magnet: "\f076"; +@fa-var-mail-forward: "\f064"; +@fa-var-mail-reply: "\f112"; +@fa-var-mail-reply-all: "\f122"; +@fa-var-male: "\f183"; +@fa-var-map: "\f279"; +@fa-var-map-marker: "\f041"; +@fa-var-map-o: "\f278"; +@fa-var-map-pin: "\f276"; +@fa-var-map-signs: "\f277"; +@fa-var-mars: "\f222"; +@fa-var-mars-double: "\f227"; +@fa-var-mars-stroke: "\f229"; +@fa-var-mars-stroke-h: "\f22b"; +@fa-var-mars-stroke-v: "\f22a"; +@fa-var-maxcdn: "\f136"; +@fa-var-meanpath: "\f20c"; +@fa-var-medium: "\f23a"; +@fa-var-medkit: "\f0fa"; +@fa-var-meetup: "\f2e0"; +@fa-var-meh-o: "\f11a"; +@fa-var-mercury: "\f223"; +@fa-var-microchip: "\f2db"; +@fa-var-microphone: "\f130"; +@fa-var-microphone-slash: "\f131"; +@fa-var-minus: "\f068"; +@fa-var-minus-circle: "\f056"; +@fa-var-minus-square: "\f146"; +@fa-var-minus-square-o: "\f147"; +@fa-var-mixcloud: "\f289"; +@fa-var-mobile: "\f10b"; +@fa-var-mobile-phone: "\f10b"; +@fa-var-modx: "\f285"; +@fa-var-money: "\f0d6"; +@fa-var-moon-o: "\f186"; +@fa-var-mortar-board: "\f19d"; +@fa-var-motorcycle: "\f21c"; +@fa-var-mouse-pointer: "\f245"; +@fa-var-music: "\f001"; +@fa-var-navicon: "\f0c9"; +@fa-var-neuter: "\f22c"; +@fa-var-newspaper-o: "\f1ea"; +@fa-var-object-group: "\f247"; +@fa-var-object-ungroup: "\f248"; +@fa-var-odnoklassniki: "\f263"; +@fa-var-odnoklassniki-square: "\f264"; +@fa-var-opencart: "\f23d"; +@fa-var-openid: "\f19b"; +@fa-var-opera: "\f26a"; +@fa-var-optin-monster: "\f23c"; +@fa-var-outdent: "\f03b"; +@fa-var-pagelines: "\f18c"; +@fa-var-paint-brush: "\f1fc"; +@fa-var-paper-plane: "\f1d8"; +@fa-var-paper-plane-o: "\f1d9"; +@fa-var-paperclip: "\f0c6"; +@fa-var-paragraph: "\f1dd"; +@fa-var-paste: "\f0ea"; +@fa-var-pause: "\f04c"; +@fa-var-pause-circle: "\f28b"; +@fa-var-pause-circle-o: "\f28c"; +@fa-var-paw: "\f1b0"; +@fa-var-paypal: "\f1ed"; +@fa-var-pencil: "\f040"; +@fa-var-pencil-square: "\f14b"; +@fa-var-pencil-square-o: "\f044"; +@fa-var-percent: "\f295"; +@fa-var-phone: "\f095"; +@fa-var-phone-square: "\f098"; +@fa-var-photo: "\f03e"; +@fa-var-picture-o: "\f03e"; +@fa-var-pie-chart: "\f200"; +@fa-var-pied-piper: "\f2ae"; +@fa-var-pied-piper-alt: "\f1a8"; +@fa-var-pied-piper-pp: "\f1a7"; +@fa-var-pinterest: "\f0d2"; +@fa-var-pinterest-p: "\f231"; +@fa-var-pinterest-square: "\f0d3"; +@fa-var-plane: "\f072"; +@fa-var-play: "\f04b"; +@fa-var-play-circle: "\f144"; +@fa-var-play-circle-o: "\f01d"; +@fa-var-plug: "\f1e6"; +@fa-var-plus: "\f067"; +@fa-var-plus-circle: "\f055"; +@fa-var-plus-square: "\f0fe"; +@fa-var-plus-square-o: "\f196"; +@fa-var-podcast: "\f2ce"; +@fa-var-power-off: "\f011"; +@fa-var-print: "\f02f"; +@fa-var-product-hunt: "\f288"; +@fa-var-puzzle-piece: "\f12e"; +@fa-var-qq: "\f1d6"; +@fa-var-qrcode: "\f029"; +@fa-var-question: "\f128"; +@fa-var-question-circle: "\f059"; +@fa-var-question-circle-o: "\f29c"; +@fa-var-quora: "\f2c4"; +@fa-var-quote-left: "\f10d"; +@fa-var-quote-right: "\f10e"; +@fa-var-ra: "\f1d0"; +@fa-var-random: "\f074"; +@fa-var-ravelry: "\f2d9"; +@fa-var-rebel: "\f1d0"; +@fa-var-recycle: "\f1b8"; +@fa-var-reddit: "\f1a1"; +@fa-var-reddit-alien: "\f281"; +@fa-var-reddit-square: "\f1a2"; +@fa-var-refresh: "\f021"; +@fa-var-registered: "\f25d"; +@fa-var-remove: "\f00d"; +@fa-var-renren: "\f18b"; +@fa-var-reorder: "\f0c9"; +@fa-var-repeat: "\f01e"; +@fa-var-reply: "\f112"; +@fa-var-reply-all: "\f122"; +@fa-var-resistance: "\f1d0"; +@fa-var-retweet: "\f079"; +@fa-var-rmb: "\f157"; +@fa-var-road: "\f018"; +@fa-var-rocket: "\f135"; +@fa-var-rotate-left: "\f0e2"; +@fa-var-rotate-right: "\f01e"; +@fa-var-rouble: "\f158"; +@fa-var-rss: "\f09e"; +@fa-var-rss-square: "\f143"; +@fa-var-rub: "\f158"; +@fa-var-ruble: "\f158"; +@fa-var-rupee: "\f156"; +@fa-var-s15: "\f2cd"; +@fa-var-safari: "\f267"; +@fa-var-save: "\f0c7"; +@fa-var-scissors: "\f0c4"; +@fa-var-scribd: "\f28a"; +@fa-var-search: "\f002"; +@fa-var-search-minus: "\f010"; +@fa-var-search-plus: "\f00e"; +@fa-var-sellsy: "\f213"; +@fa-var-send: "\f1d8"; +@fa-var-send-o: "\f1d9"; +@fa-var-server: "\f233"; +@fa-var-share: "\f064"; +@fa-var-share-alt: "\f1e0"; +@fa-var-share-alt-square: "\f1e1"; +@fa-var-share-square: "\f14d"; +@fa-var-share-square-o: "\f045"; +@fa-var-shekel: "\f20b"; +@fa-var-sheqel: "\f20b"; +@fa-var-shield: "\f132"; +@fa-var-ship: "\f21a"; +@fa-var-shirtsinbulk: "\f214"; +@fa-var-shopping-bag: "\f290"; +@fa-var-shopping-basket: "\f291"; +@fa-var-shopping-cart: "\f07a"; +@fa-var-shower: "\f2cc"; +@fa-var-sign-in: "\f090"; +@fa-var-sign-language: "\f2a7"; +@fa-var-sign-out: "\f08b"; +@fa-var-signal: "\f012"; +@fa-var-signing: "\f2a7"; +@fa-var-simplybuilt: "\f215"; +@fa-var-sitemap: "\f0e8"; +@fa-var-skyatlas: "\f216"; +@fa-var-skype: "\f17e"; +@fa-var-slack: "\f198"; +@fa-var-sliders: "\f1de"; +@fa-var-slideshare: "\f1e7"; +@fa-var-smile-o: "\f118"; +@fa-var-snapchat: "\f2ab"; +@fa-var-snapchat-ghost: "\f2ac"; +@fa-var-snapchat-square: "\f2ad"; +@fa-var-snowflake-o: "\f2dc"; +@fa-var-soccer-ball-o: "\f1e3"; +@fa-var-sort: "\f0dc"; +@fa-var-sort-alpha-asc: "\f15d"; +@fa-var-sort-alpha-desc: "\f15e"; +@fa-var-sort-amount-asc: "\f160"; +@fa-var-sort-amount-desc: "\f161"; +@fa-var-sort-asc: "\f0de"; +@fa-var-sort-desc: "\f0dd"; +@fa-var-sort-down: "\f0dd"; +@fa-var-sort-numeric-asc: "\f162"; +@fa-var-sort-numeric-desc: "\f163"; +@fa-var-sort-up: "\f0de"; +@fa-var-soundcloud: "\f1be"; +@fa-var-space-shuttle: "\f197"; +@fa-var-spinner: "\f110"; +@fa-var-spoon: "\f1b1"; +@fa-var-spotify: "\f1bc"; +@fa-var-square: "\f0c8"; +@fa-var-square-o: "\f096"; +@fa-var-stack-exchange: "\f18d"; +@fa-var-stack-overflow: "\f16c"; +@fa-var-star: "\f005"; +@fa-var-star-half: "\f089"; +@fa-var-star-half-empty: "\f123"; +@fa-var-star-half-full: "\f123"; +@fa-var-star-half-o: "\f123"; +@fa-var-star-o: "\f006"; +@fa-var-steam: "\f1b6"; +@fa-var-steam-square: "\f1b7"; +@fa-var-step-backward: "\f048"; +@fa-var-step-forward: "\f051"; +@fa-var-stethoscope: "\f0f1"; +@fa-var-sticky-note: "\f249"; +@fa-var-sticky-note-o: "\f24a"; +@fa-var-stop: "\f04d"; +@fa-var-stop-circle: "\f28d"; +@fa-var-stop-circle-o: "\f28e"; +@fa-var-street-view: "\f21d"; +@fa-var-strikethrough: "\f0cc"; +@fa-var-stumbleupon: "\f1a4"; +@fa-var-stumbleupon-circle: "\f1a3"; +@fa-var-subscript: "\f12c"; +@fa-var-subway: "\f239"; +@fa-var-suitcase: "\f0f2"; +@fa-var-sun-o: "\f185"; +@fa-var-superpowers: "\f2dd"; +@fa-var-superscript: "\f12b"; +@fa-var-support: "\f1cd"; +@fa-var-table: "\f0ce"; +@fa-var-tablet: "\f10a"; +@fa-var-tachometer: "\f0e4"; +@fa-var-tag: "\f02b"; +@fa-var-tags: "\f02c"; +@fa-var-tasks: "\f0ae"; +@fa-var-taxi: "\f1ba"; +@fa-var-telegram: "\f2c6"; +@fa-var-television: "\f26c"; +@fa-var-tencent-weibo: "\f1d5"; +@fa-var-terminal: "\f120"; +@fa-var-text-height: "\f034"; +@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"; +@fa-var-thumbs-o-up: "\f087"; +@fa-var-thumbs-up: "\f164"; +@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"; +@fa-var-toggle-off: "\f204"; +@fa-var-toggle-on: "\f205"; +@fa-var-toggle-right: "\f152"; +@fa-var-toggle-up: "\f151"; +@fa-var-trademark: "\f25c"; +@fa-var-train: "\f238"; +@fa-var-transgender: "\f224"; +@fa-var-transgender-alt: "\f225"; +@fa-var-trash: "\f1f8"; +@fa-var-trash-o: "\f014"; +@fa-var-tree: "\f1bb"; +@fa-var-trello: "\f181"; +@fa-var-tripadvisor: "\f262"; +@fa-var-trophy: "\f091"; +@fa-var-truck: "\f0d1"; +@fa-var-try: "\f195"; +@fa-var-tty: "\f1e4"; +@fa-var-tumblr: "\f173"; +@fa-var-tumblr-square: "\f174"; +@fa-var-turkish-lira: "\f195"; +@fa-var-tv: "\f26c"; +@fa-var-twitch: "\f1e8"; +@fa-var-twitter: "\f099"; +@fa-var-twitter-square: "\f081"; +@fa-var-umbrella: "\f0e9"; +@fa-var-underline: "\f0cd"; +@fa-var-undo: "\f0e2"; +@fa-var-universal-access: "\f29a"; +@fa-var-university: "\f19c"; +@fa-var-unlink: "\f127"; +@fa-var-unlock: "\f09c"; +@fa-var-unlock-alt: "\f13e"; +@fa-var-unsorted: "\f0dc"; +@fa-var-upload: "\f093"; +@fa-var-usb: "\f287"; +@fa-var-usd: "\f155"; +@fa-var-user: "\f007"; +@fa-var-user-circle: "\f2bd"; +@fa-var-user-circle-o: "\f2be"; +@fa-var-user-md: "\f0f0"; +@fa-var-user-o: "\f2c0"; +@fa-var-user-plus: "\f234"; +@fa-var-user-secret: "\f21b"; +@fa-var-user-times: "\f235"; +@fa-var-users: "\f0c0"; +@fa-var-vcard: "\f2bb"; +@fa-var-vcard-o: "\f2bc"; +@fa-var-venus: "\f221"; +@fa-var-venus-double: "\f226"; +@fa-var-venus-mars: "\f228"; +@fa-var-viacoin: "\f237"; +@fa-var-viadeo: "\f2a9"; +@fa-var-viadeo-square: "\f2aa"; +@fa-var-video-camera: "\f03d"; +@fa-var-vimeo: "\f27d"; +@fa-var-vimeo-square: "\f194"; +@fa-var-vine: "\f1ca"; +@fa-var-vk: "\f189"; +@fa-var-volume-control-phone: "\f2a0"; +@fa-var-volume-down: "\f027"; +@fa-var-volume-off: "\f026"; +@fa-var-volume-up: "\f028"; +@fa-var-warning: "\f071"; +@fa-var-wechat: "\f1d7"; +@fa-var-weibo: "\f18a"; +@fa-var-weixin: "\f1d7"; +@fa-var-whatsapp: "\f232"; +@fa-var-wheelchair: "\f193"; +@fa-var-wheelchair-alt: "\f29b"; +@fa-var-wifi: "\f1eb"; +@fa-var-wikipedia-w: "\f266"; +@fa-var-window-close: "\f2d3"; +@fa-var-window-close-o: "\f2d4"; +@fa-var-window-maximize: "\f2d0"; +@fa-var-window-minimize: "\f2d1"; +@fa-var-window-restore: "\f2d2"; +@fa-var-windows: "\f17a"; +@fa-var-won: "\f159"; +@fa-var-wordpress: "\f19a"; +@fa-var-wpbeginner: "\f297"; +@fa-var-wpexplorer: "\f2de"; +@fa-var-wpforms: "\f298"; +@fa-var-wrench: "\f0ad"; +@fa-var-xing: "\f168"; +@fa-var-xing-square: "\f169"; +@fa-var-y-combinator: "\f23b"; +@fa-var-y-combinator-square: "\f1d4"; +@fa-var-yahoo: "\f19e"; +@fa-var-yc: "\f23b"; +@fa-var-yc-square: "\f1d4"; +@fa-var-yelp: "\f1e9"; +@fa-var-yen: "\f157"; +@fa-var-yoast: "\f2b1"; +@fa-var-youtube: "\f167"; +@fa-var-youtube-play: "\f16a"; +@fa-var-youtube-square: "\f166"; + diff --git a/static/font-awesome/scss/_animated.scss b/static/font-awesome/scss/_animated.scss new file mode 100644 index 0000000..8a020db --- /dev/null +++ b/static/font-awesome/scss/_animated.scss @@ -0,0 +1,34 @@ +// Spinning Icons +// -------------------------- + +.#{$fa-css-prefix}-spin { + -webkit-animation: fa-spin 2s infinite linear; + animation: fa-spin 2s infinite linear; +} + +.#{$fa-css-prefix}-pulse { + -webkit-animation: fa-spin 1s infinite steps(8); + animation: fa-spin 1s infinite steps(8); +} + +@-webkit-keyframes fa-spin { + 0% { + -webkit-transform: rotate(0deg); + 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); + } +} diff --git a/static/font-awesome/scss/_bordered-pulled.scss b/static/font-awesome/scss/_bordered-pulled.scss new file mode 100644 index 0000000..d4b85a0 --- /dev/null +++ b/static/font-awesome/scss/_bordered-pulled.scss @@ -0,0 +1,25 @@ +// Bordered & Pulled +// ------------------------- + +.#{$fa-css-prefix}-border { + padding: .2em .25em .15em; + border: solid .08em $fa-border-color; + border-radius: .1em; +} + +.#{$fa-css-prefix}-pull-left { float: left; } +.#{$fa-css-prefix}-pull-right { float: right; } + +.#{$fa-css-prefix} { + &.#{$fa-css-prefix}-pull-left { margin-right: .3em; } + &.#{$fa-css-prefix}-pull-right { margin-left: .3em; } +} + +/* Deprecated as of 4.4.0 */ +.pull-right { float: right; } +.pull-left { float: left; } + +.#{$fa-css-prefix} { + &.pull-left { margin-right: .3em; } + &.pull-right { margin-left: .3em; } +} diff --git a/static/font-awesome/scss/_core.scss b/static/font-awesome/scss/_core.scss new file mode 100644 index 0000000..7425ef8 --- /dev/null +++ b/static/font-awesome/scss/_core.scss @@ -0,0 +1,12 @@ +// Base Class Definition +// ------------------------- + +.#{$fa-css-prefix} { + display: inline-block; + font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration + font-size: inherit; // can't have font-size inherit on line above, so need to override + text-rendering: auto; // optimizelegibility throws things off #1094 + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + +} diff --git a/static/font-awesome/scss/_fixed-width.scss b/static/font-awesome/scss/_fixed-width.scss new file mode 100644 index 0000000..b221c98 --- /dev/null +++ b/static/font-awesome/scss/_fixed-width.scss @@ -0,0 +1,6 @@ +// Fixed Width Icons +// ------------------------- +.#{$fa-css-prefix}-fw { + width: (18em / 14); + text-align: center; +} diff --git a/static/font-awesome/scss/_icons.scss b/static/font-awesome/scss/_icons.scss new file mode 100644 index 0000000..e63e702 --- /dev/null +++ b/static/font-awesome/scss/_icons.scss @@ -0,0 +1,789 @@ +/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen + readers do not read off random characters that represent icons */ + +.#{$fa-css-prefix}-glass:before { content: $fa-var-glass; } +.#{$fa-css-prefix}-music:before { content: $fa-var-music; } +.#{$fa-css-prefix}-search:before { content: $fa-var-search; } +.#{$fa-css-prefix}-envelope-o:before { content: $fa-var-envelope-o; } +.#{$fa-css-prefix}-heart:before { content: $fa-var-heart; } +.#{$fa-css-prefix}-star:before { content: $fa-var-star; } +.#{$fa-css-prefix}-star-o:before { content: $fa-var-star-o; } +.#{$fa-css-prefix}-user:before { content: $fa-var-user; } +.#{$fa-css-prefix}-film:before { content: $fa-var-film; } +.#{$fa-css-prefix}-th-large:before { content: $fa-var-th-large; } +.#{$fa-css-prefix}-th:before { content: $fa-var-th; } +.#{$fa-css-prefix}-th-list:before { content: $fa-var-th-list; } +.#{$fa-css-prefix}-check:before { content: $fa-var-check; } +.#{$fa-css-prefix}-remove:before, +.#{$fa-css-prefix}-close:before, +.#{$fa-css-prefix}-times:before { content: $fa-var-times; } +.#{$fa-css-prefix}-search-plus:before { content: $fa-var-search-plus; } +.#{$fa-css-prefix}-search-minus:before { content: $fa-var-search-minus; } +.#{$fa-css-prefix}-power-off:before { content: $fa-var-power-off; } +.#{$fa-css-prefix}-signal:before { content: $fa-var-signal; } +.#{$fa-css-prefix}-gear:before, +.#{$fa-css-prefix}-cog:before { content: $fa-var-cog; } +.#{$fa-css-prefix}-trash-o:before { content: $fa-var-trash-o; } +.#{$fa-css-prefix}-home:before { content: $fa-var-home; } +.#{$fa-css-prefix}-file-o:before { content: $fa-var-file-o; } +.#{$fa-css-prefix}-clock-o:before { content: $fa-var-clock-o; } +.#{$fa-css-prefix}-road:before { content: $fa-var-road; } +.#{$fa-css-prefix}-download:before { content: $fa-var-download; } +.#{$fa-css-prefix}-arrow-circle-o-down:before { content: $fa-var-arrow-circle-o-down; } +.#{$fa-css-prefix}-arrow-circle-o-up:before { content: $fa-var-arrow-circle-o-up; } +.#{$fa-css-prefix}-inbox:before { content: $fa-var-inbox; } +.#{$fa-css-prefix}-play-circle-o:before { content: $fa-var-play-circle-o; } +.#{$fa-css-prefix}-rotate-right:before, +.#{$fa-css-prefix}-repeat:before { content: $fa-var-repeat; } +.#{$fa-css-prefix}-refresh:before { content: $fa-var-refresh; } +.#{$fa-css-prefix}-list-alt:before { content: $fa-var-list-alt; } +.#{$fa-css-prefix}-lock:before { content: $fa-var-lock; } +.#{$fa-css-prefix}-flag:before { content: $fa-var-flag; } +.#{$fa-css-prefix}-headphones:before { content: $fa-var-headphones; } +.#{$fa-css-prefix}-volume-off:before { content: $fa-var-volume-off; } +.#{$fa-css-prefix}-volume-down:before { content: $fa-var-volume-down; } +.#{$fa-css-prefix}-volume-up:before { content: $fa-var-volume-up; } +.#{$fa-css-prefix}-qrcode:before { content: $fa-var-qrcode; } +.#{$fa-css-prefix}-barcode:before { content: $fa-var-barcode; } +.#{$fa-css-prefix}-tag:before { content: $fa-var-tag; } +.#{$fa-css-prefix}-tags:before { content: $fa-var-tags; } +.#{$fa-css-prefix}-book:before { content: $fa-var-book; } +.#{$fa-css-prefix}-bookmark:before { content: $fa-var-bookmark; } +.#{$fa-css-prefix}-print:before { content: $fa-var-print; } +.#{$fa-css-prefix}-camera:before { content: $fa-var-camera; } +.#{$fa-css-prefix}-font:before { content: $fa-var-font; } +.#{$fa-css-prefix}-bold:before { content: $fa-var-bold; } +.#{$fa-css-prefix}-italic:before { content: $fa-var-italic; } +.#{$fa-css-prefix}-text-height:before { content: $fa-var-text-height; } +.#{$fa-css-prefix}-text-width:before { content: $fa-var-text-width; } +.#{$fa-css-prefix}-align-left:before { content: $fa-var-align-left; } +.#{$fa-css-prefix}-align-center:before { content: $fa-var-align-center; } +.#{$fa-css-prefix}-align-right:before { content: $fa-var-align-right; } +.#{$fa-css-prefix}-align-justify:before { content: $fa-var-align-justify; } +.#{$fa-css-prefix}-list:before { content: $fa-var-list; } +.#{$fa-css-prefix}-dedent:before, +.#{$fa-css-prefix}-outdent:before { content: $fa-var-outdent; } +.#{$fa-css-prefix}-indent:before { content: $fa-var-indent; } +.#{$fa-css-prefix}-video-camera:before { content: $fa-var-video-camera; } +.#{$fa-css-prefix}-photo:before, +.#{$fa-css-prefix}-image:before, +.#{$fa-css-prefix}-picture-o:before { content: $fa-var-picture-o; } +.#{$fa-css-prefix}-pencil:before { content: $fa-var-pencil; } +.#{$fa-css-prefix}-map-marker:before { content: $fa-var-map-marker; } +.#{$fa-css-prefix}-adjust:before { content: $fa-var-adjust; } +.#{$fa-css-prefix}-tint:before { content: $fa-var-tint; } +.#{$fa-css-prefix}-edit:before, +.#{$fa-css-prefix}-pencil-square-o:before { content: $fa-var-pencil-square-o; } +.#{$fa-css-prefix}-share-square-o:before { content: $fa-var-share-square-o; } +.#{$fa-css-prefix}-check-square-o:before { content: $fa-var-check-square-o; } +.#{$fa-css-prefix}-arrows:before { content: $fa-var-arrows; } +.#{$fa-css-prefix}-step-backward:before { content: $fa-var-step-backward; } +.#{$fa-css-prefix}-fast-backward:before { content: $fa-var-fast-backward; } +.#{$fa-css-prefix}-backward:before { content: $fa-var-backward; } +.#{$fa-css-prefix}-play:before { content: $fa-var-play; } +.#{$fa-css-prefix}-pause:before { content: $fa-var-pause; } +.#{$fa-css-prefix}-stop:before { content: $fa-var-stop; } +.#{$fa-css-prefix}-forward:before { content: $fa-var-forward; } +.#{$fa-css-prefix}-fast-forward:before { content: $fa-var-fast-forward; } +.#{$fa-css-prefix}-step-forward:before { content: $fa-var-step-forward; } +.#{$fa-css-prefix}-eject:before { content: $fa-var-eject; } +.#{$fa-css-prefix}-chevron-left:before { content: $fa-var-chevron-left; } +.#{$fa-css-prefix}-chevron-right:before { content: $fa-var-chevron-right; } +.#{$fa-css-prefix}-plus-circle:before { content: $fa-var-plus-circle; } +.#{$fa-css-prefix}-minus-circle:before { content: $fa-var-minus-circle; } +.#{$fa-css-prefix}-times-circle:before { content: $fa-var-times-circle; } +.#{$fa-css-prefix}-check-circle:before { content: $fa-var-check-circle; } +.#{$fa-css-prefix}-question-circle:before { content: $fa-var-question-circle; } +.#{$fa-css-prefix}-info-circle:before { content: $fa-var-info-circle; } +.#{$fa-css-prefix}-crosshairs:before { content: $fa-var-crosshairs; } +.#{$fa-css-prefix}-times-circle-o:before { content: $fa-var-times-circle-o; } +.#{$fa-css-prefix}-check-circle-o:before { content: $fa-var-check-circle-o; } +.#{$fa-css-prefix}-ban:before { content: $fa-var-ban; } +.#{$fa-css-prefix}-arrow-left:before { content: $fa-var-arrow-left; } +.#{$fa-css-prefix}-arrow-right:before { content: $fa-var-arrow-right; } +.#{$fa-css-prefix}-arrow-up:before { content: $fa-var-arrow-up; } +.#{$fa-css-prefix}-arrow-down:before { content: $fa-var-arrow-down; } +.#{$fa-css-prefix}-mail-forward:before, +.#{$fa-css-prefix}-share:before { content: $fa-var-share; } +.#{$fa-css-prefix}-expand:before { content: $fa-var-expand; } +.#{$fa-css-prefix}-compress:before { content: $fa-var-compress; } +.#{$fa-css-prefix}-plus:before { content: $fa-var-plus; } +.#{$fa-css-prefix}-minus:before { content: $fa-var-minus; } +.#{$fa-css-prefix}-asterisk:before { content: $fa-var-asterisk; } +.#{$fa-css-prefix}-exclamation-circle:before { content: $fa-var-exclamation-circle; } +.#{$fa-css-prefix}-gift:before { content: $fa-var-gift; } +.#{$fa-css-prefix}-leaf:before { content: $fa-var-leaf; } +.#{$fa-css-prefix}-fire:before { content: $fa-var-fire; } +.#{$fa-css-prefix}-eye:before { content: $fa-var-eye; } +.#{$fa-css-prefix}-eye-slash:before { content: $fa-var-eye-slash; } +.#{$fa-css-prefix}-warning:before, +.#{$fa-css-prefix}-exclamation-triangle:before { content: $fa-var-exclamation-triangle; } +.#{$fa-css-prefix}-plane:before { content: $fa-var-plane; } +.#{$fa-css-prefix}-calendar:before { content: $fa-var-calendar; } +.#{$fa-css-prefix}-random:before { content: $fa-var-random; } +.#{$fa-css-prefix}-comment:before { content: $fa-var-comment; } +.#{$fa-css-prefix}-magnet:before { content: $fa-var-magnet; } +.#{$fa-css-prefix}-chevron-up:before { content: $fa-var-chevron-up; } +.#{$fa-css-prefix}-chevron-down:before { content: $fa-var-chevron-down; } +.#{$fa-css-prefix}-retweet:before { content: $fa-var-retweet; } +.#{$fa-css-prefix}-shopping-cart:before { content: $fa-var-shopping-cart; } +.#{$fa-css-prefix}-folder:before { content: $fa-var-folder; } +.#{$fa-css-prefix}-folder-open:before { content: $fa-var-folder-open; } +.#{$fa-css-prefix}-arrows-v:before { content: $fa-var-arrows-v; } +.#{$fa-css-prefix}-arrows-h:before { content: $fa-var-arrows-h; } +.#{$fa-css-prefix}-bar-chart-o:before, +.#{$fa-css-prefix}-bar-chart:before { content: $fa-var-bar-chart; } +.#{$fa-css-prefix}-twitter-square:before { content: $fa-var-twitter-square; } +.#{$fa-css-prefix}-facebook-square:before { content: $fa-var-facebook-square; } +.#{$fa-css-prefix}-camera-retro:before { content: $fa-var-camera-retro; } +.#{$fa-css-prefix}-key:before { content: $fa-var-key; } +.#{$fa-css-prefix}-gears:before, +.#{$fa-css-prefix}-cogs:before { content: $fa-var-cogs; } +.#{$fa-css-prefix}-comments:before { content: $fa-var-comments; } +.#{$fa-css-prefix}-thumbs-o-up:before { content: $fa-var-thumbs-o-up; } +.#{$fa-css-prefix}-thumbs-o-down:before { content: $fa-var-thumbs-o-down; } +.#{$fa-css-prefix}-star-half:before { content: $fa-var-star-half; } +.#{$fa-css-prefix}-heart-o:before { content: $fa-var-heart-o; } +.#{$fa-css-prefix}-sign-out:before { content: $fa-var-sign-out; } +.#{$fa-css-prefix}-linkedin-square:before { content: $fa-var-linkedin-square; } +.#{$fa-css-prefix}-thumb-tack:before { content: $fa-var-thumb-tack; } +.#{$fa-css-prefix}-external-link:before { content: $fa-var-external-link; } +.#{$fa-css-prefix}-sign-in:before { content: $fa-var-sign-in; } +.#{$fa-css-prefix}-trophy:before { content: $fa-var-trophy; } +.#{$fa-css-prefix}-github-square:before { content: $fa-var-github-square; } +.#{$fa-css-prefix}-upload:before { content: $fa-var-upload; } +.#{$fa-css-prefix}-lemon-o:before { content: $fa-var-lemon-o; } +.#{$fa-css-prefix}-phone:before { content: $fa-var-phone; } +.#{$fa-css-prefix}-square-o:before { content: $fa-var-square-o; } +.#{$fa-css-prefix}-bookmark-o:before { content: $fa-var-bookmark-o; } +.#{$fa-css-prefix}-phone-square:before { content: $fa-var-phone-square; } +.#{$fa-css-prefix}-twitter:before { content: $fa-var-twitter; } +.#{$fa-css-prefix}-facebook-f:before, +.#{$fa-css-prefix}-facebook:before { content: $fa-var-facebook; } +.#{$fa-css-prefix}-github:before { content: $fa-var-github; } +.#{$fa-css-prefix}-unlock:before { content: $fa-var-unlock; } +.#{$fa-css-prefix}-credit-card:before { content: $fa-var-credit-card; } +.#{$fa-css-prefix}-feed:before, +.#{$fa-css-prefix}-rss:before { content: $fa-var-rss; } +.#{$fa-css-prefix}-hdd-o:before { content: $fa-var-hdd-o; } +.#{$fa-css-prefix}-bullhorn:before { content: $fa-var-bullhorn; } +.#{$fa-css-prefix}-bell:before { content: $fa-var-bell; } +.#{$fa-css-prefix}-certificate:before { content: $fa-var-certificate; } +.#{$fa-css-prefix}-hand-o-right:before { content: $fa-var-hand-o-right; } +.#{$fa-css-prefix}-hand-o-left:before { content: $fa-var-hand-o-left; } +.#{$fa-css-prefix}-hand-o-up:before { content: $fa-var-hand-o-up; } +.#{$fa-css-prefix}-hand-o-down:before { content: $fa-var-hand-o-down; } +.#{$fa-css-prefix}-arrow-circle-left:before { content: $fa-var-arrow-circle-left; } +.#{$fa-css-prefix}-arrow-circle-right:before { content: $fa-var-arrow-circle-right; } +.#{$fa-css-prefix}-arrow-circle-up:before { content: $fa-var-arrow-circle-up; } +.#{$fa-css-prefix}-arrow-circle-down:before { content: $fa-var-arrow-circle-down; } +.#{$fa-css-prefix}-globe:before { content: $fa-var-globe; } +.#{$fa-css-prefix}-wrench:before { content: $fa-var-wrench; } +.#{$fa-css-prefix}-tasks:before { content: $fa-var-tasks; } +.#{$fa-css-prefix}-filter:before { content: $fa-var-filter; } +.#{$fa-css-prefix}-briefcase:before { content: $fa-var-briefcase; } +.#{$fa-css-prefix}-arrows-alt:before { content: $fa-var-arrows-alt; } +.#{$fa-css-prefix}-group:before, +.#{$fa-css-prefix}-users:before { content: $fa-var-users; } +.#{$fa-css-prefix}-chain:before, +.#{$fa-css-prefix}-link:before { content: $fa-var-link; } +.#{$fa-css-prefix}-cloud:before { content: $fa-var-cloud; } +.#{$fa-css-prefix}-flask:before { content: $fa-var-flask; } +.#{$fa-css-prefix}-cut:before, +.#{$fa-css-prefix}-scissors:before { content: $fa-var-scissors; } +.#{$fa-css-prefix}-copy:before, +.#{$fa-css-prefix}-files-o:before { content: $fa-var-files-o; } +.#{$fa-css-prefix}-paperclip:before { content: $fa-var-paperclip; } +.#{$fa-css-prefix}-save:before, +.#{$fa-css-prefix}-floppy-o:before { content: $fa-var-floppy-o; } +.#{$fa-css-prefix}-square:before { content: $fa-var-square; } +.#{$fa-css-prefix}-navicon:before, +.#{$fa-css-prefix}-reorder:before, +.#{$fa-css-prefix}-bars:before { content: $fa-var-bars; } +.#{$fa-css-prefix}-list-ul:before { content: $fa-var-list-ul; } +.#{$fa-css-prefix}-list-ol:before { content: $fa-var-list-ol; } +.#{$fa-css-prefix}-strikethrough:before { content: $fa-var-strikethrough; } +.#{$fa-css-prefix}-underline:before { content: $fa-var-underline; } +.#{$fa-css-prefix}-table:before { content: $fa-var-table; } +.#{$fa-css-prefix}-magic:before { content: $fa-var-magic; } +.#{$fa-css-prefix}-truck:before { content: $fa-var-truck; } +.#{$fa-css-prefix}-pinterest:before { content: $fa-var-pinterest; } +.#{$fa-css-prefix}-pinterest-square:before { content: $fa-var-pinterest-square; } +.#{$fa-css-prefix}-google-plus-square:before { content: $fa-var-google-plus-square; } +.#{$fa-css-prefix}-google-plus:before { content: $fa-var-google-plus; } +.#{$fa-css-prefix}-money:before { content: $fa-var-money; } +.#{$fa-css-prefix}-caret-down:before { content: $fa-var-caret-down; } +.#{$fa-css-prefix}-caret-up:before { content: $fa-var-caret-up; } +.#{$fa-css-prefix}-caret-left:before { content: $fa-var-caret-left; } +.#{$fa-css-prefix}-caret-right:before { content: $fa-var-caret-right; } +.#{$fa-css-prefix}-columns:before { content: $fa-var-columns; } +.#{$fa-css-prefix}-unsorted:before, +.#{$fa-css-prefix}-sort:before { content: $fa-var-sort; } +.#{$fa-css-prefix}-sort-down:before, +.#{$fa-css-prefix}-sort-desc:before { content: $fa-var-sort-desc; } +.#{$fa-css-prefix}-sort-up:before, +.#{$fa-css-prefix}-sort-asc:before { content: $fa-var-sort-asc; } +.#{$fa-css-prefix}-envelope:before { content: $fa-var-envelope; } +.#{$fa-css-prefix}-linkedin:before { content: $fa-var-linkedin; } +.#{$fa-css-prefix}-rotate-left:before, +.#{$fa-css-prefix}-undo:before { content: $fa-var-undo; } +.#{$fa-css-prefix}-legal:before, +.#{$fa-css-prefix}-gavel:before { content: $fa-var-gavel; } +.#{$fa-css-prefix}-dashboard:before, +.#{$fa-css-prefix}-tachometer:before { content: $fa-var-tachometer; } +.#{$fa-css-prefix}-comment-o:before { content: $fa-var-comment-o; } +.#{$fa-css-prefix}-comments-o:before { content: $fa-var-comments-o; } +.#{$fa-css-prefix}-flash:before, +.#{$fa-css-prefix}-bolt:before { content: $fa-var-bolt; } +.#{$fa-css-prefix}-sitemap:before { content: $fa-var-sitemap; } +.#{$fa-css-prefix}-umbrella:before { content: $fa-var-umbrella; } +.#{$fa-css-prefix}-paste:before, +.#{$fa-css-prefix}-clipboard:before { content: $fa-var-clipboard; } +.#{$fa-css-prefix}-lightbulb-o:before { content: $fa-var-lightbulb-o; } +.#{$fa-css-prefix}-exchange:before { content: $fa-var-exchange; } +.#{$fa-css-prefix}-cloud-download:before { content: $fa-var-cloud-download; } +.#{$fa-css-prefix}-cloud-upload:before { content: $fa-var-cloud-upload; } +.#{$fa-css-prefix}-user-md:before { content: $fa-var-user-md; } +.#{$fa-css-prefix}-stethoscope:before { content: $fa-var-stethoscope; } +.#{$fa-css-prefix}-suitcase:before { content: $fa-var-suitcase; } +.#{$fa-css-prefix}-bell-o:before { content: $fa-var-bell-o; } +.#{$fa-css-prefix}-coffee:before { content: $fa-var-coffee; } +.#{$fa-css-prefix}-cutlery:before { content: $fa-var-cutlery; } +.#{$fa-css-prefix}-file-text-o:before { content: $fa-var-file-text-o; } +.#{$fa-css-prefix}-building-o:before { content: $fa-var-building-o; } +.#{$fa-css-prefix}-hospital-o:before { content: $fa-var-hospital-o; } +.#{$fa-css-prefix}-ambulance:before { content: $fa-var-ambulance; } +.#{$fa-css-prefix}-medkit:before { content: $fa-var-medkit; } +.#{$fa-css-prefix}-fighter-jet:before { content: $fa-var-fighter-jet; } +.#{$fa-css-prefix}-beer:before { content: $fa-var-beer; } +.#{$fa-css-prefix}-h-square:before { content: $fa-var-h-square; } +.#{$fa-css-prefix}-plus-square:before { content: $fa-var-plus-square; } +.#{$fa-css-prefix}-angle-double-left:before { content: $fa-var-angle-double-left; } +.#{$fa-css-prefix}-angle-double-right:before { content: $fa-var-angle-double-right; } +.#{$fa-css-prefix}-angle-double-up:before { content: $fa-var-angle-double-up; } +.#{$fa-css-prefix}-angle-double-down:before { content: $fa-var-angle-double-down; } +.#{$fa-css-prefix}-angle-left:before { content: $fa-var-angle-left; } +.#{$fa-css-prefix}-angle-right:before { content: $fa-var-angle-right; } +.#{$fa-css-prefix}-angle-up:before { content: $fa-var-angle-up; } +.#{$fa-css-prefix}-angle-down:before { content: $fa-var-angle-down; } +.#{$fa-css-prefix}-desktop:before { content: $fa-var-desktop; } +.#{$fa-css-prefix}-laptop:before { content: $fa-var-laptop; } +.#{$fa-css-prefix}-tablet:before { content: $fa-var-tablet; } +.#{$fa-css-prefix}-mobile-phone:before, +.#{$fa-css-prefix}-mobile:before { content: $fa-var-mobile; } +.#{$fa-css-prefix}-circle-o:before { content: $fa-var-circle-o; } +.#{$fa-css-prefix}-quote-left:before { content: $fa-var-quote-left; } +.#{$fa-css-prefix}-quote-right:before { content: $fa-var-quote-right; } +.#{$fa-css-prefix}-spinner:before { content: $fa-var-spinner; } +.#{$fa-css-prefix}-circle:before { content: $fa-var-circle; } +.#{$fa-css-prefix}-mail-reply:before, +.#{$fa-css-prefix}-reply:before { content: $fa-var-reply; } +.#{$fa-css-prefix}-github-alt:before { content: $fa-var-github-alt; } +.#{$fa-css-prefix}-folder-o:before { content: $fa-var-folder-o; } +.#{$fa-css-prefix}-folder-open-o:before { content: $fa-var-folder-open-o; } +.#{$fa-css-prefix}-smile-o:before { content: $fa-var-smile-o; } +.#{$fa-css-prefix}-frown-o:before { content: $fa-var-frown-o; } +.#{$fa-css-prefix}-meh-o:before { content: $fa-var-meh-o; } +.#{$fa-css-prefix}-gamepad:before { content: $fa-var-gamepad; } +.#{$fa-css-prefix}-keyboard-o:before { content: $fa-var-keyboard-o; } +.#{$fa-css-prefix}-flag-o:before { content: $fa-var-flag-o; } +.#{$fa-css-prefix}-flag-checkered:before { content: $fa-var-flag-checkered; } +.#{$fa-css-prefix}-terminal:before { content: $fa-var-terminal; } +.#{$fa-css-prefix}-code:before { content: $fa-var-code; } +.#{$fa-css-prefix}-mail-reply-all:before, +.#{$fa-css-prefix}-reply-all:before { content: $fa-var-reply-all; } +.#{$fa-css-prefix}-star-half-empty:before, +.#{$fa-css-prefix}-star-half-full:before, +.#{$fa-css-prefix}-star-half-o:before { content: $fa-var-star-half-o; } +.#{$fa-css-prefix}-location-arrow:before { content: $fa-var-location-arrow; } +.#{$fa-css-prefix}-crop:before { content: $fa-var-crop; } +.#{$fa-css-prefix}-code-fork:before { content: $fa-var-code-fork; } +.#{$fa-css-prefix}-unlink:before, +.#{$fa-css-prefix}-chain-broken:before { content: $fa-var-chain-broken; } +.#{$fa-css-prefix}-question:before { content: $fa-var-question; } +.#{$fa-css-prefix}-info:before { content: $fa-var-info; } +.#{$fa-css-prefix}-exclamation:before { content: $fa-var-exclamation; } +.#{$fa-css-prefix}-superscript:before { content: $fa-var-superscript; } +.#{$fa-css-prefix}-subscript:before { content: $fa-var-subscript; } +.#{$fa-css-prefix}-eraser:before { content: $fa-var-eraser; } +.#{$fa-css-prefix}-puzzle-piece:before { content: $fa-var-puzzle-piece; } +.#{$fa-css-prefix}-microphone:before { content: $fa-var-microphone; } +.#{$fa-css-prefix}-microphone-slash:before { content: $fa-var-microphone-slash; } +.#{$fa-css-prefix}-shield:before { content: $fa-var-shield; } +.#{$fa-css-prefix}-calendar-o:before { content: $fa-var-calendar-o; } +.#{$fa-css-prefix}-fire-extinguisher:before { content: $fa-var-fire-extinguisher; } +.#{$fa-css-prefix}-rocket:before { content: $fa-var-rocket; } +.#{$fa-css-prefix}-maxcdn:before { content: $fa-var-maxcdn; } +.#{$fa-css-prefix}-chevron-circle-left:before { content: $fa-var-chevron-circle-left; } +.#{$fa-css-prefix}-chevron-circle-right:before { content: $fa-var-chevron-circle-right; } +.#{$fa-css-prefix}-chevron-circle-up:before { content: $fa-var-chevron-circle-up; } +.#{$fa-css-prefix}-chevron-circle-down:before { content: $fa-var-chevron-circle-down; } +.#{$fa-css-prefix}-html5:before { content: $fa-var-html5; } +.#{$fa-css-prefix}-css3:before { content: $fa-var-css3; } +.#{$fa-css-prefix}-anchor:before { content: $fa-var-anchor; } +.#{$fa-css-prefix}-unlock-alt:before { content: $fa-var-unlock-alt; } +.#{$fa-css-prefix}-bullseye:before { content: $fa-var-bullseye; } +.#{$fa-css-prefix}-ellipsis-h:before { content: $fa-var-ellipsis-h; } +.#{$fa-css-prefix}-ellipsis-v:before { content: $fa-var-ellipsis-v; } +.#{$fa-css-prefix}-rss-square:before { content: $fa-var-rss-square; } +.#{$fa-css-prefix}-play-circle:before { content: $fa-var-play-circle; } +.#{$fa-css-prefix}-ticket:before { content: $fa-var-ticket; } +.#{$fa-css-prefix}-minus-square:before { content: $fa-var-minus-square; } +.#{$fa-css-prefix}-minus-square-o:before { content: $fa-var-minus-square-o; } +.#{$fa-css-prefix}-level-up:before { content: $fa-var-level-up; } +.#{$fa-css-prefix}-level-down:before { content: $fa-var-level-down; } +.#{$fa-css-prefix}-check-square:before { content: $fa-var-check-square; } +.#{$fa-css-prefix}-pencil-square:before { content: $fa-var-pencil-square; } +.#{$fa-css-prefix}-external-link-square:before { content: $fa-var-external-link-square; } +.#{$fa-css-prefix}-share-square:before { content: $fa-var-share-square; } +.#{$fa-css-prefix}-compass:before { content: $fa-var-compass; } +.#{$fa-css-prefix}-toggle-down:before, +.#{$fa-css-prefix}-caret-square-o-down:before { content: $fa-var-caret-square-o-down; } +.#{$fa-css-prefix}-toggle-up:before, +.#{$fa-css-prefix}-caret-square-o-up:before { content: $fa-var-caret-square-o-up; } +.#{$fa-css-prefix}-toggle-right:before, +.#{$fa-css-prefix}-caret-square-o-right:before { content: $fa-var-caret-square-o-right; } +.#{$fa-css-prefix}-euro:before, +.#{$fa-css-prefix}-eur:before { content: $fa-var-eur; } +.#{$fa-css-prefix}-gbp:before { content: $fa-var-gbp; } +.#{$fa-css-prefix}-dollar:before, +.#{$fa-css-prefix}-usd:before { content: $fa-var-usd; } +.#{$fa-css-prefix}-rupee:before, +.#{$fa-css-prefix}-inr:before { content: $fa-var-inr; } +.#{$fa-css-prefix}-cny:before, +.#{$fa-css-prefix}-rmb:before, +.#{$fa-css-prefix}-yen:before, +.#{$fa-css-prefix}-jpy:before { content: $fa-var-jpy; } +.#{$fa-css-prefix}-ruble:before, +.#{$fa-css-prefix}-rouble:before, +.#{$fa-css-prefix}-rub:before { content: $fa-var-rub; } +.#{$fa-css-prefix}-won:before, +.#{$fa-css-prefix}-krw:before { content: $fa-var-krw; } +.#{$fa-css-prefix}-bitcoin:before, +.#{$fa-css-prefix}-btc:before { content: $fa-var-btc; } +.#{$fa-css-prefix}-file:before { content: $fa-var-file; } +.#{$fa-css-prefix}-file-text:before { content: $fa-var-file-text; } +.#{$fa-css-prefix}-sort-alpha-asc:before { content: $fa-var-sort-alpha-asc; } +.#{$fa-css-prefix}-sort-alpha-desc:before { content: $fa-var-sort-alpha-desc; } +.#{$fa-css-prefix}-sort-amount-asc:before { content: $fa-var-sort-amount-asc; } +.#{$fa-css-prefix}-sort-amount-desc:before { content: $fa-var-sort-amount-desc; } +.#{$fa-css-prefix}-sort-numeric-asc:before { content: $fa-var-sort-numeric-asc; } +.#{$fa-css-prefix}-sort-numeric-desc:before { content: $fa-var-sort-numeric-desc; } +.#{$fa-css-prefix}-thumbs-up:before { content: $fa-var-thumbs-up; } +.#{$fa-css-prefix}-thumbs-down:before { content: $fa-var-thumbs-down; } +.#{$fa-css-prefix}-youtube-square:before { content: $fa-var-youtube-square; } +.#{$fa-css-prefix}-youtube:before { content: $fa-var-youtube; } +.#{$fa-css-prefix}-xing:before { content: $fa-var-xing; } +.#{$fa-css-prefix}-xing-square:before { content: $fa-var-xing-square; } +.#{$fa-css-prefix}-youtube-play:before { content: $fa-var-youtube-play; } +.#{$fa-css-prefix}-dropbox:before { content: $fa-var-dropbox; } +.#{$fa-css-prefix}-stack-overflow:before { content: $fa-var-stack-overflow; } +.#{$fa-css-prefix}-instagram:before { content: $fa-var-instagram; } +.#{$fa-css-prefix}-flickr:before { content: $fa-var-flickr; } +.#{$fa-css-prefix}-adn:before { content: $fa-var-adn; } +.#{$fa-css-prefix}-bitbucket:before { content: $fa-var-bitbucket; } +.#{$fa-css-prefix}-bitbucket-square:before { content: $fa-var-bitbucket-square; } +.#{$fa-css-prefix}-tumblr:before { content: $fa-var-tumblr; } +.#{$fa-css-prefix}-tumblr-square:before { content: $fa-var-tumblr-square; } +.#{$fa-css-prefix}-long-arrow-down:before { content: $fa-var-long-arrow-down; } +.#{$fa-css-prefix}-long-arrow-up:before { content: $fa-var-long-arrow-up; } +.#{$fa-css-prefix}-long-arrow-left:before { content: $fa-var-long-arrow-left; } +.#{$fa-css-prefix}-long-arrow-right:before { content: $fa-var-long-arrow-right; } +.#{$fa-css-prefix}-apple:before { content: $fa-var-apple; } +.#{$fa-css-prefix}-windows:before { content: $fa-var-windows; } +.#{$fa-css-prefix}-android:before { content: $fa-var-android; } +.#{$fa-css-prefix}-linux:before { content: $fa-var-linux; } +.#{$fa-css-prefix}-dribbble:before { content: $fa-var-dribbble; } +.#{$fa-css-prefix}-skype:before { content: $fa-var-skype; } +.#{$fa-css-prefix}-foursquare:before { content: $fa-var-foursquare; } +.#{$fa-css-prefix}-trello:before { content: $fa-var-trello; } +.#{$fa-css-prefix}-female:before { content: $fa-var-female; } +.#{$fa-css-prefix}-male:before { content: $fa-var-male; } +.#{$fa-css-prefix}-gittip:before, +.#{$fa-css-prefix}-gratipay:before { content: $fa-var-gratipay; } +.#{$fa-css-prefix}-sun-o:before { content: $fa-var-sun-o; } +.#{$fa-css-prefix}-moon-o:before { content: $fa-var-moon-o; } +.#{$fa-css-prefix}-archive:before { content: $fa-var-archive; } +.#{$fa-css-prefix}-bug:before { content: $fa-var-bug; } +.#{$fa-css-prefix}-vk:before { content: $fa-var-vk; } +.#{$fa-css-prefix}-weibo:before { content: $fa-var-weibo; } +.#{$fa-css-prefix}-renren:before { content: $fa-var-renren; } +.#{$fa-css-prefix}-pagelines:before { content: $fa-var-pagelines; } +.#{$fa-css-prefix}-stack-exchange:before { content: $fa-var-stack-exchange; } +.#{$fa-css-prefix}-arrow-circle-o-right:before { content: $fa-var-arrow-circle-o-right; } +.#{$fa-css-prefix}-arrow-circle-o-left:before { content: $fa-var-arrow-circle-o-left; } +.#{$fa-css-prefix}-toggle-left:before, +.#{$fa-css-prefix}-caret-square-o-left:before { content: $fa-var-caret-square-o-left; } +.#{$fa-css-prefix}-dot-circle-o:before { content: $fa-var-dot-circle-o; } +.#{$fa-css-prefix}-wheelchair:before { content: $fa-var-wheelchair; } +.#{$fa-css-prefix}-vimeo-square:before { content: $fa-var-vimeo-square; } +.#{$fa-css-prefix}-turkish-lira:before, +.#{$fa-css-prefix}-try:before { content: $fa-var-try; } +.#{$fa-css-prefix}-plus-square-o:before { content: $fa-var-plus-square-o; } +.#{$fa-css-prefix}-space-shuttle:before { content: $fa-var-space-shuttle; } +.#{$fa-css-prefix}-slack:before { content: $fa-var-slack; } +.#{$fa-css-prefix}-envelope-square:before { content: $fa-var-envelope-square; } +.#{$fa-css-prefix}-wordpress:before { content: $fa-var-wordpress; } +.#{$fa-css-prefix}-openid:before { content: $fa-var-openid; } +.#{$fa-css-prefix}-institution:before, +.#{$fa-css-prefix}-bank:before, +.#{$fa-css-prefix}-university:before { content: $fa-var-university; } +.#{$fa-css-prefix}-mortar-board:before, +.#{$fa-css-prefix}-graduation-cap:before { content: $fa-var-graduation-cap; } +.#{$fa-css-prefix}-yahoo:before { content: $fa-var-yahoo; } +.#{$fa-css-prefix}-google:before { content: $fa-var-google; } +.#{$fa-css-prefix}-reddit:before { content: $fa-var-reddit; } +.#{$fa-css-prefix}-reddit-square:before { content: $fa-var-reddit-square; } +.#{$fa-css-prefix}-stumbleupon-circle:before { content: $fa-var-stumbleupon-circle; } +.#{$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-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; } +.#{$fa-css-prefix}-language:before { content: $fa-var-language; } +.#{$fa-css-prefix}-fax:before { content: $fa-var-fax; } +.#{$fa-css-prefix}-building:before { content: $fa-var-building; } +.#{$fa-css-prefix}-child:before { content: $fa-var-child; } +.#{$fa-css-prefix}-paw:before { content: $fa-var-paw; } +.#{$fa-css-prefix}-spoon:before { content: $fa-var-spoon; } +.#{$fa-css-prefix}-cube:before { content: $fa-var-cube; } +.#{$fa-css-prefix}-cubes:before { content: $fa-var-cubes; } +.#{$fa-css-prefix}-behance:before { content: $fa-var-behance; } +.#{$fa-css-prefix}-behance-square:before { content: $fa-var-behance-square; } +.#{$fa-css-prefix}-steam:before { content: $fa-var-steam; } +.#{$fa-css-prefix}-steam-square:before { content: $fa-var-steam-square; } +.#{$fa-css-prefix}-recycle:before { content: $fa-var-recycle; } +.#{$fa-css-prefix}-automobile:before, +.#{$fa-css-prefix}-car:before { content: $fa-var-car; } +.#{$fa-css-prefix}-cab:before, +.#{$fa-css-prefix}-taxi:before { content: $fa-var-taxi; } +.#{$fa-css-prefix}-tree:before { content: $fa-var-tree; } +.#{$fa-css-prefix}-spotify:before { content: $fa-var-spotify; } +.#{$fa-css-prefix}-deviantart:before { content: $fa-var-deviantart; } +.#{$fa-css-prefix}-soundcloud:before { content: $fa-var-soundcloud; } +.#{$fa-css-prefix}-database:before { content: $fa-var-database; } +.#{$fa-css-prefix}-file-pdf-o:before { content: $fa-var-file-pdf-o; } +.#{$fa-css-prefix}-file-word-o:before { content: $fa-var-file-word-o; } +.#{$fa-css-prefix}-file-excel-o:before { content: $fa-var-file-excel-o; } +.#{$fa-css-prefix}-file-powerpoint-o:before { content: $fa-var-file-powerpoint-o; } +.#{$fa-css-prefix}-file-photo-o:before, +.#{$fa-css-prefix}-file-picture-o:before, +.#{$fa-css-prefix}-file-image-o:before { content: $fa-var-file-image-o; } +.#{$fa-css-prefix}-file-zip-o:before, +.#{$fa-css-prefix}-file-archive-o:before { content: $fa-var-file-archive-o; } +.#{$fa-css-prefix}-file-sound-o:before, +.#{$fa-css-prefix}-file-audio-o:before { content: $fa-var-file-audio-o; } +.#{$fa-css-prefix}-file-movie-o:before, +.#{$fa-css-prefix}-file-video-o:before { content: $fa-var-file-video-o; } +.#{$fa-css-prefix}-file-code-o:before { content: $fa-var-file-code-o; } +.#{$fa-css-prefix}-vine:before { content: $fa-var-vine; } +.#{$fa-css-prefix}-codepen:before { content: $fa-var-codepen; } +.#{$fa-css-prefix}-jsfiddle:before { content: $fa-var-jsfiddle; } +.#{$fa-css-prefix}-life-bouy:before, +.#{$fa-css-prefix}-life-buoy:before, +.#{$fa-css-prefix}-life-saver:before, +.#{$fa-css-prefix}-support:before, +.#{$fa-css-prefix}-life-ring:before { content: $fa-var-life-ring; } +.#{$fa-css-prefix}-circle-o-notch:before { content: $fa-var-circle-o-notch; } +.#{$fa-css-prefix}-ra:before, +.#{$fa-css-prefix}-resistance:before, +.#{$fa-css-prefix}-rebel:before { content: $fa-var-rebel; } +.#{$fa-css-prefix}-ge:before, +.#{$fa-css-prefix}-empire:before { content: $fa-var-empire; } +.#{$fa-css-prefix}-git-square:before { content: $fa-var-git-square; } +.#{$fa-css-prefix}-git:before { content: $fa-var-git; } +.#{$fa-css-prefix}-y-combinator-square:before, +.#{$fa-css-prefix}-yc-square:before, +.#{$fa-css-prefix}-hacker-news:before { content: $fa-var-hacker-news; } +.#{$fa-css-prefix}-tencent-weibo:before { content: $fa-var-tencent-weibo; } +.#{$fa-css-prefix}-qq:before { content: $fa-var-qq; } +.#{$fa-css-prefix}-wechat:before, +.#{$fa-css-prefix}-weixin:before { content: $fa-var-weixin; } +.#{$fa-css-prefix}-send:before, +.#{$fa-css-prefix}-paper-plane:before { content: $fa-var-paper-plane; } +.#{$fa-css-prefix}-send-o:before, +.#{$fa-css-prefix}-paper-plane-o:before { content: $fa-var-paper-plane-o; } +.#{$fa-css-prefix}-history:before { content: $fa-var-history; } +.#{$fa-css-prefix}-circle-thin:before { content: $fa-var-circle-thin; } +.#{$fa-css-prefix}-header:before { content: $fa-var-header; } +.#{$fa-css-prefix}-paragraph:before { content: $fa-var-paragraph; } +.#{$fa-css-prefix}-sliders:before { content: $fa-var-sliders; } +.#{$fa-css-prefix}-share-alt:before { content: $fa-var-share-alt; } +.#{$fa-css-prefix}-share-alt-square:before { content: $fa-var-share-alt-square; } +.#{$fa-css-prefix}-bomb:before { content: $fa-var-bomb; } +.#{$fa-css-prefix}-soccer-ball-o:before, +.#{$fa-css-prefix}-futbol-o:before { content: $fa-var-futbol-o; } +.#{$fa-css-prefix}-tty:before { content: $fa-var-tty; } +.#{$fa-css-prefix}-binoculars:before { content: $fa-var-binoculars; } +.#{$fa-css-prefix}-plug:before { content: $fa-var-plug; } +.#{$fa-css-prefix}-slideshare:before { content: $fa-var-slideshare; } +.#{$fa-css-prefix}-twitch:before { content: $fa-var-twitch; } +.#{$fa-css-prefix}-yelp:before { content: $fa-var-yelp; } +.#{$fa-css-prefix}-newspaper-o:before { content: $fa-var-newspaper-o; } +.#{$fa-css-prefix}-wifi:before { content: $fa-var-wifi; } +.#{$fa-css-prefix}-calculator:before { content: $fa-var-calculator; } +.#{$fa-css-prefix}-paypal:before { content: $fa-var-paypal; } +.#{$fa-css-prefix}-google-wallet:before { content: $fa-var-google-wallet; } +.#{$fa-css-prefix}-cc-visa:before { content: $fa-var-cc-visa; } +.#{$fa-css-prefix}-cc-mastercard:before { content: $fa-var-cc-mastercard; } +.#{$fa-css-prefix}-cc-discover:before { content: $fa-var-cc-discover; } +.#{$fa-css-prefix}-cc-amex:before { content: $fa-var-cc-amex; } +.#{$fa-css-prefix}-cc-paypal:before { content: $fa-var-cc-paypal; } +.#{$fa-css-prefix}-cc-stripe:before { content: $fa-var-cc-stripe; } +.#{$fa-css-prefix}-bell-slash:before { content: $fa-var-bell-slash; } +.#{$fa-css-prefix}-bell-slash-o:before { content: $fa-var-bell-slash-o; } +.#{$fa-css-prefix}-trash:before { content: $fa-var-trash; } +.#{$fa-css-prefix}-copyright:before { content: $fa-var-copyright; } +.#{$fa-css-prefix}-at:before { content: $fa-var-at; } +.#{$fa-css-prefix}-eyedropper:before { content: $fa-var-eyedropper; } +.#{$fa-css-prefix}-paint-brush:before { content: $fa-var-paint-brush; } +.#{$fa-css-prefix}-birthday-cake:before { content: $fa-var-birthday-cake; } +.#{$fa-css-prefix}-area-chart:before { content: $fa-var-area-chart; } +.#{$fa-css-prefix}-pie-chart:before { content: $fa-var-pie-chart; } +.#{$fa-css-prefix}-line-chart:before { content: $fa-var-line-chart; } +.#{$fa-css-prefix}-lastfm:before { content: $fa-var-lastfm; } +.#{$fa-css-prefix}-lastfm-square:before { content: $fa-var-lastfm-square; } +.#{$fa-css-prefix}-toggle-off:before { content: $fa-var-toggle-off; } +.#{$fa-css-prefix}-toggle-on:before { content: $fa-var-toggle-on; } +.#{$fa-css-prefix}-bicycle:before { content: $fa-var-bicycle; } +.#{$fa-css-prefix}-bus:before { content: $fa-var-bus; } +.#{$fa-css-prefix}-ioxhost:before { content: $fa-var-ioxhost; } +.#{$fa-css-prefix}-angellist:before { content: $fa-var-angellist; } +.#{$fa-css-prefix}-cc:before { content: $fa-var-cc; } +.#{$fa-css-prefix}-shekel:before, +.#{$fa-css-prefix}-sheqel:before, +.#{$fa-css-prefix}-ils:before { content: $fa-var-ils; } +.#{$fa-css-prefix}-meanpath:before { content: $fa-var-meanpath; } +.#{$fa-css-prefix}-buysellads:before { content: $fa-var-buysellads; } +.#{$fa-css-prefix}-connectdevelop:before { content: $fa-var-connectdevelop; } +.#{$fa-css-prefix}-dashcube:before { content: $fa-var-dashcube; } +.#{$fa-css-prefix}-forumbee:before { content: $fa-var-forumbee; } +.#{$fa-css-prefix}-leanpub:before { content: $fa-var-leanpub; } +.#{$fa-css-prefix}-sellsy:before { content: $fa-var-sellsy; } +.#{$fa-css-prefix}-shirtsinbulk:before { content: $fa-var-shirtsinbulk; } +.#{$fa-css-prefix}-simplybuilt:before { content: $fa-var-simplybuilt; } +.#{$fa-css-prefix}-skyatlas:before { content: $fa-var-skyatlas; } +.#{$fa-css-prefix}-cart-plus:before { content: $fa-var-cart-plus; } +.#{$fa-css-prefix}-cart-arrow-down:before { content: $fa-var-cart-arrow-down; } +.#{$fa-css-prefix}-diamond:before { content: $fa-var-diamond; } +.#{$fa-css-prefix}-ship:before { content: $fa-var-ship; } +.#{$fa-css-prefix}-user-secret:before { content: $fa-var-user-secret; } +.#{$fa-css-prefix}-motorcycle:before { content: $fa-var-motorcycle; } +.#{$fa-css-prefix}-street-view:before { content: $fa-var-street-view; } +.#{$fa-css-prefix}-heartbeat:before { content: $fa-var-heartbeat; } +.#{$fa-css-prefix}-venus:before { content: $fa-var-venus; } +.#{$fa-css-prefix}-mars:before { content: $fa-var-mars; } +.#{$fa-css-prefix}-mercury:before { content: $fa-var-mercury; } +.#{$fa-css-prefix}-intersex:before, +.#{$fa-css-prefix}-transgender:before { content: $fa-var-transgender; } +.#{$fa-css-prefix}-transgender-alt:before { content: $fa-var-transgender-alt; } +.#{$fa-css-prefix}-venus-double:before { content: $fa-var-venus-double; } +.#{$fa-css-prefix}-mars-double:before { content: $fa-var-mars-double; } +.#{$fa-css-prefix}-venus-mars:before { content: $fa-var-venus-mars; } +.#{$fa-css-prefix}-mars-stroke:before { content: $fa-var-mars-stroke; } +.#{$fa-css-prefix}-mars-stroke-v:before { content: $fa-var-mars-stroke-v; } +.#{$fa-css-prefix}-mars-stroke-h:before { content: $fa-var-mars-stroke-h; } +.#{$fa-css-prefix}-neuter:before { content: $fa-var-neuter; } +.#{$fa-css-prefix}-genderless:before { content: $fa-var-genderless; } +.#{$fa-css-prefix}-facebook-official:before { content: $fa-var-facebook-official; } +.#{$fa-css-prefix}-pinterest-p:before { content: $fa-var-pinterest-p; } +.#{$fa-css-prefix}-whatsapp:before { content: $fa-var-whatsapp; } +.#{$fa-css-prefix}-server:before { content: $fa-var-server; } +.#{$fa-css-prefix}-user-plus:before { content: $fa-var-user-plus; } +.#{$fa-css-prefix}-user-times:before { content: $fa-var-user-times; } +.#{$fa-css-prefix}-hotel:before, +.#{$fa-css-prefix}-bed:before { content: $fa-var-bed; } +.#{$fa-css-prefix}-viacoin:before { content: $fa-var-viacoin; } +.#{$fa-css-prefix}-train:before { content: $fa-var-train; } +.#{$fa-css-prefix}-subway:before { content: $fa-var-subway; } +.#{$fa-css-prefix}-medium:before { content: $fa-var-medium; } +.#{$fa-css-prefix}-yc:before, +.#{$fa-css-prefix}-y-combinator:before { content: $fa-var-y-combinator; } +.#{$fa-css-prefix}-optin-monster:before { content: $fa-var-optin-monster; } +.#{$fa-css-prefix}-opencart:before { content: $fa-var-opencart; } +.#{$fa-css-prefix}-expeditedssl:before { content: $fa-var-expeditedssl; } +.#{$fa-css-prefix}-battery-4:before, +.#{$fa-css-prefix}-battery:before, +.#{$fa-css-prefix}-battery-full:before { content: $fa-var-battery-full; } +.#{$fa-css-prefix}-battery-3:before, +.#{$fa-css-prefix}-battery-three-quarters:before { content: $fa-var-battery-three-quarters; } +.#{$fa-css-prefix}-battery-2:before, +.#{$fa-css-prefix}-battery-half:before { content: $fa-var-battery-half; } +.#{$fa-css-prefix}-battery-1:before, +.#{$fa-css-prefix}-battery-quarter:before { content: $fa-var-battery-quarter; } +.#{$fa-css-prefix}-battery-0:before, +.#{$fa-css-prefix}-battery-empty:before { content: $fa-var-battery-empty; } +.#{$fa-css-prefix}-mouse-pointer:before { content: $fa-var-mouse-pointer; } +.#{$fa-css-prefix}-i-cursor:before { content: $fa-var-i-cursor; } +.#{$fa-css-prefix}-object-group:before { content: $fa-var-object-group; } +.#{$fa-css-prefix}-object-ungroup:before { content: $fa-var-object-ungroup; } +.#{$fa-css-prefix}-sticky-note:before { content: $fa-var-sticky-note; } +.#{$fa-css-prefix}-sticky-note-o:before { content: $fa-var-sticky-note-o; } +.#{$fa-css-prefix}-cc-jcb:before { content: $fa-var-cc-jcb; } +.#{$fa-css-prefix}-cc-diners-club:before { content: $fa-var-cc-diners-club; } +.#{$fa-css-prefix}-clone:before { content: $fa-var-clone; } +.#{$fa-css-prefix}-balance-scale:before { content: $fa-var-balance-scale; } +.#{$fa-css-prefix}-hourglass-o:before { content: $fa-var-hourglass-o; } +.#{$fa-css-prefix}-hourglass-1:before, +.#{$fa-css-prefix}-hourglass-start:before { content: $fa-var-hourglass-start; } +.#{$fa-css-prefix}-hourglass-2:before, +.#{$fa-css-prefix}-hourglass-half:before { content: $fa-var-hourglass-half; } +.#{$fa-css-prefix}-hourglass-3:before, +.#{$fa-css-prefix}-hourglass-end:before { content: $fa-var-hourglass-end; } +.#{$fa-css-prefix}-hourglass:before { content: $fa-var-hourglass; } +.#{$fa-css-prefix}-hand-grab-o:before, +.#{$fa-css-prefix}-hand-rock-o:before { content: $fa-var-hand-rock-o; } +.#{$fa-css-prefix}-hand-stop-o:before, +.#{$fa-css-prefix}-hand-paper-o:before { content: $fa-var-hand-paper-o; } +.#{$fa-css-prefix}-hand-scissors-o:before { content: $fa-var-hand-scissors-o; } +.#{$fa-css-prefix}-hand-lizard-o:before { content: $fa-var-hand-lizard-o; } +.#{$fa-css-prefix}-hand-spock-o:before { content: $fa-var-hand-spock-o; } +.#{$fa-css-prefix}-hand-pointer-o:before { content: $fa-var-hand-pointer-o; } +.#{$fa-css-prefix}-hand-peace-o:before { content: $fa-var-hand-peace-o; } +.#{$fa-css-prefix}-trademark:before { content: $fa-var-trademark; } +.#{$fa-css-prefix}-registered:before { content: $fa-var-registered; } +.#{$fa-css-prefix}-creative-commons:before { content: $fa-var-creative-commons; } +.#{$fa-css-prefix}-gg:before { content: $fa-var-gg; } +.#{$fa-css-prefix}-gg-circle:before { content: $fa-var-gg-circle; } +.#{$fa-css-prefix}-tripadvisor:before { content: $fa-var-tripadvisor; } +.#{$fa-css-prefix}-odnoklassniki:before { content: $fa-var-odnoklassniki; } +.#{$fa-css-prefix}-odnoklassniki-square:before { content: $fa-var-odnoklassniki-square; } +.#{$fa-css-prefix}-get-pocket:before { content: $fa-var-get-pocket; } +.#{$fa-css-prefix}-wikipedia-w:before { content: $fa-var-wikipedia-w; } +.#{$fa-css-prefix}-safari:before { content: $fa-var-safari; } +.#{$fa-css-prefix}-chrome:before { content: $fa-var-chrome; } +.#{$fa-css-prefix}-firefox:before { content: $fa-var-firefox; } +.#{$fa-css-prefix}-opera:before { content: $fa-var-opera; } +.#{$fa-css-prefix}-internet-explorer:before { content: $fa-var-internet-explorer; } +.#{$fa-css-prefix}-tv:before, +.#{$fa-css-prefix}-television:before { content: $fa-var-television; } +.#{$fa-css-prefix}-contao:before { content: $fa-var-contao; } +.#{$fa-css-prefix}-500px:before { content: $fa-var-500px; } +.#{$fa-css-prefix}-amazon:before { content: $fa-var-amazon; } +.#{$fa-css-prefix}-calendar-plus-o:before { content: $fa-var-calendar-plus-o; } +.#{$fa-css-prefix}-calendar-minus-o:before { content: $fa-var-calendar-minus-o; } +.#{$fa-css-prefix}-calendar-times-o:before { content: $fa-var-calendar-times-o; } +.#{$fa-css-prefix}-calendar-check-o:before { content: $fa-var-calendar-check-o; } +.#{$fa-css-prefix}-industry:before { content: $fa-var-industry; } +.#{$fa-css-prefix}-map-pin:before { content: $fa-var-map-pin; } +.#{$fa-css-prefix}-map-signs:before { content: $fa-var-map-signs; } +.#{$fa-css-prefix}-map-o:before { content: $fa-var-map-o; } +.#{$fa-css-prefix}-map:before { content: $fa-var-map; } +.#{$fa-css-prefix}-commenting:before { content: $fa-var-commenting; } +.#{$fa-css-prefix}-commenting-o:before { content: $fa-var-commenting-o; } +.#{$fa-css-prefix}-houzz:before { content: $fa-var-houzz; } +.#{$fa-css-prefix}-vimeo:before { content: $fa-var-vimeo; } +.#{$fa-css-prefix}-black-tie:before { content: $fa-var-black-tie; } +.#{$fa-css-prefix}-fonticons:before { content: $fa-var-fonticons; } +.#{$fa-css-prefix}-reddit-alien:before { content: $fa-var-reddit-alien; } +.#{$fa-css-prefix}-edge:before { content: $fa-var-edge; } +.#{$fa-css-prefix}-credit-card-alt:before { content: $fa-var-credit-card-alt; } +.#{$fa-css-prefix}-codiepie:before { content: $fa-var-codiepie; } +.#{$fa-css-prefix}-modx:before { content: $fa-var-modx; } +.#{$fa-css-prefix}-fort-awesome:before { content: $fa-var-fort-awesome; } +.#{$fa-css-prefix}-usb:before { content: $fa-var-usb; } +.#{$fa-css-prefix}-product-hunt:before { content: $fa-var-product-hunt; } +.#{$fa-css-prefix}-mixcloud:before { content: $fa-var-mixcloud; } +.#{$fa-css-prefix}-scribd:before { content: $fa-var-scribd; } +.#{$fa-css-prefix}-pause-circle:before { content: $fa-var-pause-circle; } +.#{$fa-css-prefix}-pause-circle-o:before { content: $fa-var-pause-circle-o; } +.#{$fa-css-prefix}-stop-circle:before { content: $fa-var-stop-circle; } +.#{$fa-css-prefix}-stop-circle-o:before { content: $fa-var-stop-circle-o; } +.#{$fa-css-prefix}-shopping-bag:before { content: $fa-var-shopping-bag; } +.#{$fa-css-prefix}-shopping-basket:before { content: $fa-var-shopping-basket; } +.#{$fa-css-prefix}-hashtag:before { content: $fa-var-hashtag; } +.#{$fa-css-prefix}-bluetooth:before { content: $fa-var-bluetooth; } +.#{$fa-css-prefix}-bluetooth-b:before { content: $fa-var-bluetooth-b; } +.#{$fa-css-prefix}-percent:before { content: $fa-var-percent; } +.#{$fa-css-prefix}-gitlab:before { content: $fa-var-gitlab; } +.#{$fa-css-prefix}-wpbeginner:before { content: $fa-var-wpbeginner; } +.#{$fa-css-prefix}-wpforms:before { content: $fa-var-wpforms; } +.#{$fa-css-prefix}-envira:before { content: $fa-var-envira; } +.#{$fa-css-prefix}-universal-access:before { content: $fa-var-universal-access; } +.#{$fa-css-prefix}-wheelchair-alt:before { content: $fa-var-wheelchair-alt; } +.#{$fa-css-prefix}-question-circle-o:before { content: $fa-var-question-circle-o; } +.#{$fa-css-prefix}-blind:before { content: $fa-var-blind; } +.#{$fa-css-prefix}-audio-description:before { content: $fa-var-audio-description; } +.#{$fa-css-prefix}-volume-control-phone:before { content: $fa-var-volume-control-phone; } +.#{$fa-css-prefix}-braille:before { content: $fa-var-braille; } +.#{$fa-css-prefix}-assistive-listening-systems:before { content: $fa-var-assistive-listening-systems; } +.#{$fa-css-prefix}-asl-interpreting:before, +.#{$fa-css-prefix}-american-sign-language-interpreting:before { content: $fa-var-american-sign-language-interpreting; } +.#{$fa-css-prefix}-deafness:before, +.#{$fa-css-prefix}-hard-of-hearing:before, +.#{$fa-css-prefix}-deaf:before { content: $fa-var-deaf; } +.#{$fa-css-prefix}-glide:before { content: $fa-var-glide; } +.#{$fa-css-prefix}-glide-g:before { content: $fa-var-glide-g; } +.#{$fa-css-prefix}-signing:before, +.#{$fa-css-prefix}-sign-language:before { content: $fa-var-sign-language; } +.#{$fa-css-prefix}-low-vision:before { content: $fa-var-low-vision; } +.#{$fa-css-prefix}-viadeo:before { content: $fa-var-viadeo; } +.#{$fa-css-prefix}-viadeo-square:before { content: $fa-var-viadeo-square; } +.#{$fa-css-prefix}-snapchat:before { content: $fa-var-snapchat; } +.#{$fa-css-prefix}-snapchat-ghost:before { content: $fa-var-snapchat-ghost; } +.#{$fa-css-prefix}-snapchat-square:before { content: $fa-var-snapchat-square; } +.#{$fa-css-prefix}-pied-piper:before { content: $fa-var-pied-piper; } +.#{$fa-css-prefix}-first-order:before { content: $fa-var-first-order; } +.#{$fa-css-prefix}-yoast:before { content: $fa-var-yoast; } +.#{$fa-css-prefix}-themeisle:before { content: $fa-var-themeisle; } +.#{$fa-css-prefix}-google-plus-circle:before, +.#{$fa-css-prefix}-google-plus-official:before { content: $fa-var-google-plus-official; } +.#{$fa-css-prefix}-fa:before, +.#{$fa-css-prefix}-font-awesome:before { content: $fa-var-font-awesome; } +.#{$fa-css-prefix}-handshake-o:before { content: $fa-var-handshake-o; } +.#{$fa-css-prefix}-envelope-open:before { content: $fa-var-envelope-open; } +.#{$fa-css-prefix}-envelope-open-o:before { content: $fa-var-envelope-open-o; } +.#{$fa-css-prefix}-linode:before { content: $fa-var-linode; } +.#{$fa-css-prefix}-address-book:before { content: $fa-var-address-book; } +.#{$fa-css-prefix}-address-book-o:before { content: $fa-var-address-book-o; } +.#{$fa-css-prefix}-vcard:before, +.#{$fa-css-prefix}-address-card:before { content: $fa-var-address-card; } +.#{$fa-css-prefix}-vcard-o:before, +.#{$fa-css-prefix}-address-card-o:before { content: $fa-var-address-card-o; } +.#{$fa-css-prefix}-user-circle:before { content: $fa-var-user-circle; } +.#{$fa-css-prefix}-user-circle-o:before { content: $fa-var-user-circle-o; } +.#{$fa-css-prefix}-user-o:before { content: $fa-var-user-o; } +.#{$fa-css-prefix}-id-badge:before { content: $fa-var-id-badge; } +.#{$fa-css-prefix}-drivers-license:before, +.#{$fa-css-prefix}-id-card:before { content: $fa-var-id-card; } +.#{$fa-css-prefix}-drivers-license-o:before, +.#{$fa-css-prefix}-id-card-o:before { content: $fa-var-id-card-o; } +.#{$fa-css-prefix}-quora:before { content: $fa-var-quora; } +.#{$fa-css-prefix}-free-code-camp:before { content: $fa-var-free-code-camp; } +.#{$fa-css-prefix}-telegram:before { content: $fa-var-telegram; } +.#{$fa-css-prefix}-thermometer-4:before, +.#{$fa-css-prefix}-thermometer:before, +.#{$fa-css-prefix}-thermometer-full:before { content: $fa-var-thermometer-full; } +.#{$fa-css-prefix}-thermometer-3:before, +.#{$fa-css-prefix}-thermometer-three-quarters:before { content: $fa-var-thermometer-three-quarters; } +.#{$fa-css-prefix}-thermometer-2:before, +.#{$fa-css-prefix}-thermometer-half:before { content: $fa-var-thermometer-half; } +.#{$fa-css-prefix}-thermometer-1:before, +.#{$fa-css-prefix}-thermometer-quarter:before { content: $fa-var-thermometer-quarter; } +.#{$fa-css-prefix}-thermometer-0:before, +.#{$fa-css-prefix}-thermometer-empty:before { content: $fa-var-thermometer-empty; } +.#{$fa-css-prefix}-shower:before { content: $fa-var-shower; } +.#{$fa-css-prefix}-bathtub:before, +.#{$fa-css-prefix}-s15:before, +.#{$fa-css-prefix}-bath:before { content: $fa-var-bath; } +.#{$fa-css-prefix}-podcast:before { content: $fa-var-podcast; } +.#{$fa-css-prefix}-window-maximize:before { content: $fa-var-window-maximize; } +.#{$fa-css-prefix}-window-minimize:before { content: $fa-var-window-minimize; } +.#{$fa-css-prefix}-window-restore:before { content: $fa-var-window-restore; } +.#{$fa-css-prefix}-times-rectangle:before, +.#{$fa-css-prefix}-window-close:before { content: $fa-var-window-close; } +.#{$fa-css-prefix}-times-rectangle-o:before, +.#{$fa-css-prefix}-window-close-o:before { content: $fa-var-window-close-o; } +.#{$fa-css-prefix}-bandcamp:before { content: $fa-var-bandcamp; } +.#{$fa-css-prefix}-grav:before { content: $fa-var-grav; } +.#{$fa-css-prefix}-etsy:before { content: $fa-var-etsy; } +.#{$fa-css-prefix}-imdb:before { content: $fa-var-imdb; } +.#{$fa-css-prefix}-ravelry:before { content: $fa-var-ravelry; } +.#{$fa-css-prefix}-eercast:before { content: $fa-var-eercast; } +.#{$fa-css-prefix}-microchip:before { content: $fa-var-microchip; } +.#{$fa-css-prefix}-snowflake-o:before { content: $fa-var-snowflake-o; } +.#{$fa-css-prefix}-superpowers:before { content: $fa-var-superpowers; } +.#{$fa-css-prefix}-wpexplorer:before { content: $fa-var-wpexplorer; } +.#{$fa-css-prefix}-meetup:before { content: $fa-var-meetup; } diff --git a/static/font-awesome/scss/_larger.scss b/static/font-awesome/scss/_larger.scss new file mode 100644 index 0000000..41e9a81 --- /dev/null +++ b/static/font-awesome/scss/_larger.scss @@ -0,0 +1,13 @@ +// Icon Sizes +// ------------------------- + +/* makes the font 33% larger relative to the icon container */ +.#{$fa-css-prefix}-lg { + font-size: (4em / 3); + line-height: (3em / 4); + vertical-align: -15%; +} +.#{$fa-css-prefix}-2x { font-size: 2em; } +.#{$fa-css-prefix}-3x { font-size: 3em; } +.#{$fa-css-prefix}-4x { font-size: 4em; } +.#{$fa-css-prefix}-5x { font-size: 5em; } diff --git a/static/font-awesome/scss/_list.scss b/static/font-awesome/scss/_list.scss new file mode 100644 index 0000000..7d1e4d5 --- /dev/null +++ b/static/font-awesome/scss/_list.scss @@ -0,0 +1,19 @@ +// List Icons +// ------------------------- + +.#{$fa-css-prefix}-ul { + padding-left: 0; + margin-left: $fa-li-width; + list-style-type: none; + > li { position: relative; } +} +.#{$fa-css-prefix}-li { + position: absolute; + left: -$fa-li-width; + width: $fa-li-width; + top: (2em / 14); + text-align: center; + &.#{$fa-css-prefix}-lg { + left: -$fa-li-width + (4em / 14); + } +} diff --git a/static/font-awesome/scss/_mixins.scss b/static/font-awesome/scss/_mixins.scss new file mode 100644 index 0000000..c3bbd57 --- /dev/null +++ b/static/font-awesome/scss/_mixins.scss @@ -0,0 +1,60 @@ +// Mixins +// -------------------------- + +@mixin fa-icon() { + display: inline-block; + font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration + font-size: inherit; // can't have font-size inherit on line above, so need to override + text-rendering: auto; // optimizelegibility throws things off #1094 + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + +} + +@mixin fa-icon-rotate($degrees, $rotation) { + -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) { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation}, mirror=1)"; + -webkit-transform: scale($horiz, $vert); + -ms-transform: scale($horiz, $vert); + transform: scale($horiz, $vert); +} + + +// Only display content to screen readers. A la Bootstrap 4. +// +// See: http://a11yproject.com/posts/how-to-hide-content/ + +@mixin sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0,0,0,0); + border: 0; +} + +// Use in conjunction with .sr-only to only display content when it's focused. +// +// Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1 +// +// Credit: HTML5 Boilerplate + +@mixin sr-only-focusable { + &:active, + &:focus { + position: static; + width: auto; + height: auto; + margin: 0; + overflow: visible; + clip: auto; + } +} diff --git a/static/font-awesome/scss/_path.scss b/static/font-awesome/scss/_path.scss new file mode 100644 index 0000000..bb457c2 --- /dev/null +++ b/static/font-awesome/scss/_path.scss @@ -0,0 +1,15 @@ +/* FONT PATH + * -------------------------- */ + +@font-face { + font-family: 'FontAwesome'; + src: url('#{$fa-font-path}/fontawesome-webfont.eot?v=#{$fa-version}'); + src: url('#{$fa-font-path}/fontawesome-webfont.eot?#iefix&v=#{$fa-version}') format('embedded-opentype'), + url('#{$fa-font-path}/fontawesome-webfont.woff2?v=#{$fa-version}') format('woff2'), + url('#{$fa-font-path}/fontawesome-webfont.woff?v=#{$fa-version}') format('woff'), + url('#{$fa-font-path}/fontawesome-webfont.ttf?v=#{$fa-version}') format('truetype'), + url('#{$fa-font-path}/fontawesome-webfont.svg?v=#{$fa-version}#fontawesomeregular') format('svg'); +// src: url('#{$fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts + font-weight: normal; + font-style: normal; +} diff --git a/static/font-awesome/scss/_rotated-flipped.scss b/static/font-awesome/scss/_rotated-flipped.scss new file mode 100644 index 0000000..a3558fd --- /dev/null +++ b/static/font-awesome/scss/_rotated-flipped.scss @@ -0,0 +1,20 @@ +// Rotated & Flipped Icons +// ------------------------- + +.#{$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); } + +// Hook for IE8-9 +// ------------------------- + +:root .#{$fa-css-prefix}-rotate-90, +:root .#{$fa-css-prefix}-rotate-180, +:root .#{$fa-css-prefix}-rotate-270, +:root .#{$fa-css-prefix}-flip-horizontal, +:root .#{$fa-css-prefix}-flip-vertical { + filter: none; +} diff --git a/static/font-awesome/scss/_screen-reader.scss b/static/font-awesome/scss/_screen-reader.scss new file mode 100644 index 0000000..637426f --- /dev/null +++ b/static/font-awesome/scss/_screen-reader.scss @@ -0,0 +1,5 @@ +// Screen Readers +// ------------------------- + +.sr-only { @include sr-only(); } +.sr-only-focusable { @include sr-only-focusable(); } diff --git a/static/font-awesome/scss/_stacked.scss b/static/font-awesome/scss/_stacked.scss new file mode 100644 index 0000000..aef7403 --- /dev/null +++ b/static/font-awesome/scss/_stacked.scss @@ -0,0 +1,20 @@ +// Stacked Icons +// ------------------------- + +.#{$fa-css-prefix}-stack { + position: relative; + display: inline-block; + width: 2em; + height: 2em; + line-height: 2em; + vertical-align: middle; +} +.#{$fa-css-prefix}-stack-1x, .#{$fa-css-prefix}-stack-2x { + position: absolute; + left: 0; + width: 100%; + text-align: center; +} +.#{$fa-css-prefix}-stack-1x { line-height: inherit; } +.#{$fa-css-prefix}-stack-2x { font-size: 2em; } +.#{$fa-css-prefix}-inverse { color: $fa-inverse; } diff --git a/static/font-awesome/scss/_variables.scss b/static/font-awesome/scss/_variables.scss new file mode 100644 index 0000000..498fc4a --- /dev/null +++ b/static/font-awesome/scss/_variables.scss @@ -0,0 +1,800 @@ +// Variables +// -------------------------- + +$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.7.0/fonts" !default; // for referencing Bootstrap CDN font files directly +$fa-css-prefix: fa !default; +$fa-version: "4.7.0" !default; +$fa-border-color: #eee !default; +$fa-inverse: #fff !default; +$fa-li-width: (30em / 14) !default; + +$fa-var-500px: "\f26e"; +$fa-var-address-book: "\f2b9"; +$fa-var-address-book-o: "\f2ba"; +$fa-var-address-card: "\f2bb"; +$fa-var-address-card-o: "\f2bc"; +$fa-var-adjust: "\f042"; +$fa-var-adn: "\f170"; +$fa-var-align-center: "\f037"; +$fa-var-align-justify: "\f039"; +$fa-var-align-left: "\f036"; +$fa-var-align-right: "\f038"; +$fa-var-amazon: "\f270"; +$fa-var-ambulance: "\f0f9"; +$fa-var-american-sign-language-interpreting: "\f2a3"; +$fa-var-anchor: "\f13d"; +$fa-var-android: "\f17b"; +$fa-var-angellist: "\f209"; +$fa-var-angle-double-down: "\f103"; +$fa-var-angle-double-left: "\f100"; +$fa-var-angle-double-right: "\f101"; +$fa-var-angle-double-up: "\f102"; +$fa-var-angle-down: "\f107"; +$fa-var-angle-left: "\f104"; +$fa-var-angle-right: "\f105"; +$fa-var-angle-up: "\f106"; +$fa-var-apple: "\f179"; +$fa-var-archive: "\f187"; +$fa-var-area-chart: "\f1fe"; +$fa-var-arrow-circle-down: "\f0ab"; +$fa-var-arrow-circle-left: "\f0a8"; +$fa-var-arrow-circle-o-down: "\f01a"; +$fa-var-arrow-circle-o-left: "\f190"; +$fa-var-arrow-circle-o-right: "\f18e"; +$fa-var-arrow-circle-o-up: "\f01b"; +$fa-var-arrow-circle-right: "\f0a9"; +$fa-var-arrow-circle-up: "\f0aa"; +$fa-var-arrow-down: "\f063"; +$fa-var-arrow-left: "\f060"; +$fa-var-arrow-right: "\f061"; +$fa-var-arrow-up: "\f062"; +$fa-var-arrows: "\f047"; +$fa-var-arrows-alt: "\f0b2"; +$fa-var-arrows-h: "\f07e"; +$fa-var-arrows-v: "\f07d"; +$fa-var-asl-interpreting: "\f2a3"; +$fa-var-assistive-listening-systems: "\f2a2"; +$fa-var-asterisk: "\f069"; +$fa-var-at: "\f1fa"; +$fa-var-audio-description: "\f29e"; +$fa-var-automobile: "\f1b9"; +$fa-var-backward: "\f04a"; +$fa-var-balance-scale: "\f24e"; +$fa-var-ban: "\f05e"; +$fa-var-bandcamp: "\f2d5"; +$fa-var-bank: "\f19c"; +$fa-var-bar-chart: "\f080"; +$fa-var-bar-chart-o: "\f080"; +$fa-var-barcode: "\f02a"; +$fa-var-bars: "\f0c9"; +$fa-var-bath: "\f2cd"; +$fa-var-bathtub: "\f2cd"; +$fa-var-battery: "\f240"; +$fa-var-battery-0: "\f244"; +$fa-var-battery-1: "\f243"; +$fa-var-battery-2: "\f242"; +$fa-var-battery-3: "\f241"; +$fa-var-battery-4: "\f240"; +$fa-var-battery-empty: "\f244"; +$fa-var-battery-full: "\f240"; +$fa-var-battery-half: "\f242"; +$fa-var-battery-quarter: "\f243"; +$fa-var-battery-three-quarters: "\f241"; +$fa-var-bed: "\f236"; +$fa-var-beer: "\f0fc"; +$fa-var-behance: "\f1b4"; +$fa-var-behance-square: "\f1b5"; +$fa-var-bell: "\f0f3"; +$fa-var-bell-o: "\f0a2"; +$fa-var-bell-slash: "\f1f6"; +$fa-var-bell-slash-o: "\f1f7"; +$fa-var-bicycle: "\f206"; +$fa-var-binoculars: "\f1e5"; +$fa-var-birthday-cake: "\f1fd"; +$fa-var-bitbucket: "\f171"; +$fa-var-bitbucket-square: "\f172"; +$fa-var-bitcoin: "\f15a"; +$fa-var-black-tie: "\f27e"; +$fa-var-blind: "\f29d"; +$fa-var-bluetooth: "\f293"; +$fa-var-bluetooth-b: "\f294"; +$fa-var-bold: "\f032"; +$fa-var-bolt: "\f0e7"; +$fa-var-bomb: "\f1e2"; +$fa-var-book: "\f02d"; +$fa-var-bookmark: "\f02e"; +$fa-var-bookmark-o: "\f097"; +$fa-var-braille: "\f2a1"; +$fa-var-briefcase: "\f0b1"; +$fa-var-btc: "\f15a"; +$fa-var-bug: "\f188"; +$fa-var-building: "\f1ad"; +$fa-var-building-o: "\f0f7"; +$fa-var-bullhorn: "\f0a1"; +$fa-var-bullseye: "\f140"; +$fa-var-bus: "\f207"; +$fa-var-buysellads: "\f20d"; +$fa-var-cab: "\f1ba"; +$fa-var-calculator: "\f1ec"; +$fa-var-calendar: "\f073"; +$fa-var-calendar-check-o: "\f274"; +$fa-var-calendar-minus-o: "\f272"; +$fa-var-calendar-o: "\f133"; +$fa-var-calendar-plus-o: "\f271"; +$fa-var-calendar-times-o: "\f273"; +$fa-var-camera: "\f030"; +$fa-var-camera-retro: "\f083"; +$fa-var-car: "\f1b9"; +$fa-var-caret-down: "\f0d7"; +$fa-var-caret-left: "\f0d9"; +$fa-var-caret-right: "\f0da"; +$fa-var-caret-square-o-down: "\f150"; +$fa-var-caret-square-o-left: "\f191"; +$fa-var-caret-square-o-right: "\f152"; +$fa-var-caret-square-o-up: "\f151"; +$fa-var-caret-up: "\f0d8"; +$fa-var-cart-arrow-down: "\f218"; +$fa-var-cart-plus: "\f217"; +$fa-var-cc: "\f20a"; +$fa-var-cc-amex: "\f1f3"; +$fa-var-cc-diners-club: "\f24c"; +$fa-var-cc-discover: "\f1f2"; +$fa-var-cc-jcb: "\f24b"; +$fa-var-cc-mastercard: "\f1f1"; +$fa-var-cc-paypal: "\f1f4"; +$fa-var-cc-stripe: "\f1f5"; +$fa-var-cc-visa: "\f1f0"; +$fa-var-certificate: "\f0a3"; +$fa-var-chain: "\f0c1"; +$fa-var-chain-broken: "\f127"; +$fa-var-check: "\f00c"; +$fa-var-check-circle: "\f058"; +$fa-var-check-circle-o: "\f05d"; +$fa-var-check-square: "\f14a"; +$fa-var-check-square-o: "\f046"; +$fa-var-chevron-circle-down: "\f13a"; +$fa-var-chevron-circle-left: "\f137"; +$fa-var-chevron-circle-right: "\f138"; +$fa-var-chevron-circle-up: "\f139"; +$fa-var-chevron-down: "\f078"; +$fa-var-chevron-left: "\f053"; +$fa-var-chevron-right: "\f054"; +$fa-var-chevron-up: "\f077"; +$fa-var-child: "\f1ae"; +$fa-var-chrome: "\f268"; +$fa-var-circle: "\f111"; +$fa-var-circle-o: "\f10c"; +$fa-var-circle-o-notch: "\f1ce"; +$fa-var-circle-thin: "\f1db"; +$fa-var-clipboard: "\f0ea"; +$fa-var-clock-o: "\f017"; +$fa-var-clone: "\f24d"; +$fa-var-close: "\f00d"; +$fa-var-cloud: "\f0c2"; +$fa-var-cloud-download: "\f0ed"; +$fa-var-cloud-upload: "\f0ee"; +$fa-var-cny: "\f157"; +$fa-var-code: "\f121"; +$fa-var-code-fork: "\f126"; +$fa-var-codepen: "\f1cb"; +$fa-var-codiepie: "\f284"; +$fa-var-coffee: "\f0f4"; +$fa-var-cog: "\f013"; +$fa-var-cogs: "\f085"; +$fa-var-columns: "\f0db"; +$fa-var-comment: "\f075"; +$fa-var-comment-o: "\f0e5"; +$fa-var-commenting: "\f27a"; +$fa-var-commenting-o: "\f27b"; +$fa-var-comments: "\f086"; +$fa-var-comments-o: "\f0e6"; +$fa-var-compass: "\f14e"; +$fa-var-compress: "\f066"; +$fa-var-connectdevelop: "\f20e"; +$fa-var-contao: "\f26d"; +$fa-var-copy: "\f0c5"; +$fa-var-copyright: "\f1f9"; +$fa-var-creative-commons: "\f25e"; +$fa-var-credit-card: "\f09d"; +$fa-var-credit-card-alt: "\f283"; +$fa-var-crop: "\f125"; +$fa-var-crosshairs: "\f05b"; +$fa-var-css3: "\f13c"; +$fa-var-cube: "\f1b2"; +$fa-var-cubes: "\f1b3"; +$fa-var-cut: "\f0c4"; +$fa-var-cutlery: "\f0f5"; +$fa-var-dashboard: "\f0e4"; +$fa-var-dashcube: "\f210"; +$fa-var-database: "\f1c0"; +$fa-var-deaf: "\f2a4"; +$fa-var-deafness: "\f2a4"; +$fa-var-dedent: "\f03b"; +$fa-var-delicious: "\f1a5"; +$fa-var-desktop: "\f108"; +$fa-var-deviantart: "\f1bd"; +$fa-var-diamond: "\f219"; +$fa-var-digg: "\f1a6"; +$fa-var-dollar: "\f155"; +$fa-var-dot-circle-o: "\f192"; +$fa-var-download: "\f019"; +$fa-var-dribbble: "\f17d"; +$fa-var-drivers-license: "\f2c2"; +$fa-var-drivers-license-o: "\f2c3"; +$fa-var-dropbox: "\f16b"; +$fa-var-drupal: "\f1a9"; +$fa-var-edge: "\f282"; +$fa-var-edit: "\f044"; +$fa-var-eercast: "\f2da"; +$fa-var-eject: "\f052"; +$fa-var-ellipsis-h: "\f141"; +$fa-var-ellipsis-v: "\f142"; +$fa-var-empire: "\f1d1"; +$fa-var-envelope: "\f0e0"; +$fa-var-envelope-o: "\f003"; +$fa-var-envelope-open: "\f2b6"; +$fa-var-envelope-open-o: "\f2b7"; +$fa-var-envelope-square: "\f199"; +$fa-var-envira: "\f299"; +$fa-var-eraser: "\f12d"; +$fa-var-etsy: "\f2d7"; +$fa-var-eur: "\f153"; +$fa-var-euro: "\f153"; +$fa-var-exchange: "\f0ec"; +$fa-var-exclamation: "\f12a"; +$fa-var-exclamation-circle: "\f06a"; +$fa-var-exclamation-triangle: "\f071"; +$fa-var-expand: "\f065"; +$fa-var-expeditedssl: "\f23e"; +$fa-var-external-link: "\f08e"; +$fa-var-external-link-square: "\f14c"; +$fa-var-eye: "\f06e"; +$fa-var-eye-slash: "\f070"; +$fa-var-eyedropper: "\f1fb"; +$fa-var-fa: "\f2b4"; +$fa-var-facebook: "\f09a"; +$fa-var-facebook-f: "\f09a"; +$fa-var-facebook-official: "\f230"; +$fa-var-facebook-square: "\f082"; +$fa-var-fast-backward: "\f049"; +$fa-var-fast-forward: "\f050"; +$fa-var-fax: "\f1ac"; +$fa-var-feed: "\f09e"; +$fa-var-female: "\f182"; +$fa-var-fighter-jet: "\f0fb"; +$fa-var-file: "\f15b"; +$fa-var-file-archive-o: "\f1c6"; +$fa-var-file-audio-o: "\f1c7"; +$fa-var-file-code-o: "\f1c9"; +$fa-var-file-excel-o: "\f1c3"; +$fa-var-file-image-o: "\f1c5"; +$fa-var-file-movie-o: "\f1c8"; +$fa-var-file-o: "\f016"; +$fa-var-file-pdf-o: "\f1c1"; +$fa-var-file-photo-o: "\f1c5"; +$fa-var-file-picture-o: "\f1c5"; +$fa-var-file-powerpoint-o: "\f1c4"; +$fa-var-file-sound-o: "\f1c7"; +$fa-var-file-text: "\f15c"; +$fa-var-file-text-o: "\f0f6"; +$fa-var-file-video-o: "\f1c8"; +$fa-var-file-word-o: "\f1c2"; +$fa-var-file-zip-o: "\f1c6"; +$fa-var-files-o: "\f0c5"; +$fa-var-film: "\f008"; +$fa-var-filter: "\f0b0"; +$fa-var-fire: "\f06d"; +$fa-var-fire-extinguisher: "\f134"; +$fa-var-firefox: "\f269"; +$fa-var-first-order: "\f2b0"; +$fa-var-flag: "\f024"; +$fa-var-flag-checkered: "\f11e"; +$fa-var-flag-o: "\f11d"; +$fa-var-flash: "\f0e7"; +$fa-var-flask: "\f0c3"; +$fa-var-flickr: "\f16e"; +$fa-var-floppy-o: "\f0c7"; +$fa-var-folder: "\f07b"; +$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"; +$fa-var-gavel: "\f0e3"; +$fa-var-gbp: "\f154"; +$fa-var-ge: "\f1d1"; +$fa-var-gear: "\f013"; +$fa-var-gears: "\f085"; +$fa-var-genderless: "\f22d"; +$fa-var-get-pocket: "\f265"; +$fa-var-gg: "\f260"; +$fa-var-gg-circle: "\f261"; +$fa-var-gift: "\f06b"; +$fa-var-git: "\f1d3"; +$fa-var-git-square: "\f1d2"; +$fa-var-github: "\f09b"; +$fa-var-github-alt: "\f113"; +$fa-var-github-square: "\f092"; +$fa-var-gitlab: "\f296"; +$fa-var-gittip: "\f184"; +$fa-var-glass: "\f000"; +$fa-var-glide: "\f2a5"; +$fa-var-glide-g: "\f2a6"; +$fa-var-globe: "\f0ac"; +$fa-var-google: "\f1a0"; +$fa-var-google-plus: "\f0d5"; +$fa-var-google-plus-circle: "\f2b3"; +$fa-var-google-plus-official: "\f2b3"; +$fa-var-google-plus-square: "\f0d4"; +$fa-var-google-wallet: "\f1ee"; +$fa-var-graduation-cap: "\f19d"; +$fa-var-gratipay: "\f184"; +$fa-var-grav: "\f2d6"; +$fa-var-group: "\f0c0"; +$fa-var-h-square: "\f0fd"; +$fa-var-hacker-news: "\f1d4"; +$fa-var-hand-grab-o: "\f255"; +$fa-var-hand-lizard-o: "\f258"; +$fa-var-hand-o-down: "\f0a7"; +$fa-var-hand-o-left: "\f0a5"; +$fa-var-hand-o-right: "\f0a4"; +$fa-var-hand-o-up: "\f0a6"; +$fa-var-hand-paper-o: "\f256"; +$fa-var-hand-peace-o: "\f25b"; +$fa-var-hand-pointer-o: "\f25a"; +$fa-var-hand-rock-o: "\f255"; +$fa-var-hand-scissors-o: "\f257"; +$fa-var-hand-spock-o: "\f259"; +$fa-var-hand-stop-o: "\f256"; +$fa-var-handshake-o: "\f2b5"; +$fa-var-hard-of-hearing: "\f2a4"; +$fa-var-hashtag: "\f292"; +$fa-var-hdd-o: "\f0a0"; +$fa-var-header: "\f1dc"; +$fa-var-headphones: "\f025"; +$fa-var-heart: "\f004"; +$fa-var-heart-o: "\f08a"; +$fa-var-heartbeat: "\f21e"; +$fa-var-history: "\f1da"; +$fa-var-home: "\f015"; +$fa-var-hospital-o: "\f0f8"; +$fa-var-hotel: "\f236"; +$fa-var-hourglass: "\f254"; +$fa-var-hourglass-1: "\f251"; +$fa-var-hourglass-2: "\f252"; +$fa-var-hourglass-3: "\f253"; +$fa-var-hourglass-end: "\f253"; +$fa-var-hourglass-half: "\f252"; +$fa-var-hourglass-o: "\f250"; +$fa-var-hourglass-start: "\f251"; +$fa-var-houzz: "\f27c"; +$fa-var-html5: "\f13b"; +$fa-var-i-cursor: "\f246"; +$fa-var-id-badge: "\f2c1"; +$fa-var-id-card: "\f2c2"; +$fa-var-id-card-o: "\f2c3"; +$fa-var-ils: "\f20b"; +$fa-var-image: "\f03e"; +$fa-var-imdb: "\f2d8"; +$fa-var-inbox: "\f01c"; +$fa-var-indent: "\f03c"; +$fa-var-industry: "\f275"; +$fa-var-info: "\f129"; +$fa-var-info-circle: "\f05a"; +$fa-var-inr: "\f156"; +$fa-var-instagram: "\f16d"; +$fa-var-institution: "\f19c"; +$fa-var-internet-explorer: "\f26b"; +$fa-var-intersex: "\f224"; +$fa-var-ioxhost: "\f208"; +$fa-var-italic: "\f033"; +$fa-var-joomla: "\f1aa"; +$fa-var-jpy: "\f157"; +$fa-var-jsfiddle: "\f1cc"; +$fa-var-key: "\f084"; +$fa-var-keyboard-o: "\f11c"; +$fa-var-krw: "\f159"; +$fa-var-language: "\f1ab"; +$fa-var-laptop: "\f109"; +$fa-var-lastfm: "\f202"; +$fa-var-lastfm-square: "\f203"; +$fa-var-leaf: "\f06c"; +$fa-var-leanpub: "\f212"; +$fa-var-legal: "\f0e3"; +$fa-var-lemon-o: "\f094"; +$fa-var-level-down: "\f149"; +$fa-var-level-up: "\f148"; +$fa-var-life-bouy: "\f1cd"; +$fa-var-life-buoy: "\f1cd"; +$fa-var-life-ring: "\f1cd"; +$fa-var-life-saver: "\f1cd"; +$fa-var-lightbulb-o: "\f0eb"; +$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"; +$fa-var-list-ol: "\f0cb"; +$fa-var-list-ul: "\f0ca"; +$fa-var-location-arrow: "\f124"; +$fa-var-lock: "\f023"; +$fa-var-long-arrow-down: "\f175"; +$fa-var-long-arrow-left: "\f177"; +$fa-var-long-arrow-right: "\f178"; +$fa-var-long-arrow-up: "\f176"; +$fa-var-low-vision: "\f2a8"; +$fa-var-magic: "\f0d0"; +$fa-var-magnet: "\f076"; +$fa-var-mail-forward: "\f064"; +$fa-var-mail-reply: "\f112"; +$fa-var-mail-reply-all: "\f122"; +$fa-var-male: "\f183"; +$fa-var-map: "\f279"; +$fa-var-map-marker: "\f041"; +$fa-var-map-o: "\f278"; +$fa-var-map-pin: "\f276"; +$fa-var-map-signs: "\f277"; +$fa-var-mars: "\f222"; +$fa-var-mars-double: "\f227"; +$fa-var-mars-stroke: "\f229"; +$fa-var-mars-stroke-h: "\f22b"; +$fa-var-mars-stroke-v: "\f22a"; +$fa-var-maxcdn: "\f136"; +$fa-var-meanpath: "\f20c"; +$fa-var-medium: "\f23a"; +$fa-var-medkit: "\f0fa"; +$fa-var-meetup: "\f2e0"; +$fa-var-meh-o: "\f11a"; +$fa-var-mercury: "\f223"; +$fa-var-microchip: "\f2db"; +$fa-var-microphone: "\f130"; +$fa-var-microphone-slash: "\f131"; +$fa-var-minus: "\f068"; +$fa-var-minus-circle: "\f056"; +$fa-var-minus-square: "\f146"; +$fa-var-minus-square-o: "\f147"; +$fa-var-mixcloud: "\f289"; +$fa-var-mobile: "\f10b"; +$fa-var-mobile-phone: "\f10b"; +$fa-var-modx: "\f285"; +$fa-var-money: "\f0d6"; +$fa-var-moon-o: "\f186"; +$fa-var-mortar-board: "\f19d"; +$fa-var-motorcycle: "\f21c"; +$fa-var-mouse-pointer: "\f245"; +$fa-var-music: "\f001"; +$fa-var-navicon: "\f0c9"; +$fa-var-neuter: "\f22c"; +$fa-var-newspaper-o: "\f1ea"; +$fa-var-object-group: "\f247"; +$fa-var-object-ungroup: "\f248"; +$fa-var-odnoklassniki: "\f263"; +$fa-var-odnoklassniki-square: "\f264"; +$fa-var-opencart: "\f23d"; +$fa-var-openid: "\f19b"; +$fa-var-opera: "\f26a"; +$fa-var-optin-monster: "\f23c"; +$fa-var-outdent: "\f03b"; +$fa-var-pagelines: "\f18c"; +$fa-var-paint-brush: "\f1fc"; +$fa-var-paper-plane: "\f1d8"; +$fa-var-paper-plane-o: "\f1d9"; +$fa-var-paperclip: "\f0c6"; +$fa-var-paragraph: "\f1dd"; +$fa-var-paste: "\f0ea"; +$fa-var-pause: "\f04c"; +$fa-var-pause-circle: "\f28b"; +$fa-var-pause-circle-o: "\f28c"; +$fa-var-paw: "\f1b0"; +$fa-var-paypal: "\f1ed"; +$fa-var-pencil: "\f040"; +$fa-var-pencil-square: "\f14b"; +$fa-var-pencil-square-o: "\f044"; +$fa-var-percent: "\f295"; +$fa-var-phone: "\f095"; +$fa-var-phone-square: "\f098"; +$fa-var-photo: "\f03e"; +$fa-var-picture-o: "\f03e"; +$fa-var-pie-chart: "\f200"; +$fa-var-pied-piper: "\f2ae"; +$fa-var-pied-piper-alt: "\f1a8"; +$fa-var-pied-piper-pp: "\f1a7"; +$fa-var-pinterest: "\f0d2"; +$fa-var-pinterest-p: "\f231"; +$fa-var-pinterest-square: "\f0d3"; +$fa-var-plane: "\f072"; +$fa-var-play: "\f04b"; +$fa-var-play-circle: "\f144"; +$fa-var-play-circle-o: "\f01d"; +$fa-var-plug: "\f1e6"; +$fa-var-plus: "\f067"; +$fa-var-plus-circle: "\f055"; +$fa-var-plus-square: "\f0fe"; +$fa-var-plus-square-o: "\f196"; +$fa-var-podcast: "\f2ce"; +$fa-var-power-off: "\f011"; +$fa-var-print: "\f02f"; +$fa-var-product-hunt: "\f288"; +$fa-var-puzzle-piece: "\f12e"; +$fa-var-qq: "\f1d6"; +$fa-var-qrcode: "\f029"; +$fa-var-question: "\f128"; +$fa-var-question-circle: "\f059"; +$fa-var-question-circle-o: "\f29c"; +$fa-var-quora: "\f2c4"; +$fa-var-quote-left: "\f10d"; +$fa-var-quote-right: "\f10e"; +$fa-var-ra: "\f1d0"; +$fa-var-random: "\f074"; +$fa-var-ravelry: "\f2d9"; +$fa-var-rebel: "\f1d0"; +$fa-var-recycle: "\f1b8"; +$fa-var-reddit: "\f1a1"; +$fa-var-reddit-alien: "\f281"; +$fa-var-reddit-square: "\f1a2"; +$fa-var-refresh: "\f021"; +$fa-var-registered: "\f25d"; +$fa-var-remove: "\f00d"; +$fa-var-renren: "\f18b"; +$fa-var-reorder: "\f0c9"; +$fa-var-repeat: "\f01e"; +$fa-var-reply: "\f112"; +$fa-var-reply-all: "\f122"; +$fa-var-resistance: "\f1d0"; +$fa-var-retweet: "\f079"; +$fa-var-rmb: "\f157"; +$fa-var-road: "\f018"; +$fa-var-rocket: "\f135"; +$fa-var-rotate-left: "\f0e2"; +$fa-var-rotate-right: "\f01e"; +$fa-var-rouble: "\f158"; +$fa-var-rss: "\f09e"; +$fa-var-rss-square: "\f143"; +$fa-var-rub: "\f158"; +$fa-var-ruble: "\f158"; +$fa-var-rupee: "\f156"; +$fa-var-s15: "\f2cd"; +$fa-var-safari: "\f267"; +$fa-var-save: "\f0c7"; +$fa-var-scissors: "\f0c4"; +$fa-var-scribd: "\f28a"; +$fa-var-search: "\f002"; +$fa-var-search-minus: "\f010"; +$fa-var-search-plus: "\f00e"; +$fa-var-sellsy: "\f213"; +$fa-var-send: "\f1d8"; +$fa-var-send-o: "\f1d9"; +$fa-var-server: "\f233"; +$fa-var-share: "\f064"; +$fa-var-share-alt: "\f1e0"; +$fa-var-share-alt-square: "\f1e1"; +$fa-var-share-square: "\f14d"; +$fa-var-share-square-o: "\f045"; +$fa-var-shekel: "\f20b"; +$fa-var-sheqel: "\f20b"; +$fa-var-shield: "\f132"; +$fa-var-ship: "\f21a"; +$fa-var-shirtsinbulk: "\f214"; +$fa-var-shopping-bag: "\f290"; +$fa-var-shopping-basket: "\f291"; +$fa-var-shopping-cart: "\f07a"; +$fa-var-shower: "\f2cc"; +$fa-var-sign-in: "\f090"; +$fa-var-sign-language: "\f2a7"; +$fa-var-sign-out: "\f08b"; +$fa-var-signal: "\f012"; +$fa-var-signing: "\f2a7"; +$fa-var-simplybuilt: "\f215"; +$fa-var-sitemap: "\f0e8"; +$fa-var-skyatlas: "\f216"; +$fa-var-skype: "\f17e"; +$fa-var-slack: "\f198"; +$fa-var-sliders: "\f1de"; +$fa-var-slideshare: "\f1e7"; +$fa-var-smile-o: "\f118"; +$fa-var-snapchat: "\f2ab"; +$fa-var-snapchat-ghost: "\f2ac"; +$fa-var-snapchat-square: "\f2ad"; +$fa-var-snowflake-o: "\f2dc"; +$fa-var-soccer-ball-o: "\f1e3"; +$fa-var-sort: "\f0dc"; +$fa-var-sort-alpha-asc: "\f15d"; +$fa-var-sort-alpha-desc: "\f15e"; +$fa-var-sort-amount-asc: "\f160"; +$fa-var-sort-amount-desc: "\f161"; +$fa-var-sort-asc: "\f0de"; +$fa-var-sort-desc: "\f0dd"; +$fa-var-sort-down: "\f0dd"; +$fa-var-sort-numeric-asc: "\f162"; +$fa-var-sort-numeric-desc: "\f163"; +$fa-var-sort-up: "\f0de"; +$fa-var-soundcloud: "\f1be"; +$fa-var-space-shuttle: "\f197"; +$fa-var-spinner: "\f110"; +$fa-var-spoon: "\f1b1"; +$fa-var-spotify: "\f1bc"; +$fa-var-square: "\f0c8"; +$fa-var-square-o: "\f096"; +$fa-var-stack-exchange: "\f18d"; +$fa-var-stack-overflow: "\f16c"; +$fa-var-star: "\f005"; +$fa-var-star-half: "\f089"; +$fa-var-star-half-empty: "\f123"; +$fa-var-star-half-full: "\f123"; +$fa-var-star-half-o: "\f123"; +$fa-var-star-o: "\f006"; +$fa-var-steam: "\f1b6"; +$fa-var-steam-square: "\f1b7"; +$fa-var-step-backward: "\f048"; +$fa-var-step-forward: "\f051"; +$fa-var-stethoscope: "\f0f1"; +$fa-var-sticky-note: "\f249"; +$fa-var-sticky-note-o: "\f24a"; +$fa-var-stop: "\f04d"; +$fa-var-stop-circle: "\f28d"; +$fa-var-stop-circle-o: "\f28e"; +$fa-var-street-view: "\f21d"; +$fa-var-strikethrough: "\f0cc"; +$fa-var-stumbleupon: "\f1a4"; +$fa-var-stumbleupon-circle: "\f1a3"; +$fa-var-subscript: "\f12c"; +$fa-var-subway: "\f239"; +$fa-var-suitcase: "\f0f2"; +$fa-var-sun-o: "\f185"; +$fa-var-superpowers: "\f2dd"; +$fa-var-superscript: "\f12b"; +$fa-var-support: "\f1cd"; +$fa-var-table: "\f0ce"; +$fa-var-tablet: "\f10a"; +$fa-var-tachometer: "\f0e4"; +$fa-var-tag: "\f02b"; +$fa-var-tags: "\f02c"; +$fa-var-tasks: "\f0ae"; +$fa-var-taxi: "\f1ba"; +$fa-var-telegram: "\f2c6"; +$fa-var-television: "\f26c"; +$fa-var-tencent-weibo: "\f1d5"; +$fa-var-terminal: "\f120"; +$fa-var-text-height: "\f034"; +$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"; +$fa-var-thumbs-o-up: "\f087"; +$fa-var-thumbs-up: "\f164"; +$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"; +$fa-var-toggle-off: "\f204"; +$fa-var-toggle-on: "\f205"; +$fa-var-toggle-right: "\f152"; +$fa-var-toggle-up: "\f151"; +$fa-var-trademark: "\f25c"; +$fa-var-train: "\f238"; +$fa-var-transgender: "\f224"; +$fa-var-transgender-alt: "\f225"; +$fa-var-trash: "\f1f8"; +$fa-var-trash-o: "\f014"; +$fa-var-tree: "\f1bb"; +$fa-var-trello: "\f181"; +$fa-var-tripadvisor: "\f262"; +$fa-var-trophy: "\f091"; +$fa-var-truck: "\f0d1"; +$fa-var-try: "\f195"; +$fa-var-tty: "\f1e4"; +$fa-var-tumblr: "\f173"; +$fa-var-tumblr-square: "\f174"; +$fa-var-turkish-lira: "\f195"; +$fa-var-tv: "\f26c"; +$fa-var-twitch: "\f1e8"; +$fa-var-twitter: "\f099"; +$fa-var-twitter-square: "\f081"; +$fa-var-umbrella: "\f0e9"; +$fa-var-underline: "\f0cd"; +$fa-var-undo: "\f0e2"; +$fa-var-universal-access: "\f29a"; +$fa-var-university: "\f19c"; +$fa-var-unlink: "\f127"; +$fa-var-unlock: "\f09c"; +$fa-var-unlock-alt: "\f13e"; +$fa-var-unsorted: "\f0dc"; +$fa-var-upload: "\f093"; +$fa-var-usb: "\f287"; +$fa-var-usd: "\f155"; +$fa-var-user: "\f007"; +$fa-var-user-circle: "\f2bd"; +$fa-var-user-circle-o: "\f2be"; +$fa-var-user-md: "\f0f0"; +$fa-var-user-o: "\f2c0"; +$fa-var-user-plus: "\f234"; +$fa-var-user-secret: "\f21b"; +$fa-var-user-times: "\f235"; +$fa-var-users: "\f0c0"; +$fa-var-vcard: "\f2bb"; +$fa-var-vcard-o: "\f2bc"; +$fa-var-venus: "\f221"; +$fa-var-venus-double: "\f226"; +$fa-var-venus-mars: "\f228"; +$fa-var-viacoin: "\f237"; +$fa-var-viadeo: "\f2a9"; +$fa-var-viadeo-square: "\f2aa"; +$fa-var-video-camera: "\f03d"; +$fa-var-vimeo: "\f27d"; +$fa-var-vimeo-square: "\f194"; +$fa-var-vine: "\f1ca"; +$fa-var-vk: "\f189"; +$fa-var-volume-control-phone: "\f2a0"; +$fa-var-volume-down: "\f027"; +$fa-var-volume-off: "\f026"; +$fa-var-volume-up: "\f028"; +$fa-var-warning: "\f071"; +$fa-var-wechat: "\f1d7"; +$fa-var-weibo: "\f18a"; +$fa-var-weixin: "\f1d7"; +$fa-var-whatsapp: "\f232"; +$fa-var-wheelchair: "\f193"; +$fa-var-wheelchair-alt: "\f29b"; +$fa-var-wifi: "\f1eb"; +$fa-var-wikipedia-w: "\f266"; +$fa-var-window-close: "\f2d3"; +$fa-var-window-close-o: "\f2d4"; +$fa-var-window-maximize: "\f2d0"; +$fa-var-window-minimize: "\f2d1"; +$fa-var-window-restore: "\f2d2"; +$fa-var-windows: "\f17a"; +$fa-var-won: "\f159"; +$fa-var-wordpress: "\f19a"; +$fa-var-wpbeginner: "\f297"; +$fa-var-wpexplorer: "\f2de"; +$fa-var-wpforms: "\f298"; +$fa-var-wrench: "\f0ad"; +$fa-var-xing: "\f168"; +$fa-var-xing-square: "\f169"; +$fa-var-y-combinator: "\f23b"; +$fa-var-y-combinator-square: "\f1d4"; +$fa-var-yahoo: "\f19e"; +$fa-var-yc: "\f23b"; +$fa-var-yc-square: "\f1d4"; +$fa-var-yelp: "\f1e9"; +$fa-var-yen: "\f157"; +$fa-var-yoast: "\f2b1"; +$fa-var-youtube: "\f167"; +$fa-var-youtube-play: "\f16a"; +$fa-var-youtube-square: "\f166"; + diff --git a/static/font-awesome/scss/font-awesome.scss b/static/font-awesome/scss/font-awesome.scss new file mode 100644 index 0000000..f1c83aa --- /dev/null +++ b/static/font-awesome/scss/font-awesome.scss @@ -0,0 +1,18 @@ +/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */ + +@import "variables"; +@import "mixins"; +@import "path"; +@import "core"; +@import "larger"; +@import "fixed-width"; +@import "list"; +@import "bordered-pulled"; +@import "animated"; +@import "rotated-flipped"; +@import "stacked"; +@import "icons"; +@import "screen-reader"; diff --git a/static/images/3.jpg b/static/images/3.jpg new file mode 100644 index 0000000..a45266c Binary files /dev/null and b/static/images/3.jpg differ diff --git a/static/images/bg.jpg b/static/images/bg.jpg new file mode 100644 index 0000000..20ac8f4 Binary files /dev/null and b/static/images/bg.jpg differ diff --git a/static/images/bg.png b/static/images/bg.png new file mode 100644 index 0000000..77e81bb Binary files /dev/null and b/static/images/bg.png differ diff --git a/static/images/c70.jpg b/static/images/c70.jpg new file mode 100644 index 0000000..e5f9def Binary files /dev/null and b/static/images/c70.jpg differ diff --git a/static/images/dubious_290.png b/static/images/dubious_290.png new file mode 100644 index 0000000..ae06733 Binary files /dev/null and b/static/images/dubious_290.png differ diff --git a/static/images/logo.png b/static/images/logo.png new file mode 100644 index 0000000..c96f16c Binary files /dev/null and b/static/images/logo.png differ diff --git a/static/images/touxiang_100.jpg b/static/images/touxiang_100.jpg new file mode 100644 index 0000000..1d11e1c Binary files /dev/null and b/static/images/touxiang_100.jpg differ diff --git a/static/jquery.min.js b/static/jquery.min.js new file mode 100644 index 0000000..4d9b3a2 --- /dev/null +++ b/static/jquery.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.3.1 | (c) JS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(e,t){"use strict";var n=[],r=e.document,i=Object.getPrototypeOf,o=n.slice,a=n.concat,s=n.push,u=n.indexOf,l={},c=l.toString,f=l.hasOwnProperty,p=f.toString,d=p.call(Object),h={},g=function e(t){return"function"==typeof t&&"number"!=typeof t.nodeType},y=function e(t){return null!=t&&t===t.window},v={type:!0,src:!0,noModule:!0};function m(e,t,n){var i,o=(t=t||r).createElement("script");if(o.text=e,n)for(i in v)n[i]&&(o[i]=n[i]);t.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[c.call(e)]||"object":typeof e}var b="3.3.1",w=function(e,t){return new w.fn.init(e,t)},T=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;w.fn=w.prototype={jquery:"3.3.1",constructor:w,length:0,toArray:function(){return o.call(this)},get:function(e){return null==e?o.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=w.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return w.each(this,e)},map:function(e){return this.pushStack(w.map(this,function(t,n){return e.call(t,n,t)}))},slice:function(){return this.pushStack(o.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(n>=0&&n0&&t-1 in e)}var E=function(e){var t,n,r,i,o,a,s,u,l,c,f,p,d,h,g,y,v,m,x,b="sizzle"+1*new Date,w=e.document,T=0,C=0,E=ae(),k=ae(),S=ae(),D=function(e,t){return e===t&&(f=!0),0},N={}.hasOwnProperty,A=[],j=A.pop,q=A.push,L=A.push,H=A.slice,O=function(e,t){for(var n=0,r=e.length;n+~]|"+M+")"+M+"*"),z=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),X=new RegExp(W),U=new RegExp("^"+R+"$"),V={ID:new RegExp("^#("+R+")"),CLASS:new RegExp("^\\.("+R+")"),TAG:new RegExp("^("+R+"|[*])"),ATTR:new RegExp("^"+I),PSEUDO:new RegExp("^"+W),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+P+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},G=/^(?:input|select|textarea|button)$/i,Y=/^h\d$/i,Q=/^[^{]+\{\s*\[native \w/,J=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,K=/[+~]/,Z=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ee=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},te=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ne=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},re=function(){p()},ie=me(function(e){return!0===e.disabled&&("form"in e||"label"in e)},{dir:"parentNode",next:"legend"});try{L.apply(A=H.call(w.childNodes),w.childNodes),A[w.childNodes.length].nodeType}catch(e){L={apply:A.length?function(e,t){q.apply(e,H.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function oe(e,t,r,i){var o,s,l,c,f,h,v,m=t&&t.ownerDocument,T=t?t.nodeType:9;if(r=r||[],"string"!=typeof e||!e||1!==T&&9!==T&&11!==T)return r;if(!i&&((t?t.ownerDocument||t:w)!==d&&p(t),t=t||d,g)){if(11!==T&&(f=J.exec(e)))if(o=f[1]){if(9===T){if(!(l=t.getElementById(o)))return r;if(l.id===o)return r.push(l),r}else if(m&&(l=m.getElementById(o))&&x(t,l)&&l.id===o)return r.push(l),r}else{if(f[2])return L.apply(r,t.getElementsByTagName(e)),r;if((o=f[3])&&n.getElementsByClassName&&t.getElementsByClassName)return L.apply(r,t.getElementsByClassName(o)),r}if(n.qsa&&!S[e+" "]&&(!y||!y.test(e))){if(1!==T)m=t,v=e;else if("object"!==t.nodeName.toLowerCase()){(c=t.getAttribute("id"))?c=c.replace(te,ne):t.setAttribute("id",c=b),s=(h=a(e)).length;while(s--)h[s]="#"+c+" "+ve(h[s]);v=h.join(","),m=K.test(e)&&ge(t.parentNode)||t}if(v)try{return L.apply(r,m.querySelectorAll(v)),r}catch(e){}finally{c===b&&t.removeAttribute("id")}}}return u(e.replace(B,"$1"),t,r,i)}function ae(){var e=[];function t(n,i){return e.push(n+" ")>r.cacheLength&&delete t[e.shift()],t[n+" "]=i}return t}function se(e){return e[b]=!0,e}function ue(e){var t=d.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function le(e,t){var n=e.split("|"),i=n.length;while(i--)r.attrHandle[n[i]]=t}function ce(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function fe(e){return function(t){return"input"===t.nodeName.toLowerCase()&&t.type===e}}function pe(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function de(e){return function(t){return"form"in t?t.parentNode&&!1===t.disabled?"label"in t?"label"in t.parentNode?t.parentNode.disabled===e:t.disabled===e:t.isDisabled===e||t.isDisabled!==!e&&ie(t)===e:t.disabled===e:"label"in t&&t.disabled===e}}function he(e){return se(function(t){return t=+t,se(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}function ge(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}n=oe.support={},o=oe.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return!!t&&"HTML"!==t.nodeName},p=oe.setDocument=function(e){var t,i,a=e?e.ownerDocument||e:w;return a!==d&&9===a.nodeType&&a.documentElement?(d=a,h=d.documentElement,g=!o(d),w!==d&&(i=d.defaultView)&&i.top!==i&&(i.addEventListener?i.addEventListener("unload",re,!1):i.attachEvent&&i.attachEvent("onunload",re)),n.attributes=ue(function(e){return e.className="i",!e.getAttribute("className")}),n.getElementsByTagName=ue(function(e){return e.appendChild(d.createComment("")),!e.getElementsByTagName("*").length}),n.getElementsByClassName=Q.test(d.getElementsByClassName),n.getById=ue(function(e){return h.appendChild(e).id=b,!d.getElementsByName||!d.getElementsByName(b).length}),n.getById?(r.filter.ID=function(e){var t=e.replace(Z,ee);return function(e){return e.getAttribute("id")===t}},r.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&g){var n=t.getElementById(e);return n?[n]:[]}}):(r.filter.ID=function(e){var t=e.replace(Z,ee);return function(e){var n="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return n&&n.value===t}},r.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&g){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),r.find.TAG=n.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):n.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},r.find.CLASS=n.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&g)return t.getElementsByClassName(e)},v=[],y=[],(n.qsa=Q.test(d.querySelectorAll))&&(ue(function(e){h.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&y.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||y.push("\\["+M+"*(?:value|"+P+")"),e.querySelectorAll("[id~="+b+"-]").length||y.push("~="),e.querySelectorAll(":checked").length||y.push(":checked"),e.querySelectorAll("a#"+b+"+*").length||y.push(".#.+[+~]")}),ue(function(e){e.innerHTML="";var t=d.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&y.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&y.push(":enabled",":disabled"),h.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&y.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),y.push(",.*:")})),(n.matchesSelector=Q.test(m=h.matches||h.webkitMatchesSelector||h.mozMatchesSelector||h.oMatchesSelector||h.msMatchesSelector))&&ue(function(e){n.disconnectedMatch=m.call(e,"*"),m.call(e,"[s!='']:x"),v.push("!=",W)}),y=y.length&&new RegExp(y.join("|")),v=v.length&&new RegExp(v.join("|")),t=Q.test(h.compareDocumentPosition),x=t||Q.test(h.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return f=!0,0;var r=!e.compareDocumentPosition-!t.compareDocumentPosition;return r||(1&(r=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!n.sortDetached&&t.compareDocumentPosition(e)===r?e===d||e.ownerDocument===w&&x(w,e)?-1:t===d||t.ownerDocument===w&&x(w,t)?1:c?O(c,e)-O(c,t):0:4&r?-1:1)}:function(e,t){if(e===t)return f=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===d?-1:t===d?1:i?-1:o?1:c?O(c,e)-O(c,t):0;if(i===o)return ce(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?ce(a[r],s[r]):a[r]===w?-1:s[r]===w?1:0},d):d},oe.matches=function(e,t){return oe(e,null,null,t)},oe.matchesSelector=function(e,t){if((e.ownerDocument||e)!==d&&p(e),t=t.replace(z,"='$1']"),n.matchesSelector&&g&&!S[t+" "]&&(!v||!v.test(t))&&(!y||!y.test(t)))try{var r=m.call(e,t);if(r||n.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(e){}return oe(t,d,null,[e]).length>0},oe.contains=function(e,t){return(e.ownerDocument||e)!==d&&p(e),x(e,t)},oe.attr=function(e,t){(e.ownerDocument||e)!==d&&p(e);var i=r.attrHandle[t.toLowerCase()],o=i&&N.call(r.attrHandle,t.toLowerCase())?i(e,t,!g):void 0;return void 0!==o?o:n.attributes||!g?e.getAttribute(t):(o=e.getAttributeNode(t))&&o.specified?o.value:null},oe.escape=function(e){return(e+"").replace(te,ne)},oe.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},oe.uniqueSort=function(e){var t,r=[],i=0,o=0;if(f=!n.detectDuplicates,c=!n.sortStable&&e.slice(0),e.sort(D),f){while(t=e[o++])t===e[o]&&(i=r.push(o));while(i--)e.splice(r[i],1)}return c=null,e},i=oe.getText=function(e){var t,n="",r=0,o=e.nodeType;if(o){if(1===o||9===o||11===o){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=i(e)}else if(3===o||4===o)return e.nodeValue}else while(t=e[r++])n+=i(t);return n},(r=oe.selectors={cacheLength:50,createPseudo:se,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(Z,ee),e[3]=(e[3]||e[4]||e[5]||"").replace(Z,ee),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||oe.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&oe.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return V.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=a(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(Z,ee).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=E[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&E(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=oe.attr(r,e);return null==i?"!="===t:!t||(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i.replace($," ")+" ").indexOf(n)>-1:"|="===t&&(i===n||i.slice(0,n.length+1)===n+"-"))}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,f,p,d,h,g=o!==a?"nextSibling":"previousSibling",y=t.parentNode,v=s&&t.nodeName.toLowerCase(),m=!u&&!s,x=!1;if(y){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===v:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?y.firstChild:y.lastChild],a&&m){x=(d=(l=(c=(f=(p=y)[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]||[])[0]===T&&l[1])&&l[2],p=d&&y.childNodes[d];while(p=++d&&p&&p[g]||(x=d=0)||h.pop())if(1===p.nodeType&&++x&&p===t){c[e]=[T,d,x];break}}else if(m&&(x=d=(l=(c=(f=(p=t)[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]||[])[0]===T&&l[1]),!1===x)while(p=++d&&p&&p[g]||(x=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===v:1===p.nodeType)&&++x&&(m&&((c=(f=p[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]=[T,x]),p===t))break;return(x-=i)===r||x%r==0&&x/r>=0}}},PSEUDO:function(e,t){var n,i=r.pseudos[e]||r.setFilters[e.toLowerCase()]||oe.error("unsupported pseudo: "+e);return i[b]?i(t):i.length>1?(n=[e,e,"",t],r.setFilters.hasOwnProperty(e.toLowerCase())?se(function(e,n){var r,o=i(e,t),a=o.length;while(a--)e[r=O(e,o[a])]=!(n[r]=o[a])}):function(e){return i(e,0,n)}):i}},pseudos:{not:se(function(e){var t=[],n=[],r=s(e.replace(B,"$1"));return r[b]?se(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),t[0]=null,!n.pop()}}),has:se(function(e){return function(t){return oe(e,t).length>0}}),contains:se(function(e){return e=e.replace(Z,ee),function(t){return(t.textContent||t.innerText||i(t)).indexOf(e)>-1}}),lang:se(function(e){return U.test(e||"")||oe.error("unsupported lang: "+e),e=e.replace(Z,ee).toLowerCase(),function(t){var n;do{if(n=g?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return(n=n.toLowerCase())===e||0===n.indexOf(e+"-")}while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===h},focus:function(e){return e===d.activeElement&&(!d.hasFocus||d.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:de(!1),disabled:de(!0),checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!r.pseudos.empty(e)},header:function(e){return Y.test(e.nodeName)},input:function(e){return G.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:he(function(){return[0]}),last:he(function(e,t){return[t-1]}),eq:he(function(e,t,n){return[n<0?n+t:n]}),even:he(function(e,t){for(var n=0;n=0;)e.push(r);return e}),gt:he(function(e,t,n){for(var r=n<0?n+t:n;++r1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function be(e,t,n){for(var r=0,i=t.length;r-1&&(o[l]=!(a[l]=f))}}else v=we(v===a?v.splice(h,v.length):v),i?i(null,a,v,u):L.apply(a,v)})}function Ce(e){for(var t,n,i,o=e.length,a=r.relative[e[0].type],s=a||r.relative[" "],u=a?1:0,c=me(function(e){return e===t},s,!0),f=me(function(e){return O(t,e)>-1},s,!0),p=[function(e,n,r){var i=!a&&(r||n!==l)||((t=n).nodeType?c(e,n,r):f(e,n,r));return t=null,i}];u1&&xe(p),u>1&&ve(e.slice(0,u-1).concat({value:" "===e[u-2].type?"*":""})).replace(B,"$1"),n,u0,i=e.length>0,o=function(o,a,s,u,c){var f,h,y,v=0,m="0",x=o&&[],b=[],w=l,C=o||i&&r.find.TAG("*",c),E=T+=null==w?1:Math.random()||.1,k=C.length;for(c&&(l=a===d||a||c);m!==k&&null!=(f=C[m]);m++){if(i&&f){h=0,a||f.ownerDocument===d||(p(f),s=!g);while(y=e[h++])if(y(f,a||d,s)){u.push(f);break}c&&(T=E)}n&&((f=!y&&f)&&v--,o&&x.push(f))}if(v+=m,n&&m!==v){h=0;while(y=t[h++])y(x,b,a,s);if(o){if(v>0)while(m--)x[m]||b[m]||(b[m]=j.call(u));b=we(b)}L.apply(u,b),c&&!o&&b.length>0&&v+t.length>1&&oe.uniqueSort(u)}return c&&(T=E,l=w),x};return n?se(o):o}return s=oe.compile=function(e,t){var n,r=[],i=[],o=S[e+" "];if(!o){t||(t=a(e)),n=t.length;while(n--)(o=Ce(t[n]))[b]?r.push(o):i.push(o);(o=S(e,Ee(i,r))).selector=e}return o},u=oe.select=function(e,t,n,i){var o,u,l,c,f,p="function"==typeof e&&e,d=!i&&a(e=p.selector||e);if(n=n||[],1===d.length){if((u=d[0]=d[0].slice(0)).length>2&&"ID"===(l=u[0]).type&&9===t.nodeType&&g&&r.relative[u[1].type]){if(!(t=(r.find.ID(l.matches[0].replace(Z,ee),t)||[])[0]))return n;p&&(t=t.parentNode),e=e.slice(u.shift().value.length)}o=V.needsContext.test(e)?0:u.length;while(o--){if(l=u[o],r.relative[c=l.type])break;if((f=r.find[c])&&(i=f(l.matches[0].replace(Z,ee),K.test(u[0].type)&&ge(t.parentNode)||t))){if(u.splice(o,1),!(e=i.length&&ve(u)))return L.apply(n,i),n;break}}}return(p||s(e,d))(i,t,!g,n,!t||K.test(e)&&ge(t.parentNode)||t),n},n.sortStable=b.split("").sort(D).join("")===b,n.detectDuplicates=!!f,p(),n.sortDetached=ue(function(e){return 1&e.compareDocumentPosition(d.createElement("fieldset"))}),ue(function(e){return e.innerHTML="","#"===e.firstChild.getAttribute("href")})||le("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),n.attributes&&ue(function(e){return e.innerHTML="",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||le("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),ue(function(e){return null==e.getAttribute("disabled")})||le(P,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),oe}(e);w.find=E,w.expr=E.selectors,w.expr[":"]=w.expr.pseudos,w.uniqueSort=w.unique=E.uniqueSort,w.text=E.getText,w.isXMLDoc=E.isXML,w.contains=E.contains,w.escapeSelector=E.escape;var k=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&w(e).is(n))break;r.push(e)}return r},S=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},D=w.expr.match.needsContext;function N(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var A=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,t,n){return g(t)?w.grep(e,function(e,r){return!!t.call(e,r,e)!==n}):t.nodeType?w.grep(e,function(e){return e===t!==n}):"string"!=typeof t?w.grep(e,function(e){return u.call(t,e)>-1!==n}):w.filter(t,e,n)}w.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?w.find.matchesSelector(r,e)?[r]:[]:w.find.matches(e,w.grep(t,function(e){return 1===e.nodeType}))},w.fn.extend({find:function(e){var t,n,r=this.length,i=this;if("string"!=typeof e)return this.pushStack(w(e).filter(function(){for(t=0;t1?w.uniqueSort(n):n},filter:function(e){return this.pushStack(j(this,e||[],!1))},not:function(e){return this.pushStack(j(this,e||[],!0))},is:function(e){return!!j(this,"string"==typeof e&&D.test(e)?w(e):e||[],!1).length}});var q,L=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(w.fn.init=function(e,t,n){var i,o;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(i="<"===e[0]&&">"===e[e.length-1]&&e.length>=3?[null,e,null]:L.exec(e))||!i[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(i[1]){if(t=t instanceof w?t[0]:t,w.merge(this,w.parseHTML(i[1],t&&t.nodeType?t.ownerDocument||t:r,!0)),A.test(i[1])&&w.isPlainObject(t))for(i in t)g(this[i])?this[i](t[i]):this.attr(i,t[i]);return this}return(o=r.getElementById(i[2]))&&(this[0]=o,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):g(e)?void 0!==n.ready?n.ready(e):e(w):w.makeArray(e,this)}).prototype=w.fn,q=w(r);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};w.fn.extend({has:function(e){var t=w(e,this),n=t.length;return this.filter(function(){for(var e=0;e-1:1===n.nodeType&&w.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(o.length>1?w.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?u.call(w(e),this[0]):u.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(w.uniqueSort(w.merge(this.get(),w(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}w.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return k(e,"parentNode")},parentsUntil:function(e,t,n){return k(e,"parentNode",n)},next:function(e){return P(e,"nextSibling")},prev:function(e){return P(e,"previousSibling")},nextAll:function(e){return k(e,"nextSibling")},prevAll:function(e){return k(e,"previousSibling")},nextUntil:function(e,t,n){return k(e,"nextSibling",n)},prevUntil:function(e,t,n){return k(e,"previousSibling",n)},siblings:function(e){return S((e.parentNode||{}).firstChild,e)},children:function(e){return S(e.firstChild)},contents:function(e){return N(e,"iframe")?e.contentDocument:(N(e,"template")&&(e=e.content||e),w.merge([],e.childNodes))}},function(e,t){w.fn[e]=function(n,r){var i=w.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=w.filter(r,i)),this.length>1&&(O[e]||w.uniqueSort(i),H.test(e)&&i.reverse()),this.pushStack(i)}});var M=/[^\x20\t\r\n\f]+/g;function R(e){var t={};return w.each(e.match(M)||[],function(e,n){t[n]=!0}),t}w.Callbacks=function(e){e="string"==typeof e?R(e):w.extend({},e);var t,n,r,i,o=[],a=[],s=-1,u=function(){for(i=i||e.once,r=t=!0;a.length;s=-1){n=a.shift();while(++s-1)o.splice(n,1),n<=s&&s--}),this},has:function(e){return e?w.inArray(e,o)>-1:o.length>0},empty:function(){return o&&(o=[]),this},disable:function(){return i=a=[],o=n="",this},disabled:function(){return!o},lock:function(){return i=a=[],n||t||(o=n=""),this},locked:function(){return!!i},fireWith:function(e,n){return i||(n=[e,(n=n||[]).slice?n.slice():n],a.push(n),t||u()),this},fire:function(){return l.fireWith(this,arguments),this},fired:function(){return!!r}};return l};function I(e){return e}function W(e){throw e}function $(e,t,n,r){var i;try{e&&g(i=e.promise)?i.call(e).done(t).fail(n):e&&g(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}w.extend({Deferred:function(t){var n=[["notify","progress",w.Callbacks("memory"),w.Callbacks("memory"),2],["resolve","done",w.Callbacks("once memory"),w.Callbacks("once memory"),0,"resolved"],["reject","fail",w.Callbacks("once memory"),w.Callbacks("once memory"),1,"rejected"]],r="pending",i={state:function(){return r},always:function(){return o.done(arguments).fail(arguments),this},"catch":function(e){return i.then(null,e)},pipe:function(){var e=arguments;return w.Deferred(function(t){w.each(n,function(n,r){var i=g(e[r[4]])&&e[r[4]];o[r[1]](function(){var e=i&&i.apply(this,arguments);e&&g(e.promise)?e.promise().progress(t.notify).done(t.resolve).fail(t.reject):t[r[0]+"With"](this,i?[e]:arguments)})}),e=null}).promise()},then:function(t,r,i){var o=0;function a(t,n,r,i){return function(){var s=this,u=arguments,l=function(){var e,l;if(!(t=o&&(r!==W&&(s=void 0,u=[e]),n.rejectWith(s,u))}};t?c():(w.Deferred.getStackHook&&(c.stackTrace=w.Deferred.getStackHook()),e.setTimeout(c))}}return w.Deferred(function(e){n[0][3].add(a(0,e,g(i)?i:I,e.notifyWith)),n[1][3].add(a(0,e,g(t)?t:I)),n[2][3].add(a(0,e,g(r)?r:W))}).promise()},promise:function(e){return null!=e?w.extend(e,i):i}},o={};return w.each(n,function(e,t){var a=t[2],s=t[5];i[t[1]]=a.add,s&&a.add(function(){r=s},n[3-e][2].disable,n[3-e][3].disable,n[0][2].lock,n[0][3].lock),a.add(t[3].fire),o[t[0]]=function(){return o[t[0]+"With"](this===o?void 0:this,arguments),this},o[t[0]+"With"]=a.fireWith}),i.promise(o),t&&t.call(o,o),o},when:function(e){var t=arguments.length,n=t,r=Array(n),i=o.call(arguments),a=w.Deferred(),s=function(e){return function(n){r[e]=this,i[e]=arguments.length>1?o.call(arguments):n,--t||a.resolveWith(r,i)}};if(t<=1&&($(e,a.done(s(n)).resolve,a.reject,!t),"pending"===a.state()||g(i[n]&&i[n].then)))return a.then();while(n--)$(i[n],s(n),a.reject);return a.promise()}});var B=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;w.Deferred.exceptionHook=function(t,n){e.console&&e.console.warn&&t&&B.test(t.name)&&e.console.warn("jQuery.Deferred exception: "+t.message,t.stack,n)},w.readyException=function(t){e.setTimeout(function(){throw t})};var F=w.Deferred();w.fn.ready=function(e){return F.then(e)["catch"](function(e){w.readyException(e)}),this},w.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--w.readyWait:w.isReady)||(w.isReady=!0,!0!==e&&--w.readyWait>0||F.resolveWith(r,[w]))}}),w.ready.then=F.then;function _(){r.removeEventListener("DOMContentLoaded",_),e.removeEventListener("load",_),w.ready()}"complete"===r.readyState||"loading"!==r.readyState&&!r.documentElement.doScroll?e.setTimeout(w.ready):(r.addEventListener("DOMContentLoaded",_),e.addEventListener("load",_));var z=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if("object"===x(n)){i=!0;for(s in n)z(e,t,s,n[s],!0,o,a)}else if(void 0!==r&&(i=!0,g(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(w(e),n)})),t))for(;s1,null,!0)},removeData:function(e){return this.each(function(){K.remove(this,e)})}}),w.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=J.get(e,t),n&&(!r||Array.isArray(n)?r=J.access(e,t,w.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=w.queue(e,t),r=n.length,i=n.shift(),o=w._queueHooks(e,t),a=function(){w.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return J.get(e,n)||J.access(e,n,{empty:w.Callbacks("once memory").add(function(){J.remove(e,[t+"queue",n])})})}}),w.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),arguments.length\x20\t\r\n\f]+)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};ge.optgroup=ge.option,ge.tbody=ge.tfoot=ge.colgroup=ge.caption=ge.thead,ge.th=ge.td;function ye(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&N(e,t)?w.merge([e],n):n}function ve(e,t){for(var n=0,r=e.length;n-1)i&&i.push(o);else if(l=w.contains(o.ownerDocument,o),a=ye(f.appendChild(o),"script"),l&&ve(a),n){c=0;while(o=a[c++])he.test(o.type||"")&&n.push(o)}return f}!function(){var e=r.createDocumentFragment().appendChild(r.createElement("div")),t=r.createElement("input");t.setAttribute("type","radio"),t.setAttribute("checked","checked"),t.setAttribute("name","t"),e.appendChild(t),h.checkClone=e.cloneNode(!0).cloneNode(!0).lastChild.checked,e.innerHTML="",h.noCloneChecked=!!e.cloneNode(!0).lastChild.defaultValue}();var be=r.documentElement,we=/^key/,Te=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ce=/^([^.]*)(?:\.(.+)|)/;function Ee(){return!0}function ke(){return!1}function Se(){try{return r.activeElement}catch(e){}}function De(e,t,n,r,i,o){var a,s;if("object"==typeof t){"string"!=typeof n&&(r=r||n,n=void 0);for(s in t)De(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=ke;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return w().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=w.guid++)),e.each(function(){w.event.add(this,t,i,r,n)})}w.event={global:{},add:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,y=J.get(e);if(y){n.handler&&(n=(o=n).handler,i=o.selector),i&&w.find.matchesSelector(be,i),n.guid||(n.guid=w.guid++),(u=y.events)||(u=y.events={}),(a=y.handle)||(a=y.handle=function(t){return"undefined"!=typeof w&&w.event.triggered!==t.type?w.event.dispatch.apply(e,arguments):void 0}),l=(t=(t||"").match(M)||[""]).length;while(l--)d=g=(s=Ce.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=w.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=w.event.special[d]||{},c=w.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&w.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(e,r,h,a)||e.addEventListener&&e.addEventListener(d,a)),f.add&&(f.add.call(e,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),w.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,y=J.hasData(e)&&J.get(e);if(y&&(u=y.events)){l=(t=(t||"").match(M)||[""]).length;while(l--)if(s=Ce.exec(t[l])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){f=w.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,y.handle)||w.removeEvent(e,d,y.handle),delete u[d])}else for(d in u)w.event.remove(e,d+t[l],n,r,!0);w.isEmptyObject(u)&&J.remove(e,"handle events")}},dispatch:function(e){var t=w.event.fix(e),n,r,i,o,a,s,u=new Array(arguments.length),l=(J.get(this,"events")||{})[t.type]||[],c=w.event.special[t.type]||{};for(u[0]=t,n=1;n=1))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&("click"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n-1:w.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u\x20\t\r\n\f]*)[^>]*)\/>/gi,Ae=/\s*$/g;function Le(e,t){return N(e,"table")&&N(11!==t.nodeType?t:t.firstChild,"tr")?w(e).children("tbody")[0]||e:e}function He(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Oe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Pe(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(J.hasData(e)&&(o=J.access(e),a=J.set(t,o),l=o.events)){delete a.handle,a.events={};for(i in l)for(n=0,r=l[i].length;n1&&"string"==typeof y&&!h.checkClone&&je.test(y))return e.each(function(i){var o=e.eq(i);v&&(t[0]=y.call(this,i,o.html())),Re(o,t,n,r)});if(p&&(i=xe(t,e[0].ownerDocument,!1,e,r),o=i.firstChild,1===i.childNodes.length&&(i=o),o||r)){for(u=(s=w.map(ye(i,"script"),He)).length;f")},clone:function(e,t,n){var r,i,o,a,s=e.cloneNode(!0),u=w.contains(e.ownerDocument,e);if(!(h.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||w.isXMLDoc(e)))for(a=ye(s),r=0,i=(o=ye(e)).length;r0&&ve(a,!u&&ye(e,"script")),s},cleanData:function(e){for(var t,n,r,i=w.event.special,o=0;void 0!==(n=e[o]);o++)if(Y(n)){if(t=n[J.expando]){if(t.events)for(r in t.events)i[r]?w.event.remove(n,r):w.removeEvent(n,r,t.handle);n[J.expando]=void 0}n[K.expando]&&(n[K.expando]=void 0)}}}),w.fn.extend({detach:function(e){return Ie(this,e,!0)},remove:function(e){return Ie(this,e)},text:function(e){return z(this,function(e){return void 0===e?w.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return Re(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||Le(this,e).appendChild(e)})},prepend:function(){return Re(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Le(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return Re(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return Re(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(w.cleanData(ye(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return w.clone(this,e,t)})},html:function(e){return z(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!Ae.test(e)&&!ge[(de.exec(e)||["",""])[1].toLowerCase()]){e=w.htmlPrefilter(e);try{for(;n=0&&(u+=Math.max(0,Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))),u}function et(e,t,n){var r=$e(e),i=Fe(e,t,r),o="border-box"===w.css(e,"boxSizing",!1,r),a=o;if(We.test(i)){if(!n)return i;i="auto"}return a=a&&(h.boxSizingReliable()||i===e.style[t]),("auto"===i||!parseFloat(i)&&"inline"===w.css(e,"display",!1,r))&&(i=e["offset"+t[0].toUpperCase()+t.slice(1)],a=!0),(i=parseFloat(i)||0)+Ze(e,t,n||(o?"border":"content"),a,r,i)+"px"}w.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Fe(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=G(t),u=Xe.test(t),l=e.style;if(u||(t=Je(s)),a=w.cssHooks[t]||w.cssHooks[s],void 0===n)return a&&"get"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];"string"==(o=typeof n)&&(i=ie.exec(n))&&i[1]&&(n=ue(e,t,i),o="number"),null!=n&&n===n&&("number"===o&&(n+=i&&i[3]||(w.cssNumber[s]?"":"px")),h.clearCloneStyle||""!==n||0!==t.indexOf("background")||(l[t]="inherit"),a&&"set"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=G(t);return Xe.test(t)||(t=Je(s)),(a=w.cssHooks[t]||w.cssHooks[s])&&"get"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=Fe(e,t,r)),"normal"===i&&t in Ve&&(i=Ve[t]),""===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),w.each(["height","width"],function(e,t){w.cssHooks[t]={get:function(e,n,r){if(n)return!ze.test(w.css(e,"display"))||e.getClientRects().length&&e.getBoundingClientRect().width?et(e,t,r):se(e,Ue,function(){return et(e,t,r)})},set:function(e,n,r){var i,o=$e(e),a="border-box"===w.css(e,"boxSizing",!1,o),s=r&&Ze(e,t,r,a,o);return a&&h.scrollboxSize()===o.position&&(s-=Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-parseFloat(o[t])-Ze(e,t,"border",!1,o)-.5)),s&&(i=ie.exec(n))&&"px"!==(i[3]||"px")&&(e.style[t]=n,n=w.css(e,t)),Ke(e,n,s)}}}),w.cssHooks.marginLeft=_e(h.reliableMarginLeft,function(e,t){if(t)return(parseFloat(Fe(e,"marginLeft"))||e.getBoundingClientRect().left-se(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+"px"}),w.each({margin:"",padding:"",border:"Width"},function(e,t){w.cssHooks[e+t]={expand:function(n){for(var r=0,i={},o="string"==typeof n?n.split(" "):[n];r<4;r++)i[e+oe[r]+t]=o[r]||o[r-2]||o[0];return i}},"margin"!==e&&(w.cssHooks[e+t].set=Ke)}),w.fn.extend({css:function(e,t){return z(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=$e(e),i=t.length;a1)}});function tt(e,t,n,r,i){return new tt.prototype.init(e,t,n,r,i)}w.Tween=tt,tt.prototype={constructor:tt,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||w.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(w.cssNumber[n]?"":"px")},cur:function(){var e=tt.propHooks[this.prop];return e&&e.get?e.get(this):tt.propHooks._default.get(this)},run:function(e){var t,n=tt.propHooks[this.prop];return this.options.duration?this.pos=t=w.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):tt.propHooks._default.set(this),this}},tt.prototype.init.prototype=tt.prototype,tt.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=w.css(e.elem,e.prop,""))&&"auto"!==t?t:0},set:function(e){w.fx.step[e.prop]?w.fx.step[e.prop](e):1!==e.elem.nodeType||null==e.elem.style[w.cssProps[e.prop]]&&!w.cssHooks[e.prop]?e.elem[e.prop]=e.now:w.style(e.elem,e.prop,e.now+e.unit)}}},tt.propHooks.scrollTop=tt.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},w.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},w.fx=tt.prototype.init,w.fx.step={};var nt,rt,it=/^(?:toggle|show|hide)$/,ot=/queueHooks$/;function at(){rt&&(!1===r.hidden&&e.requestAnimationFrame?e.requestAnimationFrame(at):e.setTimeout(at,w.fx.interval),w.fx.tick())}function st(){return e.setTimeout(function(){nt=void 0}),nt=Date.now()}function ut(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i["margin"+(n=oe[r])]=i["padding"+n]=e;return t&&(i.opacity=i.width=e),i}function lt(e,t,n){for(var r,i=(pt.tweeners[t]||[]).concat(pt.tweeners["*"]),o=0,a=i.length;o1)},removeAttr:function(e){return this.each(function(){w.removeAttr(this,e)})}}),w.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return"undefined"==typeof e.getAttribute?w.prop(e,t,n):(1===o&&w.isXMLDoc(e)||(i=w.attrHooks[t.toLowerCase()]||(w.expr.match.bool.test(t)?dt:void 0)),void 0!==n?null===n?void w.removeAttr(e,t):i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+""),n):i&&"get"in i&&null!==(r=i.get(e,t))?r:null==(r=w.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!h.radioValue&&"radio"===t&&N(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(M);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),dt={set:function(e,t,n){return!1===t?w.removeAttr(e,n):e.setAttribute(n,n),n}},w.each(w.expr.match.bool.source.match(/\w+/g),function(e,t){var n=ht[t]||w.find.attr;ht[t]=function(e,t,r){var i,o,a=t.toLowerCase();return r||(o=ht[a],ht[a]=i,i=null!=n(e,t,r)?a:null,ht[a]=o),i}});var gt=/^(?:input|select|textarea|button)$/i,yt=/^(?:a|area)$/i;w.fn.extend({prop:function(e,t){return z(this,w.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each(function(){delete this[w.propFix[e]||e]})}}),w.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&w.isXMLDoc(e)||(t=w.propFix[t]||t,i=w.propHooks[t]),void 0!==n?i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=w.find.attr(e,"tabindex");return t?parseInt(t,10):gt.test(e.nodeName)||yt.test(e.nodeName)&&e.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),h.optSelected||(w.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),w.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){w.propFix[this.toLowerCase()]=this});function vt(e){return(e.match(M)||[]).join(" ")}function mt(e){return e.getAttribute&&e.getAttribute("class")||""}function xt(e){return Array.isArray(e)?e:"string"==typeof e?e.match(M)||[]:[]}w.fn.extend({addClass:function(e){var t,n,r,i,o,a,s,u=0;if(g(e))return this.each(function(t){w(this).addClass(e.call(this,t,mt(this)))});if((t=xt(e)).length)while(n=this[u++])if(i=mt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=t[a++])r.indexOf(" "+o+" ")<0&&(r+=o+" ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},removeClass:function(e){var t,n,r,i,o,a,s,u=0;if(g(e))return this.each(function(t){w(this).removeClass(e.call(this,t,mt(this)))});if(!arguments.length)return this.attr("class","");if((t=xt(e)).length)while(n=this[u++])if(i=mt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=t[a++])while(r.indexOf(" "+o+" ")>-1)r=r.replace(" "+o+" "," ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},toggleClass:function(e,t){var n=typeof e,r="string"===n||Array.isArray(e);return"boolean"==typeof t&&r?t?this.addClass(e):this.removeClass(e):g(e)?this.each(function(n){w(this).toggleClass(e.call(this,n,mt(this),t),t)}):this.each(function(){var t,i,o,a;if(r){i=0,o=w(this),a=xt(e);while(t=a[i++])o.hasClass(t)?o.removeClass(t):o.addClass(t)}else void 0!==e&&"boolean"!==n||((t=mt(this))&&J.set(this,"__className__",t),this.setAttribute&&this.setAttribute("class",t||!1===e?"":J.get(this,"__className__")||""))})},hasClass:function(e){var t,n,r=0;t=" "+e+" ";while(n=this[r++])if(1===n.nodeType&&(" "+vt(mt(n))+" ").indexOf(t)>-1)return!0;return!1}});var bt=/\r/g;w.fn.extend({val:function(e){var t,n,r,i=this[0];{if(arguments.length)return r=g(e),this.each(function(n){var i;1===this.nodeType&&(null==(i=r?e.call(this,n,w(this).val()):e)?i="":"number"==typeof i?i+="":Array.isArray(i)&&(i=w.map(i,function(e){return null==e?"":e+""})),(t=w.valHooks[this.type]||w.valHooks[this.nodeName.toLowerCase()])&&"set"in t&&void 0!==t.set(this,i,"value")||(this.value=i))});if(i)return(t=w.valHooks[i.type]||w.valHooks[i.nodeName.toLowerCase()])&&"get"in t&&void 0!==(n=t.get(i,"value"))?n:"string"==typeof(n=i.value)?n.replace(bt,""):null==n?"":n}}}),w.extend({valHooks:{option:{get:function(e){var t=w.find.attr(e,"value");return null!=t?t:vt(w.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a="select-one"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r-1)&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),w.each(["radio","checkbox"],function(){w.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=w.inArray(w(e).val(),t)>-1}},h.checkOn||(w.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})}),h.focusin="onfocusin"in e;var wt=/^(?:focusinfocus|focusoutblur)$/,Tt=function(e){e.stopPropagation()};w.extend(w.event,{trigger:function(t,n,i,o){var a,s,u,l,c,p,d,h,v=[i||r],m=f.call(t,"type")?t.type:t,x=f.call(t,"namespace")?t.namespace.split("."):[];if(s=h=u=i=i||r,3!==i.nodeType&&8!==i.nodeType&&!wt.test(m+w.event.triggered)&&(m.indexOf(".")>-1&&(m=(x=m.split(".")).shift(),x.sort()),c=m.indexOf(":")<0&&"on"+m,t=t[w.expando]?t:new w.Event(m,"object"==typeof t&&t),t.isTrigger=o?2:3,t.namespace=x.join("."),t.rnamespace=t.namespace?new RegExp("(^|\\.)"+x.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,t.result=void 0,t.target||(t.target=i),n=null==n?[t]:w.makeArray(n,[t]),d=w.event.special[m]||{},o||!d.trigger||!1!==d.trigger.apply(i,n))){if(!o&&!d.noBubble&&!y(i)){for(l=d.delegateType||m,wt.test(l+m)||(s=s.parentNode);s;s=s.parentNode)v.push(s),u=s;u===(i.ownerDocument||r)&&v.push(u.defaultView||u.parentWindow||e)}a=0;while((s=v[a++])&&!t.isPropagationStopped())h=s,t.type=a>1?l:d.bindType||m,(p=(J.get(s,"events")||{})[t.type]&&J.get(s,"handle"))&&p.apply(s,n),(p=c&&s[c])&&p.apply&&Y(s)&&(t.result=p.apply(s,n),!1===t.result&&t.preventDefault());return t.type=m,o||t.isDefaultPrevented()||d._default&&!1!==d._default.apply(v.pop(),n)||!Y(i)||c&&g(i[m])&&!y(i)&&((u=i[c])&&(i[c]=null),w.event.triggered=m,t.isPropagationStopped()&&h.addEventListener(m,Tt),i[m](),t.isPropagationStopped()&&h.removeEventListener(m,Tt),w.event.triggered=void 0,u&&(i[c]=u)),t.result}},simulate:function(e,t,n){var r=w.extend(new w.Event,n,{type:e,isSimulated:!0});w.event.trigger(r,null,t)}}),w.fn.extend({trigger:function(e,t){return this.each(function(){w.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return w.event.trigger(e,t,n,!0)}}),h.focusin||w.each({focus:"focusin",blur:"focusout"},function(e,t){var n=function(e){w.event.simulate(t,e.target,w.event.fix(e))};w.event.special[t]={setup:function(){var r=this.ownerDocument||this,i=J.access(r,t);i||r.addEventListener(e,n,!0),J.access(r,t,(i||0)+1)},teardown:function(){var r=this.ownerDocument||this,i=J.access(r,t)-1;i?J.access(r,t,i):(r.removeEventListener(e,n,!0),J.remove(r,t))}}});var Ct=e.location,Et=Date.now(),kt=/\?/;w.parseXML=function(t){var n;if(!t||"string"!=typeof t)return null;try{n=(new e.DOMParser).parseFromString(t,"text/xml")}catch(e){n=void 0}return n&&!n.getElementsByTagName("parsererror").length||w.error("Invalid XML: "+t),n};var St=/\[\]$/,Dt=/\r?\n/g,Nt=/^(?:submit|button|image|reset|file)$/i,At=/^(?:input|select|textarea|keygen)/i;function jt(e,t,n,r){var i;if(Array.isArray(t))w.each(t,function(t,i){n||St.test(e)?r(e,i):jt(e+"["+("object"==typeof i&&null!=i?t:"")+"]",i,n,r)});else if(n||"object"!==x(t))r(e,t);else for(i in t)jt(e+"["+i+"]",t[i],n,r)}w.param=function(e,t){var n,r=[],i=function(e,t){var n=g(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(Array.isArray(e)||e.jquery&&!w.isPlainObject(e))w.each(e,function(){i(this.name,this.value)});else for(n in e)jt(n,e[n],t,i);return r.join("&")},w.fn.extend({serialize:function(){return w.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=w.prop(this,"elements");return e?w.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!w(this).is(":disabled")&&At.test(this.nodeName)&&!Nt.test(e)&&(this.checked||!pe.test(e))}).map(function(e,t){var n=w(this).val();return null==n?null:Array.isArray(n)?w.map(n,function(e){return{name:t.name,value:e.replace(Dt,"\r\n")}}):{name:t.name,value:n.replace(Dt,"\r\n")}}).get()}});var qt=/%20/g,Lt=/#.*$/,Ht=/([?&])_=[^&]*/,Ot=/^(.*?):[ \t]*([^\r\n]*)$/gm,Pt=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Mt=/^(?:GET|HEAD)$/,Rt=/^\/\//,It={},Wt={},$t="*/".concat("*"),Bt=r.createElement("a");Bt.href=Ct.href;function Ft(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(M)||[];if(g(n))while(r=o[i++])"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function _t(e,t,n,r){var i={},o=e===Wt;function a(s){var u;return i[s]=!0,w.each(e[s]||[],function(e,s){var l=s(t,n,r);return"string"!=typeof l||o||i[l]?o?!(u=l):void 0:(t.dataTypes.unshift(l),a(l),!1)}),u}return a(t.dataTypes[0])||!i["*"]&&a("*")}function zt(e,t){var n,r,i=w.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&w.extend(!0,e,r),e}function Xt(e,t,n){var r,i,o,a,s=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}function Ut(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(!(a=l[u+" "+o]||l["* "+o]))for(i in l)if((s=i.split(" "))[1]===o&&(a=l[u+" "+s[0]]||l["* "+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e["throws"])t=a(t);else try{t=a(t)}catch(e){return{state:"parsererror",error:a?e:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}w.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Ct.href,type:"GET",isLocal:Pt.test(Ct.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":$t,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":w.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?zt(zt(e,w.ajaxSettings),t):zt(w.ajaxSettings,e)},ajaxPrefilter:Ft(It),ajaxTransport:Ft(Wt),ajax:function(t,n){"object"==typeof t&&(n=t,t=void 0),n=n||{};var i,o,a,s,u,l,c,f,p,d,h=w.ajaxSetup({},n),g=h.context||h,y=h.context&&(g.nodeType||g.jquery)?w(g):w.event,v=w.Deferred(),m=w.Callbacks("once memory"),x=h.statusCode||{},b={},T={},C="canceled",E={readyState:0,getResponseHeader:function(e){var t;if(c){if(!s){s={};while(t=Ot.exec(a))s[t[1].toLowerCase()]=t[2]}t=s[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return c?a:null},setRequestHeader:function(e,t){return null==c&&(e=T[e.toLowerCase()]=T[e.toLowerCase()]||e,b[e]=t),this},overrideMimeType:function(e){return null==c&&(h.mimeType=e),this},statusCode:function(e){var t;if(e)if(c)E.always(e[E.status]);else for(t in e)x[t]=[x[t],e[t]];return this},abort:function(e){var t=e||C;return i&&i.abort(t),k(0,t),this}};if(v.promise(E),h.url=((t||h.url||Ct.href)+"").replace(Rt,Ct.protocol+"//"),h.type=n.method||n.type||h.method||h.type,h.dataTypes=(h.dataType||"*").toLowerCase().match(M)||[""],null==h.crossDomain){l=r.createElement("a");try{l.href=h.url,l.href=l.href,h.crossDomain=Bt.protocol+"//"+Bt.host!=l.protocol+"//"+l.host}catch(e){h.crossDomain=!0}}if(h.data&&h.processData&&"string"!=typeof h.data&&(h.data=w.param(h.data,h.traditional)),_t(It,h,n,E),c)return E;(f=w.event&&h.global)&&0==w.active++&&w.event.trigger("ajaxStart"),h.type=h.type.toUpperCase(),h.hasContent=!Mt.test(h.type),o=h.url.replace(Lt,""),h.hasContent?h.data&&h.processData&&0===(h.contentType||"").indexOf("application/x-www-form-urlencoded")&&(h.data=h.data.replace(qt,"+")):(d=h.url.slice(o.length),h.data&&(h.processData||"string"==typeof h.data)&&(o+=(kt.test(o)?"&":"?")+h.data,delete h.data),!1===h.cache&&(o=o.replace(Ht,"$1"),d=(kt.test(o)?"&":"?")+"_="+Et+++d),h.url=o+d),h.ifModified&&(w.lastModified[o]&&E.setRequestHeader("If-Modified-Since",w.lastModified[o]),w.etag[o]&&E.setRequestHeader("If-None-Match",w.etag[o])),(h.data&&h.hasContent&&!1!==h.contentType||n.contentType)&&E.setRequestHeader("Content-Type",h.contentType),E.setRequestHeader("Accept",h.dataTypes[0]&&h.accepts[h.dataTypes[0]]?h.accepts[h.dataTypes[0]]+("*"!==h.dataTypes[0]?", "+$t+"; q=0.01":""):h.accepts["*"]);for(p in h.headers)E.setRequestHeader(p,h.headers[p]);if(h.beforeSend&&(!1===h.beforeSend.call(g,E,h)||c))return E.abort();if(C="abort",m.add(h.complete),E.done(h.success),E.fail(h.error),i=_t(Wt,h,n,E)){if(E.readyState=1,f&&y.trigger("ajaxSend",[E,h]),c)return E;h.async&&h.timeout>0&&(u=e.setTimeout(function(){E.abort("timeout")},h.timeout));try{c=!1,i.send(b,k)}catch(e){if(c)throw e;k(-1,e)}}else k(-1,"No Transport");function k(t,n,r,s){var l,p,d,b,T,C=n;c||(c=!0,u&&e.clearTimeout(u),i=void 0,a=s||"",E.readyState=t>0?4:0,l=t>=200&&t<300||304===t,r&&(b=Xt(h,E,r)),b=Ut(h,b,E,l),l?(h.ifModified&&((T=E.getResponseHeader("Last-Modified"))&&(w.lastModified[o]=T),(T=E.getResponseHeader("etag"))&&(w.etag[o]=T)),204===t||"HEAD"===h.type?C="nocontent":304===t?C="notmodified":(C=b.state,p=b.data,l=!(d=b.error))):(d=C,!t&&C||(C="error",t<0&&(t=0))),E.status=t,E.statusText=(n||C)+"",l?v.resolveWith(g,[p,C,E]):v.rejectWith(g,[E,C,d]),E.statusCode(x),x=void 0,f&&y.trigger(l?"ajaxSuccess":"ajaxError",[E,h,l?p:d]),m.fireWith(g,[E,C]),f&&(y.trigger("ajaxComplete",[E,h]),--w.active||w.event.trigger("ajaxStop")))}return E},getJSON:function(e,t,n){return w.get(e,t,n,"json")},getScript:function(e,t){return w.get(e,void 0,t,"script")}}),w.each(["get","post"],function(e,t){w[t]=function(e,n,r,i){return g(n)&&(i=i||r,r=n,n=void 0),w.ajax(w.extend({url:e,type:t,dataType:i,data:n,success:r},w.isPlainObject(e)&&e))}}),w._evalUrl=function(e){return w.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,"throws":!0})},w.fn.extend({wrapAll:function(e){var t;return this[0]&&(g(e)&&(e=e.call(this[0])),t=w(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(e){return g(e)?this.each(function(t){w(this).wrapInner(e.call(this,t))}):this.each(function(){var t=w(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=g(e);return this.each(function(n){w(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(e){return this.parent(e).not("body").each(function(){w(this).replaceWith(this.childNodes)}),this}}),w.expr.pseudos.hidden=function(e){return!w.expr.pseudos.visible(e)},w.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},w.ajaxSettings.xhr=function(){try{return new e.XMLHttpRequest}catch(e){}};var Vt={0:200,1223:204},Gt=w.ajaxSettings.xhr();h.cors=!!Gt&&"withCredentials"in Gt,h.ajax=Gt=!!Gt,w.ajaxTransport(function(t){var n,r;if(h.cors||Gt&&!t.crossDomain)return{send:function(i,o){var a,s=t.xhr();if(s.open(t.type,t.url,t.async,t.username,t.password),t.xhrFields)for(a in t.xhrFields)s[a]=t.xhrFields[a];t.mimeType&&s.overrideMimeType&&s.overrideMimeType(t.mimeType),t.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest");for(a in i)s.setRequestHeader(a,i[a]);n=function(e){return function(){n&&(n=r=s.onload=s.onerror=s.onabort=s.ontimeout=s.onreadystatechange=null,"abort"===e?s.abort():"error"===e?"number"!=typeof s.status?o(0,"error"):o(s.status,s.statusText):o(Vt[s.status]||s.status,s.statusText,"text"!==(s.responseType||"text")||"string"!=typeof s.responseText?{binary:s.response}:{text:s.responseText},s.getAllResponseHeaders()))}},s.onload=n(),r=s.onerror=s.ontimeout=n("error"),void 0!==s.onabort?s.onabort=r:s.onreadystatechange=function(){4===s.readyState&&e.setTimeout(function(){n&&r()})},n=n("abort");try{s.send(t.hasContent&&t.data||null)}catch(e){if(n)throw e}},abort:function(){n&&n()}}}),w.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),w.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(e){return w.globalEval(e),e}}}),w.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),w.ajaxTransport("script",function(e){if(e.crossDomain){var t,n;return{send:function(i,o){t=w("' + : $r; + } +} + +// ------------------------------------------------------------------------ + +if ( ! function_exists('get_clickable_smileys')) +{ + /** + * Get Clickable Smileys + * + * Returns an array of image tag links that can be clicked to be inserted + * into a form field. + * + * @param string the URL to the folder containing the smiley images + * @param array + * @return array + */ + function get_clickable_smileys($image_url, $alias = '') + { + // For backward compatibility with js_insert_smiley + if (is_array($alias)) + { + $smileys = $alias; + } + elseif (FALSE === ($smileys = _get_smiley_array())) + { + return FALSE; + } + + // Add a trailing slash to the file path if needed + $image_url = rtrim($image_url, '/').'/'; + + $used = array(); + foreach ($smileys as $key => $val) + { + // Keep duplicates from being used, which can happen if the + // mapping array contains multiple identical replacements. For example: + // :-) and :) might be replaced with the same image so both smileys + // will be in the array. + if (isset($used[$smileys[$key][0]])) + { + continue; + } + + $link[] = ''.$smileys[$key][3].''; + $used[$smileys[$key][0]] = TRUE; + } + + return $link; + } +} + +// ------------------------------------------------------------------------ + +if ( ! function_exists('parse_smileys')) +{ + /** + * Parse Smileys + * + * Takes a string as input and swaps any contained smileys for the actual image + * + * @param string the text to be parsed + * @param string the URL to the folder containing the smiley images + * @param array + * @return string + */ + function parse_smileys($str = '', $image_url = '', $smileys = NULL) + { + if ($image_url === '' OR ( ! is_array($smileys) && FALSE === ($smileys = _get_smiley_array()))) + { + return $str; + } + + // Add a trailing slash to the file path if needed + $image_url = rtrim($image_url, '/').'/'; + + foreach ($smileys as $key => $val) + { + $str = str_replace($key, ''.$smileys[$key][3].'', $str); + } + + return $str; + } +} + +// ------------------------------------------------------------------------ + +if ( ! function_exists('_get_smiley_array')) +{ + /** + * Get Smiley Array + * + * Fetches the config/smiley.php file + * + * @return mixed + */ + function _get_smiley_array() + { + static $_smileys; + + if ( ! is_array($_smileys)) + { + if (file_exists(APPPATH.'config/smileys.php')) + { + include(APPPATH.'config/smileys.php'); + } + + if (file_exists(APPPATH.'config/'.ENVIRONMENT.'/smileys.php')) + { + include(APPPATH.'config/'.ENVIRONMENT.'/smileys.php'); + } + + if (empty($smileys) OR ! is_array($smileys)) + { + $_smileys = array(); + return FALSE; + } + + $_smileys = $smileys; + } + + return $_smileys; + } +} diff --git a/system/helpers/string_helper.php b/system/helpers/string_helper.php new file mode 100644 index 0000000..3aa92fa --- /dev/null +++ b/system/helpers/string_helper.php @@ -0,0 +1,304 @@ + $val) + { + $str[$key] = strip_slashes($val); + } + + return $str; + } +} + +// ------------------------------------------------------------------------ + +if ( ! function_exists('strip_quotes')) +{ + /** + * Strip Quotes + * + * Removes single and double quotes from a string + * + * @param string + * @return string + */ + function strip_quotes($str) + { + return str_replace(array('"', "'"), '', $str); + } +} + +// ------------------------------------------------------------------------ + +if ( ! function_exists('quotes_to_entities')) +{ + /** + * Quotes to Entities + * + * Converts single and double quotes to entities + * + * @param string + * @return string + */ + function quotes_to_entities($str) + { + return str_replace(array("\'","\"","'",'"'), array("'",""","'","""), $str); + } +} + +// ------------------------------------------------------------------------ + +if ( ! function_exists('reduce_double_slashes')) +{ + /** + * Reduce Double Slashes + * + * Converts double slashes in a string to a single slash, + * except those found in http:// + * + * http://www.some-site.com//index.php + * + * becomes: + * + * http://www.some-site.com/index.php + * + * @param string + * @return string + */ + function reduce_double_slashes($str) + { + return preg_replace('#(^|[^:])//+#', '\\1/', $str); + } +} + +// ------------------------------------------------------------------------ + +if ( ! function_exists('reduce_multiples')) +{ + /** + * Reduce Multiples + * + * Reduces multiple instances of a particular character. Example: + * + * Fred, Bill,, Joe, Jimmy + * + * becomes: + * + * Fred, Bill, Joe, Jimmy + * + * @param string + * @param string the character you wish to reduce + * @param bool TRUE/FALSE - whether to trim the character from the beginning/end + * @return string + */ + function reduce_multiples($str, $character = ',', $trim = FALSE) + { + $str = preg_replace('#'.preg_quote($character, '#').'{2,}#', $character, $str); + return ($trim === TRUE) ? trim($str, $character) : $str; + } +} + +// ------------------------------------------------------------------------ + +if ( ! function_exists('random_string')) +{ + /** + * Create a "Random" String + * + * @param string type of random string. basic, alpha, alnum, numeric, nozero, unique, md5, encrypt and sha1 + * @param int number of characters + * @return string + */ + function random_string($type = 'alnum', $len = 8) + { + switch ($type) + { + case 'basic': + return mt_rand(); + case 'alnum': + case 'numeric': + case 'nozero': + case 'alpha': + switch ($type) + { + case 'alpha': + $pool = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + break; + case 'alnum': + $pool = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + break; + case 'numeric': + $pool = '0123456789'; + break; + case 'nozero': + $pool = '123456789'; + break; + } + return substr(str_shuffle(str_repeat($pool, ceil($len / strlen($pool)))), 0, $len); + case 'unique': // todo: remove in 3.1+ + case 'md5': + return md5(uniqid(mt_rand())); + case 'encrypt': // todo: remove in 3.1+ + case 'sha1': + return sha1(uniqid(mt_rand(), TRUE)); + } + } +} + +// ------------------------------------------------------------------------ + +if ( ! function_exists('increment_string')) +{ + /** + * Add's _1 to a string or increment the ending number to allow _2, _3, etc + * + * @param string required + * @param string What should the duplicate number be appended with + * @param string Which number should be used for the first dupe increment + * @return string + */ + function increment_string($str, $separator = '_', $first = 1) + { + preg_match('/(.+)'.preg_quote($separator, '/').'([0-9]+)$/', $str, $match); + return isset($match[2]) ? $match[1].$separator.($match[2] + 1) : $str.$separator.$first; + } +} + +// ------------------------------------------------------------------------ + +if ( ! function_exists('alternator')) +{ + /** + * Alternator + * + * Allows strings to be alternated. See docs... + * + * @param string (as many parameters as needed) + * @return string + */ + function alternator() + { + static $i; + + if (func_num_args() === 0) + { + $i = 0; + return ''; + } + + $args = func_get_args(); + return $args[($i++ % count($args))]; + } +} + +// ------------------------------------------------------------------------ + +if ( ! function_exists('repeater')) +{ + /** + * Repeater function + * + * @todo Remove in version 3.1+. + * @deprecated 3.0.0 This is just an alias for PHP's native str_repeat() + * + * @param string $data String to repeat + * @param int $num Number of repeats + * @return string + */ + function repeater($data, $num = 1) + { + return ($num > 0) ? str_repeat($data, $num) : ''; + } +} diff --git a/system/helpers/text_helper.php b/system/helpers/text_helper.php new file mode 100644 index 0000000..3e2dca8 --- /dev/null +++ b/system/helpers/text_helper.php @@ -0,0 +1,567 @@ += $n) + { + $out = trim($out); + return (mb_strlen($out) === mb_strlen($str)) ? $out : $out.$end_char; + } + } + } +} + +// ------------------------------------------------------------------------ + +if ( ! function_exists('ascii_to_entities')) +{ + /** + * High ASCII to Entities + * + * Converts high ASCII text and MS Word special characters to character entities + * + * @param string $str + * @return string + */ + function ascii_to_entities($str) + { + $out = ''; + $length = defined('MB_OVERLOAD_STRING') + ? mb_strlen($str, '8bit') - 1 + : strlen($str) - 1; + for ($i = 0, $count = 1, $temp = array(); $i <= $length; $i++) + { + $ordinal = ord($str[$i]); + + if ($ordinal < 128) + { + /* + If the $temp array has a value but we have moved on, then it seems only + fair that we output that entity and restart $temp before continuing. -Paul + */ + if (count($temp) === 1) + { + $out .= '&#'.array_shift($temp).';'; + $count = 1; + } + + $out .= $str[$i]; + } + else + { + if (count($temp) === 0) + { + $count = ($ordinal < 224) ? 2 : 3; + } + + $temp[] = $ordinal; + + if (count($temp) === $count) + { + $number = ($count === 3) + ? (($temp[0] % 16) * 4096) + (($temp[1] % 64) * 64) + ($temp[2] % 64) + : (($temp[0] % 32) * 64) + ($temp[1] % 64); + + $out .= '&#'.$number.';'; + $count = 1; + $temp = array(); + } + // If this is the last iteration, just output whatever we have + elseif ($i === $length) + { + $out .= '&#'.implode(';', $temp).';'; + } + } + } + + return $out; + } +} + +// ------------------------------------------------------------------------ + +if ( ! function_exists('entities_to_ascii')) +{ + /** + * Entities to ASCII + * + * Converts character entities back to ASCII + * + * @param string + * @param bool + * @return string + */ + function entities_to_ascii($str, $all = TRUE) + { + if (preg_match_all('/\&#(\d+)\;/', $str, $matches)) + { + for ($i = 0, $s = count($matches[0]); $i < $s; $i++) + { + $digits = $matches[1][$i]; + $out = ''; + + if ($digits < 128) + { + $out .= chr($digits); + + } + elseif ($digits < 2048) + { + $out .= chr(192 + (($digits - ($digits % 64)) / 64)).chr(128 + ($digits % 64)); + } + else + { + $out .= chr(224 + (($digits - ($digits % 4096)) / 4096)) + .chr(128 + ((($digits % 4096) - ($digits % 64)) / 64)) + .chr(128 + ($digits % 64)); + } + + $str = str_replace($matches[0][$i], $out, $str); + } + } + + if ($all) + { + return str_replace( + array('&', '<', '>', '"', ''', '-'), + array('&', '<', '>', '"', "'", '-'), + $str + ); + } + + return $str; + } +} + +// ------------------------------------------------------------------------ + +if ( ! function_exists('word_censor')) +{ + /** + * Word Censoring Function + * + * Supply a string and an array of disallowed words and any + * matched words will be converted to #### or to the replacement + * word you've submitted. + * + * @param string the text string + * @param string the array of censored words + * @param string the optional replacement value + * @return string + */ + function word_censor($str, $censored, $replacement = '') + { + if ( ! is_array($censored)) + { + return $str; + } + + $str = ' '.$str.' '; + + // \w, \b and a few others do not match on a unicode character + // set for performance reasons. As a result words like über + // will not match on a word boundary. Instead, we'll assume that + // a bad word will be bookeneded by any of these characters. + $delim = '[-_\'\"`(){}<>\[\]|!?@#%&,.:;^~*+=\/ 0-9\n\r\t]'; + + foreach ($censored as $badword) + { + $badword = str_replace('\*', '\w*?', preg_quote($badword, '/')); + if ($replacement !== '') + { + $str = preg_replace( + "/({$delim})(".$badword.")({$delim})/i", + "\\1{$replacement}\\3", + $str + ); + } + elseif (preg_match_all("/{$delim}(".$badword."){$delim}/i", $str, $matches, PREG_PATTERN_ORDER | PREG_OFFSET_CAPTURE)) + { + $matches = $matches[1]; + for ($i = count($matches) - 1; $i >= 0; $i--) + { + $length = strlen($matches[$i][0]); + $str = substr_replace( + $str, + str_repeat('#', $length), + $matches[$i][1], + $length + ); + } + } + } + + return trim($str); + } +} + +// ------------------------------------------------------------------------ + +if ( ! function_exists('highlight_code')) +{ + /** + * Code Highlighter + * + * Colorizes code strings + * + * @param string the text string + * @return string + */ + function highlight_code($str) + { + /* The highlight string function encodes and highlights + * brackets so we need them to start raw. + * + * Also replace any existing PHP tags to temporary markers + * so they don't accidentally break the string out of PHP, + * and thus, thwart the highlighting. + */ + $str = str_replace( + array('<', '>', '', '<%', '%>', '\\', ''), + array('<', '>', 'phptagopen', 'phptagclose', 'asptagopen', 'asptagclose', 'backslashtmp', 'scriptclose'), + $str + ); + + // The highlight_string function requires that the text be surrounded + // by PHP tags, which we will remove later + $str = highlight_string('', TRUE); + + // Remove our artificially added PHP, and the syntax highlighting that came with it + $str = preg_replace( + array( + '/<\?php( | )/i', + '/(.*?)\?><\/span>\n<\/span>\n<\/code>/is', + '/<\/span>/i' + ), + array( + '', + "$1\n\n", + '' + ), + $str + ); + + // Replace our markers back to PHP tags. + return str_replace( + array('phptagopen', 'phptagclose', 'asptagopen', 'asptagclose', 'backslashtmp', 'scriptclose'), + array('<?', '?>', '<%', '%>', '\\', '</script>'), + $str + ); + } +} + +// ------------------------------------------------------------------------ + +if ( ! function_exists('highlight_phrase')) +{ + /** + * Phrase Highlighter + * + * Highlights a phrase within a text string + * + * @param string $str the text string + * @param string $phrase the phrase you'd like to highlight + * @param string $tag_open the openging tag to precede the phrase with + * @param string $tag_close the closing tag to end the phrase with + * @return string + */ + function highlight_phrase($str, $phrase, $tag_open = '', $tag_close = '') + { + return ($str !== '' && $phrase !== '') + ? preg_replace('/('.preg_quote($phrase, '/').')/i'.(UTF8_ENABLED ? 'u' : ''), $tag_open.'\\1'.$tag_close, $str) + : $str; + } +} + +// ------------------------------------------------------------------------ + +if ( ! function_exists('convert_accented_characters')) +{ + /** + * Convert Accented Foreign Characters to ASCII + * + * @param string $str Input string + * @return string + */ + function convert_accented_characters($str) + { + static $array_from, $array_to; + + if ( ! is_array($array_from)) + { + if (file_exists(APPPATH.'config/foreign_chars.php')) + { + include(APPPATH.'config/foreign_chars.php'); + } + + if (file_exists(APPPATH.'config/'.ENVIRONMENT.'/foreign_chars.php')) + { + include(APPPATH.'config/'.ENVIRONMENT.'/foreign_chars.php'); + } + + if (empty($foreign_characters) OR ! is_array($foreign_characters)) + { + $array_from = array(); + $array_to = array(); + + return $str; + } + + $array_from = array_keys($foreign_characters); + $array_to = array_values($foreign_characters); + } + + return preg_replace($array_from, $array_to, $str); + } +} + +// ------------------------------------------------------------------------ + +if ( ! function_exists('word_wrap')) +{ + /** + * Word Wrap + * + * Wraps text at the specified character. Maintains the integrity of words. + * Anything placed between {unwrap}{/unwrap} will not be word wrapped, nor + * will URLs. + * + * @param string $str the text string + * @param int $charlim = 76 the number of characters to wrap at + * @return string + */ + function word_wrap($str, $charlim = 76) + { + // Set the character limit + is_numeric($charlim) OR $charlim = 76; + + // Reduce multiple spaces + $str = preg_replace('| +|', ' ', $str); + + // Standardize newlines + if (strpos($str, "\r") !== FALSE) + { + $str = str_replace(array("\r\n", "\r"), "\n", $str); + } + + // If the current word is surrounded by {unwrap} tags we'll + // strip the entire chunk and replace it with a marker. + $unwrap = array(); + if (preg_match_all('|\{unwrap\}(.+?)\{/unwrap\}|s', $str, $matches)) + { + for ($i = 0, $c = count($matches[0]); $i < $c; $i++) + { + $unwrap[] = $matches[1][$i]; + $str = str_replace($matches[0][$i], '{{unwrapped'.$i.'}}', $str); + } + } + + // Use PHP's native function to do the initial wordwrap. + // We set the cut flag to FALSE so that any individual words that are + // too long get left alone. In the next step we'll deal with them. + $str = wordwrap($str, $charlim, "\n", FALSE); + + // Split the string into individual lines of text and cycle through them + $output = ''; + foreach (explode("\n", $str) as $line) + { + // Is the line within the allowed character count? + // If so we'll join it to the output and continue + if (mb_strlen($line) <= $charlim) + { + $output .= $line."\n"; + continue; + } + + $temp = ''; + while (mb_strlen($line) > $charlim) + { + // If the over-length word is a URL we won't wrap it + if (preg_match('!\[url.+\]|://|www\.!', $line)) + { + break; + } + + // Trim the word down + $temp .= mb_substr($line, 0, $charlim - 1); + $line = mb_substr($line, $charlim - 1); + } + + // If $temp contains data it means we had to split up an over-length + // word into smaller chunks so we'll add it back to our current line + if ($temp !== '') + { + $output .= $temp."\n".$line."\n"; + } + else + { + $output .= $line."\n"; + } + } + + // Put our markers back + if (count($unwrap) > 0) + { + foreach ($unwrap as $key => $val) + { + $output = str_replace('{{unwrapped'.$key.'}}', $val, $output); + } + } + + return $output; + } +} + +// ------------------------------------------------------------------------ + +if ( ! function_exists('ellipsize')) +{ + /** + * Ellipsize String + * + * This function will strip tags from a string, split it at its max_length and ellipsize + * + * @param string string to ellipsize + * @param int max length of string + * @param mixed int (1|0) or float, .5, .2, etc for position to split + * @param string ellipsis ; Default '...' + * @return string ellipsized string + */ + function ellipsize($str, $max_length, $position = 1, $ellipsis = '…') + { + // Strip tags + $str = trim(strip_tags($str)); + + // Is the string long enough to ellipsize? + if (mb_strlen($str) <= $max_length) + { + return $str; + } + + $beg = mb_substr($str, 0, floor($max_length * $position)); + $position = ($position > 1) ? 1 : $position; + + if ($position === 1) + { + $end = mb_substr($str, 0, -($max_length - mb_strlen($beg))); + } + else + { + $end = mb_substr($str, -($max_length - mb_strlen($beg))); + } + + return $beg.$ellipsis.$end; + } +} diff --git a/system/helpers/typography_helper.php b/system/helpers/typography_helper.php new file mode 100644 index 0000000..e97c83b --- /dev/null +++ b/system/helpers/typography_helper.php @@ -0,0 +1,104 @@ +load->library('typography'); + return $CI->typography->nl2br_except_pre($str); + } +} + +// ------------------------------------------------------------------------ + +if ( ! function_exists('auto_typography')) +{ + /** + * Auto Typography Wrapper Function + * + * @param string $str + * @param bool $reduce_linebreaks = FALSE whether to reduce multiple instances of double newlines to two + * @return string + */ + function auto_typography($str, $reduce_linebreaks = FALSE) + { + $CI =& get_instance(); + $CI->load->library('typography'); + return $CI->typography->auto_typography($str, $reduce_linebreaks); + } +} + +// -------------------------------------------------------------------- + +if ( ! function_exists('entity_decode')) +{ + /** + * HTML Entities Decode + * + * This function is a replacement for html_entity_decode() + * + * @param string + * @param string + * @return string + */ + function entity_decode($str, $charset = NULL) + { + return get_instance()->security->entity_decode($str, $charset); + } +} diff --git a/system/helpers/url_helper.php b/system/helpers/url_helper.php new file mode 100644 index 0000000..a22c4c2 --- /dev/null +++ b/system/helpers/url_helper.php @@ -0,0 +1,569 @@ +config->site_url($uri, $protocol); + } +} + +// ------------------------------------------------------------------------ + +if ( ! function_exists('base_url')) +{ + /** + * Base URL + * + * Create a local URL based on your basepath. + * Segments can be passed in as a string or an array, same as site_url + * or a URL to a file can be passed in, e.g. to an image file. + * + * @param string $uri + * @param string $protocol + * @return string + */ + function base_url($uri = '', $protocol = NULL) + { + return get_instance()->config->base_url($uri, $protocol); + } +} + +// ------------------------------------------------------------------------ + +if ( ! function_exists('current_url')) +{ + /** + * Current URL + * + * Returns the full URL (including segments) of the page where this + * function is placed + * + * @return string + */ + function current_url() + { + $CI =& get_instance(); + return $CI->config->site_url($CI->uri->uri_string()); + } +} + +// ------------------------------------------------------------------------ + +if ( ! function_exists('uri_string')) +{ + /** + * URL String + * + * Returns the URI segments. + * + * @return string + */ + function uri_string() + { + return get_instance()->uri->uri_string(); + } +} + +// ------------------------------------------------------------------------ + +if ( ! function_exists('index_page')) +{ + /** + * Index page + * + * Returns the "index_page" from your config file + * + * @return string + */ + function index_page() + { + return get_instance()->config->item('index_page'); + } +} + +// ------------------------------------------------------------------------ + +if ( ! function_exists('anchor')) +{ + /** + * Anchor Link + * + * Creates an anchor based on the local URL. + * + * @param string the URL + * @param string the link title + * @param mixed any attributes + * @return string + */ + function anchor($uri = '', $title = '', $attributes = '') + { + $title = (string) $title; + + $site_url = is_array($uri) + ? site_url($uri) + : (preg_match('#^(\w+:)?//#i', $uri) ? $uri : site_url($uri)); + + if ($title === '') + { + $title = $site_url; + } + + if ($attributes !== '') + { + $attributes = _stringify_attributes($attributes); + } + + return ''.$title.''; + } +} + +// ------------------------------------------------------------------------ + +if ( ! function_exists('anchor_popup')) +{ + /** + * Anchor Link - Pop-up version + * + * Creates an anchor based on the local URL. The link + * opens a new window based on the attributes specified. + * + * @param string the URL + * @param string the link title + * @param mixed any attributes + * @return string + */ + function anchor_popup($uri = '', $title = '', $attributes = FALSE) + { + $title = (string) $title; + $site_url = preg_match('#^(\w+:)?//#i', $uri) ? $uri : site_url($uri); + + if ($title === '') + { + $title = $site_url; + } + + if ($attributes === FALSE) + { + return '".$title.''; + } + + if ( ! is_array($attributes)) + { + $attributes = array($attributes); + + // Ref: http://www.w3schools.com/jsref/met_win_open.asp + $window_name = '_blank'; + } + elseif ( ! empty($attributes['window_name'])) + { + $window_name = $attributes['window_name']; + unset($attributes['window_name']); + } + else + { + $window_name = '_blank'; + } + + foreach (array('width' => '800', 'height' => '600', 'scrollbars' => 'yes', 'menubar' => 'no', 'status' => 'yes', 'resizable' => 'yes', 'screenx' => '0', 'screeny' => '0') as $key => $val) + { + $atts[$key] = isset($attributes[$key]) ? $attributes[$key] : $val; + unset($attributes[$key]); + } + + $attributes = _stringify_attributes($attributes); + + return ''.$title.''; + } +} + +// ------------------------------------------------------------------------ + +if ( ! function_exists('mailto')) +{ + /** + * Mailto Link + * + * @param string the email address + * @param string the link title + * @param mixed any attributes + * @return string + */ + function mailto($email, $title = '', $attributes = '') + { + $title = (string) $title; + + if ($title === '') + { + $title = $email; + } + + return ''.$title.''; + } +} + +// ------------------------------------------------------------------------ + +if ( ! function_exists('safe_mailto')) +{ + /** + * Encoded Mailto Link + * + * Create a spam-protected mailto link written in Javascript + * + * @param string the email address + * @param string the link title + * @param mixed any attributes + * @return string + */ + function safe_mailto($email, $title = '', $attributes = '') + { + $title = (string) $title; + + if ($title === '') + { + $title = $email; + } + + $x = str_split(' $val) + { + $x[] = ' '.$key.'="'; + for ($i = 0, $l = strlen($val); $i < $l; $i++) + { + $x[] = '|'.ord($val[$i]); + } + $x[] = '"'; + } + } + else + { + for ($i = 0, $l = strlen($attributes); $i < $l; $i++) + { + $x[] = $attributes[$i]; + } + } + } + + $x[] = '>'; + + $temp = array(); + for ($i = 0, $l = strlen($title); $i < $l; $i++) + { + $ordinal = ord($title[$i]); + + if ($ordinal < 128) + { + $x[] = '|'.$ordinal; + } + else + { + if (count($temp) === 0) + { + $count = ($ordinal < 224) ? 2 : 3; + } + + $temp[] = $ordinal; + if (count($temp) === $count) + { + $number = ($count === 3) + ? (($temp[0] % 16) * 4096) + (($temp[1] % 64) * 64) + ($temp[2] % 64) + : (($temp[0] % 32) * 64) + ($temp[1] % 64); + $x[] = '|'.$number; + $count = 1; + $temp = array(); + } + } + } + + $x[] = '<'; $x[] = '/'; $x[] = 'a'; $x[] = '>'; + + $x = array_reverse($x); + + $output = "'; + + return $output; + } +} + +// ------------------------------------------------------------------------ + +if ( ! function_exists('auto_link')) +{ + /** + * Auto-linker + * + * Automatically links URL and Email addresses. + * Note: There's a bit of extra code here to deal with + * URLs or emails that end in a period. We'll strip these + * off and add them after the link. + * + * @param string the string + * @param string the type: email, url, or both + * @param bool whether to create pop-up links + * @return string + */ + function auto_link($str, $type = 'both', $popup = FALSE) + { + // Find and replace any URLs. + if ($type !== 'email' && preg_match_all('#(\w*://|www\.)[a-z0-9]+(-+[a-z0-9]+)*(\.[a-z0-9]+(-+[a-z0-9]+)*)+(/([^\s()<>;]+\w)?/?)?#i', $str, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER)) + { + // Set our target HTML if using popup links. + $target = ($popup) ? ' target="_blank" rel="noopener"' : ''; + + // We process the links in reverse order (last -> first) so that + // the returned string offsets from preg_match_all() are not + // moved as we add more HTML. + foreach (array_reverse($matches) as $match) + { + // $match[0] is the matched string/link + // $match[1] is either a protocol prefix or 'www.' + // + // With PREG_OFFSET_CAPTURE, both of the above is an array, + // where the actual value is held in [0] and its offset at the [1] index. + $a = ''.$match[0][0].''; + $str = substr_replace($str, $a, $match[0][1], strlen($match[0][0])); + } + } + + // Find and replace any emails. + if ($type !== 'url' && preg_match_all('#([\w\.\-\+]+@[a-z0-9\-]+\.[a-z0-9\-\.]+[^[:punct:]\s])#i', $str, $matches, PREG_OFFSET_CAPTURE)) + { + foreach (array_reverse($matches[0]) as $match) + { + if (filter_var($match[0], FILTER_VALIDATE_EMAIL) !== FALSE) + { + $str = substr_replace($str, safe_mailto($match[0]), $match[1], strlen($match[0])); + } + } + } + + return $str; + } +} + +// ------------------------------------------------------------------------ + +if ( ! function_exists('prep_url')) +{ + /** + * Prep URL + * + * Simply adds the http:// part if no scheme is included + * + * @param string the URL + * @return string + */ + function prep_url($str = '') + { + if ($str === 'http://' OR $str === '') + { + return ''; + } + + $url = parse_url($str); + + if ( ! $url OR ! isset($url['scheme'])) + { + return 'http://'.$str; + } + + return $str; + } +} + +// ------------------------------------------------------------------------ + +if ( ! function_exists('url_title')) +{ + /** + * Create URL Title + * + * Takes a "title" string as input and creates a + * human-friendly URL string with a "separator" string + * as the word separator. + * + * @todo Remove old 'dash' and 'underscore' usage in 3.1+. + * @param string $str Input string + * @param string $separator Word separator + * (usually '-' or '_') + * @param bool $lowercase Whether to transform the output string to lowercase + * @return string + */ + function url_title($str, $separator = '-', $lowercase = FALSE) + { + if ($separator === 'dash') + { + $separator = '-'; + } + elseif ($separator === 'underscore') + { + $separator = '_'; + } + + $q_separator = preg_quote($separator, '#'); + + $trans = array( + '&.+?;' => '', + '[^\w\d _-]' => '', + '\s+' => $separator, + '('.$q_separator.')+' => $separator + ); + + $str = strip_tags($str); + foreach ($trans as $key => $val) + { + $str = preg_replace('#'.$key.'#i'.(UTF8_ENABLED ? 'u' : ''), $val, $str); + } + + if ($lowercase === TRUE) + { + $str = strtolower($str); + } + + return trim(trim($str, $separator)); + } +} + +// ------------------------------------------------------------------------ + +if ( ! function_exists('redirect')) +{ + /** + * Header Redirect + * + * Header redirect in two flavors + * For very fine grained control over headers, you could use the Output + * Library's set_header() function. + * + * @param string $uri URL + * @param string $method Redirect method + * 'auto', 'location' or 'refresh' + * @param int $code HTTP Response status code + * @return void + */ + function redirect($uri = '', $method = 'auto', $code = NULL) + { + if ( ! preg_match('#^(\w+:)?//#i', $uri)) + { + $uri = site_url($uri); + } + + // IIS environment likely? Use 'refresh' for better compatibility + if ($method === 'auto' && isset($_SERVER['SERVER_SOFTWARE']) && strpos($_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS') !== FALSE) + { + $method = 'refresh'; + } + elseif ($method !== 'refresh' && (empty($code) OR ! is_numeric($code))) + { + if (isset($_SERVER['SERVER_PROTOCOL'], $_SERVER['REQUEST_METHOD']) && $_SERVER['SERVER_PROTOCOL'] === 'HTTP/1.1') + { + $code = ($_SERVER['REQUEST_METHOD'] !== 'GET') + ? 303 // reference: http://en.wikipedia.org/wiki/Post/Redirect/Get + : 307; + } + else + { + $code = 302; + } + } + + switch ($method) + { + case 'refresh': + header('Refresh:0;url='.$uri); + break; + default: + header('Location: '.$uri, TRUE, $code); + break; + } + exit; + } +} diff --git a/system/helpers/xml_helper.php b/system/helpers/xml_helper.php new file mode 100644 index 0000000..68fb9d7 --- /dev/null +++ b/system/helpers/xml_helper.php @@ -0,0 +1,90 @@ +', '"', "'", '-'), + array('&', '<', '>', '"', ''', '-'), + $str + ); + + // Decode the temp markers back to entities + $str = preg_replace('/'.$temp.'(\d+);/', '&#\\1;', $str); + + if ($protect_all === TRUE) + { + return preg_replace('/'.$temp.'(\w+);/', '&\\1;', $str); + } + + return $str; + } +} diff --git a/system/index.html b/system/index.html new file mode 100644 index 0000000..b702fbc --- /dev/null +++ b/system/index.html @@ -0,0 +1,11 @@ + + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + diff --git a/system/language/english/calendar_lang.php b/system/language/english/calendar_lang.php new file mode 100644 index 0000000..e8d673d --- /dev/null +++ b/system/language/english/calendar_lang.php @@ -0,0 +1,84 @@ + + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + diff --git a/system/language/english/migration_lang.php b/system/language/english/migration_lang.php new file mode 100644 index 0000000..68f431b --- /dev/null +++ b/system/language/english/migration_lang.php @@ -0,0 +1,47 @@ + + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + diff --git a/system/libraries/Cache/Cache.php b/system/libraries/Cache/Cache.php new file mode 100644 index 0000000..f13c024 --- /dev/null +++ b/system/libraries/Cache/Cache.php @@ -0,0 +1,255 @@ +_adapter = $config['adapter']; + isset($config['backup']) && $this->_backup_driver = $config['backup']; + isset($config['key_prefix']) && $this->key_prefix = $config['key_prefix']; + + // If the specified adapter isn't available, check the backup. + if ( ! $this->is_supported($this->_adapter)) + { + if ( ! $this->is_supported($this->_backup_driver)) + { + // Backup isn't supported either. Default to 'Dummy' driver. + log_message('error', 'Cache adapter "'.$this->_adapter.'" and backup "'.$this->_backup_driver.'" are both unavailable. Cache is now using "Dummy" adapter.'); + $this->_adapter = 'dummy'; + } + else + { + // Backup is supported. Set it to primary. + log_message('debug', 'Cache adapter "'.$this->_adapter.'" is unavailable. Falling back to "'.$this->_backup_driver.'" backup adapter.'); + $this->_adapter = $this->_backup_driver; + } + } + } + + // ------------------------------------------------------------------------ + + /** + * Get + * + * Look for a value in the cache. If it exists, return the data + * if not, return FALSE + * + * @param string $id + * @return mixed value matching $id or FALSE on failure + */ + public function get($id) + { + return $this->{$this->_adapter}->get($this->key_prefix.$id); + } + + // ------------------------------------------------------------------------ + + /** + * Cache Save + * + * @param string $id Cache ID + * @param mixed $data Data to store + * @param int $ttl Cache TTL (in seconds) + * @param bool $raw Whether to store the raw value + * @return bool TRUE on success, FALSE on failure + */ + public function save($id, $data, $ttl = 60, $raw = FALSE) + { + return $this->{$this->_adapter}->save($this->key_prefix.$id, $data, $ttl, $raw); + } + + // ------------------------------------------------------------------------ + + /** + * Delete from Cache + * + * @param string $id Cache ID + * @return bool TRUE on success, FALSE on failure + */ + public function delete($id) + { + return $this->{$this->_adapter}->delete($this->key_prefix.$id); + } + + // ------------------------------------------------------------------------ + + /** + * Increment a raw value + * + * @param string $id Cache ID + * @param int $offset Step/value to add + * @return mixed New value on success or FALSE on failure + */ + public function increment($id, $offset = 1) + { + return $this->{$this->_adapter}->increment($this->key_prefix.$id, $offset); + } + + // ------------------------------------------------------------------------ + + /** + * Decrement a raw value + * + * @param string $id Cache ID + * @param int $offset Step/value to reduce by + * @return mixed New value on success or FALSE on failure + */ + public function decrement($id, $offset = 1) + { + return $this->{$this->_adapter}->decrement($this->key_prefix.$id, $offset); + } + + // ------------------------------------------------------------------------ + + /** + * Clean the cache + * + * @return bool TRUE on success, FALSE on failure + */ + public function clean() + { + return $this->{$this->_adapter}->clean(); + } + + // ------------------------------------------------------------------------ + + /** + * Cache Info + * + * @param string $type = 'user' user/filehits + * @return mixed array containing cache info on success OR FALSE on failure + */ + public function cache_info($type = 'user') + { + return $this->{$this->_adapter}->cache_info($type); + } + + // ------------------------------------------------------------------------ + + /** + * Get Cache Metadata + * + * @param string $id key to get cache metadata on + * @return mixed cache item metadata + */ + public function get_metadata($id) + { + return $this->{$this->_adapter}->get_metadata($this->key_prefix.$id); + } + + // ------------------------------------------------------------------------ + + /** + * Is the requested driver supported in this environment? + * + * @param string $driver The driver to test + * @return array + */ + public function is_supported($driver) + { + static $support; + + if ( ! isset($support, $support[$driver])) + { + $support[$driver] = $this->{$driver}->is_supported(); + } + + return $support[$driver]; + } +} diff --git a/system/libraries/Cache/drivers/Cache_apc.php b/system/libraries/Cache/drivers/Cache_apc.php new file mode 100644 index 0000000..b42a832 --- /dev/null +++ b/system/libraries/Cache/drivers/Cache_apc.php @@ -0,0 +1,217 @@ +is_supported()) + { + log_message('error', 'Cache: Failed to initialize APC; extension not loaded/enabled?'); + } + } + + // ------------------------------------------------------------------------ + + /** + * Get + * + * Look for a value in the cache. If it exists, return the data + * if not, return FALSE + * + * @param string + * @return mixed value that is stored/FALSE on failure + */ + public function get($id) + { + $success = FALSE; + $data = apc_fetch($id, $success); + + return ($success === TRUE) ? $data : FALSE; + } + + // ------------------------------------------------------------------------ + + /** + * Cache Save + * + * @param string $id Cache ID + * @param mixed $data Data to store + * @param int $ttl Length of time (in seconds) to cache the data + * @param bool $raw Whether to store the raw value (unused) + * @return bool TRUE on success, FALSE on failure + */ + public function save($id, $data, $ttl = 60, $raw = FALSE) + { + return apc_store($id, $data, (int) $ttl); + } + + // ------------------------------------------------------------------------ + + /** + * Delete from Cache + * + * @param mixed unique identifier of the item in the cache + * @return bool true on success/false on failure + */ + public function delete($id) + { + return apc_delete($id); + } + + // ------------------------------------------------------------------------ + + /** + * Increment a raw value + * + * @param string $id Cache ID + * @param int $offset Step/value to add + * @return mixed New value on success or FALSE on failure + */ + public function increment($id, $offset = 1) + { + return apc_inc($id, $offset); + } + + // ------------------------------------------------------------------------ + + /** + * Decrement a raw value + * + * @param string $id Cache ID + * @param int $offset Step/value to reduce by + * @return mixed New value on success or FALSE on failure + */ + public function decrement($id, $offset = 1) + { + return apc_dec($id, $offset); + } + + // ------------------------------------------------------------------------ + + /** + * Clean the cache + * + * @return bool false on failure/true on success + */ + public function clean() + { + return apc_clear_cache('user'); + } + + // ------------------------------------------------------------------------ + + /** + * Cache Info + * + * @param string user/filehits + * @return mixed array on success, false on failure + */ + public function cache_info($type = NULL) + { + return apc_cache_info($type); + } + + // ------------------------------------------------------------------------ + + /** + * Get Cache Metadata + * + * @param mixed key to get cache metadata on + * @return mixed array on success/false on failure + */ + public function get_metadata($id) + { + $cache_info = apc_cache_info('user', FALSE); + if (empty($cache_info) OR empty($cache_info['cache_list'])) + { + return FALSE; + } + + foreach ($cache_info['cache_list'] as &$entry) + { + if ($entry['info'] !== $id) + { + continue; + } + + $success = FALSE; + $metadata = array( + 'expire' => ($entry['ttl'] ? $entry['mtime'] + $entry['ttl'] : 0), + 'mtime' => $entry['ttl'], + 'data' => apc_fetch($id, $success) + ); + + return ($success === TRUE) ? $metadata : FALSE; + } + + return FALSE; + } + + // ------------------------------------------------------------------------ + + /** + * is_supported() + * + * Check to see if APC is available on this system, bail if it isn't. + * + * @return bool + */ + public function is_supported() + { + return (extension_loaded('apc') && ini_get('apc.enabled')); + } +} diff --git a/system/libraries/Cache/drivers/Cache_dummy.php b/system/libraries/Cache/drivers/Cache_dummy.php new file mode 100644 index 0000000..bbaf96f --- /dev/null +++ b/system/libraries/Cache/drivers/Cache_dummy.php @@ -0,0 +1,172 @@ +load->helper('file'); + $path = $CI->config->item('cache_path'); + $this->_cache_path = ($path === '') ? APPPATH.'cache/' : $path; + } + + // ------------------------------------------------------------------------ + + /** + * Fetch from cache + * + * @param string $id Cache ID + * @return mixed Data on success, FALSE on failure + */ + public function get($id) + { + $data = $this->_get($id); + return is_array($data) ? $data['data'] : FALSE; + } + + // ------------------------------------------------------------------------ + + /** + * Save into cache + * + * @param string $id Cache ID + * @param mixed $data Data to store + * @param int $ttl Time to live in seconds + * @param bool $raw Whether to store the raw value (unused) + * @return bool TRUE on success, FALSE on failure + */ + public function save($id, $data, $ttl = 60, $raw = FALSE) + { + $contents = array( + 'time' => time(), + 'ttl' => $ttl, + 'data' => $data + ); + + if (write_file($this->_cache_path.$id, serialize($contents))) + { + chmod($this->_cache_path.$id, 0640); + return TRUE; + } + + return FALSE; + } + + // ------------------------------------------------------------------------ + + /** + * Delete from Cache + * + * @param mixed unique identifier of item in cache + * @return bool true on success/false on failure + */ + public function delete($id) + { + return is_file($this->_cache_path.$id) ? unlink($this->_cache_path.$id) : FALSE; + } + + // ------------------------------------------------------------------------ + + /** + * Increment a raw value + * + * @param string $id Cache ID + * @param int $offset Step/value to add + * @return New value on success, FALSE on failure + */ + public function increment($id, $offset = 1) + { + $data = $this->_get($id); + + if ($data === FALSE) + { + $data = array('data' => 0, 'ttl' => 60); + } + elseif ( ! is_int($data['data'])) + { + return FALSE; + } + + $new_value = $data['data'] + $offset; + return $this->save($id, $new_value, $data['ttl']) + ? $new_value + : FALSE; + } + + // ------------------------------------------------------------------------ + + /** + * Decrement a raw value + * + * @param string $id Cache ID + * @param int $offset Step/value to reduce by + * @return New value on success, FALSE on failure + */ + public function decrement($id, $offset = 1) + { + $data = $this->_get($id); + + if ($data === FALSE) + { + $data = array('data' => 0, 'ttl' => 60); + } + elseif ( ! is_int($data['data'])) + { + return FALSE; + } + + $new_value = $data['data'] - $offset; + return $this->save($id, $new_value, $data['ttl']) + ? $new_value + : FALSE; + } + + // ------------------------------------------------------------------------ + + /** + * Clean the Cache + * + * @return bool false on failure/true on success + */ + public function clean() + { + return delete_files($this->_cache_path, FALSE, TRUE); + } + + // ------------------------------------------------------------------------ + + /** + * Cache Info + * + * Not supported by file-based caching + * + * @param string user/filehits + * @return mixed FALSE + */ + public function cache_info($type = NULL) + { + return get_dir_file_info($this->_cache_path); + } + + // ------------------------------------------------------------------------ + + /** + * Get Cache Metadata + * + * @param mixed key to get cache metadata on + * @return mixed FALSE on failure, array on success. + */ + public function get_metadata($id) + { + if ( ! is_file($this->_cache_path.$id)) + { + return FALSE; + } + + $data = unserialize(file_get_contents($this->_cache_path.$id)); + + if (is_array($data)) + { + $mtime = filemtime($this->_cache_path.$id); + + if ( ! isset($data['ttl'], $data['time'])) + { + return FALSE; + } + + return array( + 'expire' => $data['time'] + $data['ttl'], + 'mtime' => $mtime + ); + } + + return FALSE; + } + + // ------------------------------------------------------------------------ + + /** + * Is supported + * + * In the file driver, check to see that the cache directory is indeed writable + * + * @return bool + */ + public function is_supported() + { + return is_really_writable($this->_cache_path); + } + + // ------------------------------------------------------------------------ + + /** + * Get all data + * + * Internal method to get all the relevant data about a cache item + * + * @param string $id Cache ID + * @return mixed Data array on success or FALSE on failure + */ + protected function _get($id) + { + if ( ! is_file($this->_cache_path.$id)) + { + return FALSE; + } + + $data = unserialize(file_get_contents($this->_cache_path.$id)); + + if ($data['ttl'] > 0 && time() > $data['time'] + $data['ttl']) + { + unlink($this->_cache_path.$id); + return FALSE; + } + + return $data; + } + +} diff --git a/system/libraries/Cache/drivers/Cache_memcached.php b/system/libraries/Cache/drivers/Cache_memcached.php new file mode 100644 index 0000000..9dfee47 --- /dev/null +++ b/system/libraries/Cache/drivers/Cache_memcached.php @@ -0,0 +1,313 @@ + array( + 'host' => '127.0.0.1', + 'port' => 11211, + 'weight' => 1 + ) + ); + + // ------------------------------------------------------------------------ + + /** + * Class constructor + * + * Setup Memcache(d) + * + * @return void + */ + public function __construct() + { + // Try to load memcached server info from the config file. + $CI =& get_instance(); + $defaults = $this->_config['default']; + + if ($CI->config->load('memcached', TRUE, TRUE)) + { + $this->_config = $CI->config->config['memcached']; + } + + if (class_exists('Memcached', FALSE)) + { + $this->_memcached = new Memcached(); + } + elseif (class_exists('Memcache', FALSE)) + { + $this->_memcached = new Memcache(); + } + else + { + log_message('error', 'Cache: Failed to create Memcache(d) object; extension not loaded?'); + return; + } + + foreach ($this->_config as $cache_server) + { + isset($cache_server['hostname']) OR $cache_server['hostname'] = $defaults['host']; + isset($cache_server['port']) OR $cache_server['port'] = $defaults['port']; + isset($cache_server['weight']) OR $cache_server['weight'] = $defaults['weight']; + + if ($this->_memcached instanceof Memcache) + { + // Third parameter is persistence and defaults to TRUE. + $this->_memcached->addServer( + $cache_server['hostname'], + $cache_server['port'], + TRUE, + $cache_server['weight'] + ); + } + elseif ($this->_memcached instanceof Memcached) + { + $this->_memcached->addServer( + $cache_server['hostname'], + $cache_server['port'], + $cache_server['weight'] + ); + } + } + } + + // ------------------------------------------------------------------------ + + /** + * Fetch from cache + * + * @param string $id Cache ID + * @return mixed Data on success, FALSE on failure + */ + public function get($id) + { + $data = $this->_memcached->get($id); + + return is_array($data) ? $data[0] : $data; + } + + // ------------------------------------------------------------------------ + + /** + * Save + * + * @param string $id Cache ID + * @param mixed $data Data being cached + * @param int $ttl Time to live + * @param bool $raw Whether to store the raw value + * @return bool TRUE on success, FALSE on failure + */ + public function save($id, $data, $ttl = 60, $raw = FALSE) + { + if ($raw !== TRUE) + { + $data = array($data, time(), $ttl); + } + + if ($this->_memcached instanceof Memcached) + { + return $this->_memcached->set($id, $data, $ttl); + } + elseif ($this->_memcached instanceof Memcache) + { + return $this->_memcached->set($id, $data, 0, $ttl); + } + + return FALSE; + } + + // ------------------------------------------------------------------------ + + /** + * Delete from Cache + * + * @param mixed $id key to be deleted. + * @return bool true on success, false on failure + */ + public function delete($id) + { + return $this->_memcached->delete($id); + } + + // ------------------------------------------------------------------------ + + /** + * Increment a raw value + * + * @param string $id Cache ID + * @param int $offset Step/value to add + * @return mixed New value on success or FALSE on failure + */ + public function increment($id, $offset = 1) + { + if (($result = $this->_memcached->increment($id, $offset)) === FALSE) + { + return $this->_memcached->add($id, $offset) ? $offset : FALSE; + } + + return $result; + } + + // ------------------------------------------------------------------------ + + /** + * Decrement a raw value + * + * @param string $id Cache ID + * @param int $offset Step/value to reduce by + * @return mixed New value on success or FALSE on failure + */ + public function decrement($id, $offset = 1) + { + if (($result = $this->_memcached->decrement($id, $offset)) === FALSE) + { + return $this->_memcached->add($id, 0) ? 0 : FALSE; + } + + return $result; + } + + // ------------------------------------------------------------------------ + + /** + * Clean the Cache + * + * @return bool false on failure/true on success + */ + public function clean() + { + return $this->_memcached->flush(); + } + + // ------------------------------------------------------------------------ + + /** + * Cache Info + * + * @return mixed array on success, false on failure + */ + public function cache_info() + { + return $this->_memcached->getStats(); + } + + // ------------------------------------------------------------------------ + + /** + * Get Cache Metadata + * + * @param mixed $id key to get cache metadata on + * @return mixed FALSE on failure, array on success. + */ + public function get_metadata($id) + { + $stored = $this->_memcached->get($id); + + if (count($stored) !== 3) + { + return FALSE; + } + + list($data, $time, $ttl) = $stored; + + return array( + 'expire' => $time + $ttl, + 'mtime' => $time, + 'data' => $data + ); + } + + // ------------------------------------------------------------------------ + + /** + * Is supported + * + * Returns FALSE if memcached is not supported on the system. + * If it is, we setup the memcached object & return TRUE + * + * @return bool + */ + public function is_supported() + { + return (extension_loaded('memcached') OR extension_loaded('memcache')); + } + + // ------------------------------------------------------------------------ + + /** + * Class destructor + * + * Closes the connection to Memcache(d) if present. + * + * @return void + */ + public function __destruct() + { + if ($this->_memcached instanceof Memcache) + { + $this->_memcached->close(); + } + elseif ($this->_memcached instanceof Memcached && method_exists($this->_memcached, 'quit')) + { + $this->_memcached->quit(); + } + } +} diff --git a/system/libraries/Cache/drivers/Cache_redis.php b/system/libraries/Cache/drivers/Cache_redis.php new file mode 100644 index 0000000..bfd6204 --- /dev/null +++ b/system/libraries/Cache/drivers/Cache_redis.php @@ -0,0 +1,328 @@ + + * @link + */ +class CI_Cache_redis extends CI_Driver +{ + /** + * Default config + * + * @static + * @var array + */ + protected static $_default_config = array( + 'socket_type' => 'tcp', + 'host' => '127.0.0.1', + 'password' => NULL, + 'port' => 6379, + 'timeout' => 0 + ); + + /** + * Redis connection + * + * @var Redis + */ + protected $_redis; + + /** + * An internal cache for storing keys of serialized values. + * + * @var array + */ + protected $_serialized = array(); + + // ------------------------------------------------------------------------ + + /** + * Class constructor + * + * Setup Redis + * + * Loads Redis config file if present. Will halt execution + * if a Redis connection can't be established. + * + * @return void + * @see Redis::connect() + */ + public function __construct() + { + if ( ! $this->is_supported()) + { + log_message('error', 'Cache: Failed to create Redis object; extension not loaded?'); + return; + } + + $CI =& get_instance(); + + if ($CI->config->load('redis', TRUE, TRUE)) + { + $config = array_merge(self::$_default_config, $CI->config->item('redis')); + } + else + { + $config = self::$_default_config; + } + + $this->_redis = new Redis(); + + try + { + if ($config['socket_type'] === 'unix') + { + $success = $this->_redis->connect($config['socket']); + } + else // tcp socket + { + $success = $this->_redis->connect($config['host'], $config['port'], $config['timeout']); + } + + if ( ! $success) + { + log_message('error', 'Cache: Redis connection failed. Check your configuration.'); + } + + if (isset($config['password']) && ! $this->_redis->auth($config['password'])) + { + log_message('error', 'Cache: Redis authentication failed.'); + } + } + catch (RedisException $e) + { + log_message('error', 'Cache: Redis connection refused ('.$e->getMessage().')'); + } + + // Initialize the index of serialized values. + $serialized = $this->_redis->sMembers('_ci_redis_serialized'); + empty($serialized) OR $this->_serialized = array_flip($serialized); + } + + // ------------------------------------------------------------------------ + + /** + * Get cache + * + * @param string $key Cache ID + * @return mixed + */ + public function get($key) + { + $value = $this->_redis->get($key); + + if ($value !== FALSE && isset($this->_serialized[$key])) + { + return unserialize($value); + } + + return $value; + } + + // ------------------------------------------------------------------------ + + /** + * Save cache + * + * @param string $id Cache ID + * @param mixed $data Data to save + * @param int $ttl Time to live in seconds + * @param bool $raw Whether to store the raw value (unused) + * @return bool TRUE on success, FALSE on failure + */ + public function save($id, $data, $ttl = 60, $raw = FALSE) + { + if (is_array($data) OR is_object($data)) + { + if ( ! $this->_redis->sIsMember('_ci_redis_serialized', $id) && ! $this->_redis->sAdd('_ci_redis_serialized', $id)) + { + return FALSE; + } + + isset($this->_serialized[$id]) OR $this->_serialized[$id] = TRUE; + $data = serialize($data); + } + elseif (isset($this->_serialized[$id])) + { + $this->_serialized[$id] = NULL; + $this->_redis->sRemove('_ci_redis_serialized', $id); + } + + return $this->_redis->set($id, $data, $ttl); + } + + // ------------------------------------------------------------------------ + + /** + * Delete from cache + * + * @param string $key Cache key + * @return bool + */ + public function delete($key) + { + if ($this->_redis->delete($key) !== 1) + { + return FALSE; + } + + if (isset($this->_serialized[$key])) + { + $this->_serialized[$key] = NULL; + $this->_redis->sRemove('_ci_redis_serialized', $key); + } + + return TRUE; + } + + // ------------------------------------------------------------------------ + + /** + * Increment a raw value + * + * @param string $id Cache ID + * @param int $offset Step/value to add + * @return mixed New value on success or FALSE on failure + */ + public function increment($id, $offset = 1) + { + return $this->_redis->incr($id, $offset); + } + + // ------------------------------------------------------------------------ + + /** + * Decrement a raw value + * + * @param string $id Cache ID + * @param int $offset Step/value to reduce by + * @return mixed New value on success or FALSE on failure + */ + public function decrement($id, $offset = 1) + { + return $this->_redis->decr($id, $offset); + } + + // ------------------------------------------------------------------------ + + /** + * Clean cache + * + * @return bool + * @see Redis::flushDB() + */ + public function clean() + { + return $this->_redis->flushDB(); + } + + // ------------------------------------------------------------------------ + + /** + * Get cache driver info + * + * @param string $type Not supported in Redis. + * Only included in order to offer a + * consistent cache API. + * @return array + * @see Redis::info() + */ + public function cache_info($type = NULL) + { + return $this->_redis->info(); + } + + // ------------------------------------------------------------------------ + + /** + * Get cache metadata + * + * @param string $key Cache key + * @return array + */ + public function get_metadata($key) + { + $value = $this->get($key); + + if ($value !== FALSE) + { + return array( + 'expire' => time() + $this->_redis->ttl($key), + 'data' => $value + ); + } + + return FALSE; + } + + // ------------------------------------------------------------------------ + + /** + * Check if Redis driver is supported + * + * @return bool + */ + public function is_supported() + { + return extension_loaded('redis'); + } + + // ------------------------------------------------------------------------ + + /** + * Class destructor + * + * Closes the connection to Redis if present. + * + * @return void + */ + public function __destruct() + { + if ($this->_redis) + { + $this->_redis->close(); + } + } +} diff --git a/system/libraries/Cache/drivers/Cache_wincache.php b/system/libraries/Cache/drivers/Cache_wincache.php new file mode 100644 index 0000000..b4279bb --- /dev/null +++ b/system/libraries/Cache/drivers/Cache_wincache.php @@ -0,0 +1,217 @@ +is_supported()) + { + log_message('error', 'Cache: Failed to initialize Wincache; extension not loaded/enabled?'); + } + } + + // ------------------------------------------------------------------------ + + /** + * Get + * + * Look for a value in the cache. If it exists, return the data, + * if not, return FALSE + * + * @param string $id Cache Ide + * @return mixed Value that is stored/FALSE on failure + */ + public function get($id) + { + $success = FALSE; + $data = wincache_ucache_get($id, $success); + + // Success returned by reference from wincache_ucache_get() + return ($success) ? $data : FALSE; + } + + // ------------------------------------------------------------------------ + + /** + * Cache Save + * + * @param string $id Cache ID + * @param mixed $data Data to store + * @param int $ttl Time to live (in seconds) + * @param bool $raw Whether to store the raw value (unused) + * @return bool true on success/false on failure + */ + public function save($id, $data, $ttl = 60, $raw = FALSE) + { + return wincache_ucache_set($id, $data, $ttl); + } + + // ------------------------------------------------------------------------ + + /** + * Delete from Cache + * + * @param mixed unique identifier of the item in the cache + * @return bool true on success/false on failure + */ + public function delete($id) + { + return wincache_ucache_delete($id); + } + + // ------------------------------------------------------------------------ + + /** + * Increment a raw value + * + * @param string $id Cache ID + * @param int $offset Step/value to add + * @return mixed New value on success or FALSE on failure + */ + public function increment($id, $offset = 1) + { + $success = FALSE; + $value = wincache_ucache_inc($id, $offset, $success); + + return ($success === TRUE) ? $value : FALSE; + } + + // ------------------------------------------------------------------------ + + /** + * Decrement a raw value + * + * @param string $id Cache ID + * @param int $offset Step/value to reduce by + * @return mixed New value on success or FALSE on failure + */ + public function decrement($id, $offset = 1) + { + $success = FALSE; + $value = wincache_ucache_dec($id, $offset, $success); + + return ($success === TRUE) ? $value : FALSE; + } + + // ------------------------------------------------------------------------ + + /** + * Clean the cache + * + * @return bool false on failure/true on success + */ + public function clean() + { + return wincache_ucache_clear(); + } + + // ------------------------------------------------------------------------ + + /** + * Cache Info + * + * @return mixed array on success, false on failure + */ + public function cache_info() + { + return wincache_ucache_info(TRUE); + } + + // ------------------------------------------------------------------------ + + /** + * Get Cache Metadata + * + * @param mixed key to get cache metadata on + * @return mixed array on success/false on failure + */ + public function get_metadata($id) + { + if ($stored = wincache_ucache_info(FALSE, $id)) + { + $age = $stored['ucache_entries'][1]['age_seconds']; + $ttl = $stored['ucache_entries'][1]['ttl_seconds']; + $hitcount = $stored['ucache_entries'][1]['hitcount']; + + return array( + 'expire' => $ttl - $age, + 'hitcount' => $hitcount, + 'age' => $age, + 'ttl' => $ttl + ); + } + + return FALSE; + } + + // ------------------------------------------------------------------------ + + /** + * is_supported() + * + * Check to see if WinCache is available on this system, bail if it isn't. + * + * @return bool + */ + public function is_supported() + { + return (extension_loaded('wincache') && ini_get('wincache.ucenabled')); + } +} diff --git a/system/libraries/Cache/drivers/index.html b/system/libraries/Cache/drivers/index.html new file mode 100644 index 0000000..b702fbc --- /dev/null +++ b/system/libraries/Cache/drivers/index.html @@ -0,0 +1,11 @@ + + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + diff --git a/system/libraries/Cache/index.html b/system/libraries/Cache/index.html new file mode 100644 index 0000000..b702fbc --- /dev/null +++ b/system/libraries/Cache/index.html @@ -0,0 +1,11 @@ + + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + diff --git a/system/libraries/Calendar.php b/system/libraries/Calendar.php new file mode 100644 index 0000000..450350c --- /dev/null +++ b/system/libraries/Calendar.php @@ -0,0 +1,546 @@ +CI =& get_instance(); + $this->CI->lang->load('calendar'); + + empty($config) OR $this->initialize($config); + + log_message('info', 'Calendar Class Initialized'); + } + + // -------------------------------------------------------------------- + + /** + * Initialize the user preferences + * + * Accepts an associative array as input, containing display preferences + * + * @param array config preferences + * @return CI_Calendar + */ + public function initialize($config = array()) + { + foreach ($config as $key => $val) + { + if (isset($this->$key)) + { + $this->$key = $val; + } + } + + // Set the next_prev_url to the controller if required but not defined + if ($this->show_next_prev === TRUE && empty($this->next_prev_url)) + { + $this->next_prev_url = $this->CI->config->site_url($this->CI->router->class.'/'.$this->CI->router->method); + } + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Generate the calendar + * + * @param int the year + * @param int the month + * @param array the data to be shown in the calendar cells + * @return string + */ + public function generate($year = '', $month = '', $data = array()) + { + $local_time = time(); + + // Set and validate the supplied month/year + if (empty($year)) + { + $year = date('Y', $local_time); + } + elseif (strlen($year) === 1) + { + $year = '200'.$year; + } + elseif (strlen($year) === 2) + { + $year = '20'.$year; + } + + if (empty($month)) + { + $month = date('m', $local_time); + } + elseif (strlen($month) === 1) + { + $month = '0'.$month; + } + + $adjusted_date = $this->adjust_date($month, $year); + + $month = $adjusted_date['month']; + $year = $adjusted_date['year']; + + // Determine the total days in the month + $total_days = $this->get_total_days($month, $year); + + // Set the starting day of the week + $start_days = array('sunday' => 0, 'monday' => 1, 'tuesday' => 2, 'wednesday' => 3, 'thursday' => 4, 'friday' => 5, 'saturday' => 6); + $start_day = isset($start_days[$this->start_day]) ? $start_days[$this->start_day] : 0; + + // Set the starting day number + $local_date = mktime(12, 0, 0, $month, 1, $year); + $date = getdate($local_date); + $day = $start_day + 1 - $date['wday']; + + while ($day > 1) + { + $day -= 7; + } + + // Set the current month/year/day + // We use this to determine the "today" date + $cur_year = date('Y', $local_time); + $cur_month = date('m', $local_time); + $cur_day = date('j', $local_time); + + $is_current_month = ($cur_year == $year && $cur_month == $month); + + // Generate the template data array + $this->parse_template(); + + // Begin building the calendar output + $out = $this->replacements['table_open']."\n\n".$this->replacements['heading_row_start']."\n"; + + // "previous" month link + if ($this->show_next_prev === TRUE) + { + // Add a trailing slash to the URL if needed + $this->next_prev_url = preg_replace('/(.+?)\/*$/', '\\1/', $this->next_prev_url); + + $adjusted_date = $this->adjust_date($month - 1, $year); + $out .= str_replace('{previous_url}', $this->next_prev_url.$adjusted_date['year'].'/'.$adjusted_date['month'], $this->replacements['heading_previous_cell'])."\n"; + } + + // Heading containing the month/year + $colspan = ($this->show_next_prev === TRUE) ? 5 : 7; + + $this->replacements['heading_title_cell'] = str_replace('{colspan}', $colspan, + str_replace('{heading}', $this->get_month_name($month).' '.$year, $this->replacements['heading_title_cell'])); + + $out .= $this->replacements['heading_title_cell']."\n"; + + // "next" month link + if ($this->show_next_prev === TRUE) + { + $adjusted_date = $this->adjust_date($month + 1, $year); + $out .= str_replace('{next_url}', $this->next_prev_url.$adjusted_date['year'].'/'.$adjusted_date['month'], $this->replacements['heading_next_cell']); + } + + $out .= "\n".$this->replacements['heading_row_end']."\n\n" + // Write the cells containing the days of the week + .$this->replacements['week_row_start']."\n"; + + $day_names = $this->get_day_names(); + + for ($i = 0; $i < 7; $i ++) + { + $out .= str_replace('{week_day}', $day_names[($start_day + $i) %7], $this->replacements['week_day_cell']); + } + + $out .= "\n".$this->replacements['week_row_end']."\n"; + + // Build the main body of the calendar + while ($day <= $total_days) + { + $out .= "\n".$this->replacements['cal_row_start']."\n"; + + for ($i = 0; $i < 7; $i++) + { + if ($day > 0 && $day <= $total_days) + { + $out .= ($is_current_month === TRUE && $day == $cur_day) ? $this->replacements['cal_cell_start_today'] : $this->replacements['cal_cell_start']; + + if (isset($data[$day])) + { + // Cells with content + $temp = ($is_current_month === TRUE && $day == $cur_day) ? + $this->replacements['cal_cell_content_today'] : $this->replacements['cal_cell_content']; + $out .= str_replace(array('{content}', '{day}'), array($data[$day], $day), $temp); + } + else + { + // Cells with no content + $temp = ($is_current_month === TRUE && $day == $cur_day) ? + $this->replacements['cal_cell_no_content_today'] : $this->replacements['cal_cell_no_content']; + $out .= str_replace('{day}', $day, $temp); + } + + $out .= ($is_current_month === TRUE && $day == $cur_day) ? $this->replacements['cal_cell_end_today'] : $this->replacements['cal_cell_end']; + } + elseif ($this->show_other_days === TRUE) + { + $out .= $this->replacements['cal_cell_start_other']; + + if ($day <= 0) + { + // Day of previous month + $prev_month = $this->adjust_date($month - 1, $year); + $prev_month_days = $this->get_total_days($prev_month['month'], $prev_month['year']); + $out .= str_replace('{day}', $prev_month_days + $day, $this->replacements['cal_cell_other']); + } + else + { + // Day of next month + $out .= str_replace('{day}', $day - $total_days, $this->replacements['cal_cell_other']); + } + + $out .= $this->replacements['cal_cell_end_other']; + } + else + { + // Blank cells + $out .= $this->replacements['cal_cell_start'].$this->replacements['cal_cell_blank'].$this->replacements['cal_cell_end']; + } + + $day++; + } + + $out .= "\n".$this->replacements['cal_row_end']."\n"; + } + + return $out .= "\n".$this->replacements['table_close']; + } + + // -------------------------------------------------------------------- + + /** + * Get Month Name + * + * Generates a textual month name based on the numeric + * month provided. + * + * @param int the month + * @return string + */ + public function get_month_name($month) + { + if ($this->month_type === 'short') + { + $month_names = array('01' => 'cal_jan', '02' => 'cal_feb', '03' => 'cal_mar', '04' => 'cal_apr', '05' => 'cal_may', '06' => 'cal_jun', '07' => 'cal_jul', '08' => 'cal_aug', '09' => 'cal_sep', '10' => 'cal_oct', '11' => 'cal_nov', '12' => 'cal_dec'); + } + else + { + $month_names = array('01' => 'cal_january', '02' => 'cal_february', '03' => 'cal_march', '04' => 'cal_april', '05' => 'cal_mayl', '06' => 'cal_june', '07' => 'cal_july', '08' => 'cal_august', '09' => 'cal_september', '10' => 'cal_october', '11' => 'cal_november', '12' => 'cal_december'); + } + + return ($this->CI->lang->line($month_names[$month]) === FALSE) + ? ucfirst(substr($month_names[$month], 4)) + : $this->CI->lang->line($month_names[$month]); + } + + // -------------------------------------------------------------------- + + /** + * Get Day Names + * + * Returns an array of day names (Sunday, Monday, etc.) based + * on the type. Options: long, short, abr + * + * @param string + * @return array + */ + public function get_day_names($day_type = '') + { + if ($day_type !== '') + { + $this->day_type = $day_type; + } + + if ($this->day_type === 'long') + { + $day_names = array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'); + } + elseif ($this->day_type === 'short') + { + $day_names = array('sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'); + } + else + { + $day_names = array('su', 'mo', 'tu', 'we', 'th', 'fr', 'sa'); + } + + $days = array(); + for ($i = 0, $c = count($day_names); $i < $c; $i++) + { + $days[] = ($this->CI->lang->line('cal_'.$day_names[$i]) === FALSE) ? ucfirst($day_names[$i]) : $this->CI->lang->line('cal_'.$day_names[$i]); + } + + return $days; + } + + // -------------------------------------------------------------------- + + /** + * Adjust Date + * + * This function makes sure that we have a valid month/year. + * For example, if you submit 13 as the month, the year will + * increment and the month will become January. + * + * @param int the month + * @param int the year + * @return array + */ + public function adjust_date($month, $year) + { + $date = array(); + + $date['month'] = $month; + $date['year'] = $year; + + while ($date['month'] > 12) + { + $date['month'] -= 12; + $date['year']++; + } + + while ($date['month'] <= 0) + { + $date['month'] += 12; + $date['year']--; + } + + if (strlen($date['month']) === 1) + { + $date['month'] = '0'.$date['month']; + } + + return $date; + } + + // -------------------------------------------------------------------- + + /** + * Total days in a given month + * + * @param int the month + * @param int the year + * @return int + */ + public function get_total_days($month, $year) + { + $this->CI->load->helper('date'); + return days_in_month($month, $year); + } + + // -------------------------------------------------------------------- + + /** + * Set Default Template Data + * + * This is used in the event that the user has not created their own template + * + * @return array + */ + public function default_template() + { + return array( + 'table_open' => '', + 'heading_row_start' => '', + 'heading_previous_cell' => '', + 'heading_title_cell' => '', + 'heading_next_cell' => '', + 'heading_row_end' => '', + 'week_row_start' => '', + 'week_day_cell' => '', + 'week_row_end' => '', + 'cal_row_start' => '', + 'cal_cell_start' => '', + 'cal_cell_end_today' => '', + 'cal_cell_end_other' => '', + 'cal_row_end' => '', + 'table_close' => '
<<{heading}>>
{week_day}
', + 'cal_cell_start_today' => '', + 'cal_cell_start_other' => '', + 'cal_cell_content' => '{day}', + 'cal_cell_content_today' => '{day}', + 'cal_cell_no_content' => '{day}', + 'cal_cell_no_content_today' => '{day}', + 'cal_cell_blank' => ' ', + 'cal_cell_other' => '{day}', + 'cal_cell_end' => '
' + ); + } + + // -------------------------------------------------------------------- + + /** + * Parse Template + * + * Harvests the data within the template {pseudo-variables} + * used to display the calendar + * + * @return CI_Calendar + */ + public function parse_template() + { + $this->replacements = $this->default_template(); + + if (empty($this->template)) + { + return $this; + } + + if (is_string($this->template)) + { + $today = array('cal_cell_start_today', 'cal_cell_content_today', 'cal_cell_no_content_today', 'cal_cell_end_today'); + + foreach (array('table_open', 'table_close', 'heading_row_start', 'heading_previous_cell', 'heading_title_cell', 'heading_next_cell', 'heading_row_end', 'week_row_start', 'week_day_cell', 'week_row_end', 'cal_row_start', 'cal_cell_start', 'cal_cell_content', 'cal_cell_no_content', 'cal_cell_blank', 'cal_cell_end', 'cal_row_end', 'cal_cell_start_today', 'cal_cell_content_today', 'cal_cell_no_content_today', 'cal_cell_end_today', 'cal_cell_start_other', 'cal_cell_other', 'cal_cell_end_other') as $val) + { + if (preg_match('/\{'.$val.'\}(.*?)\{\/'.$val.'\}/si', $this->template, $match)) + { + $this->replacements[$val] = $match[1]; + } + elseif (in_array($val, $today, TRUE)) + { + $this->replacements[$val] = $this->replacements[substr($val, 0, -6)]; + } + } + } + elseif (is_array($this->template)) + { + $this->replacements = array_merge($this->replacements, $this->template); + } + + return $this; + } + +} diff --git a/system/libraries/Cart.php b/system/libraries/Cart.php new file mode 100644 index 0000000..4c51e7a --- /dev/null +++ b/system/libraries/Cart.php @@ -0,0 +1,567 @@ +CI =& get_instance(); + + // Are any config settings being passed manually? If so, set them + $config = is_array($params) ? $params : array(); + + // Load the Sessions class + $this->CI->load->driver('session', $config); + + // Grab the shopping cart array from the session table + $this->_cart_contents = $this->CI->session->userdata('cart_contents'); + if ($this->_cart_contents === NULL) + { + // No cart exists so we'll set some base values + $this->_cart_contents = array('cart_total' => 0, 'total_items' => 0); + } + + log_message('info', 'Cart Class Initialized'); + } + + // -------------------------------------------------------------------- + + /** + * Insert items into the cart and save it to the session table + * + * @param array + * @return bool + */ + public function insert($items = array()) + { + // Was any cart data passed? No? Bah... + if ( ! is_array($items) OR count($items) === 0) + { + log_message('error', 'The insert method must be passed an array containing data.'); + return FALSE; + } + + // You can either insert a single product using a one-dimensional array, + // or multiple products using a multi-dimensional one. The way we + // determine the array type is by looking for a required array key named "id" + // at the top level. If it's not found, we will assume it's a multi-dimensional array. + + $save_cart = FALSE; + if (isset($items['id'])) + { + if (($rowid = $this->_insert($items))) + { + $save_cart = TRUE; + } + } + else + { + foreach ($items as $val) + { + if (is_array($val) && isset($val['id'])) + { + if ($this->_insert($val)) + { + $save_cart = TRUE; + } + } + } + } + + // Save the cart data if the insert was successful + if ($save_cart === TRUE) + { + $this->_save_cart(); + return isset($rowid) ? $rowid : TRUE; + } + + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Insert + * + * @param array + * @return bool + */ + protected function _insert($items = array()) + { + // Was any cart data passed? No? Bah... + if ( ! is_array($items) OR count($items) === 0) + { + log_message('error', 'The insert method must be passed an array containing data.'); + return FALSE; + } + + // -------------------------------------------------------------------- + + // Does the $items array contain an id, quantity, price, and name? These are required + if ( ! isset($items['id'], $items['qty'], $items['price'], $items['name'])) + { + log_message('error', 'The cart array must contain a product ID, quantity, price, and name.'); + return FALSE; + } + + // -------------------------------------------------------------------- + + // Prep the quantity. It can only be a number. Duh... also trim any leading zeros + $items['qty'] = (float) $items['qty']; + + // If the quantity is zero or blank there's nothing for us to do + if ($items['qty'] == 0) + { + return FALSE; + } + + // -------------------------------------------------------------------- + + // Validate the product ID. It can only be alpha-numeric, dashes, underscores or periods + // Not totally sure we should impose this rule, but it seems prudent to standardize IDs. + // Note: These can be user-specified by setting the $this->product_id_rules variable. + if ( ! preg_match('/^['.$this->product_id_rules.']+$/i', $items['id'])) + { + log_message('error', 'Invalid product ID. The product ID can only contain alpha-numeric characters, dashes, and underscores'); + return FALSE; + } + + // -------------------------------------------------------------------- + + // Validate the product name. It can only be alpha-numeric, dashes, underscores, colons or periods. + // Note: These can be user-specified by setting the $this->product_name_rules variable. + if ($this->product_name_safe && ! preg_match('/^['.$this->product_name_rules.']+$/i'.(UTF8_ENABLED ? 'u' : ''), $items['name'])) + { + log_message('error', 'An invalid name was submitted as the product name: '.$items['name'].' The name can only contain alpha-numeric characters, dashes, underscores, colons, and spaces'); + return FALSE; + } + + // -------------------------------------------------------------------- + + // Prep the price. Remove leading zeros and anything that isn't a number or decimal point. + $items['price'] = (float) $items['price']; + + // We now need to create a unique identifier for the item being inserted into the cart. + // Every time something is added to the cart it is stored in the master cart array. + // Each row in the cart array, however, must have a unique index that identifies not only + // a particular product, but makes it possible to store identical products with different options. + // For example, what if someone buys two identical t-shirts (same product ID), but in + // different sizes? The product ID (and other attributes, like the name) will be identical for + // both sizes because it's the same shirt. The only difference will be the size. + // Internally, we need to treat identical submissions, but with different options, as a unique product. + // Our solution is to convert the options array to a string and MD5 it along with the product ID. + // This becomes the unique "row ID" + if (isset($items['options']) && count($items['options']) > 0) + { + $rowid = md5($items['id'].serialize($items['options'])); + } + else + { + // No options were submitted so we simply MD5 the product ID. + // Technically, we don't need to MD5 the ID in this case, but it makes + // sense to standardize the format of array indexes for both conditions + $rowid = md5($items['id']); + } + + // -------------------------------------------------------------------- + + // Now that we have our unique "row ID", we'll add our cart items to the master array + // grab quantity if it's already there and add it on + $old_quantity = isset($this->_cart_contents[$rowid]['qty']) ? (int) $this->_cart_contents[$rowid]['qty'] : 0; + + // Re-create the entry, just to make sure our index contains only the data from this submission + $items['rowid'] = $rowid; + $items['qty'] += $old_quantity; + $this->_cart_contents[$rowid] = $items; + + return $rowid; + } + + // -------------------------------------------------------------------- + + /** + * Update the cart + * + * This function permits the quantity of a given item to be changed. + * Typically it is called from the "view cart" page if a user makes + * changes to the quantity before checkout. That array must contain the + * product ID and quantity for each item. + * + * @param array + * @return bool + */ + public function update($items = array()) + { + // Was any cart data passed? + if ( ! is_array($items) OR count($items) === 0) + { + return FALSE; + } + + // You can either update a single product using a one-dimensional array, + // or multiple products using a multi-dimensional one. The way we + // determine the array type is by looking for a required array key named "rowid". + // If it's not found we assume it's a multi-dimensional array + $save_cart = FALSE; + if (isset($items['rowid'])) + { + if ($this->_update($items) === TRUE) + { + $save_cart = TRUE; + } + } + else + { + foreach ($items as $val) + { + if (is_array($val) && isset($val['rowid'])) + { + if ($this->_update($val) === TRUE) + { + $save_cart = TRUE; + } + } + } + } + + // Save the cart data if the insert was successful + if ($save_cart === TRUE) + { + $this->_save_cart(); + return TRUE; + } + + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Update the cart + * + * This function permits changing item properties. + * Typically it is called from the "view cart" page if a user makes + * changes to the quantity before checkout. That array must contain the + * rowid and quantity for each item. + * + * @param array + * @return bool + */ + protected function _update($items = array()) + { + // Without these array indexes there is nothing we can do + if ( ! isset($items['rowid'], $this->_cart_contents[$items['rowid']])) + { + return FALSE; + } + + // Prep the quantity + if (isset($items['qty'])) + { + $items['qty'] = (float) $items['qty']; + // Is the quantity zero? If so we will remove the item from the cart. + // If the quantity is greater than zero we are updating + if ($items['qty'] == 0) + { + unset($this->_cart_contents[$items['rowid']]); + return TRUE; + } + } + + // find updatable keys + $keys = array_intersect(array_keys($this->_cart_contents[$items['rowid']]), array_keys($items)); + // if a price was passed, make sure it contains valid data + if (isset($items['price'])) + { + $items['price'] = (float) $items['price']; + } + + // product id & name shouldn't be changed + foreach (array_diff($keys, array('id', 'name')) as $key) + { + $this->_cart_contents[$items['rowid']][$key] = $items[$key]; + } + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Save the cart array to the session DB + * + * @return bool + */ + protected function _save_cart() + { + // Let's add up the individual prices and set the cart sub-total + $this->_cart_contents['total_items'] = $this->_cart_contents['cart_total'] = 0; + foreach ($this->_cart_contents as $key => $val) + { + // We make sure the array contains the proper indexes + if ( ! is_array($val) OR ! isset($val['price'], $val['qty'])) + { + continue; + } + + $this->_cart_contents['cart_total'] += ($val['price'] * $val['qty']); + $this->_cart_contents['total_items'] += $val['qty']; + $this->_cart_contents[$key]['subtotal'] = ($this->_cart_contents[$key]['price'] * $this->_cart_contents[$key]['qty']); + } + + // Is our cart empty? If so we delete it from the session + if (count($this->_cart_contents) <= 2) + { + $this->CI->session->unset_userdata('cart_contents'); + + // Nothing more to do... coffee time! + return FALSE; + } + + // If we made it this far it means that our cart has data. + // Let's pass it to the Session class so it can be stored + $this->CI->session->set_userdata(array('cart_contents' => $this->_cart_contents)); + + // Woot! + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Cart Total + * + * @return int + */ + public function total() + { + return $this->_cart_contents['cart_total']; + } + + // -------------------------------------------------------------------- + + /** + * Remove Item + * + * Removes an item from the cart + * + * @param int + * @return bool + */ + public function remove($rowid) + { + // unset & save + unset($this->_cart_contents[$rowid]); + $this->_save_cart(); + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Total Items + * + * Returns the total item count + * + * @return int + */ + public function total_items() + { + return $this->_cart_contents['total_items']; + } + + // -------------------------------------------------------------------- + + /** + * Cart Contents + * + * Returns the entire cart array + * + * @param bool + * @return array + */ + public function contents($newest_first = FALSE) + { + // do we want the newest first? + $cart = ($newest_first) ? array_reverse($this->_cart_contents) : $this->_cart_contents; + + // Remove these so they don't create a problem when showing the cart table + unset($cart['total_items']); + unset($cart['cart_total']); + + return $cart; + } + + // -------------------------------------------------------------------- + + /** + * Get cart item + * + * Returns the details of a specific item in the cart + * + * @param string $row_id + * @return array + */ + public function get_item($row_id) + { + return (in_array($row_id, array('total_items', 'cart_total'), TRUE) OR ! isset($this->_cart_contents[$row_id])) + ? FALSE + : $this->_cart_contents[$row_id]; + } + + // -------------------------------------------------------------------- + + /** + * Has options + * + * Returns TRUE if the rowid passed to this function correlates to an item + * that has options associated with it. + * + * @param string $row_id = '' + * @return bool + */ + public function has_options($row_id = '') + { + return (isset($this->_cart_contents[$row_id]['options']) && count($this->_cart_contents[$row_id]['options']) !== 0); + } + + // -------------------------------------------------------------------- + + /** + * Product options + * + * Returns the an array of options, for a particular product row ID + * + * @param string $row_id = '' + * @return array + */ + public function product_options($row_id = '') + { + return isset($this->_cart_contents[$row_id]['options']) ? $this->_cart_contents[$row_id]['options'] : array(); + } + + // -------------------------------------------------------------------- + + /** + * Format Number + * + * Returns the supplied number with commas and a decimal point. + * + * @param float + * @return string + */ + public function format_number($n = '') + { + return ($n === '') ? '' : number_format( (float) $n, 2, '.', ','); + } + + // -------------------------------------------------------------------- + + /** + * Destroy the cart + * + * Empties the cart and kills the session + * + * @return void + */ + public function destroy() + { + $this->_cart_contents = array('cart_total' => 0, 'total_items' => 0); + $this->CI->session->unset_userdata('cart_contents'); + } + +} diff --git a/system/libraries/Driver.php b/system/libraries/Driver.php new file mode 100644 index 0000000..7dd66ec --- /dev/null +++ b/system/libraries/Driver.php @@ -0,0 +1,342 @@ +load_driver($child); + } + + /** + * Load driver + * + * Separate load_driver call to support explicit driver load by library or user + * + * @param string Driver name (w/o parent prefix) + * @return object Child class + */ + public function load_driver($child) + { + // Get CodeIgniter instance and subclass prefix + $prefix = config_item('subclass_prefix'); + + if ( ! isset($this->lib_name)) + { + // Get library name without any prefix + $this->lib_name = str_replace(array('CI_', $prefix), '', get_class($this)); + } + + // The child will be prefixed with the parent lib + $child_name = $this->lib_name.'_'.$child; + + // See if requested child is a valid driver + if ( ! in_array($child, $this->valid_drivers)) + { + // The requested driver isn't valid! + $msg = 'Invalid driver requested: '.$child_name; + log_message('error', $msg); + show_error($msg); + } + + // Get package paths and filename case variations to search + $CI = get_instance(); + $paths = $CI->load->get_package_paths(TRUE); + + // Is there an extension? + $class_name = $prefix.$child_name; + $found = class_exists($class_name, FALSE); + if ( ! $found) + { + // Check for subclass file + foreach ($paths as $path) + { + // Does the file exist? + $file = $path.'libraries/'.$this->lib_name.'/drivers/'.$prefix.$child_name.'.php'; + if (file_exists($file)) + { + // Yes - require base class from BASEPATH + $basepath = BASEPATH.'libraries/'.$this->lib_name.'/drivers/'.$child_name.'.php'; + if ( ! file_exists($basepath)) + { + $msg = 'Unable to load the requested class: CI_'.$child_name; + log_message('error', $msg); + show_error($msg); + } + + // Include both sources and mark found + include_once($basepath); + include_once($file); + $found = TRUE; + break; + } + } + } + + // Do we need to search for the class? + if ( ! $found) + { + // Use standard class name + $class_name = 'CI_'.$child_name; + if ( ! class_exists($class_name, FALSE)) + { + // Check package paths + foreach ($paths as $path) + { + // Does the file exist? + $file = $path.'libraries/'.$this->lib_name.'/drivers/'.$child_name.'.php'; + if (file_exists($file)) + { + // Include source + include_once($file); + break; + } + } + } + } + + // Did we finally find the class? + if ( ! class_exists($class_name, FALSE)) + { + if (class_exists($child_name, FALSE)) + { + $class_name = $child_name; + } + else + { + $msg = 'Unable to load the requested driver: '.$class_name; + log_message('error', $msg); + show_error($msg); + } + } + + // Instantiate, decorate and add child + $obj = new $class_name(); + $obj->decorate($this); + $this->$child = $obj; + return $this->$child; + } + +} + +// -------------------------------------------------------------------------- + +/** + * CodeIgniter Driver Class + * + * This class enables you to create drivers for a Library based on the Driver Library. + * It handles the drivers' access to the parent library + * + * @package CodeIgniter + * @subpackage Libraries + * @category Libraries + * @author EllisLab Dev Team + * @link + */ +class CI_Driver { + + /** + * Instance of the parent class + * + * @var object + */ + protected $_parent; + + /** + * List of methods in the parent class + * + * @var array + */ + protected $_methods = array(); + + /** + * List of properties in the parent class + * + * @var array + */ + protected $_properties = array(); + + /** + * Array of methods and properties for the parent class(es) + * + * @static + * @var array + */ + protected static $_reflections = array(); + + /** + * Decorate + * + * Decorates the child with the parent driver lib's methods and properties + * + * @param object + * @return void + */ + public function decorate($parent) + { + $this->_parent = $parent; + + // Lock down attributes to what is defined in the class + // and speed up references in magic methods + + $class_name = get_class($parent); + + if ( ! isset(self::$_reflections[$class_name])) + { + $r = new ReflectionObject($parent); + + foreach ($r->getMethods() as $method) + { + if ($method->isPublic()) + { + $this->_methods[] = $method->getName(); + } + } + + foreach ($r->getProperties() as $prop) + { + if ($prop->isPublic()) + { + $this->_properties[] = $prop->getName(); + } + } + + self::$_reflections[$class_name] = array($this->_methods, $this->_properties); + } + else + { + list($this->_methods, $this->_properties) = self::$_reflections[$class_name]; + } + } + + // -------------------------------------------------------------------- + + /** + * __call magic method + * + * Handles access to the parent driver library's methods + * + * @param string + * @param array + * @return mixed + */ + public function __call($method, $args = array()) + { + if (in_array($method, $this->_methods)) + { + return call_user_func_array(array($this->_parent, $method), $args); + } + + throw new BadMethodCallException('No such method: '.$method.'()'); + } + + // -------------------------------------------------------------------- + + /** + * __get magic method + * + * Handles reading of the parent driver library's properties + * + * @param string + * @return mixed + */ + public function __get($var) + { + if (in_array($var, $this->_properties)) + { + return $this->_parent->$var; + } + } + + // -------------------------------------------------------------------- + + /** + * __set magic method + * + * Handles writing to the parent driver library's properties + * + * @param string + * @param array + * @return mixed + */ + public function __set($var, $val) + { + if (in_array($var, $this->_properties)) + { + $this->_parent->$var = $val; + } + } + +} diff --git a/system/libraries/Email.php b/system/libraries/Email.php new file mode 100644 index 0000000..cd74d6d --- /dev/null +++ b/system/libraries/Email.php @@ -0,0 +1,2490 @@ + '1 (Highest)', + 2 => '2 (High)', + 3 => '3 (Normal)', + 4 => '4 (Low)', + 5 => '5 (Lowest)' + ); + + /** + * mbstring.func_overload flag + * + * @var bool + */ + protected static $func_overload; + + // -------------------------------------------------------------------- + + /** + * Constructor - Sets Email Preferences + * + * The constructor can be passed an array of config values + * + * @param array $config = array() + * @return void + */ + public function __construct(array $config = array()) + { + $this->charset = config_item('charset'); + $this->initialize($config); + $this->_safe_mode = ( ! is_php('5.4') && ini_get('safe_mode')); + + isset(self::$func_overload) OR self::$func_overload = (extension_loaded('mbstring') && ini_get('mbstring.func_overload')); + + log_message('info', 'Email Class Initialized'); + } + + // -------------------------------------------------------------------- + + /** + * Initialize preferences + * + * @param array $config + * @return CI_Email + */ + public function initialize(array $config = array()) + { + $this->clear(); + + foreach ($config as $key => $val) + { + if (isset($this->$key)) + { + $method = 'set_'.$key; + + if (method_exists($this, $method)) + { + $this->$method($val); + } + else + { + $this->$key = $val; + } + } + } + + $this->charset = strtoupper($this->charset); + $this->_smtp_auth = isset($this->smtp_user[0], $this->smtp_pass[0]); + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Initialize the Email Data + * + * @param bool + * @return CI_Email + */ + public function clear($clear_attachments = FALSE) + { + $this->_subject = ''; + $this->_body = ''; + $this->_finalbody = ''; + $this->_header_str = ''; + $this->_replyto_flag = FALSE; + $this->_recipients = array(); + $this->_cc_array = array(); + $this->_bcc_array = array(); + $this->_headers = array(); + $this->_debug_msg = array(); + + $this->set_header('Date', $this->_set_date()); + + if ($clear_attachments !== FALSE) + { + $this->_attachments = array(); + } + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Set FROM + * + * @param string $from + * @param string $name + * @param string $return_path = NULL Return-Path + * @return CI_Email + */ + public function from($from, $name = '', $return_path = NULL) + { + if (preg_match('/\<(.*)\>/', $from, $match)) + { + $from = $match[1]; + } + + if ($this->validate) + { + $this->validate_email($this->_str_to_array($from)); + if ($return_path) + { + $this->validate_email($this->_str_to_array($return_path)); + } + } + + // prepare the display name + if ($name !== '') + { + // only use Q encoding if there are characters that would require it + if ( ! preg_match('/[\200-\377]/', $name)) + { + // add slashes for non-printing characters, slashes, and double quotes, and surround it in double quotes + $name = '"'.addcslashes($name, "\0..\37\177'\"\\").'"'; + } + else + { + $name = $this->_prep_q_encoding($name); + } + } + + $this->set_header('From', $name.' <'.$from.'>'); + + isset($return_path) OR $return_path = $from; + $this->set_header('Return-Path', '<'.$return_path.'>'); + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Set Reply-to + * + * @param string + * @param string + * @return CI_Email + */ + public function reply_to($replyto, $name = '') + { + if (preg_match('/\<(.*)\>/', $replyto, $match)) + { + $replyto = $match[1]; + } + + if ($this->validate) + { + $this->validate_email($this->_str_to_array($replyto)); + } + + if ($name !== '') + { + // only use Q encoding if there are characters that would require it + if ( ! preg_match('/[\200-\377]/', $name)) + { + // add slashes for non-printing characters, slashes, and double quotes, and surround it in double quotes + $name = '"'.addcslashes($name, "\0..\37\177'\"\\").'"'; + } + else + { + $name = $this->_prep_q_encoding($name); + } + } + + $this->set_header('Reply-To', $name.' <'.$replyto.'>'); + $this->_replyto_flag = TRUE; + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Set Recipients + * + * @param string + * @return CI_Email + */ + public function to($to) + { + $to = $this->_str_to_array($to); + $to = $this->clean_email($to); + + if ($this->validate) + { + $this->validate_email($to); + } + + if ($this->_get_protocol() !== 'mail') + { + $this->set_header('To', implode(', ', $to)); + } + + $this->_recipients = $to; + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Set CC + * + * @param string + * @return CI_Email + */ + public function cc($cc) + { + $cc = $this->clean_email($this->_str_to_array($cc)); + + if ($this->validate) + { + $this->validate_email($cc); + } + + $this->set_header('Cc', implode(', ', $cc)); + + if ($this->_get_protocol() === 'smtp') + { + $this->_cc_array = $cc; + } + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Set BCC + * + * @param string + * @param string + * @return CI_Email + */ + public function bcc($bcc, $limit = '') + { + if ($limit !== '' && is_numeric($limit)) + { + $this->bcc_batch_mode = TRUE; + $this->bcc_batch_size = $limit; + } + + $bcc = $this->clean_email($this->_str_to_array($bcc)); + + if ($this->validate) + { + $this->validate_email($bcc); + } + + if ($this->_get_protocol() === 'smtp' OR ($this->bcc_batch_mode && count($bcc) > $this->bcc_batch_size)) + { + $this->_bcc_array = $bcc; + } + else + { + $this->set_header('Bcc', implode(', ', $bcc)); + } + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Set Email Subject + * + * @param string + * @return CI_Email + */ + public function subject($subject) + { + $subject = $this->_prep_q_encoding($subject); + $this->set_header('Subject', $subject); + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Set Body + * + * @param string + * @return CI_Email + */ + public function message($body) + { + $this->_body = rtrim(str_replace("\r", '', $body)); + + /* strip slashes only if magic quotes is ON + if we do it with magic quotes OFF, it strips real, user-inputted chars. + + NOTE: In PHP 5.4 get_magic_quotes_gpc() will always return 0 and + it will probably not exist in future versions at all. + */ + if ( ! is_php('5.4') && get_magic_quotes_gpc()) + { + $this->_body = stripslashes($this->_body); + } + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Assign file attachments + * + * @param string $file Can be local path, URL or buffered content + * @param string $disposition = 'attachment' + * @param string $newname = NULL + * @param string $mime = '' + * @return CI_Email + */ + public function attach($file, $disposition = '', $newname = NULL, $mime = '') + { + if ($mime === '') + { + if (strpos($file, '://') === FALSE && ! file_exists($file)) + { + $this->_set_error_message('lang:email_attachment_missing', $file); + return FALSE; + } + + if ( ! $fp = @fopen($file, 'rb')) + { + $this->_set_error_message('lang:email_attachment_unreadable', $file); + return FALSE; + } + + $file_content = stream_get_contents($fp); + $mime = $this->_mime_types(pathinfo($file, PATHINFO_EXTENSION)); + fclose($fp); + } + else + { + $file_content =& $file; // buffered file + } + + $this->_attachments[] = array( + 'name' => array($file, $newname), + 'disposition' => empty($disposition) ? 'attachment' : $disposition, // Can also be 'inline' Not sure if it matters + 'type' => $mime, + 'content' => chunk_split(base64_encode($file_content)), + 'multipart' => 'mixed' + ); + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Set and return attachment Content-ID + * + * Useful for attached inline pictures + * + * @param string $filename + * @return string + */ + public function attachment_cid($filename) + { + for ($i = 0, $c = count($this->_attachments); $i < $c; $i++) + { + if ($this->_attachments[$i]['name'][0] === $filename) + { + $this->_attachments[$i]['multipart'] = 'related'; + $this->_attachments[$i]['cid'] = uniqid(basename($this->_attachments[$i]['name'][0]).'@'); + return $this->_attachments[$i]['cid']; + } + } + + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Add a Header Item + * + * @param string + * @param string + * @return CI_Email + */ + public function set_header($header, $value) + { + $this->_headers[$header] = str_replace(array("\n", "\r"), '', $value); + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Convert a String to an Array + * + * @param string + * @return array + */ + protected function _str_to_array($email) + { + if ( ! is_array($email)) + { + return (strpos($email, ',') !== FALSE) + ? preg_split('/[\s,]/', $email, -1, PREG_SPLIT_NO_EMPTY) + : (array) trim($email); + } + + return $email; + } + + // -------------------------------------------------------------------- + + /** + * Set Multipart Value + * + * @param string + * @return CI_Email + */ + public function set_alt_message($str) + { + $this->alt_message = (string) $str; + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Set Mailtype + * + * @param string + * @return CI_Email + */ + public function set_mailtype($type = 'text') + { + $this->mailtype = ($type === 'html') ? 'html' : 'text'; + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Set Wordwrap + * + * @param bool + * @return CI_Email + */ + public function set_wordwrap($wordwrap = TRUE) + { + $this->wordwrap = (bool) $wordwrap; + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Set Protocol + * + * @param string + * @return CI_Email + */ + public function set_protocol($protocol = 'mail') + { + $this->protocol = in_array($protocol, $this->_protocols, TRUE) ? strtolower($protocol) : 'mail'; + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Set Priority + * + * @param int + * @return CI_Email + */ + public function set_priority($n = 3) + { + $this->priority = preg_match('/^[1-5]$/', $n) ? (int) $n : 3; + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Set Newline Character + * + * @param string + * @return CI_Email + */ + public function set_newline($newline = "\n") + { + $this->newline = in_array($newline, array("\n", "\r\n", "\r")) ? $newline : "\n"; + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Set CRLF + * + * @param string + * @return CI_Email + */ + public function set_crlf($crlf = "\n") + { + $this->crlf = ($crlf !== "\n" && $crlf !== "\r\n" && $crlf !== "\r") ? "\n" : $crlf; + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Get the Message ID + * + * @return string + */ + protected function _get_message_id() + { + $from = str_replace(array('>', '<'), '', $this->_headers['Return-Path']); + return '<'.uniqid('').strstr($from, '@').'>'; + } + + // -------------------------------------------------------------------- + + /** + * Get Mail Protocol + * + * @return mixed + */ + protected function _get_protocol() + { + $this->protocol = strtolower($this->protocol); + in_array($this->protocol, $this->_protocols, TRUE) OR $this->protocol = 'mail'; + return $this->protocol; + } + + // -------------------------------------------------------------------- + + /** + * Get Mail Encoding + * + * @return string + */ + protected function _get_encoding() + { + in_array($this->_encoding, $this->_bit_depths) OR $this->_encoding = '8bit'; + + foreach ($this->_base_charsets as $charset) + { + if (strpos($this->charset, $charset) === 0) + { + $this->_encoding = '7bit'; + } + } + + return $this->_encoding; + } + + // -------------------------------------------------------------------- + + /** + * Get content type (text/html/attachment) + * + * @return string + */ + protected function _get_content_type() + { + if ($this->mailtype === 'html') + { + return empty($this->_attachments) ? 'html' : 'html-attach'; + } + elseif ($this->mailtype === 'text' && ! empty($this->_attachments)) + { + return 'plain-attach'; + } + + return 'plain'; + } + + // -------------------------------------------------------------------- + + /** + * Set RFC 822 Date + * + * @return string + */ + protected function _set_date() + { + $timezone = date('Z'); + $operator = ($timezone[0] === '-') ? '-' : '+'; + $timezone = abs($timezone); + $timezone = floor($timezone/3600) * 100 + ($timezone % 3600) / 60; + + return sprintf('%s %s%04d', date('D, j M Y H:i:s'), $operator, $timezone); + } + + // -------------------------------------------------------------------- + + /** + * Mime message + * + * @return string + */ + protected function _get_mime_message() + { + return 'This is a multi-part message in MIME format.'.$this->newline.'Your email application may not support this format.'; + } + + // -------------------------------------------------------------------- + + /** + * Validate Email Address + * + * @param string + * @return bool + */ + public function validate_email($email) + { + if ( ! is_array($email)) + { + $this->_set_error_message('lang:email_must_be_array'); + return FALSE; + } + + foreach ($email as $val) + { + if ( ! $this->valid_email($val)) + { + $this->_set_error_message('lang:email_invalid_address', $val); + return FALSE; + } + } + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Email Validation + * + * @param string + * @return bool + */ + public function valid_email($email) + { + if (function_exists('idn_to_ascii') && strpos($email, '@')) + { + list($account, $domain) = explode('@', $email, 2); + $domain = defined('INTL_IDNA_VARIANT_UTS46') + ? idn_to_ascii($domain, 0, INTL_IDNA_VARIANT_UTS46) + : idn_to_ascii($domain); + + if ($domain !== FALSE) + { + $email = $account.'@'.$domain; + } + } + + return (bool) filter_var($email, FILTER_VALIDATE_EMAIL); + } + + // -------------------------------------------------------------------- + + /** + * Clean Extended Email Address: Joe Smith + * + * @param string + * @return string + */ + public function clean_email($email) + { + if ( ! is_array($email)) + { + return preg_match('/\<(.*)\>/', $email, $match) ? $match[1] : $email; + } + + $clean_email = array(); + + foreach ($email as $addy) + { + $clean_email[] = preg_match('/\<(.*)\>/', $addy, $match) ? $match[1] : $addy; + } + + return $clean_email; + } + + // -------------------------------------------------------------------- + + /** + * Build alternative plain text message + * + * Provides the raw message for use in plain-text headers of + * HTML-formatted emails. + * If the user hasn't specified his own alternative message + * it creates one by stripping the HTML + * + * @return string + */ + protected function _get_alt_message() + { + if ( ! empty($this->alt_message)) + { + return ($this->wordwrap) + ? $this->word_wrap($this->alt_message, 76) + : $this->alt_message; + } + + $body = preg_match('/\(.*)\<\/body\>/si', $this->_body, $match) ? $match[1] : $this->_body; + $body = str_replace("\t", '', preg_replace('#\n"; + } + + return $r; + } + + // -------------------------------------------------------------------- + + /** + * Executes the Method + * + * @param object + * @return mixed + */ + protected function _execute($m) + { + $methName = $m->method_name; + + // Check to see if it is a system call + $system_call = (strpos($methName, 'system') === 0); + + if ($this->xss_clean === FALSE) + { + $m->xss_clean = FALSE; + } + + //------------------------------------- + // Valid Method + //------------------------------------- + + if ( ! isset($this->methods[$methName]['function'])) + { + return new XML_RPC_Response(0, $this->xmlrpcerr['unknown_method'], $this->xmlrpcstr['unknown_method']); + } + + //------------------------------------- + // Check for Method (and Object) + //------------------------------------- + + $method_parts = explode('.', $this->methods[$methName]['function']); + $objectCall = ! empty($method_parts[1]); + + if ($system_call === TRUE) + { + if ( ! is_callable(array($this, $method_parts[1]))) + { + return new XML_RPC_Response(0, $this->xmlrpcerr['unknown_method'], $this->xmlrpcstr['unknown_method']); + } + } + elseif (($objectCall && ! is_callable(array($method_parts[0], $method_parts[1]))) + OR ( ! $objectCall && ! is_callable($this->methods[$methName]['function'])) + ) + { + return new XML_RPC_Response(0, $this->xmlrpcerr['unknown_method'], $this->xmlrpcstr['unknown_method']); + } + + //------------------------------------- + // Checking Methods Signature + //------------------------------------- + + if (isset($this->methods[$methName]['signature'])) + { + $sig = $this->methods[$methName]['signature']; + for ($i = 0, $c = count($sig); $i < $c; $i++) + { + $current_sig = $sig[$i]; + + if (count($current_sig) === count($m->params)+1) + { + for ($n = 0, $mc = count($m->params); $n < $mc; $n++) + { + $p = $m->params[$n]; + $pt = ($p->kindOf() === 'scalar') ? $p->scalarval() : $p->kindOf(); + + if ($pt !== $current_sig[$n+1]) + { + $pno = $n+1; + $wanted = $current_sig[$n+1]; + + return new XML_RPC_Response(0, + $this->xmlrpcerr['incorrect_params'], + $this->xmlrpcstr['incorrect_params'] . + ': Wanted '.$wanted.', got '.$pt.' at param '.$pno.')'); + } + } + } + } + } + + //------------------------------------- + // Calls the Function + //------------------------------------- + + if ($objectCall === TRUE) + { + if ($method_parts[0] === 'this' && $system_call === TRUE) + { + return call_user_func(array($this, $method_parts[1]), $m); + } + elseif ($this->object === FALSE) + { + return get_instance()->{$method_parts[1]}($m); + } + + return $this->object->{$method_parts[1]}($m); + } + + return call_user_func($this->methods[$methName]['function'], $m); + } + + // -------------------------------------------------------------------- + + /** + * Server Function: List Methods + * + * @param mixed + * @return object + */ + public function listMethods($m) + { + $v = new XML_RPC_Values(); + $output = array(); + + foreach ($this->methods as $key => $value) + { + $output[] = new XML_RPC_Values($key, 'string'); + } + + foreach ($this->system_methods as $key => $value) + { + $output[] = new XML_RPC_Values($key, 'string'); + } + + $v->addArray($output); + return new XML_RPC_Response($v); + } + + // -------------------------------------------------------------------- + + /** + * Server Function: Return Signature for Method + * + * @param mixed + * @return object + */ + public function methodSignature($m) + { + $parameters = $m->output_parameters(); + $method_name = $parameters[0]; + + if (isset($this->methods[$method_name])) + { + if ($this->methods[$method_name]['signature']) + { + $sigs = array(); + $signature = $this->methods[$method_name]['signature']; + + for ($i = 0, $c = count($signature); $i < $c; $i++) + { + $cursig = array(); + $inSig = $signature[$i]; + for ($j = 0, $jc = count($inSig); $j < $jc; $j++) + { + $cursig[]= new XML_RPC_Values($inSig[$j], 'string'); + } + $sigs[] = new XML_RPC_Values($cursig, 'array'); + } + + return new XML_RPC_Response(new XML_RPC_Values($sigs, 'array')); + } + + return new XML_RPC_Response(new XML_RPC_Values('undef', 'string')); + } + + return new XML_RPC_Response(0, $this->xmlrpcerr['introspect_unknown'], $this->xmlrpcstr['introspect_unknown']); + } + + // -------------------------------------------------------------------- + + /** + * Server Function: Doc String for Method + * + * @param mixed + * @return object + */ + public function methodHelp($m) + { + $parameters = $m->output_parameters(); + $method_name = $parameters[0]; + + if (isset($this->methods[$method_name])) + { + $docstring = isset($this->methods[$method_name]['docstring']) ? $this->methods[$method_name]['docstring'] : ''; + + return new XML_RPC_Response(new XML_RPC_Values($docstring, 'string')); + } + + return new XML_RPC_Response(0, $this->xmlrpcerr['introspect_unknown'], $this->xmlrpcstr['introspect_unknown']); + } + + // -------------------------------------------------------------------- + + /** + * Server Function: Multi-call + * + * @param mixed + * @return object + */ + public function multicall($m) + { + // Disabled + return new XML_RPC_Response(0, $this->xmlrpcerr['unknown_method'], $this->xmlrpcstr['unknown_method']); + + $parameters = $m->output_parameters(); + $calls = $parameters[0]; + + $result = array(); + + foreach ($calls as $value) + { + $m = new XML_RPC_Message($value[0]); + $plist = ''; + + for ($i = 0, $c = count($value[1]); $i < $c; $i++) + { + $m->addParam(new XML_RPC_Values($value[1][$i], 'string')); + } + + $attempt = $this->_execute($m); + + if ($attempt->faultCode() !== 0) + { + return $attempt; + } + + $result[] = new XML_RPC_Values(array($attempt->value()), 'array'); + } + + return new XML_RPC_Response(new XML_RPC_Values($result, 'array')); + } + + // -------------------------------------------------------------------- + + /** + * Multi-call Function: Error Handling + * + * @param mixed + * @return object + */ + public function multicall_error($err) + { + $str = is_string($err) ? $this->xmlrpcstr["multicall_${err}"] : $err->faultString(); + $code = is_string($err) ? $this->xmlrpcerr["multicall_${err}"] : $err->faultCode(); + + $struct['faultCode'] = new XML_RPC_Values($code, 'int'); + $struct['faultString'] = new XML_RPC_Values($str, 'string'); + + return new XML_RPC_Values($struct, 'struct'); + } + + // -------------------------------------------------------------------- + + /** + * Multi-call Function: Processes method + * + * @param mixed + * @return object + */ + public function do_multicall($call) + { + if ($call->kindOf() !== 'struct') + { + return $this->multicall_error('notstruct'); + } + elseif ( ! $methName = $call->me['struct']['methodName']) + { + return $this->multicall_error('nomethod'); + } + + list($scalar_value, $scalar_type) = array(reset($methName->me), key($methName->me)); + $scalar_type = $scalar_type === $this->xmlrpcI4 ? $this->xmlrpcInt : $scalar_type; + + if ($methName->kindOf() !== 'scalar' OR $scalar_type !== 'string') + { + return $this->multicall_error('notstring'); + } + elseif ($scalar_value === 'system.multicall') + { + return $this->multicall_error('recursion'); + } + elseif ( ! $params = $call->me['struct']['params']) + { + return $this->multicall_error('noparams'); + } + elseif ($params->kindOf() !== 'array') + { + return $this->multicall_error('notarray'); + } + + list($b, $a) = array(reset($params->me), key($params->me)); + + $msg = new XML_RPC_Message($scalar_value); + for ($i = 0, $numParams = count($b); $i < $numParams; $i++) + { + $msg->params[] = $params->me['array'][$i]; + } + + $result = $this->_execute($msg); + + if ($result->faultCode() !== 0) + { + return $this->multicall_error($result); + } + + return new XML_RPC_Values(array($result->value()), 'array'); + } + +} diff --git a/system/libraries/Zip.php b/system/libraries/Zip.php new file mode 100644 index 0000000..f8f95fe --- /dev/null +++ b/system/libraries/Zip.php @@ -0,0 +1,532 @@ +now = time(); + log_message('info', 'Zip Compression Class Initialized'); + } + + // -------------------------------------------------------------------- + + /** + * Add Directory + * + * Lets you add a virtual directory into which you can place files. + * + * @param mixed $directory the directory name. Can be string or array + * @return void + */ + public function add_dir($directory) + { + foreach ((array) $directory as $dir) + { + if ( ! preg_match('|.+/$|', $dir)) + { + $dir .= '/'; + } + + $dir_time = $this->_get_mod_time($dir); + $this->_add_dir($dir, $dir_time['file_mtime'], $dir_time['file_mdate']); + } + } + + // -------------------------------------------------------------------- + + /** + * Get file/directory modification time + * + * If this is a newly created file/dir, we will set the time to 'now' + * + * @param string $dir path to file + * @return array filemtime/filemdate + */ + protected function _get_mod_time($dir) + { + // filemtime() may return false, but raises an error for non-existing files + $date = file_exists($dir) ? getdate(filemtime($dir)) : getdate($this->now); + + return array( + 'file_mtime' => ($date['hours'] << 11) + ($date['minutes'] << 5) + $date['seconds'] / 2, + 'file_mdate' => (($date['year'] - 1980) << 9) + ($date['mon'] << 5) + $date['mday'] + ); + } + + // -------------------------------------------------------------------- + + /** + * Add Directory + * + * @param string $dir the directory name + * @param int $file_mtime + * @param int $file_mdate + * @return void + */ + protected function _add_dir($dir, $file_mtime, $file_mdate) + { + $dir = str_replace('\\', '/', $dir); + + $this->zipdata .= + "\x50\x4b\x03\x04\x0a\x00\x00\x00\x00\x00" + .pack('v', $file_mtime) + .pack('v', $file_mdate) + .pack('V', 0) // crc32 + .pack('V', 0) // compressed filesize + .pack('V', 0) // uncompressed filesize + .pack('v', self::strlen($dir)) // length of pathname + .pack('v', 0) // extra field length + .$dir + // below is "data descriptor" segment + .pack('V', 0) // crc32 + .pack('V', 0) // compressed filesize + .pack('V', 0); // uncompressed filesize + + $this->directory .= + "\x50\x4b\x01\x02\x00\x00\x0a\x00\x00\x00\x00\x00" + .pack('v', $file_mtime) + .pack('v', $file_mdate) + .pack('V',0) // crc32 + .pack('V',0) // compressed filesize + .pack('V',0) // uncompressed filesize + .pack('v', self::strlen($dir)) // length of pathname + .pack('v', 0) // extra field length + .pack('v', 0) // file comment length + .pack('v', 0) // disk number start + .pack('v', 0) // internal file attributes + .pack('V', 16) // external file attributes - 'directory' bit set + .pack('V', $this->offset) // relative offset of local header + .$dir; + + $this->offset = self::strlen($this->zipdata); + $this->entries++; + } + + // -------------------------------------------------------------------- + + /** + * Add Data to Zip + * + * Lets you add files to the archive. If the path is included + * in the filename it will be placed within a directory. Make + * sure you use add_dir() first to create the folder. + * + * @param mixed $filepath A single filepath or an array of file => data pairs + * @param string $data Single file contents + * @return void + */ + public function add_data($filepath, $data = NULL) + { + if (is_array($filepath)) + { + foreach ($filepath as $path => $data) + { + $file_data = $this->_get_mod_time($path); + $this->_add_data($path, $data, $file_data['file_mtime'], $file_data['file_mdate']); + } + } + else + { + $file_data = $this->_get_mod_time($filepath); + $this->_add_data($filepath, $data, $file_data['file_mtime'], $file_data['file_mdate']); + } + } + + // -------------------------------------------------------------------- + + /** + * Add Data to Zip + * + * @param string $filepath the file name/path + * @param string $data the data to be encoded + * @param int $file_mtime + * @param int $file_mdate + * @return void + */ + protected function _add_data($filepath, $data, $file_mtime, $file_mdate) + { + $filepath = str_replace('\\', '/', $filepath); + + $uncompressed_size = self::strlen($data); + $crc32 = crc32($data); + $gzdata = self::substr(gzcompress($data, $this->compression_level), 2, -4); + $compressed_size = self::strlen($gzdata); + + $this->zipdata .= + "\x50\x4b\x03\x04\x14\x00\x00\x00\x08\x00" + .pack('v', $file_mtime) + .pack('v', $file_mdate) + .pack('V', $crc32) + .pack('V', $compressed_size) + .pack('V', $uncompressed_size) + .pack('v', self::strlen($filepath)) // length of filename + .pack('v', 0) // extra field length + .$filepath + .$gzdata; // "file data" segment + + $this->directory .= + "\x50\x4b\x01\x02\x00\x00\x14\x00\x00\x00\x08\x00" + .pack('v', $file_mtime) + .pack('v', $file_mdate) + .pack('V', $crc32) + .pack('V', $compressed_size) + .pack('V', $uncompressed_size) + .pack('v', self::strlen($filepath)) // length of filename + .pack('v', 0) // extra field length + .pack('v', 0) // file comment length + .pack('v', 0) // disk number start + .pack('v', 0) // internal file attributes + .pack('V', 32) // external file attributes - 'archive' bit set + .pack('V', $this->offset) // relative offset of local header + .$filepath; + + $this->offset = self::strlen($this->zipdata); + $this->entries++; + $this->file_num++; + } + + // -------------------------------------------------------------------- + + /** + * Read the contents of a file and add it to the zip + * + * @param string $path + * @param bool $archive_filepath + * @return bool + */ + public function read_file($path, $archive_filepath = FALSE) + { + if (file_exists($path) && FALSE !== ($data = file_get_contents($path))) + { + if (is_string($archive_filepath)) + { + $name = str_replace('\\', '/', $archive_filepath); + } + else + { + $name = str_replace('\\', '/', $path); + + if ($archive_filepath === FALSE) + { + $name = preg_replace('|.*/(.+)|', '\\1', $name); + } + } + + $this->add_data($name, $data); + return TRUE; + } + + return FALSE; + } + + // ------------------------------------------------------------------------ + + /** + * Read a directory and add it to the zip. + * + * This function recursively reads a folder and everything it contains (including + * sub-folders) and creates a zip based on it. Whatever directory structure + * is in the original file path will be recreated in the zip file. + * + * @param string $path path to source directory + * @param bool $preserve_filepath + * @param string $root_path + * @return bool + */ + public function read_dir($path, $preserve_filepath = TRUE, $root_path = NULL) + { + $path = rtrim($path, '/\\').DIRECTORY_SEPARATOR; + if ( ! $fp = @opendir($path)) + { + return FALSE; + } + + // Set the original directory root for child dir's to use as relative + if ($root_path === NULL) + { + $root_path = str_replace(array('\\', '/'), DIRECTORY_SEPARATOR, dirname($path)).DIRECTORY_SEPARATOR; + } + + while (FALSE !== ($file = readdir($fp))) + { + if ($file[0] === '.') + { + continue; + } + + if (is_dir($path.$file)) + { + $this->read_dir($path.$file.DIRECTORY_SEPARATOR, $preserve_filepath, $root_path); + } + elseif (FALSE !== ($data = file_get_contents($path.$file))) + { + $name = str_replace(array('\\', '/'), DIRECTORY_SEPARATOR, $path); + if ($preserve_filepath === FALSE) + { + $name = str_replace($root_path, '', $name); + } + + $this->add_data($name.$file, $data); + } + } + + closedir($fp); + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Get the Zip file + * + * @return string (binary encoded) + */ + public function get_zip() + { + // Is there any data to return? + if ($this->entries === 0) + { + return FALSE; + } + + return $this->zipdata + .$this->directory."\x50\x4b\x05\x06\x00\x00\x00\x00" + .pack('v', $this->entries) // total # of entries "on this disk" + .pack('v', $this->entries) // total # of entries overall + .pack('V', self::strlen($this->directory)) // size of central dir + .pack('V', self::strlen($this->zipdata)) // offset to start of central dir + ."\x00\x00"; // .zip file comment length + } + + // -------------------------------------------------------------------- + + /** + * Write File to the specified directory + * + * Lets you write a file + * + * @param string $filepath the file name + * @return bool + */ + public function archive($filepath) + { + if ( ! ($fp = @fopen($filepath, 'w+b'))) + { + return FALSE; + } + + flock($fp, LOCK_EX); + + for ($result = $written = 0, $data = $this->get_zip(), $length = self::strlen($data); $written < $length; $written += $result) + { + if (($result = fwrite($fp, self::substr($data, $written))) === FALSE) + { + break; + } + } + + flock($fp, LOCK_UN); + fclose($fp); + + return is_int($result); + } + + // -------------------------------------------------------------------- + + /** + * Download + * + * @param string $filename the file name + * @return void + */ + public function download($filename = 'backup.zip') + { + if ( ! preg_match('|.+?\.zip$|', $filename)) + { + $filename .= '.zip'; + } + + get_instance()->load->helper('download'); + $get_zip = $this->get_zip(); + $zip_content =& $get_zip; + + force_download($filename, $zip_content); + } + + // -------------------------------------------------------------------- + + /** + * Initialize Data + * + * Lets you clear current zip data. Useful if you need to create + * multiple zips with different data. + * + * @return CI_Zip + */ + public function clear_data() + { + $this->zipdata = ''; + $this->directory = ''; + $this->entries = 0; + $this->file_num = 0; + $this->offset = 0; + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Byte-safe strlen() + * + * @param string $str + * @return int + */ + protected static function strlen($str) + { + return (self::$func_overload) + ? mb_strlen($str, '8bit') + : strlen($str); + } + + // -------------------------------------------------------------------- + + /** + * Byte-safe substr() + * + * @param string $str + * @param int $start + * @param int $length + * @return string + */ + protected static function substr($str, $start, $length = NULL) + { + if (self::$func_overload) + { + // mb_substr($str, $start, null, '8bit') returns an empty + // string on PHP 5.3 + isset($length) OR $length = ($start >= 0 ? self::strlen($str) - $start : -$start); + return mb_substr($str, $start, $length, '8bit'); + } + + return isset($length) + ? substr($str, $start, $length) + : substr($str, $start); + } +} diff --git a/system/libraries/index.html b/system/libraries/index.html new file mode 100644 index 0000000..b702fbc --- /dev/null +++ b/system/libraries/index.html @@ -0,0 +1,11 @@ + + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + +