diff --git a/.gitignore b/.gitignore index 57901d6d8..05272d898 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,12 @@ # Local Config -/public/include/config/global.inc.php -/public/include/config/security.inc.php +/include/config/global.inc.php +/include/config/security.inc.php # Templates -/public/templates/compile/*.php -/public/templates/compile/** -/public/templates/cache/*.php -/public/templates/cache/** +/templates/compile/*.php +/templates/compile/** +/templates/cache/*.php +/templates/cache/** # Logs /cronjobs/logs @@ -14,9 +14,13 @@ /logs/* # Test configs -public/include/config/global.inc.scrypt.php -public/include/config/global.inc.sha.php -public/include/config/**/*.php +/include/config/global.inc.test.php +/include/config/global.inc.scrypt.php +/include/config/global.inc.sha.php + +# Test files +/scripts/test.php +/cronjobs/test.php # IDE Settings /.idea/* diff --git a/.htaccess b/.htaccess index d71420f82..6fb22ef25 100644 --- a/.htaccess +++ b/.htaccess @@ -1,3 +1,10 @@ ErrorDocument 404 /public/index.php?page=error&action=404 RedirectMatch 404 /logs(/|$) -Options -Indexes \ No newline at end of file +RedirectMatch 404 /templates(/|$) +RedirectMatch 404 /include(/|$) +RedirectMatch 404 /scripts(/|$) +RedirectMatch 404 /sql(/|$) +RedirectMatch 404 /upgrade(/|$) +RedirectMatch 404 /cronjobs(/|$) +RedirectMatch 404 /tests(/|$) +Options -Indexes diff --git a/README.md b/README.md index 4fdbff001..c8c01563a 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,7 @@ -Description [ ![Codeship Status for TheSerapher/php-mpos](https://www.codeship.io/projects/40fa7600-61a6-0131-3fd3-367b94dc0d60/status?branch=next)](https://www.codeship.io/projects/12276) +Description =========== -MPOS is a web based Mining Portal for various crypto currencies. It was created by [TheSerapher](https://github.com/TheSerapher) and has hence grown quite large. Recently it was migrated into a Github Organization to make development easier. It's a community driven open source project. Support can be requested on IRC at https://webchat.freenode.net/?channels=#mpos - - -**NOTE**: This project is still under development and commits are happening on a daily basis. -I do not recommend using this for a live setup as of yet. Wait for the later Release Candidate -if you wish to run your pool with it. Testing pools are much appreciated though! +MPOS is a web based Mining Portal for various crypto currencies. It was created by [TheSerapher](https://github.com/TheSerapher) and has hence grown quite large. Recently it was migrated into a Github Organization to make development easier. It's a community driven open source project. Support can be requested on IRC at https://webchat.freenode.net/?channels=#mpos - Be **PATIENT** ... People listed in this channel may currently be inactive but most users there have offline logging of messages. They **will** see your questions and answer if they can. Don't join, ask the question and leave. Sit around if you want answers to your questions! Donations ========= @@ -15,13 +10,16 @@ Donations to this project are going directly to [TheSerapher](https://github.com * LTC address: `Lge95QR2frp9y1wJufjUPCycVsg5gLJPW8` * BTC address: `1HuYK6WPU8o3yWCrAaADDZPRpL5QiXitfv` -* DOGE Address: `D6YtvxFGBmaD8Yq3i8LZsBQVPvCbZwCDzF` +* DOGE address: `DANk8bnc3vHEf7Jthaxq1Xgn1BSiArNdjG` +* 42Coin address: `4VxA6Ht59Mj6ikhA4gDXLiHuAaDCJEvYTZ` +* FST address: `fiRqMgZyhjTN1GSEB3ZxV35JXsE5bjEaQ2` +* FRK address: `FDcgGZjX2B29qevSuiuQVwXhkNhtQT4cEW` * Cryptsy Trade Key: `6ff7292142463b7b80cbbbdfc52334ba89727b11` Website Footer ============== -When you decide to use `MPOS` please be so kind and leave the footer intact. You are not the author of the software and should honor those that have worked on it. I don't mind changing the LTC donation address at the bottom, but keep in mind who really wrote this software and would deserve those ;-). +When you decide to use `MPOS` please be so kind and leave the footer intact. You are not the author of the software and should honor those that have worked on it. Keeping the footer intact helps spreading the word. Leaving the donation address untouched allows miners to donate to the author. Donors ====== @@ -79,15 +77,14 @@ The following feature have been implemented so far: * Fully re-written GUI with [Smarty][2] templates * Full file based template support - * **NEW** SQL based templates -* Mobile WebUI -* Scrypt, SHA256, VARDIFF Support +* VARDIFF Support * Reward Systems * Propotional, PPS and PPLNS * New Theme * Live Dashboard * AJAX Support * Overhauled API + * Bootstrap * Web User accounts * Re-Captcha protected registration form * Worker accounts @@ -95,7 +92,7 @@ The following feature have been implemented so far: * Worker hashrates * Pool statistics * Block statistics -* Pool donations, fees and block bonuses +* Pool donations, bonuses, fees and block bonuses * Manual and auto payout * Transaction list * Admin Panel @@ -105,24 +102,24 @@ The following feature have been implemented so far: * User Transactions * News Posts * Pool Settings - * Templates * Pool Workers * User Reports - * Template Overwrite * Notification system * IDLE Workers * New blocks found in pool * Auto Payout * Manual Payout * User-to-user Invitation System -* Support for various coins via config +* Support for various coins via coin class and config * All scrypt coins * All sha256d coins + * All x11 coins + * Others may be supported by creating a custom coin class Installation ============ -Please take a look at the [Quick Start Guide](https://github.com/TheSerapher/php-mpos/wiki/Quick-Start-Guide). This will give you an idea how to setup `MPOS`. +Please take a look at the [Quick Start Guide](https://github.com/TheSerapher/php-mpos/wiki/Quick-Start-Guide). This will give you an idea how to setup `MPOS`. Please be aware that the `master` branch is our currently considered stable system while `development` is used as a test bed for all upcoming changes for `master`. If you wish to run a stable, well tested system ensure you run `git checkout master`. If you decide to stick to the `development` branch with bleeding edge code and potential bugs, just `git clone` the project. Customization ============= @@ -131,7 +128,7 @@ This project was meant to allow users to easily customize the system and templat If you are just using the system, there will be no need to adjust anything. Things will work out of the box! But if you plan on creating your own theme, things are pretty easy: -* Create a new theme folder in `public/templates/` +* Create a new theme folder in `templates/` * Create a new site_assets folder in `public/site_assets` * Create your own complete custom template or copy from an existing one * Change your theme in the `Admin Panel` and point it to the newly created folder @@ -153,6 +150,7 @@ There are a few other projects out there that take advantage of MPOS and it's in * [MPOS Eggdrop Module](https://github.com/iAmShorty/mpos-eggdrop-tcl) written in TCL, adding MPOS commands to this bot, using the MPOS API * [Windows Phone Pool App](http://www.windowsphone.com/en-us/store/app/meeneminermonitor/7ec6eac7-a642-409b-96c8-57b5cfdf45cf) * [iPhone iMPOS App](https://itunes.apple.com/us/app/impos/id742179239?mt=8) +* [Other Windows Phone App](http://www.windowsphone.com/en-us/store/app/mining-info/952f1137-eb62-4613-8057-34576d3c9c44) Contributing ============ @@ -173,7 +171,7 @@ You can find the team on Freenode.net, #MPOS. Team Members ============ -Author and Github Owner: [TheSerapher](https://github.com/TheSerapher) aka Sebastian Grewe +Author and Project Owner: [TheSerapher](https://github.com/TheSerapher) aka Sebastian Grewe Developers: diff --git a/cronjobs/findblock.php b/cronjobs/findblock.php index 42e347a0e..3516fe2c6 100755 --- a/cronjobs/findblock.php +++ b/cronjobs/findblock.php @@ -59,7 +59,7 @@ $config['reward_type'] == 'block' ? $aData['amount'] = $aData['amount'] : $aData['amount'] = $config['reward']; $aData['height'] = $aBlockRPCInfo['height']; $aTxDetails = $bitcoin->gettransaction($aBlockRPCInfo['tx'][0]); - if (!isset($aBlockRPCInfo['confirmations'])) { + if (isset($aBlockRPCInfo['confirmations'])) { $aData['confirmations'] = $aBlockRPCInfo['confirmations']; } else if (isset($aTxDetails['confirmations'])) { $aData['confirmations'] = $aTxDetails['confirmations']; diff --git a/cronjobs/logs/README.md b/cronjobs/logs/README.md deleted file mode 100644 index 864999fd5..000000000 --- a/cronjobs/logs/README.md +++ /dev/null @@ -1 +0,0 @@ -Logging directory for cronjobs. diff --git a/cronjobs/payouts.php b/cronjobs/payouts.php index 33775d38e..5971fbd69 100755 --- a/cronjobs/payouts.php +++ b/cronjobs/payouts.php @@ -69,9 +69,9 @@ foreach ($aManualPayouts as $aUserData) $dMPTotalAmount += $aUserData['confirmed']; if ($dMPTotalAmount > $dWalletBalance) { $log->logError(" Wallet does not cover MP payouts - Payout: " . $dMPTotalAmount . " - Balance: " . $dWalletBalance); - $monitoring->endCronjob($cron_name, 'E0079', 0, true); + $monitoring->endCronjob($cron_name, 'E0079', 1, true); } - + $log->logInfo("Manual Payout Sum: " . $dMPTotalAmount . " | Liquid Assets: " . $dWalletBalance . " | Wallet Balance: " . ($dWalletBalance + $dBlocksUnconfirmedBalance) . " | Unconfirmed: " . $dBlocksUnconfirmedBalance); $log->logInfo(' found ' . count($aManualPayouts) . ' queued manual payouts'); $mask = ' | %-10.10s | %-25.25s | %-20.20s | %-40.40s | %-20.20s |'; @@ -156,9 +156,9 @@ foreach ($aAutoPayouts as $aUserData) $dAPTotalAmount += $aUserData['confirmed']; if ($dAPTotalAmount > $dWalletBalance) { $log->logError(" Wallet does not cover AP payouts - Payout: " . $dAPTotalAmount . " - Balance: " . $dWalletBalance); - $monitoring->endCronjob($cron_name, 'E0079', 0, true); + $monitoring->endCronjob($cron_name, 'E0079', 1, true); } - + $log->logInfo("Auto Payout Sum: " . $dAPTotalAmount . " | Liquid Assets: " . $dWalletBalance . " | Wallet Balance: " . ($dWalletBalance + $dBlocksUnconfirmedBalance) . " | Unconfirmed: " . $dBlocksUnconfirmedBalance); $log->logInfo(' found ' . count($aAutoPayouts) . ' queued auto payouts'); $mask = ' | %-10.10s | %-25.25s | %-20.20s | %-40.40s | %-20.20s |'; diff --git a/cronjobs/pplns_payout.php b/cronjobs/pplns_payout.php index c256b2792..832f6e59d 100755 --- a/cronjobs/pplns_payout.php +++ b/cronjobs/pplns_payout.php @@ -38,6 +38,10 @@ $monitoring->endCronjob($cron_name, 'E0011', 0, true, false); } +// Fetch precision +$precision = $coin->getCoinValuePrevision(); +$table_precision = $coin->getCoinValuePrevision() + 3; + $log->logDebug('Starting PPLNS payout process'); $count = 0; foreach ($aAllBlocks as $iIndex => $aBlock) { @@ -115,16 +119,16 @@ // Add archived shares to users current shares, if we have any in archive if (is_array($aArchiveShares)) { $log->logDebug('Found shares in archive to match PPLNS target, calculating per-user shares'); - $strLogMask = "| %-20.20s | %15.15s | %15.15s | %15.15s | %15.15s | %15.15s | %15.15s |"; - $log->logDebug(sprintf($strLogMask, 'Username', 'Round Valid', 'Archive Valid', 'Total Valid', 'Round Invalid', 'Archive Invalid', 'Total Invalid')); + $strLogMask = "| %5.5s | %-20.20s | %15.15s | %15.15s | %15.15s | %15.15s | %15.15s | %15.15s |"; + $log->logDebug(sprintf($strLogMask, 'ID', 'Username', 'Round Valid', 'Archive Valid', 'Total Valid', 'Round Invalid', 'Archive Invalid', 'Total Invalid')); foreach($aAccountShares as $key => $aData) { - if (array_key_exists($aData['username'], $aArchiveShares)) { - $log->logDebug(sprintf($strLogMask, $aData['username'], - $aAccountShares[$key]['valid'], $aArchiveShares[$aData['username']]['valid'], ($aAccountShares[$key]['valid'] + $aArchiveShares[$aData['username']]['valid']), - $aAccountShares[$key]['invalid'], $aArchiveShares[$aData['username']]['invalid'], ($aAccountShares[$key]['invalid'] + $aArchiveShares[$aData['username']]['invalid'])) + if (array_key_exists(strtolower($aData['username']), $aArchiveShares)) { + $log->logDebug(sprintf($strLogMask, $aData['id'], $aData['username'], + $aAccountShares[$key]['valid'], $aArchiveShares[strtolower($aData['username'])]['valid'], ($aAccountShares[$key]['valid'] + $aArchiveShares[strtolower($aData['username'])]['valid']), + $aAccountShares[$key]['invalid'], $aArchiveShares[strtolower($aData['username'])]['invalid'], ($aAccountShares[$key]['invalid'] + $aArchiveShares[strtolower($aData['username'])]['invalid'])) ); - $aAccountShares[$key]['valid'] += $aArchiveShares[$aData['username']]['valid']; - $aAccountShares[$key]['invalid'] += $aArchiveShares[$aData['username']]['invalid']; + $aAccountShares[$key]['valid'] += $aArchiveShares[strtolower($aData['username'])]['valid']; + $aAccountShares[$key]['invalid'] += $aArchiveShares[strtolower($aData['username'])]['invalid']; } } // reverse payout @@ -132,13 +136,13 @@ $log->logDebug('Reverse payout enabled, adding shelved shares for all users'); $aSharesData = NULL; foreach($aAccountShares as $key => $aData) { - $aSharesData[$aData['username']] = $aData; + $aSharesData[strtolower($aData['username'])] = $aData; } // Add users from archive not in current round $strLogMask = "| %-20.20s | %15.15s | %15.15s |"; $log->logDebug(sprintf($strLogMask, 'Username', 'Shelved Valid', 'Shelved Invalid')); foreach($aArchiveShares as $key => $aArchData) { - if (!array_key_exists($aArchData['account'], $aSharesData)) { + if (!array_key_exists(strtolower($aArchData['account']), $aSharesData)) { $log->logDebug(sprintf($strLogMask, $aArchData['account'], $aArchData['valid'], $aArchData['invalid'])); $aArchData['username'] = $aArchData['account']; $aSharesData[$aArchData['account']] = $aArchData; @@ -181,7 +185,7 @@ } // Table header for account shares - $strLogMask = "| %5.5s | %-15.15s | %15.15s | %15.15s | %12.12s | %15.15s | %15.15s | %15.15s | %15.15s |"; + $strLogMask = "| %5.5s | %-15.15s | %15.15s | %15.15s | %12.12s | %${table_precision}.${table_precision}s | %${table_precision}.${table_precision}s | %${table_precision}.${table_precision}s | %${table_precision}.${table_precision}s |"; $log->logInfo(sprintf($strLogMask, 'ID', 'Username', 'Valid', 'Invalid', 'Percentage', 'Payout', 'Donation', 'Fee', 'Bonus')); // Loop through all accounts that have found shares for this round @@ -197,7 +201,7 @@ // Payout based on PPLNS target shares, proportional payout for all users $aData['percentage'] = round(( 100 / $iRoundShares) * $aData['pplns_valid'], 8); - $aData['payout'] = round(( $aData['percentage'] / 100 ) * $dReward, 8); + $aData['payout'] = ( $aData['percentage'] / 100 ) * $dReward; // Defaults $aData['fee' ] = 0; $aData['donation'] = 0; @@ -205,19 +209,19 @@ // Calculate pool fees if ($config['fees'] > 0 && $aData['no_fees'] == 0) - $aData['fee'] = round($config['fees'] / 100 * $aData['payout'], 8); + $aData['fee'] = $config['fees'] / 100 * $aData['payout']; // Calculate pool bonus if it applies, will be paid from liquid assets! if ($config['pool_bonus'] > 0) { if ($config['pool_bonus_type'] == 'block') { - $aData['pool_bonus'] = round(( $config['pool_bonus'] / 100 ) * $dReward, 8); + $aData['pool_bonus'] = ( $config['pool_bonus'] / 100 ) * $dReward; } else { - $aData['pool_bonus'] = round(( $config['pool_bonus'] / 100 ) * $aData['payout'], 8); + $aData['pool_bonus'] = ( $config['pool_bonus'] / 100 ) * $aData['payout']; } } // Calculate donation amount, fees not included - $aData['donation'] = round($user->getDonatePercent($user->getUserId($aData['username'])) / 100 * ( $aData['payout'] - $aData['fee']), 8); + $aData['donation'] = $user->getDonatePercent($user->getUserId($aData['username'])) / 100 * ( $aData['payout'] - $aData['fee']); // Verbose output of this users calculations $log->logInfo( diff --git a/cronjobs/pps_payout.php b/cronjobs/pps_payout.php index 509176d2e..f35f15605 100755 --- a/cronjobs/pps_payout.php +++ b/cronjobs/pps_payout.php @@ -63,7 +63,7 @@ } // Per-share value to be paid out to users -$pps_value = round($coin->calcPPSValue($pps_reward, $dDifficulty), 12); +$pps_value = $coin->calcPPSValue($pps_reward, $dDifficulty); // Find our last share accounted and last inserted share for PPS calculations if (!$iPreviousShareId = $setting->getValue('pps_last_share_id')) { @@ -89,13 +89,15 @@ if (!empty($aAccountShares)) { // Runtime information for this payout + $precision = $coin->getCoinValuePrevision(); + $table_precision = $coin->getCoinValuePrevision() + 3; $log->logInfo('Runtime information for this payout'); - $strLogMask = "| %-15.15s | %15.15s | %15.15s | %15.15s |"; - $log->logInfo(sprintf($strLogMask, 'PPS reward type', 'Reward Base', 'Difficulty', 'PPS Value')); - $log->logInfo(sprintf($strLogMask, $strRewardType, $pps_reward, $dDifficulty, $pps_value)); + $strLogMask = "| %-15.15s | %15.15s | %15.15s | %${table_precision}.${table_precision}s | %3.3s |"; + $log->logInfo(sprintf($strLogMask, 'PPS reward type', 'Reward Base', 'Difficulty', 'PPS Value', 'Precision')); + $log->logInfo(sprintf($strLogMask, $strRewardType, $pps_reward, $dDifficulty, $pps_value, $precision)); $log->logInfo('Per-user payout information'); - $strLogMask = "| %8.8s | %25.25s | %15.15s | %15.15s | %18.18s | %18.18s | %18.18s |"; - $log->logInfo(sprintf($strLogMask, 'User ID', 'Username', 'Invalid', 'Valid', ' * PPS Value', ' = Payout', 'Donation', 'Fee')); + $strLogMask = "| %8.8s | %25.25s | %15.15s | %${table_precision}.${table_precision}s | %${table_precision}.${table_precision}s | %${table_precision}.${table_precision}s | %${table_precision}.${table_precision}s |"; + $log->logInfo(sprintf($strLogMask, 'User ID', 'Username', 'Invalid', 'Valid', '* PPS Value', ' = Payout', 'Donation', 'Fee')); } foreach ($aAccountShares as $aData) { @@ -106,7 +108,7 @@ } // Payout for this user - $aData['payout'] = round($aData['valid'] * $pps_value, 12); + $aData['payout'] = $aData['valid'] * $pps_value; // Defaults $aData['fee' ] = 0; @@ -114,13 +116,13 @@ // Calculate block fees if ($config['fees'] > 0 && $aData['no_fees'] == 0) - $aData['fee'] = round($config['fees'] / 100 * $aData['payout'], 12); + $aData['fee'] = $config['fees'] / 100 * $aData['payout']; // Calculate donation amount - $aData['donation'] = round($user->getDonatePercent($user->getUserId($aData['username'])) / 100 * ( $aData['payout'] - $aData['fee']), 12); + $aData['donation'] = $user->getDonatePercent($user->getUserId($aData['username'])) / 100 * ( $aData['payout'] - $aData['fee']); $log->logInfo(sprintf( $strLogMask, $aData['id'], $aData['username'], $aData['invalid'], $aData['valid'], - number_format($pps_value, 12), number_format($aData['payout'], 12), number_format($aData['donation'], 12), number_format($aData['fee'], 12) + number_format($pps_value, $precision), number_format($aData['payout'], $precision), number_format($aData['donation'], $precision), number_format($aData['fee'], $precision) )); // Add new credit transaction diff --git a/cronjobs/proportional_payout.php b/cronjobs/proportional_payout.php index a49bccf20..d9172ec5b 100755 --- a/cronjobs/proportional_payout.php +++ b/cronjobs/proportional_payout.php @@ -40,9 +40,13 @@ $monitoring->endCronjob($cron_name, 'E0011', 0, true, false); } +// Fetch precision +$precision = $coin->getCoinValuePrevision(); +$table_precision = $coin->getCoinValuePrevision() + 3; + $count = 0; // Table header for account shares -$strLogMask = "| %10.10s | %-5.5s | %15.15s | %15.15s | %12.12s | %12.12s | %15.15s | %15.15s | %15.15s | %15.15s |"; +$strLogMask = "| %10.10s | %-5.5s | %15.15s | %15.15s | %12.12s | %12.12s | %${table_precision}.${table_precision}s | %${table_precision}.${table_precision}s | %${table_precision}.${table_precision}s | %${table_precision}.${table_precision}s |"; $log->logInfo(sprintf($strLogMask, 'Block', 'ID', 'Username', 'Valid', 'Invalid', 'Percentage', 'Payout', 'Donation', 'Fee', 'Bonus')); foreach ($aAllBlocks as $iIndex => $aBlock) { // If we have unaccounted blocks without share_ids, they might not have been inserted yet @@ -89,29 +93,29 @@ $aData['fee' ] = 0; $aData['donation'] = 0; $aData['pool_bonus'] = 0; - $aData['percentage'] = round(( 100 / $iRoundShares ) * $aData['valid'], 8); - $aData['payout'] = round(( $aData['percentage'] / 100 ) * $dReward, 8); + $aData['percentage'] = ( 100 / $iRoundShares ) * $aData['valid']; + $aData['payout'] = ( $aData['percentage'] / 100 ) * $dReward; // Calculate pool fees if they apply if ($config['fees'] > 0 && $aData['no_fees'] == 0) - $aData['fee'] = round($config['fees'] / 100 * $aData['payout'], 8); + $aData['fee'] = $config['fees'] / 100 * $aData['payout']; // Calculate pool bonus if it applies, will be paid from liquid assets! if ($config['pool_bonus'] > 0) { if ($config['pool_bonus_type'] == 'block') { - $aData['pool_bonus'] = round(( $config['pool_bonus'] / 100 ) * $dReward, 8); + $aData['pool_bonus'] = ( $config['pool_bonus'] / 100 ) * $dReward; } else { - $aData['pool_bonus'] = round(( $config['pool_bonus'] / 100 ) * $aData['payout'], 8); + $aData['pool_bonus'] = ( $config['pool_bonus'] / 100 ) * $aData['payout']; } } // Calculate donation amount, fees not included - $aData['donation'] = round($user->getDonatePercent($user->getUserId($aData['username'])) / 100 * ( $aData['payout'] - $aData['fee']), 8); + $aData['donation'] = $user->getDonatePercent($user->getUserId($aData['username'])) / 100 * ( $aData['payout'] - $aData['fee']); // Verbose output of this users calculations $log->logInfo( sprintf($strLogMask, $aBlock['height'], $aData['id'], $aData['username'], $aData['valid'], $aData['invalid'], - number_format($aData['percentage'], 8), number_format($aData['payout'], 8), number_format($aData['donation'], 8), number_format($aData['fee'], 8), number_format($aData['pool_bonus'], 8)) + number_format($aData['percentage'], $precision), number_format($aData['payout'], $precision), number_format($aData['donation'], $precision), number_format($aData['fee'], $precision), number_format($aData['pool_bonus'], $precision)) ); // Update user share statistics diff --git a/cronjobs/shared.inc.php b/cronjobs/shared.inc.php index 3b6f93db5..34dacd049 100644 --- a/cronjobs/shared.inc.php +++ b/cronjobs/shared.inc.php @@ -35,7 +35,8 @@ function cfip() { return (@defined('SECURITY')) ? 1 : 0; } // MODIFY THIS // We need to find our include files so set this properly -define("BASEPATH", "../public/"); +define("BASEPATH", dirname(__FILE__) . "/"); + /***************************************************** * No need to change beyond this point * *****************************************************/ @@ -51,14 +52,8 @@ function cfip() { return (@defined('SECURITY')) ? 1 : 0; } $coin = $argv[$index]; // Include our configuration (holding defines for the requires) -require_once(BASEPATH . 'include/config/global.inc.dist.php'); -require_once(BASEPATH . 'include/config/' . $coin . '/global.inc.php'); - -require_once(BASEPATH . 'include/config/security.inc.dist.php'); -@include_once(BASEPATH . 'include/config/security.inc.php'); - -require_once(BASEPATH . 'include/bootstrap.php'); -require_once(BASEPATH . 'include/version.inc.php'); +require_once(BASEPATH . '../include/bootstrap.php'); +require_once(BASEPATH . '../include/version.inc.php'); // Command line switches array_shift($argv); @@ -72,7 +67,7 @@ function cfip() { return (@defined('SECURITY')) ? 1 : 0; } } // Load 3rd party logging library for running crons -$log = KLogger::instance( 'logs/' . $cron_name, KLogger::INFO ); +$log = KLogger::instance( BASEPATH . '../logs/' . $cron_name, KLogger::INFO ); $log->LogDebug('Starting ' . $cron_name); // Load the start time for later runtime calculations for monitoring diff --git a/cronjobs/statistics.php b/cronjobs/statistics.php index 6530fab71..eb564c1a8 100755 --- a/cronjobs/statistics.php +++ b/cronjobs/statistics.php @@ -27,7 +27,7 @@ // Header $log->logInfo('Running statistical queries, errors may just mean no shares were available'); -$strLogMask = "| %-26.26s | %8.8s | %-6.6s |"; +$strLogMask = "| %-33.33s | %8.8s | %-6.6s |"; $log->logInfo(sprintf($strLogMask, 'Method', 'Runtime', 'Status')); // Per user share statistics based on all shares submitted @@ -37,9 +37,15 @@ // Get all user hashrate statistics for caching $start = microtime(true); -$statistics->getAllUserMiningStats() ? $status = 'OK' : $status = 'ERROR'; -$log->logInfo(sprintf($strLogMask, 'getAllUserMiningStats', number_format(microtime(true) - $start, 3), $status)); +$statistics->fetchAllUserMiningStats() ? $status = 'OK' : $status = 'ERROR'; +$log->logInfo(sprintf($strLogMask, 'fetchAllUserMiningStats', number_format(microtime(true) - $start, 3), $status)); +// Store our statistical data into our `statistics_users` table +$start = microtime(true); +$statistics->storeAllUserMiningStatsSnapshot($statistics->getAllUserMiningStats()) ? $status = 'OK' : $status = 'ERROR'; +$log->logInfo(sprintf($strLogMask, 'storeAllUserMiningStatsSnapshot', number_format(microtime(true) - $start, 3), $status)); + +// Get stats for pool overview $start = microtime(true); $statistics->getTopContributors('hashes') ? $status = 'OK' : $status = 'ERROR'; $log->logInfo(sprintf($strLogMask, 'getTopContributors(hashes)', number_format(microtime(true) - $start, 3), $status)); diff --git a/cronjobs/tables_cleanup.php b/cronjobs/tables_cleanup.php index 04386133d..42189f2f2 100755 --- a/cronjobs/tables_cleanup.php +++ b/cronjobs/tables_cleanup.php @@ -65,7 +65,7 @@ $message = ''; $affected = $share->purgeArchive(); if ($affected === false) { - $message = 'Failed to delete notifications: ' . $oToken->getCronError(); + $message = 'Failed to delete shares: ' . $share->getCronError(); $status = 'ERROR'; $monitoring->endCronjob($cron_name, 'E0008', 0, false, false); } else { @@ -73,6 +73,19 @@ } $log->logInfo(sprintf($strLogMask, 'purgeArchive', $affected, number_format(microtime(true) - $start, 3), $status, $message)); +// Clenaup shares archive +$start = microtime(true); +$status = 'OK'; +$message = ''; +$affected = $statistics->purgeUserStats($setting->getValue('statistics_graphing_days', 1)); +if ($affected === false) { + $message = 'Failed to delete entries: ' . $statistics->getCronError(); + $status = 'ERROR'; + $monitoring->endCronjob($cron_name, 'E0008', 0, false, false); +} else { + $affected == 0 ? $message = 'No entries deleted' : $message = 'Deleted old entries'; +} +$log->logInfo(sprintf($strLogMask, 'purgeUserStats', $affected, number_format(microtime(true) - $start, 3), $status, $message)); // Cron cleanup and monitoring require_once('cron_end.inc.php'); diff --git a/public/include/admin_checks.php b/include/admin_checks.php similarity index 95% rename from public/include/admin_checks.php rename to include/admin_checks.php index 179d873ae..27e7011a8 100644 --- a/public/include/admin_checks.php +++ b/include/admin_checks.php @@ -34,6 +34,10 @@ } if (class_exists('Memcached')) { $memcache_test = @new Memcached(); + if ($config['memcache']['sasl'] === true) { + $memcache_test->setOption(Memcached::OPT_BINARY_PROTOCOL, true); + $memcache_test->setSaslAuthData($config['memcache']['sasl']['username'], $config['memcache']['sasl']['password']); + } $memcache_test_add = @$memcache_test->addServer($config['memcache']['host'], $config['memcache']['port']); $randmctv = rand(5,10); $memcache_test_set = @$memcache_test->set('test_mpos_setval', $randmctv); @@ -53,10 +57,10 @@ } // check if we can write templates/cache and templates/compile -> error - if (!is_writable(THEME_DIR.'/cache')) { + if (!is_writable(TEMPLATE_DIR . '/cache')) { $error[] = "templates/cache folder is not writable for uid {$apache_user['name']}"; } - if (!is_writable(THEME_DIR.'/compile')) { + if (!is_writable(TEMPLATE_DIR . '/compile')) { $error[] = "templates/compile folder is not writable for uid {$apache_user['name']}"; } diff --git a/public/include/autoloader.inc.php b/include/autoloader.inc.php similarity index 87% rename from public/include/autoloader.inc.php rename to include/autoloader.inc.php index 84a8dfac1..fdb435dff 100644 --- a/public/include/autoloader.inc.php +++ b/include/autoloader.inc.php @@ -16,7 +16,10 @@ // We need to load these first require_once(CLASS_DIR . '/base.class.php'); require_once(CLASS_DIR . '/coins/coin_base.class.php'); +require_once(CLASS_DIR . '/coin_address.class.php'); require_once(CLASS_DIR . '/setting.class.php'); +require_once(INCLUDE_DIR . '/version.inc.php'); +if (PHP_OS == 'WINNT') require_once(CLASS_DIR . '/memcached.class.php'); $currency = $setting->getValue('currency'); @@ -36,13 +39,18 @@ require_once(INCLUDE_DIR . '/lib/swiftmailer/swift_required.php'); // Detect device -if ( PHP_SAPI == 'cli') { +require_once(INCLUDE_DIR . '/lib/Mobile_Detect.php'); +$detect = new Mobile_Detect; + +if ($detect->isMobile()) { + $theme = $setting->getValue('website_mobile_theme', 'bootstrap'); +} else if ( PHP_SAPI == 'cli') { // Create a new compile folder just for crons // We call mail templates directly anyway $theme = 'cron'; } else { // Use configured theme, fallback to default theme - $setting->getValue('website_theme') ? $theme = $setting->getValue('website_theme') : $theme = 'bootstrap'; + $theme = $setting->getValue('website_theme', 'bootstrap'); } define('THEME', $theme); diff --git a/public/include/bootstrap.php b/include/bootstrap.php similarity index 59% rename from public/include/bootstrap.php rename to include/bootstrap.php index 0c5edd15d..c0178a897 100644 --- a/public/include/bootstrap.php +++ b/include/bootstrap.php @@ -3,10 +3,10 @@ // Used for performance calculations $dStartTime = microtime(true); -define('INCLUDE_DIR', BASEPATH . 'include'); +define('INCLUDE_DIR', BASEPATH . '../include'); define('CLASS_DIR', INCLUDE_DIR . '/classes'); define('PAGES_DIR', INCLUDE_DIR . '/pages'); -define('THEME_DIR', BASEPATH . 'templates'); +define('TEMPLATE_DIR', BASEPATH . '../templates'); $quickstartlink = "Quick Start Guide"; @@ -18,12 +18,12 @@ } // Include our configuration (holding defines for the requires) -if (!include_once(BASEPATH . 'include/config/global.inc.dist.php')) die('Unable to load base global config - '.$quickstartlink); -if (!@include_once(BASEPATH . "include/config/$currency_code/global.inc.php")) die('Unable to load your global config - '.$quickstartlink); +if (!include_once(INCLUDE_DIR . '/config/global.inc.dist.php')) die('Unable to load base global config from ['.INCLUDE_DIR. '/config/global.inc.dist.php' . '] - '.$quickstartlink); +if (!@include_once(INCLUDE_DIR . "/config/$currency_code/global.inc.php")) die('Unable to load your global config from ['.INCLUDE_DIR. '/config/global.inc.php' . '] - '.$quickstartlink); // load our security configs -if (!include_once(BASEPATH . 'include/config/security.inc.dist.php')) die('Unable to load base security config - '.$quickstartlink); -if (@file_exists(BASEPATH . "include/config/$currency_code/security.inc.php")) include_once(BASEPATH . 'include/config/security.inc.php'); +if (!include_once(INCLUDE_DIR . '/config/security.inc.dist.php')) die('Unable to load base security config from ['.INCLUDE_DIR. '/config/security.inc.dist.php' . '] - '.$quickstartlink); +if (@file_exists(INCLUDE_DIR . "/config/$currency_code/security.inc.php")) include_once(INCLUDE_DIR . '/config/security.inc.php'); // start our session, we need it for smarty caching session_set_cookie_params(time()+$config['cookie']['duration'], $config['cookie']['path'], $config['cookie']['domain'], $config['cookie']['secure'], $config['cookie']['httponly']); @@ -36,6 +36,14 @@ } @setcookie(session_name(), session_id(), time()+$config['cookie']['duration'], $config['cookie']['path'], $config['cookie']['domain'], $config['cookie']['secure'], $config['cookie']['httponly']); +// Set the timezone if a user has it set, default UTC +if (isset($_SESSION['USERDATA']['timezone'])) { + $aTimezones = DateTimeZone::listIdentifiers(); + date_default_timezone_set($aTimezones[$_SESSION['USERDATA']['timezone']]); +} else { + date_default_timezone_set('UTC'); +} + // Our default template to load, pages can overwrite this later $master_template = 'master.tpl'; diff --git a/public/include/classes/api.class.php b/include/classes/api.class.php similarity index 93% rename from public/include/classes/api.class.php rename to include/classes/api.class.php index 913a1f033..bc6670f36 100644 --- a/public/include/classes/api.class.php +++ b/include/classes/api.class.php @@ -37,8 +37,10 @@ function get_json($data, $force=false) { )), $force ? JSON_FORCE_OBJECT : 0 ); // JSONP support issue #1700 - if (isset($_REQUEST['callback'])) + if (isset($_REQUEST['callback']) && ctype_alpha($_REQUEST['callback'])) { + header('Content-type: application/json; charset=utf-8'); return $_REQUEST['callback'] . '(' . $json . ');'; + } return $json; } diff --git a/public/include/classes/base.class.php b/include/classes/base.class.php similarity index 98% rename from public/include/classes/base.class.php rename to include/classes/base.class.php index 1bb27e3ac..d9f950add 100644 --- a/public/include/classes/base.class.php +++ b/include/classes/base.class.php @@ -22,6 +22,9 @@ public function setDebug($debug) { public function setCoin($coin) { $this->coin = $coin; } + public function setCoinAddress($coin_address) { + $this->coin_address = $coin_address; + } public function setLog($log) { $this->log = $log; } diff --git a/public/include/classes/bitcoin.class.php b/include/classes/bitcoin.class.php similarity index 100% rename from public/include/classes/bitcoin.class.php rename to include/classes/bitcoin.class.php diff --git a/public/include/classes/bitcoinwrapper.class.php b/include/classes/bitcoinwrapper.class.php similarity index 100% rename from public/include/classes/bitcoinwrapper.class.php rename to include/classes/bitcoinwrapper.class.php diff --git a/public/include/classes/block.class.php b/include/classes/block.class.php similarity index 100% rename from public/include/classes/block.class.php rename to include/classes/block.class.php diff --git a/include/classes/coinaddress.class.php b/include/classes/coinaddress.class.php new file mode 100644 index 000000000..6cf9190d4 --- /dev/null +++ b/include/classes/coinaddress.class.php @@ -0,0 +1,88 @@ +currency = $currency; + } + /** + * Check whether the coin address already exists + * @param address string Coin Address + * @return bool address exists? + **/ + public function existsCoinAddress($address) { + $this->debug->append("STA " . __METHOD__, 4); + return $this->getSingle($address, 'address', 'address') === $address; + } + + /** + * Fetch coin address for one account + * @param account_id int Account ID + * @return string address on success, bool on failure + **/ + public function getCoinAddress($account_id) { + $this->debug->append("STA " . __METHOD__, 4); + + $stmt = $this->mysqli->prepare("SELECT address FROM $this->table WHERE account_id=? AND coin=?"); + if ($stmt && $stmt->bind_param('is', $account_id, $this->currency) && $stmt->execute() && $stmt->bind_result($coinAddress) && $stmt->fetch()) + return $coinAddress; + return false; + } + + /** + * Insert or update coin address + * @param account_id int Account ID + * @param coin_address string Coin Address + * @return bool insert or update success + **/ + public function insertOrUpdateCoinAddress($account_id, $coin_address, $threshold) { + $this->debug->append("STA " . __METHOD__, 4); + + if ($old_address = $this->getCoinAddress($account_id)) { + return $this->updateCoinAddress($account_id, $old_address, $coin_address, $threshold); + } else { + return $this->insertCoinAddress($account_id, $coin_address, $threshold); + } + } + + /** + * update coin address + * @param account_id int Account ID + * @param old_address string Address to update + * @param coin_address string Coin Address + * @return bool update success + **/ + public function updateCoinAddress($account_id, $old_address, $coin_address, $threshold) { + $this->debug->append("STA " . __METHOD__, 4); + $str = "UPDATE $this->table SET address = ?, ap_threshold = ? WHERE address = ? AND account_id = ?"; + $stmt = $this->mysqli->prepare($str); + + return $this->checkStmt($stmt) && $stmt->bind_param('sdsd', $coin_address, $threshold, $old_address, $account_id) && $stmt->execute(); + } + + /** + * insert coin address + * @param account_id int Account ID + * @param coin_address string Coin Address + * @return bool insert success + **/ + public function insertCoinAddress($account_id, $coin_address, $threshold) { + $this->debug->append("STA " . __METHOD__, 4); + $this->debug->append("Currency in coinaddress is: ". $this->currency); + $str = "INSERT INTO $this->table (address, coin, account_id, ap_threshold) VALUES (?,?,?,?)"; + $stmt = $this->mysqli->prepare($str); + + return $this->checkStmt($stmt) && $stmt->bind_param('ssid', $coin_address, $this->currency, $account_id, $threshold) && $stmt->execute(); + } +} + +$coinAddress = new CoinAddress(); +$coinAddress->setDebug($debug); +$coinAddress->setMysql($mysqli); +$coinAddress->setErrorCodes($aErrorCodes); +$coinAddress->setCurrency($currency); +?> diff --git a/public/include/classes/coins/coin_base.class.php b/include/classes/coins/coin_base.class.php similarity index 80% rename from public/include/classes/coins/coin_base.class.php rename to include/classes/coins/coin_base.class.php index 7eeb3ee12..ab84c311a 100644 --- a/public/include/classes/coins/coin_base.class.php +++ b/include/classes/coins/coin_base.class.php @@ -12,6 +12,12 @@ class CoinBase extends Base { // Our coins target bits protected $target_bits = NULL; + // Our coins share difficulty precision + protected $share_difficulty_precision = 0; + + // Our coin value precision, mostly used on frontend + protected $coin_value_precision = 8; + /** * Read our target bits **/ @@ -19,6 +25,20 @@ public function getTargetBits() { return $this->target_bits; } + /** + * Read our coin value precision + **/ + public function getCoinValuePrevision() { + return $this->coin_value_precision; + } + + /** + * Read our share difficulty precision + **/ + public function getShareDifficultyPrecision() { + return $this->share_difficulty_precision; + } + /** * Calculate the PPS value for this coin * WARNING: Get this wrong and you will over- or underpay your miners! diff --git a/public/include/classes/coins/coin_scrypt.class.php b/include/classes/coins/coin_scrypt.class.php similarity index 100% rename from public/include/classes/coins/coin_scrypt.class.php rename to include/classes/coins/coin_scrypt.class.php diff --git a/include/classes/coins/coin_scryptn.class.php b/include/classes/coins/coin_scryptn.class.php new file mode 100644 index 000000000..db588f61b --- /dev/null +++ b/include/classes/coins/coin_scryptn.class.php @@ -0,0 +1,16 @@ + diff --git a/public/include/classes/coins/coin_sha256d.class.php b/include/classes/coins/coin_sha256d.class.php similarity index 86% rename from public/include/classes/coins/coin_sha256d.class.php rename to include/classes/coins/coin_sha256d.class.php index 1147770ef..2b8302636 100644 --- a/public/include/classes/coins/coin_sha256d.class.php +++ b/include/classes/coins/coin_sha256d.class.php @@ -8,6 +8,7 @@ **/ class Coin extends CoinBase { protected $target_bits = 32; + protected $coin_value_precision = 20; } ?> diff --git a/include/classes/coins/coin_x11.class.php b/include/classes/coins/coin_x11.class.php new file mode 100644 index 000000000..60c14f630 --- /dev/null +++ b/include/classes/coins/coin_x11.class.php @@ -0,0 +1,14 @@ + diff --git a/public/include/classes/csrftoken.class.php b/include/classes/csrftoken.class.php similarity index 97% rename from public/include/classes/csrftoken.class.php rename to include/classes/csrftoken.class.php index 13e20955f..4a3c8269f 100644 --- a/public/include/classes/csrftoken.class.php +++ b/include/classes/csrftoken.class.php @@ -82,7 +82,7 @@ public static function getErrorWithDescriptionHTML($tokentype="", $dowhat="try") * @return string HTML image with description */ public static function getDescriptionImageHTML($dowhat="try") { - $string = "setToken($oToken); $csrftoken->setConfig($config); $csrftoken->setErrorCodes($aErrorCodes); -?> \ No newline at end of file +?> diff --git a/public/include/classes/debug.class.php b/include/classes/debug.class.php similarity index 100% rename from public/include/classes/debug.class.php rename to include/classes/debug.class.php diff --git a/public/include/classes/invitation.class.php b/include/classes/invitation.class.php similarity index 100% rename from public/include/classes/invitation.class.php rename to include/classes/invitation.class.php diff --git a/public/include/classes/logger.class.php b/include/classes/logger.class.php similarity index 97% rename from public/include/classes/logger.class.php rename to include/classes/logger.class.php index eb7b30e59..0283798db 100644 --- a/public/include/classes/logger.class.php +++ b/include/classes/logger.class.php @@ -5,7 +5,7 @@ class Logger { private $logging = false; public function __construct($config) { if ($config['logging']['enabled'] && $config['logging']['level'] > 0) { - $this->KLogger = KLogger::instance($config['logging']['path'], $config['logging']['level']); + $this->KLogger = KLogger::instance($config['logging']['path'] . '/website', $config['logging']['level']); $this->logging = true; $this->floatStartTime = microtime(true); } diff --git a/public/include/classes/mail.class.php b/include/classes/mail.class.php similarity index 84% rename from public/include/classes/mail.class.php rename to include/classes/mail.class.php index 3a26b0899..a60359bd0 100644 --- a/public/include/classes/mail.class.php +++ b/include/classes/mail.class.php @@ -58,10 +58,10 @@ public function sendMail($template, $aData, $throttle=false) { if ($transport_type == 'sendmail') { $transport = Swift_SendmailTransport::newInstance($this->config['swiftmailer'][$transport_type]['path'] . ' ' . $this->config['swiftmailer'][$transport_type]['options']); } else if ($this->config['swiftmailer']['type'] == 'smtp') { - $transport = Swift_SmtpTransport::newInstance($this->config['switfmailer']['smtp']['host'], $this->config['switfmailer']['smtp']['port'], $this->config['switfmailer']['smtp']['encryption']); - if (!empty($this->config['switfmailer']['smtp']['username']) && !empty($this->config['switfmailer']['smtp']['password'])) { - $transport->setUsername($this->config['switfmailer']['smtp']['username']); - $transport->setPassword($this->config['switfmailer']['smtp']['password']); + $transport = Swift_SmtpTransport::newInstance($this->config['swiftmailer']['smtp']['host'], $this->config['swiftmailer']['smtp']['port'], $this->config['swiftmailer']['smtp']['encryption']); + if (!empty($this->config['swiftmailer']['smtp']['username']) && !empty($this->config['swiftmailer']['smtp']['password'])) { + $transport->setUsername($this->config['swiftmailer']['smtp']['username']); + $transport->setPassword($this->config['swiftmailer']['smtp']['password']); } } $mailer = Swift_Mailer::newInstance($transport); @@ -69,13 +69,13 @@ public function sendMail($template, $aData, $throttle=false) { // Throttle mails to x per minute, used for newsletter for example if ($this->config['swiftmailer']['type'] == 'smtp' && $throttle) { $mailer->registerPlugin(new Swift_Plugins_ThrottlerPlugin( - $this->config['switfmailer']['smtp']['throttle'], Swift_Plugins_ThrottlerPlugin::MESSAGES_PER_MINUTE + $this->config['swiftmailer']['smtp']['throttle'], Swift_Plugins_ThrottlerPlugin::MESSAGES_PER_MINUTE )); } // Prepare the smarty templates used - $this->smarty->clearCache(BASEPATH . 'templates/mail/' . $template . '.tpl'); - $this->smarty->clearCache(BASEPATH . 'templates/mail/subject.tpl'); + $this->smarty->clearCache(TEMPLATE_DIR . '/mail/' . $template . '.tpl'); + $this->smarty->clearCache(TEMPLATE_DIR . '/mail/subject.tpl'); $this->smarty->assign('WEBSITENAME', $this->setting->getValue('website_name')); $this->smarty->assign('SUBJECT', $aData['subject']); $this->smarty->assign('DATA', $aData); @@ -84,12 +84,12 @@ public function sendMail($template, $aData, $throttle=false) { $senderEmail = $this->setting->getValue('website_email', 'test@example.com'); $senderName = $this->setting->getValue('website_name', 'test@example.com'); $message = Swift_Message::newInstance() - ->setSubject($this->smarty->fetch(BASEPATH . 'templates/mail/subject.tpl')) + ->setSubject($this->smarty->fetch(TEMPLATE_DIR . '/mail/subject.tpl')) ->setFrom(array( $senderEmail => $senderName)) ->setTo($aData['email']) ->setSender($senderEmail) ->setReturnPath($senderEmail) - ->setBody($this->smarty->fetch(BASEPATH . 'templates/mail/' . $template . '.tpl'), 'text/html'); + ->setBody($this->smarty->fetch(TEMPLATE_DIR . '/mail/' . $template . '.tpl'), 'text/html'); if (isset($aData['senderName']) && isset($aData['senderEmail']) && strlen($aData['senderName']) > 0 && diff --git a/public/include/classes/memcache_ad.class.php b/include/classes/memcache_ad.class.php similarity index 100% rename from public/include/classes/memcache_ad.class.php rename to include/classes/memcache_ad.class.php diff --git a/public/include/classes/memcached.class.php b/include/classes/memcached.class.php similarity index 100% rename from public/include/classes/memcached.class.php rename to include/classes/memcached.class.php diff --git a/public/include/classes/monitoring.class.php b/include/classes/monitoring.class.php similarity index 100% rename from public/include/classes/monitoring.class.php rename to include/classes/monitoring.class.php diff --git a/public/include/classes/news.class.php b/include/classes/news.class.php similarity index 98% rename from public/include/classes/news.class.php rename to include/classes/news.class.php index bccc6cab0..b4de57e24 100644 --- a/public/include/classes/news.class.php +++ b/include/classes/news.class.php @@ -88,6 +88,7 @@ public function addNews($account_id, $aData, $active=false) { if (empty($aData['header'])) return false; if (empty($aData['content'])) return false; if (!is_int($account_id)) return false; + if (@$aData['active']) $active = true; $stmt = $this->mysqli->prepare("INSERT INTO $this->table (account_id, header, content, active) VALUES (?,?,?,?)"); if ($stmt && $stmt->bind_param('issi', $account_id, $aData['header'], $aData['content'], $active) && $stmt->execute()) return true; diff --git a/public/include/classes/notification.class.php b/include/classes/notification.class.php similarity index 100% rename from public/include/classes/notification.class.php rename to include/classes/notification.class.php diff --git a/public/include/classes/payout.class.php b/include/classes/payout.class.php similarity index 100% rename from public/include/classes/payout.class.php rename to include/classes/payout.class.php diff --git a/public/include/classes/roundstats.class.php b/include/classes/roundstats.class.php similarity index 100% rename from public/include/classes/roundstats.class.php rename to include/classes/roundstats.class.php diff --git a/public/include/classes/setting.class.php b/include/classes/setting.class.php similarity index 100% rename from public/include/classes/setting.class.php rename to include/classes/setting.class.php diff --git a/public/include/classes/share.class.php b/include/classes/share.class.php similarity index 99% rename from public/include/classes/share.class.php rename to include/classes/share.class.php index b93235b3e..eb99ff500 100644 --- a/public/include/classes/share.class.php +++ b/include/classes/share.class.php @@ -130,8 +130,8 @@ function getMaxArchiveShareId() { * return array data Returns an array with usernames as keys for easy access **/ function getArchiveShares($iCount) { - $iMinId = $this->getMinArchiveShareId($iCount); $iMaxId = $this->getMaxArchiveShareId(); + $iMinId = $this->getMinArchiveShareId($iCount); $stmt = $this->mysqli->prepare(" SELECT a.id, @@ -147,7 +147,7 @@ function getArchiveShares($iCount) { if ($this->checkStmt($stmt) && $stmt->bind_param("ii", $iMinId, $iMaxId) && $stmt->execute() && $result = $stmt->get_result()) { $aData = NULL; while ($row = $result->fetch_assoc()) { - $aData[$row['account']] = $row; + $aData[strtolower($row['account'])] = $row; } if (is_array($aData)) return $aData; } diff --git a/public/include/classes/statistics.class.php b/include/classes/statistics.class.php similarity index 85% rename from public/include/classes/statistics.class.php rename to include/classes/statistics.class.php index 22f45c239..4a9c36f3e 100644 --- a/public/include/classes/statistics.class.php +++ b/include/classes/statistics.class.php @@ -9,6 +9,7 @@ **/ class Statistics extends Base { protected $table = 'statistics_shares'; + protected $table_user_stats = 'statistics_users'; private $getcache = true; // Disable fetching values from cache @@ -18,6 +19,12 @@ public function setGetCache($set=false) { public function getGetCache() { return $this->getcache; } + public function getAllUserMiningStats() { + return $this->allUserMiningStats; + } + public function getUserStatsTableName() { + return $this->table_user_stats; + } /** * Get our first block found @@ -45,37 +52,37 @@ function getLastBlocksbyTime() { IFNULL(SUM(IF(confirmations > 0, 1, 0)), 0) AS TotalValid, IFNULL(SUM(IF(confirmations = -1, 1, 0)), 0) AS TotalOrphan, IFNULL(SUM(IF(confirmations > 0, difficulty, 0)), 0) AS TotalDifficulty, - IFNULL(ROUND(SUM(IF(confirmations > -1, shares, 0))), 0) AS TotalShares, + IFNULL(SUM(IF(confirmations > -1, shares, 0)), 0) AS TotalShares, IFNULL(SUM(IF(confirmations > -1, amount, 0)), 0) AS TotalAmount, IFNULL(SUM(IF(FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 3600 SECOND), 1, 0)), 0) AS 1HourTotal, IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 3600 SECOND), 1, 0)), 0) AS 1HourValid, IFNULL(SUM(IF(confirmations = -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 3600 SECOND), 1, 0)), 0) AS 1HourOrphan, IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 3600 SECOND), difficulty, 0)), 0) AS 1HourDifficulty, - IFNULL(ROUND(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 3600 SECOND), shares, 0))), 0) AS 1HourShares, + IFNULL(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 3600 SECOND), shares, 0)), 0) AS 1HourShares, IFNULL(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 3600 SECOND), amount, 0)), 0) AS 1HourAmount, IFNULL(SUM(IF(FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 86400 SECOND), 1, 0)), 0) AS 24HourTotal, IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 86400 SECOND), 1, 0)), 0) AS 24HourValid, IFNULL(SUM(IF(confirmations = -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 86400 SECOND), 1, 0)), 0) AS 24HourOrphan, IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 86400 SECOND), difficulty, 0)), 0) AS 24HourDifficulty, - IFNULL(ROUND(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 86400 SECOND), shares, 0))), 0) AS 24HourShares, + IFNULL(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 86400 SECOND), shares, 0)), 0) AS 24HourShares, IFNULL(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 86400 SECOND), amount, 0)), 0) AS 24HourAmount, IFNULL(SUM(IF(FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 604800 SECOND), 1, 0)), 0) AS 7DaysTotal, IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 604800 SECOND), 1, 0)), 0) AS 7DaysValid, IFNULL(SUM(IF(confirmations = -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 604800 SECOND), 1, 0)), 0) AS 7DaysOrphan, IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 604800 SECOND), difficulty, 0)), 0) AS 7DaysDifficulty, - IFNULL(ROUND(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 604800 SECOND), shares, 0))), 0) AS 7DaysShares, + IFNULL(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 604800 SECOND), shares, 0)), 0) AS 7DaysShares, IFNULL(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 604800 SECOND), amount, 0)), 0) AS 7DaysAmount, IFNULL(SUM(IF(FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 2419200 SECOND), 1, 0)), 0) AS 4WeeksTotal, IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 2419200 SECOND), 1, 0)), 0) AS 4WeeksValid, IFNULL(SUM(IF(confirmations = -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 2419200 SECOND), 1, 0)), 0) AS 4WeeksOrphan, IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 2419200 SECOND), difficulty, 0)), 0) AS 4WeeksDifficulty, - IFNULL(ROUND(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 2419200 SECOND), shares, 0))), 0) AS 4WeeksShares, + IFNULL(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 2419200 SECOND), shares, 0)), 0) AS 4WeeksShares, IFNULL(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 2419200 SECOND), amount, 0)), 0) AS 4WeeksAmount, IFNULL(SUM(IF(FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 29030400 SECOND), 1, 0)), 0) AS 12MonthTotal, IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 29030400 SECOND), 1, 0)), 0) AS 12MonthValid, IFNULL(SUM(IF(confirmations = -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 29030400 SECOND), 1, 0)), 0) AS 12MonthOrphan, IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 29030400 SECOND), difficulty, 0)), 0) AS 12MonthDifficulty, - IFNULL(ROUND(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 29030400 SECOND), shares, 0))), 0) AS 12MonthShares, + IFNULL(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 29030400 SECOND), shares, 0)), 0) AS 12MonthShares, IFNULL(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 29030400 SECOND), amount, 0)), 0) AS 12MonthAmount FROM " . $this->block->getTableName()); if ($this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result()) { @@ -127,7 +134,7 @@ public function getBlocksFoundHeight($iHeight=0, $limit=10) { b.*, a.username AS finder, a.is_anonymous AS is_anonymous, - ROUND(difficulty * POW(2, 32 - " . $this->coin->getTargetBits() . "), 0) AS estshares + ROUND(difficulty * POW(2, 32 - " . $this->coin->getTargetBits() . "), 4) AS estshares FROM " . $this->block->getTableName() . " AS b LEFT JOIN " . $this->user->getTableName() . " AS a ON b.account_id = a.id @@ -163,7 +170,7 @@ public function getBlocksSolvedbyAccount($limit=25) { return $this->memcache->setCache(__FUNCTION__ . $limit, $result->fetch_all(MYSQLI_ASSOC), 5); return $this->sqlError(); } - + /** * Get SUM of blocks found and generated Coins for each worker * @param limit int Last limit blocks @@ -185,7 +192,7 @@ public function getBlocksSolvedbyWorker($account_id, $limit=25) { return $this->memcache->setCache(__FUNCTION__ . $account_id . $limit, $result->fetch_all(MYSQLI_ASSOC), 5); return $this->sqlError(); } - + /** * Currently the only function writing to the database * Stored per block user statistics of valid and invalid shares @@ -223,12 +230,12 @@ public function getCurrentHashrate($interval=180) { SELECT ( ( - SELECT IFNULL(ROUND(SUM(IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty))), 0) AS shares + SELECT IFNULL(SUM(IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty)), 0) AS shares FROM " . $this->share->getTableName() . " WHERE time > DATE_SUB(now(), INTERVAL ? SECOND) AND our_result = 'Y' ) + ( - SELECT IFNULL(ROUND(SUM(IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty))), 0) AS shares + SELECT IFNULL(SUM(IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty)), 0) AS shares FROM " . $this->share->getArchiveTableName() . " WHERE time > DATE_SUB(now(), INTERVAL ? SECOND) AND our_result = 'Y' @@ -254,12 +261,12 @@ public function getCurrentShareRate($interval=180) { SELECT ( ( - SELECT ROUND(COUNT(id) / ?, 2) AS sharerate + SELECT ROUND(SUM(difficulty) / ?, 2) AS sharerate FROM " . $this->share->getTableName() . " WHERE time > DATE_SUB(now(), INTERVAL ? SECOND) AND our_result = 'Y' ) + ( - SELECT ROUND(COUNT(id) / ?, 2) AS sharerate + SELECT ROUND(SUM(difficulty) / ?, 2) AS sharerate FROM " . $this->share->getArchiveTableName() . " WHERE time > DATE_SUB(now(), INTERVAL ? SECOND) AND our_result = 'Y' @@ -293,8 +300,8 @@ public function getRoundShares() { } $stmt = $this->mysqli->prepare(" SELECT - ROUND(IFNULL(SUM(IF(our_result='Y', IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty), 0)), 0), 0) AS valid, - ROUND(IFNULL(SUM(IF(our_result='N', IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty), 0)), 0), 0) AS invalid + IFNULL(SUM(IF(our_result='Y', IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty), 0)), 0) AS valid, + IFNULL(SUM(IF(our_result='N', IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty), 0)), 0) AS invalid FROM " . $this->share->getTableName() . " WHERE UNIX_TIMESTAMP(time) > IFNULL((SELECT MAX(time) FROM " . $this->block->getTableName() . "), 0)"); if ( $this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result() ) @@ -316,8 +323,8 @@ public function getAllUserShares() { } $stmt = $this->mysqli->prepare(" SELECT - ROUND(IFNULL(SUM(IF(our_result='Y', IF(s.difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty), 0)), 0), 0) AS valid, - ROUND(IFNULL(SUM(IF(our_result='N', IF(s.difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty), 0)), 0), 0) AS invalid, + IFNULL(SUM(IF(our_result='Y', IF(s.difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty), 0)), 0) AS valid, + IFNULL(SUM(IF(our_result='N', IF(s.difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty), 0)), 0) AS invalid, u.id AS id, u.donate_percent AS donate_percent, u.is_anonymous AS is_anonymous, @@ -368,11 +375,11 @@ public function getUserShares($username, $account_id=NULL) { if ($data = $this->memcache->get(__FUNCTION__ . $account_id)) return $data; $stmt = $this->mysqli->prepare(" SELECT - ROUND(IFNULL(SUM(IF(our_result='Y', IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty), 0)), 0), 0) AS valid, - ROUND(IFNULL(SUM(IF(our_result='N', IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty), 0)), 0), 0) AS invalid + IFNULL(SUM(IF(our_result='Y', IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty), 0)), 0) AS valid, + IFNULL(SUM(IF(our_result='N', IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty), 0)), 0) AS invalid FROM " . $this->share->getTableName() . " WHERE username LIKE ? - AND UNIX_TIMESTAMP(time) >IFNULL((SELECT MAX(b.time) FROM " . $this->block->getTableName() . " AS b),0)"); + AND UNIX_TIMESTAMP(time) >IFNULL((SELECT MAX(b.time) FROM " . $this->block->getTableName() . " AS b),0)"); $username = $username . ".%"; if ($stmt && $stmt->bind_param("s", $username) && $stmt->execute() && $result = $stmt->get_result()) return $this->memcache->setCache(__FUNCTION__ . $account_id, $result->fetch_assoc()); @@ -451,16 +458,19 @@ public function getAllUserStats($filter='%',$limit=1,$start=0) { /** * Fetch all user hashrates based on shares and archived shares + * Store it in cache, also keep a copy of the data internally to + * return it for further processing * @return data array Set of all user stats **/ - public function getAllUserMiningStats($interval=180) { + public function fetchAllUserMiningStats($interval=180) { $this->debug->append("STA " . __METHOD__, 4); $stmt = $this->mysqli->prepare(" SELECT a.id AS id, a.username AS account, + COUNT(DISTINCT t1.username) AS workers, IFNULL(SUM(t1.difficulty), 0) AS shares, - ROUND(COUNT(t1.id) / ?, 2) AS sharerate, + ROUND(SUM(t1.difficulty) / ?, 2) AS sharerate, IFNULL(AVG(IF(difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), difficulty)), 0) AS avgsharediff FROM ( SELECT @@ -489,18 +499,51 @@ public function getAllUserMiningStats($interval=180) { $aData['data'][$row['id']] = $row; $aData['data'][$row['id']]['hashrate'] = $this->coin->calcHashrate($row['shares'], $interval); } + $this->allUserMiningStats = $aData; return $this->memcache->setStaticCache(STATISTICS_ALL_USER_HASHRATES, $aData, 600); } else { return $this->sqlError(); } } + /** + * Store our gathered data into our statistic table for users + * @param aData array Data created by fetchAllUserMiningStats + * @return bool true or false + **/ + public function storeAllUserMiningStatsSnapshot($aData) { + $this->debug->append("STA " . __METHOD__, 4); + if (!isset($aData['data'])) return false; + // initilize + $timestamp = time(); // Store all entries with the same timestamp to reduce cardinality + $ok = 0; + $failed = 0; + foreach ($aData['data'] as $key => $aUserData) { + $stmt = $this->mysqli->prepare(" + INSERT INTO " . $this->getUserStatsTableName() . " + ( account_id, hashrate, workers, sharerate, timestamp ) VALUES ( ?, ?, ?, ?, ?)"); + if ($this->checkStmt($stmt) && $stmt->bind_param("ididi", $aUserData['id'], $aUserData['hashrate'], $aUserData['workers'], $aUserData['sharerate'], $timestamp) && $stmt->execute() ) { + $ok++; + } else { + $failed++; + } + } + return array('ok' => $ok, 'failed' => $failed); + } + + /** + * Fetch unpaid PPS shares for an account + * @param username string Username + * @param account_id int User ID + * @param last_paid_pps_id int Last paid out share by pps_payout cron + * @return data int Sum of unpaid diff1 shares + **/ public function getUserUnpaidPPSShares($username, $account_id=NULL, $last_paid_pps_id) { $this->debug->append("STA " . __METHOD__, 4); if ($this->getGetCache() && $data = $this->memcache->get(__FUNCTION__ . $account_id)) return $data; $stmt = $this->mysqli->prepare(" SELECT - ROUND(IFNULL(SUM(IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty)), 0), 0) AS total + IFNULL(SUM(IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty)), 0) AS total FROM " . $this->share->getTableName() . " WHERE username LIKE ? AND id > ? @@ -515,7 +558,7 @@ public function getUserUnpaidPPSShares($username, $account_id=NULL, $last_paid_p * Get Shares per x interval by user * @param username string username * @param $account_id int account id - * @return data integer Current Sharerate in shares/s + * @return data integer Current Sharerate in diff1 shares/s **/ public function getUserMiningStats($username, $account_id=NULL, $interval=180) { $this->debug->append("STA " . __METHOD__, 4); @@ -532,7 +575,7 @@ public function getUserMiningStats($username, $account_id=NULL, $interval=180) { if ($this->getGetCache() && $data = $this->memcache->get(__FUNCTION__ . $account_id)) return $data; $stmt = $this->mysqli->prepare(" SELECT - IFNULL(COUNT(*) / ?, 0) AS sharerate, + IFNULL(SUM(difficulty) / ?, 0) AS sharerate, IFNULL(SUM(difficulty), 0) AS shares, IFNULL(AVG(difficulty), 0) AS avgsharediff FROM ( @@ -603,7 +646,7 @@ public function getTopContributors($type='shares', $limit=15) { a.username AS account, a.donate_percent AS donate_percent, a.is_anonymous AS is_anonymous, - ROUND(IFNULL(SUM(IF(s.difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty)), 0), 0) AS shares + IFNULL(SUM(IF(s.difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty)), 0) AS shares FROM " . $this->share->getTableName() . " AS s LEFT JOIN " . $this->user->getTableName() . " AS a ON SUBSTRING_INDEX( s.username, '.', 1 ) = a.username @@ -655,78 +698,24 @@ public function getTopContributors($type='shares', $limit=15) { * @param $account_id int account id * @return data array NOT FINISHED YET **/ - public function getHourlyHashrateByAccount($username, $account_id=NULL) { + public function getHourlyMiningStatsByAccount($account_id, $format='array', $days = 1) { $this->debug->append("STA " . __METHOD__, 4); if ($data = $this->memcache->get(__FUNCTION__ . $account_id)) return $data; $stmt = $this->mysqli->prepare(" SELECT - id, - IFNULL(SUM(IF(difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), difficulty)), 0) AS shares, - HOUR(time) AS hour - FROM " . $this->share->getTableName() . " - WHERE time <= FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(NOW())/(60*60))*(60*60)) - AND time >= FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(NOW())/(60*60))*(60*60)) - INTERVAL 24 HOUR - AND our_result = 'Y' - AND username LIKE ? - GROUP BY HOUR(time) - UNION - SELECT - share_id, - IFNULL(SUM(IF(difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), difficulty)), 0) AS shares, - HOUR(time) AS hour - FROM " . $this->share->getArchiveTableName() . " - WHERE time <= FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(NOW())/(60*60))*(60*60)) - AND time >= FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(NOW())/(60*60))*(60*60)) - INTERVAL 24 HOUR - AND our_result = 'Y' - AND username LIKE ? - GROUP BY HOUR(time)"); - $username = $username . ".%"; - if ($this->checkStmt($stmt) && $stmt->bind_param('ss', $username, $username) && $stmt->execute() && $result = $stmt->get_result()) { - $iStartHour = date('G'); - // Initilize array - for ($i = 0; $i < 24; $i++) $aData[($iStartHour + $i) % 24] = 0; - // Fill data - while ($row = $result->fetch_assoc()) $aData[$row['hour']] += (int) $this->coin->calcHashrate($row['shares'], 3600); - return $this->memcache->setCache(__FUNCTION__ . $account_id, $aData); - } - return $this->sqlError(); - } - - /** - * get Hourly hashrate for the pool - * @param none - * @return data array NOT FINISHED YET - **/ - public function getHourlyHashrateByPool() { - $this->debug->append("STA " . __METHOD__, 4); - if ($this->getGetCache() && $data = $this->memcache->get(__FUNCTION__)) return $data; - $stmt = $this->mysqli->prepare(" - SELECT - id, - IFNULL(SUM(IF(s.difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty)), 0) AS shares, - HOUR(s.time) AS hour - FROM " . $this->share->getTableName() . " AS s - WHERE time <= FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(NOW())/(60*60))*(60*60)) - AND time >= FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(NOW())/(60*60))*(60*60)) - INTERVAL 24 HOUR - AND our_result = 'Y' - GROUP BY HOUR(time) - UNION - SELECT - share_id, - IFNULL(SUM(IF(s.difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty)), 0) AS shares, - HOUR(s.time) AS hour - FROM " . $this->share->getArchiveTableName() . " AS s - WHERE time <= FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(NOW())/(60*60))*(60*60)) - AND time >= FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(NOW())/(60*60))*(60*60)) - INTERVAL 24 HOUR - AND our_result = 'Y' - GROUP BY HOUR(time)"); - if ($this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result()) { - $iStartHour = date('G'); - // Initilize array - for ($i = 0; $i < 24; $i++) $aData[($iStartHour + $i) % 24] = 0; - // Fill data - while ($row = $result->fetch_assoc()) $aData[$row['hour']] += (int) $this->coin->calcHashrate($row['shares'], 3600); - return $this->memcache->setCache(__FUNCTION__, $aData); + timestamp, + FROM_UNIXTIME(timestamp, '%Y-%m-%d %H:%i') AS time, + AVG(hashrate) AS hashrate, + AVG(workers) AS workers, + AVG(sharerate) AS sharerate + FROM " . $this->getUserStatsTableName() . " + WHERE FROM_UNIXTIME(timestamp) >= DATE_SUB(NOW(), INTERVAL $days DAY) + AND account_id = ? + GROUP BY DAY(FROM_UNIXTIME(timestamp)), HOUR(FROM_UNIXTIME(timestamp))"); + if ($this->checkStmt($stmt) && $stmt->bind_param('i', $account_id) && $stmt->execute() && $result = $stmt->get_result()) { + $aData = $result->fetch_all(MYSQLI_ASSOC); + if ($format == 'json') $aData = json_encode($aData); + return $this->memcache->setCache(__FUNCTION__ . $account_id . $format, $aData); } return $this->sqlError(); } @@ -744,7 +733,7 @@ public function getUserEstimates($value1, $value2, $dDonate, $bNoFees, $ppsvalue if ($this->config['payout_system'] != 'pps') { if (@$value1['valid'] > 0 && @$value2['valid'] > 0) { $this->config['reward_type'] == 'fixed' ? $reward = $this->config['reward'] : $reward = $this->block->getAverageAmount(); - $aEstimates['block'] = round(( (int)$value2['valid'] / (int)$value1['valid'] ) * (float)$reward, 8); + $aEstimates['block'] = round(( (float)$value2['valid'] / (float)$value1['valid'] ) * (float)$reward, 8); $bNoFees == 0 ? $aEstimates['fee'] = round(((float)$this->config['fees'] / 100) * (float)$aEstimates['block'], 8) : $aEstimates['fee'] = 0; $aEstimates['donation'] = round((( (float)$dDonate / 100) * ((float)$aEstimates['block'] - (float)$aEstimates['fee'])), 8); $aEstimates['payout'] = round((float)$aEstimates['block'] - (float)$aEstimates['donation'] - (float)$aEstimates['fee'], 8); @@ -789,7 +778,7 @@ public function getPoolStatsHours($hour=24) { SELECT IFNULL(COUNT(id), 0) as count, IFNULL(AVG(difficulty), 0) as average, - IFNULL(ROUND(SUM(shares)), 0) as shares, + IFNULL(SUM(shares), 0) as shares, IFNULL(SUM(amount), 0) as rewards FROM " . $this->block->getTableName() . " WHERE FROM_UNIXTIME(time) > DATE_SUB(now(), INTERVAL ? HOUR) @@ -815,21 +804,23 @@ public function getEstimatedShares($dDiff) { * Get the Expected Time per Block in the whole Network in seconde * @return seconds double Seconds per Block */ - public function getNetworkExpectedTimePerBlock(){ + public function getExpectedTimePerBlock($type='network',$hashrate = 0){ if ($data = $this->memcache->get(__FUNCTION__)) return $data; if ($this->bitcoin->can_connect() === true) { - $dNetworkHashrate = $this->bitcoin->getnetworkhashps(); + if ($type == 'network') { + $hashrate = $this->bitcoin->getnetworkhashps(); + } else { + // We need hashes/second and expect khash as input + $hashrate = $hashrate * 1000; + } $dDifficulty = $this->bitcoin->getdifficulty(); } else { - $dNetworkHashrate = 1; + $hashrate = 1; $dDifficulty = 1; } - if($dNetworkHashrate <= 0){ - return $this->memcache->setCache(__FUNCTION__, $this->config['cointarget']); - } - - return $this->memcache->setCache(__FUNCTION__, $this->coin->calcNetworkExpectedTimePerBlock($dDifficulty, $dNetworkHashrate)); + if ($hashrate <= 0) $hashrate = 1; + return $this->memcache->setCache(__FUNCTION__ . '_' . $type, $this->coin->calcNetworkExpectedTimePerBlock($dDifficulty, $hashrate)); } /** @@ -912,6 +903,17 @@ public function getCountAllActiveUsers($interval=120) { return $this->memcache->setCache(__FUNCTION__, $result->fetch_object()->total); return $this->sqlError(); } + + /** + * Purge older entries from our statistics_users table + **/ + public function purgeUserStats($days = 1) { + // Fallbacks if unset + $stmt = $this->mysqli->prepare("DELETE FROM " . $this->getUserStatsTableName() . " WHERE FROM_UNIXTIME(timestamp) <= DATE_SUB(NOW(), INTERVAL ? DAY)"); + if ($this->checkStmt($stmt) && $stmt->bind_param('i', $days) && $stmt->execute()) + return $stmt->affected_rows; + return $this->sqlError(); + } } $statistics = new Statistics(); diff --git a/public/include/classes/statscache.class.php b/include/classes/statscache.class.php similarity index 94% rename from public/include/classes/statscache.class.php rename to include/classes/statscache.class.php index c17d8a743..615ba5d17 100644 --- a/public/include/classes/statscache.class.php +++ b/include/classes/statscache.class.php @@ -19,6 +19,10 @@ public function __construct($config, $debug) { require_once(CLASS_DIR . '/memcached.class.php'); } $this->cache = new Memcached(); + if ($config['memcache']['sasl'] === true) { + $this->cache->setOption(Memcached::OPT_BINARY_PROTOCOL, true); + $this->cache->setSaslAuthData($config['memcache']['sasl']['username'], $config['memcache']['sasl']['password']); + } } } diff --git a/public/include/classes/strict.class.php b/include/classes/strict.class.php similarity index 100% rename from public/include/classes/strict.class.php rename to include/classes/strict.class.php diff --git a/public/include/classes/template.class.php b/include/classes/template.class.php similarity index 95% rename from public/include/classes/template.class.php rename to include/classes/template.class.php index fd0eea583..dac32fdde 100644 --- a/public/include/classes/template.class.php +++ b/include/classes/template.class.php @@ -17,13 +17,13 @@ public function getFullpath($name) { /** * Get all available themes - * Read theme folders from THEME_DIR + * Read theme folders from TEMPLATE_DIR * * @return array - list of available themes */ public function getThemes() { $this->debug->append("STA " . __METHOD__, 4); - $aTmpThemes = glob(THEME_DIR . '/*'); + $aTmpThemes = glob(TEMPLATE_DIR . '/*'); $aThemes = array(); foreach ($aTmpThemes as $dir) { if (basename($dir) != 'cache' && basename($dir) != 'compile' && basename($dir) != 'mail') $aThemes[basename($dir)] = basename($dir); @@ -86,12 +86,12 @@ public function getActiveTemplates() { /** * Return the content of specific template file * - * @param $file - file of template related to THEME_DIR + * @param $file - file of template related to TEMPLATE_DIR * @return string - content of the template file */ public function getTemplateContent($file) { $this->debug->append("STA " . __METHOD__, 4); - $filepath = THEME_DIR . '/' . $file; + $filepath = TEMPLATE_DIR . '/' . $file; return file_get_contents($filepath); } @@ -103,7 +103,7 @@ public function getTemplateContent($file) { */ public function getTemplateFiles($theme) { $this->debug->append("STA " . __METHOD__, 4); - $folder = THEME_DIR . '/' . $theme; + $folder = TEMPLATE_DIR . '/' . $theme; $dir = new RecursiveDirectoryIterator($folder); $ite = new RecursiveIteratorIterator($dir); @@ -130,7 +130,7 @@ public function getTemplatesTree($themes = null) { $templates = array(); foreach($themes as $theme) { - $templates[$theme] = $this->_getTemplatesTreeRecursive(THEME_DIR . '/' . $theme); + $templates[$theme] = $this->_getTemplatesTreeRecursive(TEMPLATE_DIR . '/' . $theme); } return $templates; diff --git a/public/include/classes/token.class.php b/include/classes/token.class.php similarity index 100% rename from public/include/classes/token.class.php rename to include/classes/token.class.php diff --git a/public/include/classes/tokentype.class.php b/include/classes/tokentype.class.php similarity index 100% rename from public/include/classes/tokentype.class.php rename to include/classes/tokentype.class.php diff --git a/public/include/classes/tools.class.php b/include/classes/tools.class.php similarity index 74% rename from public/include/classes/tools.class.php rename to include/classes/tools.class.php index 210e27e06..06b3626e0 100644 --- a/public/include/classes/tools.class.php +++ b/include/classes/tools.class.php @@ -7,6 +7,28 @@ * the scope of our web application **/ class Tools extends Base { + public function getOnlineVersions() { + // Fetch version online, cache for a bit + $key = $this->config['memcache']['keyprefix'] . 'ONLINE_VERSIONS'; + if (! $mpos_versions = $this->memcache->get($key)) { + $url = $this->config['version_url']; + $curl = curl_init(); + curl_setopt($curl, CURLOPT_URL, $url); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_HEADER, false); + $data = curl_exec($curl); + preg_match('/define\(\'MPOS_VERSION\', \'(.*)\'\);/', $data, $match); + $mpos_versions['MPOS_VERSION'] = @$match[1]; + preg_match('/define\(\'DB_VERSION\', \'(.*)\'\);/', $data, $match); + $mpos_versions['DB_VERSION'] = @$match[1]; + preg_match('/define\(\'CONFIG_VERSION\', \'(.*)\'\);/', $data, $match); + $mpos_versions['CONFIG_VERSION'] = @$match[1]; + curl_close($curl); + return $this->memcache->setCache($key, $mpos_versions, 30); + } else { + return $mpos_versions; + } + } /** * Fetch JSON data from an API * @param url string API URL @@ -59,6 +81,8 @@ private function getApiType($url) { return 'cryptorush'; } else if (preg_match('/mintpal.com/', $url)) { return 'mintpal'; + } else if (preg_match('/bittrex.com/', $url)) { + return 'bittrex'; } $this->setErrorMessage("API URL unknown"); return false; @@ -94,6 +118,9 @@ public function getPrice() { case 'mintpal': return @$aData['0']['last_price']; break; + case 'bittrex': + return @$aData['result']['Last']; + break; } } else { $this->setErrorMessage("Got an invalid response from ticker API"); @@ -108,3 +135,4 @@ public function getPrice() { $tools = new Tools(); $tools->setDebug($debug); $tools->setConfig($config); +$tools->setMemcache($memcache); diff --git a/public/include/classes/transaction.class.php b/include/classes/transaction.class.php similarity index 96% rename from public/include/classes/transaction.class.php rename to include/classes/transaction.class.php index 316007ef8..9db64e6c7 100644 --- a/public/include/classes/transaction.class.php +++ b/include/classes/transaction.class.php @@ -23,8 +23,9 @@ public function setCoinAddress($coinAddress) { * @param coin_address string Coin address for this transaction [optional] * @return bool **/ - public function addTransaction($account_id, $amount, $type='Credit', $block_id=NULL, $coin_address=NULL, $txid=NULL, $convertible=NULL, $database_name=NULL) { + public function addTransaction($account_id, $amount, $type='Credit', $block_id=NULL, $coin_address=NULL, $txid=NULL, $convertible=NULL, $database=NULL) { $where_to_insert = isset($database_name) ? "$database_name.$this->table" : $this->table; + $amount = number_format($amount, $this->coin->getCoinValuePrevision(), '.', ''); $stmt = $this->mysqli->prepare("INSERT INTO $where_to_insert (account_id, amount, block_id, type, coin_address, txid, convertible) VALUES (?, ?, ?, ?, ?, ?, ?)"); if ($this->checkStmt($stmt) && $stmt->bind_param("idissss", $account_id, $amount, $block_id, $type, $coin_address, $txid, $convertible) && $stmt->execute()) { $this->insert_id = $stmt->insert_id; @@ -62,9 +63,10 @@ public function setArchived($account_id, $txid) { WHERE t.archived = 0 AND ( ( t.account_id = ? AND t.id <= ? AND b.confirmations >= ? AND t.type != 'Convertible') + OR ( t.account_id = ? AND t.id <= ? AND b.confirmations = -1 AND t.type != 'Convertible') OR ( t.account_id = ? AND t.id <= ? AND t.type IN ( 'Credit_PPS', 'Donation_PPS', 'Fee_PPS', 'TXFee', 'Debit_MP', 'Debit_AP' ) ) )"); - if ($this->checkStmt($stmt) && $stmt->bind_param('iiiii', $account_id, $txid, $this->config['confirmations'], $account_id, $txid) && $stmt->execute()) + if ($this->checkStmt($stmt) && $stmt->bind_param('iiiiiii', $account_id, $txid, $this->config['confirmations'], $account_id, $txid, $account_id, $txid) && $stmt->execute()) return true; return $this->sqlError(); } @@ -322,11 +324,11 @@ public function getLockedBalance() { $this->debug->append("STA " . __METHOD__, 4); $stmt = $this->mysqli->prepare(" SELECT - ROUND(( + ( SUM( IF( ( t.type IN ('Credit','Bonus') AND b.confirmations >= ? ) OR t.type = 'Credit_PPS', t.amount, 0 ) ) - SUM( IF( t.type IN ('Debit_MP', 'Debit_AP'), t.amount, 0 ) ) - SUM( IF( ( t.type IN ('Donation','Fee') AND b.confirmations >= ? ) OR ( t.type IN ('Donation_PPS', 'Fee_PPS', 'TXFee') ), t.amount, 0 ) ) - ), 8) AS balance + ) AS balance FROM $this->table AS t LEFT JOIN " . $this->block->getTableName() . " AS b ON t.block_id = b.id @@ -345,24 +347,24 @@ public function getBalance($account_id) { $this->debug->append("STA " . __METHOD__, 4); $stmt = $this->mysqli->prepare(" SELECT - IFNULL(ROUND(( + IFNULL(( SUM( IF( ( t.type IN ('Credit','Bonus') AND b.confirmations >= ? ) OR t.type = 'Credit_PPS', t.amount, 0 ) ) - SUM( IF( t.type IN ('Debit_MP', 'Debit_AP'), t.amount, 0 ) ) - SUM( IF( ( t.type IN ('Donation','Fee') AND b.confirmations >= ? ) OR ( t.type IN ('Donation_PPS', 'Fee_PPS', 'TXFee') ), t.amount, 0 ) ) - ), 8), 0) AS confirmed, + ), 0) AS confirmed, IFNULL(ROUND(( SUM( IF( ( t.type IN ('Convertible') AND b.confirmations >= ? ), t.amount, 0 ) ) - SUM( IF( t.type IN ('Convertible_Transfer'), t.amount, 0 ) ) - SUM( IF( ( t.type IN ('Donation','Fee') AND b.confirmations >= ? ) OR ( t.type IN ('Donation_PPS', 'Fee_PPS', 'TXFee') ), t.amount, 0 ) ) ), 8), 0) AS convertible, - IFNULL(ROUND(( + IFNULL(( SUM( IF( t.type IN ('Credit','Bonus') AND b.confirmations < ? AND b.confirmations >= 0, t.amount, 0 ) ) - SUM( IF( t.type IN ('Donation','Fee') AND b.confirmations < ? AND b.confirmations >= 0, t.amount, 0 ) ) - ), 8), 0) AS unconfirmed, - IFNULL(ROUND(( + ), 0) AS unconfirmed, + IFNULL(( SUM( IF( t.type IN ('Credit','Bonus') AND b.confirmations = -1, t.amount, 0) ) - SUM( IF( t.type IN ('Donation','Fee') AND b.confirmations = -1, t.amount, 0) ) - ), 8), 0) AS orphaned + ), 0) AS orphaned FROM $this->table AS t LEFT JOIN " . $this->block->getTableName() . " AS b ON t.block_id = b.id @@ -418,12 +420,10 @@ public function getAPQueue($limit=250) { c.ap_threshold as ap_threshold, c.address as coin_address, IFNULL( - ROUND( ( SUM( IF( ( t.type IN ('Credit','Bonus') AND b.confirmations >= " . $this->config['confirmations'] . ") OR t.type = 'Credit_PPS', t.amount, 0 ) ) - SUM( IF( t.type IN ('Debit_MP', 'Debit_AP'), t.amount, 0 ) ) - SUM( IF( ( t.type IN ('Donation','Fee') AND b.confirmations >= " . $this->config['confirmations'] . ") OR ( t.type IN ('Donation_PPS', 'Fee_PPS', 'TXFee') ), t.amount, 0 ) ) - ), 8 ), 0 ) AS confirmed FROM $this->table AS t @@ -431,13 +431,13 @@ public function getAPQueue($limit=250) { ON t.block_id = b.id LEFT JOIN " . $this->user->getTableName() . " AS a ON t.account_id = a.id - LEFT JOIN " . $this->coinAddress->getTableName() . " AS c + LEFT JOIN " . $this->coin_address->getTableName() . " AS c ON a.id = c.account_id AND '$this->currency' = c.coin WHERE t.archived = 0 AND c.ap_threshold > 0 AND c.address IS NOT NULL AND c.address != '' GROUP BY t.account_id HAVING confirmed > c.ap_threshold AND confirmed > " . $this->config['txfee_auto'] . " LIMIT ?"); - if ($this->checkStmt($stmt) && $stmt->bind_param('i', $limit) && $stmt->execute() && $result = $stmt->get_result()) + if ($this->checkStmt($stmt) && $stmt->bind_param('si', $this->config['currency'], $limit) && $stmt->execute() && $result = $stmt->get_result()) return $result->fetch_all(MYSQLI_ASSOC); return $this->sqlError(); } @@ -512,12 +512,10 @@ public function getMPQueue($limit=250) { c.address as coin_address, p.id AS payout_id, IFNULL( - ROUND( ( SUM( IF( ( t.type IN ('Credit','Bonus') AND b.confirmations >= " . $this->config['confirmations'] . ") OR t.type = 'Credit_PPS', t.amount, 0 ) ) - SUM( IF( t.type IN ('Debit_MP', 'Debit_AP'), t.amount, 0 ) ) - SUM( IF( ( t.type IN ('Donation','Fee') AND b.confirmations >= " . $this->config['confirmations'] . ") OR ( t.type IN ('Donation_PPS', 'Fee_PPS', 'TXFee') ), t.amount, 0 ) ) - ), 8 ), 0 ) AS confirmed FROM " . $this->payout->getTableName() . " AS p @@ -527,13 +525,13 @@ public function getMPQueue($limit=250) { ON t.account_id = p.account_id LEFT JOIN " . $this->block->getTableName() . " AS b ON t.block_id = b.id - LEFT JOIN " . $this->coinAddress->getTableName() . " AS c + LEFT JOIN " . $this->coin_address->getTableName() . " AS c ON a.id = c.account_id AND '$this->currency' = c.coin WHERE p.completed = 0 AND t.archived = 0 AND c.address IS NOT NULL AND c.address != '' GROUP BY t.account_id HAVING confirmed > " . $this->config['txfee_manual'] . " LIMIT ?"); - if ($this->checkStmt($stmt) && $stmt->bind_param('i', $limit) && $stmt->execute() && $result = $stmt->get_result()) + if ($this->checkStmt($stmt) && $stmt->bind_param('si', $this->config['currency'], $limit) && $stmt->execute() && $result = $stmt->get_result()) return $result->fetch_all(MYSQLI_ASSOC); return $this->sqlError('E0050'); } @@ -542,7 +540,9 @@ public function getMPQueue($limit=250) { $transaction = new Transaction(); $transaction->setMemcache($memcache); $transaction->setNotification($notification); +$transaction->setSetting($setting); $transaction->setDebug($debug); +$transaction->setCoin($coin); $transaction->setMysql($mysqli); $transaction->setConfig($config); $transaction->setBlock($block); diff --git a/public/include/classes/user.class.php b/include/classes/user.class.php similarity index 88% rename from public/include/classes/user.class.php rename to include/classes/user.class.php index 9335f8f53..2af661228 100644 --- a/public/include/classes/user.class.php +++ b/include/classes/user.class.php @@ -7,8 +7,15 @@ class User extends Base { private $user = array(); // get and set methods - private function getHash($string) { - return hash('sha256', $string.$this->salt); + private function getHash($string, $version=0, $pepper='') { + switch($version) { + case 0: + return hash('sha256', $string.$this->salt); + break; + case 1: + return '$' . $version . '$' . $pepper . '$' . hash('sha256', $string.$this->salt.$pepper); + break; + } } public function getUserName($id) { return $this->getSingle($id, 'username', 'id'); @@ -28,6 +35,12 @@ public function getUserEmail($username, $lower=false) { public function getUserEmailById($id) { return $this->getSingle($id, 'email', 'id', 'i'); } + public function getUserPasswordHashById($id) { + return $this->getSingle($id, 'pass', 'id', 'i'); + } + public function getUserPinHashById($id) { + return $this->getSingle($id, 'pin', 'id', 'i'); + } public function getUserNoFee($id) { return $this->getSingle($id, 'no_fees', 'id'); } @@ -263,11 +276,13 @@ public function checkLogin($username, $password) { * @param pin int PIN to check * @return bool **/ - public function checkPin($userId, $pin=false) { + public function checkPin($userId, $pin='') { $this->debug->append("STA " . __METHOD__, 4); $this->debug->append("Confirming PIN for $userId and pin $pin", 2); - $stmt = $this->mysqli->prepare("SELECT pin FROM $this->table WHERE id=? AND pin=? LIMIT 1"); - $pin_hash = $this->getHash($pin); + $strPinHash = $this->getUserPinHashById($userId); + $aPin = explode('$', $strPinHash); + count($aPin) == 1 ? $pin_hash = $this->getHash($pin, 0) : $pin_hash = $this->getHash($pin, $aPin[1], $aPin[2]); + $stmt = $this->mysqli->prepare("SELECT pin FROM $this->table WHERE id = ? AND pin = ? LIMIT 1"); if ($stmt->bind_param('is', $userId, $pin_hash) && $stmt->execute() && $stmt->bind_result($row_pin) && $stmt->fetch()) { $this->setUserPinFailed($userId, 0); return ($pin_hash === $row_pin); @@ -295,15 +310,17 @@ public function generatePin($userID, $current) { $this->debug->append("STA " . __METHOD__, 4); $username = $this->getUserName($userID); $email = $this->getUserEmail($username); - $current = $this->getHash($current); + $strPasswordHash = $this->getUserPasswordHashById($userID); + $aPassword = explode('$', $strPasswordHash); + count($aPassword) == 1 ? $password_hash = $this->getHash($current, 0) : $password_hash = $this->getHash($current, $aPassword[1], $aPassword[2]); $newpin = intval( '0' . rand(1,9) . rand(0,9) . rand(0,9) . rand(0,9) ); $aData['username'] = $username; $aData['email'] = $email; $aData['pin'] = $newpin; - $newpin = $this->getHash($newpin); + $newpin = $this->getHash($newpin, HASH_VERSION, bin2hex(openssl_random_pseudo_bytes(32))); $aData['subject'] = 'PIN Reset Request'; $stmt = $this->mysqli->prepare("UPDATE $this->table SET pin = ? WHERE ( id = ? AND pass = ? )"); - if ($this->checkStmt($stmt) && $stmt->bind_param('sis', $newpin, $userID, $current) && $stmt->execute()) { + if ($this->checkStmt($stmt) && $stmt->bind_param('sis', $newpin, $userID, $password_hash) && $stmt->execute()) { if ($stmt->errno == 0 && $stmt->affected_rows === 1) { if ($this->mail->sendMail('pin/reset', $aData)) { $this->log->log("info", "$username was sent a pin reset e-mail"); @@ -336,7 +353,7 @@ public function getAllAutoPayout() { WHERE c.ap_threshold > 0 AND c.address IS NOT NULL "); - if ( $this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result()) { + if ( $this->checkStmt($stmt) && $stmt->bind_param('s', $this->config['currency']) && $stmt->execute() && $result = $stmt->get_result()) { return $result->fetch_all(MYSQLI_ASSOC); } $this->debug->append("Unable to fetch users with AP set"); @@ -435,8 +452,10 @@ public function updatePassword($userID, $current, $new1, $new2, $strToken) { $this->setErrorMessage( 'New password is too short, please use more than 8 chars' ); return false; } - $current = $this->getHash($current); - $new = $this->getHash($new1); + $strPasswordHash = $this->getUserPasswordHashById($userID); + $aPassword = explode('$', $strPasswordHash); + count($aPassword) == 1 ? $password_hash = $this->getHash($current, 0) : $password_hash = $this->getHash($current, $aPassword[1], $aPassword[2]); + $new = $this->getHash($new1, HASH_VERSION, bin2hex(openssl_random_pseudo_bytes(32))); if ($this->config['twofactor']['enabled'] && $this->config['twofactor']['options']['changepw']) { $tValid = $this->token->isTokenValid($userID, $strToken, 6); if ($tValid) { @@ -456,7 +475,7 @@ public function updatePassword($userID, $current, $new1, $new2, $strToken) { } $stmt = $this->mysqli->prepare("UPDATE $this->table SET pass = ? WHERE ( id = ? AND pass = ? )"); if ($this->checkStmt($stmt)) { - $stmt->bind_param('sis', $new, $userID, $current); + $stmt->bind_param('sis', $new, $userID, $password_hash); $stmt->execute(); if ($stmt->errno == 0 && $stmt->affected_rows === 1) { $this->log->log("info", $this->getUserName($userID)." updated password"); @@ -478,7 +497,7 @@ public function updatePassword($userID, $current, $new1, $new2, $strToken) { * @param strToken string Token for confirmation * @return bool **/ - public function updateAccount($userID, $address, $threshold, $donate, $email, $is_anonymous, $strToken) { + public function updateAccount($userID, $address, $threshold, $donate, $email, $timezone, $is_anonymous, $strToken) { $this->debug->append("STA " . __METHOD__, 4); $bUser = false; $donate = round($donate, 2); @@ -503,12 +522,12 @@ public function updateAccount($userID, $address, $threshold, $donate, $email, $i $this->setErrorMessage('Donation above allowed 100% limit'); return false; } - if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { + if ($email != 'hidden' && $email != NULL && !filter_var($email, FILTER_VALIDATE_EMAIL)) { $this->setErrorMessage('Invalid email address'); return false; } if (!empty($address)) { - if ($address != $this->getCoinAddress($userID) && $this->existsCoinAddress($address)) { + if ($address != $this->coinAddress->getCoinAddress($userID) && $this->coinAddress->existsCoinAddress($address)) { $this->setErrorMessage('Address is already in use'); return false; } @@ -547,16 +566,20 @@ public function updateAccount($userID, $address, $threshold, $donate, $email, $i } } - if ($this->bitcoin->can_connect() === true && !empty($address)) { - if ($this->coinAddress->insertOrUpdateCoinAddress($userID, $address, $threshold)) { - $str = "UPDATE $this->table SET donate_percent = ?, email = ?, is_anonymous = ? WHERE id = ?"; - $stmt = $this->mysqli->prepare($str); - - if ($this->checkStmt($stmt) && $stmt->bind_param('dsii', $donate, $email, $is_anonymous, $userID) && $stmt->execute()) { - $this->log->log("info", $this->getUserName($userID)." updated their account details"); - return true; - } - } + // If we hide our email or it's not set, fetch current one to update + if ($email == 'hidden' || $email == NULL) + $email = $this->getUserEmailById($userID); + // We passed all validation checks so update the account + $stmt = $this->mysqli->prepare("UPDATE $this->table SET donate_percent = ?, email = ?, timezone = ?, is_anonymous = ? WHERE id = ?"); + if ($this->checkStmt($stmt) && $stmt->bind_param('dssii', $donate, $email, $timezone, $is_anonymous, $userID) && $stmt->execute()) { + $this->log->log("info", $this->getUserName($userID)." updated their account details"); + // Update coin address too + if ($address) { + if ($this->bitcoin->can_connect() === true && !empty($address)) { + if ($this->coinAddress->insertOrUpdateCoinAddress($userID, $address, $threshold)) { + return true; + } + } } // Catchall @@ -591,14 +614,15 @@ public function checkApiKey($key) { private function checkUserPassword($username, $password) { $this->debug->append("STA " . __METHOD__, 4); $user = array(); - $password_hash = $this->getHash($password); - $stmt = $this->mysqli->prepare("SELECT username, id, is_admin FROM $this->table WHERE LOWER(username) = LOWER(?) AND pass = ? LIMIT 1"); - if ($this->checkStmt($stmt) && $stmt->bind_param('ss', $username, $password_hash) && $stmt->execute() && $stmt->bind_result($row_username, $row_id, $row_admin)) { + $stmt = $this->mysqli->prepare("SELECT username, pass, id, timezone, is_admin FROM $this->table WHERE LOWER(username) = LOWER(?) LIMIT 1"); + if ($this->checkStmt($stmt) && $stmt->bind_param('s', $username) && $stmt->execute() && $stmt->bind_result($row_username, $row_password, $row_id, $row_timezone, $row_admin)) { $stmt->fetch(); $stmt->close(); + $aPassword = explode('$', $row_password); + count($aPassword) == 1 ? $password_hash = $this->getHash($password, 0) : $password_hash = $this->getHash($password, $aPassword[1], $aPassword[2]); // Store the basic login information - $this->user = array('username' => $row_username, 'id' => $row_id, 'is_admin' => $row_admin); - return strtolower($username) === strtolower($row_username); + $this->user = array('username' => $row_username, 'id' => $row_id, 'timezone' => $row_timezone, 'is_admin' => $row_admin); + return $password_hash === $row_password && strtolower($username) === strtolower($row_username); } return $this->sqlError(); } @@ -697,23 +721,18 @@ public function getUserData($userID) { $this->debug->append("Fetching user information for user id: $userID"); $stmt = $this->mysqli->prepare(" SELECT - a.id, a.username, a.pin, a.api_key, a.is_admin, a.is_anonymous, a.email, a.no_fees, + a.id , a.username, a.pin, a.api_key, a.is_admin, a.is_anonymous, a.email, a.timezone, a.no_fees, IFNULL(a.donate_percent, '0') as donate_percent, c.address as coin_address, c.ap_threshold as ap_threshold - FROM $this->table AS a + FROM " . $this->table . " AS a LEFT JOIN " . $this->coinAddress->table . " AS c ON c.account_id = a.id AND c.coin = ? WHERE a.id = ? LIMIT 0,1"); - if ($this->checkStmt($stmt)) { - $stmt->bind_param('si', $this->currency, $userID); - if (!$stmt->execute()) { - $this->debug->append('Failed to execute statement'); - return false; - } - $result = $stmt->get_result(); + if ($this->checkStmt($stmt) && $stmt->bind_param('si', $this->currency, $userID) && $stmt->execute() && $result = $stmt->get_result()) { + $aData = $result->fetch_assoc(); $stmt->close(); - return $result->fetch_assoc(); + return $aData; } $this->debug->append("Failed to fetch user information for $userID"); - return false; + return $this->sqlError(); } /** @@ -726,7 +745,7 @@ public function getUserData($userID) { * @param email2 string Email confirmation * @return bool **/ - public function register($username, $password1, $password2, $pin, $email1='', $email2='', $tac='', $strToken='') { + public function register($username, $coinaddress, $password1, $password2, $pin, $email1='', $email2='', $tac='', $strToken='') { $this->debug->append("STA " . __METHOD__, 4); if ($tac != 1) { $this->setErrorMessage('You need to accept our Terms and Conditions'); @@ -736,6 +755,16 @@ public function register($username, $password1, $password2, $pin, $email1='', $e $this->setErrorMessage('Username exceeding character limit'); return false; } + if (!is_null($coinaddress)) { + if ($this->coinAddress->existsCoinAddress($coinaddress)) { + $this->setErrorMessage('Coin address is already taken'); + return false; + } + if (!$this->bitcoin->validateaddress($coinaddress)) { + $this->setErrorMessage('Coin address is not valid'); + return false; + } + } if (preg_match('/[^a-z_\-0-9]/i', $username)) { $this->setErrorMessage('Username may only contain alphanumeric characters'); return false; @@ -803,13 +832,15 @@ public function register($username, $password1, $password2, $pin, $email1='', $e } // Create hashed strings using original string and salt - $password_hash = $this->getHash($password1); - $pin_hash = $this->getHash($pin); - $apikey_hash = $this->getHash($username); + $password_hash = $this->getHash($password1, HASH_VERSION, bin2hex(openssl_random_pseudo_bytes(32))); + $pin_hash = $this->getHash($pin, HASH_VERSION, bin2hex(openssl_random_pseudo_bytes(32))); + $apikey_hash = $this->getHash($username, 0); $username_clean = strip_tags($username); $signup_time = time(); if ($this->checkStmt($stmt) && $stmt->bind_param('sssissi', $username_clean, $password_hash, $email1, $signup_time, $pin_hash, $apikey_hash, $is_locked) && $stmt->execute()) { + $new_account_id = $this->mysqli->insert_id; + if (!is_null($coinaddress)) $this->coinAddress->add($new_account_id, $coinaddress); if (! $this->setting->getValue('accounts_confirm_email_disabled') && $is_admin != 1) { if ($token = $this->token->createToken('confirm_email', $stmt->insert_id)) { $aData['username'] = $username_clean; @@ -832,6 +863,7 @@ public function register($username, $password1, $password2, $pin, $email1='', $e } else { $this->setErrorMessage( 'Unable to register' ); $this->debug->append('Failed to insert user into DB: ' . $this->mysqli->error); + echo $this->mysqli->error; if ($stmt->sqlstate == '23000') $this->setErrorMessage( 'Username or email already registered' ); return false; } @@ -856,7 +888,7 @@ public function resetPassword($token, $new1, $new2) { $this->setErrorMessage( 'New password is too short, please use more than 8 chars' ); return false; } - $new_hash = $this->getHash($new1); + $new_hash = $this->getHash($new1, HASH_VERSION, bin2hex(openssl_random_pseudo_bytes(32))); $stmt = $this->mysqli->prepare("UPDATE $this->table SET pass = ? WHERE id = ?"); if ($this->checkStmt($stmt) && $stmt->bind_param('si', $new_hash, $aToken['account_id']) && $stmt->execute() && $stmt->affected_rows === 1) { if ($this->token->deleteToken($aToken['token'])) { @@ -986,7 +1018,7 @@ public function getCurrentIP($trustremote=false, $checkcloudflare=true, $checkcl $user->setToken($oToken); $user->setBitcoin($bitcoin); $user->setSetting($setting); -$user->setErrorCodes($aErrorCodes); $user->setCoinAddress($coinAddress); +$user->setErrorCodes($aErrorCodes); $user->setCurrency($currency); diff --git a/public/include/classes/worker.class.php b/include/classes/worker.class.php similarity index 53% rename from public/include/classes/worker.class.php rename to include/classes/worker.class.php index 9b7344ace..1f273d3e8 100644 --- a/public/include/classes/worker.class.php +++ b/include/classes/worker.class.php @@ -48,15 +48,34 @@ public function getAllIdleWorkers($interval=600) { $this->debug->append("STA " . __METHOD__, 4); $stmt = $this->mysqli->prepare(" SELECT w.account_id AS account_id, w.id AS id, w.username AS username - FROM " . $this->share->getTableName() . " AS s + FROM + ( + SELECT username AS s_username, MAX(shares_id) AS shares_id, MAX(shares_archive_id) AS shares_archive_id + FROM + ( + SELECT + s.username AS username, MAX(s.id) AS shares_id, NULL AS shares_archive_id + FROM . " . $this->share->getTableName() . " AS s + WHERE s.time > DATE_SUB(now(), INTERVAL ? SECOND) + AND s.our_result = 'Y' + GROUP BY s.username + UNION + SELECT + sa.username AS username, NULL AS shares_id, MAX(sa.id) AS shares_archive_id + FROM " . $this->share->getArchiveTableName() . " AS sa + WHERE sa.time > DATE_SUB(now(), INTERVAL ? SECOND) + AND sa.our_result = 'Y' + GROUP BY sa.username + ) AS derived0 + GROUP BY s_username + ) AS derived1 RIGHT JOIN " . $this->getTableName() . " AS w - ON w.username = s.username - AND s.time > DATE_SUB(now(), INTERVAL ? SECOND) - AND our_result = 'Y' + ON s_username = w.username WHERE w.monitor = 1 - AND s.id IS NULL + AND shares_id IS NULL + AND shares_archive_id IS NULL "); - if ($this->checkStmt($stmt) && $stmt->bind_param('i', $interval) && $stmt->execute() && $result = $stmt->get_result()) + if ($this->checkStmt($stmt) && $stmt->bind_param('ii', $interval, $interval) && $stmt->execute() && $result = $stmt->get_result()) return $result->fetch_all(MYSQLI_ASSOC); return $this->sqlError('E0054'); } @@ -69,38 +88,41 @@ public function getAllIdleWorkers($interval=600) { public function getWorker($id, $interval=600) { $this->debug->append("STA " . __METHOD__, 4); $stmt = $this->mysqli->prepare(" - SELECT id, username, password, monitor, - ( SELECT COUNT(id) FROM " . $this->share->getTableName() . " WHERE username = w.username AND time > DATE_SUB(now(), INTERVAL ? SECOND)) AS count_all, - ( SELECT COUNT(id) FROM " . $this->share->getArchiveTableName() . " WHERE username = w.username AND time > DATE_SUB(now(), INTERVAL ? SECOND)) AS count_all_archive, - ( - SELECT - IFNULL(IF(our_result='Y', ROUND(SUM(IF(difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), difficulty)) * POW(2, " . $this->coin->getTargetBits() . ") / ? / 1000), 0), 0) AS hashrate + SELECT id, username, password, monitor, + ( + SELECT COUNT(id) FROM " . $this->share->getTableName() . " WHERE our_result = 'Y' AND username = w.username AND time > DATE_SUB(now(), INTERVAL ? SECOND) + ) + ( + SELECT COUNT(id) FROM " . $this->share->getArchiveTableName() . " WHERE our_result = 'Y' AND username = w.username AND time > DATE_SUB(now(), INTERVAL ? SECOND) + ) AS count_all, + ( + SELECT + IFNULL(SUM(difficulty), 0) FROM " . $this->share->getTableName() . " WHERE username = w.username - AND time > DATE_SUB(now(), INTERVAL ? SECOND) + AND our_result = 'Y' + AND time > DATE_SUB(now(), INTERVAL ? SECOND) ) + ( - SELECT - IFNULL(IF(our_result='Y', ROUND(SUM(IF(difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), difficulty)) * POW(2, " . $this->coin->getTargetBits() . ") / ? / 1000), 0), 0) AS hashrate + SELECT + IFNULL(SUM(difficulty), 0) FROM " . $this->share->getArchiveTableName() . " WHERE username = w.username - AND time > DATE_SUB(now(), INTERVAL ? SECOND) - ) AS hashrate, - ( - SELECT IFNULL(ROUND(SUM(IF(difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), difficulty)) / count_all, 2), 0) - FROM " . $this->share->getTableName() . " - WHERE username = w.username AND time > DATE_SUB(now(), INTERVAL ? SECOND) - ) + ( - SELECT IFNULL(ROUND(SUM(IF(difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), difficulty)) / count_all_archive, 2), 0) - FROM " . $this->share->getArchiveTableName() . " - WHERE username = w.username AND time > DATE_SUB(now(), INTERVAL ? SECOND) - ) AS difficulty + AND our_result = 'Y' + AND time > DATE_SUB(now(), INTERVAL ? SECOND) + ) AS shares FROM $this->table AS w - WHERE id = ? - "); - if ($this->checkStmt($stmt) && $stmt->bind_param('iiiiiiiii',$interval, $interval, $interval, $interval, $interval, $interval, $interval, $interval, $id) && $stmt->execute() && $result = $stmt->get_result()) - return $result->fetch_assoc(); + WHERE id = ?"); + if ($this->checkStmt($stmt) && $stmt->bind_param('iiiii', $interval, $interval, $interval, $interval, $id) && $stmt->execute() && $result = $stmt->get_result()) { + $row = $result->fetch_assoc(); + $row['hashrate'] = round($this->coin->calcHashrate($row['shares'], $interval), 2); + if ($row['count_all'] > 0) { + $row['difficulty'] = round($row['shares'] / $row['count_all'], 2); + } else { + $row['difficulty'] = 0.00; + } + return $row; + } return $this->sqlError('E0055'); } @@ -113,85 +135,93 @@ public function getWorkers($account_id, $interval=600) { $this->debug->append("STA " . __METHOD__, 4); $stmt = $this->mysqli->prepare(" SELECT id, username, password, monitor, - ( SELECT COUNT(id) FROM " . $this->share->getTableName() . " WHERE username = w.username AND time > DATE_SUB(now(), INTERVAL ? SECOND)) AS count_all, - ( SELECT COUNT(id) FROM " . $this->share->getArchiveTableName() . " WHERE username = w.username AND time > DATE_SUB(now(), INTERVAL ? SECOND)) AS count_all_archive, - ( - SELECT - IFNULL(IF(our_result='Y', ROUND(SUM(IF(difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), difficulty)) * POW(2, " . $this->coin->getTargetBits() . ") / ? / 1000), 0), 0) AS hashrate + ( + SELECT COUNT(id) FROM " . $this->share->getTableName() . " WHERE our_result = 'Y' AND username = w.username AND time > DATE_SUB(now(), INTERVAL ? SECOND) + ) + ( + SELECT COUNT(id) FROM " . $this->share->getArchiveTableName() . " WHERE our_result = 'Y' AND username = w.username AND time > DATE_SUB(now(), INTERVAL ? SECOND) + ) AS count_all, + ( + SELECT + IFNULL(SUM(difficulty), 0) FROM " . $this->share->getTableName() . " WHERE username = w.username - AND time > DATE_SUB(now(), INTERVAL ? SECOND) - ) + ( - SELECT - IFNULL(IF(our_result='Y', ROUND(SUM(IF(difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), difficulty)) * POW(2, " . $this->coin->getTargetBits() . ") / ? / 1000), 0), 0) AS hashrate + AND our_result = 'Y' + AND time > DATE_SUB(now(), INTERVAL ? SECOND) + ) + ( + SELECT + IFNULL(SUM(difficulty), 0) FROM " . $this->share->getArchiveTableName() . " WHERE username = w.username - AND time > DATE_SUB(now(), INTERVAL ? SECOND) - ) AS hashrate, - ( - SELECT IFNULL(ROUND(SUM(IF(difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), difficulty)) / count_all, 2), 0) - FROM " . $this->share->getTableName() . " - WHERE username = w.username AND time > DATE_SUB(now(), INTERVAL ? SECOND) - ) + ( - SELECT IFNULL(ROUND(SUM(IF(difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), difficulty)) / count_all_archive, 2), 0) - FROM " . $this->share->getArchiveTableName() . " - WHERE username = w.username AND time > DATE_SUB(now(), INTERVAL ? SECOND) - ) AS difficulty + AND our_result = 'Y' + AND time > DATE_SUB(now(), INTERVAL ? SECOND) + ) AS shares FROM $this->table AS w WHERE account_id = ?"); - if ($this->checkStmt($stmt) && $stmt->bind_param('iiiiiiiii', $interval, $interval, $interval, $interval, $interval, $interval, $interval, $interval, $account_id) && $stmt->execute() && $result = $stmt->get_result()) - return $result->fetch_all(MYSQLI_ASSOC); + if ($this->checkStmt($stmt) && $stmt->bind_param('iiiii', $interval, $interval, $interval, $interval, $account_id) && $stmt->execute() && $result = $stmt->get_result()) { + $aData = array(); + while ($row = $result->fetch_assoc()) { + $row['hashrate'] = round($this->coin->calcHashrate($row['shares'], $interval), 2); + if ($row['count_all'] > 0) { + $row['difficulty'] = round($row['shares'] / $row['count_all'], 2); + } else { + $row['difficulty'] = 0.00; + } + $aData[] = $row; + } + return $aData; + } return $this->sqlError('E0056'); } /** * Fetch all workers for admin panel - * @param limit int + * @param limit int max amount of workers * @return mixed array Workers and their settings or false **/ public function getAllWorkers($iLimit=0, $interval=600, $start=0) { $this->debug->append("STA " . __METHOD__, 4); $stmt = $this->mysqli->prepare(" SELECT id, username, password, monitor, - IFNULL(IF(difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), difficulty), 0) AS difficulty, - ( - SELECT - IFNULL(IF(our_result='Y', ROUND(SUM(IF(difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), difficulty)) * POW(2, " . $this->coin->getTargetBits() . ") / ? / 1000), 0), 0) AS hashrate + ( + SELECT COUNT(id) FROM " . $this->share->getTableName() . " WHERE our_result = 'Y' AND username = w.username AND time > DATE_SUB(now(), INTERVAL ? SECOND) + ) + ( + SELECT COUNT(id) FROM " . $this->share->getArchiveTableName() . " WHERE our_result = 'Y' AND username = w.username AND time > DATE_SUB(now(), INTERVAL ? SECOND) + ) AS count_all, + IFNULL(IF(difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), difficulty), 0) AS difficulty, + ( + SELECT + IFNULL(SUM(difficulty), 0) FROM " . $this->share->getTableName() . " WHERE username = w.username - AND time > DATE_SUB(now(), INTERVAL ? SECOND) - ) + ( - SELECT - IFNULL(IF(our_result='Y', ROUND(SUM(IF(difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), difficulty)) * POW(2, " . $this->coin->getTargetBits() . ") / ? / 1000), 0), 0) AS hashrate + AND our_result = 'Y' + AND time > DATE_SUB(now(), INTERVAL ? SECOND) + ) + ( + SELECT + IFNULL(SUM(difficulty), 0) FROM " . $this->share->getArchiveTableName() . " WHERE username = w.username - AND time > DATE_SUB(now(), INTERVAL ? SECOND) - ) AS hashrate, - (( - SELECT IFNULL(ROUND(SUM(IF(difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), difficulty)), 2), 0) - FROM " . $this->share->getTableName() . " - WHERE username = w.username AND time > DATE_SUB(now(), INTERVAL ? SECOND) - ) + ( - SELECT IFNULL(ROUND(SUM(IF(difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), difficulty)), 2), 0) - FROM " . $this->share->getArchiveTableName() . " - WHERE username = w.username AND time > DATE_SUB(now(), INTERVAL ? SECOND) - )) / (( - SELECT COUNT(id) - FROM " . $this->share->getTableName() . " - WHERE username = w.username AND time > DATE_SUB(now(), INTERVAL ? SECOND) - ) + ( - SELECT COUNT(id) - FROM " . $this->share->getArchiveTableName() . " - WHERE username = w.username AND time > DATE_SUB(now(), INTERVAL ? SECOND) - )) AS avg_difficulty + AND our_result = 'Y' + AND time > DATE_SUB(now(), INTERVAL ? SECOND) + ) AS shares FROM $this->table AS w - ORDER BY hashrate DESC LIMIT ?,?"); - if ($this->checkStmt($stmt) && $stmt->bind_param('iiiiiiiiii', $interval, $interval, $interval, $interval, $interval, $interval, $interval, $interval, $start, $iLimit) && $stmt->execute() && $result = $stmt->get_result()) - return $result->fetch_all(MYSQLI_ASSOC); + ORDER BY shares DESC LIMIT ?,?"); + if ($this->checkStmt($stmt) && $stmt->bind_param('iiiiii', $interval, $interval, $interval, $interval, $start, $iLimit) && $stmt->execute() && $result = $stmt->get_result()) { + $aData = array(); + while ($row = $result->fetch_assoc()) { + $row['hashrate'] = round($this->coin->calcHashrate($row['shares'], $interval), 2); + if ($row['count_all'] > 0) { + $row['avg_difficulty'] = round($row['shares'] / $row['count_all'], 2); + } else { + $row['avg_difficulty'] = 0.00; + } + $aData[] = $row; + } + return $aData; + } return $this->sqlError('E0057'); } diff --git a/public/include/config/admin_settings.inc.php b/include/config/admin_settings.inc.php similarity index 93% rename from public/include/config/admin_settings.inc.php rename to include/config/admin_settings.inc.php index d8a0ed866..624d239d4 100644 --- a/public/include/config/admin_settings.inc.php +++ b/include/config/admin_settings.inc.php @@ -20,6 +20,20 @@ 'name' => 'system_motd', 'value' => $setting->getValue('system_motd'), 'tooltip' => 'Display a message of the day as information popup if set.' ); +$aSettings['website'][] = array( + 'display' => 'MOTD Style', 'type' => 'select', + 'options' => array( 0 => 'Success', 1 => 'Information', 2 => 'Warning', 3 => 'Danger' ), + 'default' => 0, + 'name' => 'system_motd_style', 'value' => $setting->getValue('system_motd_style'), + 'tooltip' => 'Set the Style what MOTD looks like.' +); +$aSettings['website'][] = array( + 'display' => 'MOTD Dismiss', 'type' => 'select', + 'options' => array( 0 => 'No', 1 => 'Yes' ), + 'default' => 0, + 'name' => 'system_motd_dismiss', 'value' => $setting->getValue('system_motd_dismiss'), + 'tooltip' => 'Set if users can hide MOTD.' +); $aSettings['website'][] = array( 'display' => 'Website Name', 'type' => 'text', 'size' => 25, @@ -55,6 +69,13 @@ 'name' => 'website_theme', 'value' => $setting->getValue('website_theme'), 'tooltip' => 'The default theme used on your pool.' ); +$aSettings['website'][] = array( + 'display' => 'Website mobile theme', 'type' => 'select', + 'options' => $aThemes, + 'default' => 'bootstrap', + 'name' => 'website_mobile_theme', 'value' => $setting->getValue('website_mobile_theme'), + 'tooltip' => 'The mobile theme used on your pool.' +); $aSettings['website'][] = array( 'display' => 'Website Design', 'type' => 'select', 'options' => $aDesigns, @@ -146,6 +167,13 @@ 'name' => 'statistics_ajax_data_interval', 'value' => $setting->getValue('statistics_ajax_data_interval'), 'tooltip' => 'Time in minutes, interval for hashrate and sharerate calculations. Higher intervals allow for better accuracy at a higer server load.' ); +$aSettings['statistics'][] = array( + 'display' => 'Graphing Days', 'type' => 'text', + 'size' => 25, + 'default' => 1, + 'name' => 'statistics_graphing_days', 'value' => $setting->getValue('statistics_graphing_days'), + 'tooltip' => 'How many days to graph out on the statistics -> graphs page.' +); $aSettings['statistics'][] = array( 'display' => 'Block Statistics Count', 'type' => 'text', 'size' => 25, @@ -294,6 +322,13 @@ 'name' => 'system_error_email', 'value' => $setting->getValue('system_error_email'), 'tooltip' => 'The email address for system errors notifications, like cronjobs failures.' ); +$aSettings['system'][] = array( + 'display' => 'Date format string', 'type' => 'text', + 'size' => 25, + 'default' => '%m/%d/%Y %H:%M:%S', + 'name' => 'system_date_format', 'value' => $setting->getValue('system_date_format'), + 'tooltip' => 'Date format to be used throughout the site. Please check PHP strftime for details.' +); $aSettings['system'][] = array( 'display' => 'Disable e-mail confirmations', 'type' => 'select', 'options' => array( 0 => 'No', 1 => 'Yes' ), @@ -358,25 +393,18 @@ 'tooltip' => 'Disable dashboard API entirely to reduce server load.' ); $aSettings['system'][] = array( - 'display' => 'Disable Live Navbar', 'type' => 'select', - 'options' => array( 0 => 'No', 1 => 'Yes'), - 'default' => 0, - 'name' => 'disable_navbar', 'value' => $setting->getValue('disable_navbar'), - 'tooltip' => 'Disable live updates on the navbar to reduce server load.' -); -$aSettings['system'][] = array( - 'display' => 'Disable Navbar API', 'type' => 'select', + 'display' => 'Disable TX Summaries', 'type' => 'select', 'options' => array( 0 => 'No', 1 => 'Yes'), 'default' => 0, - 'name' => 'disable_navbar_api', 'value' => $setting->getValue('disable_navbar_api'), - 'tooltip' => 'Disable navbar API entirely to reduce server load. Used in pool stats and navbar mini stats.' + 'name' => 'disable_transactionsummary', 'value' => $setting->getValue('disable_transactionsummary'), + 'tooltip' => 'Disable transaction summaries. Helpful with large transaction tables.' ); $aSettings['system'][] = array( - 'display' => 'Disable TX Summaries', 'type' => 'select', + 'display' => 'Disable Worker Edit without valid Coin Address', 'type' => 'select', 'options' => array( 0 => 'No', 1 => 'Yes'), 'default' => 0, - 'name' => 'disable_transactionsummary', 'value' => $setting->getValue('disable_transactionsummary'), - 'tooltip' => 'Disable transaction summaries. Helpful with large transaction tables.' + 'name' => 'disable_worker_edit', 'value' => $setting->getValue('disable_worker_edit'), + 'tooltip' => 'No worker editing without valid Payout Address set in Account Settings.' ); $aSettings['system'][] = array( 'display' => 'IRC Chat Channel', 'type' => 'text', diff --git a/public/include/config/error_codes.inc.php b/include/config/error_codes.inc.php similarity index 100% rename from public/include/config/error_codes.inc.php rename to include/config/error_codes.inc.php diff --git a/public/include/config/global.inc.dist.php b/include/config/global.inc.dist.php similarity index 90% rename from public/include/config/global.inc.dist.php rename to include/config/global.inc.dist.php index 67f798079..f0c3c1cc1 100644 --- a/public/include/config/global.inc.dist.php +++ b/include/config/global.inc.dist.php @@ -3,9 +3,11 @@ /** * Do not edit this unless you have confirmed that your config has been updated! + * Also the URL to check for the most recent upstream versions available * https://github.com/MPOS/php-mpos/wiki/Config-Setup#wiki-config-version **/ -$config['version'] = '0.0.7'; +$config['version'] = '0.0.8'; +$config['version_url'] = 'https://raw.githubusercontent.com/MPOS/php-mpos/master/include/version.inc.php'; /** * Unless you disable this, we'll do a quick check on your config first. @@ -13,6 +15,12 @@ */ $config['skip_config_tests'] = false; +/** + * Unless you disable this, we'll do a check for a valid coin address on registration. + * https://github.com/MPOS/php-mpos/wiki/Config-Setup#check-for-valid-wallet-address + */ +$config['check_valid_coinaddress'] = true; + /** * Defines * Debug setting and salts for hashing passwords @@ -65,12 +73,12 @@ $config['swiftmailer']['type'] = 'sendmail'; $config['swiftmailer']['sendmail']['path'] = '/usr/sbin/sendmail'; $config['swiftmailer']['sendmail']['options'] = '-bs'; -$config['switfmailer']['smtp']['host'] = 'your.mail-relay.com'; -$config['switfmailer']['smtp']['port'] = '587'; -$config['switfmailer']['smtp']['encryption'] = 'tls'; -$config['switfmailer']['smtp']['username'] = ''; -$config['switfmailer']['smtp']['password'] = ''; -$config['switfmailer']['smtp']['throttle'] = 100; +$config['swiftmailer']['smtp']['host'] = 'your.mail-relay.com'; +$config['swiftmailer']['smtp']['port'] = '587'; +$config['swiftmailer']['smtp']['encryption'] = 'tls'; +$config['swiftmailer']['smtp']['username'] = ''; +$config['swiftmailer']['smtp']['password'] = ''; +$config['swiftmailer']['smtp']['throttle'] = 100; /** * Getting Started Config @@ -260,6 +268,9 @@ $config['memcache']['expiration'] = 90; $config['memcache']['splay'] = 15; $config['memcache']['force']['contrib_shares'] = false; +$config['memcache']['sasl'] = false; +$config['memcache']['sasl']['username'] = ''; +$config['memcache']['sasl']['password'] = ''; /** * Cookies diff --git a/public/include/config/memcache_keys.inc.php b/include/config/memcache_keys.inc.php similarity index 100% rename from public/include/config/memcache_keys.inc.php rename to include/config/memcache_keys.inc.php diff --git a/public/include/config/monitor_crons.inc.php b/include/config/monitor_crons.inc.php similarity index 78% rename from public/include/config/monitor_crons.inc.php rename to include/config/monitor_crons.inc.php index 732c1bdce..d3726539a 100644 --- a/public/include/config/monitor_crons.inc.php +++ b/include/config/monitor_crons.inc.php @@ -3,15 +3,13 @@ // Small helper array that may be used on some page controllers to // fetch the crons we wish to monitor switch ($config['payout_system']) { - case 'pplns': - $sPayoutSystem = $config['payout_system'] . '_payout'; - break; - case 'pps': - $sPayoutSystem = $config['payout_system'] . '_payout'; - break; case 'prop': $sPayoutSystem = 'proportional_payout'; break; + default: // pps && pplns land here + $sPayoutSystem = $config['payout_system'] . '_payout'; } $aMonitorCrons = array('statistics','tickerupdate','notifications','tables_cleanup','findblock',$sPayoutSystem,'blockupdate','payouts'); + +?> diff --git a/public/include/config/security.inc.dist.php b/include/config/security.inc.dist.php similarity index 100% rename from public/include/config/security.inc.dist.php rename to include/config/security.inc.dist.php diff --git a/public/include/database.inc.php b/include/database.inc.php similarity index 100% rename from public/include/database.inc.php rename to include/database.inc.php diff --git a/public/include/lib/KLogger.php b/include/lib/KLogger.php similarity index 100% rename from public/include/lib/KLogger.php rename to include/lib/KLogger.php diff --git a/public/include/lib/Michelf/Markdown.php b/include/lib/Michelf/Markdown.php similarity index 100% rename from public/include/lib/Michelf/Markdown.php rename to include/lib/Michelf/Markdown.php diff --git a/public/include/lib/Michelf/MarkdownExtra.php b/include/lib/Michelf/MarkdownExtra.php similarity index 100% rename from public/include/lib/Michelf/MarkdownExtra.php rename to include/lib/Michelf/MarkdownExtra.php diff --git a/include/lib/Mobile_Detect.php b/include/lib/Mobile_Detect.php new file mode 100644 index 000000000..b6eb0da21 --- /dev/null +++ b/include/lib/Mobile_Detect.php @@ -0,0 +1,1248 @@ +, Nick Ilyin + * Original author: Victor Stanciu + * + * @license Code and contributions have 'MIT License' + * More details: https://github.com/serbanghita/Mobile-Detect/blob/master/LICENSE.txt + * + * @link Homepage: http://mobiledetect.net + * GitHub Repo: https://github.com/serbanghita/Mobile-Detect + * Google Code: http://code.google.com/p/php-mobile-detect/ + * README: https://github.com/serbanghita/Mobile-Detect/blob/master/README.md + * HOWTO: https://github.com/serbanghita/Mobile-Detect/wiki/Code-examples + * + * @version 2.8.3 + */ + +class Mobile_Detect +{ + /** + * Mobile detection type. + * + * @deprecated since version 2.6.9 + */ + const DETECTION_TYPE_MOBILE = 'mobile'; + + /** + * Extended detection type. + * + * @deprecated since version 2.6.9 + */ + const DETECTION_TYPE_EXTENDED = 'extended'; + + /** + * A frequently used regular expression to extract version #s. + * + * @deprecated since version 2.6.9 + */ + const VER = '([\w._\+]+)'; + + /** + * Top-level device. + */ + const MOBILE_GRADE_A = 'A'; + + /** + * Mid-level device. + */ + const MOBILE_GRADE_B = 'B'; + + /** + * Low-level device. + */ + const MOBILE_GRADE_C = 'C'; + + /** + * Stores the version number of the current release. + */ + const VERSION = '2.8.3'; + + /** + * A type for the version() method indicating a string return value. + */ + const VERSION_TYPE_STRING = 'text'; + + /** + * A type for the version() method indicating a float return value. + */ + const VERSION_TYPE_FLOAT = 'float'; + + /** + * The User-Agent HTTP header is stored in here. + * @var string + */ + protected $userAgent = null; + + /** + * HTTP headers in the PHP-flavor. So HTTP_USER_AGENT and SERVER_SOFTWARE. + * @var array + */ + protected $httpHeaders = array(); + + /** + * The detection type, using self::DETECTION_TYPE_MOBILE or self::DETECTION_TYPE_EXTENDED. + * + * @deprecated since version 2.6.9 + * + * @var string + */ + protected $detectionType = self::DETECTION_TYPE_MOBILE; + + /** + * HTTP headers that trigger the 'isMobile' detection + * to be true. + * + * @var array + */ + protected static $mobileHeaders = array( + + 'HTTP_ACCEPT' => array('matches' => array( + // Opera Mini; @reference: http://dev.opera.com/articles/view/opera-binary-markup-language/ + 'application/x-obml2d', + // BlackBerry devices. + 'application/vnd.rim.html', + 'text/vnd.wap.wml', + 'application/vnd.wap.xhtml+xml' + )), + 'HTTP_X_WAP_PROFILE' => null, + 'HTTP_X_WAP_CLIENTID' => null, + 'HTTP_WAP_CONNECTION' => null, + 'HTTP_PROFILE' => null, + // Reported by Opera on Nokia devices (eg. C3). + 'HTTP_X_OPERAMINI_PHONE_UA' => null, + 'HTTP_X_NOKIA_GATEWAY_ID' => null, + 'HTTP_X_ORANGE_ID' => null, + 'HTTP_X_VODAFONE_3GPDPCONTEXT' => null, + 'HTTP_X_HUAWEI_USERID' => null, + // Reported by Windows Smartphones. + 'HTTP_UA_OS' => null, + // Reported by Verizon, Vodafone proxy system. + 'HTTP_X_MOBILE_GATEWAY' => null, + // Seend this on HTC Sensation. @ref: SensationXE_Beats_Z715e. + 'HTTP_X_ATT_DEVICEID' => null, + // Seen this on a HTC. + 'HTTP_UA_CPU' => array('matches' => array('ARM')), + ); + + /** + * List of mobile devices (phones). + * + * @var array + */ + protected static $phoneDevices = array( + 'iPhone' => '\biPhone.*(Mobile|PhoneGap)|\biPod', // |\biTunes + 'BlackBerry' => 'BlackBerry|\bBB10\b|rim[0-9]+', + 'HTC' => 'HTC|HTC.*(Sensation|Evo|Vision|Explorer|6800|8100|8900|A7272|S510e|C110e|Legend|Desire|T8282)|APX515CKT|Qtek9090|APA9292KT|HD_mini|Sensation.*Z710e|PG86100|Z715e|Desire.*(A8181|HD)|ADR6200|ADR6400L|ADR6425|001HT|Inspire 4G|Android.*\bEVO\b|T-Mobile G1|Z520m', + 'Nexus' => 'Nexus One|Nexus S|Galaxy.*Nexus|Android.*Nexus.*Mobile', + // @todo: Is 'Dell Streak' a tablet or a phone? ;) + 'Dell' => 'Dell.*Streak|Dell.*Aero|Dell.*Venue|DELL.*Venue Pro|Dell Flash|Dell Smoke|Dell Mini 3iX|XCD28|XCD35|\b001DL\b|\b101DL\b|\bGS01\b', + 'Motorola' => 'Motorola|DROIDX|DROID BIONIC|\bDroid\b.*Build|Android.*Xoom|HRI39|MOT-|A1260|A1680|A555|A853|A855|A953|A955|A956|Motorola.*ELECTRIFY|Motorola.*i1|i867|i940|MB200|MB300|MB501|MB502|MB508|MB511|MB520|MB525|MB526|MB611|MB612|MB632|MB810|MB855|MB860|MB861|MB865|MB870|ME501|ME502|ME511|ME525|ME600|ME632|ME722|ME811|ME860|ME863|ME865|MT620|MT710|MT716|MT720|MT810|MT870|MT917|Motorola.*TITANIUM|WX435|WX445|XT300|XT301|XT311|XT316|XT317|XT319|XT320|XT390|XT502|XT530|XT531|XT532|XT535|XT603|XT610|XT611|XT615|XT681|XT701|XT702|XT711|XT720|XT800|XT806|XT860|XT862|XT875|XT882|XT883|XT894|XT901|XT907|XT909|XT910|XT912|XT928|XT926|XT915|XT919|XT925', + 'Samsung' => 'Samsung|SGH-I337|BGT-S5230|GT-B2100|GT-B2700|GT-B2710|GT-B3210|GT-B3310|GT-B3410|GT-B3730|GT-B3740|GT-B5510|GT-B5512|GT-B5722|GT-B6520|GT-B7300|GT-B7320|GT-B7330|GT-B7350|GT-B7510|GT-B7722|GT-B7800|GT-C3010|GT-C3011|GT-C3060|GT-C3200|GT-C3212|GT-C3212I|GT-C3262|GT-C3222|GT-C3300|GT-C3300K|GT-C3303|GT-C3303K|GT-C3310|GT-C3322|GT-C3330|GT-C3350|GT-C3500|GT-C3510|GT-C3530|GT-C3630|GT-C3780|GT-C5010|GT-C5212|GT-C6620|GT-C6625|GT-C6712|GT-E1050|GT-E1070|GT-E1075|GT-E1080|GT-E1081|GT-E1085|GT-E1087|GT-E1100|GT-E1107|GT-E1110|GT-E1120|GT-E1125|GT-E1130|GT-E1160|GT-E1170|GT-E1175|GT-E1180|GT-E1182|GT-E1200|GT-E1210|GT-E1225|GT-E1230|GT-E1390|GT-E2100|GT-E2120|GT-E2121|GT-E2152|GT-E2220|GT-E2222|GT-E2230|GT-E2232|GT-E2250|GT-E2370|GT-E2550|GT-E2652|GT-E3210|GT-E3213|GT-I5500|GT-I5503|GT-I5700|GT-I5800|GT-I5801|GT-I6410|GT-I6420|GT-I7110|GT-I7410|GT-I7500|GT-I8000|GT-I8150|GT-I8160|GT-I8190|GT-I8320|GT-I8330|GT-I8350|GT-I8530|GT-I8700|GT-I8703|GT-I8910|GT-I9000|GT-I9001|GT-I9003|GT-I9010|GT-I9020|GT-I9023|GT-I9070|GT-I9082|GT-I9100|GT-I9103|GT-I9220|GT-I9250|GT-I9300|GT-I9305|GT-I9500|GT-I9505|GT-M3510|GT-M5650|GT-M7500|GT-M7600|GT-M7603|GT-M8800|GT-M8910|GT-N7000|GT-S3110|GT-S3310|GT-S3350|GT-S3353|GT-S3370|GT-S3650|GT-S3653|GT-S3770|GT-S3850|GT-S5210|GT-S5220|GT-S5229|GT-S5230|GT-S5233|GT-S5250|GT-S5253|GT-S5260|GT-S5263|GT-S5270|GT-S5300|GT-S5330|GT-S5350|GT-S5360|GT-S5363|GT-S5369|GT-S5380|GT-S5380D|GT-S5560|GT-S5570|GT-S5600|GT-S5603|GT-S5610|GT-S5620|GT-S5660|GT-S5670|GT-S5690|GT-S5750|GT-S5780|GT-S5830|GT-S5839|GT-S6102|GT-S6500|GT-S7070|GT-S7200|GT-S7220|GT-S7230|GT-S7233|GT-S7250|GT-S7500|GT-S7530|GT-S7550|GT-S7562|GT-S7710|GT-S8000|GT-S8003|GT-S8500|GT-S8530|GT-S8600|SCH-A310|SCH-A530|SCH-A570|SCH-A610|SCH-A630|SCH-A650|SCH-A790|SCH-A795|SCH-A850|SCH-A870|SCH-A890|SCH-A930|SCH-A950|SCH-A970|SCH-A990|SCH-I100|SCH-I110|SCH-I400|SCH-I405|SCH-I500|SCH-I510|SCH-I515|SCH-I600|SCH-I730|SCH-I760|SCH-I770|SCH-I830|SCH-I910|SCH-I920|SCH-I959|SCH-LC11|SCH-N150|SCH-N300|SCH-R100|SCH-R300|SCH-R351|SCH-R400|SCH-R410|SCH-T300|SCH-U310|SCH-U320|SCH-U350|SCH-U360|SCH-U365|SCH-U370|SCH-U380|SCH-U410|SCH-U430|SCH-U450|SCH-U460|SCH-U470|SCH-U490|SCH-U540|SCH-U550|SCH-U620|SCH-U640|SCH-U650|SCH-U660|SCH-U700|SCH-U740|SCH-U750|SCH-U810|SCH-U820|SCH-U900|SCH-U940|SCH-U960|SCS-26UC|SGH-A107|SGH-A117|SGH-A127|SGH-A137|SGH-A157|SGH-A167|SGH-A177|SGH-A187|SGH-A197|SGH-A227|SGH-A237|SGH-A257|SGH-A437|SGH-A517|SGH-A597|SGH-A637|SGH-A657|SGH-A667|SGH-A687|SGH-A697|SGH-A707|SGH-A717|SGH-A727|SGH-A737|SGH-A747|SGH-A767|SGH-A777|SGH-A797|SGH-A817|SGH-A827|SGH-A837|SGH-A847|SGH-A867|SGH-A877|SGH-A887|SGH-A897|SGH-A927|SGH-B100|SGH-B130|SGH-B200|SGH-B220|SGH-C100|SGH-C110|SGH-C120|SGH-C130|SGH-C140|SGH-C160|SGH-C170|SGH-C180|SGH-C200|SGH-C207|SGH-C210|SGH-C225|SGH-C230|SGH-C417|SGH-C450|SGH-D307|SGH-D347|SGH-D357|SGH-D407|SGH-D415|SGH-D780|SGH-D807|SGH-D980|SGH-E105|SGH-E200|SGH-E315|SGH-E316|SGH-E317|SGH-E335|SGH-E590|SGH-E635|SGH-E715|SGH-E890|SGH-F300|SGH-F480|SGH-I200|SGH-I300|SGH-I320|SGH-I550|SGH-I577|SGH-I600|SGH-I607|SGH-I617|SGH-I627|SGH-I637|SGH-I677|SGH-I700|SGH-I717|SGH-I727|SGH-i747M|SGH-I777|SGH-I780|SGH-I827|SGH-I847|SGH-I857|SGH-I896|SGH-I897|SGH-I900|SGH-I907|SGH-I917|SGH-I927|SGH-I937|SGH-I997|SGH-J150|SGH-J200|SGH-L170|SGH-L700|SGH-M110|SGH-M150|SGH-M200|SGH-N105|SGH-N500|SGH-N600|SGH-N620|SGH-N625|SGH-N700|SGH-N710|SGH-P107|SGH-P207|SGH-P300|SGH-P310|SGH-P520|SGH-P735|SGH-P777|SGH-Q105|SGH-R210|SGH-R220|SGH-R225|SGH-S105|SGH-S307|SGH-T109|SGH-T119|SGH-T139|SGH-T209|SGH-T219|SGH-T229|SGH-T239|SGH-T249|SGH-T259|SGH-T309|SGH-T319|SGH-T329|SGH-T339|SGH-T349|SGH-T359|SGH-T369|SGH-T379|SGH-T409|SGH-T429|SGH-T439|SGH-T459|SGH-T469|SGH-T479|SGH-T499|SGH-T509|SGH-T519|SGH-T539|SGH-T559|SGH-T589|SGH-T609|SGH-T619|SGH-T629|SGH-T639|SGH-T659|SGH-T669|SGH-T679|SGH-T709|SGH-T719|SGH-T729|SGH-T739|SGH-T746|SGH-T749|SGH-T759|SGH-T769|SGH-T809|SGH-T819|SGH-T839|SGH-T919|SGH-T929|SGH-T939|SGH-T959|SGH-T989|SGH-U100|SGH-U200|SGH-U800|SGH-V205|SGH-V206|SGH-X100|SGH-X105|SGH-X120|SGH-X140|SGH-X426|SGH-X427|SGH-X475|SGH-X495|SGH-X497|SGH-X507|SGH-X600|SGH-X610|SGH-X620|SGH-X630|SGH-X700|SGH-X820|SGH-X890|SGH-Z130|SGH-Z150|SGH-Z170|SGH-ZX10|SGH-ZX20|SHW-M110|SPH-A120|SPH-A400|SPH-A420|SPH-A460|SPH-A500|SPH-A560|SPH-A600|SPH-A620|SPH-A660|SPH-A700|SPH-A740|SPH-A760|SPH-A790|SPH-A800|SPH-A820|SPH-A840|SPH-A880|SPH-A900|SPH-A940|SPH-A960|SPH-D600|SPH-D700|SPH-D710|SPH-D720|SPH-I300|SPH-I325|SPH-I330|SPH-I350|SPH-I500|SPH-I600|SPH-I700|SPH-L700|SPH-M100|SPH-M220|SPH-M240|SPH-M300|SPH-M305|SPH-M320|SPH-M330|SPH-M350|SPH-M360|SPH-M370|SPH-M380|SPH-M510|SPH-M540|SPH-M550|SPH-M560|SPH-M570|SPH-M580|SPH-M610|SPH-M620|SPH-M630|SPH-M800|SPH-M810|SPH-M850|SPH-M900|SPH-M910|SPH-M920|SPH-M930|SPH-N100|SPH-N200|SPH-N240|SPH-N300|SPH-N400|SPH-Z400|SWC-E100|SCH-i909|GT-N7100|GT-N7105|SCH-I535|SM-N900A|SGH-I317|SGH-T999L|GT-S5360B|GT-I8262|GT-S6802|GT-S6312|GT-S6310|GT-S5312|GT-S5310|GT-I9105|GT-I8510|GT-S6790N|SM-G7105|SM-N9005|GT-S5301|GT-I9295|GT-I9195|SM-C101|GT-S7392|GT-S7560|GT-B7610|GT-I5510|GT-S7582|GT-S7530E', + 'LG' => '\bLG\b;|LG[- ]?(C800|C900|E400|E610|E900|E-900|F160|F180K|F180L|F180S|730|855|L160|LS840|LS970|LU6200|MS690|MS695|MS770|MS840|MS870|MS910|P500|P700|P705|VM696|AS680|AS695|AX840|C729|E970|GS505|272|C395|E739BK|E960|L55C|L75C|LS696|LS860|P769BK|P350|P500|P509|P870|UN272|US730|VS840|VS950|LN272|LN510|LS670|LS855|LW690|MN270|MN510|P509|P769|P930|UN200|UN270|UN510|UN610|US670|US740|US760|UX265|UX840|VN271|VN530|VS660|VS700|VS740|VS750|VS910|VS920|VS930|VX9200|VX11000|AX840A|LW770|P506|P925|P999|E612|D955|D802)', + 'Sony' => 'SonyST|SonyLT|SonyEricsson|SonyEricssonLT15iv|LT18i|E10i|LT28h|LT26w|SonyEricssonMT27i', + 'Asus' => 'Asus.*Galaxy|PadFone.*Mobile', + // @ref: http://www.micromaxinfo.com/mobiles/smartphones + // Added because the codes might conflict with Acer Tablets. + 'Micromax' => 'Micromax.*\b(A210|A92|A88|A72|A111|A110Q|A115|A116|A110|A90S|A26|A51|A35|A54|A25|A27|A89|A68|A65|A57|A90)\b', + 'Palm' => 'PalmSource|Palm', // avantgo|blazer|elaine|hiptop|plucker|xiino ; @todo - complete the regex. + 'Vertu' => 'Vertu|Vertu.*Ltd|Vertu.*Ascent|Vertu.*Ayxta|Vertu.*Constellation(F|Quest)?|Vertu.*Monika|Vertu.*Signature', // Just for fun ;) + // @ref: http://www.pantech.co.kr/en/prod/prodList.do?gbrand=VEGA (PANTECH) + // Most of the VEGA devices are legacy. PANTECH seem to be newer devices based on Android. + 'Pantech' => 'PANTECH|IM-A850S|IM-A840S|IM-A830L|IM-A830K|IM-A830S|IM-A820L|IM-A810K|IM-A810S|IM-A800S|IM-T100K|IM-A725L|IM-A780L|IM-A775C|IM-A770K|IM-A760S|IM-A750K|IM-A740S|IM-A730S|IM-A720L|IM-A710K|IM-A690L|IM-A690S|IM-A650S|IM-A630K|IM-A600S|VEGA PTL21|PT003|P8010|ADR910L|P6030|P6020|P9070|P4100|P9060|P5000|CDM8992|TXT8045|ADR8995|IS11PT|P2030|P6010|P8000|PT002|IS06|CDM8999|P9050|PT001|TXT8040|P2020|P9020|P2000|P7040|P7000|C790', + // @ref: http://www.fly-phone.com/devices/smartphones/ ; Included only smartphones. + 'Fly' => 'IQ230|IQ444|IQ450|IQ440|IQ442|IQ441|IQ245|IQ256|IQ236|IQ255|IQ235|IQ245|IQ275|IQ240|IQ285|IQ280|IQ270|IQ260|IQ250', + 'iMobile' => 'i-mobile (IQ|i-STYLE|idea|ZAA|Hitz)', + // Added simvalley mobile just for fun. They have some interesting devices. + // @ref: http://www.simvalley.fr/telephonie---gps-_22_telephonie-mobile_telephones_.html + 'SimValley' => '\b(SP-80|XT-930|SX-340|XT-930|SX-310|SP-360|SP60|SPT-800|SP-120|SPT-800|SP-140|SPX-5|SPX-8|SP-100|SPX-8|SPX-12)\b', + // @Tapatalk is a mobile app; @ref: http://support.tapatalk.com/threads/smf-2-0-2-os-and-browser-detection-plugin-and-tapatalk.15565/#post-79039 + 'GenericPhone' => 'Tapatalk|PDA;|SAGEM|\bmmp\b|pocket|\bpsp\b|symbian|Smartphone|smartfon|treo|up.browser|up.link|vodafone|\bwap\b|nokia|Series40|Series60|S60|SonyEricsson|N900|MAUI.*WAP.*Browser' + ); + + /** + * List of tablet devices. + * + * @var array + */ + protected static $tabletDevices = array( + 'iPad' => 'iPad|iPad.*Mobile', // @todo: check for mobile friendly emails topic. + 'NexusTablet' => 'Android.*Nexus[\s]+(7|10)|^.*Android.*Nexus(?:(?!Mobile).)*$', + 'SamsungTablet' => 'SAMSUNG.*Tablet|Galaxy.*Tab|SC-01C|GT-P1000|GT-P1003|GT-P1010|GT-P3105|GT-P6210|GT-P6800|GT-P6810|GT-P7100|GT-P7300|GT-P7310|GT-P7500|GT-P7510|SCH-I800|SCH-I815|SCH-I905|SGH-I957|SGH-I987|SGH-T849|SGH-T859|SGH-T869|SPH-P100|GT-P3100|GT-P3108|GT-P3110|GT-P5100|GT-P5110|GT-P6200|GT-P7320|GT-P7511|GT-N8000|GT-P8510|SGH-I497|SPH-P500|SGH-T779|SCH-I705|SCH-I915|GT-N8013|GT-P3113|GT-P5113|GT-P8110|GT-N8010|GT-N8005|GT-N8020|GT-P1013|GT-P6201|GT-P7501|GT-N5100|GT-N5105|GT-N5110|SHV-E140K|SHV-E140L|SHV-E140S|SHV-E150S|SHV-E230K|SHV-E230L|SHV-E230S|SHW-M180K|SHW-M180L|SHW-M180S|SHW-M180W|SHW-M300W|SHW-M305W|SHW-M380K|SHW-M380S|SHW-M380W|SHW-M430W|SHW-M480K|SHW-M480S|SHW-M480W|SHW-M485W|SHW-M486W|SHW-M500W|GT-I9228|SCH-P739|SCH-I925|GT-I9200|GT-I9205|GT-P5200|GT-P5210|GT-P5210X|SM-T311|SM-T310|SM-T310X|SM-T210|SM-T210R|SM-T211|SM-P600|SM-P601|SM-P605|SM-P900|SM-P901|SM-T217|SM-T217A|SM-T217S|SM-P6000|SM-T3100|SGH-I467|XE500|SM-T110|GT-P5220|GT-I9200X|GT-N5110X|GT-N5120|SM-P905|SM-T111|SM-T2105|SM-T315|SM-T320|SM-T320X|SM-T321|SM-T520|SM-T525|SM-T530NU|SM-T230NU|SM-T330NU|SM-T900|XE500T1C|SM-P605V|SM-P905V|SM-P600X|SM-P900X|SM-T210X|SM-T230|SM-T230X|SM-T325|GT-P7503|SM-T531|SM-T330|SM-T530|SM-T705C|SM-T535|SM-T331', // SCH-P709|SCH-P729|SM-T2558 - Samsung Mega - treat them like a regular phone. + // @reference: http://www.labnol.org/software/kindle-user-agent-string/20378/ + 'Kindle' => 'Kindle|Silk.*Accelerated|Android.*\b(KFOT|KFTT|KFJWI|KFJWA|KFOTE|KFSOWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|WFJWAE)\b', + // Only the Surface tablets with Windows RT are considered mobile. + // @ref: http://msdn.microsoft.com/en-us/library/ie/hh920767(v=vs.85).aspx + 'SurfaceTablet' => 'Windows NT [0-9.]+; ARM;', + // @ref: http://shopping1.hp.com/is-bin/INTERSHOP.enfinity/WFS/WW-USSMBPublicStore-Site/en_US/-/USD/ViewStandardCatalog-Browse?CatalogCategoryID=JfIQ7EN5lqMAAAEyDcJUDwMT + 'HPTablet' => 'HP Slate 7|HP ElitePad 900|hp-tablet|EliteBook.*Touch|HP 8', + // @note: watch out for PadFone, see #132 + 'AsusTablet' => '^.*PadFone((?!Mobile).)*$|Transformer|TF101|TF101G|TF300T|TF300TG|TF300TL|TF700T|TF700KL|TF701T|TF810C|ME171|ME301T|ME302C|ME371MG|ME370T|ME372MG|ME172V|ME173X|ME400C|Slider SL101|\bK00F\b|TX201LA', + 'BlackBerryTablet' => 'PlayBook|RIM Tablet', + 'HTCtablet' => 'HTC Flyer|HTC Jetstream|HTC-P715a|HTC EVO View 4G|PG41200', + 'MotorolaTablet' => 'xoom|sholest|MZ615|MZ605|MZ505|MZ601|MZ602|MZ603|MZ604|MZ606|MZ607|MZ608|MZ609|MZ615|MZ616|MZ617', + 'NookTablet' => 'Android.*Nook|NookColor|nook browser|BNRV200|BNRV200A|BNTV250|BNTV250A|BNTV400|BNTV600|LogicPD Zoom2', + // @ref: http://www.acer.ro/ac/ro/RO/content/drivers + // @ref: http://www.packardbell.co.uk/pb/en/GB/content/download (Packard Bell is part of Acer) + // @ref: http://us.acer.com/ac/en/US/content/group/tablets + // @note: Can conflict with Micromax and Motorola phones codes. + 'AcerTablet' => 'Android.*; \b(A100|A101|A110|A200|A210|A211|A500|A501|A510|A511|A700|A701|W500|W500P|W501|W501P|W510|W511|W700|G100|G100W|B1-A71|B1-710|B1-711|A1-810|A1-830)\b|W3-810|\bA3-A10\b', + // @ref: http://eu.computers.toshiba-europe.com/innovation/family/Tablets/1098744/banner_id/tablet_footerlink/ + // @ref: http://us.toshiba.com/tablets/tablet-finder + // @ref: http://www.toshiba.co.jp/regza/tablet/ + 'ToshibaTablet' => 'Android.*(AT100|AT105|AT200|AT205|AT270|AT275|AT300|AT305|AT1S5|AT500|AT570|AT700|AT830)|TOSHIBA.*FOLIO', + // @ref: http://www.nttdocomo.co.jp/english/service/developer/smart_phone/technical_info/spec/index.html + // @ref: http://www.lg.com/us/tablets + 'LGTablet' => '\bL-06C|LG-V900|LG-V500|LG-V909|LG-V500|LG-V510|LG-VK810\b', + 'FujitsuTablet' => 'Android.*\b(F-01D|F-02F|F-05E|F-10D|M532|Q572)\b', + // Prestigio Tablets http://www.prestigio.com/support + 'PrestigioTablet' => 'PMP3170B|PMP3270B|PMP3470B|PMP7170B|PMP3370B|PMP3570C|PMP5870C|PMP3670B|PMP5570C|PMP5770D|PMP3970B|PMP3870C|PMP5580C|PMP5880D|PMP5780D|PMP5588C|PMP7280C|PMP7280C3G|PMP7280|PMP7880D|PMP5597D|PMP5597|PMP7100D|PER3464|PER3274|PER3574|PER3884|PER5274|PER5474|PMP5097CPRO|PMP5097|PMP7380D|PMP5297C|PMP5297C_QUAD', + // @ref: http://support.lenovo.com/en_GB/downloads/default.page?# + 'LenovoTablet' => 'IdeaTab|ThinkPad([ ]+)?Tablet|Lenovo.*(S2109|S2110|S5000|S6000|K3011|A3000|A1000|A2107|A2109|A1107|B6000|B8000|B8080-F)', + // @ref: http://www.yarvik.com/en/matrix/tablets/ + 'YarvikTablet' => 'Android.*\b(TAB210|TAB211|TAB224|TAB250|TAB260|TAB264|TAB310|TAB360|TAB364|TAB410|TAB411|TAB420|TAB424|TAB450|TAB460|TAB461|TAB464|TAB465|TAB467|TAB468|TAB07-100|TAB07-101|TAB07-150|TAB07-151|TAB07-152|TAB07-200|TAB07-201-3G|TAB07-210|TAB07-211|TAB07-212|TAB07-214|TAB07-220|TAB07-400|TAB07-485|TAB08-150|TAB08-200|TAB08-201-3G|TAB08-201-30|TAB09-100|TAB09-211|TAB09-410|TAB10-150|TAB10-201|TAB10-211|TAB10-400|TAB10-410|TAB13-201|TAB274EUK|TAB275EUK|TAB374EUK|TAB462EUK|TAB474EUK|TAB9-200)\b', + 'MedionTablet' => 'Android.*\bOYO\b|LIFE.*(P9212|P9514|P9516|S9512)|LIFETAB', + 'ArnovaTablet' => 'AN10G2|AN7bG3|AN7fG3|AN8G3|AN8cG3|AN7G3|AN9G3|AN7dG3|AN7dG3ST|AN7dG3ChildPad|AN10bG3|AN10bG3DT', + // http://www.intenso.de/kategorie_en.php?kategorie=33 + // @todo: http://www.nbhkdz.com/read/b8e64202f92a2df129126bff.html - investigate + 'IntensoTablet' => 'INM8002KP|INM1010FP|INM805ND|Intenso Tab', + // IRU.ru Tablets http://www.iru.ru/catalog/soho/planetable/ + 'IRUTablet' => 'M702pro', + 'MegafonTablet' => 'MegaFon V9|\bZTE V9\b|Android.*\bMT7A\b', + // @ref: http://www.e-boda.ro/tablete-pc.html + 'EbodaTablet' => 'E-Boda (Supreme|Impresspeed|Izzycomm|Essential)', + // @ref: http://www.allview.ro/produse/droseries/lista-tablete-pc/ + 'AllViewTablet' => 'Allview.*(Viva|Alldro|City|Speed|All TV|Frenzy|Quasar|Shine|TX1|AX1|AX2)', + // @reference: http://wiki.archosfans.com/index.php?title=Main_Page + 'ArchosTablet' => '\b(101G9|80G9|A101IT)\b|Qilive 97R|ARCHOS 101G10|Archos 101 Neon', + // @ref: http://www.ainol.com/plugin.php?identifier=ainol&module=product + 'AinolTablet' => 'NOVO7|NOVO8|NOVO10|Novo7Aurora|Novo7Basic|NOVO7PALADIN|novo9-Spark', + // @todo: inspect http://esupport.sony.com/US/p/select-system.pl?DIRECTOR=DRIVER + // @ref: Readers http://www.atsuhiro-me.net/ebook/sony-reader/sony-reader-web-browser + // @ref: http://www.sony.jp/support/tablet/ + 'SonyTablet' => 'Sony.*Tablet|Xperia Tablet|Sony Tablet S|SO-03E|SGPT12|SGPT13|SGPT114|SGPT121|SGPT122|SGPT123|SGPT111|SGPT112|SGPT113|SGPT131|SGPT132|SGPT133|SGPT211|SGPT212|SGPT213|SGP311|SGP312|SGP321|EBRD1101|EBRD1102|EBRD1201|SGP351|SGP341|SGP511|SGP512|SGP521|SGP541|SGP551', + // @ref: db + http://www.cube-tablet.com/buy-products.html + 'CubeTablet' => 'Android.*(K8GT|U9GT|U10GT|U16GT|U17GT|U18GT|U19GT|U20GT|U23GT|U30GT)|CUBE U8GT', + // @ref: http://www.cobyusa.com/?p=pcat&pcat_id=3001 + 'CobyTablet' => 'MID1042|MID1045|MID1125|MID1126|MID7012|MID7014|MID7015|MID7034|MID7035|MID7036|MID7042|MID7048|MID7127|MID8042|MID8048|MID8127|MID9042|MID9740|MID9742|MID7022|MID7010', + // @ref: http://www.match.net.cn/products.asp + 'MIDTablet' => 'M9701|M9000|M9100|M806|M1052|M806|T703|MID701|MID713|MID710|MID727|MID760|MID830|MID728|MID933|MID125|MID810|MID732|MID120|MID930|MID800|MID731|MID900|MID100|MID820|MID735|MID980|MID130|MID833|MID737|MID960|MID135|MID860|MID736|MID140|MID930|MID835|MID733', + // @ref: http://pdadb.net/index.php?m=pdalist&list=SMiT (NoName Chinese Tablets) + // @ref: http://www.imp3.net/14/show.php?itemid=20454 + 'SMiTTablet' => 'Android.*(\bMID\b|MID-560|MTV-T1200|MTV-PND531|MTV-P1101|MTV-PND530)', + // @ref: http://www.rock-chips.com/index.php?do=prod&pid=2 + 'RockChipTablet' => 'Android.*(RK2818|RK2808A|RK2918|RK3066)|RK2738|RK2808A', + // @ref: http://www.fly-phone.com/devices/tablets/ ; http://www.fly-phone.com/service/ + 'FlyTablet' => 'IQ310|Fly Vision', + // @ref: http://www.bqreaders.com/gb/tablets-prices-sale.html + 'bqTablet' => 'bq.*(Elcano|Curie|Edison|Maxwell|Kepler|Pascal|Tesla|Hypatia|Platon|Newton|Livingstone|Cervantes|Avant)|Maxwell.*Lite|Maxwell.*Plus', + // @ref: http://www.huaweidevice.com/worldwide/productFamily.do?method=index&directoryId=5011&treeId=3290 + // @ref: http://www.huaweidevice.com/worldwide/downloadCenter.do?method=index&directoryId=3372&treeId=0&tb=1&type=software (including legacy tablets) + 'HuaweiTablet' => 'MediaPad|MediaPad 7 Youth|IDEOS S7|S7-201c|S7-202u|S7-101|S7-103|S7-104|S7-105|S7-106|S7-201|S7-Slim', + // Nec or Medias Tab + 'NecTablet' => '\bN-06D|\bN-08D', + // Pantech Tablets: http://www.pantechusa.com/phones/ + 'PantechTablet' => 'Pantech.*P4100', + // Broncho Tablets: http://www.broncho.cn/ (hard to find) + 'BronchoTablet' => 'Broncho.*(N701|N708|N802|a710)', + // @ref: http://versusuk.com/support.html + 'VersusTablet' => 'TOUCHPAD.*[78910]|\bTOUCHTAB\b', + // @ref: http://www.zync.in/index.php/our-products/tablet-phablets + 'ZyncTablet' => 'z1000|Z99 2G|z99|z930|z999|z990|z909|Z919|z900', + // @ref: http://www.positivoinformatica.com.br/www/pessoal/tablet-ypy/ + 'PositivoTablet' => 'TB07STA|TB10STA|TB07FTA|TB10FTA', + // @ref: https://www.nabitablet.com/ + 'NabiTablet' => 'Android.*\bNabi', + 'KoboTablet' => 'Kobo Touch|\bK080\b|\bVox\b Build|\bArc\b Build', + // French Danew Tablets http://www.danew.com/produits-tablette.php + 'DanewTablet' => 'DSlide.*\b(700|701R|702|703R|704|802|970|971|972|973|974|1010|1012)\b', + // Texet Tablets and Readers http://www.texet.ru/tablet/ + 'TexetTablet' => 'NaviPad|TB-772A|TM-7045|TM-7055|TM-9750|TM-7016|TM-7024|TM-7026|TM-7041|TM-7043|TM-7047|TM-8041|TM-9741|TM-9747|TM-9748|TM-9751|TM-7022|TM-7021|TM-7020|TM-7011|TM-7010|TM-7023|TM-7025|TM-7037W|TM-7038W|TM-7027W|TM-9720|TM-9725|TM-9737W|TM-1020|TM-9738W|TM-9740|TM-9743W|TB-807A|TB-771A|TB-727A|TB-725A|TB-719A|TB-823A|TB-805A|TB-723A|TB-715A|TB-707A|TB-705A|TB-709A|TB-711A|TB-890HD|TB-880HD|TB-790HD|TB-780HD|TB-770HD|TB-721HD|TB-710HD|TB-434HD|TB-860HD|TB-840HD|TB-760HD|TB-750HD|TB-740HD|TB-730HD|TB-722HD|TB-720HD|TB-700HD|TB-500HD|TB-470HD|TB-431HD|TB-430HD|TB-506|TB-504|TB-446|TB-436|TB-416|TB-146SE|TB-126SE', + // @note: Avoid detecting 'PLAYSTATION 3' as mobile. + 'PlaystationTablet' => 'Playstation.*(Portable|Vita)', + // @ref: http://www.trekstor.de/surftabs.html + 'TrekstorTablet' => 'ST10416-1|VT10416-1|ST70408-1|ST702xx-1|ST702xx-2|ST80208|ST97216|ST70104-2|VT10416-2|ST10216-2A', + // @ref: http://www.pyleaudio.com/Products.aspx?%2fproducts%2fPersonal-Electronics%2fTablets + 'PyleAudioTablet' => '\b(PTBL10CEU|PTBL10C|PTBL72BC|PTBL72BCEU|PTBL7CEU|PTBL7C|PTBL92BC|PTBL92BCEU|PTBL9CEU|PTBL9CUK|PTBL9C)\b', + // @ref: http://www.advandigital.com/index.php?link=content-product&jns=JP001 + // @Note: because of the short codenames we have to include whitespaces to reduce the possible conflicts. + 'AdvanTablet' => 'Android.* \b(E3A|T3X|T5C|T5B|T3E|T3C|T3B|T1J|T1F|T2A|T1H|T1i|E1C|T1-E|T5-A|T4|E1-B|T2Ci|T1-B|T1-D|O1-A|E1-A|T1-A|T3A|T4i)\b ', + // @ref: http://www.danytech.com/category/tablet-pc + 'DanyTechTablet' => 'Genius Tab G3|Genius Tab S2|Genius Tab Q3|Genius Tab G4|Genius Tab Q4|Genius Tab G-II|Genius TAB GII|Genius TAB GIII|Genius Tab S1', + // @ref: http://www.galapad.net/product.html + 'GalapadTablet' => 'Android.*\bG1\b', + // @ref: http://www.micromaxinfo.com/tablet/funbook + 'MicromaxTablet' => 'Funbook|Micromax.*\b(P250|P560|P360|P362|P600|P300|P350|P500|P275)\b', + // http://www.karbonnmobiles.com/products_tablet.php + 'KarbonnTablet' => 'Android.*\b(A39|A37|A34|ST8|ST10|ST7|Smart Tab3|Smart Tab2)\b', + // @ref: http://www.myallfine.com/Products.asp + 'AllFineTablet' => 'Fine7 Genius|Fine7 Shine|Fine7 Air|Fine8 Style|Fine9 More|Fine10 Joy|Fine11 Wide', + // @ref: http://www.proscanvideo.com/products-search.asp?itemClass=TABLET&itemnmbr= + 'PROSCANTablet' => '\b(PEM63|PLT1023G|PLT1041|PLT1044|PLT1044G|PLT1091|PLT4311|PLT4311PL|PLT4315|PLT7030|PLT7033|PLT7033D|PLT7035|PLT7035D|PLT7044K|PLT7045K|PLT7045KB|PLT7071KG|PLT7072|PLT7223G|PLT7225G|PLT7777G|PLT7810K|PLT7849G|PLT7851G|PLT7852G|PLT8015|PLT8031|PLT8034|PLT8036|PLT8080K|PLT8082|PLT8088|PLT8223G|PLT8234G|PLT8235G|PLT8816K|PLT9011|PLT9045K|PLT9233G|PLT9735|PLT9760G|PLT9770G)\b', + // @ref: http://www.yonesnav.com/products/products.php + 'YONESTablet' => 'BQ1078|BC1003|BC1077|RK9702|BC9730|BC9001|IT9001|BC7008|BC7010|BC708|BC728|BC7012|BC7030|BC7027|BC7026', + // @ref: http://www.cjshowroom.com/eproducts.aspx?classcode=004001001 + // China manufacturer makes tablets for different small brands (eg. http://www.zeepad.net/index.html) + 'ChangJiaTablet' => 'TPC7102|TPC7103|TPC7105|TPC7106|TPC7107|TPC7201|TPC7203|TPC7205|TPC7210|TPC7708|TPC7709|TPC7712|TPC7110|TPC8101|TPC8103|TPC8105|TPC8106|TPC8203|TPC8205|TPC8503|TPC9106|TPC9701|TPC97101|TPC97103|TPC97105|TPC97106|TPC97111|TPC97113|TPC97203|TPC97603|TPC97809|TPC97205|TPC10101|TPC10103|TPC10106|TPC10111|TPC10203|TPC10205|TPC10503', + // @ref: http://www.gloryunion.cn/products.asp + // @ref: http://www.allwinnertech.com/en/apply/mobile.html + // @ref: http://www.ptcl.com.pk/pd_content.php?pd_id=284 (EVOTAB) + // @todo: Softwiner tablets? + // aka. Cute or Cool tablets. Not sure yet, must research to avoid collisions. + 'GUTablet' => 'TX-A1301|TX-M9002|Q702|kf026', // A12R|D75A|D77|D79|R83|A95|A106C|R15|A75|A76|D71|D72|R71|R73|R77|D82|R85|D92|A97|D92|R91|A10F|A77F|W71F|A78F|W78F|W81F|A97F|W91F|W97F|R16G|C72|C73E|K72|K73|R96G + // @ref: http://www.pointofview-online.com/showroom.php?shop_mode=product_listing&category_id=118 + 'PointOfViewTablet' => 'TAB-P506|TAB-navi-7-3G-M|TAB-P517|TAB-P-527|TAB-P701|TAB-P703|TAB-P721|TAB-P731N|TAB-P741|TAB-P825|TAB-P905|TAB-P925|TAB-PR945|TAB-PL1015|TAB-P1025|TAB-PI1045|TAB-P1325|TAB-PROTAB[0-9]+|TAB-PROTAB25|TAB-PROTAB26|TAB-PROTAB27|TAB-PROTAB26XL|TAB-PROTAB2-IPS9|TAB-PROTAB30-IPS9|TAB-PROTAB25XXL|TAB-PROTAB26-IPS10|TAB-PROTAB30-IPS10', + // @ref: http://www.overmax.pl/pl/katalog-produktow,p8/tablety,c14/ + // @todo: add more tests. + 'OvermaxTablet' => 'OV-(SteelCore|NewBase|Basecore|Baseone|Exellen|Quattor|EduTab|Solution|ACTION|BasicTab|TeddyTab|MagicTab|Stream|TB-08|TB-09)', + // @ref: http://hclmetablet.com/India/index.php + 'HCLTablet' => 'HCL.*Tablet|Connect-3G-2.0|Connect-2G-2.0|ME Tablet U1|ME Tablet U2|ME Tablet G1|ME Tablet X1|ME Tablet Y2|ME Tablet Sync', + // @ref: http://www.edigital.hu/Tablet_es_e-book_olvaso/Tablet-c18385.html + 'DPSTablet' => 'DPS Dream 9|DPS Dual 7', + // @ref: http://www.visture.com/index.asp + 'VistureTablet' => 'V97 HD|i75 3G|Visture V4( HD)?|Visture V5( HD)?|Visture V10', + // @ref: http://www.mijncresta.nl/tablet + 'CrestaTablet' => 'CTP(-)?810|CTP(-)?818|CTP(-)?828|CTP(-)?838|CTP(-)?888|CTP(-)?978|CTP(-)?980|CTP(-)?987|CTP(-)?988|CTP(-)?989', + // MediaTek - http://www.mediatek.com/_en/01_products/02_proSys.php?cata_sn=1&cata1_sn=1&cata2_sn=309 + 'MediatekTablet' => '\bMT8125|MT8389|MT8135|MT8377\b', + // Concorde tab + 'ConcordeTablet' => 'Concorde([ ]+)?Tab|ConCorde ReadMan', + // GoClever Tablets - http://www.goclever.com/uk/products,c1/tablet,c5/ + 'GoCleverTablet' => 'GOCLEVER TAB|A7GOCLEVER|M1042|M7841|M742|R1042BK|R1041|TAB A975|TAB A7842|TAB A741|TAB A741L|TAB M723G|TAB M721|TAB A1021|TAB I921|TAB R721|TAB I720|TAB T76|TAB R70|TAB R76.2|TAB R106|TAB R83.2|TAB M813G|TAB I721|GCTA722|TAB I70|TAB I71|TAB S73|TAB R73|TAB R74|TAB R93|TAB R75|TAB R76.1|TAB A73|TAB A93|TAB A93.2|TAB T72|TAB R83|TAB R974|TAB R973|TAB A101|TAB A103|TAB A104|TAB A104.2|R105BK|M713G|A972BK|TAB A971|TAB R974.2|TAB R104|TAB R83.3|TAB A1042', + // Modecom Tablets - http://www.modecom.eu/tablets/portal/ + 'ModecomTablet' => 'FreeTAB 9000|FreeTAB 7.4|FreeTAB 7004|FreeTAB 7800|FreeTAB 2096|FreeTAB 7.5|FreeTAB 1014|FreeTAB 1001 |FreeTAB 8001|FreeTAB 9706|FreeTAB 9702|FreeTAB 7003|FreeTAB 7002|FreeTAB 1002|FreeTAB 7801|FreeTAB 1331|FreeTAB 1004|FreeTAB 8002|FreeTAB 8014|FreeTAB 9704|FreeTAB 1003', + // Vonino Tablets - http://www.vonino.eu/tablets + 'VoninoTablet' => '\b(Argus[ _]?S|Diamond[ _]?79HD|Emerald[ _]?78E|Luna[ _]?70C|Onyx[ _]?S|Onyx[ _]?Z|Orin[ _]?HD|Orin[ _]?S|Otis[ _]?S|SpeedStar[ _]?S|Magnet[ _]?M9|Primus[ _]?94[ _]?3G|Primus[ _]?94HD|Primus[ _]?QS|Android.*\bQ8\b|Sirius[ _]?EVO[ _]?QS|Sirius[ _]?QS|Spirit[ _]?S)\b', + // ECS Tablets - http://www.ecs.com.tw/ECSWebSite/Product/Product_Tablet_List.aspx?CategoryID=14&MenuID=107&childid=M_107&LanID=0 + 'ECSTablet' => 'V07OT2|TM105A|S10OT1|TR10CS1', + // Storex Tablets - http://storex.fr/espace_client/support.html + // @note: no need to add all the tablet codes since they are guided by the first regex. + 'StorexTablet' => 'eZee[_\']?(Tab|Go)[0-9]+|TabLC7|Looney Tunes Tab', + // Generic Vodafone tablets. + 'VodafoneTablet' => 'SmartTab([ ]+)?[0-9]+|SmartTabII10', + // French tablets - Essentiel B http://www.boulanger.fr/tablette_tactile_e-book/tablette_tactile_essentiel_b/cl_68908.htm?multiChoiceToDelete=brand&mc_brand=essentielb + // Aka: http://www.essentielb.fr/ + 'EssentielBTablet' => 'Smart[ \']?TAB[ ]+?[0-9]+|Family[ \']?TAB2', + // Ross & Moor - http://ross-moor.ru/ + 'RossMoorTablet' => 'RM-790|RM-997|RMD-878G|RMD-974R|RMT-705A|RMT-701|RME-601|RMT-501|RMT-711', + // i-mobile http://product.i-mobilephone.com/Mobile_Device + 'iMobileTablet' => 'i-mobile i-note', + // @ref: http://www.tolino.de/de/vergleichen/ + 'TolinoTablet' => 'tolino tab [0-9.]+|tolino shine', + // AudioSonic - a Kmart brand + // http://www.kmart.com.au/webapp/wcs/stores/servlet/Search?langId=-1&storeId=10701&catalogId=10001&categoryId=193001&pageSize=72¤tPage=1&searchCategory=193001%2b4294965664&sortBy=p_MaxPrice%7c1 + 'AudioSonicTablet' => '\bC-22Q|T7-QC|T-17B|T-17P\b', + // AMPE Tablets - http://www.ampe.com.my/product-category/tablets/ + // @todo: add them gradually to avoid conflicts. + 'AMPETablet' => 'Android.* A78 ', + // Skk Mobile - http://skkmobile.com.ph/product_tablets.php + 'SkkTablet' => 'Android.* (SKYPAD|PHOENIX|CYCLOPS)', + // Tecno Mobile (only tablet) - http://www.tecno-mobile.com/index.php/product?filterby=smart&list_order=all&page=1 + 'TecnoTablet' => 'TECNO P9', + // JXD (consoles & tablets) - http://jxd.hk/products.asp?selectclassid=009008&clsid=3 + 'JXDTablet' => 'Android.*\b(F3000|A3300|JXD5000|JXD3000|JXD2000|JXD300B|JXD300|S5800|S7800|S602b|S5110b|S7300|S5300|S602|S603|S5100|S5110|S601|S7100a|P3000F|P3000s|P101|P200s|P1000m|P200m|P9100|P1000s|S6600b|S908|P1000|P300|S18|S6600|S9100)\b', + // i-Joy tablets - http://www.i-joy.es/en/cat/products/tablets/ + 'iJoyTablet' => 'Tablet (Spirit 7|Essentia|Galatea|Fusion|Onix 7|Landa|Titan|Scooby|Deox|Stella|Themis|Argon|Unique 7|Sygnus|Hexen|Finity 7|Cream|Cream X2|Jade|Neon 7|Neron 7|Kandy|Scape|Saphyr 7|Rebel|Biox|Rebel|Rebel 8GB|Myst|Draco 7|Myst|Tab7-004|Myst|Tadeo Jones|Tablet Boing|Arrow|Draco Dual Cam|Aurix|Mint|Amity|Revolution|Finity 9|Neon 9|T9w|Amity 4GB Dual Cam|Stone 4GB|Stone 8GB|Andromeda|Silken|X2|Andromeda II|Halley|Flame|Saphyr 9,7|Touch 8|Planet|Triton|Unique 10|Hexen 10|Memphis 4GB|Memphis 8GB|Onix 10)', + // http://www.intracon.eu/tablet + 'FX2Tablet' => 'FX2 PAD7|FX2 PAD10', + // http://www.xoro.de/produkte/ + // @note: Might be the same brand with 'Simply tablets' + 'XoroTablet' => 'KidsPAD 701|PAD[ ]?712|PAD[ ]?714|PAD[ ]?716|PAD[ ]?717|PAD[ ]?718|PAD[ ]?720|PAD[ ]?721|PAD[ ]?722|PAD[ ]?790|PAD[ ]?792|PAD[ ]?900|PAD[ ]?9715D|PAD[ ]?9716DR|PAD[ ]?9718DR|PAD[ ]?9719QR|PAD[ ]?9720QR|TelePAD1030|Telepad1032|TelePAD730|TelePAD731|TelePAD732|TelePAD735Q|TelePAD830|TelePAD9730|TelePAD795|MegaPAD 1331|MegaPAD 1851|MegaPAD 2151', + // http://www1.viewsonic.com/products/computing/tablets/ + 'ViewsonicTablet' => 'ViewPad 10pi|ViewPad 10e|ViewPad 10s|ViewPad E72|ViewPad7|ViewPad E100|ViewPad 7e|ViewSonic VB733|VB100a', + // http://www.odys.de/web/internet-tablet_en.html + 'OdysTablet' => 'LOOX|XENO10|ODYS Space', + // http://www.captiva-power.de/products.html#tablets-en + 'CaptivaTablet' => 'CAPTIVA PAD', + // IconBIT - http://www.iconbit.com/products/tablets/ + 'IconbitTablet' => 'NetTAB|NT-3702|NT-3702S|NT-3702S|NT-3603P|NT-3603P|NT-0704S|NT-0704S|NT-3805C|NT-3805C|NT-0806C|NT-0806C|NT-0909T|NT-0909T|NT-0907S|NT-0907S|NT-0902S|NT-0902S', + // @ref: http://www.tesco.com/direct/hudl/ + 'Hudl' => 'Hudl HT7S3', + // @ref: http://www.telstra.com.au/home-phone/thub-2/ + 'TelstraTablet' => 'T-Hub2', + 'GenericTablet' => 'Android.*\b97D\b|Tablet(?!.*PC)|BNTV250A|MID-WCDMA|LogicPD Zoom2|\bA7EB\b|CatNova8|A1_07|CT704|CT1002|\bM721\b|rk30sdk|\bEVOTAB\b|M758A|ET904|ALUMIUM10|Smartfren Tab|Endeavour 1010|Tablet-PC-4', + ); + + /** + * List of mobile Operating Systems. + * + * @var array + */ + protected static $operatingSystems = array( + 'AndroidOS' => 'Android', + 'BlackBerryOS' => 'blackberry|\bBB10\b|rim tablet os', + 'PalmOS' => 'PalmOS|avantgo|blazer|elaine|hiptop|palm|plucker|xiino', + 'SymbianOS' => 'Symbian|SymbOS|Series60|Series40|SYB-[0-9]+|\bS60\b', + // @reference: http://en.wikipedia.org/wiki/Windows_Mobile + 'WindowsMobileOS' => 'Windows CE.*(PPC|Smartphone|Mobile|[0-9]{3}x[0-9]{3})|Window Mobile|Windows Phone [0-9.]+|WCE;', + // @reference: http://en.wikipedia.org/wiki/Windows_Phone + // http://wifeng.cn/?r=blog&a=view&id=106 + // http://nicksnettravels.builttoroam.com/post/2011/01/10/Bogus-Windows-Phone-7-User-Agent-String.aspx + 'WindowsPhoneOS' => 'Windows Phone 8.0|Windows Phone OS|XBLWP7|ZuneWP7', + 'iOS' => '\biPhone.*Mobile|\biPod|\biPad', + // http://en.wikipedia.org/wiki/MeeGo + // @todo: research MeeGo in UAs + 'MeeGoOS' => 'MeeGo', + // http://en.wikipedia.org/wiki/Maemo + // @todo: research Maemo in UAs + 'MaemoOS' => 'Maemo', + 'JavaOS' => 'J2ME/|\bMIDP\b|\bCLDC\b', // '|Java/' produces bug #135 + 'webOS' => 'webOS|hpwOS', + 'badaOS' => '\bBada\b', + 'BREWOS' => 'BREW', + ); + + /** + * List of mobile User Agents. + * + * @var array + */ + protected static $browsers = array( + // @reference: https://developers.google.com/chrome/mobile/docs/user-agent + 'Chrome' => '\bCrMo\b|CriOS|Android.*Chrome/[.0-9]* (Mobile)?', + 'Dolfin' => '\bDolfin\b', + 'Opera' => 'Opera.*Mini|Opera.*Mobi|Android.*Opera|Mobile.*OPR/[0-9.]+|Coast/[0-9.]+', + 'Skyfire' => 'Skyfire', + 'IE' => 'IEMobile|MSIEMobile', // |Trident/[.0-9]+ + 'Firefox' => 'fennec|firefox.*maemo|(Mobile|Tablet).*Firefox|Firefox.*Mobile', + 'Bolt' => 'bolt', + 'TeaShark' => 'teashark', + 'Blazer' => 'Blazer', + // @reference: http://developer.apple.com/library/safari/#documentation/AppleApplications/Reference/SafariWebContent/OptimizingforSafarioniPhone/OptimizingforSafarioniPhone.html#//apple_ref/doc/uid/TP40006517-SW3 + 'Safari' => 'Version.*Mobile.*Safari|Safari.*Mobile', + // @ref: http://en.wikipedia.org/wiki/Midori_(web_browser) + //'Midori' => 'midori', + 'Tizen' => 'Tizen', + 'UCBrowser' => 'UC.*Browser|UCWEB', + // @ref: https://github.com/serbanghita/Mobile-Detect/issues/7 + 'DiigoBrowser' => 'DiigoBrowser', + // http://www.puffinbrowser.com/index.php + 'Puffin' => 'Puffin', + // @ref: http://mercury-browser.com/index.html + 'Mercury' => '\bMercury\b', + // @reference: http://en.wikipedia.org/wiki/Minimo + // http://en.wikipedia.org/wiki/Vision_Mobile_Browser + 'GenericBrowser' => 'NokiaBrowser|OviBrowser|OneBrowser|TwonkyBeamBrowser|SEMC.*Browser|FlyFlow|Minimo|NetFront|Novarra-Vision|MQQBrowser|MicroMessenger' + ); + + /** + * Utilities. + * + * @var array + */ + protected static $utilities = array( + // Experimental. When a mobile device wants to switch to 'Desktop Mode'. + // @ref: http://scottcate.com/technology/windows-phone-8-ie10-desktop-or-mobile/ + // @ref: https://github.com/serbanghita/Mobile-Detect/issues/57#issuecomment-15024011 + 'DesktopMode' => 'WPDesktop', + 'TV' => 'SonyDTV|HbbTV', // experimental + 'WebKit' => '(webkit)[ /]([\w.]+)', + 'Bot' => 'Googlebot|DoCoMo|YandexBot|bingbot|ia_archiver|AhrefsBot|Ezooms|GSLFbot|WBSearchBot|Twitterbot|TweetmemeBot|Twikle|PaperLiBot|Wotbox|UnwindFetchor|facebookexternalhit', + 'MobileBot' => 'Googlebot-Mobile|DoCoMo|YahooSeeker/M1A1-R2D2', + // @todo: Include JXD consoles. + 'Console' => '\b(Nintendo|Nintendo WiiU|PLAYSTATION|Xbox)\b', + 'Watch' => 'SM-V700', + ); + + /** + * All possible HTTP headers that represent the + * User-Agent string. + * + * @var array + */ + protected static $uaHttpHeaders = array( + // The default User-Agent string. + 'HTTP_USER_AGENT', + // Header can occur on devices using Opera Mini. + 'HTTP_X_OPERAMINI_PHONE_UA', + // Vodafone specific header: http://www.seoprinciple.com/mobile-web-community-still-angry-at-vodafone/24/ + 'HTTP_X_DEVICE_USER_AGENT', + 'HTTP_X_ORIGINAL_USER_AGENT', + 'HTTP_X_SKYFIRE_PHONE', + 'HTTP_X_BOLT_PHONE_UA', + 'HTTP_DEVICE_STOCK_UA', + 'HTTP_X_UCBROWSER_DEVICE_UA' + ); + + /** + * The individual segments that could exist in a User-Agent string. VER refers to the regular + * expression defined in the constant self::VER. + * + * @var array + */ + protected static $properties = array( + + // Build + 'Mobile' => 'Mobile/[VER]', + 'Build' => 'Build/[VER]', + 'Version' => 'Version/[VER]', + 'VendorID' => 'VendorID/[VER]', + + // Devices + 'iPad' => 'iPad.*CPU[a-z ]+[VER]', + 'iPhone' => 'iPhone.*CPU[a-z ]+[VER]', + 'iPod' => 'iPod.*CPU[a-z ]+[VER]', + //'BlackBerry' => array('BlackBerry[VER]', 'BlackBerry [VER];'), + 'Kindle' => 'Kindle/[VER]', + + // Browser + 'Chrome' => array('Chrome/[VER]', 'CriOS/[VER]', 'CrMo/[VER]'), + 'Coast' => array('Coast/[VER]'), + 'Dolfin' => 'Dolfin/[VER]', + // @reference: https://developer.mozilla.org/en-US/docs/User_Agent_Strings_Reference + 'Firefox' => 'Firefox/[VER]', + 'Fennec' => 'Fennec/[VER]', + // @reference: http://msdn.microsoft.com/en-us/library/ms537503(v=vs.85).aspx + 'IE' => array('IEMobile/[VER];', 'IEMobile [VER]', 'MSIE [VER];'), + // http://en.wikipedia.org/wiki/NetFront + 'NetFront' => 'NetFront/[VER]', + 'NokiaBrowser' => 'NokiaBrowser/[VER]', + 'Opera' => array( ' OPR/[VER]', 'Opera Mini/[VER]', 'Version/[VER]' ), + 'Opera Mini' => 'Opera Mini/[VER]', + 'Opera Mobi' => 'Version/[VER]', + 'UC Browser' => 'UC Browser[VER]', + 'MQQBrowser' => 'MQQBrowser/[VER]', + 'MicroMessenger' => 'MicroMessenger/[VER]', + // @note: Safari 7534.48.3 is actually Version 5.1. + // @note: On BlackBerry the Version is overwriten by the OS. + 'Safari' => array( 'Version/[VER]', 'Safari/[VER]' ), + 'Skyfire' => 'Skyfire/[VER]', + 'Tizen' => 'Tizen/[VER]', + 'Webkit' => 'webkit[ /][VER]', + + // Engine + 'Gecko' => 'Gecko/[VER]', + 'Trident' => 'Trident/[VER]', + 'Presto' => 'Presto/[VER]', + + // OS + 'iOS' => ' \bOS\b [VER] ', + 'Android' => 'Android [VER]', + 'BlackBerry' => array('BlackBerry[\w]+/[VER]', 'BlackBerry.*Version/[VER]', 'Version/[VER]'), + 'BREW' => 'BREW [VER]', + 'Java' => 'Java/[VER]', + // @reference: http://windowsteamblog.com/windows_phone/b/wpdev/archive/2011/08/29/introducing-the-ie9-on-windows-phone-mango-user-agent-string.aspx + // @reference: http://en.wikipedia.org/wiki/Windows_NT#Releases + 'Windows Phone OS' => array( 'Windows Phone OS [VER]', 'Windows Phone [VER]'), + 'Windows Phone' => 'Windows Phone [VER]', + 'Windows CE' => 'Windows CE/[VER]', + // http://social.msdn.microsoft.com/Forums/en-US/windowsdeveloperpreviewgeneral/thread/6be392da-4d2f-41b4-8354-8dcee20c85cd + 'Windows NT' => 'Windows NT [VER]', + 'Symbian' => array('SymbianOS/[VER]', 'Symbian/[VER]'), + 'webOS' => array('webOS/[VER]', 'hpwOS/[VER];'), + ); + + /** + * Construct an instance of this class. + * + * @param array $headers Specify the headers as injection. Should be PHP _SERVER flavored. + * If left empty, will use the global _SERVER['HTTP_*'] vars instead. + * @param string $userAgent Inject the User-Agent header. If null, will use HTTP_USER_AGENT + * from the $headers array instead. + */ + public function __construct( + array $headers = null, + $userAgent = null + ){ + $this->setHttpHeaders($headers); + $this->setUserAgent($userAgent); + } + + /** + * Get the current script version. + * This is useful for the demo.php file, + * so people can check on what version they are testing + * for mobile devices. + * + * @return string The version number in semantic version format. + */ + public static function getScriptVersion() + { + return self::VERSION; + } + + /** + * Set the HTTP Headers. Must be PHP-flavored. This method will reset existing headers. + * + * @param array $httpHeaders The headers to set. If null, then using PHP's _SERVER to extract + * the headers. The default null is left for backwards compatibilty. + */ + public function setHttpHeaders($httpHeaders = null) + { + //use global _SERVER if $httpHeaders aren't defined + if (!is_array($httpHeaders) || !count($httpHeaders)) { + $httpHeaders = $_SERVER; + } + + //clear existing headers + $this->httpHeaders = array(); + + //Only save HTTP headers. In PHP land, that means only _SERVER vars that + //start with HTTP_. + foreach ($httpHeaders as $key => $value) { + if (substr($key,0,5) == 'HTTP_') { + $this->httpHeaders[$key] = $value; + } + } + } + + /** + * Retrieves the HTTP headers. + * + * @return array + */ + public function getHttpHeaders() + { + return $this->httpHeaders; + } + + /** + * Retrieves a particular header. If it doesn't exist, no exception/error is caused. + * Simply null is returned. + * + * @param string $header The name of the header to retrieve. Can be HTTP compliant such as + * "User-Agent" or "X-Device-User-Agent" or can be php-esque with the + * all-caps, HTTP_ prefixed, underscore seperated awesomeness. + * + * @return string|null The value of the header. + */ + public function getHttpHeader($header) + { + //are we using PHP-flavored headers? + if (strpos($header, '_') === false) { + $header = str_replace('-', '_', $header); + $header = strtoupper($header); + } + + //test the alternate, too + $altHeader = 'HTTP_' . $header; + + //Test both the regular and the HTTP_ prefix + if (isset($this->httpHeaders[$header])) { + return $this->httpHeaders[$header]; + } elseif (isset($this->httpHeaders[$altHeader])) { + return $this->httpHeaders[$altHeader]; + } + + return null; + } + + public function getMobileHeaders() + { + return self::$mobileHeaders; + } + + /** + * Get all possible HTTP headers that + * can contain the User-Agent string. + * + * @return array List of HTTP headers. + */ + public function getUaHttpHeaders() + { + return self::$uaHttpHeaders; + } + + /** + * Set the User-Agent to be used. + * + * @param string $userAgent The user agent string to set. + * + * @return string|null + */ + public function setUserAgent($userAgent = null) + { + if (!empty($userAgent)) { + return $this->userAgent = $userAgent; + } else { + + $this->userAgent = null; + + foreach($this->getUaHttpHeaders() as $altHeader){ + if(!empty($this->httpHeaders[$altHeader])){ // @todo: should use getHttpHeader(), but it would be slow. (Serban) + $this->userAgent .= $this->httpHeaders[$altHeader] . " "; + } + } + + return $this->userAgent = (!empty($this->userAgent) ? trim($this->userAgent) : null); + + } + } + + /** + * Retrieve the User-Agent. + * + * @return string|null The user agent if it's set. + */ + public function getUserAgent() + { + return $this->userAgent; + } + + /** + * Set the detection type. Must be one of self::DETECTION_TYPE_MOBILE or + * self::DETECTION_TYPE_EXTENDED. Otherwise, nothing is set. + * + * @deprecated since version 2.6.9 + * + * @param string $type The type. Must be a self::DETECTION_TYPE_* constant. The default + * parameter is null which will default to self::DETECTION_TYPE_MOBILE. + */ + public function setDetectionType($type = null) + { + if ($type === null) { + $type = self::DETECTION_TYPE_MOBILE; + } + + if ($type != self::DETECTION_TYPE_MOBILE && $type != self::DETECTION_TYPE_EXTENDED) { + return; + } + + $this->detectionType = $type; + } + + /** + * Retrieve the list of known phone devices. + * + * @return array List of phone devices. + */ + public static function getPhoneDevices() + { + return self::$phoneDevices; + } + + /** + * Retrieve the list of known tablet devices. + * + * @return array List of tablet devices. + */ + public static function getTabletDevices() + { + return self::$tabletDevices; + } + + /** + * Alias for getBrowsers() method. + * + * @return array List of user agents. + */ + public static function getUserAgents() + { + return self::getBrowsers(); + } + + /** + * Retrieve the list of known browsers. Specifically, the user agents. + * + * @return array List of browsers / user agents. + */ + public static function getBrowsers() + { + return self::$browsers; + } + + /** + * Retrieve the list of known utilities. + * + * @return array List of utilities. + */ + public static function getUtilities() + { + return self::$utilities; + } + + /** + * Method gets the mobile detection rules. This method is used for the magic methods $detect->is*(). + * + * @deprecated since version 2.6.9 + * + * @return array All the rules (but not extended). + */ + public static function getMobileDetectionRules() + { + static $rules; + + if (!$rules) { + $rules = array_merge( + self::$phoneDevices, + self::$tabletDevices, + self::$operatingSystems, + self::$browsers + ); + } + + return $rules; + + } + + /** + * Method gets the mobile detection rules + utilities. + * The reason this is separate is because utilities rules + * don't necessary imply mobile. This method is used inside + * the new $detect->is('stuff') method. + * + * @deprecated since version 2.6.9 + * + * @return array All the rules + extended. + */ + public function getMobileDetectionRulesExtended() + { + static $rules; + + if (!$rules) { + // Merge all rules together. + $rules = array_merge( + self::$phoneDevices, + self::$tabletDevices, + self::$operatingSystems, + self::$browsers, + self::$utilities + ); + } + + return $rules; + } + + /** + * Retrieve the current set of rules. + * + * @deprecated since version 2.6.9 + * + * @return array + */ + public function getRules() + { + if ($this->detectionType == self::DETECTION_TYPE_EXTENDED) { + return self::getMobileDetectionRulesExtended(); + } else { + return self::getMobileDetectionRules(); + } + } + + /** + * Retrieve the list of mobile operating systems. + * + * @return array The list of mobile operating systems. + */ + public static function getOperatingSystems() + { + return self::$operatingSystems; + } + + /** + * Check the HTTP headers for signs of mobile. + * This is the fastest mobile check possible; it's used + * inside isMobile() method. + * + * @return bool + */ + public function checkHttpHeadersForMobile() + { + + foreach($this->getMobileHeaders() as $mobileHeader => $matchType){ + if( isset($this->httpHeaders[$mobileHeader]) ){ + if( is_array($matchType['matches']) ){ + foreach($matchType['matches'] as $_match){ + if( strpos($this->httpHeaders[$mobileHeader], $_match) !== false ){ + return true; + } + } + return false; + } else { + return true; + } + } + } + + return false; + + } + + /** + * Magic overloading method. + * + * @method boolean is[...]() + * @param string $name + * @param array $arguments + * @return mixed + * @throws BadMethodCallException when the method doesn't exist and doesn't start with 'is' + */ + public function __call($name, $arguments) + { + //make sure the name starts with 'is', otherwise + if (substr($name, 0, 2) != 'is') { + throw new BadMethodCallException("No such method exists: $name"); + } + + $this->setDetectionType(self::DETECTION_TYPE_MOBILE); + + $key = substr($name, 2); + + return $this->matchUAAgainstKey($key); + } + + /** + * Find a detection rule that matches the current User-agent. + * + * @param null $userAgent deprecated + * @return boolean + */ + protected function matchDetectionRulesAgainstUA($userAgent = null) + { + // Begin general search. + foreach ($this->getRules() as $_regex) { + if (empty($_regex)) { + continue; + } + if ($this->match($_regex, $userAgent)) { + return true; + } + } + + return false; + } + + /** + * Search for a certain key in the rules array. + * If the key is found the try to match the corresponding + * regex agains the User-Agent. + * + * @param string $key + * @param null $userAgent deprecated + * @return mixed + */ + protected function matchUAAgainstKey($key, $userAgent = null) + { + // Make the keys lowercase so we can match: isIphone(), isiPhone(), isiphone(), etc. + $key = strtolower($key); + + //change the keys to lower case + $_rules = array_change_key_case($this->getRules()); + + if (array_key_exists($key, $_rules)) { + if (empty($_rules[$key])) { + return null; + } + + return $this->match($_rules[$key], $userAgent); + } + + return false; + } + + /** + * Check if the device is mobile. + * Returns true if any type of mobile device detected, including special ones + * @param null $userAgent deprecated + * @param null $httpHeaders deprecated + * @return bool + */ + public function isMobile($userAgent = null, $httpHeaders = null) + { + + if ($httpHeaders) { + $this->setHttpHeaders($httpHeaders); + } + + if ($userAgent) { + $this->setUserAgent($userAgent); + } + + $this->setDetectionType(self::DETECTION_TYPE_MOBILE); + + if ($this->checkHttpHeadersForMobile()) { + return true; + } else { + return $this->matchDetectionRulesAgainstUA(); + } + + } + + /** + * Check if the device is a tablet. + * Return true if any type of tablet device is detected. + * + * @param string $userAgent deprecated + * @param array $httpHeaders deprecated + * @return bool + */ + public function isTablet($userAgent = null, $httpHeaders = null) + { + $this->setDetectionType(self::DETECTION_TYPE_MOBILE); + + foreach (self::$tabletDevices as $_regex) { + if ($this->match($_regex, $userAgent)) { + return true; + } + } + + return false; + } + + /** + * This method checks for a certain property in the + * userAgent. + * @todo: The httpHeaders part is not yet used. + * + * @param string $key + * @param string $userAgent deprecated + * @param string $httpHeaders deprecated + * @return bool|int|null + */ + public function is($key, $userAgent = null, $httpHeaders = null) + { + // Set the UA and HTTP headers only if needed (eg. batch mode). + if ($httpHeaders) { + $this->setHttpHeaders($httpHeaders); + } + + if ($userAgent) { + $this->setUserAgent($userAgent); + } + + $this->setDetectionType(self::DETECTION_TYPE_EXTENDED); + + return $this->matchUAAgainstKey($key); + } + + /** + * Some detection rules are relative (not standard), + * because of the diversity of devices, vendors and + * their conventions in representing the User-Agent or + * the HTTP headers. + * + * This method will be used to check custom regexes against + * the User-Agent string. + * + * @param $regex + * @param string $userAgent + * @return bool + * + * @todo: search in the HTTP headers too. + */ + public function match($regex, $userAgent = null) + { + // Escape the special character which is the delimiter. + $regex = str_replace('/', '\/', $regex); + + return (bool) preg_match('/'.$regex.'/is', (!empty($userAgent) ? $userAgent : $this->userAgent)); + } + + /** + * Get the properties array. + * + * @return array + */ + public static function getProperties() + { + return self::$properties; + } + + /** + * Prepare the version number. + * + * @todo Remove the error supression from str_replace() call. + * + * @param string $ver The string version, like "2.6.21.2152"; + * + * @return float + */ + public function prepareVersionNo($ver) + { + $ver = str_replace(array('_', ' ', '/'), '.', $ver); + $arrVer = explode('.', $ver, 2); + + if (isset($arrVer[1])) { + $arrVer[1] = @str_replace('.', '', $arrVer[1]); // @todo: treat strings versions. + } + + return (float) implode('.', $arrVer); + } + + /** + * Check the version of the given property in the User-Agent. + * Will return a float number. (eg. 2_0 will return 2.0, 4.3.1 will return 4.31) + * + * @param string $propertyName The name of the property. See self::getProperties() array + * keys for all possible properties. + * @param string $type Either self::VERSION_TYPE_STRING to get a string value or + * self::VERSION_TYPE_FLOAT indicating a float value. This parameter + * is optional and defaults to self::VERSION_TYPE_STRING. Passing an + * invalid parameter will default to the this type as well. + * + * @return string|float The version of the property we are trying to extract. + */ + public function version($propertyName, $type = self::VERSION_TYPE_STRING) + { + if (empty($propertyName)) { + return false; + } + + //set the $type to the default if we don't recognize the type + if ($type != self::VERSION_TYPE_STRING && $type != self::VERSION_TYPE_FLOAT) { + $type = self::VERSION_TYPE_STRING; + } + + $properties = self::getProperties(); + + // Check if the property exists in the properties array. + if (array_key_exists($propertyName, $properties)) { + + // Prepare the pattern to be matched. + // Make sure we always deal with an array (string is converted). + $properties[$propertyName] = (array) $properties[$propertyName]; + + foreach ($properties[$propertyName] as $propertyMatchString) { + + $propertyPattern = str_replace('[VER]', self::VER, $propertyMatchString); + + // Escape the special character which is the delimiter. + $propertyPattern = str_replace('/', '\/', $propertyPattern); + + // Identify and extract the version. + preg_match('/'.$propertyPattern.'/is', $this->userAgent, $match); + + if (!empty($match[1])) { + $version = ( $type == self::VERSION_TYPE_FLOAT ? $this->prepareVersionNo($match[1]) : $match[1] ); + + return $version; + } + + } + + } + + return false; + } + + /** + * Retrieve the mobile grading, using self::MOBILE_GRADE_* constants. + * + * @return string One of the self::MOBILE_GRADE_* constants. + */ + public function mobileGrade() + { + $isMobile = $this->isMobile(); + + if ( + // Apple iOS 3.2-5.1 - Tested on the original iPad (4.3 / 5.0), iPad 2 (4.3), iPad 3 (5.1), original iPhone (3.1), iPhone 3 (3.2), 3GS (4.3), 4 (4.3 / 5.0), and 4S (5.1) + $this->isIOS() && $this->version('iPad', self::VERSION_TYPE_FLOAT)>=4.3 || + $this->isIOS() && $this->version('iPhone', self::VERSION_TYPE_FLOAT)>=3.1 || + $this->isIOS() && $this->version('iPod', self::VERSION_TYPE_FLOAT)>=3.1 || + + // Android 2.1-2.3 - Tested on the HTC Incredible (2.2), original Droid (2.2), HTC Aria (2.1), Google Nexus S (2.3). Functional on 1.5 & 1.6 but performance may be sluggish, tested on Google G1 (1.5) + // Android 3.1 (Honeycomb) - Tested on the Samsung Galaxy Tab 10.1 and Motorola XOOM + // Android 4.0 (ICS) - Tested on a Galaxy Nexus. Note: transition performance can be poor on upgraded devices + // Android 4.1 (Jelly Bean) - Tested on a Galaxy Nexus and Galaxy 7 + ( $this->version('Android', self::VERSION_TYPE_FLOAT)>2.1 && $this->is('Webkit') ) || + + // Windows Phone 7-7.5 - Tested on the HTC Surround (7.0) HTC Trophy (7.5), LG-E900 (7.5), Nokia Lumia 800 + $this->version('Windows Phone OS', self::VERSION_TYPE_FLOAT)>=7.0 || + + // Blackberry 7 - Tested on BlackBerry Torch 9810 + // Blackberry 6.0 - Tested on the Torch 9800 and Style 9670 + $this->is('BlackBerry') && $this->version('BlackBerry', self::VERSION_TYPE_FLOAT)>=6.0 || + // Blackberry Playbook (1.0-2.0) - Tested on PlayBook + $this->match('Playbook.*Tablet') || + + // Palm WebOS (1.4-2.0) - Tested on the Palm Pixi (1.4), Pre (1.4), Pre 2 (2.0) + ( $this->version('webOS', self::VERSION_TYPE_FLOAT)>=1.4 && $this->match('Palm|Pre|Pixi') ) || + // Palm WebOS 3.0 - Tested on HP TouchPad + $this->match('hp.*TouchPad') || + + // Firefox Mobile (12 Beta) - Tested on Android 2.3 device + ( $this->is('Firefox') && $this->version('Firefox', self::VERSION_TYPE_FLOAT)>=12 ) || + + // Chrome for Android - Tested on Android 4.0, 4.1 device + ( $this->is('Chrome') && $this->is('AndroidOS') && $this->version('Android', self::VERSION_TYPE_FLOAT)>=4.0 ) || + + // Skyfire 4.1 - Tested on Android 2.3 device + ( $this->is('Skyfire') && $this->version('Skyfire', self::VERSION_TYPE_FLOAT)>=4.1 && $this->is('AndroidOS') && $this->version('Android', self::VERSION_TYPE_FLOAT)>=2.3 ) || + + // Opera Mobile 11.5-12: Tested on Android 2.3 + ( $this->is('Opera') && $this->version('Opera Mobi', self::VERSION_TYPE_FLOAT)>11 && $this->is('AndroidOS') ) || + + // Meego 1.2 - Tested on Nokia 950 and N9 + $this->is('MeeGoOS') || + + // Tizen (pre-release) - Tested on early hardware + $this->is('Tizen') || + + // Samsung Bada 2.0 - Tested on a Samsung Wave 3, Dolphin browser + // @todo: more tests here! + $this->is('Dolfin') && $this->version('Bada', self::VERSION_TYPE_FLOAT)>=2.0 || + + // UC Browser - Tested on Android 2.3 device + ( ($this->is('UC Browser') || $this->is('Dolfin')) && $this->version('Android', self::VERSION_TYPE_FLOAT)>=2.3 ) || + + // Kindle 3 and Fire - Tested on the built-in WebKit browser for each + ( $this->match('Kindle Fire') || + $this->is('Kindle') && $this->version('Kindle', self::VERSION_TYPE_FLOAT)>=3.0 ) || + + // Nook Color 1.4.1 - Tested on original Nook Color, not Nook Tablet + $this->is('AndroidOS') && $this->is('NookTablet') || + + // Chrome Desktop 11-21 - Tested on OS X 10.7 and Windows 7 + $this->version('Chrome', self::VERSION_TYPE_FLOAT)>=11 && !$isMobile || + + // Safari Desktop 4-5 - Tested on OS X 10.7 and Windows 7 + $this->version('Safari', self::VERSION_TYPE_FLOAT)>=5.0 && !$isMobile || + + // Firefox Desktop 4-13 - Tested on OS X 10.7 and Windows 7 + $this->version('Firefox', self::VERSION_TYPE_FLOAT)>=4.0 && !$isMobile || + + // Internet Explorer 7-9 - Tested on Windows XP, Vista and 7 + $this->version('MSIE', self::VERSION_TYPE_FLOAT)>=7.0 && !$isMobile || + + // Opera Desktop 10-12 - Tested on OS X 10.7 and Windows 7 + // @reference: http://my.opera.com/community/openweb/idopera/ + $this->version('Opera', self::VERSION_TYPE_FLOAT)>=10 && !$isMobile + + ){ + return self::MOBILE_GRADE_A; + } + + if ( + $this->isIOS() && $this->version('iPad', self::VERSION_TYPE_FLOAT)<4.3 || + $this->isIOS() && $this->version('iPhone', self::VERSION_TYPE_FLOAT)<3.1 || + $this->isIOS() && $this->version('iPod', self::VERSION_TYPE_FLOAT)<3.1 || + + // Blackberry 5.0: Tested on the Storm 2 9550, Bold 9770 + $this->is('Blackberry') && $this->version('BlackBerry', self::VERSION_TYPE_FLOAT)>=5 && $this->version('BlackBerry', self::VERSION_TYPE_FLOAT)<6 || + + //Opera Mini (5.0-6.5) - Tested on iOS 3.2/4.3 and Android 2.3 + ( $this->version('Opera Mini', self::VERSION_TYPE_FLOAT)>=5.0 && $this->version('Opera Mini', self::VERSION_TYPE_FLOAT)<=6.5 && + ($this->version('Android', self::VERSION_TYPE_FLOAT)>=2.3 || $this->is('iOS')) ) || + + // Nokia Symbian^3 - Tested on Nokia N8 (Symbian^3), C7 (Symbian^3), also works on N97 (Symbian^1) + $this->match('NokiaN8|NokiaC7|N97.*Series60|Symbian/3') || + + // @todo: report this (tested on Nokia N71) + $this->version('Opera Mobi', self::VERSION_TYPE_FLOAT)>=11 && $this->is('SymbianOS') + ){ + return self::MOBILE_GRADE_B; + } + + if ( + // Blackberry 4.x - Tested on the Curve 8330 + $this->version('BlackBerry', self::VERSION_TYPE_FLOAT)<5.0 || + // Windows Mobile - Tested on the HTC Leo (WinMo 5.2) + $this->match('MSIEMobile|Windows CE.*Mobile') || $this->version('Windows Mobile', self::VERSION_TYPE_FLOAT)<=5.2 + + ){ + return self::MOBILE_GRADE_C; + } + + //All older smartphone platforms and featurephones - Any device that doesn't support media queries + //will receive the basic, C grade experience. + return self::MOBILE_GRADE_C; + } +} diff --git a/public/include/lib/jsonRPCClient.php b/include/lib/jsonRPCClient.php similarity index 97% rename from public/include/lib/jsonRPCClient.php rename to include/lib/jsonRPCClient.php index ba09ba63d..b6675f2d3 100644 --- a/public/include/lib/jsonRPCClient.php +++ b/include/lib/jsonRPCClient.php @@ -108,7 +108,10 @@ public function __call($method, $params) { curl_setopt($ch, CURLOPT_USERPWD, $url['user'] . ":" . $url['pass']); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $request); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); + // curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); $response = curl_exec($ch); + if (curl_errno($ch)) throw new Exception('RPC call failed: ' . curl_error($ch)); if ($this->debug) $this->debug_output[] = 'Response: ' . $response; $response = json_decode($response, true); $resultStatus = curl_getinfo($ch); @@ -116,7 +119,6 @@ public function __call($method, $params) { if ($resultStatus['http_code'] == '401') throw new Exception('RPC call did not return 200: Authentication failed'); throw new Exception('RPC call did not return 200: HTTP error: ' . $resultStatus['http_code'] . ' - JSON Response: [' . @$response['error']['code'] . '] ' . @$response['error']['message']); } - if (curl_errno($ch)) throw new Exception('RPC call failed: ' . curl_error($ch)); curl_close($ch); // final checks and return diff --git a/public/include/lib/recaptchalib.php b/include/lib/recaptchalib.php similarity index 100% rename from public/include/lib/recaptchalib.php rename to include/lib/recaptchalib.php diff --git a/public/include/lib/scrypt.php b/include/lib/scrypt.php similarity index 100% rename from public/include/lib/scrypt.php rename to include/lib/scrypt.php diff --git a/public/include/lib/smarty_plugins/function.acl.php b/include/lib/smarty_plugins/function.acl.php similarity index 100% rename from public/include/lib/smarty_plugins/function.acl.php rename to include/lib/smarty_plugins/function.acl.php diff --git a/public/include/lib/swiftmailer/classes/Swift.php b/include/lib/swiftmailer/classes/Swift.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift.php rename to include/lib/swiftmailer/classes/Swift.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Attachment.php b/include/lib/swiftmailer/classes/Swift/Attachment.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Attachment.php rename to include/lib/swiftmailer/classes/Swift/Attachment.php diff --git a/public/include/lib/swiftmailer/classes/Swift/ByteStream/AbstractFilterableInputStream.php b/include/lib/swiftmailer/classes/Swift/ByteStream/AbstractFilterableInputStream.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/ByteStream/AbstractFilterableInputStream.php rename to include/lib/swiftmailer/classes/Swift/ByteStream/AbstractFilterableInputStream.php diff --git a/public/include/lib/swiftmailer/classes/Swift/ByteStream/ArrayByteStream.php b/include/lib/swiftmailer/classes/Swift/ByteStream/ArrayByteStream.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/ByteStream/ArrayByteStream.php rename to include/lib/swiftmailer/classes/Swift/ByteStream/ArrayByteStream.php diff --git a/public/include/lib/swiftmailer/classes/Swift/ByteStream/FileByteStream.php b/include/lib/swiftmailer/classes/Swift/ByteStream/FileByteStream.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/ByteStream/FileByteStream.php rename to include/lib/swiftmailer/classes/Swift/ByteStream/FileByteStream.php diff --git a/public/include/lib/swiftmailer/classes/Swift/ByteStream/TemporaryFileByteStream.php b/include/lib/swiftmailer/classes/Swift/ByteStream/TemporaryFileByteStream.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/ByteStream/TemporaryFileByteStream.php rename to include/lib/swiftmailer/classes/Swift/ByteStream/TemporaryFileByteStream.php diff --git a/public/include/lib/swiftmailer/classes/Swift/CharacterReader.php b/include/lib/swiftmailer/classes/Swift/CharacterReader.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/CharacterReader.php rename to include/lib/swiftmailer/classes/Swift/CharacterReader.php diff --git a/public/include/lib/swiftmailer/classes/Swift/CharacterReader/GenericFixedWidthReader.php b/include/lib/swiftmailer/classes/Swift/CharacterReader/GenericFixedWidthReader.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/CharacterReader/GenericFixedWidthReader.php rename to include/lib/swiftmailer/classes/Swift/CharacterReader/GenericFixedWidthReader.php diff --git a/public/include/lib/swiftmailer/classes/Swift/CharacterReader/UsAsciiReader.php b/include/lib/swiftmailer/classes/Swift/CharacterReader/UsAsciiReader.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/CharacterReader/UsAsciiReader.php rename to include/lib/swiftmailer/classes/Swift/CharacterReader/UsAsciiReader.php diff --git a/public/include/lib/swiftmailer/classes/Swift/CharacterReader/Utf8Reader.php b/include/lib/swiftmailer/classes/Swift/CharacterReader/Utf8Reader.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/CharacterReader/Utf8Reader.php rename to include/lib/swiftmailer/classes/Swift/CharacterReader/Utf8Reader.php diff --git a/public/include/lib/swiftmailer/classes/Swift/CharacterReaderFactory.php b/include/lib/swiftmailer/classes/Swift/CharacterReaderFactory.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/CharacterReaderFactory.php rename to include/lib/swiftmailer/classes/Swift/CharacterReaderFactory.php diff --git a/public/include/lib/swiftmailer/classes/Swift/CharacterReaderFactory/SimpleCharacterReaderFactory.php b/include/lib/swiftmailer/classes/Swift/CharacterReaderFactory/SimpleCharacterReaderFactory.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/CharacterReaderFactory/SimpleCharacterReaderFactory.php rename to include/lib/swiftmailer/classes/Swift/CharacterReaderFactory/SimpleCharacterReaderFactory.php diff --git a/public/include/lib/swiftmailer/classes/Swift/CharacterStream.php b/include/lib/swiftmailer/classes/Swift/CharacterStream.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/CharacterStream.php rename to include/lib/swiftmailer/classes/Swift/CharacterStream.php diff --git a/public/include/lib/swiftmailer/classes/Swift/CharacterStream/ArrayCharacterStream.php b/include/lib/swiftmailer/classes/Swift/CharacterStream/ArrayCharacterStream.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/CharacterStream/ArrayCharacterStream.php rename to include/lib/swiftmailer/classes/Swift/CharacterStream/ArrayCharacterStream.php diff --git a/public/include/lib/swiftmailer/classes/Swift/CharacterStream/NgCharacterStream.php b/include/lib/swiftmailer/classes/Swift/CharacterStream/NgCharacterStream.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/CharacterStream/NgCharacterStream.php rename to include/lib/swiftmailer/classes/Swift/CharacterStream/NgCharacterStream.php diff --git a/public/include/lib/swiftmailer/classes/Swift/ConfigurableSpool.php b/include/lib/swiftmailer/classes/Swift/ConfigurableSpool.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/ConfigurableSpool.php rename to include/lib/swiftmailer/classes/Swift/ConfigurableSpool.php diff --git a/public/include/lib/swiftmailer/classes/Swift/DependencyContainer.php b/include/lib/swiftmailer/classes/Swift/DependencyContainer.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/DependencyContainer.php rename to include/lib/swiftmailer/classes/Swift/DependencyContainer.php diff --git a/public/include/lib/swiftmailer/classes/Swift/DependencyException.php b/include/lib/swiftmailer/classes/Swift/DependencyException.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/DependencyException.php rename to include/lib/swiftmailer/classes/Swift/DependencyException.php diff --git a/public/include/lib/swiftmailer/classes/Swift/EmbeddedFile.php b/include/lib/swiftmailer/classes/Swift/EmbeddedFile.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/EmbeddedFile.php rename to include/lib/swiftmailer/classes/Swift/EmbeddedFile.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Encoder.php b/include/lib/swiftmailer/classes/Swift/Encoder.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Encoder.php rename to include/lib/swiftmailer/classes/Swift/Encoder.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Encoder/Base64Encoder.php b/include/lib/swiftmailer/classes/Swift/Encoder/Base64Encoder.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Encoder/Base64Encoder.php rename to include/lib/swiftmailer/classes/Swift/Encoder/Base64Encoder.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Encoder/QpEncoder.php b/include/lib/swiftmailer/classes/Swift/Encoder/QpEncoder.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Encoder/QpEncoder.php rename to include/lib/swiftmailer/classes/Swift/Encoder/QpEncoder.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Encoder/Rfc2231Encoder.php b/include/lib/swiftmailer/classes/Swift/Encoder/Rfc2231Encoder.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Encoder/Rfc2231Encoder.php rename to include/lib/swiftmailer/classes/Swift/Encoder/Rfc2231Encoder.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Encoding.php b/include/lib/swiftmailer/classes/Swift/Encoding.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Encoding.php rename to include/lib/swiftmailer/classes/Swift/Encoding.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Events/CommandEvent.php b/include/lib/swiftmailer/classes/Swift/Events/CommandEvent.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Events/CommandEvent.php rename to include/lib/swiftmailer/classes/Swift/Events/CommandEvent.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Events/CommandListener.php b/include/lib/swiftmailer/classes/Swift/Events/CommandListener.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Events/CommandListener.php rename to include/lib/swiftmailer/classes/Swift/Events/CommandListener.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Events/Event.php b/include/lib/swiftmailer/classes/Swift/Events/Event.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Events/Event.php rename to include/lib/swiftmailer/classes/Swift/Events/Event.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Events/EventDispatcher.php b/include/lib/swiftmailer/classes/Swift/Events/EventDispatcher.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Events/EventDispatcher.php rename to include/lib/swiftmailer/classes/Swift/Events/EventDispatcher.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Events/EventListener.php b/include/lib/swiftmailer/classes/Swift/Events/EventListener.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Events/EventListener.php rename to include/lib/swiftmailer/classes/Swift/Events/EventListener.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Events/EventObject.php b/include/lib/swiftmailer/classes/Swift/Events/EventObject.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Events/EventObject.php rename to include/lib/swiftmailer/classes/Swift/Events/EventObject.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Events/ResponseEvent.php b/include/lib/swiftmailer/classes/Swift/Events/ResponseEvent.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Events/ResponseEvent.php rename to include/lib/swiftmailer/classes/Swift/Events/ResponseEvent.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Events/ResponseListener.php b/include/lib/swiftmailer/classes/Swift/Events/ResponseListener.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Events/ResponseListener.php rename to include/lib/swiftmailer/classes/Swift/Events/ResponseListener.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Events/SendEvent.php b/include/lib/swiftmailer/classes/Swift/Events/SendEvent.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Events/SendEvent.php rename to include/lib/swiftmailer/classes/Swift/Events/SendEvent.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Events/SendListener.php b/include/lib/swiftmailer/classes/Swift/Events/SendListener.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Events/SendListener.php rename to include/lib/swiftmailer/classes/Swift/Events/SendListener.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Events/SimpleEventDispatcher.php b/include/lib/swiftmailer/classes/Swift/Events/SimpleEventDispatcher.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Events/SimpleEventDispatcher.php rename to include/lib/swiftmailer/classes/Swift/Events/SimpleEventDispatcher.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Events/TransportChangeEvent.php b/include/lib/swiftmailer/classes/Swift/Events/TransportChangeEvent.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Events/TransportChangeEvent.php rename to include/lib/swiftmailer/classes/Swift/Events/TransportChangeEvent.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Events/TransportChangeListener.php b/include/lib/swiftmailer/classes/Swift/Events/TransportChangeListener.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Events/TransportChangeListener.php rename to include/lib/swiftmailer/classes/Swift/Events/TransportChangeListener.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Events/TransportExceptionEvent.php b/include/lib/swiftmailer/classes/Swift/Events/TransportExceptionEvent.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Events/TransportExceptionEvent.php rename to include/lib/swiftmailer/classes/Swift/Events/TransportExceptionEvent.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Events/TransportExceptionListener.php b/include/lib/swiftmailer/classes/Swift/Events/TransportExceptionListener.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Events/TransportExceptionListener.php rename to include/lib/swiftmailer/classes/Swift/Events/TransportExceptionListener.php diff --git a/public/include/lib/swiftmailer/classes/Swift/FailoverTransport.php b/include/lib/swiftmailer/classes/Swift/FailoverTransport.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/FailoverTransport.php rename to include/lib/swiftmailer/classes/Swift/FailoverTransport.php diff --git a/public/include/lib/swiftmailer/classes/Swift/FileSpool.php b/include/lib/swiftmailer/classes/Swift/FileSpool.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/FileSpool.php rename to include/lib/swiftmailer/classes/Swift/FileSpool.php diff --git a/public/include/lib/swiftmailer/classes/Swift/FileStream.php b/include/lib/swiftmailer/classes/Swift/FileStream.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/FileStream.php rename to include/lib/swiftmailer/classes/Swift/FileStream.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Filterable.php b/include/lib/swiftmailer/classes/Swift/Filterable.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Filterable.php rename to include/lib/swiftmailer/classes/Swift/Filterable.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Image.php b/include/lib/swiftmailer/classes/Swift/Image.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Image.php rename to include/lib/swiftmailer/classes/Swift/Image.php diff --git a/public/include/lib/swiftmailer/classes/Swift/InputByteStream.php b/include/lib/swiftmailer/classes/Swift/InputByteStream.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/InputByteStream.php rename to include/lib/swiftmailer/classes/Swift/InputByteStream.php diff --git a/public/include/lib/swiftmailer/classes/Swift/IoException.php b/include/lib/swiftmailer/classes/Swift/IoException.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/IoException.php rename to include/lib/swiftmailer/classes/Swift/IoException.php diff --git a/public/include/lib/swiftmailer/classes/Swift/KeyCache.php b/include/lib/swiftmailer/classes/Swift/KeyCache.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/KeyCache.php rename to include/lib/swiftmailer/classes/Swift/KeyCache.php diff --git a/public/include/lib/swiftmailer/classes/Swift/KeyCache/ArrayKeyCache.php b/include/lib/swiftmailer/classes/Swift/KeyCache/ArrayKeyCache.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/KeyCache/ArrayKeyCache.php rename to include/lib/swiftmailer/classes/Swift/KeyCache/ArrayKeyCache.php diff --git a/public/include/lib/swiftmailer/classes/Swift/KeyCache/DiskKeyCache.php b/include/lib/swiftmailer/classes/Swift/KeyCache/DiskKeyCache.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/KeyCache/DiskKeyCache.php rename to include/lib/swiftmailer/classes/Swift/KeyCache/DiskKeyCache.php diff --git a/public/include/lib/swiftmailer/classes/Swift/KeyCache/KeyCacheInputStream.php b/include/lib/swiftmailer/classes/Swift/KeyCache/KeyCacheInputStream.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/KeyCache/KeyCacheInputStream.php rename to include/lib/swiftmailer/classes/Swift/KeyCache/KeyCacheInputStream.php diff --git a/public/include/lib/swiftmailer/classes/Swift/KeyCache/NullKeyCache.php b/include/lib/swiftmailer/classes/Swift/KeyCache/NullKeyCache.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/KeyCache/NullKeyCache.php rename to include/lib/swiftmailer/classes/Swift/KeyCache/NullKeyCache.php diff --git a/public/include/lib/swiftmailer/classes/Swift/KeyCache/SimpleKeyCacheInputStream.php b/include/lib/swiftmailer/classes/Swift/KeyCache/SimpleKeyCacheInputStream.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/KeyCache/SimpleKeyCacheInputStream.php rename to include/lib/swiftmailer/classes/Swift/KeyCache/SimpleKeyCacheInputStream.php diff --git a/public/include/lib/swiftmailer/classes/Swift/LoadBalancedTransport.php b/include/lib/swiftmailer/classes/Swift/LoadBalancedTransport.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/LoadBalancedTransport.php rename to include/lib/swiftmailer/classes/Swift/LoadBalancedTransport.php diff --git a/public/include/lib/swiftmailer/classes/Swift/MailTransport.php b/include/lib/swiftmailer/classes/Swift/MailTransport.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/MailTransport.php rename to include/lib/swiftmailer/classes/Swift/MailTransport.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Mailer.php b/include/lib/swiftmailer/classes/Swift/Mailer.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Mailer.php rename to include/lib/swiftmailer/classes/Swift/Mailer.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Mailer/ArrayRecipientIterator.php b/include/lib/swiftmailer/classes/Swift/Mailer/ArrayRecipientIterator.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Mailer/ArrayRecipientIterator.php rename to include/lib/swiftmailer/classes/Swift/Mailer/ArrayRecipientIterator.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Mailer/RecipientIterator.php b/include/lib/swiftmailer/classes/Swift/Mailer/RecipientIterator.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Mailer/RecipientIterator.php rename to include/lib/swiftmailer/classes/Swift/Mailer/RecipientIterator.php diff --git a/public/include/lib/swiftmailer/classes/Swift/MemorySpool.php b/include/lib/swiftmailer/classes/Swift/MemorySpool.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/MemorySpool.php rename to include/lib/swiftmailer/classes/Swift/MemorySpool.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Message.php b/include/lib/swiftmailer/classes/Swift/Message.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Message.php rename to include/lib/swiftmailer/classes/Swift/Message.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/Attachment.php b/include/lib/swiftmailer/classes/Swift/Mime/Attachment.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Mime/Attachment.php rename to include/lib/swiftmailer/classes/Swift/Mime/Attachment.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/CharsetObserver.php b/include/lib/swiftmailer/classes/Swift/Mime/CharsetObserver.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Mime/CharsetObserver.php rename to include/lib/swiftmailer/classes/Swift/Mime/CharsetObserver.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/ContentEncoder.php b/include/lib/swiftmailer/classes/Swift/Mime/ContentEncoder.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Mime/ContentEncoder.php rename to include/lib/swiftmailer/classes/Swift/Mime/ContentEncoder.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/ContentEncoder/Base64ContentEncoder.php b/include/lib/swiftmailer/classes/Swift/Mime/ContentEncoder/Base64ContentEncoder.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Mime/ContentEncoder/Base64ContentEncoder.php rename to include/lib/swiftmailer/classes/Swift/Mime/ContentEncoder/Base64ContentEncoder.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/ContentEncoder/NativeQpContentEncoder.php b/include/lib/swiftmailer/classes/Swift/Mime/ContentEncoder/NativeQpContentEncoder.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Mime/ContentEncoder/NativeQpContentEncoder.php rename to include/lib/swiftmailer/classes/Swift/Mime/ContentEncoder/NativeQpContentEncoder.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/ContentEncoder/PlainContentEncoder.php b/include/lib/swiftmailer/classes/Swift/Mime/ContentEncoder/PlainContentEncoder.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Mime/ContentEncoder/PlainContentEncoder.php rename to include/lib/swiftmailer/classes/Swift/Mime/ContentEncoder/PlainContentEncoder.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/ContentEncoder/QpContentEncoder.php b/include/lib/swiftmailer/classes/Swift/Mime/ContentEncoder/QpContentEncoder.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Mime/ContentEncoder/QpContentEncoder.php rename to include/lib/swiftmailer/classes/Swift/Mime/ContentEncoder/QpContentEncoder.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/ContentEncoder/QpContentEncoderProxy.php b/include/lib/swiftmailer/classes/Swift/Mime/ContentEncoder/QpContentEncoderProxy.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Mime/ContentEncoder/QpContentEncoderProxy.php rename to include/lib/swiftmailer/classes/Swift/Mime/ContentEncoder/QpContentEncoderProxy.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/ContentEncoder/RawContentEncoder.php b/include/lib/swiftmailer/classes/Swift/Mime/ContentEncoder/RawContentEncoder.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Mime/ContentEncoder/RawContentEncoder.php rename to include/lib/swiftmailer/classes/Swift/Mime/ContentEncoder/RawContentEncoder.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/EmbeddedFile.php b/include/lib/swiftmailer/classes/Swift/Mime/EmbeddedFile.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Mime/EmbeddedFile.php rename to include/lib/swiftmailer/classes/Swift/Mime/EmbeddedFile.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/EncodingObserver.php b/include/lib/swiftmailer/classes/Swift/Mime/EncodingObserver.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Mime/EncodingObserver.php rename to include/lib/swiftmailer/classes/Swift/Mime/EncodingObserver.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/Grammar.php b/include/lib/swiftmailer/classes/Swift/Mime/Grammar.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Mime/Grammar.php rename to include/lib/swiftmailer/classes/Swift/Mime/Grammar.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/Header.php b/include/lib/swiftmailer/classes/Swift/Mime/Header.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Mime/Header.php rename to include/lib/swiftmailer/classes/Swift/Mime/Header.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/HeaderEncoder.php b/include/lib/swiftmailer/classes/Swift/Mime/HeaderEncoder.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Mime/HeaderEncoder.php rename to include/lib/swiftmailer/classes/Swift/Mime/HeaderEncoder.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/HeaderEncoder/Base64HeaderEncoder.php b/include/lib/swiftmailer/classes/Swift/Mime/HeaderEncoder/Base64HeaderEncoder.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Mime/HeaderEncoder/Base64HeaderEncoder.php rename to include/lib/swiftmailer/classes/Swift/Mime/HeaderEncoder/Base64HeaderEncoder.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/HeaderEncoder/QpHeaderEncoder.php b/include/lib/swiftmailer/classes/Swift/Mime/HeaderEncoder/QpHeaderEncoder.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Mime/HeaderEncoder/QpHeaderEncoder.php rename to include/lib/swiftmailer/classes/Swift/Mime/HeaderEncoder/QpHeaderEncoder.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/HeaderFactory.php b/include/lib/swiftmailer/classes/Swift/Mime/HeaderFactory.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Mime/HeaderFactory.php rename to include/lib/swiftmailer/classes/Swift/Mime/HeaderFactory.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/HeaderSet.php b/include/lib/swiftmailer/classes/Swift/Mime/HeaderSet.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Mime/HeaderSet.php rename to include/lib/swiftmailer/classes/Swift/Mime/HeaderSet.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/Headers/AbstractHeader.php b/include/lib/swiftmailer/classes/Swift/Mime/Headers/AbstractHeader.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Mime/Headers/AbstractHeader.php rename to include/lib/swiftmailer/classes/Swift/Mime/Headers/AbstractHeader.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/Headers/DateHeader.php b/include/lib/swiftmailer/classes/Swift/Mime/Headers/DateHeader.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Mime/Headers/DateHeader.php rename to include/lib/swiftmailer/classes/Swift/Mime/Headers/DateHeader.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/Headers/IdentificationHeader.php b/include/lib/swiftmailer/classes/Swift/Mime/Headers/IdentificationHeader.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Mime/Headers/IdentificationHeader.php rename to include/lib/swiftmailer/classes/Swift/Mime/Headers/IdentificationHeader.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/Headers/MailboxHeader.php b/include/lib/swiftmailer/classes/Swift/Mime/Headers/MailboxHeader.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Mime/Headers/MailboxHeader.php rename to include/lib/swiftmailer/classes/Swift/Mime/Headers/MailboxHeader.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/Headers/OpenDKIMHeader.php b/include/lib/swiftmailer/classes/Swift/Mime/Headers/OpenDKIMHeader.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Mime/Headers/OpenDKIMHeader.php rename to include/lib/swiftmailer/classes/Swift/Mime/Headers/OpenDKIMHeader.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/Headers/ParameterizedHeader.php b/include/lib/swiftmailer/classes/Swift/Mime/Headers/ParameterizedHeader.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Mime/Headers/ParameterizedHeader.php rename to include/lib/swiftmailer/classes/Swift/Mime/Headers/ParameterizedHeader.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/Headers/PathHeader.php b/include/lib/swiftmailer/classes/Swift/Mime/Headers/PathHeader.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Mime/Headers/PathHeader.php rename to include/lib/swiftmailer/classes/Swift/Mime/Headers/PathHeader.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/Headers/UnstructuredHeader.php b/include/lib/swiftmailer/classes/Swift/Mime/Headers/UnstructuredHeader.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Mime/Headers/UnstructuredHeader.php rename to include/lib/swiftmailer/classes/Swift/Mime/Headers/UnstructuredHeader.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/Message.php b/include/lib/swiftmailer/classes/Swift/Mime/Message.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Mime/Message.php rename to include/lib/swiftmailer/classes/Swift/Mime/Message.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/MimeEntity.php b/include/lib/swiftmailer/classes/Swift/Mime/MimeEntity.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Mime/MimeEntity.php rename to include/lib/swiftmailer/classes/Swift/Mime/MimeEntity.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/MimePart.php b/include/lib/swiftmailer/classes/Swift/Mime/MimePart.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Mime/MimePart.php rename to include/lib/swiftmailer/classes/Swift/Mime/MimePart.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/ParameterizedHeader.php b/include/lib/swiftmailer/classes/Swift/Mime/ParameterizedHeader.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Mime/ParameterizedHeader.php rename to include/lib/swiftmailer/classes/Swift/Mime/ParameterizedHeader.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/SimpleHeaderFactory.php b/include/lib/swiftmailer/classes/Swift/Mime/SimpleHeaderFactory.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Mime/SimpleHeaderFactory.php rename to include/lib/swiftmailer/classes/Swift/Mime/SimpleHeaderFactory.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/SimpleHeaderSet.php b/include/lib/swiftmailer/classes/Swift/Mime/SimpleHeaderSet.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Mime/SimpleHeaderSet.php rename to include/lib/swiftmailer/classes/Swift/Mime/SimpleHeaderSet.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/SimpleMessage.php b/include/lib/swiftmailer/classes/Swift/Mime/SimpleMessage.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Mime/SimpleMessage.php rename to include/lib/swiftmailer/classes/Swift/Mime/SimpleMessage.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/SimpleMimeEntity.php b/include/lib/swiftmailer/classes/Swift/Mime/SimpleMimeEntity.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Mime/SimpleMimeEntity.php rename to include/lib/swiftmailer/classes/Swift/Mime/SimpleMimeEntity.php diff --git a/public/include/lib/swiftmailer/classes/Swift/MimePart.php b/include/lib/swiftmailer/classes/Swift/MimePart.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/MimePart.php rename to include/lib/swiftmailer/classes/Swift/MimePart.php diff --git a/public/include/lib/swiftmailer/classes/Swift/NullTransport.php b/include/lib/swiftmailer/classes/Swift/NullTransport.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/NullTransport.php rename to include/lib/swiftmailer/classes/Swift/NullTransport.php diff --git a/public/include/lib/swiftmailer/classes/Swift/OutputByteStream.php b/include/lib/swiftmailer/classes/Swift/OutputByteStream.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/OutputByteStream.php rename to include/lib/swiftmailer/classes/Swift/OutputByteStream.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Plugins/AntiFloodPlugin.php b/include/lib/swiftmailer/classes/Swift/Plugins/AntiFloodPlugin.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Plugins/AntiFloodPlugin.php rename to include/lib/swiftmailer/classes/Swift/Plugins/AntiFloodPlugin.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Plugins/BandwidthMonitorPlugin.php b/include/lib/swiftmailer/classes/Swift/Plugins/BandwidthMonitorPlugin.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Plugins/BandwidthMonitorPlugin.php rename to include/lib/swiftmailer/classes/Swift/Plugins/BandwidthMonitorPlugin.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Plugins/Decorator/Replacements.php b/include/lib/swiftmailer/classes/Swift/Plugins/Decorator/Replacements.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Plugins/Decorator/Replacements.php rename to include/lib/swiftmailer/classes/Swift/Plugins/Decorator/Replacements.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Plugins/DecoratorPlugin.php b/include/lib/swiftmailer/classes/Swift/Plugins/DecoratorPlugin.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Plugins/DecoratorPlugin.php rename to include/lib/swiftmailer/classes/Swift/Plugins/DecoratorPlugin.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Plugins/ImpersonatePlugin.php b/include/lib/swiftmailer/classes/Swift/Plugins/ImpersonatePlugin.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Plugins/ImpersonatePlugin.php rename to include/lib/swiftmailer/classes/Swift/Plugins/ImpersonatePlugin.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Plugins/Logger.php b/include/lib/swiftmailer/classes/Swift/Plugins/Logger.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Plugins/Logger.php rename to include/lib/swiftmailer/classes/Swift/Plugins/Logger.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Plugins/LoggerPlugin.php b/include/lib/swiftmailer/classes/Swift/Plugins/LoggerPlugin.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Plugins/LoggerPlugin.php rename to include/lib/swiftmailer/classes/Swift/Plugins/LoggerPlugin.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Plugins/Loggers/ArrayLogger.php b/include/lib/swiftmailer/classes/Swift/Plugins/Loggers/ArrayLogger.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Plugins/Loggers/ArrayLogger.php rename to include/lib/swiftmailer/classes/Swift/Plugins/Loggers/ArrayLogger.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Plugins/Loggers/EchoLogger.php b/include/lib/swiftmailer/classes/Swift/Plugins/Loggers/EchoLogger.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Plugins/Loggers/EchoLogger.php rename to include/lib/swiftmailer/classes/Swift/Plugins/Loggers/EchoLogger.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Plugins/MessageLogger.php b/include/lib/swiftmailer/classes/Swift/Plugins/MessageLogger.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Plugins/MessageLogger.php rename to include/lib/swiftmailer/classes/Swift/Plugins/MessageLogger.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Plugins/Pop/Pop3Connection.php b/include/lib/swiftmailer/classes/Swift/Plugins/Pop/Pop3Connection.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Plugins/Pop/Pop3Connection.php rename to include/lib/swiftmailer/classes/Swift/Plugins/Pop/Pop3Connection.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Plugins/Pop/Pop3Exception.php b/include/lib/swiftmailer/classes/Swift/Plugins/Pop/Pop3Exception.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Plugins/Pop/Pop3Exception.php rename to include/lib/swiftmailer/classes/Swift/Plugins/Pop/Pop3Exception.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Plugins/PopBeforeSmtpPlugin.php b/include/lib/swiftmailer/classes/Swift/Plugins/PopBeforeSmtpPlugin.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Plugins/PopBeforeSmtpPlugin.php rename to include/lib/swiftmailer/classes/Swift/Plugins/PopBeforeSmtpPlugin.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Plugins/RedirectingPlugin.php b/include/lib/swiftmailer/classes/Swift/Plugins/RedirectingPlugin.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Plugins/RedirectingPlugin.php rename to include/lib/swiftmailer/classes/Swift/Plugins/RedirectingPlugin.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Plugins/Reporter.php b/include/lib/swiftmailer/classes/Swift/Plugins/Reporter.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Plugins/Reporter.php rename to include/lib/swiftmailer/classes/Swift/Plugins/Reporter.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Plugins/ReporterPlugin.php b/include/lib/swiftmailer/classes/Swift/Plugins/ReporterPlugin.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Plugins/ReporterPlugin.php rename to include/lib/swiftmailer/classes/Swift/Plugins/ReporterPlugin.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Plugins/Reporters/HitReporter.php b/include/lib/swiftmailer/classes/Swift/Plugins/Reporters/HitReporter.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Plugins/Reporters/HitReporter.php rename to include/lib/swiftmailer/classes/Swift/Plugins/Reporters/HitReporter.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Plugins/Reporters/HtmlReporter.php b/include/lib/swiftmailer/classes/Swift/Plugins/Reporters/HtmlReporter.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Plugins/Reporters/HtmlReporter.php rename to include/lib/swiftmailer/classes/Swift/Plugins/Reporters/HtmlReporter.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Plugins/Sleeper.php b/include/lib/swiftmailer/classes/Swift/Plugins/Sleeper.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Plugins/Sleeper.php rename to include/lib/swiftmailer/classes/Swift/Plugins/Sleeper.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Plugins/ThrottlerPlugin.php b/include/lib/swiftmailer/classes/Swift/Plugins/ThrottlerPlugin.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Plugins/ThrottlerPlugin.php rename to include/lib/swiftmailer/classes/Swift/Plugins/ThrottlerPlugin.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Plugins/Timer.php b/include/lib/swiftmailer/classes/Swift/Plugins/Timer.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Plugins/Timer.php rename to include/lib/swiftmailer/classes/Swift/Plugins/Timer.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Preferences.php b/include/lib/swiftmailer/classes/Swift/Preferences.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Preferences.php rename to include/lib/swiftmailer/classes/Swift/Preferences.php diff --git a/public/include/lib/swiftmailer/classes/Swift/ReplacementFilterFactory.php b/include/lib/swiftmailer/classes/Swift/ReplacementFilterFactory.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/ReplacementFilterFactory.php rename to include/lib/swiftmailer/classes/Swift/ReplacementFilterFactory.php diff --git a/public/include/lib/swiftmailer/classes/Swift/RfcComplianceException.php b/include/lib/swiftmailer/classes/Swift/RfcComplianceException.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/RfcComplianceException.php rename to include/lib/swiftmailer/classes/Swift/RfcComplianceException.php diff --git a/public/include/lib/swiftmailer/classes/Swift/SendmailTransport.php b/include/lib/swiftmailer/classes/Swift/SendmailTransport.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/SendmailTransport.php rename to include/lib/swiftmailer/classes/Swift/SendmailTransport.php diff --git a/public/include/lib/swiftmailer/classes/Swift/SignedMessage.php b/include/lib/swiftmailer/classes/Swift/SignedMessage.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/SignedMessage.php rename to include/lib/swiftmailer/classes/Swift/SignedMessage.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Signer.php b/include/lib/swiftmailer/classes/Swift/Signer.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Signer.php rename to include/lib/swiftmailer/classes/Swift/Signer.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Signers/BodySigner.php b/include/lib/swiftmailer/classes/Swift/Signers/BodySigner.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Signers/BodySigner.php rename to include/lib/swiftmailer/classes/Swift/Signers/BodySigner.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Signers/DKIMSigner.php b/include/lib/swiftmailer/classes/Swift/Signers/DKIMSigner.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Signers/DKIMSigner.php rename to include/lib/swiftmailer/classes/Swift/Signers/DKIMSigner.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Signers/DomainKeySigner.php b/include/lib/swiftmailer/classes/Swift/Signers/DomainKeySigner.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Signers/DomainKeySigner.php rename to include/lib/swiftmailer/classes/Swift/Signers/DomainKeySigner.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Signers/HeaderSigner.php b/include/lib/swiftmailer/classes/Swift/Signers/HeaderSigner.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Signers/HeaderSigner.php rename to include/lib/swiftmailer/classes/Swift/Signers/HeaderSigner.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Signers/OpenDKIMSigner.php b/include/lib/swiftmailer/classes/Swift/Signers/OpenDKIMSigner.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Signers/OpenDKIMSigner.php rename to include/lib/swiftmailer/classes/Swift/Signers/OpenDKIMSigner.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Signers/SMimeSigner.php b/include/lib/swiftmailer/classes/Swift/Signers/SMimeSigner.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Signers/SMimeSigner.php rename to include/lib/swiftmailer/classes/Swift/Signers/SMimeSigner.php diff --git a/public/include/lib/swiftmailer/classes/Swift/SmtpTransport.php b/include/lib/swiftmailer/classes/Swift/SmtpTransport.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/SmtpTransport.php rename to include/lib/swiftmailer/classes/Swift/SmtpTransport.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Spool.php b/include/lib/swiftmailer/classes/Swift/Spool.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Spool.php rename to include/lib/swiftmailer/classes/Swift/Spool.php diff --git a/public/include/lib/swiftmailer/classes/Swift/SpoolTransport.php b/include/lib/swiftmailer/classes/Swift/SpoolTransport.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/SpoolTransport.php rename to include/lib/swiftmailer/classes/Swift/SpoolTransport.php diff --git a/public/include/lib/swiftmailer/classes/Swift/StreamFilter.php b/include/lib/swiftmailer/classes/Swift/StreamFilter.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/StreamFilter.php rename to include/lib/swiftmailer/classes/Swift/StreamFilter.php diff --git a/public/include/lib/swiftmailer/classes/Swift/StreamFilters/ByteArrayReplacementFilter.php b/include/lib/swiftmailer/classes/Swift/StreamFilters/ByteArrayReplacementFilter.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/StreamFilters/ByteArrayReplacementFilter.php rename to include/lib/swiftmailer/classes/Swift/StreamFilters/ByteArrayReplacementFilter.php diff --git a/public/include/lib/swiftmailer/classes/Swift/StreamFilters/StringReplacementFilter.php b/include/lib/swiftmailer/classes/Swift/StreamFilters/StringReplacementFilter.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/StreamFilters/StringReplacementFilter.php rename to include/lib/swiftmailer/classes/Swift/StreamFilters/StringReplacementFilter.php diff --git a/public/include/lib/swiftmailer/classes/Swift/StreamFilters/StringReplacementFilterFactory.php b/include/lib/swiftmailer/classes/Swift/StreamFilters/StringReplacementFilterFactory.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/StreamFilters/StringReplacementFilterFactory.php rename to include/lib/swiftmailer/classes/Swift/StreamFilters/StringReplacementFilterFactory.php diff --git a/public/include/lib/swiftmailer/classes/Swift/SwiftException.php b/include/lib/swiftmailer/classes/Swift/SwiftException.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/SwiftException.php rename to include/lib/swiftmailer/classes/Swift/SwiftException.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Transport.php b/include/lib/swiftmailer/classes/Swift/Transport.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Transport.php rename to include/lib/swiftmailer/classes/Swift/Transport.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Transport/AbstractSmtpTransport.php b/include/lib/swiftmailer/classes/Swift/Transport/AbstractSmtpTransport.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Transport/AbstractSmtpTransport.php rename to include/lib/swiftmailer/classes/Swift/Transport/AbstractSmtpTransport.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Transport/Esmtp/Auth/CramMd5Authenticator.php b/include/lib/swiftmailer/classes/Swift/Transport/Esmtp/Auth/CramMd5Authenticator.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Transport/Esmtp/Auth/CramMd5Authenticator.php rename to include/lib/swiftmailer/classes/Swift/Transport/Esmtp/Auth/CramMd5Authenticator.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Transport/Esmtp/Auth/LoginAuthenticator.php b/include/lib/swiftmailer/classes/Swift/Transport/Esmtp/Auth/LoginAuthenticator.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Transport/Esmtp/Auth/LoginAuthenticator.php rename to include/lib/swiftmailer/classes/Swift/Transport/Esmtp/Auth/LoginAuthenticator.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Transport/Esmtp/Auth/NTLMAuthenticator.php b/include/lib/swiftmailer/classes/Swift/Transport/Esmtp/Auth/NTLMAuthenticator.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Transport/Esmtp/Auth/NTLMAuthenticator.php rename to include/lib/swiftmailer/classes/Swift/Transport/Esmtp/Auth/NTLMAuthenticator.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Transport/Esmtp/Auth/PlainAuthenticator.php b/include/lib/swiftmailer/classes/Swift/Transport/Esmtp/Auth/PlainAuthenticator.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Transport/Esmtp/Auth/PlainAuthenticator.php rename to include/lib/swiftmailer/classes/Swift/Transport/Esmtp/Auth/PlainAuthenticator.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Transport/Esmtp/Auth/XOAuth2Authenticator.php b/include/lib/swiftmailer/classes/Swift/Transport/Esmtp/Auth/XOAuth2Authenticator.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Transport/Esmtp/Auth/XOAuth2Authenticator.php rename to include/lib/swiftmailer/classes/Swift/Transport/Esmtp/Auth/XOAuth2Authenticator.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Transport/Esmtp/AuthHandler.php b/include/lib/swiftmailer/classes/Swift/Transport/Esmtp/AuthHandler.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Transport/Esmtp/AuthHandler.php rename to include/lib/swiftmailer/classes/Swift/Transport/Esmtp/AuthHandler.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Transport/Esmtp/Authenticator.php b/include/lib/swiftmailer/classes/Swift/Transport/Esmtp/Authenticator.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Transport/Esmtp/Authenticator.php rename to include/lib/swiftmailer/classes/Swift/Transport/Esmtp/Authenticator.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Transport/EsmtpHandler.php b/include/lib/swiftmailer/classes/Swift/Transport/EsmtpHandler.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Transport/EsmtpHandler.php rename to include/lib/swiftmailer/classes/Swift/Transport/EsmtpHandler.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Transport/EsmtpTransport.php b/include/lib/swiftmailer/classes/Swift/Transport/EsmtpTransport.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Transport/EsmtpTransport.php rename to include/lib/swiftmailer/classes/Swift/Transport/EsmtpTransport.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Transport/FailoverTransport.php b/include/lib/swiftmailer/classes/Swift/Transport/FailoverTransport.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Transport/FailoverTransport.php rename to include/lib/swiftmailer/classes/Swift/Transport/FailoverTransport.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Transport/IoBuffer.php b/include/lib/swiftmailer/classes/Swift/Transport/IoBuffer.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Transport/IoBuffer.php rename to include/lib/swiftmailer/classes/Swift/Transport/IoBuffer.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Transport/LoadBalancedTransport.php b/include/lib/swiftmailer/classes/Swift/Transport/LoadBalancedTransport.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Transport/LoadBalancedTransport.php rename to include/lib/swiftmailer/classes/Swift/Transport/LoadBalancedTransport.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Transport/MailInvoker.php b/include/lib/swiftmailer/classes/Swift/Transport/MailInvoker.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Transport/MailInvoker.php rename to include/lib/swiftmailer/classes/Swift/Transport/MailInvoker.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Transport/MailTransport.php b/include/lib/swiftmailer/classes/Swift/Transport/MailTransport.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Transport/MailTransport.php rename to include/lib/swiftmailer/classes/Swift/Transport/MailTransport.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Transport/NullTransport.php b/include/lib/swiftmailer/classes/Swift/Transport/NullTransport.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Transport/NullTransport.php rename to include/lib/swiftmailer/classes/Swift/Transport/NullTransport.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Transport/SendmailTransport.php b/include/lib/swiftmailer/classes/Swift/Transport/SendmailTransport.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Transport/SendmailTransport.php rename to include/lib/swiftmailer/classes/Swift/Transport/SendmailTransport.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Transport/SimpleMailInvoker.php b/include/lib/swiftmailer/classes/Swift/Transport/SimpleMailInvoker.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Transport/SimpleMailInvoker.php rename to include/lib/swiftmailer/classes/Swift/Transport/SimpleMailInvoker.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Transport/SmtpAgent.php b/include/lib/swiftmailer/classes/Swift/Transport/SmtpAgent.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Transport/SmtpAgent.php rename to include/lib/swiftmailer/classes/Swift/Transport/SmtpAgent.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Transport/SpoolTransport.php b/include/lib/swiftmailer/classes/Swift/Transport/SpoolTransport.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Transport/SpoolTransport.php rename to include/lib/swiftmailer/classes/Swift/Transport/SpoolTransport.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Transport/StreamBuffer.php b/include/lib/swiftmailer/classes/Swift/Transport/StreamBuffer.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Transport/StreamBuffer.php rename to include/lib/swiftmailer/classes/Swift/Transport/StreamBuffer.php diff --git a/public/include/lib/swiftmailer/classes/Swift/TransportException.php b/include/lib/swiftmailer/classes/Swift/TransportException.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/TransportException.php rename to include/lib/swiftmailer/classes/Swift/TransportException.php diff --git a/public/include/lib/swiftmailer/classes/Swift/Validate.php b/include/lib/swiftmailer/classes/Swift/Validate.php similarity index 100% rename from public/include/lib/swiftmailer/classes/Swift/Validate.php rename to include/lib/swiftmailer/classes/Swift/Validate.php diff --git a/public/include/lib/swiftmailer/dependency_maps/cache_deps.php b/include/lib/swiftmailer/dependency_maps/cache_deps.php similarity index 100% rename from public/include/lib/swiftmailer/dependency_maps/cache_deps.php rename to include/lib/swiftmailer/dependency_maps/cache_deps.php diff --git a/public/include/lib/swiftmailer/dependency_maps/message_deps.php b/include/lib/swiftmailer/dependency_maps/message_deps.php similarity index 100% rename from public/include/lib/swiftmailer/dependency_maps/message_deps.php rename to include/lib/swiftmailer/dependency_maps/message_deps.php diff --git a/public/include/lib/swiftmailer/dependency_maps/mime_deps.php b/include/lib/swiftmailer/dependency_maps/mime_deps.php similarity index 100% rename from public/include/lib/swiftmailer/dependency_maps/mime_deps.php rename to include/lib/swiftmailer/dependency_maps/mime_deps.php diff --git a/public/include/lib/swiftmailer/dependency_maps/transport_deps.php b/include/lib/swiftmailer/dependency_maps/transport_deps.php similarity index 100% rename from public/include/lib/swiftmailer/dependency_maps/transport_deps.php rename to include/lib/swiftmailer/dependency_maps/transport_deps.php diff --git a/public/include/lib/swiftmailer/mime_types.php b/include/lib/swiftmailer/mime_types.php similarity index 100% rename from public/include/lib/swiftmailer/mime_types.php rename to include/lib/swiftmailer/mime_types.php diff --git a/public/include/lib/swiftmailer/preferences.php b/include/lib/swiftmailer/preferences.php similarity index 100% rename from public/include/lib/swiftmailer/preferences.php rename to include/lib/swiftmailer/preferences.php diff --git a/public/include/lib/swiftmailer/swift_init.php b/include/lib/swiftmailer/swift_init.php similarity index 100% rename from public/include/lib/swiftmailer/swift_init.php rename to include/lib/swiftmailer/swift_init.php diff --git a/public/include/lib/swiftmailer/swift_required.php b/include/lib/swiftmailer/swift_required.php similarity index 100% rename from public/include/lib/swiftmailer/swift_required.php rename to include/lib/swiftmailer/swift_required.php diff --git a/public/include/lib/swiftmailer/swift_required_pear.php b/include/lib/swiftmailer/swift_required_pear.php similarity index 100% rename from public/include/lib/swiftmailer/swift_required_pear.php rename to include/lib/swiftmailer/swift_required_pear.php diff --git a/public/include/lib/swiftmailer/swiftmailer_generate_mimes_config.php b/include/lib/swiftmailer/swiftmailer_generate_mimes_config.php similarity index 100% rename from public/include/lib/swiftmailer/swiftmailer_generate_mimes_config.php rename to include/lib/swiftmailer/swiftmailer_generate_mimes_config.php diff --git a/public/include/pages/about.inc.php b/include/pages/about.inc.php similarity index 100% rename from public/include/pages/about.inc.php rename to include/pages/about.inc.php diff --git a/public/include/pages/about/api.inc.php b/include/pages/about/api.inc.php similarity index 100% rename from public/include/pages/about/api.inc.php rename to include/pages/about/api.inc.php diff --git a/public/include/pages/about/chat.inc.php b/include/pages/about/chat.inc.php similarity index 100% rename from public/include/pages/about/chat.inc.php rename to include/pages/about/chat.inc.php diff --git a/public/include/pages/about/moot.inc.php b/include/pages/about/moot.inc.php similarity index 100% rename from public/include/pages/about/moot.inc.php rename to include/pages/about/moot.inc.php diff --git a/public/include/pages/about/pool.inc.php b/include/pages/about/pool.inc.php similarity index 100% rename from public/include/pages/about/pool.inc.php rename to include/pages/about/pool.inc.php diff --git a/public/include/pages/about/pplns.inc.php b/include/pages/about/pplns.inc.php similarity index 100% rename from public/include/pages/about/pplns.inc.php rename to include/pages/about/pplns.inc.php diff --git a/public/include/pages/account.inc.php b/include/pages/account.inc.php similarity index 100% rename from public/include/pages/account.inc.php rename to include/pages/account.inc.php diff --git a/public/include/pages/account/confirm.inc.php b/include/pages/account/confirm.inc.php similarity index 100% rename from public/include/pages/account/confirm.inc.php rename to include/pages/account/confirm.inc.php diff --git a/include/pages/account/earnings.inc.php b/include/pages/account/earnings.inc.php new file mode 100644 index 000000000..51453b5a1 --- /dev/null +++ b/include/pages/account/earnings.inc.php @@ -0,0 +1,23 @@ +isAuthenticated() AND !$setting->getValue('disable_transactionsummary')) { + if (!$smarty->isCached('master.tpl', $smarty_cache_key)) { + $iLimit = 30; + $debug->append('No cached version available, fetching from backend', 3); + $aTransactionSummary = $transaction->getTransactionSummary($_SESSION['USERDATA']['id']); + $aTransactionSummaryByTime = $transaction->getTransactionTypebyTime($_SESSION['USERDATA']['id']); + $smarty->assign('SUMMARY', $aTransactionSummary); + $smarty->assign('BYTIME', $aTransactionSummaryByTime); + } else { + $debug->append('Using cached page', 3); + } + $smarty->assign('CONTENT', 'default.tpl'); +} else if (!$setting->getValue('disable_transactionsummary')) { + $smarty->assign('CONTENT', 'disabled.tpl'); +} else { + $smarty->assign('CONTENT', 'disabled.tpl'); +} + +?> diff --git a/public/include/pages/account/edit.inc.php b/include/pages/account/edit.inc.php similarity index 87% rename from public/include/pages/account/edit.inc.php rename to include/pages/account/edit.inc.php index 951face4e..234f68d6d 100644 --- a/public/include/pages/account/edit.inc.php +++ b/include/pages/account/edit.inc.php @@ -30,7 +30,7 @@ $wf_editable = $user->token->isTokenValid($_SESSION['USERDATA']['id'], $oldtoken_wf, 7); $wf_sent = $user->token->doesTokenExist('withdraw_funds', $_SESSION['USERDATA']['id']); } - + // get the status of a token if set $message_tokensent_invalid = 'A token was sent to your e-mail that will allow you to '; $message_tokensent_valid = 'You can currently '; @@ -61,7 +61,7 @@ $_SESSION['POPUP'][] = array('CONTENT' => $popupmsg, 'TYPE' => 'alert alert-warning'); } } - + if (isset($_POST['do']) && $_POST['do'] == 'genPin') { if (!$config['csrf']['enabled'] || $config['csrf']['enabled'] && $csrftoken->valid) { if ($user->generatePin($_SESSION['USERDATA']['id'], $_POST['currentPassword'])) { @@ -100,9 +100,11 @@ $dBalance = $aBalance['confirmed']; if ($setting->getValue('disable_payouts') == 1 || $setting->getValue('disable_manual_payouts') == 1) { $_SESSION['POPUP'][] = array('CONTENT' => 'Manual payouts are disabled.', 'TYPE' => 'alert alert-warning'); + } else if ($config['twofactor']['enabled'] && $config['twofactor']['options']['withdraw'] && !$wf_editable) { + $_SESSION['POPUP'][] = array('CONTENT' => 'You have not yet unlocked account withdrawls.', 'TYPE' => 'alert alert-danger'); } else if ($aBalance['confirmed'] < $config['mp_threshold']) { $_SESSION['POPUP'][] = array('CONTENT' => 'Payout must be greater or equal than ' . $config['mp_threshold'] . '.', 'TYPE' => 'info'); - } else if (!$user->getCoinAddress($_SESSION['USERDATA']['id'])) { + } else if (!$coin_address->getCoinAddress($_SESSION['USERDATA']['id'])) { $_SESSION['POPUP'][] = array('CONTENT' => 'You have no payout address set.', 'TYPE' => 'alert alert-danger'); } else { $user->log->log("info", $_SESSION['USERDATA']['username']." requesting manual payout"); @@ -127,11 +129,14 @@ break; case 'updateAccount': - if (!$config['csrf']['enabled'] || $config['csrf']['enabled'] && $csrftoken->valid) { - if ($user->updateAccount($_SESSION['USERDATA']['id'], $_POST['paymentAddress'], $_POST['payoutThreshold'], $_POST['donatePercent'], $_POST['email'], $_POST['is_anonymous'], $oldtoken_ea)) { - $_SESSION['POPUP'][] = array('CONTENT' => 'Account details updated', 'TYPE' => 'alert alert-success'); + if ($config['twofactor']['enabled'] && $config['twofactor']['options']['details'] && !$ea_editable) { + $_SESSION['POPUP'][] = array('CONTENT' => 'You have not yet unlocked account updates.', 'TYPE' => 'alert alert-danger'); + } else if (!$config['csrf']['enabled'] || $config['csrf']['enabled'] && $csrftoken->valid) { + if ($user->updateAccount($_SESSION['USERDATA']['id'], $_POST['paymentAddress'], $_POST['payoutThreshold'], $_POST['donatePercent'], $_POST['email'], $_POST['timezone'], $_POST['is_anonymous'], $oldtoken_ea)) { + $_SESSION['USERDATA']['timezone'] = $_POST['timezone']; + $_SESSION['POPUP'][] = array('CONTENT' => 'Account details updated', 'TYPE' => 'alert alert-success'); } else { - $_SESSION['POPUP'][] = array('CONTENT' => 'Failed to update your account: ' . $user->getError(), 'TYPE' => 'alert alert-danger'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Failed to update your account: ' . $user->getError(), 'TYPE' => 'alert alert-danger'); } } else { $_SESSION['POPUP'][] = array('CONTENT' => $csrftoken->getErrorWithDescriptionHTML(), 'TYPE' => 'alert alert-warning'); @@ -139,7 +144,9 @@ break; case 'updatePassword': - if (!$config['csrf']['enabled'] || $config['csrf']['enabled'] && $csrftoken->valid) { + if ($config['twofactor']['enabled'] && $config['twofactor']['options']['changepw'] && !$cp_editable) { + $_SESSION['POPUP'][] = array('CONTENT' => 'You have not yet unlocked password updates.', 'TYPE' => 'alert alert-danger'); + } else if (!$config['csrf']['enabled'] || $config['csrf']['enabled'] && $csrftoken->valid) { if ($user->updatePassword($_SESSION['USERDATA']['id'], $_POST['currentPassword'], $_POST['newPassword'], $_POST['newPassword2'], $oldtoken_cp)) { $_SESSION['POPUP'][] = array('CONTENT' => 'Password updated', 'TYPE' => 'alert alert-success'); } else { @@ -191,6 +198,10 @@ $smarty->assign("DETAILSSENT", $ea_sent); } +// Grab our timezones +$smarty->assign('TIMEZONES', DateTimeZone::listIdentifiers()); + +// Fetch donation threshold $smarty->assign("DONATE_THRESHOLD", $config['donate_threshold']); // Tempalte specifics diff --git a/public/include/pages/account/invitations.inc.php b/include/pages/account/invitations.inc.php similarity index 100% rename from public/include/pages/account/invitations.inc.php rename to include/pages/account/invitations.inc.php diff --git a/public/include/pages/account/notifications.inc.php b/include/pages/account/notifications.inc.php similarity index 100% rename from public/include/pages/account/notifications.inc.php rename to include/pages/account/notifications.inc.php diff --git a/public/include/pages/account/qrcode.inc.php b/include/pages/account/qrcode.inc.php similarity index 100% rename from public/include/pages/account/qrcode.inc.php rename to include/pages/account/qrcode.inc.php diff --git a/public/include/pages/account/reset_failed.inc.php b/include/pages/account/reset_failed.inc.php similarity index 100% rename from public/include/pages/account/reset_failed.inc.php rename to include/pages/account/reset_failed.inc.php diff --git a/public/include/pages/account/transactions.inc.php b/include/pages/account/transactions.inc.php similarity index 100% rename from public/include/pages/account/transactions.inc.php rename to include/pages/account/transactions.inc.php diff --git a/public/include/pages/account/unlock.inc.php b/include/pages/account/unlock.inc.php similarity index 100% rename from public/include/pages/account/unlock.inc.php rename to include/pages/account/unlock.inc.php diff --git a/include/pages/account/workers.inc.php b/include/pages/account/workers.inc.php new file mode 100644 index 000000000..a672e11c0 --- /dev/null +++ b/include/pages/account/workers.inc.php @@ -0,0 +1,60 @@ +isAuthenticated()) { + + + if (!$coin_address->getCoinAddress($_SESSION['USERDATA']['id']) AND $setting->getValue('disable_worker_edit')) { + $_SESSION['POPUP'][] = array('CONTENT' => 'You have no payout address set.', 'TYPE' => 'alert alert-danger'); + $_SESSION['POPUP'][] = array('CONTENT' => 'You can not add workers unless a valid Payout Address is set in your User Settings.', 'TYPE' => 'alert alert-danger'); + $smarty->assign('CONTENT', 'disabled.tpl'); + } else { + switch (@$_REQUEST['do']) { + case 'delete': + if (!$config['csrf']['enabled'] || $config['csrf']['enabled'] && $csrftoken->valid) { + if ($worker->deleteWorker($_SESSION['USERDATA']['id'], $_GET['id'])) { + $_SESSION['POPUP'][] = array('CONTENT' => 'Worker removed', 'TYPE' => 'alert alert-success'); + } else { + $_SESSION['POPUP'][] = array('CONTENT' => $worker->getError(), 'TYPE' => 'alert alert-danger'); + } + } else { + $_SESSION['POPUP'][] = array('CONTENT' => $csrftoken->getErrorWithDescriptionHTML(), 'TYPE' => 'alert alert-warning'); + } + break; + + case 'add': + if (!$config['csrf']['enabled'] || $config['csrf']['enabled'] && $csrftoken->valid) { + if ($worker->addWorker($_SESSION['USERDATA']['id'], $_POST['username'], $_POST['password'])) { + $_SESSION['POPUP'][] = array('CONTENT' => 'Worker added', 'TYPE' => 'alert alert-success'); + } else { + $_SESSION['POPUP'][] = array('CONTENT' => $worker->getError(), 'TYPE' => 'alert alert-danger'); + } + } else { + $_SESSION['POPUP'][] = array('CONTENT' => $csrftoken->getErrorWithDescriptionHTML(), 'TYPE' => 'alert alert-warning'); + } + break; + + case 'update': + if (!$config['csrf']['enabled'] || $config['csrf']['enabled'] && $csrftoken->valid) { + if ($worker->updateWorkers($_SESSION['USERDATA']['id'], @$_POST['data'])) { + $_SESSION['POPUP'][] = array('CONTENT' => 'Worker updated', 'TYPE' => 'alert alert-success'); + } else { + $_SESSION['POPUP'][] = array('CONTENT' => $worker->getError(), 'TYPE' => 'alert alert-danger'); + } + } else { + $_SESSION['POPUP'][] = array('CONTENT' => $csrftoken->getErrorWithDescriptionHTML(), 'TYPE' => 'alert alert-warning'); + } + break; + } + + $smarty->assign('DISABLE_IDLEWORKERNOTIFICATIONS', $setting->getValue('notifications_disable_idle_worker')); + $aWorkers = $worker->getWorkers($_SESSION['USERDATA']['id']); + if (!$aWorkers) $_SESSION['POPUP'][] = array('CONTENT' => 'You have no workers configured', 'TYPE' => 'alert alert-danger'); + + $smarty->assign('WORKERS', $aWorkers); + $smarty->assign('CONTENT', 'default.tpl'); + } +} + + +?> diff --git a/public/include/pages/admin.inc.php b/include/pages/admin.inc.php similarity index 100% rename from public/include/pages/admin.inc.php rename to include/pages/admin.inc.php diff --git a/public/include/pages/admin/dashboard.inc.php b/include/pages/admin/dashboard.inc.php similarity index 89% rename from public/include/pages/admin/dashboard.inc.php rename to include/pages/admin/dashboard.inc.php index d5ab1bdc3..63d2738f8 100644 --- a/public/include/pages/admin/dashboard.inc.php +++ b/include/pages/admin/dashboard.inc.php @@ -14,9 +14,14 @@ $_SESSION['POPUP'][] = array('CONTENT' => 'Unable to connect to wallet RPC service: ' . $bitcoin->can_connect(), 'TYPE' => 'alert alert-danger'); } +// Grab versions from Online source +require_once(CLASS_DIR . '/tools.class.php'); +$online_versions = $tools->getOnlineVersions(); + // Fetch version information $version['CURRENT'] = array('DB' => DB_VERSION, 'CONFIG' => CONFIG_VERSION, 'CORE' => MPOS_VERSION); -$version['INSTALLED'] = array('DB' => $setting->getValue('DB_VERSION'), 'CONFIG' => $config['version'], 'CORE' => MPOS_VERSION); +$version['INSTALLED'] = array('DB' => $setting->getValue('DB_VERSION'), 'CONFIG' => $config['version'], 'CORE' => $online_versions['MPOS_VERSION']); +$version['ONLINE'] = array('DB' => $online_versions['DB_VERSION'], 'CONFIG' => $online_versions['CONFIG_VERSION'], 'CORE' => $online_versions['MPOS_VERSION']); // Fetch our cron list $aMonitorCrons require_once(INCLUDE_DIR . '/config/monitor_crons.inc.php'); diff --git a/public/include/pages/account/earnings.inc.php b/include/pages/admin/earnings.inc.php similarity index 100% rename from public/include/pages/account/earnings.inc.php rename to include/pages/admin/earnings.inc.php diff --git a/public/include/pages/admin/invitations.inc.php b/include/pages/admin/invitations.inc.php similarity index 100% rename from public/include/pages/admin/invitations.inc.php rename to include/pages/admin/invitations.inc.php diff --git a/public/include/pages/admin/monitoring.inc.php b/include/pages/admin/monitoring.inc.php similarity index 100% rename from public/include/pages/admin/monitoring.inc.php rename to include/pages/admin/monitoring.inc.php diff --git a/include/pages/admin/news.inc.php b/include/pages/admin/news.inc.php new file mode 100644 index 000000000..9d39146eb --- /dev/null +++ b/include/pages/admin/news.inc.php @@ -0,0 +1,49 @@ +isAuthenticated() || !$user->isAdmin($_SESSION['USERDATA']['id'])) { + header("HTTP/1.1 404 Page not found"); + die("404 Page not found"); +} + +// Include markdown library +use \Michelf\Markdown; + +if (@$_REQUEST['do'] == 'toggle_active') { + if (!$config['csrf']['enabled'] || $config['csrf']['enabled'] && $csrftoken->valid) { + if ($news->toggleActive($_REQUEST['id'])) { + $_SESSION['POPUP'][] = array('CONTENT' => 'News entry changed', 'TYPE' => 'alert alert-success'); + } + } +} + +if (@$_REQUEST['do'] == 'add') { + if (!$config['csrf']['enabled'] || $config['csrf']['enabled'] && $csrftoken->valid) { + if ($news->addNews($_SESSION['USERDATA']['id'], $_POST['data'])) { + $_SESSION['POPUP'][] = array('CONTENT' => 'News entry added', 'TYPE' => 'alert alert-success'); + } else { + $_SESSION['POPUP'][] = array('CONTENT' => 'Failed to add new entry: ' . $news->getError(), 'TYPE' => 'alert alert-danger'); + } + } +} + +if (@$_REQUEST['do'] == 'delete') { + if (!$config['csrf']['enabled'] || $config['csrf']['enabled'] && $csrftoken->valid) { + if ($news->deleteNews((int)$_REQUEST['id'])) { + $_SESSION['POPUP'][] = array('CONTENT' => 'Succesfully removed news entry', 'TYPE' => 'alert alert-success'); + } else { + $_SESSION['POPUP'][] = array('CONTENT' => 'Failed to delete entry: ' . $news->getError(), 'TYPE' => 'alert alert-danger'); + } + } +} + +// Fetch all news +$aNews = $news->getAll(); +foreach ($aNews as $key => $aData) { + // Transform Markdown content to HTML + $aNews[$key]['content'] = Markdown::defaultTransform($aData['content']); +} +$smarty->assign("NEWS", $aNews); +$smarty->assign("CONTENT", "default.tpl"); +?> \ No newline at end of file diff --git a/include/pages/admin/news_edit.inc.php b/include/pages/admin/news_edit.inc.php new file mode 100644 index 000000000..07c472b8d --- /dev/null +++ b/include/pages/admin/news_edit.inc.php @@ -0,0 +1,27 @@ +isAuthenticated() || !$user->isAdmin($_SESSION['USERDATA']['id'])) { + header("HTTP/1.1 404 Page not found"); + die("404 Page not found"); +} + +// Include markdown library +use \Michelf\Markdown; + +if (!$config['csrf']['enabled'] || $config['csrf']['enabled'] && $csrftoken->valid) { + if (@$_REQUEST['do'] == 'save') { + if ($news->updateNews($_REQUEST['id'], $_REQUEST['header'], $_REQUEST['content'], $_REQUEST['active'])) { + $_SESSION['POPUP'][] = array('CONTENT' => 'News updated', 'TYPE' => 'alert alert-success'); + } else { + $_SESSION['POPUP'][] = array('CONTENT' => 'News update failed: ' . $news->getError(), 'TYPE' => 'alert alert-danger'); + } + } +} + +// Fetch news entry +$aNews = $news->getEntry($_REQUEST['id']); +$smarty->assign("NEWS", $aNews); +$smarty->assign("CONTENT", "default.tpl"); +?> \ No newline at end of file diff --git a/public/include/pages/admin/newsletter.inc.php b/include/pages/admin/newsletter.inc.php similarity index 96% rename from public/include/pages/admin/newsletter.inc.php rename to include/pages/admin/newsletter.inc.php index 69204b01e..fed4f3428 100644 --- a/public/include/pages/admin/newsletter.inc.php +++ b/include/pages/admin/newsletter.inc.php @@ -20,7 +20,7 @@ $iSuccess = 0; foreach ($user->getAllAssoc() as $aData) { $aUserNotificationSettings = $notification->getNotificationSettings($aData['id']); - if ($aData['is_locked'] != 0 || $aUserNotificationSettings['newsletter'] != 1) continue; + if ($aData['is_locked'] != 0 || $aUserNotificationSettings['newsletter'] != 1 || empty($aData['email'])) continue; $aData['subject'] = $_REQUEST['data']['subject']; $aData['CONTENT'] = $_REQUEST['data']['content']; if (!$mail->sendMail('newsletter/body', $aData, true)) { diff --git a/public/include/pages/admin/poolworkers.inc.php b/include/pages/admin/poolworkers.inc.php similarity index 100% rename from public/include/pages/admin/poolworkers.inc.php rename to include/pages/admin/poolworkers.inc.php diff --git a/public/include/pages/admin/registrations.inc.php b/include/pages/admin/registrations.inc.php similarity index 100% rename from public/include/pages/admin/registrations.inc.php rename to include/pages/admin/registrations.inc.php diff --git a/public/include/pages/admin/reports.inc.php b/include/pages/admin/reports.inc.php similarity index 100% rename from public/include/pages/admin/reports.inc.php rename to include/pages/admin/reports.inc.php diff --git a/public/include/pages/admin/settings.inc.php b/include/pages/admin/settings.inc.php similarity index 53% rename from public/include/pages/admin/settings.inc.php rename to include/pages/admin/settings.inc.php index 9412f69c5..dcb749d33 100644 --- a/public/include/pages/admin/settings.inc.php +++ b/include/pages/admin/settings.inc.php @@ -8,11 +8,15 @@ } if (@$_REQUEST['do'] == 'save' && !empty($_REQUEST['data'])) { - $user->log->log("warn", @$_SESSION['USERDATA']['username']." changed admin settings"); - foreach($_REQUEST['data'] as $var => $value) { - $setting->setValue($var, $value); + if (!$config['csrf']['enabled'] || $config['csrf']['enabled'] && $csrftoken->valid) { + $user->log->log("warn", @$_SESSION['USERDATA']['username']." changed admin settings"); + foreach($_REQUEST['data'] as $var => $value) { + $setting->setValue($var, $value); + } + $_SESSION['POPUP'][] = array('CONTENT' => 'Settings updated', 'TYPE' => 'alert alert-success'); + } else { + $_SESSION['POPUP'][] = array('CONTENT' => $csrftoken->getErrorWithDescriptionHTML(), 'TYPE' => 'alert alert-warning'); } - $_SESSION['POPUP'][] = array('CONTENT' => 'Settings updated', 'TYPE' => 'alert alert-success'); } // Load our available settings from configuration @@ -23,4 +27,4 @@ // Tempalte specifics $smarty->assign("CONTENT", "default.tpl"); -?> +?> \ No newline at end of file diff --git a/public/include/pages/admin/transactions.inc.php b/include/pages/admin/transactions.inc.php similarity index 100% rename from public/include/pages/admin/transactions.inc.php rename to include/pages/admin/transactions.inc.php diff --git a/public/include/pages/admin/user.inc.php b/include/pages/admin/user.inc.php similarity index 78% rename from public/include/pages/admin/user.inc.php rename to include/pages/admin/user.inc.php index dfc9de052..8f0dfa837 100644 --- a/public/include/pages/admin/user.inc.php +++ b/include/pages/admin/user.inc.php @@ -16,26 +16,28 @@ $smarty->assign('NOFEE', array('' => '', '0' => 'No', '1' => 'Yes')); // Catch our JS queries to update some settings -switch (@$_REQUEST['do']) { -case 'lock': - $supress_master = 1; - // Reset user account - if ($user->isLocked($_POST['account_id']) == 0) { - $user->setLocked($_POST['account_id'], 2); - } else { - $user->setLocked($_POST['account_id'], 0); - $user->setUserFailed($_POST['account_id'], 0); - $user->setUserPinFailed($_POST['account_id'], 0); +if (!$config['csrf']['enabled'] || $config['csrf']['enabled'] && $csrftoken->valid) { + switch (@$_REQUEST['do']) { + case 'lock': + $supress_master = 1; + // Reset user account + if ($user->isLocked($_POST['account_id']) == 0) { + $user->setLocked($_POST['account_id'], 2); + } else { + $user->setLocked($_POST['account_id'], 0); + $user->setUserFailed($_POST['account_id'], 0); + $user->setUserPinFailed($_POST['account_id'], 0); + } + break; + case 'fee': + $supress_master = 1; + $user->changeNoFee($_POST['account_id']); + break; + case 'admin': + $supress_master = 1; + $user->changeAdmin($_POST['account_id']); + break; } - break; -case 'fee': - $supress_master = 1; - $user->changeNoFee($_POST['account_id']); - break; -case 'admin': - $supress_master = 1; - $user->changeAdmin($_POST['account_id']); - break; } // Gernerate the GET URL for filters @@ -81,4 +83,4 @@ // Tempalte specifics $smarty->assign("CONTENT", "default.tpl"); -?> +?> \ No newline at end of file diff --git a/include/pages/admin/userdetails.inc.php b/include/pages/admin/userdetails.inc.php new file mode 100644 index 000000000..4bac75f4b --- /dev/null +++ b/include/pages/admin/userdetails.inc.php @@ -0,0 +1,24 @@ +isAuthenticated() || !$user->isAdmin($_SESSION['USERDATA']['id'])) { + header("HTTP/1.1 404 Page not found"); + die("404 Page not found"); +} + +if (!$smarty->isCached('master.tpl', $smarty_cache_key)) { + $debug->append('No cached version available, fetching from backend', 3); + if (isset($_REQUEST['id']) && !empty($_REQUEST['id'])) { + $aTransactionSummary = $transaction->getTransactionSummary($_REQUEST['id']); + $aTransactionSummaryByTime = $transaction->getTransactionTypebyTime($_REQUEST['id']); + $smarty->assign('USERNAME', $user->getUsername($_REQUEST['id'])); + $smarty->assign('SUMMARY', $aTransactionSummary); + $smarty->assign('BYTIME', $aTransactionSummaryByTime); + } +} else { + $debug->append('Using cached page', 3); +} + +$smarty->assign('CONTENT', 'default.tpl'); +?> diff --git a/public/include/pages/admin/wallet.inc.php b/include/pages/admin/wallet.inc.php similarity index 100% rename from public/include/pages/admin/wallet.inc.php rename to include/pages/admin/wallet.inc.php diff --git a/public/include/pages/api.inc.php b/include/pages/api.inc.php similarity index 81% rename from public/include/pages/api.inc.php rename to include/pages/api.inc.php index 01cd20f52..32fd0a34b 100644 --- a/public/include/pages/api.inc.php +++ b/include/pages/api.inc.php @@ -5,7 +5,7 @@ $api->isActive(); // Check for valid API key -$id = $user->checkApiKey($_REQUEST['api_key']); +$id = $user->checkApiKey(@$_REQUEST['api_key']); header('HTTP/1.1 400 Bad Request'); die('400 Bad Request'); diff --git a/public/include/pages/api/getblockcount.inc.php b/include/pages/api/getblockcount.inc.php similarity index 100% rename from public/include/pages/api/getblockcount.inc.php rename to include/pages/api/getblockcount.inc.php diff --git a/public/include/pages/api/getblocksfound.inc.php b/include/pages/api/getblocksfound.inc.php similarity index 100% rename from public/include/pages/api/getblocksfound.inc.php rename to include/pages/api/getblocksfound.inc.php diff --git a/public/include/pages/api/getblockstats.inc.php b/include/pages/api/getblockstats.inc.php similarity index 100% rename from public/include/pages/api/getblockstats.inc.php rename to include/pages/api/getblockstats.inc.php diff --git a/public/include/pages/api/getcronjobstatus.inc.php b/include/pages/api/getcronjobstatus.inc.php similarity index 100% rename from public/include/pages/api/getcronjobstatus.inc.php rename to include/pages/api/getcronjobstatus.inc.php diff --git a/public/include/pages/api/getcurrentworkers.inc.php b/include/pages/api/getcurrentworkers.inc.php similarity index 100% rename from public/include/pages/api/getcurrentworkers.inc.php rename to include/pages/api/getcurrentworkers.inc.php diff --git a/public/include/pages/api/getdashboarddata.inc.php b/include/pages/api/getdashboarddata.inc.php similarity index 90% rename from public/include/pages/api/getdashboarddata.inc.php rename to include/pages/api/getdashboarddata.inc.php index b4b3575bc..ccd8a645c 100644 --- a/public/include/pages/api/getdashboarddata.inc.php +++ b/include/pages/api/getdashboarddata.inc.php @@ -78,10 +78,22 @@ $iEstShares > 0 && $aRoundShares['valid'] > 0 ? $dEstPercent = round(100 / $iEstShares * $aRoundShares['valid'], 2) : $dEstPercent = 0; // Some estimates -$dExpectedTimePerBlock = $statistics->getNetworkExpectedTimePerBlock(); +$dExpectedTimePerBlock = $statistics->getExpectedTimePerBlock(); +$dPoolExpectedTimePerBlock = $statistics->getExpectedTimePerBlock('pool', $dPoolHashrate); $dEstNextDifficulty = $statistics->getExpectedNextDifficulty(); $iBlocksUntilDiffChange = $statistics->getBlocksUntilDiffChange(); +// Block statistics +$aLastBlocks = $statistics->getBlocksFound(5); +if (!$user->isAdmin(@$_SESSION['USERDATA']['id'])) { + foreach ($aLastBlocks as $key => $data) { + if ($data['is_anonymous'] == 1) { + $aLastBlocks[$key]['worker_name'] = 'anonymous'; + $aLastBlocks[$key]['finder'] = 'anonymous'; + } + } +} + // Output JSON format $data = array( 'raw' => array( 'personal' => array( 'hashrate' => $dPersonalHashrate ), 'pool' => array( 'hashrate' => $dPoolHashrate ), 'network' => array( 'hashrate' => $dNetworkHashrate / 1000, 'esttimeperblock' => $dExpectedTimePerBlock, 'nextdifficulty' => $dEstNextDifficulty, 'blocksuntildiffchange' => $iBlocksUntilDiffChange ) ), @@ -94,6 +106,8 @@ 'name' => $setting->getValue('website_name'), 'currency' => $config['currency'] ), + 'esttimeperblock' => round($dPoolExpectedTimePerBlock, 2), + 'blocks' => $aLastBlocks, 'workers' => $worker->getCountAllActiveWorkers(), 'hashrate' => $dPoolHashrateAdjusted, 'shares' => array( 'valid' => $aRoundShares['valid'], 'invalid' => $aRoundShares['invalid'], 'invalid_percent' => $dPoolInvalidPercent, 'estimated' => $iEstShares, 'progress' => $dEstPercent ), 'price' => $aPrice, diff --git a/public/include/pages/api/getdifficulty.inc.php b/include/pages/api/getdifficulty.inc.php similarity index 100% rename from public/include/pages/api/getdifficulty.inc.php rename to include/pages/api/getdifficulty.inc.php diff --git a/public/include/pages/api/getestimatedtime.inc.php b/include/pages/api/getestimatedtime.inc.php similarity index 100% rename from public/include/pages/api/getestimatedtime.inc.php rename to include/pages/api/getestimatedtime.inc.php diff --git a/public/include/pages/api/gethourlyhashrates.inc.php b/include/pages/api/gethourlyhashrates.inc.php similarity index 100% rename from public/include/pages/api/gethourlyhashrates.inc.php rename to include/pages/api/gethourlyhashrates.inc.php diff --git a/public/include/pages/api/getpoolhashrate.inc.php b/include/pages/api/getpoolhashrate.inc.php similarity index 100% rename from public/include/pages/api/getpoolhashrate.inc.php rename to include/pages/api/getpoolhashrate.inc.php diff --git a/include/pages/api/getpoolinfo.inc.php b/include/pages/api/getpoolinfo.inc.php new file mode 100644 index 000000000..7d08ceb5a --- /dev/null +++ b/include/pages/api/getpoolinfo.inc.php @@ -0,0 +1,39 @@ +isActive(); + +// Check user token +$user_id = $api->checkAccess($user->checkApiKey($_REQUEST['api_key']), @$_REQUEST['id']); + +// Output JSON format +$data = array( + // coin info + 'currency' => $config['currency'], + 'coinname' => $config['gettingstarted']['coinname'], + // coin algorithm info + 'cointarget' => $config['cointarget'], + 'coindiffchangetarget' => $config['coindiffchangetarget'], + 'algorithm' => $config['algorithm'], + // stratum + 'stratumport' => $config['gettingstarted']['stratumport'], + // payments + 'payout_system' => $config['payout_system'], + 'confirmations' => $config['confirmations'], + 'min_ap_threshold' => $config['ap_threshold']['min'], + 'max_ap_threshold' => $config['ap_threshold']['max'], + 'reward_type' => $config['payout_system'] == 'pps' ? $config['pps']['reward']['type'] : $config['reward_type'], + 'reward' => $config['payout_system'] == 'pps' ? $config['pps']['reward']['default'] : $config['reward'], + // fees + 'txfee' => $config['txfee_manual'], // make it backwards compatible + 'txfee_manual' => $config['txfee_manual'], + 'txfee_auto' => $config['txfee_auto'], + 'fees' => $config['fees'] +); + +echo $api->get_json($data); + +// Supress master template +$supress_master = 1; +?> diff --git a/public/include/pages/api/getpoolsharerate.inc.php b/include/pages/api/getpoolsharerate.inc.php similarity index 100% rename from public/include/pages/api/getpoolsharerate.inc.php rename to include/pages/api/getpoolsharerate.inc.php diff --git a/public/include/pages/api/getpoolstatus.inc.php b/include/pages/api/getpoolstatus.inc.php similarity index 100% rename from public/include/pages/api/getpoolstatus.inc.php rename to include/pages/api/getpoolstatus.inc.php diff --git a/public/include/pages/api/gettimesincelastblock.inc.php b/include/pages/api/gettimesincelastblock.inc.php similarity index 100% rename from public/include/pages/api/gettimesincelastblock.inc.php rename to include/pages/api/gettimesincelastblock.inc.php diff --git a/public/include/pages/api/gettopcontributors.inc.php b/include/pages/api/gettopcontributors.inc.php similarity index 100% rename from public/include/pages/api/gettopcontributors.inc.php rename to include/pages/api/gettopcontributors.inc.php diff --git a/public/include/pages/api/getuserbalance.inc.php b/include/pages/api/getuserbalance.inc.php similarity index 100% rename from public/include/pages/api/getuserbalance.inc.php rename to include/pages/api/getuserbalance.inc.php diff --git a/public/include/pages/api/getuserhashrate.inc.php b/include/pages/api/getuserhashrate.inc.php similarity index 100% rename from public/include/pages/api/getuserhashrate.inc.php rename to include/pages/api/getuserhashrate.inc.php diff --git a/public/include/pages/api/getusersharerate.inc.php b/include/pages/api/getusersharerate.inc.php similarity index 100% rename from public/include/pages/api/getusersharerate.inc.php rename to include/pages/api/getusersharerate.inc.php diff --git a/public/include/pages/api/getuserstatus.inc.php b/include/pages/api/getuserstatus.inc.php similarity index 100% rename from public/include/pages/api/getuserstatus.inc.php rename to include/pages/api/getuserstatus.inc.php diff --git a/public/include/pages/api/getusertransactions.inc.php b/include/pages/api/getusertransactions.inc.php similarity index 100% rename from public/include/pages/api/getusertransactions.inc.php rename to include/pages/api/getusertransactions.inc.php diff --git a/public/include/pages/api/getuserworkers.inc.php b/include/pages/api/getuserworkers.inc.php similarity index 100% rename from public/include/pages/api/getuserworkers.inc.php rename to include/pages/api/getuserworkers.inc.php diff --git a/public/include/pages/api/public.inc.php b/include/pages/api/public.inc.php similarity index 86% rename from public/include/pages/api/public.inc.php rename to include/pages/api/public.inc.php index c6b128d62..6446b5e51 100644 --- a/public/include/pages/api/public.inc.php +++ b/include/pages/api/public.inc.php @@ -19,7 +19,9 @@ 'workers' => $worker->getCountAllActiveWorkers(), 'shares_this_round' => $aShares['valid'], 'last_block' => $aLastBlock['height'], - 'network_hashrate' => $dNetworkHashrate + 'network_hashrate' => $dNetworkHashrate, + 'fee' => $config['fees'], + 'payout' => $config['payout_system'] ) ); diff --git a/public/include/pages/contactform.inc.php b/include/pages/contactform.inc.php similarity index 100% rename from public/include/pages/contactform.inc.php rename to include/pages/contactform.inc.php diff --git a/public/include/pages/contactform/contactform.inc.php b/include/pages/contactform/contactform.inc.php similarity index 100% rename from public/include/pages/contactform/contactform.inc.php rename to include/pages/contactform/contactform.inc.php diff --git a/public/include/pages/dashboard.inc.php b/include/pages/dashboard.inc.php similarity index 76% rename from public/include/pages/dashboard.inc.php rename to include/pages/dashboard.inc.php index 7047cfb8a..01598da6a 100644 --- a/public/include/pages/dashboard.inc.php +++ b/include/pages/dashboard.inc.php @@ -33,13 +33,27 @@ // Avoid confusion, ensure our nethash isn't higher than poolhash if ($iCurrentPoolHashrate > $dNetworkHashrate) $dNetworkHashrate = $iCurrentPoolHashrate; - $dExpectedTimePerBlock = $statistics->getNetworkExpectedTimePerBlock(); + $dExpectedTimePerBlock = $statistics->getExpectedTimePerBlock('pool', $iCurrentPoolHashrate); $dEstNextDifficulty = $statistics->getExpectedNextDifficulty(); $iBlocksUntilDiffChange = $statistics->getBlocksUntilDiffChange(); + // Block statistics + $aLastBlocks = $statistics->getBlocksFound(5); + if (!$user->isAdmin(@$_SESSION['USERDATA']['id'])) { + foreach ($aLastBlocks as $key => $data) { + if ($data['is_anonymous'] == 1) { + $aLastBlocks[$key]['worker_name'] = 'anonymous'; + $aLastBlocks[$key]['finder'] = 'anonymous'; + } + } + } + // Make it available in Smarty + $smarty->assign('PRECISION', $coin->getCoinValuePrevision()); + $smarty->assign('BLOCKSFOUND', $aLastBlocks); $smarty->assign('DISABLED_DASHBOARD', $setting->getValue('disable_dashboard')); $smarty->assign('DISABLED_DASHBOARD_API', $setting->getValue('disable_dashboard_api')); + $smarty->assign('DISABLED_API', $setting->getValue('disable_api')); $smarty->assign('ESTIMATES', array('shares' => $iEstShares, 'percent' => $dEstPercent)); $smarty->assign('NETWORK', array('difficulty' => $dDifficulty, 'block' => $iBlock, 'EstNextDifficulty' => $dEstNextDifficulty, 'EstTimePerBlock' => $dExpectedTimePerBlock, 'BlocksUntilDiffChange' => $iBlocksUntilDiffChange)); $smarty->assign('INTERVAL', $interval / 60); diff --git a/public/include/pages/error.inc.php b/include/pages/error.inc.php similarity index 100% rename from public/include/pages/error.inc.php rename to include/pages/error.inc.php diff --git a/public/include/pages/error/404.inc.php b/include/pages/error/404.inc.php similarity index 100% rename from public/include/pages/error/404.inc.php rename to include/pages/error/404.inc.php diff --git a/public/include/pages/error/ratelimit.inc.php b/include/pages/error/ratelimit.inc.php similarity index 100% rename from public/include/pages/error/ratelimit.inc.php rename to include/pages/error/ratelimit.inc.php diff --git a/public/include/pages/gettingstarted.inc.php b/include/pages/gettingstarted.inc.php similarity index 100% rename from public/include/pages/gettingstarted.inc.php rename to include/pages/gettingstarted.inc.php diff --git a/public/include/pages/home.inc.php b/include/pages/home.inc.php similarity index 100% rename from public/include/pages/home.inc.php rename to include/pages/home.inc.php diff --git a/include/pages/login.inc.php b/include/pages/login.inc.php new file mode 100644 index 000000000..8d4a05df0 --- /dev/null +++ b/include/pages/login.inc.php @@ -0,0 +1,50 @@ +getValue('recaptcha_enabled') && $setting->getValue('recaptcha_enabled_logins')) { + require_once(INCLUDE_DIR . '/lib/recaptchalib.php'); + if (!empty($_POST['username']) && !empty($_POST['password'])) { + // Load re-captcha specific data + $rsp = recaptcha_check_answer ( + $setting->getValue('recaptcha_private_key'), + $_SERVER["REMOTE_ADDR"], + ( (isset($_POST["recaptcha_challenge_field"])) ? $_POST["recaptcha_challenge_field"] : null ), + ( (isset($_POST["recaptcha_response_field"])) ? $_POST["recaptcha_response_field"] : null ) + ); + $smarty->assign("RECAPTCHA", recaptcha_get_html($setting->getValue('recaptcha_public_key'), $rsp->error, true)); + } else { + $smarty->assign("RECAPTCHA", recaptcha_get_html($setting->getValue('recaptcha_public_key'), null, true)); + } +} + +if (!empty($_POST['username']) && !empty($_POST['password'])) { + if ($setting->getValue('maintenance') && !$user->isAdmin($user->getUserIdByEmail($_POST['username']))) { + $_SESSION['POPUP'][] = array('CONTENT' => 'You are not allowed to login during maintenace.', 'TYPE' => 'alert alert-info'); + } else { + // Check if recaptcha is enabled, process form data if valid + if (!$setting->getValue('recaptcha_enabled') || !$setting->getValue('recaptcha_enabled_logins') || ($setting->getValue('recaptcha_enabled') && $setting->getValue('recaptcha_enabled_logins') && $rsp->is_valid)) { + if (!$config['csrf']['enabled'] || $config['csrf']['enabled'] && $csrftoken->valid) { + // check if login is correct + if ($user->checkLogin(@$_POST['username'], @$_POST['password']) ) { + $port = ($_SERVER["SERVER_PORT"] == "80" || $_SERVER["SERVER_PORT"] == "443") ? "" : (":".$_SERVER["SERVER_PORT"]); + $location = (@$_SERVER['HTTPS'] == "on") ? 'https://' : 'http://'; + $location .= $_SERVER['SERVER_NAME'] . $port . $_SERVER['SCRIPT_NAME']; + $location.= '?page=dashboard'; + if (!headers_sent()) header('Location: ' . $location); + exit(''); + } else { + $_SESSION['POPUP'][] = array('CONTENT' => 'Unable to login: '.$user->getError(), 'TYPE' => 'alert alert-danger'); + } + } else { + $_SESSION['POPUP'][] = array('CONTENT' => $csrftoken->getErrorWithDescriptionHTML(), 'TYPE' => 'alert alert-warning'); + } + } else { + $_SESSION['POPUP'][] = array('CONTENT' => 'Invalid Captcha, please try again.', 'TYPE' => 'alert alert-danger'); + } + } +} +// Load login template +$smarty->assign('CONTENT', 'default.tpl'); + +?> diff --git a/public/include/pages/logout.inc.php b/include/pages/logout.inc.php similarity index 100% rename from public/include/pages/logout.inc.php rename to include/pages/logout.inc.php diff --git a/public/include/pages/news.inc.php b/include/pages/news.inc.php similarity index 100% rename from public/include/pages/news.inc.php rename to include/pages/news.inc.php diff --git a/public/include/pages/password.inc.php b/include/pages/password.inc.php similarity index 100% rename from public/include/pages/password.inc.php rename to include/pages/password.inc.php diff --git a/public/include/pages/password/change.inc.php b/include/pages/password/change.inc.php similarity index 100% rename from public/include/pages/password/change.inc.php rename to include/pages/password/change.inc.php diff --git a/public/include/pages/password/reset.inc.php b/include/pages/password/reset.inc.php similarity index 100% rename from public/include/pages/password/reset.inc.php rename to include/pages/password/reset.inc.php diff --git a/public/include/pages/register.inc.php b/include/pages/register.inc.php similarity index 100% rename from public/include/pages/register.inc.php rename to include/pages/register.inc.php diff --git a/public/include/pages/register/register.inc.php b/include/pages/register/register.inc.php similarity index 70% rename from public/include/pages/register/register.inc.php rename to include/pages/register/register.inc.php index e2dcd75f2..87f856ee3 100644 --- a/public/include/pages/register/register.inc.php +++ b/include/pages/register/register.inc.php @@ -26,10 +26,15 @@ if ($setting->getValue('recaptcha_enabled') != 1 || $setting->getValue('recaptcha_enabled_registrations') != 1 || $rsp->is_valid) { // Check if recaptcha is enabled, process form data if valid or disabled isset($_POST['token']) ? $token = $_POST['token'] : $token = ''; - if ($user->register(@$_POST['username'], @$_POST['password1'], @$_POST['password2'], @$_POST['pin'], @$_POST['email1'], @$_POST['email2'], @$_POST['tac'], $token)) { - (!$setting->getValue('accounts_confirm_email_disabled')) ? $_SESSION['POPUP'][] = array('CONTENT' => 'Please check your mailbox to activate this account') : $_SESSION['POPUP'][] = array('CONTENT' => 'Account created, please login'); + isset($_POST['coinaddress']) ? $validcoinaddress = $_POST['coinaddress'] : $validcoinaddress = NULL; + if ($config['check_valid_coinaddress'] AND empty($validcoinaddress)) { + $_SESSION['POPUP'][] = array('CONTENT' => 'Please enter a valid Wallet Address', 'TYPE' => 'alert alert-danger'); } else { - $_SESSION['POPUP'][] = array('CONTENT' => 'Unable to create account: ' . $user->getError(), 'TYPE' => 'alert alert-danger'); + if ($user->register(@$_POST['username'], $validcoinaddress, @$_POST['password1'], @$_POST['password2'], @$_POST['pin'], @$_POST['email1'], @$_POST['email2'], @$_POST['tac'], $token)) { + (!$setting->getValue('accounts_confirm_email_disabled')) ? $_SESSION['POPUP'][] = array('CONTENT' => 'Please check your mailbox to activate this account') : $_SESSION['POPUP'][] = array('CONTENT' => 'Account created, please login'); + } else { + $_SESSION['POPUP'][] = array('CONTENT' => 'Unable to create account: ' . $user->getError(), 'TYPE' => 'alert alert-danger'); + } } } } else { diff --git a/public/include/pages/statistics.inc.php b/include/pages/statistics.inc.php similarity index 100% rename from public/include/pages/statistics.inc.php rename to include/pages/statistics.inc.php diff --git a/public/include/pages/statistics/blockfinder.inc.php b/include/pages/statistics/blockfinder.inc.php similarity index 100% rename from public/include/pages/statistics/blockfinder.inc.php rename to include/pages/statistics/blockfinder.inc.php diff --git a/public/include/pages/statistics/blocks.inc.php b/include/pages/statistics/blocks.inc.php similarity index 97% rename from public/include/pages/statistics/blocks.inc.php rename to include/pages/statistics/blocks.inc.php index 90ea84251..3fd0d6167 100644 --- a/public/include/pages/statistics/blocks.inc.php +++ b/include/pages/statistics/blocks.inc.php @@ -34,9 +34,9 @@ $test = true; $count = 10; $percent = 30; - if (@$_REQUEST['count'] && is_numeric($_REQUEST['count'])) + if (@$_REQUEST['count'] && is_numeric($_REQUEST['count'])) $count = $_REQUEST['count']; - if (@$_REQUEST['percent'] && is_numeric($_REQUEST['percent'])) + if (@$_REQUEST['percent'] && is_numeric($_REQUEST['percent'])) $percent = $_REQUEST['percent']; } @@ -48,19 +48,19 @@ if ($setting->getValue('statistics_show_block_average') && !$test) { $aBlocksFoundData[$key]['block_avg'] = round($block->getAvgBlockShares($aData['height'], $config['pplns']['blockavg']['blockcount'])); $use_average = true; - } + } } } else if ($config['payout_system'] == 'prop' || $config['payout_system'] == 'pps') { if ($setting->getValue('statistics_show_block_average') && !$test) { foreach($aBlocksFoundData as $key => $aData) { $aBlocksFoundData[$key]['block_avg'] = round($block->getAvgBlockShares($aData['height'], $config['pplns']['blockavg']['blockcount'])); $use_average = true; - } + } } } // show test data in graph if ($test) { - $use_average = true; + $use_average = true; foreach($aBlocksFoundData as $key => $aData) { if ($_REQUEST['test'] == 1) { $aBlocksFoundData[$key]['block_avg'] = round($block->getAvgBlockShares($aData['height'], $count)); diff --git a/public/include/pages/statistics/donors.inc.php b/include/pages/statistics/donors.inc.php similarity index 100% rename from public/include/pages/statistics/donors.inc.php rename to include/pages/statistics/donors.inc.php diff --git a/public/include/pages/statistics/graphs.inc.php b/include/pages/statistics/graphs.inc.php similarity index 69% rename from public/include/pages/statistics/graphs.inc.php rename to include/pages/statistics/graphs.inc.php index 0a19492d9..a212e941d 100644 --- a/public/include/pages/statistics/graphs.inc.php +++ b/include/pages/statistics/graphs.inc.php @@ -4,11 +4,9 @@ if (!$smarty->isCached('master.tpl', $smarty_cache_key)) { $debug->append('No cached version available, fetching from backend', 3); if ($user->isAuthenticated()) { - $aHourlyHashRates = $statistics->getHourlyHashrateByAccount($_SESSION['USERDATA']['username'], $_SESSION['USERDATA']['id']); - $aPoolHourlyHashRates = $statistics->getHourlyHashrateByPool(); + $aHourlyMiningStats = $statistics->getHourlyMiningStatsByAccount($_SESSION['USERDATA']['id'], 'json', $setting->getValue('statistics_graphing_days', 1)); } - $smarty->assign("YOURHASHRATES", @$aHourlyHashRates); - $smarty->assign("POOLHASHRATES", @$aPoolHourlyHashRates); + $smarty->assign('YOURMININGSTATS', @$aHourlyMiningStats); } else { $debug->append('Using cached page', 3); } diff --git a/public/include/pages/statistics/pool.inc.php b/include/pages/statistics/pool.inc.php similarity index 94% rename from public/include/pages/statistics/pool.inc.php rename to include/pages/statistics/pool.inc.php index 47ba55c4a..cc27b12f1 100644 --- a/public/include/pages/statistics/pool.inc.php +++ b/include/pages/statistics/pool.inc.php @@ -32,7 +32,7 @@ $iCurrentPoolHashrate = $statistics->getCurrentHashrate(); // Time in seconds, not hours, using modifier in smarty to translate - $iCurrentPoolHashrate > 0 ? $iEstTime = $dDifficulty * pow(2,32) / ($iCurrentPoolHashrate * 1000) : $iEstTime = 0; + $iCurrentPoolHashrate > 0 ? $iEstTime = $statistics->getExpectedTimePerBlock('pool', $iCurrentPoolHashrate) : $iEstTime = 0; // Time since last block if (!empty($aBlockData)) { @@ -54,7 +54,7 @@ $dEstPercent = 0; } - $dExpectedTimePerBlock = $statistics->getNetworkExpectedTimePerBlock(); + $dExpectedTimePerBlock = $statistics->getExpectedTimePerBlock(); $dEstNextDifficulty = $statistics->getExpectedNextDifficulty(); $iBlocksUntilDiffChange = $statistics->getBlocksUntilDiffChange(); diff --git a/public/include/pages/statistics/round.inc.php b/include/pages/statistics/round.inc.php similarity index 100% rename from public/include/pages/statistics/round.inc.php rename to include/pages/statistics/round.inc.php diff --git a/public/include/pages/statistics/uptime.inc.php b/include/pages/statistics/uptime.inc.php similarity index 100% rename from public/include/pages/statistics/uptime.inc.php rename to include/pages/statistics/uptime.inc.php diff --git a/public/include/pages/tac.inc.php b/include/pages/tac.inc.php similarity index 100% rename from public/include/pages/tac.inc.php rename to include/pages/tac.inc.php diff --git a/public/include/pages/tacpop.inc.php b/include/pages/tacpop.inc.php similarity index 100% rename from public/include/pages/tacpop.inc.php rename to include/pages/tacpop.inc.php diff --git a/include/smarty.inc.php b/include/smarty.inc.php new file mode 100644 index 000000000..ac2935d98 --- /dev/null +++ b/include/smarty.inc.php @@ -0,0 +1,32 @@ +append('Loading Smarty libraries', 2); +define('SMARTY_DIR', INCLUDE_DIR . '/smarty/libs/'); + +// Include the actual smarty class file +include(SMARTY_DIR . 'Smarty.class.php'); + +// We initialize smarty here +$debug->append('Instantiating Smarty Object', 3); +$smarty = new Smarty; + +// Assign our local paths +$debug->append('Define Smarty Paths', 3); +$smarty->template_dir = TEMPLATE_DIR . '/' . THEME . '/'; +$smarty->compile_dir = TEMPLATE_DIR . '/compile/' . THEME . '/'; +$smarty_cache_key = md5(serialize($_REQUEST) . serialize(@$_SESSION['USERDATA']['id'])); + +// Optional smarty caching, check Smarty documentation for details +if ($config['smarty']['cache']) { + $debug->append('Enable smarty cache'); + $smarty->setCaching(Smarty::CACHING_LIFETIME_SAVED); + $smarty->cache_lifetime = $config['smarty']['cache_lifetime']; + $smarty->cache_dir = TEMPLATE_DIR . '/cache/' . THEME; + $smarty->escape_html = true; + $smarty->use_sub_dirs = true; +} + +// Load custom smarty plugins +require_once(INCLUDE_DIR . '/lib/smarty_plugins/function.acl.php'); +?> diff --git a/public/include/smarty/libs/Smarty.class.php b/include/smarty/libs/Smarty.class.php similarity index 100% rename from public/include/smarty/libs/Smarty.class.php rename to include/smarty/libs/Smarty.class.php diff --git a/public/include/smarty/libs/SmartyBC.class.php b/include/smarty/libs/SmartyBC.class.php similarity index 100% rename from public/include/smarty/libs/SmartyBC.class.php rename to include/smarty/libs/SmartyBC.class.php diff --git a/public/include/smarty/libs/debug.tpl b/include/smarty/libs/debug.tpl similarity index 100% rename from public/include/smarty/libs/debug.tpl rename to include/smarty/libs/debug.tpl diff --git a/public/include/smarty/libs/plugins/block.textformat.php b/include/smarty/libs/plugins/block.textformat.php similarity index 100% rename from public/include/smarty/libs/plugins/block.textformat.php rename to include/smarty/libs/plugins/block.textformat.php diff --git a/public/include/smarty/libs/plugins/function.counter.php b/include/smarty/libs/plugins/function.counter.php similarity index 100% rename from public/include/smarty/libs/plugins/function.counter.php rename to include/smarty/libs/plugins/function.counter.php diff --git a/public/include/smarty/libs/plugins/function.cycle.php b/include/smarty/libs/plugins/function.cycle.php similarity index 100% rename from public/include/smarty/libs/plugins/function.cycle.php rename to include/smarty/libs/plugins/function.cycle.php diff --git a/public/include/smarty/libs/plugins/function.fetch.php b/include/smarty/libs/plugins/function.fetch.php similarity index 100% rename from public/include/smarty/libs/plugins/function.fetch.php rename to include/smarty/libs/plugins/function.fetch.php diff --git a/public/include/smarty/libs/plugins/function.html_checkboxes.php b/include/smarty/libs/plugins/function.html_checkboxes.php similarity index 100% rename from public/include/smarty/libs/plugins/function.html_checkboxes.php rename to include/smarty/libs/plugins/function.html_checkboxes.php diff --git a/public/include/smarty/libs/plugins/function.html_image.php b/include/smarty/libs/plugins/function.html_image.php similarity index 100% rename from public/include/smarty/libs/plugins/function.html_image.php rename to include/smarty/libs/plugins/function.html_image.php diff --git a/public/include/smarty/libs/plugins/function.html_options.php b/include/smarty/libs/plugins/function.html_options.php similarity index 100% rename from public/include/smarty/libs/plugins/function.html_options.php rename to include/smarty/libs/plugins/function.html_options.php diff --git a/public/include/smarty/libs/plugins/function.html_radios.php b/include/smarty/libs/plugins/function.html_radios.php similarity index 100% rename from public/include/smarty/libs/plugins/function.html_radios.php rename to include/smarty/libs/plugins/function.html_radios.php diff --git a/public/include/smarty/libs/plugins/function.html_select_date.php b/include/smarty/libs/plugins/function.html_select_date.php similarity index 100% rename from public/include/smarty/libs/plugins/function.html_select_date.php rename to include/smarty/libs/plugins/function.html_select_date.php diff --git a/public/include/smarty/libs/plugins/function.html_select_time.php b/include/smarty/libs/plugins/function.html_select_time.php similarity index 100% rename from public/include/smarty/libs/plugins/function.html_select_time.php rename to include/smarty/libs/plugins/function.html_select_time.php diff --git a/public/include/smarty/libs/plugins/function.html_table.php b/include/smarty/libs/plugins/function.html_table.php similarity index 100% rename from public/include/smarty/libs/plugins/function.html_table.php rename to include/smarty/libs/plugins/function.html_table.php diff --git a/public/include/smarty/libs/plugins/function.mailto.php b/include/smarty/libs/plugins/function.mailto.php similarity index 100% rename from public/include/smarty/libs/plugins/function.mailto.php rename to include/smarty/libs/plugins/function.mailto.php diff --git a/public/include/smarty/libs/plugins/function.math.php b/include/smarty/libs/plugins/function.math.php similarity index 100% rename from public/include/smarty/libs/plugins/function.math.php rename to include/smarty/libs/plugins/function.math.php diff --git a/public/include/smarty/libs/plugins/modifier.capitalize.php b/include/smarty/libs/plugins/modifier.capitalize.php similarity index 100% rename from public/include/smarty/libs/plugins/modifier.capitalize.php rename to include/smarty/libs/plugins/modifier.capitalize.php diff --git a/public/include/smarty/libs/plugins/modifier.date_format.php b/include/smarty/libs/plugins/modifier.date_format.php similarity index 100% rename from public/include/smarty/libs/plugins/modifier.date_format.php rename to include/smarty/libs/plugins/modifier.date_format.php diff --git a/public/include/smarty/libs/plugins/modifier.debug_print_var.php b/include/smarty/libs/plugins/modifier.debug_print_var.php similarity index 100% rename from public/include/smarty/libs/plugins/modifier.debug_print_var.php rename to include/smarty/libs/plugins/modifier.debug_print_var.php diff --git a/public/include/smarty/libs/plugins/modifier.escape.php b/include/smarty/libs/plugins/modifier.escape.php similarity index 100% rename from public/include/smarty/libs/plugins/modifier.escape.php rename to include/smarty/libs/plugins/modifier.escape.php diff --git a/public/include/smarty/libs/plugins/modifier.regex_replace.php b/include/smarty/libs/plugins/modifier.regex_replace.php similarity index 100% rename from public/include/smarty/libs/plugins/modifier.regex_replace.php rename to include/smarty/libs/plugins/modifier.regex_replace.php diff --git a/public/include/smarty/libs/plugins/modifier.relative_date.php b/include/smarty/libs/plugins/modifier.relative_date.php similarity index 100% rename from public/include/smarty/libs/plugins/modifier.relative_date.php rename to include/smarty/libs/plugins/modifier.relative_date.php diff --git a/public/include/smarty/libs/plugins/modifier.replace.php b/include/smarty/libs/plugins/modifier.replace.php similarity index 100% rename from public/include/smarty/libs/plugins/modifier.replace.php rename to include/smarty/libs/plugins/modifier.replace.php diff --git a/include/smarty/libs/plugins/modifier.seconds_to_hhmmss.php b/include/smarty/libs/plugins/modifier.seconds_to_hhmmss.php new file mode 100644 index 000000000..08a064177 --- /dev/null +++ b/include/smarty/libs/plugins/modifier.seconds_to_hhmmss.php @@ -0,0 +1,18 @@ +getCurrentHashrate(); // Avoid confusion, ensure our nethash isn't higher than poolhash -if ($iCurrentPoolHashrate > $dNetworkHashrate / 1000) $dNetworkHashrate = $iCurrentPoolHashrate; +if ($iCurrentPoolHashrate > $dNetworkHashrate / 1000) $dNetworkHashrate = $iCurrentPoolHashrate * 1000; // Baseline network hashrate for templates if ( ! $dPersonalHashrateModifier = $setting->getValue('statistics_personal_hashrate_modifier') ) $dPersonalHashrateModifier = 1; @@ -63,8 +63,11 @@ 'reward' => $config['reward_type'] == 'fixed' ? $config['reward'] : $block->getAverageAmount(), 'price' => $setting->getValue('price'), 'twofactor' => $config['twofactor'], + 'coinaddresscheck' => $config['check_valid_coinaddress'], 'csrf' => $config['csrf'], 'config' => array( + 'sharediffprecision' => $coin->getShareDifficultyPrecision(), + 'date' => $setting->getValue('system_date_format', '%m/%d/%Y %H:%M:%S'), 'website_design' => $setting->getValue('website_design'), 'poolnav_enabled' => $setting->getValue('poolnav_enabled'), 'poolnav_pools' => $setting->getValue('poolnav_pools'), @@ -77,6 +80,8 @@ 'disable_auto_payouts' => $setting->getValue('disable_auto_payouts'), 'disable_contactform' => $setting->getValue('disable_contactform'), 'disable_contactform_guest' => $setting->getValue('disable_contactform_guest'), + 'disable_worker_edit' => $setting->getValue('disable_worker_edit'), + 'disable_transactionsummary' => $setting->getValue('disable_transactionsummary'), 'algorithm' => $config['algorithm'], 'getbalancewithunconfirmed' => $config['getbalancewithunconfirmed'], 'target_bits' => $coin->getTargetBits(), @@ -171,7 +176,8 @@ break; case 'pps': $aGlobal['userdata']['pps']['unpaidshares'] = $statistics->getUserUnpaidPPSShares($_SESSION['USERDATA']['username'], $_SESSION['USERDATA']['id'], $setting->getValue('pps_last_share_id')); - $aGlobal['ppsvalue'] = number_format($statistics->getPPSValue(), 12); + // We use coin precision + 8 to display PPS value + $aGlobal['ppsvalue'] = number_format($statistics->getPPSValue(), $coin->getCoinValuePrevision() + 8); $aGlobal['poolppsvalue'] = $aGlobal['ppsvalue'] * pow(2, $config['difficulty'] - 16); $aGlobal['userdata']['estimates'] = $statistics->getUserEstimates($aGlobal['userdata']['sharerate'], $aGlobal['userdata']['sharedifficulty'], $aGlobal['userdata']['donate_percent'], $aGlobal['userdata']['no_fees'], $aGlobal['ppsvalue']); break; @@ -186,8 +192,30 @@ if ($setting->getValue('maintenance')) $_SESSION['POPUP'][] = array('CONTENT' => 'This pool is currently in maintenance mode.', 'TYPE' => 'alert alert-warning'); -if ($motd = $setting->getValue('system_motd')) - $_SESSION['POPUP'][] = array('CONTENT' => $motd, 'DISMISS' => 'yes', 'ID' => 'motd', 'TYPE' => 'alert alert-info'); +if ($motd = $setting->getValue('system_motd')) { + if ($setting->getValue('system_motd_dismiss')) { + $motd_dismiss = "yes"; + } else { + $motd_dismiss = "no"; + } + switch ($setting->getValue('system_motd_style', 0)) { + case 0: + $motd_style = "alert-success"; + break; + case 1: + $motd_style = "alert-info"; + break; + case 2: + $motd_style = "alert-warning"; + break; + case 3: + $motd_style = "alert-danger"; + break; + default: + $motd_style = "alert-info"; + } + $_SESSION['POPUP'][] = array('CONTENT' => $motd, 'DISMISS' => $motd_dismiss, 'ID' => 'motd', 'TYPE' => 'alert ' . $motd_style . ''); +} // check for deprecated theme if ($setting->getValue('website_theme') == "mpos") diff --git a/public/include/version.inc.php b/include/version.inc.php similarity index 90% rename from public/include/version.inc.php rename to include/version.inc.php index e9968618e..1007908c0 100644 --- a/public/include/version.inc.php +++ b/include/version.inc.php @@ -2,8 +2,9 @@ $defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1; define('MPOS_VERSION', '0.0.4'); -define('DB_VERSION', '0.0.8'); -define('CONFIG_VERSION', '0.0.7'); +define('DB_VERSION', '0.0.15'); +define('CONFIG_VERSION', '0.0.8'); +define('HASH_VERSION', 1); // Fetch installed database version $db_version = $setting->getValue('DB_VERSION'); diff --git a/public/.htaccess b/public/.htaccess index 9750f3bbe..20cf67c68 100644 --- a/public/.htaccess +++ b/public/.htaccess @@ -1,4 +1,2 @@ ErrorDocument 404 /index.php?page=error&action=404 -RedirectMatch 404 /templates(/|$) -RedirectMatch 404 /include(/|$) RedirectMatch 404 /.git(/|$) diff --git a/public/include/pages/account/workers.inc.php b/public/include/pages/account/workers.inc.php deleted file mode 100644 index 2284aa412..000000000 --- a/public/include/pages/account/workers.inc.php +++ /dev/null @@ -1,51 +0,0 @@ -isAuthenticated()) { - switch (@$_REQUEST['do']) { - case 'delete': - if (!$config['csrf']['enabled'] || $config['csrf']['enabled'] && $csrftoken->valid) { - if ($worker->deleteWorker($_SESSION['USERDATA']['id'], $_GET['id'])) { - $_SESSION['POPUP'][] = array('CONTENT' => 'Worker removed', 'TYPE' => 'alert alert-success'); - } else { - $_SESSION['POPUP'][] = array('CONTENT' => $worker->getError(), 'TYPE' => 'alert alert-danger'); - } - } else { - $_SESSION['POPUP'][] = array('CONTENT' => $csrftoken->getErrorWithDescriptionHTML(), 'TYPE' => 'alert alert-warning'); - } - break; - - case 'add': - if (!$config['csrf']['enabled'] || $config['csrf']['enabled'] && $csrftoken->valid) { - if ($worker->addWorker($_SESSION['USERDATA']['id'], $_POST['username'], $_POST['password'])) { - $_SESSION['POPUP'][] = array('CONTENT' => 'Worker added', 'TYPE' => 'alert alert-success'); - } else { - $_SESSION['POPUP'][] = array('CONTENT' => $worker->getError(), 'TYPE' => 'alert alert-danger'); - } - } else { - $_SESSION['POPUP'][] = array('CONTENT' => $csrftoken->getErrorWithDescriptionHTML(), 'TYPE' => 'alert alert-warning'); - } - break; - - case 'update': - if (!$config['csrf']['enabled'] || $config['csrf']['enabled'] && $csrftoken->valid) { - if ($worker->updateWorkers($_SESSION['USERDATA']['id'], @$_POST['data'])) { - $_SESSION['POPUP'][] = array('CONTENT' => 'Worker updated', 'TYPE' => 'alert alert-success'); - } else { - $_SESSION['POPUP'][] = array('CONTENT' => $worker->getError(), 'TYPE' => 'alert alert-danger'); - } - } else { - $_SESSION['POPUP'][] = array('CONTENT' => $csrftoken->getErrorWithDescriptionHTML(), 'TYPE' => 'alert alert-warning'); - } - break; - } - - $smarty->assign('DISABLE_IDLEWORKERNOTIFICATIONS', $setting->getValue('notifications_disable_idle_worker')); - $aWorkers = $worker->getWorkers($_SESSION['USERDATA']['id']); - if (!$aWorkers) $_SESSION['POPUP'][] = array('CONTENT' => 'You have no workers configured', 'TYPE' => 'alert alert-danger'); - - $smarty->assign('WORKERS', $aWorkers); -} -$smarty->assign('CONTENT', 'default.tpl'); - -?> diff --git a/public/include/pages/admin/news.inc.php b/public/include/pages/admin/news.inc.php deleted file mode 100644 index 197bdba50..000000000 --- a/public/include/pages/admin/news.inc.php +++ /dev/null @@ -1,41 +0,0 @@ -isAuthenticated() || !$user->isAdmin($_SESSION['USERDATA']['id'])) { - header("HTTP/1.1 404 Page not found"); - die("404 Page not found"); -} - -// Include markdown library -use \Michelf\Markdown; - -if (@$_REQUEST['do'] == 'toggle_active') - if ($news->toggleActive($_REQUEST['id'])) - $_SESSION['POPUP'][] = array('CONTENT' => 'News entry changed', 'TYPE' => 'alert alert-success'); - -if (@$_REQUEST['do'] == 'add') { - if ($news->addNews($_SESSION['USERDATA']['id'], $_POST['data'])) { - $_SESSION['POPUP'][] = array('CONTENT' => 'News entry added', 'TYPE' => 'alert alert-success'); - } else { - $_SESSION['POPUP'][] = array('CONTENT' => 'Failed to add new entry: ' . $news->getError(), 'TYPE' => 'alert alert-danger'); - } -} - -if (@$_REQUEST['do'] == 'delete') { - if ($news->deleteNews((int)$_REQUEST['id'])) { - $_SESSION['POPUP'][] = array('CONTENT' => 'Succesfully removed news entry', 'TYPE' => 'alert alert-success'); - } else { - $_SESSION['POPUP'][] = array('CONTENT' => 'Failed to delete entry: ' . $news->getError(), 'TYPE' => 'alert alert-danger'); - } -} - -// Fetch all news -$aNews = $news->getAll(); -foreach ($aNews as $key => $aData) { - // Transform Markdown content to HTML - $aNews[$key]['content'] = Markdown::defaultTransform($aData['content']); -} -$smarty->assign("NEWS", $aNews); -$smarty->assign("CONTENT", "default.tpl"); -?> diff --git a/public/include/pages/admin/news_edit.inc.php b/public/include/pages/admin/news_edit.inc.php deleted file mode 100644 index 8b21c0e5f..000000000 --- a/public/include/pages/admin/news_edit.inc.php +++ /dev/null @@ -1,25 +0,0 @@ -isAuthenticated() || !$user->isAdmin($_SESSION['USERDATA']['id'])) { - header("HTTP/1.1 404 Page not found"); - die("404 Page not found"); -} - -// Include markdown library -use \Michelf\Markdown; - -if (@$_REQUEST['do'] == 'save') { - if ($news->updateNews($_REQUEST['id'], $_REQUEST['header'], $_REQUEST['content'], $_REQUEST['active'])) { - $_SESSION['POPUP'][] = array('CONTENT' => 'News updated', 'TYPE' => 'success'); - } else { - $_SESSION['POPUP'][] = array('CONTENT' => 'News update failed: ' . $news->getError(), 'TYPE' => 'alert alert-danger'); - } -} - -// Fetch news entry -$aNews = $news->getEntry($_REQUEST['id']); -$smarty->assign("NEWS", $aNews); -$smarty->assign("CONTENT", "default.tpl"); -?> diff --git a/public/include/pages/admin/templates.inc.php b/public/include/pages/admin/templates.inc.php deleted file mode 100644 index 00af92812..000000000 --- a/public/include/pages/admin/templates.inc.php +++ /dev/null @@ -1,48 +0,0 @@ -isAuthenticated() || !$user->isAdmin($_SESSION['USERDATA']['id'])) { - header("HTTP/1.1 404 Page not found"); - die("404 Page not found"); -} - -$aThemes = $template->getThemes(); -$aTemplates = $template->getTemplatesTree($aThemes); -$aActiveTemplates = $template->cachedGetActiveTemplates(); - -$aFlatTemplatesList = array(); -foreach($aThemes as $sTheme) { - $templates = $template->getTemplateFiles($sTheme); - $aFlatTemplatesList = array_merge($aFlatTemplatesList, $templates); -} - -//Fetch current slug and template -$sTemplate = @$_REQUEST['template']; -if(!in_array($sTemplate, $aFlatTemplatesList)) { - $sTemplate = $aFlatTemplatesList[0]; -} - -$sOriginalTemplate = $template->getTemplateContent($sTemplate); - -if (@$_REQUEST['do'] == 'save') { - if ($template->updateEntry(@$_REQUEST['template'], @$_REQUEST['content'], @$_REQUEST['active'])) { - $_SESSION['POPUP'][] = array('CONTENT' => 'Page updated', 'TYPE' => 'alert alert-success'); - } else { - $_SESSION['POPUP'][] = array('CONTENT' => 'Page update failed: ' . $template->getError(), 'TYPE' => 'alert alert-danger'); - } -} - -$oDatabaseTemplate = $template->getEntry($sTemplate); - -if ( $oDatabaseTemplate === false ) { - $_SESSION['POPUP'][] = array('CONTENT' => 'Can\'t fetch template from Database. Have you created `templates` table? Run 005_create_templates_table.sql from sql folder', 'TYPE' => 'alert alert-danger'); -} - -$smarty->assign("TEMPLATES", $aTemplates); -$smarty->assign("ACTIVE_TEMPLATES", $aActiveTemplates); -$smarty->assign("CURRENT_TEMPLATE", $sTemplate); -$smarty->assign("ORIGINAL_TEMPLATE", $sOriginalTemplate); -$smarty->assign("DATABASE_TEMPLATE", $oDatabaseTemplate); -$smarty->assign("CONTENT", "default.tpl"); -?> diff --git a/public/include/pages/api/getnavbardata.inc.php b/public/include/pages/api/getnavbardata.inc.php deleted file mode 100644 index 24ab357e5..000000000 --- a/public/include/pages/api/getnavbardata.inc.php +++ /dev/null @@ -1,76 +0,0 @@ -getValue('disable_navbar_api')) { - echo $api->get_json(array('error' => 'disabled')); - die(); -} - -// System load check -if ($load = @sys_getloadavg()) { - if (isset($config['system']['load']['max']) && $load[0] > $config['system']['load']['max']) { - header('HTTP/1.1 503 Too busy, try again later'); - die('Server too busy. Please try again later.'); - } -} - -// Fetch RPC information -if ($bitcoin->can_connect() === true) { - $dNetworkHashrate = $bitcoin->getnetworkhashps(); - $dDifficulty = $bitcoin->getdifficulty(); - $iBlock = $bitcoin->getblockcount(); -} else { - $dNetworkHashrate = 0; - $dDifficulty = 1; - $iBlock = 0; -} - -// Some settings -if ( ! $interval = $setting->getValue('statistics_ajax_data_interval')) $interval = 300; -if ( ! $dPoolHashrateModifier = $setting->getValue('statistics_pool_hashrate_modifier') ) $dPoolHashrateModifier = 1; -if ( ! $dNetworkHashrateModifier = $setting->getValue('statistics_network_hashrate_modifier') ) $dNetworkHashrateModifier = 1; - -// Fetch raw data -$statistics->setGetCache(false); -$dPoolHashrate = $statistics->getCurrentHashrate($interval); -if ($dPoolHashrate > $dNetworkHashrate) $dNetworkHashrate = $dPoolHashrate; -$statistics->setGetCache(true); - -// Small helper -$aHashunits = array( '1' => 'KH/s', '0.001' => 'MH/s', '0.000001' => 'GH/s', '0.000000001' => 'TH/s' ); - -// Apply pool modifiers -$dPoolHashrateAdjusted = $dPoolHashrate * $dPoolHashrateModifier; -$dNetworkHashrateAdjusted = $dNetworkHashrate / 1000 * $dNetworkHashrateModifier; - -// Use caches for this one -$aRoundShares = $statistics->getRoundShares(); - -$iTotalRoundShares = $aRoundShares['valid'] + $aRoundShares['invalid']; -if ($iTotalRoundShares > 0) { - $dPoolInvalidPercent = round($aRoundShares['invalid'] / $iTotalRoundShares * 100, 2); -} else { - $dUserInvalidPercent = 0; - $dPoolInvalidPercent = 0; -} - -// Round progress -$iEstShares = $statistics->getEstimatedShares($dDifficulty); -if ($iEstShares > 0 && $aRoundShares['valid'] > 0) { - $dEstPercent = round(100 / $iEstShares * $aRoundShares['valid'], 2); -} else { - $dEstPercent = 0; -} - -// Output JSON format -$data = array( - 'raw' => array( 'workers' => $worker->getCountAllActiveWorkers(), 'pool' => array( 'hashrate' => $dPoolHashrate ) ), - 'pool' => array( 'workers' => $worker->getCountAllActiveWorkers(), 'hashrate' => $dPoolHashrateAdjusted, 'estimated' => $iEstShares, 'progress' => $dEstPercent ), - 'network' => array( 'hashrate' => $dNetworkHashrateAdjusted, 'difficulty' => $dDifficulty, 'block' => $iBlock ) -); -echo $api->get_json($data); - -// Supress master template -$supress_master = 1; -?> diff --git a/public/include/pages/api/getpoolinfo.inc.php b/public/include/pages/api/getpoolinfo.inc.php deleted file mode 100644 index 217a22241..000000000 --- a/public/include/pages/api/getpoolinfo.inc.php +++ /dev/null @@ -1,39 +0,0 @@ -isActive(); - -// Check user token -$user_id = $api->checkAccess($user->checkApiKey($_REQUEST['api_key']), @$_REQUEST['id']); - -// Output JSON format -$data = array( - // coin info - 'currency' => $config[currency], - 'coinname' => $config[gettingstarted][coinname], - // coin algorithm info - 'cointarget' => $config[cointarget], - 'coindiffchangetarget' => $config[coindiffchangetarget], - 'algorithm' => $config[algorithm], - // stratum - 'stratumport' => $config[gettingstarted][stratumport], - // payments - 'payout_system' => $config[payout_system], - 'confirmations' => $config[confirmations], - 'min_ap_threshold' => $config[ap_threshold][min], - 'max_ap_threshold' => $config[ap_threshold][max], - 'reward_type' => $config[payout_system] == 'pps' ? $config['pps']['reward']['type'] : $config['reward_type'], - 'reward' => $config[payout_system] == 'pps' ? $config['pps']['reward']['default'] : $config['reward'], - // fees - 'txfee' => $config[txfee_manual], // make it backwards compatible - 'txfee_manual' => $config[txfee_manual], - 'txfee_auto' => $config[txfee_auto], - 'fees' => $config[fees] -); - -echo $api->get_json($data); - -// Supress master template -$supress_master = 1; -?> diff --git a/public/include/pages/login.inc.php b/public/include/pages/login.inc.php deleted file mode 100644 index d58f9213b..000000000 --- a/public/include/pages/login.inc.php +++ /dev/null @@ -1,48 +0,0 @@ -getValue('recaptcha_enabled') && $setting->getValue('recaptcha_enabled_logins')) { - require_once(INCLUDE_DIR . '/lib/recaptchalib.php'); - if (!empty($_POST['username']) && !empty($_POST['password'])) { - // Load re-captcha specific data - $rsp = recaptcha_check_answer ( - $setting->getValue('recaptcha_private_key'), - $_SERVER["REMOTE_ADDR"], - ( (isset($_POST["recaptcha_challenge_field"])) ? $_POST["recaptcha_challenge_field"] : null ), - ( (isset($_POST["recaptcha_response_field"])) ? $_POST["recaptcha_response_field"] : null ) - ); - $smarty->assign("RECAPTCHA", recaptcha_get_html($setting->getValue('recaptcha_public_key'), $rsp->error, true)); - } else { - $smarty->assign("RECAPTCHA", recaptcha_get_html($setting->getValue('recaptcha_public_key'), null, true)); - } -} - -if ($setting->getValue('maintenance') && !$user->isAdmin($user->getUserIdByEmail($_POST['username']))) { - $_SESSION['POPUP'][] = array('CONTENT' => 'You are not allowed to login during maintenace.', 'TYPE' => 'info'); -} else if (!empty($_POST['username']) && !empty($_POST['password'])) { - // Check if recaptcha is enabled, process form data if valid - if (!$setting->getValue('recaptcha_enabled') || !$setting->getValue('recaptcha_enabled_logins') || ($setting->getValue('recaptcha_enabled') && $setting->getValue('recaptcha_enabled_logins') && $rsp->is_valid)) { - if (!$config['csrf']['enabled'] || $config['csrf']['enabled'] && $csrftoken->valid) { - // check if login is correct - if ($user->checkLogin(@$_POST['username'], @$_POST['password']) ) { - $port = ($_SERVER["SERVER_PORT"] == "80" || $_SERVER["SERVER_PORT"] == "443") ? "" : (":".$_SERVER["SERVER_PORT"]); - $location = (@$_SERVER['HTTPS'] == "on") ? 'https://' : 'http://'; - $location .= $_SERVER['SERVER_NAME'] . $port . $_SERVER['SCRIPT_NAME']; - $location.= '?page=dashboard'; - if (!headers_sent()) header('Location: ' . $location); - exit(''); - } else { - $_SESSION['POPUP'][] = array('CONTENT' => 'Unable to login: '.$user->getError(), 'TYPE' => 'alert alert-danger'); - } - } else { - $_SESSION['POPUP'][] = array('CONTENT' => $csrftoken->getErrorWithDescriptionHTML(), 'TYPE' => 'alert alert-warning'); - } - } else { - $_SESSION['POPUP'][] = array('CONTENT' => 'Invalid Captcha, please try again.', 'TYPE' => 'alert alert-danger'); - } -} -// Load login template -$smarty->assign('CONTENT', 'default.tpl'); - -?> diff --git a/public/include/smarty.inc.php b/public/include/smarty.inc.php deleted file mode 100644 index df084e488..000000000 --- a/public/include/smarty.inc.php +++ /dev/null @@ -1,176 +0,0 @@ -append('Loading Smarty libraries', 2); -define('SMARTY_DIR', INCLUDE_DIR . '/smarty/libs/'); - -// Include the actual smarty class file -include(SMARTY_DIR . 'Smarty.class.php'); - -/** - * Custom Smarty Template Resource for Pages - * Get templates from Database - * Allow admin to manage his templates from Backoffice - */ -class Smarty_Resource_Database extends Smarty_Resource_Custom { - protected $template; - - public function __construct($template) { - $this->template = $template; - } - /** - * Fetch a template and its modification time from database - * - * @param string $name template name - * @param string $source template source - * @param integer $mtime template modification timestamp (epoch) - * @return void - */ - protected function fetch($name, &$source, &$mtime) { - $oTemplate = $this->template->getEntry($this->fullTemplateName($name)); - if ( $oTemplate && $oTemplate['active'] ) { - $source = $oTemplate['content']; - $mtime = strtotime($oTemplate['modified_at']); - } else { - $source = null; - $mtime = null; - } - } - - /** - * Fetch a template's modification time from database - * - * @note implementing this method is optional. Only implement it if modification times can be accessed faster than loading the comple template source. - * @param string $name template name - * @return integer timestamp (epoch) the template was modified - */ - protected function fetchTimestamp($name) { - $templates = $this->template->cachedGetActiveTemplates(); - $mtime = @$templates[$this->fullTemplateName($name)]; - return $mtime ? $mtime : false; - } - - /** - * Prepend THEME name to template name to get valid DB primary key - * - * @param string $name template name - */ - protected function fullTemplateName($name) { - return $this->normalisePath(THEME . "/" . $name); - } - - /** - * Normalise a file path string so that it can be checked safely. - * - * Attempt to avoid invalid encoding bugs by transcoding the path. Then - * remove any unnecessary path components including '.', '..' and ''. - * - * @param $path string - * The path to normalise. - * @return string - * The path, normalised. - * @see https://gist.github.com/thsutton/772287 - */ - protected function normalisePath($path) { - // Process the components - $parts = explode('/', $path); - $safe = array(); - foreach ($parts as $idx => $part) { - if (empty($part) || ('.' == $part)) { - continue; - } elseif ('..' == $part) { - array_pop($safe); - continue; - } else { - $safe[] = $part; - } - } - // Return the "clean" path - $path = implode(DIRECTORY_SEPARATOR, $safe); - return $path; - } - -} - -class Smarty_Resource_Hybrid extends Smarty_Resource { - - protected $databaseResource; - - protected $fileResource; - - public function __construct($dbResource, $fileResource) { - $this->databaseResource = $dbResource; - $this->fileResource = $fileResource; - } - - /** - * populate Source Object with meta data from Resource - * - * @param Smarty_Template_Source $source source object - * @param Smarty_Internal_Template $_template template object - */ - public function populate(Smarty_Template_Source $source, Smarty_Internal_Template $_template=null) { - if ( !@$_REQUEST['disable_template_override'] ) { - $this->databaseResource->populate($source, $_template); - if( $source->exists ) - return; - } - $source->type = 'file'; - return $this->fileResource->populate($source, $_template); - } - - /** - * Load template's source into current template object - * - * @param Smarty_Template_Source $source source object - * @return string template source - * @throws SmartyException if source cannot be loaded - */ - public function getContent(Smarty_Template_Source $source) { - try { - return $this->databaseResource->getContent($source); - } catch(SmartyException $e) { - return $this->fileResource->getContent($source); - } - } - - /** - * Determine basename for compiled filename - * - * @param Smarty_Template_Source $source source object - * @return string resource's basename - */ - public function getBasename(Smarty_Template_Source $source) { - return $this->fileResource->getBasename($source); - } - -} - -// We initialize smarty here -$debug->append('Instantiating Smarty Object', 3); -$smarty = new Smarty; - -// Assign our local paths -$debug->append('Define Smarty Paths', 3); -$smarty->template_dir = BASEPATH . 'templates/' . THEME . '/'; -$smarty->compile_dir = BASEPATH . 'templates/compile/' . THEME . '/'; -$smarty->registerResource('hybrid', new Smarty_Resource_Hybrid( - new Smarty_Resource_Database($template), - new Smarty_Internal_Resource_File() -)); -$smarty->default_resource_type = "hybrid"; -$smarty_cache_key = md5(serialize($_REQUEST) . serialize(@$_SESSION['USERDATA']['id'])); - -// Optional smarty caching, check Smarty documentation for details -if ($config['smarty']['cache']) { - $debug->append('Enable smarty cache'); - $smarty->setCaching(Smarty::CACHING_LIFETIME_SAVED); - $smarty->cache_lifetime = $config['smarty']['cache_lifetime']; - $smarty->cache_dir = BASEPATH . "templates/cache/" . THEME; - $smarty->escape_html = true; - $smarty->use_sub_dirs = true; -} - -// Load custom smarty plugins -require_once(INCLUDE_DIR . '/lib/smarty_plugins/function.acl.php'); -?> diff --git a/public/index.php b/public/index.php index 3d1df50cb..0fdd56cea 100644 --- a/public/index.php +++ b/public/index.php @@ -37,21 +37,15 @@ function cfip() { return (@defined('SECURITY')) ? 1 : 0; } define("BASEPATH", dirname(__FILE__) . "/"); // all our includes and config etc are now in bootstrap -include_once('include/bootstrap.php'); +include_once(BASEPATH . '../include/bootstrap.php'); // switch to https if config option is enabled $hts = ($config['https_only'] && (!empty($_SERVER['QUERY_STRING']))) ? "https://".$_SERVER['SERVER_NAME'].$_SERVER['SCRIPT_NAME']."?".$_SERVER['QUERY_STRING'] : "https://".$_SERVER['SERVER_NAME'].$_SERVER['SCRIPT_NAME']; ($config['https_only'] && @!$_SERVER['HTTPS']) ? exit(header("Location: ".$hts)):0; -// Rate limiting +// Rate limiting, we use our initilized memcache from bootstrap/autoloader if ($config['memcache']['enabled'] && $config['mc_antidos']['enabled']) { - if (PHP_OS == 'WINNT') { - require_once(CLASS_DIR . '/memcached.class.php'); - } - // memcache antidos needs a memcache handle - $memcache = new Memcached(); - $memcache->addServer($config['memcache']['host'], $config['memcache']['port']); require_once(CLASS_DIR . '/memcache_ad.class.php'); $skip_check = false; // if this is an api call we need to be careful not to time them out for those calls separately @@ -108,7 +102,6 @@ function cfip() { return (@defined('SECURITY')) ? 1 : 0; } // version check and config check if not disabled if (@$_SESSION['USERDATA']['is_admin'] && $user->isAdmin(@$_SESSION['USERDATA']['id'])) { - require_once(INCLUDE_DIR . '/version.inc.php'); if (!@$config['skip_config_tests']) { require_once(INCLUDE_DIR . '/admin_checks.php'); } diff --git a/public/site_assets/bootstrap/audio/ding.ogg b/public/site_assets/bootstrap/audio/ding.ogg new file mode 100644 index 000000000..201777fed Binary files /dev/null and b/public/site_assets/bootstrap/audio/ding.ogg differ diff --git a/public/site_assets/bootstrap/css/bootstrap.css b/public/site_assets/bootstrap/css/bootstrap.css index 25d47e1d1..7f3665196 100644 --- a/public/site_assets/bootstrap/css/bootstrap.css +++ b/public/site_assets/bootstrap/css/bootstrap.css @@ -1,5 +1,5 @@ /*! - * Bootstrap v3.1.0 (http://getbootstrap.com) + * Bootstrap v3.1.1 (http://getbootstrap.com) * Copyright 2011-2014 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) */ @@ -275,7 +275,7 @@ html { body { font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 14px; - line-height: 1.428571429; + line-height: 1.42857143; color: #333; background-color: #fff; } @@ -307,7 +307,11 @@ figure { img { vertical-align: middle; } -.img-responsive { +.img-responsive, +.thumbnail > img, +.thumbnail a > img, +.carousel-inner > .item > img, +.carousel-inner > .item > a > img { display: block; max-width: 100%; height: auto; @@ -320,7 +324,7 @@ img { max-width: 100%; height: auto; padding: 4px; - line-height: 1.428571429; + line-height: 1.42857143; background-color: #fff; border: 1px solid #ddd; border-radius: 4px; @@ -580,6 +584,7 @@ ol ol { } .list-inline { padding-left: 0; + margin-left: -5px; list-style: none; } .list-inline > li { @@ -587,16 +592,13 @@ ol ol { padding-right: 5px; padding-left: 5px; } -.list-inline > li:first-child { - padding-left: 0; -} dl { margin-top: 0; margin-bottom: 20px; } dt, dd { - line-height: 1.428571429; + line-height: 1.42857143; } dt { font-weight: bold; @@ -643,7 +645,7 @@ blockquote small, blockquote .small { display: block; font-size: 80%; - line-height: 1.428571429; + line-height: 1.42857143; color: #999; } blockquote footer:before, @@ -682,7 +684,7 @@ blockquote:after { address { margin-bottom: 20px; font-style: normal; - line-height: 1.428571429; + line-height: 1.42857143; } code, kbd, @@ -711,7 +713,7 @@ pre { padding: 9.5px; margin: 0 0 10px; font-size: 13px; - line-height: 1.428571429; + line-height: 1.42857143; color: #333; word-break: break-all; word-wrap: break-word; @@ -775,73 +777,73 @@ pre code { width: 100%; } .col-xs-11 { - width: 91.66666666666666%; + width: 91.66666667%; } .col-xs-10 { - width: 83.33333333333334%; + width: 83.33333333%; } .col-xs-9 { width: 75%; } .col-xs-8 { - width: 66.66666666666666%; + width: 66.66666667%; } .col-xs-7 { - width: 58.333333333333336%; + width: 58.33333333%; } .col-xs-6 { width: 50%; } .col-xs-5 { - width: 41.66666666666667%; + width: 41.66666667%; } .col-xs-4 { - width: 33.33333333333333%; + width: 33.33333333%; } .col-xs-3 { width: 25%; } .col-xs-2 { - width: 16.666666666666664%; + width: 16.66666667%; } .col-xs-1 { - width: 8.333333333333332%; + width: 8.33333333%; } .col-xs-pull-12 { right: 100%; } .col-xs-pull-11 { - right: 91.66666666666666%; + right: 91.66666667%; } .col-xs-pull-10 { - right: 83.33333333333334%; + right: 83.33333333%; } .col-xs-pull-9 { right: 75%; } .col-xs-pull-8 { - right: 66.66666666666666%; + right: 66.66666667%; } .col-xs-pull-7 { - right: 58.333333333333336%; + right: 58.33333333%; } .col-xs-pull-6 { right: 50%; } .col-xs-pull-5 { - right: 41.66666666666667%; + right: 41.66666667%; } .col-xs-pull-4 { - right: 33.33333333333333%; + right: 33.33333333%; } .col-xs-pull-3 { right: 25%; } .col-xs-pull-2 { - right: 16.666666666666664%; + right: 16.66666667%; } .col-xs-pull-1 { - right: 8.333333333333332%; + right: 8.33333333%; } .col-xs-pull-0 { right: 0; @@ -850,37 +852,37 @@ pre code { left: 100%; } .col-xs-push-11 { - left: 91.66666666666666%; + left: 91.66666667%; } .col-xs-push-10 { - left: 83.33333333333334%; + left: 83.33333333%; } .col-xs-push-9 { left: 75%; } .col-xs-push-8 { - left: 66.66666666666666%; + left: 66.66666667%; } .col-xs-push-7 { - left: 58.333333333333336%; + left: 58.33333333%; } .col-xs-push-6 { left: 50%; } .col-xs-push-5 { - left: 41.66666666666667%; + left: 41.66666667%; } .col-xs-push-4 { - left: 33.33333333333333%; + left: 33.33333333%; } .col-xs-push-3 { left: 25%; } .col-xs-push-2 { - left: 16.666666666666664%; + left: 16.66666667%; } .col-xs-push-1 { - left: 8.333333333333332%; + left: 8.33333333%; } .col-xs-push-0 { left: 0; @@ -889,37 +891,37 @@ pre code { margin-left: 100%; } .col-xs-offset-11 { - margin-left: 91.66666666666666%; + margin-left: 91.66666667%; } .col-xs-offset-10 { - margin-left: 83.33333333333334%; + margin-left: 83.33333333%; } .col-xs-offset-9 { margin-left: 75%; } .col-xs-offset-8 { - margin-left: 66.66666666666666%; + margin-left: 66.66666667%; } .col-xs-offset-7 { - margin-left: 58.333333333333336%; + margin-left: 58.33333333%; } .col-xs-offset-6 { margin-left: 50%; } .col-xs-offset-5 { - margin-left: 41.66666666666667%; + margin-left: 41.66666667%; } .col-xs-offset-4 { - margin-left: 33.33333333333333%; + margin-left: 33.33333333%; } .col-xs-offset-3 { margin-left: 25%; } .col-xs-offset-2 { - margin-left: 16.666666666666664%; + margin-left: 16.66666667%; } .col-xs-offset-1 { - margin-left: 8.333333333333332%; + margin-left: 8.33333333%; } .col-xs-offset-0 { margin-left: 0; @@ -932,73 +934,73 @@ pre code { width: 100%; } .col-sm-11 { - width: 91.66666666666666%; + width: 91.66666667%; } .col-sm-10 { - width: 83.33333333333334%; + width: 83.33333333%; } .col-sm-9 { width: 75%; } .col-sm-8 { - width: 66.66666666666666%; + width: 66.66666667%; } .col-sm-7 { - width: 58.333333333333336%; + width: 58.33333333%; } .col-sm-6 { width: 50%; } .col-sm-5 { - width: 41.66666666666667%; + width: 41.66666667%; } .col-sm-4 { - width: 33.33333333333333%; + width: 33.33333333%; } .col-sm-3 { width: 25%; } .col-sm-2 { - width: 16.666666666666664%; + width: 16.66666667%; } .col-sm-1 { - width: 8.333333333333332%; + width: 8.33333333%; } .col-sm-pull-12 { right: 100%; } .col-sm-pull-11 { - right: 91.66666666666666%; + right: 91.66666667%; } .col-sm-pull-10 { - right: 83.33333333333334%; + right: 83.33333333%; } .col-sm-pull-9 { right: 75%; } .col-sm-pull-8 { - right: 66.66666666666666%; + right: 66.66666667%; } .col-sm-pull-7 { - right: 58.333333333333336%; + right: 58.33333333%; } .col-sm-pull-6 { right: 50%; } .col-sm-pull-5 { - right: 41.66666666666667%; + right: 41.66666667%; } .col-sm-pull-4 { - right: 33.33333333333333%; + right: 33.33333333%; } .col-sm-pull-3 { right: 25%; } .col-sm-pull-2 { - right: 16.666666666666664%; + right: 16.66666667%; } .col-sm-pull-1 { - right: 8.333333333333332%; + right: 8.33333333%; } .col-sm-pull-0 { right: 0; @@ -1007,37 +1009,37 @@ pre code { left: 100%; } .col-sm-push-11 { - left: 91.66666666666666%; + left: 91.66666667%; } .col-sm-push-10 { - left: 83.33333333333334%; + left: 83.33333333%; } .col-sm-push-9 { left: 75%; } .col-sm-push-8 { - left: 66.66666666666666%; + left: 66.66666667%; } .col-sm-push-7 { - left: 58.333333333333336%; + left: 58.33333333%; } .col-sm-push-6 { left: 50%; } .col-sm-push-5 { - left: 41.66666666666667%; + left: 41.66666667%; } .col-sm-push-4 { - left: 33.33333333333333%; + left: 33.33333333%; } .col-sm-push-3 { left: 25%; } .col-sm-push-2 { - left: 16.666666666666664%; + left: 16.66666667%; } .col-sm-push-1 { - left: 8.333333333333332%; + left: 8.33333333%; } .col-sm-push-0 { left: 0; @@ -1046,37 +1048,37 @@ pre code { margin-left: 100%; } .col-sm-offset-11 { - margin-left: 91.66666666666666%; + margin-left: 91.66666667%; } .col-sm-offset-10 { - margin-left: 83.33333333333334%; + margin-left: 83.33333333%; } .col-sm-offset-9 { margin-left: 75%; } .col-sm-offset-8 { - margin-left: 66.66666666666666%; + margin-left: 66.66666667%; } .col-sm-offset-7 { - margin-left: 58.333333333333336%; + margin-left: 58.33333333%; } .col-sm-offset-6 { margin-left: 50%; } .col-sm-offset-5 { - margin-left: 41.66666666666667%; + margin-left: 41.66666667%; } .col-sm-offset-4 { - margin-left: 33.33333333333333%; + margin-left: 33.33333333%; } .col-sm-offset-3 { margin-left: 25%; } .col-sm-offset-2 { - margin-left: 16.666666666666664%; + margin-left: 16.66666667%; } .col-sm-offset-1 { - margin-left: 8.333333333333332%; + margin-left: 8.33333333%; } .col-sm-offset-0 { margin-left: 0; @@ -1090,73 +1092,73 @@ pre code { width: 100%; } .col-md-11 { - width: 91.66666666666666%; + width: 91.66666667%; } .col-md-10 { - width: 83.33333333333334%; + width: 83.33333333%; } .col-md-9 { width: 75%; } .col-md-8 { - width: 66.66666666666666%; + width: 66.66666667%; } .col-md-7 { - width: 58.333333333333336%; + width: 58.33333333%; } .col-md-6 { width: 50%; } .col-md-5 { - width: 41.66666666666667%; + width: 41.66666667%; } .col-md-4 { - width: 33.33333333333333%; + width: 33.33333333%; } .col-md-3 { width: 25%; } .col-md-2 { - width: 16.666666666666664%; + width: 16.66666667%; } .col-md-1 { - width: 8.333333333333332%; + width: 8.33333333%; } .col-md-pull-12 { right: 100%; } .col-md-pull-11 { - right: 91.66666666666666%; + right: 91.66666667%; } .col-md-pull-10 { - right: 83.33333333333334%; + right: 83.33333333%; } .col-md-pull-9 { right: 75%; } .col-md-pull-8 { - right: 66.66666666666666%; + right: 66.66666667%; } .col-md-pull-7 { - right: 58.333333333333336%; + right: 58.33333333%; } .col-md-pull-6 { right: 50%; } .col-md-pull-5 { - right: 41.66666666666667%; + right: 41.66666667%; } .col-md-pull-4 { - right: 33.33333333333333%; + right: 33.33333333%; } .col-md-pull-3 { right: 25%; } .col-md-pull-2 { - right: 16.666666666666664%; + right: 16.66666667%; } .col-md-pull-1 { - right: 8.333333333333332%; + right: 8.33333333%; } .col-md-pull-0 { right: 0; @@ -1165,37 +1167,37 @@ pre code { left: 100%; } .col-md-push-11 { - left: 91.66666666666666%; + left: 91.66666667%; } .col-md-push-10 { - left: 83.33333333333334%; + left: 83.33333333%; } .col-md-push-9 { left: 75%; } .col-md-push-8 { - left: 66.66666666666666%; + left: 66.66666667%; } .col-md-push-7 { - left: 58.333333333333336%; + left: 58.33333333%; } .col-md-push-6 { left: 50%; } .col-md-push-5 { - left: 41.66666666666667%; + left: 41.66666667%; } .col-md-push-4 { - left: 33.33333333333333%; + left: 33.33333333%; } .col-md-push-3 { left: 25%; } .col-md-push-2 { - left: 16.666666666666664%; + left: 16.66666667%; } .col-md-push-1 { - left: 8.333333333333332%; + left: 8.33333333%; } .col-md-push-0 { left: 0; @@ -1204,37 +1206,37 @@ pre code { margin-left: 100%; } .col-md-offset-11 { - margin-left: 91.66666666666666%; + margin-left: 91.66666667%; } .col-md-offset-10 { - margin-left: 83.33333333333334%; + margin-left: 83.33333333%; } .col-md-offset-9 { margin-left: 75%; } .col-md-offset-8 { - margin-left: 66.66666666666666%; + margin-left: 66.66666667%; } .col-md-offset-7 { - margin-left: 58.333333333333336%; + margin-left: 58.33333333%; } .col-md-offset-6 { margin-left: 50%; } .col-md-offset-5 { - margin-left: 41.66666666666667%; + margin-left: 41.66666667%; } .col-md-offset-4 { - margin-left: 33.33333333333333%; + margin-left: 33.33333333%; } .col-md-offset-3 { margin-left: 25%; } .col-md-offset-2 { - margin-left: 16.666666666666664%; + margin-left: 16.66666667%; } .col-md-offset-1 { - margin-left: 8.333333333333332%; + margin-left: 8.33333333%; } .col-md-offset-0 { margin-left: 0; @@ -1248,73 +1250,73 @@ pre code { width: 100%; } .col-lg-11 { - width: 91.66666666666666%; + width: 91.66666667%; } .col-lg-10 { - width: 83.33333333333334%; + width: 83.33333333%; } .col-lg-9 { width: 75%; } .col-lg-8 { - width: 66.66666666666666%; + width: 66.66666667%; } .col-lg-7 { - width: 58.333333333333336%; + width: 58.33333333%; } .col-lg-6 { width: 50%; } .col-lg-5 { - width: 41.66666666666667%; + width: 41.66666667%; } .col-lg-4 { - width: 33.33333333333333%; + width: 33.33333333%; } .col-lg-3 { width: 25%; } .col-lg-2 { - width: 16.666666666666664%; + width: 16.66666667%; } .col-lg-1 { - width: 8.333333333333332%; + width: 8.33333333%; } .col-lg-pull-12 { right: 100%; } .col-lg-pull-11 { - right: 91.66666666666666%; + right: 91.66666667%; } .col-lg-pull-10 { - right: 83.33333333333334%; + right: 83.33333333%; } .col-lg-pull-9 { right: 75%; } .col-lg-pull-8 { - right: 66.66666666666666%; + right: 66.66666667%; } .col-lg-pull-7 { - right: 58.333333333333336%; + right: 58.33333333%; } .col-lg-pull-6 { right: 50%; } .col-lg-pull-5 { - right: 41.66666666666667%; + right: 41.66666667%; } .col-lg-pull-4 { - right: 33.33333333333333%; + right: 33.33333333%; } .col-lg-pull-3 { right: 25%; } .col-lg-pull-2 { - right: 16.666666666666664%; + right: 16.66666667%; } .col-lg-pull-1 { - right: 8.333333333333332%; + right: 8.33333333%; } .col-lg-pull-0 { right: 0; @@ -1323,37 +1325,37 @@ pre code { left: 100%; } .col-lg-push-11 { - left: 91.66666666666666%; + left: 91.66666667%; } .col-lg-push-10 { - left: 83.33333333333334%; + left: 83.33333333%; } .col-lg-push-9 { left: 75%; } .col-lg-push-8 { - left: 66.66666666666666%; + left: 66.66666667%; } .col-lg-push-7 { - left: 58.333333333333336%; + left: 58.33333333%; } .col-lg-push-6 { left: 50%; } .col-lg-push-5 { - left: 41.66666666666667%; + left: 41.66666667%; } .col-lg-push-4 { - left: 33.33333333333333%; + left: 33.33333333%; } .col-lg-push-3 { left: 25%; } .col-lg-push-2 { - left: 16.666666666666664%; + left: 16.66666667%; } .col-lg-push-1 { - left: 8.333333333333332%; + left: 8.33333333%; } .col-lg-push-0 { left: 0; @@ -1362,37 +1364,37 @@ pre code { margin-left: 100%; } .col-lg-offset-11 { - margin-left: 91.66666666666666%; + margin-left: 91.66666667%; } .col-lg-offset-10 { - margin-left: 83.33333333333334%; + margin-left: 83.33333333%; } .col-lg-offset-9 { margin-left: 75%; } .col-lg-offset-8 { - margin-left: 66.66666666666666%; + margin-left: 66.66666667%; } .col-lg-offset-7 { - margin-left: 58.333333333333336%; + margin-left: 58.33333333%; } .col-lg-offset-6 { margin-left: 50%; } .col-lg-offset-5 { - margin-left: 41.66666666666667%; + margin-left: 41.66666667%; } .col-lg-offset-4 { - margin-left: 33.33333333333333%; + margin-left: 33.33333333%; } .col-lg-offset-3 { margin-left: 25%; } .col-lg-offset-2 { - margin-left: 16.666666666666664%; + margin-left: 16.66666667%; } .col-lg-offset-1 { - margin-left: 8.333333333333332%; + margin-left: 8.33333333%; } .col-lg-offset-0 { margin-left: 0; @@ -1416,7 +1418,7 @@ th { .table > tbody > tr > td, .table > tfoot > tr > td { padding: 8px; - line-height: 1.428571429; + line-height: 1.42857143; vertical-align: top; border-top: 1px solid #ddd; } @@ -1683,7 +1685,7 @@ output { display: block; padding-top: 7px; font-size: 14px; - line-height: 1.428571429; + line-height: 1.42857143; color: #555; } .form-control { @@ -1692,7 +1694,7 @@ output { height: 34px; padding: 6px 12px; font-size: 14px; - line-height: 1.428571429; + line-height: 1.42857143; color: #555; background-color: #fff; background-image: none; @@ -1709,9 +1711,6 @@ output { -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6); box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6); } -.form-control:-moz-placeholder { - color: #999; -} .form-control::-moz-placeholder { color: #999; opacity: 1; @@ -1732,6 +1731,9 @@ fieldset[disabled] .form-control { textarea.form-control { height: auto; } +input[type="search"] { + -webkit-appearance: none; +} input[type="date"] { line-height: 34px; } @@ -1935,6 +1937,9 @@ select[multiple].input-lg { width: auto; vertical-align: middle; } + .form-inline .input-group > .form-control { + width: 100%; + } .form-inline .control-label { margin-bottom: 0; vertical-align: middle; @@ -1991,7 +1996,7 @@ select[multiple].input-lg { margin-bottom: 0; font-size: 14px; font-weight: normal; - line-height: 1.428571429; + line-height: 1.42857143; text-align: center; white-space: nowrap; vertical-align: middle; @@ -1999,13 +2004,14 @@ select[multiple].input-lg { -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; - -o-user-select: none; user-select: none; background-image: none; border: 1px solid transparent; border-radius: 4px; } -.btn:focus { +.btn:focus, +.btn:active:focus, +.btn.active:focus { outline: thin dotted; outline: 5px auto -webkit-focus-ring-color; outline-offset: -2px; @@ -2311,19 +2317,22 @@ fieldset[disabled] .btn-link:focus { color: #999; text-decoration: none; } -.btn-lg { +.btn-lg, +.btn-group-lg > .btn { padding: 10px 16px; font-size: 18px; line-height: 1.33; border-radius: 6px; } -.btn-sm { +.btn-sm, +.btn-group-sm > .btn { padding: 5px 10px; font-size: 12px; line-height: 1.5; border-radius: 3px; } -.btn-xs { +.btn-xs, +.btn-group-xs > .btn { padding: 1px 5px; font-size: 12px; line-height: 1.5; @@ -3033,7 +3042,7 @@ input[type="button"].btn-block { padding: 3px 20px; clear: both; font-weight: normal; - line-height: 1.428571429; + line-height: 1.42857143; color: #333; white-space: nowrap; } @@ -3082,7 +3091,7 @@ input[type="button"].btn-block { display: block; padding: 3px 20px; font-size: 12px; - line-height: 1.428571429; + line-height: 1.42857143; color: #999; } .dropdown-backdrop { @@ -3196,24 +3205,6 @@ input[type="button"].btn-block { .btn-group.open .dropdown-toggle { outline: 0; } -.btn-group-xs > .btn { - padding: 1px 5px; - font-size: 12px; - line-height: 1.5; - border-radius: 3px; -} -.btn-group-sm > .btn { - padding: 5px 10px; - font-size: 12px; - line-height: 1.5; - border-radius: 3px; -} -.btn-group-lg > .btn { - padding: 10px 16px; - font-size: 18px; - line-height: 1.33; - border-radius: 6px; -} .btn-group > .btn + .dropdown-toggle { padding-right: 8px; padding-left: 8px; @@ -3313,6 +3304,8 @@ input[type="button"].btn-block { padding-left: 0; } .input-group .form-control { + position: relative; + z-index: 2; float: left; width: 100%; margin-bottom: 0; @@ -3507,7 +3500,7 @@ select[multiple].input-group-sm > .input-group-btn > .btn { } .nav-tabs > li > a { margin-right: 2px; - line-height: 1.428571429; + line-height: 1.42857143; border: 1px solid transparent; border-radius: 4px 4px 0 0; } @@ -3745,7 +3738,7 @@ select[multiple].input-group-sm > .input-group-btn > .btn { } .navbar-brand { float: left; - height: 20px; + height: 50px; padding: 15px 15px; font-size: 18px; line-height: 20px; @@ -3865,6 +3858,9 @@ select[multiple].input-group-sm > .input-group-btn > .btn { width: auto; vertical-align: middle; } + .navbar-form .input-group > .form-control { + width: 100%; + } .navbar-form .control-label { margin-bottom: 0; vertical-align: middle; @@ -4146,7 +4142,7 @@ select[multiple].input-group-sm > .input-group-btn > .btn { float: left; padding: 6px 12px; margin-left: -1px; - line-height: 1.428571429; + line-height: 1.42857143; color: #428bca; text-decoration: none; background-color: #fff; @@ -4407,7 +4403,7 @@ a.list-group-item.active > .badge, display: block; padding: 4px; margin-bottom: 20px; - line-height: 1.428571429; + line-height: 1.42857143; background-color: #fff; border: 1px solid #ddd; border-radius: 4px; @@ -4416,9 +4412,6 @@ a.list-group-item.active > .badge, } .thumbnail > img, .thumbnail a > img { - display: block; - max-width: 100%; - height: auto; margin-right: auto; margin-left: auto; } @@ -4769,7 +4762,32 @@ a.list-group-item-danger.active:focus { box-shadow: 0 1px 1px rgba(0, 0, 0, .05); } .panel-body { - padding: 20px 10px 0px 10px; + padding: 15px; +} +.panel-heading { + padding: 10px 15px; + border-bottom: 1px solid transparent; + border-top-left-radius: 3px; + border-top-right-radius: 3px; +} +.panel-heading > .dropdown .dropdown-toggle { + color: inherit; +} +.panel-title { + margin-top: 0; + margin-bottom: 0; + font-size: 16px; + color: inherit; +} +.panel-title > a { + color: inherit; +} +.panel-footer { + padding: 10px 15px; + background-color: #f5f5f5; + border-top: 1px solid #ddd; + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; } .panel > .list-group { margin-bottom: 0; @@ -4778,17 +4796,13 @@ a.list-group-item-danger.active:focus { border-width: 1px 0; border-radius: 0; } -.panel > .list-group .list-group-item:first-child { - border-top: 0; -} -.panel > .list-group .list-group-item:last-child { - border-bottom: 0; -} .panel > .list-group:first-child .list-group-item:first-child { + border-top: 0; border-top-left-radius: 3px; border-top-right-radius: 3px; } .panel > .list-group:last-child .list-group-item:last-child { + border-bottom: 0; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; } @@ -4799,6 +4813,11 @@ a.list-group-item-danger.active:focus { .panel > .table-responsive > .table { margin-bottom: 0; } +.panel > .table:first-child, +.panel > .table-responsive:first-child > .table:first-child { + border-top-left-radius: 3px; + border-top-right-radius: 3px; +} .panel > .table:first-child > thead:first-child > tr:first-child td:first-child, .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child, .panel > .table:first-child > tbody:first-child > tr:first-child td:first-child, @@ -4819,6 +4838,11 @@ a.list-group-item-danger.active:focus { .panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child { border-top-right-radius: 3px; } +.panel > .table:last-child, +.panel > .table-responsive:last-child > .table:last-child { + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; +} .panel > .table:last-child > tbody:last-child > tr:last-child td:first-child, .panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child, .panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child, @@ -4879,63 +4903,30 @@ a.list-group-item-danger.active:focus { .panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child { border-right: 0; } -.panel > .table-bordered > thead > tr:first-child > th, -.panel > .table-responsive > .table-bordered > thead > tr:first-child > th, -.panel > .table-bordered > tbody > tr:first-child > th, -.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th, -.panel > .table-bordered > tfoot > tr:first-child > th, -.panel > .table-responsive > .table-bordered > tfoot > tr:first-child > th, .panel > .table-bordered > thead > tr:first-child > td, .panel > .table-responsive > .table-bordered > thead > tr:first-child > td, .panel > .table-bordered > tbody > tr:first-child > td, .panel > .table-responsive > .table-bordered > tbody > tr:first-child > td, -.panel > .table-bordered > tfoot > tr:first-child > td, -.panel > .table-responsive > .table-bordered > tfoot > tr:first-child > td { - border-top: 0; +.panel > .table-bordered > thead > tr:first-child > th, +.panel > .table-responsive > .table-bordered > thead > tr:first-child > th, +.panel > .table-bordered > tbody > tr:first-child > th, +.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th { + border-bottom: 0; } -.panel > .table-bordered > thead > tr:last-child > th, -.panel > .table-responsive > .table-bordered > thead > tr:last-child > th, -.panel > .table-bordered > tbody > tr:last-child > th, -.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th, -.panel > .table-bordered > tfoot > tr:last-child > th, -.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th, -.panel > .table-bordered > thead > tr:last-child > td, -.panel > .table-responsive > .table-bordered > thead > tr:last-child > td, .panel > .table-bordered > tbody > tr:last-child > td, .panel > .table-responsive > .table-bordered > tbody > tr:last-child > td, .panel > .table-bordered > tfoot > tr:last-child > td, -.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td { +.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td, +.panel > .table-bordered > tbody > tr:last-child > th, +.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th, +.panel > .table-bordered > tfoot > tr:last-child > th, +.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th { border-bottom: 0; } .panel > .table-responsive { margin-bottom: 0; border: 0; } -.panel-heading { - padding: 10px 15px; - border-bottom: 1px solid transparent; - border-top-left-radius: 3px; - border-top-right-radius: 3px; -} -.panel-heading > .dropdown .dropdown-toggle { - color: inherit; -} -.panel-title { - margin-top: 0; - margin-bottom: 0; - font-size: 16px; - color: inherit; -} -.panel-title > a { - color: inherit; -} -.panel-footer { - padding: 10px 15px; - background-color: #f5f5f5; - border-top: 1px solid #ddd; - border-bottom-right-radius: 3px; - border-bottom-left-radius: 3px; -} .panel-group { margin-bottom: 20px; } @@ -5154,7 +5145,7 @@ button.close { opacity: .5; } .modal-header { - min-height: 16.428571429px; + min-height: 16.42857143px; padding: 15px; border-bottom: 1px solid #e5e5e5; } @@ -5163,7 +5154,7 @@ button.close { } .modal-title { margin: 0; - line-height: 1.428571429; + line-height: 1.42857143; } .modal-body { position: relative; @@ -5197,6 +5188,8 @@ button.close { .modal-sm { width: 300px; } +} +@media (min-width: 992px) { .modal-lg { width: 900px; } @@ -5342,8 +5335,8 @@ button.close { .popover-content { padding: 9px 14px; } -.popover .arrow, -.popover .arrow:after { +.popover > .arrow, +.popover > .arrow:after { position: absolute; display: block; width: 0; @@ -5351,14 +5344,14 @@ button.close { border-color: transparent; border-style: solid; } -.popover .arrow { +.popover > .arrow { border-width: 11px; } -.popover .arrow:after { +.popover > .arrow:after { content: ""; border-width: 10px; } -.popover.top .arrow { +.popover.top > .arrow { bottom: -11px; left: 50%; margin-left: -11px; @@ -5366,14 +5359,14 @@ button.close { border-top-color: rgba(0, 0, 0, .25); border-bottom-width: 0; } -.popover.top .arrow:after { +.popover.top > .arrow:after { bottom: 1px; margin-left: -10px; content: " "; border-top-color: #fff; border-bottom-width: 0; } -.popover.right .arrow { +.popover.right > .arrow { top: 50%; left: -11px; margin-top: -11px; @@ -5381,14 +5374,14 @@ button.close { border-right-color: rgba(0, 0, 0, .25); border-left-width: 0; } -.popover.right .arrow:after { +.popover.right > .arrow:after { bottom: -10px; left: 1px; content: " "; border-right-color: #fff; border-left-width: 0; } -.popover.bottom .arrow { +.popover.bottom > .arrow { top: -11px; left: 50%; margin-left: -11px; @@ -5396,14 +5389,14 @@ button.close { border-bottom-color: #999; border-bottom-color: rgba(0, 0, 0, .25); } -.popover.bottom .arrow:after { +.popover.bottom > .arrow:after { top: 1px; margin-left: -10px; content: " "; border-top-width: 0; border-bottom-color: #fff; } -.popover.left .arrow { +.popover.left > .arrow { top: 50%; right: -11px; margin-top: -11px; @@ -5411,7 +5404,7 @@ button.close { border-left-color: #999; border-left-color: rgba(0, 0, 0, .25); } -.popover.left .arrow:after { +.popover.left > .arrow:after { right: 1px; bottom: -10px; content: " "; @@ -5434,9 +5427,6 @@ button.close { } .carousel-inner > .item > img, .carousel-inner > .item > a > img { - display: block; - max-width: 100%; - height: auto; line-height: 1; } .carousel-inner > .active, @@ -5580,8 +5570,8 @@ button.close { text-shadow: none; } @media screen and (min-width: 768px) { - .carousel-control .glyphicons-chevron-left, - .carousel-control .glyphicons-chevron-right, + .carousel-control .glyphicon-chevron-left, + .carousel-control .glyphicon-chevron-right, .carousel-control .icon-prev, .carousel-control .icon-next { width: 30px; @@ -5684,9 +5674,9 @@ button.close { width: device-width; } .visible-xs, -tr.visible-xs, -th.visible-xs, -td.visible-xs { +.visible-sm, +.visible-md, +.visible-lg { display: none !important; } @media (max-width: 767px) { @@ -5704,12 +5694,6 @@ td.visible-xs { display: table-cell !important; } } -.visible-sm, -tr.visible-sm, -th.visible-sm, -td.visible-sm { - display: none !important; -} @media (min-width: 768px) and (max-width: 991px) { .visible-sm { display: block !important; @@ -5725,12 +5709,6 @@ td.visible-sm { display: table-cell !important; } } -.visible-md, -tr.visible-md, -th.visible-md, -td.visible-md { - display: none !important; -} @media (min-width: 992px) and (max-width: 1199px) { .visible-md { display: block !important; @@ -5746,12 +5724,6 @@ td.visible-md { display: table-cell !important; } } -.visible-lg, -tr.visible-lg, -th.visible-lg, -td.visible-lg { - display: none !important; -} @media (min-width: 1200px) { .visible-lg { display: block !important; @@ -5768,41 +5740,26 @@ td.visible-lg { } } @media (max-width: 767px) { - .hidden-xs, - tr.hidden-xs, - th.hidden-xs, - td.hidden-xs { + .hidden-xs { display: none !important; } } @media (min-width: 768px) and (max-width: 991px) { - .hidden-sm, - tr.hidden-sm, - th.hidden-sm, - td.hidden-sm { + .hidden-sm { display: none !important; } } @media (min-width: 992px) and (max-width: 1199px) { - .hidden-md, - tr.hidden-md, - th.hidden-md, - td.hidden-md { + .hidden-md { display: none !important; } } @media (min-width: 1200px) { - .hidden-lg, - tr.hidden-lg, - th.hidden-lg, - td.hidden-lg { + .hidden-lg { display: none !important; } } -.visible-print, -tr.visible-print, -th.visible-print, -td.visible-print { +.visible-print { display: none !important; } @media print { @@ -5821,10 +5778,7 @@ td.visible-print { } } @media print { - .hidden-print, - tr.hidden-print, - th.hidden-print, - td.hidden-print { + .hidden-print { display: none !important; } } diff --git a/public/site_assets/bootstrap/css/bootstrap.css.map b/public/site_assets/bootstrap/css/bootstrap.css.map new file mode 100644 index 000000000..6bc5a2dc7 --- /dev/null +++ b/public/site_assets/bootstrap/css/bootstrap.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["less/normalize.less","less/print.less","less/scaffolding.less","less/mixins.less","less/variables.less","less/thumbnails.less","less/carousel.less","less/type.less","less/code.less","less/grid.less","less/tables.less","less/forms.less","less/buttons.less","less/button-groups.less","less/component-animations.less","less/glyphicons.less","less/dropdowns.less","less/input-groups.less","less/navs.less","less/navbar.less","less/utilities.less","less/breadcrumbs.less","less/pagination.less","less/pager.less","less/labels.less","less/badges.less","less/jumbotron.less","less/alerts.less","less/progress-bars.less","less/media.less","less/list-group.less","less/panels.less","less/wells.less","less/close.less","less/modals.less","less/tooltip.less","less/popovers.less","less/responsive-utilities.less"],"names":[],"mappings":"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","sourcesContent":["/*! normalize.css v3.0.0 | MIT License | git.io/normalize */\n\n//\n// 1. Set default font family to sans-serif.\n// 2. Prevent iOS text size adjust after orientation change, without disabling\n// user zoom.\n//\n\nhtml {\n font-family: sans-serif; // 1\n -ms-text-size-adjust: 100%; // 2\n -webkit-text-size-adjust: 100%; // 2\n}\n\n//\n// Remove default margin.\n//\n\nbody {\n margin: 0;\n}\n\n// HTML5 display definitions\n// ==========================================================================\n\n//\n// Correct `block` display not defined in IE 8/9.\n//\n\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nnav,\nsection,\nsummary {\n display: block;\n}\n\n//\n// 1. Correct `inline-block` display not defined in IE 8/9.\n// 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.\n//\n\naudio,\ncanvas,\nprogress,\nvideo {\n display: inline-block; // 1\n vertical-align: baseline; // 2\n}\n\n//\n// Prevent modern browsers from displaying `audio` without controls.\n// Remove excess height in iOS 5 devices.\n//\n\naudio:not([controls]) {\n display: none;\n height: 0;\n}\n\n//\n// Address `[hidden]` styling not present in IE 8/9.\n// Hide the `template` element in IE, Safari, and Firefox < 22.\n//\n\n[hidden],\ntemplate {\n display: none;\n}\n\n// Links\n// ==========================================================================\n\n//\n// Remove the gray background color from active links in IE 10.\n//\n\na {\n background: transparent;\n}\n\n//\n// Improve readability when focused and also mouse hovered in all browsers.\n//\n\na:active,\na:hover {\n outline: 0;\n}\n\n// Text-level semantics\n// ==========================================================================\n\n//\n// Address styling not present in IE 8/9, Safari 5, and Chrome.\n//\n\nabbr[title] {\n border-bottom: 1px dotted;\n}\n\n//\n// Address style set to `bolder` in Firefox 4+, Safari 5, and Chrome.\n//\n\nb,\nstrong {\n font-weight: bold;\n}\n\n//\n// Address styling not present in Safari 5 and Chrome.\n//\n\ndfn {\n font-style: italic;\n}\n\n//\n// Address variable `h1` font-size and margin within `section` and `article`\n// contexts in Firefox 4+, Safari 5, and Chrome.\n//\n\nh1 {\n font-size: 2em;\n margin: 0.67em 0;\n}\n\n//\n// Address styling not present in IE 8/9.\n//\n\nmark {\n background: #ff0;\n color: #000;\n}\n\n//\n// Address inconsistent and variable font size in all browsers.\n//\n\nsmall {\n font-size: 80%;\n}\n\n//\n// Prevent `sub` and `sup` affecting `line-height` in all browsers.\n//\n\nsub,\nsup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n}\n\nsup {\n top: -0.5em;\n}\n\nsub {\n bottom: -0.25em;\n}\n\n// Embedded content\n// ==========================================================================\n\n//\n// Remove border when inside `a` element in IE 8/9.\n//\n\nimg {\n border: 0;\n}\n\n//\n// Correct overflow displayed oddly in IE 9.\n//\n\nsvg:not(:root) {\n overflow: hidden;\n}\n\n// Grouping content\n// ==========================================================================\n\n//\n// Address margin not present in IE 8/9 and Safari 5.\n//\n\nfigure {\n margin: 1em 40px;\n}\n\n//\n// Address differences between Firefox and other browsers.\n//\n\nhr {\n -moz-box-sizing: content-box;\n box-sizing: content-box;\n height: 0;\n}\n\n//\n// Contain overflow in all browsers.\n//\n\npre {\n overflow: auto;\n}\n\n//\n// Address odd `em`-unit font size rendering in all browsers.\n//\n\ncode,\nkbd,\npre,\nsamp {\n font-family: monospace, monospace;\n font-size: 1em;\n}\n\n// Forms\n// ==========================================================================\n\n//\n// Known limitation: by default, Chrome and Safari on OS X allow very limited\n// styling of `select`, unless a `border` property is set.\n//\n\n//\n// 1. Correct color not being inherited.\n// Known issue: affects color of disabled elements.\n// 2. Correct font properties not being inherited.\n// 3. Address margins set differently in Firefox 4+, Safari 5, and Chrome.\n//\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n color: inherit; // 1\n font: inherit; // 2\n margin: 0; // 3\n}\n\n//\n// Address `overflow` set to `hidden` in IE 8/9/10.\n//\n\nbutton {\n overflow: visible;\n}\n\n//\n// Address inconsistent `text-transform` inheritance for `button` and `select`.\n// All other form control elements do not inherit `text-transform` values.\n// Correct `button` style inheritance in Firefox, IE 8+, and Opera\n// Correct `select` style inheritance in Firefox.\n//\n\nbutton,\nselect {\n text-transform: none;\n}\n\n//\n// 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`\n// and `video` controls.\n// 2. Correct inability to style clickable `input` types in iOS.\n// 3. Improve usability and consistency of cursor style between image-type\n// `input` and others.\n//\n\nbutton,\nhtml input[type=\"button\"], // 1\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n -webkit-appearance: button; // 2\n cursor: pointer; // 3\n}\n\n//\n// Re-set default cursor for disabled elements.\n//\n\nbutton[disabled],\nhtml input[disabled] {\n cursor: default;\n}\n\n//\n// Remove inner padding and border in Firefox 4+.\n//\n\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n border: 0;\n padding: 0;\n}\n\n//\n// Address Firefox 4+ setting `line-height` on `input` using `!important` in\n// the UA stylesheet.\n//\n\ninput {\n line-height: normal;\n}\n\n//\n// It's recommended that you don't attempt to style these elements.\n// Firefox's implementation doesn't respect box-sizing, padding, or width.\n//\n// 1. Address box sizing set to `content-box` in IE 8/9/10.\n// 2. Remove excess padding in IE 8/9/10.\n//\n\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n box-sizing: border-box; // 1\n padding: 0; // 2\n}\n\n//\n// Fix the cursor style for Chrome's increment/decrement buttons. For certain\n// `font-size` values of the `input`, it causes the cursor style of the\n// decrement button to change from `default` to `text`.\n//\n\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n height: auto;\n}\n\n//\n// 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome.\n// 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome\n// (include `-moz` to future-proof).\n//\n\ninput[type=\"search\"] {\n -webkit-appearance: textfield; // 1\n -moz-box-sizing: content-box;\n -webkit-box-sizing: content-box; // 2\n box-sizing: content-box;\n}\n\n//\n// Remove inner padding and search cancel button in Safari and Chrome on OS X.\n// Safari (but not Chrome) clips the cancel button when the search input has\n// padding (and `textfield` appearance).\n//\n\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n\n//\n// Define consistent border, margin, and padding.\n//\n\nfieldset {\n border: 1px solid #c0c0c0;\n margin: 0 2px;\n padding: 0.35em 0.625em 0.75em;\n}\n\n//\n// 1. Correct `color` not being inherited in IE 8/9.\n// 2. Remove padding so people aren't caught out if they zero out fieldsets.\n//\n\nlegend {\n border: 0; // 1\n padding: 0; // 2\n}\n\n//\n// Remove default vertical scrollbar in IE 8/9.\n//\n\ntextarea {\n overflow: auto;\n}\n\n//\n// Don't inherit the `font-weight` (applied by a rule above).\n// NOTE: the default cannot safely be changed in Chrome and Safari on OS X.\n//\n\noptgroup {\n font-weight: bold;\n}\n\n// Tables\n// ==========================================================================\n\n//\n// Remove most spacing between table cells.\n//\n\ntable {\n border-collapse: collapse;\n border-spacing: 0;\n}\n\ntd,\nth {\n padding: 0;\n}","//\n// Basic print styles\n// --------------------------------------------------\n// Source: https://github.com/h5bp/html5-boilerplate/blob/master/css/main.css\n\n@media print {\n\n * {\n text-shadow: none !important;\n color: #000 !important; // Black prints faster: h5bp.com/s\n background: transparent !important;\n box-shadow: none !important;\n }\n\n a,\n a:visited {\n text-decoration: underline;\n }\n\n a[href]:after {\n content: \" (\" attr(href) \")\";\n }\n\n abbr[title]:after {\n content: \" (\" attr(title) \")\";\n }\n\n // Don't show links for images, or javascript/internal links\n a[href^=\"javascript:\"]:after,\n a[href^=\"#\"]:after {\n content: \"\";\n }\n\n pre,\n blockquote {\n border: 1px solid #999;\n page-break-inside: avoid;\n }\n\n thead {\n display: table-header-group; // h5bp.com/t\n }\n\n tr,\n img {\n page-break-inside: avoid;\n }\n\n img {\n max-width: 100% !important;\n }\n\n p,\n h2,\n h3 {\n orphans: 3;\n widows: 3;\n }\n\n h2,\n h3 {\n page-break-after: avoid;\n }\n\n // Chrome (OSX) fix for https://github.com/twbs/bootstrap/issues/11245\n // Once fixed, we can just straight up remove this.\n select {\n background: #fff !important;\n }\n\n // Bootstrap components\n .navbar {\n display: none;\n }\n .table {\n td,\n th {\n background-color: #fff !important;\n }\n }\n .btn,\n .dropup > .btn {\n > .caret {\n border-top-color: #000 !important;\n }\n }\n .label {\n border: 1px solid #000;\n }\n\n .table {\n border-collapse: collapse !important;\n }\n .table-bordered {\n th,\n td {\n border: 1px solid #ddd !important;\n }\n }\n\n}\n","//\n// Scaffolding\n// --------------------------------------------------\n\n\n// Reset the box-sizing\n//\n// Heads up! This reset may cause conflicts with some third-party widgets.\n// For recommendations on resolving such conflicts, see\n// http://getbootstrap.com/getting-started/#third-box-sizing\n* {\n .box-sizing(border-box);\n}\n*:before,\n*:after {\n .box-sizing(border-box);\n}\n\n\n// Body reset\n\nhtml {\n font-size: 62.5%;\n -webkit-tap-highlight-color: rgba(0,0,0,0);\n}\n\nbody {\n font-family: @font-family-base;\n font-size: @font-size-base;\n line-height: @line-height-base;\n color: @text-color;\n background-color: @body-bg;\n}\n\n// Reset fonts for relevant elements\ninput,\nbutton,\nselect,\ntextarea {\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n}\n\n\n// Links\n\na {\n color: @link-color;\n text-decoration: none;\n\n &:hover,\n &:focus {\n color: @link-hover-color;\n text-decoration: underline;\n }\n\n &:focus {\n .tab-focus();\n }\n}\n\n\n// Figures\n//\n// We reset this here because previously Normalize had no `figure` margins. This\n// ensures we don't break anyone's use of the element.\n\nfigure {\n margin: 0;\n}\n\n\n// Images\n\nimg {\n vertical-align: middle;\n}\n\n// Responsive images (ensure images don't scale beyond their parents)\n.img-responsive {\n .img-responsive();\n}\n\n// Rounded corners\n.img-rounded {\n border-radius: @border-radius-large;\n}\n\n// Image thumbnails\n//\n// Heads up! This is mixin-ed into thumbnails.less for `.thumbnail`.\n.img-thumbnail {\n padding: @thumbnail-padding;\n line-height: @line-height-base;\n background-color: @thumbnail-bg;\n border: 1px solid @thumbnail-border;\n border-radius: @thumbnail-border-radius;\n .transition(all .2s ease-in-out);\n\n // Keep them at most 100% wide\n .img-responsive(inline-block);\n}\n\n// Perfect circle\n.img-circle {\n border-radius: 50%; // set radius in percents\n}\n\n\n// Horizontal rules\n\nhr {\n margin-top: @line-height-computed;\n margin-bottom: @line-height-computed;\n border: 0;\n border-top: 1px solid @hr-border;\n}\n\n\n// Only display content to screen readers\n//\n// See: http://a11yproject.com/posts/how-to-hide-content/\n\n.sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n margin: -1px;\n padding: 0;\n overflow: hidden;\n clip: rect(0,0,0,0);\n border: 0;\n}\n","//\n// Mixins\n// --------------------------------------------------\n\n\n// Utilities\n// -------------------------\n\n// Clearfix\n// Source: http://nicolasgallagher.com/micro-clearfix-hack/\n//\n// For modern browsers\n// 1. The space content is one way to avoid an Opera bug when the\n// contenteditable attribute is included anywhere else in the document.\n// Otherwise it causes space to appear at the top and bottom of elements\n// that are clearfixed.\n// 2. The use of `table` rather than `block` is only necessary if using\n// `:before` to contain the top-margins of child elements.\n.clearfix() {\n &:before,\n &:after {\n content: \" \"; // 1\n display: table; // 2\n }\n &:after {\n clear: both;\n }\n}\n\n// WebKit-style focus\n.tab-focus() {\n // Default\n outline: thin dotted;\n // WebKit\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\n\n// Center-align a block level element\n.center-block() {\n display: block;\n margin-left: auto;\n margin-right: auto;\n}\n\n// Sizing shortcuts\n.size(@width; @height) {\n width: @width;\n height: @height;\n}\n.square(@size) {\n .size(@size; @size);\n}\n\n// Placeholder text\n.placeholder(@color: @input-color-placeholder) {\n &::-moz-placeholder { color: @color; // Firefox\n opacity: 1; } // See https://github.com/twbs/bootstrap/pull/11526\n &:-ms-input-placeholder { color: @color; } // Internet Explorer 10+\n &::-webkit-input-placeholder { color: @color; } // Safari and Chrome\n}\n\n// Text overflow\n// Requires inline-block or block for proper styling\n.text-overflow() {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n// CSS image replacement\n//\n// Heads up! v3 launched with with only `.hide-text()`, but per our pattern for\n// mixins being reused as classes with the same name, this doesn't hold up. As\n// of v3.0.1 we have added `.text-hide()` and deprecated `.hide-text()`. Note\n// that we cannot chain the mixins together in Less, so they are repeated.\n//\n// Source: https://github.com/h5bp/html5-boilerplate/commit/aa0396eae757\n\n// Deprecated as of v3.0.1 (will be removed in v4)\n.hide-text() {\n font: ~\"0/0\" a;\n color: transparent;\n text-shadow: none;\n background-color: transparent;\n border: 0;\n}\n// New mixin to use as of v3.0.1\n.text-hide() {\n .hide-text();\n}\n\n\n\n// CSS3 PROPERTIES\n// --------------------------------------------------\n\n// Single side border-radius\n.border-top-radius(@radius) {\n border-top-right-radius: @radius;\n border-top-left-radius: @radius;\n}\n.border-right-radius(@radius) {\n border-bottom-right-radius: @radius;\n border-top-right-radius: @radius;\n}\n.border-bottom-radius(@radius) {\n border-bottom-right-radius: @radius;\n border-bottom-left-radius: @radius;\n}\n.border-left-radius(@radius) {\n border-bottom-left-radius: @radius;\n border-top-left-radius: @radius;\n}\n\n// Drop shadows\n//\n// Note: Deprecated `.box-shadow()` as of v3.1.0 since all of Bootstrap's\n// supported browsers that have box shadow capabilities now support the\n// standard `box-shadow` property.\n.box-shadow(@shadow) {\n -webkit-box-shadow: @shadow; // iOS <4.3 & Android <4.1\n box-shadow: @shadow;\n}\n\n// Transitions\n.transition(@transition) {\n -webkit-transition: @transition;\n transition: @transition;\n}\n.transition-property(@transition-property) {\n -webkit-transition-property: @transition-property;\n transition-property: @transition-property;\n}\n.transition-delay(@transition-delay) {\n -webkit-transition-delay: @transition-delay;\n transition-delay: @transition-delay;\n}\n.transition-duration(@transition-duration) {\n -webkit-transition-duration: @transition-duration;\n transition-duration: @transition-duration;\n}\n.transition-transform(@transition) {\n -webkit-transition: -webkit-transform @transition;\n -moz-transition: -moz-transform @transition;\n -o-transition: -o-transform @transition;\n transition: transform @transition;\n}\n\n// Transformations\n.rotate(@degrees) {\n -webkit-transform: rotate(@degrees);\n -ms-transform: rotate(@degrees); // IE9 only\n transform: rotate(@degrees);\n}\n.scale(@ratio; @ratio-y...) {\n -webkit-transform: scale(@ratio, @ratio-y);\n -ms-transform: scale(@ratio, @ratio-y); // IE9 only\n transform: scale(@ratio, @ratio-y);\n}\n.translate(@x; @y) {\n -webkit-transform: translate(@x, @y);\n -ms-transform: translate(@x, @y); // IE9 only\n transform: translate(@x, @y);\n}\n.skew(@x; @y) {\n -webkit-transform: skew(@x, @y);\n -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+\n transform: skew(@x, @y);\n}\n.translate3d(@x; @y; @z) {\n -webkit-transform: translate3d(@x, @y, @z);\n transform: translate3d(@x, @y, @z);\n}\n\n.rotateX(@degrees) {\n -webkit-transform: rotateX(@degrees);\n -ms-transform: rotateX(@degrees); // IE9 only\n transform: rotateX(@degrees);\n}\n.rotateY(@degrees) {\n -webkit-transform: rotateY(@degrees);\n -ms-transform: rotateY(@degrees); // IE9 only\n transform: rotateY(@degrees);\n}\n.perspective(@perspective) {\n -webkit-perspective: @perspective;\n -moz-perspective: @perspective;\n perspective: @perspective;\n}\n.perspective-origin(@perspective) {\n -webkit-perspective-origin: @perspective;\n -moz-perspective-origin: @perspective;\n perspective-origin: @perspective;\n}\n.transform-origin(@origin) {\n -webkit-transform-origin: @origin;\n -moz-transform-origin: @origin;\n -ms-transform-origin: @origin; // IE9 only\n transform-origin: @origin;\n}\n\n// Animations\n.animation(@animation) {\n -webkit-animation: @animation;\n animation: @animation;\n}\n.animation-name(@name) {\n -webkit-animation-name: @name;\n animation-name: @name;\n}\n.animation-duration(@duration) {\n -webkit-animation-duration: @duration;\n animation-duration: @duration;\n}\n.animation-timing-function(@timing-function) {\n -webkit-animation-timing-function: @timing-function;\n animation-timing-function: @timing-function;\n}\n.animation-delay(@delay) {\n -webkit-animation-delay: @delay;\n animation-delay: @delay;\n}\n.animation-iteration-count(@iteration-count) {\n -webkit-animation-iteration-count: @iteration-count;\n animation-iteration-count: @iteration-count;\n}\n.animation-direction(@direction) {\n -webkit-animation-direction: @direction;\n animation-direction: @direction;\n}\n\n// Backface visibility\n// Prevent browsers from flickering when using CSS 3D transforms.\n// Default value is `visible`, but can be changed to `hidden`\n.backface-visibility(@visibility){\n -webkit-backface-visibility: @visibility;\n -moz-backface-visibility: @visibility;\n backface-visibility: @visibility;\n}\n\n// Box sizing\n.box-sizing(@boxmodel) {\n -webkit-box-sizing: @boxmodel;\n -moz-box-sizing: @boxmodel;\n box-sizing: @boxmodel;\n}\n\n// User select\n// For selecting text on the page\n.user-select(@select) {\n -webkit-user-select: @select;\n -moz-user-select: @select;\n -ms-user-select: @select; // IE10+\n user-select: @select;\n}\n\n// Resize anything\n.resizable(@direction) {\n resize: @direction; // Options: horizontal, vertical, both\n overflow: auto; // Safari fix\n}\n\n// CSS3 Content Columns\n.content-columns(@column-count; @column-gap: @grid-gutter-width) {\n -webkit-column-count: @column-count;\n -moz-column-count: @column-count;\n column-count: @column-count;\n -webkit-column-gap: @column-gap;\n -moz-column-gap: @column-gap;\n column-gap: @column-gap;\n}\n\n// Optional hyphenation\n.hyphens(@mode: auto) {\n word-wrap: break-word;\n -webkit-hyphens: @mode;\n -moz-hyphens: @mode;\n -ms-hyphens: @mode; // IE10+\n -o-hyphens: @mode;\n hyphens: @mode;\n}\n\n// Opacity\n.opacity(@opacity) {\n opacity: @opacity;\n // IE8 filter\n @opacity-ie: (@opacity * 100);\n filter: ~\"alpha(opacity=@{opacity-ie})\";\n}\n\n\n\n// GRADIENTS\n// --------------------------------------------------\n\n#gradient {\n\n // Horizontal gradient, from left to right\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .horizontal(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(left, color-stop(@start-color @start-percent), color-stop(@end-color @end-percent)); // Safari 5.1-6, Chrome 10+\n background-image: linear-gradient(to right, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n // Vertical gradient, from top to bottom\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .vertical(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: linear-gradient(to bottom, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n .directional(@start-color: #555; @end-color: #333; @deg: 45deg) {\n background-repeat: repeat-x;\n background-image: -webkit-linear-gradient(@deg, @start-color, @end-color); // Safari 5.1-6, Chrome 10+\n background-image: linear-gradient(@deg, @start-color, @end-color); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n }\n .horizontal-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(to right, @start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .vertical-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .radial(@inner-color: #555; @outer-color: #333) {\n background-image: -webkit-radial-gradient(circle, @inner-color, @outer-color);\n background-image: radial-gradient(circle, @inner-color, @outer-color);\n background-repeat: no-repeat;\n }\n .striped(@color: rgba(255,255,255,.15); @angle: 45deg) {\n background-image: -webkit-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n }\n}\n\n// Reset filters for IE\n//\n// When you need to remove a gradient background, do not forget to use this to reset\n// the IE filter for IE9 and below.\n.reset-filter() {\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(enabled = false)\"));\n}\n\n\n\n// Retina images\n//\n// Short retina mixin for setting background-image and -size\n\n.img-retina(@file-1x; @file-2x; @width-1x; @height-1x) {\n background-image: url(\"@{file-1x}\");\n\n @media\n only screen and (-webkit-min-device-pixel-ratio: 2),\n only screen and ( min--moz-device-pixel-ratio: 2),\n only screen and ( -o-min-device-pixel-ratio: 2/1),\n only screen and ( min-device-pixel-ratio: 2),\n only screen and ( min-resolution: 192dpi),\n only screen and ( min-resolution: 2dppx) {\n background-image: url(\"@{file-2x}\");\n background-size: @width-1x @height-1x;\n }\n}\n\n\n// Responsive image\n//\n// Keep images from scaling beyond the width of their parents.\n\n.img-responsive(@display: block) {\n display: @display;\n max-width: 100%; // Part 1: Set a maximum relative to the parent\n height: auto; // Part 2: Scale the height according to the width, otherwise you get stretching\n}\n\n\n// COMPONENT MIXINS\n// --------------------------------------------------\n\n// Horizontal dividers\n// -------------------------\n// Dividers (basically an hr) within dropdowns and nav lists\n.nav-divider(@color: #e5e5e5) {\n height: 1px;\n margin: ((@line-height-computed / 2) - 1) 0;\n overflow: hidden;\n background-color: @color;\n}\n\n// Panels\n// -------------------------\n.panel-variant(@border; @heading-text-color; @heading-bg-color; @heading-border) {\n border-color: @border;\n\n & > .panel-heading {\n color: @heading-text-color;\n background-color: @heading-bg-color;\n border-color: @heading-border;\n\n + .panel-collapse .panel-body {\n border-top-color: @border;\n }\n }\n & > .panel-footer {\n + .panel-collapse .panel-body {\n border-bottom-color: @border;\n }\n }\n}\n\n// Alerts\n// -------------------------\n.alert-variant(@background; @border; @text-color) {\n background-color: @background;\n border-color: @border;\n color: @text-color;\n\n hr {\n border-top-color: darken(@border, 5%);\n }\n .alert-link {\n color: darken(@text-color, 10%);\n }\n}\n\n// Tables\n// -------------------------\n.table-row-variant(@state; @background) {\n // Exact selectors below required to override `.table-striped` and prevent\n // inheritance to nested tables.\n .table > thead > tr,\n .table > tbody > tr,\n .table > tfoot > tr {\n > td.@{state},\n > th.@{state},\n &.@{state} > td,\n &.@{state} > th {\n background-color: @background;\n }\n }\n\n // Hover states for `.table-hover`\n // Note: this is not available for cells or rows within `thead` or `tfoot`.\n .table-hover > tbody > tr {\n > td.@{state}:hover,\n > th.@{state}:hover,\n &.@{state}:hover > td,\n &.@{state}:hover > th {\n background-color: darken(@background, 5%);\n }\n }\n}\n\n// List Groups\n// -------------------------\n.list-group-item-variant(@state; @background; @color) {\n .list-group-item-@{state} {\n color: @color;\n background-color: @background;\n\n a& {\n color: @color;\n\n .list-group-item-heading { color: inherit; }\n\n &:hover,\n &:focus {\n color: @color;\n background-color: darken(@background, 5%);\n }\n &.active,\n &.active:hover,\n &.active:focus {\n color: #fff;\n background-color: @color;\n border-color: @color;\n }\n }\n }\n}\n\n// Button variants\n// -------------------------\n// Easily pump out default styles, as well as :hover, :focus, :active,\n// and disabled options for all buttons\n.button-variant(@color; @background; @border) {\n color: @color;\n background-color: @background;\n border-color: @border;\n\n &:hover,\n &:focus,\n &:active,\n &.active,\n .open .dropdown-toggle& {\n color: @color;\n background-color: darken(@background, 8%);\n border-color: darken(@border, 12%);\n }\n &:active,\n &.active,\n .open .dropdown-toggle& {\n background-image: none;\n }\n &.disabled,\n &[disabled],\n fieldset[disabled] & {\n &,\n &:hover,\n &:focus,\n &:active,\n &.active {\n background-color: @background;\n border-color: @border;\n }\n }\n\n .badge {\n color: @background;\n background-color: @color;\n }\n}\n\n// Button sizes\n// -------------------------\n.button-size(@padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) {\n padding: @padding-vertical @padding-horizontal;\n font-size: @font-size;\n line-height: @line-height;\n border-radius: @border-radius;\n}\n\n// Pagination\n// -------------------------\n.pagination-size(@padding-vertical; @padding-horizontal; @font-size; @border-radius) {\n > li {\n > a,\n > span {\n padding: @padding-vertical @padding-horizontal;\n font-size: @font-size;\n }\n &:first-child {\n > a,\n > span {\n .border-left-radius(@border-radius);\n }\n }\n &:last-child {\n > a,\n > span {\n .border-right-radius(@border-radius);\n }\n }\n }\n}\n\n// Labels\n// -------------------------\n.label-variant(@color) {\n background-color: @color;\n &[href] {\n &:hover,\n &:focus {\n background-color: darken(@color, 10%);\n }\n }\n}\n\n// Contextual backgrounds\n// -------------------------\n.bg-variant(@color) {\n background-color: @color;\n a&:hover {\n background-color: darken(@color, 10%);\n }\n}\n\n// Typography\n// -------------------------\n.text-emphasis-variant(@color) {\n color: @color;\n a&:hover {\n color: darken(@color, 10%);\n }\n}\n\n// Navbar vertical align\n// -------------------------\n// Vertically center elements in the navbar.\n// Example: an element has a height of 30px, so write out `.navbar-vertical-align(30px);` to calculate the appropriate top margin.\n.navbar-vertical-align(@element-height) {\n margin-top: ((@navbar-height - @element-height) / 2);\n margin-bottom: ((@navbar-height - @element-height) / 2);\n}\n\n// Progress bars\n// -------------------------\n.progress-bar-variant(@color) {\n background-color: @color;\n .progress-striped & {\n #gradient > .striped();\n }\n}\n\n// Responsive utilities\n// -------------------------\n// More easily include all the states for responsive-utilities.less.\n.responsive-visibility() {\n display: block !important;\n table& { display: table; }\n tr& { display: table-row !important; }\n th&,\n td& { display: table-cell !important; }\n}\n\n.responsive-invisibility() {\n display: none !important;\n}\n\n\n// Grid System\n// -----------\n\n// Centered container element\n.container-fixed() {\n margin-right: auto;\n margin-left: auto;\n padding-left: (@grid-gutter-width / 2);\n padding-right: (@grid-gutter-width / 2);\n &:extend(.clearfix all);\n}\n\n// Creates a wrapper for a series of columns\n.make-row(@gutter: @grid-gutter-width) {\n margin-left: (@gutter / -2);\n margin-right: (@gutter / -2);\n &:extend(.clearfix all);\n}\n\n// Generate the extra small columns\n.make-xs-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n float: left;\n width: percentage((@columns / @grid-columns));\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n}\n.make-xs-column-offset(@columns) {\n @media (min-width: @screen-xs-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-xs-column-push(@columns) {\n @media (min-width: @screen-xs-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-xs-column-pull(@columns) {\n @media (min-width: @screen-xs-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n\n\n// Generate the small columns\n.make-sm-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n\n @media (min-width: @screen-sm-min) {\n float: left;\n width: percentage((@columns / @grid-columns));\n }\n}\n.make-sm-column-offset(@columns) {\n @media (min-width: @screen-sm-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-sm-column-push(@columns) {\n @media (min-width: @screen-sm-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-sm-column-pull(@columns) {\n @media (min-width: @screen-sm-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n\n\n// Generate the medium columns\n.make-md-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n\n @media (min-width: @screen-md-min) {\n float: left;\n width: percentage((@columns / @grid-columns));\n }\n}\n.make-md-column-offset(@columns) {\n @media (min-width: @screen-md-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-md-column-push(@columns) {\n @media (min-width: @screen-md-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-md-column-pull(@columns) {\n @media (min-width: @screen-md-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n\n\n// Generate the large columns\n.make-lg-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n\n @media (min-width: @screen-lg-min) {\n float: left;\n width: percentage((@columns / @grid-columns));\n }\n}\n.make-lg-column-offset(@columns) {\n @media (min-width: @screen-lg-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-lg-column-push(@columns) {\n @media (min-width: @screen-lg-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-lg-column-pull(@columns) {\n @media (min-width: @screen-lg-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n\n\n// Framework grid generation\n//\n// Used only by Bootstrap to generate the correct number of grid classes given\n// any value of `@grid-columns`.\n\n.make-grid-columns() {\n // Common styles for all sizes of grid columns, widths 1-12\n .col(@index) when (@index = 1) { // initial\n @item: ~\".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}\";\n .col((@index + 1), @item);\n }\n .col(@index, @list) when (@index =< @grid-columns) { // general; \"=<\" isn't a typo\n @item: ~\".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}\";\n .col((@index + 1), ~\"@{list}, @{item}\");\n }\n .col(@index, @list) when (@index > @grid-columns) { // terminal\n @{list} {\n position: relative;\n // Prevent columns from collapsing when empty\n min-height: 1px;\n // Inner gutter via padding\n padding-left: (@grid-gutter-width / 2);\n padding-right: (@grid-gutter-width / 2);\n }\n }\n .col(1); // kickstart it\n}\n\n.float-grid-columns(@class) {\n .col(@index) when (@index = 1) { // initial\n @item: ~\".col-@{class}-@{index}\";\n .col((@index + 1), @item);\n }\n .col(@index, @list) when (@index =< @grid-columns) { // general\n @item: ~\".col-@{class}-@{index}\";\n .col((@index + 1), ~\"@{list}, @{item}\");\n }\n .col(@index, @list) when (@index > @grid-columns) { // terminal\n @{list} {\n float: left;\n }\n }\n .col(1); // kickstart it\n}\n\n.calc-grid-column(@index, @class, @type) when (@type = width) and (@index > 0) {\n .col-@{class}-@{index} {\n width: percentage((@index / @grid-columns));\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = push) {\n .col-@{class}-push-@{index} {\n left: percentage((@index / @grid-columns));\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = pull) {\n .col-@{class}-pull-@{index} {\n right: percentage((@index / @grid-columns));\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = offset) {\n .col-@{class}-offset-@{index} {\n margin-left: percentage((@index / @grid-columns));\n }\n}\n\n// Basic looping in LESS\n.loop-grid-columns(@index, @class, @type) when (@index >= 0) {\n .calc-grid-column(@index, @class, @type);\n // next iteration\n .loop-grid-columns((@index - 1), @class, @type);\n}\n\n// Create grid for specific class\n.make-grid(@class) {\n .float-grid-columns(@class);\n .loop-grid-columns(@grid-columns, @class, width);\n .loop-grid-columns(@grid-columns, @class, pull);\n .loop-grid-columns(@grid-columns, @class, push);\n .loop-grid-columns(@grid-columns, @class, offset);\n}\n\n// Form validation states\n//\n// Used in forms.less to generate the form validation CSS for warnings, errors,\n// and successes.\n\n.form-control-validation(@text-color: #555; @border-color: #ccc; @background-color: #f5f5f5) {\n // Color the label and help text\n .help-block,\n .control-label,\n .radio,\n .checkbox,\n .radio-inline,\n .checkbox-inline {\n color: @text-color;\n }\n // Set the border and box shadow on specific inputs to match\n .form-control {\n border-color: @border-color;\n .box-shadow(inset 0 1px 1px rgba(0,0,0,.075)); // Redeclare so transitions work\n &:focus {\n border-color: darken(@border-color, 10%);\n @shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 6px lighten(@border-color, 20%);\n .box-shadow(@shadow);\n }\n }\n // Set validation states also for addons\n .input-group-addon {\n color: @text-color;\n border-color: @border-color;\n background-color: @background-color;\n }\n // Optional feedback icon\n .form-control-feedback {\n color: @text-color;\n }\n}\n\n// Form control focus state\n//\n// Generate a customized focus state and for any input with the specified color,\n// which defaults to the `@input-focus-border` variable.\n//\n// We highly encourage you to not customize the default value, but instead use\n// this to tweak colors on an as-needed basis. This aesthetic change is based on\n// WebKit's default styles, but applicable to a wider range of browsers. Its\n// usability and accessibility should be taken into account with any change.\n//\n// Example usage: change the default blue border and shadow to white for better\n// contrast against a dark gray background.\n\n.form-control-focus(@color: @input-border-focus) {\n @color-rgba: rgba(red(@color), green(@color), blue(@color), .6);\n &:focus {\n border-color: @color;\n outline: 0;\n .box-shadow(~\"inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px @{color-rgba}\");\n }\n}\n\n// Form control sizing\n//\n// Relative text size, padding, and border-radii changes for form controls. For\n// horizontal sizing, wrap controls in the predefined grid classes. `` background color\n@input-bg: #fff;\n//** `` background color\n@input-bg-disabled: @gray-lighter;\n\n//** Text color for ``s\n@input-color: @gray;\n//** `` border color\n@input-border: #ccc;\n//** `` border radius\n@input-border-radius: @border-radius-base;\n//** Border color for inputs on focus\n@input-border-focus: #66afe9;\n\n//** Placeholder text color\n@input-color-placeholder: @gray-light;\n\n//** Default `.form-control` height\n@input-height-base: (@line-height-computed + (@padding-base-vertical * 2) + 2);\n//** Large `.form-control` height\n@input-height-large: (ceil(@font-size-large * @line-height-large) + (@padding-large-vertical * 2) + 2);\n//** Small `.form-control` height\n@input-height-small: (floor(@font-size-small * @line-height-small) + (@padding-small-vertical * 2) + 2);\n\n@legend-color: @gray-dark;\n@legend-border-color: #e5e5e5;\n\n//** Background color for textual input addons\n@input-group-addon-bg: @gray-lighter;\n//** Border color for textual input addons\n@input-group-addon-border-color: @input-border;\n\n\n//== Dropdowns\n//\n//## Dropdown menu container and contents.\n\n//** Background for the dropdown menu.\n@dropdown-bg: #fff;\n//** Dropdown menu `border-color`.\n@dropdown-border: rgba(0,0,0,.15);\n//** Dropdown menu `border-color` **for IE8**.\n@dropdown-fallback-border: #ccc;\n//** Divider color for between dropdown items.\n@dropdown-divider-bg: #e5e5e5;\n\n//** Dropdown link text color.\n@dropdown-link-color: @gray-dark;\n//** Hover color for dropdown links.\n@dropdown-link-hover-color: darken(@gray-dark, 5%);\n//** Hover background for dropdown links.\n@dropdown-link-hover-bg: #f5f5f5;\n\n//** Active dropdown menu item text color.\n@dropdown-link-active-color: @component-active-color;\n//** Active dropdown menu item background color.\n@dropdown-link-active-bg: @component-active-bg;\n\n//** Disabled dropdown menu item background color.\n@dropdown-link-disabled-color: @gray-light;\n\n//** Text color for headers within dropdown menus.\n@dropdown-header-color: @gray-light;\n\n// Note: Deprecated @dropdown-caret-color as of v3.1.0\n@dropdown-caret-color: #000;\n\n\n//-- Z-index master list\n//\n// Warning: Avoid customizing these values. They're used for a bird's eye view\n// of components dependent on the z-axis and are designed to all work together.\n//\n// Note: These variables are not generated into the Customizer.\n\n@zindex-navbar: 1000;\n@zindex-dropdown: 1000;\n@zindex-popover: 1010;\n@zindex-tooltip: 1030;\n@zindex-navbar-fixed: 1030;\n@zindex-modal-background: 1040;\n@zindex-modal: 1050;\n\n\n//== Media queries breakpoints\n//\n//## Define the breakpoints at which your layout will change, adapting to different screen sizes.\n\n// Extra small screen / phone\n// Note: Deprecated @screen-xs and @screen-phone as of v3.0.1\n@screen-xs: 480px;\n@screen-xs-min: @screen-xs;\n@screen-phone: @screen-xs-min;\n\n// Small screen / tablet\n// Note: Deprecated @screen-sm and @screen-tablet as of v3.0.1\n@screen-sm: 768px;\n@screen-sm-min: @screen-sm;\n@screen-tablet: @screen-sm-min;\n\n// Medium screen / desktop\n// Note: Deprecated @screen-md and @screen-desktop as of v3.0.1\n@screen-md: 992px;\n@screen-md-min: @screen-md;\n@screen-desktop: @screen-md-min;\n\n// Large screen / wide desktop\n// Note: Deprecated @screen-lg and @screen-lg-desktop as of v3.0.1\n@screen-lg: 1200px;\n@screen-lg-min: @screen-lg;\n@screen-lg-desktop: @screen-lg-min;\n\n// So media queries don't overlap when required, provide a maximum\n@screen-xs-max: (@screen-sm-min - 1);\n@screen-sm-max: (@screen-md-min - 1);\n@screen-md-max: (@screen-lg-min - 1);\n\n\n//== Grid system\n//\n//## Define your custom responsive grid.\n\n//** Number of columns in the grid.\n@grid-columns: 12;\n//** Padding between columns. Gets divided in half for the left and right.\n@grid-gutter-width: 30px;\n// Navbar collapse\n//** Point at which the navbar becomes uncollapsed.\n@grid-float-breakpoint: @screen-sm-min;\n//** Point at which the navbar begins collapsing.\n@grid-float-breakpoint-max: (@grid-float-breakpoint - 1);\n\n\n//== Container sizes\n//\n//## Define the maximum width of `.container` for different screen sizes.\n\n// Small screen / tablet\n@container-tablet: ((720px + @grid-gutter-width));\n//** For `@screen-sm-min` and up.\n@container-sm: @container-tablet;\n\n// Medium screen / desktop\n@container-desktop: ((940px + @grid-gutter-width));\n//** For `@screen-md-min` and up.\n@container-md: @container-desktop;\n\n// Large screen / wide desktop\n@container-large-desktop: ((1140px + @grid-gutter-width));\n//** For `@screen-lg-min` and up.\n@container-lg: @container-large-desktop;\n\n\n//== Navbar\n//\n//##\n\n// Basics of a navbar\n@navbar-height: 50px;\n@navbar-margin-bottom: @line-height-computed;\n@navbar-border-radius: @border-radius-base;\n@navbar-padding-horizontal: floor((@grid-gutter-width / 2));\n@navbar-padding-vertical: ((@navbar-height - @line-height-computed) / 2);\n@navbar-collapse-max-height: 340px;\n\n@navbar-default-color: #777;\n@navbar-default-bg: #f8f8f8;\n@navbar-default-border: darken(@navbar-default-bg, 6.5%);\n\n// Navbar links\n@navbar-default-link-color: #777;\n@navbar-default-link-hover-color: #333;\n@navbar-default-link-hover-bg: transparent;\n@navbar-default-link-active-color: #555;\n@navbar-default-link-active-bg: darken(@navbar-default-bg, 6.5%);\n@navbar-default-link-disabled-color: #ccc;\n@navbar-default-link-disabled-bg: transparent;\n\n// Navbar brand label\n@navbar-default-brand-color: @navbar-default-link-color;\n@navbar-default-brand-hover-color: darken(@navbar-default-brand-color, 10%);\n@navbar-default-brand-hover-bg: transparent;\n\n// Navbar toggle\n@navbar-default-toggle-hover-bg: #ddd;\n@navbar-default-toggle-icon-bar-bg: #888;\n@navbar-default-toggle-border-color: #ddd;\n\n\n// Inverted navbar\n// Reset inverted navbar basics\n@navbar-inverse-color: @gray-light;\n@navbar-inverse-bg: #222;\n@navbar-inverse-border: darken(@navbar-inverse-bg, 10%);\n\n// Inverted navbar links\n@navbar-inverse-link-color: @gray-light;\n@navbar-inverse-link-hover-color: #fff;\n@navbar-inverse-link-hover-bg: transparent;\n@navbar-inverse-link-active-color: @navbar-inverse-link-hover-color;\n@navbar-inverse-link-active-bg: darken(@navbar-inverse-bg, 10%);\n@navbar-inverse-link-disabled-color: #444;\n@navbar-inverse-link-disabled-bg: transparent;\n\n// Inverted navbar brand label\n@navbar-inverse-brand-color: @navbar-inverse-link-color;\n@navbar-inverse-brand-hover-color: #fff;\n@navbar-inverse-brand-hover-bg: transparent;\n\n// Inverted navbar toggle\n@navbar-inverse-toggle-hover-bg: #333;\n@navbar-inverse-toggle-icon-bar-bg: #fff;\n@navbar-inverse-toggle-border-color: #333;\n\n\n//== Navs\n//\n//##\n\n//=== Shared nav styles\n@nav-link-padding: 10px 15px;\n@nav-link-hover-bg: @gray-lighter;\n\n@nav-disabled-link-color: @gray-light;\n@nav-disabled-link-hover-color: @gray-light;\n\n@nav-open-link-hover-color: #fff;\n\n//== Tabs\n@nav-tabs-border-color: #ddd;\n\n@nav-tabs-link-hover-border-color: @gray-lighter;\n\n@nav-tabs-active-link-hover-bg: @body-bg;\n@nav-tabs-active-link-hover-color: @gray;\n@nav-tabs-active-link-hover-border-color: #ddd;\n\n@nav-tabs-justified-link-border-color: #ddd;\n@nav-tabs-justified-active-link-border-color: @body-bg;\n\n//== Pills\n@nav-pills-border-radius: @border-radius-base;\n@nav-pills-active-link-hover-bg: @component-active-bg;\n@nav-pills-active-link-hover-color: @component-active-color;\n\n\n//== Pagination\n//\n//##\n\n@pagination-color: @link-color;\n@pagination-bg: #fff;\n@pagination-border: #ddd;\n\n@pagination-hover-color: @link-hover-color;\n@pagination-hover-bg: @gray-lighter;\n@pagination-hover-border: #ddd;\n\n@pagination-active-color: #fff;\n@pagination-active-bg: @brand-primary;\n@pagination-active-border: @brand-primary;\n\n@pagination-disabled-color: @gray-light;\n@pagination-disabled-bg: #fff;\n@pagination-disabled-border: #ddd;\n\n\n//== Pager\n//\n//##\n\n@pager-bg: @pagination-bg;\n@pager-border: @pagination-border;\n@pager-border-radius: 15px;\n\n@pager-hover-bg: @pagination-hover-bg;\n\n@pager-active-bg: @pagination-active-bg;\n@pager-active-color: @pagination-active-color;\n\n@pager-disabled-color: @pagination-disabled-color;\n\n\n//== Jumbotron\n//\n//##\n\n@jumbotron-padding: 30px;\n@jumbotron-color: inherit;\n@jumbotron-bg: @gray-lighter;\n@jumbotron-heading-color: inherit;\n@jumbotron-font-size: ceil((@font-size-base * 1.5));\n\n\n//== Form states and alerts\n//\n//## Define colors for form feedback states and, by default, alerts.\n\n@state-success-text: #3c763d;\n@state-success-bg: #dff0d8;\n@state-success-border: darken(spin(@state-success-bg, -10), 5%);\n\n@state-info-text: #31708f;\n@state-info-bg: #d9edf7;\n@state-info-border: darken(spin(@state-info-bg, -10), 7%);\n\n@state-warning-text: #8a6d3b;\n@state-warning-bg: #fcf8e3;\n@state-warning-border: darken(spin(@state-warning-bg, -10), 5%);\n\n@state-danger-text: #a94442;\n@state-danger-bg: #f2dede;\n@state-danger-border: darken(spin(@state-danger-bg, -10), 5%);\n\n\n//== Tooltips\n//\n//##\n\n//** Tooltip max width\n@tooltip-max-width: 200px;\n//** Tooltip text color\n@tooltip-color: #fff;\n//** Tooltip background color\n@tooltip-bg: #000;\n@tooltip-opacity: .9;\n\n//** Tooltip arrow width\n@tooltip-arrow-width: 5px;\n//** Tooltip arrow color\n@tooltip-arrow-color: @tooltip-bg;\n\n\n//== Popovers\n//\n//##\n\n//** Popover body background color\n@popover-bg: #fff;\n//** Popover maximum width\n@popover-max-width: 276px;\n//** Popover border color\n@popover-border-color: rgba(0,0,0,.2);\n//** Popover fallback border color\n@popover-fallback-border-color: #ccc;\n\n//** Popover title background color\n@popover-title-bg: darken(@popover-bg, 3%);\n\n//** Popover arrow width\n@popover-arrow-width: 10px;\n//** Popover arrow color\n@popover-arrow-color: #fff;\n\n//** Popover outer arrow width\n@popover-arrow-outer-width: (@popover-arrow-width + 1);\n//** Popover outer arrow color\n@popover-arrow-outer-color: fadein(@popover-border-color, 5%);\n//** Popover outer arrow fallback color\n@popover-arrow-outer-fallback-color: darken(@popover-fallback-border-color, 20%);\n\n\n//== Labels\n//\n//##\n\n//** Default label background color\n@label-default-bg: @gray-light;\n//** Primary label background color\n@label-primary-bg: @brand-primary;\n//** Success label background color\n@label-success-bg: @brand-success;\n//** Info label background color\n@label-info-bg: @brand-info;\n//** Warning label background color\n@label-warning-bg: @brand-warning;\n//** Danger label background color\n@label-danger-bg: @brand-danger;\n\n//** Default label text color\n@label-color: #fff;\n//** Default text color of a linked label\n@label-link-hover-color: #fff;\n\n\n//== Modals\n//\n//##\n\n//** Padding applied to the modal body\n@modal-inner-padding: 20px;\n\n//** Padding applied to the modal title\n@modal-title-padding: 15px;\n//** Modal title line-height\n@modal-title-line-height: @line-height-base;\n\n//** Background color of modal content area\n@modal-content-bg: #fff;\n//** Modal content border color\n@modal-content-border-color: rgba(0,0,0,.2);\n//** Modal content border color **for IE8**\n@modal-content-fallback-border-color: #999;\n\n//** Modal backdrop background color\n@modal-backdrop-bg: #000;\n//** Modal backdrop opacity\n@modal-backdrop-opacity: .5;\n//** Modal header border color\n@modal-header-border-color: #e5e5e5;\n//** Modal footer border color\n@modal-footer-border-color: @modal-header-border-color;\n\n@modal-lg: 900px;\n@modal-md: 600px;\n@modal-sm: 300px;\n\n\n//== Alerts\n//\n//## Define alert colors, border radius, and padding.\n\n@alert-padding: 15px;\n@alert-border-radius: @border-radius-base;\n@alert-link-font-weight: bold;\n\n@alert-success-bg: @state-success-bg;\n@alert-success-text: @state-success-text;\n@alert-success-border: @state-success-border;\n\n@alert-info-bg: @state-info-bg;\n@alert-info-text: @state-info-text;\n@alert-info-border: @state-info-border;\n\n@alert-warning-bg: @state-warning-bg;\n@alert-warning-text: @state-warning-text;\n@alert-warning-border: @state-warning-border;\n\n@alert-danger-bg: @state-danger-bg;\n@alert-danger-text: @state-danger-text;\n@alert-danger-border: @state-danger-border;\n\n\n//== Progress bars\n//\n//##\n\n//** Background color of the whole progress component\n@progress-bg: #f5f5f5;\n//** Progress bar text color\n@progress-bar-color: #fff;\n\n//** Default progress bar color\n@progress-bar-bg: @brand-primary;\n//** Success progress bar color\n@progress-bar-success-bg: @brand-success;\n//** Warning progress bar color\n@progress-bar-warning-bg: @brand-warning;\n//** Danger progress bar color\n@progress-bar-danger-bg: @brand-danger;\n//** Info progress bar color\n@progress-bar-info-bg: @brand-info;\n\n\n//== List group\n//\n//##\n\n//** Background color on `.list-group-item`\n@list-group-bg: #fff;\n//** `.list-group-item` border color\n@list-group-border: #ddd;\n//** List group border radius\n@list-group-border-radius: @border-radius-base;\n\n//** Background color of single list elements on hover\n@list-group-hover-bg: #f5f5f5;\n//** Text color of active list elements\n@list-group-active-color: @component-active-color;\n//** Background color of active list elements\n@list-group-active-bg: @component-active-bg;\n//** Border color of active list elements\n@list-group-active-border: @list-group-active-bg;\n@list-group-active-text-color: lighten(@list-group-active-bg, 40%);\n\n@list-group-link-color: #555;\n@list-group-link-heading-color: #333;\n\n\n//== Panels\n//\n//##\n\n@panel-bg: #fff;\n@panel-body-padding: 15px;\n@panel-border-radius: @border-radius-base;\n\n//** Border color for elements within panels\n@panel-inner-border: #ddd;\n@panel-footer-bg: #f5f5f5;\n\n@panel-default-text: @gray-dark;\n@panel-default-border: #ddd;\n@panel-default-heading-bg: #f5f5f5;\n\n@panel-primary-text: #fff;\n@panel-primary-border: @brand-primary;\n@panel-primary-heading-bg: @brand-primary;\n\n@panel-success-text: @state-success-text;\n@panel-success-border: @state-success-border;\n@panel-success-heading-bg: @state-success-bg;\n\n@panel-info-text: @state-info-text;\n@panel-info-border: @state-info-border;\n@panel-info-heading-bg: @state-info-bg;\n\n@panel-warning-text: @state-warning-text;\n@panel-warning-border: @state-warning-border;\n@panel-warning-heading-bg: @state-warning-bg;\n\n@panel-danger-text: @state-danger-text;\n@panel-danger-border: @state-danger-border;\n@panel-danger-heading-bg: @state-danger-bg;\n\n\n//== Thumbnails\n//\n//##\n\n//** Padding around the thumbnail image\n@thumbnail-padding: 4px;\n//** Thumbnail background color\n@thumbnail-bg: @body-bg;\n//** Thumbnail border color\n@thumbnail-border: #ddd;\n//** Thumbnail border radius\n@thumbnail-border-radius: @border-radius-base;\n\n//** Custom text color for thumbnail captions\n@thumbnail-caption-color: @text-color;\n//** Padding around the thumbnail caption\n@thumbnail-caption-padding: 9px;\n\n\n//== Wells\n//\n//##\n\n@well-bg: #f5f5f5;\n@well-border: darken(@well-bg, 7%);\n\n\n//== Badges\n//\n//##\n\n@badge-color: #fff;\n//** Linked badge text color on hover\n@badge-link-hover-color: #fff;\n@badge-bg: @gray-light;\n\n//** Badge text color in active nav link\n@badge-active-color: @link-color;\n//** Badge background color in active nav link\n@badge-active-bg: #fff;\n\n@badge-font-weight: bold;\n@badge-line-height: 1;\n@badge-border-radius: 10px;\n\n\n//== Breadcrumbs\n//\n//##\n\n@breadcrumb-padding-vertical: 8px;\n@breadcrumb-padding-horizontal: 15px;\n//** Breadcrumb background color\n@breadcrumb-bg: #f5f5f5;\n//** Breadcrumb text color\n@breadcrumb-color: #ccc;\n//** Text color of current page in the breadcrumb\n@breadcrumb-active-color: @gray-light;\n//** Textual separator for between breadcrumb elements\n@breadcrumb-separator: \"/\";\n\n\n//== Carousel\n//\n//##\n\n@carousel-text-shadow: 0 1px 2px rgba(0,0,0,.6);\n\n@carousel-control-color: #fff;\n@carousel-control-width: 15%;\n@carousel-control-opacity: .5;\n@carousel-control-font-size: 20px;\n\n@carousel-indicator-active-bg: #fff;\n@carousel-indicator-border-color: #fff;\n\n@carousel-caption-color: #fff;\n\n\n//== Close\n//\n//##\n\n@close-font-weight: bold;\n@close-color: #000;\n@close-text-shadow: 0 1px 0 #fff;\n\n\n//== Code\n//\n//##\n\n@code-color: #c7254e;\n@code-bg: #f9f2f4;\n\n@kbd-color: #fff;\n@kbd-bg: #333;\n\n@pre-bg: #f5f5f5;\n@pre-color: @gray-dark;\n@pre-border-color: #ccc;\n@pre-scrollable-max-height: 340px;\n\n\n//== Type\n//\n//##\n\n//** Text muted color\n@text-muted: @gray-light;\n//** Abbreviations and acronyms border color\n@abbr-border-color: @gray-light;\n//** Headings small color\n@headings-small-color: @gray-light;\n//** Blockquote small color\n@blockquote-small-color: @gray-light;\n//** Blockquote font size\n@blockquote-font-size: (@font-size-base * 1.25);\n//** Blockquote border color\n@blockquote-border-color: @gray-lighter;\n//** Page header border color\n@page-header-border-color: @gray-lighter;\n\n\n//== Miscellaneous\n//\n//##\n\n//** Horizontal line color.\n@hr-border: @gray-lighter;\n\n//** Horizontal offset for forms and lists.\n@component-offset-horizontal: 180px;\n","//\n// Thumbnails\n// --------------------------------------------------\n\n\n// Mixin and adjust the regular image class\n.thumbnail {\n display: block;\n padding: @thumbnail-padding;\n margin-bottom: @line-height-computed;\n line-height: @line-height-base;\n background-color: @thumbnail-bg;\n border: 1px solid @thumbnail-border;\n border-radius: @thumbnail-border-radius;\n .transition(all .2s ease-in-out);\n\n > img,\n a > img {\n &:extend(.img-responsive);\n margin-left: auto;\n margin-right: auto;\n }\n\n // Add a hover state for linked versions only\n a&:hover,\n a&:focus,\n a&.active {\n border-color: @link-color;\n }\n\n // Image captions\n .caption {\n padding: @thumbnail-caption-padding;\n color: @thumbnail-caption-color;\n }\n}\n","//\n// Carousel\n// --------------------------------------------------\n\n\n// Wrapper for the slide container and indicators\n.carousel {\n position: relative;\n}\n\n.carousel-inner {\n position: relative;\n overflow: hidden;\n width: 100%;\n\n > .item {\n display: none;\n position: relative;\n .transition(.6s ease-in-out left);\n\n // Account for jankitude on images\n > img,\n > a > img {\n &:extend(.img-responsive);\n line-height: 1;\n }\n }\n\n > .active,\n > .next,\n > .prev { display: block; }\n\n > .active {\n left: 0;\n }\n\n > .next,\n > .prev {\n position: absolute;\n top: 0;\n width: 100%;\n }\n\n > .next {\n left: 100%;\n }\n > .prev {\n left: -100%;\n }\n > .next.left,\n > .prev.right {\n left: 0;\n }\n\n > .active.left {\n left: -100%;\n }\n > .active.right {\n left: 100%;\n }\n\n}\n\n// Left/right controls for nav\n// ---------------------------\n\n.carousel-control {\n position: absolute;\n top: 0;\n left: 0;\n bottom: 0;\n width: @carousel-control-width;\n .opacity(@carousel-control-opacity);\n font-size: @carousel-control-font-size;\n color: @carousel-control-color;\n text-align: center;\n text-shadow: @carousel-text-shadow;\n // We can't have this transition here because WebKit cancels the carousel\n // animation if you trip this while in the middle of another animation.\n\n // Set gradients for backgrounds\n &.left {\n #gradient > .horizontal(@start-color: rgba(0,0,0,.5); @end-color: rgba(0,0,0,.0001));\n }\n &.right {\n left: auto;\n right: 0;\n #gradient > .horizontal(@start-color: rgba(0,0,0,.0001); @end-color: rgba(0,0,0,.5));\n }\n\n // Hover/focus state\n &:hover,\n &:focus {\n outline: none;\n color: @carousel-control-color;\n text-decoration: none;\n .opacity(.9);\n }\n\n // Toggles\n .icon-prev,\n .icon-next,\n .glyphicon-chevron-left,\n .glyphicon-chevron-right {\n position: absolute;\n top: 50%;\n z-index: 5;\n display: inline-block;\n }\n .icon-prev,\n .glyphicon-chevron-left {\n left: 50%;\n }\n .icon-next,\n .glyphicon-chevron-right {\n right: 50%;\n }\n .icon-prev,\n .icon-next {\n width: 20px;\n height: 20px;\n margin-top: -10px;\n margin-left: -10px;\n font-family: serif;\n }\n\n .icon-prev {\n &:before {\n content: '\\2039';// SINGLE LEFT-POINTING ANGLE QUOTATION MARK (U+2039)\n }\n }\n .icon-next {\n &:before {\n content: '\\203a';// SINGLE RIGHT-POINTING ANGLE QUOTATION MARK (U+203A)\n }\n }\n}\n\n// Optional indicator pips\n//\n// Add an unordered list with the following class and add a list item for each\n// slide your carousel holds.\n\n.carousel-indicators {\n position: absolute;\n bottom: 10px;\n left: 50%;\n z-index: 15;\n width: 60%;\n margin-left: -30%;\n padding-left: 0;\n list-style: none;\n text-align: center;\n\n li {\n display: inline-block;\n width: 10px;\n height: 10px;\n margin: 1px;\n text-indent: -999px;\n border: 1px solid @carousel-indicator-border-color;\n border-radius: 10px;\n cursor: pointer;\n\n // IE8-9 hack for event handling\n //\n // Internet Explorer 8-9 does not support clicks on elements without a set\n // `background-color`. We cannot use `filter` since that's not viewed as a\n // background color by the browser. Thus, a hack is needed.\n //\n // For IE8, we set solid black as it doesn't support `rgba()`. For IE9, we\n // set alpha transparency for the best results possible.\n background-color: #000 \\9; // IE8\n background-color: rgba(0,0,0,0); // IE9\n }\n .active {\n margin: 0;\n width: 12px;\n height: 12px;\n background-color: @carousel-indicator-active-bg;\n }\n}\n\n// Optional captions\n// -----------------------------\n// Hidden by default for smaller viewports\n.carousel-caption {\n position: absolute;\n left: 15%;\n right: 15%;\n bottom: 20px;\n z-index: 10;\n padding-top: 20px;\n padding-bottom: 20px;\n color: @carousel-caption-color;\n text-align: center;\n text-shadow: @carousel-text-shadow;\n & .btn {\n text-shadow: none; // No shadow for button elements in carousel-caption\n }\n}\n\n\n// Scale up controls for tablets and up\n@media screen and (min-width: @screen-sm-min) {\n\n // Scale up the controls a smidge\n .carousel-control {\n .glyphicon-chevron-left,\n .glyphicon-chevron-right,\n .icon-prev,\n .icon-next {\n width: 30px;\n height: 30px;\n margin-top: -15px;\n margin-left: -15px;\n font-size: 30px;\n }\n }\n\n // Show and left align the captions\n .carousel-caption {\n left: 20%;\n right: 20%;\n padding-bottom: 30px;\n }\n\n // Move up the indicators\n .carousel-indicators {\n bottom: 20px;\n }\n}\n","//\n// Typography\n// --------------------------------------------------\n\n\n// Headings\n// -------------------------\n\nh1, h2, h3, h4, h5, h6,\n.h1, .h2, .h3, .h4, .h5, .h6 {\n font-family: @headings-font-family;\n font-weight: @headings-font-weight;\n line-height: @headings-line-height;\n color: @headings-color;\n\n small,\n .small {\n font-weight: normal;\n line-height: 1;\n color: @headings-small-color;\n }\n}\n\nh1, .h1,\nh2, .h2,\nh3, .h3 {\n margin-top: @line-height-computed;\n margin-bottom: (@line-height-computed / 2);\n\n small,\n .small {\n font-size: 65%;\n }\n}\nh4, .h4,\nh5, .h5,\nh6, .h6 {\n margin-top: (@line-height-computed / 2);\n margin-bottom: (@line-height-computed / 2);\n\n small,\n .small {\n font-size: 75%;\n }\n}\n\nh1, .h1 { font-size: @font-size-h1; }\nh2, .h2 { font-size: @font-size-h2; }\nh3, .h3 { font-size: @font-size-h3; }\nh4, .h4 { font-size: @font-size-h4; }\nh5, .h5 { font-size: @font-size-h5; }\nh6, .h6 { font-size: @font-size-h6; }\n\n\n// Body text\n// -------------------------\n\np {\n margin: 0 0 (@line-height-computed / 2);\n}\n\n.lead {\n margin-bottom: @line-height-computed;\n font-size: floor((@font-size-base * 1.15));\n font-weight: 200;\n line-height: 1.4;\n\n @media (min-width: @screen-sm-min) {\n font-size: (@font-size-base * 1.5);\n }\n}\n\n\n// Emphasis & misc\n// -------------------------\n\n// Ex: 14px base font * 85% = about 12px\nsmall,\n.small { font-size: 85%; }\n\n// Undo browser default styling\ncite { font-style: normal; }\n\n// Alignment\n.text-left { text-align: left; }\n.text-right { text-align: right; }\n.text-center { text-align: center; }\n.text-justify { text-align: justify; }\n\n// Contextual colors\n.text-muted {\n color: @text-muted;\n}\n.text-primary {\n .text-emphasis-variant(@brand-primary);\n}\n.text-success {\n .text-emphasis-variant(@state-success-text);\n}\n.text-info {\n .text-emphasis-variant(@state-info-text);\n}\n.text-warning {\n .text-emphasis-variant(@state-warning-text);\n}\n.text-danger {\n .text-emphasis-variant(@state-danger-text);\n}\n\n// Contextual backgrounds\n// For now we'll leave these alongside the text classes until v4 when we can\n// safely shift things around (per SemVer rules).\n.bg-primary {\n // Given the contrast here, this is the only class to have its color inverted\n // automatically.\n color: #fff;\n .bg-variant(@brand-primary);\n}\n.bg-success {\n .bg-variant(@state-success-bg);\n}\n.bg-info {\n .bg-variant(@state-info-bg);\n}\n.bg-warning {\n .bg-variant(@state-warning-bg);\n}\n.bg-danger {\n .bg-variant(@state-danger-bg);\n}\n\n\n// Page header\n// -------------------------\n\n.page-header {\n padding-bottom: ((@line-height-computed / 2) - 1);\n margin: (@line-height-computed * 2) 0 @line-height-computed;\n border-bottom: 1px solid @page-header-border-color;\n}\n\n\n// Lists\n// --------------------------------------------------\n\n// Unordered and Ordered lists\nul,\nol {\n margin-top: 0;\n margin-bottom: (@line-height-computed / 2);\n ul,\n ol {\n margin-bottom: 0;\n }\n}\n\n// List options\n\n// Unstyled keeps list items block level, just removes default browser padding and list-style\n.list-unstyled {\n padding-left: 0;\n list-style: none;\n}\n\n// Inline turns list items into inline-block\n.list-inline {\n .list-unstyled();\n margin-left: -5px;\n\n > li {\n display: inline-block;\n padding-left: 5px;\n padding-right: 5px;\n }\n}\n\n// Description Lists\ndl {\n margin-top: 0; // Remove browser default\n margin-bottom: @line-height-computed;\n}\ndt,\ndd {\n line-height: @line-height-base;\n}\ndt {\n font-weight: bold;\n}\ndd {\n margin-left: 0; // Undo browser default\n}\n\n// Horizontal description lists\n//\n// Defaults to being stacked without any of the below styles applied, until the\n// grid breakpoint is reached (default of ~768px).\n\n@media (min-width: @grid-float-breakpoint) {\n .dl-horizontal {\n dt {\n float: left;\n width: (@component-offset-horizontal - 20);\n clear: left;\n text-align: right;\n .text-overflow();\n }\n dd {\n margin-left: @component-offset-horizontal;\n &:extend(.clearfix all); // Clear the floated `dt` if an empty `dd` is present\n }\n }\n}\n\n// MISC\n// ----\n\n// Abbreviations and acronyms\nabbr[title],\n// Add data-* attribute to help out our tooltip plugin, per https://github.com/twbs/bootstrap/issues/5257\nabbr[data-original-title] {\n cursor: help;\n border-bottom: 1px dotted @abbr-border-color;\n}\n.initialism {\n font-size: 90%;\n text-transform: uppercase;\n}\n\n// Blockquotes\nblockquote {\n padding: (@line-height-computed / 2) @line-height-computed;\n margin: 0 0 @line-height-computed;\n font-size: @blockquote-font-size;\n border-left: 5px solid @blockquote-border-color;\n\n p,\n ul,\n ol {\n &:last-child {\n margin-bottom: 0;\n }\n }\n\n // Note: Deprecated small and .small as of v3.1.0\n // Context: https://github.com/twbs/bootstrap/issues/11660\n footer,\n small,\n .small {\n display: block;\n font-size: 80%; // back to default font-size\n line-height: @line-height-base;\n color: @blockquote-small-color;\n\n &:before {\n content: '\\2014 \\00A0'; // em dash, nbsp\n }\n }\n}\n\n// Opposite alignment of blockquote\n//\n// Heads up: `blockquote.pull-right` has been deprecated as of v3.1.0.\n.blockquote-reverse,\nblockquote.pull-right {\n padding-right: 15px;\n padding-left: 0;\n border-right: 5px solid @blockquote-border-color;\n border-left: 0;\n text-align: right;\n\n // Account for citation\n footer,\n small,\n .small {\n &:before { content: ''; }\n &:after {\n content: '\\00A0 \\2014'; // nbsp, em dash\n }\n }\n}\n\n// Quotes\nblockquote:before,\nblockquote:after {\n content: \"\";\n}\n\n// Addresses\naddress {\n margin-bottom: @line-height-computed;\n font-style: normal;\n line-height: @line-height-base;\n}\n","//\n// Code (inline and block)\n// --------------------------------------------------\n\n\n// Inline and block code styles\ncode,\nkbd,\npre,\nsamp {\n font-family: @font-family-monospace;\n}\n\n// Inline code\ncode {\n padding: 2px 4px;\n font-size: 90%;\n color: @code-color;\n background-color: @code-bg;\n white-space: nowrap;\n border-radius: @border-radius-base;\n}\n\n// User input typically entered via keyboard\nkbd {\n padding: 2px 4px;\n font-size: 90%;\n color: @kbd-color;\n background-color: @kbd-bg;\n border-radius: @border-radius-small;\n box-shadow: inset 0 -1px 0 rgba(0,0,0,.25);\n}\n\n// Blocks of code\npre {\n display: block;\n padding: ((@line-height-computed - 1) / 2);\n margin: 0 0 (@line-height-computed / 2);\n font-size: (@font-size-base - 1); // 14px to 13px\n line-height: @line-height-base;\n word-break: break-all;\n word-wrap: break-word;\n color: @pre-color;\n background-color: @pre-bg;\n border: 1px solid @pre-border-color;\n border-radius: @border-radius-base;\n\n // Account for some code outputs that place code tags in pre tags\n code {\n padding: 0;\n font-size: inherit;\n color: inherit;\n white-space: pre-wrap;\n background-color: transparent;\n border-radius: 0;\n }\n}\n\n// Enable scrollable blocks of code\n.pre-scrollable {\n max-height: @pre-scrollable-max-height;\n overflow-y: scroll;\n}\n","//\n// Grid system\n// --------------------------------------------------\n\n\n// Container widths\n//\n// Set the container width, and override it for fixed navbars in media queries.\n\n.container {\n .container-fixed();\n\n @media (min-width: @screen-sm-min) {\n width: @container-sm;\n }\n @media (min-width: @screen-md-min) {\n width: @container-md;\n }\n @media (min-width: @screen-lg-min) {\n width: @container-lg;\n }\n}\n\n\n// Fluid container\n//\n// Utilizes the mixin meant for fixed width containers, but without any defined\n// width for fluid, full width layouts.\n\n.container-fluid {\n .container-fixed();\n}\n\n\n// Row\n//\n// Rows contain and clear the floats of your columns.\n\n.row {\n .make-row();\n}\n\n\n// Columns\n//\n// Common styles for small and large grid columns\n\n.make-grid-columns();\n\n\n// Extra small grid\n//\n// Columns, offsets, pushes, and pulls for extra small devices like\n// smartphones.\n\n.make-grid(xs);\n\n\n// Small grid\n//\n// Columns, offsets, pushes, and pulls for the small device range, from phones\n// to tablets.\n\n@media (min-width: @screen-sm-min) {\n .make-grid(sm);\n}\n\n\n// Medium grid\n//\n// Columns, offsets, pushes, and pulls for the desktop device range.\n\n@media (min-width: @screen-md-min) {\n .make-grid(md);\n}\n\n\n// Large grid\n//\n// Columns, offsets, pushes, and pulls for the large desktop device range.\n\n@media (min-width: @screen-lg-min) {\n .make-grid(lg);\n}\n","//\n// Tables\n// --------------------------------------------------\n\n\ntable {\n max-width: 100%;\n background-color: @table-bg;\n}\nth {\n text-align: left;\n}\n\n\n// Baseline styles\n\n.table {\n width: 100%;\n margin-bottom: @line-height-computed;\n // Cells\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th,\n > td {\n padding: @table-cell-padding;\n line-height: @line-height-base;\n vertical-align: top;\n border-top: 1px solid @table-border-color;\n }\n }\n }\n // Bottom align for column headings\n > thead > tr > th {\n vertical-align: bottom;\n border-bottom: 2px solid @table-border-color;\n }\n // Remove top border from thead by default\n > caption + thead,\n > colgroup + thead,\n > thead:first-child {\n > tr:first-child {\n > th,\n > td {\n border-top: 0;\n }\n }\n }\n // Account for multiple tbody instances\n > tbody + tbody {\n border-top: 2px solid @table-border-color;\n }\n\n // Nesting\n .table {\n background-color: @body-bg;\n }\n}\n\n\n// Condensed table w/ half padding\n\n.table-condensed {\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th,\n > td {\n padding: @table-condensed-cell-padding;\n }\n }\n }\n}\n\n\n// Bordered version\n//\n// Add borders all around the table and between all the columns.\n\n.table-bordered {\n border: 1px solid @table-border-color;\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th,\n > td {\n border: 1px solid @table-border-color;\n }\n }\n }\n > thead > tr {\n > th,\n > td {\n border-bottom-width: 2px;\n }\n }\n}\n\n\n// Zebra-striping\n//\n// Default zebra-stripe styles (alternating gray and transparent backgrounds)\n\n.table-striped {\n > tbody > tr:nth-child(odd) {\n > td,\n > th {\n background-color: @table-bg-accent;\n }\n }\n}\n\n\n// Hover effect\n//\n// Placed here since it has to come after the potential zebra striping\n\n.table-hover {\n > tbody > tr:hover {\n > td,\n > th {\n background-color: @table-bg-hover;\n }\n }\n}\n\n\n// Table cell sizing\n//\n// Reset default table behavior\n\ntable col[class*=\"col-\"] {\n position: static; // Prevent border hiding in Firefox and IE9/10 (see https://github.com/twbs/bootstrap/issues/11623)\n float: none;\n display: table-column;\n}\ntable {\n td,\n th {\n &[class*=\"col-\"] {\n position: static; // Prevent border hiding in Firefox and IE9/10 (see https://github.com/twbs/bootstrap/issues/11623)\n float: none;\n display: table-cell;\n }\n }\n}\n\n\n// Table backgrounds\n//\n// Exact selectors below required to override `.table-striped` and prevent\n// inheritance to nested tables.\n\n// Generate the contextual variants\n.table-row-variant(active; @table-bg-active);\n.table-row-variant(success; @state-success-bg);\n.table-row-variant(info; @state-info-bg);\n.table-row-variant(warning; @state-warning-bg);\n.table-row-variant(danger; @state-danger-bg);\n\n\n// Responsive tables\n//\n// Wrap your tables in `.table-responsive` and we'll make them mobile friendly\n// by enabling horizontal scrolling. Only applies <768px. Everything above that\n// will display normally.\n\n@media (max-width: @screen-xs-max) {\n .table-responsive {\n width: 100%;\n margin-bottom: (@line-height-computed * 0.75);\n overflow-y: hidden;\n overflow-x: scroll;\n -ms-overflow-style: -ms-autohiding-scrollbar;\n border: 1px solid @table-border-color;\n -webkit-overflow-scrolling: touch;\n\n // Tighten up spacing\n > .table {\n margin-bottom: 0;\n\n // Ensure the content doesn't wrap\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th,\n > td {\n white-space: nowrap;\n }\n }\n }\n }\n\n // Special overrides for the bordered tables\n > .table-bordered {\n border: 0;\n\n // Nuke the appropriate borders so that the parent can handle them\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th:first-child,\n > td:first-child {\n border-left: 0;\n }\n > th:last-child,\n > td:last-child {\n border-right: 0;\n }\n }\n }\n\n // Only nuke the last row's bottom-border in `tbody` and `tfoot` since\n // chances are there will be only one `tr` in a `thead` and that would\n // remove the border altogether.\n > tbody,\n > tfoot {\n > tr:last-child {\n > th,\n > td {\n border-bottom: 0;\n }\n }\n }\n\n }\n }\n}\n","//\n// Forms\n// --------------------------------------------------\n\n\n// Normalize non-controls\n//\n// Restyle and baseline non-control form elements.\n\nfieldset {\n padding: 0;\n margin: 0;\n border: 0;\n // Chrome and Firefox set a `min-width: -webkit-min-content;` on fieldsets,\n // so we reset that to ensure it behaves more like a standard block element.\n // See https://github.com/twbs/bootstrap/issues/12359.\n min-width: 0;\n}\n\nlegend {\n display: block;\n width: 100%;\n padding: 0;\n margin-bottom: @line-height-computed;\n font-size: (@font-size-base * 1.5);\n line-height: inherit;\n color: @legend-color;\n border: 0;\n border-bottom: 1px solid @legend-border-color;\n}\n\nlabel {\n display: inline-block;\n margin-bottom: 5px;\n font-weight: bold;\n}\n\n\n// Normalize form controls\n//\n// While most of our form styles require extra classes, some basic normalization\n// is required to ensure optimum display with or without those classes to better\n// address browser inconsistencies.\n\n// Override content-box in Normalize (* isn't specific enough)\ninput[type=\"search\"] {\n .box-sizing(border-box);\n}\n\n// Position radios and checkboxes better\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n margin: 4px 0 0;\n margin-top: 1px \\9; /* IE8-9 */\n line-height: normal;\n}\n\n// Set the height of file controls to match text inputs\ninput[type=\"file\"] {\n display: block;\n}\n\n// Make range inputs behave like textual form controls\ninput[type=\"range\"] {\n display: block;\n width: 100%;\n}\n\n// Make multiple select elements height not fixed\nselect[multiple],\nselect[size] {\n height: auto;\n}\n\n// Focus for file, radio, and checkbox\ninput[type=\"file\"]:focus,\ninput[type=\"radio\"]:focus,\ninput[type=\"checkbox\"]:focus {\n .tab-focus();\n}\n\n// Adjust output element\noutput {\n display: block;\n padding-top: (@padding-base-vertical + 1);\n font-size: @font-size-base;\n line-height: @line-height-base;\n color: @input-color;\n}\n\n\n// Common form controls\n//\n// Shared size and type resets for form controls. Apply `.form-control` to any\n// of the following form controls:\n//\n// select\n// textarea\n// input[type=\"text\"]\n// input[type=\"password\"]\n// input[type=\"datetime\"]\n// input[type=\"datetime-local\"]\n// input[type=\"date\"]\n// input[type=\"month\"]\n// input[type=\"time\"]\n// input[type=\"week\"]\n// input[type=\"number\"]\n// input[type=\"email\"]\n// input[type=\"url\"]\n// input[type=\"search\"]\n// input[type=\"tel\"]\n// input[type=\"color\"]\n\n.form-control {\n display: block;\n width: 100%;\n height: @input-height-base; // Make inputs at least the height of their button counterpart (base line-height + padding + border)\n padding: @padding-base-vertical @padding-base-horizontal;\n font-size: @font-size-base;\n line-height: @line-height-base;\n color: @input-color;\n background-color: @input-bg;\n background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214\n border: 1px solid @input-border;\n border-radius: @input-border-radius;\n .box-shadow(inset 0 1px 1px rgba(0,0,0,.075));\n .transition(~\"border-color ease-in-out .15s, box-shadow ease-in-out .15s\");\n\n // Customize the `:focus` state to imitate native WebKit styles.\n .form-control-focus();\n\n // Placeholder\n .placeholder();\n\n // Disabled and read-only inputs\n //\n // HTML5 says that controls under a fieldset > legend:first-child won't be\n // disabled if the fieldset is disabled. Due to implementation difficulty, we\n // don't honor that edge case; we style them as disabled anyway.\n &[disabled],\n &[readonly],\n fieldset[disabled] & {\n cursor: not-allowed;\n background-color: @input-bg-disabled;\n opacity: 1; // iOS fix for unreadable disabled content\n }\n\n // Reset height for `textarea`s\n textarea& {\n height: auto;\n }\n}\n\n\n// Search inputs in iOS\n//\n// This overrides the extra rounded corners on search inputs in iOS so that our\n// `.form-control` class can properly style them. Note that this cannot simply\n// be added to `.form-control` as it's not specific enough. For details, see\n// https://github.com/twbs/bootstrap/issues/11586.\n\ninput[type=\"search\"] {\n -webkit-appearance: none;\n}\n\n\n// Special styles for iOS date input\n//\n// In Mobile Safari, date inputs require a pixel line-height that matches the\n// given height of the input.\n\ninput[type=\"date\"] {\n line-height: @input-height-base;\n}\n\n\n// Form groups\n//\n// Designed to help with the organization and spacing of vertical forms. For\n// horizontal forms, use the predefined grid classes.\n\n.form-group {\n margin-bottom: 15px;\n}\n\n\n// Checkboxes and radios\n//\n// Indent the labels to position radios/checkboxes as hanging controls.\n\n.radio,\n.checkbox {\n display: block;\n min-height: @line-height-computed; // clear the floating input if there is no label text\n margin-top: 10px;\n margin-bottom: 10px;\n padding-left: 20px;\n label {\n display: inline;\n font-weight: normal;\n cursor: pointer;\n }\n}\n.radio input[type=\"radio\"],\n.radio-inline input[type=\"radio\"],\n.checkbox input[type=\"checkbox\"],\n.checkbox-inline input[type=\"checkbox\"] {\n float: left;\n margin-left: -20px;\n}\n.radio + .radio,\n.checkbox + .checkbox {\n margin-top: -5px; // Move up sibling radios or checkboxes for tighter spacing\n}\n\n// Radios and checkboxes on same line\n.radio-inline,\n.checkbox-inline {\n display: inline-block;\n padding-left: 20px;\n margin-bottom: 0;\n vertical-align: middle;\n font-weight: normal;\n cursor: pointer;\n}\n.radio-inline + .radio-inline,\n.checkbox-inline + .checkbox-inline {\n margin-top: 0;\n margin-left: 10px; // space out consecutive inline controls\n}\n\n// Apply same disabled cursor tweak as for inputs\n//\n// Note: Neither radios nor checkboxes can be readonly.\ninput[type=\"radio\"],\ninput[type=\"checkbox\"],\n.radio,\n.radio-inline,\n.checkbox,\n.checkbox-inline {\n &[disabled],\n fieldset[disabled] & {\n cursor: not-allowed;\n }\n}\n\n\n// Form control sizing\n//\n// Build on `.form-control` with modifier classes to decrease or increase the\n// height and font-size of form controls.\n\n.input-sm {\n .input-size(@input-height-small; @padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @border-radius-small);\n}\n\n.input-lg {\n .input-size(@input-height-large; @padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @border-radius-large);\n}\n\n\n// Form control feedback states\n//\n// Apply contextual and semantic states to individual form controls.\n\n.has-feedback {\n // Enable absolute positioning\n position: relative;\n\n // Ensure icons don't overlap text\n .form-control {\n padding-right: (@input-height-base * 1.25);\n }\n\n // Feedback icon (requires .glyphicon classes)\n .form-control-feedback {\n position: absolute;\n top: (@line-height-computed + 5); // Height of the `label` and its margin\n right: 0;\n display: block;\n width: @input-height-base;\n height: @input-height-base;\n line-height: @input-height-base;\n text-align: center;\n }\n}\n\n// Feedback states\n.has-success {\n .form-control-validation(@state-success-text; @state-success-text; @state-success-bg);\n}\n.has-warning {\n .form-control-validation(@state-warning-text; @state-warning-text; @state-warning-bg);\n}\n.has-error {\n .form-control-validation(@state-danger-text; @state-danger-text; @state-danger-bg);\n}\n\n\n// Static form control text\n//\n// Apply class to a `p` element to make any string of text align with labels in\n// a horizontal form layout.\n\n.form-control-static {\n margin-bottom: 0; // Remove default margin from `p`\n}\n\n\n// Help text\n//\n// Apply to any element you wish to create light text for placement immediately\n// below a form control. Use for general help, formatting, or instructional text.\n\n.help-block {\n display: block; // account for any element using help-block\n margin-top: 5px;\n margin-bottom: 10px;\n color: lighten(@text-color, 25%); // lighten the text some for contrast\n}\n\n\n\n// Inline forms\n//\n// Make forms appear inline(-block) by adding the `.form-inline` class. Inline\n// forms begin stacked on extra small (mobile) devices and then go inline when\n// viewports reach <768px.\n//\n// Requires wrapping inputs and labels with `.form-group` for proper display of\n// default HTML form controls and our custom form controls (e.g., input groups).\n//\n// Heads up! This is mixin-ed into `.navbar-form` in navbars.less.\n\n.form-inline {\n\n // Kick in the inline\n @media (min-width: @screen-sm-min) {\n // Inline-block all the things for \"inline\"\n .form-group {\n display: inline-block;\n margin-bottom: 0;\n vertical-align: middle;\n }\n\n // In navbar-form, allow folks to *not* use `.form-group`\n .form-control {\n display: inline-block;\n width: auto; // Prevent labels from stacking above inputs in `.form-group`\n vertical-align: middle;\n }\n // Input groups need that 100% width though\n .input-group > .form-control {\n width: 100%;\n }\n\n .control-label {\n margin-bottom: 0;\n vertical-align: middle;\n }\n\n // Remove default margin on radios/checkboxes that were used for stacking, and\n // then undo the floating of radios and checkboxes to match (which also avoids\n // a bug in WebKit: https://github.com/twbs/bootstrap/issues/1969).\n .radio,\n .checkbox {\n display: inline-block;\n margin-top: 0;\n margin-bottom: 0;\n padding-left: 0;\n vertical-align: middle;\n }\n .radio input[type=\"radio\"],\n .checkbox input[type=\"checkbox\"] {\n float: none;\n margin-left: 0;\n }\n\n // Validation states\n //\n // Reposition the icon because it's now within a grid column and columns have\n // `position: relative;` on them. Also accounts for the grid gutter padding.\n .has-feedback .form-control-feedback {\n top: 0;\n }\n }\n}\n\n\n// Horizontal forms\n//\n// Horizontal forms are built on grid classes and allow you to create forms with\n// labels on the left and inputs on the right.\n\n.form-horizontal {\n\n // Consistent vertical alignment of labels, radios, and checkboxes\n .control-label,\n .radio,\n .checkbox,\n .radio-inline,\n .checkbox-inline {\n margin-top: 0;\n margin-bottom: 0;\n padding-top: (@padding-base-vertical + 1); // Default padding plus a border\n }\n // Account for padding we're adding to ensure the alignment and of help text\n // and other content below items\n .radio,\n .checkbox {\n min-height: (@line-height-computed + (@padding-base-vertical + 1));\n }\n\n // Make form groups behave like rows\n .form-group {\n .make-row();\n }\n\n .form-control-static {\n padding-top: (@padding-base-vertical + 1);\n }\n\n // Only right align form labels here when the columns stop stacking\n @media (min-width: @screen-sm-min) {\n .control-label {\n text-align: right;\n }\n }\n\n // Validation states\n //\n // Reposition the icon because it's now within a grid column and columns have\n // `position: relative;` on them. Also accounts for the grid gutter padding.\n .has-feedback .form-control-feedback {\n top: 0;\n right: (@grid-gutter-width / 2);\n }\n}\n","//\n// Buttons\n// --------------------------------------------------\n\n\n// Base styles\n// --------------------------------------------------\n\n.btn {\n display: inline-block;\n margin-bottom: 0; // For input.btn\n font-weight: @btn-font-weight;\n text-align: center;\n vertical-align: middle;\n cursor: pointer;\n background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214\n border: 1px solid transparent;\n white-space: nowrap;\n .button-size(@padding-base-vertical; @padding-base-horizontal; @font-size-base; @line-height-base; @border-radius-base);\n .user-select(none);\n\n &,\n &:active,\n &.active {\n &:focus {\n .tab-focus();\n }\n }\n\n &:hover,\n &:focus {\n color: @btn-default-color;\n text-decoration: none;\n }\n\n &:active,\n &.active {\n outline: 0;\n background-image: none;\n .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n }\n\n &.disabled,\n &[disabled],\n fieldset[disabled] & {\n cursor: not-allowed;\n pointer-events: none; // Future-proof disabling of clicks\n .opacity(.65);\n .box-shadow(none);\n }\n}\n\n\n// Alternate buttons\n// --------------------------------------------------\n\n.btn-default {\n .button-variant(@btn-default-color; @btn-default-bg; @btn-default-border);\n}\n.btn-primary {\n .button-variant(@btn-primary-color; @btn-primary-bg; @btn-primary-border);\n}\n// Success appears as green\n.btn-success {\n .button-variant(@btn-success-color; @btn-success-bg; @btn-success-border);\n}\n// Info appears as blue-green\n.btn-info {\n .button-variant(@btn-info-color; @btn-info-bg; @btn-info-border);\n}\n// Warning appears as orange\n.btn-warning {\n .button-variant(@btn-warning-color; @btn-warning-bg; @btn-warning-border);\n}\n// Danger and error appear as red\n.btn-danger {\n .button-variant(@btn-danger-color; @btn-danger-bg; @btn-danger-border);\n}\n\n\n// Link buttons\n// -------------------------\n\n// Make a button look and behave like a link\n.btn-link {\n color: @link-color;\n font-weight: normal;\n cursor: pointer;\n border-radius: 0;\n\n &,\n &:active,\n &[disabled],\n fieldset[disabled] & {\n background-color: transparent;\n .box-shadow(none);\n }\n &,\n &:hover,\n &:focus,\n &:active {\n border-color: transparent;\n }\n &:hover,\n &:focus {\n color: @link-hover-color;\n text-decoration: underline;\n background-color: transparent;\n }\n &[disabled],\n fieldset[disabled] & {\n &:hover,\n &:focus {\n color: @btn-link-disabled-color;\n text-decoration: none;\n }\n }\n}\n\n\n// Button Sizes\n// --------------------------------------------------\n\n.btn-lg {\n // line-height: ensure even-numbered height of button next to large input\n .button-size(@padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @border-radius-large);\n}\n.btn-sm {\n // line-height: ensure proper height of button next to small input\n .button-size(@padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @border-radius-small);\n}\n.btn-xs {\n .button-size(@padding-xs-vertical; @padding-xs-horizontal; @font-size-small; @line-height-small; @border-radius-small);\n}\n\n\n// Block button\n// --------------------------------------------------\n\n.btn-block {\n display: block;\n width: 100%;\n padding-left: 0;\n padding-right: 0;\n}\n\n// Vertically space out multiple block buttons\n.btn-block + .btn-block {\n margin-top: 5px;\n}\n\n// Specificity overrides\ninput[type=\"submit\"],\ninput[type=\"reset\"],\ninput[type=\"button\"] {\n &.btn-block {\n width: 100%;\n }\n}\n","//\n// Button groups\n// --------------------------------------------------\n\n// Make the div behave like a button\n.btn-group,\n.btn-group-vertical {\n position: relative;\n display: inline-block;\n vertical-align: middle; // match .btn alignment given font-size hack above\n > .btn {\n position: relative;\n float: left;\n // Bring the \"active\" button to the front\n &:hover,\n &:focus,\n &:active,\n &.active {\n z-index: 2;\n }\n &:focus {\n // Remove focus outline when dropdown JS adds it after closing the menu\n outline: none;\n }\n }\n}\n\n// Prevent double borders when buttons are next to each other\n.btn-group {\n .btn + .btn,\n .btn + .btn-group,\n .btn-group + .btn,\n .btn-group + .btn-group {\n margin-left: -1px;\n }\n}\n\n// Optional: Group multiple button groups together for a toolbar\n.btn-toolbar {\n margin-left: -5px; // Offset the first child's margin\n &:extend(.clearfix all);\n\n .btn-group,\n .input-group {\n float: left;\n }\n > .btn,\n > .btn-group,\n > .input-group {\n margin-left: 5px;\n }\n}\n\n.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {\n border-radius: 0;\n}\n\n// Set corners individual because sometimes a single button can be in a .btn-group and we need :first-child and :last-child to both match\n.btn-group > .btn:first-child {\n margin-left: 0;\n &:not(:last-child):not(.dropdown-toggle) {\n .border-right-radius(0);\n }\n}\n// Need .dropdown-toggle since :last-child doesn't apply given a .dropdown-menu immediately after it\n.btn-group > .btn:last-child:not(:first-child),\n.btn-group > .dropdown-toggle:not(:first-child) {\n .border-left-radius(0);\n}\n\n// Custom edits for including btn-groups within btn-groups (useful for including dropdown buttons within a btn-group)\n.btn-group > .btn-group {\n float: left;\n}\n.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {\n border-radius: 0;\n}\n.btn-group > .btn-group:first-child {\n > .btn:last-child,\n > .dropdown-toggle {\n .border-right-radius(0);\n }\n}\n.btn-group > .btn-group:last-child > .btn:first-child {\n .border-left-radius(0);\n}\n\n// On active and open, don't show outline\n.btn-group .dropdown-toggle:active,\n.btn-group.open .dropdown-toggle {\n outline: 0;\n}\n\n\n// Sizing\n//\n// Remix the default button sizing classes into new ones for easier manipulation.\n\n.btn-group-xs > .btn { &:extend(.btn-xs); }\n.btn-group-sm > .btn { &:extend(.btn-sm); }\n.btn-group-lg > .btn { &:extend(.btn-lg); }\n\n\n// Split button dropdowns\n// ----------------------\n\n// Give the line between buttons some depth\n.btn-group > .btn + .dropdown-toggle {\n padding-left: 8px;\n padding-right: 8px;\n}\n.btn-group > .btn-lg + .dropdown-toggle {\n padding-left: 12px;\n padding-right: 12px;\n}\n\n// The clickable button for toggling the menu\n// Remove the gradient and set the same inset shadow as the :active state\n.btn-group.open .dropdown-toggle {\n .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n\n // Show no shadow for `.btn-link` since it has no other button styles.\n &.btn-link {\n .box-shadow(none);\n }\n}\n\n\n// Reposition the caret\n.btn .caret {\n margin-left: 0;\n}\n// Carets in other button sizes\n.btn-lg .caret {\n border-width: @caret-width-large @caret-width-large 0;\n border-bottom-width: 0;\n}\n// Upside down carets for .dropup\n.dropup .btn-lg .caret {\n border-width: 0 @caret-width-large @caret-width-large;\n}\n\n\n// Vertical button groups\n// ----------------------\n\n.btn-group-vertical {\n > .btn,\n > .btn-group,\n > .btn-group > .btn {\n display: block;\n float: none;\n width: 100%;\n max-width: 100%;\n }\n\n // Clear floats so dropdown menus can be properly placed\n > .btn-group {\n &:extend(.clearfix all);\n > .btn {\n float: none;\n }\n }\n\n > .btn + .btn,\n > .btn + .btn-group,\n > .btn-group + .btn,\n > .btn-group + .btn-group {\n margin-top: -1px;\n margin-left: 0;\n }\n}\n\n.btn-group-vertical > .btn {\n &:not(:first-child):not(:last-child) {\n border-radius: 0;\n }\n &:first-child:not(:last-child) {\n border-top-right-radius: @border-radius-base;\n .border-bottom-radius(0);\n }\n &:last-child:not(:first-child) {\n border-bottom-left-radius: @border-radius-base;\n .border-top-radius(0);\n }\n}\n.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {\n border-radius: 0;\n}\n.btn-group-vertical > .btn-group:first-child:not(:last-child) {\n > .btn:last-child,\n > .dropdown-toggle {\n .border-bottom-radius(0);\n }\n}\n.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {\n .border-top-radius(0);\n}\n\n\n\n// Justified button groups\n// ----------------------\n\n.btn-group-justified {\n display: table;\n width: 100%;\n table-layout: fixed;\n border-collapse: separate;\n > .btn,\n > .btn-group {\n float: none;\n display: table-cell;\n width: 1%;\n }\n > .btn-group .btn {\n width: 100%;\n }\n}\n\n\n// Checkbox and radio options\n[data-toggle=\"buttons\"] > .btn > input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn > input[type=\"checkbox\"] {\n display: none;\n}\n","//\n// Component animations\n// --------------------------------------------------\n\n// Heads up!\n//\n// We don't use the `.opacity()` mixin here since it causes a bug with text\n// fields in IE7-8. Source: https://github.com/twitter/bootstrap/pull/3552.\n\n.fade {\n opacity: 0;\n .transition(opacity .15s linear);\n &.in {\n opacity: 1;\n }\n}\n\n.collapse {\n display: none;\n &.in {\n display: block;\n }\n}\n.collapsing {\n position: relative;\n height: 0;\n overflow: hidden;\n .transition(height .35s ease);\n}\n","//\n// Glyphicons for Bootstrap\n//\n// Since icons are fonts, they can be placed anywhere text is placed and are\n// thus automatically sized to match the surrounding child. To use, create an\n// inline element with the appropriate classes, like so:\n//\n// Star\n\n// Import the fonts\n@font-face {\n font-family: 'Glyphicons Halflings';\n src: ~\"url('@{icon-font-path}@{icon-font-name}.eot')\";\n src: ~\"url('@{icon-font-path}@{icon-font-name}.eot?#iefix') format('embedded-opentype')\",\n ~\"url('@{icon-font-path}@{icon-font-name}.woff') format('woff')\",\n ~\"url('@{icon-font-path}@{icon-font-name}.ttf') format('truetype')\",\n ~\"url('@{icon-font-path}@{icon-font-name}.svg#@{icon-font-svg-id}') format('svg')\";\n}\n\n// Catchall baseclass\n.glyphicon {\n position: relative;\n top: 1px;\n display: inline-block;\n font-family: 'Glyphicons Halflings';\n font-style: normal;\n font-weight: normal;\n line-height: 1;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\n// Individual icons\n.glyphicon-asterisk { &:before { content: \"\\2a\"; } }\n.glyphicon-plus { &:before { content: \"\\2b\"; } }\n.glyphicon-euro { &:before { content: \"\\20ac\"; } }\n.glyphicon-minus { &:before { content: \"\\2212\"; } }\n.glyphicon-cloud { &:before { content: \"\\2601\"; } }\n.glyphicon-envelope { &:before { content: \"\\2709\"; } }\n.glyphicon-pencil { &:before { content: \"\\270f\"; } }\n.glyphicon-glass { &:before { content: \"\\e001\"; } }\n.glyphicon-music { &:before { content: \"\\e002\"; } }\n.glyphicon-search { &:before { content: \"\\e003\"; } }\n.glyphicon-heart { &:before { content: \"\\e005\"; } }\n.glyphicon-star { &:before { content: \"\\e006\"; } }\n.glyphicon-star-empty { &:before { content: \"\\e007\"; } }\n.glyphicon-user { &:before { content: \"\\e008\"; } }\n.glyphicon-film { &:before { content: \"\\e009\"; } }\n.glyphicon-th-large { &:before { content: \"\\e010\"; } }\n.glyphicon-th { &:before { content: \"\\e011\"; } }\n.glyphicon-th-list { &:before { content: \"\\e012\"; } }\n.glyphicon-ok { &:before { content: \"\\e013\"; } }\n.glyphicon-remove { &:before { content: \"\\e014\"; } }\n.glyphicon-zoom-in { &:before { content: \"\\e015\"; } }\n.glyphicon-zoom-out { &:before { content: \"\\e016\"; } }\n.glyphicon-off { &:before { content: \"\\e017\"; } }\n.glyphicon-signal { &:before { content: \"\\e018\"; } }\n.glyphicon-cog { &:before { content: \"\\e019\"; } }\n.glyphicon-trash { &:before { content: \"\\e020\"; } }\n.glyphicon-home { &:before { content: \"\\e021\"; } }\n.glyphicon-file { &:before { content: \"\\e022\"; } }\n.glyphicon-time { &:before { content: \"\\e023\"; } }\n.glyphicon-road { &:before { content: \"\\e024\"; } }\n.glyphicon-download-alt { &:before { content: \"\\e025\"; } }\n.glyphicon-download { &:before { content: \"\\e026\"; } }\n.glyphicon-upload { &:before { content: \"\\e027\"; } }\n.glyphicon-inbox { &:before { content: \"\\e028\"; } }\n.glyphicon-play-circle { &:before { content: \"\\e029\"; } }\n.glyphicon-repeat { &:before { content: \"\\e030\"; } }\n.glyphicon-refresh { &:before { content: \"\\e031\"; } }\n.glyphicon-list-alt { &:before { content: \"\\e032\"; } }\n.glyphicon-lock { &:before { content: \"\\e033\"; } }\n.glyphicon-flag { &:before { content: \"\\e034\"; } }\n.glyphicon-headphones { &:before { content: \"\\e035\"; } }\n.glyphicon-volume-off { &:before { content: \"\\e036\"; } }\n.glyphicon-volume-down { &:before { content: \"\\e037\"; } }\n.glyphicon-volume-up { &:before { content: \"\\e038\"; } }\n.glyphicon-qrcode { &:before { content: \"\\e039\"; } }\n.glyphicon-barcode { &:before { content: \"\\e040\"; } }\n.glyphicon-tag { &:before { content: \"\\e041\"; } }\n.glyphicon-tags { &:before { content: \"\\e042\"; } }\n.glyphicon-book { &:before { content: \"\\e043\"; } }\n.glyphicon-bookmark { &:before { content: \"\\e044\"; } }\n.glyphicon-print { &:before { content: \"\\e045\"; } }\n.glyphicon-camera { &:before { content: \"\\e046\"; } }\n.glyphicon-font { &:before { content: \"\\e047\"; } }\n.glyphicon-bold { &:before { content: \"\\e048\"; } }\n.glyphicon-italic { &:before { content: \"\\e049\"; } }\n.glyphicon-text-height { &:before { content: \"\\e050\"; } }\n.glyphicon-text-width { &:before { content: \"\\e051\"; } }\n.glyphicon-align-left { &:before { content: \"\\e052\"; } }\n.glyphicon-align-center { &:before { content: \"\\e053\"; } }\n.glyphicon-align-right { &:before { content: \"\\e054\"; } }\n.glyphicon-align-justify { &:before { content: \"\\e055\"; } }\n.glyphicon-list { &:before { content: \"\\e056\"; } }\n.glyphicon-indent-left { &:before { content: \"\\e057\"; } }\n.glyphicon-indent-right { &:before { content: \"\\e058\"; } }\n.glyphicon-facetime-video { &:before { content: \"\\e059\"; } }\n.glyphicon-picture { &:before { content: \"\\e060\"; } }\n.glyphicon-map-marker { &:before { content: \"\\e062\"; } }\n.glyphicon-adjust { &:before { content: \"\\e063\"; } }\n.glyphicon-tint { &:before { content: \"\\e064\"; } }\n.glyphicon-edit { &:before { content: \"\\e065\"; } }\n.glyphicon-share { &:before { content: \"\\e066\"; } }\n.glyphicon-check { &:before { content: \"\\e067\"; } }\n.glyphicon-move { &:before { content: \"\\e068\"; } }\n.glyphicon-step-backward { &:before { content: \"\\e069\"; } }\n.glyphicon-fast-backward { &:before { content: \"\\e070\"; } }\n.glyphicon-backward { &:before { content: \"\\e071\"; } }\n.glyphicon-play { &:before { content: \"\\e072\"; } }\n.glyphicon-pause { &:before { content: \"\\e073\"; } }\n.glyphicon-stop { &:before { content: \"\\e074\"; } }\n.glyphicon-forward { &:before { content: \"\\e075\"; } }\n.glyphicon-fast-forward { &:before { content: \"\\e076\"; } }\n.glyphicon-step-forward { &:before { content: \"\\e077\"; } }\n.glyphicon-eject { &:before { content: \"\\e078\"; } }\n.glyphicon-chevron-left { &:before { content: \"\\e079\"; } }\n.glyphicon-chevron-right { &:before { content: \"\\e080\"; } }\n.glyphicon-plus-sign { &:before { content: \"\\e081\"; } }\n.glyphicon-minus-sign { &:before { content: \"\\e082\"; } }\n.glyphicon-remove-sign { &:before { content: \"\\e083\"; } }\n.glyphicon-ok-sign { &:before { content: \"\\e084\"; } }\n.glyphicon-question-sign { &:before { content: \"\\e085\"; } }\n.glyphicon-info-sign { &:before { content: \"\\e086\"; } }\n.glyphicon-screenshot { &:before { content: \"\\e087\"; } }\n.glyphicon-remove-circle { &:before { content: \"\\e088\"; } }\n.glyphicon-ok-circle { &:before { content: \"\\e089\"; } }\n.glyphicon-ban-circle { &:before { content: \"\\e090\"; } }\n.glyphicon-arrow-left { &:before { content: \"\\e091\"; } }\n.glyphicon-arrow-right { &:before { content: \"\\e092\"; } }\n.glyphicon-arrow-up { &:before { content: \"\\e093\"; } }\n.glyphicon-arrow-down { &:before { content: \"\\e094\"; } }\n.glyphicon-share-alt { &:before { content: \"\\e095\"; } }\n.glyphicon-resize-full { &:before { content: \"\\e096\"; } }\n.glyphicon-resize-small { &:before { content: \"\\e097\"; } }\n.glyphicon-exclamation-sign { &:before { content: \"\\e101\"; } }\n.glyphicon-gift { &:before { content: \"\\e102\"; } }\n.glyphicon-leaf { &:before { content: \"\\e103\"; } }\n.glyphicon-fire { &:before { content: \"\\e104\"; } }\n.glyphicon-eye-open { &:before { content: \"\\e105\"; } }\n.glyphicon-eye-close { &:before { content: \"\\e106\"; } }\n.glyphicon-warning-sign { &:before { content: \"\\e107\"; } }\n.glyphicon-plane { &:before { content: \"\\e108\"; } }\n.glyphicon-calendar { &:before { content: \"\\e109\"; } }\n.glyphicon-random { &:before { content: \"\\e110\"; } }\n.glyphicon-comment { &:before { content: \"\\e111\"; } }\n.glyphicon-magnet { &:before { content: \"\\e112\"; } }\n.glyphicon-chevron-up { &:before { content: \"\\e113\"; } }\n.glyphicon-chevron-down { &:before { content: \"\\e114\"; } }\n.glyphicon-retweet { &:before { content: \"\\e115\"; } }\n.glyphicon-shopping-cart { &:before { content: \"\\e116\"; } }\n.glyphicon-folder-close { &:before { content: \"\\e117\"; } }\n.glyphicon-folder-open { &:before { content: \"\\e118\"; } }\n.glyphicon-resize-vertical { &:before { content: \"\\e119\"; } }\n.glyphicon-resize-horizontal { &:before { content: \"\\e120\"; } }\n.glyphicon-hdd { &:before { content: \"\\e121\"; } }\n.glyphicon-bullhorn { &:before { content: \"\\e122\"; } }\n.glyphicon-bell { &:before { content: \"\\e123\"; } }\n.glyphicon-certificate { &:before { content: \"\\e124\"; } }\n.glyphicon-thumbs-up { &:before { content: \"\\e125\"; } }\n.glyphicon-thumbs-down { &:before { content: \"\\e126\"; } }\n.glyphicon-hand-right { &:before { content: \"\\e127\"; } }\n.glyphicon-hand-left { &:before { content: \"\\e128\"; } }\n.glyphicon-hand-up { &:before { content: \"\\e129\"; } }\n.glyphicon-hand-down { &:before { content: \"\\e130\"; } }\n.glyphicon-circle-arrow-right { &:before { content: \"\\e131\"; } }\n.glyphicon-circle-arrow-left { &:before { content: \"\\e132\"; } }\n.glyphicon-circle-arrow-up { &:before { content: \"\\e133\"; } }\n.glyphicon-circle-arrow-down { &:before { content: \"\\e134\"; } }\n.glyphicon-globe { &:before { content: \"\\e135\"; } }\n.glyphicon-wrench { &:before { content: \"\\e136\"; } }\n.glyphicon-tasks { &:before { content: \"\\e137\"; } }\n.glyphicon-filter { &:before { content: \"\\e138\"; } }\n.glyphicon-briefcase { &:before { content: \"\\e139\"; } }\n.glyphicon-fullscreen { &:before { content: \"\\e140\"; } }\n.glyphicon-dashboard { &:before { content: \"\\e141\"; } }\n.glyphicon-paperclip { &:before { content: \"\\e142\"; } }\n.glyphicon-heart-empty { &:before { content: \"\\e143\"; } }\n.glyphicon-link { &:before { content: \"\\e144\"; } }\n.glyphicon-phone { &:before { content: \"\\e145\"; } }\n.glyphicon-pushpin { &:before { content: \"\\e146\"; } }\n.glyphicon-usd { &:before { content: \"\\e148\"; } }\n.glyphicon-gbp { &:before { content: \"\\e149\"; } }\n.glyphicon-sort { &:before { content: \"\\e150\"; } }\n.glyphicon-sort-by-alphabet { &:before { content: \"\\e151\"; } }\n.glyphicon-sort-by-alphabet-alt { &:before { content: \"\\e152\"; } }\n.glyphicon-sort-by-order { &:before { content: \"\\e153\"; } }\n.glyphicon-sort-by-order-alt { &:before { content: \"\\e154\"; } }\n.glyphicon-sort-by-attributes { &:before { content: \"\\e155\"; } }\n.glyphicon-sort-by-attributes-alt { &:before { content: \"\\e156\"; } }\n.glyphicon-unchecked { &:before { content: \"\\e157\"; } }\n.glyphicon-expand { &:before { content: \"\\e158\"; } }\n.glyphicon-collapse-down { &:before { content: \"\\e159\"; } }\n.glyphicon-collapse-up { &:before { content: \"\\e160\"; } }\n.glyphicon-log-in { &:before { content: \"\\e161\"; } }\n.glyphicon-flash { &:before { content: \"\\e162\"; } }\n.glyphicon-log-out { &:before { content: \"\\e163\"; } }\n.glyphicon-new-window { &:before { content: \"\\e164\"; } }\n.glyphicon-record { &:before { content: \"\\e165\"; } }\n.glyphicon-save { &:before { content: \"\\e166\"; } }\n.glyphicon-open { &:before { content: \"\\e167\"; } }\n.glyphicon-saved { &:before { content: \"\\e168\"; } }\n.glyphicon-import { &:before { content: \"\\e169\"; } }\n.glyphicon-export { &:before { content: \"\\e170\"; } }\n.glyphicon-send { &:before { content: \"\\e171\"; } }\n.glyphicon-floppy-disk { &:before { content: \"\\e172\"; } }\n.glyphicon-floppy-saved { &:before { content: \"\\e173\"; } }\n.glyphicon-floppy-remove { &:before { content: \"\\e174\"; } }\n.glyphicon-floppy-save { &:before { content: \"\\e175\"; } }\n.glyphicon-floppy-open { &:before { content: \"\\e176\"; } }\n.glyphicon-credit-card { &:before { content: \"\\e177\"; } }\n.glyphicon-transfer { &:before { content: \"\\e178\"; } }\n.glyphicon-cutlery { &:before { content: \"\\e179\"; } }\n.glyphicon-header { &:before { content: \"\\e180\"; } }\n.glyphicon-compressed { &:before { content: \"\\e181\"; } }\n.glyphicon-earphone { &:before { content: \"\\e182\"; } }\n.glyphicon-phone-alt { &:before { content: \"\\e183\"; } }\n.glyphicon-tower { &:before { content: \"\\e184\"; } }\n.glyphicon-stats { &:before { content: \"\\e185\"; } }\n.glyphicon-sd-video { &:before { content: \"\\e186\"; } }\n.glyphicon-hd-video { &:before { content: \"\\e187\"; } }\n.glyphicon-subtitles { &:before { content: \"\\e188\"; } }\n.glyphicon-sound-stereo { &:before { content: \"\\e189\"; } }\n.glyphicon-sound-dolby { &:before { content: \"\\e190\"; } }\n.glyphicon-sound-5-1 { &:before { content: \"\\e191\"; } }\n.glyphicon-sound-6-1 { &:before { content: \"\\e192\"; } }\n.glyphicon-sound-7-1 { &:before { content: \"\\e193\"; } }\n.glyphicon-copyright-mark { &:before { content: \"\\e194\"; } }\n.glyphicon-registration-mark { &:before { content: \"\\e195\"; } }\n.glyphicon-cloud-download { &:before { content: \"\\e197\"; } }\n.glyphicon-cloud-upload { &:before { content: \"\\e198\"; } }\n.glyphicon-tree-conifer { &:before { content: \"\\e199\"; } }\n.glyphicon-tree-deciduous { &:before { content: \"\\e200\"; } }\n","//\n// Dropdown menus\n// --------------------------------------------------\n\n\n// Dropdown arrow/caret\n.caret {\n display: inline-block;\n width: 0;\n height: 0;\n margin-left: 2px;\n vertical-align: middle;\n border-top: @caret-width-base solid;\n border-right: @caret-width-base solid transparent;\n border-left: @caret-width-base solid transparent;\n}\n\n// The dropdown wrapper (div)\n.dropdown {\n position: relative;\n}\n\n// Prevent the focus on the dropdown toggle when closing dropdowns\n.dropdown-toggle:focus {\n outline: 0;\n}\n\n// The dropdown menu (ul)\n.dropdown-menu {\n position: absolute;\n top: 100%;\n left: 0;\n z-index: @zindex-dropdown;\n display: none; // none by default, but block on \"open\" of the menu\n float: left;\n min-width: 160px;\n padding: 5px 0;\n margin: 2px 0 0; // override default ul\n list-style: none;\n font-size: @font-size-base;\n background-color: @dropdown-bg;\n border: 1px solid @dropdown-fallback-border; // IE8 fallback\n border: 1px solid @dropdown-border;\n border-radius: @border-radius-base;\n .box-shadow(0 6px 12px rgba(0,0,0,.175));\n background-clip: padding-box;\n\n // Aligns the dropdown menu to right\n //\n // Deprecated as of 3.1.0 in favor of `.dropdown-menu-[dir]`\n &.pull-right {\n right: 0;\n left: auto;\n }\n\n // Dividers (basically an hr) within the dropdown\n .divider {\n .nav-divider(@dropdown-divider-bg);\n }\n\n // Links within the dropdown menu\n > li > a {\n display: block;\n padding: 3px 20px;\n clear: both;\n font-weight: normal;\n line-height: @line-height-base;\n color: @dropdown-link-color;\n white-space: nowrap; // prevent links from randomly breaking onto new lines\n }\n}\n\n// Hover/Focus state\n.dropdown-menu > li > a {\n &:hover,\n &:focus {\n text-decoration: none;\n color: @dropdown-link-hover-color;\n background-color: @dropdown-link-hover-bg;\n }\n}\n\n// Active state\n.dropdown-menu > .active > a {\n &,\n &:hover,\n &:focus {\n color: @dropdown-link-active-color;\n text-decoration: none;\n outline: 0;\n background-color: @dropdown-link-active-bg;\n }\n}\n\n// Disabled state\n//\n// Gray out text and ensure the hover/focus state remains gray\n\n.dropdown-menu > .disabled > a {\n &,\n &:hover,\n &:focus {\n color: @dropdown-link-disabled-color;\n }\n}\n// Nuke hover/focus effects\n.dropdown-menu > .disabled > a {\n &:hover,\n &:focus {\n text-decoration: none;\n background-color: transparent;\n background-image: none; // Remove CSS gradient\n .reset-filter();\n cursor: not-allowed;\n }\n}\n\n// Open state for the dropdown\n.open {\n // Show the menu\n > .dropdown-menu {\n display: block;\n }\n\n // Remove the outline when :focus is triggered\n > a {\n outline: 0;\n }\n}\n\n// Menu positioning\n//\n// Add extra class to `.dropdown-menu` to flip the alignment of the dropdown\n// menu with the parent.\n.dropdown-menu-right {\n left: auto; // Reset the default from `.dropdown-menu`\n right: 0;\n}\n// With v3, we enabled auto-flipping if you have a dropdown within a right\n// aligned nav component. To enable the undoing of that, we provide an override\n// to restore the default dropdown menu alignment.\n//\n// This is only for left-aligning a dropdown menu within a `.navbar-right` or\n// `.pull-right` nav component.\n.dropdown-menu-left {\n left: 0;\n right: auto;\n}\n\n// Dropdown section headers\n.dropdown-header {\n display: block;\n padding: 3px 20px;\n font-size: @font-size-small;\n line-height: @line-height-base;\n color: @dropdown-header-color;\n}\n\n// Backdrop to catch body clicks on mobile, etc.\n.dropdown-backdrop {\n position: fixed;\n left: 0;\n right: 0;\n bottom: 0;\n top: 0;\n z-index: (@zindex-dropdown - 10);\n}\n\n// Right aligned dropdowns\n.pull-right > .dropdown-menu {\n right: 0;\n left: auto;\n}\n\n// Allow for dropdowns to go bottom up (aka, dropup-menu)\n//\n// Just add .dropup after the standard .dropdown class and you're set, bro.\n// TODO: abstract this so that the navbar fixed styles are not placed here?\n\n.dropup,\n.navbar-fixed-bottom .dropdown {\n // Reverse the caret\n .caret {\n border-top: 0;\n border-bottom: @caret-width-base solid;\n content: \"\";\n }\n // Different positioning for bottom up menu\n .dropdown-menu {\n top: auto;\n bottom: 100%;\n margin-bottom: 1px;\n }\n}\n\n\n// Component alignment\n//\n// Reiterate per navbar.less and the modified component alignment there.\n\n@media (min-width: @grid-float-breakpoint) {\n .navbar-right {\n .dropdown-menu {\n .dropdown-menu-right();\n }\n // Necessary for overrides of the default right aligned menu.\n // Will remove come v4 in all likelihood.\n .dropdown-menu-left {\n .dropdown-menu-left();\n }\n }\n}\n\n","//\n// Input groups\n// --------------------------------------------------\n\n// Base styles\n// -------------------------\n.input-group {\n position: relative; // For dropdowns\n display: table;\n border-collapse: separate; // prevent input groups from inheriting border styles from table cells when placed within a table\n\n // Undo padding and float of grid classes\n &[class*=\"col-\"] {\n float: none;\n padding-left: 0;\n padding-right: 0;\n }\n\n .form-control {\n // Ensure that the input is always above the *appended* addon button for\n // proper border colors.\n position: relative;\n z-index: 2;\n\n // IE9 fubars the placeholder attribute in text inputs and the arrows on\n // select elements in input groups. To fix it, we float the input. Details:\n // https://github.com/twbs/bootstrap/issues/11561#issuecomment-28936855\n float: left;\n\n width: 100%;\n margin-bottom: 0;\n }\n}\n\n// Sizing options\n//\n// Remix the default form control sizing classes into new ones for easier\n// manipulation.\n\n.input-group-lg > .form-control,\n.input-group-lg > .input-group-addon,\n.input-group-lg > .input-group-btn > .btn { .input-lg(); }\n.input-group-sm > .form-control,\n.input-group-sm > .input-group-addon,\n.input-group-sm > .input-group-btn > .btn { .input-sm(); }\n\n\n// Display as table-cell\n// -------------------------\n.input-group-addon,\n.input-group-btn,\n.input-group .form-control {\n display: table-cell;\n\n &:not(:first-child):not(:last-child) {\n border-radius: 0;\n }\n}\n// Addon and addon wrapper for buttons\n.input-group-addon,\n.input-group-btn {\n width: 1%;\n white-space: nowrap;\n vertical-align: middle; // Match the inputs\n}\n\n// Text input groups\n// -------------------------\n.input-group-addon {\n padding: @padding-base-vertical @padding-base-horizontal;\n font-size: @font-size-base;\n font-weight: normal;\n line-height: 1;\n color: @input-color;\n text-align: center;\n background-color: @input-group-addon-bg;\n border: 1px solid @input-group-addon-border-color;\n border-radius: @border-radius-base;\n\n // Sizing\n &.input-sm {\n padding: @padding-small-vertical @padding-small-horizontal;\n font-size: @font-size-small;\n border-radius: @border-radius-small;\n }\n &.input-lg {\n padding: @padding-large-vertical @padding-large-horizontal;\n font-size: @font-size-large;\n border-radius: @border-radius-large;\n }\n\n // Nuke default margins from checkboxes and radios to vertically center within.\n input[type=\"radio\"],\n input[type=\"checkbox\"] {\n margin-top: 0;\n }\n}\n\n// Reset rounded corners\n.input-group .form-control:first-child,\n.input-group-addon:first-child,\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group > .btn,\n.input-group-btn:first-child > .dropdown-toggle,\n.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),\n.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {\n .border-right-radius(0);\n}\n.input-group-addon:first-child {\n border-right: 0;\n}\n.input-group .form-control:last-child,\n.input-group-addon:last-child,\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group > .btn,\n.input-group-btn:last-child > .dropdown-toggle,\n.input-group-btn:first-child > .btn:not(:first-child),\n.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {\n .border-left-radius(0);\n}\n.input-group-addon:last-child {\n border-left: 0;\n}\n\n// Button input groups\n// -------------------------\n.input-group-btn {\n position: relative;\n // Jankily prevent input button groups from wrapping with `white-space` and\n // `font-size` in combination with `inline-block` on buttons.\n font-size: 0;\n white-space: nowrap;\n\n // Negative margin for spacing, position for bringing hovered/focused/actived\n // element above the siblings.\n > .btn {\n position: relative;\n + .btn {\n margin-left: -1px;\n }\n // Bring the \"active\" button to the front\n &:hover,\n &:focus,\n &:active {\n z-index: 2;\n }\n }\n\n // Negative margin to only have a 1px border between the two\n &:first-child {\n > .btn,\n > .btn-group {\n margin-right: -1px;\n }\n }\n &:last-child {\n > .btn,\n > .btn-group {\n margin-left: -1px;\n }\n }\n}\n","//\n// Navs\n// --------------------------------------------------\n\n\n// Base class\n// --------------------------------------------------\n\n.nav {\n margin-bottom: 0;\n padding-left: 0; // Override default ul/ol\n list-style: none;\n &:extend(.clearfix all);\n\n > li {\n position: relative;\n display: block;\n\n > a {\n position: relative;\n display: block;\n padding: @nav-link-padding;\n &:hover,\n &:focus {\n text-decoration: none;\n background-color: @nav-link-hover-bg;\n }\n }\n\n // Disabled state sets text to gray and nukes hover/tab effects\n &.disabled > a {\n color: @nav-disabled-link-color;\n\n &:hover,\n &:focus {\n color: @nav-disabled-link-hover-color;\n text-decoration: none;\n background-color: transparent;\n cursor: not-allowed;\n }\n }\n }\n\n // Open dropdowns\n .open > a {\n &,\n &:hover,\n &:focus {\n background-color: @nav-link-hover-bg;\n border-color: @link-color;\n }\n }\n\n // Nav dividers (deprecated with v3.0.1)\n //\n // This should have been removed in v3 with the dropping of `.nav-list`, but\n // we missed it. We don't currently support this anywhere, but in the interest\n // of maintaining backward compatibility in case you use it, it's deprecated.\n .nav-divider {\n .nav-divider();\n }\n\n // Prevent IE8 from misplacing imgs\n //\n // See https://github.com/h5bp/html5-boilerplate/issues/984#issuecomment-3985989\n > li > a > img {\n max-width: none;\n }\n}\n\n\n// Tabs\n// -------------------------\n\n// Give the tabs something to sit on\n.nav-tabs {\n border-bottom: 1px solid @nav-tabs-border-color;\n > li {\n float: left;\n // Make the list-items overlay the bottom border\n margin-bottom: -1px;\n\n // Actual tabs (as links)\n > a {\n margin-right: 2px;\n line-height: @line-height-base;\n border: 1px solid transparent;\n border-radius: @border-radius-base @border-radius-base 0 0;\n &:hover {\n border-color: @nav-tabs-link-hover-border-color @nav-tabs-link-hover-border-color @nav-tabs-border-color;\n }\n }\n\n // Active state, and its :hover to override normal :hover\n &.active > a {\n &,\n &:hover,\n &:focus {\n color: @nav-tabs-active-link-hover-color;\n background-color: @nav-tabs-active-link-hover-bg;\n border: 1px solid @nav-tabs-active-link-hover-border-color;\n border-bottom-color: transparent;\n cursor: default;\n }\n }\n }\n // pulling this in mainly for less shorthand\n &.nav-justified {\n .nav-justified();\n .nav-tabs-justified();\n }\n}\n\n\n// Pills\n// -------------------------\n.nav-pills {\n > li {\n float: left;\n\n // Links rendered as pills\n > a {\n border-radius: @nav-pills-border-radius;\n }\n + li {\n margin-left: 2px;\n }\n\n // Active state\n &.active > a {\n &,\n &:hover,\n &:focus {\n color: @nav-pills-active-link-hover-color;\n background-color: @nav-pills-active-link-hover-bg;\n }\n }\n }\n}\n\n\n// Stacked pills\n.nav-stacked {\n > li {\n float: none;\n + li {\n margin-top: 2px;\n margin-left: 0; // no need for this gap between nav items\n }\n }\n}\n\n\n// Nav variations\n// --------------------------------------------------\n\n// Justified nav links\n// -------------------------\n\n.nav-justified {\n width: 100%;\n\n > li {\n float: none;\n > a {\n text-align: center;\n margin-bottom: 5px;\n }\n }\n\n > .dropdown .dropdown-menu {\n top: auto;\n left: auto;\n }\n\n @media (min-width: @screen-sm-min) {\n > li {\n display: table-cell;\n width: 1%;\n > a {\n margin-bottom: 0;\n }\n }\n }\n}\n\n// Move borders to anchors instead of bottom of list\n//\n// Mixin for adding on top the shared `.nav-justified` styles for our tabs\n.nav-tabs-justified {\n border-bottom: 0;\n\n > li > a {\n // Override margin from .nav-tabs\n margin-right: 0;\n border-radius: @border-radius-base;\n }\n\n > .active > a,\n > .active > a:hover,\n > .active > a:focus {\n border: 1px solid @nav-tabs-justified-link-border-color;\n }\n\n @media (min-width: @screen-sm-min) {\n > li > a {\n border-bottom: 1px solid @nav-tabs-justified-link-border-color;\n border-radius: @border-radius-base @border-radius-base 0 0;\n }\n > .active > a,\n > .active > a:hover,\n > .active > a:focus {\n border-bottom-color: @nav-tabs-justified-active-link-border-color;\n }\n }\n}\n\n\n// Tabbable tabs\n// -------------------------\n\n// Hide tabbable panes to start, show them when `.active`\n.tab-content {\n > .tab-pane {\n display: none;\n }\n > .active {\n display: block;\n }\n}\n\n\n// Dropdowns\n// -------------------------\n\n// Specific dropdowns\n.nav-tabs .dropdown-menu {\n // make dropdown border overlap tab border\n margin-top: -1px;\n // Remove the top rounded corners here since there is a hard edge above the menu\n .border-top-radius(0);\n}\n","//\n// Navbars\n// --------------------------------------------------\n\n\n// Wrapper and base class\n//\n// Provide a static navbar from which we expand to create full-width, fixed, and\n// other navbar variations.\n\n.navbar {\n position: relative;\n min-height: @navbar-height; // Ensure a navbar always shows (e.g., without a .navbar-brand in collapsed mode)\n margin-bottom: @navbar-margin-bottom;\n border: 1px solid transparent;\n\n // Prevent floats from breaking the navbar\n &:extend(.clearfix all);\n\n @media (min-width: @grid-float-breakpoint) {\n border-radius: @navbar-border-radius;\n }\n}\n\n\n// Navbar heading\n//\n// Groups `.navbar-brand` and `.navbar-toggle` into a single component for easy\n// styling of responsive aspects.\n\n.navbar-header {\n &:extend(.clearfix all);\n\n @media (min-width: @grid-float-breakpoint) {\n float: left;\n }\n}\n\n\n// Navbar collapse (body)\n//\n// Group your navbar content into this for easy collapsing and expanding across\n// various device sizes. By default, this content is collapsed when <768px, but\n// will expand past that for a horizontal display.\n//\n// To start (on mobile devices) the navbar links, forms, and buttons are stacked\n// vertically and include a `max-height` to overflow in case you have too much\n// content for the user's viewport.\n\n.navbar-collapse {\n max-height: @navbar-collapse-max-height;\n overflow-x: visible;\n padding-right: @navbar-padding-horizontal;\n padding-left: @navbar-padding-horizontal;\n border-top: 1px solid transparent;\n box-shadow: inset 0 1px 0 rgba(255,255,255,.1);\n &:extend(.clearfix all);\n -webkit-overflow-scrolling: touch;\n\n &.in {\n overflow-y: auto;\n }\n\n @media (min-width: @grid-float-breakpoint) {\n width: auto;\n border-top: 0;\n box-shadow: none;\n\n &.collapse {\n display: block !important;\n height: auto !important;\n padding-bottom: 0; // Override default setting\n overflow: visible !important;\n }\n\n &.in {\n overflow-y: visible;\n }\n\n // Undo the collapse side padding for navbars with containers to ensure\n // alignment of right-aligned contents.\n .navbar-fixed-top &,\n .navbar-static-top &,\n .navbar-fixed-bottom & {\n padding-left: 0;\n padding-right: 0;\n }\n }\n}\n\n\n// Both navbar header and collapse\n//\n// When a container is present, change the behavior of the header and collapse.\n\n.container,\n.container-fluid {\n > .navbar-header,\n > .navbar-collapse {\n margin-right: -@navbar-padding-horizontal;\n margin-left: -@navbar-padding-horizontal;\n\n @media (min-width: @grid-float-breakpoint) {\n margin-right: 0;\n margin-left: 0;\n }\n }\n}\n\n\n//\n// Navbar alignment options\n//\n// Display the navbar across the entirety of the page or fixed it to the top or\n// bottom of the page.\n\n// Static top (unfixed, but 100% wide) navbar\n.navbar-static-top {\n z-index: @zindex-navbar;\n border-width: 0 0 1px;\n\n @media (min-width: @grid-float-breakpoint) {\n border-radius: 0;\n }\n}\n\n// Fix the top/bottom navbars when screen real estate supports it\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n position: fixed;\n right: 0;\n left: 0;\n z-index: @zindex-navbar-fixed;\n\n // Undo the rounded corners\n @media (min-width: @grid-float-breakpoint) {\n border-radius: 0;\n }\n}\n.navbar-fixed-top {\n top: 0;\n border-width: 0 0 1px;\n}\n.navbar-fixed-bottom {\n bottom: 0;\n margin-bottom: 0; // override .navbar defaults\n border-width: 1px 0 0;\n}\n\n\n// Brand/project name\n\n.navbar-brand {\n float: left;\n padding: @navbar-padding-vertical @navbar-padding-horizontal;\n font-size: @font-size-large;\n line-height: @line-height-computed;\n height: @navbar-height;\n\n &:hover,\n &:focus {\n text-decoration: none;\n }\n\n @media (min-width: @grid-float-breakpoint) {\n .navbar > .container &,\n .navbar > .container-fluid & {\n margin-left: -@navbar-padding-horizontal;\n }\n }\n}\n\n\n// Navbar toggle\n//\n// Custom button for toggling the `.navbar-collapse`, powered by the collapse\n// JavaScript plugin.\n\n.navbar-toggle {\n position: relative;\n float: right;\n margin-right: @navbar-padding-horizontal;\n padding: 9px 10px;\n .navbar-vertical-align(34px);\n background-color: transparent;\n background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214\n border: 1px solid transparent;\n border-radius: @border-radius-base;\n\n // We remove the `outline` here, but later compensate by attaching `:hover`\n // styles to `:focus`.\n &:focus {\n outline: none;\n }\n\n // Bars\n .icon-bar {\n display: block;\n width: 22px;\n height: 2px;\n border-radius: 1px;\n }\n .icon-bar + .icon-bar {\n margin-top: 4px;\n }\n\n @media (min-width: @grid-float-breakpoint) {\n display: none;\n }\n}\n\n\n// Navbar nav links\n//\n// Builds on top of the `.nav` components with its own modifier class to make\n// the nav the full height of the horizontal nav (above 768px).\n\n.navbar-nav {\n margin: (@navbar-padding-vertical / 2) -@navbar-padding-horizontal;\n\n > li > a {\n padding-top: 10px;\n padding-bottom: 10px;\n line-height: @line-height-computed;\n }\n\n @media (max-width: @grid-float-breakpoint-max) {\n // Dropdowns get custom display when collapsed\n .open .dropdown-menu {\n position: static;\n float: none;\n width: auto;\n margin-top: 0;\n background-color: transparent;\n border: 0;\n box-shadow: none;\n > li > a,\n .dropdown-header {\n padding: 5px 15px 5px 25px;\n }\n > li > a {\n line-height: @line-height-computed;\n &:hover,\n &:focus {\n background-image: none;\n }\n }\n }\n }\n\n // Uncollapse the nav\n @media (min-width: @grid-float-breakpoint) {\n float: left;\n margin: 0;\n\n > li {\n float: left;\n > a {\n padding-top: @navbar-padding-vertical;\n padding-bottom: @navbar-padding-vertical;\n }\n }\n\n &.navbar-right:last-child {\n margin-right: -@navbar-padding-horizontal;\n }\n }\n}\n\n\n// Component alignment\n//\n// Repurpose the pull utilities as their own navbar utilities to avoid specificity\n// issues with parents and chaining. Only do this when the navbar is uncollapsed\n// though so that navbar contents properly stack and align in mobile.\n\n@media (min-width: @grid-float-breakpoint) {\n .navbar-left { .pull-left(); }\n .navbar-right { .pull-right(); }\n}\n\n\n// Navbar form\n//\n// Extension of the `.form-inline` with some extra flavor for optimum display in\n// our navbars.\n\n.navbar-form {\n margin-left: -@navbar-padding-horizontal;\n margin-right: -@navbar-padding-horizontal;\n padding: 10px @navbar-padding-horizontal;\n border-top: 1px solid transparent;\n border-bottom: 1px solid transparent;\n @shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);\n .box-shadow(@shadow);\n\n // Mixin behavior for optimum display\n .form-inline();\n\n .form-group {\n @media (max-width: @grid-float-breakpoint-max) {\n margin-bottom: 5px;\n }\n }\n\n // Vertically center in expanded, horizontal navbar\n .navbar-vertical-align(@input-height-base);\n\n // Undo 100% width for pull classes\n @media (min-width: @grid-float-breakpoint) {\n width: auto;\n border: 0;\n margin-left: 0;\n margin-right: 0;\n padding-top: 0;\n padding-bottom: 0;\n .box-shadow(none);\n\n // Outdent the form if last child to line up with content down the page\n &.navbar-right:last-child {\n margin-right: -@navbar-padding-horizontal;\n }\n }\n}\n\n\n// Dropdown menus\n\n// Menu position and menu carets\n.navbar-nav > li > .dropdown-menu {\n margin-top: 0;\n .border-top-radius(0);\n}\n// Menu position and menu caret support for dropups via extra dropup class\n.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {\n .border-bottom-radius(0);\n}\n\n\n// Buttons in navbars\n//\n// Vertically center a button within a navbar (when *not* in a form).\n\n.navbar-btn {\n .navbar-vertical-align(@input-height-base);\n\n &.btn-sm {\n .navbar-vertical-align(@input-height-small);\n }\n &.btn-xs {\n .navbar-vertical-align(22);\n }\n}\n\n\n// Text in navbars\n//\n// Add a class to make any element properly align itself vertically within the navbars.\n\n.navbar-text {\n .navbar-vertical-align(@line-height-computed);\n\n @media (min-width: @grid-float-breakpoint) {\n float: left;\n margin-left: @navbar-padding-horizontal;\n margin-right: @navbar-padding-horizontal;\n\n // Outdent the form if last child to line up with content down the page\n &.navbar-right:last-child {\n margin-right: 0;\n }\n }\n}\n\n// Alternate navbars\n// --------------------------------------------------\n\n// Default navbar\n.navbar-default {\n background-color: @navbar-default-bg;\n border-color: @navbar-default-border;\n\n .navbar-brand {\n color: @navbar-default-brand-color;\n &:hover,\n &:focus {\n color: @navbar-default-brand-hover-color;\n background-color: @navbar-default-brand-hover-bg;\n }\n }\n\n .navbar-text {\n color: @navbar-default-color;\n }\n\n .navbar-nav {\n > li > a {\n color: @navbar-default-link-color;\n\n &:hover,\n &:focus {\n color: @navbar-default-link-hover-color;\n background-color: @navbar-default-link-hover-bg;\n }\n }\n > .active > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-default-link-active-color;\n background-color: @navbar-default-link-active-bg;\n }\n }\n > .disabled > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-default-link-disabled-color;\n background-color: @navbar-default-link-disabled-bg;\n }\n }\n }\n\n .navbar-toggle {\n border-color: @navbar-default-toggle-border-color;\n &:hover,\n &:focus {\n background-color: @navbar-default-toggle-hover-bg;\n }\n .icon-bar {\n background-color: @navbar-default-toggle-icon-bar-bg;\n }\n }\n\n .navbar-collapse,\n .navbar-form {\n border-color: @navbar-default-border;\n }\n\n // Dropdown menu items\n .navbar-nav {\n // Remove background color from open dropdown\n > .open > a {\n &,\n &:hover,\n &:focus {\n background-color: @navbar-default-link-active-bg;\n color: @navbar-default-link-active-color;\n }\n }\n\n @media (max-width: @grid-float-breakpoint-max) {\n // Dropdowns get custom display when collapsed\n .open .dropdown-menu {\n > li > a {\n color: @navbar-default-link-color;\n &:hover,\n &:focus {\n color: @navbar-default-link-hover-color;\n background-color: @navbar-default-link-hover-bg;\n }\n }\n > .active > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-default-link-active-color;\n background-color: @navbar-default-link-active-bg;\n }\n }\n > .disabled > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-default-link-disabled-color;\n background-color: @navbar-default-link-disabled-bg;\n }\n }\n }\n }\n }\n\n\n // Links in navbars\n //\n // Add a class to ensure links outside the navbar nav are colored correctly.\n\n .navbar-link {\n color: @navbar-default-link-color;\n &:hover {\n color: @navbar-default-link-hover-color;\n }\n }\n\n}\n\n// Inverse navbar\n\n.navbar-inverse {\n background-color: @navbar-inverse-bg;\n border-color: @navbar-inverse-border;\n\n .navbar-brand {\n color: @navbar-inverse-brand-color;\n &:hover,\n &:focus {\n color: @navbar-inverse-brand-hover-color;\n background-color: @navbar-inverse-brand-hover-bg;\n }\n }\n\n .navbar-text {\n color: @navbar-inverse-color;\n }\n\n .navbar-nav {\n > li > a {\n color: @navbar-inverse-link-color;\n\n &:hover,\n &:focus {\n color: @navbar-inverse-link-hover-color;\n background-color: @navbar-inverse-link-hover-bg;\n }\n }\n > .active > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-inverse-link-active-color;\n background-color: @navbar-inverse-link-active-bg;\n }\n }\n > .disabled > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-inverse-link-disabled-color;\n background-color: @navbar-inverse-link-disabled-bg;\n }\n }\n }\n\n // Darken the responsive nav toggle\n .navbar-toggle {\n border-color: @navbar-inverse-toggle-border-color;\n &:hover,\n &:focus {\n background-color: @navbar-inverse-toggle-hover-bg;\n }\n .icon-bar {\n background-color: @navbar-inverse-toggle-icon-bar-bg;\n }\n }\n\n .navbar-collapse,\n .navbar-form {\n border-color: darken(@navbar-inverse-bg, 7%);\n }\n\n // Dropdowns\n .navbar-nav {\n > .open > a {\n &,\n &:hover,\n &:focus {\n background-color: @navbar-inverse-link-active-bg;\n color: @navbar-inverse-link-active-color;\n }\n }\n\n @media (max-width: @grid-float-breakpoint-max) {\n // Dropdowns get custom display\n .open .dropdown-menu {\n > .dropdown-header {\n border-color: @navbar-inverse-border;\n }\n .divider {\n background-color: @navbar-inverse-border;\n }\n > li > a {\n color: @navbar-inverse-link-color;\n &:hover,\n &:focus {\n color: @navbar-inverse-link-hover-color;\n background-color: @navbar-inverse-link-hover-bg;\n }\n }\n > .active > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-inverse-link-active-color;\n background-color: @navbar-inverse-link-active-bg;\n }\n }\n > .disabled > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-inverse-link-disabled-color;\n background-color: @navbar-inverse-link-disabled-bg;\n }\n }\n }\n }\n }\n\n .navbar-link {\n color: @navbar-inverse-link-color;\n &:hover {\n color: @navbar-inverse-link-hover-color;\n }\n }\n\n}\n","//\n// Utility classes\n// --------------------------------------------------\n\n\n// Floats\n// -------------------------\n\n.clearfix {\n .clearfix();\n}\n.center-block {\n .center-block();\n}\n.pull-right {\n float: right !important;\n}\n.pull-left {\n float: left !important;\n}\n\n\n// Toggling content\n// -------------------------\n\n// Note: Deprecated .hide in favor of .hidden or .sr-only (as appropriate) in v3.0.1\n.hide {\n display: none !important;\n}\n.show {\n display: block !important;\n}\n.invisible {\n visibility: hidden;\n}\n.text-hide {\n .text-hide();\n}\n\n\n// Hide from screenreaders and browsers\n//\n// Credit: HTML5 Boilerplate\n\n.hidden {\n display: none !important;\n visibility: hidden !important;\n}\n\n\n// For Affix plugin\n// -------------------------\n\n.affix {\n position: fixed;\n}\n","//\n// Breadcrumbs\n// --------------------------------------------------\n\n\n.breadcrumb {\n padding: @breadcrumb-padding-vertical @breadcrumb-padding-horizontal;\n margin-bottom: @line-height-computed;\n list-style: none;\n background-color: @breadcrumb-bg;\n border-radius: @border-radius-base;\n\n > li {\n display: inline-block;\n\n + li:before {\n content: \"@{breadcrumb-separator}\\00a0\"; // Unicode space added since inline-block means non-collapsing white-space\n padding: 0 5px;\n color: @breadcrumb-color;\n }\n }\n\n > .active {\n color: @breadcrumb-active-color;\n }\n}\n","//\n// Pagination (multiple pages)\n// --------------------------------------------------\n.pagination {\n display: inline-block;\n padding-left: 0;\n margin: @line-height-computed 0;\n border-radius: @border-radius-base;\n\n > li {\n display: inline; // Remove list-style and block-level defaults\n > a,\n > span {\n position: relative;\n float: left; // Collapse white-space\n padding: @padding-base-vertical @padding-base-horizontal;\n line-height: @line-height-base;\n text-decoration: none;\n color: @pagination-color;\n background-color: @pagination-bg;\n border: 1px solid @pagination-border;\n margin-left: -1px;\n }\n &:first-child {\n > a,\n > span {\n margin-left: 0;\n .border-left-radius(@border-radius-base);\n }\n }\n &:last-child {\n > a,\n > span {\n .border-right-radius(@border-radius-base);\n }\n }\n }\n\n > li > a,\n > li > span {\n &:hover,\n &:focus {\n color: @pagination-hover-color;\n background-color: @pagination-hover-bg;\n border-color: @pagination-hover-border;\n }\n }\n\n > .active > a,\n > .active > span {\n &,\n &:hover,\n &:focus {\n z-index: 2;\n color: @pagination-active-color;\n background-color: @pagination-active-bg;\n border-color: @pagination-active-border;\n cursor: default;\n }\n }\n\n > .disabled {\n > span,\n > span:hover,\n > span:focus,\n > a,\n > a:hover,\n > a:focus {\n color: @pagination-disabled-color;\n background-color: @pagination-disabled-bg;\n border-color: @pagination-disabled-border;\n cursor: not-allowed;\n }\n }\n}\n\n// Sizing\n// --------------------------------------------------\n\n// Large\n.pagination-lg {\n .pagination-size(@padding-large-vertical; @padding-large-horizontal; @font-size-large; @border-radius-large);\n}\n\n// Small\n.pagination-sm {\n .pagination-size(@padding-small-vertical; @padding-small-horizontal; @font-size-small; @border-radius-small);\n}\n","//\n// Pager pagination\n// --------------------------------------------------\n\n\n.pager {\n padding-left: 0;\n margin: @line-height-computed 0;\n list-style: none;\n text-align: center;\n &:extend(.clearfix all);\n li {\n display: inline;\n > a,\n > span {\n display: inline-block;\n padding: 5px 14px;\n background-color: @pager-bg;\n border: 1px solid @pager-border;\n border-radius: @pager-border-radius;\n }\n\n > a:hover,\n > a:focus {\n text-decoration: none;\n background-color: @pager-hover-bg;\n }\n }\n\n .next {\n > a,\n > span {\n float: right;\n }\n }\n\n .previous {\n > a,\n > span {\n float: left;\n }\n }\n\n .disabled {\n > a,\n > a:hover,\n > a:focus,\n > span {\n color: @pager-disabled-color;\n background-color: @pager-bg;\n cursor: not-allowed;\n }\n }\n\n}\n","//\n// Labels\n// --------------------------------------------------\n\n.label {\n display: inline;\n padding: .2em .6em .3em;\n font-size: 75%;\n font-weight: bold;\n line-height: 1;\n color: @label-color;\n text-align: center;\n white-space: nowrap;\n vertical-align: baseline;\n border-radius: .25em;\n\n // Add hover effects, but only for links\n &[href] {\n &:hover,\n &:focus {\n color: @label-link-hover-color;\n text-decoration: none;\n cursor: pointer;\n }\n }\n\n // Empty labels collapse automatically (not available in IE8)\n &:empty {\n display: none;\n }\n\n // Quick fix for labels in buttons\n .btn & {\n position: relative;\n top: -1px;\n }\n}\n\n// Colors\n// Contextual variations (linked labels get darker on :hover)\n\n.label-default {\n .label-variant(@label-default-bg);\n}\n\n.label-primary {\n .label-variant(@label-primary-bg);\n}\n\n.label-success {\n .label-variant(@label-success-bg);\n}\n\n.label-info {\n .label-variant(@label-info-bg);\n}\n\n.label-warning {\n .label-variant(@label-warning-bg);\n}\n\n.label-danger {\n .label-variant(@label-danger-bg);\n}\n","//\n// Badges\n// --------------------------------------------------\n\n\n// Base classes\n.badge {\n display: inline-block;\n min-width: 10px;\n padding: 3px 7px;\n font-size: @font-size-small;\n font-weight: @badge-font-weight;\n color: @badge-color;\n line-height: @badge-line-height;\n vertical-align: baseline;\n white-space: nowrap;\n text-align: center;\n background-color: @badge-bg;\n border-radius: @badge-border-radius;\n\n // Empty badges collapse automatically (not available in IE8)\n &:empty {\n display: none;\n }\n\n // Quick fix for badges in buttons\n .btn & {\n position: relative;\n top: -1px;\n }\n .btn-xs & {\n top: 0;\n padding: 1px 5px;\n }\n}\n\n// Hover state, but only for links\na.badge {\n &:hover,\n &:focus {\n color: @badge-link-hover-color;\n text-decoration: none;\n cursor: pointer;\n }\n}\n\n// Account for counters in navs\na.list-group-item.active > .badge,\n.nav-pills > .active > a > .badge {\n color: @badge-active-color;\n background-color: @badge-active-bg;\n}\n.nav-pills > li > a > .badge {\n margin-left: 3px;\n}\n","//\n// Jumbotron\n// --------------------------------------------------\n\n\n.jumbotron {\n padding: @jumbotron-padding;\n margin-bottom: @jumbotron-padding;\n color: @jumbotron-color;\n background-color: @jumbotron-bg;\n\n h1,\n .h1 {\n color: @jumbotron-heading-color;\n }\n p {\n margin-bottom: (@jumbotron-padding / 2);\n font-size: @jumbotron-font-size;\n font-weight: 200;\n }\n\n .container & {\n border-radius: @border-radius-large; // Only round corners at higher resolutions if contained in a container\n }\n\n .container {\n max-width: 100%;\n }\n\n @media screen and (min-width: @screen-sm-min) {\n padding-top: (@jumbotron-padding * 1.6);\n padding-bottom: (@jumbotron-padding * 1.6);\n\n .container & {\n padding-left: (@jumbotron-padding * 2);\n padding-right: (@jumbotron-padding * 2);\n }\n\n h1,\n .h1 {\n font-size: (@font-size-base * 4.5);\n }\n }\n}\n","//\n// Alerts\n// --------------------------------------------------\n\n\n// Base styles\n// -------------------------\n\n.alert {\n padding: @alert-padding;\n margin-bottom: @line-height-computed;\n border: 1px solid transparent;\n border-radius: @alert-border-radius;\n\n // Headings for larger alerts\n h4 {\n margin-top: 0;\n // Specified for the h4 to prevent conflicts of changing @headings-color\n color: inherit;\n }\n // Provide class for links that match alerts\n .alert-link {\n font-weight: @alert-link-font-weight;\n }\n\n // Improve alignment and spacing of inner content\n > p,\n > ul {\n margin-bottom: 0;\n }\n > p + p {\n margin-top: 5px;\n }\n}\n\n// Dismissable alerts\n//\n// Expand the right padding and account for the close button's positioning.\n\n.alert-dismissable {\n padding-right: (@alert-padding + 20);\n\n // Adjust close link position\n .close {\n position: relative;\n top: -2px;\n right: -21px;\n color: inherit;\n }\n}\n\n// Alternate styles\n//\n// Generate contextual modifier classes for colorizing the alert.\n\n.alert-success {\n .alert-variant(@alert-success-bg; @alert-success-border; @alert-success-text);\n}\n.alert-info {\n .alert-variant(@alert-info-bg; @alert-info-border; @alert-info-text);\n}\n.alert-warning {\n .alert-variant(@alert-warning-bg; @alert-warning-border; @alert-warning-text);\n}\n.alert-danger {\n .alert-variant(@alert-danger-bg; @alert-danger-border; @alert-danger-text);\n}\n","//\n// Progress bars\n// --------------------------------------------------\n\n\n// Bar animations\n// -------------------------\n\n// WebKit\n@-webkit-keyframes progress-bar-stripes {\n from { background-position: 40px 0; }\n to { background-position: 0 0; }\n}\n\n// Spec and IE10+\n@keyframes progress-bar-stripes {\n from { background-position: 40px 0; }\n to { background-position: 0 0; }\n}\n\n\n\n// Bar itself\n// -------------------------\n\n// Outer container\n.progress {\n overflow: hidden;\n height: @line-height-computed;\n margin-bottom: @line-height-computed;\n background-color: @progress-bg;\n border-radius: @border-radius-base;\n .box-shadow(inset 0 1px 2px rgba(0,0,0,.1));\n}\n\n// Bar of progress\n.progress-bar {\n float: left;\n width: 0%;\n height: 100%;\n font-size: @font-size-small;\n line-height: @line-height-computed;\n color: @progress-bar-color;\n text-align: center;\n background-color: @progress-bar-bg;\n .box-shadow(inset 0 -1px 0 rgba(0,0,0,.15));\n .transition(width .6s ease);\n}\n\n// Striped bars\n.progress-striped .progress-bar {\n #gradient > .striped();\n background-size: 40px 40px;\n}\n\n// Call animation for the active one\n.progress.active .progress-bar {\n .animation(progress-bar-stripes 2s linear infinite);\n}\n\n\n\n// Variations\n// -------------------------\n\n.progress-bar-success {\n .progress-bar-variant(@progress-bar-success-bg);\n}\n\n.progress-bar-info {\n .progress-bar-variant(@progress-bar-info-bg);\n}\n\n.progress-bar-warning {\n .progress-bar-variant(@progress-bar-warning-bg);\n}\n\n.progress-bar-danger {\n .progress-bar-variant(@progress-bar-danger-bg);\n}\n","// Media objects\n// Source: http://stubbornella.org/content/?p=497\n// --------------------------------------------------\n\n\n// Common styles\n// -------------------------\n\n// Clear the floats\n.media,\n.media-body {\n overflow: hidden;\n zoom: 1;\n}\n\n// Proper spacing between instances of .media\n.media,\n.media .media {\n margin-top: 15px;\n}\n.media:first-child {\n margin-top: 0;\n}\n\n// For images and videos, set to block\n.media-object {\n display: block;\n}\n\n// Reset margins on headings for tighter default spacing\n.media-heading {\n margin: 0 0 5px;\n}\n\n\n// Media image alignment\n// -------------------------\n\n.media {\n > .pull-left {\n margin-right: 10px;\n }\n > .pull-right {\n margin-left: 10px;\n }\n}\n\n\n// Media list variation\n// -------------------------\n\n// Undo default ul/ol styles\n.media-list {\n padding-left: 0;\n list-style: none;\n}\n","//\n// List groups\n// --------------------------------------------------\n\n\n// Base class\n//\n// Easily usable on

3. Configure your miner.

    If your using Linux, Then type the following into the console:

  • CGMiner
  • -
    ./cgminer {if $GLOBAL.config.algorithm == 'scrypt'}--scrypt{/if} -o stratum+tcp://{$SITESTRATUMURL|default:$smarty.server.SERVER_NAME}:{$SITESTRATUMPORT|default:"3333"} -u Weblogin.WorkerName -p WorkerPassword
    +
    ./cgminer {if $GLOBAL.config.algorithm == 'scrypt'}--scrypt {/if}-o stratum+tcp://{$SITESTRATUMURL|default:$smarty.server.SERVER_NAME}:{$SITESTRATUMPORT|default:"3333"} -u Weblogin.WorkerName -p WorkerPassword
  • BFGMiner
  • -
    ./bfgminer {if $GLOBAL.config.algorithm == 'scrypt'}--scrypt{/if} -o stratum+tcp://{$SITESTRATUMURL|default:$smarty.server.SERVER_NAME}:{$SITESTRATUMPORT|default:"3333"} -u Weblogin.WorkerName -p WorkerPassword
    +
    ./bfgminer {if $GLOBAL.config.algorithm == 'scrypt'}--scrypt {/if}-o stratum+tcp://{$SITESTRATUMURL|default:$smarty.server.SERVER_NAME}:{$SITESTRATUMPORT|default:"3333"} -u Weblogin.WorkerName -p WorkerPassword

    -

    If you want to mine on a Windows Operating System , Then you'll need to create a Batch File to start your miner.

    You can download pre-configured one from MEGA Here or you can make your own by opening notepad and then copy and pasting the following:

    -
  • MinerD
  • -
    minerd -a {if $GLOBAL.config.algorithm == 'scrypt'}--scrypt{/if} -t 6 -s 4 -o stratum+tcp://{$SITESTRATUMURL|default:$smarty.server.SERVER_NAME}:{$SITESTRATUMPORT|default:"3333"} -u Weblogin.WorkerName -p WorkerPassword
    +

    If you want to mine on a Windows Operating System, then you'll need to create a batch file to start your miner.

    Simply open notepad and then copy and paste the following:

  • CGMiner
  • -
    cgminer {if $GLOBAL.config.algorithm == 'scrypt'}--scrypt{/if} -o stratum+tcp://{$SITESTRATUMURL|default:$smarty.server.SERVER_NAME}:{$SITESTRATUMPORT|default:"3333"} -u Weblogin.WorkerName -p WorkerPassword
    +
    cgminer {if $GLOBAL.config.algorithm == 'scrypt'}--scrypt {/if}-o stratum+tcp://{$SITESTRATUMURL|default:$smarty.server.SERVER_NAME}:{$SITESTRATUMPORT|default:"3333"} -u Weblogin.WorkerName -p WorkerPassword
  • BFGMiner
  • -
    bfgminer {if $GLOBAL.config.algorithm == 'scrypt'}--scrypt{/if} -o stratum+tcp://{$SITESTRATUMURL|default:$smarty.server.SERVER_NAME}:{$SITESTRATUMPORT|default:"3333"} -u Weblogin.WorkerName -p WorkerPassword
    +
    bfgminer {if $GLOBAL.config.algorithm == 'scrypt'}--scrypt {/if}-o stratum+tcp://{$SITESTRATUMURL|default:$smarty.server.SERVER_NAME}:{$SITESTRATUMPORT|default:"3333"} -u Weblogin.WorkerName -p WorkerPassword
    +
  • MinerD
  • +
    minerd -a {if $GLOBAL.config.algorithm == 'scrypt'}--scrypt {/if}-t 6 -s 4 -o stratum+tcp://{$SITESTRATUMURL|default:$smarty.server.SERVER_NAME}:{$SITESTRATUMPORT|default:"3333"} -u Weblogin.WorkerName -p WorkerPassword
    + {if $GLOBAL.config.algorithm == 'scrypt'}
  • Cudaminer For NVIDIA Cards
  • cudaminer -o stratum+tcp://{$SITESTRATUMURL|default:$smarty.server.SERVER_NAME}:{$SITESTRATUMPORT|default:"3333"} -u Weblogin.WorkerName -p WorkerPassword
    + {/if}
    -

    You then need to change "-u Weblogin.Worker -p Worker password" to reflect your own account. Eg, "-u Steve.StevesWorker -p StevesWorkerPassword" Then go to "File => Save as" and save the file as "RunMe.bat" in the same folder as minerd. You are now ready to mine, double click on "RunMe.bat" to start mining. If you want, you can create additional workers with usernames and passwords of your choice here

    +

    You then need to change "-u Weblogin.Worker -p Worker password" to reflect your own account. Eg, "-u Steve.StevesWorker -p StevesWorkerPassword" then go to "File > Save as" and save the file as "RunMe.bat" in the same folder containing your miners application files. You are now ready to mine, double click on "RunMe.bat" to start mining. If you want, you can create additional workers with usernames and passwords of your choice here

4. Create a {$SITECOINNAME|default:"Litecoin"} address to receive payments.

    @@ -51,15 +57,17 @@
-

5. Advanced cgminer settings / FAQ

+ {if $GLOBAL.config.algorithm == 'scrypt'} +

5. Advanced CGMiner settings / FAQ

  • Scrypt readme
  • -
  • Don't set intensity too high, I=11 is standard and safest. Higher intensity takes more GPU RAM. Check for hardware errors in cgminer (HW). HW=0 is good, otherwise lower intensity :)
  • -
  • Set shaders according to the readme (or look at your graphic cards specifications). Cgminer uses this value at first run to calculate thread-concurrency. Easiest way to get this optimized is to use same settings as others have used here: here.
  • -
  • There's also an interesting project which gives you a GUI for cgminer. Windows only it seems.
  • +
  • Don't set intensity too high, I=11 is standard and safest. Higher intensity takes more GPU RAM. Check for hardware errors in CGMiner (HW). HW=0 is good, otherwise lower intensity.
  • +
  • Set shaders according to the readme (or look at your graphic cards specifications). CGMiner uses this value at first run to calculate thread-concurrency. Easiest way to get this optimized is to use same settings as others have used here: here.
  • +
  • There's also an interesting project which gives you a GUI for CGMiner. Windows only it seems.
  • Here's a great guide how to get up and running with Xubuntu.
+ {/if} diff --git a/public/templates/bootstrap/global/footer.tpl b/templates/bootstrap/global/footer.tpl similarity index 100% rename from public/templates/bootstrap/global/footer.tpl rename to templates/bootstrap/global/footer.tpl diff --git a/public/templates/bootstrap/global/header.tpl b/templates/bootstrap/global/header.tpl similarity index 100% rename from public/templates/bootstrap/global/header.tpl rename to templates/bootstrap/global/header.tpl diff --git a/public/templates/bootstrap/global/navigation.tpl b/templates/bootstrap/global/navigation.tpl similarity index 63% rename from public/templates/bootstrap/global/navigation.tpl rename to templates/bootstrap/global/navigation.tpl index 6982f8d26..a2f0dd413 100644 --- a/public/templates/bootstrap/global/navigation.tpl +++ b/templates/bootstrap/global/navigation.tpl @@ -8,14 +8,14 @@
  • Dashboard
  • - +
  • My Account